if_cdce.c revision 1.27 1 /* $NetBSD: if_cdce.c,v 1.27 2010/01/19 22:07:43 pooka 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.27 2010/01/19 22:07:43 pooka 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 if (ifp->if_bpf)
348 bpf_ops->bpf_mtap(ifp->if_bpf, m_head);
349
350 ifp->if_flags |= IFF_OACTIVE;
351
352 ifp->if_timer = 6;
353 }
354
355 Static int
356 cdce_encap(struct cdce_softc *sc, struct mbuf *m, int idx)
357 {
358 struct cdce_chain *c;
359 usbd_status err;
360 int extra = 0;
361
362 c = &sc->cdce_cdata.cdce_tx_chain[idx];
363
364 m_copydata(m, 0, m->m_pkthdr.len, c->cdce_buf);
365 if (sc->cdce_flags & CDCE_ZAURUS) {
366 /* Zaurus wants a 32-bit CRC appended to every frame */
367 u_int32_t crc;
368
369 crc = cdce_crc32(c->cdce_buf, m->m_pkthdr.len);
370 memcpy(c->cdce_buf + m->m_pkthdr.len, &crc, 4);
371 extra = 4;
372 }
373 c->cdce_mbuf = m;
374
375 usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkout_pipe, c, c->cdce_buf,
376 m->m_pkthdr.len + extra, USBD_NO_COPY, 10000, cdce_txeof);
377 err = usbd_transfer(c->cdce_xfer);
378 if (err != USBD_IN_PROGRESS) {
379 cdce_stop(sc);
380 return (EIO);
381 }
382
383 sc->cdce_cdata.cdce_tx_cnt++;
384
385 return (0);
386 }
387
388 Static void
389 cdce_stop(struct cdce_softc *sc)
390 {
391 usbd_status err;
392 struct ifnet *ifp = GET_IFP(sc);
393 int i;
394
395 ifp->if_timer = 0;
396
397 if (sc->cdce_bulkin_pipe != NULL) {
398 err = usbd_abort_pipe(sc->cdce_bulkin_pipe);
399 if (err)
400 printf("%s: abort rx pipe failed: %s\n",
401 device_xname(sc->cdce_dev), usbd_errstr(err));
402 err = usbd_close_pipe(sc->cdce_bulkin_pipe);
403 if (err)
404 printf("%s: close rx pipe failed: %s\n",
405 device_xname(sc->cdce_dev), usbd_errstr(err));
406 sc->cdce_bulkin_pipe = NULL;
407 }
408
409 if (sc->cdce_bulkout_pipe != NULL) {
410 err = usbd_abort_pipe(sc->cdce_bulkout_pipe);
411 if (err)
412 printf("%s: abort tx pipe failed: %s\n",
413 device_xname(sc->cdce_dev), usbd_errstr(err));
414 err = usbd_close_pipe(sc->cdce_bulkout_pipe);
415 if (err)
416 printf("%s: close tx pipe failed: %s\n",
417 device_xname(sc->cdce_dev), usbd_errstr(err));
418 sc->cdce_bulkout_pipe = NULL;
419 }
420
421 for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
422 if (sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf != NULL) {
423 m_freem(sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf);
424 sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf = NULL;
425 }
426 if (sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer != NULL) {
427 usbd_free_xfer(sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer);
428 sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer = NULL;
429 }
430 }
431
432 for (i = 0; i < CDCE_TX_LIST_CNT; i++) {
433 if (sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf != NULL) {
434 m_freem(sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf);
435 sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf = NULL;
436 }
437 if (sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer != NULL) {
438 usbd_free_xfer(sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer);
439 sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer = NULL;
440 }
441 }
442
443 ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
444 }
445
446 Static int
447 cdce_ioctl(struct ifnet *ifp, u_long command, void *data)
448 {
449 struct cdce_softc *sc = ifp->if_softc;
450 struct ifaddr *ifa = (struct ifaddr *)data;
451 struct ifreq *ifr = (struct ifreq *)data;
452 int s, error = 0;
453
454 if (sc->cdce_dying)
455 return (EIO);
456
457 s = splnet();
458
459 switch(command) {
460 case SIOCINITIFADDR:
461 ifp->if_flags |= IFF_UP;
462 cdce_init(sc);
463 switch (ifa->ifa_addr->sa_family) {
464 #ifdef INET
465 case AF_INET:
466 arp_ifinit(ifp, ifa);
467 break;
468 #endif /* INET */
469 }
470 break;
471
472 case SIOCSIFMTU:
473 if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ETHERMTU)
474 error = EINVAL;
475 else if ((error = ifioctl_common(ifp, command, data)) == ENETRESET)
476 error = 0;
477 break;
478
479 case SIOCSIFFLAGS:
480 if ((error = ifioctl_common(ifp, command, data)) != 0)
481 break;
482 /* XXX re-use ether_ioctl() */
483 switch (ifp->if_flags & (IFF_UP|IFF_RUNNING)) {
484 case IFF_UP:
485 cdce_init(sc);
486 break;
487 case IFF_RUNNING:
488 cdce_stop(sc);
489 break;
490 default:
491 break;
492 }
493 break;
494
495 default:
496 error = ether_ioctl(ifp, command, data);
497 break;
498 }
499
500 splx(s);
501
502 return (error);
503 }
504
505 Static void
506 cdce_watchdog(struct ifnet *ifp)
507 {
508 struct cdce_softc *sc = ifp->if_softc;
509
510 if (sc->cdce_dying)
511 return;
512
513 ifp->if_oerrors++;
514 printf("%s: watchdog timeout\n", device_xname(sc->cdce_dev));
515 }
516
517 Static void
518 cdce_init(void *xsc)
519 {
520 struct cdce_softc *sc = xsc;
521 struct ifnet *ifp = GET_IFP(sc);
522 struct cdce_chain *c;
523 usbd_status err;
524 int s, i;
525
526 if (ifp->if_flags & IFF_RUNNING)
527 return;
528
529 s = splnet();
530
531 if (cdce_tx_list_init(sc) == ENOBUFS) {
532 printf("%s: tx list init failed\n", device_xname(sc->cdce_dev));
533 splx(s);
534 return;
535 }
536
537 if (cdce_rx_list_init(sc) == ENOBUFS) {
538 printf("%s: rx list init failed\n", device_xname(sc->cdce_dev));
539 splx(s);
540 return;
541 }
542
543 /* Maybe set multicast / broadcast here??? */
544
545 err = usbd_open_pipe(sc->cdce_data_iface, sc->cdce_bulkin_no,
546 USBD_EXCLUSIVE_USE, &sc->cdce_bulkin_pipe);
547 if (err) {
548 printf("%s: open rx pipe failed: %s\n", device_xname(sc->cdce_dev),
549 usbd_errstr(err));
550 splx(s);
551 return;
552 }
553
554 err = usbd_open_pipe(sc->cdce_data_iface, sc->cdce_bulkout_no,
555 USBD_EXCLUSIVE_USE, &sc->cdce_bulkout_pipe);
556 if (err) {
557 printf("%s: open tx pipe failed: %s\n",
558 device_xname(sc->cdce_dev), usbd_errstr(err));
559 splx(s);
560 return;
561 }
562
563 for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
564 c = &sc->cdce_cdata.cdce_rx_chain[i];
565 usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkin_pipe, c,
566 c->cdce_buf, CDCE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
567 USBD_NO_TIMEOUT, cdce_rxeof);
568 usbd_transfer(c->cdce_xfer);
569 }
570
571 ifp->if_flags |= IFF_RUNNING;
572 ifp->if_flags &= ~IFF_OACTIVE;
573
574 splx(s);
575 }
576
577 Static int
578 cdce_newbuf(struct cdce_softc *sc, struct cdce_chain *c, struct mbuf *m)
579 {
580 struct mbuf *m_new = NULL;
581
582 if (m == NULL) {
583 MGETHDR(m_new, M_DONTWAIT, MT_DATA);
584 if (m_new == NULL) {
585 printf("%s: no memory for rx list "
586 "-- packet dropped!\n", device_xname(sc->cdce_dev));
587 return (ENOBUFS);
588 }
589 MCLGET(m_new, M_DONTWAIT);
590 if (!(m_new->m_flags & M_EXT)) {
591 printf("%s: no memory for rx list "
592 "-- packet dropped!\n", device_xname(sc->cdce_dev));
593 m_freem(m_new);
594 return (ENOBUFS);
595 }
596 m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
597 } else {
598 m_new = m;
599 m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
600 m_new->m_data = m_new->m_ext.ext_buf;
601 }
602 c->cdce_mbuf = m_new;
603 return (0);
604 }
605
606 Static int
607 cdce_rx_list_init(struct cdce_softc *sc)
608 {
609 struct cdce_cdata *cd;
610 struct cdce_chain *c;
611 int i;
612
613 cd = &sc->cdce_cdata;
614 for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
615 c = &cd->cdce_rx_chain[i];
616 c->cdce_sc = sc;
617 c->cdce_idx = i;
618 if (cdce_newbuf(sc, c, NULL) == ENOBUFS)
619 return (ENOBUFS);
620 if (c->cdce_xfer == NULL) {
621 c->cdce_xfer = usbd_alloc_xfer(sc->cdce_udev);
622 if (c->cdce_xfer == NULL)
623 return (ENOBUFS);
624 c->cdce_buf = usbd_alloc_buffer(c->cdce_xfer, CDCE_BUFSZ);
625 if (c->cdce_buf == NULL)
626 return (ENOBUFS);
627 }
628 }
629
630 return (0);
631 }
632
633 Static int
634 cdce_tx_list_init(struct cdce_softc *sc)
635 {
636 struct cdce_cdata *cd;
637 struct cdce_chain *c;
638 int i;
639
640 cd = &sc->cdce_cdata;
641 for (i = 0; i < CDCE_TX_LIST_CNT; i++) {
642 c = &cd->cdce_tx_chain[i];
643 c->cdce_sc = sc;
644 c->cdce_idx = i;
645 c->cdce_mbuf = NULL;
646 if (c->cdce_xfer == NULL) {
647 c->cdce_xfer = usbd_alloc_xfer(sc->cdce_udev);
648 if (c->cdce_xfer == NULL)
649 return (ENOBUFS);
650 c->cdce_buf = usbd_alloc_buffer(c->cdce_xfer, CDCE_BUFSZ);
651 if (c->cdce_buf == NULL)
652 return (ENOBUFS);
653 }
654 }
655
656 return (0);
657 }
658
659 Static void
660 cdce_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
661 {
662 struct cdce_chain *c = priv;
663 struct cdce_softc *sc = c->cdce_sc;
664 struct ifnet *ifp = GET_IFP(sc);
665 struct mbuf *m;
666 int total_len = 0;
667 int s;
668
669 if (sc->cdce_dying || !(ifp->if_flags & IFF_RUNNING))
670 return;
671
672 if (status != USBD_NORMAL_COMPLETION) {
673 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
674 return;
675 if (sc->cdce_rxeof_errors == 0)
676 printf("%s: usb error on rx: %s\n",
677 device_xname(sc->cdce_dev), usbd_errstr(status));
678 if (status == USBD_STALLED)
679 usbd_clear_endpoint_stall_async(sc->cdce_bulkin_pipe);
680 DELAY(sc->cdce_rxeof_errors * 10000);
681 sc->cdce_rxeof_errors++;
682 goto done;
683 }
684
685 sc->cdce_rxeof_errors = 0;
686
687 usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
688 if (sc->cdce_flags & CDCE_ZAURUS)
689 total_len -= 4; /* Strip off CRC added by Zaurus */
690 if (total_len <= 1)
691 goto done;
692
693 m = c->cdce_mbuf;
694 memcpy(mtod(m, char *), c->cdce_buf, total_len);
695
696 if (total_len < sizeof(struct ether_header)) {
697 ifp->if_ierrors++;
698 goto done;
699 }
700
701 ifp->if_ipackets++;
702 m->m_pkthdr.len = m->m_len = total_len;
703 m->m_pkthdr.rcvif = ifp;
704
705 s = splnet();
706
707 if (cdce_newbuf(sc, c, NULL) == ENOBUFS) {
708 ifp->if_ierrors++;
709 goto done1;
710 }
711
712 if (ifp->if_bpf)
713 bpf_ops->bpf_mtap(ifp->if_bpf, m);
714
715 (*(ifp)->if_input)((ifp), (m));
716
717 done1:
718 splx(s);
719
720 done:
721 /* Setup new transfer. */
722 usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkin_pipe, c, c->cdce_buf,
723 CDCE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
724 cdce_rxeof);
725 usbd_transfer(c->cdce_xfer);
726 }
727
728 Static void
729 cdce_txeof(usbd_xfer_handle xfer, usbd_private_handle priv,
730 usbd_status status)
731 {
732 struct cdce_chain *c = priv;
733 struct cdce_softc *sc = c->cdce_sc;
734 struct ifnet *ifp = GET_IFP(sc);
735 usbd_status err;
736 int s;
737
738 if (sc->cdce_dying)
739 return;
740
741 s = splnet();
742
743 ifp->if_timer = 0;
744 ifp->if_flags &= ~IFF_OACTIVE;
745
746 if (status != USBD_NORMAL_COMPLETION) {
747 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
748 splx(s);
749 return;
750 }
751 ifp->if_oerrors++;
752 printf("%s: usb error on tx: %s\n", device_xname(sc->cdce_dev),
753 usbd_errstr(status));
754 if (status == USBD_STALLED)
755 usbd_clear_endpoint_stall_async(sc->cdce_bulkout_pipe);
756 splx(s);
757 return;
758 }
759
760 usbd_get_xfer_status(c->cdce_xfer, NULL, NULL, NULL, &err);
761
762 if (c->cdce_mbuf != NULL) {
763 m_freem(c->cdce_mbuf);
764 c->cdce_mbuf = NULL;
765 }
766
767 if (err)
768 ifp->if_oerrors++;
769 else
770 ifp->if_opackets++;
771
772 if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
773 cdce_start(ifp);
774
775 splx(s);
776 }
777
778 int
779 cdce_activate(device_t self, enum devact act)
780 {
781 struct cdce_softc *sc = device_private(self);
782
783 switch (act) {
784 case DVACT_DEACTIVATE:
785 if_deactivate(GET_IFP(sc));
786 sc->cdce_dying = 1;
787 return 0;
788 default:
789 return EOPNOTSUPP;
790 }
791 }
792
793
794 /* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
795 * code or tables extracted from it, as desired without restriction.
796 */
797
798 static uint32_t cdce_crc32_tab[] = {
799 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
800 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
801 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
802 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
803 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
804 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
805 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
806 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
807 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
808 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
809 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
810 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
811 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
812 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
813 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
814 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
815 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
816 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
817 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
818 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
819 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
820 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
821 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
822 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
823 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
824 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
825 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
826 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
827 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
828 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
829 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
830 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
831 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
832 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
833 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
834 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
835 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
836 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
837 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
838 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
839 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
840 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
841 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
842 };
843
844 Static uint32_t
845 cdce_crc32(const void *buf, size_t size)
846 {
847 const uint8_t *p;
848 uint32_t crc;
849
850 p = buf;
851 crc = ~0U;
852
853 while (size--)
854 crc = cdce_crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
855
856 return (crc ^ ~0U);
857 }
858