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