if_udav.c revision 223486
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 223486 2011-06-24 02:30:02Z hselasky $ */ 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 223486 2011-06-24 02:30:02Z hselasky $"); 48184610Salfred 49194677Sthompsa#include <sys/stdint.h> 50194677Sthompsa#include <sys/stddef.h> 51194677Sthompsa#include <sys/param.h> 52194677Sthompsa#include <sys/queue.h> 53194677Sthompsa#include <sys/types.h> 54194677Sthompsa#include <sys/systm.h> 55194677Sthompsa#include <sys/kernel.h> 56194677Sthompsa#include <sys/bus.h> 57194677Sthompsa#include <sys/module.h> 58194677Sthompsa#include <sys/lock.h> 59194677Sthompsa#include <sys/mutex.h> 60194677Sthompsa#include <sys/condvar.h> 61194677Sthompsa#include <sys/sysctl.h> 62194677Sthompsa#include <sys/sx.h> 63194677Sthompsa#include <sys/unistd.h> 64194677Sthompsa#include <sys/callout.h> 65194677Sthompsa#include <sys/malloc.h> 66194677Sthompsa#include <sys/priv.h> 67194677Sthompsa 68194677Sthompsa#include <dev/usb/usb.h> 69194677Sthompsa#include <dev/usb/usbdi.h> 70194677Sthompsa#include <dev/usb/usbdi_util.h> 71188746Sthompsa#include "usbdevs.h" 72184610Salfred 73184610Salfred#define USB_DEBUG_VAR udav_debug 74194677Sthompsa#include <dev/usb/usb_debug.h> 75188942Sthompsa#include <dev/usb/usb_process.h> 76184610Salfred 77188942Sthompsa#include <dev/usb/net/usb_ethernet.h> 78188942Sthompsa#include <dev/usb/net/if_udavreg.h> 79184610Salfred 80184610Salfred/* prototypes */ 81184610Salfred 82184610Salfredstatic device_probe_t udav_probe; 83184610Salfredstatic device_attach_t udav_attach; 84184610Salfredstatic device_detach_t udav_detach; 85184610Salfred 86193045Sthompsastatic usb_callback_t udav_bulk_write_callback; 87193045Sthompsastatic usb_callback_t udav_bulk_read_callback; 88193045Sthompsastatic usb_callback_t udav_intr_callback; 89184610Salfred 90193045Sthompsastatic uether_fn_t udav_attach_post; 91193045Sthompsastatic uether_fn_t udav_init; 92193045Sthompsastatic uether_fn_t udav_stop; 93193045Sthompsastatic uether_fn_t udav_start; 94193045Sthompsastatic uether_fn_t udav_tick; 95193045Sthompsastatic uether_fn_t udav_setmulti; 96193045Sthompsastatic uether_fn_t udav_setpromisc; 97184610Salfred 98188412Sthompsastatic int udav_csr_read(struct udav_softc *, uint16_t, void *, int); 99188412Sthompsastatic int udav_csr_write(struct udav_softc *, uint16_t, void *, int); 100188412Sthompsastatic uint8_t udav_csr_read1(struct udav_softc *, uint16_t); 101188412Sthompsastatic int udav_csr_write1(struct udav_softc *, uint16_t, uint8_t); 102188412Sthompsastatic void udav_reset(struct udav_softc *); 103188412Sthompsastatic int udav_ifmedia_upd(struct ifnet *); 104188412Sthompsastatic void udav_ifmedia_status(struct ifnet *, struct ifmediareq *); 105184610Salfred 106188412Sthompsastatic miibus_readreg_t udav_miibus_readreg; 107188412Sthompsastatic miibus_writereg_t udav_miibus_writereg; 108188412Sthompsastatic miibus_statchg_t udav_miibus_statchg; 109184610Salfred 110192984Sthompsastatic const struct usb_config udav_config[UDAV_N_TRANSFER] = { 111184610Salfred 112187259Sthompsa [UDAV_BULK_DT_WR] = { 113184610Salfred .type = UE_BULK, 114184610Salfred .endpoint = UE_ADDR_ANY, 115184610Salfred .direction = UE_DIR_OUT, 116190734Sthompsa .bufsize = (MCLBYTES + 2), 117190734Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 118190734Sthompsa .callback = udav_bulk_write_callback, 119190734Sthompsa .timeout = 10000, /* 10 seconds */ 120184610Salfred }, 121184610Salfred 122187259Sthompsa [UDAV_BULK_DT_RD] = { 123184610Salfred .type = UE_BULK, 124184610Salfred .endpoint = UE_ADDR_ANY, 125184610Salfred .direction = UE_DIR_IN, 126190734Sthompsa .bufsize = (MCLBYTES + 3), 127190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 128190734Sthompsa .callback = udav_bulk_read_callback, 129190734Sthompsa .timeout = 0, /* no timeout */ 130184610Salfred }, 131184610Salfred 132187259Sthompsa [UDAV_INTR_DT_RD] = { 133184610Salfred .type = UE_INTERRUPT, 134184610Salfred .endpoint = UE_ADDR_ANY, 135184610Salfred .direction = UE_DIR_IN, 136190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 137190734Sthompsa .bufsize = 0, /* use wMaxPacketSize */ 138190734Sthompsa .callback = udav_intr_callback, 139184610Salfred }, 140184610Salfred}; 141184610Salfred 142184610Salfredstatic device_method_t udav_methods[] = { 143184610Salfred /* Device interface */ 144184610Salfred DEVMETHOD(device_probe, udav_probe), 145184610Salfred DEVMETHOD(device_attach, udav_attach), 146184610Salfred DEVMETHOD(device_detach, udav_detach), 147184610Salfred 148184610Salfred /* bus interface */ 149184610Salfred DEVMETHOD(bus_print_child, bus_generic_print_child), 150184610Salfred DEVMETHOD(bus_driver_added, bus_generic_driver_added), 151184610Salfred 152184610Salfred /* MII interface */ 153188412Sthompsa DEVMETHOD(miibus_readreg, udav_miibus_readreg), 154188412Sthompsa DEVMETHOD(miibus_writereg, udav_miibus_writereg), 155188412Sthompsa DEVMETHOD(miibus_statchg, udav_miibus_statchg), 156184610Salfred 157184610Salfred {0, 0} 158184610Salfred}; 159184610Salfred 160184610Salfredstatic driver_t udav_driver = { 161184610Salfred .name = "udav", 162184610Salfred .methods = udav_methods, 163184610Salfred .size = sizeof(struct udav_softc), 164184610Salfred}; 165184610Salfred 166184610Salfredstatic devclass_t udav_devclass; 167184610Salfred 168189275SthompsaDRIVER_MODULE(udav, uhub, udav_driver, udav_devclass, NULL, 0); 169184610SalfredDRIVER_MODULE(miibus, udav, miibus_driver, miibus_devclass, 0, 0); 170188942SthompsaMODULE_DEPEND(udav, uether, 1, 1, 1); 171188942SthompsaMODULE_DEPEND(udav, usb, 1, 1, 1); 172184610SalfredMODULE_DEPEND(udav, ether, 1, 1, 1); 173184610SalfredMODULE_DEPEND(udav, miibus, 1, 1, 1); 174212122SthompsaMODULE_VERSION(udav, 1); 175184610Salfred 176192984Sthompsastatic const struct usb_ether_methods udav_ue_methods = { 177188412Sthompsa .ue_attach_post = udav_attach_post, 178188412Sthompsa .ue_start = udav_start, 179188412Sthompsa .ue_init = udav_init, 180188412Sthompsa .ue_stop = udav_stop, 181188412Sthompsa .ue_tick = udav_tick, 182188412Sthompsa .ue_setmulti = udav_setmulti, 183188412Sthompsa .ue_setpromisc = udav_setpromisc, 184188412Sthompsa .ue_mii_upd = udav_ifmedia_upd, 185188412Sthompsa .ue_mii_sts = udav_ifmedia_status, 186188412Sthompsa}; 187188412Sthompsa 188207077Sthompsa#ifdef USB_DEBUG 189184610Salfredstatic int udav_debug = 0; 190184610Salfred 191192502SthompsaSYSCTL_NODE(_hw_usb, OID_AUTO, udav, CTLFLAG_RW, 0, "USB udav"); 192192502SthompsaSYSCTL_INT(_hw_usb_udav, OID_AUTO, debug, CTLFLAG_RW, &udav_debug, 0, 193184610Salfred "Debug level"); 194184610Salfred#endif 195184610Salfred 196188412Sthompsa#define UDAV_SETBIT(sc, reg, x) \ 197188412Sthompsa udav_csr_write1(sc, reg, udav_csr_read1(sc, reg) | (x)) 198184610Salfred 199188412Sthompsa#define UDAV_CLRBIT(sc, reg, x) \ 200188412Sthompsa udav_csr_write1(sc, reg, udav_csr_read1(sc, reg) & ~(x)) 201184610Salfred 202223486Shselaskystatic const STRUCT_USB_HOST_ID udav_devs[] = { 203184610Salfred /* ShanTou DM9601 USB NIC */ 204184610Salfred {USB_VPI(USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_DM9601, 0)}, 205184610Salfred /* ShanTou ST268 USB NIC */ 206184610Salfred {USB_VPI(USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_ST268, 0)}, 207184610Salfred /* Corega USB-TXC */ 208184610Salfred {USB_VPI(USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TXC, 0)}, 209218864Shselasky /* ShanTou AMD8515 USB NIC */ 210218864Shselasky {USB_VPI(USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_ADM8515, 0)}, 211218864Shselasky /* Kontron AG USB Ethernet */ 212218864Shselasky {USB_VPI(USB_VENDOR_KONTRON, USB_PRODUCT_KONTRON_DM9601, 0)}, 213223288Shselasky {USB_VPI(USB_VENDOR_KONTRON, USB_PRODUCT_KONTRON_JP1082, 0)}, 214184610Salfred}; 215184610Salfred 216188412Sthompsastatic void 217192984Sthompsaudav_attach_post(struct usb_ether *ue) 218188412Sthompsa{ 219194228Sthompsa struct udav_softc *sc = uether_getsc(ue); 220188412Sthompsa 221188412Sthompsa /* reset the adapter */ 222188412Sthompsa udav_reset(sc); 223188412Sthompsa 224188412Sthompsa /* Get Ethernet Address */ 225188412Sthompsa udav_csr_read(sc, UDAV_PAR, ue->ue_eaddr, ETHER_ADDR_LEN); 226188412Sthompsa} 227188412Sthompsa 228184610Salfredstatic int 229184610Salfredudav_probe(device_t dev) 230184610Salfred{ 231192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 232184610Salfred 233192499Sthompsa if (uaa->usb_mode != USB_MODE_HOST) 234184610Salfred return (ENXIO); 235188412Sthompsa if (uaa->info.bConfigIndex != UDAV_CONFIG_INDEX) 236184610Salfred return (ENXIO); 237188412Sthompsa if (uaa->info.bIfaceIndex != UDAV_IFACE_INDEX) 238184610Salfred return (ENXIO); 239188412Sthompsa 240194228Sthompsa return (usbd_lookup_id_by_uaa(udav_devs, sizeof(udav_devs), uaa)); 241184610Salfred} 242184610Salfred 243184610Salfredstatic int 244184610Salfredudav_attach(device_t dev) 245184610Salfred{ 246192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 247184610Salfred struct udav_softc *sc = device_get_softc(dev); 248192984Sthompsa struct usb_ether *ue = &sc->sc_ue; 249184610Salfred uint8_t iface_index; 250188412Sthompsa int error; 251184610Salfred 252184610Salfred sc->sc_flags = USB_GET_DRIVER_INFO(uaa); 253184610Salfred 254194228Sthompsa device_set_usb_desc(dev); 255184610Salfred 256188412Sthompsa mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 257184610Salfred 258184610Salfred iface_index = UDAV_IFACE_INDEX; 259194228Sthompsa error = usbd_transfer_setup(uaa->device, &iface_index, 260187259Sthompsa sc->sc_xfer, udav_config, UDAV_N_TRANSFER, sc, &sc->sc_mtx); 261184610Salfred if (error) { 262199816Sthompsa device_printf(dev, "allocating USB transfers failed\n"); 263184610Salfred goto detach; 264184610Salfred } 265188412Sthompsa 266188412Sthompsa ue->ue_sc = sc; 267188412Sthompsa ue->ue_dev = dev; 268188412Sthompsa ue->ue_udev = uaa->device; 269188412Sthompsa ue->ue_mtx = &sc->sc_mtx; 270188412Sthompsa ue->ue_methods = &udav_ue_methods; 271188412Sthompsa 272194228Sthompsa error = uether_ifattach(ue); 273184610Salfred if (error) { 274188412Sthompsa device_printf(dev, "could not attach interface\n"); 275184610Salfred goto detach; 276184610Salfred } 277184610Salfred 278184610Salfred return (0); /* success */ 279184610Salfred 280184610Salfreddetach: 281184610Salfred udav_detach(dev); 282184610Salfred return (ENXIO); /* failure */ 283184610Salfred} 284184610Salfred 285184610Salfredstatic int 286184610Salfredudav_detach(device_t dev) 287184610Salfred{ 288184610Salfred struct udav_softc *sc = device_get_softc(dev); 289192984Sthompsa struct usb_ether *ue = &sc->sc_ue; 290184610Salfred 291194228Sthompsa usbd_transfer_unsetup(sc->sc_xfer, UDAV_N_TRANSFER); 292194228Sthompsa uether_ifdetach(ue); 293184610Salfred mtx_destroy(&sc->sc_mtx); 294184610Salfred 295184610Salfred return (0); 296184610Salfred} 297184610Salfred 298184610Salfred#if 0 299188412Sthompsastatic int 300188412Sthompsaudav_mem_read(struct udav_softc *sc, uint16_t offset, void *buf, 301188412Sthompsa int len) 302184610Salfred{ 303192984Sthompsa struct usb_device_request req; 304184610Salfred 305184610Salfred len &= 0xff; 306184610Salfred 307184610Salfred req.bmRequestType = UT_READ_VENDOR_DEVICE; 308184610Salfred req.bRequest = UDAV_REQ_MEM_READ; 309184610Salfred USETW(req.wValue, 0x0000); 310184610Salfred USETW(req.wIndex, offset); 311184610Salfred USETW(req.wLength, len); 312184610Salfred 313194228Sthompsa return (uether_do_request(&sc->sc_ue, &req, buf, 1000)); 314184610Salfred} 315184610Salfred 316188412Sthompsastatic int 317188412Sthompsaudav_mem_write(struct udav_softc *sc, uint16_t offset, void *buf, 318188412Sthompsa int len) 319184610Salfred{ 320192984Sthompsa struct usb_device_request req; 321184610Salfred 322184610Salfred len &= 0xff; 323184610Salfred 324184610Salfred req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 325184610Salfred req.bRequest = UDAV_REQ_MEM_WRITE; 326184610Salfred USETW(req.wValue, 0x0000); 327184610Salfred USETW(req.wIndex, offset); 328184610Salfred USETW(req.wLength, len); 329184610Salfred 330194228Sthompsa return (uether_do_request(&sc->sc_ue, &req, buf, 1000)); 331184610Salfred} 332184610Salfred 333188412Sthompsastatic int 334188412Sthompsaudav_mem_write1(struct udav_softc *sc, uint16_t offset, 335184610Salfred uint8_t ch) 336184610Salfred{ 337192984Sthompsa struct usb_device_request req; 338184610Salfred 339184610Salfred req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 340184610Salfred req.bRequest = UDAV_REQ_MEM_WRITE1; 341184610Salfred USETW(req.wValue, ch); 342184610Salfred USETW(req.wIndex, offset); 343184610Salfred USETW(req.wLength, 0x0000); 344184610Salfred 345194228Sthompsa return (uether_do_request(&sc->sc_ue, &req, NULL, 1000)); 346184610Salfred} 347184610Salfred#endif 348184610Salfred 349188412Sthompsastatic int 350188412Sthompsaudav_csr_read(struct udav_softc *sc, uint16_t offset, void *buf, int len) 351184610Salfred{ 352192984Sthompsa struct usb_device_request req; 353184610Salfred 354184610Salfred len &= 0xff; 355184610Salfred 356184610Salfred req.bmRequestType = UT_READ_VENDOR_DEVICE; 357184610Salfred req.bRequest = UDAV_REQ_REG_READ; 358184610Salfred USETW(req.wValue, 0x0000); 359184610Salfred USETW(req.wIndex, offset); 360184610Salfred USETW(req.wLength, len); 361184610Salfred 362194228Sthompsa return (uether_do_request(&sc->sc_ue, &req, buf, 1000)); 363184610Salfred} 364184610Salfred 365188412Sthompsastatic int 366188412Sthompsaudav_csr_write(struct udav_softc *sc, uint16_t offset, void *buf, int len) 367184610Salfred{ 368192984Sthompsa struct usb_device_request req; 369184610Salfred 370184610Salfred offset &= 0xff; 371184610Salfred len &= 0xff; 372184610Salfred 373184610Salfred req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 374184610Salfred req.bRequest = UDAV_REQ_REG_WRITE; 375184610Salfred USETW(req.wValue, 0x0000); 376184610Salfred USETW(req.wIndex, offset); 377184610Salfred USETW(req.wLength, len); 378184610Salfred 379194228Sthompsa return (uether_do_request(&sc->sc_ue, &req, buf, 1000)); 380184610Salfred} 381184610Salfred 382184610Salfredstatic uint8_t 383188412Sthompsaudav_csr_read1(struct udav_softc *sc, uint16_t offset) 384184610Salfred{ 385184610Salfred uint8_t val; 386184610Salfred 387188412Sthompsa udav_csr_read(sc, offset, &val, 1); 388184610Salfred return (val); 389184610Salfred} 390184610Salfred 391188412Sthompsastatic int 392188412Sthompsaudav_csr_write1(struct udav_softc *sc, uint16_t offset, 393184610Salfred uint8_t ch) 394184610Salfred{ 395192984Sthompsa struct usb_device_request req; 396184610Salfred 397184610Salfred offset &= 0xff; 398184610Salfred 399184610Salfred req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 400184610Salfred req.bRequest = UDAV_REQ_REG_WRITE1; 401184610Salfred USETW(req.wValue, ch); 402184610Salfred USETW(req.wIndex, offset); 403184610Salfred USETW(req.wLength, 0x0000); 404184610Salfred 405194228Sthompsa return (uether_do_request(&sc->sc_ue, &req, NULL, 1000)); 406184610Salfred} 407184610Salfred 408184610Salfredstatic void 409192984Sthompsaudav_init(struct usb_ether *ue) 410184610Salfred{ 411188412Sthompsa struct udav_softc *sc = ue->ue_sc; 412194228Sthompsa struct ifnet *ifp = uether_getifp(&sc->sc_ue); 413184610Salfred 414188412Sthompsa UDAV_LOCK_ASSERT(sc, MA_OWNED); 415184610Salfred 416184610Salfred /* 417184610Salfred * Cancel pending I/O 418184610Salfred */ 419188412Sthompsa udav_stop(ue); 420184610Salfred 421184610Salfred /* set MAC address */ 422188412Sthompsa udav_csr_write(sc, UDAV_PAR, IF_LLADDR(ifp), ETHER_ADDR_LEN); 423184610Salfred 424184610Salfred /* initialize network control register */ 425184610Salfred 426184610Salfred /* disable loopback */ 427188412Sthompsa UDAV_CLRBIT(sc, UDAV_NCR, UDAV_NCR_LBK0 | UDAV_NCR_LBK1); 428184610Salfred 429184610Salfred /* Initialize RX control register */ 430188412Sthompsa UDAV_SETBIT(sc, UDAV_RCR, UDAV_RCR_DIS_LONG | UDAV_RCR_DIS_CRC); 431184610Salfred 432184610Salfred /* load multicast filter and update promiscious mode bit */ 433188412Sthompsa udav_setpromisc(ue); 434184610Salfred 435184610Salfred /* enable RX */ 436188412Sthompsa UDAV_SETBIT(sc, UDAV_RCR, UDAV_RCR_RXEN); 437184610Salfred 438184610Salfred /* clear POWER_DOWN state of internal PHY */ 439188412Sthompsa UDAV_SETBIT(sc, UDAV_GPCR, UDAV_GPCR_GEP_CNTL0); 440188412Sthompsa UDAV_CLRBIT(sc, UDAV_GPR, UDAV_GPR_GEPIO0); 441184610Salfred 442194677Sthompsa usbd_xfer_set_stall(sc->sc_xfer[UDAV_BULK_DT_WR]); 443184610Salfred 444188412Sthompsa ifp->if_drv_flags |= IFF_DRV_RUNNING; 445188412Sthompsa udav_start(ue); 446184610Salfred} 447184610Salfred 448184610Salfredstatic void 449188412Sthompsaudav_reset(struct udav_softc *sc) 450184610Salfred{ 451188412Sthompsa int i; 452184610Salfred 453184610Salfred /* Select PHY */ 454184610Salfred#if 1 455184610Salfred /* 456184610Salfred * XXX: force select internal phy. 457184610Salfred * external phy routines are not tested. 458184610Salfred */ 459188412Sthompsa UDAV_CLRBIT(sc, UDAV_NCR, UDAV_NCR_EXT_PHY); 460184610Salfred#else 461188412Sthompsa if (sc->sc_flags & UDAV_EXT_PHY) 462188412Sthompsa UDAV_SETBIT(sc, UDAV_NCR, UDAV_NCR_EXT_PHY); 463188412Sthompsa else 464188412Sthompsa UDAV_CLRBIT(sc, UDAV_NCR, UDAV_NCR_EXT_PHY); 465184610Salfred#endif 466184610Salfred 467188412Sthompsa UDAV_SETBIT(sc, UDAV_NCR, UDAV_NCR_RST); 468184610Salfred 469188412Sthompsa for (i = 0; i < UDAV_TX_TIMEOUT; i++) { 470188412Sthompsa if (!(udav_csr_read1(sc, UDAV_NCR) & UDAV_NCR_RST)) 471184610Salfred break; 472194228Sthompsa if (uether_pause(&sc->sc_ue, hz / 100)) 473188412Sthompsa break; 474184610Salfred } 475184610Salfred 476194228Sthompsa uether_pause(&sc->sc_ue, hz / 100); 477184610Salfred} 478184610Salfred 479184610Salfred#define UDAV_BITS 6 480184610Salfredstatic void 481192984Sthompsaudav_setmulti(struct usb_ether *ue) 482184610Salfred{ 483188412Sthompsa struct udav_softc *sc = ue->ue_sc; 484194228Sthompsa struct ifnet *ifp = uether_getifp(&sc->sc_ue); 485188412Sthompsa struct ifmultiaddr *ifma; 486188412Sthompsa uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 487188412Sthompsa int h = 0; 488184610Salfred 489188412Sthompsa UDAV_LOCK_ASSERT(sc, MA_OWNED); 490184610Salfred 491188412Sthompsa if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 492188412Sthompsa UDAV_SETBIT(sc, UDAV_RCR, UDAV_RCR_ALL|UDAV_RCR_PRMSC); 493188412Sthompsa return; 494188412Sthompsa } 495188412Sthompsa 496188412Sthompsa /* first, zot all the existing hash bits */ 497188412Sthompsa memset(hashtbl, 0x00, sizeof(hashtbl)); 498188412Sthompsa hashtbl[7] |= 0x80; /* broadcast address */ 499188412Sthompsa udav_csr_write(sc, UDAV_MAR, hashtbl, sizeof(hashtbl)); 500188412Sthompsa 501188412Sthompsa /* now program new ones */ 502195049Srwatson if_maddr_rlock(ifp); 503188412Sthompsa TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) 504188412Sthompsa { 505188412Sthompsa if (ifma->ifma_addr->sa_family != AF_LINK) 506188412Sthompsa continue; 507188412Sthompsa h = ether_crc32_be(LLADDR((struct sockaddr_dl *) 508188412Sthompsa ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; 509188412Sthompsa hashtbl[h / 8] |= 1 << (h % 8); 510188412Sthompsa } 511195049Srwatson if_maddr_runlock(ifp); 512188412Sthompsa 513188412Sthompsa /* disable all multicast */ 514188412Sthompsa UDAV_CLRBIT(sc, UDAV_RCR, UDAV_RCR_ALL); 515188412Sthompsa 516188412Sthompsa /* write hash value to the register */ 517188412Sthompsa udav_csr_write(sc, UDAV_MAR, hashtbl, sizeof(hashtbl)); 518184610Salfred} 519184610Salfred 520184610Salfredstatic void 521192984Sthompsaudav_setpromisc(struct usb_ether *ue) 522184610Salfred{ 523188412Sthompsa struct udav_softc *sc = ue->ue_sc; 524194228Sthompsa struct ifnet *ifp = uether_getifp(&sc->sc_ue); 525184610Salfred uint8_t rxmode; 526184610Salfred 527188412Sthompsa rxmode = udav_csr_read1(sc, UDAV_RCR); 528184610Salfred rxmode &= ~(UDAV_RCR_ALL | UDAV_RCR_PRMSC); 529184610Salfred 530188412Sthompsa if (ifp->if_flags & IFF_PROMISC) 531184610Salfred rxmode |= UDAV_RCR_ALL | UDAV_RCR_PRMSC; 532188412Sthompsa else if (ifp->if_flags & IFF_ALLMULTI) 533184610Salfred rxmode |= UDAV_RCR_ALL; 534184610Salfred 535184610Salfred /* write new mode bits */ 536188412Sthompsa udav_csr_write1(sc, UDAV_RCR, rxmode); 537184610Salfred} 538184610Salfred 539184610Salfredstatic void 540192984Sthompsaudav_start(struct usb_ether *ue) 541184610Salfred{ 542188412Sthompsa struct udav_softc *sc = ue->ue_sc; 543184610Salfred 544188412Sthompsa /* 545188412Sthompsa * start the USB transfers, if not already started: 546188412Sthompsa */ 547194228Sthompsa usbd_transfer_start(sc->sc_xfer[UDAV_INTR_DT_RD]); 548194228Sthompsa usbd_transfer_start(sc->sc_xfer[UDAV_BULK_DT_RD]); 549194228Sthompsa usbd_transfer_start(sc->sc_xfer[UDAV_BULK_DT_WR]); 550184610Salfred} 551184610Salfred 552184610Salfredstatic void 553194677Sthompsaudav_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) 554184610Salfred{ 555194677Sthompsa struct udav_softc *sc = usbd_xfer_softc(xfer); 556194228Sthompsa struct ifnet *ifp = uether_getifp(&sc->sc_ue); 557194677Sthompsa struct usb_page_cache *pc; 558184610Salfred struct mbuf *m; 559188412Sthompsa int extra_len; 560188412Sthompsa int temp_len; 561184610Salfred uint8_t buf[2]; 562184610Salfred 563184610Salfred switch (USB_GET_STATE(xfer)) { 564184610Salfred case USB_ST_TRANSFERRED: 565184610Salfred DPRINTFN(11, "transfer complete\n"); 566184610Salfred ifp->if_opackets++; 567184610Salfred 568188412Sthompsa /* FALLTHROUGH */ 569184610Salfred case USB_ST_SETUP: 570188412Sthompsatr_setup: 571188412Sthompsa if ((sc->sc_flags & UDAV_FLAG_LINK) == 0) { 572184610Salfred /* 573184610Salfred * don't send anything if there is no link ! 574184610Salfred */ 575188412Sthompsa return; 576184610Salfred } 577184610Salfred IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 578184610Salfred 579188412Sthompsa if (m == NULL) 580188412Sthompsa return; 581188412Sthompsa if (m->m_pkthdr.len > MCLBYTES) 582184610Salfred m->m_pkthdr.len = MCLBYTES; 583184610Salfred if (m->m_pkthdr.len < UDAV_MIN_FRAME_LEN) { 584184610Salfred extra_len = UDAV_MIN_FRAME_LEN - m->m_pkthdr.len; 585184610Salfred } else { 586184610Salfred extra_len = 0; 587184610Salfred } 588184610Salfred 589184610Salfred temp_len = (m->m_pkthdr.len + extra_len); 590184610Salfred 591184610Salfred /* 592184610Salfred * the frame length is specified in the first 2 bytes of the 593184610Salfred * buffer 594184610Salfred */ 595184610Salfred buf[0] = (uint8_t)(temp_len); 596184610Salfred buf[1] = (uint8_t)(temp_len >> 8); 597184610Salfred 598184610Salfred temp_len += 2; 599184610Salfred 600194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 601194677Sthompsa usbd_copy_in(pc, 0, buf, 2); 602194677Sthompsa usbd_m_copy_in(pc, 2, m, 0, m->m_pkthdr.len); 603184610Salfred 604194677Sthompsa if (extra_len) 605194677Sthompsa usbd_frame_zero(pc, temp_len - extra_len, extra_len); 606184610Salfred /* 607184610Salfred * if there's a BPF listener, bounce a copy 608184610Salfred * of this frame to him: 609184610Salfred */ 610184610Salfred BPF_MTAP(ifp, m); 611184610Salfred 612184610Salfred m_freem(m); 613184610Salfred 614194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, temp_len); 615194228Sthompsa usbd_transfer_submit(xfer); 616184610Salfred return; 617184610Salfred 618184610Salfred default: /* Error */ 619184610Salfred DPRINTFN(11, "transfer error, %s\n", 620194677Sthompsa usbd_errstr(error)); 621184610Salfred 622188412Sthompsa ifp->if_oerrors++; 623188412Sthompsa 624194677Sthompsa if (error != USB_ERR_CANCELLED) { 625184610Salfred /* try to clear stall first */ 626194677Sthompsa usbd_xfer_set_stall(xfer); 627188412Sthompsa goto tr_setup; 628184610Salfred } 629184610Salfred return; 630184610Salfred } 631184610Salfred} 632184610Salfred 633184610Salfredstatic void 634194677Sthompsaudav_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) 635184610Salfred{ 636194677Sthompsa struct udav_softc *sc = usbd_xfer_softc(xfer); 637192984Sthompsa struct usb_ether *ue = &sc->sc_ue; 638194228Sthompsa struct ifnet *ifp = uether_getifp(ue); 639194677Sthompsa struct usb_page_cache *pc; 640188412Sthompsa struct udav_rxpkt stat; 641188412Sthompsa int len; 642194677Sthompsa int actlen; 643184610Salfred 644194677Sthompsa usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 645194677Sthompsa 646184610Salfred switch (USB_GET_STATE(xfer)) { 647184610Salfred case USB_ST_TRANSFERRED: 648184610Salfred 649194677Sthompsa if (actlen < sizeof(stat) + ETHER_CRC_LEN) { 650184610Salfred ifp->if_ierrors++; 651184610Salfred goto tr_setup; 652184610Salfred } 653194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 654194677Sthompsa usbd_copy_out(pc, 0, &stat, sizeof(stat)); 655194677Sthompsa actlen -= sizeof(stat); 656194677Sthompsa len = min(actlen, le16toh(stat.pktlen)); 657188412Sthompsa len -= ETHER_CRC_LEN; 658184610Salfred 659188412Sthompsa if (stat.rxstat & UDAV_RSR_LCS) { 660184610Salfred ifp->if_collisions++; 661184610Salfred goto tr_setup; 662184610Salfred } 663188412Sthompsa if (stat.rxstat & UDAV_RSR_ERR) { 664184610Salfred ifp->if_ierrors++; 665184610Salfred goto tr_setup; 666184610Salfred } 667194677Sthompsa uether_rxbuf(ue, pc, sizeof(stat), len); 668188412Sthompsa /* FALLTHROUGH */ 669184610Salfred case USB_ST_SETUP: 670184610Salfredtr_setup: 671194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 672194228Sthompsa usbd_transfer_submit(xfer); 673194228Sthompsa uether_rxflush(ue); 674184610Salfred return; 675184610Salfred 676184610Salfred default: /* Error */ 677188412Sthompsa DPRINTF("bulk read error, %s\n", 678194677Sthompsa usbd_errstr(error)); 679188412Sthompsa 680194677Sthompsa if (error != USB_ERR_CANCELLED) { 681184610Salfred /* try to clear stall first */ 682194677Sthompsa usbd_xfer_set_stall(xfer); 683188412Sthompsa goto tr_setup; 684184610Salfred } 685184610Salfred return; 686184610Salfred } 687184610Salfred} 688184610Salfred 689184610Salfredstatic void 690194677Sthompsaudav_intr_callback(struct usb_xfer *xfer, usb_error_t error) 691184610Salfred{ 692184610Salfred switch (USB_GET_STATE(xfer)) { 693184610Salfred case USB_ST_TRANSFERRED: 694184610Salfred case USB_ST_SETUP: 695188412Sthompsatr_setup: 696194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 697194228Sthompsa usbd_transfer_submit(xfer); 698184610Salfred return; 699184610Salfred 700184610Salfred default: /* Error */ 701194677Sthompsa if (error != USB_ERR_CANCELLED) { 702188412Sthompsa /* try to clear stall first */ 703194677Sthompsa usbd_xfer_set_stall(xfer); 704188412Sthompsa goto tr_setup; 705184610Salfred } 706184610Salfred return; 707184610Salfred } 708184610Salfred} 709184610Salfred 710184610Salfredstatic void 711192984Sthompsaudav_stop(struct usb_ether *ue) 712184610Salfred{ 713188412Sthompsa struct udav_softc *sc = ue->ue_sc; 714194228Sthompsa struct ifnet *ifp = uether_getifp(&sc->sc_ue); 715184610Salfred 716188412Sthompsa UDAV_LOCK_ASSERT(sc, MA_OWNED); 717184610Salfred 718188412Sthompsa ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 719188412Sthompsa sc->sc_flags &= ~UDAV_FLAG_LINK; 720184610Salfred 721184610Salfred /* 722184610Salfred * stop all the transfers, if not already stopped: 723184610Salfred */ 724194228Sthompsa usbd_transfer_stop(sc->sc_xfer[UDAV_BULK_DT_WR]); 725194228Sthompsa usbd_transfer_stop(sc->sc_xfer[UDAV_BULK_DT_RD]); 726194228Sthompsa usbd_transfer_stop(sc->sc_xfer[UDAV_INTR_DT_RD]); 727184610Salfred 728188412Sthompsa udav_reset(sc); 729184610Salfred} 730184610Salfred 731184610Salfredstatic int 732188412Sthompsaudav_ifmedia_upd(struct ifnet *ifp) 733184610Salfred{ 734184610Salfred struct udav_softc *sc = ifp->if_softc; 735184610Salfred struct mii_data *mii = GET_MII(sc); 736221407Smarius struct mii_softc *miisc; 737184610Salfred 738188412Sthompsa UDAV_LOCK_ASSERT(sc, MA_OWNED); 739184610Salfred 740188412Sthompsa sc->sc_flags &= ~UDAV_FLAG_LINK; 741221407Smarius LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 742221407Smarius PHY_RESET(miisc); 743184610Salfred mii_mediachg(mii); 744188412Sthompsa return (0); 745184610Salfred} 746184610Salfred 747184610Salfredstatic void 748188412Sthompsaudav_ifmedia_status(struct ifnet *ifp, struct ifmediareq *ifmr) 749184610Salfred{ 750184610Salfred struct udav_softc *sc = ifp->if_softc; 751188412Sthompsa struct mii_data *mii = GET_MII(sc); 752184610Salfred 753188412Sthompsa UDAV_LOCK(sc); 754188412Sthompsa mii_pollstat(mii); 755188412Sthompsa UDAV_UNLOCK(sc); 756188412Sthompsa ifmr->ifm_active = mii->mii_media_active; 757188412Sthompsa ifmr->ifm_status = mii->mii_media_status; 758184610Salfred} 759184610Salfred 760184610Salfredstatic void 761192984Sthompsaudav_tick(struct usb_ether *ue) 762184610Salfred{ 763188412Sthompsa struct udav_softc *sc = ue->ue_sc; 764184610Salfred struct mii_data *mii = GET_MII(sc); 765184610Salfred 766188412Sthompsa UDAV_LOCK_ASSERT(sc, MA_OWNED); 767188412Sthompsa 768184610Salfred mii_tick(mii); 769188412Sthompsa if ((sc->sc_flags & UDAV_FLAG_LINK) == 0 770188412Sthompsa && mii->mii_media_status & IFM_ACTIVE && 771188412Sthompsa IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 772188412Sthompsa sc->sc_flags |= UDAV_FLAG_LINK; 773188412Sthompsa udav_start(ue); 774184610Salfred } 775184610Salfred} 776184610Salfred 777184610Salfredstatic int 778188412Sthompsaudav_miibus_readreg(device_t dev, int phy, int reg) 779184610Salfred{ 780184610Salfred struct udav_softc *sc = device_get_softc(dev); 781184610Salfred uint16_t data16; 782184610Salfred uint8_t val[2]; 783188412Sthompsa int locked; 784184610Salfred 785184610Salfred /* XXX: one PHY only for the internal PHY */ 786188412Sthompsa if (phy != 0) 787184610Salfred return (0); 788184610Salfred 789188412Sthompsa locked = mtx_owned(&sc->sc_mtx); 790188412Sthompsa if (!locked) 791188412Sthompsa UDAV_LOCK(sc); 792188412Sthompsa 793184610Salfred /* select internal PHY and set PHY register address */ 794188412Sthompsa udav_csr_write1(sc, UDAV_EPAR, 795184610Salfred UDAV_EPAR_PHY_ADR0 | (reg & UDAV_EPAR_EROA_MASK)); 796184610Salfred 797184610Salfred /* select PHY operation and start read command */ 798188412Sthompsa udav_csr_write1(sc, UDAV_EPCR, UDAV_EPCR_EPOS | UDAV_EPCR_ERPRR); 799184610Salfred 800184610Salfred /* XXX: should we wait? */ 801184610Salfred 802184610Salfred /* end read command */ 803188412Sthompsa UDAV_CLRBIT(sc, UDAV_EPCR, UDAV_EPCR_ERPRR); 804184610Salfred 805184610Salfred /* retrieve the result from data registers */ 806188412Sthompsa udav_csr_read(sc, UDAV_EPDRL, val, 2); 807184610Salfred 808184610Salfred data16 = (val[0] | (val[1] << 8)); 809184610Salfred 810184610Salfred DPRINTFN(11, "phy=%d reg=0x%04x => 0x%04x\n", 811184610Salfred phy, reg, data16); 812184610Salfred 813188412Sthompsa if (!locked) 814188412Sthompsa UDAV_UNLOCK(sc); 815184610Salfred return (data16); 816184610Salfred} 817184610Salfred 818184610Salfredstatic int 819188412Sthompsaudav_miibus_writereg(device_t dev, int phy, int reg, int data) 820184610Salfred{ 821184610Salfred struct udav_softc *sc = device_get_softc(dev); 822184610Salfred uint8_t val[2]; 823188412Sthompsa int locked; 824184610Salfred 825184610Salfred /* XXX: one PHY only for the internal PHY */ 826188412Sthompsa if (phy != 0) 827184610Salfred return (0); 828184610Salfred 829188412Sthompsa locked = mtx_owned(&sc->sc_mtx); 830188412Sthompsa if (!locked) 831188412Sthompsa UDAV_LOCK(sc); 832188412Sthompsa 833184610Salfred /* select internal PHY and set PHY register address */ 834188412Sthompsa udav_csr_write1(sc, UDAV_EPAR, 835184610Salfred UDAV_EPAR_PHY_ADR0 | (reg & UDAV_EPAR_EROA_MASK)); 836184610Salfred 837184610Salfred /* put the value to the data registers */ 838184610Salfred val[0] = (data & 0xff); 839184610Salfred val[1] = (data >> 8) & 0xff; 840188412Sthompsa udav_csr_write(sc, UDAV_EPDRL, val, 2); 841184610Salfred 842184610Salfred /* select PHY operation and start write command */ 843188412Sthompsa udav_csr_write1(sc, UDAV_EPCR, UDAV_EPCR_EPOS | UDAV_EPCR_ERPRW); 844184610Salfred 845184610Salfred /* XXX: should we wait? */ 846184610Salfred 847184610Salfred /* end write command */ 848188412Sthompsa UDAV_CLRBIT(sc, UDAV_EPCR, UDAV_EPCR_ERPRW); 849184610Salfred 850188412Sthompsa if (!locked) 851188412Sthompsa UDAV_UNLOCK(sc); 852184610Salfred return (0); 853184610Salfred} 854184610Salfred 855184610Salfredstatic void 856188412Sthompsaudav_miibus_statchg(device_t dev) 857184610Salfred{ 858184610Salfred /* nothing to do */ 859184610Salfred} 860