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> 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"); 140276701ShselaskySYSCTL_INT(_hw_usb_mos, OID_AUTO, debug, CTLFLAG_RWTUN, &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); 250292080SimpUSB_PNP_HOST_INFO(mos_devs); 251218729Shselasky 252218729Shselaskystatic const struct usb_ether_methods mos_ue_methods = { 253218729Shselasky .ue_attach_post = mos_attach_post, 254218729Shselasky .ue_start = mos_start, 255218729Shselasky .ue_init = mos_init, 256218729Shselasky .ue_stop = mos_stop, 257218729Shselasky .ue_tick = mos_tick, 258218729Shselasky .ue_setmulti = mos_setmulti, 259218729Shselasky .ue_setpromisc = mos_setpromisc, 260218729Shselasky .ue_mii_upd = mos_ifmedia_upd, 261218729Shselasky .ue_mii_sts = mos_ifmedia_sts, 262218729Shselasky}; 263218729Shselasky 264218729Shselasky 265218729Shselaskystatic int 266218729Shselaskymos_reg_read_1(struct mos_softc *sc, int reg) 267218729Shselasky{ 268218729Shselasky struct usb_device_request req; 269218729Shselasky usb_error_t err; 270218729Shselasky uByte val = 0; 271218729Shselasky 272218729Shselasky req.bmRequestType = UT_READ_VENDOR_DEVICE; 273218729Shselasky req.bRequest = MOS_UR_READREG; 274218729Shselasky USETW(req.wValue, 0); 275218729Shselasky USETW(req.wIndex, reg); 276218729Shselasky USETW(req.wLength, 1); 277218729Shselasky 278218729Shselasky err = uether_do_request(&sc->sc_ue, &req, &val, 1000); 279218729Shselasky 280218729Shselasky if (err) { 281218729Shselasky MOS_DPRINTFN("mos_reg_read_1 error, reg: %d\n", reg); 282218729Shselasky return (-1); 283218729Shselasky } 284218729Shselasky return (val); 285218729Shselasky} 286218729Shselasky 287218729Shselaskystatic int 288218729Shselaskymos_reg_read_2(struct mos_softc *sc, int reg) 289218729Shselasky{ 290218729Shselasky struct usb_device_request req; 291218729Shselasky usb_error_t err; 292218729Shselasky uWord val; 293218729Shselasky 294218729Shselasky USETW(val, 0); 295218729Shselasky 296218729Shselasky req.bmRequestType = UT_READ_VENDOR_DEVICE; 297218729Shselasky req.bRequest = MOS_UR_READREG; 298218729Shselasky USETW(req.wValue, 0); 299218729Shselasky USETW(req.wIndex, reg); 300218729Shselasky USETW(req.wLength, 2); 301218729Shselasky 302218729Shselasky err = uether_do_request(&sc->sc_ue, &req, &val, 1000); 303218729Shselasky 304218729Shselasky if (err) { 305218729Shselasky MOS_DPRINTFN("mos_reg_read_2 error, reg: %d", reg); 306218729Shselasky return (-1); 307218729Shselasky } 308218729Shselasky return (UGETW(val)); 309218729Shselasky} 310218729Shselasky 311218729Shselaskystatic int 312218729Shselaskymos_reg_write_1(struct mos_softc *sc, int reg, int aval) 313218729Shselasky{ 314218729Shselasky struct usb_device_request req; 315218729Shselasky usb_error_t err; 316218729Shselasky uByte val; 317218729Shselasky val = aval; 318218729Shselasky 319218729Shselasky req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 320218729Shselasky req.bRequest = MOS_UR_WRITEREG; 321218729Shselasky USETW(req.wValue, 0); 322218729Shselasky USETW(req.wIndex, reg); 323218729Shselasky USETW(req.wLength, 1); 324218729Shselasky 325218729Shselasky err = uether_do_request(&sc->sc_ue, &req, &val, 1000); 326218729Shselasky 327218729Shselasky if (err) { 328218729Shselasky MOS_DPRINTFN("mos_reg_write_1 error, reg: %d", reg); 329218729Shselasky return (-1); 330218729Shselasky } 331218729Shselasky return (0); 332218729Shselasky} 333218729Shselasky 334218729Shselaskystatic int 335218729Shselaskymos_reg_write_2(struct mos_softc *sc, int reg, int aval) 336218729Shselasky{ 337218729Shselasky struct usb_device_request req; 338218729Shselasky usb_error_t err; 339218729Shselasky uWord val; 340218729Shselasky 341218729Shselasky USETW(val, aval); 342218729Shselasky 343218729Shselasky req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 344218729Shselasky req.bRequest = MOS_UR_WRITEREG; 345218729Shselasky USETW(req.wValue, 0); 346218729Shselasky USETW(req.wIndex, reg); 347218729Shselasky USETW(req.wLength, 2); 348218729Shselasky 349218729Shselasky err = uether_do_request(&sc->sc_ue, &req, &val, 1000); 350218729Shselasky 351218729Shselasky if (err) { 352218729Shselasky MOS_DPRINTFN("mos_reg_write_2 error, reg: %d", reg); 353218729Shselasky return (-1); 354218729Shselasky } 355218729Shselasky return (0); 356218729Shselasky} 357218729Shselasky 358218729Shselaskystatic int 359218729Shselaskymos_readmac(struct mos_softc *sc, u_char *mac) 360218729Shselasky{ 361218729Shselasky struct usb_device_request req; 362218729Shselasky usb_error_t err; 363218729Shselasky 364218729Shselasky req.bmRequestType = UT_READ_VENDOR_DEVICE; 365218729Shselasky req.bRequest = MOS_UR_READREG; 366218729Shselasky USETW(req.wValue, 0); 367218729Shselasky USETW(req.wIndex, MOS_MAC); 368218729Shselasky USETW(req.wLength, ETHER_ADDR_LEN); 369218729Shselasky 370218729Shselasky err = uether_do_request(&sc->sc_ue, &req, mac, 1000); 371218729Shselasky 372218729Shselasky if (err) { 373218729Shselasky return (-1); 374218729Shselasky } 375218729Shselasky return (0); 376218729Shselasky} 377218729Shselasky 378218729Shselaskystatic int 379218729Shselaskymos_writemac(struct mos_softc *sc, uint8_t *mac) 380218729Shselasky{ 381218729Shselasky struct usb_device_request req; 382218729Shselasky usb_error_t err; 383218729Shselasky 384218729Shselasky req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 385218729Shselasky req.bRequest = MOS_UR_WRITEREG; 386218729Shselasky USETW(req.wValue, 0); 387218729Shselasky USETW(req.wIndex, MOS_MAC); 388218729Shselasky USETW(req.wLength, ETHER_ADDR_LEN); 389218729Shselasky 390218729Shselasky err = uether_do_request(&sc->sc_ue, &req, mac, 1000); 391218729Shselasky 392218729Shselasky if (err) { 393218729Shselasky MOS_DPRINTFN("mos_writemac error"); 394218729Shselasky return (-1); 395218729Shselasky } 396218729Shselasky return (0); 397218729Shselasky} 398218729Shselasky 399218729Shselaskystatic int 400218729Shselaskymos_write_mcast(struct mos_softc *sc, u_char *hashtbl) 401218729Shselasky{ 402218729Shselasky struct usb_device_request req; 403218729Shselasky usb_error_t err; 404218729Shselasky 405218729Shselasky req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 406218729Shselasky req.bRequest = MOS_UR_WRITEREG; 407218729Shselasky USETW(req.wValue, 0); 408218729Shselasky USETW(req.wIndex, MOS_MCAST_TABLE); 409218729Shselasky USETW(req.wLength, 8); 410218729Shselasky 411218729Shselasky err = uether_do_request(&sc->sc_ue, &req, hashtbl, 1000); 412218729Shselasky 413218729Shselasky if (err) { 414218729Shselasky MOS_DPRINTFN("mos_reg_mcast error"); 415218729Shselasky return (-1); 416218729Shselasky } 417218729Shselasky return (0); 418218729Shselasky} 419218729Shselasky 420218729Shselaskystatic int 421298918Sadrianmos_miibus_readreg(device_t dev, int phy, int reg) 422218729Shselasky{ 423218729Shselasky struct mos_softc *sc = device_get_softc(dev); 424218729Shselasky uWord val; 425218729Shselasky int i, res, locked; 426218729Shselasky 427218729Shselasky USETW(val, 0); 428218729Shselasky 429218729Shselasky locked = mtx_owned(&sc->sc_mtx); 430218729Shselasky if (!locked) 431218729Shselasky MOS_LOCK(sc); 432218729Shselasky 433218729Shselasky mos_reg_write_2(sc, MOS_PHY_DATA, 0); 434218729Shselasky mos_reg_write_1(sc, MOS_PHY_CTL, (phy & MOS_PHYCTL_PHYADDR) | 435218729Shselasky MOS_PHYCTL_READ); 436218729Shselasky mos_reg_write_1(sc, MOS_PHY_STS, (reg & MOS_PHYSTS_PHYREG) | 437218729Shselasky MOS_PHYSTS_PENDING); 438218729Shselasky 439218729Shselasky for (i = 0; i < MOS_TIMEOUT; i++) { 440218729Shselasky if (mos_reg_read_1(sc, MOS_PHY_STS) & MOS_PHYSTS_READY) 441218729Shselasky break; 442218729Shselasky } 443218729Shselasky if (i == MOS_TIMEOUT) { 444218729Shselasky MOS_DPRINTFN("MII read timeout"); 445218729Shselasky } 446218729Shselasky res = mos_reg_read_2(sc, MOS_PHY_DATA); 447218729Shselasky 448218729Shselasky if (!locked) 449218729Shselasky MOS_UNLOCK(sc); 450218729Shselasky return (res); 451218729Shselasky} 452218729Shselasky 453218729Shselaskystatic int 454218729Shselaskymos_miibus_writereg(device_t dev, int phy, int reg, int val) 455218729Shselasky{ 456218729Shselasky struct mos_softc *sc = device_get_softc(dev); 457218729Shselasky int i, locked; 458218729Shselasky 459218729Shselasky locked = mtx_owned(&sc->sc_mtx); 460218729Shselasky if (!locked) 461218729Shselasky MOS_LOCK(sc); 462218729Shselasky 463218729Shselasky mos_reg_write_2(sc, MOS_PHY_DATA, val); 464218729Shselasky mos_reg_write_1(sc, MOS_PHY_CTL, (phy & MOS_PHYCTL_PHYADDR) | 465218729Shselasky MOS_PHYCTL_WRITE); 466218729Shselasky mos_reg_write_1(sc, MOS_PHY_STS, (reg & MOS_PHYSTS_PHYREG) | 467218729Shselasky MOS_PHYSTS_PENDING); 468218729Shselasky 469218729Shselasky for (i = 0; i < MOS_TIMEOUT; i++) { 470218729Shselasky if (mos_reg_read_1(sc, MOS_PHY_STS) & MOS_PHYSTS_READY) 471218729Shselasky break; 472218729Shselasky } 473218729Shselasky if (i == MOS_TIMEOUT) 474218729Shselasky MOS_DPRINTFN("MII write timeout"); 475218729Shselasky 476218729Shselasky if (!locked) 477218729Shselasky MOS_UNLOCK(sc); 478218729Shselasky return 0; 479218729Shselasky} 480218729Shselasky 481218729Shselaskystatic void 482218729Shselaskymos_miibus_statchg(device_t dev) 483218729Shselasky{ 484218729Shselasky struct mos_softc *sc = device_get_softc(dev); 485218729Shselasky struct mii_data *mii = GET_MII(sc); 486218729Shselasky int val, err, locked; 487218729Shselasky 488218729Shselasky locked = mtx_owned(&sc->sc_mtx); 489218729Shselasky if (!locked) 490218729Shselasky MOS_LOCK(sc); 491218729Shselasky 492218729Shselasky /* disable RX, TX prior to changing FDX, SPEEDSEL */ 493218729Shselasky val = mos_reg_read_1(sc, MOS_CTL); 494218729Shselasky val &= ~(MOS_CTL_TX_ENB | MOS_CTL_RX_ENB); 495218729Shselasky mos_reg_write_1(sc, MOS_CTL, val); 496218729Shselasky 497218729Shselasky /* reset register which counts dropped frames */ 498218729Shselasky mos_reg_write_1(sc, MOS_FRAME_DROP_CNT, 0); 499218729Shselasky 500218729Shselasky if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) 501218729Shselasky val |= MOS_CTL_FDX_ENB; 502218729Shselasky else 503218729Shselasky val &= ~(MOS_CTL_FDX_ENB); 504218729Shselasky 505218729Shselasky switch (IFM_SUBTYPE(mii->mii_media_active)) { 506218729Shselasky case IFM_100_TX: 507218729Shselasky val |= MOS_CTL_SPEEDSEL; 508218729Shselasky break; 509218729Shselasky case IFM_10_T: 510218729Shselasky val &= ~(MOS_CTL_SPEEDSEL); 511218729Shselasky break; 512218729Shselasky } 513218729Shselasky 514218729Shselasky /* re-enable TX, RX */ 515218729Shselasky val |= (MOS_CTL_TX_ENB | MOS_CTL_RX_ENB); 516218729Shselasky err = mos_reg_write_1(sc, MOS_CTL, val); 517218729Shselasky 518218729Shselasky if (err) 519218729Shselasky MOS_DPRINTFN("media change failed"); 520218729Shselasky 521218729Shselasky if (!locked) 522218729Shselasky MOS_UNLOCK(sc); 523218729Shselasky} 524218729Shselasky 525218729Shselasky/* 526218729Shselasky * Set media options. 527218729Shselasky */ 528218729Shselaskystatic int 529218729Shselaskymos_ifmedia_upd(struct ifnet *ifp) 530218729Shselasky{ 531218729Shselasky struct mos_softc *sc = ifp->if_softc; 532218729Shselasky struct mii_data *mii = GET_MII(sc); 533218729Shselasky struct mii_softc *miisc; 534251734Skevlo int error; 535218729Shselasky 536218729Shselasky MOS_LOCK_ASSERT(sc, MA_OWNED); 537218729Shselasky 538218729Shselasky sc->mos_link = 0; 539251734Skevlo LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 540251734Skevlo PHY_RESET(miisc); 541251734Skevlo error = mii_mediachg(mii); 542251734Skevlo return (error); 543218729Shselasky} 544218729Shselasky 545218729Shselasky/* 546218729Shselasky * Report current media status. 547218729Shselasky */ 548218729Shselaskystatic void 549218729Shselaskymos_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 550218729Shselasky{ 551218729Shselasky struct mos_softc *sc = ifp->if_softc; 552218729Shselasky struct mii_data *mii = GET_MII(sc); 553218729Shselasky 554218729Shselasky MOS_LOCK(sc); 555218729Shselasky mii_pollstat(mii); 556218729Shselasky 557218729Shselasky ifmr->ifm_active = mii->mii_media_active; 558218729Shselasky ifmr->ifm_status = mii->mii_media_status; 559226479Syongari MOS_UNLOCK(sc); 560218729Shselasky} 561218729Shselasky 562218729Shselaskystatic void 563218729Shselaskymos_setpromisc(struct usb_ether *ue) 564218729Shselasky{ 565218729Shselasky struct mos_softc *sc = uether_getsc(ue); 566218729Shselasky struct ifnet *ifp = uether_getifp(ue); 567218729Shselasky 568218729Shselasky uint8_t rxmode; 569218729Shselasky 570218729Shselasky MOS_LOCK_ASSERT(sc, MA_OWNED); 571218729Shselasky 572218729Shselasky rxmode = mos_reg_read_1(sc, MOS_CTL); 573218729Shselasky 574218729Shselasky /* If we want promiscuous mode, set the allframes bit. */ 575218729Shselasky if (ifp->if_flags & IFF_PROMISC) { 576218729Shselasky rxmode |= MOS_CTL_RX_PROMISC; 577218729Shselasky } else { 578218729Shselasky rxmode &= ~MOS_CTL_RX_PROMISC; 579218729Shselasky } 580218729Shselasky 581218729Shselasky mos_reg_write_1(sc, MOS_CTL, rxmode); 582218729Shselasky} 583218729Shselasky 584218729Shselasky 585218729Shselasky 586218729Shselaskystatic void 587218729Shselaskymos_setmulti(struct usb_ether *ue) 588218729Shselasky{ 589218729Shselasky struct mos_softc *sc = uether_getsc(ue); 590218729Shselasky struct ifnet *ifp = uether_getifp(ue); 591218729Shselasky struct ifmultiaddr *ifma; 592218729Shselasky 593218729Shselasky uint32_t h = 0; 594218729Shselasky uint8_t rxmode; 595218729Shselasky uint8_t hashtbl[8] = {0, 0, 0, 0, 0, 0, 0, 0}; 596218729Shselasky int allmulti = 0; 597218729Shselasky 598218729Shselasky MOS_LOCK_ASSERT(sc, MA_OWNED); 599218729Shselasky 600218729Shselasky rxmode = mos_reg_read_1(sc, MOS_CTL); 601218729Shselasky 602218729Shselasky if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) 603218729Shselasky allmulti = 1; 604218729Shselasky 605218729Shselasky /* get all new ones */ 606218729Shselasky if_maddr_rlock(ifp); 607218729Shselasky TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 608218729Shselasky if (ifma->ifma_addr->sa_family != AF_LINK) { 609218729Shselasky allmulti = 1; 610218729Shselasky continue; 611297793Spfg } 612218729Shselasky h = ether_crc32_be(LLADDR((struct sockaddr_dl *) 613218729Shselasky ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; 614218729Shselasky hashtbl[h / 8] |= 1 << (h % 8); 615218729Shselasky } 616218729Shselasky if_maddr_runlock(ifp); 617218729Shselasky 618218729Shselasky /* now program new ones */ 619218729Shselasky if (allmulti == 1) { 620218729Shselasky rxmode |= MOS_CTL_ALLMULTI; 621218729Shselasky mos_reg_write_1(sc, MOS_CTL, rxmode); 622218729Shselasky } else { 623218729Shselasky rxmode &= ~MOS_CTL_ALLMULTI; 624218729Shselasky mos_write_mcast(sc, (void *)&hashtbl); 625218729Shselasky mos_reg_write_1(sc, MOS_CTL, rxmode); 626218729Shselasky } 627218729Shselasky} 628218729Shselasky 629218729Shselaskystatic void 630218729Shselaskymos_reset(struct mos_softc *sc) 631218729Shselasky{ 632218729Shselasky uint8_t ctl; 633218729Shselasky 634218729Shselasky ctl = mos_reg_read_1(sc, MOS_CTL); 635218729Shselasky ctl &= ~(MOS_CTL_RX_PROMISC | MOS_CTL_ALLMULTI | MOS_CTL_TX_ENB | 636218729Shselasky MOS_CTL_RX_ENB); 637218729Shselasky /* Disable RX, TX, promiscuous and allmulticast mode */ 638218729Shselasky mos_reg_write_1(sc, MOS_CTL, ctl); 639218729Shselasky 640218729Shselasky /* Reset frame drop counter register to zero */ 641218729Shselasky mos_reg_write_1(sc, MOS_FRAME_DROP_CNT, 0); 642218729Shselasky 643218729Shselasky /* Wait a little while for the chip to get its brains in order. */ 644218729Shselasky usb_pause_mtx(&sc->sc_mtx, hz / 128); 645218729Shselasky return; 646218729Shselasky} 647218729Shselasky 648218729Shselaskystatic void 649218729Shselaskymos_chip_init(struct mos_softc *sc) 650218729Shselasky{ 651218729Shselasky int i; 652218729Shselasky 653218729Shselasky /* 654218729Shselasky * Rev.C devices have a pause threshold register which needs to be set 655218729Shselasky * at startup. 656218729Shselasky */ 657218729Shselasky if (mos_reg_read_1(sc, MOS_PAUSE_TRHD) != -1) { 658218729Shselasky for (i = 0; i < MOS_PAUSE_REWRITES; i++) 659218729Shselasky mos_reg_write_1(sc, MOS_PAUSE_TRHD, 0); 660218729Shselasky } 661218729Shselasky sc->mos_phyaddrs[0] = 1; 662218729Shselasky sc->mos_phyaddrs[1] = 0xFF; 663218729Shselasky} 664218729Shselasky 665218729Shselasky/* 666218729Shselasky * Probe for a MCS7x30 chip. 667218729Shselasky */ 668218729Shselaskystatic int 669218729Shselaskymos_probe(device_t dev) 670218729Shselasky{ 671218729Shselasky struct usb_attach_arg *uaa = device_get_ivars(dev); 672218729Shselasky int retval; 673218729Shselasky 674218729Shselasky if (uaa->usb_mode != USB_MODE_HOST) 675218729Shselasky return (ENXIO); 676218729Shselasky if (uaa->info.bConfigIndex != MOS_CONFIG_IDX) 677218729Shselasky return (ENXIO); 678218729Shselasky if (uaa->info.bIfaceIndex != MOS_IFACE_IDX) 679218729Shselasky return (ENXIO); 680218729Shselasky 681218729Shselasky retval = usbd_lookup_id_by_uaa(mos_devs, sizeof(mos_devs), uaa); 682218729Shselasky return (retval); 683218729Shselasky} 684218729Shselasky 685218729Shselasky/* 686218729Shselasky * Attach the interface. Allocate softc structures, do ifmedia 687218729Shselasky * setup and ethernet/BPF attach. 688218729Shselasky */ 689218729Shselaskystatic int 690218729Shselaskymos_attach(device_t dev) 691218729Shselasky{ 692218729Shselasky struct usb_attach_arg *uaa = device_get_ivars(dev); 693218729Shselasky struct mos_softc *sc = device_get_softc(dev); 694218729Shselasky struct usb_ether *ue = &sc->sc_ue; 695218729Shselasky uint8_t iface_index; 696218729Shselasky int error; 697218729Shselasky 698218729Shselasky sc->mos_flags = USB_GET_DRIVER_INFO(uaa); 699218729Shselasky 700218729Shselasky device_set_usb_desc(dev); 701218729Shselasky mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 702218729Shselasky 703218729Shselasky iface_index = MOS_IFACE_IDX; 704218729Shselasky error = usbd_transfer_setup(uaa->device, &iface_index, 705218729Shselasky sc->sc_xfer, mos_config, MOS_ENDPT_MAX, 706218729Shselasky sc, &sc->sc_mtx); 707218729Shselasky 708218729Shselasky if (error) { 709218729Shselasky device_printf(dev, "allocating USB transfers failed\n"); 710218729Shselasky goto detach; 711218729Shselasky } 712218729Shselasky ue->ue_sc = sc; 713218729Shselasky ue->ue_dev = dev; 714218729Shselasky ue->ue_udev = uaa->device; 715218729Shselasky ue->ue_mtx = &sc->sc_mtx; 716218729Shselasky ue->ue_methods = &mos_ue_methods; 717218729Shselasky 718218729Shselasky 719218729Shselasky if (sc->mos_flags & MCS7730) { 720218729Shselasky MOS_DPRINTFN("model: MCS7730"); 721218729Shselasky } else if (sc->mos_flags & MCS7830) { 722218729Shselasky MOS_DPRINTFN("model: MCS7830"); 723232257Skevlo } else if (sc->mos_flags & MCS7832) { 724232257Skevlo MOS_DPRINTFN("model: MCS7832"); 725218729Shselasky } 726218729Shselasky error = uether_ifattach(ue); 727218729Shselasky if (error) { 728218729Shselasky device_printf(dev, "could not attach interface\n"); 729218729Shselasky goto detach; 730218729Shselasky } 731218729Shselasky return (0); 732218729Shselasky 733218729Shselasky 734218729Shselaskydetach: 735218729Shselasky mos_detach(dev); 736218729Shselasky return (ENXIO); 737218729Shselasky} 738218729Shselasky 739218729Shselasky 740218729Shselaskystatic void 741218729Shselaskymos_attach_post(struct usb_ether *ue) 742218729Shselasky{ 743218729Shselasky struct mos_softc *sc = uether_getsc(ue); 744218729Shselasky int err; 745218729Shselasky 746218729Shselasky /* Read MAC address, inform the world. */ 747218729Shselasky err = mos_readmac(sc, ue->ue_eaddr); 748218729Shselasky 749218729Shselasky if (err) 750218729Shselasky MOS_DPRINTFN("couldn't get MAC address"); 751218729Shselasky 752218729Shselasky MOS_DPRINTFN("address: %s", ether_sprintf(ue->ue_eaddr)); 753218729Shselasky 754218729Shselasky mos_chip_init(sc); 755218729Shselasky} 756218729Shselasky 757218729Shselaskystatic int 758218729Shselaskymos_detach(device_t dev) 759218729Shselasky{ 760218729Shselasky struct mos_softc *sc = device_get_softc(dev); 761218729Shselasky struct usb_ether *ue = &sc->sc_ue; 762218729Shselasky 763218729Shselasky usbd_transfer_unsetup(sc->sc_xfer, MOS_ENDPT_MAX); 764218729Shselasky uether_ifdetach(ue); 765218729Shselasky mtx_destroy(&sc->sc_mtx); 766218729Shselasky 767218729Shselasky return (0); 768218729Shselasky} 769218729Shselasky 770218729Shselasky 771218729Shselasky 772218729Shselasky 773218729Shselasky/* 774218729Shselasky * A frame has been uploaded: pass the resulting mbuf chain up to 775218729Shselasky * the higher level protocols. 776218729Shselasky */ 777218729Shselaskystatic void 778218729Shselaskymos_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) 779218729Shselasky{ 780218729Shselasky struct mos_softc *sc = usbd_xfer_softc(xfer); 781218729Shselasky struct usb_ether *ue = &sc->sc_ue; 782218729Shselasky struct ifnet *ifp = uether_getifp(ue); 783218729Shselasky 784218729Shselasky uint8_t rxstat = 0; 785218729Shselasky uint32_t actlen; 786218729Shselasky uint16_t pktlen = 0; 787218729Shselasky struct usb_page_cache *pc; 788218729Shselasky 789218729Shselasky usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 790218729Shselasky pc = usbd_xfer_get_frame(xfer, 0); 791218729Shselasky 792218729Shselasky switch (USB_GET_STATE(xfer)) { 793218729Shselasky case USB_ST_TRANSFERRED: 794218729Shselasky MOS_DPRINTFN("actlen : %d", actlen); 795218729Shselasky if (actlen <= 1) { 796271832Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 797218729Shselasky goto tr_setup; 798218729Shselasky } 799218729Shselasky /* evaluate status byte at the end */ 800218729Shselasky usbd_copy_out(pc, actlen - sizeof(rxstat), &rxstat, 801218729Shselasky sizeof(rxstat)); 802218729Shselasky 803218729Shselasky if (rxstat != MOS_RXSTS_VALID) { 804218729Shselasky MOS_DPRINTFN("erroneous frame received"); 805218729Shselasky if (rxstat & MOS_RXSTS_SHORT_FRAME) 806218729Shselasky MOS_DPRINTFN("frame size less than 64 bytes"); 807218765Shselasky if (rxstat & MOS_RXSTS_LARGE_FRAME) { 808218765Shselasky MOS_DPRINTFN("frame size larger than " 809218765Shselasky "1532 bytes"); 810218765Shselasky } 811218729Shselasky if (rxstat & MOS_RXSTS_CRC_ERROR) 812218729Shselasky MOS_DPRINTFN("CRC error"); 813218729Shselasky if (rxstat & MOS_RXSTS_ALIGN_ERROR) 814218729Shselasky MOS_DPRINTFN("alignment error"); 815271832Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 816218729Shselasky goto tr_setup; 817218729Shselasky } 818218729Shselasky /* Remember the last byte was used for the status fields */ 819218729Shselasky pktlen = actlen - 1; 820218729Shselasky if (pktlen < sizeof(struct ether_header)) { 821218765Shselasky MOS_DPRINTFN("error: pktlen %d is smaller " 822218765Shselasky "than ether_header %zd", pktlen, 823218765Shselasky sizeof(struct ether_header)); 824271832Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 825218729Shselasky goto tr_setup; 826218729Shselasky } 827218729Shselasky uether_rxbuf(ue, pc, 0, actlen); 828218729Shselasky /* FALLTHROUGH */ 829218729Shselasky case USB_ST_SETUP: 830218729Shselaskytr_setup: 831218729Shselasky usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 832218729Shselasky usbd_transfer_submit(xfer); 833218729Shselasky uether_rxflush(ue); 834218729Shselasky return; 835218729Shselasky default: 836218729Shselasky MOS_DPRINTFN("bulk read error, %s", usbd_errstr(error)); 837218729Shselasky if (error != USB_ERR_CANCELLED) { 838218729Shselasky usbd_xfer_set_stall(xfer); 839218729Shselasky goto tr_setup; 840218729Shselasky } 841218729Shselasky MOS_DPRINTFN("start rx %i", usbd_xfer_max_len(xfer)); 842218729Shselasky return; 843218729Shselasky } 844218729Shselasky} 845218729Shselasky 846218729Shselasky/* 847218729Shselasky * A frame was downloaded to the chip. It's safe for us to clean up 848218729Shselasky * the list buffers. 849218729Shselasky */ 850218729Shselaskystatic void 851218729Shselaskymos_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) 852218729Shselasky{ 853218729Shselasky struct mos_softc *sc = usbd_xfer_softc(xfer); 854218729Shselasky struct ifnet *ifp = uether_getifp(&sc->sc_ue); 855218729Shselasky struct usb_page_cache *pc; 856218729Shselasky struct mbuf *m; 857218729Shselasky 858218729Shselasky 859218729Shselasky 860218729Shselasky switch (USB_GET_STATE(xfer)) { 861218729Shselasky case USB_ST_TRANSFERRED: 862218729Shselasky MOS_DPRINTFN("transfer of complete"); 863271832Sglebius if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 864218729Shselasky /* FALLTHROUGH */ 865218729Shselasky case USB_ST_SETUP: 866218729Shselaskytr_setup: 867218729Shselasky /* 868218729Shselasky * XXX: don't send anything if there is no link? 869218729Shselasky */ 870218729Shselasky IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 871218729Shselasky if (m == NULL) 872218729Shselasky return; 873218729Shselasky 874218729Shselasky pc = usbd_xfer_get_frame(xfer, 0); 875218729Shselasky usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len); 876218729Shselasky 877218729Shselasky usbd_xfer_set_frame_len(xfer, 0, m->m_pkthdr.len); 878218729Shselasky 879218729Shselasky 880218729Shselasky /* 881218729Shselasky * if there's a BPF listener, bounce a copy 882218729Shselasky * of this frame to him: 883218729Shselasky */ 884218729Shselasky BPF_MTAP(ifp, m); 885218729Shselasky 886218729Shselasky m_freem(m); 887218729Shselasky 888218729Shselasky usbd_transfer_submit(xfer); 889218729Shselasky 890271832Sglebius if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 891218729Shselasky return; 892218729Shselasky default: 893218729Shselasky MOS_DPRINTFN("usb error on tx: %s\n", usbd_errstr(error)); 894271832Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 895218729Shselasky if (error != USB_ERR_CANCELLED) { 896218729Shselasky usbd_xfer_set_stall(xfer); 897218729Shselasky goto tr_setup; 898218729Shselasky } 899218729Shselasky return; 900218729Shselasky } 901218729Shselasky} 902218729Shselasky 903218729Shselaskystatic void 904218729Shselaskymos_tick(struct usb_ether *ue) 905218729Shselasky{ 906218729Shselasky struct mos_softc *sc = uether_getsc(ue); 907218729Shselasky struct mii_data *mii = GET_MII(sc); 908218729Shselasky 909218729Shselasky MOS_LOCK_ASSERT(sc, MA_OWNED); 910218729Shselasky 911218729Shselasky mii_tick(mii); 912218729Shselasky if (!sc->mos_link && mii->mii_media_status & IFM_ACTIVE && 913218729Shselasky IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 914218729Shselasky MOS_DPRINTFN("got link"); 915218729Shselasky sc->mos_link++; 916218729Shselasky mos_start(ue); 917218729Shselasky } 918218729Shselasky} 919218729Shselasky 920218729Shselasky 921218729Shselaskystatic void 922218729Shselaskymos_start(struct usb_ether *ue) 923218729Shselasky{ 924218729Shselasky struct mos_softc *sc = uether_getsc(ue); 925218729Shselasky 926218729Shselasky /* 927218729Shselasky * start the USB transfers, if not already started: 928218729Shselasky */ 929218729Shselasky usbd_transfer_start(sc->sc_xfer[MOS_ENDPT_TX]); 930218729Shselasky usbd_transfer_start(sc->sc_xfer[MOS_ENDPT_RX]); 931218729Shselasky usbd_transfer_start(sc->sc_xfer[MOS_ENDPT_INTR]); 932218729Shselasky} 933218729Shselasky 934218729Shselaskystatic void 935218729Shselaskymos_init(struct usb_ether *ue) 936218729Shselasky{ 937218729Shselasky struct mos_softc *sc = uether_getsc(ue); 938218729Shselasky struct ifnet *ifp = uether_getifp(ue); 939218729Shselasky uint8_t rxmode; 940218729Shselasky 941218729Shselasky MOS_LOCK_ASSERT(sc, MA_OWNED); 942218729Shselasky 943218729Shselasky /* Cancel pending I/O and free all RX/TX buffers. */ 944218729Shselasky mos_reset(sc); 945218729Shselasky 946218729Shselasky /* Write MAC address */ 947218729Shselasky mos_writemac(sc, IF_LLADDR(ifp)); 948218729Shselasky 949218729Shselasky /* Read and set transmitter IPG values */ 950218729Shselasky sc->mos_ipgs[0] = mos_reg_read_1(sc, MOS_IPG0); 951218729Shselasky sc->mos_ipgs[1] = mos_reg_read_1(sc, MOS_IPG1); 952218729Shselasky mos_reg_write_1(sc, MOS_IPG0, sc->mos_ipgs[0]); 953218729Shselasky mos_reg_write_1(sc, MOS_IPG1, sc->mos_ipgs[1]); 954218729Shselasky 955218729Shselasky /* 956218729Shselasky * Enable receiver and transmitter, bridge controls speed/duplex 957218729Shselasky * mode 958218729Shselasky */ 959218729Shselasky rxmode = mos_reg_read_1(sc, MOS_CTL); 960218729Shselasky rxmode |= MOS_CTL_RX_ENB | MOS_CTL_TX_ENB | MOS_CTL_BS_ENB; 961218729Shselasky rxmode &= ~(MOS_CTL_SLEEP); 962218729Shselasky 963218729Shselasky mos_setpromisc(ue); 964218729Shselasky 965218729Shselasky /* XXX: broadcast mode? */ 966218729Shselasky mos_reg_write_1(sc, MOS_CTL, rxmode); 967218729Shselasky 968218729Shselasky /* Load the multicast filter. */ 969218729Shselasky mos_setmulti(ue); 970218729Shselasky 971218729Shselasky ifp->if_drv_flags |= IFF_DRV_RUNNING; 972218729Shselasky mos_start(ue); 973218729Shselasky} 974218729Shselasky 975218729Shselasky 976218729Shselaskystatic void 977218729Shselaskymos_intr_callback(struct usb_xfer *xfer, usb_error_t error) 978218729Shselasky{ 979218729Shselasky struct mos_softc *sc = usbd_xfer_softc(xfer); 980218729Shselasky struct ifnet *ifp = uether_getifp(&sc->sc_ue); 981218729Shselasky struct usb_page_cache *pc; 982218729Shselasky uint32_t pkt; 983218729Shselasky int actlen; 984218729Shselasky 985271832Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 986218729Shselasky 987218729Shselasky usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 988218729Shselasky MOS_DPRINTFN("actlen %i", actlen); 989218729Shselasky 990218729Shselasky switch (USB_GET_STATE(xfer)) { 991218729Shselasky case USB_ST_TRANSFERRED: 992218729Shselasky 993218729Shselasky pc = usbd_xfer_get_frame(xfer, 0); 994218729Shselasky usbd_copy_out(pc, 0, &pkt, sizeof(pkt)); 995218729Shselasky /* FALLTHROUGH */ 996218729Shselasky case USB_ST_SETUP: 997218729Shselaskytr_setup: 998218729Shselasky return; 999218729Shselasky default: 1000218729Shselasky if (error != USB_ERR_CANCELLED) { 1001218729Shselasky usbd_xfer_set_stall(xfer); 1002218729Shselasky goto tr_setup; 1003218729Shselasky } 1004218729Shselasky return; 1005218729Shselasky } 1006218729Shselasky} 1007218729Shselasky 1008218729Shselasky 1009218729Shselasky/* 1010218729Shselasky * Stop the adapter and free any mbufs allocated to the 1011218729Shselasky * RX and TX lists. 1012218729Shselasky */ 1013218729Shselaskystatic void 1014218729Shselaskymos_stop(struct usb_ether *ue) 1015218729Shselasky{ 1016218729Shselasky struct mos_softc *sc = uether_getsc(ue); 1017218729Shselasky struct ifnet *ifp = uether_getifp(ue); 1018218729Shselasky 1019218729Shselasky mos_reset(sc); 1020218729Shselasky 1021218729Shselasky MOS_LOCK_ASSERT(sc, MA_OWNED); 1022218729Shselasky ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1023218729Shselasky 1024218729Shselasky /* stop all the transfers, if not already stopped */ 1025218729Shselasky usbd_transfer_stop(sc->sc_xfer[MOS_ENDPT_TX]); 1026218729Shselasky usbd_transfer_stop(sc->sc_xfer[MOS_ENDPT_RX]); 1027218729Shselasky usbd_transfer_stop(sc->sc_xfer[MOS_ENDPT_INTR]); 1028218729Shselasky 1029218729Shselasky sc->mos_link = 0; 1030218729Shselasky} 1031