if_mos.c revision 271832
1218729Shselasky/*- 2218729Shselasky * Copyright (c) 2011 Rick van der Zwet <info@rickvanderzwet.nl> 3218729Shselasky * 4218729Shselasky * Permission to use, copy, modify, and distribute this software for any 5218729Shselasky * purpose with or without fee is hereby granted, provided that the above 6218729Shselasky * copyright notice and this permission notice appear in all copies. 7218729Shselasky * 8218729Shselasky * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9218729Shselasky * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10218729Shselasky * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11218729Shselasky * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12218729Shselasky * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13218729Shselasky * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14218729Shselasky * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15218729Shselasky */ 16218729Shselasky 17218729Shselasky/*- 18218729Shselasky * Copyright (c) 2008 Johann Christian Rode <jcrode@gmx.net> 19218729Shselasky * 20218729Shselasky * Permission to use, copy, modify, and distribute this software for any 21218729Shselasky * purpose with or without fee is hereby granted, provided that the above 22218729Shselasky * copyright notice and this permission notice appear in all copies. 23218729Shselasky * 24218729Shselasky * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 25218729Shselasky * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 26218729Shselasky * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 27218729Shselasky * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 28218729Shselasky * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 29218729Shselasky * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 30218729Shselasky * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 31218729Shselasky */ 32218729Shselasky 33218729Shselasky/*- 34218729Shselasky * Copyright (c) 2005, 2006, 2007 Jonathan Gray <jsg@openbsd.org> 35218729Shselasky * 36218729Shselasky * Permission to use, copy, modify, and distribute this software for any 37218729Shselasky * purpose with or without fee is hereby granted, provided that the above 38218729Shselasky * copyright notice and this permission notice appear in all copies. 39218729Shselasky * 40218729Shselasky * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 41218729Shselasky * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 42218729Shselasky * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 43218729Shselasky * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 44218729Shselasky * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 45218729Shselasky * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 46218729Shselasky * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 47218729Shselasky */ 48218729Shselasky 49218729Shselasky/*- 50218729Shselasky * Copyright (c) 1997, 1998, 1999, 2000-2003 51218729Shselasky * Bill Paul <wpaul@windriver.com>. All rights reserved. 52218729Shselasky * 53218729Shselasky * Redistribution and use in source and binary forms, with or without 54218729Shselasky * modification, are permitted provided that the following conditions 55218729Shselasky * are met: 56218729Shselasky * 1. Redistributions of source code must retain the above copyright 57218729Shselasky * notice, this list of conditions and the following disclaimer. 58218729Shselasky * 2. Redistributions in binary form must reproduce the above copyright 59218729Shselasky * notice, this list of conditions and the following disclaimer in the 60218729Shselasky * documentation and/or other materials provided with the distribution. 61218729Shselasky * 3. All advertising materials mentioning features or use of this software 62218729Shselasky * must display the following acknowledgement: 63218729Shselasky * This product includes software developed by Bill Paul. 64218729Shselasky * 4. Neither the name of the author nor the names of any co-contributors 65218729Shselasky * may be used to endorse or promote products derived from this software 66218729Shselasky * without specific prior written permission. 67218729Shselasky * 68218729Shselasky * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 69218729Shselasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 70218729Shselasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 71218729Shselasky * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 72218729Shselasky * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 73218729Shselasky * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 74218729Shselasky * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 75218729Shselasky * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 76218729Shselasky * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 77218729Shselasky * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 78218729Shselasky * THE POSSIBILITY OF SUCH DAMAGE. 79218729Shselasky */ 80218729Shselasky 81218729Shselasky#include <sys/cdefs.h> 82218729Shselasky__FBSDID("$FreeBSD: head/sys/dev/usb/net/if_mos.c 271832 2014-09-18 21:09:22Z glebius $"); 83218729Shselasky 84218729Shselasky/* 85232257Skevlo * Moschip MCS7730/MCS7830/MCS7832 USB to Ethernet controller 86218729Shselasky * The datasheet is available at the following URL: 87218729Shselasky * http://www.moschip.com/data/products/MCS7830/Data%20Sheet_7830.pdf 88218729Shselasky */ 89218729Shselasky 90218729Shselasky/* 91218729Shselasky * The FreeBSD if_mos.c driver is based on various different sources: 92218729Shselasky * The vendor provided driver at the following URL: 93218729Shselasky * http://www.moschip.com/data/products/MCS7830/Driver_FreeBSD_7830.tar.gz 94218729Shselasky * 95218729Shselasky * Mixed together with the OpenBSD if_mos.c driver for validation and checking 96218729Shselasky * and the FreeBSD if_reu.c as reference for the USB Ethernet framework. 97218729Shselasky */ 98218729Shselasky 99218729Shselasky#include <sys/stdint.h> 100218729Shselasky#include <sys/stddef.h> 101218729Shselasky#include <sys/param.h> 102218729Shselasky#include <sys/queue.h> 103218729Shselasky#include <sys/types.h> 104218729Shselasky#include <sys/systm.h> 105257176Sglebius#include <sys/socket.h> 106218729Shselasky#include <sys/kernel.h> 107218729Shselasky#include <sys/bus.h> 108218729Shselasky#include <sys/module.h> 109218729Shselasky#include <sys/lock.h> 110218729Shselasky#include <sys/mutex.h> 111218729Shselasky#include <sys/condvar.h> 112218729Shselasky#include <sys/sysctl.h> 113218729Shselasky#include <sys/sx.h> 114218729Shselasky#include <sys/unistd.h> 115218729Shselasky#include <sys/callout.h> 116218729Shselasky#include <sys/malloc.h> 117218729Shselasky#include <sys/priv.h> 118218729Shselasky 119257176Sglebius#include <net/if.h> 120257176Sglebius#include <net/if_var.h> 121257176Sglebius 122218729Shselasky#include <dev/usb/usb.h> 123218729Shselasky#include <dev/usb/usbdi.h> 124218729Shselasky#include <dev/usb/usbdi_util.h> 125218729Shselasky#include "usbdevs.h" 126218729Shselasky 127218729Shselasky#define USB_DEBUG_VAR mos_debug 128218729Shselasky#include <dev/usb/usb_debug.h> 129218729Shselasky#include <dev/usb/usb_process.h> 130218729Shselasky 131218729Shselasky#include <dev/usb/net/usb_ethernet.h> 132218729Shselasky 133218729Shselasky//#include <dev/usb/net/if_mosreg.h> 134218729Shselasky#include "if_mosreg.h" 135218729Shselasky 136218729Shselasky#ifdef USB_DEBUG 137218729Shselaskystatic int mos_debug = 0; 138218729Shselasky 139227309Sedstatic SYSCTL_NODE(_hw_usb, OID_AUTO, mos, CTLFLAG_RW, 0, "USB mos"); 140218729ShselaskySYSCTL_INT(_hw_usb_mos, OID_AUTO, debug, CTLFLAG_RW, &mos_debug, 0, 141218729Shselasky "Debug level"); 142218729Shselasky#endif 143218729Shselasky 144218729Shselasky#define MOS_DPRINTFN(fmt,...) \ 145218729Shselasky DPRINTF("mos: %s: " fmt "\n",__FUNCTION__,## __VA_ARGS__) 146218729Shselasky 147218729Shselasky#define USB_PRODUCT_MOSCHIP_MCS7730 0x7730 148218729Shselasky#define USB_PRODUCT_SITECOMEU_LN030 0x0021 149218729Shselasky 150218729Shselasky 151218729Shselasky 152218729Shselasky/* Various supported device vendors/products. */ 153223486Shselaskystatic const STRUCT_USB_HOST_ID mos_devs[] = { 154218729Shselasky {USB_VPI(USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7730, MCS7730)}, 155218729Shselasky {USB_VPI(USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7830, MCS7830)}, 156232257Skevlo {USB_VPI(USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7832, MCS7832)}, 157218729Shselasky {USB_VPI(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_LN030, MCS7830)}, 158218729Shselasky}; 159218729Shselasky 160218729Shselaskystatic int mos_probe(device_t dev); 161218729Shselaskystatic int mos_attach(device_t dev); 162218729Shselaskystatic void mos_attach_post(struct usb_ether *ue); 163218729Shselaskystatic int mos_detach(device_t dev); 164218729Shselasky 165218729Shselaskystatic void mos_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error); 166218729Shselaskystatic void mos_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error); 167218729Shselaskystatic void mos_intr_callback(struct usb_xfer *xfer, usb_error_t error); 168218729Shselaskystatic void mos_tick(struct usb_ether *); 169218729Shselaskystatic void mos_start(struct usb_ether *); 170218729Shselaskystatic void mos_init(struct usb_ether *); 171218729Shselaskystatic void mos_chip_init(struct mos_softc *); 172218729Shselaskystatic void mos_stop(struct usb_ether *); 173218729Shselaskystatic int mos_miibus_readreg(device_t, int, int); 174218729Shselaskystatic int mos_miibus_writereg(device_t, int, int, int); 175218729Shselaskystatic void mos_miibus_statchg(device_t); 176218729Shselaskystatic int mos_ifmedia_upd(struct ifnet *); 177218729Shselaskystatic void mos_ifmedia_sts(struct ifnet *, struct ifmediareq *); 178218729Shselaskystatic void mos_reset(struct mos_softc *sc); 179218729Shselasky 180218729Shselaskystatic int mos_reg_read_1(struct mos_softc *, int); 181218729Shselaskystatic int mos_reg_read_2(struct mos_softc *, int); 182218729Shselaskystatic int mos_reg_write_1(struct mos_softc *, int, int); 183218729Shselaskystatic int mos_reg_write_2(struct mos_softc *, int, int); 184218729Shselaskystatic int mos_readmac(struct mos_softc *, uint8_t *); 185218729Shselaskystatic int mos_writemac(struct mos_softc *, uint8_t *); 186218729Shselaskystatic int mos_write_mcast(struct mos_softc *, u_char *); 187218729Shselasky 188218729Shselaskystatic void mos_setmulti(struct usb_ether *); 189218729Shselaskystatic void mos_setpromisc(struct usb_ether *); 190218729Shselasky 191218729Shselaskystatic const struct usb_config mos_config[MOS_ENDPT_MAX] = { 192218729Shselasky 193218729Shselasky [MOS_ENDPT_TX] = { 194218729Shselasky .type = UE_BULK, 195218729Shselasky .endpoint = UE_ADDR_ANY, 196218729Shselasky .direction = UE_DIR_OUT, 197218729Shselasky .bufsize = (MCLBYTES + 2), 198218729Shselasky .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 199218729Shselasky .callback = mos_bulk_write_callback, 200218729Shselasky .timeout = 10000, 201218729Shselasky }, 202218729Shselasky 203218729Shselasky [MOS_ENDPT_RX] = { 204218729Shselasky .type = UE_BULK, 205218729Shselasky .endpoint = UE_ADDR_ANY, 206218729Shselasky .direction = UE_DIR_IN, 207218729Shselasky .bufsize = (MCLBYTES + 4 + ETHER_CRC_LEN), 208218729Shselasky .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 209218729Shselasky .callback = mos_bulk_read_callback, 210218729Shselasky }, 211218729Shselasky 212218729Shselasky [MOS_ENDPT_INTR] = { 213218729Shselasky .type = UE_INTERRUPT, 214218729Shselasky .endpoint = UE_ADDR_ANY, 215218729Shselasky .direction = UE_DIR_IN, 216218729Shselasky .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 217218729Shselasky .bufsize = 0, 218218729Shselasky .callback = mos_intr_callback, 219218729Shselasky }, 220218729Shselasky}; 221218729Shselasky 222218729Shselaskystatic device_method_t mos_methods[] = { 223218729Shselasky /* Device interface */ 224218729Shselasky DEVMETHOD(device_probe, mos_probe), 225218729Shselasky DEVMETHOD(device_attach, mos_attach), 226218729Shselasky DEVMETHOD(device_detach, mos_detach), 227218729Shselasky 228218729Shselasky /* MII interface */ 229218729Shselasky DEVMETHOD(miibus_readreg, mos_miibus_readreg), 230218729Shselasky DEVMETHOD(miibus_writereg, mos_miibus_writereg), 231218729Shselasky DEVMETHOD(miibus_statchg, mos_miibus_statchg), 232218729Shselasky 233227843Smarius DEVMETHOD_END 234218729Shselasky}; 235218729Shselasky 236218729Shselaskystatic driver_t mos_driver = { 237218729Shselasky .name = "mos", 238218729Shselasky .methods = mos_methods, 239218729Shselasky .size = sizeof(struct mos_softc) 240218729Shselasky}; 241218729Shselasky 242218729Shselaskystatic devclass_t mos_devclass; 243218729Shselasky 244218729ShselaskyDRIVER_MODULE(mos, uhub, mos_driver, mos_devclass, NULL, 0); 245218729ShselaskyDRIVER_MODULE(miibus, mos, miibus_driver, miibus_devclass, 0, 0); 246218729ShselaskyMODULE_DEPEND(mos, uether, 1, 1, 1); 247218729ShselaskyMODULE_DEPEND(mos, usb, 1, 1, 1); 248218729ShselaskyMODULE_DEPEND(mos, ether, 1, 1, 1); 249218729ShselaskyMODULE_DEPEND(mos, miibus, 1, 1, 1); 250218729Shselasky 251218729Shselaskystatic const struct usb_ether_methods mos_ue_methods = { 252218729Shselasky .ue_attach_post = mos_attach_post, 253218729Shselasky .ue_start = mos_start, 254218729Shselasky .ue_init = mos_init, 255218729Shselasky .ue_stop = mos_stop, 256218729Shselasky .ue_tick = mos_tick, 257218729Shselasky .ue_setmulti = mos_setmulti, 258218729Shselasky .ue_setpromisc = mos_setpromisc, 259218729Shselasky .ue_mii_upd = mos_ifmedia_upd, 260218729Shselasky .ue_mii_sts = mos_ifmedia_sts, 261218729Shselasky}; 262218729Shselasky 263218729Shselasky 264218729Shselaskystatic int 265218729Shselaskymos_reg_read_1(struct mos_softc *sc, int reg) 266218729Shselasky{ 267218729Shselasky struct usb_device_request req; 268218729Shselasky usb_error_t err; 269218729Shselasky uByte val = 0; 270218729Shselasky 271218729Shselasky req.bmRequestType = UT_READ_VENDOR_DEVICE; 272218729Shselasky req.bRequest = MOS_UR_READREG; 273218729Shselasky USETW(req.wValue, 0); 274218729Shselasky USETW(req.wIndex, reg); 275218729Shselasky USETW(req.wLength, 1); 276218729Shselasky 277218729Shselasky err = uether_do_request(&sc->sc_ue, &req, &val, 1000); 278218729Shselasky 279218729Shselasky if (err) { 280218729Shselasky MOS_DPRINTFN("mos_reg_read_1 error, reg: %d\n", reg); 281218729Shselasky return (-1); 282218729Shselasky } 283218729Shselasky return (val); 284218729Shselasky} 285218729Shselasky 286218729Shselaskystatic int 287218729Shselaskymos_reg_read_2(struct mos_softc *sc, int reg) 288218729Shselasky{ 289218729Shselasky struct usb_device_request req; 290218729Shselasky usb_error_t err; 291218729Shselasky uWord val; 292218729Shselasky 293218729Shselasky USETW(val, 0); 294218729Shselasky 295218729Shselasky req.bmRequestType = UT_READ_VENDOR_DEVICE; 296218729Shselasky req.bRequest = MOS_UR_READREG; 297218729Shselasky USETW(req.wValue, 0); 298218729Shselasky USETW(req.wIndex, reg); 299218729Shselasky USETW(req.wLength, 2); 300218729Shselasky 301218729Shselasky err = uether_do_request(&sc->sc_ue, &req, &val, 1000); 302218729Shselasky 303218729Shselasky if (err) { 304218729Shselasky MOS_DPRINTFN("mos_reg_read_2 error, reg: %d", reg); 305218729Shselasky return (-1); 306218729Shselasky } 307218729Shselasky return (UGETW(val)); 308218729Shselasky} 309218729Shselasky 310218729Shselaskystatic int 311218729Shselaskymos_reg_write_1(struct mos_softc *sc, int reg, int aval) 312218729Shselasky{ 313218729Shselasky struct usb_device_request req; 314218729Shselasky usb_error_t err; 315218729Shselasky uByte val; 316218729Shselasky val = aval; 317218729Shselasky 318218729Shselasky req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 319218729Shselasky req.bRequest = MOS_UR_WRITEREG; 320218729Shselasky USETW(req.wValue, 0); 321218729Shselasky USETW(req.wIndex, reg); 322218729Shselasky USETW(req.wLength, 1); 323218729Shselasky 324218729Shselasky err = uether_do_request(&sc->sc_ue, &req, &val, 1000); 325218729Shselasky 326218729Shselasky if (err) { 327218729Shselasky MOS_DPRINTFN("mos_reg_write_1 error, reg: %d", reg); 328218729Shselasky return (-1); 329218729Shselasky } 330218729Shselasky return (0); 331218729Shselasky} 332218729Shselasky 333218729Shselaskystatic int 334218729Shselaskymos_reg_write_2(struct mos_softc *sc, int reg, int aval) 335218729Shselasky{ 336218729Shselasky struct usb_device_request req; 337218729Shselasky usb_error_t err; 338218729Shselasky uWord val; 339218729Shselasky 340218729Shselasky USETW(val, aval); 341218729Shselasky 342218729Shselasky req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 343218729Shselasky req.bRequest = MOS_UR_WRITEREG; 344218729Shselasky USETW(req.wValue, 0); 345218729Shselasky USETW(req.wIndex, reg); 346218729Shselasky USETW(req.wLength, 2); 347218729Shselasky 348218729Shselasky err = uether_do_request(&sc->sc_ue, &req, &val, 1000); 349218729Shselasky 350218729Shselasky if (err) { 351218729Shselasky MOS_DPRINTFN("mos_reg_write_2 error, reg: %d", reg); 352218729Shselasky return (-1); 353218729Shselasky } 354218729Shselasky return (0); 355218729Shselasky} 356218729Shselasky 357218729Shselaskystatic int 358218729Shselaskymos_readmac(struct mos_softc *sc, u_char *mac) 359218729Shselasky{ 360218729Shselasky struct usb_device_request req; 361218729Shselasky usb_error_t err; 362218729Shselasky 363218729Shselasky req.bmRequestType = UT_READ_VENDOR_DEVICE; 364218729Shselasky req.bRequest = MOS_UR_READREG; 365218729Shselasky USETW(req.wValue, 0); 366218729Shselasky USETW(req.wIndex, MOS_MAC); 367218729Shselasky USETW(req.wLength, ETHER_ADDR_LEN); 368218729Shselasky 369218729Shselasky err = uether_do_request(&sc->sc_ue, &req, mac, 1000); 370218729Shselasky 371218729Shselasky if (err) { 372218729Shselasky return (-1); 373218729Shselasky } 374218729Shselasky return (0); 375218729Shselasky} 376218729Shselasky 377218729Shselaskystatic int 378218729Shselaskymos_writemac(struct mos_softc *sc, uint8_t *mac) 379218729Shselasky{ 380218729Shselasky struct usb_device_request req; 381218729Shselasky usb_error_t err; 382218729Shselasky 383218729Shselasky req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 384218729Shselasky req.bRequest = MOS_UR_WRITEREG; 385218729Shselasky USETW(req.wValue, 0); 386218729Shselasky USETW(req.wIndex, MOS_MAC); 387218729Shselasky USETW(req.wLength, ETHER_ADDR_LEN); 388218729Shselasky 389218729Shselasky err = uether_do_request(&sc->sc_ue, &req, mac, 1000); 390218729Shselasky 391218729Shselasky if (err) { 392218729Shselasky MOS_DPRINTFN("mos_writemac error"); 393218729Shselasky return (-1); 394218729Shselasky } 395218729Shselasky return (0); 396218729Shselasky} 397218729Shselasky 398218729Shselaskystatic int 399218729Shselaskymos_write_mcast(struct mos_softc *sc, u_char *hashtbl) 400218729Shselasky{ 401218729Shselasky struct usb_device_request req; 402218729Shselasky usb_error_t err; 403218729Shselasky 404218729Shselasky req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 405218729Shselasky req.bRequest = MOS_UR_WRITEREG; 406218729Shselasky USETW(req.wValue, 0); 407218729Shselasky USETW(req.wIndex, MOS_MCAST_TABLE); 408218729Shselasky USETW(req.wLength, 8); 409218729Shselasky 410218729Shselasky err = uether_do_request(&sc->sc_ue, &req, hashtbl, 1000); 411218729Shselasky 412218729Shselasky if (err) { 413218729Shselasky MOS_DPRINTFN("mos_reg_mcast error"); 414218729Shselasky return (-1); 415218729Shselasky } 416218729Shselasky return (0); 417218729Shselasky} 418218729Shselasky 419218729Shselaskystatic int 420218729Shselaskymos_miibus_readreg(struct device *dev, int phy, int reg) 421218729Shselasky{ 422218729Shselasky struct mos_softc *sc = device_get_softc(dev); 423218729Shselasky uWord val; 424218729Shselasky int i, res, locked; 425218729Shselasky 426218729Shselasky USETW(val, 0); 427218729Shselasky 428218729Shselasky locked = mtx_owned(&sc->sc_mtx); 429218729Shselasky if (!locked) 430218729Shselasky MOS_LOCK(sc); 431218729Shselasky 432218729Shselasky mos_reg_write_2(sc, MOS_PHY_DATA, 0); 433218729Shselasky mos_reg_write_1(sc, MOS_PHY_CTL, (phy & MOS_PHYCTL_PHYADDR) | 434218729Shselasky MOS_PHYCTL_READ); 435218729Shselasky mos_reg_write_1(sc, MOS_PHY_STS, (reg & MOS_PHYSTS_PHYREG) | 436218729Shselasky MOS_PHYSTS_PENDING); 437218729Shselasky 438218729Shselasky for (i = 0; i < MOS_TIMEOUT; i++) { 439218729Shselasky if (mos_reg_read_1(sc, MOS_PHY_STS) & MOS_PHYSTS_READY) 440218729Shselasky break; 441218729Shselasky } 442218729Shselasky if (i == MOS_TIMEOUT) { 443218729Shselasky MOS_DPRINTFN("MII read timeout"); 444218729Shselasky } 445218729Shselasky res = mos_reg_read_2(sc, MOS_PHY_DATA); 446218729Shselasky 447218729Shselasky if (!locked) 448218729Shselasky MOS_UNLOCK(sc); 449218729Shselasky return (res); 450218729Shselasky} 451218729Shselasky 452218729Shselaskystatic int 453218729Shselaskymos_miibus_writereg(device_t dev, int phy, int reg, int val) 454218729Shselasky{ 455218729Shselasky struct mos_softc *sc = device_get_softc(dev); 456218729Shselasky int i, locked; 457218729Shselasky 458218729Shselasky locked = mtx_owned(&sc->sc_mtx); 459218729Shselasky if (!locked) 460218729Shselasky MOS_LOCK(sc); 461218729Shselasky 462218729Shselasky mos_reg_write_2(sc, MOS_PHY_DATA, val); 463218729Shselasky mos_reg_write_1(sc, MOS_PHY_CTL, (phy & MOS_PHYCTL_PHYADDR) | 464218729Shselasky MOS_PHYCTL_WRITE); 465218729Shselasky mos_reg_write_1(sc, MOS_PHY_STS, (reg & MOS_PHYSTS_PHYREG) | 466218729Shselasky MOS_PHYSTS_PENDING); 467218729Shselasky 468218729Shselasky for (i = 0; i < MOS_TIMEOUT; i++) { 469218729Shselasky if (mos_reg_read_1(sc, MOS_PHY_STS) & MOS_PHYSTS_READY) 470218729Shselasky break; 471218729Shselasky } 472218729Shselasky if (i == MOS_TIMEOUT) 473218729Shselasky MOS_DPRINTFN("MII write timeout"); 474218729Shselasky 475218729Shselasky if (!locked) 476218729Shselasky MOS_UNLOCK(sc); 477218729Shselasky return 0; 478218729Shselasky} 479218729Shselasky 480218729Shselaskystatic void 481218729Shselaskymos_miibus_statchg(device_t dev) 482218729Shselasky{ 483218729Shselasky struct mos_softc *sc = device_get_softc(dev); 484218729Shselasky struct mii_data *mii = GET_MII(sc); 485218729Shselasky int val, err, locked; 486218729Shselasky 487218729Shselasky locked = mtx_owned(&sc->sc_mtx); 488218729Shselasky if (!locked) 489218729Shselasky MOS_LOCK(sc); 490218729Shselasky 491218729Shselasky /* disable RX, TX prior to changing FDX, SPEEDSEL */ 492218729Shselasky val = mos_reg_read_1(sc, MOS_CTL); 493218729Shselasky val &= ~(MOS_CTL_TX_ENB | MOS_CTL_RX_ENB); 494218729Shselasky mos_reg_write_1(sc, MOS_CTL, val); 495218729Shselasky 496218729Shselasky /* reset register which counts dropped frames */ 497218729Shselasky mos_reg_write_1(sc, MOS_FRAME_DROP_CNT, 0); 498218729Shselasky 499218729Shselasky if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) 500218729Shselasky val |= MOS_CTL_FDX_ENB; 501218729Shselasky else 502218729Shselasky val &= ~(MOS_CTL_FDX_ENB); 503218729Shselasky 504218729Shselasky switch (IFM_SUBTYPE(mii->mii_media_active)) { 505218729Shselasky case IFM_100_TX: 506218729Shselasky val |= MOS_CTL_SPEEDSEL; 507218729Shselasky break; 508218729Shselasky case IFM_10_T: 509218729Shselasky val &= ~(MOS_CTL_SPEEDSEL); 510218729Shselasky break; 511218729Shselasky } 512218729Shselasky 513218729Shselasky /* re-enable TX, RX */ 514218729Shselasky val |= (MOS_CTL_TX_ENB | MOS_CTL_RX_ENB); 515218729Shselasky err = mos_reg_write_1(sc, MOS_CTL, val); 516218729Shselasky 517218729Shselasky if (err) 518218729Shselasky MOS_DPRINTFN("media change failed"); 519218729Shselasky 520218729Shselasky if (!locked) 521218729Shselasky MOS_UNLOCK(sc); 522218729Shselasky} 523218729Shselasky 524218729Shselasky/* 525218729Shselasky * Set media options. 526218729Shselasky */ 527218729Shselaskystatic int 528218729Shselaskymos_ifmedia_upd(struct ifnet *ifp) 529218729Shselasky{ 530218729Shselasky struct mos_softc *sc = ifp->if_softc; 531218729Shselasky struct mii_data *mii = GET_MII(sc); 532218729Shselasky struct mii_softc *miisc; 533251734Skevlo int error; 534218729Shselasky 535218729Shselasky MOS_LOCK_ASSERT(sc, MA_OWNED); 536218729Shselasky 537218729Shselasky sc->mos_link = 0; 538251734Skevlo LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 539251734Skevlo PHY_RESET(miisc); 540251734Skevlo error = mii_mediachg(mii); 541251734Skevlo return (error); 542218729Shselasky} 543218729Shselasky 544218729Shselasky/* 545218729Shselasky * Report current media status. 546218729Shselasky */ 547218729Shselaskystatic void 548218729Shselaskymos_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 549218729Shselasky{ 550218729Shselasky struct mos_softc *sc = ifp->if_softc; 551218729Shselasky struct mii_data *mii = GET_MII(sc); 552218729Shselasky 553218729Shselasky MOS_LOCK(sc); 554218729Shselasky mii_pollstat(mii); 555218729Shselasky 556218729Shselasky ifmr->ifm_active = mii->mii_media_active; 557218729Shselasky ifmr->ifm_status = mii->mii_media_status; 558226479Syongari MOS_UNLOCK(sc); 559218729Shselasky} 560218729Shselasky 561218729Shselaskystatic void 562218729Shselaskymos_setpromisc(struct usb_ether *ue) 563218729Shselasky{ 564218729Shselasky struct mos_softc *sc = uether_getsc(ue); 565218729Shselasky struct ifnet *ifp = uether_getifp(ue); 566218729Shselasky 567218729Shselasky uint8_t rxmode; 568218729Shselasky 569218729Shselasky MOS_LOCK_ASSERT(sc, MA_OWNED); 570218729Shselasky 571218729Shselasky rxmode = mos_reg_read_1(sc, MOS_CTL); 572218729Shselasky 573218729Shselasky /* If we want promiscuous mode, set the allframes bit. */ 574218729Shselasky if (ifp->if_flags & IFF_PROMISC) { 575218729Shselasky rxmode |= MOS_CTL_RX_PROMISC; 576218729Shselasky } else { 577218729Shselasky rxmode &= ~MOS_CTL_RX_PROMISC; 578218729Shselasky } 579218729Shselasky 580218729Shselasky mos_reg_write_1(sc, MOS_CTL, rxmode); 581218729Shselasky} 582218729Shselasky 583218729Shselasky 584218729Shselasky 585218729Shselaskystatic void 586218729Shselaskymos_setmulti(struct usb_ether *ue) 587218729Shselasky{ 588218729Shselasky struct mos_softc *sc = uether_getsc(ue); 589218729Shselasky struct ifnet *ifp = uether_getifp(ue); 590218729Shselasky struct ifmultiaddr *ifma; 591218729Shselasky 592218729Shselasky uint32_t h = 0; 593218729Shselasky uint8_t rxmode; 594218729Shselasky uint8_t hashtbl[8] = {0, 0, 0, 0, 0, 0, 0, 0}; 595218729Shselasky int allmulti = 0; 596218729Shselasky 597218729Shselasky MOS_LOCK_ASSERT(sc, MA_OWNED); 598218729Shselasky 599218729Shselasky rxmode = mos_reg_read_1(sc, MOS_CTL); 600218729Shselasky 601218729Shselasky if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) 602218729Shselasky allmulti = 1; 603218729Shselasky 604218729Shselasky /* get all new ones */ 605218729Shselasky if_maddr_rlock(ifp); 606218729Shselasky TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 607218729Shselasky if (ifma->ifma_addr->sa_family != AF_LINK) { 608218729Shselasky allmulti = 1; 609218729Shselasky continue; 610218729Shselasky }; 611218729Shselasky h = ether_crc32_be(LLADDR((struct sockaddr_dl *) 612218729Shselasky ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; 613218729Shselasky hashtbl[h / 8] |= 1 << (h % 8); 614218729Shselasky } 615218729Shselasky if_maddr_runlock(ifp); 616218729Shselasky 617218729Shselasky /* now program new ones */ 618218729Shselasky if (allmulti == 1) { 619218729Shselasky rxmode |= MOS_CTL_ALLMULTI; 620218729Shselasky mos_reg_write_1(sc, MOS_CTL, rxmode); 621218729Shselasky } else { 622218729Shselasky rxmode &= ~MOS_CTL_ALLMULTI; 623218729Shselasky mos_write_mcast(sc, (void *)&hashtbl); 624218729Shselasky mos_reg_write_1(sc, MOS_CTL, rxmode); 625218729Shselasky } 626218729Shselasky} 627218729Shselasky 628218729Shselaskystatic void 629218729Shselaskymos_reset(struct mos_softc *sc) 630218729Shselasky{ 631218729Shselasky uint8_t ctl; 632218729Shselasky 633218729Shselasky ctl = mos_reg_read_1(sc, MOS_CTL); 634218729Shselasky ctl &= ~(MOS_CTL_RX_PROMISC | MOS_CTL_ALLMULTI | MOS_CTL_TX_ENB | 635218729Shselasky MOS_CTL_RX_ENB); 636218729Shselasky /* Disable RX, TX, promiscuous and allmulticast mode */ 637218729Shselasky mos_reg_write_1(sc, MOS_CTL, ctl); 638218729Shselasky 639218729Shselasky /* Reset frame drop counter register to zero */ 640218729Shselasky mos_reg_write_1(sc, MOS_FRAME_DROP_CNT, 0); 641218729Shselasky 642218729Shselasky /* Wait a little while for the chip to get its brains in order. */ 643218729Shselasky usb_pause_mtx(&sc->sc_mtx, hz / 128); 644218729Shselasky return; 645218729Shselasky} 646218729Shselasky 647218729Shselaskystatic void 648218729Shselaskymos_chip_init(struct mos_softc *sc) 649218729Shselasky{ 650218729Shselasky int i; 651218729Shselasky 652218729Shselasky /* 653218729Shselasky * Rev.C devices have a pause threshold register which needs to be set 654218729Shselasky * at startup. 655218729Shselasky */ 656218729Shselasky if (mos_reg_read_1(sc, MOS_PAUSE_TRHD) != -1) { 657218729Shselasky for (i = 0; i < MOS_PAUSE_REWRITES; i++) 658218729Shselasky mos_reg_write_1(sc, MOS_PAUSE_TRHD, 0); 659218729Shselasky } 660218729Shselasky sc->mos_phyaddrs[0] = 1; 661218729Shselasky sc->mos_phyaddrs[1] = 0xFF; 662218729Shselasky} 663218729Shselasky 664218729Shselasky/* 665218729Shselasky * Probe for a MCS7x30 chip. 666218729Shselasky */ 667218729Shselaskystatic int 668218729Shselaskymos_probe(device_t dev) 669218729Shselasky{ 670218729Shselasky struct usb_attach_arg *uaa = device_get_ivars(dev); 671218729Shselasky int retval; 672218729Shselasky 673218729Shselasky if (uaa->usb_mode != USB_MODE_HOST) 674218729Shselasky return (ENXIO); 675218729Shselasky if (uaa->info.bConfigIndex != MOS_CONFIG_IDX) 676218729Shselasky return (ENXIO); 677218729Shselasky if (uaa->info.bIfaceIndex != MOS_IFACE_IDX) 678218729Shselasky return (ENXIO); 679218729Shselasky 680218729Shselasky retval = usbd_lookup_id_by_uaa(mos_devs, sizeof(mos_devs), uaa); 681218729Shselasky return (retval); 682218729Shselasky} 683218729Shselasky 684218729Shselasky/* 685218729Shselasky * Attach the interface. Allocate softc structures, do ifmedia 686218729Shselasky * setup and ethernet/BPF attach. 687218729Shselasky */ 688218729Shselaskystatic int 689218729Shselaskymos_attach(device_t dev) 690218729Shselasky{ 691218729Shselasky struct usb_attach_arg *uaa = device_get_ivars(dev); 692218729Shselasky struct mos_softc *sc = device_get_softc(dev); 693218729Shselasky struct usb_ether *ue = &sc->sc_ue; 694218729Shselasky uint8_t iface_index; 695218729Shselasky int error; 696218729Shselasky 697218729Shselasky sc->mos_flags = USB_GET_DRIVER_INFO(uaa); 698218729Shselasky 699218729Shselasky device_set_usb_desc(dev); 700218729Shselasky mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 701218729Shselasky 702218729Shselasky iface_index = MOS_IFACE_IDX; 703218729Shselasky error = usbd_transfer_setup(uaa->device, &iface_index, 704218729Shselasky sc->sc_xfer, mos_config, MOS_ENDPT_MAX, 705218729Shselasky sc, &sc->sc_mtx); 706218729Shselasky 707218729Shselasky if (error) { 708218729Shselasky device_printf(dev, "allocating USB transfers failed\n"); 709218729Shselasky goto detach; 710218729Shselasky } 711218729Shselasky ue->ue_sc = sc; 712218729Shselasky ue->ue_dev = dev; 713218729Shselasky ue->ue_udev = uaa->device; 714218729Shselasky ue->ue_mtx = &sc->sc_mtx; 715218729Shselasky ue->ue_methods = &mos_ue_methods; 716218729Shselasky 717218729Shselasky 718218729Shselasky if (sc->mos_flags & MCS7730) { 719218729Shselasky MOS_DPRINTFN("model: MCS7730"); 720218729Shselasky } else if (sc->mos_flags & MCS7830) { 721218729Shselasky MOS_DPRINTFN("model: MCS7830"); 722232257Skevlo } else if (sc->mos_flags & MCS7832) { 723232257Skevlo MOS_DPRINTFN("model: MCS7832"); 724218729Shselasky } 725218729Shselasky error = uether_ifattach(ue); 726218729Shselasky if (error) { 727218729Shselasky device_printf(dev, "could not attach interface\n"); 728218729Shselasky goto detach; 729218729Shselasky } 730218729Shselasky return (0); 731218729Shselasky 732218729Shselasky 733218729Shselaskydetach: 734218729Shselasky mos_detach(dev); 735218729Shselasky return (ENXIO); 736218729Shselasky} 737218729Shselasky 738218729Shselasky 739218729Shselaskystatic void 740218729Shselaskymos_attach_post(struct usb_ether *ue) 741218729Shselasky{ 742218729Shselasky struct mos_softc *sc = uether_getsc(ue); 743218729Shselasky int err; 744218729Shselasky 745218729Shselasky /* Read MAC address, inform the world. */ 746218729Shselasky err = mos_readmac(sc, ue->ue_eaddr); 747218729Shselasky 748218729Shselasky if (err) 749218729Shselasky MOS_DPRINTFN("couldn't get MAC address"); 750218729Shselasky 751218729Shselasky MOS_DPRINTFN("address: %s", ether_sprintf(ue->ue_eaddr)); 752218729Shselasky 753218729Shselasky mos_chip_init(sc); 754218729Shselasky} 755218729Shselasky 756218729Shselaskystatic int 757218729Shselaskymos_detach(device_t dev) 758218729Shselasky{ 759218729Shselasky struct mos_softc *sc = device_get_softc(dev); 760218729Shselasky struct usb_ether *ue = &sc->sc_ue; 761218729Shselasky 762218729Shselasky usbd_transfer_unsetup(sc->sc_xfer, MOS_ENDPT_MAX); 763218729Shselasky uether_ifdetach(ue); 764218729Shselasky mtx_destroy(&sc->sc_mtx); 765218729Shselasky 766218729Shselasky return (0); 767218729Shselasky} 768218729Shselasky 769218729Shselasky 770218729Shselasky 771218729Shselasky 772218729Shselasky/* 773218729Shselasky * A frame has been uploaded: pass the resulting mbuf chain up to 774218729Shselasky * the higher level protocols. 775218729Shselasky */ 776218729Shselaskystatic void 777218729Shselaskymos_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) 778218729Shselasky{ 779218729Shselasky struct mos_softc *sc = usbd_xfer_softc(xfer); 780218729Shselasky struct usb_ether *ue = &sc->sc_ue; 781218729Shselasky struct ifnet *ifp = uether_getifp(ue); 782218729Shselasky 783218729Shselasky uint8_t rxstat = 0; 784218729Shselasky uint32_t actlen; 785218729Shselasky uint16_t pktlen = 0; 786218729Shselasky struct usb_page_cache *pc; 787218729Shselasky 788218729Shselasky usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 789218729Shselasky pc = usbd_xfer_get_frame(xfer, 0); 790218729Shselasky 791218729Shselasky switch (USB_GET_STATE(xfer)) { 792218729Shselasky case USB_ST_TRANSFERRED: 793218729Shselasky MOS_DPRINTFN("actlen : %d", actlen); 794218729Shselasky if (actlen <= 1) { 795271832Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 796218729Shselasky goto tr_setup; 797218729Shselasky } 798218729Shselasky /* evaluate status byte at the end */ 799218729Shselasky usbd_copy_out(pc, actlen - sizeof(rxstat), &rxstat, 800218729Shselasky sizeof(rxstat)); 801218729Shselasky 802218729Shselasky if (rxstat != MOS_RXSTS_VALID) { 803218729Shselasky MOS_DPRINTFN("erroneous frame received"); 804218729Shselasky if (rxstat & MOS_RXSTS_SHORT_FRAME) 805218729Shselasky MOS_DPRINTFN("frame size less than 64 bytes"); 806218765Shselasky if (rxstat & MOS_RXSTS_LARGE_FRAME) { 807218765Shselasky MOS_DPRINTFN("frame size larger than " 808218765Shselasky "1532 bytes"); 809218765Shselasky } 810218729Shselasky if (rxstat & MOS_RXSTS_CRC_ERROR) 811218729Shselasky MOS_DPRINTFN("CRC error"); 812218729Shselasky if (rxstat & MOS_RXSTS_ALIGN_ERROR) 813218729Shselasky MOS_DPRINTFN("alignment error"); 814271832Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 815218729Shselasky goto tr_setup; 816218729Shselasky } 817218729Shselasky /* Remember the last byte was used for the status fields */ 818218729Shselasky pktlen = actlen - 1; 819218729Shselasky if (pktlen < sizeof(struct ether_header)) { 820218765Shselasky MOS_DPRINTFN("error: pktlen %d is smaller " 821218765Shselasky "than ether_header %zd", pktlen, 822218765Shselasky sizeof(struct ether_header)); 823271832Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 824218729Shselasky goto tr_setup; 825218729Shselasky } 826218729Shselasky uether_rxbuf(ue, pc, 0, actlen); 827218729Shselasky /* FALLTHROUGH */ 828218729Shselasky case USB_ST_SETUP: 829218729Shselaskytr_setup: 830218729Shselasky usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 831218729Shselasky usbd_transfer_submit(xfer); 832218729Shselasky uether_rxflush(ue); 833218729Shselasky return; 834218729Shselasky default: 835218729Shselasky MOS_DPRINTFN("bulk read error, %s", usbd_errstr(error)); 836218729Shselasky if (error != USB_ERR_CANCELLED) { 837218729Shselasky usbd_xfer_set_stall(xfer); 838218729Shselasky goto tr_setup; 839218729Shselasky } 840218729Shselasky MOS_DPRINTFN("start rx %i", usbd_xfer_max_len(xfer)); 841218729Shselasky return; 842218729Shselasky } 843218729Shselasky} 844218729Shselasky 845218729Shselasky/* 846218729Shselasky * A frame was downloaded to the chip. It's safe for us to clean up 847218729Shselasky * the list buffers. 848218729Shselasky */ 849218729Shselaskystatic void 850218729Shselaskymos_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) 851218729Shselasky{ 852218729Shselasky struct mos_softc *sc = usbd_xfer_softc(xfer); 853218729Shselasky struct ifnet *ifp = uether_getifp(&sc->sc_ue); 854218729Shselasky struct usb_page_cache *pc; 855218729Shselasky struct mbuf *m; 856218729Shselasky 857218729Shselasky 858218729Shselasky 859218729Shselasky switch (USB_GET_STATE(xfer)) { 860218729Shselasky case USB_ST_TRANSFERRED: 861218729Shselasky MOS_DPRINTFN("transfer of complete"); 862271832Sglebius if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 863218729Shselasky /* FALLTHROUGH */ 864218729Shselasky case USB_ST_SETUP: 865218729Shselaskytr_setup: 866218729Shselasky /* 867218729Shselasky * XXX: don't send anything if there is no link? 868218729Shselasky */ 869218729Shselasky IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 870218729Shselasky if (m == NULL) 871218729Shselasky return; 872218729Shselasky 873218729Shselasky pc = usbd_xfer_get_frame(xfer, 0); 874218729Shselasky usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len); 875218729Shselasky 876218729Shselasky usbd_xfer_set_frame_len(xfer, 0, m->m_pkthdr.len); 877218729Shselasky 878218729Shselasky 879218729Shselasky /* 880218729Shselasky * if there's a BPF listener, bounce a copy 881218729Shselasky * of this frame to him: 882218729Shselasky */ 883218729Shselasky BPF_MTAP(ifp, m); 884218729Shselasky 885218729Shselasky m_freem(m); 886218729Shselasky 887218729Shselasky usbd_transfer_submit(xfer); 888218729Shselasky 889271832Sglebius if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 890218729Shselasky return; 891218729Shselasky default: 892218729Shselasky MOS_DPRINTFN("usb error on tx: %s\n", usbd_errstr(error)); 893271832Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 894218729Shselasky if (error != USB_ERR_CANCELLED) { 895218729Shselasky usbd_xfer_set_stall(xfer); 896218729Shselasky goto tr_setup; 897218729Shselasky } 898218729Shselasky return; 899218729Shselasky } 900218729Shselasky} 901218729Shselasky 902218729Shselaskystatic void 903218729Shselaskymos_tick(struct usb_ether *ue) 904218729Shselasky{ 905218729Shselasky struct mos_softc *sc = uether_getsc(ue); 906218729Shselasky struct mii_data *mii = GET_MII(sc); 907218729Shselasky 908218729Shselasky MOS_LOCK_ASSERT(sc, MA_OWNED); 909218729Shselasky 910218729Shselasky mii_tick(mii); 911218729Shselasky if (!sc->mos_link && mii->mii_media_status & IFM_ACTIVE && 912218729Shselasky IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 913218729Shselasky MOS_DPRINTFN("got link"); 914218729Shselasky sc->mos_link++; 915218729Shselasky mos_start(ue); 916218729Shselasky } 917218729Shselasky} 918218729Shselasky 919218729Shselasky 920218729Shselaskystatic void 921218729Shselaskymos_start(struct usb_ether *ue) 922218729Shselasky{ 923218729Shselasky struct mos_softc *sc = uether_getsc(ue); 924218729Shselasky 925218729Shselasky /* 926218729Shselasky * start the USB transfers, if not already started: 927218729Shselasky */ 928218729Shselasky usbd_transfer_start(sc->sc_xfer[MOS_ENDPT_TX]); 929218729Shselasky usbd_transfer_start(sc->sc_xfer[MOS_ENDPT_RX]); 930218729Shselasky usbd_transfer_start(sc->sc_xfer[MOS_ENDPT_INTR]); 931218729Shselasky} 932218729Shselasky 933218729Shselaskystatic void 934218729Shselaskymos_init(struct usb_ether *ue) 935218729Shselasky{ 936218729Shselasky struct mos_softc *sc = uether_getsc(ue); 937218729Shselasky struct ifnet *ifp = uether_getifp(ue); 938218729Shselasky uint8_t rxmode; 939218729Shselasky 940218729Shselasky MOS_LOCK_ASSERT(sc, MA_OWNED); 941218729Shselasky 942218729Shselasky /* Cancel pending I/O and free all RX/TX buffers. */ 943218729Shselasky mos_reset(sc); 944218729Shselasky 945218729Shselasky /* Write MAC address */ 946218729Shselasky mos_writemac(sc, IF_LLADDR(ifp)); 947218729Shselasky 948218729Shselasky /* Read and set transmitter IPG values */ 949218729Shselasky sc->mos_ipgs[0] = mos_reg_read_1(sc, MOS_IPG0); 950218729Shselasky sc->mos_ipgs[1] = mos_reg_read_1(sc, MOS_IPG1); 951218729Shselasky mos_reg_write_1(sc, MOS_IPG0, sc->mos_ipgs[0]); 952218729Shselasky mos_reg_write_1(sc, MOS_IPG1, sc->mos_ipgs[1]); 953218729Shselasky 954218729Shselasky /* 955218729Shselasky * Enable receiver and transmitter, bridge controls speed/duplex 956218729Shselasky * mode 957218729Shselasky */ 958218729Shselasky rxmode = mos_reg_read_1(sc, MOS_CTL); 959218729Shselasky rxmode |= MOS_CTL_RX_ENB | MOS_CTL_TX_ENB | MOS_CTL_BS_ENB; 960218729Shselasky rxmode &= ~(MOS_CTL_SLEEP); 961218729Shselasky 962218729Shselasky mos_setpromisc(ue); 963218729Shselasky 964218729Shselasky /* XXX: broadcast mode? */ 965218729Shselasky mos_reg_write_1(sc, MOS_CTL, rxmode); 966218729Shselasky 967218729Shselasky /* Load the multicast filter. */ 968218729Shselasky mos_setmulti(ue); 969218729Shselasky 970218729Shselasky ifp->if_drv_flags |= IFF_DRV_RUNNING; 971218729Shselasky mos_start(ue); 972218729Shselasky} 973218729Shselasky 974218729Shselasky 975218729Shselaskystatic void 976218729Shselaskymos_intr_callback(struct usb_xfer *xfer, usb_error_t error) 977218729Shselasky{ 978218729Shselasky struct mos_softc *sc = usbd_xfer_softc(xfer); 979218729Shselasky struct ifnet *ifp = uether_getifp(&sc->sc_ue); 980218729Shselasky struct usb_page_cache *pc; 981218729Shselasky uint32_t pkt; 982218729Shselasky int actlen; 983218729Shselasky 984271832Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 985218729Shselasky 986218729Shselasky usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 987218729Shselasky MOS_DPRINTFN("actlen %i", actlen); 988218729Shselasky 989218729Shselasky switch (USB_GET_STATE(xfer)) { 990218729Shselasky case USB_ST_TRANSFERRED: 991218729Shselasky 992218729Shselasky pc = usbd_xfer_get_frame(xfer, 0); 993218729Shselasky usbd_copy_out(pc, 0, &pkt, sizeof(pkt)); 994218729Shselasky /* FALLTHROUGH */ 995218729Shselasky case USB_ST_SETUP: 996218729Shselaskytr_setup: 997218729Shselasky return; 998218729Shselasky default: 999218729Shselasky if (error != USB_ERR_CANCELLED) { 1000218729Shselasky usbd_xfer_set_stall(xfer); 1001218729Shselasky goto tr_setup; 1002218729Shselasky } 1003218729Shselasky return; 1004218729Shselasky } 1005218729Shselasky} 1006218729Shselasky 1007218729Shselasky 1008218729Shselasky/* 1009218729Shselasky * Stop the adapter and free any mbufs allocated to the 1010218729Shselasky * RX and TX lists. 1011218729Shselasky */ 1012218729Shselaskystatic void 1013218729Shselaskymos_stop(struct usb_ether *ue) 1014218729Shselasky{ 1015218729Shselasky struct mos_softc *sc = uether_getsc(ue); 1016218729Shselasky struct ifnet *ifp = uether_getifp(ue); 1017218729Shselasky 1018218729Shselasky mos_reset(sc); 1019218729Shselasky 1020218729Shselasky MOS_LOCK_ASSERT(sc, MA_OWNED); 1021218729Shselasky ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1022218729Shselasky 1023218729Shselasky /* stop all the transfers, if not already stopped */ 1024218729Shselasky usbd_transfer_stop(sc->sc_xfer[MOS_ENDPT_TX]); 1025218729Shselasky usbd_transfer_stop(sc->sc_xfer[MOS_ENDPT_RX]); 1026218729Shselasky usbd_transfer_stop(sc->sc_xfer[MOS_ENDPT_INTR]); 1027218729Shselasky 1028218729Shselasky sc->mos_link = 0; 1029218729Shselasky} 1030