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$"); 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> 105218729Shselasky#include <sys/kernel.h> 106218729Shselasky#include <sys/bus.h> 107218729Shselasky#include <sys/module.h> 108218729Shselasky#include <sys/lock.h> 109218729Shselasky#include <sys/mutex.h> 110218729Shselasky#include <sys/condvar.h> 111218729Shselasky#include <sys/sysctl.h> 112218729Shselasky#include <sys/sx.h> 113218729Shselasky#include <sys/unistd.h> 114218729Shselasky#include <sys/callout.h> 115218729Shselasky#include <sys/malloc.h> 116218729Shselasky#include <sys/priv.h> 117218729Shselasky 118218729Shselasky#include <dev/usb/usb.h> 119218729Shselasky#include <dev/usb/usbdi.h> 120218729Shselasky#include <dev/usb/usbdi_util.h> 121218729Shselasky#include "usbdevs.h" 122218729Shselasky 123218729Shselasky#define USB_DEBUG_VAR mos_debug 124218729Shselasky#include <dev/usb/usb_debug.h> 125218729Shselasky#include <dev/usb/usb_process.h> 126218729Shselasky 127218729Shselasky#include <dev/usb/net/usb_ethernet.h> 128218729Shselasky 129218729Shselasky//#include <dev/usb/net/if_mosreg.h> 130218729Shselasky#include "if_mosreg.h" 131218729Shselasky 132218729Shselasky#ifdef USB_DEBUG 133218729Shselaskystatic int mos_debug = 0; 134218729Shselasky 135227309Sedstatic SYSCTL_NODE(_hw_usb, OID_AUTO, mos, CTLFLAG_RW, 0, "USB mos"); 136218729ShselaskySYSCTL_INT(_hw_usb_mos, OID_AUTO, debug, CTLFLAG_RW, &mos_debug, 0, 137218729Shselasky "Debug level"); 138218729Shselasky#endif 139218729Shselasky 140218729Shselasky#define MOS_DPRINTFN(fmt,...) \ 141218729Shselasky DPRINTF("mos: %s: " fmt "\n",__FUNCTION__,## __VA_ARGS__) 142218729Shselasky 143218729Shselasky#define USB_PRODUCT_MOSCHIP_MCS7730 0x7730 144218729Shselasky#define USB_PRODUCT_SITECOMEU_LN030 0x0021 145218729Shselasky 146218729Shselasky 147218729Shselasky 148218729Shselasky/* Various supported device vendors/products. */ 149223486Shselaskystatic const STRUCT_USB_HOST_ID mos_devs[] = { 150218729Shselasky {USB_VPI(USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7730, MCS7730)}, 151218729Shselasky {USB_VPI(USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7830, MCS7830)}, 152232257Skevlo {USB_VPI(USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7832, MCS7832)}, 153218729Shselasky {USB_VPI(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_LN030, MCS7830)}, 154218729Shselasky}; 155218729Shselasky 156218729Shselaskystatic int mos_probe(device_t dev); 157218729Shselaskystatic int mos_attach(device_t dev); 158218729Shselaskystatic void mos_attach_post(struct usb_ether *ue); 159218729Shselaskystatic int mos_detach(device_t dev); 160218729Shselasky 161218729Shselaskystatic void mos_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error); 162218729Shselaskystatic void mos_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error); 163218729Shselaskystatic void mos_intr_callback(struct usb_xfer *xfer, usb_error_t error); 164218729Shselaskystatic void mos_tick(struct usb_ether *); 165218729Shselaskystatic void mos_start(struct usb_ether *); 166218729Shselaskystatic void mos_init(struct usb_ether *); 167218729Shselaskystatic void mos_chip_init(struct mos_softc *); 168218729Shselaskystatic void mos_stop(struct usb_ether *); 169218729Shselaskystatic int mos_miibus_readreg(device_t, int, int); 170218729Shselaskystatic int mos_miibus_writereg(device_t, int, int, int); 171218729Shselaskystatic void mos_miibus_statchg(device_t); 172218729Shselaskystatic int mos_ifmedia_upd(struct ifnet *); 173218729Shselaskystatic void mos_ifmedia_sts(struct ifnet *, struct ifmediareq *); 174218729Shselaskystatic void mos_reset(struct mos_softc *sc); 175218729Shselasky 176218729Shselaskystatic int mos_reg_read_1(struct mos_softc *, int); 177218729Shselaskystatic int mos_reg_read_2(struct mos_softc *, int); 178218729Shselaskystatic int mos_reg_write_1(struct mos_softc *, int, int); 179218729Shselaskystatic int mos_reg_write_2(struct mos_softc *, int, int); 180218729Shselaskystatic int mos_readmac(struct mos_softc *, uint8_t *); 181218729Shselaskystatic int mos_writemac(struct mos_softc *, uint8_t *); 182218729Shselaskystatic int mos_write_mcast(struct mos_softc *, u_char *); 183218729Shselasky 184218729Shselaskystatic void mos_setmulti(struct usb_ether *); 185218729Shselaskystatic void mos_setpromisc(struct usb_ether *); 186218729Shselasky 187218729Shselaskystatic const struct usb_config mos_config[MOS_ENDPT_MAX] = { 188218729Shselasky 189218729Shselasky [MOS_ENDPT_TX] = { 190218729Shselasky .type = UE_BULK, 191218729Shselasky .endpoint = UE_ADDR_ANY, 192218729Shselasky .direction = UE_DIR_OUT, 193218729Shselasky .bufsize = (MCLBYTES + 2), 194218729Shselasky .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 195218729Shselasky .callback = mos_bulk_write_callback, 196218729Shselasky .timeout = 10000, 197218729Shselasky }, 198218729Shselasky 199218729Shselasky [MOS_ENDPT_RX] = { 200218729Shselasky .type = UE_BULK, 201218729Shselasky .endpoint = UE_ADDR_ANY, 202218729Shselasky .direction = UE_DIR_IN, 203218729Shselasky .bufsize = (MCLBYTES + 4 + ETHER_CRC_LEN), 204218729Shselasky .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 205218729Shselasky .callback = mos_bulk_read_callback, 206218729Shselasky }, 207218729Shselasky 208218729Shselasky [MOS_ENDPT_INTR] = { 209218729Shselasky .type = UE_INTERRUPT, 210218729Shselasky .endpoint = UE_ADDR_ANY, 211218729Shselasky .direction = UE_DIR_IN, 212218729Shselasky .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 213218729Shselasky .bufsize = 0, 214218729Shselasky .callback = mos_intr_callback, 215218729Shselasky }, 216218729Shselasky}; 217218729Shselasky 218218729Shselaskystatic device_method_t mos_methods[] = { 219218729Shselasky /* Device interface */ 220218729Shselasky DEVMETHOD(device_probe, mos_probe), 221218729Shselasky DEVMETHOD(device_attach, mos_attach), 222218729Shselasky DEVMETHOD(device_detach, mos_detach), 223218729Shselasky 224218729Shselasky /* MII interface */ 225218729Shselasky DEVMETHOD(miibus_readreg, mos_miibus_readreg), 226218729Shselasky DEVMETHOD(miibus_writereg, mos_miibus_writereg), 227218729Shselasky DEVMETHOD(miibus_statchg, mos_miibus_statchg), 228218729Shselasky 229227843Smarius DEVMETHOD_END 230218729Shselasky}; 231218729Shselasky 232218729Shselaskystatic driver_t mos_driver = { 233218729Shselasky .name = "mos", 234218729Shselasky .methods = mos_methods, 235218729Shselasky .size = sizeof(struct mos_softc) 236218729Shselasky}; 237218729Shselasky 238218729Shselaskystatic devclass_t mos_devclass; 239218729Shselasky 240218729ShselaskyDRIVER_MODULE(mos, uhub, mos_driver, mos_devclass, NULL, 0); 241218729ShselaskyDRIVER_MODULE(miibus, mos, miibus_driver, miibus_devclass, 0, 0); 242218729ShselaskyMODULE_DEPEND(mos, uether, 1, 1, 1); 243218729ShselaskyMODULE_DEPEND(mos, usb, 1, 1, 1); 244218729ShselaskyMODULE_DEPEND(mos, ether, 1, 1, 1); 245218729ShselaskyMODULE_DEPEND(mos, miibus, 1, 1, 1); 246218729Shselasky 247218729Shselaskystatic const struct usb_ether_methods mos_ue_methods = { 248218729Shselasky .ue_attach_post = mos_attach_post, 249218729Shselasky .ue_start = mos_start, 250218729Shselasky .ue_init = mos_init, 251218729Shselasky .ue_stop = mos_stop, 252218729Shselasky .ue_tick = mos_tick, 253218729Shselasky .ue_setmulti = mos_setmulti, 254218729Shselasky .ue_setpromisc = mos_setpromisc, 255218729Shselasky .ue_mii_upd = mos_ifmedia_upd, 256218729Shselasky .ue_mii_sts = mos_ifmedia_sts, 257218729Shselasky}; 258218729Shselasky 259218729Shselasky 260218729Shselaskystatic int 261218729Shselaskymos_reg_read_1(struct mos_softc *sc, int reg) 262218729Shselasky{ 263218729Shselasky struct usb_device_request req; 264218729Shselasky usb_error_t err; 265218729Shselasky uByte val = 0; 266218729Shselasky 267218729Shselasky req.bmRequestType = UT_READ_VENDOR_DEVICE; 268218729Shselasky req.bRequest = MOS_UR_READREG; 269218729Shselasky USETW(req.wValue, 0); 270218729Shselasky USETW(req.wIndex, reg); 271218729Shselasky USETW(req.wLength, 1); 272218729Shselasky 273218729Shselasky err = uether_do_request(&sc->sc_ue, &req, &val, 1000); 274218729Shselasky 275218729Shselasky if (err) { 276218729Shselasky MOS_DPRINTFN("mos_reg_read_1 error, reg: %d\n", reg); 277218729Shselasky return (-1); 278218729Shselasky } 279218729Shselasky return (val); 280218729Shselasky} 281218729Shselasky 282218729Shselaskystatic int 283218729Shselaskymos_reg_read_2(struct mos_softc *sc, int reg) 284218729Shselasky{ 285218729Shselasky struct usb_device_request req; 286218729Shselasky usb_error_t err; 287218729Shselasky uWord val; 288218729Shselasky 289218729Shselasky USETW(val, 0); 290218729Shselasky 291218729Shselasky req.bmRequestType = UT_READ_VENDOR_DEVICE; 292218729Shselasky req.bRequest = MOS_UR_READREG; 293218729Shselasky USETW(req.wValue, 0); 294218729Shselasky USETW(req.wIndex, reg); 295218729Shselasky USETW(req.wLength, 2); 296218729Shselasky 297218729Shselasky err = uether_do_request(&sc->sc_ue, &req, &val, 1000); 298218729Shselasky 299218729Shselasky if (err) { 300218729Shselasky MOS_DPRINTFN("mos_reg_read_2 error, reg: %d", reg); 301218729Shselasky return (-1); 302218729Shselasky } 303218729Shselasky return (UGETW(val)); 304218729Shselasky} 305218729Shselasky 306218729Shselaskystatic int 307218729Shselaskymos_reg_write_1(struct mos_softc *sc, int reg, int aval) 308218729Shselasky{ 309218729Shselasky struct usb_device_request req; 310218729Shselasky usb_error_t err; 311218729Shselasky uByte val; 312218729Shselasky val = aval; 313218729Shselasky 314218729Shselasky req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 315218729Shselasky req.bRequest = MOS_UR_WRITEREG; 316218729Shselasky USETW(req.wValue, 0); 317218729Shselasky USETW(req.wIndex, reg); 318218729Shselasky USETW(req.wLength, 1); 319218729Shselasky 320218729Shselasky err = uether_do_request(&sc->sc_ue, &req, &val, 1000); 321218729Shselasky 322218729Shselasky if (err) { 323218729Shselasky MOS_DPRINTFN("mos_reg_write_1 error, reg: %d", reg); 324218729Shselasky return (-1); 325218729Shselasky } 326218729Shselasky return (0); 327218729Shselasky} 328218729Shselasky 329218729Shselaskystatic int 330218729Shselaskymos_reg_write_2(struct mos_softc *sc, int reg, int aval) 331218729Shselasky{ 332218729Shselasky struct usb_device_request req; 333218729Shselasky usb_error_t err; 334218729Shselasky uWord val; 335218729Shselasky 336218729Shselasky USETW(val, aval); 337218729Shselasky 338218729Shselasky req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 339218729Shselasky req.bRequest = MOS_UR_WRITEREG; 340218729Shselasky USETW(req.wValue, 0); 341218729Shselasky USETW(req.wIndex, reg); 342218729Shselasky USETW(req.wLength, 2); 343218729Shselasky 344218729Shselasky err = uether_do_request(&sc->sc_ue, &req, &val, 1000); 345218729Shselasky 346218729Shselasky if (err) { 347218729Shselasky MOS_DPRINTFN("mos_reg_write_2 error, reg: %d", reg); 348218729Shselasky return (-1); 349218729Shselasky } 350218729Shselasky return (0); 351218729Shselasky} 352218729Shselasky 353218729Shselaskystatic int 354218729Shselaskymos_readmac(struct mos_softc *sc, u_char *mac) 355218729Shselasky{ 356218729Shselasky struct usb_device_request req; 357218729Shselasky usb_error_t err; 358218729Shselasky 359218729Shselasky req.bmRequestType = UT_READ_VENDOR_DEVICE; 360218729Shselasky req.bRequest = MOS_UR_READREG; 361218729Shselasky USETW(req.wValue, 0); 362218729Shselasky USETW(req.wIndex, MOS_MAC); 363218729Shselasky USETW(req.wLength, ETHER_ADDR_LEN); 364218729Shselasky 365218729Shselasky err = uether_do_request(&sc->sc_ue, &req, mac, 1000); 366218729Shselasky 367218729Shselasky if (err) { 368218729Shselasky return (-1); 369218729Shselasky } 370218729Shselasky return (0); 371218729Shselasky} 372218729Shselasky 373218729Shselaskystatic int 374218729Shselaskymos_writemac(struct mos_softc *sc, uint8_t *mac) 375218729Shselasky{ 376218729Shselasky struct usb_device_request req; 377218729Shselasky usb_error_t err; 378218729Shselasky 379218729Shselasky req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 380218729Shselasky req.bRequest = MOS_UR_WRITEREG; 381218729Shselasky USETW(req.wValue, 0); 382218729Shselasky USETW(req.wIndex, MOS_MAC); 383218729Shselasky USETW(req.wLength, ETHER_ADDR_LEN); 384218729Shselasky 385218729Shselasky err = uether_do_request(&sc->sc_ue, &req, mac, 1000); 386218729Shselasky 387218729Shselasky if (err) { 388218729Shselasky MOS_DPRINTFN("mos_writemac error"); 389218729Shselasky return (-1); 390218729Shselasky } 391218729Shselasky return (0); 392218729Shselasky} 393218729Shselasky 394218729Shselaskystatic int 395218729Shselaskymos_write_mcast(struct mos_softc *sc, u_char *hashtbl) 396218729Shselasky{ 397218729Shselasky struct usb_device_request req; 398218729Shselasky usb_error_t err; 399218729Shselasky 400218729Shselasky req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 401218729Shselasky req.bRequest = MOS_UR_WRITEREG; 402218729Shselasky USETW(req.wValue, 0); 403218729Shselasky USETW(req.wIndex, MOS_MCAST_TABLE); 404218729Shselasky USETW(req.wLength, 8); 405218729Shselasky 406218729Shselasky err = uether_do_request(&sc->sc_ue, &req, hashtbl, 1000); 407218729Shselasky 408218729Shselasky if (err) { 409218729Shselasky MOS_DPRINTFN("mos_reg_mcast error"); 410218729Shselasky return (-1); 411218729Shselasky } 412218729Shselasky return (0); 413218729Shselasky} 414218729Shselasky 415218729Shselaskystatic int 416218729Shselaskymos_miibus_readreg(struct device *dev, int phy, int reg) 417218729Shselasky{ 418218729Shselasky struct mos_softc *sc = device_get_softc(dev); 419218729Shselasky uWord val; 420218729Shselasky int i, res, locked; 421218729Shselasky 422218729Shselasky USETW(val, 0); 423218729Shselasky 424218729Shselasky locked = mtx_owned(&sc->sc_mtx); 425218729Shselasky if (!locked) 426218729Shselasky MOS_LOCK(sc); 427218729Shselasky 428218729Shselasky mos_reg_write_2(sc, MOS_PHY_DATA, 0); 429218729Shselasky mos_reg_write_1(sc, MOS_PHY_CTL, (phy & MOS_PHYCTL_PHYADDR) | 430218729Shselasky MOS_PHYCTL_READ); 431218729Shselasky mos_reg_write_1(sc, MOS_PHY_STS, (reg & MOS_PHYSTS_PHYREG) | 432218729Shselasky MOS_PHYSTS_PENDING); 433218729Shselasky 434218729Shselasky for (i = 0; i < MOS_TIMEOUT; i++) { 435218729Shselasky if (mos_reg_read_1(sc, MOS_PHY_STS) & MOS_PHYSTS_READY) 436218729Shselasky break; 437218729Shselasky } 438218729Shselasky if (i == MOS_TIMEOUT) { 439218729Shselasky MOS_DPRINTFN("MII read timeout"); 440218729Shselasky } 441218729Shselasky res = mos_reg_read_2(sc, MOS_PHY_DATA); 442218729Shselasky 443218729Shselasky if (!locked) 444218729Shselasky MOS_UNLOCK(sc); 445218729Shselasky return (res); 446218729Shselasky} 447218729Shselasky 448218729Shselaskystatic int 449218729Shselaskymos_miibus_writereg(device_t dev, int phy, int reg, int val) 450218729Shselasky{ 451218729Shselasky struct mos_softc *sc = device_get_softc(dev); 452218729Shselasky int i, locked; 453218729Shselasky 454218729Shselasky locked = mtx_owned(&sc->sc_mtx); 455218729Shselasky if (!locked) 456218729Shselasky MOS_LOCK(sc); 457218729Shselasky 458218729Shselasky mos_reg_write_2(sc, MOS_PHY_DATA, val); 459218729Shselasky mos_reg_write_1(sc, MOS_PHY_CTL, (phy & MOS_PHYCTL_PHYADDR) | 460218729Shselasky MOS_PHYCTL_WRITE); 461218729Shselasky mos_reg_write_1(sc, MOS_PHY_STS, (reg & MOS_PHYSTS_PHYREG) | 462218729Shselasky MOS_PHYSTS_PENDING); 463218729Shselasky 464218729Shselasky for (i = 0; i < MOS_TIMEOUT; i++) { 465218729Shselasky if (mos_reg_read_1(sc, MOS_PHY_STS) & MOS_PHYSTS_READY) 466218729Shselasky break; 467218729Shselasky } 468218729Shselasky if (i == MOS_TIMEOUT) 469218729Shselasky MOS_DPRINTFN("MII write timeout"); 470218729Shselasky 471218729Shselasky if (!locked) 472218729Shselasky MOS_UNLOCK(sc); 473218729Shselasky return 0; 474218729Shselasky} 475218729Shselasky 476218729Shselaskystatic void 477218729Shselaskymos_miibus_statchg(device_t dev) 478218729Shselasky{ 479218729Shselasky struct mos_softc *sc = device_get_softc(dev); 480218729Shselasky struct mii_data *mii = GET_MII(sc); 481218729Shselasky int val, err, locked; 482218729Shselasky 483218729Shselasky locked = mtx_owned(&sc->sc_mtx); 484218729Shselasky if (!locked) 485218729Shselasky MOS_LOCK(sc); 486218729Shselasky 487218729Shselasky /* disable RX, TX prior to changing FDX, SPEEDSEL */ 488218729Shselasky val = mos_reg_read_1(sc, MOS_CTL); 489218729Shselasky val &= ~(MOS_CTL_TX_ENB | MOS_CTL_RX_ENB); 490218729Shselasky mos_reg_write_1(sc, MOS_CTL, val); 491218729Shselasky 492218729Shselasky /* reset register which counts dropped frames */ 493218729Shselasky mos_reg_write_1(sc, MOS_FRAME_DROP_CNT, 0); 494218729Shselasky 495218729Shselasky if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) 496218729Shselasky val |= MOS_CTL_FDX_ENB; 497218729Shselasky else 498218729Shselasky val &= ~(MOS_CTL_FDX_ENB); 499218729Shselasky 500218729Shselasky switch (IFM_SUBTYPE(mii->mii_media_active)) { 501218729Shselasky case IFM_100_TX: 502218729Shselasky val |= MOS_CTL_SPEEDSEL; 503218729Shselasky break; 504218729Shselasky case IFM_10_T: 505218729Shselasky val &= ~(MOS_CTL_SPEEDSEL); 506218729Shselasky break; 507218729Shselasky } 508218729Shselasky 509218729Shselasky /* re-enable TX, RX */ 510218729Shselasky val |= (MOS_CTL_TX_ENB | MOS_CTL_RX_ENB); 511218729Shselasky err = mos_reg_write_1(sc, MOS_CTL, val); 512218729Shselasky 513218729Shselasky if (err) 514218729Shselasky MOS_DPRINTFN("media change failed"); 515218729Shselasky 516218729Shselasky if (!locked) 517218729Shselasky MOS_UNLOCK(sc); 518218729Shselasky} 519218729Shselasky 520218729Shselasky/* 521218729Shselasky * Set media options. 522218729Shselasky */ 523218729Shselaskystatic int 524218729Shselaskymos_ifmedia_upd(struct ifnet *ifp) 525218729Shselasky{ 526218729Shselasky struct mos_softc *sc = ifp->if_softc; 527218729Shselasky struct mii_data *mii = GET_MII(sc); 528218729Shselasky struct mii_softc *miisc; 529251734Skevlo int error; 530218729Shselasky 531218729Shselasky MOS_LOCK_ASSERT(sc, MA_OWNED); 532218729Shselasky 533218729Shselasky sc->mos_link = 0; 534251734Skevlo LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 535251734Skevlo PHY_RESET(miisc); 536251734Skevlo error = mii_mediachg(mii); 537251734Skevlo return (error); 538218729Shselasky} 539218729Shselasky 540218729Shselasky/* 541218729Shselasky * Report current media status. 542218729Shselasky */ 543218729Shselaskystatic void 544218729Shselaskymos_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 545218729Shselasky{ 546218729Shselasky struct mos_softc *sc = ifp->if_softc; 547218729Shselasky struct mii_data *mii = GET_MII(sc); 548218729Shselasky 549218729Shselasky MOS_LOCK(sc); 550218729Shselasky mii_pollstat(mii); 551218729Shselasky 552218729Shselasky ifmr->ifm_active = mii->mii_media_active; 553218729Shselasky ifmr->ifm_status = mii->mii_media_status; 554226479Syongari MOS_UNLOCK(sc); 555218729Shselasky} 556218729Shselasky 557218729Shselaskystatic void 558218729Shselaskymos_setpromisc(struct usb_ether *ue) 559218729Shselasky{ 560218729Shselasky struct mos_softc *sc = uether_getsc(ue); 561218729Shselasky struct ifnet *ifp = uether_getifp(ue); 562218729Shselasky 563218729Shselasky uint8_t rxmode; 564218729Shselasky 565218729Shselasky MOS_LOCK_ASSERT(sc, MA_OWNED); 566218729Shselasky 567218729Shselasky rxmode = mos_reg_read_1(sc, MOS_CTL); 568218729Shselasky 569218729Shselasky /* If we want promiscuous mode, set the allframes bit. */ 570218729Shselasky if (ifp->if_flags & IFF_PROMISC) { 571218729Shselasky rxmode |= MOS_CTL_RX_PROMISC; 572218729Shselasky } else { 573218729Shselasky rxmode &= ~MOS_CTL_RX_PROMISC; 574218729Shselasky } 575218729Shselasky 576218729Shselasky mos_reg_write_1(sc, MOS_CTL, rxmode); 577218729Shselasky} 578218729Shselasky 579218729Shselasky 580218729Shselasky 581218729Shselaskystatic void 582218729Shselaskymos_setmulti(struct usb_ether *ue) 583218729Shselasky{ 584218729Shselasky struct mos_softc *sc = uether_getsc(ue); 585218729Shselasky struct ifnet *ifp = uether_getifp(ue); 586218729Shselasky struct ifmultiaddr *ifma; 587218729Shselasky 588218729Shselasky uint32_t h = 0; 589218729Shselasky uint8_t rxmode; 590218729Shselasky uint8_t hashtbl[8] = {0, 0, 0, 0, 0, 0, 0, 0}; 591218729Shselasky int allmulti = 0; 592218729Shselasky 593218729Shselasky MOS_LOCK_ASSERT(sc, MA_OWNED); 594218729Shselasky 595218729Shselasky rxmode = mos_reg_read_1(sc, MOS_CTL); 596218729Shselasky 597218729Shselasky if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) 598218729Shselasky allmulti = 1; 599218729Shselasky 600218729Shselasky /* get all new ones */ 601218729Shselasky if_maddr_rlock(ifp); 602218729Shselasky TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 603218729Shselasky if (ifma->ifma_addr->sa_family != AF_LINK) { 604218729Shselasky allmulti = 1; 605218729Shselasky continue; 606218729Shselasky }; 607218729Shselasky h = ether_crc32_be(LLADDR((struct sockaddr_dl *) 608218729Shselasky ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; 609218729Shselasky hashtbl[h / 8] |= 1 << (h % 8); 610218729Shselasky } 611218729Shselasky if_maddr_runlock(ifp); 612218729Shselasky 613218729Shselasky /* now program new ones */ 614218729Shselasky if (allmulti == 1) { 615218729Shselasky rxmode |= MOS_CTL_ALLMULTI; 616218729Shselasky mos_reg_write_1(sc, MOS_CTL, rxmode); 617218729Shselasky } else { 618218729Shselasky rxmode &= ~MOS_CTL_ALLMULTI; 619218729Shselasky mos_write_mcast(sc, (void *)&hashtbl); 620218729Shselasky mos_reg_write_1(sc, MOS_CTL, rxmode); 621218729Shselasky } 622218729Shselasky} 623218729Shselasky 624218729Shselaskystatic void 625218729Shselaskymos_reset(struct mos_softc *sc) 626218729Shselasky{ 627218729Shselasky uint8_t ctl; 628218729Shselasky 629218729Shselasky ctl = mos_reg_read_1(sc, MOS_CTL); 630218729Shselasky ctl &= ~(MOS_CTL_RX_PROMISC | MOS_CTL_ALLMULTI | MOS_CTL_TX_ENB | 631218729Shselasky MOS_CTL_RX_ENB); 632218729Shselasky /* Disable RX, TX, promiscuous and allmulticast mode */ 633218729Shselasky mos_reg_write_1(sc, MOS_CTL, ctl); 634218729Shselasky 635218729Shselasky /* Reset frame drop counter register to zero */ 636218729Shselasky mos_reg_write_1(sc, MOS_FRAME_DROP_CNT, 0); 637218729Shselasky 638218729Shselasky /* Wait a little while for the chip to get its brains in order. */ 639218729Shselasky usb_pause_mtx(&sc->sc_mtx, hz / 128); 640218729Shselasky return; 641218729Shselasky} 642218729Shselasky 643218729Shselaskystatic void 644218729Shselaskymos_chip_init(struct mos_softc *sc) 645218729Shselasky{ 646218729Shselasky int i; 647218729Shselasky 648218729Shselasky /* 649218729Shselasky * Rev.C devices have a pause threshold register which needs to be set 650218729Shselasky * at startup. 651218729Shselasky */ 652218729Shselasky if (mos_reg_read_1(sc, MOS_PAUSE_TRHD) != -1) { 653218729Shselasky for (i = 0; i < MOS_PAUSE_REWRITES; i++) 654218729Shselasky mos_reg_write_1(sc, MOS_PAUSE_TRHD, 0); 655218729Shselasky } 656218729Shselasky sc->mos_phyaddrs[0] = 1; 657218729Shselasky sc->mos_phyaddrs[1] = 0xFF; 658218729Shselasky} 659218729Shselasky 660218729Shselasky/* 661218729Shselasky * Probe for a MCS7x30 chip. 662218729Shselasky */ 663218729Shselaskystatic int 664218729Shselaskymos_probe(device_t dev) 665218729Shselasky{ 666218729Shselasky struct usb_attach_arg *uaa = device_get_ivars(dev); 667218729Shselasky int retval; 668218729Shselasky 669218729Shselasky if (uaa->usb_mode != USB_MODE_HOST) 670218729Shselasky return (ENXIO); 671218729Shselasky if (uaa->info.bConfigIndex != MOS_CONFIG_IDX) 672218729Shselasky return (ENXIO); 673218729Shselasky if (uaa->info.bIfaceIndex != MOS_IFACE_IDX) 674218729Shselasky return (ENXIO); 675218729Shselasky 676218729Shselasky retval = usbd_lookup_id_by_uaa(mos_devs, sizeof(mos_devs), uaa); 677218729Shselasky return (retval); 678218729Shselasky} 679218729Shselasky 680218729Shselasky/* 681218729Shselasky * Attach the interface. Allocate softc structures, do ifmedia 682218729Shselasky * setup and ethernet/BPF attach. 683218729Shselasky */ 684218729Shselaskystatic int 685218729Shselaskymos_attach(device_t dev) 686218729Shselasky{ 687218729Shselasky struct usb_attach_arg *uaa = device_get_ivars(dev); 688218729Shselasky struct mos_softc *sc = device_get_softc(dev); 689218729Shselasky struct usb_ether *ue = &sc->sc_ue; 690218729Shselasky uint8_t iface_index; 691218729Shselasky int error; 692218729Shselasky 693218729Shselasky sc->mos_flags = USB_GET_DRIVER_INFO(uaa); 694218729Shselasky 695218729Shselasky device_set_usb_desc(dev); 696218729Shselasky mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 697218729Shselasky 698218729Shselasky iface_index = MOS_IFACE_IDX; 699218729Shselasky error = usbd_transfer_setup(uaa->device, &iface_index, 700218729Shselasky sc->sc_xfer, mos_config, MOS_ENDPT_MAX, 701218729Shselasky sc, &sc->sc_mtx); 702218729Shselasky 703218729Shselasky if (error) { 704218729Shselasky device_printf(dev, "allocating USB transfers failed\n"); 705218729Shselasky goto detach; 706218729Shselasky } 707218729Shselasky ue->ue_sc = sc; 708218729Shselasky ue->ue_dev = dev; 709218729Shselasky ue->ue_udev = uaa->device; 710218729Shselasky ue->ue_mtx = &sc->sc_mtx; 711218729Shselasky ue->ue_methods = &mos_ue_methods; 712218729Shselasky 713218729Shselasky 714218729Shselasky if (sc->mos_flags & MCS7730) { 715218729Shselasky MOS_DPRINTFN("model: MCS7730"); 716218729Shselasky } else if (sc->mos_flags & MCS7830) { 717218729Shselasky MOS_DPRINTFN("model: MCS7830"); 718232257Skevlo } else if (sc->mos_flags & MCS7832) { 719232257Skevlo MOS_DPRINTFN("model: MCS7832"); 720218729Shselasky } 721218729Shselasky error = uether_ifattach(ue); 722218729Shselasky if (error) { 723218729Shselasky device_printf(dev, "could not attach interface\n"); 724218729Shselasky goto detach; 725218729Shselasky } 726218729Shselasky return (0); 727218729Shselasky 728218729Shselasky 729218729Shselaskydetach: 730218729Shselasky mos_detach(dev); 731218729Shselasky return (ENXIO); 732218729Shselasky} 733218729Shselasky 734218729Shselasky 735218729Shselaskystatic void 736218729Shselaskymos_attach_post(struct usb_ether *ue) 737218729Shselasky{ 738218729Shselasky struct mos_softc *sc = uether_getsc(ue); 739218729Shselasky int err; 740218729Shselasky 741218729Shselasky /* Read MAC address, inform the world. */ 742218729Shselasky err = mos_readmac(sc, ue->ue_eaddr); 743218729Shselasky 744218729Shselasky if (err) 745218729Shselasky MOS_DPRINTFN("couldn't get MAC address"); 746218729Shselasky 747218729Shselasky MOS_DPRINTFN("address: %s", ether_sprintf(ue->ue_eaddr)); 748218729Shselasky 749218729Shselasky mos_chip_init(sc); 750218729Shselasky} 751218729Shselasky 752218729Shselaskystatic int 753218729Shselaskymos_detach(device_t dev) 754218729Shselasky{ 755218729Shselasky struct mos_softc *sc = device_get_softc(dev); 756218729Shselasky struct usb_ether *ue = &sc->sc_ue; 757218729Shselasky 758218729Shselasky usbd_transfer_unsetup(sc->sc_xfer, MOS_ENDPT_MAX); 759218729Shselasky uether_ifdetach(ue); 760218729Shselasky mtx_destroy(&sc->sc_mtx); 761218729Shselasky 762218729Shselasky return (0); 763218729Shselasky} 764218729Shselasky 765218729Shselasky 766218729Shselasky 767218729Shselasky 768218729Shselasky/* 769218729Shselasky * A frame has been uploaded: pass the resulting mbuf chain up to 770218729Shselasky * the higher level protocols. 771218729Shselasky */ 772218729Shselaskystatic void 773218729Shselaskymos_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) 774218729Shselasky{ 775218729Shselasky struct mos_softc *sc = usbd_xfer_softc(xfer); 776218729Shselasky struct usb_ether *ue = &sc->sc_ue; 777218729Shselasky struct ifnet *ifp = uether_getifp(ue); 778218729Shselasky 779218729Shselasky uint8_t rxstat = 0; 780218729Shselasky uint32_t actlen; 781218729Shselasky uint16_t pktlen = 0; 782218729Shselasky struct usb_page_cache *pc; 783218729Shselasky 784218729Shselasky usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 785218729Shselasky pc = usbd_xfer_get_frame(xfer, 0); 786218729Shselasky 787218729Shselasky switch (USB_GET_STATE(xfer)) { 788218729Shselasky case USB_ST_TRANSFERRED: 789218729Shselasky MOS_DPRINTFN("actlen : %d", actlen); 790218729Shselasky if (actlen <= 1) { 791218729Shselasky ifp->if_ierrors++; 792218729Shselasky goto tr_setup; 793218729Shselasky } 794218729Shselasky /* evaluate status byte at the end */ 795218729Shselasky usbd_copy_out(pc, actlen - sizeof(rxstat), &rxstat, 796218729Shselasky sizeof(rxstat)); 797218729Shselasky 798218729Shselasky if (rxstat != MOS_RXSTS_VALID) { 799218729Shselasky MOS_DPRINTFN("erroneous frame received"); 800218729Shselasky if (rxstat & MOS_RXSTS_SHORT_FRAME) 801218729Shselasky MOS_DPRINTFN("frame size less than 64 bytes"); 802218765Shselasky if (rxstat & MOS_RXSTS_LARGE_FRAME) { 803218765Shselasky MOS_DPRINTFN("frame size larger than " 804218765Shselasky "1532 bytes"); 805218765Shselasky } 806218729Shselasky if (rxstat & MOS_RXSTS_CRC_ERROR) 807218729Shselasky MOS_DPRINTFN("CRC error"); 808218729Shselasky if (rxstat & MOS_RXSTS_ALIGN_ERROR) 809218729Shselasky MOS_DPRINTFN("alignment error"); 810218729Shselasky ifp->if_ierrors++; 811218729Shselasky goto tr_setup; 812218729Shselasky } 813218729Shselasky /* Remember the last byte was used for the status fields */ 814218729Shselasky pktlen = actlen - 1; 815218729Shselasky if (pktlen < sizeof(struct ether_header)) { 816218765Shselasky MOS_DPRINTFN("error: pktlen %d is smaller " 817218765Shselasky "than ether_header %zd", pktlen, 818218765Shselasky sizeof(struct ether_header)); 819218729Shselasky ifp->if_ierrors++; 820218729Shselasky goto tr_setup; 821218729Shselasky } 822218729Shselasky uether_rxbuf(ue, pc, 0, actlen); 823218729Shselasky /* FALLTHROUGH */ 824218729Shselasky case USB_ST_SETUP: 825218729Shselaskytr_setup: 826218729Shselasky usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 827218729Shselasky usbd_transfer_submit(xfer); 828218729Shselasky uether_rxflush(ue); 829218729Shselasky return; 830218729Shselasky default: 831218729Shselasky MOS_DPRINTFN("bulk read error, %s", usbd_errstr(error)); 832218729Shselasky if (error != USB_ERR_CANCELLED) { 833218729Shselasky usbd_xfer_set_stall(xfer); 834218729Shselasky goto tr_setup; 835218729Shselasky } 836218729Shselasky MOS_DPRINTFN("start rx %i", usbd_xfer_max_len(xfer)); 837218729Shselasky return; 838218729Shselasky } 839218729Shselasky} 840218729Shselasky 841218729Shselasky/* 842218729Shselasky * A frame was downloaded to the chip. It's safe for us to clean up 843218729Shselasky * the list buffers. 844218729Shselasky */ 845218729Shselaskystatic void 846218729Shselaskymos_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) 847218729Shselasky{ 848218729Shselasky struct mos_softc *sc = usbd_xfer_softc(xfer); 849218729Shselasky struct ifnet *ifp = uether_getifp(&sc->sc_ue); 850218729Shselasky struct usb_page_cache *pc; 851218729Shselasky struct mbuf *m; 852218729Shselasky 853218729Shselasky 854218729Shselasky 855218729Shselasky switch (USB_GET_STATE(xfer)) { 856218729Shselasky case USB_ST_TRANSFERRED: 857218729Shselasky MOS_DPRINTFN("transfer of complete"); 858218729Shselasky ifp->if_opackets++; 859218729Shselasky /* FALLTHROUGH */ 860218729Shselasky case USB_ST_SETUP: 861218729Shselaskytr_setup: 862218729Shselasky /* 863218729Shselasky * XXX: don't send anything if there is no link? 864218729Shselasky */ 865218729Shselasky IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 866218729Shselasky if (m == NULL) 867218729Shselasky return; 868218729Shselasky 869218729Shselasky pc = usbd_xfer_get_frame(xfer, 0); 870218729Shselasky usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len); 871218729Shselasky 872218729Shselasky usbd_xfer_set_frame_len(xfer, 0, m->m_pkthdr.len); 873218729Shselasky 874218729Shselasky 875218729Shselasky /* 876218729Shselasky * if there's a BPF listener, bounce a copy 877218729Shselasky * of this frame to him: 878218729Shselasky */ 879218729Shselasky BPF_MTAP(ifp, m); 880218729Shselasky 881218729Shselasky m_freem(m); 882218729Shselasky 883218729Shselasky usbd_transfer_submit(xfer); 884218729Shselasky 885218729Shselasky ifp->if_opackets++; 886218729Shselasky return; 887218729Shselasky default: 888218729Shselasky MOS_DPRINTFN("usb error on tx: %s\n", usbd_errstr(error)); 889218729Shselasky ifp->if_oerrors++; 890218729Shselasky if (error != USB_ERR_CANCELLED) { 891218729Shselasky usbd_xfer_set_stall(xfer); 892218729Shselasky goto tr_setup; 893218729Shselasky } 894218729Shselasky return; 895218729Shselasky } 896218729Shselasky} 897218729Shselasky 898218729Shselaskystatic void 899218729Shselaskymos_tick(struct usb_ether *ue) 900218729Shselasky{ 901218729Shselasky struct mos_softc *sc = uether_getsc(ue); 902218729Shselasky struct mii_data *mii = GET_MII(sc); 903218729Shselasky 904218729Shselasky MOS_LOCK_ASSERT(sc, MA_OWNED); 905218729Shselasky 906218729Shselasky mii_tick(mii); 907218729Shselasky if (!sc->mos_link && mii->mii_media_status & IFM_ACTIVE && 908218729Shselasky IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 909218729Shselasky MOS_DPRINTFN("got link"); 910218729Shselasky sc->mos_link++; 911218729Shselasky mos_start(ue); 912218729Shselasky } 913218729Shselasky} 914218729Shselasky 915218729Shselasky 916218729Shselaskystatic void 917218729Shselaskymos_start(struct usb_ether *ue) 918218729Shselasky{ 919218729Shselasky struct mos_softc *sc = uether_getsc(ue); 920218729Shselasky 921218729Shselasky /* 922218729Shselasky * start the USB transfers, if not already started: 923218729Shselasky */ 924218729Shselasky usbd_transfer_start(sc->sc_xfer[MOS_ENDPT_TX]); 925218729Shselasky usbd_transfer_start(sc->sc_xfer[MOS_ENDPT_RX]); 926218729Shselasky usbd_transfer_start(sc->sc_xfer[MOS_ENDPT_INTR]); 927218729Shselasky} 928218729Shselasky 929218729Shselaskystatic void 930218729Shselaskymos_init(struct usb_ether *ue) 931218729Shselasky{ 932218729Shselasky struct mos_softc *sc = uether_getsc(ue); 933218729Shselasky struct ifnet *ifp = uether_getifp(ue); 934218729Shselasky uint8_t rxmode; 935218729Shselasky 936218729Shselasky MOS_LOCK_ASSERT(sc, MA_OWNED); 937218729Shselasky 938218729Shselasky /* Cancel pending I/O and free all RX/TX buffers. */ 939218729Shselasky mos_reset(sc); 940218729Shselasky 941218729Shselasky /* Write MAC address */ 942218729Shselasky mos_writemac(sc, IF_LLADDR(ifp)); 943218729Shselasky 944218729Shselasky /* Read and set transmitter IPG values */ 945218729Shselasky sc->mos_ipgs[0] = mos_reg_read_1(sc, MOS_IPG0); 946218729Shselasky sc->mos_ipgs[1] = mos_reg_read_1(sc, MOS_IPG1); 947218729Shselasky mos_reg_write_1(sc, MOS_IPG0, sc->mos_ipgs[0]); 948218729Shselasky mos_reg_write_1(sc, MOS_IPG1, sc->mos_ipgs[1]); 949218729Shselasky 950218729Shselasky /* 951218729Shselasky * Enable receiver and transmitter, bridge controls speed/duplex 952218729Shselasky * mode 953218729Shselasky */ 954218729Shselasky rxmode = mos_reg_read_1(sc, MOS_CTL); 955218729Shselasky rxmode |= MOS_CTL_RX_ENB | MOS_CTL_TX_ENB | MOS_CTL_BS_ENB; 956218729Shselasky rxmode &= ~(MOS_CTL_SLEEP); 957218729Shselasky 958218729Shselasky mos_setpromisc(ue); 959218729Shselasky 960218729Shselasky /* XXX: broadcast mode? */ 961218729Shselasky mos_reg_write_1(sc, MOS_CTL, rxmode); 962218729Shselasky 963218729Shselasky /* Load the multicast filter. */ 964218729Shselasky mos_setmulti(ue); 965218729Shselasky 966218729Shselasky ifp->if_drv_flags |= IFF_DRV_RUNNING; 967218729Shselasky mos_start(ue); 968218729Shselasky} 969218729Shselasky 970218729Shselasky 971218729Shselaskystatic void 972218729Shselaskymos_intr_callback(struct usb_xfer *xfer, usb_error_t error) 973218729Shselasky{ 974218729Shselasky struct mos_softc *sc = usbd_xfer_softc(xfer); 975218729Shselasky struct ifnet *ifp = uether_getifp(&sc->sc_ue); 976218729Shselasky struct usb_page_cache *pc; 977218729Shselasky uint32_t pkt; 978218729Shselasky int actlen; 979218729Shselasky 980218729Shselasky ifp->if_oerrors++; 981218729Shselasky 982218729Shselasky usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 983218729Shselasky MOS_DPRINTFN("actlen %i", actlen); 984218729Shselasky 985218729Shselasky switch (USB_GET_STATE(xfer)) { 986218729Shselasky case USB_ST_TRANSFERRED: 987218729Shselasky 988218729Shselasky pc = usbd_xfer_get_frame(xfer, 0); 989218729Shselasky usbd_copy_out(pc, 0, &pkt, sizeof(pkt)); 990218729Shselasky /* FALLTHROUGH */ 991218729Shselasky case USB_ST_SETUP: 992218729Shselaskytr_setup: 993218729Shselasky return; 994218729Shselasky default: 995218729Shselasky if (error != USB_ERR_CANCELLED) { 996218729Shselasky usbd_xfer_set_stall(xfer); 997218729Shselasky goto tr_setup; 998218729Shselasky } 999218729Shselasky return; 1000218729Shselasky } 1001218729Shselasky} 1002218729Shselasky 1003218729Shselasky 1004218729Shselasky/* 1005218729Shselasky * Stop the adapter and free any mbufs allocated to the 1006218729Shselasky * RX and TX lists. 1007218729Shselasky */ 1008218729Shselaskystatic void 1009218729Shselaskymos_stop(struct usb_ether *ue) 1010218729Shselasky{ 1011218729Shselasky struct mos_softc *sc = uether_getsc(ue); 1012218729Shselasky struct ifnet *ifp = uether_getifp(ue); 1013218729Shselasky 1014218729Shselasky mos_reset(sc); 1015218729Shselasky 1016218729Shselasky MOS_LOCK_ASSERT(sc, MA_OWNED); 1017218729Shselasky ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1018218729Shselasky 1019218729Shselasky /* stop all the transfers, if not already stopped */ 1020218729Shselasky usbd_transfer_stop(sc->sc_xfer[MOS_ENDPT_TX]); 1021218729Shselasky usbd_transfer_stop(sc->sc_xfer[MOS_ENDPT_RX]); 1022218729Shselasky usbd_transfer_stop(sc->sc_xfer[MOS_ENDPT_INTR]); 1023218729Shselasky 1024218729Shselasky sc->mos_link = 0; 1025218729Shselasky} 1026