Home | History | Annotate | Line # | Download | only in usb
      1 /*	$NetBSD: if_cue.c,v 1.109 2024/06/29 12:11:12 riastradh Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1997, 1998, 1999, 2000
      5  *	Bill Paul <wpaul (at) ee.columbia.edu>.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *	This product includes software developed by Bill Paul.
     18  * 4. Neither the name of the author nor the names of any co-contributors
     19  *    may be used to endorse or promote products derived from this software
     20  *    without specific prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
     23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
     26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
     32  * THE POSSIBILITY OF SUCH DAMAGE.
     33  *
     34  * $FreeBSD: src/sys/dev/usb/if_cue.c,v 1.4 2000/01/16 22:45:06 wpaul Exp $
     35  */
     36 
     37 /*
     38  * CATC USB-EL1210A USB to ethernet driver. Used in the CATC Netmate
     39  * adapters and others.
     40  *
     41  * Written by Bill Paul <wpaul (at) ee.columbia.edu>
     42  * Electrical Engineering Department
     43  * Columbia University, New York City
     44  */
     45 
     46 /*
     47  * The CATC USB-EL1210A provides USB ethernet support at 10Mbps. The
     48  * RX filter uses a 512-bit multicast hash table, single perfect entry
     49  * for the station address, and promiscuous mode. Unlike the ADMtek
     50  * and KLSI chips, the CATC ASIC supports read and write combining
     51  * mode where multiple packets can be transferred using a single bulk
     52  * transaction, which helps performance a great deal.
     53  */
     54 
     55 /*
     56  * Ported to NetBSD and somewhat rewritten by Lennart Augustsson.
     57  */
     58 
     59 #include <sys/cdefs.h>
     60 __KERNEL_RCSID(0, "$NetBSD: if_cue.c,v 1.109 2024/06/29 12:11:12 riastradh Exp $");
     61 
     62 #ifdef _KERNEL_OPT
     63 #include "opt_inet.h"
     64 #include "opt_usb.h"
     65 #endif
     66 
     67 #include <sys/param.h>
     68 
     69 #include <dev/usb/usbnet.h>
     70 #include <dev/usb/if_cuereg.h>
     71 
     72 #ifdef INET
     73 #include <netinet/in.h>
     74 #include <netinet/if_inarp.h>
     75 #endif
     76 
     77 #ifdef CUE_DEBUG
     78 #define DPRINTF(x)	if (cuedebug) printf x
     79 #define DPRINTFN(n, x)	if (cuedebug >= (n)) printf x
     80 int	cuedebug = 0;
     81 #else
     82 #define DPRINTF(x)
     83 #define DPRINTFN(n, x)
     84 #endif
     85 
     86 #define CUE_BUFSZ		1536
     87 #define CUE_MIN_FRAMELEN	60
     88 #define CUE_RX_FRAMES		1
     89 #define CUE_TX_FRAMES		1
     90 
     91 #define CUE_CONFIG_NO		1
     92 #define CUE_IFACE_IDX		0
     93 
     94 #define CUE_RX_LIST_CNT		1
     95 #define CUE_TX_LIST_CNT		1
     96 
     97 struct cue_type {
     98 	uint16_t		cue_vid;
     99 	uint16_t		cue_did;
    100 };
    101 
    102 struct cue_softc;
    103 
    104 struct cue_chain {
    105 	struct cue_softc	*cue_sc;
    106 	struct usbd_xfer	*cue_xfer;
    107 	char			*cue_buf;
    108 	struct mbuf		*cue_mbuf;
    109 	int			cue_idx;
    110 };
    111 
    112 struct cue_cdata {
    113 	struct cue_chain	cue_tx_chain[CUE_TX_LIST_CNT];
    114 	struct cue_chain	cue_rx_chain[CUE_RX_LIST_CNT];
    115 	int			cue_tx_prod;
    116 	int			cue_tx_cnt;
    117 };
    118 
    119 struct cue_softc {
    120 	struct usbnet		cue_un;
    121 	uint8_t			cue_mctab[CUE_MCAST_TABLE_LEN];
    122 };
    123 
    124 /*
    125  * Various supported device vendors/products.
    126  */
    127 static const struct usb_devno cue_devs[] = {
    128 	{ USB_VENDOR_CATC, USB_PRODUCT_CATC_NETMATE },
    129 	{ USB_VENDOR_CATC, USB_PRODUCT_CATC_NETMATE2 },
    130 	{ USB_VENDOR_SMARTBRIDGES, USB_PRODUCT_SMARTBRIDGES_SMARTLINK },
    131 	/* Belkin F5U111 adapter covered by NETMATE entry */
    132 };
    133 #define cue_lookup(v, p) (usb_lookup(cue_devs, v, p))
    134 
    135 static int cue_match(device_t, cfdata_t, void *);
    136 static void cue_attach(device_t, device_t, void *);
    137 
    138 CFATTACH_DECL_NEW(cue, sizeof(struct cue_softc), cue_match, cue_attach,
    139     usbnet_detach, usbnet_activate);
    140 
    141 static unsigned cue_uno_tx_prepare(struct usbnet *, struct mbuf *,
    142 				   struct usbnet_chain *);
    143 static void cue_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t);
    144 static void cue_uno_mcast(struct ifnet *);
    145 static void cue_uno_stop(struct ifnet *, int);
    146 static int cue_uno_init(struct ifnet *);
    147 static void cue_uno_tick(struct usbnet *);
    148 
    149 static const struct usbnet_ops cue_ops = {
    150 	.uno_stop = cue_uno_stop,
    151 	.uno_mcast = cue_uno_mcast,
    152 	.uno_tx_prepare = cue_uno_tx_prepare,
    153 	.uno_rx_loop = cue_uno_rx_loop,
    154 	.uno_init = cue_uno_init,
    155 	.uno_tick = cue_uno_tick,
    156 };
    157 
    158 #ifdef CUE_DEBUG
    159 static int
    160 cue_csr_read_1(struct usbnet *un, int reg)
    161 {
    162 	usb_device_request_t	req;
    163 	usbd_status		err;
    164 	uint8_t			val = 0;
    165 
    166 	if (usbnet_isdying(un))
    167 		return 0;
    168 
    169 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
    170 	req.bRequest = CUE_CMD_READREG;
    171 	USETW(req.wValue, 0);
    172 	USETW(req.wIndex, reg);
    173 	USETW(req.wLength, 1);
    174 
    175 	err = usbd_do_request(un->un_udev, &req, &val);
    176 
    177 	if (err) {
    178 		DPRINTF(("%s: cue_csr_read_1: reg=%#x err=%s\n",
    179 		    device_xname(un->un_dev), reg, usbd_errstr(err)));
    180 		return 0;
    181 	}
    182 
    183 	DPRINTFN(10,("%s: cue_csr_read_1 reg=%#x val=%#x\n",
    184 	    device_xname(un->un_dev), reg, val));
    185 
    186 	return val;
    187 }
    188 #endif
    189 
    190 static int
    191 cue_csr_read_2(struct usbnet *un, int reg)
    192 {
    193 	usb_device_request_t	req;
    194 	usbd_status		err;
    195 	uWord			val;
    196 
    197 	if (usbnet_isdying(un))
    198 		return 0;
    199 
    200 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
    201 	req.bRequest = CUE_CMD_READREG;
    202 	USETW(req.wValue, 0);
    203 	USETW(req.wIndex, reg);
    204 	USETW(req.wLength, 2);
    205 
    206 	err = usbd_do_request(un->un_udev, &req, &val);
    207 
    208 	DPRINTFN(10,("%s: cue_csr_read_2 reg=%#x val=%#x\n",
    209 	    device_xname(un->un_dev), reg, UGETW(val)));
    210 
    211 	if (err) {
    212 		DPRINTF(("%s: cue_csr_read_2: reg=%#x err=%s\n",
    213 		    device_xname(un->un_dev), reg, usbd_errstr(err)));
    214 		return 0;
    215 	}
    216 
    217 	return UGETW(val);
    218 }
    219 
    220 static int
    221 cue_csr_write_1(struct usbnet *un, int reg, int val)
    222 {
    223 	usb_device_request_t	req;
    224 	usbd_status		err;
    225 
    226 	if (usbnet_isdying(un))
    227 		return 0;
    228 
    229 	DPRINTFN(10,("%s: cue_csr_write_1 reg=%#x val=%#x\n",
    230 	    device_xname(un->un_dev), reg, val));
    231 
    232 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
    233 	req.bRequest = CUE_CMD_WRITEREG;
    234 	USETW(req.wValue, val);
    235 	USETW(req.wIndex, reg);
    236 	USETW(req.wLength, 0);
    237 
    238 	err = usbd_do_request(un->un_udev, &req, NULL);
    239 
    240 	if (err) {
    241 		DPRINTF(("%s: cue_csr_write_1: reg=%#x err=%s\n",
    242 		    device_xname(un->un_dev), reg, usbd_errstr(err)));
    243 		return -1;
    244 	}
    245 
    246 	DPRINTFN(20,("%s: cue_csr_write_1, after reg=%#x val=%#x\n",
    247 	    device_xname(un->un_dev), reg, cue_csr_read_1(un, reg)));
    248 
    249 	return 0;
    250 }
    251 
    252 #if 0
    253 static int
    254 cue_csr_write_2(struct usbnet *un, int reg, int aval)
    255 {
    256 	usb_device_request_t	req;
    257 	usbd_status		err;
    258 	uWord			val;
    259 	int			s;
    260 
    261 	if (usbnet_isdying(un))
    262 		return 0;
    263 
    264 	DPRINTFN(10,("%s: cue_csr_write_2 reg=%#x val=%#x\n",
    265 	    device_xname(un->un_dev), reg, aval));
    266 
    267 	USETW(val, aval);
    268 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
    269 	req.bRequest = CUE_CMD_WRITEREG;
    270 	USETW(req.wValue, val);
    271 	USETW(req.wIndex, reg);
    272 	USETW(req.wLength, 0);
    273 
    274 	err = usbd_do_request(un->un_udev, &req, NULL);
    275 
    276 	if (err) {
    277 		DPRINTF(("%s: cue_csr_write_2: reg=%#x err=%s\n",
    278 		    device_xname(un->un_dev), reg, usbd_errstr(err)));
    279 		return -1;
    280 	}
    281 
    282 	return 0;
    283 }
    284 #endif
    285 
    286 static int
    287 cue_mem(struct usbnet *un, int cmd, int addr, void *buf, int len)
    288 {
    289 	usb_device_request_t	req;
    290 	usbd_status		err;
    291 
    292 	DPRINTFN(10,("%s: cue_mem cmd=%#x addr=%#x len=%d\n",
    293 	    device_xname(un->un_dev), cmd, addr, len));
    294 
    295 	if (cmd == CUE_CMD_READSRAM)
    296 		req.bmRequestType = UT_READ_VENDOR_DEVICE;
    297 	else
    298 		req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
    299 	req.bRequest = cmd;
    300 	USETW(req.wValue, 0);
    301 	USETW(req.wIndex, addr);
    302 	USETW(req.wLength, len);
    303 
    304 	err = usbd_do_request(un->un_udev, &req, buf);
    305 
    306 	if (err) {
    307 		DPRINTF(("%s: cue_csr_mem: addr=%#x err=%s\n",
    308 		    device_xname(un->un_dev), addr, usbd_errstr(err)));
    309 		return -1;
    310 	}
    311 
    312 	return 0;
    313 }
    314 
    315 static int
    316 cue_getmac(struct usbnet *un)
    317 {
    318 	usb_device_request_t	req;
    319 	usbd_status		err;
    320 
    321 	DPRINTFN(10,("%s: cue_getmac\n", device_xname(un->un_dev)));
    322 
    323 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
    324 	req.bRequest = CUE_CMD_GET_MACADDR;
    325 	USETW(req.wValue, 0);
    326 	USETW(req.wIndex, 0);
    327 	USETW(req.wLength, ETHER_ADDR_LEN);
    328 
    329 	err = usbd_do_request(un->un_udev, &req, un->un_eaddr);
    330 
    331 	if (err) {
    332 		printf("%s: read MAC address failed\n",
    333 		    device_xname(un->un_dev));
    334 		return -1;
    335 	}
    336 
    337 	return 0;
    338 }
    339 
    340 #define CUE_POLY	0xEDB88320
    341 #define CUE_BITS	9
    342 
    343 static uint32_t
    344 cue_crc(const char *addr)
    345 {
    346 	uint32_t		idx, bit, data, crc;
    347 
    348 	/* Compute CRC for the address value. */
    349 	crc = 0xFFFFFFFF; /* initial value */
    350 
    351 	for (idx = 0; idx < 6; idx++) {
    352 		for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1)
    353 			crc = (crc >> 1) ^ (((crc ^ data) & 1) ? CUE_POLY : 0);
    354 	}
    355 
    356 	return crc & ((1 << CUE_BITS) - 1);
    357 }
    358 
    359 static void
    360 cue_uno_mcast(struct ifnet *ifp)
    361 {
    362 	struct usbnet		*un = ifp->if_softc;
    363 	struct cue_softc	*sc = usbnet_softc(un);
    364 	struct ethercom		*ec = usbnet_ec(un);
    365 	struct ether_multi	*enm;
    366 	struct ether_multistep	step;
    367 	uint32_t		h, i;
    368 
    369 	DPRINTFN(2,("%s: cue_setiff promisc=%d\n",
    370 	    device_xname(un->un_dev), usbnet_ispromisc(un)));
    371 
    372 	if (usbnet_ispromisc(un)) {
    373 		ETHER_LOCK(ec);
    374 allmulti:
    375 		ec->ec_flags |= ETHER_F_ALLMULTI;
    376 		ETHER_UNLOCK(ec);
    377 		for (i = 0; i < CUE_MCAST_TABLE_LEN; i++)
    378 			sc->cue_mctab[i] = 0xFF;
    379 		cue_mem(un, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR,
    380 		    &sc->cue_mctab, CUE_MCAST_TABLE_LEN);
    381 		return;
    382 	}
    383 
    384 	/* first, zot all the existing hash bits */
    385 	for (i = 0; i < CUE_MCAST_TABLE_LEN; i++)
    386 		sc->cue_mctab[i] = 0;
    387 
    388 	/* now program new ones */
    389 	ETHER_LOCK(ec);
    390 	ETHER_FIRST_MULTI(step, ec, enm);
    391 	while (enm != NULL) {
    392 		if (memcmp(enm->enm_addrlo,
    393 		    enm->enm_addrhi, ETHER_ADDR_LEN) != 0) {
    394 			goto allmulti;
    395 		}
    396 
    397 		h = cue_crc(enm->enm_addrlo);
    398 		sc->cue_mctab[h >> 3] |= 1 << (h & 0x7);
    399 		ETHER_NEXT_MULTI(step, enm);
    400 	}
    401 	ec->ec_flags &= ~ETHER_F_ALLMULTI;
    402 	ETHER_UNLOCK(ec);
    403 
    404 	/*
    405 	 * Also include the broadcast address in the filter
    406 	 * so we can receive broadcast frames.
    407 	 */
    408 	h = cue_crc(etherbroadcastaddr);
    409 	sc->cue_mctab[h >> 3] |= 1 << (h & 0x7);
    410 
    411 	cue_mem(un, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR,
    412 	    &sc->cue_mctab, CUE_MCAST_TABLE_LEN);
    413 }
    414 
    415 static void
    416 cue_reset(struct usbnet *un)
    417 {
    418 	usb_device_request_t	req;
    419 	usbd_status		err;
    420 
    421 	DPRINTFN(2,("%s: cue_reset\n", device_xname(un->un_dev)));
    422 
    423 	if (usbnet_isdying(un))
    424 		return;
    425 
    426 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
    427 	req.bRequest = CUE_CMD_RESET;
    428 	USETW(req.wValue, 0);
    429 	USETW(req.wIndex, 0);
    430 	USETW(req.wLength, 0);
    431 
    432 	err = usbd_do_request(un->un_udev, &req, NULL);
    433 
    434 	if (err)
    435 		printf("%s: reset failed\n", device_xname(un->un_dev));
    436 
    437 	/* Wait a little while for the chip to get its brains in order. */
    438 	usbd_delay_ms(un->un_udev, 1);
    439 }
    440 
    441 /*
    442  * Probe for a CATC chip.
    443  */
    444 static int
    445 cue_match(device_t parent, cfdata_t match, void *aux)
    446 {
    447 	struct usb_attach_arg *uaa = aux;
    448 
    449 	return cue_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ?
    450 		UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
    451 }
    452 
    453 /*
    454  * Attach the interface. Allocate softc structures, do ifmedia
    455  * setup and ethernet/BPF attach.
    456  */
    457 static void
    458 cue_attach(device_t parent, device_t self, void *aux)
    459 {
    460 	struct cue_softc *sc = device_private(self);
    461 	struct usbnet * const un = &sc->cue_un;
    462 	struct usb_attach_arg *uaa = aux;
    463 	char			*devinfop;
    464 	struct usbd_device *	dev = uaa->uaa_device;
    465 	usbd_status		err;
    466 	usb_interface_descriptor_t	*id;
    467 	usb_endpoint_descriptor_t	*ed;
    468 	int			i;
    469 
    470 	KASSERT((void *)sc == un);
    471 
    472 	DPRINTFN(5,(" : cue_attach: sc=%p, dev=%p", sc, dev));
    473 
    474 	aprint_naive("\n");
    475 	aprint_normal("\n");
    476 	devinfop = usbd_devinfo_alloc(dev, 0);
    477 	aprint_normal_dev(self, "%s\n", devinfop);
    478 	usbd_devinfo_free(devinfop);
    479 
    480 	err = usbd_set_config_no(dev, CUE_CONFIG_NO, 1);
    481 	if (err) {
    482 		aprint_error_dev(self, "failed to set configuration"
    483 		    ", err=%s\n", usbd_errstr(err));
    484 		return;
    485 	}
    486 
    487 	un->un_dev = self;
    488 	un->un_udev = dev;
    489 	un->un_sc = sc;
    490 	un->un_ops = &cue_ops;
    491 	un->un_rx_xfer_flags = USBD_SHORT_XFER_OK;
    492 	un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER;
    493 	un->un_rx_list_cnt = CUE_RX_LIST_CNT;
    494 	un->un_tx_list_cnt = CUE_TX_LIST_CNT;
    495 	un->un_rx_bufsz = CUE_BUFSZ;
    496 	un->un_tx_bufsz = CUE_BUFSZ;
    497 
    498 	err = usbd_device2interface_handle(dev, CUE_IFACE_IDX, &un->un_iface);
    499 	if (err) {
    500 		aprint_error_dev(self, "getting interface handle failed\n");
    501 		return;
    502 	}
    503 
    504 	id = usbd_get_interface_descriptor(un->un_iface);
    505 
    506 	/* Find endpoints. */
    507 	for (i = 0; i < id->bNumEndpoints; i++) {
    508 		ed = usbd_interface2endpoint_descriptor(un->un_iface, i);
    509 		if (ed == NULL) {
    510 			aprint_error_dev(self, "couldn't get ep %d\n", i);
    511 			return;
    512 		}
    513 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
    514 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
    515 			un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress;
    516 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
    517 			   UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
    518 			un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress;
    519 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
    520 			   UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
    521 			un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress;
    522 		}
    523 	}
    524 
    525 	/* First level attach. */
    526 	usbnet_attach(un);
    527 
    528 #if 0
    529 	/* Reset the adapter. */
    530 	cue_reset(un);
    531 #endif
    532 	/*
    533 	 * Get station address.
    534 	 */
    535 	cue_getmac(un);
    536 
    537 	usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST,
    538 	    0, NULL);
    539 }
    540 
    541 static void
    542 cue_uno_tick(struct usbnet *un)
    543 {
    544 	struct ifnet		*ifp = usbnet_ifp(un);
    545 
    546 	net_stat_ref_t nsr = IF_STAT_GETREF(ifp);
    547 	if (cue_csr_read_2(un, CUE_RX_FRAMEERR))
    548 		if_statinc_ref(ifp, nsr, if_ierrors);
    549 
    550 	if_statadd_ref(ifp, nsr, if_collisions,
    551 	    cue_csr_read_2(un, CUE_TX_SINGLECOLL));
    552 	if_statadd_ref(ifp, nsr, if_collisions,
    553 	    cue_csr_read_2(un, CUE_TX_MULTICOLL));
    554 	if_statadd_ref(ifp, nsr, if_collisions,
    555 	    cue_csr_read_2(un, CUE_TX_EXCESSCOLL));
    556 	IF_STAT_PUTREF(ifp);
    557 }
    558 
    559 static void
    560 cue_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len)
    561 {
    562 	struct ifnet		*ifp = usbnet_ifp(un);
    563 	uint8_t			*buf = c->unc_buf;
    564 	uint16_t		len;
    565 
    566 	DPRINTFN(5,("%s: %s: total_len=%d len=%d\n",
    567 		     device_xname(un->un_dev), __func__,
    568 		     total_len, le16dec(buf)));
    569 
    570 	len = UGETW(buf);
    571 	if (total_len < 2 ||
    572 	    len > total_len - 2 ||
    573 	    len < sizeof(struct ether_header)) {
    574 		if_statinc(ifp, if_ierrors);
    575 		return;
    576 	}
    577 
    578 	/* No errors; receive the packet. */
    579 	usbnet_enqueue(un, buf + 2, len, 0, 0, 0);
    580 }
    581 
    582 static unsigned
    583 cue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c)
    584 {
    585 	unsigned		total_len;
    586 
    587 	DPRINTFN(5,("%s: %s: mbuf len=%d\n",
    588 		     device_xname(un->un_dev), __func__,
    589 		     m->m_pkthdr.len));
    590 
    591 	if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - 2)
    592 		return 0;
    593 
    594 	/*
    595 	 * Copy the mbuf data into a contiguous buffer, leaving two
    596 	 * bytes at the beginning to hold the frame length.
    597 	 */
    598 	m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf + 2);
    599 
    600 	total_len = m->m_pkthdr.len + 2;
    601 
    602 	/* The first two bytes are the frame length */
    603 	c->unc_buf[0] = (uint8_t)m->m_pkthdr.len;
    604 	c->unc_buf[1] = (uint8_t)(m->m_pkthdr.len >> 8);
    605 
    606 	return total_len;
    607 }
    608 
    609 static int
    610 cue_uno_init(struct ifnet *ifp)
    611 {
    612 	struct usbnet * const	un = ifp->if_softc;
    613 	int			i, ctl;
    614 	const u_char		*eaddr;
    615 
    616 	DPRINTFN(10,("%s: %s: enter\n", device_xname(un->un_dev),__func__));
    617 
    618 	/* Cancel pending I/O */
    619 	cue_uno_stop(ifp, 1);
    620 
    621 	/* Reset the interface. */
    622 #if 1
    623 	cue_reset(un);
    624 #endif
    625 
    626 	/* Set advanced operation modes. */
    627 	cue_csr_write_1(un, CUE_ADVANCED_OPMODES,
    628 	    CUE_AOP_EMBED_RXLEN | 0x03); /* 1 wait state */
    629 
    630 	eaddr = CLLADDR(ifp->if_sadl);
    631 	/* Set MAC address */
    632 	for (i = 0; i < ETHER_ADDR_LEN; i++)
    633 		cue_csr_write_1(un, CUE_PAR0 - i, eaddr[i]);
    634 
    635 	/* Enable RX logic. */
    636 	ctl = CUE_ETHCTL_RX_ON | CUE_ETHCTL_MCAST_ON;
    637 	if (usbnet_ispromisc(un))
    638 		ctl |= CUE_ETHCTL_PROMISC;
    639 	cue_csr_write_1(un, CUE_ETHCTL, ctl);
    640 
    641 	/*
    642 	 * Set the number of RX and TX buffers that we want
    643 	 * to reserve inside the ASIC.
    644 	 */
    645 	cue_csr_write_1(un, CUE_RX_BUFPKTS, CUE_RX_FRAMES);
    646 	cue_csr_write_1(un, CUE_TX_BUFPKTS, CUE_TX_FRAMES);
    647 
    648 	/* Set advanced operation modes. */
    649 	cue_csr_write_1(un, CUE_ADVANCED_OPMODES,
    650 	    CUE_AOP_EMBED_RXLEN | 0x01); /* 1 wait state */
    651 
    652 	/* Program the LED operation. */
    653 	cue_csr_write_1(un, CUE_LEDCTL, CUE_LEDCTL_FOLLOW_LINK);
    654 
    655 	return 0;
    656 }
    657 
    658 /* Stop and reset the adapter.  */
    659 static void
    660 cue_uno_stop(struct ifnet *ifp, int disable)
    661 {
    662 	struct usbnet * const	un = ifp->if_softc;
    663 
    664 	DPRINTFN(10,("%s: %s: enter\n", device_xname(un->un_dev), __func__));
    665 
    666 	cue_csr_write_1(un, CUE_ETHCTL, 0);
    667 	cue_reset(un);
    668 }
    669 
    670 #ifdef _MODULE
    671 #include "ioconf.c"
    672 #endif
    673 
    674 USBNET_MODULE(cue)
    675