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