if_cdce.c revision 1.28 1 /* $NetBSD: if_cdce.c,v 1.28 2010/04/05 07:21:48 joerg Exp $ */
2
3 /*
4 * Copyright (c) 1997, 1998, 1999, 2000-2003 Bill Paul <wpaul (at) windriver.com>
5 * Copyright (c) 2003 Craig Boston
6 * Copyright (c) 2004 Daniel Hartmeier
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by Bill Paul.
20 * 4. Neither the name of the author nor the names of any co-contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul, THE VOICES IN HIS HEAD OR
28 * THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
30 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
31 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
32 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
33 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
34 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 */
36
37 /*
38 * USB Communication Device Class (Ethernet Networking Control Model)
39 * http://www.usb.org/developers/devclass_docs/usbcdc11.pdf
40 *
41 */
42
43 #include <sys/cdefs.h>
44 __KERNEL_RCSID(0, "$NetBSD: if_cdce.c,v 1.28 2010/04/05 07:21:48 joerg Exp $");
45 #ifdef __NetBSD__
46 #include "opt_inet.h"
47 #endif
48
49 #include <sys/param.h>
50 #include <sys/systm.h>
51 #include <sys/sockio.h>
52 #include <sys/mbuf.h>
53 #include <sys/malloc.h>
54 #include <sys/kernel.h>
55 #include <sys/socket.h>
56 #include <sys/device.h>
57
58 #if NRND > 0
59 #include <sys/rnd.h>
60 #endif
61
62 #include <net/if.h>
63 #include <net/if_arp.h>
64 #include <net/if_dl.h>
65 #include <net/if_media.h>
66
67 #include <net/bpf.h>
68
69 #include <net/if_ether.h>
70 #ifdef INET
71 #include <netinet/in.h>
72 #include <netinet/if_inarp.h>
73 #endif
74
75
76
77 #include <dev/usb/usb.h>
78 #include <dev/usb/usbdi.h>
79 #include <dev/usb/usbdi_util.h>
80 #include <dev/usb/usbdevs.h>
81 #include <dev/usb/usbcdc.h>
82
83 #include <dev/usb/if_cdcereg.h>
84
85 Static int cdce_tx_list_init(struct cdce_softc *);
86 Static int cdce_rx_list_init(struct cdce_softc *);
87 Static int cdce_newbuf(struct cdce_softc *, struct cdce_chain *,
88 struct mbuf *);
89 Static int cdce_encap(struct cdce_softc *, struct mbuf *, int);
90 Static void cdce_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
91 Static void cdce_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
92 Static void cdce_start(struct ifnet *);
93 Static int cdce_ioctl(struct ifnet *, u_long, void *);
94 Static void cdce_init(void *);
95 Static void cdce_watchdog(struct ifnet *);
96 Static void cdce_stop(struct cdce_softc *);
97 Static uint32_t cdce_crc32(const void *, size_t);
98
99 Static const struct cdce_type cdce_devs[] = {
100 {{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2501 }, CDCE_NO_UNION },
101 {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5500 }, CDCE_ZAURUS },
102 {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_A300 }, CDCE_ZAURUS | CDCE_NO_UNION },
103 {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5600 }, CDCE_ZAURUS | CDCE_NO_UNION },
104 {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_C700 }, CDCE_ZAURUS | CDCE_NO_UNION },
105 {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_C750 }, CDCE_ZAURUS | CDCE_NO_UNION },
106 };
107 #define cdce_lookup(v, p) ((const struct cdce_type *)usb_lookup(cdce_devs, v, p))
108
109 int cdce_match(device_t, cfdata_t, void *);
110 void cdce_attach(device_t, device_t, void *);
111 int cdce_detach(device_t, int);
112 int cdce_activate(device_t, enum devact);
113 extern struct cfdriver cdce_cd;
114 CFATTACH_DECL_NEW(cdce, sizeof(struct cdce_softc), cdce_match, cdce_attach,
115 cdce_detach, cdce_activate);
116
117 int
118 cdce_match(device_t parent, cfdata_t match, void *aux)
119 {
120 struct usbif_attach_arg *uaa = aux;
121
122 if (cdce_lookup(uaa->vendor, uaa->product) != NULL)
123 return (UMATCH_VENDOR_PRODUCT);
124
125 if (uaa->class == UICLASS_CDC && uaa->subclass ==
126 UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL)
127 return (UMATCH_IFACECLASS_GENERIC);
128
129 return (UMATCH_NONE);
130 }
131
132 void
133 cdce_attach(device_t parent, device_t self, void *aux)
134 {
135 struct cdce_softc *sc = device_private(self);
136 struct usbif_attach_arg *uaa = aux;
137 char *devinfop;
138 int s;
139 struct ifnet *ifp;
140 usbd_device_handle dev = uaa->device;
141 const struct cdce_type *t;
142 usb_interface_descriptor_t *id;
143 usb_endpoint_descriptor_t *ed;
144 const usb_cdc_union_descriptor_t *ud;
145 usb_config_descriptor_t *cd;
146 int data_ifcno;
147 int i, j, numalts;
148 u_char eaddr[ETHER_ADDR_LEN];
149 const usb_cdc_ethernet_descriptor_t *ue;
150 char eaddr_str[USB_MAX_ENCODED_STRING_LEN];
151
152 sc->cdce_dev = self;
153
154 aprint_naive("\n");
155 aprint_normal("\n");
156
157 devinfop = usbd_devinfo_alloc(dev, 0);
158 aprint_normal_dev(self, "%s\n", devinfop);
159 usbd_devinfo_free(devinfop);
160
161 sc->cdce_udev = uaa->device;
162 sc->cdce_ctl_iface = uaa->iface;
163
164 t = cdce_lookup(uaa->vendor, uaa->product);
165 if (t)
166 sc->cdce_flags = t->cdce_flags;
167
168 if (sc->cdce_flags & CDCE_NO_UNION)
169 sc->cdce_data_iface = sc->cdce_ctl_iface;
170 else {
171 ud = (const usb_cdc_union_descriptor_t *)usb_find_desc(sc->cdce_udev,
172 UDESC_CS_INTERFACE, UDESCSUB_CDC_UNION);
173 if (ud == NULL) {
174 aprint_error_dev(self, "no union descriptor\n");
175 return;
176 }
177 data_ifcno = ud->bSlaveInterface[0];
178
179 for (i = 0; i < uaa->nifaces; i++) {
180 if (uaa->ifaces[i] != NULL) {
181 id = usbd_get_interface_descriptor(
182 uaa->ifaces[i]);
183 if (id != NULL && id->bInterfaceNumber ==
184 data_ifcno) {
185 sc->cdce_data_iface = uaa->ifaces[i];
186 uaa->ifaces[i] = NULL;
187 }
188 }
189 }
190 }
191
192 if (sc->cdce_data_iface == NULL) {
193 aprint_error_dev(self, "no data interface\n");
194 return;
195 }
196
197 /*
198 * <quote>
199 * The Data Class interface of a networking device shall have a minimum
200 * of two interface settings. The first setting (the default interface
201 * setting) includes no endpoints and therefore no networking traffic is
202 * exchanged whenever the default interface setting is selected. One or
203 * more additional interface settings are used for normal operation, and
204 * therefore each includes a pair of endpoints (one IN, and one OUT) to
205 * exchange network traffic. Select an alternate interface setting to
206 * initialize the network aspects of the device and to enable the
207 * exchange of network traffic.
208 * </quote>
209 *
210 * Some devices, most notably cable modems, include interface settings
211 * that have no IN or OUT endpoint, therefore loop through the list of all
212 * available interface settings looking for one with both IN and OUT
213 * endpoints.
214 */
215 id = usbd_get_interface_descriptor(sc->cdce_data_iface);
216 cd = usbd_get_config_descriptor(sc->cdce_udev);
217 numalts = usbd_get_no_alts(cd, id->bInterfaceNumber);
218
219 for (j = 0; j < numalts; j++) {
220 if (usbd_set_interface(sc->cdce_data_iface, j)) {
221 aprint_error_dev(sc->cdce_dev,
222 "setting alternate interface failed\n");
223 return;
224 }
225 /* Find endpoints. */
226 id = usbd_get_interface_descriptor(sc->cdce_data_iface);
227 sc->cdce_bulkin_no = sc->cdce_bulkout_no = -1;
228 for (i = 0; i < id->bNumEndpoints; i++) {
229 ed = usbd_interface2endpoint_descriptor(sc->cdce_data_iface, i);
230 if (!ed) {
231 aprint_error_dev(self,
232 "could not read endpoint descriptor\n");
233 return;
234 }
235 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
236 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
237 sc->cdce_bulkin_no = ed->bEndpointAddress;
238 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
239 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
240 sc->cdce_bulkout_no = ed->bEndpointAddress;
241 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
242 UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
243 /* XXX: CDC spec defines an interrupt pipe, but it is not
244 * needed for simple host-to-host applications. */
245 } else {
246 aprint_error_dev(self, "unexpected endpoint\n");
247 }
248 }
249 /* If we found something, try and use it... */
250 if ((sc->cdce_bulkin_no != -1) && (sc->cdce_bulkout_no != -1))
251 break;
252 }
253
254 if (sc->cdce_bulkin_no == -1) {
255 aprint_error_dev(self, "could not find data bulk in\n");
256 return;
257 }
258 if (sc->cdce_bulkout_no == -1 ) {
259 aprint_error_dev(self, "could not find data bulk out\n");
260 return;
261 }
262
263 ue = (const usb_cdc_ethernet_descriptor_t *)usb_find_desc(dev,
264 UDESC_INTERFACE, UDESCSUB_CDC_ENF);
265 if (!ue || usbd_get_string(dev, ue->iMacAddress, eaddr_str)) {
266 aprint_normal_dev(self, "faking address\n");
267 eaddr[0]= 0x2a;
268 memcpy(&eaddr[1], &hardclock_ticks, sizeof(u_int32_t));
269 eaddr[5] = (u_int8_t)(device_unit(sc->cdce_dev));
270 } else {
271 (void)ether_nonstatic_aton(eaddr, eaddr_str);
272 }
273
274 s = splnet();
275
276 aprint_normal_dev(self, "address %s\n", ether_sprintf(eaddr));
277
278 ifp = GET_IFP(sc);
279 ifp->if_softc = sc;
280 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
281 ifp->if_ioctl = cdce_ioctl;
282 ifp->if_start = cdce_start;
283 ifp->if_watchdog = cdce_watchdog;
284 strncpy(ifp->if_xname, device_xname(sc->cdce_dev), IFNAMSIZ);
285
286 IFQ_SET_READY(&ifp->if_snd);
287
288 if_attach(ifp);
289 ether_ifattach(ifp, eaddr);
290
291 sc->cdce_attached = 1;
292 splx(s);
293
294 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->cdce_udev,
295 sc->cdce_dev);
296
297 return;
298 }
299
300 int
301 cdce_detach(device_t self, int flags)
302 {
303 struct cdce_softc *sc = device_private(self);
304 struct ifnet *ifp = GET_IFP(sc);
305 int s;
306
307 s = splusb();
308
309 if (!sc->cdce_attached) {
310 splx(s);
311 return (0);
312 }
313
314 if (ifp->if_flags & IFF_RUNNING)
315 cdce_stop(sc);
316
317 ether_ifdetach(ifp);
318
319 if_detach(ifp);
320
321 sc->cdce_attached = 0;
322 splx(s);
323
324 return (0);
325 }
326
327 Static void
328 cdce_start(struct ifnet *ifp)
329 {
330 struct cdce_softc *sc = ifp->if_softc;
331 struct mbuf *m_head = NULL;
332
333 if (sc->cdce_dying || (ifp->if_flags & IFF_OACTIVE))
334 return;
335
336 IFQ_POLL(&ifp->if_snd, m_head);
337 if (m_head == NULL)
338 return;
339
340 if (cdce_encap(sc, m_head, 0)) {
341 ifp->if_flags |= IFF_OACTIVE;
342 return;
343 }
344
345 IFQ_DEQUEUE(&ifp->if_snd, m_head);
346
347 bpf_mtap(ifp, m_head);
348
349 ifp->if_flags |= IFF_OACTIVE;
350
351 ifp->if_timer = 6;
352 }
353
354 Static int
355 cdce_encap(struct cdce_softc *sc, struct mbuf *m, int idx)
356 {
357 struct cdce_chain *c;
358 usbd_status err;
359 int extra = 0;
360
361 c = &sc->cdce_cdata.cdce_tx_chain[idx];
362
363 m_copydata(m, 0, m->m_pkthdr.len, c->cdce_buf);
364 if (sc->cdce_flags & CDCE_ZAURUS) {
365 /* Zaurus wants a 32-bit CRC appended to every frame */
366 u_int32_t crc;
367
368 crc = cdce_crc32(c->cdce_buf, m->m_pkthdr.len);
369 memcpy(c->cdce_buf + m->m_pkthdr.len, &crc, 4);
370 extra = 4;
371 }
372 c->cdce_mbuf = m;
373
374 usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkout_pipe, c, c->cdce_buf,
375 m->m_pkthdr.len + extra, USBD_NO_COPY, 10000, cdce_txeof);
376 err = usbd_transfer(c->cdce_xfer);
377 if (err != USBD_IN_PROGRESS) {
378 cdce_stop(sc);
379 return (EIO);
380 }
381
382 sc->cdce_cdata.cdce_tx_cnt++;
383
384 return (0);
385 }
386
387 Static void
388 cdce_stop(struct cdce_softc *sc)
389 {
390 usbd_status err;
391 struct ifnet *ifp = GET_IFP(sc);
392 int i;
393
394 ifp->if_timer = 0;
395
396 if (sc->cdce_bulkin_pipe != NULL) {
397 err = usbd_abort_pipe(sc->cdce_bulkin_pipe);
398 if (err)
399 printf("%s: abort rx pipe failed: %s\n",
400 device_xname(sc->cdce_dev), usbd_errstr(err));
401 err = usbd_close_pipe(sc->cdce_bulkin_pipe);
402 if (err)
403 printf("%s: close rx pipe failed: %s\n",
404 device_xname(sc->cdce_dev), usbd_errstr(err));
405 sc->cdce_bulkin_pipe = NULL;
406 }
407
408 if (sc->cdce_bulkout_pipe != NULL) {
409 err = usbd_abort_pipe(sc->cdce_bulkout_pipe);
410 if (err)
411 printf("%s: abort tx pipe failed: %s\n",
412 device_xname(sc->cdce_dev), usbd_errstr(err));
413 err = usbd_close_pipe(sc->cdce_bulkout_pipe);
414 if (err)
415 printf("%s: close tx pipe failed: %s\n",
416 device_xname(sc->cdce_dev), usbd_errstr(err));
417 sc->cdce_bulkout_pipe = NULL;
418 }
419
420 for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
421 if (sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf != NULL) {
422 m_freem(sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf);
423 sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf = NULL;
424 }
425 if (sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer != NULL) {
426 usbd_free_xfer(sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer);
427 sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer = NULL;
428 }
429 }
430
431 for (i = 0; i < CDCE_TX_LIST_CNT; i++) {
432 if (sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf != NULL) {
433 m_freem(sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf);
434 sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf = NULL;
435 }
436 if (sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer != NULL) {
437 usbd_free_xfer(sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer);
438 sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer = NULL;
439 }
440 }
441
442 ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
443 }
444
445 Static int
446 cdce_ioctl(struct ifnet *ifp, u_long command, void *data)
447 {
448 struct cdce_softc *sc = ifp->if_softc;
449 struct ifaddr *ifa = (struct ifaddr *)data;
450 struct ifreq *ifr = (struct ifreq *)data;
451 int s, error = 0;
452
453 if (sc->cdce_dying)
454 return (EIO);
455
456 s = splnet();
457
458 switch(command) {
459 case SIOCINITIFADDR:
460 ifp->if_flags |= IFF_UP;
461 cdce_init(sc);
462 switch (ifa->ifa_addr->sa_family) {
463 #ifdef INET
464 case AF_INET:
465 arp_ifinit(ifp, ifa);
466 break;
467 #endif /* INET */
468 }
469 break;
470
471 case SIOCSIFMTU:
472 if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ETHERMTU)
473 error = EINVAL;
474 else if ((error = ifioctl_common(ifp, command, data)) == ENETRESET)
475 error = 0;
476 break;
477
478 case SIOCSIFFLAGS:
479 if ((error = ifioctl_common(ifp, command, data)) != 0)
480 break;
481 /* XXX re-use ether_ioctl() */
482 switch (ifp->if_flags & (IFF_UP|IFF_RUNNING)) {
483 case IFF_UP:
484 cdce_init(sc);
485 break;
486 case IFF_RUNNING:
487 cdce_stop(sc);
488 break;
489 default:
490 break;
491 }
492 break;
493
494 default:
495 error = ether_ioctl(ifp, command, data);
496 break;
497 }
498
499 splx(s);
500
501 return (error);
502 }
503
504 Static void
505 cdce_watchdog(struct ifnet *ifp)
506 {
507 struct cdce_softc *sc = ifp->if_softc;
508
509 if (sc->cdce_dying)
510 return;
511
512 ifp->if_oerrors++;
513 printf("%s: watchdog timeout\n", device_xname(sc->cdce_dev));
514 }
515
516 Static void
517 cdce_init(void *xsc)
518 {
519 struct cdce_softc *sc = xsc;
520 struct ifnet *ifp = GET_IFP(sc);
521 struct cdce_chain *c;
522 usbd_status err;
523 int s, i;
524
525 if (ifp->if_flags & IFF_RUNNING)
526 return;
527
528 s = splnet();
529
530 if (cdce_tx_list_init(sc) == ENOBUFS) {
531 printf("%s: tx list init failed\n", device_xname(sc->cdce_dev));
532 splx(s);
533 return;
534 }
535
536 if (cdce_rx_list_init(sc) == ENOBUFS) {
537 printf("%s: rx list init failed\n", device_xname(sc->cdce_dev));
538 splx(s);
539 return;
540 }
541
542 /* Maybe set multicast / broadcast here??? */
543
544 err = usbd_open_pipe(sc->cdce_data_iface, sc->cdce_bulkin_no,
545 USBD_EXCLUSIVE_USE, &sc->cdce_bulkin_pipe);
546 if (err) {
547 printf("%s: open rx pipe failed: %s\n", device_xname(sc->cdce_dev),
548 usbd_errstr(err));
549 splx(s);
550 return;
551 }
552
553 err = usbd_open_pipe(sc->cdce_data_iface, sc->cdce_bulkout_no,
554 USBD_EXCLUSIVE_USE, &sc->cdce_bulkout_pipe);
555 if (err) {
556 printf("%s: open tx pipe failed: %s\n",
557 device_xname(sc->cdce_dev), usbd_errstr(err));
558 splx(s);
559 return;
560 }
561
562 for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
563 c = &sc->cdce_cdata.cdce_rx_chain[i];
564 usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkin_pipe, c,
565 c->cdce_buf, CDCE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
566 USBD_NO_TIMEOUT, cdce_rxeof);
567 usbd_transfer(c->cdce_xfer);
568 }
569
570 ifp->if_flags |= IFF_RUNNING;
571 ifp->if_flags &= ~IFF_OACTIVE;
572
573 splx(s);
574 }
575
576 Static int
577 cdce_newbuf(struct cdce_softc *sc, struct cdce_chain *c, struct mbuf *m)
578 {
579 struct mbuf *m_new = NULL;
580
581 if (m == NULL) {
582 MGETHDR(m_new, M_DONTWAIT, MT_DATA);
583 if (m_new == NULL) {
584 printf("%s: no memory for rx list "
585 "-- packet dropped!\n", device_xname(sc->cdce_dev));
586 return (ENOBUFS);
587 }
588 MCLGET(m_new, M_DONTWAIT);
589 if (!(m_new->m_flags & M_EXT)) {
590 printf("%s: no memory for rx list "
591 "-- packet dropped!\n", device_xname(sc->cdce_dev));
592 m_freem(m_new);
593 return (ENOBUFS);
594 }
595 m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
596 } else {
597 m_new = m;
598 m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
599 m_new->m_data = m_new->m_ext.ext_buf;
600 }
601 c->cdce_mbuf = m_new;
602 return (0);
603 }
604
605 Static int
606 cdce_rx_list_init(struct cdce_softc *sc)
607 {
608 struct cdce_cdata *cd;
609 struct cdce_chain *c;
610 int i;
611
612 cd = &sc->cdce_cdata;
613 for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
614 c = &cd->cdce_rx_chain[i];
615 c->cdce_sc = sc;
616 c->cdce_idx = i;
617 if (cdce_newbuf(sc, c, NULL) == ENOBUFS)
618 return (ENOBUFS);
619 if (c->cdce_xfer == NULL) {
620 c->cdce_xfer = usbd_alloc_xfer(sc->cdce_udev);
621 if (c->cdce_xfer == NULL)
622 return (ENOBUFS);
623 c->cdce_buf = usbd_alloc_buffer(c->cdce_xfer, CDCE_BUFSZ);
624 if (c->cdce_buf == NULL)
625 return (ENOBUFS);
626 }
627 }
628
629 return (0);
630 }
631
632 Static int
633 cdce_tx_list_init(struct cdce_softc *sc)
634 {
635 struct cdce_cdata *cd;
636 struct cdce_chain *c;
637 int i;
638
639 cd = &sc->cdce_cdata;
640 for (i = 0; i < CDCE_TX_LIST_CNT; i++) {
641 c = &cd->cdce_tx_chain[i];
642 c->cdce_sc = sc;
643 c->cdce_idx = i;
644 c->cdce_mbuf = NULL;
645 if (c->cdce_xfer == NULL) {
646 c->cdce_xfer = usbd_alloc_xfer(sc->cdce_udev);
647 if (c->cdce_xfer == NULL)
648 return (ENOBUFS);
649 c->cdce_buf = usbd_alloc_buffer(c->cdce_xfer, CDCE_BUFSZ);
650 if (c->cdce_buf == NULL)
651 return (ENOBUFS);
652 }
653 }
654
655 return (0);
656 }
657
658 Static void
659 cdce_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
660 {
661 struct cdce_chain *c = priv;
662 struct cdce_softc *sc = c->cdce_sc;
663 struct ifnet *ifp = GET_IFP(sc);
664 struct mbuf *m;
665 int total_len = 0;
666 int s;
667
668 if (sc->cdce_dying || !(ifp->if_flags & IFF_RUNNING))
669 return;
670
671 if (status != USBD_NORMAL_COMPLETION) {
672 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
673 return;
674 if (sc->cdce_rxeof_errors == 0)
675 printf("%s: usb error on rx: %s\n",
676 device_xname(sc->cdce_dev), usbd_errstr(status));
677 if (status == USBD_STALLED)
678 usbd_clear_endpoint_stall_async(sc->cdce_bulkin_pipe);
679 DELAY(sc->cdce_rxeof_errors * 10000);
680 sc->cdce_rxeof_errors++;
681 goto done;
682 }
683
684 sc->cdce_rxeof_errors = 0;
685
686 usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
687 if (sc->cdce_flags & CDCE_ZAURUS)
688 total_len -= 4; /* Strip off CRC added by Zaurus */
689 if (total_len <= 1)
690 goto done;
691
692 m = c->cdce_mbuf;
693 memcpy(mtod(m, char *), c->cdce_buf, total_len);
694
695 if (total_len < sizeof(struct ether_header)) {
696 ifp->if_ierrors++;
697 goto done;
698 }
699
700 ifp->if_ipackets++;
701 m->m_pkthdr.len = m->m_len = total_len;
702 m->m_pkthdr.rcvif = ifp;
703
704 s = splnet();
705
706 if (cdce_newbuf(sc, c, NULL) == ENOBUFS) {
707 ifp->if_ierrors++;
708 goto done1;
709 }
710
711 bpf_mtap(ifp, m);
712
713 (*(ifp)->if_input)((ifp), (m));
714
715 done1:
716 splx(s);
717
718 done:
719 /* Setup new transfer. */
720 usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkin_pipe, c, c->cdce_buf,
721 CDCE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
722 cdce_rxeof);
723 usbd_transfer(c->cdce_xfer);
724 }
725
726 Static void
727 cdce_txeof(usbd_xfer_handle xfer, usbd_private_handle priv,
728 usbd_status status)
729 {
730 struct cdce_chain *c = priv;
731 struct cdce_softc *sc = c->cdce_sc;
732 struct ifnet *ifp = GET_IFP(sc);
733 usbd_status err;
734 int s;
735
736 if (sc->cdce_dying)
737 return;
738
739 s = splnet();
740
741 ifp->if_timer = 0;
742 ifp->if_flags &= ~IFF_OACTIVE;
743
744 if (status != USBD_NORMAL_COMPLETION) {
745 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
746 splx(s);
747 return;
748 }
749 ifp->if_oerrors++;
750 printf("%s: usb error on tx: %s\n", device_xname(sc->cdce_dev),
751 usbd_errstr(status));
752 if (status == USBD_STALLED)
753 usbd_clear_endpoint_stall_async(sc->cdce_bulkout_pipe);
754 splx(s);
755 return;
756 }
757
758 usbd_get_xfer_status(c->cdce_xfer, NULL, NULL, NULL, &err);
759
760 if (c->cdce_mbuf != NULL) {
761 m_freem(c->cdce_mbuf);
762 c->cdce_mbuf = NULL;
763 }
764
765 if (err)
766 ifp->if_oerrors++;
767 else
768 ifp->if_opackets++;
769
770 if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
771 cdce_start(ifp);
772
773 splx(s);
774 }
775
776 int
777 cdce_activate(device_t self, enum devact act)
778 {
779 struct cdce_softc *sc = device_private(self);
780
781 switch (act) {
782 case DVACT_DEACTIVATE:
783 if_deactivate(GET_IFP(sc));
784 sc->cdce_dying = 1;
785 return 0;
786 default:
787 return EOPNOTSUPP;
788 }
789 }
790
791
792 /* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
793 * code or tables extracted from it, as desired without restriction.
794 */
795
796 static uint32_t cdce_crc32_tab[] = {
797 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
798 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
799 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
800 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
801 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
802 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
803 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
804 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
805 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
806 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
807 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
808 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
809 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
810 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
811 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
812 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
813 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
814 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
815 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
816 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
817 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
818 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
819 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
820 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
821 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
822 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
823 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
824 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
825 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
826 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
827 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
828 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
829 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
830 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
831 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
832 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
833 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
834 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
835 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
836 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
837 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
838 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
839 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
840 };
841
842 Static uint32_t
843 cdce_crc32(const void *buf, size_t size)
844 {
845 const uint8_t *p;
846 uint32_t crc;
847
848 p = buf;
849 crc = ~0U;
850
851 while (size--)
852 crc = cdce_crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
853
854 return (crc ^ ~0U);
855 }
856