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


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

FreeBSD/Linux Kernel Cross Reference
sys/dev/usb/net/if_mos.c

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

    1 /*-
    2  * SPDX-License-Identifier: (BSD-1-Clause AND BSD-4-Clause)
    3  *
    4  * Copyright (c) 2011 Rick van der Zwet <info@rickvanderzwet.nl>
    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) 2008 Johann Christian Rode <jcrode@gmx.net>
   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) 2005, 2006, 2007 Jonathan Gray <jsg@openbsd.org>
   37  *
   38  * Permission to use, copy, modify, and distribute this software for any
   39  * purpose with or without fee is hereby granted, provided that the above
   40  * copyright notice and this permission notice appear in all copies.
   41  *
   42  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   43  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   44  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   45  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   46  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   47  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   48  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   49  */
   50 
   51 /*-
   52  * Copyright (c) 1997, 1998, 1999, 2000-2003
   53  *      Bill Paul <wpaul@windriver.com>.  All rights reserved.
   54  *
   55  * Redistribution and use in source and binary forms, with or without
   56  * modification, are permitted provided that the following conditions
   57  * are met:
   58  * 1. Redistributions of source code must retain the above copyright
   59  *    notice, this list of conditions and the following disclaimer.
   60  * 2. Redistributions in binary form must reproduce the above copyright
   61  *    notice, this list of conditions and the following disclaimer in the
   62  *    documentation and/or other materials provided with the distribution.
   63  * 3. All advertising materials mentioning features or use of this software
   64  *    must display the following acknowledgement:
   65  *      This product includes software developed by Bill Paul.
   66  * 4. Neither the name of the author nor the names of any co-contributors
   67  *    may be used to endorse or promote products derived from this software
   68  *    without specific prior written permission.
   69  *
   70  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
   71  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   72  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   73  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
   74  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   75  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   76  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   77  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   78  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   79  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   80  * THE POSSIBILITY OF SUCH DAMAGE.
   81  */
   82 
   83 #include <sys/cdefs.h>
   84 __FBSDID("$FreeBSD$");
   85 
   86 /*
   87  * Moschip MCS7730/MCS7830/MCS7832 USB to Ethernet controller
   88  * The datasheet is available at the following URL:
   89  * http://www.moschip.com/data/products/MCS7830/Data%20Sheet_7830.pdf
   90  */
   91 
   92 /*
   93  * The FreeBSD if_mos.c driver is based on various different sources:
   94  * The vendor provided driver at the following URL:
   95  * http://www.moschip.com/data/products/MCS7830/Driver_FreeBSD_7830.tar.gz
   96  *
   97  * Mixed together with the OpenBSD if_mos.c driver for validation and checking
   98  * and the FreeBSD if_reu.c as reference for the USB Ethernet framework.
   99  */
  100 
  101 #include <sys/stdint.h>
  102 #include <sys/stddef.h>
  103 #include <sys/param.h>
  104 #include <sys/queue.h>
  105 #include <sys/types.h>
  106 #include <sys/systm.h>
  107 #include <sys/socket.h>
  108 #include <sys/kernel.h>
  109 #include <sys/bus.h>
  110 #include <sys/module.h>
  111 #include <sys/lock.h>
  112 #include <sys/mutex.h>
  113 #include <sys/condvar.h>
  114 #include <sys/sysctl.h>
  115 #include <sys/sx.h>
  116 #include <sys/unistd.h>
  117 #include <sys/callout.h>
  118 #include <sys/malloc.h>
  119 #include <sys/priv.h>
  120 
  121 #include <net/if.h>
  122 #include <net/if_var.h>
  123 #include <net/if_media.h>
  124 
  125 #include <dev/mii/mii.h>
  126 #include <dev/mii/miivar.h>
  127 
  128 #include <dev/usb/usb.h>
  129 #include <dev/usb/usbdi.h>
  130 #include <dev/usb/usbdi_util.h>
  131 #include "usbdevs.h"
  132 
  133 #define USB_DEBUG_VAR mos_debug
  134 #include <dev/usb/usb_debug.h>
  135 #include <dev/usb/usb_process.h>
  136 
  137 #include <dev/usb/net/usb_ethernet.h>
  138 
  139 #include "miibus_if.h"
  140 
  141 //#include <dev/usb/net/if_mosreg.h>
  142 #include "if_mosreg.h"
  143 
  144 #ifdef USB_DEBUG
  145 static int mos_debug = 0;
  146 
  147 static SYSCTL_NODE(_hw_usb, OID_AUTO, mos, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
  148     "USB mos");
  149 SYSCTL_INT(_hw_usb_mos, OID_AUTO, debug, CTLFLAG_RWTUN, &mos_debug, 0,
  150     "Debug level");
  151 #endif
  152 
  153 #define MOS_DPRINTFN(fmt,...) \
  154   DPRINTF("mos: %s: " fmt "\n",__FUNCTION__,## __VA_ARGS__)
  155 
  156 #define USB_PRODUCT_MOSCHIP_MCS7730     0x7730
  157 #define USB_PRODUCT_SITECOMEU_LN030     0x0021
  158 
  159 /* Various supported device vendors/products. */
  160 static const STRUCT_USB_HOST_ID mos_devs[] = {
  161         {USB_VPI(USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7730, MCS7730)},
  162         {USB_VPI(USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7830, MCS7830)},
  163         {USB_VPI(USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7832, MCS7832)},
  164         {USB_VPI(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_LN030, MCS7830)},
  165 };
  166 
  167 static int mos_probe(device_t dev);
  168 static int mos_attach(device_t dev);
  169 static void mos_attach_post(struct usb_ether *ue);
  170 static int mos_detach(device_t dev);
  171 
  172 static void mos_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error);
  173 static void mos_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error);
  174 static void mos_intr_callback(struct usb_xfer *xfer, usb_error_t error);
  175 static void mos_tick(struct usb_ether *);
  176 static void mos_start(struct usb_ether *);
  177 static void mos_init(struct usb_ether *);
  178 static void mos_chip_init(struct mos_softc *);
  179 static void mos_stop(struct usb_ether *);
  180 static int mos_miibus_readreg(device_t, int, int);
  181 static int mos_miibus_writereg(device_t, int, int, int);
  182 static void mos_miibus_statchg(device_t);
  183 static int mos_ifmedia_upd(struct ifnet *);
  184 static void mos_ifmedia_sts(struct ifnet *, struct ifmediareq *);
  185 static void mos_reset(struct mos_softc *sc);
  186 
  187 static int mos_reg_read_1(struct mos_softc *, int);
  188 static int mos_reg_read_2(struct mos_softc *, int);
  189 static int mos_reg_write_1(struct mos_softc *, int, int);
  190 static int mos_reg_write_2(struct mos_softc *, int, int);
  191 static int mos_readmac(struct mos_softc *, uint8_t *);
  192 static int mos_writemac(struct mos_softc *, uint8_t *);
  193 static int mos_write_mcast(struct mos_softc *, u_char *);
  194 
  195 static void mos_setmulti(struct usb_ether *);
  196 static void mos_setpromisc(struct usb_ether *);
  197 
  198 static const struct usb_config mos_config[MOS_ENDPT_MAX] = {
  199         [MOS_ENDPT_TX] = {
  200                 .type = UE_BULK,
  201                 .endpoint = UE_ADDR_ANY,
  202                 .direction = UE_DIR_OUT,
  203                 .bufsize = (MCLBYTES + 2),
  204                 .flags = {.pipe_bof = 1,.force_short_xfer = 1,},
  205                 .callback = mos_bulk_write_callback,
  206                 .timeout = 10000,
  207         },
  208 
  209         [MOS_ENDPT_RX] = {
  210                 .type = UE_BULK,
  211                 .endpoint = UE_ADDR_ANY,
  212                 .direction = UE_DIR_IN,
  213                 .bufsize = (MCLBYTES + 4 + ETHER_CRC_LEN),
  214                 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
  215                 .callback = mos_bulk_read_callback,
  216         },
  217 
  218         [MOS_ENDPT_INTR] = {
  219                 .type = UE_INTERRUPT,
  220                 .endpoint = UE_ADDR_ANY,
  221                 .direction = UE_DIR_IN,
  222                 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
  223                 .bufsize = 0,
  224                 .callback = mos_intr_callback,
  225         },
  226 };
  227 
  228 static device_method_t mos_methods[] = {
  229         /* Device interface */
  230         DEVMETHOD(device_probe, mos_probe),
  231         DEVMETHOD(device_attach, mos_attach),
  232         DEVMETHOD(device_detach, mos_detach),
  233 
  234         /* MII interface */
  235         DEVMETHOD(miibus_readreg, mos_miibus_readreg),
  236         DEVMETHOD(miibus_writereg, mos_miibus_writereg),
  237         DEVMETHOD(miibus_statchg, mos_miibus_statchg),
  238 
  239         DEVMETHOD_END
  240 };
  241 
  242 static driver_t mos_driver = {
  243         .name = "mos",
  244         .methods = mos_methods,
  245         .size = sizeof(struct mos_softc)
  246 };
  247 
  248 DRIVER_MODULE(mos, uhub, mos_driver, NULL, NULL);
  249 DRIVER_MODULE(miibus, mos, miibus_driver, 0, 0);
  250 MODULE_DEPEND(mos, uether, 1, 1, 1);
  251 MODULE_DEPEND(mos, usb, 1, 1, 1);
  252 MODULE_DEPEND(mos, ether, 1, 1, 1);
  253 MODULE_DEPEND(mos, miibus, 1, 1, 1);
  254 USB_PNP_HOST_INFO(mos_devs);
  255 
  256 static const struct usb_ether_methods mos_ue_methods = {
  257         .ue_attach_post = mos_attach_post,
  258         .ue_start = mos_start,
  259         .ue_init = mos_init,
  260         .ue_stop = mos_stop,
  261         .ue_tick = mos_tick,
  262         .ue_setmulti = mos_setmulti,
  263         .ue_setpromisc = mos_setpromisc,
  264         .ue_mii_upd = mos_ifmedia_upd,
  265         .ue_mii_sts = mos_ifmedia_sts,
  266 };
  267 
  268 static int
  269 mos_reg_read_1(struct mos_softc *sc, int reg)
  270 {
  271         struct usb_device_request req;
  272         usb_error_t err;
  273         uByte val = 0;
  274 
  275         req.bmRequestType = UT_READ_VENDOR_DEVICE;
  276         req.bRequest = MOS_UR_READREG;
  277         USETW(req.wValue, 0);
  278         USETW(req.wIndex, reg);
  279         USETW(req.wLength, 1);
  280 
  281         err = uether_do_request(&sc->sc_ue, &req, &val, 1000);
  282 
  283         if (err) {
  284                 MOS_DPRINTFN("mos_reg_read_1 error, reg: %d\n", reg);
  285                 return (-1);
  286         }
  287         return (val);
  288 }
  289 
  290 static int
  291 mos_reg_read_2(struct mos_softc *sc, int reg)
  292 {
  293         struct usb_device_request req;
  294         usb_error_t err;
  295         uWord val;
  296 
  297         USETW(val, 0);
  298 
  299         req.bmRequestType = UT_READ_VENDOR_DEVICE;
  300         req.bRequest = MOS_UR_READREG;
  301         USETW(req.wValue, 0);
  302         USETW(req.wIndex, reg);
  303         USETW(req.wLength, 2);
  304 
  305         err = uether_do_request(&sc->sc_ue, &req, &val, 1000);
  306 
  307         if (err) {
  308                 MOS_DPRINTFN("mos_reg_read_2 error, reg: %d", reg);
  309                 return (-1);
  310         }
  311         return (UGETW(val));
  312 }
  313 
  314 static int
  315 mos_reg_write_1(struct mos_softc *sc, int reg, int aval)
  316 {
  317         struct usb_device_request req;
  318         usb_error_t err;
  319         uByte val;
  320         val = aval;
  321 
  322         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
  323         req.bRequest = MOS_UR_WRITEREG;
  324         USETW(req.wValue, 0);
  325         USETW(req.wIndex, reg);
  326         USETW(req.wLength, 1);
  327 
  328         err = uether_do_request(&sc->sc_ue, &req, &val, 1000);
  329 
  330         if (err) {
  331                 MOS_DPRINTFN("mos_reg_write_1 error, reg: %d", reg);
  332                 return (-1);
  333         }
  334         return (0);
  335 }
  336 
  337 static int
  338 mos_reg_write_2(struct mos_softc *sc, int reg, int aval)
  339 {
  340         struct usb_device_request req;
  341         usb_error_t err;
  342         uWord val;
  343 
  344         USETW(val, aval);
  345 
  346         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
  347         req.bRequest = MOS_UR_WRITEREG;
  348         USETW(req.wValue, 0);
  349         USETW(req.wIndex, reg);
  350         USETW(req.wLength, 2);
  351 
  352         err = uether_do_request(&sc->sc_ue, &req, &val, 1000);
  353 
  354         if (err) {
  355                 MOS_DPRINTFN("mos_reg_write_2 error, reg: %d", reg);
  356                 return (-1);
  357         }
  358         return (0);
  359 }
  360 
  361 static int
  362 mos_readmac(struct mos_softc *sc, u_char *mac)
  363 {
  364         struct usb_device_request req;
  365         usb_error_t err;
  366 
  367         req.bmRequestType = UT_READ_VENDOR_DEVICE;
  368         req.bRequest = MOS_UR_READREG;
  369         USETW(req.wValue, 0);
  370         USETW(req.wIndex, MOS_MAC);
  371         USETW(req.wLength, ETHER_ADDR_LEN);
  372 
  373         err = uether_do_request(&sc->sc_ue, &req, mac, 1000);
  374 
  375         if (err) {
  376                 return (-1);
  377         }
  378         return (0);
  379 }
  380 
  381 static int
  382 mos_writemac(struct mos_softc *sc, uint8_t *mac)
  383 {
  384         struct usb_device_request req;
  385         usb_error_t err;
  386 
  387         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
  388         req.bRequest = MOS_UR_WRITEREG;
  389         USETW(req.wValue, 0);
  390         USETW(req.wIndex, MOS_MAC);
  391         USETW(req.wLength, ETHER_ADDR_LEN);
  392 
  393         err = uether_do_request(&sc->sc_ue, &req, mac, 1000);
  394 
  395         if (err) {
  396                 MOS_DPRINTFN("mos_writemac error");
  397                 return (-1);
  398         }
  399         return (0);
  400 }
  401 
  402 static int
  403 mos_write_mcast(struct mos_softc *sc, u_char *hashtbl)
  404 {
  405         struct usb_device_request req;
  406         usb_error_t err;
  407 
  408         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
  409         req.bRequest = MOS_UR_WRITEREG;
  410         USETW(req.wValue, 0);
  411         USETW(req.wIndex, MOS_MCAST_TABLE);
  412         USETW(req.wLength, 8);
  413 
  414         err = uether_do_request(&sc->sc_ue, &req, hashtbl, 1000);
  415 
  416         if (err) {
  417                 MOS_DPRINTFN("mos_reg_mcast error");
  418                 return (-1);
  419         }
  420         return (0);
  421 }
  422 
  423 static int
  424 mos_miibus_readreg(device_t dev, int phy, int reg)
  425 {
  426         struct mos_softc *sc = device_get_softc(dev);
  427         uWord val;
  428         int i, res, locked;
  429 
  430         USETW(val, 0);
  431 
  432         locked = mtx_owned(&sc->sc_mtx);
  433         if (!locked)
  434                 MOS_LOCK(sc);
  435 
  436         mos_reg_write_2(sc, MOS_PHY_DATA, 0);
  437         mos_reg_write_1(sc, MOS_PHY_CTL, (phy & MOS_PHYCTL_PHYADDR) |
  438             MOS_PHYCTL_READ);
  439         mos_reg_write_1(sc, MOS_PHY_STS, (reg & MOS_PHYSTS_PHYREG) |
  440             MOS_PHYSTS_PENDING);
  441 
  442         for (i = 0; i < MOS_TIMEOUT; i++) {
  443                 if (mos_reg_read_1(sc, MOS_PHY_STS) & MOS_PHYSTS_READY)
  444                         break;
  445         }
  446         if (i == MOS_TIMEOUT) {
  447                 MOS_DPRINTFN("MII read timeout");
  448         }
  449         res = mos_reg_read_2(sc, MOS_PHY_DATA);
  450 
  451         if (!locked)
  452                 MOS_UNLOCK(sc);
  453         return (res);
  454 }
  455 
  456 static int
  457 mos_miibus_writereg(device_t dev, int phy, int reg, int val)
  458 {
  459         struct mos_softc *sc = device_get_softc(dev);
  460         int i, locked;
  461 
  462         locked = mtx_owned(&sc->sc_mtx);
  463         if (!locked)
  464                 MOS_LOCK(sc);
  465 
  466         mos_reg_write_2(sc, MOS_PHY_DATA, val);
  467         mos_reg_write_1(sc, MOS_PHY_CTL, (phy & MOS_PHYCTL_PHYADDR) |
  468             MOS_PHYCTL_WRITE);
  469         mos_reg_write_1(sc, MOS_PHY_STS, (reg & MOS_PHYSTS_PHYREG) |
  470             MOS_PHYSTS_PENDING);
  471 
  472         for (i = 0; i < MOS_TIMEOUT; i++) {
  473                 if (mos_reg_read_1(sc, MOS_PHY_STS) & MOS_PHYSTS_READY)
  474                         break;
  475         }
  476         if (i == MOS_TIMEOUT)
  477                 MOS_DPRINTFN("MII write timeout");
  478 
  479         if (!locked)
  480                 MOS_UNLOCK(sc);
  481         return 0;
  482 }
  483 
  484 static void
  485 mos_miibus_statchg(device_t dev)
  486 {
  487         struct mos_softc *sc = device_get_softc(dev);
  488         struct mii_data *mii = GET_MII(sc);
  489         int val, err, locked;
  490 
  491         locked = mtx_owned(&sc->sc_mtx);
  492         if (!locked)
  493                 MOS_LOCK(sc);
  494 
  495         /* disable RX, TX prior to changing FDX, SPEEDSEL */
  496         val = mos_reg_read_1(sc, MOS_CTL);
  497         val &= ~(MOS_CTL_TX_ENB | MOS_CTL_RX_ENB);
  498         mos_reg_write_1(sc, MOS_CTL, val);
  499 
  500         /* reset register which counts dropped frames */
  501         mos_reg_write_1(sc, MOS_FRAME_DROP_CNT, 0);
  502 
  503         if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX)
  504                 val |= MOS_CTL_FDX_ENB;
  505         else
  506                 val &= ~(MOS_CTL_FDX_ENB);
  507 
  508         switch (IFM_SUBTYPE(mii->mii_media_active)) {
  509         case IFM_100_TX:
  510                 val |= MOS_CTL_SPEEDSEL;
  511                 break;
  512         case IFM_10_T:
  513                 val &= ~(MOS_CTL_SPEEDSEL);
  514                 break;
  515         }
  516 
  517         /* re-enable TX, RX */
  518         val |= (MOS_CTL_TX_ENB | MOS_CTL_RX_ENB);
  519         err = mos_reg_write_1(sc, MOS_CTL, val);
  520 
  521         if (err)
  522                 MOS_DPRINTFN("media change failed");
  523 
  524         if (!locked)
  525                 MOS_UNLOCK(sc);
  526 }
  527 
  528 /*
  529  * Set media options.
  530  */
  531 static int
  532 mos_ifmedia_upd(struct ifnet *ifp)
  533 {
  534         struct mos_softc *sc = ifp->if_softc;
  535         struct mii_data *mii = GET_MII(sc);
  536         struct mii_softc *miisc;
  537         int error;
  538 
  539         MOS_LOCK_ASSERT(sc, MA_OWNED);
  540 
  541         sc->mos_link = 0;
  542         LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
  543                 PHY_RESET(miisc);
  544         error = mii_mediachg(mii);
  545         return (error);
  546 }
  547 
  548 /*
  549  * Report current media status.
  550  */
  551 static void
  552 mos_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
  553 {
  554         struct mos_softc *sc = ifp->if_softc;
  555         struct mii_data *mii = GET_MII(sc);
  556 
  557         MOS_LOCK(sc);
  558         mii_pollstat(mii);
  559 
  560         ifmr->ifm_active = mii->mii_media_active;
  561         ifmr->ifm_status = mii->mii_media_status;
  562         MOS_UNLOCK(sc);
  563 }
  564 
  565 static void
  566 mos_setpromisc(struct usb_ether *ue)
  567 {
  568         struct mos_softc *sc = uether_getsc(ue);
  569         struct ifnet *ifp = uether_getifp(ue);
  570 
  571         uint8_t rxmode;
  572 
  573         MOS_LOCK_ASSERT(sc, MA_OWNED);
  574 
  575         rxmode = mos_reg_read_1(sc, MOS_CTL);
  576 
  577         /* If we want promiscuous mode, set the allframes bit. */
  578         if (ifp->if_flags & IFF_PROMISC) {
  579                 rxmode |= MOS_CTL_RX_PROMISC;
  580         } else {
  581                 rxmode &= ~MOS_CTL_RX_PROMISC;
  582         }
  583 
  584         mos_reg_write_1(sc, MOS_CTL, rxmode);
  585 }
  586 
  587 static u_int
  588 mos_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)
  589 {
  590         uint8_t *hashtbl = arg;
  591         uint32_t h;
  592 
  593         h = ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN) >> 26;
  594         hashtbl[h / 8] |= 1 << (h % 8);
  595 
  596         return (1);
  597 }
  598 
  599 static void
  600 mos_setmulti(struct usb_ether *ue)
  601 {
  602         struct mos_softc *sc = uether_getsc(ue);
  603         struct ifnet *ifp = uether_getifp(ue);
  604         uint8_t rxmode;
  605         uint8_t hashtbl[8] = {0, 0, 0, 0, 0, 0, 0, 0};
  606         int allmulti = 0;
  607 
  608         MOS_LOCK_ASSERT(sc, MA_OWNED);
  609 
  610         rxmode = mos_reg_read_1(sc, MOS_CTL);
  611 
  612         if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC)
  613                 allmulti = 1;
  614 
  615         /* get all new ones */
  616         if_foreach_llmaddr(ifp, mos_hash_maddr, &hashtbl);
  617 
  618         /* now program new ones */
  619         if (allmulti == 1) {
  620                 rxmode |= MOS_CTL_ALLMULTI;
  621                 mos_reg_write_1(sc, MOS_CTL, rxmode);
  622         } else {
  623                 rxmode &= ~MOS_CTL_ALLMULTI;
  624                 mos_write_mcast(sc, (void *)&hashtbl);
  625                 mos_reg_write_1(sc, MOS_CTL, rxmode);
  626         }
  627 }
  628 
  629 static void
  630 mos_reset(struct mos_softc *sc)
  631 {
  632         uint8_t ctl;
  633 
  634         ctl = mos_reg_read_1(sc, MOS_CTL);
  635         ctl &= ~(MOS_CTL_RX_PROMISC | MOS_CTL_ALLMULTI | MOS_CTL_TX_ENB |
  636             MOS_CTL_RX_ENB);
  637         /* Disable RX, TX, promiscuous and allmulticast mode */
  638         mos_reg_write_1(sc, MOS_CTL, ctl);
  639 
  640         /* Reset frame drop counter register to zero */
  641         mos_reg_write_1(sc, MOS_FRAME_DROP_CNT, 0);
  642 
  643         /* Wait a little while for the chip to get its brains in order. */
  644         usb_pause_mtx(&sc->sc_mtx, hz / 128);
  645         return;
  646 }
  647 
  648 static void
  649 mos_chip_init(struct mos_softc *sc)
  650 {
  651         int i;
  652 
  653         /*
  654          * Rev.C devices have a pause threshold register which needs to be set
  655          * at startup.
  656          */
  657         if (mos_reg_read_1(sc, MOS_PAUSE_TRHD) != -1) {
  658                 for (i = 0; i < MOS_PAUSE_REWRITES; i++)
  659                         mos_reg_write_1(sc, MOS_PAUSE_TRHD, 0);
  660         }
  661         sc->mos_phyaddrs[0] = 1;
  662         sc->mos_phyaddrs[1] = 0xFF;
  663 }
  664 
  665 /*
  666  * Probe for a MCS7x30 chip.
  667  */
  668 static int
  669 mos_probe(device_t dev)
  670 {
  671         struct usb_attach_arg *uaa = device_get_ivars(dev);
  672         int retval;
  673 
  674         if (uaa->usb_mode != USB_MODE_HOST)
  675                 return (ENXIO);
  676         if (uaa->info.bConfigIndex != MOS_CONFIG_IDX)
  677                 return (ENXIO);
  678         if (uaa->info.bIfaceIndex != MOS_IFACE_IDX)
  679                 return (ENXIO);
  680 
  681         retval = usbd_lookup_id_by_uaa(mos_devs, sizeof(mos_devs), uaa);
  682         return (retval);
  683 }
  684 
  685 /*
  686  * Attach the interface. Allocate softc structures, do ifmedia
  687  * setup and ethernet/BPF attach.
  688  */
  689 static int
  690 mos_attach(device_t dev)
  691 {
  692         struct usb_attach_arg *uaa = device_get_ivars(dev);
  693         struct mos_softc *sc = device_get_softc(dev);
  694         struct usb_ether *ue = &sc->sc_ue;
  695         uint8_t iface_index;
  696         int error;
  697 
  698         sc->mos_flags = USB_GET_DRIVER_INFO(uaa);
  699 
  700         device_set_usb_desc(dev);
  701         mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
  702 
  703         iface_index = MOS_IFACE_IDX;
  704         error = usbd_transfer_setup(uaa->device, &iface_index,
  705             sc->sc_xfer, mos_config, MOS_ENDPT_MAX,
  706             sc, &sc->sc_mtx);
  707 
  708         if (error) {
  709                 device_printf(dev, "allocating USB transfers failed\n");
  710                 goto detach;
  711         }
  712         ue->ue_sc = sc;
  713         ue->ue_dev = dev;
  714         ue->ue_udev = uaa->device;
  715         ue->ue_mtx = &sc->sc_mtx;
  716         ue->ue_methods = &mos_ue_methods;
  717 
  718         if (sc->mos_flags & MCS7730) {
  719                 MOS_DPRINTFN("model: MCS7730");
  720         } else if (sc->mos_flags & MCS7830) {
  721                 MOS_DPRINTFN("model: MCS7830");
  722         } else if (sc->mos_flags & MCS7832) {
  723                 MOS_DPRINTFN("model: MCS7832");
  724         }
  725         error = uether_ifattach(ue);
  726         if (error) {
  727                 device_printf(dev, "could not attach interface\n");
  728                 goto detach;
  729         }
  730         return (0);
  731 
  732 detach:
  733         mos_detach(dev);
  734         return (ENXIO);
  735 }
  736 
  737 static void
  738 mos_attach_post(struct usb_ether *ue)
  739 {
  740         struct mos_softc *sc = uether_getsc(ue);
  741         int err;
  742 
  743         /* Read MAC address, inform the world. */
  744         err = mos_readmac(sc, ue->ue_eaddr);
  745 
  746         if (err)
  747           MOS_DPRINTFN("couldn't get MAC address");
  748 
  749         MOS_DPRINTFN("address: %s", ether_sprintf(ue->ue_eaddr));
  750 
  751         mos_chip_init(sc);
  752 }
  753 
  754 static int
  755 mos_detach(device_t dev)
  756 {
  757         struct mos_softc *sc = device_get_softc(dev);
  758         struct usb_ether *ue = &sc->sc_ue;
  759 
  760         usbd_transfer_unsetup(sc->sc_xfer, MOS_ENDPT_MAX);
  761         uether_ifdetach(ue);
  762         mtx_destroy(&sc->sc_mtx);
  763 
  764         return (0);
  765 }
  766 
  767 /*
  768  * A frame has been uploaded: pass the resulting mbuf chain up to
  769  * the higher level protocols.
  770  */
  771 static void
  772 mos_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
  773 {
  774         struct mos_softc *sc = usbd_xfer_softc(xfer);
  775         struct usb_ether *ue = &sc->sc_ue;
  776         struct ifnet *ifp = uether_getifp(ue);
  777 
  778         uint8_t rxstat = 0;
  779         uint32_t actlen;
  780         uint16_t pktlen = 0;
  781         struct usb_page_cache *pc;
  782 
  783         usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
  784         pc = usbd_xfer_get_frame(xfer, 0);
  785 
  786         switch (USB_GET_STATE(xfer)) {
  787         case USB_ST_TRANSFERRED:
  788                 MOS_DPRINTFN("actlen : %d", actlen);
  789                 if (actlen <= 1) {
  790                         if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
  791                         goto tr_setup;
  792                 }
  793                 /* evaluate status byte at the end */
  794                 usbd_copy_out(pc, actlen - sizeof(rxstat), &rxstat,
  795                     sizeof(rxstat));
  796 
  797                 if (rxstat != MOS_RXSTS_VALID) {
  798                         MOS_DPRINTFN("erroneous frame received");
  799                         if (rxstat & MOS_RXSTS_SHORT_FRAME)
  800                                 MOS_DPRINTFN("frame size less than 64 bytes");
  801                         if (rxstat & MOS_RXSTS_LARGE_FRAME) {
  802                                 MOS_DPRINTFN("frame size larger than "
  803                                     "1532 bytes");
  804                         }
  805                         if (rxstat & MOS_RXSTS_CRC_ERROR)
  806                                 MOS_DPRINTFN("CRC error");
  807                         if (rxstat & MOS_RXSTS_ALIGN_ERROR)
  808                                 MOS_DPRINTFN("alignment error");
  809                         if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
  810                         goto tr_setup;
  811                 }
  812                 /* Remember the last byte was used for the status fields */
  813                 pktlen = actlen - 1;
  814                 if (pktlen < sizeof(struct ether_header)) {
  815                         MOS_DPRINTFN("error: pktlen %d is smaller "
  816                             "than ether_header %zd", pktlen,
  817                             sizeof(struct ether_header));
  818                         if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
  819                         goto tr_setup;
  820                 }
  821                 uether_rxbuf(ue, pc, 0, actlen);
  822                 /* FALLTHROUGH */
  823         case USB_ST_SETUP:
  824 tr_setup:
  825                 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
  826                 usbd_transfer_submit(xfer);
  827                 uether_rxflush(ue);
  828                 return;
  829         default:
  830                 MOS_DPRINTFN("bulk read error, %s", usbd_errstr(error));
  831                 if (error != USB_ERR_CANCELLED) {
  832                         usbd_xfer_set_stall(xfer);
  833                         goto tr_setup;
  834                 }
  835                 MOS_DPRINTFN("start rx %i", usbd_xfer_max_len(xfer));
  836                 return;
  837         }
  838 }
  839 
  840 /*
  841  * A frame was downloaded to the chip. It's safe for us to clean up
  842  * the list buffers.
  843  */
  844 static void
  845 mos_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
  846 {
  847         struct mos_softc *sc = usbd_xfer_softc(xfer);
  848         struct ifnet *ifp = uether_getifp(&sc->sc_ue);
  849         struct usb_page_cache *pc;
  850         struct mbuf *m;
  851 
  852         switch (USB_GET_STATE(xfer)) {
  853         case USB_ST_TRANSFERRED:
  854                 MOS_DPRINTFN("transfer of complete");
  855                 if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
  856                 /* FALLTHROUGH */
  857         case USB_ST_SETUP:
  858 tr_setup:
  859                 /*
  860                  * XXX: don't send anything if there is no link?
  861                  */
  862                 IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
  863                 if (m == NULL)
  864                         return;
  865 
  866                 pc = usbd_xfer_get_frame(xfer, 0);
  867                 usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len);
  868 
  869                 usbd_xfer_set_frame_len(xfer, 0, m->m_pkthdr.len);
  870 
  871                 /*
  872                  * if there's a BPF listener, bounce a copy
  873                  * of this frame to him:
  874                  */
  875                 BPF_MTAP(ifp, m);
  876 
  877                 m_freem(m);
  878 
  879                 usbd_transfer_submit(xfer);
  880 
  881                 if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
  882                 return;
  883         default:
  884                 MOS_DPRINTFN("usb error on tx: %s\n", usbd_errstr(error));
  885                 if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
  886                 if (error != USB_ERR_CANCELLED) {
  887                         usbd_xfer_set_stall(xfer);
  888                         goto tr_setup;
  889                 }
  890                 return;
  891         }
  892 }
  893 
  894 static void
  895 mos_tick(struct usb_ether *ue)
  896 {
  897         struct mos_softc *sc = uether_getsc(ue);
  898         struct mii_data *mii = GET_MII(sc);
  899 
  900         MOS_LOCK_ASSERT(sc, MA_OWNED);
  901 
  902         mii_tick(mii);
  903         if (!sc->mos_link && mii->mii_media_status & IFM_ACTIVE &&
  904             IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
  905                 MOS_DPRINTFN("got link");
  906                 sc->mos_link++;
  907                 mos_start(ue);
  908         }
  909 }
  910 
  911 static void
  912 mos_start(struct usb_ether *ue)
  913 {
  914         struct mos_softc *sc = uether_getsc(ue);
  915 
  916         /*
  917          * start the USB transfers, if not already started:
  918          */
  919         usbd_transfer_start(sc->sc_xfer[MOS_ENDPT_TX]);
  920         usbd_transfer_start(sc->sc_xfer[MOS_ENDPT_RX]);
  921         usbd_transfer_start(sc->sc_xfer[MOS_ENDPT_INTR]);
  922 }
  923 
  924 static void
  925 mos_init(struct usb_ether *ue)
  926 {
  927         struct mos_softc *sc = uether_getsc(ue);
  928         struct ifnet *ifp = uether_getifp(ue);
  929         uint8_t rxmode;
  930 
  931         MOS_LOCK_ASSERT(sc, MA_OWNED);
  932 
  933         /* Cancel pending I/O and free all RX/TX buffers. */
  934         mos_reset(sc);
  935 
  936         /* Write MAC address */
  937         mos_writemac(sc, IF_LLADDR(ifp));
  938 
  939         /* Read and set transmitter IPG values */
  940         sc->mos_ipgs[0] = mos_reg_read_1(sc, MOS_IPG0);
  941         sc->mos_ipgs[1] = mos_reg_read_1(sc, MOS_IPG1);
  942         mos_reg_write_1(sc, MOS_IPG0, sc->mos_ipgs[0]);
  943         mos_reg_write_1(sc, MOS_IPG1, sc->mos_ipgs[1]);
  944 
  945         /*
  946          * Enable receiver and transmitter, bridge controls speed/duplex
  947          * mode
  948          */
  949         rxmode = mos_reg_read_1(sc, MOS_CTL);
  950         rxmode |= MOS_CTL_RX_ENB | MOS_CTL_TX_ENB | MOS_CTL_BS_ENB;
  951         rxmode &= ~(MOS_CTL_SLEEP);
  952 
  953         mos_setpromisc(ue);
  954 
  955         /* XXX: broadcast mode? */
  956         mos_reg_write_1(sc, MOS_CTL, rxmode);
  957 
  958         /* Load the multicast filter. */
  959         mos_setmulti(ue);
  960 
  961         ifp->if_drv_flags |= IFF_DRV_RUNNING;
  962         mos_start(ue);
  963 }
  964 
  965 static void
  966 mos_intr_callback(struct usb_xfer *xfer, usb_error_t error)
  967 {
  968         struct mos_softc *sc = usbd_xfer_softc(xfer);
  969         struct ifnet *ifp = uether_getifp(&sc->sc_ue);
  970         struct usb_page_cache *pc;
  971         uint32_t pkt;
  972         int actlen;
  973 
  974         if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
  975 
  976         usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
  977         MOS_DPRINTFN("actlen %i", actlen);
  978 
  979         switch (USB_GET_STATE(xfer)) {
  980         case USB_ST_TRANSFERRED:
  981 
  982                 pc = usbd_xfer_get_frame(xfer, 0);
  983                 usbd_copy_out(pc, 0, &pkt, sizeof(pkt));
  984                 /* FALLTHROUGH */
  985         case USB_ST_SETUP:
  986 tr_setup:
  987                 return;
  988         default:
  989                 if (error != USB_ERR_CANCELLED) {
  990                         usbd_xfer_set_stall(xfer);
  991                         goto tr_setup;
  992                 }
  993                 return;
  994         }
  995 }
  996 
  997 /*
  998  * Stop the adapter and free any mbufs allocated to the
  999  * RX and TX lists.
 1000  */
 1001 static void
 1002 mos_stop(struct usb_ether *ue)
 1003 {
 1004         struct mos_softc *sc = uether_getsc(ue);
 1005         struct ifnet *ifp = uether_getifp(ue);
 1006 
 1007         mos_reset(sc);
 1008 
 1009         MOS_LOCK_ASSERT(sc, MA_OWNED);
 1010         ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
 1011 
 1012         /* stop all the transfers, if not already stopped */
 1013         usbd_transfer_stop(sc->sc_xfer[MOS_ENDPT_TX]);
 1014         usbd_transfer_stop(sc->sc_xfer[MOS_ENDPT_RX]);
 1015         usbd_transfer_stop(sc->sc_xfer[MOS_ENDPT_INTR]);
 1016 
 1017         sc->mos_link = 0;
 1018 }

Cache object: 026e55a07f959c15161afae06c0c6212


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


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