if_udav.c revision 189275
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 189275 2009-03-02 05:37:05Z 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 189275 2009-03-02 05:37:05Z 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; 72184610Salfredstatic device_shutdown_t udav_shutdown; 73184610Salfred 74184610Salfredstatic usb2_callback_t udav_bulk_write_callback; 75184610Salfredstatic usb2_callback_t udav_bulk_read_callback; 76184610Salfredstatic usb2_callback_t udav_intr_callback; 77184610Salfred 78188412Sthompsastatic usb2_ether_fn_t udav_attach_post; 79188412Sthompsastatic usb2_ether_fn_t udav_init; 80188412Sthompsastatic usb2_ether_fn_t udav_stop; 81188412Sthompsastatic usb2_ether_fn_t udav_start; 82188412Sthompsastatic usb2_ether_fn_t udav_tick; 83188412Sthompsastatic usb2_ether_fn_t udav_setmulti; 84188412Sthompsastatic usb2_ether_fn_t udav_setpromisc; 85184610Salfred 86188412Sthompsastatic int udav_csr_read(struct udav_softc *, uint16_t, void *, int); 87188412Sthompsastatic int udav_csr_write(struct udav_softc *, uint16_t, void *, int); 88188412Sthompsastatic uint8_t udav_csr_read1(struct udav_softc *, uint16_t); 89188412Sthompsastatic int udav_csr_write1(struct udav_softc *, uint16_t, uint8_t); 90188412Sthompsastatic void udav_reset(struct udav_softc *); 91188412Sthompsastatic int udav_ifmedia_upd(struct ifnet *); 92188412Sthompsastatic void udav_ifmedia_status(struct ifnet *, struct ifmediareq *); 93184610Salfred 94188412Sthompsastatic miibus_readreg_t udav_miibus_readreg; 95188412Sthompsastatic miibus_writereg_t udav_miibus_writereg; 96188412Sthompsastatic miibus_statchg_t udav_miibus_statchg; 97184610Salfred 98187259Sthompsastatic const struct usb2_config udav_config[UDAV_N_TRANSFER] = { 99184610Salfred 100187259Sthompsa [UDAV_BULK_DT_WR] = { 101184610Salfred .type = UE_BULK, 102184610Salfred .endpoint = UE_ADDR_ANY, 103184610Salfred .direction = UE_DIR_OUT, 104184610Salfred .mh.bufsize = (MCLBYTES + 2), 105184610Salfred .mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 106188412Sthompsa .mh.callback = udav_bulk_write_callback, 107184610Salfred .mh.timeout = 10000, /* 10 seconds */ 108184610Salfred }, 109184610Salfred 110187259Sthompsa [UDAV_BULK_DT_RD] = { 111184610Salfred .type = UE_BULK, 112184610Salfred .endpoint = UE_ADDR_ANY, 113184610Salfred .direction = UE_DIR_IN, 114184610Salfred .mh.bufsize = (MCLBYTES + 3), 115184610Salfred .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 116188412Sthompsa .mh.callback = udav_bulk_read_callback, 117184610Salfred .mh.timeout = 0, /* no timeout */ 118184610Salfred }, 119184610Salfred 120187259Sthompsa [UDAV_INTR_DT_RD] = { 121184610Salfred .type = UE_INTERRUPT, 122184610Salfred .endpoint = UE_ADDR_ANY, 123184610Salfred .direction = UE_DIR_IN, 124184610Salfred .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 125184610Salfred .mh.bufsize = 0, /* use wMaxPacketSize */ 126188412Sthompsa .mh.callback = udav_intr_callback, 127184610Salfred }, 128184610Salfred}; 129184610Salfred 130184610Salfredstatic device_method_t udav_methods[] = { 131184610Salfred /* Device interface */ 132184610Salfred DEVMETHOD(device_probe, udav_probe), 133184610Salfred DEVMETHOD(device_attach, udav_attach), 134184610Salfred DEVMETHOD(device_detach, udav_detach), 135184610Salfred DEVMETHOD(device_shutdown, udav_shutdown), 136184610Salfred 137184610Salfred /* bus interface */ 138184610Salfred DEVMETHOD(bus_print_child, bus_generic_print_child), 139184610Salfred DEVMETHOD(bus_driver_added, bus_generic_driver_added), 140184610Salfred 141184610Salfred /* MII interface */ 142188412Sthompsa DEVMETHOD(miibus_readreg, udav_miibus_readreg), 143188412Sthompsa DEVMETHOD(miibus_writereg, udav_miibus_writereg), 144188412Sthompsa DEVMETHOD(miibus_statchg, udav_miibus_statchg), 145184610Salfred 146184610Salfred {0, 0} 147184610Salfred}; 148184610Salfred 149184610Salfredstatic driver_t udav_driver = { 150184610Salfred .name = "udav", 151184610Salfred .methods = udav_methods, 152184610Salfred .size = sizeof(struct udav_softc), 153184610Salfred}; 154184610Salfred 155184610Salfredstatic devclass_t udav_devclass; 156184610Salfred 157189275SthompsaDRIVER_MODULE(udav, uhub, udav_driver, udav_devclass, NULL, 0); 158184610SalfredDRIVER_MODULE(miibus, udav, miibus_driver, miibus_devclass, 0, 0); 159188942SthompsaMODULE_DEPEND(udav, uether, 1, 1, 1); 160188942SthompsaMODULE_DEPEND(udav, usb, 1, 1, 1); 161184610SalfredMODULE_DEPEND(udav, ether, 1, 1, 1); 162184610SalfredMODULE_DEPEND(udav, miibus, 1, 1, 1); 163184610Salfred 164188412Sthompsastatic const struct usb2_ether_methods udav_ue_methods = { 165188412Sthompsa .ue_attach_post = udav_attach_post, 166188412Sthompsa .ue_start = udav_start, 167188412Sthompsa .ue_init = udav_init, 168188412Sthompsa .ue_stop = udav_stop, 169188412Sthompsa .ue_tick = udav_tick, 170188412Sthompsa .ue_setmulti = udav_setmulti, 171188412Sthompsa .ue_setpromisc = udav_setpromisc, 172188412Sthompsa .ue_mii_upd = udav_ifmedia_upd, 173188412Sthompsa .ue_mii_sts = udav_ifmedia_status, 174188412Sthompsa}; 175188412Sthompsa 176184610Salfred#if USB_DEBUG 177184610Salfredstatic int udav_debug = 0; 178184610Salfred 179184610SalfredSYSCTL_NODE(_hw_usb2, OID_AUTO, udav, CTLFLAG_RW, 0, "USB udav"); 180184610SalfredSYSCTL_INT(_hw_usb2_udav, OID_AUTO, debug, CTLFLAG_RW, &udav_debug, 0, 181184610Salfred "Debug level"); 182184610Salfred#endif 183184610Salfred 184188412Sthompsa#define UDAV_SETBIT(sc, reg, x) \ 185188412Sthompsa udav_csr_write1(sc, reg, udav_csr_read1(sc, reg) | (x)) 186184610Salfred 187188412Sthompsa#define UDAV_CLRBIT(sc, reg, x) \ 188188412Sthompsa udav_csr_write1(sc, reg, udav_csr_read1(sc, reg) & ~(x)) 189184610Salfred 190184610Salfredstatic const struct usb2_device_id udav_devs[] = { 191184610Salfred /* ShanTou DM9601 USB NIC */ 192184610Salfred {USB_VPI(USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_DM9601, 0)}, 193184610Salfred /* ShanTou ST268 USB NIC */ 194184610Salfred {USB_VPI(USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_ST268, 0)}, 195184610Salfred /* Corega USB-TXC */ 196184610Salfred {USB_VPI(USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TXC, 0)}, 197184610Salfred}; 198184610Salfred 199188412Sthompsastatic void 200188412Sthompsaudav_attach_post(struct usb2_ether *ue) 201188412Sthompsa{ 202188412Sthompsa struct udav_softc *sc = usb2_ether_getsc(ue); 203188412Sthompsa 204188412Sthompsa /* reset the adapter */ 205188412Sthompsa udav_reset(sc); 206188412Sthompsa 207188412Sthompsa /* Get Ethernet Address */ 208188412Sthompsa udav_csr_read(sc, UDAV_PAR, ue->ue_eaddr, ETHER_ADDR_LEN); 209188412Sthompsa} 210188412Sthompsa 211184610Salfredstatic int 212184610Salfredudav_probe(device_t dev) 213184610Salfred{ 214184610Salfred struct usb2_attach_arg *uaa = device_get_ivars(dev); 215184610Salfred 216188412Sthompsa if (uaa->usb2_mode != USB_MODE_HOST) 217184610Salfred return (ENXIO); 218188412Sthompsa if (uaa->info.bConfigIndex != UDAV_CONFIG_INDEX) 219184610Salfred return (ENXIO); 220188412Sthompsa if (uaa->info.bIfaceIndex != UDAV_IFACE_INDEX) 221184610Salfred return (ENXIO); 222188412Sthompsa 223184610Salfred return (usb2_lookup_id_by_uaa(udav_devs, sizeof(udav_devs), uaa)); 224184610Salfred} 225184610Salfred 226184610Salfredstatic int 227184610Salfredudav_attach(device_t dev) 228184610Salfred{ 229184610Salfred struct usb2_attach_arg *uaa = device_get_ivars(dev); 230184610Salfred struct udav_softc *sc = device_get_softc(dev); 231188412Sthompsa struct usb2_ether *ue = &sc->sc_ue; 232184610Salfred uint8_t iface_index; 233188412Sthompsa int error; 234184610Salfred 235184610Salfred sc->sc_flags = USB_GET_DRIVER_INFO(uaa); 236184610Salfred 237184610Salfred device_set_usb2_desc(dev); 238184610Salfred 239188412Sthompsa mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 240184610Salfred 241184610Salfred iface_index = UDAV_IFACE_INDEX; 242184610Salfred error = usb2_transfer_setup(uaa->device, &iface_index, 243187259Sthompsa sc->sc_xfer, udav_config, UDAV_N_TRANSFER, sc, &sc->sc_mtx); 244184610Salfred if (error) { 245188412Sthompsa device_printf(dev, "allocating USB transfers failed!\n"); 246184610Salfred goto detach; 247184610Salfred } 248188412Sthompsa 249188412Sthompsa ue->ue_sc = sc; 250188412Sthompsa ue->ue_dev = dev; 251188412Sthompsa ue->ue_udev = uaa->device; 252188412Sthompsa ue->ue_mtx = &sc->sc_mtx; 253188412Sthompsa ue->ue_methods = &udav_ue_methods; 254188412Sthompsa 255188412Sthompsa error = usb2_ether_ifattach(ue); 256184610Salfred if (error) { 257188412Sthompsa device_printf(dev, "could not attach interface\n"); 258184610Salfred goto detach; 259184610Salfred } 260184610Salfred 261184610Salfred return (0); /* success */ 262184610Salfred 263184610Salfreddetach: 264184610Salfred udav_detach(dev); 265184610Salfred return (ENXIO); /* failure */ 266184610Salfred} 267184610Salfred 268184610Salfredstatic int 269184610Salfredudav_detach(device_t dev) 270184610Salfred{ 271184610Salfred struct udav_softc *sc = device_get_softc(dev); 272188412Sthompsa struct usb2_ether *ue = &sc->sc_ue; 273184610Salfred 274187259Sthompsa usb2_transfer_unsetup(sc->sc_xfer, UDAV_N_TRANSFER); 275188412Sthompsa usb2_ether_ifdetach(ue); 276184610Salfred mtx_destroy(&sc->sc_mtx); 277184610Salfred 278184610Salfred return (0); 279184610Salfred} 280184610Salfred 281184610Salfred#if 0 282188412Sthompsastatic int 283188412Sthompsaudav_mem_read(struct udav_softc *sc, uint16_t offset, void *buf, 284188412Sthompsa int len) 285184610Salfred{ 286184610Salfred struct usb2_device_request req; 287184610Salfred 288184610Salfred len &= 0xff; 289184610Salfred 290184610Salfred req.bmRequestType = UT_READ_VENDOR_DEVICE; 291184610Salfred req.bRequest = UDAV_REQ_MEM_READ; 292184610Salfred USETW(req.wValue, 0x0000); 293184610Salfred USETW(req.wIndex, offset); 294184610Salfred USETW(req.wLength, len); 295184610Salfred 296188412Sthompsa return (usb2_ether_do_request(&sc->sc_ue, &req, buf, 1000)); 297184610Salfred} 298184610Salfred 299188412Sthompsastatic int 300188412Sthompsaudav_mem_write(struct udav_softc *sc, uint16_t offset, void *buf, 301188412Sthompsa int len) 302184610Salfred{ 303184610Salfred struct usb2_device_request req; 304184610Salfred 305184610Salfred len &= 0xff; 306184610Salfred 307184610Salfred req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 308184610Salfred req.bRequest = UDAV_REQ_MEM_WRITE; 309184610Salfred USETW(req.wValue, 0x0000); 310184610Salfred USETW(req.wIndex, offset); 311184610Salfred USETW(req.wLength, len); 312184610Salfred 313188412Sthompsa return (usb2_ether_do_request(&sc->sc_ue, &req, buf, 1000)); 314184610Salfred} 315184610Salfred 316188412Sthompsastatic int 317188412Sthompsaudav_mem_write1(struct udav_softc *sc, uint16_t offset, 318184610Salfred uint8_t ch) 319184610Salfred{ 320184610Salfred struct usb2_device_request req; 321184610Salfred 322184610Salfred req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 323184610Salfred req.bRequest = UDAV_REQ_MEM_WRITE1; 324184610Salfred USETW(req.wValue, ch); 325184610Salfred USETW(req.wIndex, offset); 326184610Salfred USETW(req.wLength, 0x0000); 327184610Salfred 328188412Sthompsa return (usb2_ether_do_request(&sc->sc_ue, &req, NULL, 1000)); 329184610Salfred} 330184610Salfred#endif 331184610Salfred 332188412Sthompsastatic int 333188412Sthompsaudav_csr_read(struct udav_softc *sc, uint16_t offset, void *buf, int len) 334184610Salfred{ 335184610Salfred struct usb2_device_request req; 336184610Salfred 337184610Salfred len &= 0xff; 338184610Salfred 339184610Salfred req.bmRequestType = UT_READ_VENDOR_DEVICE; 340184610Salfred req.bRequest = UDAV_REQ_REG_READ; 341184610Salfred USETW(req.wValue, 0x0000); 342184610Salfred USETW(req.wIndex, offset); 343184610Salfred USETW(req.wLength, len); 344184610Salfred 345188412Sthompsa return (usb2_ether_do_request(&sc->sc_ue, &req, buf, 1000)); 346184610Salfred} 347184610Salfred 348188412Sthompsastatic int 349188412Sthompsaudav_csr_write(struct udav_softc *sc, uint16_t offset, void *buf, int len) 350184610Salfred{ 351184610Salfred struct usb2_device_request req; 352184610Salfred 353184610Salfred offset &= 0xff; 354184610Salfred len &= 0xff; 355184610Salfred 356184610Salfred req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 357184610Salfred req.bRequest = UDAV_REQ_REG_WRITE; 358184610Salfred USETW(req.wValue, 0x0000); 359184610Salfred USETW(req.wIndex, offset); 360184610Salfred USETW(req.wLength, len); 361184610Salfred 362188412Sthompsa return (usb2_ether_do_request(&sc->sc_ue, &req, buf, 1000)); 363184610Salfred} 364184610Salfred 365184610Salfredstatic uint8_t 366188412Sthompsaudav_csr_read1(struct udav_softc *sc, uint16_t offset) 367184610Salfred{ 368184610Salfred uint8_t val; 369184610Salfred 370188412Sthompsa udav_csr_read(sc, offset, &val, 1); 371184610Salfred return (val); 372184610Salfred} 373184610Salfred 374188412Sthompsastatic int 375188412Sthompsaudav_csr_write1(struct udav_softc *sc, uint16_t offset, 376184610Salfred uint8_t ch) 377184610Salfred{ 378184610Salfred struct usb2_device_request req; 379184610Salfred 380184610Salfred offset &= 0xff; 381184610Salfred 382184610Salfred req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 383184610Salfred req.bRequest = UDAV_REQ_REG_WRITE1; 384184610Salfred USETW(req.wValue, ch); 385184610Salfred USETW(req.wIndex, offset); 386184610Salfred USETW(req.wLength, 0x0000); 387184610Salfred 388188412Sthompsa return (usb2_ether_do_request(&sc->sc_ue, &req, NULL, 1000)); 389184610Salfred} 390184610Salfred 391184610Salfredstatic void 392188412Sthompsaudav_init(struct usb2_ether *ue) 393184610Salfred{ 394188412Sthompsa struct udav_softc *sc = ue->ue_sc; 395188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(&sc->sc_ue); 396184610Salfred 397188412Sthompsa UDAV_LOCK_ASSERT(sc, MA_OWNED); 398184610Salfred 399184610Salfred /* 400184610Salfred * Cancel pending I/O 401184610Salfred */ 402188412Sthompsa udav_stop(ue); 403184610Salfred 404184610Salfred /* set MAC address */ 405188412Sthompsa udav_csr_write(sc, UDAV_PAR, IF_LLADDR(ifp), ETHER_ADDR_LEN); 406184610Salfred 407184610Salfred /* initialize network control register */ 408184610Salfred 409184610Salfred /* disable loopback */ 410188412Sthompsa UDAV_CLRBIT(sc, UDAV_NCR, UDAV_NCR_LBK0 | UDAV_NCR_LBK1); 411184610Salfred 412184610Salfred /* Initialize RX control register */ 413188412Sthompsa UDAV_SETBIT(sc, UDAV_RCR, UDAV_RCR_DIS_LONG | UDAV_RCR_DIS_CRC); 414184610Salfred 415184610Salfred /* load multicast filter and update promiscious mode bit */ 416188412Sthompsa udav_setpromisc(ue); 417184610Salfred 418184610Salfred /* enable RX */ 419188412Sthompsa UDAV_SETBIT(sc, UDAV_RCR, UDAV_RCR_RXEN); 420184610Salfred 421184610Salfred /* clear POWER_DOWN state of internal PHY */ 422188412Sthompsa UDAV_SETBIT(sc, UDAV_GPCR, UDAV_GPCR_GEP_CNTL0); 423188412Sthompsa UDAV_CLRBIT(sc, UDAV_GPR, UDAV_GPR_GEPIO0); 424184610Salfred 425188412Sthompsa usb2_transfer_set_stall(sc->sc_xfer[UDAV_BULK_DT_WR]); 426184610Salfred 427188412Sthompsa ifp->if_drv_flags |= IFF_DRV_RUNNING; 428188412Sthompsa udav_start(ue); 429184610Salfred} 430184610Salfred 431184610Salfredstatic void 432188412Sthompsaudav_reset(struct udav_softc *sc) 433184610Salfred{ 434188412Sthompsa int i; 435184610Salfred 436184610Salfred /* Select PHY */ 437184610Salfred#if 1 438184610Salfred /* 439184610Salfred * XXX: force select internal phy. 440184610Salfred * external phy routines are not tested. 441184610Salfred */ 442188412Sthompsa UDAV_CLRBIT(sc, UDAV_NCR, UDAV_NCR_EXT_PHY); 443184610Salfred#else 444188412Sthompsa if (sc->sc_flags & UDAV_EXT_PHY) 445188412Sthompsa UDAV_SETBIT(sc, UDAV_NCR, UDAV_NCR_EXT_PHY); 446188412Sthompsa else 447188412Sthompsa UDAV_CLRBIT(sc, UDAV_NCR, UDAV_NCR_EXT_PHY); 448184610Salfred#endif 449184610Salfred 450188412Sthompsa UDAV_SETBIT(sc, UDAV_NCR, UDAV_NCR_RST); 451184610Salfred 452188412Sthompsa for (i = 0; i < UDAV_TX_TIMEOUT; i++) { 453188412Sthompsa if (!(udav_csr_read1(sc, UDAV_NCR) & UDAV_NCR_RST)) 454184610Salfred break; 455188412Sthompsa if (usb2_ether_pause(&sc->sc_ue, hz / 100)) 456188412Sthompsa break; 457184610Salfred } 458184610Salfred 459188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 100); 460184610Salfred} 461184610Salfred 462184610Salfred#define UDAV_BITS 6 463184610Salfredstatic void 464188412Sthompsaudav_setmulti(struct usb2_ether *ue) 465184610Salfred{ 466188412Sthompsa struct udav_softc *sc = ue->ue_sc; 467188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(&sc->sc_ue); 468188412Sthompsa struct ifmultiaddr *ifma; 469188412Sthompsa uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 470188412Sthompsa int h = 0; 471184610Salfred 472188412Sthompsa UDAV_LOCK_ASSERT(sc, MA_OWNED); 473184610Salfred 474188412Sthompsa if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 475188412Sthompsa UDAV_SETBIT(sc, UDAV_RCR, UDAV_RCR_ALL|UDAV_RCR_PRMSC); 476188412Sthompsa return; 477188412Sthompsa } 478188412Sthompsa 479188412Sthompsa /* first, zot all the existing hash bits */ 480188412Sthompsa memset(hashtbl, 0x00, sizeof(hashtbl)); 481188412Sthompsa hashtbl[7] |= 0x80; /* broadcast address */ 482188412Sthompsa udav_csr_write(sc, UDAV_MAR, hashtbl, sizeof(hashtbl)); 483188412Sthompsa 484188412Sthompsa /* now program new ones */ 485188412Sthompsa IF_ADDR_LOCK(ifp); 486188412Sthompsa TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) 487188412Sthompsa { 488188412Sthompsa if (ifma->ifma_addr->sa_family != AF_LINK) 489188412Sthompsa continue; 490188412Sthompsa h = ether_crc32_be(LLADDR((struct sockaddr_dl *) 491188412Sthompsa ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; 492188412Sthompsa hashtbl[h / 8] |= 1 << (h % 8); 493188412Sthompsa } 494188412Sthompsa IF_ADDR_UNLOCK(ifp); 495188412Sthompsa 496188412Sthompsa /* disable all multicast */ 497188412Sthompsa UDAV_CLRBIT(sc, UDAV_RCR, UDAV_RCR_ALL); 498188412Sthompsa 499188412Sthompsa /* write hash value to the register */ 500188412Sthompsa udav_csr_write(sc, UDAV_MAR, hashtbl, sizeof(hashtbl)); 501184610Salfred} 502184610Salfred 503184610Salfredstatic void 504188412Sthompsaudav_setpromisc(struct usb2_ether *ue) 505184610Salfred{ 506188412Sthompsa struct udav_softc *sc = ue->ue_sc; 507188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(&sc->sc_ue); 508184610Salfred uint8_t rxmode; 509184610Salfred 510188412Sthompsa rxmode = udav_csr_read1(sc, UDAV_RCR); 511184610Salfred rxmode &= ~(UDAV_RCR_ALL | UDAV_RCR_PRMSC); 512184610Salfred 513188412Sthompsa if (ifp->if_flags & IFF_PROMISC) 514184610Salfred rxmode |= UDAV_RCR_ALL | UDAV_RCR_PRMSC; 515188412Sthompsa else if (ifp->if_flags & IFF_ALLMULTI) 516184610Salfred rxmode |= UDAV_RCR_ALL; 517184610Salfred 518184610Salfred /* write new mode bits */ 519188412Sthompsa udav_csr_write1(sc, UDAV_RCR, rxmode); 520184610Salfred} 521184610Salfred 522184610Salfredstatic void 523188412Sthompsaudav_start(struct usb2_ether *ue) 524184610Salfred{ 525188412Sthompsa struct udav_softc *sc = ue->ue_sc; 526184610Salfred 527188412Sthompsa /* 528188412Sthompsa * start the USB transfers, if not already started: 529188412Sthompsa */ 530188412Sthompsa usb2_transfer_start(sc->sc_xfer[UDAV_INTR_DT_RD]); 531188412Sthompsa usb2_transfer_start(sc->sc_xfer[UDAV_BULK_DT_RD]); 532188412Sthompsa usb2_transfer_start(sc->sc_xfer[UDAV_BULK_DT_WR]); 533184610Salfred} 534184610Salfred 535184610Salfredstatic void 536184610Salfredudav_bulk_write_callback(struct usb2_xfer *xfer) 537184610Salfred{ 538184610Salfred struct udav_softc *sc = xfer->priv_sc; 539188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(&sc->sc_ue); 540184610Salfred struct mbuf *m; 541188412Sthompsa int extra_len; 542188412Sthompsa int temp_len; 543184610Salfred uint8_t buf[2]; 544184610Salfred 545184610Salfred switch (USB_GET_STATE(xfer)) { 546184610Salfred case USB_ST_TRANSFERRED: 547184610Salfred DPRINTFN(11, "transfer complete\n"); 548184610Salfred ifp->if_opackets++; 549184610Salfred 550188412Sthompsa /* FALLTHROUGH */ 551184610Salfred case USB_ST_SETUP: 552188412Sthompsatr_setup: 553188412Sthompsa if ((sc->sc_flags & UDAV_FLAG_LINK) == 0) { 554184610Salfred /* 555184610Salfred * don't send anything if there is no link ! 556184610Salfred */ 557188412Sthompsa return; 558184610Salfred } 559184610Salfred IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 560184610Salfred 561188412Sthompsa if (m == NULL) 562188412Sthompsa return; 563188412Sthompsa if (m->m_pkthdr.len > MCLBYTES) 564184610Salfred m->m_pkthdr.len = MCLBYTES; 565184610Salfred if (m->m_pkthdr.len < UDAV_MIN_FRAME_LEN) { 566184610Salfred extra_len = UDAV_MIN_FRAME_LEN - m->m_pkthdr.len; 567184610Salfred } else { 568184610Salfred extra_len = 0; 569184610Salfred } 570184610Salfred 571184610Salfred temp_len = (m->m_pkthdr.len + extra_len); 572184610Salfred 573184610Salfred /* 574184610Salfred * the frame length is specified in the first 2 bytes of the 575184610Salfred * buffer 576184610Salfred */ 577184610Salfred buf[0] = (uint8_t)(temp_len); 578184610Salfred buf[1] = (uint8_t)(temp_len >> 8); 579184610Salfred 580184610Salfred temp_len += 2; 581184610Salfred 582184610Salfred usb2_copy_in(xfer->frbuffers, 0, buf, 2); 583184610Salfred 584184610Salfred usb2_m_copy_in(xfer->frbuffers, 2, 585184610Salfred m, 0, m->m_pkthdr.len); 586184610Salfred 587184610Salfred if (extra_len) { 588184610Salfred usb2_bzero(xfer->frbuffers, temp_len - extra_len, 589184610Salfred extra_len); 590184610Salfred } 591184610Salfred /* 592184610Salfred * if there's a BPF listener, bounce a copy 593184610Salfred * of this frame to him: 594184610Salfred */ 595184610Salfred BPF_MTAP(ifp, m); 596184610Salfred 597184610Salfred m_freem(m); 598184610Salfred 599184610Salfred xfer->frlengths[0] = temp_len; 600184610Salfred usb2_start_hardware(xfer); 601184610Salfred return; 602184610Salfred 603184610Salfred default: /* Error */ 604184610Salfred DPRINTFN(11, "transfer error, %s\n", 605184610Salfred usb2_errstr(xfer->error)); 606184610Salfred 607188412Sthompsa ifp->if_oerrors++; 608188412Sthompsa 609184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 610184610Salfred /* try to clear stall first */ 611188412Sthompsa xfer->flags.stall_pipe = 1; 612188412Sthompsa goto tr_setup; 613184610Salfred } 614184610Salfred return; 615184610Salfred } 616184610Salfred} 617184610Salfred 618184610Salfredstatic void 619184610Salfredudav_bulk_read_callback(struct usb2_xfer *xfer) 620184610Salfred{ 621184610Salfred struct udav_softc *sc = xfer->priv_sc; 622188412Sthompsa struct usb2_ether *ue = &sc->sc_ue; 623188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(ue); 624188412Sthompsa struct udav_rxpkt stat; 625188412Sthompsa int len; 626184610Salfred 627184610Salfred switch (USB_GET_STATE(xfer)) { 628184610Salfred case USB_ST_TRANSFERRED: 629184610Salfred 630188412Sthompsa if (xfer->actlen < sizeof(stat) + ETHER_CRC_LEN) { 631184610Salfred ifp->if_ierrors++; 632184610Salfred goto tr_setup; 633184610Salfred } 634188412Sthompsa usb2_copy_out(xfer->frbuffers, 0, &stat, sizeof(stat)); 635188412Sthompsa xfer->actlen -= sizeof(stat); 636188412Sthompsa len = min(xfer->actlen, le16toh(stat.pktlen)); 637188412Sthompsa len -= ETHER_CRC_LEN; 638184610Salfred 639188412Sthompsa if (stat.rxstat & UDAV_RSR_LCS) { 640184610Salfred ifp->if_collisions++; 641184610Salfred goto tr_setup; 642184610Salfred } 643188412Sthompsa if (stat.rxstat & UDAV_RSR_ERR) { 644184610Salfred ifp->if_ierrors++; 645184610Salfred goto tr_setup; 646184610Salfred } 647188412Sthompsa usb2_ether_rxbuf(ue, xfer->frbuffers, sizeof(stat), len); 648188412Sthompsa /* FALLTHROUGH */ 649184610Salfred case USB_ST_SETUP: 650184610Salfredtr_setup: 651188412Sthompsa xfer->frlengths[0] = xfer->max_data_length; 652188412Sthompsa usb2_start_hardware(xfer); 653188412Sthompsa usb2_ether_rxflush(ue); 654184610Salfred return; 655184610Salfred 656184610Salfred default: /* Error */ 657188412Sthompsa DPRINTF("bulk read error, %s\n", 658188412Sthompsa usb2_errstr(xfer->error)); 659188412Sthompsa 660184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 661184610Salfred /* try to clear stall first */ 662188412Sthompsa xfer->flags.stall_pipe = 1; 663188412Sthompsa goto tr_setup; 664184610Salfred } 665184610Salfred return; 666184610Salfred } 667184610Salfred} 668184610Salfred 669184610Salfredstatic void 670184610Salfredudav_intr_callback(struct usb2_xfer *xfer) 671184610Salfred{ 672184610Salfred switch (USB_GET_STATE(xfer)) { 673184610Salfred case USB_ST_TRANSFERRED: 674184610Salfred case USB_ST_SETUP: 675188412Sthompsatr_setup: 676188412Sthompsa xfer->frlengths[0] = xfer->max_data_length; 677188412Sthompsa usb2_start_hardware(xfer); 678184610Salfred return; 679184610Salfred 680184610Salfred default: /* Error */ 681184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 682188412Sthompsa /* try to clear stall first */ 683188412Sthompsa xfer->flags.stall_pipe = 1; 684188412Sthompsa goto tr_setup; 685184610Salfred } 686184610Salfred return; 687184610Salfred } 688184610Salfred} 689184610Salfred 690184610Salfredstatic void 691188412Sthompsaudav_stop(struct usb2_ether *ue) 692184610Salfred{ 693188412Sthompsa struct udav_softc *sc = ue->ue_sc; 694188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(&sc->sc_ue); 695184610Salfred 696188412Sthompsa UDAV_LOCK_ASSERT(sc, MA_OWNED); 697184610Salfred 698188412Sthompsa ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 699188412Sthompsa sc->sc_flags &= ~UDAV_FLAG_LINK; 700184610Salfred 701184610Salfred /* 702184610Salfred * stop all the transfers, if not already stopped: 703184610Salfred */ 704187259Sthompsa usb2_transfer_stop(sc->sc_xfer[UDAV_BULK_DT_WR]); 705187259Sthompsa usb2_transfer_stop(sc->sc_xfer[UDAV_BULK_DT_RD]); 706187259Sthompsa usb2_transfer_stop(sc->sc_xfer[UDAV_INTR_DT_RD]); 707184610Salfred 708188412Sthompsa udav_reset(sc); 709184610Salfred} 710184610Salfred 711184610Salfredstatic int 712188412Sthompsaudav_ifmedia_upd(struct ifnet *ifp) 713184610Salfred{ 714184610Salfred struct udav_softc *sc = ifp->if_softc; 715184610Salfred struct mii_data *mii = GET_MII(sc); 716184610Salfred 717188412Sthompsa UDAV_LOCK_ASSERT(sc, MA_OWNED); 718184610Salfred 719188412Sthompsa sc->sc_flags &= ~UDAV_FLAG_LINK; 720184610Salfred if (mii->mii_instance) { 721184610Salfred struct mii_softc *miisc; 722184610Salfred 723188412Sthompsa LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 724184610Salfred mii_phy_reset(miisc); 725184610Salfred } 726184610Salfred mii_mediachg(mii); 727188412Sthompsa return (0); 728184610Salfred} 729184610Salfred 730184610Salfredstatic void 731188412Sthompsaudav_ifmedia_status(struct ifnet *ifp, struct ifmediareq *ifmr) 732184610Salfred{ 733184610Salfred struct udav_softc *sc = ifp->if_softc; 734188412Sthompsa struct mii_data *mii = GET_MII(sc); 735184610Salfred 736188412Sthompsa UDAV_LOCK(sc); 737188412Sthompsa mii_pollstat(mii); 738188412Sthompsa UDAV_UNLOCK(sc); 739188412Sthompsa ifmr->ifm_active = mii->mii_media_active; 740188412Sthompsa ifmr->ifm_status = mii->mii_media_status; 741184610Salfred} 742184610Salfred 743184610Salfredstatic void 744188412Sthompsaudav_tick(struct usb2_ether *ue) 745184610Salfred{ 746188412Sthompsa struct udav_softc *sc = ue->ue_sc; 747184610Salfred struct mii_data *mii = GET_MII(sc); 748184610Salfred 749188412Sthompsa UDAV_LOCK_ASSERT(sc, MA_OWNED); 750188412Sthompsa 751184610Salfred mii_tick(mii); 752188412Sthompsa if ((sc->sc_flags & UDAV_FLAG_LINK) == 0 753188412Sthompsa && mii->mii_media_status & IFM_ACTIVE && 754188412Sthompsa IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 755188412Sthompsa sc->sc_flags |= UDAV_FLAG_LINK; 756188412Sthompsa udav_start(ue); 757184610Salfred } 758184610Salfred} 759184610Salfred 760184610Salfredstatic int 761188412Sthompsaudav_miibus_readreg(device_t dev, int phy, int reg) 762184610Salfred{ 763184610Salfred struct udav_softc *sc = device_get_softc(dev); 764184610Salfred uint16_t data16; 765184610Salfred uint8_t val[2]; 766188412Sthompsa int locked; 767184610Salfred 768184610Salfred /* XXX: one PHY only for the internal PHY */ 769188412Sthompsa if (phy != 0) 770184610Salfred return (0); 771184610Salfred 772188412Sthompsa locked = mtx_owned(&sc->sc_mtx); 773188412Sthompsa if (!locked) 774188412Sthompsa UDAV_LOCK(sc); 775188412Sthompsa 776184610Salfred /* select internal PHY and set PHY register address */ 777188412Sthompsa udav_csr_write1(sc, UDAV_EPAR, 778184610Salfred UDAV_EPAR_PHY_ADR0 | (reg & UDAV_EPAR_EROA_MASK)); 779184610Salfred 780184610Salfred /* select PHY operation and start read command */ 781188412Sthompsa udav_csr_write1(sc, UDAV_EPCR, UDAV_EPCR_EPOS | UDAV_EPCR_ERPRR); 782184610Salfred 783184610Salfred /* XXX: should we wait? */ 784184610Salfred 785184610Salfred /* end read command */ 786188412Sthompsa UDAV_CLRBIT(sc, UDAV_EPCR, UDAV_EPCR_ERPRR); 787184610Salfred 788184610Salfred /* retrieve the result from data registers */ 789188412Sthompsa udav_csr_read(sc, UDAV_EPDRL, val, 2); 790184610Salfred 791184610Salfred data16 = (val[0] | (val[1] << 8)); 792184610Salfred 793184610Salfred DPRINTFN(11, "phy=%d reg=0x%04x => 0x%04x\n", 794184610Salfred phy, reg, data16); 795184610Salfred 796188412Sthompsa if (!locked) 797188412Sthompsa UDAV_UNLOCK(sc); 798184610Salfred return (data16); 799184610Salfred} 800184610Salfred 801184610Salfredstatic int 802188412Sthompsaudav_miibus_writereg(device_t dev, int phy, int reg, int data) 803184610Salfred{ 804184610Salfred struct udav_softc *sc = device_get_softc(dev); 805184610Salfred uint8_t val[2]; 806188412Sthompsa int locked; 807184610Salfred 808184610Salfred /* XXX: one PHY only for the internal PHY */ 809188412Sthompsa if (phy != 0) 810184610Salfred return (0); 811184610Salfred 812188412Sthompsa locked = mtx_owned(&sc->sc_mtx); 813188412Sthompsa if (!locked) 814188412Sthompsa UDAV_LOCK(sc); 815188412Sthompsa 816184610Salfred /* select internal PHY and set PHY register address */ 817188412Sthompsa udav_csr_write1(sc, UDAV_EPAR, 818184610Salfred UDAV_EPAR_PHY_ADR0 | (reg & UDAV_EPAR_EROA_MASK)); 819184610Salfred 820184610Salfred /* put the value to the data registers */ 821184610Salfred val[0] = (data & 0xff); 822184610Salfred val[1] = (data >> 8) & 0xff; 823188412Sthompsa udav_csr_write(sc, UDAV_EPDRL, val, 2); 824184610Salfred 825184610Salfred /* select PHY operation and start write command */ 826188412Sthompsa udav_csr_write1(sc, UDAV_EPCR, UDAV_EPCR_EPOS | UDAV_EPCR_ERPRW); 827184610Salfred 828184610Salfred /* XXX: should we wait? */ 829184610Salfred 830184610Salfred /* end write command */ 831188412Sthompsa UDAV_CLRBIT(sc, UDAV_EPCR, UDAV_EPCR_ERPRW); 832184610Salfred 833188412Sthompsa if (!locked) 834188412Sthompsa UDAV_UNLOCK(sc); 835184610Salfred return (0); 836184610Salfred} 837184610Salfred 838184610Salfredstatic void 839188412Sthompsaudav_miibus_statchg(device_t dev) 840184610Salfred{ 841184610Salfred /* nothing to do */ 842184610Salfred} 843184610Salfred 844184610Salfred/* 845184610Salfred * Stop all chip I/O so that the kernel's probe routines don't 846184610Salfred * get confused by errant DMAs when rebooting. 847184610Salfred */ 848184610Salfredstatic int 849184610Salfredudav_shutdown(device_t dev) 850184610Salfred{ 851184610Salfred struct udav_softc *sc = device_get_softc(dev); 852184610Salfred 853188412Sthompsa usb2_ether_ifshutdown(&sc->sc_ue); 854184610Salfred 855184610Salfred return (0); 856184610Salfred} 857