Annotation of sys/dev/usb/if_cue.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_cue.c,v 1.45 2007/06/14 10:11:15 mbalmer Exp $ */
! 2: /* $NetBSD: if_cue.c,v 1.40 2002/07/11 21:14:26 augustss Exp $ */
! 3: /*
! 4: * Copyright (c) 1997, 1998, 1999, 2000
! 5: * Bill Paul <wpaul@ee.columbia.edu>. 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. All advertising materials mentioning features or use of this software
! 16: * must display the following acknowledgement:
! 17: * This product includes software developed by Bill Paul.
! 18: * 4. Neither the name of the author nor the names of any co-contributors
! 19: * may be used to endorse or promote products derived from this software
! 20: * without specific prior written permission.
! 21: *
! 22: * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
! 23: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 24: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 25: * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
! 26: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 27: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 28: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 29: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 30: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 31: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
! 32: * THE POSSIBILITY OF SUCH DAMAGE.
! 33: *
! 34: * $FreeBSD: src/sys/dev/usb/if_cue.c,v 1.4 2000/01/16 22:45:06 wpaul Exp $
! 35: */
! 36:
! 37: /*
! 38: * CATC USB-EL1210A USB to ethernet driver. Used in the CATC Netmate
! 39: * adapters and others.
! 40: *
! 41: * Written by Bill Paul <wpaul@ee.columbia.edu>
! 42: * Electrical Engineering Department
! 43: * Columbia University, New York City
! 44: */
! 45:
! 46: /*
! 47: * The CATC USB-EL1210A provides USB ethernet support at 10Mbps. The
! 48: * RX filter uses a 512-bit multicast hash table, single perfect entry
! 49: * for the station address, and promiscuous mode. Unlike the ADMtek
! 50: * and KLSI chips, the CATC ASIC supports read and write combining
! 51: * mode where multiple packets can be transferred using a single bulk
! 52: * transaction, which helps performance a great deal.
! 53: */
! 54:
! 55: /*
! 56: * Ported to NetBSD and somewhat rewritten by Lennart Augustsson.
! 57: */
! 58:
! 59: #include "bpfilter.h"
! 60:
! 61: #include <sys/param.h>
! 62: #include <sys/systm.h>
! 63: #include <sys/sockio.h>
! 64: #include <sys/mbuf.h>
! 65: #include <sys/malloc.h>
! 66: #include <sys/kernel.h>
! 67: #include <sys/socket.h>
! 68: #include <sys/timeout.h>
! 69: #include <sys/device.h>
! 70:
! 71: #include <net/if.h>
! 72: #include <net/if_dl.h>
! 73:
! 74: #if NBPFILTER > 0
! 75: #include <net/bpf.h>
! 76: #endif
! 77:
! 78: #ifdef INET
! 79: #include <netinet/in.h>
! 80: #include <netinet/in_systm.h>
! 81: #include <netinet/in_var.h>
! 82: #include <netinet/ip.h>
! 83: #include <netinet/if_ether.h>
! 84: #endif
! 85:
! 86: #include <dev/usb/usb.h>
! 87: #include <dev/usb/usbdi.h>
! 88: #include <dev/usb/usbdi_util.h>
! 89: #include <dev/usb/usbdevs.h>
! 90:
! 91: #include <dev/usb/if_cuereg.h>
! 92:
! 93: #ifdef CUE_DEBUG
! 94: #define DPRINTF(x) do { if (cuedebug) printf x; } while (0)
! 95: #define DPRINTFN(n,x) do { if (cuedebug >= (n)) printf x; } while (0)
! 96: int cuedebug = 0;
! 97: #else
! 98: #define DPRINTF(x)
! 99: #define DPRINTFN(n,x)
! 100: #endif
! 101:
! 102: /*
! 103: * Various supported device vendors/products.
! 104: */
! 105: struct usb_devno cue_devs[] = {
! 106: { USB_VENDOR_CATC, USB_PRODUCT_CATC_NETMATE },
! 107: { USB_VENDOR_CATC, USB_PRODUCT_CATC_NETMATE2 },
! 108: { USB_VENDOR_SMARTBRIDGES, USB_PRODUCT_SMARTBRIDGES_SMARTLINK },
! 109: /* Belkin F5U111 adapter covered by NETMATE entry */
! 110: };
! 111: #define cue_lookup(v, p) (usb_lookup(cue_devs, v, p))
! 112:
! 113: int cue_match(struct device *, void *, void *);
! 114: void cue_attach(struct device *, struct device *, void *);
! 115: int cue_detach(struct device *, int);
! 116: int cue_activate(struct device *, enum devact);
! 117:
! 118: struct cfdriver cue_cd = {
! 119: NULL, "cue", DV_IFNET
! 120: };
! 121:
! 122: const struct cfattach cue_ca = {
! 123: sizeof(struct cue_softc),
! 124: cue_match,
! 125: cue_attach,
! 126: cue_detach,
! 127: cue_activate,
! 128: };
! 129:
! 130: int cue_open_pipes(struct cue_softc *);
! 131: int cue_tx_list_init(struct cue_softc *);
! 132: int cue_rx_list_init(struct cue_softc *);
! 133: int cue_newbuf(struct cue_softc *, struct cue_chain *, struct mbuf *);
! 134: int cue_send(struct cue_softc *, struct mbuf *, int);
! 135: void cue_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
! 136: void cue_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
! 137: void cue_tick(void *);
! 138: void cue_tick_task(void *);
! 139: void cue_start(struct ifnet *);
! 140: int cue_ioctl(struct ifnet *, u_long, caddr_t);
! 141: void cue_init(void *);
! 142: void cue_stop(struct cue_softc *);
! 143: void cue_watchdog(struct ifnet *);
! 144:
! 145: void cue_setmulti(struct cue_softc *);
! 146: void cue_reset(struct cue_softc *);
! 147:
! 148: int cue_csr_read_1(struct cue_softc *, int);
! 149: int cue_csr_write_1(struct cue_softc *, int, int);
! 150: int cue_csr_read_2(struct cue_softc *, int);
! 151: #if 0
! 152: int cue_csr_write_2(struct cue_softc *, int, int);
! 153: #endif
! 154: int cue_mem(struct cue_softc *, int, int, void *, int);
! 155: int cue_getmac(struct cue_softc *, void *);
! 156:
! 157: #define CUE_SETBIT(sc, reg, x) \
! 158: cue_csr_write_1(sc, reg, cue_csr_read_1(sc, reg) | (x))
! 159:
! 160: #define CUE_CLRBIT(sc, reg, x) \
! 161: cue_csr_write_1(sc, reg, cue_csr_read_1(sc, reg) & ~(x))
! 162:
! 163: int
! 164: cue_csr_read_1(struct cue_softc *sc, int reg)
! 165: {
! 166: usb_device_request_t req;
! 167: usbd_status err;
! 168: u_int8_t val = 0;
! 169:
! 170: if (sc->cue_dying)
! 171: return (0);
! 172:
! 173: req.bmRequestType = UT_READ_VENDOR_DEVICE;
! 174: req.bRequest = CUE_CMD_READREG;
! 175: USETW(req.wValue, 0);
! 176: USETW(req.wIndex, reg);
! 177: USETW(req.wLength, 1);
! 178:
! 179: err = usbd_do_request(sc->cue_udev, &req, &val);
! 180:
! 181: if (err) {
! 182: DPRINTF(("%s: cue_csr_read_1: reg=0x%x err=%s\n",
! 183: sc->cue_dev.dv_xname, reg, usbd_errstr(err)));
! 184: return (0);
! 185: }
! 186:
! 187: DPRINTFN(10,("%s: cue_csr_read_1 reg=0x%x val=0x%x\n",
! 188: sc->cue_dev.dv_xname, reg, val));
! 189:
! 190: return (val);
! 191: }
! 192:
! 193: int
! 194: cue_csr_read_2(struct cue_softc *sc, int reg)
! 195: {
! 196: usb_device_request_t req;
! 197: usbd_status err;
! 198: uWord val;
! 199:
! 200: if (sc->cue_dying)
! 201: return (0);
! 202:
! 203: req.bmRequestType = UT_READ_VENDOR_DEVICE;
! 204: req.bRequest = CUE_CMD_READREG;
! 205: USETW(req.wValue, 0);
! 206: USETW(req.wIndex, reg);
! 207: USETW(req.wLength, 2);
! 208:
! 209: err = usbd_do_request(sc->cue_udev, &req, &val);
! 210:
! 211: DPRINTFN(10,("%s: cue_csr_read_2 reg=0x%x val=0x%x\n",
! 212: sc->cue_dev.dv_xname, reg, UGETW(val)));
! 213:
! 214: if (err) {
! 215: DPRINTF(("%s: cue_csr_read_2: reg=0x%x err=%s\n",
! 216: sc->cue_dev.dv_xname, reg, usbd_errstr(err)));
! 217: return (0);
! 218: }
! 219:
! 220: return (UGETW(val));
! 221: }
! 222:
! 223: int
! 224: cue_csr_write_1(struct cue_softc *sc, int reg, int val)
! 225: {
! 226: usb_device_request_t req;
! 227: usbd_status err;
! 228:
! 229: if (sc->cue_dying)
! 230: return (0);
! 231:
! 232: DPRINTFN(10,("%s: cue_csr_write_1 reg=0x%x val=0x%x\n",
! 233: sc->cue_dev.dv_xname, reg, val));
! 234:
! 235: req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
! 236: req.bRequest = CUE_CMD_WRITEREG;
! 237: USETW(req.wValue, val);
! 238: USETW(req.wIndex, reg);
! 239: USETW(req.wLength, 0);
! 240:
! 241: err = usbd_do_request(sc->cue_udev, &req, NULL);
! 242:
! 243: if (err) {
! 244: DPRINTF(("%s: cue_csr_write_1: reg=0x%x err=%s\n",
! 245: sc->cue_dev.dv_xname, reg, usbd_errstr(err)));
! 246: return (-1);
! 247: }
! 248:
! 249: DPRINTFN(20,("%s: cue_csr_write_1, after reg=0x%x val=0x%x\n",
! 250: sc->cue_dev.dv_xname, reg, cue_csr_read_1(sc, reg)));
! 251:
! 252: return (0);
! 253: }
! 254:
! 255: #if 0
! 256: int
! 257: cue_csr_write_2(struct cue_softc *sc, int reg, int aval)
! 258: {
! 259: usb_device_request_t req;
! 260: usbd_status err;
! 261: uWord val;
! 262: int s;
! 263:
! 264: if (sc->cue_dying)
! 265: return (0);
! 266:
! 267: DPRINTFN(10,("%s: cue_csr_write_2 reg=0x%x val=0x%x\n",
! 268: sc->cue_dev.dv_xname, reg, aval));
! 269:
! 270: USETW(val, aval);
! 271: req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
! 272: req.bRequest = CUE_CMD_WRITEREG;
! 273: USETW(req.wValue, val);
! 274: USETW(req.wIndex, reg);
! 275: USETW(req.wLength, 0);
! 276:
! 277: err = usbd_do_request(sc->cue_udev, &req, NULL);
! 278:
! 279: if (err) {
! 280: DPRINTF(("%s: cue_csr_write_2: reg=0x%x err=%s\n",
! 281: sc->cue_dev.dv_xname, reg, usbd_errstr(err)));
! 282: return (-1);
! 283: }
! 284:
! 285: return (0);
! 286: }
! 287: #endif
! 288:
! 289: int
! 290: cue_mem(struct cue_softc *sc, int cmd, int addr, void *buf, int len)
! 291: {
! 292: usb_device_request_t req;
! 293: usbd_status err;
! 294:
! 295: DPRINTFN(10,("%s: cue_mem cmd=0x%x addr=0x%x len=%d\n",
! 296: sc->cue_dev.dv_xname, cmd, addr, len));
! 297:
! 298: if (cmd == CUE_CMD_READSRAM)
! 299: req.bmRequestType = UT_READ_VENDOR_DEVICE;
! 300: else
! 301: req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
! 302: req.bRequest = cmd;
! 303: USETW(req.wValue, 0);
! 304: USETW(req.wIndex, addr);
! 305: USETW(req.wLength, len);
! 306:
! 307: err = usbd_do_request(sc->cue_udev, &req, buf);
! 308:
! 309: if (err) {
! 310: DPRINTF(("%s: cue_csr_mem: addr=0x%x err=%s\n",
! 311: sc->cue_dev.dv_xname, addr, usbd_errstr(err)));
! 312: return (-1);
! 313: }
! 314:
! 315: return (0);
! 316: }
! 317:
! 318: int
! 319: cue_getmac(struct cue_softc *sc, void *buf)
! 320: {
! 321: usb_device_request_t req;
! 322: usbd_status err;
! 323:
! 324: DPRINTFN(10,("%s: cue_getmac\n", sc->cue_dev.dv_xname));
! 325:
! 326: req.bmRequestType = UT_READ_VENDOR_DEVICE;
! 327: req.bRequest = CUE_CMD_GET_MACADDR;
! 328: USETW(req.wValue, 0);
! 329: USETW(req.wIndex, 0);
! 330: USETW(req.wLength, ETHER_ADDR_LEN);
! 331:
! 332: err = usbd_do_request(sc->cue_udev, &req, buf);
! 333:
! 334: if (err) {
! 335: printf("%s: read MAC address failed\n",
! 336: sc->cue_dev.dv_xname);
! 337: return (-1);
! 338: }
! 339:
! 340: return (0);
! 341: }
! 342:
! 343: #define CUE_BITS 9
! 344:
! 345: void
! 346: cue_setmulti(struct cue_softc *sc)
! 347: {
! 348: struct ifnet *ifp;
! 349: struct ether_multi *enm;
! 350: struct ether_multistep step;
! 351: u_int32_t h, i;
! 352:
! 353: ifp = GET_IFP(sc);
! 354:
! 355: DPRINTFN(2,("%s: cue_setmulti if_flags=0x%x\n",
! 356: sc->cue_dev.dv_xname, ifp->if_flags));
! 357:
! 358: if (ifp->if_flags & IFF_PROMISC) {
! 359: allmulti:
! 360: ifp->if_flags |= IFF_ALLMULTI;
! 361: for (i = 0; i < CUE_MCAST_TABLE_LEN; i++)
! 362: sc->cue_mctab[i] = 0xFF;
! 363: cue_mem(sc, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR,
! 364: &sc->cue_mctab, CUE_MCAST_TABLE_LEN);
! 365: return;
! 366: }
! 367:
! 368: /* first, zot all the existing hash bits */
! 369: for (i = 0; i < CUE_MCAST_TABLE_LEN; i++)
! 370: sc->cue_mctab[i] = 0;
! 371:
! 372: /* now program new ones */
! 373: ETHER_FIRST_MULTI(step, &sc->arpcom, enm);
! 374: while (enm != NULL) {
! 375: if (memcmp(enm->enm_addrlo,
! 376: enm->enm_addrhi, ETHER_ADDR_LEN) != 0)
! 377: goto allmulti;
! 378:
! 379: h = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN) &
! 380: ((1 << CUE_BITS) - 1);
! 381: sc->cue_mctab[h >> 3] |= 1 << (h & 0x7);
! 382: ETHER_NEXT_MULTI(step, enm);
! 383: }
! 384:
! 385: ifp->if_flags &= ~IFF_ALLMULTI;
! 386:
! 387: /*
! 388: * Also include the broadcast address in the filter
! 389: * so we can receive broadcast frames.
! 390: */
! 391: if (ifp->if_flags & IFF_BROADCAST) {
! 392: h = ether_crc32_le(etherbroadcastaddr, ETHER_ADDR_LEN) &
! 393: ((1 << CUE_BITS) - 1);
! 394: sc->cue_mctab[h >> 3] |= 1 << (h & 0x7);
! 395: }
! 396:
! 397: cue_mem(sc, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR,
! 398: &sc->cue_mctab, CUE_MCAST_TABLE_LEN);
! 399: }
! 400:
! 401: void
! 402: cue_reset(struct cue_softc *sc)
! 403: {
! 404: usb_device_request_t req;
! 405: usbd_status err;
! 406:
! 407: DPRINTFN(2,("%s: cue_reset\n", sc->cue_dev.dv_xname));
! 408:
! 409: if (sc->cue_dying)
! 410: return;
! 411:
! 412: req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
! 413: req.bRequest = CUE_CMD_RESET;
! 414: USETW(req.wValue, 0);
! 415: USETW(req.wIndex, 0);
! 416: USETW(req.wLength, 0);
! 417:
! 418: err = usbd_do_request(sc->cue_udev, &req, NULL);
! 419:
! 420: if (err)
! 421: printf("%s: reset failed\n", sc->cue_dev.dv_xname);
! 422:
! 423: /* Wait a little while for the chip to get its brains in order. */
! 424: usbd_delay_ms(sc->cue_udev, 1);
! 425: }
! 426:
! 427: /*
! 428: * Probe for a CATC chip.
! 429: */
! 430: int
! 431: cue_match(struct device *parent, void *match, void *aux)
! 432: {
! 433: struct usb_attach_arg *uaa = aux;
! 434:
! 435: if (uaa->iface != NULL)
! 436: return (UMATCH_NONE);
! 437:
! 438: return (cue_lookup(uaa->vendor, uaa->product) != NULL ?
! 439: UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
! 440: }
! 441:
! 442: /*
! 443: * Attach the interface. Allocate softc structures, do ifmedia
! 444: * setup and ethernet/BPF attach.
! 445: */
! 446: void
! 447: cue_attach(struct device *parent, struct device *self, void *aux)
! 448: {
! 449: struct cue_softc *sc = (struct cue_softc *)self;
! 450: struct usb_attach_arg *uaa = aux;
! 451: char *devinfop;
! 452: int s;
! 453: u_char eaddr[ETHER_ADDR_LEN];
! 454: usbd_device_handle dev = uaa->device;
! 455: usbd_interface_handle iface;
! 456: usbd_status err;
! 457: struct ifnet *ifp;
! 458: usb_interface_descriptor_t *id;
! 459: usb_endpoint_descriptor_t *ed;
! 460: int i;
! 461:
! 462: DPRINTFN(5,(" : cue_attach: sc=%p, dev=%p", sc, dev));
! 463:
! 464: devinfop = usbd_devinfo_alloc(dev, 0);
! 465: printf("\n%s: %s\n", sc->cue_dev.dv_xname, devinfop);
! 466: usbd_devinfo_free(devinfop);
! 467:
! 468: err = usbd_set_config_no(dev, CUE_CONFIG_NO, 1);
! 469: if (err) {
! 470: printf("%s: setting config no failed\n",
! 471: sc->cue_dev.dv_xname);
! 472: return;
! 473: }
! 474:
! 475: sc->cue_udev = dev;
! 476: sc->cue_product = uaa->product;
! 477: sc->cue_vendor = uaa->vendor;
! 478:
! 479: usb_init_task(&sc->cue_tick_task, cue_tick_task, sc);
! 480: usb_init_task(&sc->cue_stop_task, (void (*)(void *))cue_stop, sc);
! 481:
! 482: err = usbd_device2interface_handle(dev, CUE_IFACE_IDX, &iface);
! 483: if (err) {
! 484: printf("%s: getting interface handle failed\n",
! 485: sc->cue_dev.dv_xname);
! 486: return;
! 487: }
! 488:
! 489: sc->cue_iface = iface;
! 490: id = usbd_get_interface_descriptor(iface);
! 491:
! 492: /* Find endpoints. */
! 493: for (i = 0; i < id->bNumEndpoints; i++) {
! 494: ed = usbd_interface2endpoint_descriptor(iface, i);
! 495: if (ed == NULL) {
! 496: printf("%s: couldn't get ep %d\n",
! 497: sc->cue_dev.dv_xname, i);
! 498: return;
! 499: }
! 500: if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
! 501: UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
! 502: sc->cue_ed[CUE_ENDPT_RX] = ed->bEndpointAddress;
! 503: } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
! 504: UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
! 505: sc->cue_ed[CUE_ENDPT_TX] = ed->bEndpointAddress;
! 506: } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
! 507: UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
! 508: sc->cue_ed[CUE_ENDPT_INTR] = ed->bEndpointAddress;
! 509: }
! 510: }
! 511:
! 512: #if 0
! 513: /* Reset the adapter. */
! 514: cue_reset(sc);
! 515: #endif
! 516: /*
! 517: * Get station address.
! 518: */
! 519: cue_getmac(sc, &eaddr);
! 520:
! 521: s = splnet();
! 522:
! 523: /*
! 524: * A CATC chip was detected. Inform the world.
! 525: */
! 526: printf("%s: address %s\n", sc->cue_dev.dv_xname,
! 527: ether_sprintf(eaddr));
! 528:
! 529: bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
! 530:
! 531: /* Initialize interface info.*/
! 532: ifp = GET_IFP(sc);
! 533: ifp->if_softc = sc;
! 534: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
! 535: ifp->if_ioctl = cue_ioctl;
! 536: ifp->if_start = cue_start;
! 537: ifp->if_watchdog = cue_watchdog;
! 538: strlcpy(ifp->if_xname, sc->cue_dev.dv_xname, IFNAMSIZ);
! 539:
! 540: IFQ_SET_READY(&ifp->if_snd);
! 541:
! 542: /* Attach the interface. */
! 543: if_attach(ifp);
! 544: ether_ifattach(ifp);
! 545:
! 546: timeout_set(&sc->cue_stat_ch, NULL, NULL);
! 547:
! 548: sc->cue_attached = 1;
! 549: splx(s);
! 550:
! 551: usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->cue_udev,
! 552: &sc->cue_dev);
! 553: }
! 554:
! 555: int
! 556: cue_detach(struct device *self, int flags)
! 557: {
! 558: struct cue_softc *sc = (struct cue_softc *)self;
! 559: struct ifnet *ifp = GET_IFP(sc);
! 560: int s;
! 561:
! 562: DPRINTFN(2,("%s: %s: enter\n", sc->cue_dev.dv_xname, __func__));
! 563:
! 564: timeout_del(&sc->cue_stat_ch);
! 565: /*
! 566: * Remove any pending task. It cannot be executing because it run
! 567: * in the same thread as detach.
! 568: */
! 569: usb_rem_task(sc->cue_udev, &sc->cue_tick_task);
! 570: usb_rem_task(sc->cue_udev, &sc->cue_stop_task);
! 571:
! 572: if (!sc->cue_attached) {
! 573: /* Detached before attached finished, so just bail out. */
! 574: return (0);
! 575: }
! 576:
! 577: s = splusb();
! 578:
! 579: if (ifp->if_flags & IFF_RUNNING)
! 580: cue_stop(sc);
! 581:
! 582: ether_ifdetach(ifp);
! 583:
! 584: if_detach(ifp);
! 585:
! 586: #ifdef DIAGNOSTIC
! 587: if (sc->cue_ep[CUE_ENDPT_TX] != NULL ||
! 588: sc->cue_ep[CUE_ENDPT_RX] != NULL ||
! 589: sc->cue_ep[CUE_ENDPT_INTR] != NULL)
! 590: printf("%s: detach has active endpoints\n",
! 591: sc->cue_dev.dv_xname);
! 592: #endif
! 593:
! 594: sc->cue_attached = 0;
! 595: splx(s);
! 596:
! 597: usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->cue_udev,
! 598: &sc->cue_dev);
! 599:
! 600: return (0);
! 601: }
! 602:
! 603: int
! 604: cue_activate(struct device *self, enum devact act)
! 605: {
! 606: struct cue_softc *sc = (struct cue_softc *)self;
! 607:
! 608: DPRINTFN(2,("%s: %s: enter\n", sc->cue_dev.dv_xname, __func__));
! 609:
! 610: switch (act) {
! 611: case DVACT_ACTIVATE:
! 612: break;
! 613:
! 614: case DVACT_DEACTIVATE:
! 615: sc->cue_dying = 1;
! 616: break;
! 617: }
! 618: return (0);
! 619: }
! 620:
! 621: /*
! 622: * Initialize an RX descriptor and attach an MBUF cluster.
! 623: */
! 624: int
! 625: cue_newbuf(struct cue_softc *sc, struct cue_chain *c, struct mbuf *m)
! 626: {
! 627: struct mbuf *m_new = NULL;
! 628:
! 629: if (m == NULL) {
! 630: MGETHDR(m_new, M_DONTWAIT, MT_DATA);
! 631: if (m_new == NULL) {
! 632: printf("%s: no memory for rx list "
! 633: "-- packet dropped!\n", sc->cue_dev.dv_xname);
! 634: return (ENOBUFS);
! 635: }
! 636:
! 637: MCLGET(m_new, M_DONTWAIT);
! 638: if (!(m_new->m_flags & M_EXT)) {
! 639: printf("%s: no memory for rx list "
! 640: "-- packet dropped!\n", sc->cue_dev.dv_xname);
! 641: m_freem(m_new);
! 642: return (ENOBUFS);
! 643: }
! 644: m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
! 645: } else {
! 646: m_new = m;
! 647: m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
! 648: m_new->m_data = m_new->m_ext.ext_buf;
! 649: }
! 650:
! 651: m_adj(m_new, ETHER_ALIGN);
! 652: c->cue_mbuf = m_new;
! 653:
! 654: return (0);
! 655: }
! 656:
! 657: int
! 658: cue_rx_list_init(struct cue_softc *sc)
! 659: {
! 660: struct cue_cdata *cd;
! 661: struct cue_chain *c;
! 662: int i;
! 663:
! 664: cd = &sc->cue_cdata;
! 665: for (i = 0; i < CUE_RX_LIST_CNT; i++) {
! 666: c = &cd->cue_rx_chain[i];
! 667: c->cue_sc = sc;
! 668: c->cue_idx = i;
! 669: if (cue_newbuf(sc, c, NULL) == ENOBUFS)
! 670: return (ENOBUFS);
! 671: if (c->cue_xfer == NULL) {
! 672: c->cue_xfer = usbd_alloc_xfer(sc->cue_udev);
! 673: if (c->cue_xfer == NULL)
! 674: return (ENOBUFS);
! 675: c->cue_buf = usbd_alloc_buffer(c->cue_xfer, CUE_BUFSZ);
! 676: if (c->cue_buf == NULL) {
! 677: usbd_free_xfer(c->cue_xfer);
! 678: return (ENOBUFS);
! 679: }
! 680: }
! 681: }
! 682:
! 683: return (0);
! 684: }
! 685:
! 686: int
! 687: cue_tx_list_init(struct cue_softc *sc)
! 688: {
! 689: struct cue_cdata *cd;
! 690: struct cue_chain *c;
! 691: int i;
! 692:
! 693: cd = &sc->cue_cdata;
! 694: for (i = 0; i < CUE_TX_LIST_CNT; i++) {
! 695: c = &cd->cue_tx_chain[i];
! 696: c->cue_sc = sc;
! 697: c->cue_idx = i;
! 698: c->cue_mbuf = NULL;
! 699: if (c->cue_xfer == NULL) {
! 700: c->cue_xfer = usbd_alloc_xfer(sc->cue_udev);
! 701: if (c->cue_xfer == NULL)
! 702: return (ENOBUFS);
! 703: c->cue_buf = usbd_alloc_buffer(c->cue_xfer, CUE_BUFSZ);
! 704: if (c->cue_buf == NULL) {
! 705: usbd_free_xfer(c->cue_xfer);
! 706: return (ENOBUFS);
! 707: }
! 708: }
! 709: }
! 710:
! 711: return (0);
! 712: }
! 713:
! 714: /*
! 715: * A frame has been uploaded: pass the resulting mbuf chain up to
! 716: * the higher level protocols.
! 717: */
! 718: void
! 719: cue_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
! 720: {
! 721: struct cue_chain *c = priv;
! 722: struct cue_softc *sc = c->cue_sc;
! 723: struct ifnet *ifp = GET_IFP(sc);
! 724: struct mbuf *m;
! 725: int total_len = 0;
! 726: u_int16_t len;
! 727: int s;
! 728:
! 729: DPRINTFN(10,("%s: %s: enter status=%d\n", sc->cue_dev.dv_xname,
! 730: __func__, status));
! 731:
! 732: if (sc->cue_dying)
! 733: return;
! 734:
! 735: if (!(ifp->if_flags & IFF_RUNNING))
! 736: return;
! 737:
! 738: if (status != USBD_NORMAL_COMPLETION) {
! 739: if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
! 740: return;
! 741: sc->cue_rx_errs++;
! 742: if (usbd_ratecheck(&sc->cue_rx_notice)) {
! 743: printf("%s: %u usb errors on rx: %s\n",
! 744: sc->cue_dev.dv_xname, sc->cue_rx_errs,
! 745: usbd_errstr(status));
! 746: sc->cue_rx_errs = 0;
! 747: }
! 748: if (status == USBD_STALLED)
! 749: usbd_clear_endpoint_stall_async(sc->cue_ep[CUE_ENDPT_RX]);
! 750: goto done;
! 751: }
! 752:
! 753: usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
! 754:
! 755: memcpy(mtod(c->cue_mbuf, char *), c->cue_buf, total_len);
! 756:
! 757: m = c->cue_mbuf;
! 758: len = UGETW(mtod(m, u_int8_t *));
! 759:
! 760: /* No errors; receive the packet. */
! 761: total_len = len;
! 762:
! 763: if (len < sizeof(struct ether_header)) {
! 764: ifp->if_ierrors++;
! 765: goto done;
! 766: }
! 767:
! 768: ifp->if_ipackets++;
! 769: m_adj(m, sizeof(u_int16_t));
! 770: m->m_pkthdr.len = m->m_len = total_len;
! 771:
! 772: m->m_pkthdr.rcvif = ifp;
! 773:
! 774: s = splnet();
! 775:
! 776: /* XXX ugly */
! 777: if (cue_newbuf(sc, c, NULL) == ENOBUFS) {
! 778: ifp->if_ierrors++;
! 779: goto done1;
! 780: }
! 781:
! 782: #if NBPFILTER > 0
! 783: /*
! 784: * Handle BPF listeners. Let the BPF user see the packet, but
! 785: * don't pass it up to the ether_input() layer unless it's
! 786: * a broadcast packet, multicast packet, matches our ethernet
! 787: * address or the interface is in promiscuous mode.
! 788: */
! 789: if (ifp->if_bpf)
! 790: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
! 791: #endif
! 792:
! 793: DPRINTFN(10,("%s: %s: deliver %d\n", sc->cue_dev.dv_xname,
! 794: __func__, m->m_len));
! 795: ether_input_mbuf(ifp, m);
! 796: done1:
! 797: splx(s);
! 798:
! 799: done:
! 800: /* Setup new transfer. */
! 801: usbd_setup_xfer(c->cue_xfer, sc->cue_ep[CUE_ENDPT_RX],
! 802: c, c->cue_buf, CUE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
! 803: USBD_NO_TIMEOUT, cue_rxeof);
! 804: usbd_transfer(c->cue_xfer);
! 805:
! 806: DPRINTFN(10,("%s: %s: start rx\n", sc->cue_dev.dv_xname,
! 807: __func__));
! 808: }
! 809:
! 810: /*
! 811: * A frame was downloaded to the chip. It's safe for us to clean up
! 812: * the list buffers.
! 813: */
! 814: void
! 815: cue_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
! 816: {
! 817: struct cue_chain *c = priv;
! 818: struct cue_softc *sc = c->cue_sc;
! 819: struct ifnet *ifp = GET_IFP(sc);
! 820: int s;
! 821:
! 822: if (sc->cue_dying)
! 823: return;
! 824:
! 825: s = splnet();
! 826:
! 827: DPRINTFN(10,("%s: %s: enter status=%d\n", sc->cue_dev.dv_xname,
! 828: __func__, status));
! 829:
! 830: ifp->if_timer = 0;
! 831: ifp->if_flags &= ~IFF_OACTIVE;
! 832:
! 833: if (status != USBD_NORMAL_COMPLETION) {
! 834: if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
! 835: splx(s);
! 836: return;
! 837: }
! 838: ifp->if_oerrors++;
! 839: printf("%s: usb error on tx: %s\n", sc->cue_dev.dv_xname,
! 840: usbd_errstr(status));
! 841: if (status == USBD_STALLED)
! 842: usbd_clear_endpoint_stall_async(sc->cue_ep[CUE_ENDPT_TX]);
! 843: splx(s);
! 844: return;
! 845: }
! 846:
! 847: ifp->if_opackets++;
! 848:
! 849: m_freem(c->cue_mbuf);
! 850: c->cue_mbuf = NULL;
! 851:
! 852: if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
! 853: cue_start(ifp);
! 854:
! 855: splx(s);
! 856: }
! 857:
! 858: void
! 859: cue_tick(void *xsc)
! 860: {
! 861: struct cue_softc *sc = xsc;
! 862:
! 863: if (sc == NULL)
! 864: return;
! 865:
! 866: if (sc->cue_dying)
! 867: return;
! 868:
! 869: DPRINTFN(2,("%s: %s: enter\n", sc->cue_dev.dv_xname, __func__));
! 870:
! 871: /* Perform statistics update in process context. */
! 872: usb_add_task(sc->cue_udev, &sc->cue_tick_task);
! 873: }
! 874:
! 875: void
! 876: cue_tick_task(void *xsc)
! 877: {
! 878: struct cue_softc *sc = xsc;
! 879: struct ifnet *ifp;
! 880:
! 881: if (sc->cue_dying)
! 882: return;
! 883:
! 884: DPRINTFN(2,("%s: %s: enter\n", sc->cue_dev.dv_xname, __func__));
! 885:
! 886: ifp = GET_IFP(sc);
! 887:
! 888: ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_SINGLECOLL);
! 889: ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_MULTICOLL);
! 890: ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_EXCESSCOLL);
! 891:
! 892: if (cue_csr_read_2(sc, CUE_RX_FRAMEERR))
! 893: ifp->if_ierrors++;
! 894: }
! 895:
! 896: int
! 897: cue_send(struct cue_softc *sc, struct mbuf *m, int idx)
! 898: {
! 899: int total_len;
! 900: struct cue_chain *c;
! 901: usbd_status err;
! 902:
! 903: c = &sc->cue_cdata.cue_tx_chain[idx];
! 904:
! 905: /*
! 906: * Copy the mbuf data into a contiguous buffer, leaving two
! 907: * bytes at the beginning to hold the frame length.
! 908: */
! 909: m_copydata(m, 0, m->m_pkthdr.len, c->cue_buf + 2);
! 910: c->cue_mbuf = m;
! 911:
! 912: total_len = m->m_pkthdr.len + 2;
! 913:
! 914: DPRINTFN(10,("%s: %s: total_len=%d\n",
! 915: sc->cue_dev.dv_xname, __func__, total_len));
! 916:
! 917: /* The first two bytes are the frame length */
! 918: c->cue_buf[0] = (u_int8_t)m->m_pkthdr.len;
! 919: c->cue_buf[1] = (u_int8_t)(m->m_pkthdr.len >> 8);
! 920:
! 921: /* XXX 10000 */
! 922: usbd_setup_xfer(c->cue_xfer, sc->cue_ep[CUE_ENDPT_TX],
! 923: c, c->cue_buf, total_len, USBD_NO_COPY, 10000, cue_txeof);
! 924:
! 925: /* Transmit */
! 926: err = usbd_transfer(c->cue_xfer);
! 927: if (err != USBD_IN_PROGRESS) {
! 928: printf("%s: cue_send error=%s\n", sc->cue_dev.dv_xname,
! 929: usbd_errstr(err));
! 930: /* Stop the interface from process context. */
! 931: usb_add_task(sc->cue_udev, &sc->cue_stop_task);
! 932: return (EIO);
! 933: }
! 934:
! 935: sc->cue_cdata.cue_tx_cnt++;
! 936:
! 937: return (0);
! 938: }
! 939:
! 940: void
! 941: cue_start(struct ifnet *ifp)
! 942: {
! 943: struct cue_softc *sc = ifp->if_softc;
! 944: struct mbuf *m_head = NULL;
! 945:
! 946: if (sc->cue_dying)
! 947: return;
! 948:
! 949: DPRINTFN(10,("%s: %s: enter\n", sc->cue_dev.dv_xname,__func__));
! 950:
! 951: if (ifp->if_flags & IFF_OACTIVE)
! 952: return;
! 953:
! 954: IFQ_POLL(&ifp->if_snd, m_head);
! 955: if (m_head == NULL)
! 956: return;
! 957:
! 958: if (cue_send(sc, m_head, 0)) {
! 959: ifp->if_flags |= IFF_OACTIVE;
! 960: return;
! 961: }
! 962:
! 963: IFQ_DEQUEUE(&ifp->if_snd, m_head);
! 964:
! 965: #if NBPFILTER > 0
! 966: /*
! 967: * If there's a BPF listener, bounce a copy of this frame
! 968: * to him.
! 969: */
! 970: if (ifp->if_bpf)
! 971: bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
! 972: #endif
! 973:
! 974: ifp->if_flags |= IFF_OACTIVE;
! 975:
! 976: /*
! 977: * Set a timeout in case the chip goes out to lunch.
! 978: */
! 979: ifp->if_timer = 5;
! 980: }
! 981:
! 982: void
! 983: cue_init(void *xsc)
! 984: {
! 985: struct cue_softc *sc = xsc;
! 986: struct ifnet *ifp = GET_IFP(sc);
! 987: int i, s, ctl;
! 988: u_char *eaddr;
! 989:
! 990: if (sc->cue_dying)
! 991: return;
! 992:
! 993: DPRINTFN(10,("%s: %s: enter\n", sc->cue_dev.dv_xname,__func__));
! 994:
! 995: if (ifp->if_flags & IFF_RUNNING)
! 996: return;
! 997:
! 998: s = splnet();
! 999:
! 1000: /*
! 1001: * Cancel pending I/O and free all RX/TX buffers.
! 1002: */
! 1003: #if 1
! 1004: cue_reset(sc);
! 1005: #endif
! 1006:
! 1007: /* Set advanced operation modes. */
! 1008: cue_csr_write_1(sc, CUE_ADVANCED_OPMODES,
! 1009: CUE_AOP_EMBED_RXLEN | 0x03); /* 1 wait state */
! 1010:
! 1011: eaddr = sc->arpcom.ac_enaddr;
! 1012: /* Set MAC address */
! 1013: for (i = 0; i < ETHER_ADDR_LEN; i++)
! 1014: cue_csr_write_1(sc, CUE_PAR0 - i, eaddr[i]);
! 1015:
! 1016: /* Enable RX logic. */
! 1017: ctl = CUE_ETHCTL_RX_ON | CUE_ETHCTL_MCAST_ON;
! 1018: if (ifp->if_flags & IFF_PROMISC)
! 1019: ctl |= CUE_ETHCTL_PROMISC;
! 1020: cue_csr_write_1(sc, CUE_ETHCTL, ctl);
! 1021:
! 1022: /* Init TX ring. */
! 1023: if (cue_tx_list_init(sc) == ENOBUFS) {
! 1024: printf("%s: tx list init failed\n", sc->cue_dev.dv_xname);
! 1025: splx(s);
! 1026: return;
! 1027: }
! 1028:
! 1029: /* Init RX ring. */
! 1030: if (cue_rx_list_init(sc) == ENOBUFS) {
! 1031: printf("%s: rx list init failed\n", sc->cue_dev.dv_xname);
! 1032: splx(s);
! 1033: return;
! 1034: }
! 1035:
! 1036: /* Load the multicast filter. */
! 1037: cue_setmulti(sc);
! 1038:
! 1039: /*
! 1040: * Set the number of RX and TX buffers that we want
! 1041: * to reserve inside the ASIC.
! 1042: */
! 1043: cue_csr_write_1(sc, CUE_RX_BUFPKTS, CUE_RX_FRAMES);
! 1044: cue_csr_write_1(sc, CUE_TX_BUFPKTS, CUE_TX_FRAMES);
! 1045:
! 1046: /* Set advanced operation modes. */
! 1047: cue_csr_write_1(sc, CUE_ADVANCED_OPMODES,
! 1048: CUE_AOP_EMBED_RXLEN | 0x01); /* 1 wait state */
! 1049:
! 1050: /* Program the LED operation. */
! 1051: cue_csr_write_1(sc, CUE_LEDCTL, CUE_LEDCTL_FOLLOW_LINK);
! 1052:
! 1053: if (sc->cue_ep[CUE_ENDPT_RX] == NULL) {
! 1054: if (cue_open_pipes(sc)) {
! 1055: splx(s);
! 1056: return;
! 1057: }
! 1058: }
! 1059:
! 1060: ifp->if_flags |= IFF_RUNNING;
! 1061: ifp->if_flags &= ~IFF_OACTIVE;
! 1062:
! 1063: splx(s);
! 1064:
! 1065: timeout_del(&sc->cue_stat_ch);
! 1066: timeout_set(&sc->cue_stat_ch, cue_tick, sc);
! 1067: timeout_add(&sc->cue_stat_ch, hz);
! 1068: }
! 1069:
! 1070: int
! 1071: cue_open_pipes(struct cue_softc *sc)
! 1072: {
! 1073: struct cue_chain *c;
! 1074: usbd_status err;
! 1075: int i;
! 1076:
! 1077: /* Open RX and TX pipes. */
! 1078: err = usbd_open_pipe(sc->cue_iface, sc->cue_ed[CUE_ENDPT_RX],
! 1079: USBD_EXCLUSIVE_USE, &sc->cue_ep[CUE_ENDPT_RX]);
! 1080: if (err) {
! 1081: printf("%s: open rx pipe failed: %s\n",
! 1082: sc->cue_dev.dv_xname, usbd_errstr(err));
! 1083: return (EIO);
! 1084: }
! 1085: err = usbd_open_pipe(sc->cue_iface, sc->cue_ed[CUE_ENDPT_TX],
! 1086: USBD_EXCLUSIVE_USE, &sc->cue_ep[CUE_ENDPT_TX]);
! 1087: if (err) {
! 1088: printf("%s: open tx pipe failed: %s\n",
! 1089: sc->cue_dev.dv_xname, usbd_errstr(err));
! 1090: return (EIO);
! 1091: }
! 1092:
! 1093: /* Start up the receive pipe. */
! 1094: for (i = 0; i < CUE_RX_LIST_CNT; i++) {
! 1095: c = &sc->cue_cdata.cue_rx_chain[i];
! 1096: usbd_setup_xfer(c->cue_xfer, sc->cue_ep[CUE_ENDPT_RX],
! 1097: c, c->cue_buf, CUE_BUFSZ,
! 1098: USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
! 1099: cue_rxeof);
! 1100: usbd_transfer(c->cue_xfer);
! 1101: }
! 1102:
! 1103: return (0);
! 1104: }
! 1105:
! 1106: int
! 1107: cue_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
! 1108: {
! 1109: struct cue_softc *sc = ifp->if_softc;
! 1110: struct ifaddr *ifa = (struct ifaddr *)data;
! 1111: struct ifreq *ifr = (struct ifreq *)data;
! 1112: int s, error = 0;
! 1113:
! 1114: if (sc->cue_dying)
! 1115: return (EIO);
! 1116:
! 1117: s = splnet();
! 1118:
! 1119: switch(command) {
! 1120: case SIOCSIFADDR:
! 1121: ifp->if_flags |= IFF_UP;
! 1122: cue_init(sc);
! 1123:
! 1124: switch (ifa->ifa_addr->sa_family) {
! 1125: #ifdef INET
! 1126: case AF_INET:
! 1127: arp_ifinit(&sc->arpcom, ifa);
! 1128: break;
! 1129: #endif /* INET */
! 1130: }
! 1131: break;
! 1132:
! 1133: case SIOCSIFMTU:
! 1134: if (ifr->ifr_mtu > ETHERMTU)
! 1135: error = EINVAL;
! 1136: else
! 1137: ifp->if_mtu = ifr->ifr_mtu;
! 1138: break;
! 1139:
! 1140: case SIOCSIFFLAGS:
! 1141: if (ifp->if_flags & IFF_UP) {
! 1142: if (ifp->if_flags & IFF_RUNNING &&
! 1143: ifp->if_flags & IFF_PROMISC &&
! 1144: !(sc->cue_if_flags & IFF_PROMISC)) {
! 1145: CUE_SETBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC);
! 1146: cue_setmulti(sc);
! 1147: } else if (ifp->if_flags & IFF_RUNNING &&
! 1148: !(ifp->if_flags & IFF_PROMISC) &&
! 1149: sc->cue_if_flags & IFF_PROMISC) {
! 1150: CUE_CLRBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC);
! 1151: cue_setmulti(sc);
! 1152: } else if (!(ifp->if_flags & IFF_RUNNING))
! 1153: cue_init(sc);
! 1154: } else {
! 1155: if (ifp->if_flags & IFF_RUNNING)
! 1156: cue_stop(sc);
! 1157: }
! 1158: sc->cue_if_flags = ifp->if_flags;
! 1159: error = 0;
! 1160: break;
! 1161: case SIOCADDMULTI:
! 1162: case SIOCDELMULTI:
! 1163: error = (command == SIOCADDMULTI) ?
! 1164: ether_addmulti(ifr, &sc->arpcom) :
! 1165: ether_delmulti(ifr, &sc->arpcom);
! 1166:
! 1167: if (error == ENETRESET) {
! 1168: /*
! 1169: * Multicast list has changed; set the hardware
! 1170: * filter accordingly.
! 1171: */
! 1172: if (ifp->if_flags & IFF_RUNNING)
! 1173: cue_setmulti(sc);
! 1174: error = 0;
! 1175: }
! 1176: break;
! 1177: default:
! 1178: error = EINVAL;
! 1179: break;
! 1180: }
! 1181:
! 1182: splx(s);
! 1183:
! 1184: return (error);
! 1185: }
! 1186:
! 1187: void
! 1188: cue_watchdog(struct ifnet *ifp)
! 1189: {
! 1190: struct cue_softc *sc = ifp->if_softc;
! 1191: struct cue_chain *c;
! 1192: usbd_status stat;
! 1193: int s;
! 1194:
! 1195: DPRINTFN(5,("%s: %s: enter\n", sc->cue_dev.dv_xname,__func__));
! 1196:
! 1197: if (sc->cue_dying)
! 1198: return;
! 1199:
! 1200: ifp->if_oerrors++;
! 1201: printf("%s: watchdog timeout\n", sc->cue_dev.dv_xname);
! 1202:
! 1203: s = splusb();
! 1204: c = &sc->cue_cdata.cue_tx_chain[0];
! 1205: usbd_get_xfer_status(c->cue_xfer, NULL, NULL, NULL, &stat);
! 1206: cue_txeof(c->cue_xfer, c, stat);
! 1207:
! 1208: if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
! 1209: cue_start(ifp);
! 1210: splx(s);
! 1211: }
! 1212:
! 1213: /*
! 1214: * Stop the adapter and free any mbufs allocated to the
! 1215: * RX and TX lists.
! 1216: */
! 1217: void
! 1218: cue_stop(struct cue_softc *sc)
! 1219: {
! 1220: usbd_status err;
! 1221: struct ifnet *ifp;
! 1222: int i;
! 1223:
! 1224: DPRINTFN(10,("%s: %s: enter\n", sc->cue_dev.dv_xname,__func__));
! 1225:
! 1226: ifp = GET_IFP(sc);
! 1227: ifp->if_timer = 0;
! 1228: ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
! 1229:
! 1230: cue_csr_write_1(sc, CUE_ETHCTL, 0);
! 1231: cue_reset(sc);
! 1232: timeout_del(&sc->cue_stat_ch);
! 1233:
! 1234: /* Stop transfers. */
! 1235: if (sc->cue_ep[CUE_ENDPT_RX] != NULL) {
! 1236: err = usbd_abort_pipe(sc->cue_ep[CUE_ENDPT_RX]);
! 1237: if (err) {
! 1238: printf("%s: abort rx pipe failed: %s\n",
! 1239: sc->cue_dev.dv_xname, usbd_errstr(err));
! 1240: }
! 1241: err = usbd_close_pipe(sc->cue_ep[CUE_ENDPT_RX]);
! 1242: if (err) {
! 1243: printf("%s: close rx pipe failed: %s\n",
! 1244: sc->cue_dev.dv_xname, usbd_errstr(err));
! 1245: }
! 1246: sc->cue_ep[CUE_ENDPT_RX] = NULL;
! 1247: }
! 1248:
! 1249: if (sc->cue_ep[CUE_ENDPT_TX] != NULL) {
! 1250: err = usbd_abort_pipe(sc->cue_ep[CUE_ENDPT_TX]);
! 1251: if (err) {
! 1252: printf("%s: abort tx pipe failed: %s\n",
! 1253: sc->cue_dev.dv_xname, usbd_errstr(err));
! 1254: }
! 1255: err = usbd_close_pipe(sc->cue_ep[CUE_ENDPT_TX]);
! 1256: if (err) {
! 1257: printf("%s: close tx pipe failed: %s\n",
! 1258: sc->cue_dev.dv_xname, usbd_errstr(err));
! 1259: }
! 1260: sc->cue_ep[CUE_ENDPT_TX] = NULL;
! 1261: }
! 1262:
! 1263: if (sc->cue_ep[CUE_ENDPT_INTR] != NULL) {
! 1264: err = usbd_abort_pipe(sc->cue_ep[CUE_ENDPT_INTR]);
! 1265: if (err) {
! 1266: printf("%s: abort intr pipe failed: %s\n",
! 1267: sc->cue_dev.dv_xname, usbd_errstr(err));
! 1268: }
! 1269: err = usbd_close_pipe(sc->cue_ep[CUE_ENDPT_INTR]);
! 1270: if (err) {
! 1271: printf("%s: close intr pipe failed: %s\n",
! 1272: sc->cue_dev.dv_xname, usbd_errstr(err));
! 1273: }
! 1274: sc->cue_ep[CUE_ENDPT_INTR] = NULL;
! 1275: }
! 1276:
! 1277: /* Free RX resources. */
! 1278: for (i = 0; i < CUE_RX_LIST_CNT; i++) {
! 1279: if (sc->cue_cdata.cue_rx_chain[i].cue_mbuf != NULL) {
! 1280: m_freem(sc->cue_cdata.cue_rx_chain[i].cue_mbuf);
! 1281: sc->cue_cdata.cue_rx_chain[i].cue_mbuf = NULL;
! 1282: }
! 1283: if (sc->cue_cdata.cue_rx_chain[i].cue_xfer != NULL) {
! 1284: usbd_free_xfer(sc->cue_cdata.cue_rx_chain[i].cue_xfer);
! 1285: sc->cue_cdata.cue_rx_chain[i].cue_xfer = NULL;
! 1286: }
! 1287: }
! 1288:
! 1289: /* Free TX resources. */
! 1290: for (i = 0; i < CUE_TX_LIST_CNT; i++) {
! 1291: if (sc->cue_cdata.cue_tx_chain[i].cue_mbuf != NULL) {
! 1292: m_freem(sc->cue_cdata.cue_tx_chain[i].cue_mbuf);
! 1293: sc->cue_cdata.cue_tx_chain[i].cue_mbuf = NULL;
! 1294: }
! 1295: if (sc->cue_cdata.cue_tx_chain[i].cue_xfer != NULL) {
! 1296: usbd_free_xfer(sc->cue_cdata.cue_tx_chain[i].cue_xfer);
! 1297: sc->cue_cdata.cue_tx_chain[i].cue_xfer = NULL;
! 1298: }
! 1299: }
! 1300: }
CVSweb