xref: /openbsd-src/sys/dev/usb/if_cdce.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: if_cdce.c,v 1.43 2008/11/28 02:44:18 brad 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 	int			 s, error = 0;
535 
536 	if (sc->cdce_dying)
537 		return (EIO);
538 
539 	s = splnet();
540 
541 	switch(command) {
542 	case SIOCSIFADDR:
543 		ifp->if_flags |= IFF_UP;
544 		cdce_init(sc);
545 		switch (ifa->ifa_addr->sa_family) {
546 		case AF_INET:
547 			arp_ifinit(&sc->cdce_arpcom, ifa);
548 			break;
549 		}
550 		break;
551 
552 	case SIOCSIFFLAGS:
553 		if (ifp->if_flags & IFF_UP) {
554 			if (!(ifp->if_flags & IFF_RUNNING))
555 				cdce_init(sc);
556 		} else {
557 			if (ifp->if_flags & IFF_RUNNING)
558 				cdce_stop(sc);
559 		}
560 		error = 0;
561 		break;
562 
563 	default:
564 		error = ether_ioctl(ifp, &sc->cdce_arpcom, command, data);
565 		break;
566 	}
567 
568 	if (error == ENETRESET)
569 		error = 0;
570 
571 	splx(s);
572 	return (error);
573 }
574 
575 void
576 cdce_watchdog(struct ifnet *ifp)
577 {
578 	struct cdce_softc	*sc = ifp->if_softc;
579 
580 	if (sc->cdce_dying)
581 		return;
582 
583 	ifp->if_oerrors++;
584 	printf("%s: watchdog timeout\n", sc->cdce_dev.dv_xname);
585 }
586 
587 void
588 cdce_init(void *xsc)
589 {
590 	struct cdce_softc	*sc = xsc;
591 	struct ifnet		*ifp = GET_IFP(sc);
592 	struct cdce_chain	*c;
593 	usbd_status		 err;
594 	int			 s, i;
595 
596 	if (ifp->if_flags & IFF_RUNNING)
597 		return;
598 
599 	s = splnet();
600 
601 	if (sc->cdce_intr_no != -1 && sc->cdce_intr_pipe == NULL) {
602 		DPRINTFN(1, ("cdce_init: establish interrupt pipe\n"));
603 		err = usbd_open_pipe_intr(sc->cdce_ctl_iface, sc->cdce_intr_no,
604 		    USBD_SHORT_XFER_OK, &sc->cdce_intr_pipe, sc,
605 		    &sc->cdce_intr_buf, sc->cdce_intr_size, cdce_intr,
606 		    USBD_DEFAULT_INTERVAL);
607 		if (err) {
608 			printf("%s: open interrupt pipe failed: %s\n",
609 			    sc->cdce_dev.dv_xname, usbd_errstr(err));
610 			splx(s);
611 			return;
612 		}
613 	}
614 
615 	if (cdce_tx_list_init(sc) == ENOBUFS) {
616 		printf("%s: tx list init failed\n", sc->cdce_dev.dv_xname);
617 		splx(s);
618 		return;
619 	}
620 
621 	if (cdce_rx_list_init(sc) == ENOBUFS) {
622 		printf("%s: rx list init failed\n", sc->cdce_dev.dv_xname);
623 		splx(s);
624 		return;
625 	}
626 
627 	/* Maybe set multicast / broadcast here??? */
628 
629 	err = usbd_open_pipe(sc->cdce_data_iface, sc->cdce_bulkin_no,
630 	    USBD_EXCLUSIVE_USE, &sc->cdce_bulkin_pipe);
631 	if (err) {
632 		printf("%s: open rx pipe failed: %s\n", sc->cdce_dev.dv_xname,
633 		    usbd_errstr(err));
634 		splx(s);
635 		return;
636 	}
637 
638 	err = usbd_open_pipe(sc->cdce_data_iface, sc->cdce_bulkout_no,
639 	    USBD_EXCLUSIVE_USE, &sc->cdce_bulkout_pipe);
640 	if (err) {
641 		printf("%s: open tx pipe failed: %s\n", sc->cdce_dev.dv_xname,
642 		    usbd_errstr(err));
643 		splx(s);
644 		return;
645 	}
646 
647 	for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
648 		c = &sc->cdce_cdata.cdce_rx_chain[i];
649 		usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkin_pipe, c,
650 		    c->cdce_buf, CDCE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
651 		    USBD_NO_TIMEOUT, cdce_rxeof);
652 		usbd_transfer(c->cdce_xfer);
653 	}
654 
655 	ifp->if_flags |= IFF_RUNNING;
656 	ifp->if_flags &= ~IFF_OACTIVE;
657 
658 	splx(s);
659 }
660 
661 int
662 cdce_newbuf(struct cdce_softc *sc, struct cdce_chain *c, struct mbuf *m)
663 {
664 	struct mbuf	*m_new = NULL;
665 
666 	if (m == NULL) {
667 		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
668 		if (m_new == NULL) {
669 			printf("%s: no memory for rx list "
670 			    "-- packet dropped!\n", sc->cdce_dev.dv_xname);
671 			return (ENOBUFS);
672 		}
673 		MCLGET(m_new, M_DONTWAIT);
674 		if (!(m_new->m_flags & M_EXT)) {
675 			printf("%s: no memory for rx list "
676 			    "-- packet dropped!\n", sc->cdce_dev.dv_xname);
677 			m_freem(m_new);
678 			return (ENOBUFS);
679 		}
680 		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
681 	} else {
682 		m_new = m;
683 		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
684 		m_new->m_data = m_new->m_ext.ext_buf;
685 	}
686 
687 	m_adj(m_new, ETHER_ALIGN);
688 	c->cdce_mbuf = m_new;
689 	return (0);
690 }
691 
692 int
693 cdce_rx_list_init(struct cdce_softc *sc)
694 {
695 	struct cdce_cdata	*cd;
696 	struct cdce_chain	*c;
697 	int			 i;
698 
699 	cd = &sc->cdce_cdata;
700 	for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
701 		c = &cd->cdce_rx_chain[i];
702 		c->cdce_sc = sc;
703 		c->cdce_idx = i;
704 		if (cdce_newbuf(sc, c, NULL) == ENOBUFS)
705 			return (ENOBUFS);
706 		if (c->cdce_xfer == NULL) {
707 			c->cdce_xfer = usbd_alloc_xfer(sc->cdce_udev);
708 			if (c->cdce_xfer == NULL)
709 				return (ENOBUFS);
710 			c->cdce_buf = usbd_alloc_buffer(c->cdce_xfer,
711 			    CDCE_BUFSZ);
712 			if (c->cdce_buf == NULL)
713 				return (ENOBUFS);
714 		}
715 	}
716 
717 	return (0);
718 }
719 
720 int
721 cdce_tx_list_init(struct cdce_softc *sc)
722 {
723 	struct cdce_cdata	*cd;
724 	struct cdce_chain	*c;
725 	int			 i;
726 
727 	cd = &sc->cdce_cdata;
728 	for (i = 0; i < CDCE_TX_LIST_CNT; i++) {
729 		c = &cd->cdce_tx_chain[i];
730 		c->cdce_sc = sc;
731 		c->cdce_idx = i;
732 		c->cdce_mbuf = NULL;
733 		if (c->cdce_xfer == NULL) {
734 			c->cdce_xfer = usbd_alloc_xfer(sc->cdce_udev);
735 			if (c->cdce_xfer == NULL)
736 				return (ENOBUFS);
737 			c->cdce_buf = usbd_alloc_buffer(c->cdce_xfer,
738 			    CDCE_BUFSZ);
739 			if (c->cdce_buf == NULL)
740 				return (ENOBUFS);
741 		}
742 	}
743 
744 	return (0);
745 }
746 
747 void
748 cdce_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
749 {
750 	struct cdce_chain	*c = priv;
751 	struct cdce_softc	*sc = c->cdce_sc;
752 	struct ifnet		*ifp = GET_IFP(sc);
753 	struct mbuf		*m;
754 	int			 total_len = 0;
755 	int			 s;
756 
757 	if (sc->cdce_dying || !(ifp->if_flags & IFF_RUNNING))
758 		return;
759 
760 	if (status != USBD_NORMAL_COMPLETION) {
761 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
762 			return;
763 		if (sc->cdce_rxeof_errors == 0)
764 			printf("%s: usb error on rx: %s\n",
765 			    sc->cdce_dev.dv_xname, usbd_errstr(status));
766 		if (status == USBD_STALLED)
767 			usbd_clear_endpoint_stall_async(sc->cdce_bulkin_pipe);
768 		DELAY(sc->cdce_rxeof_errors * 10000);
769 		if (sc->cdce_rxeof_errors++ > 10) {
770 			printf("%s: too many errors, disabling\n",
771 			    sc->cdce_dev.dv_xname);
772 			sc->cdce_dying = 1;
773 			return;
774 		}
775 		goto done;
776 	}
777 
778 	sc->cdce_rxeof_errors = 0;
779 
780 	usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
781 	if (sc->cdce_flags & CDCE_ZAURUS)
782 		total_len -= 4;	/* Strip off CRC added by Zaurus */
783 	if (total_len <= 1)
784 		goto done;
785 
786 	m = c->cdce_mbuf;
787 	memcpy(mtod(m, char *), c->cdce_buf, total_len);
788 
789 	if (total_len < sizeof(struct ether_header)) {
790 		ifp->if_ierrors++;
791 		goto done;
792 	}
793 
794 	ifp->if_ipackets++;
795 
796 	m->m_pkthdr.len = m->m_len = total_len;
797 	m->m_pkthdr.rcvif = ifp;
798 
799 	s = splnet();
800 
801 	if (cdce_newbuf(sc, c, NULL) == ENOBUFS) {
802 		ifp->if_ierrors++;
803 		goto done1;
804 	}
805 
806 #if NBPFILTER > 0
807 	if (ifp->if_bpf)
808 		bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
809 #endif
810 
811 	ether_input_mbuf(ifp, m);
812 
813 done1:
814 	splx(s);
815 
816 done:
817 	/* Setup new transfer. */
818 	usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkin_pipe, c, c->cdce_buf,
819 	    CDCE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
820 	    cdce_rxeof);
821 	usbd_transfer(c->cdce_xfer);
822 }
823 
824 void
825 cdce_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
826 {
827 	struct cdce_chain	*c = priv;
828 	struct cdce_softc	*sc = c->cdce_sc;
829 	struct ifnet		*ifp = GET_IFP(sc);
830 	usbd_status		 err;
831 	int			 s;
832 
833 	if (sc->cdce_dying)
834 		return;
835 
836 	s = splnet();
837 
838 	ifp->if_timer = 0;
839 	ifp->if_flags &= ~IFF_OACTIVE;
840 
841 	if (status != USBD_NORMAL_COMPLETION) {
842 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
843 			splx(s);
844 			return;
845 		}
846 		ifp->if_oerrors++;
847 		printf("%s: usb error on tx: %s\n", sc->cdce_dev.dv_xname,
848 		    usbd_errstr(status));
849 		if (status == USBD_STALLED)
850 			usbd_clear_endpoint_stall_async(sc->cdce_bulkout_pipe);
851 		splx(s);
852 		return;
853 	}
854 
855 	usbd_get_xfer_status(c->cdce_xfer, NULL, NULL, NULL, &err);
856 
857 	if (c->cdce_mbuf != NULL) {
858 		m_freem(c->cdce_mbuf);
859 		c->cdce_mbuf = NULL;
860 	}
861 
862 	if (err)
863 		ifp->if_oerrors++;
864 	else
865 		ifp->if_opackets++;
866 
867 	if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
868 		cdce_start(ifp);
869 
870 	splx(s);
871 }
872 
873 int
874 cdce_activate(struct device *self, enum devact act)
875 {
876 	struct cdce_softc *sc = (struct cdce_softc *)self;
877 
878 	switch (act) {
879 	case DVACT_ACTIVATE:
880 		break;
881 
882 	case DVACT_DEACTIVATE:
883 		sc->cdce_dying = 1;
884 		break;
885 	}
886 	return (0);
887 }
888 
889 void
890 cdce_intr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status)
891 {
892 	struct cdce_softc	*sc = addr;
893 	usb_cdc_notification_t	*buf = &sc->cdce_intr_buf;
894 	usb_cdc_connection_speed_t	*speed;
895 	u_int32_t		 count;
896 
897 	if (status == USBD_CANCELLED)
898 		return;
899 
900 	if (status != USBD_NORMAL_COMPLETION) {
901 		DPRINTFN(2, ("cdce_intr: status=%d\n", status));
902 		if (status == USBD_STALLED)
903 			usbd_clear_endpoint_stall_async(sc->cdce_intr_pipe);
904 		return;
905 	}
906 
907 	usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
908 
909 	if (buf->bmRequestType == UCDC_NOTIFICATION) {
910 		switch (buf->bNotification) {
911 		case UCDC_N_NETWORK_CONNECTION:
912 			DPRINTFN(1, ("cdce_intr: network %s\n",
913 			    UGETW(buf->wValue) ? "connected" : "disconnected"));
914 			break;
915 		case UCDC_N_CONNECTION_SPEED_CHANGE:
916 			speed = (usb_cdc_connection_speed_t *)&buf->data;
917 			DPRINTFN(1, ("cdce_intr: up=%d, down=%d\n",
918 			    UGETDW(speed->dwUSBitRate),
919 			    UGETDW(speed->dwDSBitRate)));
920 			break;
921 		default:
922 			DPRINTF(("cdce_intr: bNotification 0x%x\n",
923 			    buf->bNotification));
924 		}
925 	}
926 #ifdef CDCE_DEBUG
927 	else {
928 		printf("cdce_intr: bmRequestType=%d ", buf->bmRequestType);
929 		printf("wValue=%d wIndex=%d wLength=%d\n", UGETW(buf->wValue),
930 		    UGETW(buf->wIndex), UGETW(buf->wLength));
931 	}
932 #endif
933 }
934 
935 
936 /*  COPYRIGHT (C) 1986 Gary S. Brown.  You may use this program, or
937  *  code or tables extracted from it, as desired without restriction.
938  */
939 
940 static uint32_t cdce_crc32_tab[] = {
941 	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
942 	0xe963a535, 0x9e6495a3,	0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
943 	0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
944 	0xf3b97148, 0x84be41de,	0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
945 	0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,	0x14015c4f, 0x63066cd9,
946 	0xfa0f3d63, 0x8d080df5,	0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
947 	0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,	0x35b5a8fa, 0x42b2986c,
948 	0xdbbbc9d6, 0xacbcf940,	0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
949 	0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
950 	0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
951 	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,	0x76dc4190, 0x01db7106,
952 	0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
953 	0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
954 	0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
955 	0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
956 	0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
957 	0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
958 	0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
959 	0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
960 	0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
961 	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
962 	0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
963 	0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
964 	0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
965 	0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
966 	0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
967 	0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
968 	0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
969 	0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
970 	0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
971 	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
972 	0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
973 	0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
974 	0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
975 	0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
976 	0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
977 	0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
978 	0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
979 	0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
980 	0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
981 	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
982 	0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
983 	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
984 };
985 
986 uint32_t
987 cdce_crc32(const void *buf, size_t size)
988 {
989 	const uint8_t *p;
990 	uint32_t crc;
991 
992 	p = buf;
993 	crc = ~0U;
994 
995 	while (size--)
996 		crc = cdce_crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
997 
998 	return (htole32(crc) ^ ~0U);
999 }
1000