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