if_udav.c revision 194228
1184610Salfred/* $NetBSD: if_udav.c,v 1.2 2003/09/04 15:17:38 tsutsui Exp $ */ 2184610Salfred/* $nabe: if_udav.c,v 1.3 2003/08/21 16:57:19 nabe Exp $ */ 3184610Salfred/* $FreeBSD: head/sys/dev/usb/net/if_udav.c 194228 2009-06-15 01:02:43Z thompsa $ */ 4184610Salfred/*- 5184610Salfred * Copyright (c) 2003 6184610Salfred * Shingo WATANABE <nabe@nabechan.org>. All rights reserved. 7184610Salfred * 8184610Salfred * Redistribution and use in source and binary forms, with or without 9184610Salfred * modification, are permitted provided that the following conditions 10184610Salfred * are met: 11184610Salfred * 1. Redistributions of source code must retain the above copyright 12184610Salfred * notice, this list of conditions and the following disclaimer. 13184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 14184610Salfred * notice, this list of conditions and the following disclaimer in the 15184610Salfred * documentation and/or other materials provided with the distribution. 16184610Salfred * 3. Neither the name of the author nor the names of any co-contributors 17184610Salfred * may be used to endorse or promote products derived from this software 18184610Salfred * without specific prior written permission. 19184610Salfred * 20184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30184610Salfred * SUCH DAMAGE. 31184610Salfred * 32184610Salfred */ 33184610Salfred 34184610Salfred/* 35184610Salfred * DM9601(DAVICOM USB to Ethernet MAC Controller with Integrated 10/100 PHY) 36184610Salfred * The spec can be found at the following url. 37184610Salfred * http://www.davicom.com.tw/big5/download/Data%20Sheet/DM9601-DS-P01-930914.pdf 38184610Salfred */ 39184610Salfred 40184610Salfred/* 41184610Salfred * TODO: 42184610Salfred * Interrupt Endpoint support 43184610Salfred * External PHYs 44184610Salfred */ 45184610Salfred 46184610Salfred#include <sys/cdefs.h> 47184610Salfred__FBSDID("$FreeBSD: head/sys/dev/usb/net/if_udav.c 194228 2009-06-15 01:02:43Z thompsa $"); 48184610Salfred 49188746Sthompsa#include "usbdevs.h" 50188942Sthompsa#include <dev/usb/usb.h> 51188942Sthompsa#include <dev/usb/usb_mfunc.h> 52188942Sthompsa#include <dev/usb/usb_error.h> 53184610Salfred 54184610Salfred#define USB_DEBUG_VAR udav_debug 55184610Salfred 56188942Sthompsa#include <dev/usb/usb_core.h> 57188942Sthompsa#include <dev/usb/usb_lookup.h> 58188942Sthompsa#include <dev/usb/usb_process.h> 59188942Sthompsa#include <dev/usb/usb_debug.h> 60188942Sthompsa#include <dev/usb/usb_request.h> 61188942Sthompsa#include <dev/usb/usb_busdma.h> 62188942Sthompsa#include <dev/usb/usb_util.h> 63184610Salfred 64188942Sthompsa#include <dev/usb/net/usb_ethernet.h> 65188942Sthompsa#include <dev/usb/net/if_udavreg.h> 66184610Salfred 67184610Salfred/* prototypes */ 68184610Salfred 69184610Salfredstatic device_probe_t udav_probe; 70184610Salfredstatic device_attach_t udav_attach; 71184610Salfredstatic device_detach_t udav_detach; 72184610Salfred 73193045Sthompsastatic usb_callback_t udav_bulk_write_callback; 74193045Sthompsastatic usb_callback_t udav_bulk_read_callback; 75193045Sthompsastatic usb_callback_t udav_intr_callback; 76184610Salfred 77193045Sthompsastatic uether_fn_t udav_attach_post; 78193045Sthompsastatic uether_fn_t udav_init; 79193045Sthompsastatic uether_fn_t udav_stop; 80193045Sthompsastatic uether_fn_t udav_start; 81193045Sthompsastatic uether_fn_t udav_tick; 82193045Sthompsastatic uether_fn_t udav_setmulti; 83193045Sthompsastatic uether_fn_t udav_setpromisc; 84184610Salfred 85188412Sthompsastatic int udav_csr_read(struct udav_softc *, uint16_t, void *, int); 86188412Sthompsastatic int udav_csr_write(struct udav_softc *, uint16_t, void *, int); 87188412Sthompsastatic uint8_t udav_csr_read1(struct udav_softc *, uint16_t); 88188412Sthompsastatic int udav_csr_write1(struct udav_softc *, uint16_t, uint8_t); 89188412Sthompsastatic void udav_reset(struct udav_softc *); 90188412Sthompsastatic int udav_ifmedia_upd(struct ifnet *); 91188412Sthompsastatic void udav_ifmedia_status(struct ifnet *, struct ifmediareq *); 92184610Salfred 93188412Sthompsastatic miibus_readreg_t udav_miibus_readreg; 94188412Sthompsastatic miibus_writereg_t udav_miibus_writereg; 95188412Sthompsastatic miibus_statchg_t udav_miibus_statchg; 96184610Salfred 97192984Sthompsastatic const struct usb_config udav_config[UDAV_N_TRANSFER] = { 98184610Salfred 99187259Sthompsa [UDAV_BULK_DT_WR] = { 100184610Salfred .type = UE_BULK, 101184610Salfred .endpoint = UE_ADDR_ANY, 102184610Salfred .direction = UE_DIR_OUT, 103190734Sthompsa .bufsize = (MCLBYTES + 2), 104190734Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 105190734Sthompsa .callback = udav_bulk_write_callback, 106190734Sthompsa .timeout = 10000, /* 10 seconds */ 107184610Salfred }, 108184610Salfred 109187259Sthompsa [UDAV_BULK_DT_RD] = { 110184610Salfred .type = UE_BULK, 111184610Salfred .endpoint = UE_ADDR_ANY, 112184610Salfred .direction = UE_DIR_IN, 113190734Sthompsa .bufsize = (MCLBYTES + 3), 114190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 115190734Sthompsa .callback = udav_bulk_read_callback, 116190734Sthompsa .timeout = 0, /* no timeout */ 117184610Salfred }, 118184610Salfred 119187259Sthompsa [UDAV_INTR_DT_RD] = { 120184610Salfred .type = UE_INTERRUPT, 121184610Salfred .endpoint = UE_ADDR_ANY, 122184610Salfred .direction = UE_DIR_IN, 123190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 124190734Sthompsa .bufsize = 0, /* use wMaxPacketSize */ 125190734Sthompsa .callback = udav_intr_callback, 126184610Salfred }, 127184610Salfred}; 128184610Salfred 129184610Salfredstatic device_method_t udav_methods[] = { 130184610Salfred /* Device interface */ 131184610Salfred DEVMETHOD(device_probe, udav_probe), 132184610Salfred DEVMETHOD(device_attach, udav_attach), 133184610Salfred DEVMETHOD(device_detach, udav_detach), 134184610Salfred 135184610Salfred /* bus interface */ 136184610Salfred DEVMETHOD(bus_print_child, bus_generic_print_child), 137184610Salfred DEVMETHOD(bus_driver_added, bus_generic_driver_added), 138184610Salfred 139184610Salfred /* MII interface */ 140188412Sthompsa DEVMETHOD(miibus_readreg, udav_miibus_readreg), 141188412Sthompsa DEVMETHOD(miibus_writereg, udav_miibus_writereg), 142188412Sthompsa DEVMETHOD(miibus_statchg, udav_miibus_statchg), 143184610Salfred 144184610Salfred {0, 0} 145184610Salfred}; 146184610Salfred 147184610Salfredstatic driver_t udav_driver = { 148184610Salfred .name = "udav", 149184610Salfred .methods = udav_methods, 150184610Salfred .size = sizeof(struct udav_softc), 151184610Salfred}; 152184610Salfred 153184610Salfredstatic devclass_t udav_devclass; 154184610Salfred 155189275SthompsaDRIVER_MODULE(udav, uhub, udav_driver, udav_devclass, NULL, 0); 156184610SalfredDRIVER_MODULE(miibus, udav, miibus_driver, miibus_devclass, 0, 0); 157188942SthompsaMODULE_DEPEND(udav, uether, 1, 1, 1); 158188942SthompsaMODULE_DEPEND(udav, usb, 1, 1, 1); 159184610SalfredMODULE_DEPEND(udav, ether, 1, 1, 1); 160184610SalfredMODULE_DEPEND(udav, miibus, 1, 1, 1); 161184610Salfred 162192984Sthompsastatic const struct usb_ether_methods udav_ue_methods = { 163188412Sthompsa .ue_attach_post = udav_attach_post, 164188412Sthompsa .ue_start = udav_start, 165188412Sthompsa .ue_init = udav_init, 166188412Sthompsa .ue_stop = udav_stop, 167188412Sthompsa .ue_tick = udav_tick, 168188412Sthompsa .ue_setmulti = udav_setmulti, 169188412Sthompsa .ue_setpromisc = udav_setpromisc, 170188412Sthompsa .ue_mii_upd = udav_ifmedia_upd, 171188412Sthompsa .ue_mii_sts = udav_ifmedia_status, 172188412Sthompsa}; 173188412Sthompsa 174184610Salfred#if USB_DEBUG 175184610Salfredstatic int udav_debug = 0; 176184610Salfred 177192502SthompsaSYSCTL_NODE(_hw_usb, OID_AUTO, udav, CTLFLAG_RW, 0, "USB udav"); 178192502SthompsaSYSCTL_INT(_hw_usb_udav, OID_AUTO, debug, CTLFLAG_RW, &udav_debug, 0, 179184610Salfred "Debug level"); 180184610Salfred#endif 181184610Salfred 182188412Sthompsa#define UDAV_SETBIT(sc, reg, x) \ 183188412Sthompsa udav_csr_write1(sc, reg, udav_csr_read1(sc, reg) | (x)) 184184610Salfred 185188412Sthompsa#define UDAV_CLRBIT(sc, reg, x) \ 186188412Sthompsa udav_csr_write1(sc, reg, udav_csr_read1(sc, reg) & ~(x)) 187184610Salfred 188192984Sthompsastatic const struct usb_device_id udav_devs[] = { 189184610Salfred /* ShanTou DM9601 USB NIC */ 190184610Salfred {USB_VPI(USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_DM9601, 0)}, 191184610Salfred /* ShanTou ST268 USB NIC */ 192184610Salfred {USB_VPI(USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_ST268, 0)}, 193184610Salfred /* Corega USB-TXC */ 194184610Salfred {USB_VPI(USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TXC, 0)}, 195184610Salfred}; 196184610Salfred 197188412Sthompsastatic void 198192984Sthompsaudav_attach_post(struct usb_ether *ue) 199188412Sthompsa{ 200194228Sthompsa struct udav_softc *sc = uether_getsc(ue); 201188412Sthompsa 202188412Sthompsa /* reset the adapter */ 203188412Sthompsa udav_reset(sc); 204188412Sthompsa 205188412Sthompsa /* Get Ethernet Address */ 206188412Sthompsa udav_csr_read(sc, UDAV_PAR, ue->ue_eaddr, ETHER_ADDR_LEN); 207188412Sthompsa} 208188412Sthompsa 209184610Salfredstatic int 210184610Salfredudav_probe(device_t dev) 211184610Salfred{ 212192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 213184610Salfred 214192499Sthompsa if (uaa->usb_mode != USB_MODE_HOST) 215184610Salfred return (ENXIO); 216188412Sthompsa if (uaa->info.bConfigIndex != UDAV_CONFIG_INDEX) 217184610Salfred return (ENXIO); 218188412Sthompsa if (uaa->info.bIfaceIndex != UDAV_IFACE_INDEX) 219184610Salfred return (ENXIO); 220188412Sthompsa 221194228Sthompsa return (usbd_lookup_id_by_uaa(udav_devs, sizeof(udav_devs), uaa)); 222184610Salfred} 223184610Salfred 224184610Salfredstatic int 225184610Salfredudav_attach(device_t dev) 226184610Salfred{ 227192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 228184610Salfred struct udav_softc *sc = device_get_softc(dev); 229192984Sthompsa struct usb_ether *ue = &sc->sc_ue; 230184610Salfred uint8_t iface_index; 231188412Sthompsa int error; 232184610Salfred 233184610Salfred sc->sc_flags = USB_GET_DRIVER_INFO(uaa); 234184610Salfred 235194228Sthompsa device_set_usb_desc(dev); 236184610Salfred 237188412Sthompsa mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 238184610Salfred 239184610Salfred iface_index = UDAV_IFACE_INDEX; 240194228Sthompsa error = usbd_transfer_setup(uaa->device, &iface_index, 241187259Sthompsa sc->sc_xfer, udav_config, UDAV_N_TRANSFER, sc, &sc->sc_mtx); 242184610Salfred if (error) { 243188412Sthompsa device_printf(dev, "allocating USB transfers failed!\n"); 244184610Salfred goto detach; 245184610Salfred } 246188412Sthompsa 247188412Sthompsa ue->ue_sc = sc; 248188412Sthompsa ue->ue_dev = dev; 249188412Sthompsa ue->ue_udev = uaa->device; 250188412Sthompsa ue->ue_mtx = &sc->sc_mtx; 251188412Sthompsa ue->ue_methods = &udav_ue_methods; 252188412Sthompsa 253194228Sthompsa error = uether_ifattach(ue); 254184610Salfred if (error) { 255188412Sthompsa device_printf(dev, "could not attach interface\n"); 256184610Salfred goto detach; 257184610Salfred } 258184610Salfred 259184610Salfred return (0); /* success */ 260184610Salfred 261184610Salfreddetach: 262184610Salfred udav_detach(dev); 263184610Salfred return (ENXIO); /* failure */ 264184610Salfred} 265184610Salfred 266184610Salfredstatic int 267184610Salfredudav_detach(device_t dev) 268184610Salfred{ 269184610Salfred struct udav_softc *sc = device_get_softc(dev); 270192984Sthompsa struct usb_ether *ue = &sc->sc_ue; 271184610Salfred 272194228Sthompsa usbd_transfer_unsetup(sc->sc_xfer, UDAV_N_TRANSFER); 273194228Sthompsa uether_ifdetach(ue); 274184610Salfred mtx_destroy(&sc->sc_mtx); 275184610Salfred 276184610Salfred return (0); 277184610Salfred} 278184610Salfred 279184610Salfred#if 0 280188412Sthompsastatic int 281188412Sthompsaudav_mem_read(struct udav_softc *sc, uint16_t offset, void *buf, 282188412Sthompsa int len) 283184610Salfred{ 284192984Sthompsa struct usb_device_request req; 285184610Salfred 286184610Salfred len &= 0xff; 287184610Salfred 288184610Salfred req.bmRequestType = UT_READ_VENDOR_DEVICE; 289184610Salfred req.bRequest = UDAV_REQ_MEM_READ; 290184610Salfred USETW(req.wValue, 0x0000); 291184610Salfred USETW(req.wIndex, offset); 292184610Salfred USETW(req.wLength, len); 293184610Salfred 294194228Sthompsa return (uether_do_request(&sc->sc_ue, &req, buf, 1000)); 295184610Salfred} 296184610Salfred 297188412Sthompsastatic int 298188412Sthompsaudav_mem_write(struct udav_softc *sc, uint16_t offset, void *buf, 299188412Sthompsa int len) 300184610Salfred{ 301192984Sthompsa struct usb_device_request req; 302184610Salfred 303184610Salfred len &= 0xff; 304184610Salfred 305184610Salfred req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 306184610Salfred req.bRequest = UDAV_REQ_MEM_WRITE; 307184610Salfred USETW(req.wValue, 0x0000); 308184610Salfred USETW(req.wIndex, offset); 309184610Salfred USETW(req.wLength, len); 310184610Salfred 311194228Sthompsa return (uether_do_request(&sc->sc_ue, &req, buf, 1000)); 312184610Salfred} 313184610Salfred 314188412Sthompsastatic int 315188412Sthompsaudav_mem_write1(struct udav_softc *sc, uint16_t offset, 316184610Salfred uint8_t ch) 317184610Salfred{ 318192984Sthompsa struct usb_device_request req; 319184610Salfred 320184610Salfred req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 321184610Salfred req.bRequest = UDAV_REQ_MEM_WRITE1; 322184610Salfred USETW(req.wValue, ch); 323184610Salfred USETW(req.wIndex, offset); 324184610Salfred USETW(req.wLength, 0x0000); 325184610Salfred 326194228Sthompsa return (uether_do_request(&sc->sc_ue, &req, NULL, 1000)); 327184610Salfred} 328184610Salfred#endif 329184610Salfred 330188412Sthompsastatic int 331188412Sthompsaudav_csr_read(struct udav_softc *sc, uint16_t offset, void *buf, int len) 332184610Salfred{ 333192984Sthompsa struct usb_device_request req; 334184610Salfred 335184610Salfred len &= 0xff; 336184610Salfred 337184610Salfred req.bmRequestType = UT_READ_VENDOR_DEVICE; 338184610Salfred req.bRequest = UDAV_REQ_REG_READ; 339184610Salfred USETW(req.wValue, 0x0000); 340184610Salfred USETW(req.wIndex, offset); 341184610Salfred USETW(req.wLength, len); 342184610Salfred 343194228Sthompsa return (uether_do_request(&sc->sc_ue, &req, buf, 1000)); 344184610Salfred} 345184610Salfred 346188412Sthompsastatic int 347188412Sthompsaudav_csr_write(struct udav_softc *sc, uint16_t offset, void *buf, int len) 348184610Salfred{ 349192984Sthompsa struct usb_device_request req; 350184610Salfred 351184610Salfred offset &= 0xff; 352184610Salfred len &= 0xff; 353184610Salfred 354184610Salfred req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 355184610Salfred req.bRequest = UDAV_REQ_REG_WRITE; 356184610Salfred USETW(req.wValue, 0x0000); 357184610Salfred USETW(req.wIndex, offset); 358184610Salfred USETW(req.wLength, len); 359184610Salfred 360194228Sthompsa return (uether_do_request(&sc->sc_ue, &req, buf, 1000)); 361184610Salfred} 362184610Salfred 363184610Salfredstatic uint8_t 364188412Sthompsaudav_csr_read1(struct udav_softc *sc, uint16_t offset) 365184610Salfred{ 366184610Salfred uint8_t val; 367184610Salfred 368188412Sthompsa udav_csr_read(sc, offset, &val, 1); 369184610Salfred return (val); 370184610Salfred} 371184610Salfred 372188412Sthompsastatic int 373188412Sthompsaudav_csr_write1(struct udav_softc *sc, uint16_t offset, 374184610Salfred uint8_t ch) 375184610Salfred{ 376192984Sthompsa struct usb_device_request req; 377184610Salfred 378184610Salfred offset &= 0xff; 379184610Salfred 380184610Salfred req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 381184610Salfred req.bRequest = UDAV_REQ_REG_WRITE1; 382184610Salfred USETW(req.wValue, ch); 383184610Salfred USETW(req.wIndex, offset); 384184610Salfred USETW(req.wLength, 0x0000); 385184610Salfred 386194228Sthompsa return (uether_do_request(&sc->sc_ue, &req, NULL, 1000)); 387184610Salfred} 388184610Salfred 389184610Salfredstatic void 390192984Sthompsaudav_init(struct usb_ether *ue) 391184610Salfred{ 392188412Sthompsa struct udav_softc *sc = ue->ue_sc; 393194228Sthompsa struct ifnet *ifp = uether_getifp(&sc->sc_ue); 394184610Salfred 395188412Sthompsa UDAV_LOCK_ASSERT(sc, MA_OWNED); 396184610Salfred 397184610Salfred /* 398184610Salfred * Cancel pending I/O 399184610Salfred */ 400188412Sthompsa udav_stop(ue); 401184610Salfred 402184610Salfred /* set MAC address */ 403188412Sthompsa udav_csr_write(sc, UDAV_PAR, IF_LLADDR(ifp), ETHER_ADDR_LEN); 404184610Salfred 405184610Salfred /* initialize network control register */ 406184610Salfred 407184610Salfred /* disable loopback */ 408188412Sthompsa UDAV_CLRBIT(sc, UDAV_NCR, UDAV_NCR_LBK0 | UDAV_NCR_LBK1); 409184610Salfred 410184610Salfred /* Initialize RX control register */ 411188412Sthompsa UDAV_SETBIT(sc, UDAV_RCR, UDAV_RCR_DIS_LONG | UDAV_RCR_DIS_CRC); 412184610Salfred 413184610Salfred /* load multicast filter and update promiscious mode bit */ 414188412Sthompsa udav_setpromisc(ue); 415184610Salfred 416184610Salfred /* enable RX */ 417188412Sthompsa UDAV_SETBIT(sc, UDAV_RCR, UDAV_RCR_RXEN); 418184610Salfred 419184610Salfred /* clear POWER_DOWN state of internal PHY */ 420188412Sthompsa UDAV_SETBIT(sc, UDAV_GPCR, UDAV_GPCR_GEP_CNTL0); 421188412Sthompsa UDAV_CLRBIT(sc, UDAV_GPR, UDAV_GPR_GEPIO0); 422184610Salfred 423194228Sthompsa usbd_transfer_set_stall(sc->sc_xfer[UDAV_BULK_DT_WR]); 424184610Salfred 425188412Sthompsa ifp->if_drv_flags |= IFF_DRV_RUNNING; 426188412Sthompsa udav_start(ue); 427184610Salfred} 428184610Salfred 429184610Salfredstatic void 430188412Sthompsaudav_reset(struct udav_softc *sc) 431184610Salfred{ 432188412Sthompsa int i; 433184610Salfred 434184610Salfred /* Select PHY */ 435184610Salfred#if 1 436184610Salfred /* 437184610Salfred * XXX: force select internal phy. 438184610Salfred * external phy routines are not tested. 439184610Salfred */ 440188412Sthompsa UDAV_CLRBIT(sc, UDAV_NCR, UDAV_NCR_EXT_PHY); 441184610Salfred#else 442188412Sthompsa if (sc->sc_flags & UDAV_EXT_PHY) 443188412Sthompsa UDAV_SETBIT(sc, UDAV_NCR, UDAV_NCR_EXT_PHY); 444188412Sthompsa else 445188412Sthompsa UDAV_CLRBIT(sc, UDAV_NCR, UDAV_NCR_EXT_PHY); 446184610Salfred#endif 447184610Salfred 448188412Sthompsa UDAV_SETBIT(sc, UDAV_NCR, UDAV_NCR_RST); 449184610Salfred 450188412Sthompsa for (i = 0; i < UDAV_TX_TIMEOUT; i++) { 451188412Sthompsa if (!(udav_csr_read1(sc, UDAV_NCR) & UDAV_NCR_RST)) 452184610Salfred break; 453194228Sthompsa if (uether_pause(&sc->sc_ue, hz / 100)) 454188412Sthompsa break; 455184610Salfred } 456184610Salfred 457194228Sthompsa uether_pause(&sc->sc_ue, hz / 100); 458184610Salfred} 459184610Salfred 460184610Salfred#define UDAV_BITS 6 461184610Salfredstatic void 462192984Sthompsaudav_setmulti(struct usb_ether *ue) 463184610Salfred{ 464188412Sthompsa struct udav_softc *sc = ue->ue_sc; 465194228Sthompsa struct ifnet *ifp = uether_getifp(&sc->sc_ue); 466188412Sthompsa struct ifmultiaddr *ifma; 467188412Sthompsa uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 468188412Sthompsa int h = 0; 469184610Salfred 470188412Sthompsa UDAV_LOCK_ASSERT(sc, MA_OWNED); 471184610Salfred 472188412Sthompsa if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 473188412Sthompsa UDAV_SETBIT(sc, UDAV_RCR, UDAV_RCR_ALL|UDAV_RCR_PRMSC); 474188412Sthompsa return; 475188412Sthompsa } 476188412Sthompsa 477188412Sthompsa /* first, zot all the existing hash bits */ 478188412Sthompsa memset(hashtbl, 0x00, sizeof(hashtbl)); 479188412Sthompsa hashtbl[7] |= 0x80; /* broadcast address */ 480188412Sthompsa udav_csr_write(sc, UDAV_MAR, hashtbl, sizeof(hashtbl)); 481188412Sthompsa 482188412Sthompsa /* now program new ones */ 483188412Sthompsa IF_ADDR_LOCK(ifp); 484188412Sthompsa TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) 485188412Sthompsa { 486188412Sthompsa if (ifma->ifma_addr->sa_family != AF_LINK) 487188412Sthompsa continue; 488188412Sthompsa h = ether_crc32_be(LLADDR((struct sockaddr_dl *) 489188412Sthompsa ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; 490188412Sthompsa hashtbl[h / 8] |= 1 << (h % 8); 491188412Sthompsa } 492188412Sthompsa IF_ADDR_UNLOCK(ifp); 493188412Sthompsa 494188412Sthompsa /* disable all multicast */ 495188412Sthompsa UDAV_CLRBIT(sc, UDAV_RCR, UDAV_RCR_ALL); 496188412Sthompsa 497188412Sthompsa /* write hash value to the register */ 498188412Sthompsa udav_csr_write(sc, UDAV_MAR, hashtbl, sizeof(hashtbl)); 499184610Salfred} 500184610Salfred 501184610Salfredstatic void 502192984Sthompsaudav_setpromisc(struct usb_ether *ue) 503184610Salfred{ 504188412Sthompsa struct udav_softc *sc = ue->ue_sc; 505194228Sthompsa struct ifnet *ifp = uether_getifp(&sc->sc_ue); 506184610Salfred uint8_t rxmode; 507184610Salfred 508188412Sthompsa rxmode = udav_csr_read1(sc, UDAV_RCR); 509184610Salfred rxmode &= ~(UDAV_RCR_ALL | UDAV_RCR_PRMSC); 510184610Salfred 511188412Sthompsa if (ifp->if_flags & IFF_PROMISC) 512184610Salfred rxmode |= UDAV_RCR_ALL | UDAV_RCR_PRMSC; 513188412Sthompsa else if (ifp->if_flags & IFF_ALLMULTI) 514184610Salfred rxmode |= UDAV_RCR_ALL; 515184610Salfred 516184610Salfred /* write new mode bits */ 517188412Sthompsa udav_csr_write1(sc, UDAV_RCR, rxmode); 518184610Salfred} 519184610Salfred 520184610Salfredstatic void 521192984Sthompsaudav_start(struct usb_ether *ue) 522184610Salfred{ 523188412Sthompsa struct udav_softc *sc = ue->ue_sc; 524184610Salfred 525188412Sthompsa /* 526188412Sthompsa * start the USB transfers, if not already started: 527188412Sthompsa */ 528194228Sthompsa usbd_transfer_start(sc->sc_xfer[UDAV_INTR_DT_RD]); 529194228Sthompsa usbd_transfer_start(sc->sc_xfer[UDAV_BULK_DT_RD]); 530194228Sthompsa usbd_transfer_start(sc->sc_xfer[UDAV_BULK_DT_WR]); 531184610Salfred} 532184610Salfred 533184610Salfredstatic void 534192984Sthompsaudav_bulk_write_callback(struct usb_xfer *xfer) 535184610Salfred{ 536184610Salfred struct udav_softc *sc = xfer->priv_sc; 537194228Sthompsa struct ifnet *ifp = uether_getifp(&sc->sc_ue); 538184610Salfred struct mbuf *m; 539188412Sthompsa int extra_len; 540188412Sthompsa int temp_len; 541184610Salfred uint8_t buf[2]; 542184610Salfred 543184610Salfred switch (USB_GET_STATE(xfer)) { 544184610Salfred case USB_ST_TRANSFERRED: 545184610Salfred DPRINTFN(11, "transfer complete\n"); 546184610Salfred ifp->if_opackets++; 547184610Salfred 548188412Sthompsa /* FALLTHROUGH */ 549184610Salfred case USB_ST_SETUP: 550188412Sthompsatr_setup: 551188412Sthompsa if ((sc->sc_flags & UDAV_FLAG_LINK) == 0) { 552184610Salfred /* 553184610Salfred * don't send anything if there is no link ! 554184610Salfred */ 555188412Sthompsa return; 556184610Salfred } 557184610Salfred IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 558184610Salfred 559188412Sthompsa if (m == NULL) 560188412Sthompsa return; 561188412Sthompsa if (m->m_pkthdr.len > MCLBYTES) 562184610Salfred m->m_pkthdr.len = MCLBYTES; 563184610Salfred if (m->m_pkthdr.len < UDAV_MIN_FRAME_LEN) { 564184610Salfred extra_len = UDAV_MIN_FRAME_LEN - m->m_pkthdr.len; 565184610Salfred } else { 566184610Salfred extra_len = 0; 567184610Salfred } 568184610Salfred 569184610Salfred temp_len = (m->m_pkthdr.len + extra_len); 570184610Salfred 571184610Salfred /* 572184610Salfred * the frame length is specified in the first 2 bytes of the 573184610Salfred * buffer 574184610Salfred */ 575184610Salfred buf[0] = (uint8_t)(temp_len); 576184610Salfred buf[1] = (uint8_t)(temp_len >> 8); 577184610Salfred 578184610Salfred temp_len += 2; 579184610Salfred 580194228Sthompsa usbd_copy_in(xfer->frbuffers, 0, buf, 2); 581184610Salfred 582194228Sthompsa usbd_m_copy_in(xfer->frbuffers, 2, 583184610Salfred m, 0, m->m_pkthdr.len); 584184610Salfred 585184610Salfred if (extra_len) { 586194228Sthompsa usbd_frame_zero(xfer->frbuffers, temp_len - extra_len, 587184610Salfred extra_len); 588184610Salfred } 589184610Salfred /* 590184610Salfred * if there's a BPF listener, bounce a copy 591184610Salfred * of this frame to him: 592184610Salfred */ 593184610Salfred BPF_MTAP(ifp, m); 594184610Salfred 595184610Salfred m_freem(m); 596184610Salfred 597184610Salfred xfer->frlengths[0] = temp_len; 598194228Sthompsa usbd_transfer_submit(xfer); 599184610Salfred return; 600184610Salfred 601184610Salfred default: /* Error */ 602184610Salfred DPRINTFN(11, "transfer error, %s\n", 603194228Sthompsa usbd_errstr(xfer->error)); 604184610Salfred 605188412Sthompsa ifp->if_oerrors++; 606188412Sthompsa 607184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 608184610Salfred /* try to clear stall first */ 609188412Sthompsa xfer->flags.stall_pipe = 1; 610188412Sthompsa goto tr_setup; 611184610Salfred } 612184610Salfred return; 613184610Salfred } 614184610Salfred} 615184610Salfred 616184610Salfredstatic void 617192984Sthompsaudav_bulk_read_callback(struct usb_xfer *xfer) 618184610Salfred{ 619184610Salfred struct udav_softc *sc = xfer->priv_sc; 620192984Sthompsa struct usb_ether *ue = &sc->sc_ue; 621194228Sthompsa struct ifnet *ifp = uether_getifp(ue); 622188412Sthompsa struct udav_rxpkt stat; 623188412Sthompsa int len; 624184610Salfred 625184610Salfred switch (USB_GET_STATE(xfer)) { 626184610Salfred case USB_ST_TRANSFERRED: 627184610Salfred 628188412Sthompsa if (xfer->actlen < sizeof(stat) + ETHER_CRC_LEN) { 629184610Salfred ifp->if_ierrors++; 630184610Salfred goto tr_setup; 631184610Salfred } 632194228Sthompsa usbd_copy_out(xfer->frbuffers, 0, &stat, sizeof(stat)); 633188412Sthompsa xfer->actlen -= sizeof(stat); 634188412Sthompsa len = min(xfer->actlen, le16toh(stat.pktlen)); 635188412Sthompsa len -= ETHER_CRC_LEN; 636184610Salfred 637188412Sthompsa if (stat.rxstat & UDAV_RSR_LCS) { 638184610Salfred ifp->if_collisions++; 639184610Salfred goto tr_setup; 640184610Salfred } 641188412Sthompsa if (stat.rxstat & UDAV_RSR_ERR) { 642184610Salfred ifp->if_ierrors++; 643184610Salfred goto tr_setup; 644184610Salfred } 645194228Sthompsa uether_rxbuf(ue, xfer->frbuffers, sizeof(stat), len); 646188412Sthompsa /* FALLTHROUGH */ 647184610Salfred case USB_ST_SETUP: 648184610Salfredtr_setup: 649188412Sthompsa xfer->frlengths[0] = xfer->max_data_length; 650194228Sthompsa usbd_transfer_submit(xfer); 651194228Sthompsa uether_rxflush(ue); 652184610Salfred return; 653184610Salfred 654184610Salfred default: /* Error */ 655188412Sthompsa DPRINTF("bulk read error, %s\n", 656194228Sthompsa usbd_errstr(xfer->error)); 657188412Sthompsa 658184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 659184610Salfred /* try to clear stall first */ 660188412Sthompsa xfer->flags.stall_pipe = 1; 661188412Sthompsa goto tr_setup; 662184610Salfred } 663184610Salfred return; 664184610Salfred } 665184610Salfred} 666184610Salfred 667184610Salfredstatic void 668192984Sthompsaudav_intr_callback(struct usb_xfer *xfer) 669184610Salfred{ 670184610Salfred switch (USB_GET_STATE(xfer)) { 671184610Salfred case USB_ST_TRANSFERRED: 672184610Salfred case USB_ST_SETUP: 673188412Sthompsatr_setup: 674188412Sthompsa xfer->frlengths[0] = xfer->max_data_length; 675194228Sthompsa usbd_transfer_submit(xfer); 676184610Salfred return; 677184610Salfred 678184610Salfred default: /* Error */ 679184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 680188412Sthompsa /* try to clear stall first */ 681188412Sthompsa xfer->flags.stall_pipe = 1; 682188412Sthompsa goto tr_setup; 683184610Salfred } 684184610Salfred return; 685184610Salfred } 686184610Salfred} 687184610Salfred 688184610Salfredstatic void 689192984Sthompsaudav_stop(struct usb_ether *ue) 690184610Salfred{ 691188412Sthompsa struct udav_softc *sc = ue->ue_sc; 692194228Sthompsa struct ifnet *ifp = uether_getifp(&sc->sc_ue); 693184610Salfred 694188412Sthompsa UDAV_LOCK_ASSERT(sc, MA_OWNED); 695184610Salfred 696188412Sthompsa ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 697188412Sthompsa sc->sc_flags &= ~UDAV_FLAG_LINK; 698184610Salfred 699184610Salfred /* 700184610Salfred * stop all the transfers, if not already stopped: 701184610Salfred */ 702194228Sthompsa usbd_transfer_stop(sc->sc_xfer[UDAV_BULK_DT_WR]); 703194228Sthompsa usbd_transfer_stop(sc->sc_xfer[UDAV_BULK_DT_RD]); 704194228Sthompsa usbd_transfer_stop(sc->sc_xfer[UDAV_INTR_DT_RD]); 705184610Salfred 706188412Sthompsa udav_reset(sc); 707184610Salfred} 708184610Salfred 709184610Salfredstatic int 710188412Sthompsaudav_ifmedia_upd(struct ifnet *ifp) 711184610Salfred{ 712184610Salfred struct udav_softc *sc = ifp->if_softc; 713184610Salfred struct mii_data *mii = GET_MII(sc); 714184610Salfred 715188412Sthompsa UDAV_LOCK_ASSERT(sc, MA_OWNED); 716184610Salfred 717188412Sthompsa sc->sc_flags &= ~UDAV_FLAG_LINK; 718184610Salfred if (mii->mii_instance) { 719184610Salfred struct mii_softc *miisc; 720184610Salfred 721188412Sthompsa LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 722184610Salfred mii_phy_reset(miisc); 723184610Salfred } 724184610Salfred mii_mediachg(mii); 725188412Sthompsa return (0); 726184610Salfred} 727184610Salfred 728184610Salfredstatic void 729188412Sthompsaudav_ifmedia_status(struct ifnet *ifp, struct ifmediareq *ifmr) 730184610Salfred{ 731184610Salfred struct udav_softc *sc = ifp->if_softc; 732188412Sthompsa struct mii_data *mii = GET_MII(sc); 733184610Salfred 734188412Sthompsa UDAV_LOCK(sc); 735188412Sthompsa mii_pollstat(mii); 736188412Sthompsa UDAV_UNLOCK(sc); 737188412Sthompsa ifmr->ifm_active = mii->mii_media_active; 738188412Sthompsa ifmr->ifm_status = mii->mii_media_status; 739184610Salfred} 740184610Salfred 741184610Salfredstatic void 742192984Sthompsaudav_tick(struct usb_ether *ue) 743184610Salfred{ 744188412Sthompsa struct udav_softc *sc = ue->ue_sc; 745184610Salfred struct mii_data *mii = GET_MII(sc); 746184610Salfred 747188412Sthompsa UDAV_LOCK_ASSERT(sc, MA_OWNED); 748188412Sthompsa 749184610Salfred mii_tick(mii); 750188412Sthompsa if ((sc->sc_flags & UDAV_FLAG_LINK) == 0 751188412Sthompsa && mii->mii_media_status & IFM_ACTIVE && 752188412Sthompsa IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 753188412Sthompsa sc->sc_flags |= UDAV_FLAG_LINK; 754188412Sthompsa udav_start(ue); 755184610Salfred } 756184610Salfred} 757184610Salfred 758184610Salfredstatic int 759188412Sthompsaudav_miibus_readreg(device_t dev, int phy, int reg) 760184610Salfred{ 761184610Salfred struct udav_softc *sc = device_get_softc(dev); 762184610Salfred uint16_t data16; 763184610Salfred uint8_t val[2]; 764188412Sthompsa int locked; 765184610Salfred 766184610Salfred /* XXX: one PHY only for the internal PHY */ 767188412Sthompsa if (phy != 0) 768184610Salfred return (0); 769184610Salfred 770188412Sthompsa locked = mtx_owned(&sc->sc_mtx); 771188412Sthompsa if (!locked) 772188412Sthompsa UDAV_LOCK(sc); 773188412Sthompsa 774184610Salfred /* select internal PHY and set PHY register address */ 775188412Sthompsa udav_csr_write1(sc, UDAV_EPAR, 776184610Salfred UDAV_EPAR_PHY_ADR0 | (reg & UDAV_EPAR_EROA_MASK)); 777184610Salfred 778184610Salfred /* select PHY operation and start read command */ 779188412Sthompsa udav_csr_write1(sc, UDAV_EPCR, UDAV_EPCR_EPOS | UDAV_EPCR_ERPRR); 780184610Salfred 781184610Salfred /* XXX: should we wait? */ 782184610Salfred 783184610Salfred /* end read command */ 784188412Sthompsa UDAV_CLRBIT(sc, UDAV_EPCR, UDAV_EPCR_ERPRR); 785184610Salfred 786184610Salfred /* retrieve the result from data registers */ 787188412Sthompsa udav_csr_read(sc, UDAV_EPDRL, val, 2); 788184610Salfred 789184610Salfred data16 = (val[0] | (val[1] << 8)); 790184610Salfred 791184610Salfred DPRINTFN(11, "phy=%d reg=0x%04x => 0x%04x\n", 792184610Salfred phy, reg, data16); 793184610Salfred 794188412Sthompsa if (!locked) 795188412Sthompsa UDAV_UNLOCK(sc); 796184610Salfred return (data16); 797184610Salfred} 798184610Salfred 799184610Salfredstatic int 800188412Sthompsaudav_miibus_writereg(device_t dev, int phy, int reg, int data) 801184610Salfred{ 802184610Salfred struct udav_softc *sc = device_get_softc(dev); 803184610Salfred uint8_t val[2]; 804188412Sthompsa int locked; 805184610Salfred 806184610Salfred /* XXX: one PHY only for the internal PHY */ 807188412Sthompsa if (phy != 0) 808184610Salfred return (0); 809184610Salfred 810188412Sthompsa locked = mtx_owned(&sc->sc_mtx); 811188412Sthompsa if (!locked) 812188412Sthompsa UDAV_LOCK(sc); 813188412Sthompsa 814184610Salfred /* select internal PHY and set PHY register address */ 815188412Sthompsa udav_csr_write1(sc, UDAV_EPAR, 816184610Salfred UDAV_EPAR_PHY_ADR0 | (reg & UDAV_EPAR_EROA_MASK)); 817184610Salfred 818184610Salfred /* put the value to the data registers */ 819184610Salfred val[0] = (data & 0xff); 820184610Salfred val[1] = (data >> 8) & 0xff; 821188412Sthompsa udav_csr_write(sc, UDAV_EPDRL, val, 2); 822184610Salfred 823184610Salfred /* select PHY operation and start write command */ 824188412Sthompsa udav_csr_write1(sc, UDAV_EPCR, UDAV_EPCR_EPOS | UDAV_EPCR_ERPRW); 825184610Salfred 826184610Salfred /* XXX: should we wait? */ 827184610Salfred 828184610Salfred /* end write command */ 829188412Sthompsa UDAV_CLRBIT(sc, UDAV_EPCR, UDAV_EPCR_ERPRW); 830184610Salfred 831188412Sthompsa if (!locked) 832188412Sthompsa UDAV_UNLOCK(sc); 833184610Salfred return (0); 834184610Salfred} 835184610Salfred 836184610Salfredstatic void 837188412Sthompsaudav_miibus_statchg(device_t dev) 838184610Salfred{ 839184610Salfred /* nothing to do */ 840184610Salfred} 841