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