if_rue.c revision 226479
154359Sroberto/*- 254359Sroberto * Copyright (c) 2001-2003, Shunsuke Akiyama <akiyama@FreeBSD.org>. 354363Sroberto * Copyright (c) 1997, 1998, 1999, 2000 Bill Paul <wpaul@ee.columbia.edu>. 4330141Sdelphij * All rights reserved. 5330141Sdelphij * 6132454Sroberto * Redistribution and use in source and binary forms, with or without 754359Sroberto * modification, are permitted provided that the following conditions 854359Sroberto * are met: 954359Sroberto * 1. Redistributions of source code must retain the above copyright 1054359Sroberto * notice, this list of conditions and the following disclaimer. 1154359Sroberto * 2. Redistributions in binary form must reproduce the above copyright 1254359Sroberto * notice, this list of conditions and the following disclaimer in the 1354359Sroberto * documentation and/or other materials provided with the distribution. 1454359Sroberto * 1554359Sroberto * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1654359Sroberto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17285612Sdelphij * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18285612Sdelphij * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19293650Sglebius * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2054359Sroberto * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2182505Sroberto * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22285612Sdelphij * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23285612Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2454359Sroberto * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25285612Sdelphij * SUCH DAMAGE. 26285612Sdelphij */ 2754359Sroberto/*- 2854359Sroberto * Copyright (c) 1997, 1998, 1999, 2000 29298699Sdelphij * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved. 30298699Sdelphij * 31298699Sdelphij * Redistribution and use in source and binary forms, with or without 32298699Sdelphij * modification, are permitted provided that the following conditions 33298699Sdelphij * are met: 3454359Sroberto * 1. Redistributions of source code must retain the above copyright 35182007Sroberto * notice, this list of conditions and the following disclaimer. 36338531Sdelphij * 2. Redistributions in binary form must reproduce the above copyright 37182007Sroberto * notice, this list of conditions and the following disclaimer in the 38289997Sglebius * documentation and/or other materials provided with the distribution. 39289997Sglebius * 3. All advertising materials mentioning features or use of this software 40182007Sroberto * must display the following acknowledgement: 41330141Sdelphij * This product includes software developed by Bill Paul. 42330141Sdelphij * 4. Neither the name of the author nor the names of any co-contributors 43330141Sdelphij * may be used to endorse or promote products derived from this software 44330141Sdelphij * without specific prior written permission. 45330141Sdelphij * 46330141Sdelphij * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 47330141Sdelphij * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 48330141Sdelphij * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 49285612Sdelphij * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 50182007Sroberto * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 51289997Sglebius * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 52289997Sglebius * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 53289997Sglebius * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 54330141Sdelphij * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 55330141Sdelphij * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 56289997Sglebius * THE POSSIBILITY OF SUCH DAMAGE. 57289997Sglebius */ 58289997Sglebius 59289997Sglebius#include <sys/cdefs.h> 60330141Sdelphij__FBSDID("$FreeBSD: head/sys/dev/usb/net/if_rue.c 226479 2011-10-17 19:51:38Z yongari $"); 61330141Sdelphij 62289997Sglebius/* 63330141Sdelphij * RealTek RTL8150 USB to fast ethernet controller driver. 64330141Sdelphij * Datasheet is available from 65298699Sdelphij * ftp://ftp.realtek.com.tw/lancard/data_sheet/8150/. 66298699Sdelphij */ 67298699Sdelphij 68330141Sdelphij#include <sys/stdint.h> 69298699Sdelphij#include <sys/stddef.h> 70289997Sglebius#include <sys/param.h> 71285612Sdelphij#include <sys/queue.h> 7254359Sroberto#include <sys/types.h> 73285612Sdelphij#include <sys/systm.h> 74285612Sdelphij#include <sys/kernel.h> 75285612Sdelphij#include <sys/bus.h> 76285612Sdelphij#include <sys/module.h> 77285612Sdelphij#include <sys/lock.h> 78285612Sdelphij#include <sys/mutex.h> 79285612Sdelphij#include <sys/condvar.h> 80285612Sdelphij#include <sys/sysctl.h> 81285612Sdelphij#include <sys/sx.h> 82285612Sdelphij#include <sys/unistd.h> 83285612Sdelphij#include <sys/callout.h> 84285612Sdelphij#include <sys/malloc.h> 85285612Sdelphij#include <sys/priv.h> 86285612Sdelphij 87285612Sdelphij#include <dev/usb/usb.h> 88285612Sdelphij#include <dev/usb/usbdi.h> 89285612Sdelphij#include <dev/usb/usbdi_util.h> 90285612Sdelphij#include "usbdevs.h" 91285612Sdelphij 92285612Sdelphij#define USB_DEBUG_VAR rue_debug 93285612Sdelphij#include <dev/usb/usb_debug.h> 94285612Sdelphij#include <dev/usb/usb_process.h> 95285612Sdelphij 96285612Sdelphij#include <dev/usb/net/usb_ethernet.h> 97285612Sdelphij#include <dev/usb/net/if_ruereg.h> 98285612Sdelphij 99182007Sroberto#ifdef USB_DEBUG 10082505Srobertostatic int rue_debug = 0; 101285612Sdelphij 102285612SdelphijSYSCTL_NODE(_hw_usb, OID_AUTO, rue, CTLFLAG_RW, 0, "USB rue"); 103285612SdelphijSYSCTL_INT(_hw_usb_rue, OID_AUTO, debug, CTLFLAG_RW, 104285612Sdelphij &rue_debug, 0, "Debug level"); 10554359Sroberto#endif 106285612Sdelphij 107285612Sdelphij/* 108285612Sdelphij * Various supported device vendors/products. 109285612Sdelphij */ 110285612Sdelphij 11154359Srobertostatic const STRUCT_USB_HOST_ID rue_devs[] = { 112285612Sdelphij {USB_VPI(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAKTX, 0)}, 113285612Sdelphij {USB_VPI(USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_USBKR100, 0)}, 114285612Sdelphij {USB_VPI(USB_VENDOR_OQO, USB_PRODUCT_OQO_ETHER01, 0)}, 115285612Sdelphij}; 116285612Sdelphij 117285612Sdelphij/* prototypes */ 118285612Sdelphij 119285612Sdelphijstatic device_probe_t rue_probe; 12054359Srobertostatic device_attach_t rue_attach; 121285612Sdelphijstatic device_detach_t rue_detach; 122285612Sdelphij 123285612Sdelphijstatic miibus_readreg_t rue_miibus_readreg; 124132454Srobertostatic miibus_writereg_t rue_miibus_writereg; 125132454Srobertostatic miibus_statchg_t rue_miibus_statchg; 12654359Sroberto 12754359Srobertostatic usb_callback_t rue_intr_callback; 128285612Sdelphijstatic usb_callback_t rue_bulk_read_callback; 129285612Sdelphijstatic usb_callback_t rue_bulk_write_callback; 130285612Sdelphij 131285612Sdelphijstatic uether_fn_t rue_attach_post; 132285612Sdelphijstatic uether_fn_t rue_init; 133285612Sdelphijstatic uether_fn_t rue_stop; 134285612Sdelphijstatic uether_fn_t rue_start; 135285612Sdelphijstatic uether_fn_t rue_tick; 13682505Srobertostatic uether_fn_t rue_setmulti; 13782505Srobertostatic uether_fn_t rue_setpromisc; 138285612Sdelphij 13982505Srobertostatic int rue_read_mem(struct rue_softc *, uint16_t, void *, int); 140132454Srobertostatic int rue_write_mem(struct rue_softc *, uint16_t, void *, int); 141285612Sdelphijstatic uint8_t rue_csr_read_1(struct rue_softc *, uint16_t); 14254359Srobertostatic uint16_t rue_csr_read_2(struct rue_softc *, uint16_t); 14354359Srobertostatic int rue_csr_write_1(struct rue_softc *, uint16_t, uint8_t); 144132454Srobertostatic int rue_csr_write_2(struct rue_softc *, uint16_t, uint16_t); 145132454Srobertostatic int rue_csr_write_4(struct rue_softc *, int, uint32_t); 146182007Sroberto 147309008Sdelphijstatic void rue_reset(struct rue_softc *); 148285612Sdelphijstatic int rue_ifmedia_upd(struct ifnet *); 149132454Srobertostatic void rue_ifmedia_sts(struct ifnet *, struct ifmediareq *); 150285612Sdelphij 151182007Srobertostatic const struct usb_config rue_config[RUE_N_TRANSFER] = { 152132454Sroberto 153182007Sroberto [RUE_BULK_DT_WR] = { 154285612Sdelphij .type = UE_BULK, 155182007Sroberto .endpoint = UE_ADDR_ANY, 156316069Sdelphij .direction = UE_DIR_OUT, 157132454Sroberto .bufsize = MCLBYTES, 158132454Sroberto .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 159132454Sroberto .callback = rue_bulk_write_callback, 160285612Sdelphij .timeout = 10000, /* 10 seconds */ 16154359Sroberto }, 162285612Sdelphij 163132454Sroberto [RUE_BULK_DT_RD] = { 164285612Sdelphij .type = UE_BULK, 165285612Sdelphij .endpoint = UE_ADDR_ANY, 166285612Sdelphij .direction = UE_DIR_IN, 167132454Sroberto .bufsize = (MCLBYTES + 4), 168132454Sroberto .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 169132454Sroberto .callback = rue_bulk_read_callback, 170285612Sdelphij .timeout = 0, /* no timeout */ 171132454Sroberto }, 172285612Sdelphij 17354359Sroberto [RUE_INTR_DT_RD] = { 174294569Sdelphij .type = UE_INTERRUPT, 175301256Sdelphij .endpoint = UE_ADDR_ANY, 176294569Sdelphij .direction = UE_DIR_IN, 177294569Sdelphij .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 178294569Sdelphij .bufsize = 0, /* use wMaxPacketSize */ 179294569Sdelphij .callback = rue_intr_callback, 180294569Sdelphij }, 181294569Sdelphij}; 182294569Sdelphij 183301256Sdelphijstatic device_method_t rue_methods[] = { 184294569Sdelphij /* Device interface */ 185294569Sdelphij DEVMETHOD(device_probe, rue_probe), 186294569Sdelphij DEVMETHOD(device_attach, rue_attach), 187294569Sdelphij DEVMETHOD(device_detach, rue_detach), 188298699Sdelphij 189298699Sdelphij /* Bus interface */ 190298699Sdelphij DEVMETHOD(bus_print_child, bus_generic_print_child), 191330141Sdelphij 192285612Sdelphij /* MII interface */ 193285612Sdelphij DEVMETHOD(miibus_readreg, rue_miibus_readreg), 194285612Sdelphij DEVMETHOD(miibus_writereg, rue_miibus_writereg), 195285612Sdelphij DEVMETHOD(miibus_statchg, rue_miibus_statchg), 196285612Sdelphij 197285612Sdelphij {0, 0} 198285612Sdelphij}; 199285612Sdelphij 200285612Sdelphijstatic driver_t rue_driver = { 201285612Sdelphij .name = "rue", 202285612Sdelphij .methods = rue_methods, 203285612Sdelphij .size = sizeof(struct rue_softc), 204285612Sdelphij}; 205285612Sdelphij 206285612Sdelphijstatic devclass_t rue_devclass; 207285612Sdelphij 208285612SdelphijDRIVER_MODULE(rue, uhub, rue_driver, rue_devclass, NULL, 0); 209285612SdelphijDRIVER_MODULE(miibus, rue, miibus_driver, miibus_devclass, 0, 0); 21054359SrobertoMODULE_DEPEND(rue, uether, 1, 1, 1); 211293650SglebiusMODULE_DEPEND(rue, usb, 1, 1, 1); 212293650SglebiusMODULE_DEPEND(rue, ether, 1, 1, 1); 213293650SglebiusMODULE_DEPEND(rue, miibus, 1, 1, 1); 214285612SdelphijMODULE_VERSION(rue, 1); 215293650Sglebius 216293650Sglebiusstatic const struct usb_ether_methods rue_ue_methods = { 217293650Sglebius .ue_attach_post = rue_attach_post, 218293650Sglebius .ue_start = rue_start, 219285612Sdelphij .ue_init = rue_init, 220285612Sdelphij .ue_stop = rue_stop, 221182007Sroberto .ue_tick = rue_tick, 222285612Sdelphij .ue_setmulti = rue_setmulti, 223285612Sdelphij .ue_setpromisc = rue_setpromisc, 224285612Sdelphij .ue_mii_upd = rue_ifmedia_upd, 225285612Sdelphij .ue_mii_sts = rue_ifmedia_sts, 226285612Sdelphij}; 227285612Sdelphij 228285612Sdelphij#define RUE_SETBIT(sc, reg, x) \ 229285612Sdelphij rue_csr_write_1(sc, reg, rue_csr_read_1(sc, reg) | (x)) 230285612Sdelphij 231285612Sdelphij#define RUE_CLRBIT(sc, reg, x) \ 232285612Sdelphij rue_csr_write_1(sc, reg, rue_csr_read_1(sc, reg) & ~(x)) 233285612Sdelphij 234293650Sglebiusstatic int 235293650Sglebiusrue_read_mem(struct rue_softc *sc, uint16_t addr, void *buf, int len) 236293650Sglebius{ 237285612Sdelphij struct usb_device_request req; 238285612Sdelphij 239285612Sdelphij req.bmRequestType = UT_READ_VENDOR_DEVICE; 240285612Sdelphij req.bRequest = UR_SET_ADDRESS; 241285612Sdelphij USETW(req.wValue, addr); 242285612Sdelphij USETW(req.wIndex, 0); 243285612Sdelphij USETW(req.wLength, len); 244285612Sdelphij 245293650Sglebius return (uether_do_request(&sc->sc_ue, &req, buf, 1000)); 246289997Sglebius} 247289997Sglebius 248289997Sglebiusstatic int 249293650Sglebiusrue_write_mem(struct rue_softc *sc, uint16_t addr, void *buf, int len) 250293650Sglebius{ 251293650Sglebius struct usb_device_request req; 252293650Sglebius 253293650Sglebius req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 254293650Sglebius req.bRequest = UR_SET_ADDRESS; 255293650Sglebius USETW(req.wValue, addr); 256293650Sglebius USETW(req.wIndex, 0); 257285612Sdelphij USETW(req.wLength, len); 258293650Sglebius 259293650Sglebius return (uether_do_request(&sc->sc_ue, &req, buf, 1000)); 260293650Sglebius} 261293650Sglebius 262293650Sglebiusstatic uint8_t 263293650Sglebiusrue_csr_read_1(struct rue_softc *sc, uint16_t reg) 264293650Sglebius{ 265293650Sglebius uint8_t val; 266293650Sglebius 267293650Sglebius rue_read_mem(sc, reg, &val, 1); 268293650Sglebius return (val); 269289997Sglebius} 270293650Sglebius 271330141Sdelphijstatic uint16_t 272289997Sglebiusrue_csr_read_2(struct rue_softc *sc, uint16_t reg) 273293650Sglebius{ 274293650Sglebius uint8_t val[2]; 275338531Sdelphij 276298699Sdelphij rue_read_mem(sc, reg, &val, 2); 277298699Sdelphij return (UGETW(val)); 278330141Sdelphij} 279298699Sdelphij 280298699Sdelphijstatic int 281298699Sdelphijrue_csr_write_1(struct rue_softc *sc, uint16_t reg, uint8_t val) 282298699Sdelphij{ 283298699Sdelphij return (rue_write_mem(sc, reg, &val, 1)); 284298699Sdelphij} 285309008Sdelphij 286301256Sdelphijstatic int 287301256Sdelphijrue_csr_write_2(struct rue_softc *sc, uint16_t reg, uint16_t val) 288301256Sdelphij{ 289301256Sdelphij uint8_t temp[2]; 290301256Sdelphij 291298699Sdelphij USETW(temp, val); 292298699Sdelphij return (rue_write_mem(sc, reg, &temp, 2)); 293298699Sdelphij} 294298699Sdelphij 295298699Sdelphijstatic int 296298699Sdelphijrue_csr_write_4(struct rue_softc *sc, int reg, uint32_t val) 297298699Sdelphij{ 298298699Sdelphij uint8_t temp[4]; 299298699Sdelphij 300298699Sdelphij USETDW(temp, val); 301298699Sdelphij return (rue_write_mem(sc, reg, &temp, 4)); 302298699Sdelphij} 303298699Sdelphij 304298699Sdelphijstatic int 305298699Sdelphijrue_miibus_readreg(device_t dev, int phy, int reg) 306298699Sdelphij{ 307298699Sdelphij struct rue_softc *sc = device_get_softc(dev); 308298699Sdelphij uint16_t rval; 309298699Sdelphij uint16_t ruereg; 310298699Sdelphij int locked; 311298699Sdelphij 312298699Sdelphij if (phy != 0) /* RTL8150 supports PHY == 0, only */ 313298699Sdelphij return (0); 314298699Sdelphij 315301256Sdelphij locked = mtx_owned(&sc->sc_mtx); 316298699Sdelphij if (!locked) 317298699Sdelphij RUE_LOCK(sc); 318338531Sdelphij 319298699Sdelphij switch (reg) { 320298699Sdelphij case MII_BMCR: 321298699Sdelphij ruereg = RUE_BMCR; 322298699Sdelphij break; 323298699Sdelphij case MII_BMSR: 324301256Sdelphij ruereg = RUE_BMSR; 325298699Sdelphij break; 326298699Sdelphij case MII_ANAR: 327338531Sdelphij ruereg = RUE_ANAR; 328338531Sdelphij break; 329338531Sdelphij case MII_ANER: 330338531Sdelphij ruereg = RUE_AER; 331338531Sdelphij break; 332298699Sdelphij case MII_ANLPAR: 333338531Sdelphij ruereg = RUE_ANLP; 334301256Sdelphij break; 335298699Sdelphij case MII_PHYIDR1: 336301256Sdelphij case MII_PHYIDR2: 337301256Sdelphij rval = 0; 338301256Sdelphij goto done; 339301256Sdelphij default: 340301256Sdelphij if (RUE_REG_MIN <= reg && reg <= RUE_REG_MAX) { 341301256Sdelphij rval = rue_csr_read_1(sc, reg); 342301256Sdelphij goto done; 343301256Sdelphij } 344301256Sdelphij device_printf(sc->sc_ue.ue_dev, "bad phy register\n"); 345309008Sdelphij rval = 0; 346301256Sdelphij goto done; 347301256Sdelphij } 348301256Sdelphij 349301256Sdelphij rval = rue_csr_read_2(sc, ruereg); 350298699Sdelphijdone: 351301256Sdelphij if (!locked) 352301256Sdelphij RUE_UNLOCK(sc); 353301256Sdelphij return (rval); 354301256Sdelphij} 355301256Sdelphij 356298699Sdelphijstatic int 357298699Sdelphijrue_miibus_writereg(device_t dev, int phy, int reg, int data) 358298699Sdelphij{ 35954359Sroberto struct rue_softc *sc = device_get_softc(dev); 360285612Sdelphij uint16_t ruereg; 36154359Sroberto int locked; 36254359Sroberto 36354359Sroberto if (phy != 0) /* RTL8150 supports PHY == 0, only */ 36454359Sroberto return (0); 36554359Sroberto 36654359Sroberto locked = mtx_owned(&sc->sc_mtx); 367285612Sdelphij if (!locked) 36854359Sroberto RUE_LOCK(sc); 369132454Sroberto 370132454Sroberto switch (reg) { 371132454Sroberto case MII_BMCR: 372132454Sroberto ruereg = RUE_BMCR; 373132454Sroberto break; 374132454Sroberto case MII_BMSR: 37554359Sroberto ruereg = RUE_BMSR; 376182007Sroberto break; 377182007Sroberto case MII_ANAR: 378338531Sdelphij ruereg = RUE_ANAR; 379338531Sdelphij break; 380338531Sdelphij case MII_ANER: 381338531Sdelphij ruereg = RUE_AER; 382338531Sdelphij break; 383338531Sdelphij case MII_ANLPAR: 384338531Sdelphij ruereg = RUE_ANLP; 385182007Sroberto break; 386182007Sroberto case MII_PHYIDR1: 387182007Sroberto case MII_PHYIDR2: 388132454Sroberto goto done; 389182007Sroberto default: 390285612Sdelphij if (RUE_REG_MIN <= reg && reg <= RUE_REG_MAX) { 391285612Sdelphij rue_csr_write_1(sc, reg, data); 392182007Sroberto goto done; 393182007Sroberto } 394182007Sroberto device_printf(sc->sc_ue.ue_dev, " bad phy register\n"); 39554359Sroberto goto done; 396182007Sroberto } 397182007Sroberto rue_csr_write_2(sc, ruereg, data); 398182007Srobertodone: 399182007Sroberto if (!locked) 400182007Sroberto RUE_UNLOCK(sc); 401285612Sdelphij return (0); 402182007Sroberto} 403285612Sdelphij 404285612Sdelphijstatic void 405285612Sdelphijrue_miibus_statchg(device_t dev) 406285612Sdelphij{ 407285612Sdelphij /* 408182007Sroberto * When the code below is enabled the card starts doing weird 409182007Sroberto * things after link going from UP to DOWN and back UP. 410182007Sroberto * 411182007Sroberto * Looks like some of register writes below messes up PHY 412182007Sroberto * interface. 413182007Sroberto * 414182007Sroberto * No visible regressions were found after commenting this code 415289997Sglebius * out, so that disable it for good. 416289997Sglebius */ 417316069Sdelphij#if 0 418182007Sroberto struct rue_softc *sc = device_get_softc(dev); 419182007Sroberto struct mii_data *mii = GET_MII(sc); 420182007Sroberto uint16_t bmcr; 421182007Sroberto int locked; 422182007Sroberto 423182007Sroberto locked = mtx_owned(&sc->sc_mtx); 424182007Sroberto if (!locked) 42582505Sroberto RUE_LOCK(sc); 426182007Sroberto 427285612Sdelphij RUE_CLRBIT(sc, RUE_CR, (RUE_CR_RE | RUE_CR_TE)); 428285612Sdelphij 429285612Sdelphij bmcr = rue_csr_read_2(sc, RUE_BMCR); 430285612Sdelphij 431285612Sdelphij if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) 432285612Sdelphij bmcr |= RUE_BMCR_SPD_SET; 433285612Sdelphij else 434285612Sdelphij bmcr &= ~RUE_BMCR_SPD_SET; 435285612Sdelphij 436285612Sdelphij if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) 437285612Sdelphij bmcr |= RUE_BMCR_DUPLEX; 438285612Sdelphij else 439285612Sdelphij bmcr &= ~RUE_BMCR_DUPLEX; 440289997Sglebius 441289997Sglebius rue_csr_write_2(sc, RUE_BMCR, bmcr); 442293650Sglebius 443285612Sdelphij RUE_SETBIT(sc, RUE_CR, (RUE_CR_RE | RUE_CR_TE)); 444285612Sdelphij 445285612Sdelphij if (!locked) 446285612Sdelphij RUE_UNLOCK(sc); 447285612Sdelphij#endif 448285612Sdelphij} 449182007Sroberto 450285612Sdelphijstatic void 451182007Srobertorue_setpromisc(struct usb_ether *ue) 452182007Sroberto{ 453182007Sroberto struct rue_softc *sc = uether_getsc(ue); 454182007Sroberto struct ifnet *ifp = uether_getifp(ue); 455182007Sroberto 456132454Sroberto RUE_LOCK_ASSERT(sc, MA_OWNED); 457182007Sroberto 458182007Sroberto /* If we want promiscuous mode, set the allframes bit. */ 459285612Sdelphij if (ifp->if_flags & IFF_PROMISC) 460132454Sroberto RUE_SETBIT(sc, RUE_RCR, RUE_RCR_AAP); 461182007Sroberto else 462182007Sroberto RUE_CLRBIT(sc, RUE_RCR, RUE_RCR_AAP); 463285612Sdelphij} 464182007Sroberto 465182007Sroberto/* 46682505Sroberto * Program the 64-bit multicast hash filter. 467182007Sroberto */ 468182007Srobertostatic void 469285612Sdelphijrue_setmulti(struct usb_ether *ue) 470285612Sdelphij{ 471182007Sroberto struct rue_softc *sc = uether_getsc(ue); 472285612Sdelphij struct ifnet *ifp = uether_getifp(ue); 473182007Sroberto uint16_t rxcfg; 474285612Sdelphij int h = 0; 475285612Sdelphij uint32_t hashes[2] = { 0, 0 }; 476182007Sroberto struct ifmultiaddr *ifma; 477289997Sglebius int mcnt = 0; 478289997Sglebius 479285612Sdelphij RUE_LOCK_ASSERT(sc, MA_OWNED); 480182007Sroberto 481182007Sroberto rxcfg = rue_csr_read_2(sc, RUE_RCR); 482182007Sroberto 483285612Sdelphij if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 484285612Sdelphij rxcfg |= (RUE_RCR_AAM | RUE_RCR_AAP); 485285612Sdelphij rxcfg &= ~RUE_RCR_AM; 486285612Sdelphij rue_csr_write_2(sc, RUE_RCR, rxcfg); 487285612Sdelphij rue_csr_write_4(sc, RUE_MAR0, 0xFFFFFFFF); 488182007Sroberto rue_csr_write_4(sc, RUE_MAR4, 0xFFFFFFFF); 489285612Sdelphij return; 490285612Sdelphij } 491182007Sroberto 492289997Sglebius /* first, zot all the existing hash bits */ 493289997Sglebius rue_csr_write_4(sc, RUE_MAR0, 0); 494289997Sglebius rue_csr_write_4(sc, RUE_MAR4, 0); 495285612Sdelphij 496182007Sroberto /* now program new ones */ 497182007Sroberto if_maddr_rlock(ifp); 498132454Sroberto TAILQ_FOREACH (ifma, &ifp->if_multiaddrs, ifma_link) 499285612Sdelphij { 500285612Sdelphij if (ifma->ifma_addr->sa_family != AF_LINK) 501285612Sdelphij continue; 502285612Sdelphij h = ether_crc32_be(LLADDR((struct sockaddr_dl *) 503285612Sdelphij ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; 504285612Sdelphij if (h < 32) 505285612Sdelphij hashes[0] |= (1 << h); 506132454Sroberto else 507285612Sdelphij hashes[1] |= (1 << (h - 32)); 508285612Sdelphij mcnt++; 509285612Sdelphij } 510285612Sdelphij if_maddr_runlock(ifp); 511182007Sroberto 51282505Sroberto if (mcnt) 51382505Sroberto rxcfg |= RUE_RCR_AM; 51482505Sroberto else 515289997Sglebius rxcfg &= ~RUE_RCR_AM; 516289997Sglebius 517289997Sglebius rxcfg &= ~(RUE_RCR_AAM | RUE_RCR_AAP); 518285612Sdelphij 519285612Sdelphij rue_csr_write_2(sc, RUE_RCR, rxcfg); 520285612Sdelphij rue_csr_write_4(sc, RUE_MAR0, hashes[0]); 521285612Sdelphij rue_csr_write_4(sc, RUE_MAR4, hashes[1]); 522285612Sdelphij} 52382505Sroberto 524182007Srobertostatic void 525182007Srobertorue_reset(struct rue_softc *sc) 526132454Sroberto{ 52754359Sroberto int i; 52854359Sroberto 529182007Sroberto rue_csr_write_1(sc, RUE_CR, RUE_CR_SOFT_RST); 530182007Sroberto 531182007Sroberto for (i = 0; i != RUE_TIMEOUT; i++) { 53254359Sroberto if (uether_pause(&sc->sc_ue, hz / 1000)) 533182007Sroberto break; 534182007Sroberto if (!(rue_csr_read_1(sc, RUE_CR) & RUE_CR_SOFT_RST)) 535182007Sroberto break; 536132454Sroberto } 537285612Sdelphij if (i == RUE_TIMEOUT) 538285612Sdelphij device_printf(sc->sc_ue.ue_dev, "reset never completed\n"); 539285612Sdelphij 540285612Sdelphij uether_pause(&sc->sc_ue, hz / 100); 541132454Sroberto} 542132454Sroberto 54354359Srobertostatic void 54454359Srobertorue_attach_post(struct usb_ether *ue) 54554359Sroberto{ 546285612Sdelphij struct rue_softc *sc = uether_getsc(ue); 547285612Sdelphij 54854359Sroberto /* reset the adapter */ 54954359Sroberto rue_reset(sc); 550285612Sdelphij 55154359Sroberto /* get station address from the EEPROM */ 552182007Sroberto rue_read_mem(sc, RUE_EEPROM_IDR0, ue->ue_eaddr, ETHER_ADDR_LEN); 553182007Sroberto} 554132454Sroberto 555293650Sglebius/* 556293650Sglebius * Probe for a RTL8150 chip. 55754359Sroberto */ 55854359Srobertostatic int 559182007Srobertorue_probe(device_t dev) 560293650Sglebius{ 561293650Sglebius struct usb_attach_arg *uaa = device_get_ivars(dev); 562293650Sglebius 563293650Sglebius if (uaa->usb_mode != USB_MODE_HOST) 564293650Sglebius return (ENXIO); 565293650Sglebius if (uaa->info.bConfigIndex != RUE_CONFIG_IDX) 566293650Sglebius return (ENXIO); 567293650Sglebius if (uaa->info.bIfaceIndex != RUE_IFACE_IDX) 568293650Sglebius return (ENXIO); 569293650Sglebius 570293650Sglebius return (usbd_lookup_id_by_uaa(rue_devs, sizeof(rue_devs), uaa)); 571293650Sglebius} 572293650Sglebius 573293650Sglebius/* 574293650Sglebius * Attach the interface. Allocate softc structures, do ifmedia 575293650Sglebius * setup and ethernet/BPF attach. 576293650Sglebius */ 577293650Sglebiusstatic int 578293650Sglebiusrue_attach(device_t dev) 579293650Sglebius{ 580293650Sglebius struct usb_attach_arg *uaa = device_get_ivars(dev); 581293650Sglebius struct rue_softc *sc = device_get_softc(dev); 582293650Sglebius struct usb_ether *ue = &sc->sc_ue; 583293650Sglebius uint8_t iface_index; 584293650Sglebius int error; 58554359Sroberto 586285612Sdelphij device_set_usb_desc(dev); 58754359Sroberto mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 58854359Sroberto 58954359Sroberto iface_index = RUE_IFACE_IDX; 59054359Sroberto error = usbd_transfer_setup(uaa->device, &iface_index, 59154359Sroberto sc->sc_xfer, rue_config, RUE_N_TRANSFER, 59254359Sroberto sc, &sc->sc_mtx); 593132454Sroberto if (error) { 594132454Sroberto device_printf(dev, "allocating USB transfers failed\n"); 595285612Sdelphij goto detach; 596285612Sdelphij } 597285612Sdelphij 598285612Sdelphij ue->ue_sc = sc; 599330141Sdelphij ue->ue_dev = dev; 600285612Sdelphij ue->ue_udev = uaa->device; 601293650Sglebius ue->ue_mtx = &sc->sc_mtx; 602293650Sglebius ue->ue_methods = &rue_ue_methods; 603293650Sglebius 604132454Sroberto error = uether_ifattach(ue); 605132454Sroberto if (error) { 606330141Sdelphij device_printf(dev, "could not attach interface\n"); 607330141Sdelphij goto detach; 608285612Sdelphij } 609285612Sdelphij return (0); /* success */ 610285612Sdelphij 611293650Sglebiusdetach: 612132454Sroberto rue_detach(dev); 613293650Sglebius return (ENXIO); /* failure */ 614182007Sroberto} 615182007Sroberto 616132454Srobertostatic int 617285612Sdelphijrue_detach(device_t dev) 618285612Sdelphij{ 619285612Sdelphij struct rue_softc *sc = device_get_softc(dev); 620132454Sroberto struct usb_ether *ue = &sc->sc_ue; 621132454Sroberto 622285612Sdelphij usbd_transfer_unsetup(sc->sc_xfer, RUE_N_TRANSFER); 623285612Sdelphij uether_ifdetach(ue); 624285612Sdelphij mtx_destroy(&sc->sc_mtx); 625285612Sdelphij 626285612Sdelphij return (0); 62754359Sroberto} 62854359Sroberto 629330141Sdelphijstatic void 630330141Sdelphijrue_intr_callback(struct usb_xfer *xfer, usb_error_t error) 631330141Sdelphij{ 632330141Sdelphij struct rue_softc *sc = usbd_xfer_softc(xfer); 633330141Sdelphij struct ifnet *ifp = uether_getifp(&sc->sc_ue); 634330141Sdelphij struct rue_intrpkt pkt; 635330141Sdelphij struct usb_page_cache *pc; 63682505Sroberto int actlen; 63782505Sroberto 638285612Sdelphij usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 639285612Sdelphij 64054359Sroberto switch (USB_GET_STATE(xfer)) { 641132454Sroberto case USB_ST_TRANSFERRED: 642132454Sroberto 643132454Sroberto if (ifp && (ifp->if_drv_flags & IFF_DRV_RUNNING) && 644132454Sroberto actlen >= sizeof(pkt)) { 645132454Sroberto 646285612Sdelphij pc = usbd_xfer_get_frame(xfer, 0); 647132454Sroberto usbd_copy_out(pc, 0, &pkt, sizeof(pkt)); 648132454Sroberto 649132454Sroberto ifp->if_ierrors += pkt.rue_rxlost_cnt; 650330141Sdelphij ifp->if_ierrors += pkt.rue_crcerr_cnt; 651330141Sdelphij ifp->if_collisions += pkt.rue_col_cnt; 652330141Sdelphij } 653293650Sglebius /* FALLTHROUGH */ 654182007Sroberto case USB_ST_SETUP: 655182007Srobertotr_setup: 656132454Sroberto usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 657182007Sroberto usbd_transfer_submit(xfer); 658338531Sdelphij return; 659330141Sdelphij 660330141Sdelphij default: /* Error */ 661330141Sdelphij if (error != USB_ERR_CANCELLED) { 662330141Sdelphij /* try to clear stall first */ 663330141Sdelphij usbd_xfer_set_stall(xfer); 664330141Sdelphij goto tr_setup; 665330141Sdelphij } 666330141Sdelphij return; 667301256Sdelphij } 668301256Sdelphij} 669285612Sdelphij 670330141Sdelphijstatic void 671285612Sdelphijrue_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) 672285612Sdelphij{ 673285612Sdelphij struct rue_softc *sc = usbd_xfer_softc(xfer); 674132454Sroberto struct usb_ether *ue = &sc->sc_ue; 675285612Sdelphij struct ifnet *ifp = uether_getifp(ue); 676330141Sdelphij struct usb_page_cache *pc; 677132454Sroberto uint16_t status; 67882505Sroberto int actlen; 679132454Sroberto 68056749Sroberto usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 68156749Sroberto 68254359Sroberto switch (USB_GET_STATE(xfer)) { 68354359Sroberto case USB_ST_TRANSFERRED: 684132454Sroberto 685132454Sroberto if (actlen < 4) { 686330141Sdelphij ifp->if_ierrors++; 687132454Sroberto goto tr_setup; 68882505Sroberto } 689132454Sroberto pc = usbd_xfer_get_frame(xfer, 0); 69054359Sroberto usbd_copy_out(pc, actlen - 4, &status, sizeof(status)); 69154359Sroberto actlen -= 4; 69254359Sroberto 693132454Sroberto /* check recieve packet was valid or not */ 694330141Sdelphij status = le16toh(status); 695132454Sroberto if ((status & RUE_RXSTAT_VALID) == 0) { 696285612Sdelphij ifp->if_ierrors++; 697132454Sroberto goto tr_setup; 698285612Sdelphij } 699285612Sdelphij uether_rxbuf(ue, pc, 0, actlen); 700285612Sdelphij /* FALLTHROUGH */ 701285612Sdelphij case USB_ST_SETUP: 702285612Sdelphijtr_setup: 703285612Sdelphij usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 704285612Sdelphij usbd_transfer_submit(xfer); 705330141Sdelphij uether_rxflush(ue); 706285612Sdelphij return; 707285612Sdelphij 708285612Sdelphij default: /* Error */ 70982505Sroberto DPRINTF("bulk read error, %s\n", 710285612Sdelphij usbd_errstr(error)); 711132454Sroberto 712330141Sdelphij if (error != USB_ERR_CANCELLED) { 713330141Sdelphij /* try to clear stall first */ 714330141Sdelphij usbd_xfer_set_stall(xfer); 715330141Sdelphij goto tr_setup; 716330141Sdelphij } 717330141Sdelphij return; 718330141Sdelphij } 719330141Sdelphij} 720330141Sdelphij 721330141Sdelphijstatic void 722330141Sdelphijrue_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) 723330141Sdelphij{ 724132454Sroberto struct rue_softc *sc = usbd_xfer_softc(xfer); 725285612Sdelphij struct ifnet *ifp = uether_getifp(&sc->sc_ue); 726132454Sroberto struct usb_page_cache *pc; 727182007Sroberto struct mbuf *m; 728285612Sdelphij int temp_len; 729289997Sglebius 730289997Sglebius switch (USB_GET_STATE(xfer)) { 731285612Sdelphij case USB_ST_TRANSFERRED: 732132454Sroberto DPRINTFN(11, "transfer complete\n"); 733330141Sdelphij ifp->if_opackets++; 734285612Sdelphij 735132454Sroberto /* FALLTHROUGH */ 736132454Sroberto case USB_ST_SETUP: 73754359Srobertotr_setup: 73854359Sroberto if ((sc->sc_flags & RUE_FLAG_LINK) == 0) { 739132454Sroberto /* 740132454Sroberto * don't send anything if there is no link ! 741132454Sroberto */ 742132454Sroberto return; 74354359Sroberto } 74482505Sroberto IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 745182007Sroberto 746132454Sroberto if (m == NULL) 747132454Sroberto return; 748330141Sdelphij if (m->m_pkthdr.len > MCLBYTES) 749132454Sroberto m->m_pkthdr.len = MCLBYTES; 750338531Sdelphij temp_len = m->m_pkthdr.len; 751132454Sroberto 75282505Sroberto pc = usbd_xfer_get_frame(xfer, 0); 75354359Sroberto usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len); 75454359Sroberto 75582505Sroberto /* 75682505Sroberto * This is an undocumented behavior. 757182007Sroberto * RTL8150 chip doesn't send frame length smaller than 758182007Sroberto * RUE_MIN_FRAMELEN (60) byte packet. 759182007Sroberto */ 760285612Sdelphij if (temp_len < RUE_MIN_FRAMELEN) { 761285612Sdelphij usbd_frame_zero(pc, temp_len, 762285612Sdelphij RUE_MIN_FRAMELEN - temp_len); 763285612Sdelphij temp_len = RUE_MIN_FRAMELEN; 764285612Sdelphij } 765330141Sdelphij usbd_xfer_set_frame_len(xfer, 0, temp_len); 766330141Sdelphij 767330141Sdelphij /* 768330141Sdelphij * if there's a BPF listener, bounce a copy 769330141Sdelphij * of this frame to him: 770330141Sdelphij */ 771330141Sdelphij BPF_MTAP(ifp, m); 772330141Sdelphij 773330141Sdelphij m_freem(m); 774330141Sdelphij 77554359Sroberto usbd_transfer_submit(xfer); 776298699Sdelphij 77754359Sroberto return; 778132454Sroberto 779132454Sroberto default: /* Error */ 780285612Sdelphij DPRINTFN(11, "transfer error, %s\n", 781285612Sdelphij usbd_errstr(error)); 782285612Sdelphij 783285612Sdelphij ifp->if_oerrors++; 784285612Sdelphij 78582505Sroberto if (error != USB_ERR_CANCELLED) { 786285612Sdelphij /* try to clear stall first */ 787330141Sdelphij usbd_xfer_set_stall(xfer); 78854359Sroberto goto tr_setup; 789285612Sdelphij } 79054359Sroberto return; 791330141Sdelphij } 792330141Sdelphij} 793330141Sdelphij 794330141Sdelphijstatic void 795285612Sdelphijrue_tick(struct usb_ether *ue) 79682505Sroberto{ 79782505Sroberto struct rue_softc *sc = uether_getsc(ue); 79854359Sroberto struct mii_data *mii = GET_MII(sc); 799285612Sdelphij 800285612Sdelphij RUE_LOCK_ASSERT(sc, MA_OWNED); 801285612Sdelphij 802289997Sglebius mii_tick(mii); 803289997Sglebius if ((sc->sc_flags & RUE_FLAG_LINK) == 0 804289997Sglebius && mii->mii_media_status & IFM_ACTIVE && 805330141Sdelphij IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 80682505Sroberto sc->sc_flags |= RUE_FLAG_LINK; 807285612Sdelphij rue_start(ue); 80882505Sroberto } 809285612Sdelphij} 810285612Sdelphij 811285612Sdelphijstatic void 812285612Sdelphijrue_start(struct usb_ether *ue) 813285612Sdelphij{ 814285612Sdelphij struct rue_softc *sc = uether_getsc(ue); 815289997Sglebius 816289997Sglebius /* 817285612Sdelphij * start the USB transfers, if not already started: 818285612Sdelphij */ 819289997Sglebius usbd_transfer_start(sc->sc_xfer[RUE_INTR_DT_RD]); 820289997Sglebius usbd_transfer_start(sc->sc_xfer[RUE_BULK_DT_RD]); 821289997Sglebius usbd_transfer_start(sc->sc_xfer[RUE_BULK_DT_WR]); 822330141Sdelphij} 823285612Sdelphij 824285612Sdelphijstatic void 825285612Sdelphijrue_init(struct usb_ether *ue) 826285612Sdelphij{ 827285612Sdelphij struct rue_softc *sc = uether_getsc(ue); 828285612Sdelphij struct ifnet *ifp = uether_getifp(ue); 829285612Sdelphij 830330141Sdelphij RUE_LOCK_ASSERT(sc, MA_OWNED); 831285612Sdelphij 832285612Sdelphij /* 833285612Sdelphij * Cancel pending I/O 834285612Sdelphij */ 835285612Sdelphij rue_reset(sc); 836285612Sdelphij 837285612Sdelphij /* Set MAC address */ 838285612Sdelphij rue_write_mem(sc, RUE_IDR0, IF_LLADDR(ifp), ETHER_ADDR_LEN); 83982505Sroberto 84054359Sroberto rue_stop(ue); 841285612Sdelphij 842281230Sdelphij /* 843281230Sdelphij * Set the initial TX and RX configuration. 844281230Sdelphij */ 845281230Sdelphij rue_csr_write_1(sc, RUE_TCR, RUE_TCR_CONFIG); 846330141Sdelphij rue_csr_write_2(sc, RUE_RCR, RUE_RCR_CONFIG|RUE_RCR_AB); 847281230Sdelphij 848281230Sdelphij /* Load the multicast filter */ 849281230Sdelphij rue_setpromisc(ue); 85054359Sroberto /* Load the multicast filter. */ 85154359Sroberto rue_setmulti(ue); 852330141Sdelphij 853330141Sdelphij /* Enable RX and TX */ 854338531Sdelphij rue_csr_write_1(sc, RUE_CR, (RUE_CR_TE | RUE_CR_RE | RUE_CR_EP3CLREN)); 855330141Sdelphij 856330141Sdelphij usbd_xfer_set_stall(sc->sc_xfer[RUE_BULK_DT_WR]); 857330141Sdelphij 858330141Sdelphij ifp->if_drv_flags |= IFF_DRV_RUNNING; 859330141Sdelphij rue_start(ue); 860330141Sdelphij} 861330141Sdelphij 862330141Sdelphij/* 863330141Sdelphij * Set media options. 864285612Sdelphij */ 865285612Sdelphijstatic int 866330141Sdelphijrue_ifmedia_upd(struct ifnet *ifp) 867285612Sdelphij{ 868285612Sdelphij struct rue_softc *sc = ifp->if_softc; 869285612Sdelphij struct mii_data *mii = GET_MII(sc); 870285612Sdelphij struct mii_softc *miisc; 871285612Sdelphij 872285612Sdelphij RUE_LOCK_ASSERT(sc, MA_OWNED); 873285612Sdelphij 874285612Sdelphij sc->sc_flags &= ~RUE_FLAG_LINK; 875285612Sdelphij LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 876285612Sdelphij PHY_RESET(miisc); 877285612Sdelphij mii_mediachg(mii); 878285612Sdelphij return (0); 879285612Sdelphij} 880289997Sglebius 881289997Sglebius/* 882289997Sglebius * Report current media status. 883330141Sdelphij */ 884285612Sdelphijstatic void 885285612Sdelphijrue_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 886330141Sdelphij{ 887330141Sdelphij struct rue_softc *sc = ifp->if_softc; 888330141Sdelphij struct mii_data *mii = GET_MII(sc); 889285612Sdelphij 890285612Sdelphij RUE_LOCK(sc); 891285612Sdelphij mii_pollstat(mii); 892285612Sdelphij ifmr->ifm_active = mii->mii_media_active; 893285612Sdelphij ifmr->ifm_status = mii->mii_media_status; 894285612Sdelphij RUE_UNLOCK(sc); 895285612Sdelphij} 896285612Sdelphij 897285612Sdelphijstatic void 898285612Sdelphijrue_stop(struct usb_ether *ue) 899285612Sdelphij{ 900285612Sdelphij struct rue_softc *sc = uether_getsc(ue); 901285612Sdelphij struct ifnet *ifp = uether_getifp(ue); 90282505Sroberto 90382505Sroberto RUE_LOCK_ASSERT(sc, MA_OWNED); 90482505Sroberto 90582505Sroberto ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 906285612Sdelphij sc->sc_flags &= ~RUE_FLAG_LINK; 90782505Sroberto 90882505Sroberto /* 90982505Sroberto * stop all the transfers, if not already stopped: 91082505Sroberto */ 91182505Sroberto usbd_transfer_stop(sc->sc_xfer[RUE_BULK_DT_WR]); 91282505Sroberto usbd_transfer_stop(sc->sc_xfer[RUE_BULK_DT_RD]); 91382505Sroberto usbd_transfer_stop(sc->sc_xfer[RUE_INTR_DT_RD]); 91482505Sroberto 91582505Sroberto rue_csr_write_1(sc, RUE_CR, 0x00); 916285612Sdelphij 91782505Sroberto rue_reset(sc); 91882505Sroberto} 91954359Sroberto