0b8780d3c4a7c3713a7eb310ec67d1a96c968ba0
[dragonfly.git] / sys / dev / netif / lgue / if_lgue.c
1 /*
2  * LG-P500 Smartphone
3  * Written by Yellow Rabbit <yrabbit@sdf.lonestar.org>
4  */
5
6 /*
7  * XXX
8  * USB:
9  * Takes two interfaces.
10  * IN and OUT endpoints on the data interface (altsetting).
11  * Interrupt endpoint on the control interface.
12  *
13  * NET:
14  * Transfer frames without modification (AS IS).
15  */
16
17 #include <sys/param.h>
18 #include <sys/systm.h>
19 #include <sys/kernel.h>
20 #include <sys/socket.h>
21 #include <sys/sockio.h>
22 #include <sys/bus.h>
23
24 #include <net/if.h>
25 #include <net/ifq_var.h>
26 #include <net/if_arp.h>
27 #include <net/ethernet.h>
28 #include <net/bpf.h>
29
30 #include <bus/usb/usb.h>
31 #include <bus/usb/usbcdc.h>
32 #include <bus/usb/usbdi.h>
33 #include <bus/usb/usbdi_util.h>
34 #include <bus/usb/usbdivar.h>
35 #include <bus/usb/usb_ethersubr.h>
36
37 #include "if_lgue.h"
38
39 /*
40  * Supported device vendors/products
41  */
42 static struct usb_devno lgue_devs[] = {
43         { USB_DEVICE(0x1004, 0x61a2) }  /* LG P500 */
44 };
45
46 static int lgue_match(device_t);
47 static int lgue_attach(device_t);
48 static int lgue_detach(device_t);
49
50 static void lgue_start(struct ifnet *);
51 static void lgue_stop(struct lgue_softc *);
52 static void lgue_init(void *);
53 static void lgue_watchdog(struct ifnet *);
54 static int lgue_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
55
56 static int lgue_encap(struct lgue_softc *, struct mbuf *);
57 static int lgue_start_transfer(struct lgue_softc *);
58
59 static void lgue_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
60
61 static void lgue_start_ipifunc(void *);
62 static void lgue_start_schedule(struct ifnet *);
63
64 static int lgue_newbuf(struct lgue_softc *, int, struct mbuf **);
65 static void lgue_rxstart(struct ifnet *);
66 static void lgue_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
67
68 static void lgue_intrstart(struct ifnet *);
69 static void lgue_intreof(usbd_xfer_handle, usbd_private_handle, usbd_status);
70
71 static int lgue_get_data_iface_no(usbd_device_handle,
72                usb_interface_descriptor_t *);
73
74 static int lgue_getmac(struct lgue_softc *, void *);
75 static int lgue_getmtu(struct lgue_softc *);
76
77 static int hex(char);
78
79 static device_method_t lgue_methods[] = {
80         DEVMETHOD(device_probe,  lgue_match),
81         DEVMETHOD(device_attach, lgue_attach),
82         DEVMETHOD(device_detach, lgue_detach),
83
84         { 0, 0 }
85 };
86
87 static driver_t lgue_driver = {
88         "lgue",
89         lgue_methods,
90         sizeof(struct lgue_softc)
91 };
92
93 static devclass_t lgue_devclass;
94
95 DECLARE_DUMMY_MODULE(if_lgue);
96 DRIVER_MODULE(lgue, uhub, lgue_driver, lgue_devclass, usbd_driver_load, NULL);
97 MODULE_DEPEND(lgue, usb, 1, 1, 1);
98
99 /*
100  * Probe chip
101  */
102 static int
103 lgue_match(device_t dev)
104 {
105         struct usb_attach_arg *uaa;
106         usb_interface_descriptor_t *id;
107
108         uaa = device_get_ivars(dev);
109         if (uaa->iface == NULL)
110                 return(UMATCH_NONE);
111
112         if (usb_lookup(lgue_devs, uaa->vendor, uaa->product) != NULL) {
113                 id = usbd_get_interface_descriptor(uaa->iface);
114                 if (id != NULL &&
115                     id->bInterfaceClass == UICLASS_CDC &&
116                     id->bInterfaceSubClass == UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL)
117                         return(UMATCH_VENDOR_PRODUCT);
118         }
119         return(UMATCH_NONE);
120 }
121
122 /*
123  * Attach the interface.
124  */
125 static int
126 lgue_attach(device_t dev)
127 {
128         struct lgue_softc *sc;
129         struct usb_attach_arg *uaa;
130         struct ifnet *ifp;
131         usb_interface_descriptor_t *id;
132         usb_endpoint_descriptor_t *ed;
133         int i;
134         u_char eaddr[ETHER_ADDR_LEN];
135         usbd_status err;
136
137         sc = device_get_softc(dev);
138         uaa = device_get_ivars(dev);
139
140         sc->lgue_ctl_iface = uaa->iface;
141         sc->lgue_udev = uaa->device;
142
143         /* It has only config but in case... */
144         if (usbd_set_config_no(sc->lgue_udev, LGUE_CONFIG_NO, 0)) {
145                 device_printf(dev, "setting config no %d failed\n",
146                     LGUE_CONFIG_NO);
147                 return(ENXIO);
148         }
149
150         /* Get control and data intefaces */
151         id = usbd_get_interface_descriptor(uaa->iface);
152         sc->lgue_ctl_iface_no = id->bInterfaceNumber;
153         sc->lgue_data_iface_no = lgue_get_data_iface_no(sc->lgue_udev, id);
154
155         if (sc->lgue_data_iface_no == -1) {
156                 device_printf(dev, "no data interface number\n");
157                 goto bad;
158         }
159
160         /* Claim data interface */
161         for (i = 0; i < uaa->nifaces; ++i) {
162                 if (uaa->ifaces[i] != NULL) {
163                         id = usbd_get_interface_descriptor(uaa->ifaces[i]);
164                         if (id != NULL &&
165                             id->bInterfaceNumber == sc->lgue_data_iface_no) {
166                                 err = usbd_set_interface(uaa->ifaces[i],
167                                     LGUE_ALTERNATE_SETTING);
168                                 if ( err != USBD_NORMAL_COMPLETION) {
169                                         device_printf(dev,
170                                             "no alternate data interface. err:%s\n",
171                                             usbd_errstr(err));
172                                         goto bad;
173                                 }
174                                 sc->lgue_data_iface = uaa->ifaces[i];
175                                 uaa->ifaces[i] = NULL;
176                         }
177                 }
178         }
179         if (sc->lgue_data_iface == NULL) {
180                 device_printf(dev, "no data interface\n");
181                 goto bad;
182         }
183
184         /* Find data interface endpoints */
185         id = usbd_get_interface_descriptor(sc->lgue_data_iface);
186         sc->lgue_ed[LGUE_ENDPT_RX] = sc->lgue_ed[LGUE_ENDPT_TX] = -1;
187         for (i = 0; i < id->bNumEndpoints; ++i) {
188                 ed = usbd_interface2endpoint_descriptor(sc->lgue_data_iface, i);
189                 if (!ed) {
190                         device_printf(dev,
191                             "couldn't get endpoint descriptor %d\n", i);
192                         goto bad;
193                 }
194                 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
195                                 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
196                         sc->lgue_ed[LGUE_ENDPT_RX] = ed->bEndpointAddress;
197                 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
198                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
199                         sc->lgue_ed[LGUE_ENDPT_TX] = ed->bEndpointAddress;
200                 }
201         }
202
203         if (sc->lgue_ed[LGUE_ENDPT_RX] == -1) {
204                 device_printf(dev, "couldn't find data bilk in\n");
205                 goto bad;
206         }
207         if (sc->lgue_ed[LGUE_ENDPT_TX] == -1) {
208                 device_printf(dev, "couldn't find data bilk out\n");
209                 goto bad;
210         }
211
212         /* Find control interface endpoint */
213         id = usbd_get_interface_descriptor(sc->lgue_ctl_iface);
214         sc->lgue_ed[LGUE_ENDPT_INTR] = -1;
215         for (i = 0; i < id->bNumEndpoints; ++i) {
216                 ed = usbd_interface2endpoint_descriptor(sc->lgue_ctl_iface, i);
217                 if (!ed) {
218                         device_printf(dev,
219                             "couldn't get endpoint descriptor %d\n", i);
220                         goto bad;
221                 }
222                 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
223                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
224                         sc->lgue_ed[LGUE_ENDPT_INTR] = ed->bEndpointAddress;
225                 }
226         }
227
228         if (sc->lgue_ed[LGUE_ENDPT_INTR] == -1) {
229                 device_printf(dev, "couldn't find interrupt bilk in\n");
230                 goto bad;
231         }
232
233         /* Create interface */
234         ifp = &sc->lgue_arpcom.ac_if;
235         ifp->if_softc = sc;
236         if_initname(ifp, device_get_name(dev), device_get_unit(dev));
237         lgue_getmac(sc, eaddr);
238
239         ifp->if_mtu = lgue_getmtu(sc);
240         ifp->if_data.ifi_mtu = ifp->if_mtu;
241         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
242         ifp->if_baudrate = 10000000;
243         ifp->if_ioctl = lgue_ioctl;
244         ifp->if_start = lgue_start;
245         ifp->if_watchdog = lgue_watchdog;
246         ifp->if_init = lgue_init;
247         ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN);
248         ifq_set_ready(&ifp->if_snd);
249
250         /* Call attach routine */
251         ether_ifattach(ifp, eaddr, NULL);
252         usb_register_netisr();
253         sc->lgue_dying = 0;
254         return(0);
255
256 bad:
257         return(ENXIO);
258 }
259
260 /*
261  * Device detached.
262  */
263 static int
264 lgue_detach(device_t dev)
265 {
266         struct lgue_softc *sc;
267         struct ifnet *ifp;
268
269         sc = device_get_softc(dev);
270         ifp = &sc->lgue_arpcom.ac_if;
271         ether_ifdetach(ifp);
272
273         if (sc->lgue_ep[LGUE_ENDPT_TX] != NULL)
274                 usbd_abort_pipe(sc->lgue_ep[LGUE_ENDPT_TX]);
275         if (sc->lgue_ep[LGUE_ENDPT_RX] != NULL)
276                 usbd_abort_pipe(sc->lgue_ep[LGUE_ENDPT_RX]);
277         if (sc->lgue_ep[LGUE_ENDPT_INTR] != NULL)
278                 usbd_abort_pipe(sc->lgue_ep[LGUE_ENDPT_INTR]);
279         return(0);
280 }
281
282 /*
283  * Find data interface.
284  */
285 int
286 lgue_get_data_iface_no(usbd_device_handle dev, usb_interface_descriptor_t *id)
287 {
288         const usb_cdc_union_descriptor_t *cud;
289
290         cud = (const usb_cdc_union_descriptor_t *)usb_find_desc_if(dev,
291             UDESC_CS_INTERFACE, UDESCSUB_CDC_UNION, id);
292         return(cud ? cud->bSlaveInterface[0] : -1);
293 }
294
295 /*
296  * Get hard max mtu
297  */
298 static int
299 lgue_getmtu(struct lgue_softc *sc)
300 {
301         const usb_cdc_ethernet_descriptor_t *ced;
302         usb_interface_descriptor_t *id;
303
304         id = usbd_get_interface_descriptor(sc->lgue_ctl_iface);
305         if (id == NULL) {
306                 kprintf("usbd_get_interface_descriptor() returned NULL\n");
307                 return(ETHERMTU);
308         }
309
310         ced = (const usb_cdc_ethernet_descriptor_t *)usb_find_desc_if(sc->lgue_udev,
311             UDESC_CS_INTERFACE, UDESCSUB_CDC_ETHERNET, id);
312         if (ced == NULL) {
313                 kprintf("usb_find_desc_if() returned NULL\n");
314                 return(ETHERMTU);
315         }
316         return(UGETW(ced->wMaxSegmentSize));
317 }
318
319 /*
320  * Get mac address
321  */
322 static int
323 lgue_getmac(struct lgue_softc *sc, void *buf)
324 {
325         const usb_cdc_ethernet_descriptor_t *ced;
326         usb_interface_descriptor_t *id;
327         char sbuf[ETHER_ADDR_LEN * 2 + 1];
328         usbd_status err;
329         int i;
330
331         id = usbd_get_interface_descriptor(sc->lgue_ctl_iface);
332         if (id == NULL) goto bad;
333         ced = (const usb_cdc_ethernet_descriptor_t *)usb_find_desc_if(sc->lgue_udev,
334             UDESC_CS_INTERFACE, UDESCSUB_CDC_ETHERNET, id);
335         if (ced == NULL) goto bad;
336
337         err = usbd_get_string(sc->lgue_udev, ced->iMACAddress, sbuf);
338         if(err) {
339                 kprintf("Read MAC address failed\n");
340                 goto bad;
341         }
342
343         for (i = 0; i < ETHER_ADDR_LEN; ++i) {
344                 ((uByte *)buf)[i] = (hex(sbuf[i * 2]) << 4) + hex(sbuf[(i * 2) + 1]);
345         }
346         return(0);
347 bad:
348         return(-1);
349 }
350
351 /*
352  * Listen INTR pipe
353  */
354 static void
355 lgue_intrstart(struct ifnet *ifp)
356 {
357         struct lgue_softc *sc;
358
359         sc = ifp->if_softc;
360         usbd_setup_xfer(sc->lgue_intr_xfer, sc->lgue_ep[LGUE_ENDPT_INTR], sc,
361             sc->lgue_intr_buf, LGUE_BUFSZ,
362             USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, lgue_intreof);
363         usbd_transfer(sc->lgue_intr_xfer);
364 }
365
366 /*
367  * INTR arrived
368  */
369 static void
370 lgue_intreof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
371 {
372         struct ifnet *ifp;
373         struct lgue_softc *sc;
374
375         sc = priv;
376         if (sc->lgue_dying)
377                 return;
378
379         ifp = &sc->lgue_arpcom.ac_if;
380         lwkt_serialize_enter(ifp->if_serializer);
381         if (status != USBD_NORMAL_COMPLETION) {
382                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
383                         lwkt_serialize_exit(ifp->if_serializer);
384                         return;
385                 }
386                 if_printf(ifp, "usb error on intr: %s\n", usbd_errstr(status));
387                 if (status == USBD_STALLED)
388                         usbd_clear_endpoint_stall(sc->lgue_ep[LGUE_ENDPT_INTR]);
389                 lwkt_serialize_exit(ifp->if_serializer);
390                 return;
391         }
392         lgue_intrstart(ifp);
393         lwkt_serialize_exit(ifp->if_serializer);
394 }
395
396 /*
397  * Encap packet & send
398  */
399 static int
400 lgue_encap(struct lgue_softc *sc, struct mbuf *m)
401 {
402         struct ifnet *ifp;
403         struct lgue_queue_entry *entry;
404
405         ifp = &sc->lgue_arpcom.ac_if;
406         entry = kmalloc(sizeof(struct lgue_queue_entry), M_USBDEV , M_NOWAIT);
407         if (entry == NULL) {
408                 if_printf(ifp, "no memory for internal queue entry\n");
409                 return(ENOBUFS);
410         }
411         entry->entry_mbuf = m;
412
413         /* Put packet into internal queue tail */
414         STAILQ_INSERT_TAIL(&sc->lgue_tx_queue, entry, entry_next);
415         return(0);
416 }
417
418 /*
419  * Start transfer from internal queue
420  */
421 static int
422 lgue_start_transfer(struct lgue_softc *sc) {
423         usbd_status err;
424         struct lgue_queue_entry *entry;
425         struct ifnet *ifp;
426
427         if (STAILQ_EMPTY(&sc->lgue_tx_queue))
428                 return(0);
429
430         ifp = &sc->lgue_arpcom.ac_if;
431         entry = STAILQ_FIRST(&sc->lgue_tx_queue);
432         STAILQ_REMOVE_HEAD(&sc->lgue_tx_queue, entry_next);
433
434         m_copydata(entry->entry_mbuf, 0, entry->entry_mbuf->m_pkthdr.len,
435             sc->lgue_tx_buf);
436
437         /* Transmit */
438         usbd_setup_xfer(sc->lgue_tx_xfer, sc->lgue_ep[LGUE_ENDPT_TX], sc,
439             sc->lgue_tx_buf, entry->entry_mbuf->m_pkthdr.len,
440             USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, lgue_txeof);
441         err = usbd_transfer(sc->lgue_tx_xfer);
442         if (err != USBD_IN_PROGRESS) {
443                 m_freem(entry->entry_mbuf);
444                 kfree(entry, M_USBDEV);
445                 lgue_stop(sc);
446                 ifp->if_flags &= ~IFF_OACTIVE;
447                 return(EIO);
448         }
449
450         m_freem(entry->entry_mbuf);
451         kfree(entry, M_USBDEV);
452
453         sc->lgue_tx_cnt++;
454         ifp->if_flags |= IFF_OACTIVE;
455         ifp->if_timer = 5;
456         return(0);
457 }
458
459 /*
460  * Start call
461  */
462 static void
463 lgue_start_ipifunc(void *arg)
464 {
465         struct ifnet *ifp;
466         struct lwkt_msg *lmsg;
467
468         ifp = arg;
469         lmsg = &ifp->if_start_nmsg[mycpuid].lmsg;
470         crit_enter();
471         if (lmsg->ms_flags & MSGF_DONE)
472                 lwkt_sendmsg(ifnet_portfn(mycpuid), lmsg);
473         crit_exit();
474 }
475
476 /*
477  * Schedule start call
478  */
479 static void
480 lgue_start_schedule(struct ifnet *ifp)
481 {
482 #ifdef SMP
483         int cpu;
484
485         cpu = ifp->if_start_cpuid(ifp);
486         if (cpu != mycpuid)
487                 lwkt_send_ipiq(globaldata_find(cpu), lgue_start_ipifunc, ifp);
488         else
489 #endif
490                 lgue_start_ipifunc(ifp);
491 }
492
493 /*
494  * End of sending
495  */
496 static void
497 lgue_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
498 {
499         struct ifnet *ifp;
500         struct lgue_softc *sc;
501         usbd_status err;
502
503         sc = priv;
504         if (sc->lgue_dying)
505                 return;
506
507         ifp = &sc->lgue_arpcom.ac_if;
508
509         if (status != USBD_NORMAL_COMPLETION) {
510                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
511                         return;
512                 if (status == USBD_STALLED)
513                         usbd_clear_endpoint_stall(sc->lgue_ep[LGUE_ENDPT_TX]);
514                 return;
515         }
516         usbd_get_xfer_status(sc->lgue_tx_xfer, NULL, NULL, NULL,&err);
517         if (err)
518                 ifp->if_oerrors++;
519         else
520                 ifp->if_opackets++;
521
522         if (!STAILQ_EMPTY(&sc->lgue_tx_queue)) {
523                 lgue_start_schedule(ifp);
524         }
525
526         ifp->if_timer = 0;
527         ifp->if_flags &= ~IFF_OACTIVE;
528 }
529
530 /*
531  * Start transfer
532  */
533 static void
534 lgue_start(struct ifnet *ifp)
535 {
536         struct lgue_softc *sc;
537         struct mbuf *m_head;
538
539         sc = ifp->if_softc;
540         if (sc->lgue_dying)
541                 return;
542
543         if (ifp->if_flags & IFF_OACTIVE) {
544                 return;
545         }
546
547         /* To internal queue */
548         while ((m_head = ifq_dequeue(&ifp->if_snd, NULL)) != NULL) {
549                 if (lgue_encap(sc, m_head)) {
550                         m_freem(m_head);
551                         break;
552                 }
553                 /* Filter */
554                 BPF_MTAP(ifp, m_head);
555         }
556
557         lgue_start_transfer(sc);
558 }
559
560 /*
561  * Stop
562  */
563 static void
564 lgue_stop(struct lgue_softc *sc)
565 {
566         struct ifnet *ifp;
567         usbd_status err;
568         struct lgue_queue_entry *entry;
569
570         if (sc->lgue_dying)
571                 return;
572         sc->lgue_dying = 1;
573
574         ifp = &sc->lgue_arpcom.ac_if;
575
576         /* Stop transfers */
577         if (sc->lgue_ep[LGUE_ENDPT_TX] != NULL) {
578                 err = usbd_abort_pipe(sc->lgue_ep[LGUE_ENDPT_TX]);
579                 if (err) {
580                         if_printf(ifp, "abort tx pipe failed:%s\n",
581                             usbd_errstr(err));
582                 }
583                 err = usbd_close_pipe(sc->lgue_ep[LGUE_ENDPT_TX]);
584                 if (err) {
585                         if_printf(ifp, "close tx pipe failed:%s\n",
586                             usbd_errstr(err));
587                 }
588         }
589         if (sc->lgue_ep[LGUE_ENDPT_RX] != NULL) {
590                 err = usbd_abort_pipe(sc->lgue_ep[LGUE_ENDPT_RX]);
591                 if (err) {
592                         if_printf(ifp, "abort rx pipe failed:%s\n",
593                             usbd_errstr(err));
594                 }
595                 err = usbd_close_pipe(sc->lgue_ep[LGUE_ENDPT_RX]);
596                 if (err) {
597                         if_printf(ifp, "close rx pipe failed:%s\n",
598                             usbd_errstr(err));
599                 }
600         }
601         if (sc->lgue_ep[LGUE_ENDPT_INTR] != NULL) {
602                 err = usbd_abort_pipe(sc->lgue_ep[LGUE_ENDPT_INTR]);
603                 if (err) {
604                         if_printf(ifp, "abort intr pipe failed:%s\n",
605                             usbd_errstr(err));
606                 }
607                 err = usbd_close_pipe(sc->lgue_ep[LGUE_ENDPT_INTR]);
608                 if (err) {
609                         if_printf(ifp, "close intr pipe failed:%s\n",
610                             usbd_errstr(err));
611                 }
612         }
613
614         /* Free tx buffers */
615         if (sc->lgue_tx_buf != NULL) {
616                 kfree(sc->lgue_tx_buf, M_USBDEV);
617                 sc->lgue_tx_buf = NULL;
618         }
619         if (sc->lgue_tx_xfer != NULL) {
620                 usbd_free_xfer(sc->lgue_tx_xfer);
621                 sc->lgue_tx_xfer = NULL;
622         }
623
624         /* Free rx buffers */
625         if (sc->lgue_rx_buf != NULL) {
626                 kfree(sc->lgue_rx_buf, M_USBDEV);
627                 sc->lgue_rx_buf = NULL;
628         }
629         if (sc->lgue_rx_xfer != NULL) {
630                 usbd_free_xfer(sc->lgue_rx_xfer);
631                 sc->lgue_rx_xfer = NULL;
632         }
633
634         /* Free intr buffer */
635         if (sc->lgue_intr_buf != NULL) {
636                 kfree(sc->lgue_intr_buf, M_USBDEV);
637                 sc->lgue_intr_buf = NULL;
638         }
639         if (sc->lgue_intr_xfer != NULL) {
640                 usbd_free_xfer(sc->lgue_intr_xfer);
641                 sc->lgue_intr_xfer = NULL;
642         }
643
644         /* Clear internal queue */
645         while (!STAILQ_EMPTY(&sc->lgue_tx_queue)) {
646                 entry = STAILQ_FIRST(&sc->lgue_tx_queue);
647                 STAILQ_REMOVE_HEAD(&sc->lgue_tx_queue, entry_next);
648                 m_freem(entry->entry_mbuf);
649                 kfree(entry, M_USBDEV);
650         }
651
652         ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
653 }
654
655 /*
656  * Init
657  */
658 static void
659 lgue_init(void *xsc)
660 {
661         struct lgue_softc *sc;
662         struct ifnet *ifp;
663         usbd_status err;
664
665         sc = xsc;
666         ifp = &sc->lgue_arpcom.ac_if;
667
668         if (ifp->if_flags & IFF_RUNNING)
669                 return;
670
671         /* Create RX and TX bufs */
672         if (sc->lgue_tx_xfer == NULL) {
673                 sc->lgue_tx_xfer = usbd_alloc_xfer(sc->lgue_udev);
674                 if (sc->lgue_tx_xfer == NULL) {
675                         if_printf(ifp, "tx buffer allocate failed\n");
676                         return;
677                 }
678         }
679         sc->lgue_tx_buf = kmalloc(LGUE_BUFSZ, M_USBDEV, M_WAITOK);
680         if (sc->lgue_tx_buf == NULL) {
681                 if_printf(ifp, "tx internal buffer allocate failed\n");
682                 return;
683         }
684
685         if (sc->lgue_rx_xfer == NULL) {
686                 sc->lgue_rx_xfer = usbd_alloc_xfer(sc->lgue_udev);
687                 if (sc->lgue_rx_xfer == NULL) {
688                         if_printf(ifp, "rx buffer allocate failed\n");
689                         return;
690                 }
691         }
692         sc->lgue_rx_buf = kmalloc(LGUE_BUFSZ, M_USBDEV, M_WAITOK);
693         if (sc->lgue_rx_buf == NULL) {
694                 if_printf(ifp, "rx internal buffer allocate failed\n");
695                 return;
696         }
697
698         /* Create INTR buf */
699         if (sc->lgue_intr_xfer == NULL) {
700                 sc->lgue_intr_xfer = usbd_alloc_xfer(sc->lgue_udev);
701                 if (sc->lgue_intr_xfer == NULL) {
702                         if_printf(ifp, "intr buffer allocate failed\n");
703                         return;
704                 }
705         }
706         sc->lgue_intr_buf = kmalloc(LGUE_BUFSZ, M_USBDEV, M_WAITOK);
707
708         /* Open RX and TX pipes. */
709         err = usbd_open_pipe(sc->lgue_data_iface, sc->lgue_ed[LGUE_ENDPT_RX],
710             USBD_EXCLUSIVE_USE, &sc->lgue_ep[LGUE_ENDPT_RX]);
711         if (err) {
712                 if_printf(ifp, "open RX pipe failed: %s\n", usbd_errstr(err));
713                 return;
714         }
715         err = usbd_open_pipe(sc->lgue_data_iface, sc->lgue_ed[LGUE_ENDPT_TX],
716             USBD_EXCLUSIVE_USE, &sc->lgue_ep[LGUE_ENDPT_TX]);
717         if (err) {
718                 if_printf(ifp, "open TX pipe failed: %s\n", usbd_errstr(err));
719                 return;
720         }
721         /* Open INTR pipe. */
722         err = usbd_open_pipe(sc->lgue_ctl_iface, sc->lgue_ed[LGUE_ENDPT_INTR],
723             USBD_EXCLUSIVE_USE, &sc->lgue_ep[LGUE_ENDPT_INTR]);
724         if (err) {
725                 if_printf(ifp, "open INTR pipe failed: %s\n", usbd_errstr(err));
726                 return;
727         }
728
729         /* Create internal queue */
730         STAILQ_INIT(&sc->lgue_tx_queue);
731
732         ifp->if_flags |= IFF_RUNNING;
733         ifp->if_flags &= ~IFF_OACTIVE;
734
735         sc->lgue_dying = 0;
736
737         lgue_rxstart(ifp);
738         lgue_intrstart(ifp);
739 }
740
741 /*
742  * New mbuf
743  */
744 static int
745 lgue_newbuf(struct lgue_softc *sc, int len, struct mbuf **m_buf)
746 {
747         struct ifnet *ifp;
748
749         ifp = &sc->lgue_arpcom.ac_if;
750         *m_buf = NULL;
751
752         /* Allocate mbuf */
753         *m_buf = m_getcl(MB_DONTWAIT, MT_DATA, MT_HEADER);
754         if (*m_buf == NULL) {
755                 if_printf(ifp, " no memory for rx buffer --- packet dropped!\n");
756                 return(ENOBUFS);
757         }
758         (*m_buf)->m_len = (*m_buf)->m_pkthdr.len = MCLBYTES;
759         m_adj(*m_buf, ETHER_ALIGN);
760         return(0);
761 }
762
763 /*
764  * Start read
765  */
766 static void
767 lgue_rxstart(struct ifnet *ifp)
768 {
769         struct lgue_softc *sc;
770
771         sc = ifp->if_softc;
772         if (sc->lgue_dying)
773                 return;
774
775         usbd_setup_xfer(sc->lgue_rx_xfer, sc->lgue_ep[LGUE_ENDPT_RX], sc,
776             sc->lgue_rx_buf, LGUE_BUFSZ,
777             USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, lgue_rxeof);
778         usbd_transfer(sc->lgue_rx_xfer);
779 }
780
781 /*
782  * A frame has been uploaded: pass the resulting mbuf up to
783  * the higher level protocols.
784  */
785 static void
786 lgue_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
787 {
788         struct lgue_softc       *sc;
789         struct mbuf             *m;
790         struct ifnet    *ifp;
791         int                     total_len;
792
793         sc = priv;
794         if (sc->lgue_dying)
795                 return;
796
797         ifp = &sc->lgue_arpcom.ac_if;
798
799         total_len = 0;
800
801         if (!(ifp->if_flags & IFF_RUNNING))
802                 return;
803
804         if (status != USBD_NORMAL_COMPLETION) {
805                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
806                         return;
807                 if (usbd_ratecheck(&sc->lgue_rx_notice)) {
808                         if_printf(ifp, "usb error on rx:%s\n",
809                             usbd_errstr(status));
810                 }
811                 if (status == USBD_STALLED)
812                         usbd_clear_endpoint_stall(sc->lgue_ep[LGUE_ENDPT_RX]);
813                 goto done;
814         }
815
816         usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
817
818         if (total_len < sizeof(struct ether_header)) {
819                 ifp->if_ierrors++;
820                 goto done;
821         }
822
823         if (lgue_newbuf(sc, total_len, &m) == ENOBUFS) {
824                 ifp->if_ierrors++;
825                 return;
826         }
827
828         ifp->if_ipackets++;
829         m_copyback(m, 0, total_len, sc->lgue_rx_buf);
830         m->m_pkthdr.rcvif = ifp;
831         m->m_pkthdr.len = m->m_len = total_len;
832
833         usb_ether_input(m);
834         lgue_rxstart(ifp);
835         return;
836 done:
837         usbd_setup_xfer(sc->lgue_rx_xfer, sc->lgue_ep[LGUE_ENDPT_RX], sc,
838             sc->lgue_rx_buf, LGUE_BUFSZ,
839             USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, lgue_rxeof);
840         usbd_transfer(sc->lgue_rx_xfer);
841 }
842
843 /*
844  * Control
845  */
846 static int
847 lgue_ioctl(struct ifnet *ifp, u_long command, caddr_t data, struct ucred *cr)
848 {
849         struct lgue_softc *sc;
850         struct ifreq *ifr;
851         int err;
852
853         err = 0;
854         ifr = (struct ifreq *)data;
855         sc = ifp->if_softc;
856
857         switch(command) {
858         case SIOCSIFFLAGS:
859                 if (ifp->if_flags & IFF_UP) {
860                         if (!(ifp->if_flags & IFF_RUNNING))
861                                 lgue_init(sc);
862                 } else if (ifp->if_flags & IFF_RUNNING) {
863                         lgue_stop(sc);
864                 }
865                 sc->lgue_if_flags = ifp->if_flags;
866                 err = 0;
867                 break;
868 #if 0
869         case SIOCADDMULTI:
870         case SIOCDELMULTI:
871                 err = 0;
872                 break;
873 #endif
874         case SIOCSIFMTU:
875                 ifp->if_mtu = ifr->ifr_mtu;
876                 break;
877         default:
878                 err = ether_ioctl(ifp, command, data);
879                 break;
880         }
881         return(err);
882 }
883
884 /*
885  * Watchdog
886  */
887 static void
888 lgue_watchdog(struct ifnet *ifp)
889 {
890         ifp->if_oerrors++;
891
892         if (!ifq_is_empty(&ifp->if_snd))
893                 lgue_start_schedule(ifp);
894 }
895
896 /*
897  * Hex -> bin
898  */
899 static int
900 hex(char ch)
901 {
902         if ((ch >= 'a') && (ch <= 'f')) return (ch-'a'+10);
903         if ((ch >= '0') && (ch <= '9')) return (ch-'0');
904         if ((ch >= 'A') && (ch <= 'F')) return (ch-'A'+10);
905         return (-1);
906 }