LCOV - code coverage report
Current view: top level - dev/usb - if_ugl.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 373 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 16 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: if_ugl.c,v 1.22 2018/03/15 21:36:59 uaa Exp $ */
       2             : /*      $NetBSD: if_upl.c,v 1.19 2002/07/11 21:14:26 augustss Exp $     */
       3             : /*
       4             :  * Copyright (c) 2013 SASANO Takayoshi <uaa@uaa.org.uk>
       5             :  *
       6             :  * Permission to use, copy, modify, and distribute this software for any
       7             :  * purpose with or without fee is hereby granted, provided that the above
       8             :  * copyright notice and this permission notice appear in all copies.
       9             :  *
      10             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      11             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      12             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      13             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      14             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      15             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      16             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      17             :  */
      18             : 
      19             : /*
      20             :  * Copyright (c) 2000 The NetBSD Foundation, Inc.
      21             :  * All rights reserved.
      22             :  *
      23             :  * This code is derived from software contributed to The NetBSD Foundation
      24             :  * by Lennart Augustsson (lennart@augustsson.net) at
      25             :  * Carlstedt Research & Technology.
      26             :  *
      27             :  * Redistribution and use in source and binary forms, with or without
      28             :  * modification, are permitted provided that the following conditions
      29             :  * are met:
      30             :  * 1. Redistributions of source code must retain the above copyright
      31             :  *    notice, this list of conditions and the following disclaimer.
      32             :  * 2. Redistributions in binary form must reproduce the above copyright
      33             :  *    notice, this list of conditions and the following disclaimer in the
      34             :  *    documentation and/or other materials provided with the distribution.
      35             :  *
      36             :  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
      37             :  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
      38             :  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
      39             :  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
      40             :  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      41             :  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
      42             :  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
      43             :  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
      44             :  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
      45             :  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46             :  * POSSIBILITY OF SUCH DAMAGE.
      47             :  */
      48             : 
      49             : /*
      50             :  * Genesys Logic GL620USB-A driver
      51             :  *   This driver is based on Prolific PL2301/PL2302 driver (if_upl.c).
      52             :  */
      53             : 
      54             : #include <bpfilter.h>
      55             : 
      56             : #include <sys/param.h>
      57             : #include <sys/systm.h>
      58             : #include <sys/timeout.h>
      59             : #include <sys/sockio.h>
      60             : #include <sys/mbuf.h>
      61             : #include <sys/kernel.h>
      62             : #include <sys/socket.h>
      63             : 
      64             : #include <sys/device.h>
      65             : 
      66             : #include <net/if.h>
      67             : 
      68             : #if NBPFILTER > 0
      69             : #include <net/bpf.h>
      70             : #endif
      71             : 
      72             : #include <netinet/in.h>
      73             : #include <netinet/if_ether.h>
      74             : 
      75             : #include <dev/usb/usb.h>
      76             : #include <dev/usb/usbdi.h>
      77             : #include <dev/usb/usbdi_util.h>
      78             : #include <dev/usb/usbdevs.h>
      79             : 
      80             : #define UGL_INTR_PKTLEN         8
      81             : #define UGL_BULK_PKTLEN         64
      82             : 
      83             : /***/
      84             : 
      85             : #define UGL_INTR_INTERVAL       20
      86             : 
      87             : #define UGL_MAX_MTU             1514
      88             : #define UGL_BUFSZ               roundup(sizeof(struct ugl_packet), UGL_BULK_PKTLEN)
      89             : 
      90             : #define UGL_RX_FRAMES           1       /* must be one */
      91             : #define UGL_TX_FRAMES           1       /* must be one */
      92             : 
      93             : #define UGL_RX_LIST_CNT         1
      94             : #define UGL_TX_LIST_CNT         1
      95             : 
      96             : #define UGL_ENDPT_RX            0x0
      97             : #define UGL_ENDPT_TX            0x1
      98             : #define UGL_ENDPT_INTR          0x2
      99             : #define UGL_ENDPT_MAX           0x3
     100             : 
     101             : struct ugl_softc;
     102             : 
     103             : struct ugl_packet {
     104             :         uDWord                  pkt_count;
     105             :         uDWord                  pkt_length;
     106             :         char                    pkt_data[UGL_MAX_MTU];
     107             : } __packed;
     108             : 
     109             : struct ugl_chain {
     110             :         struct ugl_softc        *ugl_sc;
     111             :         struct usbd_xfer        *ugl_xfer;
     112             :         struct ugl_packet       *ugl_buf;
     113             :         struct mbuf             *ugl_mbuf;
     114             :         int                     ugl_idx;
     115             : };
     116             : 
     117             : struct ugl_cdata {
     118             :         struct ugl_chain        ugl_tx_chain[UGL_TX_LIST_CNT];
     119             :         struct ugl_chain        ugl_rx_chain[UGL_RX_LIST_CNT];
     120             :         int                     ugl_tx_prod;
     121             :         int                     ugl_tx_cons;
     122             :         int                     ugl_tx_cnt;
     123             :         int                     ugl_rx_prod;
     124             : };
     125             : 
     126             : struct ugl_softc {
     127             :         struct device           sc_dev;
     128             : 
     129             :         struct arpcom           sc_arpcom;
     130             : #define GET_IFP(sc) (&(sc)->sc_arpcom.ac_if)
     131             :         struct timeout          sc_stat_ch;
     132             : 
     133             :         struct usbd_device      *sc_udev;
     134             :         struct usbd_interface   *sc_iface;
     135             :         int                     sc_ed[UGL_ENDPT_MAX];
     136             :         struct usbd_pipe        *sc_ep[UGL_ENDPT_MAX];
     137             :         struct ugl_cdata        sc_cdata;
     138             : 
     139             :         uByte                   sc_ibuf[UGL_INTR_PKTLEN];
     140             : 
     141             :         u_int                   sc_rx_errs;
     142             :         struct timeval          sc_rx_notice;
     143             :         u_int                   sc_intr_errs;
     144             : };
     145             : 
     146             : #ifdef UGL_DEBUG
     147             : #define DPRINTF(x)      do { if (ugldebug) printf x; } while (0)
     148             : #define DPRINTFN(n,x)   do { if (ugldebug >= (n)) printf x; } while (0)
     149             : int     ugldebug = 0;
     150             : #else
     151             : #define DPRINTF(x)
     152             : #define DPRINTFN(n,x)
     153             : #endif
     154             : 
     155             : /*
     156             :  * Various supported device vendors/products.
     157             :  */
     158             : struct usb_devno ugl_devs[] = {
     159             :         { USB_VENDOR_GENESYS, USB_PRODUCT_GENESYS_GL620USB_A },
     160             : };
     161             : 
     162             : int ugl_match(struct device *, void *, void *);
     163             : void ugl_attach(struct device *, struct device *, void *);
     164             : int ugl_detach(struct device *, int);
     165             : 
     166             : struct cfdriver ugl_cd = {
     167             :         NULL, "ugl", DV_IFNET
     168             : };
     169             : 
     170             : const struct cfattach ugl_ca = {
     171             :         sizeof(struct ugl_softc), ugl_match, ugl_attach, ugl_detach
     172             : };
     173             : 
     174             : int ugl_openpipes(struct ugl_softc *);
     175             : int ugl_tx_list_init(struct ugl_softc *);
     176             : int ugl_rx_list_init(struct ugl_softc *);
     177             : int ugl_newbuf(struct ugl_softc *, struct ugl_chain *, struct mbuf *);
     178             : int ugl_send(struct ugl_softc *, struct mbuf *, int);
     179             : void ugl_intr(struct usbd_xfer *, void *, usbd_status);
     180             : void ugl_rxeof(struct usbd_xfer *, void *, usbd_status);
     181             : void ugl_txeof(struct usbd_xfer *, void *, usbd_status);
     182             : void ugl_start(struct ifnet *);
     183             : int ugl_ioctl(struct ifnet *, u_long, caddr_t);
     184             : void ugl_init(void *);
     185             : void ugl_stop(struct ugl_softc *);
     186             : void ugl_watchdog(struct ifnet *);
     187             : 
     188             : /*
     189             :  * Probe for a Genesys Logic chip.
     190             :  */
     191             : int
     192           0 : ugl_match(struct device *parent, void *match, void *aux)
     193             : {
     194           0 :         struct usb_attach_arg           *uaa = aux;
     195             : 
     196           0 :         if (uaa->iface == NULL || uaa->configno != 1)
     197           0 :                 return (UMATCH_NONE);
     198             : 
     199           0 :         return (usb_lookup(ugl_devs, uaa->vendor, uaa->product) != NULL ?
     200             :             UMATCH_VENDOR_PRODUCT_CONF_IFACE : UMATCH_NONE);
     201           0 : }
     202             : 
     203             : void
     204           0 : ugl_attach(struct device *parent, struct device *self, void *aux)
     205             : {
     206           0 :         struct ugl_softc        *sc = (struct ugl_softc *)self;
     207           0 :         struct usb_attach_arg   *uaa = aux;
     208             :         int                     s;
     209           0 :         struct usbd_device      *dev = uaa->device;
     210           0 :         struct usbd_interface   *iface = uaa->iface;
     211           0 :         struct ifnet            *ifp = GET_IFP(sc);
     212             :         usb_interface_descriptor_t      *id;
     213             :         usb_endpoint_descriptor_t       *ed;
     214             :         int                     i;
     215             : 
     216             :         DPRINTFN(5,(" : ugl_attach: sc=%p, dev=%p", sc, dev));
     217             : 
     218           0 :         sc->sc_udev = dev;
     219           0 :         sc->sc_iface = iface;
     220           0 :         id = usbd_get_interface_descriptor(iface);
     221             : 
     222             :         /* Find endpoints. */
     223           0 :         for (i = 0; i < id->bNumEndpoints; i++) {
     224           0 :                 ed = usbd_interface2endpoint_descriptor(iface, i);
     225           0 :                 if (ed == NULL) {
     226           0 :                         printf("%s: couldn't get ep %d\n",
     227           0 :                             sc->sc_dev.dv_xname, i);
     228           0 :                         return;
     229             :                 }
     230           0 :                 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
     231           0 :                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
     232           0 :                         sc->sc_ed[UGL_ENDPT_RX] = ed->bEndpointAddress;
     233           0 :                 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
     234           0 :                            UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
     235           0 :                         sc->sc_ed[UGL_ENDPT_TX] = ed->bEndpointAddress;
     236           0 :                 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
     237           0 :                            UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
     238           0 :                         sc->sc_ed[UGL_ENDPT_INTR] = ed->bEndpointAddress;
     239           0 :                 }
     240             :         }
     241             : 
     242           0 :         if (sc->sc_ed[UGL_ENDPT_RX] == 0 || sc->sc_ed[UGL_ENDPT_TX] == 0 ||
     243           0 :             sc->sc_ed[UGL_ENDPT_INTR] == 0) {
     244           0 :                 printf("%s: missing endpoint\n", sc->sc_dev.dv_xname);
     245           0 :                 return;
     246             :         }
     247             : 
     248           0 :         s = splnet();
     249             : 
     250           0 :         ether_fakeaddr(ifp);
     251           0 :         printf("%s: address %s\n",
     252           0 :             sc->sc_dev.dv_xname, ether_sprintf(sc->sc_arpcom.ac_enaddr));
     253             : 
     254             :         /* Initialize interface info.*/
     255           0 :         ifp->if_softc = sc;
     256           0 :         ifp->if_hardmtu = UGL_MAX_MTU;
     257           0 :         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
     258           0 :         ifp->if_ioctl = ugl_ioctl;
     259           0 :         ifp->if_start = ugl_start;
     260           0 :         ifp->if_watchdog = ugl_watchdog;
     261           0 :         strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
     262             : 
     263             :         /* Attach the interface. */
     264           0 :         if_attach(ifp);
     265           0 :         ether_ifattach(ifp);
     266             : 
     267           0 :         splx(s);
     268           0 : }
     269             : 
     270             : int
     271           0 : ugl_detach(struct device *self, int flags)
     272             : {
     273           0 :         struct ugl_softc        *sc = (struct ugl_softc *)self;
     274           0 :         struct ifnet            *ifp = GET_IFP(sc);
     275             :         int                     s;
     276             : 
     277             :         DPRINTFN(2,("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
     278             : 
     279           0 :         s = splusb();
     280             : 
     281           0 :         if (ifp->if_flags & IFF_RUNNING)
     282           0 :                 ugl_stop(sc);
     283             : 
     284           0 :         if (ifp->if_softc != NULL)
     285           0 :                 if_detach(ifp);
     286             : 
     287             : #ifdef DIAGNOSTIC
     288           0 :         if (sc->sc_ep[UGL_ENDPT_TX] != NULL ||
     289           0 :             sc->sc_ep[UGL_ENDPT_RX] != NULL ||
     290           0 :             sc->sc_ep[UGL_ENDPT_INTR] != NULL)
     291           0 :                 printf("%s: detach has active endpoints\n",
     292           0 :                        sc->sc_dev.dv_xname);
     293             : #endif
     294             : 
     295           0 :         splx(s);
     296             : 
     297           0 :         return (0);
     298             : }
     299             : 
     300             : /*
     301             :  * Initialize an RX descriptor and attach an MBUF cluster.
     302             :  */
     303             : int
     304           0 : ugl_newbuf(struct ugl_softc *sc, struct ugl_chain *c, struct mbuf *m)
     305             : {
     306             :         struct mbuf             *m_new = NULL;
     307             : 
     308             :         DPRINTFN(8,("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
     309             : 
     310           0 :         if (m == NULL) {
     311           0 :                 MGETHDR(m_new, M_DONTWAIT, MT_DATA);
     312           0 :                 if (m_new == NULL) {
     313           0 :                         printf("%s: no memory for rx list "
     314           0 :                             "-- packet dropped!\n", sc->sc_dev.dv_xname);
     315           0 :                         return (ENOBUFS);
     316             :                 }
     317             : 
     318           0 :                 MCLGET(m_new, M_DONTWAIT);
     319           0 :                 if (!(m_new->m_flags & M_EXT)) {
     320           0 :                         printf("%s: no memory for rx list "
     321           0 :                             "-- packet dropped!\n", sc->sc_dev.dv_xname);
     322           0 :                         m_freem(m_new);
     323           0 :                         return (ENOBUFS);
     324             :                 }
     325           0 :                 m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
     326           0 :         } else {
     327             :                 m_new = m;
     328           0 :                 m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
     329           0 :                 m_new->m_data = m_new->m_ext.ext_buf;
     330             :         }
     331             : 
     332           0 :         c->ugl_mbuf = m_new;
     333             : 
     334           0 :         return (0);
     335           0 : }
     336             : 
     337             : int
     338           0 : ugl_rx_list_init(struct ugl_softc *sc)
     339             : {
     340             :         struct ugl_cdata        *cd;
     341             :         struct ugl_chain        *c;
     342             :         int                     i;
     343             : 
     344             :         DPRINTFN(5,("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
     345             : 
     346           0 :         cd = &sc->sc_cdata;
     347           0 :         for (i = 0; i < UGL_RX_LIST_CNT; i++) {
     348           0 :                 c = &cd->ugl_rx_chain[i];
     349           0 :                 c->ugl_sc = sc;
     350           0 :                 c->ugl_idx = i;
     351           0 :                 if (ugl_newbuf(sc, c, NULL) == ENOBUFS)
     352           0 :                         return (ENOBUFS);
     353           0 :                 if (c->ugl_xfer == NULL) {
     354           0 :                         c->ugl_xfer = usbd_alloc_xfer(sc->sc_udev);
     355           0 :                         if (c->ugl_xfer == NULL)
     356           0 :                                 return (ENOBUFS);
     357           0 :                         c->ugl_buf = usbd_alloc_buffer(c->ugl_xfer, UGL_BUFSZ);
     358           0 :                         if (c->ugl_buf == NULL) {
     359           0 :                                 usbd_free_xfer(c->ugl_xfer);
     360           0 :                                 return (ENOBUFS);
     361             :                         }
     362             :                 }
     363             :         }
     364             : 
     365           0 :         return (0);
     366           0 : }
     367             : 
     368             : int
     369           0 : ugl_tx_list_init(struct ugl_softc *sc)
     370             : {
     371             :         struct ugl_cdata        *cd;
     372             :         struct ugl_chain        *c;
     373             :         int                     i;
     374             : 
     375             :         DPRINTFN(5,("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
     376             : 
     377           0 :         cd = &sc->sc_cdata;
     378           0 :         for (i = 0; i < UGL_TX_LIST_CNT; i++) {
     379           0 :                 c = &cd->ugl_tx_chain[i];
     380           0 :                 c->ugl_sc = sc;
     381           0 :                 c->ugl_idx = i;
     382           0 :                 c->ugl_mbuf = NULL;
     383           0 :                 if (c->ugl_xfer == NULL) {
     384           0 :                         c->ugl_xfer = usbd_alloc_xfer(sc->sc_udev);
     385           0 :                         if (c->ugl_xfer == NULL)
     386           0 :                                 return (ENOBUFS);
     387           0 :                         c->ugl_buf = usbd_alloc_buffer(c->ugl_xfer, UGL_BUFSZ);
     388           0 :                         if (c->ugl_buf == NULL) {
     389           0 :                                 usbd_free_xfer(c->ugl_xfer);
     390           0 :                                 return (ENOBUFS);
     391             :                         }
     392             :                 }
     393             :         }
     394             : 
     395           0 :         return (0);
     396           0 : }
     397             : 
     398             : /*
     399             :  * A frame has been uploaded: pass the resulting mbuf chain up to
     400             :  * the higher level protocols.
     401             :  */
     402             : void
     403           0 : ugl_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
     404             : {
     405           0 :         struct ugl_chain        *c = priv;
     406           0 :         struct ugl_softc        *sc = c->ugl_sc;
     407           0 :         struct ifnet            *ifp = GET_IFP(sc);
     408           0 :         struct mbuf_list        ml = MBUF_LIST_INITIALIZER();
     409             :         struct mbuf             *m;
     410           0 :         int                     total_len = 0;
     411             :         unsigned int            packet_len, packet_count;
     412             :         int                     s;
     413             : 
     414           0 :         if (usbd_is_dying(sc->sc_udev))
     415           0 :                 return;
     416             : 
     417           0 :         if (!(ifp->if_flags & IFF_RUNNING))
     418           0 :                 return;
     419             : 
     420           0 :         if (status != USBD_NORMAL_COMPLETION) {
     421           0 :                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
     422           0 :                         return;
     423           0 :                 sc->sc_rx_errs++;
     424           0 :                 if (usbd_ratecheck(&sc->sc_rx_notice)) {
     425           0 :                         printf("%s: %u usb errors on rx: %s\n",
     426           0 :                             sc->sc_dev.dv_xname, sc->sc_rx_errs,
     427           0 :                             usbd_errstr(status));
     428           0 :                         sc->sc_rx_errs = 0;
     429           0 :                 }
     430           0 :                 if (status == USBD_STALLED)
     431           0 :                         usbd_clear_endpoint_stall_async(sc->sc_ep[UGL_ENDPT_RX]);
     432             :                 goto done;
     433             :         }
     434             : 
     435           0 :         usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
     436             : 
     437             :         DPRINTFN(9,("%s: %s: enter status=%d length=%d\n",
     438             :                     sc->sc_dev.dv_xname, __func__, status, total_len));
     439             : 
     440           0 :         if (total_len < offsetof(struct ugl_packet, pkt_data)) {
     441           0 :                 printf("%s: bad header (length=%d)\n",
     442           0 :                     sc->sc_dev.dv_xname, total_len);
     443             : 
     444           0 :                 goto done;
     445             :         }
     446             : 
     447           0 :         packet_count = UGETDW(c->ugl_buf->pkt_count);
     448           0 :         if (packet_count != UGL_RX_FRAMES) {
     449           0 :                 printf("%s: bad packet count (%d)\n",
     450           0 :                     sc->sc_dev.dv_xname, packet_count);
     451             : 
     452           0 :                 if (packet_count == 0)
     453             :                         goto done;
     454             :         }
     455             : 
     456           0 :         packet_len = UGETDW(c->ugl_buf->pkt_length);
     457           0 :         if (total_len < packet_len) {
     458           0 :                 printf("%s: bad packet size(%d), length=%d\n",
     459           0 :                     sc->sc_dev.dv_xname, packet_len, total_len);
     460             : 
     461           0 :                 if (packet_len == 0)
     462             :                         goto done;
     463             :         }
     464             : 
     465           0 :         m = c->ugl_mbuf;
     466           0 :         memcpy(mtod(c->ugl_mbuf, char *), c->ugl_buf->pkt_data, packet_len);
     467             : 
     468           0 :         m->m_pkthdr.len = m->m_len = packet_len;
     469           0 :         ml_enqueue(&ml, m);
     470             : 
     471           0 :         if (ugl_newbuf(sc, c, NULL) == ENOBUFS) {
     472           0 :                 ifp->if_ierrors++;
     473           0 :                 goto done;
     474             :         }
     475             : 
     476           0 :         s = splnet();
     477           0 :         if_input(ifp, &ml);
     478           0 :         splx(s);
     479             : 
     480             :  done:
     481             :         /* Setup new transfer. */
     482           0 :         usbd_setup_xfer(c->ugl_xfer, sc->sc_ep[UGL_ENDPT_RX],
     483           0 :             c, c->ugl_buf, UGL_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
     484             :             USBD_NO_TIMEOUT, ugl_rxeof);
     485           0 :         usbd_transfer(c->ugl_xfer);
     486             : 
     487             :         DPRINTFN(10,("%s: %s: start rx\n", sc->sc_dev.dv_xname,
     488             :                     __func__));
     489           0 : }
     490             : 
     491             : /*
     492             :  * A frame was downloaded to the chip. It's safe for us to clean up
     493             :  * the list buffers.
     494             :  */
     495             : void
     496           0 : ugl_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
     497             : {
     498           0 :         struct ugl_chain        *c = priv;
     499           0 :         struct ugl_softc        *sc = c->ugl_sc;
     500           0 :         struct ifnet            *ifp = GET_IFP(sc);
     501             :         int                     s;
     502             : 
     503           0 :         if (usbd_is_dying(sc->sc_udev))
     504           0 :                 return;
     505             : 
     506           0 :         s = splnet();
     507             : 
     508             :         DPRINTFN(10,("%s: %s: enter status=%d\n", sc->sc_dev.dv_xname,
     509             :                     __func__, status));
     510             : 
     511           0 :         ifp->if_timer = 0;
     512           0 :         ifq_clr_oactive(&ifp->if_snd);
     513             : 
     514           0 :         if (status != USBD_NORMAL_COMPLETION) {
     515           0 :                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
     516           0 :                         splx(s);
     517           0 :                         return;
     518             :                 }
     519           0 :                 ifp->if_oerrors++;
     520           0 :                 printf("%s: usb error on tx: %s\n", sc->sc_dev.dv_xname,
     521           0 :                     usbd_errstr(status));
     522           0 :                 if (status == USBD_STALLED)
     523           0 :                         usbd_clear_endpoint_stall_async(sc->sc_ep[UGL_ENDPT_TX]);
     524           0 :                 splx(s);
     525           0 :                 return;
     526             :         }
     527             : 
     528           0 :         m_freem(c->ugl_mbuf);
     529           0 :         c->ugl_mbuf = NULL;
     530             : 
     531           0 :         if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
     532           0 :                 ugl_start(ifp);
     533             : 
     534           0 :         splx(s);
     535           0 : }
     536             : 
     537             : int
     538           0 : ugl_send(struct ugl_softc *sc, struct mbuf *m, int idx)
     539             : {
     540             :         int                     total_len;
     541             :         struct ugl_chain        *c;
     542             :         usbd_status             err;
     543             : 
     544           0 :         c = &sc->sc_cdata.ugl_tx_chain[idx];
     545             : 
     546             :         /*
     547             :          * Copy the mbuf data into a contiguous buffer, leaving two
     548             :          * bytes at the beginning to hold the frame length.
     549             :          */
     550           0 :         USETDW(c->ugl_buf->pkt_count, UGL_TX_FRAMES);
     551           0 :         USETDW(c->ugl_buf->pkt_length, m->m_pkthdr.len);
     552           0 :         m_copydata(m, 0, m->m_pkthdr.len, c->ugl_buf->pkt_data);
     553           0 :         c->ugl_mbuf = m;
     554             : 
     555           0 :         total_len = offsetof(struct ugl_packet, pkt_data[m->m_pkthdr.len]);
     556             : 
     557             :         DPRINTFN(10,("%s: %s: total_len=%d\n",
     558             :                      sc->sc_dev.dv_xname, __func__, total_len));
     559             : 
     560           0 :         usbd_setup_xfer(c->ugl_xfer, sc->sc_ep[UGL_ENDPT_TX],
     561           0 :             c, c->ugl_buf, total_len, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
     562             :             USBD_DEFAULT_TIMEOUT, ugl_txeof);
     563             : 
     564             :         /* Transmit */
     565           0 :         err = usbd_transfer(c->ugl_xfer);
     566           0 :         if (err != USBD_IN_PROGRESS) {
     567           0 :                 printf("%s: ugl_send error=%s\n", sc->sc_dev.dv_xname,
     568           0 :                        usbd_errstr(err));
     569           0 :                 ugl_stop(sc);
     570           0 :                 return (EIO);
     571             :         }
     572             : 
     573           0 :         sc->sc_cdata.ugl_tx_cnt++;
     574             : 
     575           0 :         return (0);
     576           0 : }
     577             : 
     578             : void
     579           0 : ugl_start(struct ifnet *ifp)
     580             : {
     581           0 :         struct ugl_softc        *sc = ifp->if_softc;
     582             :         struct mbuf             *m_head = NULL;
     583             : 
     584           0 :         if (usbd_is_dying(sc->sc_udev))
     585           0 :                 return;
     586             : 
     587             :         DPRINTFN(10,("%s: %s: enter\n", sc->sc_dev.dv_xname,__func__));
     588             : 
     589           0 :         if (ifq_is_oactive(&ifp->if_snd))
     590           0 :                 return;
     591             : 
     592           0 :         m_head = ifq_deq_begin(&ifp->if_snd);
     593           0 :         if (m_head == NULL)
     594           0 :                 return;
     595             : 
     596           0 :         if (ugl_send(sc, m_head, 0)) {
     597           0 :                 ifq_deq_rollback(&ifp->if_snd, m_head);
     598           0 :                 ifq_set_oactive(&ifp->if_snd);
     599           0 :                 return;
     600             :         }
     601             : 
     602           0 :         ifq_deq_commit(&ifp->if_snd, m_head);
     603             : 
     604             : #if NBPFILTER > 0
     605             :         /*
     606             :          * If there's a BPF listener, bounce a copy of this frame
     607             :          * to him.
     608             :          */
     609           0 :         if (ifp->if_bpf)
     610           0 :                 bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
     611             : #endif
     612             : 
     613           0 :         ifq_set_oactive(&ifp->if_snd);
     614             : 
     615             :         /*
     616             :          * Set a timeout in case the chip goes out to lunch.
     617             :          */
     618           0 :         ifp->if_timer = 5;
     619           0 : }
     620             : 
     621             : void
     622           0 : ugl_init(void *xsc)
     623             : {
     624           0 :         struct ugl_softc        *sc = xsc;
     625           0 :         struct ifnet            *ifp = GET_IFP(sc);
     626             :         int                     s;
     627             : 
     628           0 :         if (usbd_is_dying(sc->sc_udev))
     629           0 :                 return;
     630             : 
     631             :         DPRINTFN(10,("%s: %s: enter\n", sc->sc_dev.dv_xname,__func__));
     632             : 
     633           0 :         s = splnet();
     634             : 
     635             :         /* Init TX ring. */
     636           0 :         if (ugl_tx_list_init(sc) == ENOBUFS) {
     637           0 :                 printf("%s: tx list init failed\n", sc->sc_dev.dv_xname);
     638           0 :                 splx(s);
     639           0 :                 return;
     640             :         }
     641             : 
     642             :         /* Init RX ring. */
     643           0 :         if (ugl_rx_list_init(sc) == ENOBUFS) {
     644           0 :                 printf("%s: rx list init failed\n", sc->sc_dev.dv_xname);
     645           0 :                 splx(s);
     646           0 :                 return;
     647             :         }
     648             : 
     649           0 :         if (sc->sc_ep[UGL_ENDPT_RX] == NULL) {
     650           0 :                 if (ugl_openpipes(sc)) {
     651           0 :                         splx(s);
     652           0 :                         return;
     653             :                 }
     654             :         }
     655             : 
     656           0 :         ifp->if_flags |= IFF_RUNNING;
     657           0 :         ifq_clr_oactive(&ifp->if_snd);
     658             : 
     659           0 :         splx(s);
     660           0 : }
     661             : 
     662             : int
     663           0 : ugl_openpipes(struct ugl_softc *sc)
     664             : {
     665             :         struct ugl_chain        *c;
     666             :         usbd_status             err;
     667             :         int                     i;
     668             : 
     669             :         /* Open RX and TX pipes. */
     670           0 :         err = usbd_open_pipe(sc->sc_iface, sc->sc_ed[UGL_ENDPT_RX],
     671           0 :             USBD_EXCLUSIVE_USE, &sc->sc_ep[UGL_ENDPT_RX]);
     672           0 :         if (err) {
     673           0 :                 printf("%s: open rx pipe failed: %s\n",
     674           0 :                     sc->sc_dev.dv_xname, usbd_errstr(err));
     675           0 :                 return (EIO);
     676             :         }
     677           0 :         err = usbd_open_pipe(sc->sc_iface, sc->sc_ed[UGL_ENDPT_TX],
     678           0 :             USBD_EXCLUSIVE_USE, &sc->sc_ep[UGL_ENDPT_TX]);
     679           0 :         if (err) {
     680           0 :                 printf("%s: open tx pipe failed: %s\n",
     681           0 :                     sc->sc_dev.dv_xname, usbd_errstr(err));
     682           0 :                 return (EIO);
     683             :         }
     684           0 :         err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ed[UGL_ENDPT_INTR],
     685           0 :             USBD_EXCLUSIVE_USE, &sc->sc_ep[UGL_ENDPT_INTR], sc,
     686           0 :             sc->sc_ibuf, UGL_INTR_PKTLEN, ugl_intr,
     687             :             UGL_INTR_INTERVAL);
     688           0 :         if (err) {
     689           0 :                 printf("%s: open intr pipe failed: %s\n",
     690           0 :                     sc->sc_dev.dv_xname, usbd_errstr(err));
     691           0 :                 return (EIO);
     692             :         }
     693             : 
     694             :         /* Start up the receive pipe. */
     695           0 :         for (i = 0; i < UGL_RX_LIST_CNT; i++) {
     696           0 :                 c = &sc->sc_cdata.ugl_rx_chain[i];
     697           0 :                 usbd_setup_xfer(c->ugl_xfer, sc->sc_ep[UGL_ENDPT_RX],
     698           0 :                     c, c->ugl_buf, UGL_BUFSZ,
     699             :                     USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
     700             :                     ugl_rxeof);
     701           0 :                 usbd_transfer(c->ugl_xfer);
     702             :         }
     703             : 
     704           0 :         return (0);
     705           0 : }
     706             : 
     707             : void
     708           0 : ugl_intr(struct usbd_xfer *xfer, void *priv, usbd_status status)
     709             : {
     710           0 :         struct ugl_softc        *sc = priv;
     711           0 :         struct ifnet            *ifp = GET_IFP(sc);
     712             :         int                     i;
     713             : 
     714             :         DPRINTFN(15,("%s: %s: enter\n", sc->sc_dev.dv_xname,__func__));
     715             : 
     716           0 :         if (usbd_is_dying(sc->sc_udev))
     717           0 :                 return;
     718             : 
     719           0 :         if (!(ifp->if_flags & IFF_RUNNING))
     720           0 :                 return;
     721             : 
     722           0 :         if (status != USBD_NORMAL_COMPLETION) {
     723           0 :                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
     724           0 :                         return;
     725             :                 }
     726           0 :                 sc->sc_intr_errs++;
     727           0 :                 if (usbd_ratecheck(&sc->sc_rx_notice)) {
     728           0 :                         printf("%s: %u usb errors on intr: %s\n",
     729           0 :                             sc->sc_dev.dv_xname, sc->sc_rx_errs,
     730           0 :                             usbd_errstr(status));
     731           0 :                         sc->sc_intr_errs = 0;
     732           0 :                 }
     733           0 :                 if (status == USBD_STALLED)
     734           0 :                         usbd_clear_endpoint_stall_async(sc->sc_ep[UGL_ENDPT_RX]);
     735           0 :                 return;
     736             :         }
     737             : 
     738             :         DPRINTFN(10,("%s: %s:", sc->sc_dev.dv_xname, __func__));
     739           0 :         for (i = 0; i < UGL_INTR_PKTLEN; i++)
     740             :                 DPRINTFN(10,(" 0x%02x", sc->sc_ibuf[i]));
     741             :         DPRINTFN(10,("\n"));
     742             : 
     743           0 : }
     744             : 
     745             : int
     746           0 : ugl_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
     747             : {
     748           0 :         struct ugl_softc        *sc = ifp->if_softc;
     749             :         int                     s, error = 0;
     750             : 
     751           0 :         if (usbd_is_dying(sc->sc_udev))
     752           0 :                 return (EIO);
     753             : 
     754             :         DPRINTFN(5,("%s: %s: cmd=0x%08lx\n",
     755             :                     sc->sc_dev.dv_xname, __func__, command));
     756             : 
     757           0 :         s = splnet();
     758             : 
     759           0 :         switch(command) {
     760             :         case SIOCSIFADDR:
     761           0 :                 ifp->if_flags |= IFF_UP;
     762           0 :                 if (!(ifp->if_flags & IFF_RUNNING))
     763           0 :                         ugl_init(sc);
     764             :                 break;
     765             : 
     766             :         case SIOCSIFFLAGS:
     767           0 :                 if (ifp->if_flags & IFF_UP) {
     768           0 :                         if (ifp->if_flags & IFF_RUNNING)
     769           0 :                                 error = ENETRESET;
     770             :                         else
     771           0 :                                 ugl_init(sc);
     772             :                 } else {
     773           0 :                         if (ifp->if_flags & IFF_RUNNING)
     774           0 :                                 ugl_stop(sc);
     775             :                 }
     776             :                 break;
     777             : 
     778             :         default:
     779           0 :                 error = ether_ioctl(ifp, &sc->sc_arpcom, command, data);
     780           0 :                 break;
     781             :         }
     782             : 
     783           0 :         if (error == ENETRESET)
     784           0 :                 error = 0;
     785             : 
     786           0 :         splx(s);
     787           0 :         return (error);
     788           0 : }
     789             : 
     790             : void
     791           0 : ugl_watchdog(struct ifnet *ifp)
     792             : {
     793           0 :         struct ugl_softc        *sc = ifp->if_softc;
     794             : 
     795           0 :         if (usbd_is_dying(sc->sc_udev))
     796           0 :                 return;
     797             : 
     798           0 :         ifp->if_oerrors++;
     799           0 :         printf("%s: watchdog timeout\n", sc->sc_dev.dv_xname);
     800           0 : }
     801             : 
     802             : /*
     803             :  * Stop the adapter and free any mbufs allocated to the
     804             :  * RX and TX lists.
     805             :  */
     806             : void
     807           0 : ugl_stop(struct ugl_softc *sc)
     808             : {
     809             :         struct ifnet            *ifp;
     810             :         int                     i;
     811             : 
     812             :         DPRINTFN(10,("%s: %s: enter\n", sc->sc_dev.dv_xname,__func__));
     813             : 
     814           0 :         ifp = GET_IFP(sc);
     815           0 :         ifp->if_timer = 0;
     816           0 :         ifp->if_flags &= ~IFF_RUNNING;
     817           0 :         ifq_clr_oactive(&ifp->if_snd);
     818             : 
     819             :         /* Stop transfers. */
     820           0 :         if (sc->sc_ep[UGL_ENDPT_RX] != NULL) {
     821           0 :                 usbd_abort_pipe(sc->sc_ep[UGL_ENDPT_RX]);
     822           0 :                 usbd_close_pipe(sc->sc_ep[UGL_ENDPT_RX]);
     823           0 :                 sc->sc_ep[UGL_ENDPT_RX] = NULL;
     824           0 :         }
     825             : 
     826           0 :         if (sc->sc_ep[UGL_ENDPT_TX] != NULL) {
     827           0 :                 usbd_abort_pipe(sc->sc_ep[UGL_ENDPT_TX]);
     828           0 :                 usbd_close_pipe(sc->sc_ep[UGL_ENDPT_TX]);
     829           0 :                 sc->sc_ep[UGL_ENDPT_TX] = NULL;
     830           0 :         }
     831             : 
     832           0 :         if (sc->sc_ep[UGL_ENDPT_INTR] != NULL) {
     833           0 :                 usbd_abort_pipe(sc->sc_ep[UGL_ENDPT_INTR]);
     834           0 :                 usbd_close_pipe(sc->sc_ep[UGL_ENDPT_INTR]);
     835           0 :                 sc->sc_ep[UGL_ENDPT_INTR] = NULL;
     836           0 :         }
     837             : 
     838             :         /* Free RX resources. */
     839           0 :         for (i = 0; i < UGL_RX_LIST_CNT; i++) {
     840           0 :                 if (sc->sc_cdata.ugl_rx_chain[i].ugl_mbuf != NULL) {
     841           0 :                         m_freem(sc->sc_cdata.ugl_rx_chain[i].ugl_mbuf);
     842           0 :                         sc->sc_cdata.ugl_rx_chain[i].ugl_mbuf = NULL;
     843           0 :                 }
     844           0 :                 if (sc->sc_cdata.ugl_rx_chain[i].ugl_xfer != NULL) {
     845           0 :                         usbd_free_xfer(sc->sc_cdata.ugl_rx_chain[i].ugl_xfer);
     846           0 :                         sc->sc_cdata.ugl_rx_chain[i].ugl_xfer = NULL;
     847           0 :                 }
     848             :         }
     849             : 
     850             :         /* Free TX resources. */
     851           0 :         for (i = 0; i < UGL_TX_LIST_CNT; i++) {
     852           0 :                 if (sc->sc_cdata.ugl_tx_chain[i].ugl_mbuf != NULL) {
     853           0 :                         m_freem(sc->sc_cdata.ugl_tx_chain[i].ugl_mbuf);
     854           0 :                         sc->sc_cdata.ugl_tx_chain[i].ugl_mbuf = NULL;
     855           0 :                 }
     856           0 :                 if (sc->sc_cdata.ugl_tx_chain[i].ugl_xfer != NULL) {
     857           0 :                         usbd_free_xfer(sc->sc_cdata.ugl_tx_chain[i].ugl_xfer);
     858           0 :                         sc->sc_cdata.ugl_tx_chain[i].ugl_xfer = NULL;
     859           0 :                 }
     860             :         }
     861           0 : }

Generated by: LCOV version 1.13