The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/netif/lgue/if_lgue.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 3fa64d747fb5034b7c3bc03873763b2c


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.