Annotation of sys/dev/usb/if_url.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_url.c,v 1.48 2007/06/14 10:11:15 mbalmer Exp $ */
! 2: /* $NetBSD: if_url.c,v 1.6 2002/09/29 10:19:21 martin Exp $ */
! 3: /*
! 4: * Copyright (c) 2001, 2002
! 5: * Shingo WATANABE <nabe@nabechan.org>. All rights reserved.
! 6: *
! 7: * Redistribution and use in source and binary forms, with or without
! 8: * modification, are permitted provided that the following conditions
! 9: * are met:
! 10: * 1. Redistributions of source code must retain the above copyright
! 11: * notice, this list of conditions and the following disclaimer.
! 12: * 2. Redistributions in binary form must reproduce the above copyright
! 13: * notice, this list of conditions and the following disclaimer in the
! 14: * documentation and/or other materials provided with the distribution.
! 15: * 3. Neither the name of the author nor the names of any co-contributors
! 16: * may be used to endorse or promote products derived from this software
! 17: * without specific prior written permission.
! 18: *
! 19: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
! 20: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 21: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 22: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
! 23: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 24: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 25: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 26: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 27: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 28: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 29: * SUCH DAMAGE.
! 30: *
! 31: */
! 32:
! 33: /*
! 34: * The RTL8150L(Realtek USB to fast ethernet controller) spec can be found at
! 35: * ftp://ftp.realtek.com.tw/lancard/data_sheet/8150/8150v14.pdf
! 36: * ftp://152.104.125.40/lancard/data_sheet/8150/8150v14.pdf
! 37: */
! 38:
! 39: /*
! 40: * TODO:
! 41: * Interrupt Endpoint support
! 42: * External PHYs
! 43: * powerhook() support?
! 44: */
! 45:
! 46: #include "bpfilter.h"
! 47:
! 48: #include <sys/param.h>
! 49: #include <sys/systm.h>
! 50: #include <sys/rwlock.h>
! 51: #include <sys/mbuf.h>
! 52: #include <sys/kernel.h>
! 53: #include <sys/proc.h>
! 54: #include <sys/socket.h>
! 55:
! 56: #include <sys/device.h>
! 57:
! 58: #include <net/if.h>
! 59: #include <net/if_arp.h>
! 60: #include <net/if_dl.h>
! 61: #include <net/if_media.h>
! 62:
! 63: #if NBPFILTER > 0
! 64: #include <net/bpf.h>
! 65: #endif
! 66:
! 67: #ifdef INET
! 68: #include <netinet/in.h>
! 69: #include <netinet/in_systm.h>
! 70: #include <netinet/in_var.h>
! 71: #include <netinet/ip.h>
! 72: #include <netinet/if_ether.h>
! 73: #endif
! 74:
! 75: #include <dev/mii/mii.h>
! 76: #include <dev/mii/miivar.h>
! 77: #include <dev/mii/urlphyreg.h>
! 78:
! 79: #include <dev/usb/usb.h>
! 80: #include <dev/usb/usbdi.h>
! 81: #include <dev/usb/usbdi_util.h>
! 82: #include <dev/usb/usbdevs.h>
! 83:
! 84: #include <dev/usb/if_urlreg.h>
! 85:
! 86:
! 87: /* Function declarations */
! 88: int url_match(struct device *, void *, void *);
! 89: void url_attach(struct device *, struct device *, void *);
! 90: int url_detach(struct device *, int);
! 91: int url_activate(struct device *, enum devact);
! 92:
! 93: struct cfdriver url_cd = {
! 94: NULL, "url", DV_IFNET
! 95: };
! 96:
! 97: const struct cfattach url_ca = {
! 98: sizeof(struct url_softc),
! 99: url_match,
! 100: url_attach,
! 101: url_detach,
! 102: url_activate,
! 103: };
! 104:
! 105: int url_openpipes(struct url_softc *);
! 106: int url_rx_list_init(struct url_softc *);
! 107: int url_tx_list_init(struct url_softc *);
! 108: int url_newbuf(struct url_softc *, struct url_chain *, struct mbuf *);
! 109: void url_start(struct ifnet *);
! 110: int url_send(struct url_softc *, struct mbuf *, int);
! 111: void url_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
! 112: void url_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
! 113: void url_tick(void *);
! 114: void url_tick_task(void *);
! 115: int url_ioctl(struct ifnet *, u_long, caddr_t);
! 116: void url_stop_task(struct url_softc *);
! 117: void url_stop(struct ifnet *, int);
! 118: void url_watchdog(struct ifnet *);
! 119: int url_ifmedia_change(struct ifnet *);
! 120: void url_ifmedia_status(struct ifnet *, struct ifmediareq *);
! 121: void url_lock_mii(struct url_softc *);
! 122: void url_unlock_mii(struct url_softc *);
! 123: int url_int_miibus_readreg(struct device *, int, int);
! 124: void url_int_miibus_writereg(struct device *, int, int, int);
! 125: void url_miibus_statchg(struct device *);
! 126: int url_init(struct ifnet *);
! 127: void url_setmulti(struct url_softc *);
! 128: void url_reset(struct url_softc *);
! 129:
! 130: int url_csr_read_1(struct url_softc *, int);
! 131: int url_csr_read_2(struct url_softc *, int);
! 132: int url_csr_write_1(struct url_softc *, int, int);
! 133: int url_csr_write_2(struct url_softc *, int, int);
! 134: int url_csr_write_4(struct url_softc *, int, int);
! 135: int url_mem(struct url_softc *, int, int, void *, int);
! 136:
! 137: /* Macros */
! 138: #ifdef URL_DEBUG
! 139: #define DPRINTF(x) do { if (urldebug) printf x; } while (0)
! 140: #define DPRINTFN(n,x) do { if (urldebug >= (n)) printf x; } while (0)
! 141: int urldebug = 0;
! 142: #else
! 143: #define DPRINTF(x)
! 144: #define DPRINTFN(n,x)
! 145: #endif
! 146:
! 147: #define URL_SETBIT(sc, reg, x) \
! 148: url_csr_write_1(sc, reg, url_csr_read_1(sc, reg) | (x))
! 149:
! 150: #define URL_SETBIT2(sc, reg, x) \
! 151: url_csr_write_2(sc, reg, url_csr_read_2(sc, reg) | (x))
! 152:
! 153: #define URL_CLRBIT(sc, reg, x) \
! 154: url_csr_write_1(sc, reg, url_csr_read_1(sc, reg) & ~(x))
! 155:
! 156: #define URL_CLRBIT2(sc, reg, x) \
! 157: url_csr_write_2(sc, reg, url_csr_read_2(sc, reg) & ~(x))
! 158:
! 159: static const struct url_type {
! 160: struct usb_devno url_dev;
! 161: u_int16_t url_flags;
! 162: #define URL_EXT_PHY 0x0001
! 163: } url_devs [] = {
! 164: {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_LCS8138TX}, 0},
! 165: {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_RTL8151}, 0},
! 166: {{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAKTX }, 0},
! 167: {{ USB_VENDOR_MICRONET, USB_PRODUCT_MICRONET_SP128AR}, 0},
! 168: {{ USB_VENDOR_OQO, USB_PRODUCT_OQO_ETHER01}, 0},
! 169: {{ USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8150}, 0},
! 170: {{ USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8151}, 0},
! 171: {{ USB_VENDOR_ZYXEL, USB_PRODUCT_ZYXEL_PRESTIGE}, 0}
! 172: };
! 173: #define url_lookup(v, p) ((struct url_type *)usb_lookup(url_devs, v, p))
! 174:
! 175:
! 176: /* Probe */
! 177: int
! 178: url_match(struct device *parent, void *match, void *aux)
! 179: {
! 180: struct usb_attach_arg *uaa = aux;
! 181:
! 182: if (uaa->iface != NULL)
! 183: return (UMATCH_NONE);
! 184:
! 185: return (url_lookup(uaa->vendor, uaa->product) != NULL ?
! 186: UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
! 187: }
! 188: /* Attach */
! 189: void
! 190: url_attach(struct device *parent, struct device *self, void *aux)
! 191: {
! 192: struct url_softc *sc = (struct url_softc *)self;
! 193: struct usb_attach_arg *uaa = aux;
! 194: usbd_device_handle dev = uaa->device;
! 195: usbd_interface_handle iface;
! 196: usbd_status err;
! 197: usb_interface_descriptor_t *id;
! 198: usb_endpoint_descriptor_t *ed;
! 199: char *devinfop;
! 200: char *devname = sc->sc_dev.dv_xname;
! 201: struct ifnet *ifp;
! 202: struct mii_data *mii;
! 203: u_char eaddr[ETHER_ADDR_LEN];
! 204: int i, s;
! 205:
! 206: devinfop = usbd_devinfo_alloc(dev, 0);
! 207: printf("\n%s: %s\n", devname, devinfop);
! 208: usbd_devinfo_free(devinfop);
! 209:
! 210: /* Move the device into the configured state. */
! 211: err = usbd_set_config_no(dev, URL_CONFIG_NO, 1);
! 212: if (err) {
! 213: printf("%s: setting config no failed\n", devname);
! 214: goto bad;
! 215: }
! 216:
! 217: usb_init_task(&sc->sc_tick_task, url_tick_task, sc);
! 218: rw_init(&sc->sc_mii_lock, "urlmii");
! 219: usb_init_task(&sc->sc_stop_task, (void (*)(void *)) url_stop_task, sc);
! 220:
! 221: /* get control interface */
! 222: err = usbd_device2interface_handle(dev, URL_IFACE_INDEX, &iface);
! 223: if (err) {
! 224: printf("%s: failed to get interface, err=%s\n", devname,
! 225: usbd_errstr(err));
! 226: goto bad;
! 227: }
! 228:
! 229: sc->sc_udev = dev;
! 230: sc->sc_ctl_iface = iface;
! 231: sc->sc_flags = url_lookup(uaa->vendor, uaa->product)->url_flags;
! 232:
! 233: /* get interface descriptor */
! 234: id = usbd_get_interface_descriptor(sc->sc_ctl_iface);
! 235:
! 236: /* find endpoints */
! 237: sc->sc_bulkin_no = sc->sc_bulkout_no = sc->sc_intrin_no = -1;
! 238: for (i = 0; i < id->bNumEndpoints; i++) {
! 239: ed = usbd_interface2endpoint_descriptor(sc->sc_ctl_iface, i);
! 240: if (ed == NULL) {
! 241: printf("%s: couldn't get endpoint %d\n", devname, i);
! 242: goto bad;
! 243: }
! 244: if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK &&
! 245: UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN)
! 246: sc->sc_bulkin_no = ed->bEndpointAddress; /* RX */
! 247: else if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK &&
! 248: UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT)
! 249: sc->sc_bulkout_no = ed->bEndpointAddress; /* TX */
! 250: else if ((ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT &&
! 251: UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN)
! 252: sc->sc_intrin_no = ed->bEndpointAddress; /* Status */
! 253: }
! 254:
! 255: if (sc->sc_bulkin_no == -1 || sc->sc_bulkout_no == -1 ||
! 256: sc->sc_intrin_no == -1) {
! 257: printf("%s: missing endpoint\n", devname);
! 258: goto bad;
! 259: }
! 260:
! 261: s = splnet();
! 262:
! 263: /* reset the adapter */
! 264: url_reset(sc);
! 265:
! 266: /* Get Ethernet Address */
! 267: err = url_mem(sc, URL_CMD_READMEM, URL_IDR0, (void *)eaddr,
! 268: ETHER_ADDR_LEN);
! 269: if (err) {
! 270: printf("%s: read MAC address failed\n", devname);
! 271: splx(s);
! 272: goto bad;
! 273: }
! 274:
! 275: /* Print Ethernet Address */
! 276: printf("%s: address %s\n", devname, ether_sprintf(eaddr));
! 277:
! 278: bcopy(eaddr, (char *)&sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN);
! 279: /* initialize interface information */
! 280: ifp = GET_IFP(sc);
! 281: ifp->if_softc = sc;
! 282: strlcpy(ifp->if_xname, devname, IFNAMSIZ);
! 283: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
! 284: ifp->if_start = url_start;
! 285: ifp->if_ioctl = url_ioctl;
! 286: ifp->if_watchdog = url_watchdog;
! 287:
! 288: IFQ_SET_READY(&ifp->if_snd);
! 289:
! 290: /*
! 291: * Do ifmedia setup.
! 292: */
! 293: mii = &sc->sc_mii;
! 294: mii->mii_ifp = ifp;
! 295: mii->mii_readreg = url_int_miibus_readreg;
! 296: mii->mii_writereg = url_int_miibus_writereg;
! 297: #if 0
! 298: if (sc->sc_flags & URL_EXT_PHY) {
! 299: mii->mii_readreg = url_ext_miibus_readreg;
! 300: mii->mii_writereg = url_ext_miibus_writereg;
! 301: }
! 302: #endif
! 303: mii->mii_statchg = url_miibus_statchg;
! 304: mii->mii_flags = MIIF_AUTOTSLEEP;
! 305: ifmedia_init(&mii->mii_media, 0,
! 306: url_ifmedia_change, url_ifmedia_status);
! 307: mii_attach(self, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, 0);
! 308: if (LIST_FIRST(&mii->mii_phys) == NULL) {
! 309: ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_NONE, 0, NULL);
! 310: ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_NONE);
! 311: } else
! 312: ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO);
! 313:
! 314: /* attach the interface */
! 315: if_attach(ifp);
! 316: ether_ifattach(ifp);
! 317:
! 318: timeout_set(&sc->sc_stat_ch, NULL, NULL);
! 319: sc->sc_attached = 1;
! 320: splx(s);
! 321:
! 322: usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, dev, &sc->sc_dev);
! 323:
! 324: return;
! 325:
! 326: bad:
! 327: sc->sc_dying = 1;
! 328: }
! 329:
! 330: /* detach */
! 331: int
! 332: url_detach(struct device *self, int flags)
! 333: {
! 334: struct url_softc *sc = (struct url_softc *)self;
! 335: struct ifnet *ifp = GET_IFP(sc);
! 336: int s;
! 337:
! 338: DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
! 339:
! 340: /* Detached before attached finished */
! 341: if (!sc->sc_attached)
! 342: return (0);
! 343:
! 344: timeout_del(&sc->sc_stat_ch);
! 345:
! 346: /* Remove any pending tasks */
! 347: usb_rem_task(sc->sc_udev, &sc->sc_tick_task);
! 348: usb_rem_task(sc->sc_udev, &sc->sc_stop_task);
! 349:
! 350: s = splusb();
! 351:
! 352: if (--sc->sc_refcnt >= 0) {
! 353: /* Wait for processes to go away */
! 354: usb_detach_wait(&sc->sc_dev);
! 355: }
! 356:
! 357: if (ifp->if_flags & IFF_RUNNING)
! 358: url_stop(GET_IFP(sc), 1);
! 359:
! 360: mii_detach(&sc->sc_mii, MII_PHY_ANY, MII_OFFSET_ANY);
! 361: ifmedia_delete_instance(&sc->sc_mii.mii_media, IFM_INST_ANY);
! 362: ether_ifdetach(ifp);
! 363: if_detach(ifp);
! 364:
! 365: #ifdef DIAGNOSTIC
! 366: if (sc->sc_pipe_tx != NULL)
! 367: printf("%s: detach has active tx endpoint.\n",
! 368: sc->sc_dev.dv_xname);
! 369: if (sc->sc_pipe_rx != NULL)
! 370: printf("%s: detach has active rx endpoint.\n",
! 371: sc->sc_dev.dv_xname);
! 372: if (sc->sc_pipe_intr != NULL)
! 373: printf("%s: detach has active intr endpoint.\n",
! 374: sc->sc_dev.dv_xname);
! 375: #endif
! 376:
! 377: sc->sc_attached = 0;
! 378:
! 379: splx(s);
! 380:
! 381: usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
! 382: &sc->sc_dev);
! 383:
! 384: return (0);
! 385: }
! 386:
! 387: /* read/write memory */
! 388: int
! 389: url_mem(struct url_softc *sc, int cmd, int offset, void *buf, int len)
! 390: {
! 391: usb_device_request_t req;
! 392: usbd_status err;
! 393:
! 394: if (sc == NULL)
! 395: return (0);
! 396:
! 397: DPRINTFN(0x200,
! 398: ("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
! 399:
! 400: if (sc->sc_dying)
! 401: return (0);
! 402:
! 403: if (cmd == URL_CMD_READMEM)
! 404: req.bmRequestType = UT_READ_VENDOR_DEVICE;
! 405: else
! 406: req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
! 407: req.bRequest = URL_REQ_MEM;
! 408: USETW(req.wValue, offset);
! 409: USETW(req.wIndex, 0x0000);
! 410: USETW(req.wLength, len);
! 411:
! 412: sc->sc_refcnt++;
! 413: err = usbd_do_request(sc->sc_udev, &req, buf);
! 414: if (--sc->sc_refcnt < 0)
! 415: usb_detach_wakeup(&sc->sc_dev);
! 416: if (err) {
! 417: DPRINTF(("%s: url_mem(): %s failed. off=%04x, err=%d\n",
! 418: sc->sc_dev.dv_xname,
! 419: cmd == URL_CMD_READMEM ? "read" : "write",
! 420: offset, err));
! 421: }
! 422:
! 423: return (err);
! 424: }
! 425:
! 426: /* read 1byte from register */
! 427: int
! 428: url_csr_read_1(struct url_softc *sc, int reg)
! 429: {
! 430: u_int8_t val = 0;
! 431:
! 432: DPRINTFN(0x100,
! 433: ("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
! 434:
! 435: if (sc->sc_dying)
! 436: return (0);
! 437:
! 438: return (url_mem(sc, URL_CMD_READMEM, reg, &val, 1) ? 0 : val);
! 439: }
! 440:
! 441: /* read 2bytes from register */
! 442: int
! 443: url_csr_read_2(struct url_softc *sc, int reg)
! 444: {
! 445: uWord val;
! 446:
! 447: DPRINTFN(0x100,
! 448: ("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
! 449:
! 450: if (sc->sc_dying)
! 451: return (0);
! 452:
! 453: USETW(val, 0);
! 454: return (url_mem(sc, URL_CMD_READMEM, reg, &val, 2) ? 0 : UGETW(val));
! 455: }
! 456:
! 457: /* write 1byte to register */
! 458: int
! 459: url_csr_write_1(struct url_softc *sc, int reg, int aval)
! 460: {
! 461: u_int8_t val = aval;
! 462:
! 463: DPRINTFN(0x100,
! 464: ("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
! 465:
! 466: if (sc->sc_dying)
! 467: return (0);
! 468:
! 469: return (url_mem(sc, URL_CMD_WRITEMEM, reg, &val, 1) ? -1 : 0);
! 470: }
! 471:
! 472: /* write 2bytes to register */
! 473: int
! 474: url_csr_write_2(struct url_softc *sc, int reg, int aval)
! 475: {
! 476: uWord val;
! 477:
! 478: DPRINTFN(0x100,
! 479: ("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
! 480:
! 481: USETW(val, aval);
! 482:
! 483: if (sc->sc_dying)
! 484: return (0);
! 485:
! 486: return (url_mem(sc, URL_CMD_WRITEMEM, reg, &val, 2) ? -1 : 0);
! 487: }
! 488:
! 489: /* write 4bytes to register */
! 490: int
! 491: url_csr_write_4(struct url_softc *sc, int reg, int aval)
! 492: {
! 493: uDWord val;
! 494:
! 495: DPRINTFN(0x100,
! 496: ("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
! 497:
! 498: USETDW(val, aval);
! 499:
! 500: if (sc->sc_dying)
! 501: return (0);
! 502:
! 503: return (url_mem(sc, URL_CMD_WRITEMEM, reg, &val, 4) ? -1 : 0);
! 504: }
! 505:
! 506: int
! 507: url_init(struct ifnet *ifp)
! 508: {
! 509: struct url_softc *sc = ifp->if_softc;
! 510: struct mii_data *mii = GET_MII(sc);
! 511: u_char *eaddr;
! 512: int i, s;
! 513:
! 514: DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
! 515:
! 516: if (sc->sc_dying)
! 517: return (EIO);
! 518:
! 519: s = splnet();
! 520:
! 521: /* Cancel pending I/O and free all TX/RX buffers */
! 522: url_stop(ifp, 1);
! 523:
! 524: eaddr = sc->sc_ac.ac_enaddr;
! 525: for (i = 0; i < ETHER_ADDR_LEN; i++)
! 526: url_csr_write_1(sc, URL_IDR0 + i, eaddr[i]);
! 527:
! 528: /* Init transmission control register */
! 529: URL_CLRBIT(sc, URL_TCR,
! 530: URL_TCR_TXRR1 | URL_TCR_TXRR0 |
! 531: URL_TCR_IFG1 | URL_TCR_IFG0 |
! 532: URL_TCR_NOCRC);
! 533:
! 534: /* Init receive control register */
! 535: URL_SETBIT2(sc, URL_RCR, URL_RCR_TAIL | URL_RCR_AD);
! 536: if (ifp->if_flags & IFF_BROADCAST)
! 537: URL_SETBIT2(sc, URL_RCR, URL_RCR_AB);
! 538: else
! 539: URL_CLRBIT2(sc, URL_RCR, URL_RCR_AB);
! 540:
! 541: /* If we want promiscuous mode, accept all physical frames. */
! 542: if (ifp->if_flags & IFF_PROMISC)
! 543: URL_SETBIT2(sc, URL_RCR, URL_RCR_AAM|URL_RCR_AAP);
! 544: else
! 545: URL_CLRBIT2(sc, URL_RCR, URL_RCR_AAM|URL_RCR_AAP);
! 546:
! 547:
! 548: /* Initialize transmit ring */
! 549: if (url_tx_list_init(sc) == ENOBUFS) {
! 550: printf("%s: tx list init failed\n", sc->sc_dev.dv_xname);
! 551: splx(s);
! 552: return (EIO);
! 553: }
! 554:
! 555: /* Initialize receive ring */
! 556: if (url_rx_list_init(sc) == ENOBUFS) {
! 557: printf("%s: rx list init failed\n", sc->sc_dev.dv_xname);
! 558: splx(s);
! 559: return (EIO);
! 560: }
! 561:
! 562: /* Load the multicast filter */
! 563: url_setmulti(sc);
! 564:
! 565: /* Enable RX and TX */
! 566: URL_SETBIT(sc, URL_CR, URL_CR_TE | URL_CR_RE);
! 567:
! 568: mii_mediachg(mii);
! 569:
! 570: if (sc->sc_pipe_tx == NULL || sc->sc_pipe_rx == NULL) {
! 571: if (url_openpipes(sc)) {
! 572: splx(s);
! 573: return (EIO);
! 574: }
! 575: }
! 576:
! 577: ifp->if_flags |= IFF_RUNNING;
! 578: ifp->if_flags &= ~IFF_OACTIVE;
! 579:
! 580: splx(s);
! 581:
! 582: timeout_del(&sc->sc_stat_ch);
! 583: timeout_set(&sc->sc_stat_ch, url_tick, sc);
! 584: timeout_add(&sc->sc_stat_ch, hz);
! 585:
! 586: return (0);
! 587: }
! 588:
! 589: void
! 590: url_reset(struct url_softc *sc)
! 591: {
! 592: int i;
! 593:
! 594: DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
! 595:
! 596: if (sc->sc_dying)
! 597: return;
! 598:
! 599: URL_SETBIT(sc, URL_CR, URL_CR_SOFT_RST);
! 600:
! 601: for (i = 0; i < URL_TX_TIMEOUT; i++) {
! 602: if (!(url_csr_read_1(sc, URL_CR) & URL_CR_SOFT_RST))
! 603: break;
! 604: delay(10); /* XXX */
! 605: }
! 606:
! 607: delay(10000); /* XXX */
! 608: }
! 609:
! 610: int
! 611: url_activate(struct device *self, enum devact act)
! 612: {
! 613: struct url_softc *sc = (struct url_softc *)self;
! 614:
! 615: DPRINTF(("%s: %s: enter, act=%d\n", sc->sc_dev.dv_xname,
! 616: __func__, act));
! 617:
! 618: switch (act) {
! 619: case DVACT_ACTIVATE:
! 620: break;
! 621:
! 622: case DVACT_DEACTIVATE:
! 623: sc->sc_dying = 1;
! 624: break;
! 625: }
! 626:
! 627: return (0);
! 628: }
! 629:
! 630: #define url_calchash(addr) (ether_crc32_be((addr), ETHER_ADDR_LEN) >> 26)
! 631:
! 632:
! 633: void
! 634: url_setmulti(struct url_softc *sc)
! 635: {
! 636: struct ifnet *ifp;
! 637: struct ether_multi *enm;
! 638: struct ether_multistep step;
! 639: u_int32_t hashes[2] = { 0, 0 };
! 640: int h = 0;
! 641: int mcnt = 0;
! 642:
! 643: DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
! 644:
! 645: if (sc->sc_dying)
! 646: return;
! 647:
! 648: ifp = GET_IFP(sc);
! 649:
! 650: if (ifp->if_flags & IFF_PROMISC) {
! 651: URL_SETBIT2(sc, URL_RCR, URL_RCR_AAM|URL_RCR_AAP);
! 652: return;
! 653: } else if (ifp->if_flags & IFF_ALLMULTI) {
! 654: allmulti:
! 655: ifp->if_flags |= IFF_ALLMULTI;
! 656: URL_SETBIT2(sc, URL_RCR, URL_RCR_AAM);
! 657: URL_CLRBIT2(sc, URL_RCR, URL_RCR_AAP);
! 658: return;
! 659: }
! 660:
! 661: /* first, zot all the existing hash bits */
! 662: url_csr_write_4(sc, URL_MAR0, 0);
! 663: url_csr_write_4(sc, URL_MAR4, 0);
! 664:
! 665: /* now program new ones */
! 666: ETHER_FIRST_MULTI(step, &sc->sc_ac, enm);
! 667: while (enm != NULL) {
! 668: if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
! 669: ETHER_ADDR_LEN) != 0)
! 670: goto allmulti;
! 671:
! 672: h = url_calchash(enm->enm_addrlo);
! 673: if (h < 32)
! 674: hashes[0] |= (1 << h);
! 675: else
! 676: hashes[1] |= (1 << (h -32));
! 677: mcnt++;
! 678: ETHER_NEXT_MULTI(step, enm);
! 679: }
! 680:
! 681: ifp->if_flags &= ~IFF_ALLMULTI;
! 682:
! 683: URL_CLRBIT2(sc, URL_RCR, URL_RCR_AAM|URL_RCR_AAP);
! 684:
! 685: if (mcnt){
! 686: URL_SETBIT2(sc, URL_RCR, URL_RCR_AM);
! 687: } else {
! 688: URL_CLRBIT2(sc, URL_RCR, URL_RCR_AM);
! 689: }
! 690: url_csr_write_4(sc, URL_MAR0, hashes[0]);
! 691: url_csr_write_4(sc, URL_MAR4, hashes[1]);
! 692: }
! 693:
! 694: int
! 695: url_openpipes(struct url_softc *sc)
! 696: {
! 697: struct url_chain *c;
! 698: usbd_status err;
! 699: int i;
! 700: int error = 0;
! 701:
! 702: if (sc->sc_dying)
! 703: return (EIO);
! 704:
! 705: sc->sc_refcnt++;
! 706:
! 707: /* Open RX pipe */
! 708: err = usbd_open_pipe(sc->sc_ctl_iface, sc->sc_bulkin_no,
! 709: USBD_EXCLUSIVE_USE, &sc->sc_pipe_rx);
! 710: if (err) {
! 711: printf("%s: open rx pipe failed: %s\n",
! 712: sc->sc_dev.dv_xname, usbd_errstr(err));
! 713: error = EIO;
! 714: goto done;
! 715: }
! 716:
! 717: /* Open TX pipe */
! 718: err = usbd_open_pipe(sc->sc_ctl_iface, sc->sc_bulkout_no,
! 719: USBD_EXCLUSIVE_USE, &sc->sc_pipe_tx);
! 720: if (err) {
! 721: printf("%s: open tx pipe failed: %s\n",
! 722: sc->sc_dev.dv_xname, usbd_errstr(err));
! 723: error = EIO;
! 724: goto done;
! 725: }
! 726:
! 727: #if 0
! 728: /* XXX: interrupt endpoint is not yet supported */
! 729: /* Open Interrupt pipe */
! 730: err = usbd_open_pipe_intr(sc->sc_ctl_iface, sc->sc_intrin_no,
! 731: USBD_EXCLUSIVE_USE, &sc->sc_pipe_intr, sc,
! 732: &sc->sc_cdata.url_ibuf, URL_INTR_PKGLEN,
! 733: url_intr, URL_INTR_INTERVAL);
! 734: if (err) {
! 735: printf("%s: open intr pipe failed: %s\n",
! 736: sc->sc_dev.dv_xname, usbd_errstr(err));
! 737: error = EIO;
! 738: goto done;
! 739: }
! 740: #endif
! 741:
! 742:
! 743: /* Start up the receive pipe. */
! 744: for (i = 0; i < URL_RX_LIST_CNT; i++) {
! 745: c = &sc->sc_cdata.url_rx_chain[i];
! 746: usbd_setup_xfer(c->url_xfer, sc->sc_pipe_rx,
! 747: c, c->url_buf, URL_BUFSZ,
! 748: USBD_SHORT_XFER_OK | USBD_NO_COPY,
! 749: USBD_NO_TIMEOUT, url_rxeof);
! 750: (void)usbd_transfer(c->url_xfer);
! 751: DPRINTF(("%s: %s: start read\n", sc->sc_dev.dv_xname,
! 752: __func__));
! 753: }
! 754:
! 755: done:
! 756: if (--sc->sc_refcnt < 0)
! 757: usb_detach_wakeup(&sc->sc_dev);
! 758:
! 759: return (error);
! 760: }
! 761:
! 762: int
! 763: url_newbuf(struct url_softc *sc, struct url_chain *c, struct mbuf *m)
! 764: {
! 765: struct mbuf *m_new = NULL;
! 766:
! 767: DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
! 768:
! 769: if (m == NULL) {
! 770: MGETHDR(m_new, M_DONTWAIT, MT_DATA);
! 771: if (m_new == NULL) {
! 772: printf("%s: no memory for rx list "
! 773: "-- packet dropped!\n", sc->sc_dev.dv_xname);
! 774: return (ENOBUFS);
! 775: }
! 776: MCLGET(m_new, M_DONTWAIT);
! 777: if (!(m_new->m_flags & M_EXT)) {
! 778: printf("%s: no memory for rx list "
! 779: "-- packet dropped!\n", sc->sc_dev.dv_xname);
! 780: m_freem(m_new);
! 781: return (ENOBUFS);
! 782: }
! 783: m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
! 784: } else {
! 785: m_new = m;
! 786: m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
! 787: m_new->m_data = m_new->m_ext.ext_buf;
! 788: }
! 789:
! 790: m_adj(m_new, ETHER_ALIGN);
! 791: c->url_mbuf = m_new;
! 792:
! 793: return (0);
! 794: }
! 795:
! 796:
! 797: int
! 798: url_rx_list_init(struct url_softc *sc)
! 799: {
! 800: struct url_cdata *cd;
! 801: struct url_chain *c;
! 802: int i;
! 803:
! 804: DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
! 805:
! 806: cd = &sc->sc_cdata;
! 807: for (i = 0; i < URL_RX_LIST_CNT; i++) {
! 808: c = &cd->url_rx_chain[i];
! 809: c->url_sc = sc;
! 810: c->url_idx = i;
! 811: if (url_newbuf(sc, c, NULL) == ENOBUFS)
! 812: return (ENOBUFS);
! 813: if (c->url_xfer == NULL) {
! 814: c->url_xfer = usbd_alloc_xfer(sc->sc_udev);
! 815: if (c->url_xfer == NULL)
! 816: return (ENOBUFS);
! 817: c->url_buf = usbd_alloc_buffer(c->url_xfer, URL_BUFSZ);
! 818: if (c->url_buf == NULL) {
! 819: usbd_free_xfer(c->url_xfer);
! 820: return (ENOBUFS);
! 821: }
! 822: }
! 823: }
! 824:
! 825: return (0);
! 826: }
! 827:
! 828: int
! 829: url_tx_list_init(struct url_softc *sc)
! 830: {
! 831: struct url_cdata *cd;
! 832: struct url_chain *c;
! 833: int i;
! 834:
! 835: DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
! 836:
! 837: cd = &sc->sc_cdata;
! 838: for (i = 0; i < URL_TX_LIST_CNT; i++) {
! 839: c = &cd->url_tx_chain[i];
! 840: c->url_sc = sc;
! 841: c->url_idx = i;
! 842: c->url_mbuf = NULL;
! 843: if (c->url_xfer == NULL) {
! 844: c->url_xfer = usbd_alloc_xfer(sc->sc_udev);
! 845: if (c->url_xfer == NULL)
! 846: return (ENOBUFS);
! 847: c->url_buf = usbd_alloc_buffer(c->url_xfer, URL_BUFSZ);
! 848: if (c->url_buf == NULL) {
! 849: usbd_free_xfer(c->url_xfer);
! 850: return (ENOBUFS);
! 851: }
! 852: }
! 853: }
! 854:
! 855: return (0);
! 856: }
! 857:
! 858: void
! 859: url_start(struct ifnet *ifp)
! 860: {
! 861: struct url_softc *sc = ifp->if_softc;
! 862: struct mbuf *m_head = NULL;
! 863:
! 864: DPRINTF(("%s: %s: enter, link=%d\n", sc->sc_dev.dv_xname,
! 865: __func__, sc->sc_link));
! 866:
! 867: if (sc->sc_dying)
! 868: return;
! 869:
! 870: if (!sc->sc_link)
! 871: return;
! 872:
! 873: if (ifp->if_flags & IFF_OACTIVE)
! 874: return;
! 875:
! 876: IFQ_POLL(&ifp->if_snd, m_head);
! 877: if (m_head == NULL)
! 878: return;
! 879:
! 880: if (url_send(sc, m_head, 0)) {
! 881: ifp->if_flags |= IFF_OACTIVE;
! 882: return;
! 883: }
! 884:
! 885: IFQ_DEQUEUE(&ifp->if_snd, m_head);
! 886:
! 887: #if NBPFILTER > 0
! 888: if (ifp->if_bpf)
! 889: bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
! 890: #endif
! 891:
! 892: ifp->if_flags |= IFF_OACTIVE;
! 893:
! 894: /* Set a timeout in case the chip goes out to lunch. */
! 895: ifp->if_timer = 5;
! 896: }
! 897:
! 898: int
! 899: url_send(struct url_softc *sc, struct mbuf *m, int idx)
! 900: {
! 901: int total_len;
! 902: struct url_chain *c;
! 903: usbd_status err;
! 904:
! 905: DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname,__func__));
! 906:
! 907: c = &sc->sc_cdata.url_tx_chain[idx];
! 908:
! 909: /* Copy the mbuf data into a contiguous buffer */
! 910: m_copydata(m, 0, m->m_pkthdr.len, c->url_buf);
! 911: c->url_mbuf = m;
! 912: total_len = m->m_pkthdr.len;
! 913:
! 914: if (total_len < URL_MIN_FRAME_LEN) {
! 915: bzero(c->url_buf + total_len, URL_MIN_FRAME_LEN - total_len);
! 916: total_len = URL_MIN_FRAME_LEN;
! 917: }
! 918: usbd_setup_xfer(c->url_xfer, sc->sc_pipe_tx, c, c->url_buf, total_len,
! 919: USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
! 920: URL_TX_TIMEOUT, url_txeof);
! 921:
! 922: /* Transmit */
! 923: sc->sc_refcnt++;
! 924: err = usbd_transfer(c->url_xfer);
! 925: if (--sc->sc_refcnt < 0)
! 926: usb_detach_wakeup(&sc->sc_dev);
! 927: if (err != USBD_IN_PROGRESS) {
! 928: printf("%s: url_send error=%s\n", sc->sc_dev.dv_xname,
! 929: usbd_errstr(err));
! 930: /* Stop the interface */
! 931: usb_add_task(sc->sc_udev, &sc->sc_stop_task);
! 932: return (EIO);
! 933: }
! 934:
! 935: DPRINTF(("%s: %s: send %d bytes\n", sc->sc_dev.dv_xname,
! 936: __func__, total_len));
! 937:
! 938: sc->sc_cdata.url_tx_cnt++;
! 939:
! 940: return (0);
! 941: }
! 942:
! 943: void
! 944: url_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
! 945: {
! 946: struct url_chain *c = priv;
! 947: struct url_softc *sc = c->url_sc;
! 948: struct ifnet *ifp = GET_IFP(sc);
! 949: int s;
! 950:
! 951: if (sc->sc_dying)
! 952: return;
! 953:
! 954: s = splnet();
! 955:
! 956: DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
! 957:
! 958: ifp->if_timer = 0;
! 959: ifp->if_flags &= ~IFF_OACTIVE;
! 960:
! 961: if (status != USBD_NORMAL_COMPLETION) {
! 962: if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
! 963: splx(s);
! 964: return;
! 965: }
! 966: ifp->if_oerrors++;
! 967: printf("%s: usb error on tx: %s\n", sc->sc_dev.dv_xname,
! 968: usbd_errstr(status));
! 969: if (status == USBD_STALLED) {
! 970: sc->sc_refcnt++;
! 971: usbd_clear_endpoint_stall_async(sc->sc_pipe_tx);
! 972: if (--sc->sc_refcnt < 0)
! 973: usb_detach_wakeup(&sc->sc_dev);
! 974: }
! 975: splx(s);
! 976: return;
! 977: }
! 978:
! 979: ifp->if_opackets++;
! 980:
! 981: m_freem(c->url_mbuf);
! 982: c->url_mbuf = NULL;
! 983:
! 984: if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
! 985: url_start(ifp);
! 986:
! 987: splx(s);
! 988: }
! 989:
! 990: void
! 991: url_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
! 992: {
! 993: struct url_chain *c = priv;
! 994: struct url_softc *sc = c->url_sc;
! 995: struct ifnet *ifp = GET_IFP(sc);
! 996: struct mbuf *m;
! 997: u_int32_t total_len;
! 998: url_rxhdr_t rxhdr;
! 999: int s;
! 1000:
! 1001: DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname,__func__));
! 1002:
! 1003: if (sc->sc_dying)
! 1004: return;
! 1005:
! 1006: if (status != USBD_NORMAL_COMPLETION) {
! 1007: if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
! 1008: return;
! 1009: sc->sc_rx_errs++;
! 1010: if (usbd_ratecheck(&sc->sc_rx_notice)) {
! 1011: printf("%s: %u usb errors on rx: %s\n",
! 1012: sc->sc_dev.dv_xname, sc->sc_rx_errs,
! 1013: usbd_errstr(status));
! 1014: sc->sc_rx_errs = 0;
! 1015: }
! 1016: if (status == USBD_STALLED) {
! 1017: sc->sc_refcnt++;
! 1018: usbd_clear_endpoint_stall_async(sc->sc_pipe_rx);
! 1019: if (--sc->sc_refcnt < 0)
! 1020: usb_detach_wakeup(&sc->sc_dev);
! 1021: }
! 1022: goto done;
! 1023: }
! 1024:
! 1025: usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
! 1026:
! 1027: memcpy(mtod(c->url_mbuf, char *), c->url_buf, total_len);
! 1028:
! 1029: if (total_len <= ETHER_CRC_LEN) {
! 1030: ifp->if_ierrors++;
! 1031: goto done;
! 1032: }
! 1033:
! 1034: memcpy(&rxhdr, c->url_buf + total_len - ETHER_CRC_LEN, sizeof(rxhdr));
! 1035:
! 1036: DPRINTF(("%s: RX Status: %dbytes%s%s%s%s packets\n",
! 1037: sc->sc_dev.dv_xname,
! 1038: UGETW(rxhdr) & URL_RXHDR_BYTEC_MASK,
! 1039: UGETW(rxhdr) & URL_RXHDR_VALID_MASK ? ", Valid" : "",
! 1040: UGETW(rxhdr) & URL_RXHDR_RUNTPKT_MASK ? ", Runt" : "",
! 1041: UGETW(rxhdr) & URL_RXHDR_PHYPKT_MASK ? ", Physical match" : "",
! 1042: UGETW(rxhdr) & URL_RXHDR_MCASTPKT_MASK ? ", Multicast" : ""));
! 1043:
! 1044: if ((UGETW(rxhdr) & URL_RXHDR_VALID_MASK) == 0) {
! 1045: ifp->if_ierrors++;
! 1046: goto done;
! 1047: }
! 1048:
! 1049: ifp->if_ipackets++;
! 1050: total_len -= ETHER_CRC_LEN;
! 1051:
! 1052: m = c->url_mbuf;
! 1053: m->m_pkthdr.len = m->m_len = total_len;
! 1054: m->m_pkthdr.rcvif = ifp;
! 1055:
! 1056: s = splnet();
! 1057:
! 1058: if (url_newbuf(sc, c, NULL) == ENOBUFS) {
! 1059: ifp->if_ierrors++;
! 1060: goto done1;
! 1061: }
! 1062:
! 1063: #if NBPFILTER > 0
! 1064: if (ifp->if_bpf)
! 1065: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
! 1066: #endif
! 1067:
! 1068: DPRINTF(("%s: %s: deliver %d\n", sc->sc_dev.dv_xname,
! 1069: __func__, m->m_len));
! 1070: ether_input_mbuf(ifp, m);
! 1071:
! 1072: done1:
! 1073: splx(s);
! 1074:
! 1075: done:
! 1076: /* Setup new transfer */
! 1077: usbd_setup_xfer(xfer, sc->sc_pipe_rx, c, c->url_buf, URL_BUFSZ,
! 1078: USBD_SHORT_XFER_OK | USBD_NO_COPY,
! 1079: USBD_NO_TIMEOUT, url_rxeof);
! 1080: sc->sc_refcnt++;
! 1081: usbd_transfer(xfer);
! 1082: if (--sc->sc_refcnt < 0)
! 1083: usb_detach_wakeup(&sc->sc_dev);
! 1084:
! 1085: DPRINTF(("%s: %s: start rx\n", sc->sc_dev.dv_xname, __func__));
! 1086: }
! 1087:
! 1088: #if 0
! 1089: void url_intr()
! 1090: {
! 1091: }
! 1092: #endif
! 1093:
! 1094: int
! 1095: url_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
! 1096: {
! 1097: struct url_softc *sc = ifp->if_softc;
! 1098: struct ifaddr *ifa = (struct ifaddr *)data;
! 1099: struct ifreq *ifr = (struct ifreq *)data;
! 1100: struct mii_data *mii;
! 1101: int s, error = 0;
! 1102:
! 1103: DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
! 1104:
! 1105: if (sc->sc_dying)
! 1106: return (EIO);
! 1107:
! 1108: s = splnet();
! 1109:
! 1110: switch (cmd) {
! 1111: case SIOCSIFADDR:
! 1112: ifp->if_flags |= IFF_UP;
! 1113: url_init(ifp);
! 1114:
! 1115: switch (ifa->ifa_addr->sa_family) {
! 1116: #ifdef INET
! 1117: case AF_INET:
! 1118: arp_ifinit(&sc->sc_ac, ifa);
! 1119: break;
! 1120: #endif /* INET */
! 1121: }
! 1122: break;
! 1123:
! 1124: case SIOCSIFMTU:
! 1125: if (ifr->ifr_mtu > ETHERMTU)
! 1126: error = EINVAL;
! 1127: else
! 1128: ifp->if_mtu = ifr->ifr_mtu;
! 1129: break;
! 1130:
! 1131: case SIOCSIFFLAGS:
! 1132: if (ifp->if_flags & IFF_UP) {
! 1133: if (ifp->if_flags & IFF_RUNNING &&
! 1134: ifp->if_flags & IFF_PROMISC) {
! 1135: URL_SETBIT2(sc, URL_RCR,
! 1136: URL_RCR_AAM|URL_RCR_AAP);
! 1137: } else if (ifp->if_flags & IFF_RUNNING &&
! 1138: !(ifp->if_flags & IFF_PROMISC)) {
! 1139: URL_CLRBIT2(sc, URL_RCR,
! 1140: URL_RCR_AAM|URL_RCR_AAP);
! 1141: } else if (!(ifp->if_flags & IFF_RUNNING))
! 1142: url_init(ifp);
! 1143: } else {
! 1144: if (ifp->if_flags & IFF_RUNNING)
! 1145: url_stop(ifp, 1);
! 1146: }
! 1147: error = 0;
! 1148: break;
! 1149: case SIOCADDMULTI:
! 1150: case SIOCDELMULTI:
! 1151: error = (cmd == SIOCADDMULTI) ?
! 1152: ether_addmulti(ifr, &sc->sc_ac) :
! 1153: ether_delmulti(ifr, &sc->sc_ac);
! 1154:
! 1155: if (error == ENETRESET) {
! 1156: if (ifp->if_flags & IFF_RUNNING)
! 1157: url_setmulti(sc);
! 1158: error = 0;
! 1159: }
! 1160: break;
! 1161: case SIOCGIFMEDIA:
! 1162: case SIOCSIFMEDIA:
! 1163: mii = GET_MII(sc);
! 1164: error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd);
! 1165: break;
! 1166: default:
! 1167: error = EINVAL;
! 1168: break;
! 1169: }
! 1170:
! 1171: splx(s);
! 1172:
! 1173: return (error);
! 1174: }
! 1175:
! 1176: void
! 1177: url_watchdog(struct ifnet *ifp)
! 1178: {
! 1179: struct url_softc *sc = ifp->if_softc;
! 1180: struct url_chain *c;
! 1181: usbd_status stat;
! 1182: int s;
! 1183:
! 1184: DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
! 1185:
! 1186: ifp->if_oerrors++;
! 1187: printf("%s: watchdog timeout\n", sc->sc_dev.dv_xname);
! 1188:
! 1189: s = splusb();
! 1190: c = &sc->sc_cdata.url_tx_chain[0];
! 1191: usbd_get_xfer_status(c->url_xfer, NULL, NULL, NULL, &stat);
! 1192: url_txeof(c->url_xfer, c, stat);
! 1193:
! 1194: if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
! 1195: url_start(ifp);
! 1196: splx(s);
! 1197: }
! 1198:
! 1199: void
! 1200: url_stop_task(struct url_softc *sc)
! 1201: {
! 1202: url_stop(GET_IFP(sc), 1);
! 1203: }
! 1204:
! 1205: /* Stop the adapter and free any mbufs allocated to the RX and TX lists. */
! 1206: void
! 1207: url_stop(struct ifnet *ifp, int disable)
! 1208: {
! 1209: struct url_softc *sc = ifp->if_softc;
! 1210: usbd_status err;
! 1211: int i;
! 1212:
! 1213: DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
! 1214:
! 1215: ifp->if_timer = 0;
! 1216: ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
! 1217:
! 1218: url_reset(sc);
! 1219:
! 1220: timeout_del(&sc->sc_stat_ch);
! 1221:
! 1222: /* Stop transfers */
! 1223: /* RX endpoint */
! 1224: if (sc->sc_pipe_rx != NULL) {
! 1225: err = usbd_abort_pipe(sc->sc_pipe_rx);
! 1226: if (err)
! 1227: printf("%s: abort rx pipe failed: %s\n",
! 1228: sc->sc_dev.dv_xname, usbd_errstr(err));
! 1229: err = usbd_close_pipe(sc->sc_pipe_rx);
! 1230: if (err)
! 1231: printf("%s: close rx pipe failed: %s\n",
! 1232: sc->sc_dev.dv_xname, usbd_errstr(err));
! 1233: sc->sc_pipe_rx = NULL;
! 1234: }
! 1235:
! 1236: /* TX endpoint */
! 1237: if (sc->sc_pipe_tx != NULL) {
! 1238: err = usbd_abort_pipe(sc->sc_pipe_tx);
! 1239: if (err)
! 1240: printf("%s: abort tx pipe failed: %s\n",
! 1241: sc->sc_dev.dv_xname, usbd_errstr(err));
! 1242: err = usbd_close_pipe(sc->sc_pipe_tx);
! 1243: if (err)
! 1244: printf("%s: close tx pipe failed: %s\n",
! 1245: sc->sc_dev.dv_xname, usbd_errstr(err));
! 1246: sc->sc_pipe_tx = NULL;
! 1247: }
! 1248:
! 1249: #if 0
! 1250: /* XXX: Interrupt endpoint is not yet supported!! */
! 1251: /* Interrupt endpoint */
! 1252: if (sc->sc_pipe_intr != NULL) {
! 1253: err = usbd_abort_pipe(sc->sc_pipe_intr);
! 1254: if (err)
! 1255: printf("%s: abort intr pipe failed: %s\n",
! 1256: sc->sc_dev.dv_xname, usbd_errstr(err));
! 1257: err = usbd_close_pipe(sc->sc_pipe_intr);
! 1258: if (err)
! 1259: printf("%s: close intr pipe failed: %s\n",
! 1260: sc->sc_dev.dv_xname, usbd_errstr(err));
! 1261: sc->sc_pipe_intr = NULL;
! 1262: }
! 1263: #endif
! 1264:
! 1265: /* Free RX resources. */
! 1266: for (i = 0; i < URL_RX_LIST_CNT; i++) {
! 1267: if (sc->sc_cdata.url_rx_chain[i].url_mbuf != NULL) {
! 1268: m_freem(sc->sc_cdata.url_rx_chain[i].url_mbuf);
! 1269: sc->sc_cdata.url_rx_chain[i].url_mbuf = NULL;
! 1270: }
! 1271: if (sc->sc_cdata.url_rx_chain[i].url_xfer != NULL) {
! 1272: usbd_free_xfer(sc->sc_cdata.url_rx_chain[i].url_xfer);
! 1273: sc->sc_cdata.url_rx_chain[i].url_xfer = NULL;
! 1274: }
! 1275: }
! 1276:
! 1277: /* Free TX resources. */
! 1278: for (i = 0; i < URL_TX_LIST_CNT; i++) {
! 1279: if (sc->sc_cdata.url_tx_chain[i].url_mbuf != NULL) {
! 1280: m_freem(sc->sc_cdata.url_tx_chain[i].url_mbuf);
! 1281: sc->sc_cdata.url_tx_chain[i].url_mbuf = NULL;
! 1282: }
! 1283: if (sc->sc_cdata.url_tx_chain[i].url_xfer != NULL) {
! 1284: usbd_free_xfer(sc->sc_cdata.url_tx_chain[i].url_xfer);
! 1285: sc->sc_cdata.url_tx_chain[i].url_xfer = NULL;
! 1286: }
! 1287: }
! 1288:
! 1289: sc->sc_link = 0;
! 1290: }
! 1291:
! 1292: /* Set media options */
! 1293: int
! 1294: url_ifmedia_change(struct ifnet *ifp)
! 1295: {
! 1296: struct url_softc *sc = ifp->if_softc;
! 1297: struct mii_data *mii = GET_MII(sc);
! 1298:
! 1299: DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
! 1300:
! 1301: if (sc->sc_dying)
! 1302: return (0);
! 1303:
! 1304: sc->sc_link = 0;
! 1305: if (mii->mii_instance) {
! 1306: struct mii_softc *miisc;
! 1307: for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL;
! 1308: miisc = LIST_NEXT(miisc, mii_list))
! 1309: mii_phy_reset(miisc);
! 1310: }
! 1311:
! 1312: return (mii_mediachg(mii));
! 1313: }
! 1314:
! 1315: /* Report current media status. */
! 1316: void
! 1317: url_ifmedia_status(struct ifnet *ifp, struct ifmediareq *ifmr)
! 1318: {
! 1319: struct url_softc *sc = ifp->if_softc;
! 1320: struct mii_data *mii = GET_MII(sc);
! 1321:
! 1322: DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
! 1323:
! 1324: if (sc->sc_dying)
! 1325: return;
! 1326:
! 1327: if ((ifp->if_flags & IFF_RUNNING) == 0) {
! 1328: ifmr->ifm_active = IFM_ETHER | IFM_NONE;
! 1329: ifmr->ifm_status = 0;
! 1330: return;
! 1331: }
! 1332:
! 1333: mii_pollstat(mii);
! 1334: ifmr->ifm_active = mii->mii_media_active;
! 1335: ifmr->ifm_status = mii->mii_media_status;
! 1336: }
! 1337:
! 1338: void
! 1339: url_tick(void *xsc)
! 1340: {
! 1341: struct url_softc *sc = xsc;
! 1342:
! 1343: if (sc == NULL)
! 1344: return;
! 1345:
! 1346: DPRINTFN(0xff, ("%s: %s: enter\n", sc->sc_dev.dv_xname,
! 1347: __func__));
! 1348:
! 1349: if (sc->sc_dying)
! 1350: return;
! 1351:
! 1352: /* Perform periodic stuff in process context */
! 1353: usb_add_task(sc->sc_udev, &sc->sc_tick_task);
! 1354: }
! 1355:
! 1356: void
! 1357: url_tick_task(void *xsc)
! 1358: {
! 1359: struct url_softc *sc = xsc;
! 1360: struct ifnet *ifp;
! 1361: struct mii_data *mii;
! 1362: int s;
! 1363:
! 1364: if (sc == NULL)
! 1365: return;
! 1366:
! 1367: DPRINTFN(0xff, ("%s: %s: enter\n", sc->sc_dev.dv_xname,
! 1368: __func__));
! 1369:
! 1370: if (sc->sc_dying)
! 1371: return;
! 1372:
! 1373: ifp = GET_IFP(sc);
! 1374: mii = GET_MII(sc);
! 1375:
! 1376: if (mii == NULL)
! 1377: return;
! 1378:
! 1379: s = splnet();
! 1380:
! 1381: mii_tick(mii);
! 1382: if (!sc->sc_link && mii->mii_media_status & IFM_ACTIVE &&
! 1383: IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
! 1384: DPRINTF(("%s: %s: got link\n",
! 1385: sc->sc_dev.dv_xname, __func__));
! 1386: sc->sc_link++;
! 1387: if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
! 1388: url_start(ifp);
! 1389: }
! 1390:
! 1391: timeout_del(&sc->sc_stat_ch);
! 1392: timeout_set(&sc->sc_stat_ch, url_tick, sc);
! 1393: timeout_add(&sc->sc_stat_ch, hz);
! 1394:
! 1395: splx(s);
! 1396: }
! 1397:
! 1398: /* Get exclusive access to the MII registers */
! 1399: void
! 1400: url_lock_mii(struct url_softc *sc)
! 1401: {
! 1402: DPRINTFN(0xff, ("%s: %s: enter\n", sc->sc_dev.dv_xname,
! 1403: __func__));
! 1404:
! 1405: sc->sc_refcnt++;
! 1406: rw_enter_write(&sc->sc_mii_lock);
! 1407: }
! 1408:
! 1409: void
! 1410: url_unlock_mii(struct url_softc *sc)
! 1411: {
! 1412: DPRINTFN(0xff, ("%s: %s: enter\n", sc->sc_dev.dv_xname,
! 1413: __func__));
! 1414:
! 1415: rw_exit_write(&sc->sc_mii_lock);
! 1416: if (--sc->sc_refcnt < 0)
! 1417: usb_detach_wakeup(&sc->sc_dev);
! 1418: }
! 1419:
! 1420: int
! 1421: url_int_miibus_readreg(struct device *dev, int phy, int reg)
! 1422: {
! 1423: struct url_softc *sc;
! 1424: u_int16_t val;
! 1425:
! 1426: if (dev == NULL)
! 1427: return (0);
! 1428:
! 1429: sc = (void *)dev;
! 1430:
! 1431: DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x\n",
! 1432: sc->sc_dev.dv_xname, __func__, phy, reg));
! 1433:
! 1434: if (sc->sc_dying) {
! 1435: #ifdef DIAGNOSTIC
! 1436: printf("%s: %s: dying\n", sc->sc_dev.dv_xname,
! 1437: __func__);
! 1438: #endif
! 1439: return (0);
! 1440: }
! 1441:
! 1442: /* XXX: one PHY only for the RTL8150 internal PHY */
! 1443: if (phy != 0) {
! 1444: DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n",
! 1445: sc->sc_dev.dv_xname, __func__, phy));
! 1446: return (0);
! 1447: }
! 1448:
! 1449: url_lock_mii(sc);
! 1450:
! 1451: switch (reg) {
! 1452: case MII_BMCR: /* Control Register */
! 1453: reg = URL_BMCR;
! 1454: break;
! 1455: case MII_BMSR: /* Status Register */
! 1456: reg = URL_BMSR;
! 1457: break;
! 1458: case MII_PHYIDR1:
! 1459: case MII_PHYIDR2:
! 1460: val = 0;
! 1461: goto R_DONE;
! 1462: break;
! 1463: case MII_ANAR: /* Autonegotiation advertisement */
! 1464: reg = URL_ANAR;
! 1465: break;
! 1466: case MII_ANLPAR: /* Autonegotiation link partner abilities */
! 1467: reg = URL_ANLP;
! 1468: break;
! 1469: case URLPHY_MSR: /* Media Status Register */
! 1470: reg = URL_MSR;
! 1471: break;
! 1472: default:
! 1473: printf("%s: %s: bad register %04x\n",
! 1474: sc->sc_dev.dv_xname, __func__, reg);
! 1475: val = 0;
! 1476: goto R_DONE;
! 1477: break;
! 1478: }
! 1479:
! 1480: if (reg == URL_MSR)
! 1481: val = url_csr_read_1(sc, reg);
! 1482: else
! 1483: val = url_csr_read_2(sc, reg);
! 1484:
! 1485: R_DONE:
! 1486: DPRINTFN(0xff, ("%s: %s: phy=%d reg=0x%04x => 0x%04x\n",
! 1487: sc->sc_dev.dv_xname, __func__, phy, reg, val));
! 1488:
! 1489: url_unlock_mii(sc);
! 1490: return (val);
! 1491: }
! 1492:
! 1493: void
! 1494: url_int_miibus_writereg(struct device *dev, int phy, int reg, int data)
! 1495: {
! 1496: struct url_softc *sc;
! 1497:
! 1498: if (dev == NULL)
! 1499: return;
! 1500:
! 1501: sc = (void *)dev;
! 1502:
! 1503: DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x data=0x%04x\n",
! 1504: sc->sc_dev.dv_xname, __func__, phy, reg, data));
! 1505:
! 1506: if (sc->sc_dying) {
! 1507: #ifdef DIAGNOSTIC
! 1508: printf("%s: %s: dying\n", sc->sc_dev.dv_xname,
! 1509: __func__);
! 1510: #endif
! 1511: return;
! 1512: }
! 1513:
! 1514: /* XXX: one PHY only for the RTL8150 internal PHY */
! 1515: if (phy != 0) {
! 1516: DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n",
! 1517: sc->sc_dev.dv_xname, __func__, phy));
! 1518: return;
! 1519: }
! 1520:
! 1521: url_lock_mii(sc);
! 1522:
! 1523: switch (reg) {
! 1524: case MII_BMCR: /* Control Register */
! 1525: reg = URL_BMCR;
! 1526: break;
! 1527: case MII_BMSR: /* Status Register */
! 1528: reg = URL_BMSR;
! 1529: break;
! 1530: case MII_PHYIDR1:
! 1531: case MII_PHYIDR2:
! 1532: goto W_DONE;
! 1533: break;
! 1534: case MII_ANAR: /* Autonegotiation advertisement */
! 1535: reg = URL_ANAR;
! 1536: break;
! 1537: case MII_ANLPAR: /* Autonegotiation link partner abilities */
! 1538: reg = URL_ANLP;
! 1539: break;
! 1540: case URLPHY_MSR: /* Media Status Register */
! 1541: reg = URL_MSR;
! 1542: break;
! 1543: default:
! 1544: printf("%s: %s: bad register %04x\n",
! 1545: sc->sc_dev.dv_xname, __func__, reg);
! 1546: goto W_DONE;
! 1547: break;
! 1548: }
! 1549:
! 1550: if (reg == URL_MSR)
! 1551: url_csr_write_1(sc, reg, data);
! 1552: else
! 1553: url_csr_write_2(sc, reg, data);
! 1554: W_DONE:
! 1555:
! 1556: url_unlock_mii(sc);
! 1557: return;
! 1558: }
! 1559:
! 1560: void
! 1561: url_miibus_statchg(struct device *dev)
! 1562: {
! 1563: #ifdef URL_DEBUG
! 1564: struct url_softc *sc;
! 1565:
! 1566: if (dev == NULL)
! 1567: return;
! 1568:
! 1569: sc = (void *)dev;
! 1570: DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
! 1571: #endif
! 1572: /* Nothing to do */
! 1573: }
! 1574:
! 1575: #if 0
! 1576: /*
! 1577: * external PHYs support, but not test.
! 1578: */
! 1579: int
! 1580: url_ext_miibus_redreg(struct device *dev, int phy, int reg)
! 1581: {
! 1582: struct url_softc *sc = (void *)dev;
! 1583: u_int16_t val;
! 1584:
! 1585: DPRINTF(("%s: %s: enter, phy=%d reg=0x%04x\n",
! 1586: sc->sc_dev.dv_xname, __func__, phy, reg));
! 1587:
! 1588: if (sc->sc_dying) {
! 1589: #ifdef DIAGNOSTIC
! 1590: printf("%s: %s: dying\n", sc->sc_dev.dv_xname,
! 1591: __func__);
! 1592: #endif
! 1593: return (0);
! 1594: }
! 1595:
! 1596: url_lock_mii(sc);
! 1597:
! 1598: url_csr_write_1(sc, URL_PHYADD, phy & URL_PHYADD_MASK);
! 1599: /*
! 1600: * RTL8150L will initiate a MII management data transaction
! 1601: * if PHYCNT_OWN bit is set 1 by software. After transaction,
! 1602: * this bit is auto cleared by TRL8150L.
! 1603: */
! 1604: url_csr_write_1(sc, URL_PHYCNT,
! 1605: (reg | URL_PHYCNT_PHYOWN) & ~URL_PHYCNT_RWCR);
! 1606: for (i = 0; i < URL_TIMEOUT; i++) {
! 1607: if ((url_csr_read_1(sc, URL_PHYCNT) & URL_PHYCNT_PHYOWN) == 0)
! 1608: break;
! 1609: }
! 1610: if (i == URL_TIMEOUT) {
! 1611: printf("%s: MII read timed out\n", sc->sc_dev.dv_xname);
! 1612: }
! 1613:
! 1614: val = url_csr_read_2(sc, URL_PHYDAT);
! 1615:
! 1616: DPRINTF(("%s: %s: phy=%d reg=0x%04x => 0x%04x\n",
! 1617: sc->sc_dev.dv_xname, __func__, phy, reg, val));
! 1618:
! 1619: url_unlock_mii(sc);
! 1620: return (val);
! 1621: }
! 1622:
! 1623: void
! 1624: url_ext_miibus_writereg(struct device *dev, int phy, int reg, int data)
! 1625: {
! 1626: struct url_softc *sc = (void *)dev;
! 1627:
! 1628: DPRINTF(("%s: %s: enter, phy=%d reg=0x%04x data=0x%04x\n",
! 1629: sc->sc_dev.dv_xname, __func__, phy, reg, data));
! 1630:
! 1631: if (sc->sc_dying) {
! 1632: #ifdef DIAGNOSTIC
! 1633: printf("%s: %s: dying\n", sc->sc_dev.dv_xname,
! 1634: __func__);
! 1635: #endif
! 1636: return;
! 1637: }
! 1638:
! 1639: url_lock_mii(sc);
! 1640:
! 1641: url_csr_write_2(sc, URL_PHYDAT, data);
! 1642: url_csr_write_1(sc, URL_PHYADD, phy);
! 1643: url_csr_write_1(sc, URL_PHYCNT, reg | URL_PHYCNT_RWCR); /* Write */
! 1644:
! 1645: for (i=0; i < URL_TIMEOUT; i++) {
! 1646: if (url_csr_read_1(sc, URL_PHYCNT) & URL_PHYCNT_PHYOWN)
! 1647: break;
! 1648: }
! 1649:
! 1650: if (i == URL_TIMEOUT) {
! 1651: printf("%s: MII write timed out\n",
! 1652: sc->sc_dev.dv_xname);
! 1653: }
! 1654:
! 1655: url_unlock_mii(sc);
! 1656: return;
! 1657: }
! 1658: #endif
! 1659:
CVSweb