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