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