Home | History | Annotate | Line # | Download | only in usb
if_cdce.c revision 1.12.10.8
      1 /*	$NetBSD: if_cdce.c,v 1.12.10.8 2007/06/22 10:44:55 itohy Exp $ */
      2 
      3 /*
      4  * Copyright (c) 1997, 1998, 1999, 2000-2003 Bill Paul <wpaul (at) windriver.com>
      5  * Copyright (c) 2003 Craig Boston
      6  * Copyright (c) 2004 Daniel Hartmeier
      7  * All rights reserved.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  * 3. All advertising materials mentioning features or use of this software
     18  *    must display the following acknowledgement:
     19  *	This product includes software developed by Bill Paul.
     20  * 4. Neither the name of the author nor the names of any co-contributors
     21  *    may be used to endorse or promote products derived from this software
     22  *    without specific prior written permission.
     23  *
     24  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
     25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul, THE VOICES IN HIS HEAD OR
     28  * THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     29  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     30  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     31  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     32  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     33  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     34  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     35  */
     36 
     37 /*
     38  * USB Communication Device Class (Ethernet Networking Control Model)
     39  * http://www.usb.org/developers/devclass_docs/usbcdc11.pdf
     40  *
     41  */
     42 
     43 #include <sys/cdefs.h>
     44 __KERNEL_RCSID(0, "$NetBSD: if_cdce.c,v 1.12.10.8 2007/06/22 10:44:55 itohy Exp $");
     45 #include "bpfilter.h"
     46 
     47 #include <sys/param.h>
     48 #include <sys/systm.h>
     49 #include <sys/sockio.h>
     50 #include <sys/mbuf.h>
     51 #include <sys/malloc.h>
     52 #include <sys/kernel.h>
     53 #include <sys/socket.h>
     54 #include <sys/device.h>
     55 #if defined(__OpenBSD__)
     56 #include <sys/proc.h>
     57 #endif
     58 
     59 #if NRND > 0
     60 #include <sys/rnd.h>
     61 #endif
     62 
     63 #include <net/if.h>
     64 #if defined(__NetBSD__)
     65 #include <net/if_arp.h>
     66 #endif
     67 #include <net/if_dl.h>
     68 #include <net/if_media.h>
     69 
     70 #define BPF_MTAP(ifp, m) bpf_mtap((ifp)->if_bpf, (m))
     71 
     72 #if NBPFILTER > 0
     73 #include <net/bpf.h>
     74 #endif
     75 
     76 #if defined(__NetBSD__)
     77 #include <net/if_ether.h>
     78 #ifdef INET
     79 #include <netinet/in.h>
     80 #include <netinet/if_inarp.h>
     81 #endif
     82 #endif /* defined(__NetBSD__) */
     83 
     84 #if defined(__OpenBSD__)
     85 #ifdef INET
     86 #include <netinet/in.h>
     87 #include <netinet/in_systm.h>
     88 #include <netinet/in_var.h>
     89 #include <netinet/ip.h>
     90 #include <netinet/if_ether.h>
     91 #endif
     92 #endif /* defined(__OpenBSD__) */
     93 
     94 
     95 #include <dev/usb/usb.h>
     96 #include <dev/usb/usbdi.h>
     97 #include <dev/usb/usbdi_util.h>
     98 #include <dev/usb/usbdevs.h>
     99 #include <dev/usb/usbcdc.h>
    100 #include <dev/usb/usb_ethersubr.h>
    101 
    102 #include <dev/usb/if_cdcereg.h>
    103 
    104 Static int	 cdce_encap(struct cdce_softc *, struct mbuf *, int);
    105 Static void	 cdce_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
    106 Static void	 cdce_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
    107 Static void	 cdce_start(struct ifnet *);
    108 Static int	 cdce_ioctl(struct ifnet *, u_long, usb_ioctlarg_t);
    109 Static int	 cdce_init(struct ifnet *);
    110 Static void	 cdce_watchdog(struct ifnet *);
    111 Static void	 cdce_stop(struct ifnet *, int);
    112 Static uint32_t	 cdce_crc32(struct mbuf *);
    113 
    114 Static const struct cdce_type cdce_devs[] = {
    115   {{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2501 }, CDCE_NO_UNION },
    116   {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5500 }, CDCE_ZAURUS },
    117   {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_A300 }, CDCE_ZAURUS | CDCE_NO_UNION },
    118   {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5600 }, CDCE_ZAURUS | CDCE_NO_UNION },
    119   {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_C700 }, CDCE_ZAURUS | CDCE_NO_UNION },
    120   {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_C750 }, CDCE_ZAURUS | CDCE_NO_UNION },
    121 };
    122 #define cdce_lookup(v, p) ((const struct cdce_type *)usb_lookup(cdce_devs, v, p))
    123 
    124 USB_DECLARE_DRIVER(cdce);
    125 
    126 USB_MATCH(cdce)
    127 {
    128 #ifndef USB_USE_IFATTACH
    129 	USB_MATCH_START(cdce, uaa);
    130 	usb_interface_descriptor_t *id;
    131 
    132 	if (uaa->iface == NULL)
    133 		return (UMATCH_NONE);
    134 
    135 	id = usbd_get_interface_descriptor(uaa->iface);
    136 	if (id == NULL)
    137 		return (UMATCH_NONE);
    138 #else
    139 	USB_IFMATCH_START(cdce, uaa);
    140 #endif /* USB_USE_IFATTACH */
    141 
    142 	if (cdce_lookup(uaa->vendor, uaa->product) != NULL)
    143 		return (UMATCH_VENDOR_PRODUCT);
    144 
    145 	if (
    146 #ifndef USB_USE_IFATTACH
    147 	    id->bInterfaceClass == UICLASS_CDC && id->bInterfaceSubClass ==
    148 #else
    149 	    uaa->class == UICLASS_CDC && uaa->subclass ==
    150 #endif /* USB_USE_IFATTACH */
    151 	    UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL)
    152 		return (UMATCH_IFACECLASS_GENERIC);
    153 
    154 	return (UMATCH_NONE);
    155 }
    156 
    157 USB_ATTACH(cdce)
    158 {
    159 #ifndef USB_USE_IFATTACH
    160 	USB_ATTACH_START(cdce, sc, uaa);
    161 #else
    162 	USB_IFATTACH_START(cdce, sc, uaa);
    163 #endif /* USB_USE_IFATTACH */
    164 	char				 *devinfop;
    165 	int				 s;
    166 	struct ifnet			*ifp;
    167 	usbd_device_handle		 dev = uaa->device;
    168 	const struct cdce_type		*t;
    169 	usb_interface_descriptor_t	*id;
    170 	usb_endpoint_descriptor_t	*ed;
    171 	const usb_cdc_union_descriptor_t *ud;
    172 	int				 data_ifcno;
    173 	int				 i;
    174 	u_char				 eaddr[ETHER_ADDR_LEN];
    175 	const usb_cdc_ethernet_descriptor_t *ue;
    176 	char				 eaddr_str[USB_MAX_ENCODED_STRING_LEN];
    177 
    178 	devinfop = usbd_devinfo_alloc(dev, 0);
    179 	USB_ATTACH_SETUP;
    180 	printf("%s: %s\n", USBDEVNAME(sc->cdce_dev), devinfop);
    181 	usbd_devinfo_free(devinfop);
    182 
    183 	sc->cdce_udev = uaa->device;
    184 	sc->cdce_ctl_iface = uaa->iface;
    185 
    186 	t = cdce_lookup(uaa->vendor, uaa->product);
    187 	if (t)
    188 		sc->cdce_flags = t->cdce_flags;
    189 
    190 	if (sc->cdce_flags & CDCE_NO_UNION)
    191 		sc->cdce_data_iface = sc->cdce_ctl_iface;
    192 	else {
    193 		ud = (const usb_cdc_union_descriptor_t *)usb_find_desc(sc->cdce_udev,
    194 		    UDESC_CS_INTERFACE, UDESCSUB_CDC_UNION);
    195 		if (ud == NULL) {
    196 			printf("%s: no union descriptor\n",
    197 			    USBDEVNAME(sc->cdce_dev));
    198 			USB_ATTACH_ERROR_RETURN;
    199 		}
    200 		data_ifcno = ud->bSlaveInterface[0];
    201 
    202 		for (i = 0; i < uaa->nifaces; i++) {
    203 			if (uaa->ifaces[i] != NULL) {
    204 				id = usbd_get_interface_descriptor(
    205 				    uaa->ifaces[i]);
    206 				if (id != NULL && id->bInterfaceNumber ==
    207 				    data_ifcno) {
    208 					sc->cdce_data_iface = uaa->ifaces[i];
    209 					uaa->ifaces[i] = NULL;
    210 				}
    211 			}
    212 		}
    213 	}
    214 
    215 	if (sc->cdce_data_iface == NULL) {
    216 		printf("%s: no data interface\n", USBDEVNAME(sc->cdce_dev));
    217 		USB_ATTACH_ERROR_RETURN;
    218 	}
    219 
    220 	/* Find endpoints. */
    221 	id = usbd_get_interface_descriptor(sc->cdce_data_iface);
    222 	sc->cdce_bulkin_no = sc->cdce_bulkout_no = -1;
    223 	for (i = 0; i < id->bNumEndpoints; i++) {
    224 		ed = usbd_interface2endpoint_descriptor(sc->cdce_data_iface, i);
    225 		if (!ed) {
    226 			printf("%s: could not read endpoint descriptor\n",
    227 			    USBDEVNAME(sc->cdce_dev));
    228 			USB_ATTACH_ERROR_RETURN;
    229 		}
    230 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
    231 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
    232 			sc->cdce_bulkin_no = ed->bEndpointAddress;
    233 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
    234 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
    235 			sc->cdce_bulkout_no = ed->bEndpointAddress;
    236 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
    237 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
    238 			/* XXX: CDC spec defines an interrupt pipe, but it is not
    239 			 * needed for simple host-to-host applications. */
    240 		} else {
    241 			printf("%s: unexpected endpoint\n",
    242 			    USBDEVNAME(sc->cdce_dev));
    243 		}
    244 	}
    245 
    246 	if (sc->cdce_bulkin_no == -1) {
    247 		printf("%s: could not find data bulk in\n",
    248 		    USBDEVNAME(sc->cdce_dev));
    249 		USB_ATTACH_ERROR_RETURN;
    250 	}
    251 	if (sc->cdce_bulkout_no == -1 ) {
    252 		printf("%s: could not find data bulk out\n",
    253 		    USBDEVNAME(sc->cdce_dev));
    254 		USB_ATTACH_ERROR_RETURN;
    255 	}
    256 
    257 	ue = (const usb_cdc_ethernet_descriptor_t *)usb_find_desc(dev,
    258             UDESC_INTERFACE, UDESCSUB_CDC_ENF);
    259 	if (!ue || usbd_get_string(dev, ue->iMacAddress, eaddr_str)) {
    260 		printf("%s: faking address\n", USBDEVNAME(sc->cdce_dev));
    261 		eaddr[0]= 0x2a;
    262 		memcpy(&eaddr[1], &hardclock_ticks, sizeof(u_int32_t));
    263 		eaddr[5] = (u_int8_t)(device_unit(&sc->cdce_dev));
    264 	} else {
    265 		int j;
    266 
    267 		memset(eaddr, 0, ETHER_ADDR_LEN);
    268 		for (j = 0; j < ETHER_ADDR_LEN * 2; j++) {
    269 			int c = eaddr_str[j];
    270 
    271 			if ('0' <= c && c <= '9')
    272 				c -= '0';
    273 			else
    274 				c -= 'A' - 10;
    275 			c &= 0xf;
    276 			if (c%2 == 0)
    277 				c <<= 4;
    278 			eaddr[j / 2] |= c;
    279 		}
    280 	}
    281 
    282 	s = splnet();
    283 
    284 	printf("%s: address %s\n", USBDEVNAME(sc->cdce_dev),
    285 	    ether_sprintf(eaddr));
    286 
    287 	ifp = GET_IFP(sc);
    288 	ifp->if_softc = sc;
    289 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
    290 	ifp->if_ioctl = cdce_ioctl;
    291 	ifp->if_start = cdce_start;
    292 	ifp->if_init = cdce_init;
    293 	ifp->if_stop = cdce_stop;
    294 	ifp->if_watchdog = cdce_watchdog;
    295 	strncpy(ifp->if_xname, USBDEVNAME(sc->cdce_dev), IFNAMSIZ);
    296 
    297 	IFQ_SET_READY(&ifp->if_snd);
    298 
    299 	if_attach(ifp);
    300 	Ether_ifattach(ifp, eaddr);
    301 
    302 	sc->cdce_attached = 1;
    303 	splx(s);
    304 
    305 	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->cdce_udev,
    306 	    USBDEV(sc->cdce_dev));
    307 
    308 	USB_ATTACH_SUCCESS_RETURN;
    309 }
    310 
    311 USB_DETACH(cdce)
    312 {
    313 	USB_DETACH_START(cdce, sc);
    314 	struct ifnet	*ifp = GET_IFP(sc);
    315 	int		 s;
    316 
    317 	s = splusb();
    318 
    319 	if (!sc->cdce_attached) {
    320 		splx(s);
    321 		return (0);
    322 	}
    323 
    324 	if (ifp->if_flags & IFF_RUNNING)
    325 		cdce_stop(ifp, 1);
    326 
    327 	ether_ifdetach(ifp);
    328 
    329 	if_detach(ifp);
    330 
    331 	sc->cdce_attached = 0;
    332 	splx(s);
    333 
    334 	return (0);
    335 }
    336 
    337 Static void
    338 cdce_start(struct ifnet *ifp)
    339 {
    340 	struct cdce_softc	*sc = ifp->if_softc;
    341 	struct mbuf		*m_head = NULL;
    342 
    343 	if (sc->cdce_dying || (ifp->if_flags & IFF_OACTIVE))
    344 		return;
    345 
    346 	IFQ_POLL(&ifp->if_snd, m_head);
    347 	if (m_head == NULL)
    348 		return;
    349 
    350 	IFQ_DEQUEUE(&ifp->if_snd, m_head);
    351 
    352 #if NBPFILTER > 0
    353 	if (ifp->if_bpf)
    354 		BPF_MTAP(ifp, m_head);
    355 #endif
    356 
    357 	if (cdce_encap(sc, m_head, 0)) {
    358 		ifp->if_flags |= IFF_OACTIVE;
    359 		return;
    360 	}
    361 
    362 	ifp->if_flags |= IFF_OACTIVE;
    363 
    364 	ifp->if_timer = 6;
    365 }
    366 
    367 Static int
    368 cdce_encap(struct cdce_softc *sc, struct mbuf *m, int idx)
    369 {
    370 	struct ue_chain		*c;
    371 	usbd_status		 err;
    372 	int			 ret;
    373 
    374 	c = &sc->cdce_cdata.cdce_tx_chain[idx];
    375 
    376 	if (sc->cdce_flags & CDCE_ZAURUS) {
    377 		/* Zaurus wants a 32-bit CRC appended to every frame */
    378 		u_int32_t crc, crcle;
    379 		int len;
    380 
    381 		crc = cdce_crc32(m);
    382 		crcle = htole32(crc);
    383 		len = m->m_pkthdr.len + 4;
    384 		m_copyback(m, m->m_pkthdr.len, 4, &crcle);
    385 		if (m->m_pkthdr.len != len) {
    386 			m_freem(m);
    387 			return (ENOBUFS);
    388 		}
    389 	}
    390 
    391 	ret = usb_ether_map_tx_buffer_mbuf(c, m);
    392 	if (ret) {
    393 		m_freem(m);
    394 		return (ret);
    395 	}
    396 
    397 	usbd_setup_xfer(c->ue_xfer, sc->cdce_bulkout_pipe, c, NULL /* XXX buf */,
    398 	    m->m_pkthdr.len, USBD_NO_COPY
    399 #ifdef __FreeBSD__	/* callback needs context */
    400 	    | USBD_CALLBACK_AS_TASK
    401 #endif
    402 	    , 10000, cdce_txeof);
    403 	err = usbd_transfer(c->ue_xfer);
    404 	if (err != USBD_IN_PROGRESS) {
    405 		c->ue_mbuf = NULL;
    406 		m_freem(m);
    407 		cdce_stop(GET_IFP(sc), 0);
    408 		return (EIO);
    409 	}
    410 
    411 	sc->cdce_cdata.cdce_tx_cnt++;
    412 
    413 	return (0);
    414 }
    415 
    416 Static void
    417 cdce_stop(struct ifnet *ifp, int disable)
    418 {
    419 	struct cdce_softc	*sc = ifp->if_softc;
    420 	usbd_status	 err;
    421 
    422 	ifp->if_timer = 0;
    423 
    424 	/* Stop transfers. */
    425 	if (sc->cdce_bulkin_pipe != NULL) {
    426 		err = usbd_abort_pipe(sc->cdce_bulkin_pipe);
    427 		if (err)
    428 			printf("%s: abort rx pipe failed: %s\n",
    429 			    USBDEVNAME(sc->cdce_dev), usbd_errstr(err));
    430 	}
    431 
    432 	if (sc->cdce_bulkout_pipe != NULL) {
    433 		err = usbd_abort_pipe(sc->cdce_bulkout_pipe);
    434 		if (err)
    435 			printf("%s: abort tx pipe failed: %s\n",
    436 			    USBDEVNAME(sc->cdce_dev), usbd_errstr(err));
    437 	}
    438 
    439 	/* Free RX/TX list resources. */
    440 	usb_ether_rx_list_free(sc->cdce_cdata.cdce_rx_chain, CDCE_RX_LIST_CNT);
    441 	usb_ether_tx_list_free(sc->cdce_cdata.cdce_tx_chain, CDCE_TX_LIST_CNT);
    442 
    443 	/* Close pipes. */
    444 	if (sc->cdce_bulkin_pipe != NULL) {
    445 		err = usbd_close_pipe(sc->cdce_bulkin_pipe);
    446 		if (err)
    447 			printf("%s: close rx pipe failed: %s\n",
    448 			    USBDEVNAME(sc->cdce_dev), usbd_errstr(err));
    449 		sc->cdce_bulkin_pipe = NULL;
    450 	}
    451 
    452 	if (sc->cdce_bulkout_pipe != NULL) {
    453 		err = usbd_close_pipe(sc->cdce_bulkout_pipe);
    454 		if (err)
    455 			printf("%s: close tx pipe failed: %s\n",
    456 			    USBDEVNAME(sc->cdce_dev), usbd_errstr(err));
    457 		sc->cdce_bulkout_pipe = NULL;
    458 	}
    459 
    460 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
    461 }
    462 
    463 Static int
    464 cdce_ioctl(struct ifnet *ifp, u_long command, usb_ioctlarg_t data)
    465 {
    466 	struct cdce_softc	*sc = ifp->if_softc;
    467 	int			 s, error;
    468 
    469 	if (sc->cdce_dying)
    470 		return (EIO);
    471 
    472 	s = splnet();
    473 
    474 	switch(command) {
    475 #if 0	/* no media support */
    476 	case SIOCGIFMEDIA:
    477 	case SIOCSIFMEDIA:
    478 		error = EINVAL;
    479 		break;
    480 #endif
    481 
    482 	default:
    483 		error = ether_ioctl(ifp, command, data);
    484 		if (error == ENETRESET) {
    485 #if 0	/* XXX not yet */
    486 			if (ifp->if_flags & IFF_RUNNING)
    487 				cdce_setmulti(sc);
    488 #endif
    489 			error = 0;
    490 		}
    491 		break;
    492 	}
    493 
    494 	splx(s);
    495 
    496 	return (error);
    497 }
    498 
    499 Static void
    500 cdce_watchdog(struct ifnet *ifp)
    501 {
    502 	struct cdce_softc	*sc = ifp->if_softc;
    503 
    504 	if (sc->cdce_dying)
    505 		return;
    506 
    507 	ifp->if_oerrors++;
    508 	printf("%s: watchdog timeout\n", USBDEVNAME(sc->cdce_dev));
    509 }
    510 
    511 Static int
    512 cdce_init(struct ifnet *ifp)
    513 {
    514 	struct cdce_softc	*sc = ifp->if_softc;
    515 	struct ue_chain		*c;
    516 	usbd_status		 err;
    517 	int			 s, i;
    518 
    519 	if (ifp->if_flags & IFF_RUNNING)
    520 		return (EIO);
    521 
    522 	s = splnet();
    523 
    524 	err = usbd_open_pipe(sc->cdce_data_iface, sc->cdce_bulkin_no,
    525 	    USBD_EXCLUSIVE_USE, &sc->cdce_bulkin_pipe);
    526 	if (err) {
    527 		printf("%s: open rx pipe failed: %s\n", USBDEVNAME(sc->cdce_dev),
    528 		    usbd_errstr(err));
    529 		splx(s);
    530 		return (EIO);
    531 	}
    532 
    533 	err = usbd_open_pipe(sc->cdce_data_iface, sc->cdce_bulkout_no,
    534 	    USBD_EXCLUSIVE_USE, &sc->cdce_bulkout_pipe);
    535 	if (err) {
    536 		printf("%s: open tx pipe failed: %s\n", USBDEVNAME(sc->cdce_dev),
    537 		    usbd_errstr(err));
    538 		splx(s);
    539 		return (EIO);
    540 	}
    541 
    542 	if (usb_ether_tx_list_init(USBDEV(sc->cdce_dev),
    543 	    sc->cdce_cdata.cdce_tx_chain, CDCE_TX_LIST_CNT,
    544 	    sc->cdce_udev, sc->cdce_bulkout_pipe, NULL)) {
    545 		printf("%s: tx list init failed\n", USBDEVNAME(sc->cdce_dev));
    546 		splx(s);
    547 		return (EIO);
    548 	}
    549 
    550 	if (usb_ether_rx_list_init(USBDEV(sc->cdce_dev),
    551 	    sc->cdce_cdata.cdce_rx_chain, CDCE_RX_LIST_CNT,
    552 	    sc->cdce_udev, sc->cdce_bulkin_pipe)) {
    553 		printf("%s: rx list init failed\n", USBDEVNAME(sc->cdce_dev));
    554 		splx(s);
    555 		return (ENOMEM);
    556 	}
    557 
    558 	/* Maybe set multicast / broadcast here??? */
    559 
    560 	for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
    561 		c = &sc->cdce_cdata.cdce_rx_chain[i];
    562 		(void)usbd_map_buffer_mbuf(c->ue_xfer, c->ue_mbuf);
    563 		usbd_setup_xfer(c->ue_xfer, sc->cdce_bulkin_pipe, c,
    564 		    NULL /* XXX buf */, CDCE_BUFSZ,
    565 		    USBD_SHORT_XFER_OK | USBD_NO_COPY
    566 #ifdef __FreeBSD__	/* callback needs context */
    567 		    | USBD_CALLBACK_AS_TASK
    568 #endif
    569 		    ,
    570 		    USBD_NO_TIMEOUT, cdce_rxeof);
    571 		usbd_transfer(c->ue_xfer);
    572 	}
    573 
    574 	ifp->if_flags |= IFF_RUNNING;
    575 	ifp->if_flags &= ~IFF_OACTIVE;
    576 
    577 	splx(s);
    578 
    579 	return (0);
    580 }
    581 
    582 Static void
    583 cdce_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
    584 {
    585 	struct ue_chain		*c = priv;
    586 	struct cdce_softc	*sc = (void *)c->ue_dev;
    587 	struct ifnet		*ifp = GET_IFP(sc);
    588 	struct mbuf		*m;
    589 	int			 total_len = 0;
    590 	int			 s;
    591 
    592 	if (sc->cdce_dying || !(ifp->if_flags & IFF_RUNNING))
    593 		return;
    594 
    595 	usbd_unmap_buffer(xfer);
    596 
    597 	if (status != USBD_NORMAL_COMPLETION) {
    598 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
    599 			return;
    600 		if (sc->cdce_rxeof_errors == 0)
    601 			printf("%s: usb error on rx: %s\n",
    602 			    USBDEVNAME(sc->cdce_dev), usbd_errstr(status));
    603 		if (status == USBD_STALLED)
    604 			usbd_clear_endpoint_stall_async(sc->cdce_bulkin_pipe);
    605 		DELAY(sc->cdce_rxeof_errors * 10000);
    606 		sc->cdce_rxeof_errors++;
    607 		goto done;
    608 	}
    609 
    610 	sc->cdce_rxeof_errors = 0;
    611 
    612 	usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
    613 	if (sc->cdce_flags & CDCE_ZAURUS)
    614 		total_len -= 4;	/* Strip off CRC added by Zaurus */
    615 
    616 	if (total_len < sizeof(struct ether_header)) {
    617 		ifp->if_ierrors++;
    618 		goto done;
    619 	}
    620 
    621 	m = c->ue_mbuf;
    622 
    623 	/*
    624 	 * Allocate new mbuf cluster for the next transfer.
    625 	 * If that failed, discard current packet and recycle the mbuf.
    626 	 */
    627 	if ((c->ue_mbuf = usb_ether_newbuf(NULL)) == NULL) {
    628 		printf("%s: no memory for rx list -- packet dropped!\n",
    629 		    USBDEVNAME(sc->cdce_dev));
    630 		ifp->if_ierrors++;
    631 		c->ue_mbuf = usb_ether_newbuf(m);
    632 		goto done;
    633 	}
    634 
    635 	ifp->if_ipackets++;
    636 	m->m_pkthdr.len = m->m_len = total_len;
    637 	m->m_pkthdr.rcvif = ifp;
    638 
    639 	s = splnet();
    640 
    641 #if NBPFILTER > 0
    642 	if (ifp->if_bpf)
    643 		BPF_MTAP(ifp, m);
    644 #endif
    645 
    646 	IF_INPUT(ifp, m);
    647 
    648 	splx(s);
    649 
    650 done:
    651 	/* Setup new transfer. */
    652 	(void)usbd_map_buffer_mbuf(c->ue_xfer, c->ue_mbuf);
    653 	usbd_setup_xfer(c->ue_xfer, sc->cdce_bulkin_pipe, c, NULL /* XXX buf */,
    654 	    CDCE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY
    655 #ifdef __FreeBSD__	/* callback needs context */
    656 	    | USBD_CALLBACK_AS_TASK
    657 #endif
    658 	    , USBD_NO_TIMEOUT,
    659 	    cdce_rxeof);
    660 	usbd_transfer(c->ue_xfer);
    661 }
    662 
    663 Static void
    664 cdce_txeof(usbd_xfer_handle xfer, usbd_private_handle priv,
    665     usbd_status status)
    666 {
    667 	struct ue_chain		*c = priv;
    668 	struct cdce_softc	*sc = (void *)c->ue_dev;
    669 	struct ifnet		*ifp = GET_IFP(sc);
    670 	usbd_status		 err;
    671 	int			 s;
    672 
    673 	if (sc->cdce_dying)
    674 		return;
    675 
    676 	usbd_unmap_buffer(xfer);
    677 
    678 	s = splnet();
    679 
    680 	ifp->if_timer = 0;
    681 	ifp->if_flags &= ~IFF_OACTIVE;
    682 
    683 	if (status != USBD_NORMAL_COMPLETION) {
    684 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
    685 			splx(s);
    686 			return;
    687 		}
    688 		ifp->if_oerrors++;
    689 		printf("%s: usb error on tx: %s\n", USBDEVNAME(sc->cdce_dev),
    690 		    usbd_errstr(status));
    691 		if (status == USBD_STALLED)
    692 			usbd_clear_endpoint_stall_async(sc->cdce_bulkout_pipe);
    693 		splx(s);
    694 		return;
    695 	}
    696 
    697 	usbd_get_xfer_status(c->ue_xfer, NULL, NULL, NULL, &err);
    698 
    699 	if (c->ue_mbuf != NULL) {
    700 		m_freem(c->ue_mbuf);
    701 		c->ue_mbuf = NULL;
    702 	}
    703 
    704 	if (err)
    705 		ifp->if_oerrors++;
    706 	else
    707 		ifp->if_opackets++;
    708 
    709 	if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
    710 		cdce_start(ifp);
    711 
    712 	splx(s);
    713 }
    714 
    715 int
    716 cdce_activate(device_ptr_t self, enum devact act)
    717 {
    718 	struct cdce_softc *sc = (struct cdce_softc *)self;
    719 
    720 	switch (act) {
    721 	case DVACT_ACTIVATE:
    722 		return (EOPNOTSUPP);
    723 		break;
    724 
    725 	case DVACT_DEACTIVATE:
    726 		if_deactivate(GET_IFP(sc));
    727 		sc->cdce_dying = 1;
    728 		break;
    729 	}
    730 	return (0);
    731 }
    732 
    733 
    734 /*  COPYRIGHT (C) 1986 Gary S. Brown.  You may use this program, or
    735  *  code or tables extracted from it, as desired without restriction.
    736  */
    737 
    738 static const uint32_t cdce_crc32_tab[] = {
    739 	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
    740 	0xe963a535, 0x9e6495a3,	0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
    741 	0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
    742 	0xf3b97148, 0x84be41de,	0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
    743 	0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,	0x14015c4f, 0x63066cd9,
    744 	0xfa0f3d63, 0x8d080df5,	0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
    745 	0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,	0x35b5a8fa, 0x42b2986c,
    746 	0xdbbbc9d6, 0xacbcf940,	0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
    747 	0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
    748 	0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
    749 	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,	0x76dc4190, 0x01db7106,
    750 	0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
    751 	0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
    752 	0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
    753 	0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
    754 	0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
    755 	0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
    756 	0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
    757 	0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
    758 	0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
    759 	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
    760 	0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
    761 	0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
    762 	0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
    763 	0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
    764 	0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
    765 	0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
    766 	0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
    767 	0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
    768 	0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
    769 	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
    770 	0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
    771 	0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
    772 	0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
    773 	0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
    774 	0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
    775 	0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
    776 	0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
    777 	0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
    778 	0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
    779 	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
    780 	0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
    781 	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
    782 };
    783 
    784 Static uint32_t
    785 cdce_crc32(struct mbuf *m)
    786 {
    787 	const uint8_t *p;
    788 	uint32_t crc;
    789 	int len;
    790 
    791 	crc = ~0U;
    792 
    793 	for ( ; m; m = m->m_next) {
    794 		for (p = mtod(m, uint8_t *), len = m->m_len; len > 0; len--) {
    795 			crc = cdce_crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
    796 		}
    797 	}
    798 
    799 	return (crc ^ ~0U);
    800 }
    801