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