if_cdce.c revision 1.15.10.4 1 /* $NetBSD: if_cdce.c,v 1.15.10.4 2010/03/11 15:04:05 yamt 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 __KERNEL_RCSID(0, "$NetBSD: if_cdce.c,v 1.15.10.4 2010/03/11 15:04:05 yamt Exp $");
44 #ifdef __NetBSD__
45 #include "opt_inet.h"
46 #endif
47
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/sockio.h>
51 #include <sys/mbuf.h>
52 #include <sys/malloc.h>
53 #include <sys/kernel.h>
54 #include <sys/socket.h>
55 #include <sys/device.h>
56
57 #if NRND > 0
58 #include <sys/rnd.h>
59 #endif
60
61 #include <net/if.h>
62 #include <net/if_arp.h>
63 #include <net/if_dl.h>
64 #include <net/if_media.h>
65
66 #include <net/bpf.h>
67
68 #include <net/if_ether.h>
69 #ifdef INET
70 #include <netinet/in.h>
71 #include <netinet/if_inarp.h>
72 #endif
73
74
75
76 #include <dev/usb/usb.h>
77 #include <dev/usb/usbdi.h>
78 #include <dev/usb/usbdi_util.h>
79 #include <dev/usb/usbdevs.h>
80 #include <dev/usb/usbcdc.h>
81
82 #include <dev/usb/if_cdcereg.h>
83
84 Static int cdce_tx_list_init(struct cdce_softc *);
85 Static int cdce_rx_list_init(struct cdce_softc *);
86 Static int cdce_newbuf(struct cdce_softc *, struct cdce_chain *,
87 struct mbuf *);
88 Static int cdce_encap(struct cdce_softc *, struct mbuf *, int);
89 Static void cdce_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
90 Static void cdce_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
91 Static void cdce_start(struct ifnet *);
92 Static int cdce_ioctl(struct ifnet *, u_long, void *);
93 Static void cdce_init(void *);
94 Static void cdce_watchdog(struct ifnet *);
95 Static void cdce_stop(struct cdce_softc *);
96 Static uint32_t cdce_crc32(const void *, size_t);
97
98 Static const struct cdce_type cdce_devs[] = {
99 {{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2501 }, CDCE_NO_UNION },
100 {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5500 }, CDCE_ZAURUS },
101 {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_A300 }, CDCE_ZAURUS | CDCE_NO_UNION },
102 {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5600 }, CDCE_ZAURUS | CDCE_NO_UNION },
103 {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_C700 }, CDCE_ZAURUS | CDCE_NO_UNION },
104 {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_C750 }, CDCE_ZAURUS | CDCE_NO_UNION },
105 };
106 #define cdce_lookup(v, p) ((const struct cdce_type *)usb_lookup(cdce_devs, v, p))
107
108 int cdce_match(device_t, cfdata_t, void *);
109 void cdce_attach(device_t, device_t, void *);
110 int cdce_detach(device_t, int);
111 int cdce_activate(device_t, enum devact);
112 extern struct cfdriver cdce_cd;
113 CFATTACH_DECL_NEW(cdce, sizeof(struct cdce_softc), cdce_match, cdce_attach,
114 cdce_detach, cdce_activate);
115
116 int
117 cdce_match(device_t parent, cfdata_t match, void *aux)
118 {
119 struct usbif_attach_arg *uaa = aux;
120
121 if (cdce_lookup(uaa->vendor, uaa->product) != NULL)
122 return (UMATCH_VENDOR_PRODUCT);
123
124 if (uaa->class == UICLASS_CDC && uaa->subclass ==
125 UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL)
126 return (UMATCH_IFACECLASS_GENERIC);
127
128 return (UMATCH_NONE);
129 }
130
131 void
132 cdce_attach(device_t parent, device_t self, void *aux)
133 {
134 struct cdce_softc *sc = device_private(self);
135 struct usbif_attach_arg *uaa = aux;
136 char *devinfop;
137 int s;
138 struct ifnet *ifp;
139 usbd_device_handle dev = uaa->device;
140 const struct cdce_type *t;
141 usb_interface_descriptor_t *id;
142 usb_endpoint_descriptor_t *ed;
143 const usb_cdc_union_descriptor_t *ud;
144 usb_config_descriptor_t *cd;
145 int data_ifcno;
146 int i, j, numalts;
147 u_char eaddr[ETHER_ADDR_LEN];
148 const usb_cdc_ethernet_descriptor_t *ue;
149 char eaddr_str[USB_MAX_ENCODED_STRING_LEN];
150
151 sc->cdce_dev = self;
152
153 aprint_naive("\n");
154 aprint_normal("\n");
155
156 devinfop = usbd_devinfo_alloc(dev, 0);
157 aprint_normal_dev(self, "%s\n", devinfop);
158 usbd_devinfo_free(devinfop);
159
160 sc->cdce_udev = uaa->device;
161 sc->cdce_ctl_iface = uaa->iface;
162
163 t = cdce_lookup(uaa->vendor, uaa->product);
164 if (t)
165 sc->cdce_flags = t->cdce_flags;
166
167 if (sc->cdce_flags & CDCE_NO_UNION)
168 sc->cdce_data_iface = sc->cdce_ctl_iface;
169 else {
170 ud = (const usb_cdc_union_descriptor_t *)usb_find_desc(sc->cdce_udev,
171 UDESC_CS_INTERFACE, UDESCSUB_CDC_UNION);
172 if (ud == NULL) {
173 aprint_error_dev(self, "no union descriptor\n");
174 return;
175 }
176 data_ifcno = ud->bSlaveInterface[0];
177
178 for (i = 0; i < uaa->nifaces; i++) {
179 if (uaa->ifaces[i] != NULL) {
180 id = usbd_get_interface_descriptor(
181 uaa->ifaces[i]);
182 if (id != NULL && id->bInterfaceNumber ==
183 data_ifcno) {
184 sc->cdce_data_iface = uaa->ifaces[i];
185 uaa->ifaces[i] = NULL;
186 }
187 }
188 }
189 }
190
191 if (sc->cdce_data_iface == NULL) {
192 aprint_error_dev(self, "no data interface\n");
193 return;
194 }
195
196 /*
197 * <quote>
198 * The Data Class interface of a networking device shall have a minimum
199 * of two interface settings. The first setting (the default interface
200 * setting) includes no endpoints and therefore no networking traffic is
201 * exchanged whenever the default interface setting is selected. One or
202 * more additional interface settings are used for normal operation, and
203 * therefore each includes a pair of endpoints (one IN, and one OUT) to
204 * exchange network traffic. Select an alternate interface setting to
205 * initialize the network aspects of the device and to enable the
206 * exchange of network traffic.
207 * </quote>
208 *
209 * Some devices, most notably cable modems, include interface settings
210 * that have no IN or OUT endpoint, therefore loop through the list of all
211 * available interface settings looking for one with both IN and OUT
212 * endpoints.
213 */
214 id = usbd_get_interface_descriptor(sc->cdce_data_iface);
215 cd = usbd_get_config_descriptor(sc->cdce_udev);
216 numalts = usbd_get_no_alts(cd, id->bInterfaceNumber);
217
218 for (j = 0; j < numalts; j++) {
219 if (usbd_set_interface(sc->cdce_data_iface, j)) {
220 aprint_error_dev(sc->cdce_dev,
221 "setting alternate interface failed\n");
222 return;
223 }
224 /* Find endpoints. */
225 id = usbd_get_interface_descriptor(sc->cdce_data_iface);
226 sc->cdce_bulkin_no = sc->cdce_bulkout_no = -1;
227 for (i = 0; i < id->bNumEndpoints; i++) {
228 ed = usbd_interface2endpoint_descriptor(sc->cdce_data_iface, i);
229 if (!ed) {
230 aprint_error_dev(self,
231 "could not read endpoint descriptor\n");
232 return;
233 }
234 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
235 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
236 sc->cdce_bulkin_no = ed->bEndpointAddress;
237 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
238 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
239 sc->cdce_bulkout_no = ed->bEndpointAddress;
240 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
241 UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
242 /* XXX: CDC spec defines an interrupt pipe, but it is not
243 * needed for simple host-to-host applications. */
244 } else {
245 aprint_error_dev(self, "unexpected endpoint\n");
246 }
247 }
248 /* If we found something, try and use it... */
249 if ((sc->cdce_bulkin_no != -1) && (sc->cdce_bulkout_no != -1))
250 break;
251 }
252
253 if (sc->cdce_bulkin_no == -1) {
254 aprint_error_dev(self, "could not find data bulk in\n");
255 return;
256 }
257 if (sc->cdce_bulkout_no == -1 ) {
258 aprint_error_dev(self, "could not find data bulk out\n");
259 return;
260 }
261
262 ue = (const usb_cdc_ethernet_descriptor_t *)usb_find_desc(dev,
263 UDESC_INTERFACE, UDESCSUB_CDC_ENF);
264 if (!ue || usbd_get_string(dev, ue->iMacAddress, eaddr_str)) {
265 aprint_normal_dev(self, "faking address\n");
266 eaddr[0]= 0x2a;
267 memcpy(&eaddr[1], &hardclock_ticks, sizeof(u_int32_t));
268 eaddr[5] = (u_int8_t)(device_unit(sc->cdce_dev));
269 } else {
270 (void)ether_nonstatic_aton(eaddr, eaddr_str);
271 }
272
273 s = splnet();
274
275 aprint_normal_dev(self, "address %s\n", ether_sprintf(eaddr));
276
277 ifp = GET_IFP(sc);
278 ifp->if_softc = sc;
279 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
280 ifp->if_ioctl = cdce_ioctl;
281 ifp->if_start = cdce_start;
282 ifp->if_watchdog = cdce_watchdog;
283 strncpy(ifp->if_xname, device_xname(sc->cdce_dev), IFNAMSIZ);
284
285 IFQ_SET_READY(&ifp->if_snd);
286
287 if_attach(ifp);
288 ether_ifattach(ifp, eaddr);
289
290 sc->cdce_attached = 1;
291 splx(s);
292
293 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->cdce_udev,
294 sc->cdce_dev);
295
296 return;
297 }
298
299 int
300 cdce_detach(device_t self, int flags)
301 {
302 struct cdce_softc *sc = device_private(self);
303 struct ifnet *ifp = GET_IFP(sc);
304 int s;
305
306 s = splusb();
307
308 if (!sc->cdce_attached) {
309 splx(s);
310 return (0);
311 }
312
313 if (ifp->if_flags & IFF_RUNNING)
314 cdce_stop(sc);
315
316 ether_ifdetach(ifp);
317
318 if_detach(ifp);
319
320 sc->cdce_attached = 0;
321 splx(s);
322
323 return (0);
324 }
325
326 Static void
327 cdce_start(struct ifnet *ifp)
328 {
329 struct cdce_softc *sc = ifp->if_softc;
330 struct mbuf *m_head = NULL;
331
332 if (sc->cdce_dying || (ifp->if_flags & IFF_OACTIVE))
333 return;
334
335 IFQ_POLL(&ifp->if_snd, m_head);
336 if (m_head == NULL)
337 return;
338
339 if (cdce_encap(sc, m_head, 0)) {
340 ifp->if_flags |= IFF_OACTIVE;
341 return;
342 }
343
344 IFQ_DEQUEUE(&ifp->if_snd, m_head);
345
346 if (ifp->if_bpf)
347 bpf_ops->bpf_mtap(ifp->if_bpf, 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 if (ifp->if_bpf)
712 bpf_ops->bpf_mtap(ifp->if_bpf, m);
713
714 (*(ifp)->if_input)((ifp), (m));
715
716 done1:
717 splx(s);
718
719 done:
720 /* Setup new transfer. */
721 usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkin_pipe, c, c->cdce_buf,
722 CDCE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
723 cdce_rxeof);
724 usbd_transfer(c->cdce_xfer);
725 }
726
727 Static void
728 cdce_txeof(usbd_xfer_handle xfer, usbd_private_handle priv,
729 usbd_status status)
730 {
731 struct cdce_chain *c = priv;
732 struct cdce_softc *sc = c->cdce_sc;
733 struct ifnet *ifp = GET_IFP(sc);
734 usbd_status err;
735 int s;
736
737 if (sc->cdce_dying)
738 return;
739
740 s = splnet();
741
742 ifp->if_timer = 0;
743 ifp->if_flags &= ~IFF_OACTIVE;
744
745 if (status != USBD_NORMAL_COMPLETION) {
746 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
747 splx(s);
748 return;
749 }
750 ifp->if_oerrors++;
751 printf("%s: usb error on tx: %s\n", device_xname(sc->cdce_dev),
752 usbd_errstr(status));
753 if (status == USBD_STALLED)
754 usbd_clear_endpoint_stall_async(sc->cdce_bulkout_pipe);
755 splx(s);
756 return;
757 }
758
759 usbd_get_xfer_status(c->cdce_xfer, NULL, NULL, NULL, &err);
760
761 if (c->cdce_mbuf != NULL) {
762 m_freem(c->cdce_mbuf);
763 c->cdce_mbuf = NULL;
764 }
765
766 if (err)
767 ifp->if_oerrors++;
768 else
769 ifp->if_opackets++;
770
771 if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
772 cdce_start(ifp);
773
774 splx(s);
775 }
776
777 int
778 cdce_activate(device_t self, enum devact act)
779 {
780 struct cdce_softc *sc = device_private(self);
781
782 switch (act) {
783 case DVACT_DEACTIVATE:
784 if_deactivate(GET_IFP(sc));
785 sc->cdce_dying = 1;
786 return 0;
787 default:
788 return EOPNOTSUPP;
789 }
790 }
791
792
793 /* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
794 * code or tables extracted from it, as desired without restriction.
795 */
796
797 static uint32_t cdce_crc32_tab[] = {
798 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
799 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
800 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
801 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
802 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
803 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
804 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
805 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
806 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
807 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
808 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
809 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
810 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
811 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
812 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
813 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
814 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
815 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
816 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
817 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
818 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
819 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
820 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
821 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
822 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
823 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
824 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
825 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
826 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
827 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
828 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
829 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
830 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
831 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
832 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
833 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
834 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
835 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
836 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
837 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
838 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
839 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
840 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
841 };
842
843 Static uint32_t
844 cdce_crc32(const void *buf, size_t size)
845 {
846 const uint8_t *p;
847 uint32_t crc;
848
849 p = buf;
850 crc = ~0U;
851
852 while (size--)
853 crc = cdce_crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
854
855 return (crc ^ ~0U);
856 }
857