Annotation of sys/dev/usb/if_kue.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_kue.c,v 1.55 2007/06/14 10:11:15 mbalmer Exp $ */
! 2: /* $NetBSD: if_kue.c,v 1.50 2002/07/16 22:00:31 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_kue.c,v 1.14 2000/01/14 01:36:15 wpaul Exp $
! 35: */
! 36:
! 37: /*
! 38: * Kawasaki LSI KL5KUSB101B USB to ethernet adapter driver.
! 39: *
! 40: * Written by Bill Paul <wpaul@ee.columbia.edu>
! 41: * Electrical Engineering Department
! 42: * Columbia University, New York City
! 43: */
! 44:
! 45: /*
! 46: * The KLSI USB to ethernet adapter chip contains an USB serial interface,
! 47: * ethernet MAC and embedded microcontroller (called the QT Engine).
! 48: * The chip must have firmware loaded into it before it will operate.
! 49: * Packets are passed between the chip and host via bulk transfers.
! 50: * There is an interrupt endpoint mentioned in the software spec, however
! 51: * it's currently unused. This device is 10Mbps half-duplex only, hence
! 52: * there is no media selection logic. The MAC supports a 128 entry
! 53: * multicast filter, though the exact size of the filter can depend
! 54: * on the firmware. Curiously, while the software spec describes various
! 55: * ethernet statistics counters, my sample adapter and firmware combination
! 56: * claims not to support any statistics counters at all.
! 57: *
! 58: * Note that once we load the firmware in the device, we have to be
! 59: * careful not to load it again: if you restart your computer but
! 60: * leave the adapter attached to the USB controller, it may remain
! 61: * powered on and retain its firmware. In this case, we don't need
! 62: * to load the firmware a second time.
! 63: *
! 64: * Special thanks to Rob Furr for providing an ADS Technologies
! 65: * adapter for development and testing. No monkeys were harmed during
! 66: * the development of this driver.
! 67: */
! 68:
! 69: /*
! 70: * Ported to NetBSD and somewhat rewritten by Lennart Augustsson.
! 71: */
! 72:
! 73: #include "bpfilter.h"
! 74:
! 75: #include <sys/param.h>
! 76: #include <sys/systm.h>
! 77: #include <sys/sockio.h>
! 78: #include <sys/mbuf.h>
! 79: #include <sys/malloc.h>
! 80: #include <sys/kernel.h>
! 81: #include <sys/socket.h>
! 82: #include <sys/device.h>
! 83: #include <sys/proc.h>
! 84:
! 85: #include <net/if.h>
! 86: #include <net/if_dl.h>
! 87:
! 88: #if NBPFILTER > 0
! 89: #include <net/bpf.h>
! 90: #endif
! 91:
! 92: #ifdef INET
! 93: #include <netinet/in.h>
! 94: #include <netinet/in_systm.h>
! 95: #include <netinet/in_var.h>
! 96: #include <netinet/ip.h>
! 97: #include <netinet/if_ether.h>
! 98: #endif
! 99:
! 100: #include <dev/usb/usb.h>
! 101: #include <dev/usb/usbdi.h>
! 102: #include <dev/usb/usbdi_util.h>
! 103: #include <dev/usb/usbdevs.h>
! 104:
! 105: #include <dev/usb/if_kuereg.h>
! 106: #include <dev/usb/if_kuevar.h>
! 107:
! 108: #ifdef KUE_DEBUG
! 109: #define DPRINTF(x) do { if (kuedebug) printf x; } while (0)
! 110: #define DPRINTFN(n,x) do { if (kuedebug >= (n)) printf x; } while (0)
! 111: int kuedebug = 0;
! 112: #else
! 113: #define DPRINTF(x)
! 114: #define DPRINTFN(n,x)
! 115: #endif
! 116:
! 117: /*
! 118: * Various supported device vendors/products.
! 119: */
! 120: const struct usb_devno kue_devs[] = {
! 121: { USB_VENDOR_3COM, USB_PRODUCT_3COM_3C19250 },
! 122: { USB_VENDOR_3COM, USB_PRODUCT_3COM_3C460 },
! 123: { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_URE450 },
! 124: { USB_VENDOR_ADS, USB_PRODUCT_ADS_UBS10BT },
! 125: { USB_VENDOR_ADS, USB_PRODUCT_ADS_UBS10BTX },
! 126: { USB_VENDOR_AOX, USB_PRODUCT_AOX_USB101 },
! 127: { USB_VENDOR_ASANTE, USB_PRODUCT_ASANTE_EA },
! 128: { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC10T },
! 129: { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_DSB650C },
! 130: { USB_VENDOR_COREGA, USB_PRODUCT_COREGA_ETHER_USB_T },
! 131: { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650C },
! 132: { USB_VENDOR_ENTREGA, USB_PRODUCT_ENTREGA_E45 },
! 133: { USB_VENDOR_ENTREGA, USB_PRODUCT_ENTREGA_XX1 },
! 134: { USB_VENDOR_ENTREGA, USB_PRODUCT_ENTREGA_XX2 },
! 135: { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBETT },
! 136: { USB_VENDOR_JATON, USB_PRODUCT_JATON_EDA },
! 137: { USB_VENDOR_KINGSTON, USB_PRODUCT_KINGSTON_XX1 },
! 138: { USB_VENDOR_KLSI, USB_PRODUCT_KLSI_DUH3E10BT },
! 139: { USB_VENDOR_KLSI, USB_PRODUCT_KLSI_DUH3E10BTN },
! 140: { USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10T },
! 141: { USB_VENDOR_MOBILITY, USB_PRODUCT_MOBILITY_EA },
! 142: { USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_EA101 },
! 143: { USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_EA101X },
! 144: { USB_VENDOR_PERACOM, USB_PRODUCT_PERACOM_ENET },
! 145: { USB_VENDOR_PERACOM, USB_PRODUCT_PERACOM_ENET2 },
! 146: { USB_VENDOR_PERACOM, USB_PRODUCT_PERACOM_ENET3 },
! 147: { USB_VENDOR_PORTGEAR, USB_PRODUCT_PORTGEAR_EA8 },
! 148: { USB_VENDOR_PORTGEAR, USB_PRODUCT_PORTGEAR_EA9 },
! 149: { USB_VENDOR_PORTSMITH, USB_PRODUCT_PORTSMITH_EEA },
! 150: { USB_VENDOR_SHARK, USB_PRODUCT_SHARK_PA },
! 151: { USB_VENDOR_SILICOM, USB_PRODUCT_SILICOM_U2E },
! 152: { USB_VENDOR_SILICOM, USB_PRODUCT_SILICOM_GPE },
! 153: { USB_VENDOR_SMC, USB_PRODUCT_SMC_2102USB },
! 154: };
! 155: #define kue_lookup(v, p) (usb_lookup(kue_devs, v, p))
! 156:
! 157: int kue_match(struct device *, void *, void *);
! 158: void kue_attach(struct device *, struct device *, void *);
! 159: int kue_detach(struct device *, int);
! 160: int kue_activate(struct device *, enum devact);
! 161:
! 162: struct cfdriver kue_cd = {
! 163: NULL, "kue", DV_IFNET
! 164: };
! 165:
! 166: const struct cfattach kue_ca = {
! 167: sizeof(struct kue_softc),
! 168: kue_match,
! 169: kue_attach,
! 170: kue_detach,
! 171: kue_activate,
! 172: };
! 173:
! 174: int kue_tx_list_init(struct kue_softc *);
! 175: int kue_rx_list_init(struct kue_softc *);
! 176: int kue_newbuf(struct kue_softc *, struct kue_chain *,struct mbuf *);
! 177: int kue_send(struct kue_softc *, struct mbuf *, int);
! 178: int kue_open_pipes(struct kue_softc *);
! 179: void kue_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
! 180: void kue_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
! 181: void kue_start(struct ifnet *);
! 182: int kue_ioctl(struct ifnet *, u_long, caddr_t);
! 183: void kue_init(void *);
! 184: void kue_stop(struct kue_softc *);
! 185: void kue_watchdog(struct ifnet *);
! 186:
! 187: void kue_setmulti(struct kue_softc *);
! 188: void kue_reset(struct kue_softc *);
! 189:
! 190: usbd_status kue_ctl(struct kue_softc *, int, u_int8_t,
! 191: u_int16_t, void *, u_int32_t);
! 192: usbd_status kue_setword(struct kue_softc *, u_int8_t, u_int16_t);
! 193: int kue_load_fw(struct kue_softc *);
! 194: void kue_attachhook(void *);
! 195:
! 196: usbd_status
! 197: kue_setword(struct kue_softc *sc, u_int8_t breq, u_int16_t word)
! 198: {
! 199: usb_device_request_t req;
! 200:
! 201: DPRINTFN(10,("%s: %s: enter\n", sc->kue_dev.dv_xname,__func__));
! 202:
! 203: req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
! 204: req.bRequest = breq;
! 205: USETW(req.wValue, word);
! 206: USETW(req.wIndex, 0);
! 207: USETW(req.wLength, 0);
! 208:
! 209: return (usbd_do_request(sc->kue_udev, &req, NULL));
! 210: }
! 211:
! 212: usbd_status
! 213: kue_ctl(struct kue_softc *sc, int rw, u_int8_t breq, u_int16_t val,
! 214: void *data, u_int32_t len)
! 215: {
! 216: usb_device_request_t req;
! 217:
! 218: DPRINTFN(10,("%s: %s: enter, len=%d\n", sc->kue_dev.dv_xname,
! 219: __func__, len));
! 220:
! 221: if (rw == KUE_CTL_WRITE)
! 222: req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
! 223: else
! 224: req.bmRequestType = UT_READ_VENDOR_DEVICE;
! 225:
! 226: req.bRequest = breq;
! 227: USETW(req.wValue, val);
! 228: USETW(req.wIndex, 0);
! 229: USETW(req.wLength, len);
! 230:
! 231: return (usbd_do_request(sc->kue_udev, &req, data));
! 232: }
! 233:
! 234: int
! 235: kue_load_fw(struct kue_softc *sc)
! 236: {
! 237: usb_device_descriptor_t dd;
! 238: usbd_status err;
! 239: struct kue_firmware *fw;
! 240: u_char *buf;
! 241: size_t buflen;
! 242:
! 243: DPRINTFN(1,("%s: %s: enter\n", sc->kue_dev.dv_xname, __func__));
! 244:
! 245: /*
! 246: * First, check if we even need to load the firmware.
! 247: * If the device was still attached when the system was
! 248: * rebooted, it may already have firmware loaded in it.
! 249: * If this is the case, we don't need to do it again.
! 250: * And in fact, if we try to load it again, we'll hang,
! 251: * so we have to avoid this condition if we don't want
! 252: * to look stupid.
! 253: *
! 254: * We can test this quickly by checking the bcdRevision
! 255: * code. The NIC will return a different revision code if
! 256: * it's probed while the firmware is still loaded and
! 257: * running.
! 258: */
! 259: if (usbd_get_device_desc(sc->kue_udev, &dd))
! 260: return (EIO);
! 261: if (UGETW(dd.bcdDevice) >= KUE_WARM_REV) {
! 262: printf("%s: warm boot, no firmware download\n",
! 263: sc->kue_dev.dv_xname);
! 264: return (0);
! 265: }
! 266:
! 267: err = loadfirmware("kue", &buf, &buflen);
! 268: if (err) {
! 269: printf("%s: failed loadfirmware of file %s: errno %d\n",
! 270: sc->kue_dev.dv_xname, "kue", err);
! 271: return (err);
! 272: }
! 273: fw = (struct kue_firmware *)buf;
! 274:
! 275: printf("%s: cold boot, downloading firmware\n",
! 276: sc->kue_dev.dv_xname);
! 277:
! 278: /* Load code segment */
! 279: DPRINTFN(1,("%s: kue_load_fw: download code_seg\n",
! 280: sc->kue_dev.dv_xname));
! 281: err = kue_ctl(sc, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN,
! 282: 0, (void *)&fw->data[0], ntohl(fw->codeseglen));
! 283: if (err) {
! 284: printf("%s: failed to load code segment: %s\n",
! 285: sc->kue_dev.dv_xname, usbd_errstr(err));
! 286: free(buf, M_DEVBUF);
! 287: return (EIO);
! 288: }
! 289:
! 290: /* Load fixup segment */
! 291: DPRINTFN(1,("%s: kue_load_fw: download fix_seg\n",
! 292: sc->kue_dev.dv_xname));
! 293: err = kue_ctl(sc, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN,
! 294: 0, (void *)&fw->data[ntohl(fw->codeseglen)], ntohl(fw->fixseglen));
! 295: if (err) {
! 296: printf("%s: failed to load fixup segment: %s\n",
! 297: sc->kue_dev.dv_xname, usbd_errstr(err));
! 298: free(buf, M_DEVBUF);
! 299: return (EIO);
! 300: }
! 301:
! 302: /* Send trigger command. */
! 303: DPRINTFN(1,("%s: kue_load_fw: download trig_seg\n",
! 304: sc->kue_dev.dv_xname));
! 305: err = kue_ctl(sc, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN,
! 306: 0, (void *)&fw->data[ntohl(fw->codeseglen) + ntohl(fw->fixseglen)],
! 307: ntohl(fw->trigseglen));
! 308: if (err) {
! 309: printf("%s: failed to load trigger segment: %s\n",
! 310: sc->kue_dev.dv_xname, usbd_errstr(err));
! 311: free(buf, M_DEVBUF);
! 312: return (EIO);
! 313: }
! 314: free(buf, M_DEVBUF);
! 315:
! 316: usbd_delay_ms(sc->kue_udev, 10);
! 317:
! 318: /*
! 319: * Reload device descriptor.
! 320: * Why? The chip without the firmware loaded returns
! 321: * one revision code. The chip with the firmware
! 322: * loaded and running returns a *different* revision
! 323: * code. This confuses the quirk mechanism, which is
! 324: * dependent on the revision data.
! 325: */
! 326: (void)usbd_reload_device_desc(sc->kue_udev);
! 327:
! 328: DPRINTFN(1,("%s: %s: done\n", sc->kue_dev.dv_xname, __func__));
! 329:
! 330: /* Reset the adapter. */
! 331: kue_reset(sc);
! 332:
! 333: return (0);
! 334: }
! 335:
! 336: void
! 337: kue_setmulti(struct kue_softc *sc)
! 338: {
! 339: struct ifnet *ifp = GET_IFP(sc);
! 340: struct ether_multi *enm;
! 341: struct ether_multistep step;
! 342: int i;
! 343:
! 344: DPRINTFN(5,("%s: %s: enter\n", sc->kue_dev.dv_xname, __func__));
! 345:
! 346: if (ifp->if_flags & IFF_PROMISC) {
! 347: allmulti:
! 348: ifp->if_flags |= IFF_ALLMULTI;
! 349: sc->kue_rxfilt |= KUE_RXFILT_ALLMULTI;
! 350: sc->kue_rxfilt &= ~KUE_RXFILT_MULTICAST;
! 351: kue_setword(sc, KUE_CMD_SET_PKT_FILTER, sc->kue_rxfilt);
! 352: return;
! 353: }
! 354:
! 355: sc->kue_rxfilt &= ~KUE_RXFILT_ALLMULTI;
! 356:
! 357: i = 0;
! 358: ETHER_FIRST_MULTI(step, &sc->arpcom, enm);
! 359: while (enm != NULL) {
! 360: if (i == KUE_MCFILTCNT(sc) ||
! 361: memcmp(enm->enm_addrlo, enm->enm_addrhi,
! 362: ETHER_ADDR_LEN) != 0)
! 363: goto allmulti;
! 364:
! 365: memcpy(KUE_MCFILT(sc, i), enm->enm_addrlo, ETHER_ADDR_LEN);
! 366: ETHER_NEXT_MULTI(step, enm);
! 367: i++;
! 368: }
! 369:
! 370: ifp->if_flags &= ~IFF_ALLMULTI;
! 371:
! 372: sc->kue_rxfilt |= KUE_RXFILT_MULTICAST;
! 373: kue_ctl(sc, KUE_CTL_WRITE, KUE_CMD_SET_MCAST_FILTERS,
! 374: i, sc->kue_mcfilters, i * ETHER_ADDR_LEN);
! 375:
! 376: kue_setword(sc, KUE_CMD_SET_PKT_FILTER, sc->kue_rxfilt);
! 377: }
! 378:
! 379: /*
! 380: * Issue a SET_CONFIGURATION command to reset the MAC. This should be
! 381: * done after the firmware is loaded into the adapter in order to
! 382: * bring it into proper operation.
! 383: */
! 384: void
! 385: kue_reset(struct kue_softc *sc)
! 386: {
! 387: DPRINTFN(5,("%s: %s: enter\n", sc->kue_dev.dv_xname, __func__));
! 388:
! 389: if (usbd_set_config_no(sc->kue_udev, KUE_CONFIG_NO, 1) ||
! 390: usbd_device2interface_handle(sc->kue_udev, KUE_IFACE_IDX,
! 391: &sc->kue_iface))
! 392: printf("%s: reset failed\n", sc->kue_dev.dv_xname);
! 393:
! 394: /* Wait a little while for the chip to get its brains in order. */
! 395: usbd_delay_ms(sc->kue_udev, 10);
! 396: }
! 397:
! 398: /*
! 399: * Probe for a KLSI chip.
! 400: */
! 401: int
! 402: kue_match(struct device *parent, void *match, void *aux)
! 403: {
! 404: struct usb_attach_arg *uaa = aux;
! 405:
! 406: DPRINTFN(25,("kue_match: enter\n"));
! 407:
! 408: if (uaa->iface != NULL)
! 409: return (UMATCH_NONE);
! 410:
! 411: return (kue_lookup(uaa->vendor, uaa->product) != NULL ?
! 412: UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
! 413: }
! 414:
! 415: void
! 416: kue_attachhook(void *xsc)
! 417: {
! 418: struct kue_softc *sc = xsc;
! 419: int s;
! 420: struct ifnet *ifp;
! 421: usbd_device_handle dev = sc->kue_udev;
! 422: usbd_interface_handle iface;
! 423: usbd_status err;
! 424: usb_interface_descriptor_t *id;
! 425: usb_endpoint_descriptor_t *ed;
! 426: int i;
! 427:
! 428: /* Load the firmware into the NIC. */
! 429: if (kue_load_fw(sc)) {
! 430: printf("%s: loading firmware failed\n",
! 431: sc->kue_dev.dv_xname);
! 432: return;
! 433: }
! 434:
! 435: err = usbd_device2interface_handle(dev, KUE_IFACE_IDX, &iface);
! 436: if (err) {
! 437: printf("%s: getting interface handle failed\n",
! 438: sc->kue_dev.dv_xname);
! 439: return;
! 440: }
! 441:
! 442: sc->kue_iface = iface;
! 443: id = usbd_get_interface_descriptor(iface);
! 444:
! 445: /* Find endpoints. */
! 446: for (i = 0; i < id->bNumEndpoints; i++) {
! 447: ed = usbd_interface2endpoint_descriptor(iface, i);
! 448: if (ed == NULL) {
! 449: printf("%s: couldn't get ep %d\n",
! 450: sc->kue_dev.dv_xname, i);
! 451: return;
! 452: }
! 453: if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
! 454: UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
! 455: sc->kue_ed[KUE_ENDPT_RX] = ed->bEndpointAddress;
! 456: } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
! 457: UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
! 458: sc->kue_ed[KUE_ENDPT_TX] = ed->bEndpointAddress;
! 459: } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
! 460: UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
! 461: sc->kue_ed[KUE_ENDPT_INTR] = ed->bEndpointAddress;
! 462: }
! 463: }
! 464:
! 465: if (sc->kue_ed[KUE_ENDPT_RX] == 0 || sc->kue_ed[KUE_ENDPT_TX] == 0) {
! 466: printf("%s: missing endpoint\n", sc->kue_dev.dv_xname);
! 467: return;
! 468: }
! 469:
! 470: /* Read ethernet descriptor */
! 471: err = kue_ctl(sc, KUE_CTL_READ, KUE_CMD_GET_ETHER_DESCRIPTOR,
! 472: 0, &sc->kue_desc, sizeof(sc->kue_desc));
! 473: if (err) {
! 474: printf("%s: could not read Ethernet descriptor\n",
! 475: sc->kue_dev.dv_xname);
! 476: return;
! 477: }
! 478:
! 479: sc->kue_mcfilters = malloc(KUE_MCFILTCNT(sc) * ETHER_ADDR_LEN,
! 480: M_USBDEV, M_NOWAIT);
! 481: if (sc->kue_mcfilters == NULL) {
! 482: printf("%s: no memory for multicast filter buffer\n",
! 483: sc->kue_dev.dv_xname);
! 484: return;
! 485: }
! 486:
! 487: s = splnet();
! 488:
! 489: /*
! 490: * A KLSI chip was detected. Inform the world.
! 491: */
! 492: printf("%s: address %s\n", sc->kue_dev.dv_xname,
! 493: ether_sprintf(sc->kue_desc.kue_macaddr));
! 494:
! 495: bcopy(sc->kue_desc.kue_macaddr,
! 496: (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
! 497:
! 498: /* Initialize interface info.*/
! 499: ifp = GET_IFP(sc);
! 500: ifp->if_softc = sc;
! 501: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
! 502: ifp->if_ioctl = kue_ioctl;
! 503: ifp->if_start = kue_start;
! 504: ifp->if_watchdog = kue_watchdog;
! 505: strlcpy(ifp->if_xname, sc->kue_dev.dv_xname, IFNAMSIZ);
! 506:
! 507: IFQ_SET_READY(&ifp->if_snd);
! 508:
! 509: /* Attach the interface. */
! 510: if_attach(ifp);
! 511: ether_ifattach(ifp);
! 512:
! 513: sc->kue_attached = 1;
! 514: splx(s);
! 515:
! 516: }
! 517:
! 518: /*
! 519: * Attach the interface. Allocate softc structures, do
! 520: * setup and ethernet/BPF attach.
! 521: */
! 522: void
! 523: kue_attach(struct device *parent, struct device *self, void *aux)
! 524: {
! 525: struct kue_softc *sc = (struct kue_softc *)self;
! 526: struct usb_attach_arg *uaa = aux;
! 527: char *devinfop;
! 528: usbd_device_handle dev = uaa->device;
! 529: usbd_status err;
! 530:
! 531: DPRINTFN(5,(" : kue_attach: sc=%p, dev=%p", sc, dev));
! 532:
! 533: devinfop = usbd_devinfo_alloc(dev, 0);
! 534: printf("\n%s: %s\n", sc->kue_dev.dv_xname, devinfop);
! 535: usbd_devinfo_free(devinfop);
! 536:
! 537: err = usbd_set_config_no(dev, KUE_CONFIG_NO, 1);
! 538: if (err) {
! 539: printf("%s: setting config no failed\n",
! 540: sc->kue_dev.dv_xname);
! 541: return;
! 542: }
! 543:
! 544: sc->kue_udev = dev;
! 545: sc->kue_product = uaa->product;
! 546: sc->kue_vendor = uaa->vendor;
! 547:
! 548: if (rootvp == NULL)
! 549: mountroothook_establish(kue_attachhook, sc);
! 550: else
! 551: kue_attachhook(sc);
! 552:
! 553: usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->kue_udev,
! 554: &sc->kue_dev);
! 555: }
! 556:
! 557: int
! 558: kue_detach(struct device *self, int flags)
! 559: {
! 560: struct kue_softc *sc = (struct kue_softc *)self;
! 561: struct ifnet *ifp = GET_IFP(sc);
! 562: int s;
! 563:
! 564: s = splusb(); /* XXX why? */
! 565:
! 566: if (sc->kue_mcfilters != NULL) {
! 567: free(sc->kue_mcfilters, M_USBDEV);
! 568: sc->kue_mcfilters = NULL;
! 569: }
! 570:
! 571: if (!sc->kue_attached) {
! 572: /* Detached before attached finished, so just bail out. */
! 573: splx(s);
! 574: return (0);
! 575: }
! 576:
! 577: if (ifp->if_flags & IFF_RUNNING)
! 578: kue_stop(sc);
! 579:
! 580: ether_ifdetach(ifp);
! 581:
! 582: if_detach(ifp);
! 583:
! 584: #ifdef DIAGNOSTIC
! 585: if (sc->kue_ep[KUE_ENDPT_TX] != NULL ||
! 586: sc->kue_ep[KUE_ENDPT_RX] != NULL ||
! 587: sc->kue_ep[KUE_ENDPT_INTR] != NULL)
! 588: printf("%s: detach has active endpoints\n",
! 589: sc->kue_dev.dv_xname);
! 590: #endif
! 591:
! 592: sc->kue_attached = 0;
! 593: splx(s);
! 594:
! 595: return (0);
! 596: }
! 597:
! 598: int
! 599: kue_activate(struct device *self, enum devact act)
! 600: {
! 601: struct kue_softc *sc = (struct kue_softc *)self;
! 602:
! 603: DPRINTFN(2,("%s: %s: enter\n", sc->kue_dev.dv_xname, __func__));
! 604:
! 605: switch (act) {
! 606: case DVACT_ACTIVATE:
! 607: break;
! 608:
! 609: case DVACT_DEACTIVATE:
! 610: sc->kue_dying = 1;
! 611: break;
! 612: }
! 613: return (0);
! 614: }
! 615:
! 616: /*
! 617: * Initialize an RX descriptor and attach an MBUF cluster.
! 618: */
! 619: int
! 620: kue_newbuf(struct kue_softc *sc, struct kue_chain *c, struct mbuf *m)
! 621: {
! 622: struct mbuf *m_new = NULL;
! 623:
! 624: DPRINTFN(10,("%s: %s: enter\n", sc->kue_dev.dv_xname,__func__));
! 625:
! 626: if (m == NULL) {
! 627: MGETHDR(m_new, M_DONTWAIT, MT_DATA);
! 628: if (m_new == NULL) {
! 629: printf("%s: no memory for rx list "
! 630: "-- packet dropped!\n", sc->kue_dev.dv_xname);
! 631: return (ENOBUFS);
! 632: }
! 633:
! 634: MCLGET(m_new, M_DONTWAIT);
! 635: if (!(m_new->m_flags & M_EXT)) {
! 636: printf("%s: no memory for rx list "
! 637: "-- packet dropped!\n", sc->kue_dev.dv_xname);
! 638: m_freem(m_new);
! 639: return (ENOBUFS);
! 640: }
! 641: m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
! 642: } else {
! 643: m_new = m;
! 644: m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
! 645: m_new->m_data = m_new->m_ext.ext_buf;
! 646: }
! 647:
! 648: c->kue_mbuf = m_new;
! 649:
! 650: return (0);
! 651: }
! 652:
! 653: int
! 654: kue_rx_list_init(struct kue_softc *sc)
! 655: {
! 656: struct kue_cdata *cd;
! 657: struct kue_chain *c;
! 658: int i;
! 659:
! 660: DPRINTFN(5,("%s: %s: enter\n", sc->kue_dev.dv_xname, __func__));
! 661:
! 662: cd = &sc->kue_cdata;
! 663: for (i = 0; i < KUE_RX_LIST_CNT; i++) {
! 664: c = &cd->kue_rx_chain[i];
! 665: c->kue_sc = sc;
! 666: c->kue_idx = i;
! 667: if (kue_newbuf(sc, c, NULL) == ENOBUFS)
! 668: return (ENOBUFS);
! 669: if (c->kue_xfer == NULL) {
! 670: c->kue_xfer = usbd_alloc_xfer(sc->kue_udev);
! 671: if (c->kue_xfer == NULL)
! 672: return (ENOBUFS);
! 673: c->kue_buf = usbd_alloc_buffer(c->kue_xfer, KUE_BUFSZ);
! 674: if (c->kue_buf == NULL)
! 675: return (ENOBUFS); /* XXX free xfer */
! 676: }
! 677: }
! 678:
! 679: return (0);
! 680: }
! 681:
! 682: int
! 683: kue_tx_list_init(struct kue_softc *sc)
! 684: {
! 685: struct kue_cdata *cd;
! 686: struct kue_chain *c;
! 687: int i;
! 688:
! 689: DPRINTFN(5,("%s: %s: enter\n", sc->kue_dev.dv_xname, __func__));
! 690:
! 691: cd = &sc->kue_cdata;
! 692: for (i = 0; i < KUE_TX_LIST_CNT; i++) {
! 693: c = &cd->kue_tx_chain[i];
! 694: c->kue_sc = sc;
! 695: c->kue_idx = i;
! 696: c->kue_mbuf = NULL;
! 697: if (c->kue_xfer == NULL) {
! 698: c->kue_xfer = usbd_alloc_xfer(sc->kue_udev);
! 699: if (c->kue_xfer == NULL)
! 700: return (ENOBUFS);
! 701: c->kue_buf = usbd_alloc_buffer(c->kue_xfer, KUE_BUFSZ);
! 702: if (c->kue_buf == NULL)
! 703: return (ENOBUFS);
! 704: }
! 705: }
! 706:
! 707: return (0);
! 708: }
! 709:
! 710: /*
! 711: * A frame has been uploaded: pass the resulting mbuf chain up to
! 712: * the higher level protocols.
! 713: */
! 714: void
! 715: kue_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
! 716: {
! 717: struct kue_chain *c = priv;
! 718: struct kue_softc *sc = c->kue_sc;
! 719: struct ifnet *ifp = GET_IFP(sc);
! 720: struct mbuf *m;
! 721: int total_len = 0;
! 722: int s;
! 723:
! 724: DPRINTFN(10,("%s: %s: enter status=%d\n", sc->kue_dev.dv_xname,
! 725: __func__, status));
! 726:
! 727: if (sc->kue_dying)
! 728: return;
! 729:
! 730: if (!(ifp->if_flags & IFF_RUNNING))
! 731: return;
! 732:
! 733: if (status != USBD_NORMAL_COMPLETION) {
! 734: if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
! 735: return;
! 736: sc->kue_rx_errs++;
! 737: if (usbd_ratecheck(&sc->kue_rx_notice)) {
! 738: printf("%s: %u usb errors on rx: %s\n",
! 739: sc->kue_dev.dv_xname, sc->kue_rx_errs,
! 740: usbd_errstr(status));
! 741: sc->kue_rx_errs = 0;
! 742: }
! 743: if (status == USBD_STALLED)
! 744: usbd_clear_endpoint_stall_async(sc->kue_ep[KUE_ENDPT_RX]);
! 745: goto done;
! 746: }
! 747:
! 748: usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
! 749:
! 750: DPRINTFN(10,("%s: %s: total_len=%d len=%d\n", sc->kue_dev.dv_xname,
! 751: __func__, total_len,
! 752: UGETW(mtod(c->kue_mbuf, u_int8_t *))));
! 753:
! 754: if (total_len <= 1)
! 755: goto done;
! 756:
! 757: m = c->kue_mbuf;
! 758: /* copy data to mbuf */
! 759: memcpy(mtod(m, char *), c->kue_buf, total_len);
! 760:
! 761: /* No errors; receive the packet. */
! 762: total_len = UGETW(mtod(m, u_int8_t *));
! 763: m_adj(m, sizeof(u_int16_t));
! 764:
! 765: if (total_len < sizeof(struct ether_header)) {
! 766: ifp->if_ierrors++;
! 767: goto done;
! 768: }
! 769:
! 770: ifp->if_ipackets++;
! 771: m->m_pkthdr.len = m->m_len = total_len;
! 772:
! 773: m->m_pkthdr.rcvif = ifp;
! 774:
! 775: s = splnet();
! 776:
! 777: /* XXX ugly */
! 778: if (kue_newbuf(sc, c, NULL) == ENOBUFS) {
! 779: ifp->if_ierrors++;
! 780: goto done1;
! 781: }
! 782:
! 783: #if NBPFILTER > 0
! 784: /*
! 785: * Handle BPF listeners. Let the BPF user see the packet, but
! 786: * don't pass it up to the ether_input() layer unless it's
! 787: * a broadcast packet, multicast packet, matches our ethernet
! 788: * address or the interface is in promiscuous mode.
! 789: */
! 790: if (ifp->if_bpf)
! 791: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
! 792: #endif
! 793:
! 794: DPRINTFN(10,("%s: %s: deliver %d\n", sc->kue_dev.dv_xname,
! 795: __func__, m->m_len));
! 796: ether_input_mbuf(ifp, m);
! 797: done1:
! 798: splx(s);
! 799:
! 800: done:
! 801:
! 802: /* Setup new transfer. */
! 803: usbd_setup_xfer(c->kue_xfer, sc->kue_ep[KUE_ENDPT_RX],
! 804: c, c->kue_buf, KUE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
! 805: USBD_NO_TIMEOUT, kue_rxeof);
! 806: usbd_transfer(c->kue_xfer);
! 807:
! 808: DPRINTFN(10,("%s: %s: start rx\n", sc->kue_dev.dv_xname,
! 809: __func__));
! 810: }
! 811:
! 812: /*
! 813: * A frame was downloaded to the chip. It's safe for us to clean up
! 814: * the list buffers.
! 815: */
! 816:
! 817: void
! 818: kue_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
! 819: {
! 820: struct kue_chain *c = priv;
! 821: struct kue_softc *sc = c->kue_sc;
! 822: struct ifnet *ifp = GET_IFP(sc);
! 823: int s;
! 824:
! 825: if (sc->kue_dying)
! 826: return;
! 827:
! 828: s = splnet();
! 829:
! 830: DPRINTFN(10,("%s: %s: enter status=%d\n", sc->kue_dev.dv_xname,
! 831: __func__, status));
! 832:
! 833: ifp->if_timer = 0;
! 834: ifp->if_flags &= ~IFF_OACTIVE;
! 835:
! 836: if (status != USBD_NORMAL_COMPLETION) {
! 837: if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
! 838: splx(s);
! 839: return;
! 840: }
! 841: ifp->if_oerrors++;
! 842: printf("%s: usb error on tx: %s\n", sc->kue_dev.dv_xname,
! 843: usbd_errstr(status));
! 844: if (status == USBD_STALLED)
! 845: usbd_clear_endpoint_stall_async(sc->kue_ep[KUE_ENDPT_TX]);
! 846: splx(s);
! 847: return;
! 848: }
! 849:
! 850: ifp->if_opackets++;
! 851:
! 852: m_freem(c->kue_mbuf);
! 853: c->kue_mbuf = NULL;
! 854:
! 855: if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
! 856: kue_start(ifp);
! 857:
! 858: splx(s);
! 859: }
! 860:
! 861: int
! 862: kue_send(struct kue_softc *sc, struct mbuf *m, int idx)
! 863: {
! 864: int total_len;
! 865: struct kue_chain *c;
! 866: usbd_status err;
! 867:
! 868: DPRINTFN(10,("%s: %s: enter\n", sc->kue_dev.dv_xname,__func__));
! 869:
! 870: c = &sc->kue_cdata.kue_tx_chain[idx];
! 871:
! 872: /*
! 873: * Copy the mbuf data into a contiguous buffer, leaving two
! 874: * bytes at the beginning to hold the frame length.
! 875: */
! 876: m_copydata(m, 0, m->m_pkthdr.len, c->kue_buf + 2);
! 877: c->kue_mbuf = m;
! 878:
! 879: total_len = m->m_pkthdr.len + 2;
! 880: /* XXX what's this? */
! 881: total_len += 64 - (total_len % 64);
! 882:
! 883: /* Frame length is specified in the first 2 bytes of the buffer. */
! 884: c->kue_buf[0] = (u_int8_t)m->m_pkthdr.len;
! 885: c->kue_buf[1] = (u_int8_t)(m->m_pkthdr.len >> 8);
! 886:
! 887: usbd_setup_xfer(c->kue_xfer, sc->kue_ep[KUE_ENDPT_TX],
! 888: c, c->kue_buf, total_len, USBD_NO_COPY, USBD_DEFAULT_TIMEOUT,
! 889: kue_txeof);
! 890:
! 891: /* Transmit */
! 892: err = usbd_transfer(c->kue_xfer);
! 893: if (err != USBD_IN_PROGRESS) {
! 894: printf("%s: kue_send error=%s\n", sc->kue_dev.dv_xname,
! 895: usbd_errstr(err));
! 896: kue_stop(sc);
! 897: return (EIO);
! 898: }
! 899:
! 900: sc->kue_cdata.kue_tx_cnt++;
! 901:
! 902: return (0);
! 903: }
! 904:
! 905: void
! 906: kue_start(struct ifnet *ifp)
! 907: {
! 908: struct kue_softc *sc = ifp->if_softc;
! 909: struct mbuf *m_head = NULL;
! 910:
! 911: DPRINTFN(10,("%s: %s: enter\n", sc->kue_dev.dv_xname,__func__));
! 912:
! 913: if (sc->kue_dying)
! 914: return;
! 915:
! 916: if (ifp->if_flags & IFF_OACTIVE)
! 917: return;
! 918:
! 919: IFQ_POLL(&ifp->if_snd, m_head);
! 920: if (m_head == NULL)
! 921: return;
! 922:
! 923: if (kue_send(sc, m_head, 0)) {
! 924: ifp->if_flags |= IFF_OACTIVE;
! 925: return;
! 926: }
! 927:
! 928: IFQ_DEQUEUE(&ifp->if_snd, m_head);
! 929:
! 930: #if NBPFILTER > 0
! 931: /*
! 932: * If there's a BPF listener, bounce a copy of this frame
! 933: * to him.
! 934: */
! 935: if (ifp->if_bpf)
! 936: bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
! 937: #endif
! 938:
! 939: ifp->if_flags |= IFF_OACTIVE;
! 940:
! 941: /*
! 942: * Set a timeout in case the chip goes out to lunch.
! 943: */
! 944: ifp->if_timer = 6;
! 945: }
! 946:
! 947: void
! 948: kue_init(void *xsc)
! 949: {
! 950: struct kue_softc *sc = xsc;
! 951: struct ifnet *ifp = GET_IFP(sc);
! 952: int s;
! 953: u_char *eaddr;
! 954:
! 955: DPRINTFN(5,("%s: %s: enter\n", sc->kue_dev.dv_xname,__func__));
! 956:
! 957: if (ifp->if_flags & IFF_RUNNING)
! 958: return;
! 959:
! 960: s = splnet();
! 961:
! 962: eaddr = sc->arpcom.ac_enaddr;
! 963: /* Set MAC address */
! 964: kue_ctl(sc, KUE_CTL_WRITE, KUE_CMD_SET_MAC, 0, eaddr, ETHER_ADDR_LEN);
! 965:
! 966: sc->kue_rxfilt = KUE_RXFILT_UNICAST | KUE_RXFILT_BROADCAST;
! 967:
! 968: /* If we want promiscuous mode, set the allframes bit. */
! 969: if (ifp->if_flags & IFF_PROMISC)
! 970: sc->kue_rxfilt |= KUE_RXFILT_PROMISC;
! 971:
! 972: kue_setword(sc, KUE_CMD_SET_PKT_FILTER, sc->kue_rxfilt);
! 973:
! 974: /* I'm not sure how to tune these. */
! 975: #if 0
! 976: /*
! 977: * Leave this one alone for now; setting it
! 978: * wrong causes lockups on some machines/controllers.
! 979: */
! 980: kue_setword(sc, KUE_CMD_SET_SOFS, 1);
! 981: #endif
! 982: kue_setword(sc, KUE_CMD_SET_URB_SIZE, 64);
! 983:
! 984: /* Init TX ring. */
! 985: if (kue_tx_list_init(sc) == ENOBUFS) {
! 986: printf("%s: tx list init failed\n", sc->kue_dev.dv_xname);
! 987: splx(s);
! 988: return;
! 989: }
! 990:
! 991: /* Init RX ring. */
! 992: if (kue_rx_list_init(sc) == ENOBUFS) {
! 993: printf("%s: rx list init failed\n", sc->kue_dev.dv_xname);
! 994: splx(s);
! 995: return;
! 996: }
! 997:
! 998: /* Load the multicast filter. */
! 999: kue_setmulti(sc);
! 1000:
! 1001: if (sc->kue_ep[KUE_ENDPT_RX] == NULL) {
! 1002: if (kue_open_pipes(sc)) {
! 1003: splx(s);
! 1004: return;
! 1005: }
! 1006: }
! 1007:
! 1008: ifp->if_flags |= IFF_RUNNING;
! 1009: ifp->if_flags &= ~IFF_OACTIVE;
! 1010:
! 1011: splx(s);
! 1012: }
! 1013:
! 1014: int
! 1015: kue_open_pipes(struct kue_softc *sc)
! 1016: {
! 1017: usbd_status err;
! 1018: struct kue_chain *c;
! 1019: int i;
! 1020:
! 1021: DPRINTFN(5,("%s: %s: enter\n", sc->kue_dev.dv_xname,__func__));
! 1022:
! 1023: /* Open RX and TX pipes. */
! 1024: err = usbd_open_pipe(sc->kue_iface, sc->kue_ed[KUE_ENDPT_RX],
! 1025: USBD_EXCLUSIVE_USE, &sc->kue_ep[KUE_ENDPT_RX]);
! 1026: if (err) {
! 1027: printf("%s: open rx pipe failed: %s\n",
! 1028: sc->kue_dev.dv_xname, usbd_errstr(err));
! 1029: return (EIO);
! 1030: }
! 1031:
! 1032: err = usbd_open_pipe(sc->kue_iface, sc->kue_ed[KUE_ENDPT_TX],
! 1033: USBD_EXCLUSIVE_USE, &sc->kue_ep[KUE_ENDPT_TX]);
! 1034: if (err) {
! 1035: printf("%s: open tx pipe failed: %s\n",
! 1036: sc->kue_dev.dv_xname, usbd_errstr(err));
! 1037: return (EIO);
! 1038: }
! 1039:
! 1040: /* Start up the receive pipe. */
! 1041: for (i = 0; i < KUE_RX_LIST_CNT; i++) {
! 1042: c = &sc->kue_cdata.kue_rx_chain[i];
! 1043: usbd_setup_xfer(c->kue_xfer, sc->kue_ep[KUE_ENDPT_RX],
! 1044: c, c->kue_buf, KUE_BUFSZ,
! 1045: USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
! 1046: kue_rxeof);
! 1047: DPRINTFN(5,("%s: %s: start read\n", sc->kue_dev.dv_xname,
! 1048: __func__));
! 1049: usbd_transfer(c->kue_xfer);
! 1050: }
! 1051:
! 1052: return (0);
! 1053: }
! 1054:
! 1055: int
! 1056: kue_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
! 1057: {
! 1058: struct kue_softc *sc = ifp->if_softc;
! 1059: struct ifaddr *ifa = (struct ifaddr *)data;
! 1060: struct ifreq *ifr = (struct ifreq *)data;
! 1061: int s, error = 0;
! 1062:
! 1063: DPRINTFN(5,("%s: %s: enter\n", sc->kue_dev.dv_xname,__func__));
! 1064:
! 1065: if (sc->kue_dying)
! 1066: return (EIO);
! 1067:
! 1068: #ifdef DIAGNOSTIC
! 1069: if (!curproc) {
! 1070: printf("%s: no proc!!\n", sc->kue_dev.dv_xname);
! 1071: return EIO;
! 1072: }
! 1073: #endif
! 1074:
! 1075: s = splnet();
! 1076:
! 1077: switch(command) {
! 1078: case SIOCSIFADDR:
! 1079: ifp->if_flags |= IFF_UP;
! 1080: kue_init(sc);
! 1081:
! 1082: switch (ifa->ifa_addr->sa_family) {
! 1083: #ifdef INET
! 1084: case AF_INET:
! 1085: arp_ifinit(&sc->arpcom, ifa);
! 1086: break;
! 1087: #endif /* INET */
! 1088: }
! 1089: break;
! 1090:
! 1091: case SIOCSIFMTU:
! 1092: if (ifr->ifr_mtu > ETHERMTU)
! 1093: error = EINVAL;
! 1094: else
! 1095: ifp->if_mtu = ifr->ifr_mtu;
! 1096: break;
! 1097:
! 1098: case SIOCSIFFLAGS:
! 1099: if (ifp->if_flags & IFF_UP) {
! 1100: if (ifp->if_flags & IFF_RUNNING &&
! 1101: ifp->if_flags & IFF_PROMISC &&
! 1102: !(sc->kue_if_flags & IFF_PROMISC)) {
! 1103: sc->kue_rxfilt |= KUE_RXFILT_PROMISC;
! 1104: kue_setword(sc, KUE_CMD_SET_PKT_FILTER,
! 1105: sc->kue_rxfilt);
! 1106: } else if (ifp->if_flags & IFF_RUNNING &&
! 1107: !(ifp->if_flags & IFF_PROMISC) &&
! 1108: sc->kue_if_flags & IFF_PROMISC) {
! 1109: sc->kue_rxfilt &= ~KUE_RXFILT_PROMISC;
! 1110: kue_setword(sc, KUE_CMD_SET_PKT_FILTER,
! 1111: sc->kue_rxfilt);
! 1112: } else if (!(ifp->if_flags & IFF_RUNNING))
! 1113: kue_init(sc);
! 1114: } else {
! 1115: if (ifp->if_flags & IFF_RUNNING)
! 1116: kue_stop(sc);
! 1117: }
! 1118: sc->kue_if_flags = ifp->if_flags;
! 1119: error = 0;
! 1120: break;
! 1121: case SIOCADDMULTI:
! 1122: case SIOCDELMULTI:
! 1123: error = (command == SIOCADDMULTI) ?
! 1124: ether_addmulti(ifr, &sc->arpcom) :
! 1125: ether_delmulti(ifr, &sc->arpcom);
! 1126:
! 1127: if (error == ENETRESET) {
! 1128: /*
! 1129: * Multicast list has changed; set the hardware
! 1130: * filter accordingly.
! 1131: */
! 1132: if (ifp->if_flags & IFF_RUNNING)
! 1133: kue_setmulti(sc);
! 1134: error = 0;
! 1135: }
! 1136: break;
! 1137: default:
! 1138: error = EINVAL;
! 1139: break;
! 1140: }
! 1141:
! 1142: splx(s);
! 1143:
! 1144: return (error);
! 1145: }
! 1146:
! 1147: void
! 1148: kue_watchdog(struct ifnet *ifp)
! 1149: {
! 1150: struct kue_softc *sc = ifp->if_softc;
! 1151: struct kue_chain *c;
! 1152: usbd_status stat;
! 1153: int s;
! 1154:
! 1155: DPRINTFN(5,("%s: %s: enter\n", sc->kue_dev.dv_xname,__func__));
! 1156:
! 1157: if (sc->kue_dying)
! 1158: return;
! 1159:
! 1160: ifp->if_oerrors++;
! 1161: printf("%s: watchdog timeout\n", sc->kue_dev.dv_xname);
! 1162:
! 1163: s = splusb();
! 1164: c = &sc->kue_cdata.kue_tx_chain[0];
! 1165: usbd_get_xfer_status(c->kue_xfer, NULL, NULL, NULL, &stat);
! 1166: kue_txeof(c->kue_xfer, c, stat);
! 1167:
! 1168: if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
! 1169: kue_start(ifp);
! 1170: splx(s);
! 1171: }
! 1172:
! 1173: /*
! 1174: * Stop the adapter and free any mbufs allocated to the
! 1175: * RX and TX lists.
! 1176: */
! 1177: void
! 1178: kue_stop(struct kue_softc *sc)
! 1179: {
! 1180: usbd_status err;
! 1181: struct ifnet *ifp;
! 1182: int i;
! 1183:
! 1184: DPRINTFN(5,("%s: %s: enter\n", sc->kue_dev.dv_xname,__func__));
! 1185:
! 1186: ifp = GET_IFP(sc);
! 1187: ifp->if_timer = 0;
! 1188: ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
! 1189:
! 1190: /* Stop transfers. */
! 1191: if (sc->kue_ep[KUE_ENDPT_RX] != NULL) {
! 1192: err = usbd_abort_pipe(sc->kue_ep[KUE_ENDPT_RX]);
! 1193: if (err) {
! 1194: printf("%s: abort rx pipe failed: %s\n",
! 1195: sc->kue_dev.dv_xname, usbd_errstr(err));
! 1196: }
! 1197: err = usbd_close_pipe(sc->kue_ep[KUE_ENDPT_RX]);
! 1198: if (err) {
! 1199: printf("%s: close rx pipe failed: %s\n",
! 1200: sc->kue_dev.dv_xname, usbd_errstr(err));
! 1201: }
! 1202: sc->kue_ep[KUE_ENDPT_RX] = NULL;
! 1203: }
! 1204:
! 1205: if (sc->kue_ep[KUE_ENDPT_TX] != NULL) {
! 1206: err = usbd_abort_pipe(sc->kue_ep[KUE_ENDPT_TX]);
! 1207: if (err) {
! 1208: printf("%s: abort tx pipe failed: %s\n",
! 1209: sc->kue_dev.dv_xname, usbd_errstr(err));
! 1210: }
! 1211: err = usbd_close_pipe(sc->kue_ep[KUE_ENDPT_TX]);
! 1212: if (err) {
! 1213: printf("%s: close tx pipe failed: %s\n",
! 1214: sc->kue_dev.dv_xname, usbd_errstr(err));
! 1215: }
! 1216: sc->kue_ep[KUE_ENDPT_TX] = NULL;
! 1217: }
! 1218:
! 1219: if (sc->kue_ep[KUE_ENDPT_INTR] != NULL) {
! 1220: err = usbd_abort_pipe(sc->kue_ep[KUE_ENDPT_INTR]);
! 1221: if (err) {
! 1222: printf("%s: abort intr pipe failed: %s\n",
! 1223: sc->kue_dev.dv_xname, usbd_errstr(err));
! 1224: }
! 1225: err = usbd_close_pipe(sc->kue_ep[KUE_ENDPT_INTR]);
! 1226: if (err) {
! 1227: printf("%s: close intr pipe failed: %s\n",
! 1228: sc->kue_dev.dv_xname, usbd_errstr(err));
! 1229: }
! 1230: sc->kue_ep[KUE_ENDPT_INTR] = NULL;
! 1231: }
! 1232:
! 1233: /* Free RX resources. */
! 1234: for (i = 0; i < KUE_RX_LIST_CNT; i++) {
! 1235: if (sc->kue_cdata.kue_rx_chain[i].kue_mbuf != NULL) {
! 1236: m_freem(sc->kue_cdata.kue_rx_chain[i].kue_mbuf);
! 1237: sc->kue_cdata.kue_rx_chain[i].kue_mbuf = NULL;
! 1238: }
! 1239: if (sc->kue_cdata.kue_rx_chain[i].kue_xfer != NULL) {
! 1240: usbd_free_xfer(sc->kue_cdata.kue_rx_chain[i].kue_xfer);
! 1241: sc->kue_cdata.kue_rx_chain[i].kue_xfer = NULL;
! 1242: }
! 1243: }
! 1244:
! 1245: /* Free TX resources. */
! 1246: for (i = 0; i < KUE_TX_LIST_CNT; i++) {
! 1247: if (sc->kue_cdata.kue_tx_chain[i].kue_mbuf != NULL) {
! 1248: m_freem(sc->kue_cdata.kue_tx_chain[i].kue_mbuf);
! 1249: sc->kue_cdata.kue_tx_chain[i].kue_mbuf = NULL;
! 1250: }
! 1251: if (sc->kue_cdata.kue_tx_chain[i].kue_xfer != NULL) {
! 1252: usbd_free_xfer(sc->kue_cdata.kue_tx_chain[i].kue_xfer);
! 1253: sc->kue_cdata.kue_tx_chain[i].kue_xfer = NULL;
! 1254: }
! 1255: }
! 1256: }
CVSweb