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