xref: /openbsd-src/sys/dev/usb/if_cdce.c (revision b4004a84a27f9de3da30a9385dfd1dc126a04ee4)
1 /*	$OpenBSD: if_cdce.c,v 1.35 2007/07/25 16:42:24 mbalmer 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 <bpfilter.h>
44 
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/sockio.h>
48 #include <sys/mbuf.h>
49 #include <sys/malloc.h>
50 #include <sys/kernel.h>
51 #include <sys/socket.h>
52 #include <sys/device.h>
53 #include <sys/proc.h>
54 
55 #include <net/if.h>
56 #include <net/if_dl.h>
57 
58 #include <net/bpf.h>
59 #if NBPFILTER > 0
60 #endif
61 
62 #include <netinet/in.h>
63 #include <netinet/in_systm.h>
64 #include <netinet/in_var.h>
65 #include <netinet/ip.h>
66 #include <netinet/if_ether.h>
67 
68 #include <dev/usb/usb.h>
69 #include <dev/usb/usbdi.h>
70 #include <dev/usb/usbdi_util.h>
71 #include <dev/usb/usbdevs.h>
72 #include <dev/usb/usbcdc.h>
73 
74 #include <dev/usb/if_cdcereg.h>
75 
76 #ifdef CDCE_DEBUG
77 #define DPRINTFN(n, x)	do { if (cdcedebug > (n)) printf x; } while (0)
78 int cdcedebug = 0;
79 #else
80 #define DPRINTFN(n, x)
81 #endif
82 #define DPRINTF(x)	DPRINTFN(0, x)
83 
84 int	 cdce_tx_list_init(struct cdce_softc *);
85 int	 cdce_rx_list_init(struct cdce_softc *);
86 int	 cdce_newbuf(struct cdce_softc *, struct cdce_chain *,
87 		    struct mbuf *);
88 int	 cdce_encap(struct cdce_softc *, struct mbuf *, int);
89 void	 cdce_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
90 void	 cdce_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
91 void	 cdce_start(struct ifnet *);
92 int	 cdce_ioctl(struct ifnet *, u_long, caddr_t);
93 void	 cdce_init(void *);
94 void	 cdce_watchdog(struct ifnet *);
95 void	 cdce_stop(struct cdce_softc *);
96 void	 cdce_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
97 static uint32_t	 cdce_crc32(const void *, size_t);
98 
99 const struct cdce_type cdce_devs[] = {
100     {{ USB_VENDOR_ACERLABS, USB_PRODUCT_ACERLABS_M5632 }, 0 },
101     {{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2501 }, 0 },
102     {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5500 }, CDCE_ZAURUS },
103     {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_A300 }, CDCE_ZAURUS },
104     {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5600 }, CDCE_ZAURUS },
105     {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_C700 }, CDCE_ZAURUS },
106     {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_C750 }, CDCE_ZAURUS },
107     {{ USB_VENDOR_MOTOROLA2, USB_PRODUCT_MOTOROLA2_USBLAN }, CDCE_ZAURUS },
108     {{ USB_VENDOR_MOTOROLA2, USB_PRODUCT_MOTOROLA2_USBLAN2 }, CDCE_ZAURUS },
109     {{ USB_VENDOR_GMATE, USB_PRODUCT_GMATE_YP3X00 }, 0 },
110     {{ USB_VENDOR_NETCHIP, USB_PRODUCT_NETCHIP_ETHERNETGADGET }, 0 },
111     {{ USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_IPAQLINUX }, 0 },
112     {{ USB_VENDOR_AMBIT, USB_PRODUCT_AMBIT_NTL_250 }, CDCE_SWAPUNION },
113 };
114 #define cdce_lookup(v, p) ((const struct cdce_type *)usb_lookup(cdce_devs, v, p))
115 
116 int cdce_match(struct device *, void *, void *);
117 void cdce_attach(struct device *, struct device *, void *);
118 int cdce_detach(struct device *, int);
119 int cdce_activate(struct device *, enum devact);
120 
121 struct cfdriver cdce_cd = {
122 	NULL, "cdce", DV_IFNET
123 };
124 
125 const struct cfattach cdce_ca = {
126 	sizeof(struct cdce_softc),
127 	cdce_match,
128 	cdce_attach,
129 	cdce_detach,
130 	cdce_activate,
131 };
132 
133 int
134 cdce_match(struct device *parent, void *match, void *aux)
135 {
136 	struct usb_attach_arg *uaa = aux;
137 	usb_interface_descriptor_t *id;
138 
139 	if (uaa->iface == NULL)
140 		return (UMATCH_NONE);
141 
142 	id = usbd_get_interface_descriptor(uaa->iface);
143 	if (id == NULL)
144 		return (UMATCH_NONE);
145 
146 	if (cdce_lookup(uaa->vendor, uaa->product) != NULL)
147 		return (UMATCH_VENDOR_PRODUCT);
148 
149 	if (id->bInterfaceClass == UICLASS_CDC && id->bInterfaceSubClass ==
150 	    UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL)
151 		return (UMATCH_IFACECLASS_GENERIC);
152 
153 	return (UMATCH_NONE);
154 }
155 
156 void
157 cdce_attach(struct device *parent, struct device *self, void *aux)
158 {
159 	struct cdce_softc		*sc = (struct cdce_softc *)self;
160 	struct usb_attach_arg		*uaa = aux;
161 	char				 *devinfop;
162 	int				 s;
163 	struct ifnet			*ifp;
164 	usbd_device_handle		 dev = uaa->device;
165 	const struct cdce_type		*t;
166 	usb_interface_descriptor_t	*id;
167 	usb_endpoint_descriptor_t	*ed;
168 	usb_cdc_union_descriptor_t	*ud;
169 	usb_cdc_ethernet_descriptor_t	*ethd;
170 	usb_config_descriptor_t		*cd;
171 	const usb_descriptor_t		*desc;
172 	usbd_desc_iter_t		 iter;
173 	usb_string_descriptor_t		 eaddr_str;
174 	u_int16_t			 macaddr_hi;
175 	int				 i, j, numalts, len;
176 	int				 ctl_ifcno = -1;
177 	int				 data_ifcno = -1;
178 
179 	devinfop = usbd_devinfo_alloc(dev, 0);
180 	printf("\n%s: %s\n", sc->cdce_dev.dv_xname, devinfop);
181 	usbd_devinfo_free(devinfop);
182 
183 	sc->cdce_udev = uaa->device;
184 	sc->cdce_ctl_iface = uaa->iface;
185 	id = usbd_get_interface_descriptor(sc->cdce_ctl_iface);
186 	ctl_ifcno = id->bInterfaceNumber;
187 
188 	t = cdce_lookup(uaa->vendor, uaa->product);
189 	if (t)
190 		sc->cdce_flags = t->cdce_flags;
191 
192 	/* Get the data interface no. and capabilities */
193 	ethd = NULL;
194 	usb_desc_iter_init(dev, &iter);
195 	desc = usb_desc_iter_next(&iter);
196 	while (desc) {
197 		if (desc->bDescriptorType != UDESC_CS_INTERFACE) {
198 			desc = usb_desc_iter_next(&iter);
199 			continue;
200 		}
201 		switch(desc->bDescriptorSubtype) {
202 		case UDESCSUB_CDC_UNION:
203 			ud = (usb_cdc_union_descriptor_t *)desc;
204 			if ((sc->cdce_flags & CDCE_SWAPUNION) == 0 &&
205 			    ud->bMasterInterface == ctl_ifcno)
206 				data_ifcno = ud->bSlaveInterface[0];
207 			if ((sc->cdce_flags & CDCE_SWAPUNION) &&
208 			    ud->bSlaveInterface[0] == ctl_ifcno)
209 				data_ifcno = ud->bMasterInterface;
210 			break;
211 		case UDESCSUB_CDC_ENF:
212 			if (ethd) {
213 				printf("%s: ", sc->cdce_dev.dv_xname);
214 				printf("extra ethernet descriptor\n");
215 				return;
216 			}
217 			ethd = (usb_cdc_ethernet_descriptor_t *)desc;
218 			break;
219 		}
220 		desc = usb_desc_iter_next(&iter);
221 	}
222 
223 	if (data_ifcno == -1) {
224 		DPRINTF(("cdce_attach: no union interface\n"));
225 		sc->cdce_data_iface = sc->cdce_ctl_iface;
226 	} else {
227 		DPRINTF(("cdce_attach: union interface: ctl=%d, data=%d\n",
228 		    ctl_ifcno, data_ifcno));
229 		for (i = 0; i < uaa->nifaces; i++) {
230 			if (uaa->ifaces[i] != NULL) {
231 				id = usbd_get_interface_descriptor(
232 				    uaa->ifaces[i]);
233 				if (id != NULL && id->bInterfaceNumber ==
234 				    data_ifcno) {
235 					sc->cdce_data_iface = uaa->ifaces[i];
236 					uaa->ifaces[i] = NULL;
237 				}
238 			}
239 		}
240 	}
241 
242 	if (sc->cdce_data_iface == NULL) {
243 		printf("%s: no data interface\n", sc->cdce_dev.dv_xname);
244 		return;
245 	}
246 
247 	id = usbd_get_interface_descriptor(sc->cdce_ctl_iface);
248 	sc->cdce_intr_no = -1;
249 	for (i = 0; i < id->bNumEndpoints && sc->cdce_intr_no == -1; i++) {
250 		ed = usbd_interface2endpoint_descriptor(sc->cdce_ctl_iface, i);
251 		if (!ed) {
252 			printf("%s: no descriptor for interrupt endpoint %d\n",
253 			    sc->cdce_dev.dv_xname, i);
254 			return;
255 		}
256 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
257 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
258 			sc->cdce_intr_no = ed->bEndpointAddress;
259 			sc->cdce_intr_size = sizeof(sc->cdce_intr_buf);
260 		}
261 	}
262 
263 	id = usbd_get_interface_descriptor(sc->cdce_data_iface);
264 	cd = usbd_get_config_descriptor(sc->cdce_udev);
265 	numalts = usbd_get_no_alts(cd, id->bInterfaceNumber);
266 
267 	for (j = 0; j < numalts; j++) {
268 	    if (usbd_set_interface(sc->cdce_data_iface, j)) {
269 	    	printf("%s: interface alternate setting %d failed\n",
270 		    sc->cdce_dev.dv_xname, j);
271 		return;
272     	    }
273 	    /* Find endpoints. */
274 	    id = usbd_get_interface_descriptor(sc->cdce_data_iface);
275 	    sc->cdce_bulkin_no = sc->cdce_bulkout_no = -1;
276 	    for (i = 0; i < id->bNumEndpoints; i++) {
277 		ed = usbd_interface2endpoint_descriptor(sc->cdce_data_iface, i);
278 		if (!ed) {
279 			printf("%s: no descriptor for bulk endpoint %d\n",
280 			    sc->cdce_dev.dv_xname, i);
281 			return;
282 		}
283 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
284 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
285 			sc->cdce_bulkin_no = ed->bEndpointAddress;
286 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
287 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
288 			sc->cdce_bulkout_no = ed->bEndpointAddress;
289 		}
290 #ifdef CDCE_DEBUG
291 		else if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN &&
292 		    UE_GET_XFERTYPE(ed->bmAttributes) != UE_INTERRUPT) {
293 			printf("%s: unexpected endpoint, ep=%x attr=%x\n",
294 			    sc->cdce_dev.dv_xname, ed->bEndpointAddress,
295 			    ed->bmAttributes);
296 		}
297 #endif
298 	    }
299 	    if ((sc->cdce_bulkin_no != -1) && (sc->cdce_bulkout_no != -1)) {
300 		DPRINTF(("cdce_attach: intr=0x%x, in=0x%x, out=0x%x\n",
301 		    sc->cdce_intr_no, sc->cdce_bulkin_no, sc->cdce_bulkout_no));
302 		goto found;
303 	    }
304 	}
305 
306 	if (sc->cdce_bulkin_no == -1) {
307 		printf("%s: could not find data bulk in\n",
308 		    sc->cdce_dev.dv_xname);
309 		return;
310 	}
311 	if (sc->cdce_bulkout_no == -1 ) {
312 		printf("%s: could not find data bulk out\n",
313 		    sc->cdce_dev.dv_xname);
314 		return;
315 	}
316 
317 found:
318 	s = splnet();
319 
320 	if (!ethd || usbd_get_string_desc(sc->cdce_udev, ethd->iMacAddress, 0,
321 	    &eaddr_str, &len)) {
322 		macaddr_hi = htons(0x2acb);
323 		bcopy(&macaddr_hi, &sc->cdce_arpcom.ac_enaddr[0],
324 		    sizeof(u_int16_t));
325 		bcopy(&ticks, &sc->cdce_arpcom.ac_enaddr[2], sizeof(u_int32_t));
326 		sc->cdce_arpcom.ac_enaddr[5] = (u_int8_t)(sc->cdce_unit);
327 	} else {
328 		for (i = 0; i < ETHER_ADDR_LEN * 2; i++) {
329 			int c = UGETW(eaddr_str.bString[i]);
330 
331 			if ('0' <= c && c <= '9')
332 				c -= '0';
333 			else if ('A' <= c && c <= 'F')
334 				c -= 'A' - 10;
335 			else if ('a' <= c && c <= 'f')
336 				c -= 'a' - 10;
337 			c &= 0xf;
338 			if (i % 2 == 0)
339 				c <<= 4;
340 			sc->cdce_arpcom.ac_enaddr[i / 2] |= c;
341 		}
342 	}
343 
344 	printf("%s: address %s\n", sc->cdce_dev.dv_xname,
345 	    ether_sprintf(sc->cdce_arpcom.ac_enaddr));
346 
347 	ifp = GET_IFP(sc);
348 	ifp->if_softc = sc;
349 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
350 	ifp->if_ioctl = cdce_ioctl;
351 	ifp->if_start = cdce_start;
352 	ifp->if_watchdog = cdce_watchdog;
353 	strlcpy(ifp->if_xname, sc->cdce_dev.dv_xname, IFNAMSIZ);
354 
355 	IFQ_SET_READY(&ifp->if_snd);
356 
357 	if_attach(ifp);
358 	ether_ifattach(ifp);
359 
360 	sc->cdce_attached = 1;
361 	splx(s);
362 
363 	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->cdce_udev,
364 	    &sc->cdce_dev);
365 }
366 
367 int
368 cdce_detach(struct device *self, int flags)
369 {
370 	struct cdce_softc	*sc = (struct cdce_softc *)self;
371 	struct ifnet		*ifp = GET_IFP(sc);
372 	int			 s;
373 
374 	s = splusb();
375 
376 	if (!sc->cdce_attached) {
377 		splx(s);
378 		return (0);
379 	}
380 
381 	if (ifp->if_flags & IFF_RUNNING)
382 		cdce_stop(sc);
383 
384 	ether_ifdetach(ifp);
385 
386 	if_detach(ifp);
387 
388 	sc->cdce_attached = 0;
389 	splx(s);
390 
391 	return (0);
392 }
393 
394 void
395 cdce_start(struct ifnet *ifp)
396 {
397 	struct cdce_softc	*sc = ifp->if_softc;
398 	struct mbuf		*m_head = NULL;
399 
400 	if (sc->cdce_dying || (ifp->if_flags & IFF_OACTIVE))
401 		return;
402 
403 	IFQ_POLL(&ifp->if_snd, m_head);
404 	if (m_head == NULL)
405 		return;
406 
407 	if (cdce_encap(sc, m_head, 0)) {
408 		ifp->if_flags |= IFF_OACTIVE;
409 		return;
410 	}
411 
412 	IFQ_DEQUEUE(&ifp->if_snd, m_head);
413 
414 #if NBPFILTER > 0
415 	if (ifp->if_bpf)
416 		bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
417 #endif
418 
419 	ifp->if_flags |= IFF_OACTIVE;
420 
421 	ifp->if_timer = 6;
422 }
423 
424 int
425 cdce_encap(struct cdce_softc *sc, struct mbuf *m, int idx)
426 {
427 	struct cdce_chain	*c;
428 	usbd_status		 err;
429 	int			 extra = 0;
430 
431 	c = &sc->cdce_cdata.cdce_tx_chain[idx];
432 
433 	m_copydata(m, 0, m->m_pkthdr.len, c->cdce_buf);
434 	if (sc->cdce_flags & CDCE_ZAURUS) {
435 		/* Zaurus wants a 32-bit CRC appended to every frame */
436 		u_int32_t crc;
437 
438 		crc = cdce_crc32(c->cdce_buf, m->m_pkthdr.len);
439 		bcopy(&crc, c->cdce_buf + m->m_pkthdr.len, 4);
440 		extra = 4;
441 	}
442 	c->cdce_mbuf = m;
443 
444 	usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkout_pipe, c, c->cdce_buf,
445 	    m->m_pkthdr.len + extra, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
446 	    10000, cdce_txeof);
447 	err = usbd_transfer(c->cdce_xfer);
448 	if (err != USBD_IN_PROGRESS) {
449 		cdce_stop(sc);
450 		return (EIO);
451 	}
452 
453 	sc->cdce_cdata.cdce_tx_cnt++;
454 
455 	return (0);
456 }
457 
458 void
459 cdce_stop(struct cdce_softc *sc)
460 {
461 	usbd_status	 err;
462 	struct ifnet	*ifp = GET_IFP(sc);
463 	int		 i;
464 
465 	ifp->if_timer = 0;
466 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
467 
468 	if (sc->cdce_bulkin_pipe != NULL) {
469 		err = usbd_abort_pipe(sc->cdce_bulkin_pipe);
470 		if (err)
471 			printf("%s: abort rx pipe failed: %s\n",
472 			    sc->cdce_dev.dv_xname, usbd_errstr(err));
473 		err = usbd_close_pipe(sc->cdce_bulkin_pipe);
474 		if (err)
475 			printf("%s: close rx pipe failed: %s\n",
476 			    sc->cdce_dev.dv_xname, usbd_errstr(err));
477 		sc->cdce_bulkin_pipe = NULL;
478 	}
479 
480 	if (sc->cdce_bulkout_pipe != NULL) {
481 		err = usbd_abort_pipe(sc->cdce_bulkout_pipe);
482 		if (err)
483 			printf("%s: abort tx pipe failed: %s\n",
484 			    sc->cdce_dev.dv_xname, usbd_errstr(err));
485 		err = usbd_close_pipe(sc->cdce_bulkout_pipe);
486 		if (err)
487 			printf("%s: close tx pipe failed: %s\n",
488 			    sc->cdce_dev.dv_xname, usbd_errstr(err));
489 		sc->cdce_bulkout_pipe = NULL;
490 	}
491 
492 	if (sc->cdce_intr_pipe != NULL) {
493 		err = usbd_abort_pipe(sc->cdce_intr_pipe);
494 		if (err)
495 			printf("%s: abort interrupt pipe failed: %s\n",
496 			    sc->cdce_dev.dv_xname, usbd_errstr(err));
497 		err = usbd_close_pipe(sc->cdce_intr_pipe);
498 		if (err)
499 			printf("%s: close interrupt pipe failed: %s\n",
500 			    sc->cdce_dev.dv_xname, usbd_errstr(err));
501 		sc->cdce_intr_pipe = NULL;
502 	}
503 
504 	for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
505 		if (sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf != NULL) {
506 			m_freem(sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf);
507 			sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf = NULL;
508 		}
509 		if (sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer != NULL) {
510 			usbd_free_xfer(sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer);
511 			sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer = NULL;
512 		}
513 	}
514 
515 	for (i = 0; i < CDCE_TX_LIST_CNT; i++) {
516 		if (sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf != NULL) {
517 			m_freem(sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf);
518 			sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf = NULL;
519 		}
520 		if (sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer != NULL) {
521 			usbd_free_xfer(sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer);
522 			sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer = NULL;
523 		}
524 	}
525 }
526 
527 int
528 cdce_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
529 {
530 	struct cdce_softc	*sc = ifp->if_softc;
531 	struct ifaddr		*ifa = (struct ifaddr *)data;
532 	struct ifreq		*ifr = (struct ifreq *)data;
533 	int			 s, error = 0;
534 
535 	if (sc->cdce_dying)
536 		return (EIO);
537 
538 	s = splnet();
539 
540 	switch(command) {
541 	case SIOCSIFADDR:
542 		ifp->if_flags |= IFF_UP;
543 		cdce_init(sc);
544 		switch (ifa->ifa_addr->sa_family) {
545 		case AF_INET:
546 			arp_ifinit(&sc->cdce_arpcom, ifa);
547 			break;
548 		}
549 		break;
550 
551 	case SIOCSIFMTU:
552 		if (ifr->ifr_mtu > ETHERMTU)
553 			error = EINVAL;
554 		else
555 			ifp->if_mtu = ifr->ifr_mtu;
556 		break;
557 
558 	case SIOCSIFFLAGS:
559 		if (ifp->if_flags & IFF_UP) {
560 			if (!(ifp->if_flags & IFF_RUNNING))
561 				cdce_init(sc);
562 		} else {
563 			if (ifp->if_flags & IFF_RUNNING)
564 				cdce_stop(sc);
565 		}
566 		error = 0;
567 		break;
568 
569 	case SIOCADDMULTI:
570 	case SIOCDELMULTI:
571 		error = (command == SIOCADDMULTI) ?
572 		    ether_addmulti(ifr, &sc->cdce_arpcom) :
573 		    ether_delmulti(ifr, &sc->cdce_arpcom);
574 
575 		if (error == ENETRESET)
576 			error = 0;
577 		break;
578 
579 	default:
580 		error = EINVAL;
581 		break;
582 	}
583 
584 	splx(s);
585 
586 	return (error);
587 }
588 
589 void
590 cdce_watchdog(struct ifnet *ifp)
591 {
592 	struct cdce_softc	*sc = ifp->if_softc;
593 
594 	if (sc->cdce_dying)
595 		return;
596 
597 	ifp->if_oerrors++;
598 	printf("%s: watchdog timeout\n", sc->cdce_dev.dv_xname);
599 }
600 
601 void
602 cdce_init(void *xsc)
603 {
604 	struct cdce_softc	*sc = xsc;
605 	struct ifnet		*ifp = GET_IFP(sc);
606 	struct cdce_chain	*c;
607 	usbd_status		 err;
608 	int			 s, i;
609 
610 	if (ifp->if_flags & IFF_RUNNING)
611 		return;
612 
613 	s = splnet();
614 
615 	if (sc->cdce_intr_no != -1 && sc->cdce_intr_pipe == NULL) {
616 		DPRINTFN(1, ("cdce_init: establish interrupt pipe\n"));
617 		err = usbd_open_pipe_intr(sc->cdce_ctl_iface, sc->cdce_intr_no,
618 		    USBD_SHORT_XFER_OK, &sc->cdce_intr_pipe, sc,
619 		    &sc->cdce_intr_buf, sc->cdce_intr_size, cdce_intr,
620 		    USBD_DEFAULT_INTERVAL);
621 		if (err) {
622 			printf("Failed to establish interrupt pipe: %s\n",
623 			    usbd_errstr(err));
624 			return;
625 		}
626 	}
627 
628 	if (cdce_tx_list_init(sc) == ENOBUFS) {
629 		printf("%s: tx list init failed\n", sc->cdce_dev.dv_xname);
630 		splx(s);
631 		return;
632 	}
633 
634 	if (cdce_rx_list_init(sc) == ENOBUFS) {
635 		printf("%s: rx list init failed\n", sc->cdce_dev.dv_xname);
636 		splx(s);
637 		return;
638 	}
639 
640 	/* Maybe set multicast / broadcast here??? */
641 
642 	err = usbd_open_pipe(sc->cdce_data_iface, sc->cdce_bulkin_no,
643 	    USBD_EXCLUSIVE_USE, &sc->cdce_bulkin_pipe);
644 	if (err) {
645 		printf("%s: open rx pipe failed: %s\n", sc->cdce_dev.dv_xname,
646 		    usbd_errstr(err));
647 		splx(s);
648 		return;
649 	}
650 
651 	err = usbd_open_pipe(sc->cdce_data_iface, sc->cdce_bulkout_no,
652 	    USBD_EXCLUSIVE_USE, &sc->cdce_bulkout_pipe);
653 	if (err) {
654 		printf("%s: open tx pipe failed: %s\n", sc->cdce_dev.dv_xname,
655 		    usbd_errstr(err));
656 		splx(s);
657 		return;
658 	}
659 
660 	for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
661 		c = &sc->cdce_cdata.cdce_rx_chain[i];
662 		usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkin_pipe, c,
663 		    c->cdce_buf, CDCE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
664 		    USBD_NO_TIMEOUT, cdce_rxeof);
665 		usbd_transfer(c->cdce_xfer);
666 	}
667 
668 	ifp->if_flags |= IFF_RUNNING;
669 	ifp->if_flags &= ~IFF_OACTIVE;
670 
671 	splx(s);
672 }
673 
674 int
675 cdce_newbuf(struct cdce_softc *sc, struct cdce_chain *c, struct mbuf *m)
676 {
677 	struct mbuf	*m_new = NULL;
678 
679 	if (m == NULL) {
680 		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
681 		if (m_new == NULL) {
682 			printf("%s: no memory for rx list "
683 			    "-- packet dropped!\n", sc->cdce_dev.dv_xname);
684 			return (ENOBUFS);
685 		}
686 		MCLGET(m_new, M_DONTWAIT);
687 		if (!(m_new->m_flags & M_EXT)) {
688 			printf("%s: no memory for rx list "
689 			    "-- packet dropped!\n", sc->cdce_dev.dv_xname);
690 			m_freem(m_new);
691 			return (ENOBUFS);
692 		}
693 		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
694 	} else {
695 		m_new = m;
696 		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
697 		m_new->m_data = m_new->m_ext.ext_buf;
698 	}
699 
700 	m_adj(m_new, ETHER_ALIGN);
701 	c->cdce_mbuf = m_new;
702 	return (0);
703 }
704 
705 int
706 cdce_rx_list_init(struct cdce_softc *sc)
707 {
708 	struct cdce_cdata	*cd;
709 	struct cdce_chain	*c;
710 	int			 i;
711 
712 	cd = &sc->cdce_cdata;
713 	for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
714 		c = &cd->cdce_rx_chain[i];
715 		c->cdce_sc = sc;
716 		c->cdce_idx = i;
717 		if (cdce_newbuf(sc, c, NULL) == ENOBUFS)
718 			return (ENOBUFS);
719 		if (c->cdce_xfer == NULL) {
720 			c->cdce_xfer = usbd_alloc_xfer(sc->cdce_udev);
721 			if (c->cdce_xfer == NULL)
722 				return (ENOBUFS);
723 			c->cdce_buf = usbd_alloc_buffer(c->cdce_xfer, CDCE_BUFSZ);
724 			if (c->cdce_buf == NULL)
725 				return (ENOBUFS);
726 		}
727 	}
728 
729 	return (0);
730 }
731 
732 int
733 cdce_tx_list_init(struct cdce_softc *sc)
734 {
735 	struct cdce_cdata	*cd;
736 	struct cdce_chain	*c;
737 	int			 i;
738 
739 	cd = &sc->cdce_cdata;
740 	for (i = 0; i < CDCE_TX_LIST_CNT; i++) {
741 		c = &cd->cdce_tx_chain[i];
742 		c->cdce_sc = sc;
743 		c->cdce_idx = i;
744 		c->cdce_mbuf = NULL;
745 		if (c->cdce_xfer == NULL) {
746 			c->cdce_xfer = usbd_alloc_xfer(sc->cdce_udev);
747 			if (c->cdce_xfer == NULL)
748 				return (ENOBUFS);
749 			c->cdce_buf = usbd_alloc_buffer(c->cdce_xfer, CDCE_BUFSZ);
750 			if (c->cdce_buf == NULL)
751 				return (ENOBUFS);
752 		}
753 	}
754 
755 	return (0);
756 }
757 
758 void
759 cdce_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
760 {
761 	struct cdce_chain	*c = priv;
762 	struct cdce_softc	*sc = c->cdce_sc;
763 	struct ifnet		*ifp = GET_IFP(sc);
764 	struct mbuf		*m;
765 	int			 total_len = 0;
766 	int			 s;
767 
768 	if (sc->cdce_dying || !(ifp->if_flags & IFF_RUNNING))
769 		return;
770 
771 	if (status != USBD_NORMAL_COMPLETION) {
772 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
773 			return;
774 		if (sc->cdce_rxeof_errors == 0)
775 			printf("%s: usb error on rx: %s\n",
776 			    sc->cdce_dev.dv_xname, usbd_errstr(status));
777 		if (status == USBD_STALLED)
778 			usbd_clear_endpoint_stall_async(sc->cdce_bulkin_pipe);
779 		DELAY(sc->cdce_rxeof_errors * 10000);
780 		if (sc->cdce_rxeof_errors++ > 10) {
781 			printf("%s: too many errors, disabling\n",
782 			    sc->cdce_dev.dv_xname);
783 			sc->cdce_dying = 1;
784 			return;
785 		}
786 		goto done;
787 	}
788 
789 	sc->cdce_rxeof_errors = 0;
790 
791 	usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
792 	if (sc->cdce_flags & CDCE_ZAURUS)
793 		total_len -= 4;	/* Strip off CRC added by Zaurus */
794 	if (total_len <= 1)
795 		goto done;
796 
797 	m = c->cdce_mbuf;
798 	memcpy(mtod(m, char *), c->cdce_buf, total_len);
799 
800 	if (total_len < sizeof(struct ether_header)) {
801 		ifp->if_ierrors++;
802 		goto done;
803 	}
804 
805 	ifp->if_ipackets++;
806 
807 	m->m_pkthdr.len = m->m_len = total_len;
808 	m->m_pkthdr.rcvif = ifp;
809 
810 	s = splnet();
811 
812 	if (cdce_newbuf(sc, c, NULL) == ENOBUFS) {
813 		ifp->if_ierrors++;
814 		goto done1;
815 	}
816 
817 #if NBPFILTER > 0
818 	if (ifp->if_bpf)
819 		bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
820 #endif
821 
822 	ether_input_mbuf(ifp, m);
823 
824 done1:
825 	splx(s);
826 
827 done:
828 	/* Setup new transfer. */
829 	usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkin_pipe, c, c->cdce_buf,
830 	    CDCE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
831 	    cdce_rxeof);
832 	usbd_transfer(c->cdce_xfer);
833 }
834 
835 void
836 cdce_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
837 {
838 	struct cdce_chain	*c = priv;
839 	struct cdce_softc	*sc = c->cdce_sc;
840 	struct ifnet		*ifp = GET_IFP(sc);
841 	usbd_status		 err;
842 	int			 s;
843 
844 	if (sc->cdce_dying)
845 		return;
846 
847 	s = splnet();
848 
849 	ifp->if_timer = 0;
850 	ifp->if_flags &= ~IFF_OACTIVE;
851 
852 	if (status != USBD_NORMAL_COMPLETION) {
853 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
854 			splx(s);
855 			return;
856 		}
857 		ifp->if_oerrors++;
858 		printf("%s: usb error on tx: %s\n", sc->cdce_dev.dv_xname,
859 		    usbd_errstr(status));
860 		if (status == USBD_STALLED)
861 			usbd_clear_endpoint_stall_async(sc->cdce_bulkout_pipe);
862 		splx(s);
863 		return;
864 	}
865 
866 	usbd_get_xfer_status(c->cdce_xfer, NULL, NULL, NULL, &err);
867 
868 	if (c->cdce_mbuf != NULL) {
869 		m_freem(c->cdce_mbuf);
870 		c->cdce_mbuf = NULL;
871 	}
872 
873 	if (err)
874 		ifp->if_oerrors++;
875 	else
876 		ifp->if_opackets++;
877 
878 	if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
879 		cdce_start(ifp);
880 
881 	splx(s);
882 }
883 
884 int
885 cdce_activate(struct device *self, enum devact act)
886 {
887 	struct cdce_softc *sc = (struct cdce_softc *)self;
888 
889 	switch (act) {
890 	case DVACT_ACTIVATE:
891 		break;
892 
893 	case DVACT_DEACTIVATE:
894 		sc->cdce_dying = 1;
895 		break;
896 	}
897 	return (0);
898 }
899 
900 void
901 cdce_intr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status)
902 {
903 	struct cdce_softc	*sc = addr;
904 	usb_cdc_notification_t	*buf = &sc->cdce_intr_buf;
905 	usb_cdc_connection_speed_t	*speed;
906 	u_int32_t		 count;
907 
908 	if (status == USBD_CANCELLED)
909 		return;
910 
911 	if (status != USBD_NORMAL_COMPLETION) {
912 		DPRINTFN(2, ("cdce_intr: status=%d\n", status));
913 		if (status == USBD_STALLED)
914 			usbd_clear_endpoint_stall_async(sc->cdce_intr_pipe);
915 		return;
916 	}
917 
918 	usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
919 
920 	if (buf->bmRequestType == UCDC_NOTIFICATION) {
921 		switch (buf->bNotification) {
922 		    case UCDC_N_NETWORK_CONNECTION:
923 			DPRINTFN(1, ("cdce_intr: network %s\n",
924 			    UGETW(buf->wValue) ? "connected" : "disconnected"));
925 			break;
926 		    case UCDC_N_CONNECTION_SPEED_CHANGE:
927 			speed = (usb_cdc_connection_speed_t *)&buf->data;
928 			DPRINTFN(1, ("cdce_intr: up=%d, down=%d\n",
929 			    UGETDW(speed->dwUSBitRate),
930 			    UGETDW(speed->dwDSBitRate)));
931 			break;
932 		    default:
933 			DPRINTF(("cdce_intr: bNotification 0x%x\n",
934 			    buf->bNotification));
935 		}
936 	}
937 #ifdef CDCE_DEBUG
938 	else {
939 		printf("cdce_intr: bmRequestType=%d ", buf->bmRequestType);
940 		printf("wValue=%d wIndex=%d wLength=%d\n", UGETW(buf->wValue),
941 		    UGETW(buf->wIndex), UGETW(buf->wLength));
942 	}
943 #endif
944 }
945 
946 
947 /*  COPYRIGHT (C) 1986 Gary S. Brown.  You may use this program, or
948  *  code or tables extracted from it, as desired without restriction.
949  */
950 
951 static uint32_t cdce_crc32_tab[] = {
952 	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
953 	0xe963a535, 0x9e6495a3,	0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
954 	0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
955 	0xf3b97148, 0x84be41de,	0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
956 	0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,	0x14015c4f, 0x63066cd9,
957 	0xfa0f3d63, 0x8d080df5,	0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
958 	0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,	0x35b5a8fa, 0x42b2986c,
959 	0xdbbbc9d6, 0xacbcf940,	0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
960 	0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
961 	0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
962 	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,	0x76dc4190, 0x01db7106,
963 	0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
964 	0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
965 	0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
966 	0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
967 	0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
968 	0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
969 	0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
970 	0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
971 	0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
972 	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
973 	0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
974 	0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
975 	0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
976 	0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
977 	0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
978 	0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
979 	0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
980 	0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
981 	0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
982 	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
983 	0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
984 	0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
985 	0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
986 	0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
987 	0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
988 	0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
989 	0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
990 	0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
991 	0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
992 	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
993 	0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
994 	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
995 };
996 
997 uint32_t
998 cdce_crc32(const void *buf, size_t size)
999 {
1000 	const uint8_t *p;
1001 	uint32_t crc;
1002 
1003 	p = buf;
1004 	crc = ~0U;
1005 
1006 	while (size--)
1007 		crc = cdce_crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
1008 
1009 	return (htole32(crc) ^ ~0U);
1010 }
1011