kernel: Make SMP support default (and non-optional).
[dragonfly.git] / sys / dev / netif / lgue / if_lgue.c
CommitLineData
a700a71b
SW
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 */
42static struct usb_devno lgue_devs[] = {
9de4e294 43 { USB_DEVICE(0x1004, 0x61a2) } /* LG P500 */
a700a71b
SW
44};
45
46static int lgue_match(device_t);
47static int lgue_attach(device_t);
48static int lgue_detach(device_t);
49
50static void lgue_start(struct ifnet *);
51static void lgue_stop(struct lgue_softc *);
52static void lgue_init(void *);
53static void lgue_watchdog(struct ifnet *);
54static int lgue_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
55
56static int lgue_encap(struct lgue_softc *, struct mbuf *);
57static int lgue_start_transfer(struct lgue_softc *);
58
59static void lgue_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
60
61static void lgue_start_ipifunc(void *);
62static void lgue_start_schedule(struct ifnet *);
63
64static int lgue_newbuf(struct lgue_softc *, int, struct mbuf **);
65static void lgue_rxstart(struct ifnet *);
66static void lgue_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
67
68static void lgue_intrstart(struct ifnet *);
69static void lgue_intreof(usbd_xfer_handle, usbd_private_handle, usbd_status);
70
71static int lgue_get_data_iface_no(usbd_device_handle,
72 usb_interface_descriptor_t *);
73
74static int lgue_getmac(struct lgue_softc *, void *);
75static int lgue_getmtu(struct lgue_softc *);
76
77static int hex(char);
78
79static 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
87static driver_t lgue_driver = {
88 "lgue",
89 lgue_methods,
90 sizeof(struct lgue_softc)
91};
92
93static devclass_t lgue_devclass;
94
95DECLARE_DUMMY_MODULE(if_lgue);
8515b7f9 96DRIVER_MODULE(lgue, uhub, lgue_driver, lgue_devclass, usbd_driver_load, NULL);
a700a71b
SW
97MODULE_DEPEND(lgue, usb, 1, 1, 1);
98
99/*
100 * Probe chip
101 */
102static int
103lgue_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 */
125static int
126lgue_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
256bad:
257 return(ENXIO);
258}
259
260/*
261 * Device detached.
262 */
263static int
264lgue_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 */
285int
286lgue_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 */
298static int
299lgue_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);
9de4e294
SW
305 if (id == NULL) {
306 kprintf("usbd_get_interface_descriptor() returned NULL\n");
307 return(ETHERMTU);
308 }
309
a700a71b
SW
310 ced = (const usb_cdc_ethernet_descriptor_t *)usb_find_desc_if(sc->lgue_udev,
311 UDESC_CS_INTERFACE, UDESCSUB_CDC_ETHERNET, id);
9de4e294
SW
312 if (ced == NULL) {
313 kprintf("usb_find_desc_if() returned NULL\n");
314 return(ETHERMTU);
315 }
a700a71b 316 return(UGETW(ced->wMaxSegmentSize));
a700a71b
SW
317}
318
319/*
320 * Get mac address
321 */
322static int
323lgue_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);
347bad:
348 return(-1);
349}
350
351/*
352 * Listen INTR pipe
353 */
354static void
355lgue_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 */
369static void
370lgue_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) {
b3ec9cec 382 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
a700a71b
SW
383 lwkt_serialize_exit(ifp->if_serializer);
384 return;
b3ec9cec
SW
385 }
386 if_printf(ifp, "usb error on intr: %s\n", usbd_errstr(status));
a700a71b
SW
387 if (status == USBD_STALLED)
388 usbd_clear_endpoint_stall(sc->lgue_ep[LGUE_ENDPT_INTR]);
b3ec9cec 389 lwkt_serialize_exit(ifp->if_serializer);
a700a71b
SW
390 return;
391 }
392 lgue_intrstart(ifp);
393 lwkt_serialize_exit(ifp->if_serializer);
394}
395
396/*
397 * Encap packet & send
398 */
399static int
400lgue_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 */
421static int
422lgue_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 */
462static void
463lgue_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)
006f2e1f 472 lwkt_sendmsg(netisr_portfn(mycpuid), lmsg);
a700a71b
SW
473 crit_exit();
474}
475
476/*
477 * Schedule start call
478 */
479static void
480lgue_start_schedule(struct ifnet *ifp)
481{
a700a71b
SW
482 int cpu;
483
484 cpu = ifp->if_start_cpuid(ifp);
485 if (cpu != mycpuid)
486 lwkt_send_ipiq(globaldata_find(cpu), lgue_start_ipifunc, ifp);
487 else
a700a71b
SW
488 lgue_start_ipifunc(ifp);
489}
490
491/*
492 * End of sending
493 */
494static void
495lgue_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
496{
497 struct ifnet *ifp;
498 struct lgue_softc *sc;
499 usbd_status err;
500
501 sc = priv;
502 if (sc->lgue_dying)
503 return;
504
505 ifp = &sc->lgue_arpcom.ac_if;
506
507 if (status != USBD_NORMAL_COMPLETION) {
508 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
509 return;
510 if (status == USBD_STALLED)
511 usbd_clear_endpoint_stall(sc->lgue_ep[LGUE_ENDPT_TX]);
512 return;
513 }
514 usbd_get_xfer_status(sc->lgue_tx_xfer, NULL, NULL, NULL,&err);
515 if (err)
516 ifp->if_oerrors++;
517 else
518 ifp->if_opackets++;
519
520 if (!STAILQ_EMPTY(&sc->lgue_tx_queue)) {
521 lgue_start_schedule(ifp);
522 }
523
524 ifp->if_timer = 0;
525 ifp->if_flags &= ~IFF_OACTIVE;
526}
527
528/*
529 * Start transfer
530 */
531static void
532lgue_start(struct ifnet *ifp)
533{
534 struct lgue_softc *sc;
535 struct mbuf *m_head;
536
537 sc = ifp->if_softc;
538 if (sc->lgue_dying)
539 return;
540
541 if (ifp->if_flags & IFF_OACTIVE) {
542 return;
543 }
544
545 /* To internal queue */
546 while ((m_head = ifq_dequeue(&ifp->if_snd, NULL)) != NULL) {
547 if (lgue_encap(sc, m_head)) {
548 m_freem(m_head);
549 break;
550 }
551 /* Filter */
552 BPF_MTAP(ifp, m_head);
553 }
554
555 lgue_start_transfer(sc);
556}
557
558/*
559 * Stop
560 */
561static void
562lgue_stop(struct lgue_softc *sc)
563{
564 struct ifnet *ifp;
565 usbd_status err;
566 struct lgue_queue_entry *entry;
567
568 if (sc->lgue_dying)
569 return;
570 sc->lgue_dying = 1;
571
572 ifp = &sc->lgue_arpcom.ac_if;
573
574 /* Stop transfers */
575 if (sc->lgue_ep[LGUE_ENDPT_TX] != NULL) {
576 err = usbd_abort_pipe(sc->lgue_ep[LGUE_ENDPT_TX]);
577 if (err) {
578 if_printf(ifp, "abort tx pipe failed:%s\n",
579 usbd_errstr(err));
580 }
581 err = usbd_close_pipe(sc->lgue_ep[LGUE_ENDPT_TX]);
582 if (err) {
583 if_printf(ifp, "close tx pipe failed:%s\n",
584 usbd_errstr(err));
585 }
586 }
587 if (sc->lgue_ep[LGUE_ENDPT_RX] != NULL) {
588 err = usbd_abort_pipe(sc->lgue_ep[LGUE_ENDPT_RX]);
589 if (err) {
590 if_printf(ifp, "abort rx pipe failed:%s\n",
591 usbd_errstr(err));
592 }
593 err = usbd_close_pipe(sc->lgue_ep[LGUE_ENDPT_RX]);
594 if (err) {
595 if_printf(ifp, "close rx pipe failed:%s\n",
596 usbd_errstr(err));
597 }
598 }
599 if (sc->lgue_ep[LGUE_ENDPT_INTR] != NULL) {
600 err = usbd_abort_pipe(sc->lgue_ep[LGUE_ENDPT_INTR]);
601 if (err) {
602 if_printf(ifp, "abort intr pipe failed:%s\n",
603 usbd_errstr(err));
604 }
605 err = usbd_close_pipe(sc->lgue_ep[LGUE_ENDPT_INTR]);
606 if (err) {
607 if_printf(ifp, "close intr pipe failed:%s\n",
608 usbd_errstr(err));
609 }
610 }
611
612 /* Free tx buffers */
613 if (sc->lgue_tx_buf != NULL) {
614 kfree(sc->lgue_tx_buf, M_USBDEV);
615 sc->lgue_tx_buf = NULL;
616 }
617 if (sc->lgue_tx_xfer != NULL) {
618 usbd_free_xfer(sc->lgue_tx_xfer);
619 sc->lgue_tx_xfer = NULL;
620 }
621
622 /* Free rx buffers */
623 if (sc->lgue_rx_buf != NULL) {
624 kfree(sc->lgue_rx_buf, M_USBDEV);
625 sc->lgue_rx_buf = NULL;
626 }
627 if (sc->lgue_rx_xfer != NULL) {
628 usbd_free_xfer(sc->lgue_rx_xfer);
629 sc->lgue_rx_xfer = NULL;
630 }
631
632 /* Free intr buffer */
633 if (sc->lgue_intr_buf != NULL) {
634 kfree(sc->lgue_intr_buf, M_USBDEV);
635 sc->lgue_intr_buf = NULL;
636 }
637 if (sc->lgue_intr_xfer != NULL) {
638 usbd_free_xfer(sc->lgue_intr_xfer);
639 sc->lgue_intr_xfer = NULL;
640 }
641
642 /* Clear internal queue */
643 while (!STAILQ_EMPTY(&sc->lgue_tx_queue)) {
644 entry = STAILQ_FIRST(&sc->lgue_tx_queue);
645 STAILQ_REMOVE_HEAD(&sc->lgue_tx_queue, entry_next);
646 m_freem(entry->entry_mbuf);
647 kfree(entry, M_USBDEV);
648 }
649
650 ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
651}
652
653/*
654 * Init
655 */
656static void
657lgue_init(void *xsc)
658{
659 struct lgue_softc *sc;
660 struct ifnet *ifp;
661 usbd_status err;
662
663 sc = xsc;
664 ifp = &sc->lgue_arpcom.ac_if;
665
666 if (ifp->if_flags & IFF_RUNNING)
667 return;
668
669 /* Create RX and TX bufs */
670 if (sc->lgue_tx_xfer == NULL) {
671 sc->lgue_tx_xfer = usbd_alloc_xfer(sc->lgue_udev);
672 if (sc->lgue_tx_xfer == NULL) {
673 if_printf(ifp, "tx buffer allocate failed\n");
674 return;
675 }
676 }
677 sc->lgue_tx_buf = kmalloc(LGUE_BUFSZ, M_USBDEV, M_WAITOK);
a700a71b
SW
678
679 if (sc->lgue_rx_xfer == NULL) {
680 sc->lgue_rx_xfer = usbd_alloc_xfer(sc->lgue_udev);
681 if (sc->lgue_rx_xfer == NULL) {
682 if_printf(ifp, "rx buffer allocate failed\n");
683 return;
684 }
685 }
686 sc->lgue_rx_buf = kmalloc(LGUE_BUFSZ, M_USBDEV, M_WAITOK);
a700a71b
SW
687
688 /* Create INTR buf */
689 if (sc->lgue_intr_xfer == NULL) {
690 sc->lgue_intr_xfer = usbd_alloc_xfer(sc->lgue_udev);
691 if (sc->lgue_intr_xfer == NULL) {
692 if_printf(ifp, "intr buffer allocate failed\n");
693 return;
694 }
695 }
696 sc->lgue_intr_buf = kmalloc(LGUE_BUFSZ, M_USBDEV, M_WAITOK);
697
698 /* Open RX and TX pipes. */
699 err = usbd_open_pipe(sc->lgue_data_iface, sc->lgue_ed[LGUE_ENDPT_RX],
700 USBD_EXCLUSIVE_USE, &sc->lgue_ep[LGUE_ENDPT_RX]);
701 if (err) {
702 if_printf(ifp, "open RX pipe failed: %s\n", usbd_errstr(err));
703 return;
704 }
705 err = usbd_open_pipe(sc->lgue_data_iface, sc->lgue_ed[LGUE_ENDPT_TX],
706 USBD_EXCLUSIVE_USE, &sc->lgue_ep[LGUE_ENDPT_TX]);
707 if (err) {
708 if_printf(ifp, "open TX pipe failed: %s\n", usbd_errstr(err));
709 return;
710 }
711 /* Open INTR pipe. */
712 err = usbd_open_pipe(sc->lgue_ctl_iface, sc->lgue_ed[LGUE_ENDPT_INTR],
713 USBD_EXCLUSIVE_USE, &sc->lgue_ep[LGUE_ENDPT_INTR]);
714 if (err) {
715 if_printf(ifp, "open INTR pipe failed: %s\n", usbd_errstr(err));
716 return;
717 }
718
719 /* Create internal queue */
720 STAILQ_INIT(&sc->lgue_tx_queue);
721
722 ifp->if_flags |= IFF_RUNNING;
723 ifp->if_flags &= ~IFF_OACTIVE;
724
725 sc->lgue_dying = 0;
726
727 lgue_rxstart(ifp);
728 lgue_intrstart(ifp);
729}
730
731/*
732 * New mbuf
733 */
734static int
735lgue_newbuf(struct lgue_softc *sc, int len, struct mbuf **m_buf)
736{
737 struct ifnet *ifp;
738
739 ifp = &sc->lgue_arpcom.ac_if;
740 *m_buf = NULL;
741
742 /* Allocate mbuf */
743 *m_buf = m_getcl(MB_DONTWAIT, MT_DATA, MT_HEADER);
744 if (*m_buf == NULL) {
745 if_printf(ifp, " no memory for rx buffer --- packet dropped!\n");
746 return(ENOBUFS);
747 }
748 (*m_buf)->m_len = (*m_buf)->m_pkthdr.len = MCLBYTES;
749 m_adj(*m_buf, ETHER_ALIGN);
750 return(0);
751}
752
753/*
754 * Start read
755 */
756static void
757lgue_rxstart(struct ifnet *ifp)
758{
759 struct lgue_softc *sc;
760
761 sc = ifp->if_softc;
762 if (sc->lgue_dying)
763 return;
764
765 usbd_setup_xfer(sc->lgue_rx_xfer, sc->lgue_ep[LGUE_ENDPT_RX], sc,
766 sc->lgue_rx_buf, LGUE_BUFSZ,
767 USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, lgue_rxeof);
768 usbd_transfer(sc->lgue_rx_xfer);
769}
770
771/*
772 * A frame has been uploaded: pass the resulting mbuf up to
773 * the higher level protocols.
774 */
775static void
776lgue_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
777{
778 struct lgue_softc *sc;
779 struct mbuf *m;
780 struct ifnet *ifp;
781 int total_len;
782
783 sc = priv;
784 if (sc->lgue_dying)
785 return;
786
787 ifp = &sc->lgue_arpcom.ac_if;
788
789 total_len = 0;
790
791 if (!(ifp->if_flags & IFF_RUNNING))
792 return;
793
794 if (status != USBD_NORMAL_COMPLETION) {
795 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
796 return;
797 if (usbd_ratecheck(&sc->lgue_rx_notice)) {
798 if_printf(ifp, "usb error on rx:%s\n",
799 usbd_errstr(status));
800 }
801 if (status == USBD_STALLED)
802 usbd_clear_endpoint_stall(sc->lgue_ep[LGUE_ENDPT_RX]);
803 goto done;
804 }
805
806 usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
807
808 if (total_len < sizeof(struct ether_header)) {
809 ifp->if_ierrors++;
810 goto done;
811 }
812
813 if (lgue_newbuf(sc, total_len, &m) == ENOBUFS) {
814 ifp->if_ierrors++;
815 return;
816 }
817
818 ifp->if_ipackets++;
819 m_copyback(m, 0, total_len, sc->lgue_rx_buf);
820 m->m_pkthdr.rcvif = ifp;
821 m->m_pkthdr.len = m->m_len = total_len;
822
823 usb_ether_input(m);
824 lgue_rxstart(ifp);
825 return;
826done:
827 usbd_setup_xfer(sc->lgue_rx_xfer, sc->lgue_ep[LGUE_ENDPT_RX], sc,
828 sc->lgue_rx_buf, LGUE_BUFSZ,
829 USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, lgue_rxeof);
830 usbd_transfer(sc->lgue_rx_xfer);
831}
832
833/*
834 * Control
835 */
836static int
837lgue_ioctl(struct ifnet *ifp, u_long command, caddr_t data, struct ucred *cr)
838{
839 struct lgue_softc *sc;
840 struct ifreq *ifr;
841 int err;
842
843 err = 0;
844 ifr = (struct ifreq *)data;
845 sc = ifp->if_softc;
846
847 switch(command) {
848 case SIOCSIFFLAGS:
849 if (ifp->if_flags & IFF_UP) {
850 if (!(ifp->if_flags & IFF_RUNNING))
851 lgue_init(sc);
852 } else if (ifp->if_flags & IFF_RUNNING) {
853 lgue_stop(sc);
854 }
855 sc->lgue_if_flags = ifp->if_flags;
856 err = 0;
857 break;
858#if 0
859 case SIOCADDMULTI:
860 case SIOCDELMULTI:
861 err = 0;
862 break;
863#endif
864 case SIOCSIFMTU:
865 ifp->if_mtu = ifr->ifr_mtu;
866 break;
867 default:
868 err = ether_ioctl(ifp, command, data);
869 break;
870 }
871 return(err);
872}
873
874/*
875 * Watchdog
876 */
877static void
878lgue_watchdog(struct ifnet *ifp)
879{
a700a71b
SW
880 ifp->if_oerrors++;
881
882 if (!ifq_is_empty(&ifp->if_snd))
883 lgue_start_schedule(ifp);
884}
885
886/*
887 * Hex -> bin
888 */
889static int
890hex(char ch)
891{
892 if ((ch >= 'a') && (ch <= 'f')) return (ch-'a'+10);
893 if ((ch >= '0') && (ch <= '9')) return (ch-'0');
894 if ((ch >= 'A') && (ch <= 'F')) return (ch-'A'+10);
895 return (-1);
896}