LCOV - code coverage report
Current view: top level - dev/usb - if_mos.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 670 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_mos.c,v 1.39 2018/07/03 00:47:49 kevlo Exp $       */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2008 Johann Christian Rode <jcrode@gmx.net>
       5             :  *
       6             :  * Permission to use, copy, modify, and distribute this software for any
       7             :  * purpose with or without fee is hereby granted, provided that the above
       8             :  * copyright notice and this permission notice appear in all copies.
       9             :  *
      10             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      11             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      12             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      13             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      14             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      15             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      16             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      17             :  */
      18             : 
      19             : /*
      20             :  * Copyright (c) 2005, 2006, 2007 Jonathan Gray <jsg@openbsd.org>
      21             :  *
      22             :  * Permission to use, copy, modify, and distribute this software for any
      23             :  * purpose with or without fee is hereby granted, provided that the above
      24             :  * copyright notice and this permission notice appear in all copies.
      25             :  *
      26             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      27             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      28             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      29             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      30             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      31             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      32             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      33             :  */
      34             : 
      35             : /*
      36             :  * Copyright (c) 1997, 1998, 1999, 2000-2003
      37             :  *      Bill Paul <wpaul@windriver.com>.  All rights reserved.
      38             :  *
      39             :  * Redistribution and use in source and binary forms, with or without
      40             :  * modification, are permitted provided that the following conditions
      41             :  * are met:
      42             :  * 1. Redistributions of source code must retain the above copyright
      43             :  *    notice, this list of conditions and the following disclaimer.
      44             :  * 2. Redistributions in binary form must reproduce the above copyright
      45             :  *    notice, this list of conditions and the following disclaimer in the
      46             :  *    documentation and/or other materials provided with the distribution.
      47             :  * 3. All advertising materials mentioning features or use of this software
      48             :  *    must display the following acknowledgement:
      49             :  *      This product includes software developed by Bill Paul.
      50             :  * 4. Neither the name of the author nor the names of any co-contributors
      51             :  *    may be used to endorse or promote products derived from this software
      52             :  *    without specific prior written permission.
      53             :  *
      54             :  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
      55             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      56             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      57             :  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
      58             :  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      59             :  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
      60             :  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
      61             :  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
      62             :  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
      63             :  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
      64             :  * THE POSSIBILITY OF SUCH DAMAGE.
      65             :  */
      66             : 
      67             : /*
      68             :  * Moschip MCS7730/MCS7830/MCS7832 USB to Ethernet controller 
      69             :  * The datasheet is available at the following URL: 
      70             :  * http://www.moschip.com/data/products/MCS7830/Data%20Sheet_7830.pdf
      71             :  */
      72             : 
      73             : #include "bpfilter.h"
      74             : 
      75             : #include <sys/param.h>
      76             : #include <sys/systm.h>
      77             : #include <sys/sockio.h>
      78             : #include <sys/rwlock.h>
      79             : #include <sys/mbuf.h>
      80             : #include <sys/kernel.h>
      81             : #include <sys/socket.h>
      82             : 
      83             : #include <sys/device.h>
      84             : 
      85             : #include <machine/bus.h>
      86             : 
      87             : #include <net/if.h>
      88             : #include <net/if_media.h>
      89             : 
      90             : #if NBPFILTER > 0
      91             : #include <net/bpf.h>
      92             : #endif
      93             : 
      94             : #include <netinet/in.h>
      95             : #include <netinet/if_ether.h>
      96             : 
      97             : #include <dev/mii/miivar.h>
      98             : 
      99             : #include <dev/usb/usb.h>
     100             : #include <dev/usb/usbdi.h>
     101             : #include <dev/usb/usbdi_util.h>
     102             : #include <dev/usb/usbdivar.h>
     103             : #include <dev/usb/usbdevs.h>
     104             : 
     105             : #include <dev/usb/if_mosreg.h>
     106             : 
     107             : #ifdef MOS_DEBUG
     108             : #define DPRINTF(x)      do { if (mosdebug) printf x; } while (0)
     109             : #define DPRINTFN(n,x)   do { if (mosdebug >= (n)) printf x; } while (0)
     110             : int     mosdebug = 0;
     111             : #else
     112             : #define DPRINTF(x)
     113             : #define DPRINTFN(n,x)
     114             : #endif
     115             : 
     116             : /*
     117             :  * Various supported device vendors/products.
     118             :  */
     119             : const struct mos_type mos_devs[] = {
     120             :         { { USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7730 }, MCS7730 },
     121             :         { { USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7830 }, MCS7830 },
     122             :         { { USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7832 }, MCS7832 },
     123             :         { { USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_LN030 }, MCS7830 },
     124             : };
     125             : #define mos_lookup(v, p) ((struct mos_type *)usb_lookup(mos_devs, v, p))
     126             : 
     127             : int mos_match(struct device *, void *, void *);
     128             : void mos_attach(struct device *, struct device *, void *);
     129             : int mos_detach(struct device *, int);
     130             : 
     131             : struct cfdriver mos_cd = {
     132             :         NULL, "mos", DV_IFNET
     133             : };
     134             : 
     135             : const struct cfattach mos_ca = {
     136             :         sizeof(struct mos_softc), mos_match, mos_attach, mos_detach
     137             : };
     138             : 
     139             : int mos_tx_list_init(struct mos_softc *);
     140             : int mos_rx_list_init(struct mos_softc *);
     141             : struct mbuf *mos_newbuf(void);
     142             : int mos_encap(struct mos_softc *, struct mbuf *, int);
     143             : void mos_rxeof(struct usbd_xfer *, void *, usbd_status);
     144             : void mos_txeof(struct usbd_xfer *, void *, usbd_status);
     145             : void mos_tick(void *);
     146             : void mos_tick_task(void *);
     147             : void mos_start(struct ifnet *);
     148             : int mos_ioctl(struct ifnet *, u_long, caddr_t);
     149             : void mos_init(void *);
     150             : void mos_chip_init(struct mos_softc *);
     151             : void mos_stop(struct mos_softc *);
     152             : void mos_watchdog(struct ifnet *);
     153             : int mos_miibus_readreg(struct device *, int, int);
     154             : void mos_miibus_writereg(struct device *, int, int, int);
     155             : void mos_miibus_statchg(struct device *);
     156             : int mos_ifmedia_upd(struct ifnet *);
     157             : void mos_ifmedia_sts(struct ifnet *, struct ifmediareq *);
     158             : void mos_reset(struct mos_softc *sc);
     159             : 
     160             : int mos_reg_read_1(struct mos_softc *, int);
     161             : int mos_reg_read_2(struct mos_softc *, int);
     162             : int mos_reg_write_1(struct mos_softc *, int, int);
     163             : int mos_reg_write_2(struct mos_softc *, int, int);
     164             : int mos_readmac(struct mos_softc *, u_char *);
     165             : int mos_writemac(struct mos_softc *, u_char *);
     166             : int mos_write_mcast(struct mos_softc *, u_char *);
     167             : 
     168             : void mos_iff(struct mos_softc *);
     169             : void mos_lock_mii(struct mos_softc *);
     170             : void mos_unlock_mii(struct mos_softc *);
     171             : 
     172             : /*
     173             :  * Get exclusive access to the MII registers
     174             :  */
     175             : void
     176           0 : mos_lock_mii(struct mos_softc *sc)
     177             : {
     178           0 :         sc->mos_refcnt++;
     179           0 :         rw_enter_write(&sc->mos_mii_lock);
     180           0 : }
     181             : 
     182             : void
     183           0 : mos_unlock_mii(struct mos_softc *sc)
     184             : {
     185           0 :         rw_exit_write(&sc->mos_mii_lock);
     186           0 :         if (--sc->mos_refcnt < 0)
     187           0 :                 usb_detach_wakeup(&sc->mos_dev);
     188           0 : }
     189             : 
     190             : int
     191           0 : mos_reg_read_1(struct mos_softc *sc, int reg)
     192             : {
     193           0 :         usb_device_request_t    req;
     194             :         usbd_status             err;
     195           0 :         uByte                   val = 0;
     196             : 
     197           0 :         if (usbd_is_dying(sc->mos_udev))
     198           0 :                 return(0);
     199             : 
     200           0 :         req.bmRequestType = UT_READ_VENDOR_DEVICE;
     201           0 :         req.bRequest = MOS_UR_READREG;
     202           0 :         USETW(req.wValue, 0);
     203           0 :         USETW(req.wIndex, reg);
     204           0 :         USETW(req.wLength, 1);
     205             : 
     206           0 :         err = usbd_do_request(sc->mos_udev, &req, &val);
     207             : 
     208           0 :         if (err) {
     209             :                 DPRINTF(("mos_reg_read_1 error, reg: %d\n", reg));
     210           0 :                 return (-1);
     211             :         }
     212             : 
     213           0 :         return (val);
     214           0 : }
     215             : 
     216             : int
     217           0 : mos_reg_read_2(struct mos_softc *sc, int reg)
     218             : {
     219           0 :         usb_device_request_t    req;
     220             :         usbd_status             err;
     221           0 :         uWord                   val;
     222             : 
     223           0 :         USETW(val,0);
     224             : 
     225           0 :         if (usbd_is_dying(sc->mos_udev))
     226           0 :                 return(0);
     227             : 
     228           0 :         req.bmRequestType = UT_READ_VENDOR_DEVICE;
     229           0 :         req.bRequest = MOS_UR_READREG;
     230           0 :         USETW(req.wValue, 0);
     231           0 :         USETW(req.wIndex, reg);
     232           0 :         USETW(req.wLength, 2);
     233             : 
     234           0 :         err = usbd_do_request(sc->mos_udev, &req, &val);
     235             : 
     236           0 :         if (err) {
     237             :                 DPRINTF(("mos_reg_read_2 error, reg: %d\n", reg));
     238           0 :                 return (-1);
     239             :         }
     240             : 
     241           0 :         return(UGETW(val));
     242           0 : }
     243             : 
     244             : int
     245           0 : mos_reg_write_1(struct mos_softc *sc, int reg, int aval)
     246             : {
     247           0 :         usb_device_request_t    req;
     248             :         usbd_status             err;
     249           0 :         uByte                   val;
     250             : 
     251           0 :         val = aval;
     252             : 
     253           0 :         if (usbd_is_dying(sc->mos_udev))
     254           0 :                 return(0);
     255             : 
     256           0 :         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
     257           0 :         req.bRequest = MOS_UR_WRITEREG;
     258           0 :         USETW(req.wValue, 0);
     259           0 :         USETW(req.wIndex, reg);
     260           0 :         USETW(req.wLength, 1);
     261             : 
     262           0 :         err = usbd_do_request(sc->mos_udev, &req, &val);
     263             : 
     264           0 :         if (err) {
     265             :                 DPRINTF(("mos_reg_write_1 error, reg: %d\n", reg));
     266           0 :                 return (-1);
     267             :         }
     268             : 
     269           0 :         return(0);
     270           0 : }
     271             : 
     272             : int
     273           0 : mos_reg_write_2(struct mos_softc *sc, int reg, int aval)
     274             : {
     275           0 :         usb_device_request_t    req;
     276             :         usbd_status             err;
     277           0 :         uWord                   val;
     278             : 
     279           0 :         USETW(val, aval);
     280             : 
     281           0 :         if (usbd_is_dying(sc->mos_udev))
     282           0 :                 return (0);
     283             : 
     284           0 :         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
     285           0 :         req.bRequest = MOS_UR_WRITEREG;
     286           0 :         USETW(req.wValue, 0);
     287           0 :         USETW(req.wIndex, reg);
     288           0 :         USETW(req.wLength, 2);
     289             : 
     290           0 :         err = usbd_do_request(sc->mos_udev, &req, &val);
     291             : 
     292           0 :         if (err) {
     293             :                 DPRINTF(("mos_reg_write_2 error, reg: %d\n", reg));
     294           0 :                 return (-1);
     295             :         }
     296             : 
     297           0 :         return (0);
     298           0 : }
     299             : 
     300             : int
     301           0 : mos_readmac(struct mos_softc *sc, u_char *mac)
     302             : {
     303           0 :         usb_device_request_t    req;
     304             :         usbd_status             err;
     305             : 
     306           0 :         if (usbd_is_dying(sc->mos_udev))
     307           0 :                 return(0);
     308             : 
     309           0 :         req.bmRequestType = UT_READ_VENDOR_DEVICE;
     310           0 :         req.bRequest = MOS_UR_READREG;
     311           0 :         USETW(req.wValue, 0);
     312           0 :         USETW(req.wIndex, MOS_MAC);
     313           0 :         USETW(req.wLength, ETHER_ADDR_LEN);
     314             : 
     315           0 :         err = usbd_do_request(sc->mos_udev, &req, mac);
     316             : 
     317           0 :         if (err) {
     318             :                 DPRINTF(("mos_readmac error"));
     319           0 :                 return (-1);
     320             :         }
     321             : 
     322           0 :         return (0);
     323           0 : }
     324             : 
     325             : int
     326           0 : mos_writemac(struct mos_softc *sc, u_char *mac)
     327             : {
     328           0 :         usb_device_request_t    req;
     329             :         usbd_status             err;
     330             : 
     331           0 :         if (usbd_is_dying(sc->mos_udev))
     332           0 :                 return(0);
     333             : 
     334           0 :         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
     335           0 :         req.bRequest = MOS_UR_WRITEREG;
     336           0 :         USETW(req.wValue, 0);
     337           0 :         USETW(req.wIndex, MOS_MAC);
     338           0 :         USETW(req.wLength, ETHER_ADDR_LEN);
     339             : 
     340           0 :         err = usbd_do_request(sc->mos_udev, &req, mac);
     341             : 
     342           0 :         if (err) {
     343             :                 DPRINTF(("mos_writemac error"));
     344           0 :                 return (-1);
     345             :         }
     346             : 
     347           0 :         return (0);
     348           0 : }
     349             : 
     350             : int
     351           0 : mos_write_mcast(struct mos_softc *sc, u_char *hashtbl)
     352             : {
     353           0 :         usb_device_request_t    req;
     354             :         usbd_status             err;
     355             : 
     356           0 :         if (usbd_is_dying(sc->mos_udev))
     357           0 :                 return(0);
     358             : 
     359           0 :         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
     360           0 :         req.bRequest = MOS_UR_WRITEREG;
     361           0 :         USETW(req.wValue, 0);
     362           0 :         USETW(req.wIndex, MOS_MCAST_TABLE);
     363           0 :         USETW(req.wLength, 8);
     364             : 
     365           0 :         err = usbd_do_request(sc->mos_udev, &req, hashtbl);
     366             : 
     367           0 :         if (err) {
     368             :                 DPRINTF(("mos_reg_mcast error\n"));
     369           0 :                 return(-1);
     370             :         }
     371             : 
     372           0 :         return(0);
     373           0 : }
     374             : 
     375             : int
     376           0 : mos_miibus_readreg(struct device *dev, int phy, int reg)
     377             : {
     378           0 :         struct mos_softc        *sc = (void *)dev;
     379             :         int                     i,res;
     380             : 
     381           0 :         if (usbd_is_dying(sc->mos_udev)) {
     382             :                 DPRINTF(("mos: dying\n"));
     383           0 :                 return (0);
     384             :         }
     385             : 
     386           0 :         mos_lock_mii(sc);
     387             : 
     388           0 :         mos_reg_write_2(sc, MOS_PHY_DATA, 0);
     389           0 :         mos_reg_write_1(sc, MOS_PHY_CTL, (phy & MOS_PHYCTL_PHYADDR) |
     390             :             MOS_PHYCTL_READ);
     391           0 :         mos_reg_write_1(sc, MOS_PHY_STS, (reg & MOS_PHYSTS_PHYREG) |
     392             :             MOS_PHYSTS_PENDING);
     393             : 
     394           0 :         for (i = 0; i < MOS_TIMEOUT; i++) {
     395           0 :                 if (mos_reg_read_1(sc, MOS_PHY_STS) & MOS_PHYSTS_READY)
     396             :                         break;
     397             :         }
     398           0 :         if (i == MOS_TIMEOUT) {
     399           0 :                 printf("%s: MII read timeout\n", sc->mos_dev.dv_xname);
     400           0 :         }
     401             : 
     402           0 :         res = mos_reg_read_2(sc, MOS_PHY_DATA);
     403             : 
     404           0 :         mos_unlock_mii(sc);
     405             : 
     406           0 :         return (res);
     407           0 : }
     408             : 
     409             : void
     410           0 : mos_miibus_writereg(struct device *dev, int phy, int reg, int val)
     411             : {
     412           0 :         struct mos_softc        *sc = (void *)dev;
     413             :         int                     i;
     414             : 
     415           0 :         if (usbd_is_dying(sc->mos_udev))
     416           0 :                 return;
     417             : 
     418           0 :         mos_lock_mii(sc);
     419             : 
     420           0 :         mos_reg_write_2(sc, MOS_PHY_DATA, val);
     421           0 :         mos_reg_write_1(sc, MOS_PHY_CTL, (phy & MOS_PHYCTL_PHYADDR) |
     422             :             MOS_PHYCTL_WRITE);
     423           0 :         mos_reg_write_1(sc, MOS_PHY_STS, (reg & MOS_PHYSTS_PHYREG) |
     424             :             MOS_PHYSTS_PENDING);
     425             : 
     426           0 :         for (i = 0; i < MOS_TIMEOUT; i++) {
     427           0 :                 if (mos_reg_read_1(sc, MOS_PHY_STS) & MOS_PHYSTS_READY)
     428             :                         break;
     429             :         }
     430           0 :         if (i == MOS_TIMEOUT) {
     431           0 :                 printf("%s: MII write timeout\n", sc->mos_dev.dv_xname);
     432           0 :         }
     433             : 
     434           0 :         mos_unlock_mii(sc);
     435             : 
     436           0 :         return;
     437           0 : }
     438             : 
     439             : void
     440           0 : mos_miibus_statchg(struct device *dev)
     441             : {
     442           0 :         struct mos_softc        *sc = (void *)dev;
     443           0 :         struct mii_data         *mii = GET_MII(sc);
     444             :         int                     val, err;
     445             : 
     446           0 :         mos_lock_mii(sc);
     447             : 
     448             :         /* disable RX, TX prior to changing FDX, SPEEDSEL */
     449           0 :         val = mos_reg_read_1(sc, MOS_CTL);
     450           0 :         val &= ~(MOS_CTL_TX_ENB | MOS_CTL_RX_ENB);
     451           0 :         mos_reg_write_1(sc, MOS_CTL, val);
     452             : 
     453             :         /* reset register which counts dropped frames */
     454           0 :         mos_reg_write_1(sc, MOS_FRAME_DROP_CNT, 0);
     455             : 
     456           0 :         if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX)
     457           0 :                 val |= MOS_CTL_FDX_ENB;
     458             :         else
     459           0 :                 val &= ~(MOS_CTL_FDX_ENB);
     460             : 
     461           0 :         switch (IFM_SUBTYPE(mii->mii_media_active)) {
     462             :                 case IFM_100_TX:
     463           0 :                         val |=  MOS_CTL_SPEEDSEL;
     464           0 :                         break;
     465             :                 case IFM_10_T:
     466           0 :                         val &= ~(MOS_CTL_SPEEDSEL);
     467           0 :                         break;
     468             :         }
     469             : 
     470             :         /* re-enable TX, RX */
     471           0 :         val |= (MOS_CTL_TX_ENB | MOS_CTL_RX_ENB);
     472           0 :         err = mos_reg_write_1(sc, MOS_CTL, val);
     473           0 :         mos_unlock_mii(sc);
     474             : 
     475           0 :         if (err) {
     476           0 :                 printf("%s: media change failed\n", sc->mos_dev.dv_xname);
     477           0 :                 return;
     478             :         }
     479           0 : }
     480             : 
     481             : /*
     482             :  * Set media options.
     483             :  */
     484             : int
     485           0 : mos_ifmedia_upd(struct ifnet *ifp)
     486             : {
     487           0 :         struct mos_softc        *sc = ifp->if_softc;
     488           0 :         struct mii_data         *mii = GET_MII(sc);
     489             : 
     490           0 :         sc->mos_link = 0;
     491           0 :         if (mii->mii_instance) {
     492             :                 struct mii_softc        *miisc;
     493           0 :                 LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
     494           0 :                         mii_phy_reset(miisc);
     495           0 :         }
     496           0 :         mii_mediachg(mii);
     497             : 
     498           0 :         return (0);
     499             : }
     500             : 
     501             : /*
     502             :  * Report current media status.
     503             :  */
     504             : void
     505           0 : mos_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
     506             : {
     507           0 :         struct mos_softc        *sc = ifp->if_softc;
     508           0 :         struct mii_data         *mii = GET_MII(sc);
     509             : 
     510           0 :         mii_pollstat(mii);
     511           0 :         ifmr->ifm_active = mii->mii_media_active;
     512           0 :         ifmr->ifm_status = mii->mii_media_status;
     513           0 : }
     514             : 
     515             : void
     516           0 : mos_iff(struct mos_softc *sc)
     517             : {
     518           0 :         struct ifnet            *ifp = GET_IFP(sc);
     519             :         struct arpcom           *ac = &sc->arpcom;
     520             :         struct ether_multi      *enm;
     521             :         struct ether_multistep  step;
     522             :         u_int32_t               h = 0;
     523           0 :         u_int8_t                rxmode, hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
     524             : 
     525           0 :         if (usbd_is_dying(sc->mos_udev))
     526           0 :                 return;
     527             : 
     528           0 :         rxmode = mos_reg_read_1(sc, MOS_CTL);
     529           0 :         rxmode &= ~(MOS_CTL_ALLMULTI | MOS_CTL_RX_PROMISC);
     530           0 :         ifp->if_flags &= ~IFF_ALLMULTI;
     531             : 
     532           0 :         if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) {
     533           0 :                 ifp->if_flags |= IFF_ALLMULTI;
     534           0 :                 rxmode |= MOS_CTL_ALLMULTI;
     535           0 :                 if (ifp->if_flags & IFF_PROMISC)
     536           0 :                         rxmode |= MOS_CTL_RX_PROMISC;
     537             :         } else {
     538             :                 /* now program new ones */
     539           0 :                 ETHER_FIRST_MULTI(step, ac, enm);
     540           0 :                 while (enm != NULL) {
     541           0 :                         h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN) >> 26;
     542             : 
     543           0 :                         hashtbl[h / 8] |= 1 << (h % 8);
     544             : 
     545           0 :                         ETHER_NEXT_MULTI(step, enm);
     546             :                 }
     547             :         }
     548             : 
     549             :         /* 
     550             :          * The datasheet claims broadcast frames were always accepted
     551             :          * regardless of filter settings. But the hardware seems to
     552             :          * filter broadcast frames, so pass them explicitly.
     553             :          */
     554           0 :         h = ether_crc32_be(etherbroadcastaddr, ETHER_ADDR_LEN) >> 26;
     555           0 :         hashtbl[h / 8] |= 1 << (h % 8);
     556             : 
     557           0 :         mos_write_mcast(sc, (void *)&hashtbl);
     558           0 :         mos_reg_write_1(sc, MOS_CTL, rxmode);
     559           0 : }
     560             : 
     561             : void
     562           0 : mos_reset(struct mos_softc *sc)
     563             : {
     564             :         u_int8_t ctl;
     565           0 :         if (usbd_is_dying(sc->mos_udev))
     566           0 :                 return;
     567             : 
     568           0 :         ctl = mos_reg_read_1(sc, MOS_CTL);
     569           0 :         ctl &= ~(MOS_CTL_RX_PROMISC | MOS_CTL_ALLMULTI | MOS_CTL_TX_ENB |
     570             :             MOS_CTL_RX_ENB);
     571             :         /* Disable RX, TX, promiscuous and allmulticast mode */
     572           0 :         mos_reg_write_1(sc, MOS_CTL, ctl);
     573             : 
     574             :         /* Reset frame drop counter register to zero */
     575           0 :         mos_reg_write_1(sc, MOS_FRAME_DROP_CNT, 0);
     576             : 
     577             :         /* Wait a little while for the chip to get its brains in order. */
     578           0 :         DELAY(1000);
     579           0 :         return;
     580           0 : }
     581             : 
     582             : void
     583           0 : mos_chip_init(struct mos_softc *sc)
     584             : {
     585             :         int     i;
     586             : 
     587             :         /*
     588             :          * Rev.C devices have a pause threshold register which needs to be set
     589             :          * at startup.
     590             :          */
     591           0 :         if (mos_reg_read_1(sc, MOS_PAUSE_TRHD) != -1) {
     592           0 :                 for (i=0;i<MOS_PAUSE_REWRITES;i++)
     593           0 :                         mos_reg_write_1(sc, MOS_PAUSE_TRHD, 0);
     594             :         }
     595             : 
     596           0 :         sc->mos_phyaddrs[0] = 1; sc->mos_phyaddrs[1] = 0xFF;
     597           0 : }
     598             : 
     599             : /*
     600             :  * Probe for a MCS7x30 chip.
     601             :  */
     602             : int
     603           0 : mos_match(struct device *parent, void *match, void *aux)
     604             : {
     605           0 :         struct usb_attach_arg *uaa = aux;
     606             : 
     607           0 :         if (uaa->iface == NULL || uaa->configno != MOS_CONFIG_NO)
     608           0 :                 return(UMATCH_NONE);
     609             : 
     610           0 :         return (mos_lookup(uaa->vendor, uaa->product) != NULL ?
     611             :             UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
     612           0 : }
     613             : 
     614             : /*
     615             :  * Attach the interface. Allocate softc structures, do ifmedia
     616             :  * setup and ethernet/BPF attach.
     617             :  */
     618             : void
     619           0 : mos_attach(struct device *parent, struct device *self, void *aux)
     620             : {
     621           0 :         struct mos_softc        *sc = (struct mos_softc *)self;
     622           0 :         struct usb_attach_arg   *uaa = aux;
     623             :         struct ifnet            *ifp;
     624           0 :         struct usbd_device      *dev = uaa->device;
     625             :         usbd_status             err;
     626             :         usb_interface_descriptor_t      *id;
     627             :         usb_endpoint_descriptor_t       *ed;
     628             :         struct mii_data         *mii;
     629           0 :         u_char                  eaddr[ETHER_ADDR_LEN];
     630             :         int                     i,s;
     631             : 
     632           0 :         sc->mos_udev = dev;
     633           0 :         sc->mos_unit = self->dv_unit;
     634             : 
     635           0 :         usb_init_task(&sc->mos_tick_task, mos_tick_task, sc,
     636             :             USB_TASK_TYPE_GENERIC);
     637           0 :         rw_init(&sc->mos_mii_lock, "mosmii");
     638           0 :         usb_init_task(&sc->mos_stop_task, (void (*)(void *))mos_stop, sc,
     639             :             USB_TASK_TYPE_GENERIC);
     640             : 
     641           0 :         err = usbd_device2interface_handle(dev, MOS_IFACE_IDX, &sc->mos_iface);
     642           0 :         if (err) {
     643           0 :                 printf("%s: getting interface handle failed\n",
     644           0 :                     sc->mos_dev.dv_xname);
     645           0 :                 return;
     646             :         }
     647             : 
     648           0 :         sc->mos_flags = mos_lookup(uaa->vendor, uaa->product)->mos_flags;
     649             : 
     650           0 :         id = usbd_get_interface_descriptor(sc->mos_iface);
     651             : 
     652           0 :         sc->mos_bufsz = MOS_BUFSZ;
     653             : 
     654             :         /* Find endpoints. */
     655           0 :         for (i = 0; i < id->bNumEndpoints; i++) {
     656           0 :                 ed = usbd_interface2endpoint_descriptor(sc->mos_iface, i);
     657           0 :                 if (!ed) {
     658           0 :                         printf("%s: couldn't get ep %d\n",
     659           0 :                             sc->mos_dev.dv_xname, i);
     660           0 :                         return;
     661             :                 }
     662           0 :                 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
     663           0 :                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
     664           0 :                         sc->mos_ed[MOS_ENDPT_RX] = ed->bEndpointAddress;
     665           0 :                 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
     666           0 :                            UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
     667           0 :                         sc->mos_ed[MOS_ENDPT_TX] = ed->bEndpointAddress;
     668           0 :                 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
     669           0 :                            UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
     670           0 :                         sc->mos_ed[MOS_ENDPT_INTR] = ed->bEndpointAddress;
     671           0 :                 }
     672             :         }
     673             : 
     674           0 :         s = splnet();
     675             : 
     676           0 :         printf("%s:", sc->mos_dev.dv_xname);
     677             : 
     678           0 :         if (sc->mos_flags & MCS7730)
     679           0 :                 printf(" MCS7730");
     680           0 :         else if (sc->mos_flags & MCS7830)
     681           0 :                 printf(" MCS7830");
     682           0 :         else if (sc->mos_flags & MCS7832)
     683           0 :                 printf(" MCS7832");
     684             : 
     685           0 :         mos_chip_init(sc);
     686             : 
     687             :         /*
     688             :          * Read MAC address, inform the world.
     689             :          */
     690           0 :         err = mos_readmac(sc, (void*)&eaddr);
     691           0 :         if (err) {
     692           0 :                 printf("%s: couldn't get MAC address\n",
     693             :                     sc->mos_dev.dv_xname);
     694           0 :                 splx(s);
     695           0 :                 return;
     696             :         }
     697           0 :         bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
     698           0 :         printf(", address %s\n", ether_sprintf(eaddr));
     699             : 
     700             :         /* Initialize interface info.*/
     701           0 :         ifp = GET_IFP(sc);
     702           0 :         ifp->if_softc = sc;
     703           0 :         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
     704           0 :         ifp->if_ioctl = mos_ioctl;
     705           0 :         ifp->if_start = mos_start;
     706           0 :         ifp->if_watchdog = mos_watchdog;
     707           0 :         strlcpy(ifp->if_xname, sc->mos_dev.dv_xname, IFNAMSIZ);
     708             : 
     709           0 :         ifp->if_capabilities = IFCAP_VLAN_MTU;
     710             : 
     711             :         /* Initialize MII/media info. */
     712           0 :         mii = GET_MII(sc);
     713           0 :         mii->mii_ifp = ifp;
     714           0 :         mii->mii_readreg = mos_miibus_readreg;
     715           0 :         mii->mii_writereg = mos_miibus_writereg;
     716           0 :         mii->mii_statchg = mos_miibus_statchg;
     717           0 :         mii->mii_flags = MIIF_AUTOTSLEEP;
     718             : 
     719           0 :         ifmedia_init(&mii->mii_media, 0, mos_ifmedia_upd, mos_ifmedia_sts);
     720           0 :         mii_attach(self, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, 0);
     721             : 
     722           0 :         if (LIST_FIRST(&mii->mii_phys) == NULL) {
     723           0 :                 ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_NONE, 0, NULL);
     724           0 :                 ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_NONE);
     725           0 :         } else
     726           0 :                 ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO);
     727             : 
     728             :         /* Attach the interface. */
     729           0 :         if_attach(ifp);
     730           0 :         ether_ifattach(ifp);
     731             : 
     732           0 :         timeout_set(&sc->mos_stat_ch, mos_tick, sc);
     733             : 
     734           0 :         splx(s);
     735           0 : }
     736             : 
     737             : int
     738           0 : mos_detach(struct device *self, int flags)
     739             : {
     740           0 :         struct mos_softc        *sc = (struct mos_softc *)self;
     741           0 :         struct ifnet            *ifp = GET_IFP(sc);
     742             :         int                     s;
     743             : 
     744             :         DPRINTFN(2,("%s: %s: enter\n", sc->mos_dev.dv_xname, __func__));
     745             : 
     746           0 :         if (timeout_initialized(&sc->mos_stat_ch))
     747           0 :                 timeout_del(&sc->mos_stat_ch);
     748             : 
     749           0 :         if (sc->mos_ep[MOS_ENDPT_TX] != NULL)
     750           0 :                 usbd_abort_pipe(sc->mos_ep[MOS_ENDPT_TX]);
     751           0 :         if (sc->mos_ep[MOS_ENDPT_RX] != NULL)
     752           0 :                 usbd_abort_pipe(sc->mos_ep[MOS_ENDPT_RX]);
     753           0 :         if (sc->mos_ep[MOS_ENDPT_INTR] != NULL)
     754           0 :                 usbd_abort_pipe(sc->mos_ep[MOS_ENDPT_INTR]);
     755             : 
     756             :         /*
     757             :          * Remove any pending tasks.  They cannot be executing because they run
     758             :          * in the same thread as detach.
     759             :          */
     760           0 :         usb_rem_task(sc->mos_udev, &sc->mos_tick_task);
     761           0 :         usb_rem_task(sc->mos_udev, &sc->mos_stop_task);
     762           0 :         s = splusb();
     763             : 
     764           0 :         if (--sc->mos_refcnt >= 0) {
     765             :                 /* Wait for processes to go away */
     766           0 :                 usb_detach_wait(&sc->mos_dev);
     767           0 :         }
     768             : 
     769           0 :         if (ifp->if_flags & IFF_RUNNING)
     770           0 :                 mos_stop(sc);
     771             : 
     772           0 :         mii_detach(&sc->mos_mii, MII_PHY_ANY, MII_OFFSET_ANY);
     773           0 :         ifmedia_delete_instance(&sc->mos_mii.mii_media, IFM_INST_ANY);
     774           0 :         if (ifp->if_softc != NULL) {
     775           0 :                 ether_ifdetach(ifp);
     776           0 :                 if_detach(ifp);
     777           0 :         }
     778             : 
     779             : #ifdef DIAGNOSTIC
     780           0 :         if (sc->mos_ep[MOS_ENDPT_TX] != NULL ||
     781           0 :             sc->mos_ep[MOS_ENDPT_RX] != NULL ||
     782           0 :             sc->mos_ep[MOS_ENDPT_INTR] != NULL)
     783           0 :                 printf("%s: detach has active endpoints\n",
     784           0 :                     sc->mos_dev.dv_xname);
     785             : #endif
     786             : 
     787           0 :         if (--sc->mos_refcnt >= 0) {
     788             :                 /* Wait for processes to go away. */
     789           0 :                 usb_detach_wait(&sc->mos_dev);
     790           0 :         }
     791           0 :         splx(s);
     792             : 
     793           0 :         return (0);
     794             : }
     795             : 
     796             : struct mbuf *
     797           0 : mos_newbuf(void)
     798             : {
     799             :         struct mbuf             *m;
     800             : 
     801           0 :         MGETHDR(m, M_DONTWAIT, MT_DATA);
     802           0 :         if (m == NULL)
     803           0 :                 return (NULL);
     804             : 
     805           0 :         MCLGET(m, M_DONTWAIT);
     806           0 :         if (!(m->m_flags & M_EXT)) {
     807           0 :                 m_freem(m);
     808           0 :                 return (NULL);
     809             :         }
     810             : 
     811           0 :         m->m_len = m->m_pkthdr.len = MCLBYTES;
     812           0 :         m_adj(m, ETHER_ALIGN);
     813             : 
     814           0 :         return (m);
     815           0 : }
     816             : 
     817             : int
     818           0 : mos_rx_list_init(struct mos_softc *sc)
     819             : {
     820             :         struct mos_cdata        *cd;
     821             :         struct mos_chain        *c;
     822             :         int                     i;
     823             : 
     824             :         DPRINTF(("%s: %s: enter\n", sc->mos_dev.dv_xname, __func__));
     825             : 
     826           0 :         cd = &sc->mos_cdata;
     827           0 :         for (i = 0; i < MOS_RX_LIST_CNT; i++) {
     828           0 :                 c = &cd->mos_rx_chain[i];
     829           0 :                 c->mos_sc = sc;
     830           0 :                 c->mos_idx = i;
     831           0 :                 c->mos_mbuf = NULL;
     832           0 :                 if (c->mos_xfer == NULL) {
     833           0 :                         c->mos_xfer = usbd_alloc_xfer(sc->mos_udev);
     834           0 :                         if (c->mos_xfer == NULL)
     835           0 :                                 return (ENOBUFS);
     836           0 :                         c->mos_buf = usbd_alloc_buffer(c->mos_xfer,
     837           0 :                             sc->mos_bufsz);
     838           0 :                         if (c->mos_buf == NULL) {
     839           0 :                                 usbd_free_xfer(c->mos_xfer);
     840           0 :                                 return (ENOBUFS);
     841             :                         }
     842             :                 }
     843             :         }
     844             : 
     845           0 :         return (0);
     846           0 : }
     847             : 
     848             : int
     849           0 : mos_tx_list_init(struct mos_softc *sc)
     850             : {
     851             :         struct mos_cdata        *cd;
     852             :         struct mos_chain        *c;
     853             :         int                     i;
     854             : 
     855             :         DPRINTF(("%s: %s: enter\n", sc->mos_dev.dv_xname, __func__));
     856             : 
     857           0 :         cd = &sc->mos_cdata;
     858           0 :         for (i = 0; i < MOS_TX_LIST_CNT; i++) {
     859           0 :                 c = &cd->mos_tx_chain[i];
     860           0 :                 c->mos_sc = sc;
     861           0 :                 c->mos_idx = i;
     862           0 :                 c->mos_mbuf = NULL;
     863           0 :                 if (c->mos_xfer == NULL) {
     864           0 :                         c->mos_xfer = usbd_alloc_xfer(sc->mos_udev);
     865           0 :                         if (c->mos_xfer == NULL)
     866           0 :                                 return (ENOBUFS);
     867           0 :                         c->mos_buf = usbd_alloc_buffer(c->mos_xfer,
     868           0 :                             sc->mos_bufsz);
     869           0 :                         if (c->mos_buf == NULL) {
     870           0 :                                 usbd_free_xfer(c->mos_xfer);
     871           0 :                                 return (ENOBUFS);
     872             :                         }
     873             :                 }
     874             :         }
     875             : 
     876           0 :         return (0);
     877           0 : }
     878             : 
     879             : /*
     880             :  * A frame has been uploaded: pass the resulting mbuf chain up to
     881             :  * the higher level protocols.
     882             :  */
     883             : void
     884           0 : mos_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
     885             : {
     886           0 :         struct mos_chain        *c = (struct mos_chain *)priv;
     887           0 :         struct mos_softc        *sc = c->mos_sc;
     888           0 :         struct ifnet            *ifp = GET_IFP(sc);
     889           0 :         u_char                  *buf = c->mos_buf;
     890             :         u_int8_t                rxstat;
     891           0 :         u_int32_t               total_len;
     892             :         u_int16_t               pktlen = 0;
     893           0 :         struct mbuf_list        ml = MBUF_LIST_INITIALIZER();
     894             :         struct mbuf             *m;
     895             :         int                     s;
     896             : 
     897             :         DPRINTFN(10,("%s: %s: enter\n", sc->mos_dev.dv_xname,__func__));
     898             : 
     899           0 :         if (usbd_is_dying(sc->mos_udev))
     900           0 :                 return;
     901             : 
     902           0 :         if (!(ifp->if_flags & IFF_RUNNING))
     903           0 :                 return;
     904             : 
     905           0 :         if (status != USBD_NORMAL_COMPLETION) {
     906           0 :                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
     907           0 :                         return;
     908           0 :                 if (usbd_ratecheck(&sc->mos_rx_notice)) {
     909           0 :                         printf("%s: usb errors on rx: %s\n",
     910           0 :                             sc->mos_dev.dv_xname, usbd_errstr(status));
     911           0 :                 }
     912           0 :                 if (status == USBD_STALLED)
     913           0 :                         usbd_clear_endpoint_stall_async(sc->mos_ep[MOS_ENDPT_RX]);
     914             :                 goto done;
     915             :         }
     916             : 
     917           0 :         usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
     918             : 
     919           0 :         if (total_len <= 1)
     920             :                 goto done;
     921             : 
     922             :         /* evaluate status byte at the end */
     923           0 :         pktlen = total_len - 1;
     924           0 :         rxstat = buf[pktlen] & MOS_RXSTS_MASK;
     925             : 
     926           0 :         if (rxstat != MOS_RXSTS_VALID) {
     927             :                 DPRINTF(("%s: erroneous frame received: ", 
     928             :                     sc->mos_dev.dv_xname));
     929           0 :                 if (rxstat & MOS_RXSTS_SHORT_FRAME)
     930             :                         DPRINTF(("frame size less than 64 bytes\n"));
     931           0 :                 if (rxstat & MOS_RXSTS_LARGE_FRAME)
     932             :                         DPRINTF(("frame size larger than 1532 bytes\n"));
     933           0 :                 if (rxstat & MOS_RXSTS_CRC_ERROR)
     934             :                         DPRINTF(("CRC error\n"));
     935           0 :                 if (rxstat & MOS_RXSTS_ALIGN_ERROR)
     936             :                         DPRINTF(("alignment error\n"));
     937           0 :                 ifp->if_ierrors++;
     938           0 :                 goto done;
     939             :         }
     940             : 
     941           0 :         if ( pktlen < sizeof(struct ether_header) ) {
     942           0 :                 ifp->if_ierrors++;
     943           0 :                 goto done;
     944             :         }
     945             : 
     946           0 :         m = mos_newbuf();
     947           0 :         if (m == NULL) {
     948           0 :                 ifp->if_ierrors++;
     949           0 :                 goto done;
     950             :         }
     951             : 
     952           0 :         m->m_pkthdr.len = m->m_len = pktlen;
     953             : 
     954           0 :         memcpy(mtod(m, char *), buf, pktlen);
     955             : 
     956           0 :         ml_enqueue(&ml, m);
     957             : 
     958           0 :         s = splnet();
     959           0 :         if_input(ifp, &ml);
     960           0 :         splx(s);
     961             : 
     962             : done:
     963           0 :         memset(c->mos_buf, 0, sc->mos_bufsz);
     964             : 
     965             :         /* Setup new transfer. */
     966           0 :         usbd_setup_xfer(xfer, sc->mos_ep[MOS_ENDPT_RX],
     967           0 :             c, c->mos_buf, sc->mos_bufsz,
     968             :             USBD_SHORT_XFER_OK | USBD_NO_COPY,
     969             :             USBD_NO_TIMEOUT, mos_rxeof);
     970           0 :         usbd_transfer(xfer);
     971             : 
     972             :         DPRINTFN(10,("%s: %s: start rx\n", sc->mos_dev.dv_xname, __func__));
     973             : 
     974           0 :         return;
     975           0 : }
     976             : 
     977             : /*
     978             :  * A frame was downloaded to the chip. It's safe for us to clean up
     979             :  * the list buffers.
     980             :  */
     981             : 
     982             : void
     983           0 : mos_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
     984             : {
     985             :         struct mos_softc        *sc;
     986             :         struct mos_chain        *c;
     987             :         struct ifnet            *ifp;
     988             :         int                     s;
     989             : 
     990           0 :         c = priv;
     991           0 :         sc = c->mos_sc;
     992           0 :         ifp = &sc->arpcom.ac_if;
     993             : 
     994           0 :         if (usbd_is_dying(sc->mos_udev))
     995           0 :                 return;
     996             : 
     997           0 :         s = splnet();
     998             : 
     999           0 :         if (status != USBD_NORMAL_COMPLETION) {
    1000           0 :                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
    1001           0 :                         splx(s);
    1002           0 :                         return;
    1003             :                 }
    1004           0 :                 ifp->if_oerrors++;
    1005           0 :                 printf("%s: usb error on tx: %s\n", sc->mos_dev.dv_xname,
    1006           0 :                     usbd_errstr(status));
    1007           0 :                 if (status == USBD_STALLED)
    1008           0 :                         usbd_clear_endpoint_stall_async(sc->mos_ep[MOS_ENDPT_TX]);
    1009           0 :                 splx(s);
    1010           0 :                 return;
    1011             :         }
    1012             : 
    1013           0 :         ifp->if_timer = 0;
    1014           0 :         ifq_clr_oactive(&ifp->if_snd);
    1015             : 
    1016           0 :         m_freem(c->mos_mbuf);
    1017           0 :         c->mos_mbuf = NULL;
    1018             : 
    1019           0 :         if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
    1020           0 :                 mos_start(ifp);
    1021             : 
    1022           0 :         splx(s);
    1023           0 :         return;
    1024           0 : }
    1025             : 
    1026             : void
    1027           0 : mos_tick(void *xsc)
    1028             : {
    1029           0 :         struct mos_softc *sc = xsc;
    1030             : 
    1031           0 :         if (sc == NULL)
    1032           0 :                 return;
    1033             : 
    1034             :         DPRINTFN(0xff, ("%s: %s: enter\n", sc->mos_dev.dv_xname,
    1035             :                         __func__));
    1036             : 
    1037           0 :         if (usbd_is_dying(sc->mos_udev))
    1038           0 :                 return;
    1039             : 
    1040             :         /* Perform periodic stuff in process context */
    1041           0 :         usb_add_task(sc->mos_udev, &sc->mos_tick_task);
    1042             : 
    1043           0 : }
    1044             : 
    1045             : void
    1046           0 : mos_tick_task(void *xsc)
    1047             : {
    1048             :         int                     s;
    1049             :         struct mos_softc        *sc;
    1050             :         struct ifnet            *ifp;
    1051             :         struct mii_data         *mii;
    1052             : 
    1053           0 :         sc = xsc;
    1054             : 
    1055           0 :         if (sc == NULL)
    1056           0 :                 return;
    1057             : 
    1058           0 :         if (usbd_is_dying(sc->mos_udev))
    1059           0 :                 return;
    1060             : 
    1061           0 :         ifp = GET_IFP(sc);
    1062           0 :         mii = GET_MII(sc);
    1063           0 :         if (mii == NULL)
    1064           0 :                 return;
    1065             : 
    1066           0 :         s = splnet();
    1067             : 
    1068           0 :         mii_tick(mii);
    1069           0 :         if (!sc->mos_link && mii->mii_media_status & IFM_ACTIVE &&
    1070           0 :             IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
    1071             :                 DPRINTF(("%s: %s: got link\n",
    1072             :                          sc->mos_dev.dv_xname, __func__));
    1073           0 :                 sc->mos_link++;
    1074           0 :                 if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
    1075           0 :                         mos_start(ifp);
    1076             :         }
    1077             : 
    1078           0 :         timeout_add_sec(&sc->mos_stat_ch, 1);
    1079             : 
    1080           0 :         splx(s);
    1081           0 : }
    1082             : 
    1083             : int
    1084           0 : mos_encap(struct mos_softc *sc, struct mbuf *m, int idx)
    1085             : {
    1086             :         struct mos_chain        *c;
    1087             :         usbd_status             err;
    1088             :         int                     length;
    1089             : 
    1090           0 :         c = &sc->mos_cdata.mos_tx_chain[idx];
    1091             : 
    1092           0 :         m_copydata(m, 0, m->m_pkthdr.len, c->mos_buf);
    1093           0 :         length = m->m_pkthdr.len;
    1094             : 
    1095           0 :         c->mos_mbuf = m;
    1096             : 
    1097           0 :         usbd_setup_xfer(c->mos_xfer, sc->mos_ep[MOS_ENDPT_TX],
    1098           0 :             c, c->mos_buf, length, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
    1099             :             10000, mos_txeof);
    1100             : 
    1101             :         /* Transmit */
    1102           0 :         err = usbd_transfer(c->mos_xfer);
    1103           0 :         if (err != USBD_IN_PROGRESS) {
    1104           0 :                 mos_stop(sc);
    1105           0 :                 return(EIO);
    1106             :         }
    1107             : 
    1108           0 :         sc->mos_cdata.mos_tx_cnt++;
    1109             : 
    1110           0 :         return(0);
    1111           0 : }
    1112             : 
    1113             : void
    1114           0 : mos_start(struct ifnet *ifp)
    1115             : {
    1116             :         struct mos_softc        *sc;
    1117             :         struct mbuf             *m_head = NULL;
    1118             : 
    1119           0 :         sc = ifp->if_softc;
    1120             : 
    1121           0 :         if (!sc->mos_link)
    1122           0 :                 return;
    1123             : 
    1124           0 :         if (ifq_is_oactive(&ifp->if_snd))
    1125           0 :                 return;
    1126             : 
    1127           0 :         m_head = ifq_deq_begin(&ifp->if_snd);
    1128           0 :         if (m_head == NULL)
    1129           0 :                 return;
    1130             : 
    1131           0 :         if (mos_encap(sc, m_head, 0)) {
    1132           0 :                 ifq_deq_rollback(&ifp->if_snd, m_head);
    1133           0 :                 ifq_set_oactive(&ifp->if_snd);
    1134           0 :                 return;
    1135             :         }
    1136           0 :         ifq_deq_commit(&ifp->if_snd, m_head);
    1137             : 
    1138             :         /*
    1139             :          * If there's a BPF listener, bounce a copy of this frame
    1140             :          * to him.
    1141             :          */
    1142             : #if NBPFILTER > 0
    1143           0 :         if (ifp->if_bpf)
    1144           0 :                 bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
    1145             : #endif
    1146             : 
    1147           0 :         ifq_set_oactive(&ifp->if_snd);
    1148             : 
    1149             :         /*
    1150             :          * Set a timeout in case the chip goes out to lunch.
    1151             :          */
    1152           0 :         ifp->if_timer = 5;
    1153             : 
    1154           0 :         return;
    1155           0 : }
    1156             : 
    1157             : void
    1158           0 : mos_init(void *xsc)
    1159             : {
    1160           0 :         struct mos_softc        *sc = xsc;
    1161           0 :         struct ifnet            *ifp = &sc->arpcom.ac_if;
    1162             :         struct mos_chain        *c;
    1163             :         usbd_status             err;
    1164             :         u_int8_t                rxmode;
    1165             :         int                     i, s;
    1166             : 
    1167           0 :         s = splnet();
    1168             : 
    1169             :         /*
    1170             :          * Cancel pending I/O and free all RX/TX buffers.
    1171             :          */
    1172           0 :         mos_reset(sc);
    1173             : 
    1174             :         /*
    1175             :          * Write MAC address
    1176             :          */
    1177           0 :         mos_writemac(sc, sc->arpcom.ac_enaddr);
    1178             : 
    1179             :         /* Init RX ring. */
    1180           0 :         if (mos_rx_list_init(sc) == ENOBUFS) {
    1181           0 :                 printf("%s: rx list init failed\n", sc->mos_dev.dv_xname);
    1182           0 :                 splx(s);
    1183           0 :                 return;
    1184             :         }
    1185             : 
    1186             :         /* Init TX ring. */
    1187           0 :         if (mos_tx_list_init(sc) == ENOBUFS) {
    1188           0 :                 printf("%s: tx list init failed\n", sc->mos_dev.dv_xname);
    1189           0 :                 splx(s);
    1190           0 :                 return;
    1191             :         }
    1192             : 
    1193             :         /* Read and set transmitter IPG values */
    1194           0 :         sc->mos_ipgs[0] = mos_reg_read_1(sc, MOS_IPG0);
    1195           0 :         sc->mos_ipgs[1] = mos_reg_read_1(sc, MOS_IPG1);
    1196           0 :         mos_reg_write_1(sc, MOS_IPG0, sc->mos_ipgs[0]);
    1197           0 :         mos_reg_write_1(sc, MOS_IPG1, sc->mos_ipgs[1]);
    1198             : 
    1199             :         /* Program promiscuous mode and multicast filters. */
    1200           0 :         mos_iff(sc);
    1201             : 
    1202             :         /* Enable receiver and transmitter, bridge controls speed/duplex mode */
    1203           0 :         rxmode = mos_reg_read_1(sc, MOS_CTL);
    1204           0 :         rxmode |= MOS_CTL_RX_ENB | MOS_CTL_TX_ENB | MOS_CTL_BS_ENB;
    1205           0 :         rxmode &= ~(MOS_CTL_SLEEP);
    1206           0 :         mos_reg_write_1(sc, MOS_CTL, rxmode);
    1207             : 
    1208           0 :         mii_mediachg(GET_MII(sc));
    1209             : 
    1210             :         /* Open RX and TX pipes. */
    1211           0 :         err = usbd_open_pipe(sc->mos_iface, sc->mos_ed[MOS_ENDPT_RX],
    1212           0 :             USBD_EXCLUSIVE_USE, &sc->mos_ep[MOS_ENDPT_RX]);
    1213           0 :         if (err) {
    1214           0 :                 printf("%s: open rx pipe failed: %s\n",
    1215           0 :                     sc->mos_dev.dv_xname, usbd_errstr(err));
    1216           0 :                 splx(s);
    1217           0 :                 return;
    1218             :         }
    1219             : 
    1220           0 :         err = usbd_open_pipe(sc->mos_iface, sc->mos_ed[MOS_ENDPT_TX],
    1221           0 :             USBD_EXCLUSIVE_USE, &sc->mos_ep[MOS_ENDPT_TX]);
    1222           0 :         if (err) {
    1223           0 :                 printf("%s: open tx pipe failed: %s\n",
    1224           0 :                     sc->mos_dev.dv_xname, usbd_errstr(err));
    1225           0 :                 splx(s);
    1226           0 :                 return;
    1227             :         }
    1228             : 
    1229             :         /* Start up the receive pipe. */
    1230           0 :         for (i = 0; i < MOS_RX_LIST_CNT; i++) {
    1231           0 :                 c = &sc->mos_cdata.mos_rx_chain[i];
    1232           0 :                 usbd_setup_xfer(c->mos_xfer, sc->mos_ep[MOS_ENDPT_RX],
    1233           0 :                     c, c->mos_buf, sc->mos_bufsz,
    1234             :                     USBD_SHORT_XFER_OK | USBD_NO_COPY,
    1235             :                     USBD_NO_TIMEOUT, mos_rxeof);
    1236           0 :                 usbd_transfer(c->mos_xfer);
    1237             :         }
    1238             : 
    1239           0 :         ifp->if_flags |= IFF_RUNNING;
    1240           0 :         ifq_clr_oactive(&ifp->if_snd);
    1241             : 
    1242           0 :         splx(s);
    1243             : 
    1244           0 :         timeout_add_sec(&sc->mos_stat_ch, 1);
    1245           0 :         return;
    1246           0 : }
    1247             : 
    1248             : int
    1249           0 : mos_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
    1250             : {
    1251           0 :         struct mos_softc        *sc = ifp->if_softc;
    1252           0 :         struct ifreq            *ifr = (struct ifreq *)data;
    1253             :         int                     s, error = 0;
    1254             : 
    1255           0 :         s = splnet();
    1256             : 
    1257           0 :         switch(cmd) {
    1258             :         case SIOCSIFADDR:
    1259           0 :                 ifp->if_flags |= IFF_UP;
    1260           0 :                 if (!(ifp->if_flags & IFF_RUNNING))
    1261           0 :                         mos_init(sc);
    1262             :                 break;
    1263             : 
    1264             :         case SIOCSIFFLAGS:
    1265           0 :                 if (ifp->if_flags & IFF_UP) {
    1266           0 :                         if (ifp->if_flags & IFF_RUNNING)
    1267           0 :                                 error = ENETRESET;
    1268             :                         else
    1269           0 :                                 mos_init(sc);
    1270             :                 } else {
    1271           0 :                         if (ifp->if_flags & IFF_RUNNING)
    1272           0 :                                 mos_stop(sc);
    1273             :                 }
    1274             :                 break;
    1275             : 
    1276             :         case SIOCGIFMEDIA:
    1277             :         case SIOCSIFMEDIA:
    1278           0 :                 error = ifmedia_ioctl(ifp, ifr, &sc->mos_mii.mii_media, cmd);
    1279           0 :                 break;
    1280             : 
    1281             :         default:
    1282           0 :                 error = ether_ioctl(ifp, &sc->arpcom, cmd, data);
    1283           0 :         }
    1284             : 
    1285           0 :         if (error == ENETRESET) {
    1286           0 :                 if (ifp->if_flags & IFF_RUNNING)
    1287           0 :                         mos_iff(sc);
    1288             :                 error = 0;
    1289           0 :         }
    1290             : 
    1291           0 :         splx(s);
    1292           0 :         return(error);
    1293             : }
    1294             : 
    1295             : void
    1296           0 : mos_watchdog(struct ifnet *ifp)
    1297             : {
    1298             :         struct mos_softc        *sc;
    1299             :         struct mos_chain        *c;
    1300           0 :         usbd_status             stat;
    1301             :         int                     s;
    1302             : 
    1303           0 :         sc = ifp->if_softc;
    1304             : 
    1305           0 :         ifp->if_oerrors++;
    1306           0 :         printf("%s: watchdog timeout\n", sc->mos_dev.dv_xname);
    1307             : 
    1308           0 :         s = splusb();
    1309           0 :         c = &sc->mos_cdata.mos_tx_chain[0];
    1310           0 :         usbd_get_xfer_status(c->mos_xfer, NULL, NULL, NULL, &stat);
    1311           0 :         mos_txeof(c->mos_xfer, c, stat);
    1312             : 
    1313           0 :         if (!IFQ_IS_EMPTY(&ifp->if_snd))
    1314           0 :                 mos_start(ifp);
    1315           0 :         splx(s);
    1316           0 : }
    1317             : 
    1318             : 
    1319             : /*
    1320             :  * Stop the adapter and free any mbufs allocated to the
    1321             :  * RX and TX lists.
    1322             :  */
    1323             : void
    1324           0 : mos_stop(struct mos_softc *sc)
    1325             : {
    1326             :         usbd_status             err;
    1327             :         struct ifnet            *ifp;
    1328             :         int                     i;
    1329             : 
    1330           0 :         mos_reset(sc);
    1331             : 
    1332           0 :         ifp = &sc->arpcom.ac_if;
    1333           0 :         ifp->if_timer = 0;
    1334           0 :         ifp->if_flags &= ~IFF_RUNNING;
    1335           0 :         ifq_clr_oactive(&ifp->if_snd);
    1336             : 
    1337           0 :         timeout_del(&sc->mos_stat_ch);
    1338             : 
    1339             :         /* Stop transfers. */
    1340           0 :         if (sc->mos_ep[MOS_ENDPT_RX] != NULL) {
    1341           0 :                 usbd_abort_pipe(sc->mos_ep[MOS_ENDPT_RX]);
    1342           0 :                 err = usbd_close_pipe(sc->mos_ep[MOS_ENDPT_RX]);
    1343           0 :                 if (err) {
    1344           0 :                         printf("%s: close rx pipe failed: %s\n",
    1345           0 :                             sc->mos_dev.dv_xname, usbd_errstr(err));
    1346           0 :                 }
    1347           0 :                 sc->mos_ep[MOS_ENDPT_RX] = NULL;
    1348           0 :         }
    1349             : 
    1350           0 :         if (sc->mos_ep[MOS_ENDPT_TX] != NULL) {
    1351           0 :                 usbd_abort_pipe(sc->mos_ep[MOS_ENDPT_TX]);
    1352           0 :                 err = usbd_close_pipe(sc->mos_ep[MOS_ENDPT_TX]);
    1353           0 :                 if (err) {
    1354           0 :                         printf("%s: close tx pipe failed: %s\n",
    1355           0 :                             sc->mos_dev.dv_xname, usbd_errstr(err));
    1356           0 :                 }
    1357           0 :                 sc->mos_ep[MOS_ENDPT_TX] = NULL;
    1358           0 :         }
    1359             : 
    1360           0 :         if (sc->mos_ep[MOS_ENDPT_INTR] != NULL) {
    1361           0 :                 usbd_abort_pipe(sc->mos_ep[MOS_ENDPT_INTR]);
    1362           0 :                 err = usbd_close_pipe(sc->mos_ep[MOS_ENDPT_INTR]);
    1363           0 :                 if (err) {
    1364           0 :                         printf("%s: close intr pipe failed: %s\n",
    1365           0 :                             sc->mos_dev.dv_xname, usbd_errstr(err));
    1366           0 :                 }
    1367           0 :                 sc->mos_ep[MOS_ENDPT_INTR] = NULL;
    1368           0 :         }
    1369             : 
    1370             :         /* Free RX resources. */
    1371           0 :         for (i = 0; i < MOS_RX_LIST_CNT; i++) {
    1372           0 :                 if (sc->mos_cdata.mos_rx_chain[i].mos_mbuf != NULL) {
    1373           0 :                         m_freem(sc->mos_cdata.mos_rx_chain[i].mos_mbuf);
    1374           0 :                         sc->mos_cdata.mos_rx_chain[i].mos_mbuf = NULL;
    1375           0 :                 }
    1376           0 :                 if (sc->mos_cdata.mos_rx_chain[i].mos_xfer != NULL) {
    1377           0 :                         usbd_free_xfer(sc->mos_cdata.mos_rx_chain[i].mos_xfer);
    1378           0 :                         sc->mos_cdata.mos_rx_chain[i].mos_xfer = NULL;
    1379           0 :                 }
    1380             :         }
    1381             : 
    1382             :         /* Free TX resources. */
    1383           0 :         for (i = 0; i < MOS_TX_LIST_CNT; i++) {
    1384           0 :                 if (sc->mos_cdata.mos_tx_chain[i].mos_mbuf != NULL) {
    1385           0 :                         m_freem(sc->mos_cdata.mos_tx_chain[i].mos_mbuf);
    1386           0 :                         sc->mos_cdata.mos_tx_chain[i].mos_mbuf = NULL;
    1387           0 :                 }
    1388           0 :                 if (sc->mos_cdata.mos_tx_chain[i].mos_xfer != NULL) {
    1389           0 :                         usbd_free_xfer(sc->mos_cdata.mos_tx_chain[i].mos_xfer);
    1390           0 :                         sc->mos_cdata.mos_tx_chain[i].mos_xfer = NULL;
    1391           0 :                 }
    1392             :         }
    1393             : 
    1394           0 :         sc->mos_link = 0;
    1395           0 : }
    1396             : 

Generated by: LCOV version 1.13