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

          Line data    Source code
       1             : /*      $OpenBSD: if_url.c,v 1.83 2018/07/03 14:33:43 kevlo Exp $ */
       2             : /*      $NetBSD: if_url.c,v 1.6 2002/09/29 10:19:21 martin Exp $        */
       3             : /*
       4             :  * Copyright (c) 2001, 2002
       5             :  *     Shingo WATANABE <nabe@nabechan.org>.  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. Neither the name of the author nor the names of any co-contributors
      16             :  *    may be used to endorse or promote products derived from this software
      17             :  *    without specific prior written permission.
      18             :  *
      19             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
      20             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      21             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      22             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
      23             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      24             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      25             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      26             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      27             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      28             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      29             :  * SUCH DAMAGE.
      30             :  *
      31             :  */
      32             : 
      33             : /*
      34             :  * The RTL8150L(Realtek USB to fast ethernet controller) spec can be found at
      35             :  *   ftp://ftp.realtek.com.tw/lancard/data_sheet/8150/8150v14.pdf
      36             :  *   ftp://152.104.125.40/lancard/data_sheet/8150/8150v14.pdf
      37             :  */
      38             : 
      39             : /*
      40             :  * TODO:
      41             :  *      Interrupt Endpoint support
      42             :  *      External PHYs
      43             :  */
      44             : 
      45             : #include "bpfilter.h"
      46             : 
      47             : #include <sys/param.h>
      48             : #include <sys/systm.h>
      49             : #include <sys/rwlock.h>
      50             : #include <sys/mbuf.h>
      51             : #include <sys/kernel.h>
      52             : #include <sys/socket.h>
      53             : 
      54             : #include <sys/device.h>
      55             : 
      56             : #include <net/if.h>
      57             : #include <net/if_media.h>
      58             : 
      59             : #if NBPFILTER > 0
      60             : #include <net/bpf.h>
      61             : #endif
      62             : 
      63             : #include <netinet/in.h>
      64             : #include <netinet/if_ether.h>
      65             : 
      66             : #include <dev/mii/mii.h>
      67             : #include <dev/mii/miivar.h>
      68             : #include <dev/mii/urlphyreg.h>
      69             : 
      70             : #include <dev/usb/usb.h>
      71             : #include <dev/usb/usbdi.h>
      72             : #include <dev/usb/usbdi_util.h>
      73             : #include <dev/usb/usbdevs.h>
      74             : 
      75             : #include <dev/usb/if_urlreg.h>
      76             : 
      77             : int url_match(struct device *, void *, void *);
      78             : void url_attach(struct device *, struct device *, void *);
      79             : int url_detach(struct device *, int);
      80             : 
      81             : struct cfdriver url_cd = {
      82             :         NULL, "url", DV_IFNET
      83             : };
      84             : 
      85             : const struct cfattach url_ca = {
      86             :         sizeof(struct url_softc), url_match, url_attach, url_detach
      87             : };
      88             : 
      89             : int url_openpipes(struct url_softc *);
      90             : int url_rx_list_init(struct url_softc *);
      91             : int url_tx_list_init(struct url_softc *);
      92             : int url_newbuf(struct url_softc *, struct url_chain *, struct mbuf *);
      93             : void url_start(struct ifnet *);
      94             : int url_send(struct url_softc *, struct mbuf *, int);
      95             : void url_txeof(struct usbd_xfer *, void *, usbd_status);
      96             : void url_rxeof(struct usbd_xfer *, void *, usbd_status);
      97             : void url_tick(void *);
      98             : void url_tick_task(void *);
      99             : int url_ioctl(struct ifnet *, u_long, caddr_t);
     100             : void url_stop_task(struct url_softc *);
     101             : void url_stop(struct ifnet *, int);
     102             : void url_watchdog(struct ifnet *);
     103             : int url_ifmedia_change(struct ifnet *);
     104             : void url_ifmedia_status(struct ifnet *, struct ifmediareq *);
     105             : void url_lock_mii(struct url_softc *);
     106             : void url_unlock_mii(struct url_softc *);
     107             : int url_int_miibus_readreg(struct device *, int, int);
     108             : void url_int_miibus_writereg(struct device *, int, int, int);
     109             : void url_miibus_statchg(struct device *);
     110             : int url_init(struct ifnet *);
     111             : void url_iff(struct url_softc *);
     112             : void url_reset(struct url_softc *);
     113             : 
     114             : int url_csr_read_1(struct url_softc *, int);
     115             : int url_csr_read_2(struct url_softc *, int);
     116             : int url_csr_write_1(struct url_softc *, int, int);
     117             : int url_csr_write_2(struct url_softc *, int, int);
     118             : int url_csr_write_4(struct url_softc *, int, int);
     119             : int url_mem(struct url_softc *, int, int, void *, int);
     120             : 
     121             : /* Macros */
     122             : #ifdef URL_DEBUG
     123             : #define DPRINTF(x)      do { if (urldebug) printf x; } while (0)
     124             : #define DPRINTFN(n,x)   do { if (urldebug >= (n)) printf x; } while (0)
     125             : int urldebug = 0;
     126             : #else
     127             : #define DPRINTF(x)
     128             : #define DPRINTFN(n,x)
     129             : #endif
     130             : 
     131             : #define URL_SETBIT(sc, reg, x)  \
     132             :         url_csr_write_1(sc, reg, url_csr_read_1(sc, reg) | (x))
     133             : 
     134             : #define URL_SETBIT2(sc, reg, x) \
     135             :         url_csr_write_2(sc, reg, url_csr_read_2(sc, reg) | (x))
     136             : 
     137             : #define URL_CLRBIT(sc, reg, x)  \
     138             :         url_csr_write_1(sc, reg, url_csr_read_1(sc, reg) & ~(x))
     139             : 
     140             : #define URL_CLRBIT2(sc, reg, x) \
     141             :         url_csr_write_2(sc, reg, url_csr_read_2(sc, reg) & ~(x))
     142             : 
     143             : static const struct url_type {
     144             :         struct usb_devno url_dev;
     145             :         u_int16_t url_flags;
     146             : #define URL_EXT_PHY     0x0001
     147             : } url_devs [] = {
     148             :         {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_LCS8138TX}, 0},
     149             :         {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_RTL8151}, 0},
     150             :         {{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAKTX }, 0},
     151             :         {{ USB_VENDOR_MICRONET, USB_PRODUCT_MICRONET_SP128AR}, 0},
     152             :         {{ USB_VENDOR_OQO, USB_PRODUCT_OQO_ETHER01}, 0},
     153             :         {{ USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8150}, 0},
     154             :         {{ USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8151}, 0},
     155             :         {{ USB_VENDOR_ZYXEL, USB_PRODUCT_ZYXEL_PRESTIGE}, 0}
     156             : };
     157             : #define url_lookup(v, p) ((struct url_type *)usb_lookup(url_devs, v, p))
     158             : 
     159             : 
     160             : /* Probe */
     161             : int
     162           0 : url_match(struct device *parent, void *match, void *aux)
     163             : {
     164           0 :         struct usb_attach_arg *uaa = aux;
     165             : 
     166           0 :         if (uaa->iface == NULL || uaa->configno != URL_CONFIG_NO)
     167           0 :                 return (UMATCH_NONE);
     168             : 
     169           0 :         return (url_lookup(uaa->vendor, uaa->product) != NULL ?
     170             :                 UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
     171           0 : }
     172             : /* Attach */
     173             : void
     174           0 : url_attach(struct device *parent, struct device *self, void *aux)
     175             : {
     176           0 :         struct url_softc *sc = (struct url_softc *)self;
     177           0 :         struct usb_attach_arg *uaa = aux;
     178           0 :         struct usbd_device *dev = uaa->device;
     179           0 :         struct usbd_interface *iface;
     180             :         usbd_status err;
     181             :         usb_interface_descriptor_t *id;
     182             :         usb_endpoint_descriptor_t *ed;
     183           0 :         char *devname = sc->sc_dev.dv_xname;
     184             :         struct ifnet *ifp;
     185             :         struct mii_data *mii;
     186           0 :         u_char eaddr[ETHER_ADDR_LEN];
     187             :         int i, s;
     188             : 
     189           0 :         sc->sc_udev = dev;
     190             : 
     191           0 :         usb_init_task(&sc->sc_tick_task, url_tick_task, sc,
     192             :             USB_TASK_TYPE_GENERIC);
     193           0 :         rw_init(&sc->sc_mii_lock, "urlmii");
     194           0 :         usb_init_task(&sc->sc_stop_task, (void (*)(void *)) url_stop_task, sc,
     195             :             USB_TASK_TYPE_GENERIC);
     196             : 
     197             :         /* get control interface */
     198           0 :         err = usbd_device2interface_handle(dev, URL_IFACE_INDEX, &iface);
     199           0 :         if (err) {
     200           0 :                 printf("%s: failed to get interface, err=%s\n", devname,
     201           0 :                        usbd_errstr(err));
     202           0 :                 goto bad;
     203             :         }
     204             : 
     205           0 :         sc->sc_ctl_iface = iface;
     206           0 :         sc->sc_flags = url_lookup(uaa->vendor, uaa->product)->url_flags;
     207             : 
     208             :         /* get interface descriptor */
     209           0 :         id = usbd_get_interface_descriptor(sc->sc_ctl_iface);
     210             : 
     211             :         /* find endpoints */
     212           0 :         sc->sc_bulkin_no = sc->sc_bulkout_no = sc->sc_intrin_no = -1;
     213           0 :         for (i = 0; i < id->bNumEndpoints; i++) {
     214           0 :                 ed = usbd_interface2endpoint_descriptor(sc->sc_ctl_iface, i);
     215           0 :                 if (ed == NULL) {
     216           0 :                         printf("%s: couldn't get endpoint %d\n", devname, i);
     217           0 :                         goto bad;
     218             :                 }
     219           0 :                 if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK &&
     220           0 :                     UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN)
     221           0 :                         sc->sc_bulkin_no = ed->bEndpointAddress; /* RX */
     222           0 :                 else if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK &&
     223           0 :                          UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT)
     224           0 :                         sc->sc_bulkout_no = ed->bEndpointAddress; /* TX */
     225           0 :                 else if ((ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT &&
     226           0 :                          UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN)
     227           0 :                         sc->sc_intrin_no = ed->bEndpointAddress; /* Status */
     228             :         }
     229             : 
     230           0 :         if (sc->sc_bulkin_no == -1 || sc->sc_bulkout_no == -1 ||
     231           0 :             sc->sc_intrin_no == -1) {
     232           0 :                 printf("%s: missing endpoint\n", devname);
     233           0 :                 goto bad;
     234             :         }
     235             : 
     236           0 :         s = splnet();
     237             : 
     238             :         /* reset the adapter */
     239           0 :         url_reset(sc);
     240             : 
     241             :         /* Get Ethernet Address */
     242           0 :         err = url_mem(sc, URL_CMD_READMEM, URL_IDR0, (void *)eaddr,
     243             :                       ETHER_ADDR_LEN);
     244           0 :         if (err) {
     245           0 :                 printf("%s: read MAC address failed\n", devname);
     246           0 :                 splx(s);
     247           0 :                 goto bad;
     248             :         }
     249             : 
     250             :         /* Print Ethernet Address */
     251           0 :         printf("%s: address %s\n", devname, ether_sprintf(eaddr));
     252             : 
     253           0 :         bcopy(eaddr, (char *)&sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN);
     254             :         /* initialize interface information */
     255           0 :         ifp = GET_IFP(sc);
     256           0 :         ifp->if_softc = sc;
     257           0 :         strlcpy(ifp->if_xname, devname, IFNAMSIZ);
     258           0 :         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
     259           0 :         ifp->if_start = url_start;
     260           0 :         ifp->if_ioctl = url_ioctl;
     261           0 :         ifp->if_watchdog = url_watchdog;
     262             : 
     263           0 :         ifp->if_capabilities = IFCAP_VLAN_MTU;
     264             : 
     265             :         /*
     266             :          * Do ifmedia setup.
     267             :          */
     268           0 :         mii = &sc->sc_mii;
     269           0 :         mii->mii_ifp = ifp;
     270           0 :         mii->mii_readreg = url_int_miibus_readreg;
     271           0 :         mii->mii_writereg = url_int_miibus_writereg;
     272             : #if 0
     273             :         if (sc->sc_flags & URL_EXT_PHY) {
     274             :                 mii->mii_readreg = url_ext_miibus_readreg;
     275             :                 mii->mii_writereg = url_ext_miibus_writereg;
     276             :         }
     277             : #endif
     278           0 :         mii->mii_statchg = url_miibus_statchg;
     279           0 :         mii->mii_flags = MIIF_AUTOTSLEEP;
     280           0 :         ifmedia_init(&mii->mii_media, 0,
     281             :                      url_ifmedia_change, url_ifmedia_status);
     282           0 :         mii_attach(self, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, 0);
     283           0 :         if (LIST_FIRST(&mii->mii_phys) == NULL) {
     284           0 :                 ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_NONE, 0, NULL);
     285           0 :                 ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_NONE);
     286           0 :         } else
     287           0 :                 ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO);
     288             : 
     289             :         /* attach the interface */
     290           0 :         if_attach(ifp);
     291           0 :         ether_ifattach(ifp);
     292             : 
     293           0 :         timeout_set(&sc->sc_stat_ch, url_tick, sc);
     294             : 
     295           0 :         splx(s);
     296             : 
     297           0 :         return;
     298             : 
     299             :  bad:
     300           0 :         usbd_deactivate(sc->sc_udev);
     301           0 : }
     302             : 
     303             : /* detach */
     304             : int
     305           0 : url_detach(struct device *self, int flags)
     306             : {
     307           0 :         struct url_softc *sc = (struct url_softc *)self;
     308           0 :         struct ifnet *ifp = GET_IFP(sc);
     309             :         int s;
     310             : 
     311             :         DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
     312             : 
     313           0 :         if (timeout_initialized(&sc->sc_stat_ch))
     314           0 :                 timeout_del(&sc->sc_stat_ch);
     315             : 
     316             :         /* Remove any pending tasks */
     317           0 :         usb_rem_task(sc->sc_udev, &sc->sc_tick_task);
     318           0 :         usb_rem_task(sc->sc_udev, &sc->sc_stop_task);
     319             : 
     320           0 :         s = splusb();
     321             : 
     322           0 :         if (--sc->sc_refcnt >= 0) {
     323             :                 /* Wait for processes to go away */
     324           0 :                 usb_detach_wait(&sc->sc_dev);
     325           0 :         }
     326             : 
     327           0 :         if (ifp->if_flags & IFF_RUNNING)
     328           0 :                 url_stop(GET_IFP(sc), 1);
     329             : 
     330           0 :         mii_detach(&sc->sc_mii, MII_PHY_ANY, MII_OFFSET_ANY);
     331           0 :         ifmedia_delete_instance(&sc->sc_mii.mii_media, IFM_INST_ANY);
     332           0 :         if (ifp->if_softc != NULL) {
     333           0 :                 ether_ifdetach(ifp);
     334           0 :                 if_detach(ifp);
     335           0 :         }
     336             : 
     337             : #ifdef DIAGNOSTIC
     338           0 :         if (sc->sc_pipe_tx != NULL)
     339           0 :                 printf("%s: detach has active tx endpoint.\n",
     340           0 :                        sc->sc_dev.dv_xname);
     341           0 :         if (sc->sc_pipe_rx != NULL)
     342           0 :                 printf("%s: detach has active rx endpoint.\n",
     343           0 :                        sc->sc_dev.dv_xname);
     344           0 :         if (sc->sc_pipe_intr != NULL)
     345           0 :                 printf("%s: detach has active intr endpoint.\n",
     346           0 :                        sc->sc_dev.dv_xname);
     347             : #endif
     348             : 
     349           0 :         splx(s);
     350             : 
     351           0 :         return (0);
     352             : }
     353             : 
     354             : /* read/write memory */
     355             : int
     356           0 : url_mem(struct url_softc *sc, int cmd, int offset, void *buf, int len)
     357             : {
     358           0 :         usb_device_request_t req;
     359             :         usbd_status err;
     360             : 
     361           0 :         if (sc == NULL)
     362           0 :                 return (0);
     363             : 
     364             :         DPRINTFN(0x200,
     365             :                 ("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
     366             : 
     367           0 :         if (usbd_is_dying(sc->sc_udev))
     368           0 :                 return (0);
     369             : 
     370           0 :         if (cmd == URL_CMD_READMEM)
     371           0 :                 req.bmRequestType = UT_READ_VENDOR_DEVICE;
     372             :         else
     373           0 :                 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
     374           0 :         req.bRequest = URL_REQ_MEM;
     375           0 :         USETW(req.wValue, offset);
     376           0 :         USETW(req.wIndex, 0x0000);
     377           0 :         USETW(req.wLength, len);
     378             : 
     379           0 :         sc->sc_refcnt++;
     380           0 :         err = usbd_do_request(sc->sc_udev, &req, buf);
     381           0 :         if (--sc->sc_refcnt < 0)
     382           0 :                 usb_detach_wakeup(&sc->sc_dev);
     383             :         if (err) {
     384             :                 DPRINTF(("%s: url_mem(): %s failed. off=%04x, err=%d\n",
     385             :                          sc->sc_dev.dv_xname,
     386             :                          cmd == URL_CMD_READMEM ? "read" : "write",
     387             :                          offset, err));
     388             :         }
     389             : 
     390           0 :         return (err);
     391           0 : }
     392             : 
     393             : /* read 1byte from register */
     394             : int
     395           0 : url_csr_read_1(struct url_softc *sc, int reg)
     396             : {
     397           0 :         u_int8_t val = 0;
     398             : 
     399             :         DPRINTFN(0x100,
     400             :                  ("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
     401             : 
     402           0 :         return (url_mem(sc, URL_CMD_READMEM, reg, &val, 1) ? 0 : val);
     403           0 : }
     404             : 
     405             : /* read 2bytes from register */
     406             : int
     407           0 : url_csr_read_2(struct url_softc *sc, int reg)
     408             : {
     409           0 :         uWord val;
     410             : 
     411             :         DPRINTFN(0x100,
     412             :                  ("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
     413             : 
     414           0 :         USETW(val, 0);
     415           0 :         return (url_mem(sc, URL_CMD_READMEM, reg, &val, 2) ? 0 : UGETW(val));
     416           0 : }
     417             : 
     418             : /* write 1byte to register */
     419             : int
     420           0 : url_csr_write_1(struct url_softc *sc, int reg, int aval)
     421             : {
     422           0 :         u_int8_t val = aval;
     423             : 
     424             :         DPRINTFN(0x100,
     425             :                  ("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
     426             : 
     427           0 :         return (url_mem(sc, URL_CMD_WRITEMEM, reg, &val, 1) ? -1 : 0);
     428           0 : }
     429             : 
     430             : /* write 2bytes to register */
     431             : int
     432           0 : url_csr_write_2(struct url_softc *sc, int reg, int aval)
     433             : {
     434           0 :         uWord val;
     435             : 
     436             :         DPRINTFN(0x100,
     437             :                  ("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
     438             : 
     439           0 :         USETW(val, aval);
     440             : 
     441           0 :         return (url_mem(sc, URL_CMD_WRITEMEM, reg, &val, 2) ? -1 : 0);
     442           0 : }
     443             : 
     444             : /* write 4bytes to register */
     445             : int
     446           0 : url_csr_write_4(struct url_softc *sc, int reg, int aval)
     447             : {
     448           0 :         uDWord val;
     449             : 
     450             :         DPRINTFN(0x100,
     451             :                  ("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
     452             : 
     453           0 :         USETDW(val, aval);
     454             : 
     455           0 :         return (url_mem(sc, URL_CMD_WRITEMEM, reg, &val, 4) ? -1 : 0);
     456           0 : }
     457             : 
     458             : int
     459           0 : url_init(struct ifnet *ifp)
     460             : {
     461           0 :         struct url_softc *sc = ifp->if_softc;
     462           0 :         struct mii_data *mii = GET_MII(sc);
     463             :         u_char *eaddr;
     464             :         int i, s;
     465             : 
     466             :         DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
     467             : 
     468           0 :         s = splnet();
     469             : 
     470             :         /* Cancel pending I/O and free all TX/RX buffers */
     471           0 :         url_stop(ifp, 1);
     472             : 
     473           0 :         eaddr = sc->sc_ac.ac_enaddr;
     474           0 :         for (i = 0; i < ETHER_ADDR_LEN; i++)
     475           0 :                 url_csr_write_1(sc, URL_IDR0 + i, eaddr[i]);
     476             : 
     477             :         /* Init transmission control register */
     478           0 :         URL_CLRBIT(sc, URL_TCR,
     479             :                    URL_TCR_TXRR1 | URL_TCR_TXRR0 |
     480             :                    URL_TCR_IFG1 | URL_TCR_IFG0 |
     481             :                    URL_TCR_NOCRC);
     482             : 
     483             :         /* Init receive control register */
     484           0 :         URL_SETBIT2(sc, URL_RCR, URL_RCR_TAIL);
     485             : 
     486             :         /* Initialize transmit ring */
     487           0 :         if (url_tx_list_init(sc) == ENOBUFS) {
     488           0 :                 printf("%s: tx list init failed\n", sc->sc_dev.dv_xname);
     489           0 :                 splx(s);
     490           0 :                 return (EIO);
     491             :         }
     492             : 
     493             :         /* Initialize receive ring */
     494           0 :         if (url_rx_list_init(sc) == ENOBUFS) {
     495           0 :                 printf("%s: rx list init failed\n", sc->sc_dev.dv_xname);
     496           0 :                 splx(s);
     497           0 :                 return (EIO);
     498             :         }
     499             : 
     500             :         /* Program promiscuous mode and multicast filters */
     501           0 :         url_iff(sc);
     502             : 
     503             :         /* Enable RX and TX */
     504           0 :         URL_SETBIT(sc, URL_CR, URL_CR_TE | URL_CR_RE);
     505             : 
     506           0 :         mii_mediachg(mii);
     507             : 
     508           0 :         if (sc->sc_pipe_tx == NULL || sc->sc_pipe_rx == NULL) {
     509           0 :                 if (url_openpipes(sc)) {
     510           0 :                         splx(s);
     511           0 :                         return (EIO);
     512             :                 }
     513             :         }
     514             : 
     515           0 :         ifp->if_flags |= IFF_RUNNING;
     516           0 :         ifq_clr_oactive(&ifp->if_snd);
     517             : 
     518           0 :         splx(s);
     519             : 
     520           0 :         timeout_add_sec(&sc->sc_stat_ch, 1);
     521             : 
     522           0 :         return (0);
     523           0 : }
     524             : 
     525             : void
     526           0 : url_reset(struct url_softc *sc)
     527             : {
     528             :         int i;
     529             : 
     530             :         DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
     531             : 
     532           0 :         if (usbd_is_dying(sc->sc_udev))
     533           0 :                 return;
     534             : 
     535           0 :         URL_SETBIT(sc, URL_CR, URL_CR_SOFT_RST);
     536             : 
     537           0 :         for (i = 0; i < URL_TX_TIMEOUT; i++) {
     538           0 :                 if (!(url_csr_read_1(sc, URL_CR) & URL_CR_SOFT_RST))
     539             :                         break;
     540           0 :                 delay(10);      /* XXX */
     541             :         }
     542             : 
     543           0 :         delay(10000);           /* XXX */
     544           0 : }
     545             : 
     546             : void
     547           0 : url_iff(struct url_softc *sc)
     548             : {
     549           0 :         struct ifnet *ifp = GET_IFP(sc);
     550             :         struct arpcom *ac = &sc->sc_ac;
     551             :         struct ether_multi *enm;
     552             :         struct ether_multistep step;
     553             :         u_int32_t hashes[2];
     554             :         u_int16_t rcr;
     555             :         int h = 0;
     556             : 
     557             :         DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
     558             : 
     559           0 :         if (usbd_is_dying(sc->sc_udev))
     560           0 :                 return;
     561             : 
     562           0 :         rcr = url_csr_read_2(sc, URL_RCR);
     563           0 :         rcr &= ~(URL_RCR_AAM | URL_RCR_AAP | URL_RCR_AB | URL_RCR_AD |
     564             :             URL_RCR_AM);
     565             :         bzero(hashes, sizeof(hashes));
     566           0 :         ifp->if_flags &= ~IFF_ALLMULTI;
     567             : 
     568             :         /*
     569             :          * Always accept broadcast frames.
     570             :          * Always accept frames destined to our station address.
     571             :          */
     572           0 :         rcr |= URL_RCR_AB | URL_RCR_AD;
     573             : 
     574           0 :         if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) {
     575           0 :                 ifp->if_flags |= IFF_ALLMULTI;
     576           0 :                 rcr |= URL_RCR_AAM;
     577           0 :                 if (ifp->if_flags & IFF_PROMISC)
     578           0 :                         rcr |= URL_RCR_AAP;
     579             :         } else {
     580           0 :                 rcr |= URL_RCR_AM;
     581             : 
     582             :                 /* now program new ones */
     583           0 :                 ETHER_FIRST_MULTI(step, ac, enm);
     584           0 :                 while (enm != NULL) {
     585           0 :                         h = ether_crc32_be(enm->enm_addrlo,
     586           0 :                             ETHER_ADDR_LEN) >> 26;
     587             : 
     588           0 :                         if (h < 32)
     589           0 :                                 hashes[0] |= (1 << h);
     590             :                         else
     591           0 :                                 hashes[1] |= (1 << (h - 32));
     592             : 
     593           0 :                         ETHER_NEXT_MULTI(step, enm);
     594             :                 }
     595             :         }
     596             : 
     597           0 :         url_csr_write_4(sc, URL_MAR0, hashes[0]);
     598           0 :         url_csr_write_4(sc, URL_MAR4, hashes[1]);
     599           0 :         url_csr_write_2(sc, URL_RCR, rcr);
     600           0 : }
     601             : 
     602             : int
     603           0 : url_openpipes(struct url_softc *sc)
     604             : {
     605             :         struct url_chain *c;
     606             :         usbd_status err;
     607             :         int i;
     608             :         int error = 0;
     609             : 
     610           0 :         if (usbd_is_dying(sc->sc_udev))
     611           0 :                 return (EIO);
     612             : 
     613           0 :         sc->sc_refcnt++;
     614             : 
     615             :         /* Open RX pipe */
     616           0 :         err = usbd_open_pipe(sc->sc_ctl_iface, sc->sc_bulkin_no,
     617           0 :                              USBD_EXCLUSIVE_USE, &sc->sc_pipe_rx);
     618           0 :         if (err) {
     619           0 :                 printf("%s: open rx pipe failed: %s\n",
     620           0 :                        sc->sc_dev.dv_xname, usbd_errstr(err));
     621             :                 error = EIO;
     622           0 :                 goto done;
     623             :         }
     624             : 
     625             :         /* Open TX pipe */
     626           0 :         err = usbd_open_pipe(sc->sc_ctl_iface, sc->sc_bulkout_no,
     627           0 :                              USBD_EXCLUSIVE_USE, &sc->sc_pipe_tx);
     628           0 :         if (err) {
     629           0 :                 printf("%s: open tx pipe failed: %s\n",
     630           0 :                        sc->sc_dev.dv_xname, usbd_errstr(err));
     631             :                 error = EIO;
     632           0 :                 goto done;
     633             :         }
     634             : 
     635             : #if 0
     636             :         /* XXX: interrupt endpoint is not yet supported */
     637             :         /* Open Interrupt pipe */
     638             :         err = usbd_open_pipe_intr(sc->sc_ctl_iface, sc->sc_intrin_no,
     639             :                                   USBD_EXCLUSIVE_USE, &sc->sc_pipe_intr, sc,
     640             :                                   &sc->sc_cdata.url_ibuf, URL_INTR_PKGLEN,
     641             :                                   url_intr, URL_INTR_INTERVAL);
     642             :         if (err) {
     643             :                 printf("%s: open intr pipe failed: %s\n",
     644             :                        sc->sc_dev.dv_xname, usbd_errstr(err));
     645             :                 error = EIO;
     646             :                 goto done;
     647             :         }
     648             : #endif
     649             : 
     650             : 
     651             :         /* Start up the receive pipe. */
     652           0 :         for (i = 0; i < URL_RX_LIST_CNT; i++) {
     653           0 :                 c = &sc->sc_cdata.url_rx_chain[i];
     654           0 :                 usbd_setup_xfer(c->url_xfer, sc->sc_pipe_rx,
     655           0 :                                 c, c->url_buf, URL_BUFSZ,
     656             :                                 USBD_SHORT_XFER_OK | USBD_NO_COPY,
     657             :                                 USBD_NO_TIMEOUT, url_rxeof);
     658           0 :                 (void)usbd_transfer(c->url_xfer);
     659             :                 DPRINTF(("%s: %s: start read\n", sc->sc_dev.dv_xname,
     660             :                          __func__));
     661             :         }
     662             : 
     663             :  done:
     664           0 :         if (--sc->sc_refcnt < 0)
     665           0 :                 usb_detach_wakeup(&sc->sc_dev);
     666             : 
     667           0 :         return (error);
     668           0 : }
     669             : 
     670             : int
     671           0 : url_newbuf(struct url_softc *sc, struct url_chain *c, struct mbuf *m)
     672             : {
     673             :         struct mbuf *m_new = NULL;
     674             : 
     675             :         DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
     676             : 
     677           0 :         if (m == NULL) {
     678           0 :                 MGETHDR(m_new, M_DONTWAIT, MT_DATA);
     679           0 :                 if (m_new == NULL) {
     680           0 :                         printf("%s: no memory for rx list "
     681           0 :                                "-- packet dropped!\n", sc->sc_dev.dv_xname);
     682           0 :                         return (ENOBUFS);
     683             :                 }
     684           0 :                 MCLGET(m_new, M_DONTWAIT);
     685           0 :                 if (!(m_new->m_flags & M_EXT)) {
     686           0 :                         printf("%s: no memory for rx list "
     687           0 :                                "-- packet dropped!\n", sc->sc_dev.dv_xname);
     688           0 :                         m_freem(m_new);
     689           0 :                         return (ENOBUFS);
     690             :                 }
     691           0 :                 m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
     692           0 :         } else {
     693             :                 m_new = m;
     694           0 :                 m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
     695           0 :                 m_new->m_data = m_new->m_ext.ext_buf;
     696             :         }
     697             : 
     698           0 :         m_adj(m_new, ETHER_ALIGN);
     699           0 :         c->url_mbuf = m_new;
     700             : 
     701           0 :         return (0);
     702           0 : }
     703             : 
     704             : 
     705             : int
     706           0 : url_rx_list_init(struct url_softc *sc)
     707             : {
     708             :         struct url_cdata *cd;
     709             :         struct url_chain *c;
     710             :         int i;
     711             : 
     712             :         DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
     713             : 
     714           0 :         cd = &sc->sc_cdata;
     715           0 :         for (i = 0; i < URL_RX_LIST_CNT; i++) {
     716           0 :                 c = &cd->url_rx_chain[i];
     717           0 :                 c->url_sc = sc;
     718           0 :                 c->url_idx = i;
     719           0 :                 if (url_newbuf(sc, c, NULL) == ENOBUFS)
     720           0 :                         return (ENOBUFS);
     721           0 :                 if (c->url_xfer == NULL) {
     722           0 :                         c->url_xfer = usbd_alloc_xfer(sc->sc_udev);
     723           0 :                         if (c->url_xfer == NULL)
     724           0 :                                 return (ENOBUFS);
     725           0 :                         c->url_buf = usbd_alloc_buffer(c->url_xfer, URL_BUFSZ);
     726           0 :                         if (c->url_buf == NULL) {
     727           0 :                                 usbd_free_xfer(c->url_xfer);
     728           0 :                                 return (ENOBUFS);
     729             :                         }
     730             :                 }
     731             :         }
     732             : 
     733           0 :         return (0);
     734           0 : }
     735             : 
     736             : int
     737           0 : url_tx_list_init(struct url_softc *sc)
     738             : {
     739             :         struct url_cdata *cd;
     740             :         struct url_chain *c;
     741             :         int i;
     742             : 
     743             :         DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
     744             : 
     745           0 :         cd = &sc->sc_cdata;
     746           0 :         for (i = 0; i < URL_TX_LIST_CNT; i++) {
     747           0 :                 c = &cd->url_tx_chain[i];
     748           0 :                 c->url_sc = sc;
     749           0 :                 c->url_idx = i;
     750           0 :                 c->url_mbuf = NULL;
     751           0 :                 if (c->url_xfer == NULL) {
     752           0 :                         c->url_xfer = usbd_alloc_xfer(sc->sc_udev);
     753           0 :                         if (c->url_xfer == NULL)
     754           0 :                                 return (ENOBUFS);
     755           0 :                         c->url_buf = usbd_alloc_buffer(c->url_xfer, URL_BUFSZ);
     756           0 :                         if (c->url_buf == NULL) {
     757           0 :                                 usbd_free_xfer(c->url_xfer);
     758           0 :                                 return (ENOBUFS);
     759             :                         }
     760             :                 }
     761             :         }
     762             : 
     763           0 :         return (0);
     764           0 : }
     765             : 
     766             : void
     767           0 : url_start(struct ifnet *ifp)
     768             : {
     769           0 :         struct url_softc *sc = ifp->if_softc;
     770             :         struct mbuf *m_head = NULL;
     771             : 
     772             :         DPRINTF(("%s: %s: enter, link=%d\n", sc->sc_dev.dv_xname,
     773             :                  __func__, sc->sc_link));
     774             : 
     775           0 :         if (usbd_is_dying(sc->sc_udev))
     776           0 :                 return;
     777             : 
     778           0 :         if (!sc->sc_link)
     779           0 :                 return;
     780             : 
     781           0 :         if (ifq_is_oactive(&ifp->if_snd))
     782           0 :                 return;
     783             : 
     784           0 :         m_head = ifq_deq_begin(&ifp->if_snd);
     785           0 :         if (m_head == NULL)
     786           0 :                 return;
     787             : 
     788           0 :         if (url_send(sc, m_head, 0)) {
     789           0 :                 ifq_deq_rollback(&ifp->if_snd, m_head);
     790           0 :                 ifq_set_oactive(&ifp->if_snd);
     791           0 :                 return;
     792             :         }
     793             : 
     794           0 :         ifq_deq_commit(&ifp->if_snd, m_head);
     795             : 
     796             : #if NBPFILTER > 0
     797           0 :         if (ifp->if_bpf)
     798           0 :                 bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
     799             : #endif
     800             : 
     801           0 :         ifq_set_oactive(&ifp->if_snd);
     802             : 
     803             :         /* Set a timeout in case the chip goes out to lunch. */
     804           0 :         ifp->if_timer = 5;
     805           0 : }
     806             : 
     807             : int
     808           0 : url_send(struct url_softc *sc, struct mbuf *m, int idx)
     809             : {
     810             :         int total_len;
     811             :         struct url_chain *c;
     812             :         usbd_status err;
     813             : 
     814             :         DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname,__func__));
     815             : 
     816           0 :         c = &sc->sc_cdata.url_tx_chain[idx];
     817             : 
     818             :         /* Copy the mbuf data into a contiguous buffer */
     819           0 :         m_copydata(m, 0, m->m_pkthdr.len, c->url_buf);
     820           0 :         c->url_mbuf = m;
     821           0 :         total_len = m->m_pkthdr.len;
     822             : 
     823           0 :         if (total_len < URL_MIN_FRAME_LEN) {
     824           0 :                 bzero(c->url_buf + total_len, URL_MIN_FRAME_LEN - total_len);
     825             :                 total_len = URL_MIN_FRAME_LEN;
     826           0 :         }
     827           0 :         usbd_setup_xfer(c->url_xfer, sc->sc_pipe_tx, c, c->url_buf, total_len,
     828             :                         USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
     829             :                         URL_TX_TIMEOUT, url_txeof);
     830             : 
     831             :         /* Transmit */
     832           0 :         sc->sc_refcnt++;
     833           0 :         err = usbd_transfer(c->url_xfer);
     834           0 :         if (--sc->sc_refcnt < 0)
     835           0 :                 usb_detach_wakeup(&sc->sc_dev);
     836           0 :         if (err != USBD_IN_PROGRESS) {
     837           0 :                 printf("%s: url_send error=%s\n", sc->sc_dev.dv_xname,
     838           0 :                        usbd_errstr(err));
     839             :                 /* Stop the interface */
     840           0 :                 usb_add_task(sc->sc_udev, &sc->sc_stop_task);
     841           0 :                 return (EIO);
     842             :         }
     843             : 
     844             :         DPRINTF(("%s: %s: send %d bytes\n", sc->sc_dev.dv_xname,
     845             :                  __func__, total_len));
     846             : 
     847           0 :         sc->sc_cdata.url_tx_cnt++;
     848             : 
     849           0 :         return (0);
     850           0 : }
     851             : 
     852             : void
     853           0 : url_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
     854             : {
     855           0 :         struct url_chain *c = priv;
     856           0 :         struct url_softc *sc = c->url_sc;
     857           0 :         struct ifnet *ifp = GET_IFP(sc);
     858             :         int s;
     859             : 
     860           0 :         if (usbd_is_dying(sc->sc_udev))
     861           0 :                 return;
     862             : 
     863           0 :         s = splnet();
     864             : 
     865             :         DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
     866             : 
     867           0 :         ifp->if_timer = 0;
     868           0 :         ifq_clr_oactive(&ifp->if_snd);
     869             : 
     870           0 :         if (status != USBD_NORMAL_COMPLETION) {
     871           0 :                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
     872           0 :                         splx(s);
     873           0 :                         return;
     874             :                 }
     875           0 :                 ifp->if_oerrors++;
     876           0 :                 printf("%s: usb error on tx: %s\n", sc->sc_dev.dv_xname,
     877           0 :                        usbd_errstr(status));
     878           0 :                 if (status == USBD_STALLED) {
     879           0 :                         sc->sc_refcnt++;
     880           0 :                         usbd_clear_endpoint_stall_async(sc->sc_pipe_tx);
     881           0 :                         if (--sc->sc_refcnt < 0)
     882           0 :                                 usb_detach_wakeup(&sc->sc_dev);
     883             :                 }
     884           0 :                 splx(s);
     885           0 :                 return;
     886             :         }
     887             : 
     888           0 :         m_freem(c->url_mbuf);
     889           0 :         c->url_mbuf = NULL;
     890             : 
     891           0 :         if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
     892           0 :                 url_start(ifp);
     893             : 
     894           0 :         splx(s);
     895           0 : }
     896             : 
     897             : void
     898           0 : url_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
     899             : {
     900           0 :         struct url_chain *c = priv;
     901           0 :         struct url_softc *sc = c->url_sc;
     902           0 :         struct ifnet *ifp = GET_IFP(sc);
     903           0 :         struct mbuf_list ml = MBUF_LIST_INITIALIZER();
     904             :         struct mbuf *m;
     905           0 :         u_int32_t total_len;
     906             :         url_rxhdr_t rxhdr;
     907             :         int s;
     908             : 
     909             :         DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname,__func__));
     910             : 
     911           0 :         if (usbd_is_dying(sc->sc_udev))
     912           0 :                 return;
     913             : 
     914           0 :         if (status != USBD_NORMAL_COMPLETION) {
     915           0 :                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
     916           0 :                         return;
     917           0 :                 sc->sc_rx_errs++;
     918           0 :                 if (usbd_ratecheck(&sc->sc_rx_notice)) {
     919           0 :                         printf("%s: %u usb errors on rx: %s\n",
     920           0 :                                sc->sc_dev.dv_xname, sc->sc_rx_errs,
     921           0 :                                usbd_errstr(status));
     922           0 :                         sc->sc_rx_errs = 0;
     923           0 :                 }
     924           0 :                 if (status == USBD_STALLED) {
     925           0 :                         sc->sc_refcnt++;
     926           0 :                         usbd_clear_endpoint_stall_async(sc->sc_pipe_rx);
     927           0 :                         if (--sc->sc_refcnt < 0)
     928           0 :                                 usb_detach_wakeup(&sc->sc_dev);
     929             :                 }
     930             :                 goto done;
     931             :         }
     932             : 
     933           0 :         usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
     934             : 
     935           0 :         memcpy(mtod(c->url_mbuf, char *), c->url_buf, total_len);
     936             : 
     937           0 :         if (total_len <= ETHER_CRC_LEN) {
     938           0 :                 ifp->if_ierrors++;
     939           0 :                 goto done;
     940             :         }
     941             : 
     942           0 :         memcpy(&rxhdr, c->url_buf + total_len - ETHER_CRC_LEN, sizeof(rxhdr));
     943             : 
     944             :         DPRINTF(("%s: RX Status: %dbytes%s%s%s%s packets\n",
     945             :                  sc->sc_dev.dv_xname,
     946             :                  UGETW(rxhdr) & URL_RXHDR_BYTEC_MASK,
     947             :                  UGETW(rxhdr) & URL_RXHDR_VALID_MASK ? ", Valid" : "",
     948             :                  UGETW(rxhdr) & URL_RXHDR_RUNTPKT_MASK ? ", Runt" : "",
     949             :                  UGETW(rxhdr) & URL_RXHDR_PHYPKT_MASK ? ", Physical match" : "",
     950             :                  UGETW(rxhdr) & URL_RXHDR_MCASTPKT_MASK ? ", Multicast" : ""));
     951             : 
     952           0 :         if ((UGETW(rxhdr) & URL_RXHDR_VALID_MASK) == 0) {
     953           0 :                 ifp->if_ierrors++;
     954           0 :                 goto done;
     955             :         }
     956             : 
     957           0 :         total_len -= ETHER_CRC_LEN;
     958             : 
     959           0 :         m = c->url_mbuf;
     960           0 :         m->m_pkthdr.len = m->m_len = total_len;
     961           0 :         ml_enqueue(&ml, m);
     962             : 
     963           0 :         if (url_newbuf(sc, c, NULL) == ENOBUFS) {
     964           0 :                 ifp->if_ierrors++;
     965           0 :                 goto done;
     966             :         }
     967             : 
     968             :         DPRINTF(("%s: %s: deliver %d\n", sc->sc_dev.dv_xname,
     969             :                  __func__, m->m_len));
     970             : 
     971           0 :         s = splnet();
     972           0 :         if_input(ifp, &ml);
     973           0 :         splx(s);
     974             : 
     975             :  done:
     976             :         /* Setup new transfer */
     977           0 :         usbd_setup_xfer(xfer, sc->sc_pipe_rx, c, c->url_buf, URL_BUFSZ,
     978             :                         USBD_SHORT_XFER_OK | USBD_NO_COPY,
     979             :                         USBD_NO_TIMEOUT, url_rxeof);
     980           0 :         sc->sc_refcnt++;
     981           0 :         usbd_transfer(xfer);
     982           0 :         if (--sc->sc_refcnt < 0)
     983           0 :                 usb_detach_wakeup(&sc->sc_dev);
     984             : 
     985             :         DPRINTF(("%s: %s: start rx\n", sc->sc_dev.dv_xname, __func__));
     986           0 : }
     987             : 
     988             : int
     989           0 : url_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
     990             : {
     991           0 :         struct url_softc *sc = ifp->if_softc;
     992           0 :         struct ifreq *ifr = (struct ifreq *)data;
     993             :         int s, error = 0;
     994             : 
     995             :         DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
     996             : 
     997           0 :         if (usbd_is_dying(sc->sc_udev))
     998           0 :                 return (EIO);
     999             : 
    1000           0 :         s = splnet();
    1001             : 
    1002           0 :         switch (cmd) {
    1003             :         case SIOCSIFADDR:
    1004           0 :                 ifp->if_flags |= IFF_UP;
    1005           0 :                 if (!(ifp->if_flags & IFF_RUNNING))
    1006           0 :                         url_init(ifp);
    1007             :                 break;
    1008             : 
    1009             :         case SIOCSIFFLAGS:
    1010           0 :                 if (ifp->if_flags & IFF_UP) {
    1011           0 :                         if (ifp->if_flags & IFF_RUNNING)
    1012           0 :                                 error = ENETRESET;
    1013             :                         else
    1014           0 :                                 url_init(ifp);
    1015             :                 } else {
    1016           0 :                         if (ifp->if_flags & IFF_RUNNING)
    1017           0 :                                 url_stop(ifp, 1);
    1018             :                 }
    1019             :                 break;
    1020             : 
    1021             :         case SIOCGIFMEDIA:
    1022             :         case SIOCSIFMEDIA:
    1023           0 :                 error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd);
    1024           0 :                 break;
    1025             : 
    1026             :         default:
    1027           0 :                 error = ether_ioctl(ifp, &sc->sc_ac, cmd, data);
    1028           0 :         }
    1029             : 
    1030           0 :         if (error == ENETRESET) {
    1031           0 :                 if (ifp->if_flags & IFF_RUNNING)
    1032           0 :                         url_iff(sc);
    1033             :                 error = 0;
    1034           0 :         }
    1035             : 
    1036           0 :         splx(s);
    1037           0 :         return (error);
    1038           0 : }
    1039             : 
    1040             : void
    1041           0 : url_watchdog(struct ifnet *ifp)
    1042             : {
    1043           0 :         struct url_softc *sc = ifp->if_softc;
    1044             :         struct url_chain *c;
    1045           0 :         usbd_status stat;
    1046             :         int s;
    1047             : 
    1048             :         DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
    1049             : 
    1050           0 :         ifp->if_oerrors++;
    1051           0 :         printf("%s: watchdog timeout\n", sc->sc_dev.dv_xname);
    1052             : 
    1053           0 :         s = splusb();
    1054           0 :         c = &sc->sc_cdata.url_tx_chain[0];
    1055           0 :         usbd_get_xfer_status(c->url_xfer, NULL, NULL, NULL, &stat);
    1056           0 :         url_txeof(c->url_xfer, c, stat);
    1057             : 
    1058           0 :         if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
    1059           0 :                 url_start(ifp);
    1060           0 :         splx(s);
    1061           0 : }
    1062             : 
    1063             : void
    1064           0 : url_stop_task(struct url_softc *sc)
    1065             : {
    1066           0 :         url_stop(GET_IFP(sc), 1);
    1067           0 : }
    1068             : 
    1069             : /* Stop the adapter and free any mbufs allocated to the RX and TX lists. */
    1070             : void
    1071           0 : url_stop(struct ifnet *ifp, int disable)
    1072             : {
    1073           0 :         struct url_softc *sc = ifp->if_softc;
    1074             :         usbd_status err;
    1075             :         int i;
    1076             : 
    1077             :         DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
    1078             : 
    1079           0 :         ifp->if_timer = 0;
    1080           0 :         ifp->if_flags &= ~IFF_RUNNING;
    1081           0 :         ifq_clr_oactive(&ifp->if_snd);
    1082             : 
    1083           0 :         url_reset(sc);
    1084             : 
    1085           0 :         timeout_del(&sc->sc_stat_ch);
    1086             : 
    1087             :         /* Stop transfers */
    1088             :         /* RX endpoint */
    1089           0 :         if (sc->sc_pipe_rx != NULL) {
    1090           0 :                 usbd_abort_pipe(sc->sc_pipe_rx);
    1091           0 :                 err = usbd_close_pipe(sc->sc_pipe_rx);
    1092           0 :                 if (err)
    1093           0 :                         printf("%s: close rx pipe failed: %s\n",
    1094           0 :                                sc->sc_dev.dv_xname, usbd_errstr(err));
    1095           0 :                 sc->sc_pipe_rx = NULL;
    1096           0 :         }
    1097             : 
    1098             :         /* TX endpoint */
    1099           0 :         if (sc->sc_pipe_tx != NULL) {
    1100           0 :                 usbd_abort_pipe(sc->sc_pipe_tx);
    1101           0 :                 err = usbd_close_pipe(sc->sc_pipe_tx);
    1102           0 :                 if (err)
    1103           0 :                         printf("%s: close tx pipe failed: %s\n",
    1104           0 :                                sc->sc_dev.dv_xname, usbd_errstr(err));
    1105           0 :                 sc->sc_pipe_tx = NULL;
    1106           0 :         }
    1107             : 
    1108             : #if 0
    1109             :         /* XXX: Interrupt endpoint is not yet supported!! */
    1110             :         /* Interrupt endpoint */
    1111             :         if (sc->sc_pipe_intr != NULL) {
    1112             :                 usbd_abort_pipe(sc->sc_pipe_intr);
    1113             :                 err = usbd_close_pipe(sc->sc_pipe_intr);
    1114             :                 if (err)
    1115             :                         printf("%s: close intr pipe failed: %s\n",
    1116             :                                sc->sc_dev.dv_xname, usbd_errstr(err));
    1117             :                 sc->sc_pipe_intr = NULL;
    1118             :         }
    1119             : #endif
    1120             : 
    1121             :         /* Free RX resources. */
    1122           0 :         for (i = 0; i < URL_RX_LIST_CNT; i++) {
    1123           0 :                 if (sc->sc_cdata.url_rx_chain[i].url_mbuf != NULL) {
    1124           0 :                         m_freem(sc->sc_cdata.url_rx_chain[i].url_mbuf);
    1125           0 :                         sc->sc_cdata.url_rx_chain[i].url_mbuf = NULL;
    1126           0 :                 }
    1127           0 :                 if (sc->sc_cdata.url_rx_chain[i].url_xfer != NULL) {
    1128           0 :                         usbd_free_xfer(sc->sc_cdata.url_rx_chain[i].url_xfer);
    1129           0 :                         sc->sc_cdata.url_rx_chain[i].url_xfer = NULL;
    1130           0 :                 }
    1131             :         }
    1132             : 
    1133             :         /* Free TX resources. */
    1134           0 :         for (i = 0; i < URL_TX_LIST_CNT; i++) {
    1135           0 :                 if (sc->sc_cdata.url_tx_chain[i].url_mbuf != NULL) {
    1136           0 :                         m_freem(sc->sc_cdata.url_tx_chain[i].url_mbuf);
    1137           0 :                         sc->sc_cdata.url_tx_chain[i].url_mbuf = NULL;
    1138           0 :                 }
    1139           0 :                 if (sc->sc_cdata.url_tx_chain[i].url_xfer != NULL) {
    1140           0 :                         usbd_free_xfer(sc->sc_cdata.url_tx_chain[i].url_xfer);
    1141           0 :                         sc->sc_cdata.url_tx_chain[i].url_xfer = NULL;
    1142           0 :                 }
    1143             :         }
    1144             : 
    1145           0 :         sc->sc_link = 0;
    1146           0 : }
    1147             : 
    1148             : /* Set media options */
    1149             : int
    1150           0 : url_ifmedia_change(struct ifnet *ifp)
    1151             : {
    1152           0 :         struct url_softc *sc = ifp->if_softc;
    1153           0 :         struct mii_data *mii = GET_MII(sc);
    1154             : 
    1155             :         DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
    1156             : 
    1157           0 :         if (usbd_is_dying(sc->sc_udev))
    1158           0 :                 return (0);
    1159             : 
    1160           0 :         sc->sc_link = 0;
    1161           0 :         if (mii->mii_instance) {
    1162             :                 struct mii_softc *miisc;
    1163           0 :                 LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
    1164           0 :                         mii_phy_reset(miisc);
    1165           0 :         }
    1166             : 
    1167           0 :         return (mii_mediachg(mii));
    1168           0 : }
    1169             : 
    1170             : /* Report current media status. */
    1171             : void
    1172           0 : url_ifmedia_status(struct ifnet *ifp, struct ifmediareq *ifmr)
    1173             : {
    1174           0 :         struct url_softc *sc = ifp->if_softc;
    1175           0 :         struct mii_data *mii = GET_MII(sc);
    1176             : 
    1177             :         DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
    1178             : 
    1179           0 :         if (usbd_is_dying(sc->sc_udev))
    1180           0 :                 return;
    1181             : 
    1182           0 :         if ((ifp->if_flags & IFF_RUNNING) == 0) {
    1183           0 :                 ifmr->ifm_active = IFM_ETHER | IFM_NONE;
    1184           0 :                 ifmr->ifm_status = 0;
    1185           0 :                 return;
    1186             :         }
    1187             : 
    1188           0 :         mii_pollstat(mii);
    1189           0 :         ifmr->ifm_active = mii->mii_media_active;
    1190           0 :         ifmr->ifm_status = mii->mii_media_status;
    1191           0 : }
    1192             : 
    1193             : void
    1194           0 : url_tick(void *xsc)
    1195             : {
    1196           0 :         struct url_softc *sc = xsc;
    1197             : 
    1198           0 :         if (sc == NULL)
    1199           0 :                 return;
    1200             : 
    1201             :         DPRINTFN(0xff, ("%s: %s: enter\n", sc->sc_dev.dv_xname,
    1202             :                         __func__));
    1203             : 
    1204           0 :         if (usbd_is_dying(sc->sc_udev))
    1205           0 :                 return;
    1206             : 
    1207             :         /* Perform periodic stuff in process context */
    1208           0 :         usb_add_task(sc->sc_udev, &sc->sc_tick_task);
    1209           0 : }
    1210             : 
    1211             : void
    1212           0 : url_tick_task(void *xsc)
    1213             : {
    1214           0 :         struct url_softc *sc = xsc;
    1215             :         struct ifnet *ifp;
    1216             :         struct mii_data *mii;
    1217             :         int s;
    1218             : 
    1219           0 :         if (sc == NULL)
    1220           0 :                 return;
    1221             : 
    1222             :         DPRINTFN(0xff, ("%s: %s: enter\n", sc->sc_dev.dv_xname,
    1223             :                         __func__));
    1224             : 
    1225           0 :         if (usbd_is_dying(sc->sc_udev))
    1226           0 :                 return;
    1227             : 
    1228           0 :         ifp = GET_IFP(sc);
    1229           0 :         mii = GET_MII(sc);
    1230             : 
    1231           0 :         if (mii == NULL)
    1232           0 :                 return;
    1233             : 
    1234           0 :         s = splnet();
    1235             : 
    1236           0 :         mii_tick(mii);
    1237           0 :         if (!sc->sc_link && mii->mii_media_status & IFM_ACTIVE &&
    1238           0 :             IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
    1239             :                 DPRINTF(("%s: %s: got link\n",
    1240             :                          sc->sc_dev.dv_xname, __func__));
    1241           0 :                 sc->sc_link++;
    1242           0 :                 if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
    1243           0 :                            url_start(ifp);
    1244             :         }
    1245             : 
    1246           0 :         timeout_add_sec(&sc->sc_stat_ch, 1);
    1247             : 
    1248           0 :         splx(s);
    1249           0 : }
    1250             : 
    1251             : /* Get exclusive access to the MII registers */
    1252             : void
    1253           0 : url_lock_mii(struct url_softc *sc)
    1254             : {
    1255             :         DPRINTFN(0xff, ("%s: %s: enter\n", sc->sc_dev.dv_xname,
    1256             :                         __func__));
    1257             : 
    1258           0 :         sc->sc_refcnt++;
    1259           0 :         rw_enter_write(&sc->sc_mii_lock);
    1260           0 : }
    1261             : 
    1262             : void
    1263           0 : url_unlock_mii(struct url_softc *sc)
    1264             : {
    1265             :         DPRINTFN(0xff, ("%s: %s: enter\n", sc->sc_dev.dv_xname,
    1266             :                        __func__));
    1267             : 
    1268           0 :         rw_exit_write(&sc->sc_mii_lock);
    1269           0 :         if (--sc->sc_refcnt < 0)
    1270           0 :                 usb_detach_wakeup(&sc->sc_dev);
    1271           0 : }
    1272             : 
    1273             : int
    1274           0 : url_int_miibus_readreg(struct device *dev, int phy, int reg)
    1275             : {
    1276             :         struct url_softc *sc;
    1277             :         u_int16_t val;
    1278             : 
    1279           0 :         if (dev == NULL)
    1280           0 :                 return (0);
    1281             : 
    1282           0 :         sc = (void *)dev;
    1283             : 
    1284             :         DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x\n",
    1285             :                  sc->sc_dev.dv_xname, __func__, phy, reg));
    1286             : 
    1287           0 :         if (usbd_is_dying(sc->sc_udev)) {
    1288             : #ifdef DIAGNOSTIC
    1289           0 :                 printf("%s: %s: dying\n", sc->sc_dev.dv_xname,
    1290             :                        __func__);
    1291             : #endif
    1292           0 :                 return (0);
    1293             :         }
    1294             : 
    1295             :         /* XXX: one PHY only for the RTL8150 internal PHY */
    1296           0 :         if (phy != 0) {
    1297             :                 DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n",
    1298             :                          sc->sc_dev.dv_xname, __func__, phy));
    1299           0 :                 return (0);
    1300             :         }
    1301             : 
    1302           0 :         url_lock_mii(sc);
    1303             : 
    1304           0 :         switch (reg) {
    1305             :         case MII_BMCR:          /* Control Register */
    1306             :                 reg = URL_BMCR;
    1307           0 :                 break;
    1308             :         case MII_BMSR:          /* Status Register */
    1309             :                 reg = URL_BMSR;
    1310           0 :                 break;
    1311             :         case MII_PHYIDR1:
    1312             :         case MII_PHYIDR2:
    1313             :                 val = 0;
    1314           0 :                 goto R_DONE;
    1315             :                 break;
    1316             :         case MII_ANAR:          /* Autonegotiation advertisement */
    1317             :                 reg = URL_ANAR;
    1318           0 :                 break;
    1319             :         case MII_ANLPAR:        /* Autonegotiation link partner abilities */
    1320             :                 reg = URL_ANLP;
    1321           0 :                 break;
    1322             :         case URLPHY_MSR:        /* Media Status Register */
    1323             :                 reg = URL_MSR;
    1324           0 :                 break;
    1325             :         default:
    1326           0 :                 printf("%s: %s: bad register %04x\n",
    1327           0 :                        sc->sc_dev.dv_xname, __func__, reg);
    1328             :                 val = 0;
    1329           0 :                 goto R_DONE;
    1330             :                 break;
    1331             :         }
    1332             : 
    1333           0 :         if (reg == URL_MSR)
    1334           0 :                 val = url_csr_read_1(sc, reg);
    1335             :         else
    1336           0 :                 val = url_csr_read_2(sc, reg);
    1337             : 
    1338             :  R_DONE:
    1339             :         DPRINTFN(0xff, ("%s: %s: phy=%d reg=0x%04x => 0x%04x\n",
    1340             :                  sc->sc_dev.dv_xname, __func__, phy, reg, val));
    1341             : 
    1342           0 :         url_unlock_mii(sc);
    1343           0 :         return (val);
    1344           0 : }
    1345             : 
    1346             : void
    1347           0 : url_int_miibus_writereg(struct device *dev, int phy, int reg, int data)
    1348             : {
    1349             :         struct url_softc *sc;
    1350             : 
    1351           0 :         if (dev == NULL)
    1352           0 :                 return;
    1353             : 
    1354           0 :         sc = (void *)dev;
    1355             : 
    1356             :         DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x data=0x%04x\n",
    1357             :                  sc->sc_dev.dv_xname, __func__, phy, reg, data));
    1358             : 
    1359           0 :         if (usbd_is_dying(sc->sc_udev)) {
    1360             : #ifdef DIAGNOSTIC
    1361           0 :                 printf("%s: %s: dying\n", sc->sc_dev.dv_xname,
    1362             :                        __func__);
    1363             : #endif
    1364           0 :                 return;
    1365             :         }
    1366             : 
    1367             :         /* XXX: one PHY only for the RTL8150 internal PHY */
    1368           0 :         if (phy != 0) {
    1369             :                 DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n",
    1370             :                          sc->sc_dev.dv_xname, __func__, phy));
    1371           0 :                 return;
    1372             :         }
    1373             : 
    1374           0 :         url_lock_mii(sc);
    1375             : 
    1376           0 :         switch (reg) {
    1377             :         case MII_BMCR:          /* Control Register */
    1378             :                 reg = URL_BMCR;
    1379           0 :                 break;
    1380             :         case MII_BMSR:          /* Status Register */
    1381             :                 reg = URL_BMSR;
    1382           0 :                 break;
    1383             :         case MII_PHYIDR1:
    1384             :         case MII_PHYIDR2:
    1385             :                 goto W_DONE;
    1386             :                 break;
    1387             :         case MII_ANAR:          /* Autonegotiation advertisement */
    1388             :                 reg = URL_ANAR;
    1389           0 :                 break;
    1390             :         case MII_ANLPAR:        /* Autonegotiation link partner abilities */
    1391             :                 reg = URL_ANLP;
    1392           0 :                 break;
    1393             :         case URLPHY_MSR:        /* Media Status Register */
    1394             :                 reg = URL_MSR;
    1395           0 :                 break;
    1396             :         default:
    1397           0 :                 printf("%s: %s: bad register %04x\n",
    1398           0 :                        sc->sc_dev.dv_xname, __func__, reg);
    1399           0 :                 goto W_DONE;
    1400             :                 break;
    1401             :         }
    1402             : 
    1403           0 :         if (reg == URL_MSR)
    1404           0 :                 url_csr_write_1(sc, reg, data);
    1405             :         else
    1406           0 :                 url_csr_write_2(sc, reg, data);
    1407             :  W_DONE:
    1408             : 
    1409           0 :         url_unlock_mii(sc);
    1410           0 :         return;
    1411           0 : }
    1412             : 
    1413             : void
    1414           0 : url_miibus_statchg(struct device *dev)
    1415             : {
    1416             : #ifdef URL_DEBUG
    1417             :         struct url_softc *sc;
    1418             : 
    1419             :         if (dev == NULL)
    1420             :                 return;
    1421             : 
    1422             :         sc = (void *)dev;
    1423             :         DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
    1424             : #endif
    1425             :         /* Nothing to do */
    1426           0 : }
    1427             : 
    1428             : #if 0
    1429             : /*
    1430             :  * external PHYs support, but not test.
    1431             :  */
    1432             : int
    1433             : url_ext_miibus_redreg(struct device *dev, int phy, int reg)
    1434             : {
    1435             :         struct url_softc *sc = (void *)dev;
    1436             :         u_int16_t val;
    1437             : 
    1438             :         DPRINTF(("%s: %s: enter, phy=%d reg=0x%04x\n",
    1439             :                  sc->sc_dev.dv_xname, __func__, phy, reg));
    1440             : 
    1441             :         if (usbd_is_dying(sc->sc_udev)) {
    1442             : #ifdef DIAGNOSTIC
    1443             :                 printf("%s: %s: dying\n", sc->sc_dev.dv_xname,
    1444             :                        __func__);
    1445             : #endif
    1446             :                 return (0);
    1447             :         }
    1448             : 
    1449             :         url_lock_mii(sc);
    1450             : 
    1451             :         url_csr_write_1(sc, URL_PHYADD, phy & URL_PHYADD_MASK);
    1452             :         /*
    1453             :          * RTL8150L will initiate a MII management data transaction
    1454             :          * if PHYCNT_OWN bit is set 1 by software. After transaction,
    1455             :          * this bit is auto cleared by TRL8150L.
    1456             :          */
    1457             :         url_csr_write_1(sc, URL_PHYCNT,
    1458             :                         (reg | URL_PHYCNT_PHYOWN) & ~URL_PHYCNT_RWCR);
    1459             :         for (i = 0; i < URL_TIMEOUT; i++) {
    1460             :                 if ((url_csr_read_1(sc, URL_PHYCNT) & URL_PHYCNT_PHYOWN) == 0)
    1461             :                         break;
    1462             :         }
    1463             :         if (i == URL_TIMEOUT) {
    1464             :                 printf("%s: MII read timed out\n", sc->sc_dev.dv_xname);
    1465             :         }
    1466             : 
    1467             :         val = url_csr_read_2(sc, URL_PHYDAT);
    1468             : 
    1469             :         DPRINTF(("%s: %s: phy=%d reg=0x%04x => 0x%04x\n",
    1470             :                  sc->sc_dev.dv_xname, __func__, phy, reg, val));
    1471             : 
    1472             :         url_unlock_mii(sc);
    1473             :         return (val);
    1474             : }
    1475             : 
    1476             : void
    1477             : url_ext_miibus_writereg(struct device *dev, int phy, int reg, int data)
    1478             : {
    1479             :         struct url_softc *sc = (void *)dev;
    1480             : 
    1481             :         DPRINTF(("%s: %s: enter, phy=%d reg=0x%04x data=0x%04x\n",
    1482             :                  sc->sc_dev.dv_xname, __func__, phy, reg, data));
    1483             : 
    1484             :         if (usbd_is_dying(sc->sc_udev)) {
    1485             : #ifdef DIAGNOSTIC
    1486             :                 printf("%s: %s: dying\n", sc->sc_dev.dv_xname,
    1487             :                        __func__);
    1488             : #endif
    1489             :                 return;
    1490             :         }
    1491             : 
    1492             :         url_lock_mii(sc);
    1493             : 
    1494             :         url_csr_write_2(sc, URL_PHYDAT, data);
    1495             :         url_csr_write_1(sc, URL_PHYADD, phy);
    1496             :         url_csr_write_1(sc, URL_PHYCNT, reg | URL_PHYCNT_RWCR); /* Write */
    1497             : 
    1498             :         for (i=0; i < URL_TIMEOUT; i++) {
    1499             :                 if (url_csr_read_1(sc, URL_PHYCNT) & URL_PHYCNT_PHYOWN)
    1500             :                         break;
    1501             :         }
    1502             : 
    1503             :         if (i == URL_TIMEOUT) {
    1504             :                 printf("%s: MII write timed out\n",
    1505             :                        sc->sc_dev.dv_xname);
    1506             :         }
    1507             : 
    1508             :         url_unlock_mii(sc);
    1509             :         return;
    1510             : }
    1511             : #endif
    1512             : 

Generated by: LCOV version 1.13