Home | History | Annotate | Line # | Download | only in usb
if_cdce.c revision 1.15.10.2
      1 /*	$NetBSD: if_cdce.c,v 1.15.10.2 2009/08/19 18:47:20 yamt 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.15.10.2 2009/08/19 18:47:20 yamt Exp $");
     45 #include "bpfilter.h"
     46 #ifdef	__NetBSD__
     47 #include "opt_inet.h"
     48 #endif
     49 
     50 #include <sys/param.h>
     51 #include <sys/systm.h>
     52 #include <sys/sockio.h>
     53 #include <sys/mbuf.h>
     54 #include <sys/malloc.h>
     55 #include <sys/kernel.h>
     56 #include <sys/socket.h>
     57 #include <sys/device.h>
     58 #if defined(__OpenBSD__)
     59 #include <sys/proc.h>
     60 #endif
     61 
     62 #if NRND > 0
     63 #include <sys/rnd.h>
     64 #endif
     65 
     66 #include <net/if.h>
     67 #if defined(__NetBSD__)
     68 #include <net/if_arp.h>
     69 #endif
     70 #include <net/if_dl.h>
     71 #include <net/if_media.h>
     72 
     73 #define BPF_MTAP(ifp, m) bpf_mtap((ifp)->if_bpf, (m))
     74 
     75 #if NBPFILTER > 0
     76 #include <net/bpf.h>
     77 #endif
     78 
     79 #if defined(__NetBSD__)
     80 #include <net/if_ether.h>
     81 #ifdef INET
     82 #include <netinet/in.h>
     83 #include <netinet/if_inarp.h>
     84 #endif
     85 #endif /* defined(__NetBSD__) */
     86 
     87 #if defined(__OpenBSD__)
     88 #ifdef INET
     89 #include <netinet/in.h>
     90 #include <netinet/in_systm.h>
     91 #include <netinet/in_var.h>
     92 #include <netinet/ip.h>
     93 #include <netinet/if_ether.h>
     94 #endif
     95 #endif /* defined(__OpenBSD__) */
     96 
     97 
     98 #include <dev/usb/usb.h>
     99 #include <dev/usb/usbdi.h>
    100 #include <dev/usb/usbdi_util.h>
    101 #include <dev/usb/usbdevs.h>
    102 #include <dev/usb/usbcdc.h>
    103 
    104 #include <dev/usb/if_cdcereg.h>
    105 
    106 Static int	 cdce_tx_list_init(struct cdce_softc *);
    107 Static int	 cdce_rx_list_init(struct cdce_softc *);
    108 Static int	 cdce_newbuf(struct cdce_softc *, struct cdce_chain *,
    109 		    struct mbuf *);
    110 Static int	 cdce_encap(struct cdce_softc *, struct mbuf *, int);
    111 Static void	 cdce_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
    112 Static void	 cdce_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
    113 Static void	 cdce_start(struct ifnet *);
    114 Static int	 cdce_ioctl(struct ifnet *, u_long, void *);
    115 Static void	 cdce_init(void *);
    116 Static void	 cdce_watchdog(struct ifnet *);
    117 Static void	 cdce_stop(struct cdce_softc *);
    118 Static uint32_t	 cdce_crc32(const void *, size_t);
    119 
    120 Static const struct cdce_type cdce_devs[] = {
    121   {{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2501 }, CDCE_NO_UNION },
    122   {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5500 }, CDCE_ZAURUS },
    123   {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_A300 }, CDCE_ZAURUS | CDCE_NO_UNION },
    124   {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5600 }, CDCE_ZAURUS | CDCE_NO_UNION },
    125   {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_C700 }, CDCE_ZAURUS | CDCE_NO_UNION },
    126   {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_C750 }, CDCE_ZAURUS | CDCE_NO_UNION },
    127 };
    128 #define cdce_lookup(v, p) ((const struct cdce_type *)usb_lookup(cdce_devs, v, p))
    129 
    130 USB_DECLARE_DRIVER(cdce);
    131 
    132 USB_MATCH(cdce)
    133 {
    134 	USB_IFMATCH_START(cdce, uaa);
    135 
    136 	if (cdce_lookup(uaa->vendor, uaa->product) != NULL)
    137 		return (UMATCH_VENDOR_PRODUCT);
    138 
    139 	if (uaa->class == UICLASS_CDC && uaa->subclass ==
    140 	    UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL)
    141 		return (UMATCH_IFACECLASS_GENERIC);
    142 
    143 	return (UMATCH_NONE);
    144 }
    145 
    146 USB_ATTACH(cdce)
    147 {
    148 	USB_IFATTACH_START(cdce, sc, uaa);
    149 	char				 *devinfop;
    150 	int				 s;
    151 	struct ifnet			*ifp;
    152 	usbd_device_handle		 dev = uaa->device;
    153 	const struct cdce_type		*t;
    154 	usb_interface_descriptor_t	*id;
    155 	usb_endpoint_descriptor_t	*ed;
    156 	const usb_cdc_union_descriptor_t *ud;
    157 	usb_config_descriptor_t		*cd;
    158 	int				 data_ifcno;
    159 	int				 i, j, numalts;
    160 	u_char				 eaddr[ETHER_ADDR_LEN];
    161 	const usb_cdc_ethernet_descriptor_t *ue;
    162 	char				 eaddr_str[USB_MAX_ENCODED_STRING_LEN];
    163 
    164 	devinfop = usbd_devinfo_alloc(dev, 0);
    165 	USB_ATTACH_SETUP;
    166 	sc->cdce_dev = self;
    167 	aprint_normal_dev(self, "%s\n", devinfop);
    168 	usbd_devinfo_free(devinfop);
    169 
    170 	sc->cdce_udev = uaa->device;
    171 	sc->cdce_ctl_iface = uaa->iface;
    172 
    173 	t = cdce_lookup(uaa->vendor, uaa->product);
    174 	if (t)
    175 		sc->cdce_flags = t->cdce_flags;
    176 
    177 	if (sc->cdce_flags & CDCE_NO_UNION)
    178 		sc->cdce_data_iface = sc->cdce_ctl_iface;
    179 	else {
    180 		ud = (const usb_cdc_union_descriptor_t *)usb_find_desc(sc->cdce_udev,
    181 		    UDESC_CS_INTERFACE, UDESCSUB_CDC_UNION);
    182 		if (ud == NULL) {
    183 			aprint_error_dev(self, "no union descriptor\n");
    184 			USB_ATTACH_ERROR_RETURN;
    185 		}
    186 		data_ifcno = ud->bSlaveInterface[0];
    187 
    188 		for (i = 0; i < uaa->nifaces; i++) {
    189 			if (uaa->ifaces[i] != NULL) {
    190 				id = usbd_get_interface_descriptor(
    191 				    uaa->ifaces[i]);
    192 				if (id != NULL && id->bInterfaceNumber ==
    193 				    data_ifcno) {
    194 					sc->cdce_data_iface = uaa->ifaces[i];
    195 					uaa->ifaces[i] = NULL;
    196 				}
    197 			}
    198 		}
    199 	}
    200 
    201 	if (sc->cdce_data_iface == NULL) {
    202 		aprint_error_dev(self, "no data interface\n");
    203 		USB_ATTACH_ERROR_RETURN;
    204 	}
    205 
    206 	/*
    207 	 * <quote>
    208 	 *  The Data Class interface of a networking device shall have a minimum
    209 	 *  of two interface settings. The first setting (the default interface
    210 	 *  setting) includes no endpoints and therefore no networking traffic is
    211 	 *  exchanged whenever the default interface setting is selected. One or
    212 	 *  more additional interface settings are used for normal operation, and
    213 	 *  therefore each includes a pair of endpoints (one IN, and one OUT) to
    214 	 *  exchange network traffic. Select an alternate interface setting to
    215 	 *  initialize the network aspects of the device and to enable the
    216 	 *  exchange of network traffic.
    217 	 * </quote>
    218 	 *
    219 	 * Some devices, most notably cable modems, include interface settings
    220 	 * that have no IN or OUT endpoint, therefore loop through the list of all
    221 	 * available interface settings looking for one with both IN and OUT
    222 	 * endpoints.
    223 	 */
    224 	id = usbd_get_interface_descriptor(sc->cdce_data_iface);
    225 	cd = usbd_get_config_descriptor(sc->cdce_udev);
    226 	numalts = usbd_get_no_alts(cd, id->bInterfaceNumber);
    227 
    228 	for (j = 0; j < numalts; j++) {
    229 		if (usbd_set_interface(sc->cdce_data_iface, j)) {
    230 			aprint_error_dev(sc->cdce_dev,
    231 					"setting alternate interface failed\n");
    232 			USB_ATTACH_ERROR_RETURN;
    233 		}
    234 		/* Find endpoints. */
    235 		id = usbd_get_interface_descriptor(sc->cdce_data_iface);
    236 		sc->cdce_bulkin_no = sc->cdce_bulkout_no = -1;
    237 		for (i = 0; i < id->bNumEndpoints; i++) {
    238 			ed = usbd_interface2endpoint_descriptor(sc->cdce_data_iface, i);
    239 			if (!ed) {
    240 				aprint_error_dev(self,
    241 						"could not read endpoint descriptor\n");
    242 				USB_ATTACH_ERROR_RETURN;
    243 			}
    244 			if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
    245 					UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
    246 				sc->cdce_bulkin_no = ed->bEndpointAddress;
    247 			} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
    248 					UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
    249 				sc->cdce_bulkout_no = ed->bEndpointAddress;
    250 			} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
    251 					UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
    252 				/* XXX: CDC spec defines an interrupt pipe, but it is not
    253 				 * needed for simple host-to-host applications. */
    254 			} else {
    255 				aprint_error_dev(self, "unexpected endpoint\n");
    256 			}
    257 		}
    258 		/* If we found something, try and use it... */
    259 		if ((sc->cdce_bulkin_no != -1) && (sc->cdce_bulkout_no != -1))
    260 			break;
    261 	}
    262 
    263 	if (sc->cdce_bulkin_no == -1) {
    264 		aprint_error_dev(self, "could not find data bulk in\n");
    265 		USB_ATTACH_ERROR_RETURN;
    266 	}
    267 	if (sc->cdce_bulkout_no == -1 ) {
    268 		aprint_error_dev(self, "could not find data bulk out\n");
    269 		USB_ATTACH_ERROR_RETURN;
    270 	}
    271 
    272 	ue = (const usb_cdc_ethernet_descriptor_t *)usb_find_desc(dev,
    273             UDESC_INTERFACE, UDESCSUB_CDC_ENF);
    274 	if (!ue || usbd_get_string(dev, ue->iMacAddress, eaddr_str)) {
    275 		aprint_normal_dev(self, "faking address\n");
    276 		eaddr[0]= 0x2a;
    277 		memcpy(&eaddr[1], &hardclock_ticks, sizeof(u_int32_t));
    278 		eaddr[5] = (u_int8_t)(device_unit(sc->cdce_dev));
    279 	} else {
    280 		(void)ether_nonstatic_aton(eaddr, eaddr_str);
    281 	}
    282 
    283 	s = splnet();
    284 
    285 	aprint_normal_dev(self, "address %s\n", 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_watchdog = cdce_watchdog;
    293 	strncpy(ifp->if_xname, USBDEVNAME(sc->cdce_dev), IFNAMSIZ);
    294 
    295 	IFQ_SET_READY(&ifp->if_snd);
    296 
    297 	if_attach(ifp);
    298 	Ether_ifattach(ifp, eaddr);
    299 
    300 	sc->cdce_attached = 1;
    301 	splx(s);
    302 
    303 	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->cdce_udev,
    304 	    USBDEV(sc->cdce_dev));
    305 
    306 	USB_ATTACH_SUCCESS_RETURN;
    307 }
    308 
    309 USB_DETACH(cdce)
    310 {
    311 	USB_DETACH_START(cdce, sc);
    312 	struct ifnet	*ifp = GET_IFP(sc);
    313 	int		 s;
    314 
    315 	s = splusb();
    316 
    317 	if (!sc->cdce_attached) {
    318 		splx(s);
    319 		return (0);
    320 	}
    321 
    322 	if (ifp->if_flags & IFF_RUNNING)
    323 		cdce_stop(sc);
    324 
    325 	ether_ifdetach(ifp);
    326 
    327 	if_detach(ifp);
    328 
    329 	sc->cdce_attached = 0;
    330 	splx(s);
    331 
    332 	return (0);
    333 }
    334 
    335 Static void
    336 cdce_start(struct ifnet *ifp)
    337 {
    338 	struct cdce_softc	*sc = ifp->if_softc;
    339 	struct mbuf		*m_head = NULL;
    340 
    341 	if (sc->cdce_dying || (ifp->if_flags & IFF_OACTIVE))
    342 		return;
    343 
    344 	IFQ_POLL(&ifp->if_snd, m_head);
    345 	if (m_head == NULL)
    346 		return;
    347 
    348 	if (cdce_encap(sc, m_head, 0)) {
    349 		ifp->if_flags |= IFF_OACTIVE;
    350 		return;
    351 	}
    352 
    353 	IFQ_DEQUEUE(&ifp->if_snd, m_head);
    354 
    355 #if NBPFILTER > 0
    356 	if (ifp->if_bpf)
    357 		BPF_MTAP(ifp, m_head);
    358 #endif
    359 
    360 	ifp->if_flags |= IFF_OACTIVE;
    361 
    362 	ifp->if_timer = 6;
    363 }
    364 
    365 Static int
    366 cdce_encap(struct cdce_softc *sc, struct mbuf *m, int idx)
    367 {
    368 	struct cdce_chain	*c;
    369 	usbd_status		 err;
    370 	int			 extra = 0;
    371 
    372 	c = &sc->cdce_cdata.cdce_tx_chain[idx];
    373 
    374 	m_copydata(m, 0, m->m_pkthdr.len, c->cdce_buf);
    375 	if (sc->cdce_flags & CDCE_ZAURUS) {
    376 		/* Zaurus wants a 32-bit CRC appended to every frame */
    377 		u_int32_t crc;
    378 
    379 		crc = cdce_crc32(c->cdce_buf, m->m_pkthdr.len);
    380 		memcpy(c->cdce_buf + m->m_pkthdr.len, &crc, 4);
    381 		extra = 4;
    382 	}
    383 	c->cdce_mbuf = m;
    384 
    385 	usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkout_pipe, c, c->cdce_buf,
    386 	    m->m_pkthdr.len + extra, USBD_NO_COPY, 10000, cdce_txeof);
    387 	err = usbd_transfer(c->cdce_xfer);
    388 	if (err != USBD_IN_PROGRESS) {
    389 		cdce_stop(sc);
    390 		return (EIO);
    391 	}
    392 
    393 	sc->cdce_cdata.cdce_tx_cnt++;
    394 
    395 	return (0);
    396 }
    397 
    398 Static void
    399 cdce_stop(struct cdce_softc *sc)
    400 {
    401 	usbd_status	 err;
    402 	struct ifnet	*ifp = GET_IFP(sc);
    403 	int		 i;
    404 
    405 	ifp->if_timer = 0;
    406 
    407 	if (sc->cdce_bulkin_pipe != NULL) {
    408 		err = usbd_abort_pipe(sc->cdce_bulkin_pipe);
    409 		if (err)
    410 			printf("%s: abort rx pipe failed: %s\n",
    411 			    USBDEVNAME(sc->cdce_dev), usbd_errstr(err));
    412 		err = usbd_close_pipe(sc->cdce_bulkin_pipe);
    413 		if (err)
    414 			printf("%s: close rx pipe failed: %s\n",
    415 			    USBDEVNAME(sc->cdce_dev), usbd_errstr(err));
    416 		sc->cdce_bulkin_pipe = NULL;
    417 	}
    418 
    419 	if (sc->cdce_bulkout_pipe != NULL) {
    420 		err = usbd_abort_pipe(sc->cdce_bulkout_pipe);
    421 		if (err)
    422 			printf("%s: abort tx pipe failed: %s\n",
    423 			    USBDEVNAME(sc->cdce_dev), usbd_errstr(err));
    424 		err = usbd_close_pipe(sc->cdce_bulkout_pipe);
    425 		if (err)
    426 			printf("%s: close tx pipe failed: %s\n",
    427 			    USBDEVNAME(sc->cdce_dev), usbd_errstr(err));
    428 		sc->cdce_bulkout_pipe = NULL;
    429 	}
    430 
    431 	for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
    432 		if (sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf != NULL) {
    433 			m_freem(sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf);
    434 			sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf = NULL;
    435 		}
    436 		if (sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer != NULL) {
    437 			usbd_free_xfer(sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer);
    438 			sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer = NULL;
    439 		}
    440 	}
    441 
    442 	for (i = 0; i < CDCE_TX_LIST_CNT; i++) {
    443 		if (sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf != NULL) {
    444 			m_freem(sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf);
    445 			sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf = NULL;
    446 		}
    447 		if (sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer != NULL) {
    448 			usbd_free_xfer(sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer);
    449 			sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer = NULL;
    450 		}
    451 	}
    452 
    453 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
    454 }
    455 
    456 Static int
    457 cdce_ioctl(struct ifnet *ifp, u_long command, void *data)
    458 {
    459 	struct cdce_softc	*sc = ifp->if_softc;
    460 	struct ifaddr		*ifa = (struct ifaddr *)data;
    461 	struct ifreq		*ifr = (struct ifreq *)data;
    462 	int			 s, error = 0;
    463 
    464 	if (sc->cdce_dying)
    465 		return (EIO);
    466 
    467 	s = splnet();
    468 
    469 	switch(command) {
    470 	case SIOCINITIFADDR:
    471 		ifp->if_flags |= IFF_UP;
    472 		cdce_init(sc);
    473 		switch (ifa->ifa_addr->sa_family) {
    474 #ifdef INET
    475 		case AF_INET:
    476 #if defined(__NetBSD__)
    477 			arp_ifinit(ifp, ifa);
    478 #else
    479 			arp_ifinit(&sc->arpcom, ifa);
    480 #endif
    481 			break;
    482 #endif /* INET */
    483 		}
    484 		break;
    485 
    486 	case SIOCSIFMTU:
    487 		if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ETHERMTU)
    488 			error = EINVAL;
    489 		else if ((error = ifioctl_common(ifp, command, data)) == ENETRESET)
    490 			error = 0;
    491 		break;
    492 
    493 	case SIOCSIFFLAGS:
    494 		if ((error = ifioctl_common(ifp, command, data)) != 0)
    495 			break;
    496 		/* XXX re-use ether_ioctl() */
    497 		switch (ifp->if_flags & (IFF_UP|IFF_RUNNING)) {
    498 		case IFF_UP:
    499 			cdce_init(sc);
    500 			break;
    501 		case IFF_RUNNING:
    502 			cdce_stop(sc);
    503 			break;
    504 		default:
    505 			break;
    506 		}
    507 		break;
    508 
    509 	default:
    510 		error = ether_ioctl(ifp, command, data);
    511 		break;
    512 	}
    513 
    514 	splx(s);
    515 
    516 	return (error);
    517 }
    518 
    519 Static void
    520 cdce_watchdog(struct ifnet *ifp)
    521 {
    522 	struct cdce_softc	*sc = ifp->if_softc;
    523 
    524 	if (sc->cdce_dying)
    525 		return;
    526 
    527 	ifp->if_oerrors++;
    528 	printf("%s: watchdog timeout\n", USBDEVNAME(sc->cdce_dev));
    529 }
    530 
    531 Static void
    532 cdce_init(void *xsc)
    533 {
    534 	struct cdce_softc	*sc = xsc;
    535 	struct ifnet		*ifp = GET_IFP(sc);
    536 	struct cdce_chain	*c;
    537 	usbd_status		 err;
    538 	int			 s, i;
    539 
    540 	if (ifp->if_flags & IFF_RUNNING)
    541 		return;
    542 
    543 	s = splnet();
    544 
    545 	if (cdce_tx_list_init(sc) == ENOBUFS) {
    546 		printf("%s: tx list init failed\n", USBDEVNAME(sc->cdce_dev));
    547 		splx(s);
    548 		return;
    549 	}
    550 
    551 	if (cdce_rx_list_init(sc) == ENOBUFS) {
    552 		printf("%s: rx list init failed\n", USBDEVNAME(sc->cdce_dev));
    553 		splx(s);
    554 		return;
    555 	}
    556 
    557 	/* Maybe set multicast / broadcast here??? */
    558 
    559 	err = usbd_open_pipe(sc->cdce_data_iface, sc->cdce_bulkin_no,
    560 	    USBD_EXCLUSIVE_USE, &sc->cdce_bulkin_pipe);
    561 	if (err) {
    562 		printf("%s: open rx pipe failed: %s\n", USBDEVNAME(sc->cdce_dev),
    563 		    usbd_errstr(err));
    564 		splx(s);
    565 		return;
    566 	}
    567 
    568 	err = usbd_open_pipe(sc->cdce_data_iface, sc->cdce_bulkout_no,
    569 	    USBD_EXCLUSIVE_USE, &sc->cdce_bulkout_pipe);
    570 	if (err) {
    571 		printf("%s: open tx pipe failed: %s\n", USBDEVNAME(sc->cdce_dev),
    572 		    usbd_errstr(err));
    573 		splx(s);
    574 		return;
    575 	}
    576 
    577 	for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
    578 		c = &sc->cdce_cdata.cdce_rx_chain[i];
    579 		usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkin_pipe, c,
    580 		    c->cdce_buf, CDCE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
    581 		    USBD_NO_TIMEOUT, cdce_rxeof);
    582 		usbd_transfer(c->cdce_xfer);
    583 	}
    584 
    585 	ifp->if_flags |= IFF_RUNNING;
    586 	ifp->if_flags &= ~IFF_OACTIVE;
    587 
    588 	splx(s);
    589 }
    590 
    591 Static int
    592 cdce_newbuf(struct cdce_softc *sc, struct cdce_chain *c, struct mbuf *m)
    593 {
    594 	struct mbuf	*m_new = NULL;
    595 
    596 	if (m == NULL) {
    597 		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
    598 		if (m_new == NULL) {
    599 			printf("%s: no memory for rx list "
    600 			    "-- packet dropped!\n", USBDEVNAME(sc->cdce_dev));
    601 			return (ENOBUFS);
    602 		}
    603 		MCLGET(m_new, M_DONTWAIT);
    604 		if (!(m_new->m_flags & M_EXT)) {
    605 			printf("%s: no memory for rx list "
    606 			    "-- packet dropped!\n", USBDEVNAME(sc->cdce_dev));
    607 			m_freem(m_new);
    608 			return (ENOBUFS);
    609 		}
    610 		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
    611 	} else {
    612 		m_new = m;
    613 		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
    614 		m_new->m_data = m_new->m_ext.ext_buf;
    615 	}
    616 	c->cdce_mbuf = m_new;
    617 	return (0);
    618 }
    619 
    620 Static int
    621 cdce_rx_list_init(struct cdce_softc *sc)
    622 {
    623 	struct cdce_cdata	*cd;
    624 	struct cdce_chain	*c;
    625 	int			 i;
    626 
    627 	cd = &sc->cdce_cdata;
    628 	for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
    629 		c = &cd->cdce_rx_chain[i];
    630 		c->cdce_sc = sc;
    631 		c->cdce_idx = i;
    632 		if (cdce_newbuf(sc, c, NULL) == ENOBUFS)
    633 			return (ENOBUFS);
    634 		if (c->cdce_xfer == NULL) {
    635 			c->cdce_xfer = usbd_alloc_xfer(sc->cdce_udev);
    636 			if (c->cdce_xfer == NULL)
    637 				return (ENOBUFS);
    638 			c->cdce_buf = usbd_alloc_buffer(c->cdce_xfer, CDCE_BUFSZ);
    639 			if (c->cdce_buf == NULL)
    640 				return (ENOBUFS);
    641 		}
    642 	}
    643 
    644 	return (0);
    645 }
    646 
    647 Static int
    648 cdce_tx_list_init(struct cdce_softc *sc)
    649 {
    650 	struct cdce_cdata	*cd;
    651 	struct cdce_chain	*c;
    652 	int			 i;
    653 
    654 	cd = &sc->cdce_cdata;
    655 	for (i = 0; i < CDCE_TX_LIST_CNT; i++) {
    656 		c = &cd->cdce_tx_chain[i];
    657 		c->cdce_sc = sc;
    658 		c->cdce_idx = i;
    659 		c->cdce_mbuf = NULL;
    660 		if (c->cdce_xfer == NULL) {
    661 			c->cdce_xfer = usbd_alloc_xfer(sc->cdce_udev);
    662 			if (c->cdce_xfer == NULL)
    663 				return (ENOBUFS);
    664 			c->cdce_buf = usbd_alloc_buffer(c->cdce_xfer, CDCE_BUFSZ);
    665 			if (c->cdce_buf == NULL)
    666 				return (ENOBUFS);
    667 		}
    668 	}
    669 
    670 	return (0);
    671 }
    672 
    673 Static void
    674 cdce_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
    675 {
    676 	struct cdce_chain	*c = priv;
    677 	struct cdce_softc	*sc = c->cdce_sc;
    678 	struct ifnet		*ifp = GET_IFP(sc);
    679 	struct mbuf		*m;
    680 	int			 total_len = 0;
    681 	int			 s;
    682 
    683 	if (sc->cdce_dying || !(ifp->if_flags & IFF_RUNNING))
    684 		return;
    685 
    686 	if (status != USBD_NORMAL_COMPLETION) {
    687 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
    688 			return;
    689 		if (sc->cdce_rxeof_errors == 0)
    690 			printf("%s: usb error on rx: %s\n",
    691 			    USBDEVNAME(sc->cdce_dev), usbd_errstr(status));
    692 		if (status == USBD_STALLED)
    693 			usbd_clear_endpoint_stall_async(sc->cdce_bulkin_pipe);
    694 		DELAY(sc->cdce_rxeof_errors * 10000);
    695 		sc->cdce_rxeof_errors++;
    696 		goto done;
    697 	}
    698 
    699 	sc->cdce_rxeof_errors = 0;
    700 
    701 	usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
    702 	if (sc->cdce_flags & CDCE_ZAURUS)
    703 		total_len -= 4;	/* Strip off CRC added by Zaurus */
    704 	if (total_len <= 1)
    705 		goto done;
    706 
    707 	m = c->cdce_mbuf;
    708 	memcpy(mtod(m, char *), c->cdce_buf, total_len);
    709 
    710 	if (total_len < sizeof(struct ether_header)) {
    711 		ifp->if_ierrors++;
    712 		goto done;
    713 	}
    714 
    715 	ifp->if_ipackets++;
    716 	m->m_pkthdr.len = m->m_len = total_len;
    717 	m->m_pkthdr.rcvif = ifp;
    718 
    719 	s = splnet();
    720 
    721 	if (cdce_newbuf(sc, c, NULL) == ENOBUFS) {
    722 		ifp->if_ierrors++;
    723 		goto done1;
    724 	}
    725 
    726 #if NBPFILTER > 0
    727 	if (ifp->if_bpf)
    728 		BPF_MTAP(ifp, m);
    729 #endif
    730 
    731 	IF_INPUT(ifp, m);
    732 
    733 done1:
    734 	splx(s);
    735 
    736 done:
    737 	/* Setup new transfer. */
    738 	usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkin_pipe, c, c->cdce_buf,
    739 	    CDCE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
    740 	    cdce_rxeof);
    741 	usbd_transfer(c->cdce_xfer);
    742 }
    743 
    744 Static void
    745 cdce_txeof(usbd_xfer_handle xfer, usbd_private_handle priv,
    746     usbd_status status)
    747 {
    748 	struct cdce_chain	*c = priv;
    749 	struct cdce_softc	*sc = c->cdce_sc;
    750 	struct ifnet		*ifp = GET_IFP(sc);
    751 	usbd_status		 err;
    752 	int			 s;
    753 
    754 	if (sc->cdce_dying)
    755 		return;
    756 
    757 	s = splnet();
    758 
    759 	ifp->if_timer = 0;
    760 	ifp->if_flags &= ~IFF_OACTIVE;
    761 
    762 	if (status != USBD_NORMAL_COMPLETION) {
    763 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
    764 			splx(s);
    765 			return;
    766 		}
    767 		ifp->if_oerrors++;
    768 		printf("%s: usb error on tx: %s\n", USBDEVNAME(sc->cdce_dev),
    769 		    usbd_errstr(status));
    770 		if (status == USBD_STALLED)
    771 			usbd_clear_endpoint_stall_async(sc->cdce_bulkout_pipe);
    772 		splx(s);
    773 		return;
    774 	}
    775 
    776 	usbd_get_xfer_status(c->cdce_xfer, NULL, NULL, NULL, &err);
    777 
    778 	if (c->cdce_mbuf != NULL) {
    779 		m_freem(c->cdce_mbuf);
    780 		c->cdce_mbuf = NULL;
    781 	}
    782 
    783 	if (err)
    784 		ifp->if_oerrors++;
    785 	else
    786 		ifp->if_opackets++;
    787 
    788 	if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
    789 		cdce_start(ifp);
    790 
    791 	splx(s);
    792 }
    793 
    794 int
    795 cdce_activate(device_ptr_t self, enum devact act)
    796 {
    797 	struct cdce_softc *sc = device_private(self);
    798 
    799 	switch (act) {
    800 	case DVACT_ACTIVATE:
    801 		return (EOPNOTSUPP);
    802 		break;
    803 
    804 	case DVACT_DEACTIVATE:
    805 		if_deactivate(GET_IFP(sc));
    806 		sc->cdce_dying = 1;
    807 		break;
    808 	}
    809 	return (0);
    810 }
    811 
    812 
    813 /*  COPYRIGHT (C) 1986 Gary S. Brown.  You may use this program, or
    814  *  code or tables extracted from it, as desired without restriction.
    815  */
    816 
    817 static uint32_t cdce_crc32_tab[] = {
    818 	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
    819 	0xe963a535, 0x9e6495a3,	0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
    820 	0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
    821 	0xf3b97148, 0x84be41de,	0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
    822 	0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,	0x14015c4f, 0x63066cd9,
    823 	0xfa0f3d63, 0x8d080df5,	0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
    824 	0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,	0x35b5a8fa, 0x42b2986c,
    825 	0xdbbbc9d6, 0xacbcf940,	0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
    826 	0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
    827 	0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
    828 	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,	0x76dc4190, 0x01db7106,
    829 	0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
    830 	0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
    831 	0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
    832 	0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
    833 	0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
    834 	0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
    835 	0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
    836 	0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
    837 	0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
    838 	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
    839 	0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
    840 	0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
    841 	0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
    842 	0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
    843 	0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
    844 	0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
    845 	0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
    846 	0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
    847 	0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
    848 	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
    849 	0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
    850 	0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
    851 	0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
    852 	0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
    853 	0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
    854 	0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
    855 	0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
    856 	0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
    857 	0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
    858 	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
    859 	0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
    860 	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
    861 };
    862 
    863 Static uint32_t
    864 cdce_crc32(const void *buf, size_t size)
    865 {
    866 	const uint8_t *p;
    867 	uint32_t crc;
    868 
    869 	p = buf;
    870 	crc = ~0U;
    871 
    872 	while (size--)
    873 		crc = cdce_crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
    874 
    875 	return (crc ^ ~0U);
    876 }
    877