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

          Line data    Source code
       1             : /*      $OpenBSD: if_cue.c,v 1.77 2017/01/22 10:17:39 dlg Exp $ */
       2             : /*      $NetBSD: if_cue.c,v 1.40 2002/07/11 21:14:26 augustss Exp $     */
       3             : /*
       4             :  * Copyright (c) 1997, 1998, 1999, 2000
       5             :  *      Bill Paul <wpaul@ee.columbia.edu>.  All rights reserved.
       6             :  *
       7             :  * Redistribution and use in source and binary forms, with or without
       8             :  * modification, are permitted provided that the following conditions
       9             :  * are met:
      10             :  * 1. Redistributions of source code must retain the above copyright
      11             :  *    notice, this list of conditions and the following disclaimer.
      12             :  * 2. Redistributions in binary form must reproduce the above copyright
      13             :  *    notice, this list of conditions and the following disclaimer in the
      14             :  *    documentation and/or other materials provided with the distribution.
      15             :  * 3. All advertising materials mentioning features or use of this software
      16             :  *    must display the following acknowledgement:
      17             :  *      This product includes software developed by Bill Paul.
      18             :  * 4. Neither the name of the author nor the names of any co-contributors
      19             :  *    may be used to endorse or promote products derived from this software
      20             :  *    without specific prior written permission.
      21             :  *
      22             :  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
      23             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      24             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      25             :  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
      26             :  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      27             :  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
      28             :  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
      29             :  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
      30             :  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
      31             :  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
      32             :  * THE POSSIBILITY OF SUCH DAMAGE.
      33             :  *
      34             :  * $FreeBSD: src/sys/dev/usb/if_cue.c,v 1.4 2000/01/16 22:45:06 wpaul Exp $
      35             :  */
      36             : 
      37             : /*
      38             :  * CATC USB-EL1210A USB to ethernet driver. Used in the CATC Netmate
      39             :  * adapters and others.
      40             :  *
      41             :  * Written by Bill Paul <wpaul@ee.columbia.edu>
      42             :  * Electrical Engineering Department
      43             :  * Columbia University, New York City
      44             :  */
      45             : 
      46             : /*
      47             :  * The CATC USB-EL1210A provides USB ethernet support at 10Mbps. The
      48             :  * RX filter uses a 512-bit multicast hash table, single perfect entry
      49             :  * for the station address, and promiscuous mode. Unlike the ADMtek
      50             :  * and KLSI chips, the CATC ASIC supports read and write combining
      51             :  * mode where multiple packets can be transferred using a single bulk
      52             :  * transaction, which helps performance a great deal.
      53             :  */
      54             : 
      55             : /*
      56             :  * Ported to NetBSD and somewhat rewritten by Lennart Augustsson.
      57             :  */
      58             : 
      59             : #include "bpfilter.h"
      60             : 
      61             : #include <sys/param.h>
      62             : #include <sys/systm.h>
      63             : #include <sys/sockio.h>
      64             : #include <sys/mbuf.h>
      65             : #include <sys/kernel.h>
      66             : #include <sys/socket.h>
      67             : #include <sys/timeout.h>
      68             : #include <sys/device.h>
      69             : 
      70             : #include <net/if.h>
      71             : 
      72             : #if NBPFILTER > 0
      73             : #include <net/bpf.h>
      74             : #endif
      75             : 
      76             : #include <netinet/in.h>
      77             : #include <netinet/if_ether.h>
      78             : 
      79             : #include <dev/usb/usb.h>
      80             : #include <dev/usb/usbdi.h>
      81             : #include <dev/usb/usbdi_util.h>
      82             : #include <dev/usb/usbdevs.h>
      83             : 
      84             : #include <dev/usb/if_cuereg.h>
      85             : 
      86             : #ifdef CUE_DEBUG
      87             : #define DPRINTF(x)      do { if (cuedebug) printf x; } while (0)
      88             : #define DPRINTFN(n,x)   do { if (cuedebug >= (n)) printf x; } while (0)
      89             : int     cuedebug = 0;
      90             : #else
      91             : #define DPRINTF(x)
      92             : #define DPRINTFN(n,x)
      93             : #endif
      94             : 
      95             : /*
      96             :  * Various supported device vendors/products.
      97             :  */
      98             : struct usb_devno cue_devs[] = {
      99             :         { USB_VENDOR_CATC, USB_PRODUCT_CATC_NETMATE },
     100             :         { USB_VENDOR_CATC, USB_PRODUCT_CATC_NETMATE2 },
     101             :         { USB_VENDOR_SMARTBRIDGES, USB_PRODUCT_SMARTBRIDGES_SMARTLINK },
     102             :         /* Belkin F5U111 adapter covered by NETMATE entry */
     103             : };
     104             : 
     105             : int cue_match(struct device *, void *, void *);
     106             : void cue_attach(struct device *, struct device *, void *);
     107             : int cue_detach(struct device *, int);
     108             : 
     109             : struct cfdriver cue_cd = {
     110             :         NULL, "cue", DV_IFNET
     111             : };
     112             : 
     113             : const struct cfattach cue_ca = {
     114             :         sizeof(struct cue_softc), cue_match, cue_attach, cue_detach
     115             : };
     116             : 
     117             : int cue_open_pipes(struct cue_softc *);
     118             : int cue_tx_list_init(struct cue_softc *);
     119             : int cue_rx_list_init(struct cue_softc *);
     120             : int cue_newbuf(struct cue_softc *, struct cue_chain *, struct mbuf *);
     121             : int cue_send(struct cue_softc *, struct mbuf *, int);
     122             : void cue_rxeof(struct usbd_xfer *, void *, usbd_status);
     123             : void cue_txeof(struct usbd_xfer *, void *, usbd_status);
     124             : void cue_tick(void *);
     125             : void cue_tick_task(void *);
     126             : void cue_start(struct ifnet *);
     127             : int cue_ioctl(struct ifnet *, u_long, caddr_t);
     128             : void cue_init(void *);
     129             : void cue_stop(struct cue_softc *);
     130             : void cue_watchdog(struct ifnet *);
     131             : 
     132             : void cue_setmulti(struct cue_softc *);
     133             : void cue_reset(struct cue_softc *);
     134             : 
     135             : int cue_csr_read_1(struct cue_softc *, int);
     136             : int cue_csr_write_1(struct cue_softc *, int, int);
     137             : int cue_csr_read_2(struct cue_softc *, int);
     138             : #if 0
     139             : int cue_csr_write_2(struct cue_softc *, int, int);
     140             : #endif
     141             : int cue_mem(struct cue_softc *, int, int, void *, int);
     142             : int cue_getmac(struct cue_softc *, void *);
     143             : 
     144             : #define CUE_SETBIT(sc, reg, x)                          \
     145             :         cue_csr_write_1(sc, reg, cue_csr_read_1(sc, reg) | (x))
     146             : 
     147             : #define CUE_CLRBIT(sc, reg, x)                          \
     148             :         cue_csr_write_1(sc, reg, cue_csr_read_1(sc, reg) & ~(x))
     149             : 
     150             : int
     151           0 : cue_csr_read_1(struct cue_softc *sc, int reg)
     152             : {
     153           0 :         usb_device_request_t    req;
     154             :         usbd_status             err;
     155           0 :         u_int8_t                val = 0;
     156             : 
     157           0 :         if (usbd_is_dying(sc->cue_udev))
     158           0 :                 return (0);
     159             : 
     160           0 :         req.bmRequestType = UT_READ_VENDOR_DEVICE;
     161           0 :         req.bRequest = CUE_CMD_READREG;
     162           0 :         USETW(req.wValue, 0);
     163           0 :         USETW(req.wIndex, reg);
     164           0 :         USETW(req.wLength, 1);
     165             : 
     166           0 :         err = usbd_do_request(sc->cue_udev, &req, &val);
     167             : 
     168           0 :         if (err) {
     169             :                 DPRINTF(("%s: cue_csr_read_1: reg=0x%x err=%s\n",
     170             :                          sc->cue_dev.dv_xname, reg, usbd_errstr(err)));
     171           0 :                 return (0);
     172             :         }
     173             : 
     174             :         DPRINTFN(10,("%s: cue_csr_read_1 reg=0x%x val=0x%x\n",
     175             :                      sc->cue_dev.dv_xname, reg, val));
     176             : 
     177           0 :         return (val);
     178           0 : }
     179             : 
     180             : int
     181           0 : cue_csr_read_2(struct cue_softc *sc, int reg)
     182             : {
     183           0 :         usb_device_request_t    req;
     184             :         usbd_status             err;
     185           0 :         uWord                   val;
     186             : 
     187           0 :         if (usbd_is_dying(sc->cue_udev))
     188           0 :                 return (0);
     189             : 
     190           0 :         req.bmRequestType = UT_READ_VENDOR_DEVICE;
     191           0 :         req.bRequest = CUE_CMD_READREG;
     192           0 :         USETW(req.wValue, 0);
     193           0 :         USETW(req.wIndex, reg);
     194           0 :         USETW(req.wLength, 2);
     195             : 
     196           0 :         err = usbd_do_request(sc->cue_udev, &req, &val);
     197             : 
     198             :         DPRINTFN(10,("%s: cue_csr_read_2 reg=0x%x val=0x%x\n",
     199             :                      sc->cue_dev.dv_xname, reg, UGETW(val)));
     200             : 
     201           0 :         if (err) {
     202             :                 DPRINTF(("%s: cue_csr_read_2: reg=0x%x err=%s\n",
     203             :                          sc->cue_dev.dv_xname, reg, usbd_errstr(err)));
     204           0 :                 return (0);
     205             :         }
     206             : 
     207           0 :         return (UGETW(val));
     208           0 : }
     209             : 
     210             : int
     211           0 : cue_csr_write_1(struct cue_softc *sc, int reg, int val)
     212             : {
     213           0 :         usb_device_request_t    req;
     214             :         usbd_status             err;
     215             : 
     216           0 :         if (usbd_is_dying(sc->cue_udev))
     217           0 :                 return (0);
     218             : 
     219             :         DPRINTFN(10,("%s: cue_csr_write_1 reg=0x%x val=0x%x\n",
     220             :                      sc->cue_dev.dv_xname, reg, val));
     221             : 
     222           0 :         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
     223           0 :         req.bRequest = CUE_CMD_WRITEREG;
     224           0 :         USETW(req.wValue, val);
     225           0 :         USETW(req.wIndex, reg);
     226           0 :         USETW(req.wLength, 0);
     227             : 
     228           0 :         err = usbd_do_request(sc->cue_udev, &req, NULL);
     229             : 
     230           0 :         if (err) {
     231             :                 DPRINTF(("%s: cue_csr_write_1: reg=0x%x err=%s\n",
     232             :                          sc->cue_dev.dv_xname, reg, usbd_errstr(err)));
     233           0 :                 return (-1);
     234             :         }
     235             : 
     236             :         DPRINTFN(20,("%s: cue_csr_write_1, after reg=0x%x val=0x%x\n",
     237             :                      sc->cue_dev.dv_xname, reg, cue_csr_read_1(sc, reg)));
     238             : 
     239           0 :         return (0);
     240           0 : }
     241             : 
     242             : #if 0
     243             : int
     244             : cue_csr_write_2(struct cue_softc *sc, int reg, int aval)
     245             : {
     246             :         usb_device_request_t    req;
     247             :         usbd_status             err;
     248             :         uWord                   val;
     249             :         int                     s;
     250             : 
     251             :         if (usbd_is_dying(sc->cue_udev))
     252             :                 return (0);
     253             : 
     254             :         DPRINTFN(10,("%s: cue_csr_write_2 reg=0x%x val=0x%x\n",
     255             :                      sc->cue_dev.dv_xname, reg, aval));
     256             : 
     257             :         USETW(val, aval);
     258             :         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
     259             :         req.bRequest = CUE_CMD_WRITEREG;
     260             :         USETW(req.wValue, val);
     261             :         USETW(req.wIndex, reg);
     262             :         USETW(req.wLength, 0);
     263             : 
     264             :         err = usbd_do_request(sc->cue_udev, &req, NULL);
     265             : 
     266             :         if (err) {
     267             :                 DPRINTF(("%s: cue_csr_write_2: reg=0x%x err=%s\n",
     268             :                          sc->cue_dev.dv_xname, reg, usbd_errstr(err)));
     269             :                 return (-1);
     270             :         }
     271             : 
     272             :         return (0);
     273             : }
     274             : #endif
     275             : 
     276             : int
     277           0 : cue_mem(struct cue_softc *sc, int cmd, int addr, void *buf, int len)
     278             : {
     279           0 :         usb_device_request_t    req;
     280             :         usbd_status             err;
     281             : 
     282             :         DPRINTFN(10,("%s: cue_mem cmd=0x%x addr=0x%x len=%d\n",
     283             :                      sc->cue_dev.dv_xname, cmd, addr, len));
     284             : 
     285           0 :         if (cmd == CUE_CMD_READSRAM)
     286           0 :                 req.bmRequestType = UT_READ_VENDOR_DEVICE;
     287             :         else
     288           0 :                 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
     289           0 :         req.bRequest = cmd;
     290           0 :         USETW(req.wValue, 0);
     291           0 :         USETW(req.wIndex, addr);
     292           0 :         USETW(req.wLength, len);
     293             : 
     294           0 :         err = usbd_do_request(sc->cue_udev, &req, buf);
     295             : 
     296           0 :         if (err) {
     297             :                 DPRINTF(("%s: cue_csr_mem: addr=0x%x err=%s\n",
     298             :                          sc->cue_dev.dv_xname, addr, usbd_errstr(err)));
     299           0 :                 return (-1);
     300             :         }
     301             : 
     302           0 :         return (0);
     303           0 : }
     304             : 
     305             : int
     306           0 : cue_getmac(struct cue_softc *sc, void *buf)
     307             : {
     308           0 :         usb_device_request_t    req;
     309             :         usbd_status             err;
     310             : 
     311             :         DPRINTFN(10,("%s: cue_getmac\n", sc->cue_dev.dv_xname));
     312             : 
     313           0 :         req.bmRequestType = UT_READ_VENDOR_DEVICE;
     314           0 :         req.bRequest = CUE_CMD_GET_MACADDR;
     315           0 :         USETW(req.wValue, 0);
     316           0 :         USETW(req.wIndex, 0);
     317           0 :         USETW(req.wLength, ETHER_ADDR_LEN);
     318             : 
     319           0 :         err = usbd_do_request(sc->cue_udev, &req, buf);
     320             : 
     321           0 :         if (err) {
     322           0 :                 printf("%s: read MAC address failed\n",
     323           0 :                        sc->cue_dev.dv_xname);
     324           0 :                 return (-1);
     325             :         }
     326             : 
     327           0 :         return (0);
     328           0 : }
     329             : 
     330             : #define CUE_BITS        9
     331             : 
     332             : void
     333           0 : cue_setmulti(struct cue_softc *sc)
     334             : {
     335           0 :         struct arpcom           *ac = &sc->arpcom;
     336             :         struct ifnet            *ifp;
     337             :         struct ether_multi      *enm;
     338             :         struct ether_multistep  step;
     339             :         u_int32_t               h, i;
     340             : 
     341           0 :         ifp = GET_IFP(sc);
     342             : 
     343             :         DPRINTFN(2,("%s: cue_setmulti if_flags=0x%x\n",
     344             :                     sc->cue_dev.dv_xname, ifp->if_flags));
     345             : 
     346           0 :         if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) {
     347           0 :                 ifp->if_flags |= IFF_ALLMULTI;
     348           0 :                 for (i = 0; i < CUE_MCAST_TABLE_LEN; i++)
     349           0 :                         sc->cue_mctab[i] = 0xFF;
     350           0 :                 cue_mem(sc, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR,
     351           0 :                     &sc->cue_mctab, CUE_MCAST_TABLE_LEN);
     352           0 :                 return;
     353             :         }
     354             : 
     355             :         /* first, zot all the existing hash bits */
     356           0 :         for (i = 0; i < CUE_MCAST_TABLE_LEN; i++)
     357           0 :                 sc->cue_mctab[i] = 0;
     358             : 
     359             :         /* now program new ones */
     360           0 :         ETHER_FIRST_MULTI(step, ac, enm);
     361           0 :         while (enm != NULL) {
     362           0 :                 h = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN) &
     363             :                     ((1 << CUE_BITS) - 1);
     364           0 :                 sc->cue_mctab[h >> 3] |= 1 << (h & 0x7);
     365           0 :                 ETHER_NEXT_MULTI(step, enm);
     366             :         }
     367             : 
     368           0 :         ifp->if_flags &= ~IFF_ALLMULTI;
     369             : 
     370             :         /*
     371             :          * Also include the broadcast address in the filter
     372             :          * so we can receive broadcast frames.
     373             :          */
     374           0 :         if (ifp->if_flags & IFF_BROADCAST) {
     375           0 :                 h = ether_crc32_le(etherbroadcastaddr, ETHER_ADDR_LEN) &
     376             :                     ((1 << CUE_BITS) - 1);
     377           0 :                 sc->cue_mctab[h >> 3] |= 1 << (h & 0x7);
     378           0 :         }
     379             : 
     380           0 :         cue_mem(sc, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR,
     381           0 :             &sc->cue_mctab, CUE_MCAST_TABLE_LEN);
     382           0 : }
     383             : 
     384             : void
     385           0 : cue_reset(struct cue_softc *sc)
     386             : {
     387           0 :         usb_device_request_t    req;
     388             :         usbd_status             err;
     389             : 
     390             :         DPRINTFN(2,("%s: cue_reset\n", sc->cue_dev.dv_xname));
     391             : 
     392           0 :         if (usbd_is_dying(sc->cue_udev))
     393           0 :                 return;
     394             : 
     395           0 :         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
     396           0 :         req.bRequest = CUE_CMD_RESET;
     397           0 :         USETW(req.wValue, 0);
     398           0 :         USETW(req.wIndex, 0);
     399           0 :         USETW(req.wLength, 0);
     400             : 
     401           0 :         err = usbd_do_request(sc->cue_udev, &req, NULL);
     402             : 
     403           0 :         if (err)
     404           0 :                 printf("%s: reset failed\n", sc->cue_dev.dv_xname);
     405             : 
     406             :         /* Wait a little while for the chip to get its brains in order. */
     407           0 :         usbd_delay_ms(sc->cue_udev, 1);
     408           0 : }
     409             : 
     410             : /*
     411             :  * Probe for a CATC chip.
     412             :  */
     413             : int
     414           0 : cue_match(struct device *parent, void *match, void *aux)
     415             : {
     416           0 :         struct usb_attach_arg   *uaa = aux;
     417             : 
     418           0 :         if (uaa->iface == NULL || uaa->configno != CUE_CONFIG_NO)
     419           0 :                 return (UMATCH_NONE);
     420             : 
     421           0 :         return (usb_lookup(cue_devs, uaa->vendor, uaa->product) != NULL ?
     422             :             UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
     423           0 : }
     424             : 
     425             : /*
     426             :  * Attach the interface. Allocate softc structures, do ifmedia
     427             :  * setup and ethernet/BPF attach.
     428             :  */
     429             : void
     430           0 : cue_attach(struct device *parent, struct device *self, void *aux)
     431             : {
     432           0 :         struct cue_softc        *sc = (struct cue_softc *)self;
     433           0 :         struct usb_attach_arg   *uaa = aux;
     434             :         int                     s;
     435           0 :         u_char                  eaddr[ETHER_ADDR_LEN];
     436           0 :         struct usbd_device      *dev = uaa->device;
     437           0 :         struct usbd_interface   *iface;
     438             :         usbd_status             err;
     439             :         struct ifnet            *ifp;
     440             :         usb_interface_descriptor_t      *id;
     441             :         usb_endpoint_descriptor_t       *ed;
     442             :         int                     i;
     443             : 
     444             :         DPRINTFN(5,(" : cue_attach: sc=%p, dev=%p", sc, dev));
     445             : 
     446           0 :         sc->cue_udev = dev;
     447           0 :         sc->cue_product = uaa->product;
     448           0 :         sc->cue_vendor = uaa->vendor;
     449             : 
     450           0 :         usb_init_task(&sc->cue_tick_task, cue_tick_task, sc,
     451             :             USB_TASK_TYPE_GENERIC);
     452           0 :         usb_init_task(&sc->cue_stop_task, (void (*)(void *))cue_stop, sc,
     453             :             USB_TASK_TYPE_GENERIC);
     454             : 
     455           0 :         err = usbd_device2interface_handle(dev, CUE_IFACE_IDX, &iface);
     456           0 :         if (err) {
     457           0 :                 printf("%s: getting interface handle failed\n",
     458           0 :                     sc->cue_dev.dv_xname);
     459           0 :                 return;
     460             :         }
     461             : 
     462           0 :         sc->cue_iface = iface;
     463           0 :         id = usbd_get_interface_descriptor(iface);
     464             : 
     465             :         /* Find endpoints. */
     466           0 :         for (i = 0; i < id->bNumEndpoints; i++) {
     467           0 :                 ed = usbd_interface2endpoint_descriptor(iface, i);
     468           0 :                 if (ed == NULL) {
     469           0 :                         printf("%s: couldn't get ep %d\n",
     470           0 :                             sc->cue_dev.dv_xname, i);
     471           0 :                         return;
     472             :                 }
     473           0 :                 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
     474           0 :                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
     475           0 :                         sc->cue_ed[CUE_ENDPT_RX] = ed->bEndpointAddress;
     476           0 :                 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
     477           0 :                            UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
     478           0 :                         sc->cue_ed[CUE_ENDPT_TX] = ed->bEndpointAddress;
     479           0 :                 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
     480           0 :                            UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
     481           0 :                         sc->cue_ed[CUE_ENDPT_INTR] = ed->bEndpointAddress;
     482           0 :                 }
     483             :         }
     484             : 
     485             : #if 0
     486             :         /* Reset the adapter. */
     487             :         cue_reset(sc);
     488             : #endif
     489             :         /*
     490             :          * Get station address.
     491             :          */
     492           0 :         cue_getmac(sc, &eaddr);
     493             : 
     494           0 :         s = splnet();
     495             : 
     496             :         /*
     497             :          * A CATC chip was detected. Inform the world.
     498             :          */
     499           0 :         printf("%s: address %s\n", sc->cue_dev.dv_xname,
     500           0 :             ether_sprintf(eaddr));
     501             : 
     502           0 :         bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
     503             : 
     504             :         /* Initialize interface info.*/
     505           0 :         ifp = GET_IFP(sc);
     506           0 :         ifp->if_softc = sc;
     507           0 :         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
     508           0 :         ifp->if_ioctl = cue_ioctl;
     509           0 :         ifp->if_start = cue_start;
     510           0 :         ifp->if_watchdog = cue_watchdog;
     511           0 :         strlcpy(ifp->if_xname, sc->cue_dev.dv_xname, IFNAMSIZ);
     512             : 
     513             :         /* Attach the interface. */
     514           0 :         if_attach(ifp);
     515           0 :         ether_ifattach(ifp);
     516             : 
     517           0 :         timeout_set(&sc->cue_stat_ch, cue_tick, sc);
     518             : 
     519           0 :         splx(s);
     520           0 : }
     521             : 
     522             : int
     523           0 : cue_detach(struct device *self, int flags)
     524             : {
     525           0 :         struct cue_softc        *sc = (struct cue_softc *)self;
     526           0 :         struct ifnet            *ifp = GET_IFP(sc);
     527             :         int                     s;
     528             : 
     529             :         DPRINTFN(2,("%s: %s: enter\n", sc->cue_dev.dv_xname, __func__));
     530             : 
     531           0 :         if (timeout_initialized(&sc->cue_stat_ch))
     532           0 :                 timeout_del(&sc->cue_stat_ch);
     533             : 
     534             :         /*
     535             :          * Remove any pending task.  It cannot be executing because it run
     536             :          * in the same thread as detach.
     537             :          */
     538           0 :         usb_rem_task(sc->cue_udev, &sc->cue_tick_task);
     539           0 :         usb_rem_task(sc->cue_udev, &sc->cue_stop_task);
     540             : 
     541           0 :         s = splusb();
     542             : 
     543           0 :         if (ifp->if_flags & IFF_RUNNING)
     544           0 :                 cue_stop(sc);
     545             : 
     546           0 :         if (ifp->if_softc != NULL) {
     547           0 :                 ether_ifdetach(ifp);
     548           0 :                 if_detach(ifp);
     549           0 :         }
     550             : 
     551             : #ifdef DIAGNOSTIC
     552           0 :         if (sc->cue_ep[CUE_ENDPT_TX] != NULL ||
     553           0 :             sc->cue_ep[CUE_ENDPT_RX] != NULL ||
     554           0 :             sc->cue_ep[CUE_ENDPT_INTR] != NULL)
     555           0 :                 printf("%s: detach has active endpoints\n",
     556           0 :                        sc->cue_dev.dv_xname);
     557             : #endif
     558             : 
     559           0 :         splx(s);
     560             : 
     561           0 :         return (0);
     562             : }
     563             : 
     564             : /*
     565             :  * Initialize an RX descriptor and attach an MBUF cluster.
     566             :  */
     567             : int
     568           0 : cue_newbuf(struct cue_softc *sc, struct cue_chain *c, struct mbuf *m)
     569             : {
     570             :         struct mbuf             *m_new = NULL;
     571             : 
     572           0 :         if (m == NULL) {
     573           0 :                 MGETHDR(m_new, M_DONTWAIT, MT_DATA);
     574           0 :                 if (m_new == NULL) {
     575           0 :                         printf("%s: no memory for rx list "
     576           0 :                             "-- packet dropped!\n", sc->cue_dev.dv_xname);
     577           0 :                         return (ENOBUFS);
     578             :                 }
     579             : 
     580           0 :                 MCLGET(m_new, M_DONTWAIT);
     581           0 :                 if (!(m_new->m_flags & M_EXT)) {
     582           0 :                         printf("%s: no memory for rx list "
     583           0 :                             "-- packet dropped!\n", sc->cue_dev.dv_xname);
     584           0 :                         m_freem(m_new);
     585           0 :                         return (ENOBUFS);
     586             :                 }
     587           0 :                 m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
     588           0 :         } else {
     589             :                 m_new = m;
     590           0 :                 m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
     591           0 :                 m_new->m_data = m_new->m_ext.ext_buf;
     592             :         }
     593             : 
     594           0 :         m_adj(m_new, ETHER_ALIGN);
     595           0 :         c->cue_mbuf = m_new;
     596             : 
     597           0 :         return (0);
     598           0 : }
     599             : 
     600             : int
     601           0 : cue_rx_list_init(struct cue_softc *sc)
     602             : {
     603             :         struct cue_cdata        *cd;
     604             :         struct cue_chain        *c;
     605             :         int                     i;
     606             : 
     607           0 :         cd = &sc->cue_cdata;
     608           0 :         for (i = 0; i < CUE_RX_LIST_CNT; i++) {
     609           0 :                 c = &cd->cue_rx_chain[i];
     610           0 :                 c->cue_sc = sc;
     611           0 :                 c->cue_idx = i;
     612           0 :                 if (cue_newbuf(sc, c, NULL) == ENOBUFS)
     613           0 :                         return (ENOBUFS);
     614           0 :                 if (c->cue_xfer == NULL) {
     615           0 :                         c->cue_xfer = usbd_alloc_xfer(sc->cue_udev);
     616           0 :                         if (c->cue_xfer == NULL)
     617           0 :                                 return (ENOBUFS);
     618           0 :                         c->cue_buf = usbd_alloc_buffer(c->cue_xfer, CUE_BUFSZ);
     619           0 :                         if (c->cue_buf == NULL) {
     620           0 :                                 usbd_free_xfer(c->cue_xfer);
     621           0 :                                 return (ENOBUFS);
     622             :                         }
     623             :                 }
     624             :         }
     625             : 
     626           0 :         return (0);
     627           0 : }
     628             : 
     629             : int
     630           0 : cue_tx_list_init(struct cue_softc *sc)
     631             : {
     632             :         struct cue_cdata        *cd;
     633             :         struct cue_chain        *c;
     634             :         int                     i;
     635             : 
     636           0 :         cd = &sc->cue_cdata;
     637           0 :         for (i = 0; i < CUE_TX_LIST_CNT; i++) {
     638           0 :                 c = &cd->cue_tx_chain[i];
     639           0 :                 c->cue_sc = sc;
     640           0 :                 c->cue_idx = i;
     641           0 :                 c->cue_mbuf = NULL;
     642           0 :                 if (c->cue_xfer == NULL) {
     643           0 :                         c->cue_xfer = usbd_alloc_xfer(sc->cue_udev);
     644           0 :                         if (c->cue_xfer == NULL)
     645           0 :                                 return (ENOBUFS);
     646           0 :                         c->cue_buf = usbd_alloc_buffer(c->cue_xfer, CUE_BUFSZ);
     647           0 :                         if (c->cue_buf == NULL) {
     648           0 :                                 usbd_free_xfer(c->cue_xfer);
     649           0 :                                 return (ENOBUFS);
     650             :                         }
     651             :                 }
     652             :         }
     653             : 
     654           0 :         return (0);
     655           0 : }
     656             : 
     657             : /*
     658             :  * A frame has been uploaded: pass the resulting mbuf chain up to
     659             :  * the higher level protocols.
     660             :  */
     661             : void
     662           0 : cue_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
     663             : {
     664           0 :         struct cue_chain        *c = priv;
     665           0 :         struct cue_softc        *sc = c->cue_sc;
     666           0 :         struct ifnet            *ifp = GET_IFP(sc);
     667           0 :         struct mbuf_list        ml = MBUF_LIST_INITIALIZER();
     668             :         struct mbuf             *m;
     669           0 :         int                     total_len = 0;
     670             :         u_int16_t               len;
     671             :         int                     s;
     672             : 
     673             :         DPRINTFN(10,("%s: %s: enter status=%d\n", sc->cue_dev.dv_xname,
     674             :                      __func__, status));
     675             : 
     676           0 :         if (usbd_is_dying(sc->cue_udev))
     677           0 :                 return;
     678             : 
     679           0 :         if (!(ifp->if_flags & IFF_RUNNING))
     680           0 :                 return;
     681             : 
     682           0 :         if (status != USBD_NORMAL_COMPLETION) {
     683           0 :                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
     684           0 :                         return;
     685           0 :                 sc->cue_rx_errs++;
     686           0 :                 if (usbd_ratecheck(&sc->cue_rx_notice)) {
     687           0 :                         printf("%s: %u usb errors on rx: %s\n",
     688           0 :                             sc->cue_dev.dv_xname, sc->cue_rx_errs,
     689           0 :                             usbd_errstr(status));
     690           0 :                         sc->cue_rx_errs = 0;
     691           0 :                 }
     692           0 :                 if (status == USBD_STALLED)
     693           0 :                         usbd_clear_endpoint_stall_async(sc->cue_ep[CUE_ENDPT_RX]);
     694             :                 goto done;
     695             :         }
     696             : 
     697           0 :         usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
     698             : 
     699           0 :         memcpy(mtod(c->cue_mbuf, char *), c->cue_buf, total_len);
     700             : 
     701           0 :         m = c->cue_mbuf;
     702           0 :         len = UGETW(mtod(m, u_int8_t *));
     703             : 
     704             :         /* No errors; receive the packet. */
     705           0 :         total_len = len;
     706             : 
     707           0 :         if (len < sizeof(struct ether_header)) {
     708           0 :                 ifp->if_ierrors++;
     709           0 :                 goto done;
     710             :         }
     711             : 
     712           0 :         m_adj(m, sizeof(u_int16_t));
     713           0 :         m->m_pkthdr.len = m->m_len = total_len;
     714           0 :         ml_enqueue(&ml, m);
     715             : 
     716           0 :         if (cue_newbuf(sc, c, NULL) == ENOBUFS) {
     717           0 :                 ifp->if_ierrors++;
     718           0 :                 goto done;
     719             :         }
     720             : 
     721           0 :         s = splnet();
     722           0 :         if_input(ifp, &ml);
     723           0 :         splx(s);
     724             : 
     725             : done:
     726             :         /* Setup new transfer. */
     727           0 :         usbd_setup_xfer(c->cue_xfer, sc->cue_ep[CUE_ENDPT_RX],
     728           0 :             c, c->cue_buf, CUE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
     729             :             USBD_NO_TIMEOUT, cue_rxeof);
     730           0 :         usbd_transfer(c->cue_xfer);
     731             : 
     732             :         DPRINTFN(10,("%s: %s: start rx\n", sc->cue_dev.dv_xname,
     733             :                     __func__));
     734           0 : }
     735             : 
     736             : /*
     737             :  * A frame was downloaded to the chip. It's safe for us to clean up
     738             :  * the list buffers.
     739             :  */
     740             : void
     741           0 : cue_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
     742             : {
     743           0 :         struct cue_chain        *c = priv;
     744           0 :         struct cue_softc        *sc = c->cue_sc;
     745           0 :         struct ifnet            *ifp = GET_IFP(sc);
     746             :         int                     s;
     747             : 
     748           0 :         if (usbd_is_dying(sc->cue_udev))
     749           0 :                 return;
     750             : 
     751           0 :         s = splnet();
     752             : 
     753             :         DPRINTFN(10,("%s: %s: enter status=%d\n", sc->cue_dev.dv_xname,
     754             :                     __func__, status));
     755             : 
     756           0 :         ifp->if_timer = 0;
     757           0 :         ifq_clr_oactive(&ifp->if_snd);
     758             : 
     759           0 :         if (status != USBD_NORMAL_COMPLETION) {
     760           0 :                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
     761           0 :                         splx(s);
     762           0 :                         return;
     763             :                 }
     764           0 :                 ifp->if_oerrors++;
     765           0 :                 printf("%s: usb error on tx: %s\n", sc->cue_dev.dv_xname,
     766           0 :                     usbd_errstr(status));
     767           0 :                 if (status == USBD_STALLED)
     768           0 :                         usbd_clear_endpoint_stall_async(sc->cue_ep[CUE_ENDPT_TX]);
     769           0 :                 splx(s);
     770           0 :                 return;
     771             :         }
     772             : 
     773           0 :         m_freem(c->cue_mbuf);
     774           0 :         c->cue_mbuf = NULL;
     775             : 
     776           0 :         if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
     777           0 :                 cue_start(ifp);
     778             : 
     779           0 :         splx(s);
     780           0 : }
     781             : 
     782             : void
     783           0 : cue_tick(void *xsc)
     784             : {
     785           0 :         struct cue_softc        *sc = xsc;
     786             : 
     787           0 :         if (sc == NULL)
     788           0 :                 return;
     789             : 
     790           0 :         if (usbd_is_dying(sc->cue_udev))
     791           0 :                 return;
     792             : 
     793             :         DPRINTFN(2,("%s: %s: enter\n", sc->cue_dev.dv_xname, __func__));
     794             : 
     795             :         /* Perform statistics update in process context. */
     796           0 :         usb_add_task(sc->cue_udev, &sc->cue_tick_task);
     797           0 : }
     798             : 
     799             : void
     800           0 : cue_tick_task(void *xsc)
     801             : {
     802           0 :         struct cue_softc        *sc = xsc;
     803             :         struct ifnet            *ifp;
     804             : 
     805           0 :         if (usbd_is_dying(sc->cue_udev))
     806           0 :                 return;
     807             : 
     808             :         DPRINTFN(2,("%s: %s: enter\n", sc->cue_dev.dv_xname, __func__));
     809             : 
     810           0 :         ifp = GET_IFP(sc);
     811             : 
     812           0 :         ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_SINGLECOLL);
     813           0 :         ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_MULTICOLL);
     814           0 :         ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_EXCESSCOLL);
     815             : 
     816           0 :         if (cue_csr_read_2(sc, CUE_RX_FRAMEERR))
     817           0 :                 ifp->if_ierrors++;
     818           0 : }
     819             : 
     820             : int
     821           0 : cue_send(struct cue_softc *sc, struct mbuf *m, int idx)
     822             : {
     823             :         int                     total_len;
     824             :         struct cue_chain        *c;
     825             :         usbd_status             err;
     826             : 
     827           0 :         c = &sc->cue_cdata.cue_tx_chain[idx];
     828             : 
     829             :         /*
     830             :          * Copy the mbuf data into a contiguous buffer, leaving two
     831             :          * bytes at the beginning to hold the frame length.
     832             :          */
     833           0 :         m_copydata(m, 0, m->m_pkthdr.len, c->cue_buf + 2);
     834           0 :         c->cue_mbuf = m;
     835             : 
     836           0 :         total_len = m->m_pkthdr.len + 2;
     837             : 
     838             :         DPRINTFN(10,("%s: %s: total_len=%d\n",
     839             :                      sc->cue_dev.dv_xname, __func__, total_len));
     840             : 
     841             :         /* The first two bytes are the frame length */
     842           0 :         c->cue_buf[0] = (u_int8_t)m->m_pkthdr.len;
     843           0 :         c->cue_buf[1] = (u_int8_t)(m->m_pkthdr.len >> 8);
     844             : 
     845             :         /* XXX 10000 */
     846           0 :         usbd_setup_xfer(c->cue_xfer, sc->cue_ep[CUE_ENDPT_TX],
     847           0 :             c, c->cue_buf, total_len, USBD_NO_COPY, 10000, cue_txeof);
     848             : 
     849             :         /* Transmit */
     850           0 :         err = usbd_transfer(c->cue_xfer);
     851           0 :         if (err != USBD_IN_PROGRESS) {
     852           0 :                 printf("%s: cue_send error=%s\n", sc->cue_dev.dv_xname,
     853           0 :                        usbd_errstr(err));
     854             :                 /* Stop the interface from process context. */
     855           0 :                 usb_add_task(sc->cue_udev, &sc->cue_stop_task);
     856           0 :                 return (EIO);
     857             :         }
     858             : 
     859           0 :         sc->cue_cdata.cue_tx_cnt++;
     860             : 
     861           0 :         return (0);
     862           0 : }
     863             : 
     864             : void
     865           0 : cue_start(struct ifnet *ifp)
     866             : {
     867           0 :         struct cue_softc        *sc = ifp->if_softc;
     868             :         struct mbuf             *m_head = NULL;
     869             : 
     870           0 :         if (usbd_is_dying(sc->cue_udev))
     871           0 :                 return;
     872             : 
     873             :         DPRINTFN(10,("%s: %s: enter\n", sc->cue_dev.dv_xname,__func__));
     874             : 
     875           0 :         if (ifq_is_oactive(&ifp->if_snd))
     876           0 :                 return;
     877             : 
     878           0 :         m_head = ifq_deq_begin(&ifp->if_snd);
     879           0 :         if (m_head == NULL)
     880           0 :                 return;
     881             : 
     882           0 :         if (cue_send(sc, m_head, 0)) {
     883           0 :                 ifq_deq_rollback(&ifp->if_snd, m_head);
     884           0 :                 ifq_set_oactive(&ifp->if_snd);
     885           0 :                 return;
     886             :         }
     887             : 
     888           0 :         ifq_deq_commit(&ifp->if_snd, m_head);
     889             : 
     890             : #if NBPFILTER > 0
     891             :         /*
     892             :          * If there's a BPF listener, bounce a copy of this frame
     893             :          * to him.
     894             :          */
     895           0 :         if (ifp->if_bpf)
     896           0 :                 bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
     897             : #endif
     898             : 
     899           0 :         ifq_set_oactive(&ifp->if_snd);
     900             : 
     901             :         /*
     902             :          * Set a timeout in case the chip goes out to lunch.
     903             :          */
     904           0 :         ifp->if_timer = 5;
     905           0 : }
     906             : 
     907             : void
     908           0 : cue_init(void *xsc)
     909             : {
     910           0 :         struct cue_softc        *sc = xsc;
     911           0 :         struct ifnet            *ifp = GET_IFP(sc);
     912             :         int                     i, s, ctl;
     913             :         u_char                  *eaddr;
     914             : 
     915           0 :         if (usbd_is_dying(sc->cue_udev))
     916           0 :                 return;
     917             : 
     918             :         DPRINTFN(10,("%s: %s: enter\n", sc->cue_dev.dv_xname,__func__));
     919             : 
     920           0 :         if (ifp->if_flags & IFF_RUNNING)
     921           0 :                 return;
     922             : 
     923           0 :         s = splnet();
     924             : 
     925             :         /*
     926             :          * Cancel pending I/O and free all RX/TX buffers.
     927             :          */
     928             : #if 1
     929           0 :         cue_reset(sc);
     930             : #endif
     931             : 
     932             :         /* Set advanced operation modes. */
     933           0 :         cue_csr_write_1(sc, CUE_ADVANCED_OPMODES,
     934             :             CUE_AOP_EMBED_RXLEN | 0x03); /* 1 wait state */
     935             : 
     936           0 :         eaddr = sc->arpcom.ac_enaddr;
     937             :         /* Set MAC address */
     938           0 :         for (i = 0; i < ETHER_ADDR_LEN; i++)
     939           0 :                 cue_csr_write_1(sc, CUE_PAR0 - i, eaddr[i]);
     940             : 
     941             :         /* Enable RX logic. */
     942             :         ctl = CUE_ETHCTL_RX_ON | CUE_ETHCTL_MCAST_ON;
     943           0 :         if (ifp->if_flags & IFF_PROMISC)
     944           0 :                 ctl |= CUE_ETHCTL_PROMISC;
     945           0 :         cue_csr_write_1(sc, CUE_ETHCTL, ctl);
     946             : 
     947             :         /* Init TX ring. */
     948           0 :         if (cue_tx_list_init(sc) == ENOBUFS) {
     949           0 :                 printf("%s: tx list init failed\n", sc->cue_dev.dv_xname);
     950           0 :                 splx(s);
     951           0 :                 return;
     952             :         }
     953             : 
     954             :         /* Init RX ring. */
     955           0 :         if (cue_rx_list_init(sc) == ENOBUFS) {
     956           0 :                 printf("%s: rx list init failed\n", sc->cue_dev.dv_xname);
     957           0 :                 splx(s);
     958           0 :                 return;
     959             :         }
     960             : 
     961             :         /* Load the multicast filter. */
     962           0 :         cue_setmulti(sc);
     963             : 
     964             :         /*
     965             :          * Set the number of RX and TX buffers that we want
     966             :          * to reserve inside the ASIC.
     967             :          */
     968           0 :         cue_csr_write_1(sc, CUE_RX_BUFPKTS, CUE_RX_FRAMES);
     969           0 :         cue_csr_write_1(sc, CUE_TX_BUFPKTS, CUE_TX_FRAMES);
     970             : 
     971             :         /* Set advanced operation modes. */
     972           0 :         cue_csr_write_1(sc, CUE_ADVANCED_OPMODES,
     973             :             CUE_AOP_EMBED_RXLEN | 0x01); /* 1 wait state */
     974             : 
     975             :         /* Program the LED operation. */
     976           0 :         cue_csr_write_1(sc, CUE_LEDCTL, CUE_LEDCTL_FOLLOW_LINK);
     977             : 
     978           0 :         if (sc->cue_ep[CUE_ENDPT_RX] == NULL) {
     979           0 :                 if (cue_open_pipes(sc)) {
     980           0 :                         splx(s);
     981           0 :                         return;
     982             :                 }
     983             :         }
     984             : 
     985           0 :         ifp->if_flags |= IFF_RUNNING;
     986           0 :         ifq_clr_oactive(&ifp->if_snd);
     987             : 
     988           0 :         splx(s);
     989             : 
     990           0 :         timeout_add_sec(&sc->cue_stat_ch, 1);
     991           0 : }
     992             : 
     993             : int
     994           0 : cue_open_pipes(struct cue_softc *sc)
     995             : {
     996             :         struct cue_chain        *c;
     997             :         usbd_status             err;
     998             :         int                     i;
     999             : 
    1000             :         /* Open RX and TX pipes. */
    1001           0 :         err = usbd_open_pipe(sc->cue_iface, sc->cue_ed[CUE_ENDPT_RX],
    1002           0 :             USBD_EXCLUSIVE_USE, &sc->cue_ep[CUE_ENDPT_RX]);
    1003           0 :         if (err) {
    1004           0 :                 printf("%s: open rx pipe failed: %s\n",
    1005           0 :                     sc->cue_dev.dv_xname, usbd_errstr(err));
    1006           0 :                 return (EIO);
    1007             :         }
    1008           0 :         err = usbd_open_pipe(sc->cue_iface, sc->cue_ed[CUE_ENDPT_TX],
    1009           0 :             USBD_EXCLUSIVE_USE, &sc->cue_ep[CUE_ENDPT_TX]);
    1010           0 :         if (err) {
    1011           0 :                 printf("%s: open tx pipe failed: %s\n",
    1012           0 :                     sc->cue_dev.dv_xname, usbd_errstr(err));
    1013           0 :                 return (EIO);
    1014             :         }
    1015             : 
    1016             :         /* Start up the receive pipe. */
    1017           0 :         for (i = 0; i < CUE_RX_LIST_CNT; i++) {
    1018           0 :                 c = &sc->cue_cdata.cue_rx_chain[i];
    1019           0 :                 usbd_setup_xfer(c->cue_xfer, sc->cue_ep[CUE_ENDPT_RX],
    1020           0 :                     c, c->cue_buf, CUE_BUFSZ,
    1021             :                     USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
    1022             :                     cue_rxeof);
    1023           0 :                 usbd_transfer(c->cue_xfer);
    1024             :         }
    1025             : 
    1026           0 :         return (0);
    1027           0 : }
    1028             : 
    1029             : int
    1030           0 : cue_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
    1031             : {
    1032           0 :         struct cue_softc        *sc = ifp->if_softc;
    1033             :         int                     s, error = 0;
    1034             : 
    1035           0 :         if (usbd_is_dying(sc->cue_udev))
    1036           0 :                 return (EIO);
    1037             : 
    1038           0 :         s = splnet();
    1039             : 
    1040           0 :         switch(command) {
    1041             :         case SIOCSIFADDR:
    1042           0 :                 ifp->if_flags |= IFF_UP;
    1043           0 :                 cue_init(sc);
    1044           0 :                 break;
    1045             : 
    1046             :         case SIOCSIFFLAGS:
    1047           0 :                 if (ifp->if_flags & IFF_UP) {
    1048           0 :                         if (ifp->if_flags & IFF_RUNNING &&
    1049           0 :                             ifp->if_flags & IFF_PROMISC &&
    1050           0 :                             !(sc->cue_if_flags & IFF_PROMISC)) {
    1051           0 :                                 CUE_SETBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC);
    1052           0 :                                 cue_setmulti(sc);
    1053           0 :                         } else if (ifp->if_flags & IFF_RUNNING &&
    1054           0 :                             !(ifp->if_flags & IFF_PROMISC) &&
    1055           0 :                             sc->cue_if_flags & IFF_PROMISC) {
    1056           0 :                                 CUE_CLRBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC);
    1057           0 :                                 cue_setmulti(sc);
    1058           0 :                         } else if (!(ifp->if_flags & IFF_RUNNING))
    1059           0 :                                 cue_init(sc);
    1060             :                 } else {
    1061           0 :                         if (ifp->if_flags & IFF_RUNNING)
    1062           0 :                                 cue_stop(sc);
    1063             :                 }
    1064           0 :                 sc->cue_if_flags = ifp->if_flags;
    1065             :                 error = 0;
    1066           0 :                 break;
    1067             : 
    1068             :         default:
    1069           0 :                 error = ether_ioctl(ifp, &sc->arpcom, command, data);
    1070           0 :         }
    1071             : 
    1072           0 :         if (error == ENETRESET) {
    1073           0 :                 if (ifp->if_flags & IFF_RUNNING)
    1074           0 :                         cue_setmulti(sc);
    1075             :                 error = 0;
    1076           0 :         }
    1077             : 
    1078           0 :         splx(s);
    1079           0 :         return (error);
    1080           0 : }
    1081             : 
    1082             : void
    1083           0 : cue_watchdog(struct ifnet *ifp)
    1084             : {
    1085           0 :         struct cue_softc        *sc = ifp->if_softc;
    1086             :         struct cue_chain        *c;
    1087           0 :         usbd_status             stat;
    1088             :         int                     s;
    1089             : 
    1090             :         DPRINTFN(5,("%s: %s: enter\n", sc->cue_dev.dv_xname,__func__));
    1091             : 
    1092           0 :         if (usbd_is_dying(sc->cue_udev))
    1093           0 :                 return;
    1094             : 
    1095           0 :         ifp->if_oerrors++;
    1096           0 :         printf("%s: watchdog timeout\n", sc->cue_dev.dv_xname);
    1097             : 
    1098           0 :         s = splusb();
    1099           0 :         c = &sc->cue_cdata.cue_tx_chain[0];
    1100           0 :         usbd_get_xfer_status(c->cue_xfer, NULL, NULL, NULL, &stat);
    1101           0 :         cue_txeof(c->cue_xfer, c, stat);
    1102             : 
    1103           0 :         if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
    1104           0 :                 cue_start(ifp);
    1105           0 :         splx(s);
    1106           0 : }
    1107             : 
    1108             : /*
    1109             :  * Stop the adapter and free any mbufs allocated to the
    1110             :  * RX and TX lists.
    1111             :  */
    1112             : void
    1113           0 : cue_stop(struct cue_softc *sc)
    1114             : {
    1115             :         usbd_status             err;
    1116             :         struct ifnet            *ifp;
    1117             :         int                     i;
    1118             : 
    1119             :         DPRINTFN(10,("%s: %s: enter\n", sc->cue_dev.dv_xname,__func__));
    1120             : 
    1121           0 :         ifp = GET_IFP(sc);
    1122           0 :         ifp->if_timer = 0;
    1123           0 :         ifp->if_flags &= ~IFF_RUNNING;
    1124           0 :         ifq_clr_oactive(&ifp->if_snd);
    1125             : 
    1126           0 :         cue_csr_write_1(sc, CUE_ETHCTL, 0);
    1127           0 :         cue_reset(sc);
    1128           0 :         timeout_del(&sc->cue_stat_ch);
    1129             : 
    1130             :         /* Stop transfers. */
    1131           0 :         if (sc->cue_ep[CUE_ENDPT_RX] != NULL) {
    1132           0 :                 usbd_abort_pipe(sc->cue_ep[CUE_ENDPT_RX]);
    1133           0 :                 err = usbd_close_pipe(sc->cue_ep[CUE_ENDPT_RX]);
    1134           0 :                 if (err) {
    1135           0 :                         printf("%s: close rx pipe failed: %s\n",
    1136           0 :                         sc->cue_dev.dv_xname, usbd_errstr(err));
    1137           0 :                 }
    1138           0 :                 sc->cue_ep[CUE_ENDPT_RX] = NULL;
    1139           0 :         }
    1140             : 
    1141           0 :         if (sc->cue_ep[CUE_ENDPT_TX] != NULL) {
    1142           0 :                 usbd_abort_pipe(sc->cue_ep[CUE_ENDPT_TX]);
    1143           0 :                 err = usbd_close_pipe(sc->cue_ep[CUE_ENDPT_TX]);
    1144           0 :                 if (err) {
    1145           0 :                         printf("%s: close tx pipe failed: %s\n",
    1146           0 :                             sc->cue_dev.dv_xname, usbd_errstr(err));
    1147           0 :                 }
    1148           0 :                 sc->cue_ep[CUE_ENDPT_TX] = NULL;
    1149           0 :         }
    1150             : 
    1151           0 :         if (sc->cue_ep[CUE_ENDPT_INTR] != NULL) {
    1152           0 :                 usbd_abort_pipe(sc->cue_ep[CUE_ENDPT_INTR]);
    1153           0 :                 err = usbd_close_pipe(sc->cue_ep[CUE_ENDPT_INTR]);
    1154           0 :                 if (err) {
    1155           0 :                         printf("%s: close intr pipe failed: %s\n",
    1156           0 :                             sc->cue_dev.dv_xname, usbd_errstr(err));
    1157           0 :                 }
    1158           0 :                 sc->cue_ep[CUE_ENDPT_INTR] = NULL;
    1159           0 :         }
    1160             : 
    1161             :         /* Free RX resources. */
    1162           0 :         for (i = 0; i < CUE_RX_LIST_CNT; i++) {
    1163           0 :                 if (sc->cue_cdata.cue_rx_chain[i].cue_mbuf != NULL) {
    1164           0 :                         m_freem(sc->cue_cdata.cue_rx_chain[i].cue_mbuf);
    1165           0 :                         sc->cue_cdata.cue_rx_chain[i].cue_mbuf = NULL;
    1166           0 :                 }
    1167           0 :                 if (sc->cue_cdata.cue_rx_chain[i].cue_xfer != NULL) {
    1168           0 :                         usbd_free_xfer(sc->cue_cdata.cue_rx_chain[i].cue_xfer);
    1169           0 :                         sc->cue_cdata.cue_rx_chain[i].cue_xfer = NULL;
    1170           0 :                 }
    1171             :         }
    1172             : 
    1173             :         /* Free TX resources. */
    1174           0 :         for (i = 0; i < CUE_TX_LIST_CNT; i++) {
    1175           0 :                 if (sc->cue_cdata.cue_tx_chain[i].cue_mbuf != NULL) {
    1176           0 :                         m_freem(sc->cue_cdata.cue_tx_chain[i].cue_mbuf);
    1177           0 :                         sc->cue_cdata.cue_tx_chain[i].cue_mbuf = NULL;
    1178           0 :                 }
    1179           0 :                 if (sc->cue_cdata.cue_tx_chain[i].cue_xfer != NULL) {
    1180           0 :                         usbd_free_xfer(sc->cue_cdata.cue_tx_chain[i].cue_xfer);
    1181           0 :                         sc->cue_cdata.cue_tx_chain[i].cue_xfer = NULL;
    1182           0 :                 }
    1183             :         }
    1184           0 : }

Generated by: LCOV version 1.13