Annotation of sys/dev/usb/if_cdcef.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: if_cdcef.c,v 1.17 2007/06/14 06:55:10 mbalmer Exp $ */
2:
3: /*
4: * Copyright (c) 2007 Dale Rahn <drahn@openbsd.org>
5: * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
6: *
7: * Permission to use, copy, modify, and distribute this software for any
8: * purpose with or without fee is hereby granted, provided that the above
9: * copyright notice and this permission notice appear in all copies.
10: *
11: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18: */
19:
20: /*
21: * USB Communication Device Class Ethernet Emulation Model function driver
22: * (counterpart of the host-side cdce(4) driver)
23: */
24: #include <bpfilter.h>
25:
26:
27: #include <sys/param.h>
28: #include <sys/device.h>
29: #include <sys/socket.h>
30: #include <sys/systm.h>
31: #include <sys/mbuf.h>
32: #include <sys/timeout.h>
33:
34: #include <net/if.h>
35:
36: #include <dev/usb/usb.h>
37: #include <dev/usb/usbdi.h>
38: #include <dev/usb/usbf.h>
39: #include <dev/usb/usbcdc.h>
40:
41: #if NBPFILTER > 0
42: #include <net/bpf.h>
43: #endif
44:
45: #include <netinet/in.h>
46: #include <netinet/in_systm.h>
47: #include <netinet/in_var.h>
48: #include <netinet/ip.h>
49: #include <netinet/if_ether.h>
50:
51:
52: #define CDCEF_VENDOR_ID 0x0001
53: #define CDCEF_PRODUCT_ID 0x0001
54: #define CDCEF_DEVICE_CODE 0x0100
55: #define CDCEF_VENDOR_STRING "OpenBSD.org"
56: #define CDCEF_PRODUCT_STRING "CDC Ethernet Emulation"
57: #define CDCEF_SERIAL_STRING "1.00"
58:
59: #define CDCEF_BUFSZ 1600
60:
61:
62: struct cdcef_softc {
63: struct usbf_function sc_dev;
64: usbf_config_handle sc_config;
65: usbf_interface_handle sc_iface;
66: usbf_endpoint_handle sc_ep_in;
67: usbf_endpoint_handle sc_ep_out;
68: usbf_pipe_handle sc_pipe_in;
69: usbf_pipe_handle sc_pipe_out;
70: usbf_xfer_handle sc_xfer_in;
71: usbf_xfer_handle sc_xfer_out;
72: void *sc_buffer_in;
73: void *sc_buffer_out;
74:
75: struct timeout start_to;
76:
77: struct mbuf *sc_xmit_mbuf;
78:
79: struct arpcom sc_arpcom;
80: #define GET_IFP(sc) (&(sc)->sc_arpcom.ac_if)
81:
82: int sc_rxeof_errors;
83: int sc_unit;
84: int sc_attached;
85: int sc_listening;
86: };
87:
88: int cdcef_match(struct device *, void *, void *);
89: void cdcef_attach(struct device *, struct device *, void *);
90:
91: usbf_status cdcef_do_request(usbf_function_handle,
92: usb_device_request_t *, void **);
93:
94: void cdcef_start(struct ifnet *);
95:
96: void cdcef_txeof(usbf_xfer_handle, usbf_private_handle,
97: usbf_status);
98: void cdcef_rxeof(usbf_xfer_handle, usbf_private_handle,
99: usbf_status);
100: int cdcef_ioctl(struct ifnet *ifp, u_long command, caddr_t data);
101: void cdcef_watchdog(struct ifnet *ifp);
102: void cdcef_init(struct cdcef_softc *);
103: void cdcef_stop(struct cdcef_softc *);
104: int cdcef_encap(struct cdcef_softc *sc, struct mbuf *m, int idx);
105: struct mbuf * cdcef_newbuf(void);
106: void cdcef_start_timeout (void *);
107:
108: struct cfattach cdcef_ca = {
109: sizeof(struct cdcef_softc), cdcef_match, cdcef_attach
110: };
111:
112: struct cfdriver cdcef_cd = {
113: NULL, "cdcef", DV_DULL
114: };
115:
116: struct usbf_function_methods cdcef_methods = {
117: NULL, /* set_config */
118: cdcef_do_request
119: };
120:
121: #ifndef CDCEF_DEBUG
122: #define DPRINTF(x) do {} while (0)
123: #else
124: #define DPRINTF(x) printf x
125: #endif
126:
127: #define DEVNAME(sc) ((sc)->sc_dev.bdev.dv_xname)
128:
129: /*
130: * USB function match/attach/detach
131: */
132:
133: int
134: cdcef_match(struct device *parent, void *match, void *aux)
135: {
136: return UMATCH_GENERIC;
137: }
138:
139: void
140: cdcef_attach(struct device *parent, struct device *self, void *aux)
141: {
142: struct cdcef_softc *sc = (struct cdcef_softc *)self;
143: struct usbf_attach_arg *uaa = aux;
144: usbf_device_handle dev = uaa->device;
145: char *devinfop;
146: struct ifnet *ifp;
147: usbf_status err;
148: usb_cdc_union_descriptor_t udesc;
149: int s;
150: u_int16_t macaddr_hi;
151:
152:
153: /* Set the device identification according to the function. */
154: usbf_devinfo_setup(dev, UDCLASS_IN_INTERFACE, 0, 0, CDCEF_VENDOR_ID,
155: CDCEF_PRODUCT_ID, CDCEF_DEVICE_CODE, CDCEF_VENDOR_STRING,
156: CDCEF_PRODUCT_STRING, CDCEF_SERIAL_STRING);
157:
158: devinfop = usbf_devinfo_alloc(dev);
159: printf(": %s\n", devinfop);
160: usbf_devinfo_free(devinfop);
161:
162: /* Fill in the fields needed by the parent device. */
163: sc->sc_dev.methods = &cdcef_methods;
164:
165: /* timeout to start delayed tranfers */
166: timeout_set(&sc->start_to, cdcef_start_timeout, sc);
167:
168: /*
169: * Build descriptors according to the device class specification.
170: */
171: err = usbf_add_config(dev, &sc->sc_config);
172: if (err) {
173: printf("%s: usbf_add_config failed\n", DEVNAME(sc));
174: return;
175: }
176: err = usbf_add_interface(sc->sc_config, UICLASS_CDC,
177: UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL, 0, NULL,
178: &sc->sc_iface);
179: if (err) {
180: printf("%s: usbf_add_interface failed\n", DEVNAME(sc));
181: return;
182: }
183: /* XXX don't use hard-coded values 128 and 16. */
184: err = usbf_add_endpoint(sc->sc_iface, UE_DIR_IN | 2, UE_BULK,
185: 64, 16, &sc->sc_ep_in) ||
186: usbf_add_endpoint(sc->sc_iface, UE_DIR_OUT | 1, UE_BULK,
187: 64, 16, &sc->sc_ep_out);
188: if (err) {
189: printf("%s: usbf_add_endpoint failed\n", DEVNAME(sc));
190: return;
191: }
192:
193: /* Append a CDC union descriptor. */
194: bzero(&udesc, sizeof udesc);
195: udesc.bLength = sizeof udesc;
196: udesc.bDescriptorType = UDESC_CS_INTERFACE;
197: udesc.bDescriptorSubtype = UDESCSUB_CDC_UNION;
198: udesc.bSlaveInterface[0] = usbf_interface_number(sc->sc_iface);
199: err = usbf_add_config_desc(sc->sc_config,
200: (usb_descriptor_t *)&udesc, NULL);
201: if (err) {
202: printf("%s: usbf_add_config_desc failed\n", DEVNAME(sc));
203: return;
204: }
205:
206: /*
207: * Close the configuration and build permanent descriptors.
208: */
209: err = usbf_end_config(sc->sc_config);
210: if (err) {
211: printf("%s: usbf_end_config failed\n", DEVNAME(sc));
212: return;
213: }
214:
215: /* Preallocate xfers and data buffers. */
216: sc->sc_xfer_in = usbf_alloc_xfer(dev);
217: sc->sc_xfer_out = usbf_alloc_xfer(dev);
218: sc->sc_buffer_in = usbf_alloc_buffer(sc->sc_xfer_in,
219: CDCEF_BUFSZ);
220: sc->sc_buffer_out = usbf_alloc_buffer(sc->sc_xfer_out,
221: CDCEF_BUFSZ);
222: if (sc->sc_buffer_in == NULL || sc->sc_buffer_out == NULL) {
223: printf("%s: usbf_alloc_buffer failed\n", DEVNAME(sc));
224: return;
225: }
226:
227: /* Open the bulk pipes. */
228: err = usbf_open_pipe(sc->sc_iface,
229: usbf_endpoint_address(sc->sc_ep_out), &sc->sc_pipe_out) ||
230: usbf_open_pipe(sc->sc_iface,
231: usbf_endpoint_address(sc->sc_ep_in), &sc->sc_pipe_in);
232: if (err) {
233: printf("%s: usbf_open_pipe failed\n", DEVNAME(sc));
234: return;
235: }
236:
237: /* Get ready to receive packets. */
238: usbf_setup_xfer(sc->sc_xfer_out, sc->sc_pipe_out, sc,
239: sc->sc_buffer_out, CDCEF_BUFSZ, USBD_SHORT_XFER_OK, 0, cdcef_rxeof);
240: err = usbf_transfer(sc->sc_xfer_out);
241: if (err && err != USBF_IN_PROGRESS) {
242: printf("%s: usbf_transfer failed\n", DEVNAME(sc));
243: return;
244: }
245:
246: s = splnet();
247:
248: macaddr_hi = htons(0x2acb);
249: bcopy(&macaddr_hi, &sc->sc_arpcom.ac_enaddr[0], sizeof(u_int16_t));
250: bcopy(&ticks, &sc->sc_arpcom.ac_enaddr[2], sizeof(u_int32_t));
251: sc->sc_arpcom.ac_enaddr[5] = (u_int8_t)(sc->sc_unit);
252:
253: printf("%s: address %s\n", DEVNAME(sc),
254: ether_sprintf(sc->sc_arpcom.ac_enaddr));
255:
256: ifp = GET_IFP(sc);
257: ifp->if_softc = sc;
258: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
259: ifp->if_ioctl = cdcef_ioctl;
260: ifp->if_start = cdcef_start;
261: ifp->if_watchdog = cdcef_watchdog;
262: strlcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ);
263:
264: IFQ_SET_READY(&ifp->if_snd);
265:
266: if_attach(ifp);
267: ether_ifattach(ifp);
268:
269: sc->sc_attached = 1;
270: splx(s);
271: }
272:
273: usbf_status
274: cdcef_do_request(usbf_function_handle fun, usb_device_request_t *req,
275: void **data)
276: {
277: printf("cdcef_do_request\n");
278: return USBF_STALLED;
279: }
280:
281: void
282: cdcef_start(struct ifnet *ifp)
283: {
284: struct cdcef_softc *sc = ifp->if_softc;
285: struct mbuf *m_head = NULL;
286:
287: if(ifp->if_flags & IFF_OACTIVE)
288: return;
289:
290: IFQ_POLL(&ifp->if_snd, m_head);
291: if (m_head == NULL) {
292: return;
293: }
294:
295: if (sc->sc_listening == 0 || m_head->m_pkthdr.len > CDCEF_BUFSZ) {
296: /*
297: * drop packet because reciever is not listening,
298: * or if packet is larger than xmit buffer
299: */
300: IFQ_DEQUEUE(&ifp->if_snd, m_head);
301: m_freem(m_head);
302: return;
303: }
304:
305: if (cdcef_encap(sc, m_head, 0)) {
306: ifp->if_flags |= IFF_OACTIVE;
307: return;
308: }
309:
310: IFQ_DEQUEUE(&ifp->if_snd, m_head);
311:
312: #if NBPFILTER > 0
313: if (ifp->if_bpf)
314: bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
315: #endif
316:
317: ifp->if_flags |= IFF_OACTIVE;
318:
319: ifp->if_timer = 6;
320: }
321:
322: void
323: cdcef_txeof(usbf_xfer_handle xfer, usbf_private_handle priv,
324: usbf_status err)
325: {
326: struct cdcef_softc *sc = priv;
327: struct ifnet *ifp = GET_IFP(sc);
328: int s;
329:
330: s = splnet();
331: #if 0
332: printf("cdcef_txeof: xfer=%p, priv=%p, %s\n", xfer, priv,
333: usbf_errstr(err));
334: #endif
335:
336: ifp->if_timer = 0;
337: ifp->if_flags &= ~IFF_OACTIVE;
338:
339: if (sc->sc_xmit_mbuf != NULL) {
340: m_freem(sc->sc_xmit_mbuf);
341: sc->sc_xmit_mbuf = NULL;
342: }
343:
344: if (err)
345: ifp->if_oerrors++;
346: else
347: ifp->if_opackets++;
348:
349: if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
350: timeout_add(&sc->start_to, 1); /* XXX */
351:
352: splx(s);
353: }
354: void
355: cdcef_start_timeout (void *v)
356: {
357: struct cdcef_softc *sc = v;
358: struct ifnet *ifp = GET_IFP(sc);
359: int s;
360:
361: s = splnet();
362: cdcef_start(ifp);
363: splx(s);
364: }
365:
366:
367: void
368: cdcef_rxeof(usbf_xfer_handle xfer, usbf_private_handle priv,
369: usbf_status status)
370: {
371: struct cdcef_softc *sc = priv;
372: int total_len = 0;
373: struct ifnet *ifp = GET_IFP(sc);
374: struct mbuf *m = NULL;
375:
376:
377: int s;
378:
379: #if 0
380: printf("cdcef_rxeof: xfer=%p, priv=%p, %s\n", xfer, priv,
381: usbf_errstr(status));
382: #endif
383:
384: if (status != USBF_NORMAL_COMPLETION) {
385: if (status == USBF_NOT_STARTED || status == USBF_CANCELLED)
386: return;
387: if (sc->sc_rxeof_errors == 0)
388: printf("%s: usb error on rx: %s\n",
389: DEVNAME(sc), usbf_errstr(status));
390: /* XXX - no stalls on client */
391: if (sc->sc_rxeof_errors++ > 10) {
392: printf("%s: too many errors, disabling\n",
393: DEVNAME(sc));
394: /* sc->sc_dying = 1; */
395: // return;
396: }
397: goto done;
398: }
399: sc->sc_rxeof_errors = 0;
400:
401: /* upon first incoming packet we know the host is listening */
402: if (sc->sc_listening == 0) {
403: sc->sc_listening = 1;
404: }
405:
406:
407: usbf_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
408:
409: /* total_len -= 4; Strip off CRC added for Zaurus - XXX*/
410: if (total_len <= 1)
411: goto done;
412:
413: if (total_len < sizeof(struct ether_header)) {
414: ifp->if_ierrors++;
415: goto done;
416: }
417:
418: s = splnet();
419: if (ifp->if_flags & IFF_RUNNING) {
420: m = cdcef_newbuf();
421: if (m == NULL) {
422: /* message? */
423: ifp->if_ierrors++;
424: goto done1;
425: }
426:
427: m->m_pkthdr.len = m->m_len = total_len;
428: bcopy(sc->sc_buffer_out, mtod(m, char *), total_len);
429: m->m_pkthdr.rcvif = ifp;
430:
431: ifp->if_ipackets++;
432:
433: #if NBPFILTER > 0
434: if (ifp->if_bpf)
435: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
436: #endif
437:
438: ether_input_mbuf(ifp, m);
439: }
440:
441: done1:
442: splx(s);
443:
444: done:
445: /* Setup another xfer. */
446: usbf_setup_xfer(xfer, sc->sc_pipe_out, sc, sc->sc_buffer_out,
447: CDCEF_BUFSZ, USBD_SHORT_XFER_OK, 0, cdcef_rxeof);
448:
449: status = usbf_transfer(xfer);
450: if (status && status != USBF_IN_PROGRESS) {
451: printf("%s: usbf_transfer failed\n", DEVNAME(sc));
452: return;
453: }
454: }
455:
456: struct mbuf *
457: cdcef_newbuf(void)
458: {
459: struct mbuf *m;
460:
461: MGETHDR(m, M_DONTWAIT, MT_DATA);
462: if (m == NULL)
463: return (NULL);
464:
465: MCLGET(m, M_DONTWAIT);
466: if (!(m->m_flags & M_EXT)) {
467: m_freem(m);
468: return (NULL);
469: }
470:
471: m->m_len = m->m_pkthdr.len = MCLBYTES;
472: m_adj(m, ETHER_ALIGN);
473:
474: return (m);
475: }
476:
477: int
478: cdcef_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
479: {
480: struct cdcef_softc *sc = ifp->if_softc;
481: struct ifaddr *ifa = (struct ifaddr *)data;
482: struct ifreq *ifr = (struct ifreq *)data;
483: int s, error = 0;
484:
485: s = splnet();
486:
487: switch (command) {
488: case SIOCSIFADDR:
489: ifp->if_flags |= IFF_UP;
490: cdcef_init(sc);
491: switch (ifa->ifa_addr->sa_family) {
492: case AF_INET:
493: arp_ifinit(&sc->sc_arpcom, ifa);
494: break;
495: }
496: break;
497:
498: case SIOCSIFMTU:
499: if (ifr->ifr_mtu > ETHERMTU)
500: error = EINVAL;
501: else
502: ifp->if_mtu = ifr->ifr_mtu;
503: break;
504:
505: case SIOCSIFFLAGS:
506: if (ifp->if_flags & IFF_UP) {
507: if (!(ifp->if_flags & IFF_RUNNING))
508: cdcef_init(sc);
509: } else {
510: if (ifp->if_flags & IFF_RUNNING)
511: cdcef_stop(sc);
512: }
513: error = 0;
514: break;
515:
516: case SIOCADDMULTI:
517: case SIOCDELMULTI:
518: error = (command == SIOCADDMULTI) ?
519: ether_addmulti(ifr, &sc->sc_arpcom) :
520: ether_delmulti(ifr, &sc->sc_arpcom);
521:
522: if (error == ENETRESET)
523: error = 0;
524: break;
525:
526: default:
527: error = EINVAL;
528: break;
529: }
530:
531: splx(s);
532:
533: return (error);
534: }
535:
536: void
537: cdcef_watchdog(struct ifnet *ifp)
538: {
539: struct cdcef_softc *sc = ifp->if_softc;
540: int s;
541:
542: #if 0
543: if (sc->sc_dying)
544: return;
545: #endif
546:
547: ifp->if_oerrors++;
548: printf("%s: watchdog timeout\n", DEVNAME(sc));
549:
550: s = splusb();
551: ifp->if_timer = 0;
552: ifp->if_flags &= ~IFF_OACTIVE;
553:
554: /* cancel recieve pipe? */
555: usbf_abort_pipe(sc->sc_pipe_in); /* in is tx pipe */
556: splx(s);
557: }
558:
559: void
560: cdcef_init(struct cdcef_softc *sc)
561: {
562: int s;
563: struct ifnet *ifp = GET_IFP(sc);
564: if (ifp->if_flags & IFF_RUNNING)
565: return;
566: s = splnet();
567:
568: ifp->if_flags |= IFF_RUNNING;
569: ifp->if_flags &= ~IFF_OACTIVE;
570:
571: splx(s);
572: }
573:
574: int
575: cdcef_encap(struct cdcef_softc *sc, struct mbuf *m, int idx)
576: {
577: usbf_status err;
578:
579: m_copydata(m, 0, m->m_pkthdr.len, sc->sc_buffer_in);
580: /* NO CRC */
581:
582: usbf_setup_xfer(sc->sc_xfer_in, sc->sc_pipe_in, sc, sc->sc_buffer_in,
583: m->m_pkthdr.len, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
584: 10000, cdcef_txeof);
585:
586: err = usbf_transfer(sc->sc_xfer_in);
587: if (err && err != USBD_IN_PROGRESS) {
588: printf("encap error\n");
589: cdcef_stop(sc);
590: return (EIO);
591: }
592: sc->sc_xmit_mbuf = m;
593:
594: return (0);
595: }
596:
597:
598: void
599: cdcef_stop(struct cdcef_softc *sc)
600: {
601: struct ifnet *ifp = GET_IFP(sc);
602:
603: ifp->if_timer = 0;
604: ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
605:
606: /* cancel recieve pipe? */
607:
608: if (sc->sc_xmit_mbuf != NULL) {
609: m_freem(sc->sc_xmit_mbuf);
610: sc->sc_xmit_mbuf = NULL;
611: }
612: }
CVSweb