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