3 * Written by Yellow Rabbit <yrabbit@sdf.lonestar.org>
9 * Takes two interfaces.
10 * IN and OUT endpoints on the data interface (altsetting).
11 * Interrupt endpoint on the control interface.
14 * Transfer frames without modification (AS IS).
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>
25 #include <net/ifq_var.h>
26 #include <net/if_arp.h>
27 #include <net/ethernet.h>
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>
40 * Supported device vendors/products
42 static struct usb_devno lgue_devs[] = {
43 { USB_DEVICE(0x1004, 0x61a2) } /* LG P500 */
46 static int lgue_match(device_t);
47 static int lgue_attach(device_t);
48 static int lgue_detach(device_t);
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 *);
56 static int lgue_encap(struct lgue_softc *, struct mbuf *);
57 static int lgue_start_transfer(struct lgue_softc *);
59 static void lgue_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
61 static void lgue_start_ipifunc(void *);
62 static void lgue_start_schedule(struct ifnet *);
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);
68 static void lgue_intrstart(struct ifnet *);
69 static void lgue_intreof(usbd_xfer_handle, usbd_private_handle, usbd_status);
71 static int lgue_get_data_iface_no(usbd_device_handle,
72 usb_interface_descriptor_t *);
74 static int lgue_getmac(struct lgue_softc *, void *);
75 static int lgue_getmtu(struct lgue_softc *);
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),
87 static driver_t lgue_driver = {
90 sizeof(struct lgue_softc)
93 static devclass_t lgue_devclass;
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);
103 lgue_match(device_t dev)
105 struct usb_attach_arg *uaa;
106 usb_interface_descriptor_t *id;
108 uaa = device_get_ivars(dev);
109 if (uaa->iface == NULL)
112 if (usb_lookup(lgue_devs, uaa->vendor, uaa->product) != NULL) {
113 id = usbd_get_interface_descriptor(uaa->iface);
115 id->bInterfaceClass == UICLASS_CDC &&
116 id->bInterfaceSubClass == UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL)
117 return(UMATCH_VENDOR_PRODUCT);
123 * Attach the interface.
126 lgue_attach(device_t dev)
128 struct lgue_softc *sc;
129 struct usb_attach_arg *uaa;
131 usb_interface_descriptor_t *id;
132 usb_endpoint_descriptor_t *ed;
134 u_char eaddr[ETHER_ADDR_LEN];
137 sc = device_get_softc(dev);
138 uaa = device_get_ivars(dev);
140 sc->lgue_ctl_iface = uaa->iface;
141 sc->lgue_udev = uaa->device;
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",
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);
155 if (sc->lgue_data_iface_no == -1) {
156 device_printf(dev, "no data interface number\n");
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]);
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) {
170 "no alternate data interface. err:%s\n",
174 sc->lgue_data_iface = uaa->ifaces[i];
175 uaa->ifaces[i] = NULL;
179 if (sc->lgue_data_iface == NULL) {
180 device_printf(dev, "no data interface\n");
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);
191 "couldn't get endpoint descriptor %d\n", i);
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;
203 if (sc->lgue_ed[LGUE_ENDPT_RX] == -1) {
204 device_printf(dev, "couldn't find data bilk in\n");
207 if (sc->lgue_ed[LGUE_ENDPT_TX] == -1) {
208 device_printf(dev, "couldn't find data bilk out\n");
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);
219 "couldn't get endpoint descriptor %d\n", i);
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;
228 if (sc->lgue_ed[LGUE_ENDPT_INTR] == -1) {
229 device_printf(dev, "couldn't find interrupt bilk in\n");
233 /* Create interface */
234 ifp = &sc->lgue_arpcom.ac_if;
236 if_initname(ifp, device_get_name(dev), device_get_unit(dev));
237 lgue_getmac(sc, eaddr);
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);
250 /* Call attach routine */
251 ether_ifattach(ifp, eaddr, NULL);
252 usb_register_netisr();
264 lgue_detach(device_t dev)
266 struct lgue_softc *sc;
269 sc = device_get_softc(dev);
270 ifp = &sc->lgue_arpcom.ac_if;
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]);
283 * Find data interface.
286 lgue_get_data_iface_no(usbd_device_handle dev, usb_interface_descriptor_t *id)
288 const usb_cdc_union_descriptor_t *cud;
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);
299 lgue_getmtu(struct lgue_softc *sc)
301 const usb_cdc_ethernet_descriptor_t *ced;
302 usb_interface_descriptor_t *id;
304 id = usbd_get_interface_descriptor(sc->lgue_ctl_iface);
306 kprintf("usbd_get_interface_descriptor() returned NULL\n");
310 ced = (const usb_cdc_ethernet_descriptor_t *)usb_find_desc_if(sc->lgue_udev,
311 UDESC_CS_INTERFACE, UDESCSUB_CDC_ETHERNET, id);
313 kprintf("usb_find_desc_if() returned NULL\n");
316 return(UGETW(ced->wMaxSegmentSize));
323 lgue_getmac(struct lgue_softc *sc, void *buf)
325 const usb_cdc_ethernet_descriptor_t *ced;
326 usb_interface_descriptor_t *id;
327 char sbuf[ETHER_ADDR_LEN * 2 + 1];
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;
337 err = usbd_get_string(sc->lgue_udev, ced->iMACAddress, sbuf);
339 kprintf("Read MAC address failed\n");
343 for (i = 0; i < ETHER_ADDR_LEN; ++i) {
344 ((uByte *)buf)[i] = (hex(sbuf[i * 2]) << 4) + hex(sbuf[(i * 2) + 1]);
355 lgue_intrstart(struct ifnet *ifp)
357 struct lgue_softc *sc;
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);
370 lgue_intreof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
373 struct lgue_softc *sc;
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);
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);
393 lwkt_serialize_exit(ifp->if_serializer);
397 * Encap packet & send
400 lgue_encap(struct lgue_softc *sc, struct mbuf *m)
403 struct lgue_queue_entry *entry;
405 ifp = &sc->lgue_arpcom.ac_if;
406 entry = kmalloc(sizeof(struct lgue_queue_entry), M_USBDEV , M_NOWAIT);
408 if_printf(ifp, "no memory for internal queue entry\n");
411 entry->entry_mbuf = m;
413 /* Put packet into internal queue tail */
414 STAILQ_INSERT_TAIL(&sc->lgue_tx_queue, entry, entry_next);
419 * Start transfer from internal queue
422 lgue_start_transfer(struct lgue_softc *sc) {
424 struct lgue_queue_entry *entry;
427 if (STAILQ_EMPTY(&sc->lgue_tx_queue))
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);
434 m_copydata(entry->entry_mbuf, 0, entry->entry_mbuf->m_pkthdr.len,
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);
446 ifp->if_flags &= ~IFF_OACTIVE;
450 m_freem(entry->entry_mbuf);
451 kfree(entry, M_USBDEV);
454 ifp->if_flags |= IFF_OACTIVE;
463 lgue_start_ipifunc(void *arg)
466 struct lwkt_msg *lmsg;
469 lmsg = &ifp->if_start_nmsg[mycpuid].lmsg;
471 if (lmsg->ms_flags & MSGF_DONE)
472 lwkt_sendmsg(netisr_portfn(mycpuid), lmsg);
477 * Schedule start call
480 lgue_start_schedule(struct ifnet *ifp)
485 cpu = ifp->if_start_cpuid(ifp);
487 lwkt_send_ipiq(globaldata_find(cpu), lgue_start_ipifunc, ifp);
490 lgue_start_ipifunc(ifp);
497 lgue_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
500 struct lgue_softc *sc;
507 ifp = &sc->lgue_arpcom.ac_if;
509 if (status != USBD_NORMAL_COMPLETION) {
510 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
512 if (status == USBD_STALLED)
513 usbd_clear_endpoint_stall(sc->lgue_ep[LGUE_ENDPT_TX]);
516 usbd_get_xfer_status(sc->lgue_tx_xfer, NULL, NULL, NULL,&err);
522 if (!STAILQ_EMPTY(&sc->lgue_tx_queue)) {
523 lgue_start_schedule(ifp);
527 ifp->if_flags &= ~IFF_OACTIVE;
534 lgue_start(struct ifnet *ifp)
536 struct lgue_softc *sc;
543 if (ifp->if_flags & IFF_OACTIVE) {
547 /* To internal queue */
548 while ((m_head = ifq_dequeue(&ifp->if_snd, NULL)) != NULL) {
549 if (lgue_encap(sc, m_head)) {
554 BPF_MTAP(ifp, m_head);
557 lgue_start_transfer(sc);
564 lgue_stop(struct lgue_softc *sc)
568 struct lgue_queue_entry *entry;
574 ifp = &sc->lgue_arpcom.ac_if;
577 if (sc->lgue_ep[LGUE_ENDPT_TX] != NULL) {
578 err = usbd_abort_pipe(sc->lgue_ep[LGUE_ENDPT_TX]);
580 if_printf(ifp, "abort tx pipe failed:%s\n",
583 err = usbd_close_pipe(sc->lgue_ep[LGUE_ENDPT_TX]);
585 if_printf(ifp, "close tx pipe failed:%s\n",
589 if (sc->lgue_ep[LGUE_ENDPT_RX] != NULL) {
590 err = usbd_abort_pipe(sc->lgue_ep[LGUE_ENDPT_RX]);
592 if_printf(ifp, "abort rx pipe failed:%s\n",
595 err = usbd_close_pipe(sc->lgue_ep[LGUE_ENDPT_RX]);
597 if_printf(ifp, "close rx pipe failed:%s\n",
601 if (sc->lgue_ep[LGUE_ENDPT_INTR] != NULL) {
602 err = usbd_abort_pipe(sc->lgue_ep[LGUE_ENDPT_INTR]);
604 if_printf(ifp, "abort intr pipe failed:%s\n",
607 err = usbd_close_pipe(sc->lgue_ep[LGUE_ENDPT_INTR]);
609 if_printf(ifp, "close intr pipe failed:%s\n",
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;
619 if (sc->lgue_tx_xfer != NULL) {
620 usbd_free_xfer(sc->lgue_tx_xfer);
621 sc->lgue_tx_xfer = NULL;
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;
629 if (sc->lgue_rx_xfer != NULL) {
630 usbd_free_xfer(sc->lgue_rx_xfer);
631 sc->lgue_rx_xfer = NULL;
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;
639 if (sc->lgue_intr_xfer != NULL) {
640 usbd_free_xfer(sc->lgue_intr_xfer);
641 sc->lgue_intr_xfer = NULL;
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);
652 ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
661 struct lgue_softc *sc;
666 ifp = &sc->lgue_arpcom.ac_if;
668 if (ifp->if_flags & IFF_RUNNING)
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");
679 sc->lgue_tx_buf = kmalloc(LGUE_BUFSZ, M_USBDEV, M_WAITOK);
681 if (sc->lgue_rx_xfer == NULL) {
682 sc->lgue_rx_xfer = usbd_alloc_xfer(sc->lgue_udev);
683 if (sc->lgue_rx_xfer == NULL) {
684 if_printf(ifp, "rx buffer allocate failed\n");
688 sc->lgue_rx_buf = kmalloc(LGUE_BUFSZ, M_USBDEV, M_WAITOK);
690 /* Create INTR buf */
691 if (sc->lgue_intr_xfer == NULL) {
692 sc->lgue_intr_xfer = usbd_alloc_xfer(sc->lgue_udev);
693 if (sc->lgue_intr_xfer == NULL) {
694 if_printf(ifp, "intr buffer allocate failed\n");
698 sc->lgue_intr_buf = kmalloc(LGUE_BUFSZ, M_USBDEV, M_WAITOK);
700 /* Open RX and TX pipes. */
701 err = usbd_open_pipe(sc->lgue_data_iface, sc->lgue_ed[LGUE_ENDPT_RX],
702 USBD_EXCLUSIVE_USE, &sc->lgue_ep[LGUE_ENDPT_RX]);
704 if_printf(ifp, "open RX pipe failed: %s\n", usbd_errstr(err));
707 err = usbd_open_pipe(sc->lgue_data_iface, sc->lgue_ed[LGUE_ENDPT_TX],
708 USBD_EXCLUSIVE_USE, &sc->lgue_ep[LGUE_ENDPT_TX]);
710 if_printf(ifp, "open TX pipe failed: %s\n", usbd_errstr(err));
713 /* Open INTR pipe. */
714 err = usbd_open_pipe(sc->lgue_ctl_iface, sc->lgue_ed[LGUE_ENDPT_INTR],
715 USBD_EXCLUSIVE_USE, &sc->lgue_ep[LGUE_ENDPT_INTR]);
717 if_printf(ifp, "open INTR pipe failed: %s\n", usbd_errstr(err));
721 /* Create internal queue */
722 STAILQ_INIT(&sc->lgue_tx_queue);
724 ifp->if_flags |= IFF_RUNNING;
725 ifp->if_flags &= ~IFF_OACTIVE;
737 lgue_newbuf(struct lgue_softc *sc, int len, struct mbuf **m_buf)
741 ifp = &sc->lgue_arpcom.ac_if;
745 *m_buf = m_getcl(MB_DONTWAIT, MT_DATA, MT_HEADER);
746 if (*m_buf == NULL) {
747 if_printf(ifp, " no memory for rx buffer --- packet dropped!\n");
750 (*m_buf)->m_len = (*m_buf)->m_pkthdr.len = MCLBYTES;
751 m_adj(*m_buf, ETHER_ALIGN);
759 lgue_rxstart(struct ifnet *ifp)
761 struct lgue_softc *sc;
767 usbd_setup_xfer(sc->lgue_rx_xfer, sc->lgue_ep[LGUE_ENDPT_RX], sc,
768 sc->lgue_rx_buf, LGUE_BUFSZ,
769 USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, lgue_rxeof);
770 usbd_transfer(sc->lgue_rx_xfer);
774 * A frame has been uploaded: pass the resulting mbuf up to
775 * the higher level protocols.
778 lgue_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
780 struct lgue_softc *sc;
789 ifp = &sc->lgue_arpcom.ac_if;
793 if (!(ifp->if_flags & IFF_RUNNING))
796 if (status != USBD_NORMAL_COMPLETION) {
797 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
799 if (usbd_ratecheck(&sc->lgue_rx_notice)) {
800 if_printf(ifp, "usb error on rx:%s\n",
801 usbd_errstr(status));
803 if (status == USBD_STALLED)
804 usbd_clear_endpoint_stall(sc->lgue_ep[LGUE_ENDPT_RX]);
808 usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
810 if (total_len < sizeof(struct ether_header)) {
815 if (lgue_newbuf(sc, total_len, &m) == ENOBUFS) {
821 m_copyback(m, 0, total_len, sc->lgue_rx_buf);
822 m->m_pkthdr.rcvif = ifp;
823 m->m_pkthdr.len = m->m_len = total_len;
829 usbd_setup_xfer(sc->lgue_rx_xfer, sc->lgue_ep[LGUE_ENDPT_RX], sc,
830 sc->lgue_rx_buf, LGUE_BUFSZ,
831 USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, lgue_rxeof);
832 usbd_transfer(sc->lgue_rx_xfer);
839 lgue_ioctl(struct ifnet *ifp, u_long command, caddr_t data, struct ucred *cr)
841 struct lgue_softc *sc;
846 ifr = (struct ifreq *)data;
851 if (ifp->if_flags & IFF_UP) {
852 if (!(ifp->if_flags & IFF_RUNNING))
854 } else if (ifp->if_flags & IFF_RUNNING) {
857 sc->lgue_if_flags = ifp->if_flags;
867 ifp->if_mtu = ifr->ifr_mtu;
870 err = ether_ioctl(ifp, command, data);
880 lgue_watchdog(struct ifnet *ifp)
884 if (!ifq_is_empty(&ifp->if_snd))
885 lgue_start_schedule(ifp);
894 if ((ch >= 'a') && (ch <= 'f')) return (ch-'a'+10);
895 if ((ch >= '0') && (ch <= '9')) return (ch-'0');
896 if ((ch >= 'A') && (ch <= 'F')) return (ch-'A'+10);