Annotation of sys/dev/usb/if_aue.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_aue.c,v 1.65 2007/06/14 10:11:15 mbalmer Exp $ */
! 2: /* $NetBSD: if_aue.c,v 1.82 2003/03/05 17:37:36 shiba 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_aue.c,v 1.11 2000/01/14 01:36:14 wpaul Exp $
! 35: */
! 36:
! 37: /*
! 38: * ADMtek AN986 Pegasus and AN8511 Pegasus II USB to ethernet driver.
! 39: * Datasheet is available from http://www.admtek.com.tw.
! 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 Pegasus chip uses four USB "endpoints" to provide 10/100 ethernet
! 48: * support: the control endpoint for reading/writing registers, burst
! 49: * read endpoint for packet reception, burst write for packet transmission
! 50: * and one for "interrupts." The chip uses the same RX filter scheme
! 51: * as the other ADMtek ethernet parts: one perfect filter entry for the
! 52: * the station address and a 64-bit multicast hash table. The chip supports
! 53: * both MII and HomePNA attachments.
! 54: *
! 55: * Since the maximum data transfer speed of USB is supposed to be 12Mbps,
! 56: * you're never really going to get 100Mbps speeds from this device. I
! 57: * think the idea is to allow the device to connect to 10 or 100Mbps
! 58: * networks, not necessarily to provide 100Mbps performance. Also, since
! 59: * the controller uses an external PHY chip, it's possible that board
! 60: * designers might simply choose a 10Mbps PHY.
! 61: *
! 62: * Registers are accessed using usbd_do_request(). Packet transfers are
! 63: * done using usbd_transfer() and friends.
! 64: */
! 65:
! 66: /*
! 67: * Ported to NetBSD and somewhat rewritten by Lennart Augustsson.
! 68: */
! 69:
! 70: /*
! 71: * TODO:
! 72: * better error messages from rxstat
! 73: * split out if_auevar.h
! 74: * add thread to avoid register reads from interrupt context
! 75: * more error checks
! 76: * investigate short rx problem
! 77: * proper cleanup on errors
! 78: */
! 79:
! 80: #include "bpfilter.h"
! 81:
! 82: #include <sys/param.h>
! 83: #include <sys/systm.h>
! 84: #include <sys/sockio.h>
! 85: #include <sys/rwlock.h>
! 86: #include <sys/mbuf.h>
! 87: #include <sys/malloc.h>
! 88: #include <sys/kernel.h>
! 89: #include <sys/proc.h>
! 90: #include <sys/socket.h>
! 91:
! 92: #include <sys/device.h>
! 93:
! 94: #include <net/if.h>
! 95: #include <net/if_dl.h>
! 96: #include <net/if_media.h>
! 97:
! 98: #if NBPFILTER > 0
! 99: #include <net/bpf.h>
! 100: #endif
! 101:
! 102: #ifdef INET
! 103: #include <netinet/in.h>
! 104: #include <netinet/in_systm.h>
! 105: #include <netinet/in_var.h>
! 106: #include <netinet/ip.h>
! 107: #include <netinet/if_ether.h>
! 108: #endif
! 109:
! 110: #include <dev/mii/mii.h>
! 111: #include <dev/mii/miivar.h>
! 112:
! 113: #include <dev/usb/usb.h>
! 114: #include <dev/usb/usbdi.h>
! 115: #include <dev/usb/usbdi_util.h>
! 116: #include <dev/usb/usbdevs.h>
! 117:
! 118: #include <dev/usb/if_auereg.h>
! 119:
! 120: #ifdef AUE_DEBUG
! 121: #define DPRINTF(x) do { if (auedebug) printf x; } while (0)
! 122: #define DPRINTFN(n,x) do { if (auedebug >= (n)) printf x; } while (0)
! 123: int auedebug = 0;
! 124: #else
! 125: #define DPRINTF(x)
! 126: #define DPRINTFN(n,x)
! 127: #endif
! 128:
! 129: /*
! 130: * Various supported device vendors/products.
! 131: */
! 132: struct aue_type {
! 133: struct usb_devno aue_dev;
! 134: u_int16_t aue_flags;
! 135: #define LSYS 0x0001 /* use Linksys reset */
! 136: #define PNA 0x0002 /* has Home PNA */
! 137: #define PII 0x0004 /* Pegasus II chip */
! 138: };
! 139:
! 140: const struct aue_type aue_devs[] = {
! 141: {{ USB_VENDOR_3COM, USB_PRODUCT_3COM_3C460B}, PII },
! 142: {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX1}, PNA|PII },
! 143: {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX2}, PII },
! 144: {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_UFE1000}, LSYS },
! 145: {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX4}, PNA },
! 146: {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX5}, PNA },
! 147: {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX6}, PII },
! 148: {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX7}, PII },
! 149: {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX8}, PII },
! 150: {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX9}, PNA },
! 151: {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX10}, 0 },
! 152: {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_DSB650TX_PNA}, 0 },
! 153: {{ USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_USB320_EC}, 0 },
! 154: {{ USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_SS1001}, PII },
! 155: {{ USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUS}, PNA },
! 156: {{ USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUSII}, PII },
! 157: {{ USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUSII_2}, PII },
! 158: {{ USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUSII_3}, PII },
! 159: {{ USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUSII_4}, PII },
! 160: {{ USB_VENDOR_AEI, USB_PRODUCT_AEI_FASTETHERNET}, PII },
! 161: {{ USB_VENDOR_ALLIEDTELESYN, USB_PRODUCT_ALLIEDTELESYN_ATUSB100}, PII },
! 162: {{ USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC110T}, PII },
! 163: {{ USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D5050}, PII },
! 164: {{ USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USB100}, 0 },
! 165: {{ USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USBLP100}, PNA },
! 166: {{ USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USBEL100}, 0 },
! 167: {{ USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USBE100}, PII },
! 168: {{ USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TX}, 0 },
! 169: {{ USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TXS},PII },
! 170: {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX4}, LSYS|PII },
! 171: {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX1}, LSYS },
! 172: {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX}, LSYS },
! 173: {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX_PNA}, PNA },
! 174: {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX3}, LSYS|PII },
! 175: {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX2}, LSYS|PII },
! 176: {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650}, 0 },
! 177: {{ USB_VENDOR_ELCON, USB_PRODUCT_ELCON_PLAN}, PNA|PII },
! 178: {{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX0}, 0 },
! 179: {{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX1}, LSYS },
! 180: {{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX2}, 0 },
! 181: {{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX3}, LSYS },
! 182: {{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBLTX}, PII },
! 183: {{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSB20}, PII },
! 184: {{ USB_VENDOR_ELSA, USB_PRODUCT_ELSA_USB2ETHERNET}, 0 },
! 185: {{ USB_VENDOR_GIGABYTE, USB_PRODUCT_GIGABYTE_GNBR402W}, 0 },
! 186: {{ USB_VENDOR_HAWKING, USB_PRODUCT_HAWKING_UF100}, PII },
! 187: {{ USB_VENDOR_HP, USB_PRODUCT_HP_HN210E}, PII },
! 188: {{ USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBETTX}, 0 },
! 189: {{ USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBETTXS}, PII },
! 190: {{ USB_VENDOR_KINGSTON, USB_PRODUCT_KINGSTON_KNU101TX}, 0 },
! 191: {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10TX1}, LSYS|PII },
! 192: {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10T}, LSYS },
! 193: {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB100TX}, LSYS },
! 194: {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB100H1}, LSYS|PNA },
! 195: {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10TA}, LSYS },
! 196: {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10TX2}, LSYS|PII },
! 197: {{ USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_MN110}, PII },
! 198: {{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUATX1}, 0 },
! 199: {{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUATX5}, 0 },
! 200: {{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUA2TX5}, PII },
! 201: {{ USB_VENDOR_MOBILITY, USB_PRODUCT_MOBILITY_EASIDOCK}, 0 },
! 202: {{ USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_FA101}, PII },
! 203: {{ USB_VENDOR_SIEMENS, USB_PRODUCT_SIEMENS_SPEEDSTREAM}, PII },
! 204: {{ USB_VENDOR_SIIG2, USB_PRODUCT_SIIG2_USBTOETHER}, PII },
! 205: {{ USB_VENDOR_SMARTBRIDGES, USB_PRODUCT_SMARTBRIDGES_SMARTNIC},PII },
! 206: {{ USB_VENDOR_SMC, USB_PRODUCT_SMC_2202USB}, 0 },
! 207: {{ USB_VENDOR_SMC, USB_PRODUCT_SMC_2206USB}, PII },
! 208: {{ USB_VENDOR_SOHOWARE, USB_PRODUCT_SOHOWARE_NUB100}, 0 },
! 209: {{ USB_VENDOR_SOHOWARE, USB_PRODUCT_SOHOWARE_NUB110}, PII },
! 210: };
! 211: #define aue_lookup(v, p) ((struct aue_type *)usb_lookup(aue_devs, v, p))
! 212:
! 213: int aue_match(struct device *, void *, void *);
! 214: void aue_attach(struct device *, struct device *, void *);
! 215: int aue_detach(struct device *, int);
! 216: int aue_activate(struct device *, enum devact);
! 217:
! 218: struct cfdriver aue_cd = {
! 219: NULL, "aue", DV_IFNET
! 220: };
! 221:
! 222: const struct cfattach aue_ca = {
! 223: sizeof(struct aue_softc),
! 224: aue_match,
! 225: aue_attach,
! 226: aue_detach,
! 227: aue_activate,
! 228: };
! 229:
! 230: void aue_reset_pegasus_II(struct aue_softc *sc);
! 231: int aue_tx_list_init(struct aue_softc *);
! 232: int aue_rx_list_init(struct aue_softc *);
! 233: int aue_newbuf(struct aue_softc *, struct aue_chain *, struct mbuf *);
! 234: int aue_send(struct aue_softc *, struct mbuf *, int);
! 235: void aue_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
! 236: void aue_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
! 237: void aue_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
! 238: void aue_tick(void *);
! 239: void aue_tick_task(void *);
! 240: void aue_start(struct ifnet *);
! 241: int aue_ioctl(struct ifnet *, u_long, caddr_t);
! 242: void aue_init(void *);
! 243: void aue_shutdown(void *);
! 244: void aue_stop(struct aue_softc *);
! 245: void aue_watchdog(struct ifnet *);
! 246: int aue_openpipes(struct aue_softc *);
! 247: int aue_ifmedia_upd(struct ifnet *);
! 248: void aue_ifmedia_sts(struct ifnet *, struct ifmediareq *);
! 249:
! 250: int aue_eeprom_getword(struct aue_softc *, int);
! 251: void aue_read_mac(struct aue_softc *, u_char *);
! 252: int aue_miibus_readreg(struct device *, int, int);
! 253: void aue_miibus_writereg(struct device *, int, int, int);
! 254: void aue_miibus_statchg(struct device *);
! 255:
! 256: void aue_lock_mii(struct aue_softc *);
! 257: void aue_unlock_mii(struct aue_softc *);
! 258:
! 259: void aue_setmulti(struct aue_softc *);
! 260: u_int32_t aue_crc(caddr_t);
! 261: void aue_reset(struct aue_softc *);
! 262:
! 263: int aue_csr_read_1(struct aue_softc *, int);
! 264: int aue_csr_write_1(struct aue_softc *, int, int);
! 265: int aue_csr_read_2(struct aue_softc *, int);
! 266: int aue_csr_write_2(struct aue_softc *, int, int);
! 267:
! 268: #define AUE_SETBIT(sc, reg, x) \
! 269: aue_csr_write_1(sc, reg, aue_csr_read_1(sc, reg) | (x))
! 270:
! 271: #define AUE_CLRBIT(sc, reg, x) \
! 272: aue_csr_write_1(sc, reg, aue_csr_read_1(sc, reg) & ~(x))
! 273:
! 274: int
! 275: aue_csr_read_1(struct aue_softc *sc, int reg)
! 276: {
! 277: usb_device_request_t req;
! 278: usbd_status err;
! 279: uByte val = 0;
! 280:
! 281: if (sc->aue_dying)
! 282: return (0);
! 283:
! 284: req.bmRequestType = UT_READ_VENDOR_DEVICE;
! 285: req.bRequest = AUE_UR_READREG;
! 286: USETW(req.wValue, 0);
! 287: USETW(req.wIndex, reg);
! 288: USETW(req.wLength, 1);
! 289:
! 290: err = usbd_do_request(sc->aue_udev, &req, &val);
! 291:
! 292: if (err) {
! 293: DPRINTF(("%s: aue_csr_read_1: reg=0x%x err=%s\n",
! 294: sc->aue_dev.dv_xname, reg, usbd_errstr(err)));
! 295: return (0);
! 296: }
! 297:
! 298: return (val);
! 299: }
! 300:
! 301: int
! 302: aue_csr_read_2(struct aue_softc *sc, int reg)
! 303: {
! 304: usb_device_request_t req;
! 305: usbd_status err;
! 306: uWord val;
! 307:
! 308: if (sc->aue_dying)
! 309: return (0);
! 310:
! 311: req.bmRequestType = UT_READ_VENDOR_DEVICE;
! 312: req.bRequest = AUE_UR_READREG;
! 313: USETW(req.wValue, 0);
! 314: USETW(req.wIndex, reg);
! 315: USETW(req.wLength, 2);
! 316:
! 317: err = usbd_do_request(sc->aue_udev, &req, &val);
! 318:
! 319: if (err) {
! 320: DPRINTF(("%s: aue_csr_read_2: reg=0x%x err=%s\n",
! 321: sc->aue_dev.dv_xname, reg, usbd_errstr(err)));
! 322: return (0);
! 323: }
! 324:
! 325: return (UGETW(val));
! 326: }
! 327:
! 328: int
! 329: aue_csr_write_1(struct aue_softc *sc, int reg, int aval)
! 330: {
! 331: usb_device_request_t req;
! 332: usbd_status err;
! 333: uByte val;
! 334:
! 335: if (sc->aue_dying)
! 336: return (0);
! 337:
! 338: val = aval;
! 339: req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
! 340: req.bRequest = AUE_UR_WRITEREG;
! 341: USETW(req.wValue, val);
! 342: USETW(req.wIndex, reg);
! 343: USETW(req.wLength, 1);
! 344:
! 345: err = usbd_do_request(sc->aue_udev, &req, &val);
! 346:
! 347: if (err) {
! 348: DPRINTF(("%s: aue_csr_write_1: reg=0x%x err=%s\n",
! 349: sc->aue_dev.dv_xname, reg, usbd_errstr(err)));
! 350: return (-1);
! 351: }
! 352:
! 353: return (0);
! 354: }
! 355:
! 356: int
! 357: aue_csr_write_2(struct aue_softc *sc, int reg, int aval)
! 358: {
! 359: usb_device_request_t req;
! 360: usbd_status err;
! 361: uWord val;
! 362:
! 363: if (sc->aue_dying)
! 364: return (0);
! 365:
! 366: USETW(val, aval);
! 367: req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
! 368: req.bRequest = AUE_UR_WRITEREG;
! 369: USETW(req.wValue, aval);
! 370: USETW(req.wIndex, reg);
! 371: USETW(req.wLength, 2);
! 372:
! 373: err = usbd_do_request(sc->aue_udev, &req, &val);
! 374:
! 375: if (err) {
! 376: DPRINTF(("%s: aue_csr_write_2: reg=0x%x err=%s\n",
! 377: sc->aue_dev.dv_xname, reg, usbd_errstr(err)));
! 378: return (-1);
! 379: }
! 380:
! 381: return (0);
! 382: }
! 383:
! 384: /*
! 385: * Read a word of data stored in the EEPROM at address 'addr.'
! 386: */
! 387: int
! 388: aue_eeprom_getword(struct aue_softc *sc, int addr)
! 389: {
! 390: int i;
! 391:
! 392: aue_csr_write_1(sc, AUE_EE_REG, addr);
! 393: aue_csr_write_1(sc, AUE_EE_CTL, AUE_EECTL_READ);
! 394:
! 395: for (i = 0; i < AUE_TIMEOUT; i++) {
! 396: if (aue_csr_read_1(sc, AUE_EE_CTL) & AUE_EECTL_DONE)
! 397: break;
! 398: }
! 399:
! 400: if (i == AUE_TIMEOUT) {
! 401: printf("%s: EEPROM read timed out\n",
! 402: sc->aue_dev.dv_xname);
! 403: }
! 404:
! 405: return (aue_csr_read_2(sc, AUE_EE_DATA));
! 406: }
! 407:
! 408: /*
! 409: * Read the MAC from the EEPROM. It's at offset 0.
! 410: */
! 411: void
! 412: aue_read_mac(struct aue_softc *sc, u_char *dest)
! 413: {
! 414: int i;
! 415: int off = 0;
! 416: int word;
! 417:
! 418: DPRINTFN(5,("%s: %s: enter\n", sc->aue_dev.dv_xname, __func__));
! 419:
! 420: for (i = 0; i < 3; i++) {
! 421: word = aue_eeprom_getword(sc, off + i);
! 422: dest[2 * i] = (u_char)word;
! 423: dest[2 * i + 1] = (u_char)(word >> 8);
! 424: }
! 425: }
! 426:
! 427: /* Get exclusive access to the MII registers */
! 428: void
! 429: aue_lock_mii(struct aue_softc *sc)
! 430: {
! 431: sc->aue_refcnt++;
! 432: rw_enter_write(&sc->aue_mii_lock);
! 433: }
! 434:
! 435: void
! 436: aue_unlock_mii(struct aue_softc *sc)
! 437: {
! 438: rw_exit_write(&sc->aue_mii_lock);
! 439: if (--sc->aue_refcnt < 0)
! 440: usb_detach_wakeup(&sc->aue_dev);
! 441: }
! 442:
! 443: int
! 444: aue_miibus_readreg(struct device *dev, int phy, int reg)
! 445: {
! 446: struct aue_softc *sc = (void *)dev;
! 447: int i;
! 448: u_int16_t val;
! 449:
! 450: if (sc->aue_dying) {
! 451: #ifdef DIAGNOSTIC
! 452: printf("%s: dying\n", sc->aue_dev.dv_xname);
! 453: #endif
! 454: return 0;
! 455: }
! 456:
! 457: #if 0
! 458: /*
! 459: * The Am79C901 HomePNA PHY actually contains
! 460: * two transceivers: a 1Mbps HomePNA PHY and a
! 461: * 10Mbps full/half duplex ethernet PHY with
! 462: * NWAY autoneg. However in the ADMtek adapter,
! 463: * only the 1Mbps PHY is actually connected to
! 464: * anything, so we ignore the 10Mbps one. It
! 465: * happens to be configured for MII address 3,
! 466: * so we filter that out.
! 467: */
! 468: if (sc->aue_vendor == USB_VENDOR_ADMTEK &&
! 469: sc->aue_product == USB_PRODUCT_ADMTEK_PEGASUS) {
! 470: if (phy == 3)
! 471: return (0);
! 472: }
! 473: #endif
! 474:
! 475: aue_lock_mii(sc);
! 476: aue_csr_write_1(sc, AUE_PHY_ADDR, phy);
! 477: aue_csr_write_1(sc, AUE_PHY_CTL, reg | AUE_PHYCTL_READ);
! 478:
! 479: for (i = 0; i < AUE_TIMEOUT; i++) {
! 480: if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE)
! 481: break;
! 482: }
! 483:
! 484: if (i == AUE_TIMEOUT) {
! 485: printf("%s: MII read timed out\n", sc->aue_dev.dv_xname);
! 486: }
! 487:
! 488: val = aue_csr_read_2(sc, AUE_PHY_DATA);
! 489:
! 490: DPRINTFN(11,("%s: %s: phy=%d reg=%d => 0x%04x\n",
! 491: sc->aue_dev.dv_xname, __func__, phy, reg, val));
! 492:
! 493: aue_unlock_mii(sc);
! 494: return (val);
! 495: }
! 496:
! 497: void
! 498: aue_miibus_writereg(struct device *dev, int phy, int reg, int data)
! 499: {
! 500: struct aue_softc *sc = (void *)dev;
! 501: int i;
! 502:
! 503: #if 0
! 504: if (sc->aue_vendor == USB_VENDOR_ADMTEK &&
! 505: sc->aue_product == USB_PRODUCT_ADMTEK_PEGASUS) {
! 506: if (phy == 3)
! 507: return;
! 508: }
! 509: #endif
! 510:
! 511: DPRINTFN(11,("%s: %s: phy=%d reg=%d data=0x%04x\n",
! 512: sc->aue_dev.dv_xname, __func__, phy, reg, data));
! 513:
! 514: aue_lock_mii(sc);
! 515: aue_csr_write_2(sc, AUE_PHY_DATA, data);
! 516: aue_csr_write_1(sc, AUE_PHY_ADDR, phy);
! 517: aue_csr_write_1(sc, AUE_PHY_CTL, reg | AUE_PHYCTL_WRITE);
! 518:
! 519: for (i = 0; i < AUE_TIMEOUT; i++) {
! 520: if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE)
! 521: break;
! 522: }
! 523:
! 524: if (i == AUE_TIMEOUT) {
! 525: printf("%s: MII read timed out\n",
! 526: sc->aue_dev.dv_xname);
! 527: }
! 528: aue_unlock_mii(sc);
! 529: }
! 530:
! 531: void
! 532: aue_miibus_statchg(struct device *dev)
! 533: {
! 534: struct aue_softc *sc = (void *)dev;
! 535: struct mii_data *mii = GET_MII(sc);
! 536:
! 537: DPRINTFN(5,("%s: %s: enter\n", sc->aue_dev.dv_xname, __func__));
! 538:
! 539: aue_lock_mii(sc);
! 540: AUE_CLRBIT(sc, AUE_CTL0, AUE_CTL0_RX_ENB | AUE_CTL0_TX_ENB);
! 541:
! 542: if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) {
! 543: AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_SPEEDSEL);
! 544: } else {
! 545: AUE_CLRBIT(sc, AUE_CTL1, AUE_CTL1_SPEEDSEL);
! 546: }
! 547:
! 548: if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX)
! 549: AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_DUPLEX);
! 550: else
! 551: AUE_CLRBIT(sc, AUE_CTL1, AUE_CTL1_DUPLEX);
! 552:
! 553: AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_RX_ENB | AUE_CTL0_TX_ENB);
! 554: aue_unlock_mii(sc);
! 555:
! 556: /*
! 557: * Set the LED modes on the LinkSys adapter.
! 558: * This turns on the 'dual link LED' bin in the auxmode
! 559: * register of the Broadcom PHY.
! 560: */
! 561: if (!sc->aue_dying && (sc->aue_flags & LSYS)) {
! 562: u_int16_t auxmode;
! 563: auxmode = aue_miibus_readreg(dev, 0, 0x1b);
! 564: aue_miibus_writereg(dev, 0, 0x1b, auxmode | 0x04);
! 565: }
! 566: DPRINTFN(5,("%s: %s: exit\n", sc->aue_dev.dv_xname, __func__));
! 567: }
! 568:
! 569: #define AUE_POLY 0xEDB88320
! 570: #define AUE_BITS 6
! 571:
! 572: u_int32_t
! 573: aue_crc(caddr_t addr)
! 574: {
! 575: u_int32_t idx, bit, data, crc;
! 576:
! 577: /* Compute CRC for the address value. */
! 578: crc = 0xFFFFFFFF; /* initial value */
! 579:
! 580: for (idx = 0; idx < 6; idx++) {
! 581: for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1)
! 582: crc = (crc >> 1) ^ (((crc ^ data) & 1) ? AUE_POLY : 0);
! 583: }
! 584:
! 585: return (crc & ((1 << AUE_BITS) - 1));
! 586: }
! 587:
! 588: void
! 589: aue_setmulti(struct aue_softc *sc)
! 590: {
! 591: struct ifnet *ifp;
! 592: struct ether_multi *enm;
! 593: struct ether_multistep step;
! 594: u_int32_t h = 0, i;
! 595:
! 596: DPRINTFN(5,("%s: %s: enter\n", sc->aue_dev.dv_xname, __func__));
! 597:
! 598: ifp = GET_IFP(sc);
! 599:
! 600: if (ifp->if_flags & IFF_PROMISC) {
! 601: allmulti:
! 602: ifp->if_flags |= IFF_ALLMULTI;
! 603: AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_ALLMULTI);
! 604: return;
! 605: }
! 606:
! 607: AUE_CLRBIT(sc, AUE_CTL0, AUE_CTL0_ALLMULTI);
! 608:
! 609: /* first, zot all the existing hash bits */
! 610: for (i = 0; i < 8; i++)
! 611: aue_csr_write_1(sc, AUE_MAR0 + i, 0);
! 612:
! 613: /* now program new ones */
! 614: ETHER_FIRST_MULTI(step, &sc->arpcom, enm);
! 615: while (enm != NULL) {
! 616: if (memcmp(enm->enm_addrlo,
! 617: enm->enm_addrhi, ETHER_ADDR_LEN) != 0)
! 618: goto allmulti;
! 619:
! 620: h = aue_crc(enm->enm_addrlo);
! 621: AUE_SETBIT(sc, AUE_MAR + (h >> 3), 1 << (h & 0x7));
! 622: ETHER_NEXT_MULTI(step, enm);
! 623: }
! 624:
! 625: ifp->if_flags &= ~IFF_ALLMULTI;
! 626: }
! 627:
! 628: void
! 629: aue_reset_pegasus_II(struct aue_softc *sc)
! 630: {
! 631: /* Magic constants taken from Linux driver. */
! 632: aue_csr_write_1(sc, AUE_REG_1D, 0);
! 633: aue_csr_write_1(sc, AUE_REG_7B, 2);
! 634: #if 0
! 635: if ((sc->aue_flags & HAS_HOME_PNA) && mii_mode)
! 636: aue_csr_write_1(sc, AUE_REG_81, 6);
! 637: else
! 638: #endif
! 639: aue_csr_write_1(sc, AUE_REG_81, 2);
! 640: }
! 641:
! 642: void
! 643: aue_reset(struct aue_softc *sc)
! 644: {
! 645: int i;
! 646:
! 647: DPRINTFN(2,("%s: %s: enter\n", sc->aue_dev.dv_xname, __func__));
! 648:
! 649: AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_RESETMAC);
! 650:
! 651: for (i = 0; i < AUE_TIMEOUT; i++) {
! 652: if (!(aue_csr_read_1(sc, AUE_CTL1) & AUE_CTL1_RESETMAC))
! 653: break;
! 654: }
! 655:
! 656: if (i == AUE_TIMEOUT)
! 657: printf("%s: reset failed\n", sc->aue_dev.dv_xname);
! 658:
! 659: #if 0
! 660: /* XXX what is mii_mode supposed to be */
! 661: if (sc->aue_mii_mode && (sc->aue_flags & PNA))
! 662: aue_csr_write_1(sc, AUE_GPIO1, 0x34);
! 663: else
! 664: aue_csr_write_1(sc, AUE_GPIO1, 0x26);
! 665: #endif
! 666:
! 667: /*
! 668: * The PHY(s) attached to the Pegasus chip may be held
! 669: * in reset until we flip on the GPIO outputs. Make sure
! 670: * to set the GPIO pins high so that the PHY(s) will
! 671: * be enabled.
! 672: *
! 673: * Note: We force all of the GPIO pins low first, *then*
! 674: * enable the ones we want.
! 675: */
! 676: if (sc->aue_flags & LSYS) {
! 677: /* Grrr. LinkSys has to be different from everyone else. */
! 678: aue_csr_write_1(sc, AUE_GPIO0,
! 679: AUE_GPIO_SEL0 | AUE_GPIO_SEL1);
! 680: } else {
! 681: aue_csr_write_1(sc, AUE_GPIO0,
! 682: AUE_GPIO_OUT0 | AUE_GPIO_SEL0);
! 683: }
! 684: aue_csr_write_1(sc, AUE_GPIO0,
! 685: AUE_GPIO_OUT0 | AUE_GPIO_SEL0 | AUE_GPIO_SEL1);
! 686:
! 687: if (sc->aue_flags & PII)
! 688: aue_reset_pegasus_II(sc);
! 689:
! 690: /* Wait a little while for the chip to get its brains in order. */
! 691: delay(10000); /* XXX */
! 692: }
! 693:
! 694: /*
! 695: * Probe for a Pegasus chip.
! 696: */
! 697: int
! 698: aue_match(struct device *parent, void *match, void *aux)
! 699: {
! 700: struct usb_attach_arg *uaa = aux;
! 701:
! 702: if (uaa->iface != NULL)
! 703: return (UMATCH_NONE);
! 704:
! 705: return (aue_lookup(uaa->vendor, uaa->product) != NULL ?
! 706: UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
! 707: }
! 708:
! 709: /*
! 710: * Attach the interface. Allocate softc structures, do ifmedia
! 711: * setup and ethernet/BPF attach.
! 712: */
! 713: void
! 714: aue_attach(struct device *parent, struct device *self, void *aux)
! 715: {
! 716: struct aue_softc *sc = (struct aue_softc *)self;
! 717: struct usb_attach_arg *uaa = aux;
! 718: char *devinfop;
! 719: int s;
! 720: u_char eaddr[ETHER_ADDR_LEN];
! 721: struct ifnet *ifp;
! 722: struct mii_data *mii;
! 723: usbd_device_handle dev = uaa->device;
! 724: usbd_interface_handle iface;
! 725: usbd_status err;
! 726: usb_interface_descriptor_t *id;
! 727: usb_endpoint_descriptor_t *ed;
! 728: int i;
! 729:
! 730: DPRINTFN(5,(" : aue_attach: sc=%p", sc));
! 731:
! 732: devinfop = usbd_devinfo_alloc(uaa->device, 0);
! 733: printf("\n%s: %s\n", sc->aue_dev.dv_xname, devinfop);
! 734: usbd_devinfo_free(devinfop);
! 735:
! 736: err = usbd_set_config_no(dev, AUE_CONFIG_NO, 1);
! 737: if (err) {
! 738: printf("%s: setting config no failed\n",
! 739: sc->aue_dev.dv_xname);
! 740: return;
! 741: }
! 742:
! 743: usb_init_task(&sc->aue_tick_task, aue_tick_task, sc);
! 744: usb_init_task(&sc->aue_stop_task, (void (*)(void *))aue_stop, sc);
! 745: rw_init(&sc->aue_mii_lock, "auemii");
! 746:
! 747: err = usbd_device2interface_handle(dev, AUE_IFACE_IDX, &iface);
! 748: if (err) {
! 749: printf("%s: getting interface handle failed\n",
! 750: sc->aue_dev.dv_xname);
! 751: return;
! 752: }
! 753:
! 754: sc->aue_flags = aue_lookup(uaa->vendor, uaa->product)->aue_flags;
! 755:
! 756: sc->aue_udev = dev;
! 757: sc->aue_iface = iface;
! 758: sc->aue_product = uaa->product;
! 759: sc->aue_vendor = uaa->vendor;
! 760:
! 761: id = usbd_get_interface_descriptor(iface);
! 762:
! 763: /* Find endpoints. */
! 764: for (i = 0; i < id->bNumEndpoints; i++) {
! 765: ed = usbd_interface2endpoint_descriptor(iface, i);
! 766: if (ed == NULL) {
! 767: printf("%s: couldn't get endpoint descriptor %d\n",
! 768: sc->aue_dev.dv_xname, i);
! 769: return;
! 770: }
! 771: if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
! 772: UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
! 773: sc->aue_ed[AUE_ENDPT_RX] = ed->bEndpointAddress;
! 774: } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
! 775: UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
! 776: sc->aue_ed[AUE_ENDPT_TX] = ed->bEndpointAddress;
! 777: } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
! 778: UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
! 779: sc->aue_ed[AUE_ENDPT_INTR] = ed->bEndpointAddress;
! 780: }
! 781: }
! 782:
! 783: if (sc->aue_ed[AUE_ENDPT_RX] == 0 || sc->aue_ed[AUE_ENDPT_TX] == 0 ||
! 784: sc->aue_ed[AUE_ENDPT_INTR] == 0) {
! 785: printf("%s: missing endpoint\n", sc->aue_dev.dv_xname);
! 786: return;
! 787: }
! 788:
! 789:
! 790: s = splnet();
! 791:
! 792: /* Reset the adapter. */
! 793: aue_reset(sc);
! 794:
! 795: /*
! 796: * Get station address from the EEPROM.
! 797: */
! 798: aue_read_mac(sc, eaddr);
! 799:
! 800: /*
! 801: * A Pegasus chip was detected. Inform the world.
! 802: */
! 803: ifp = GET_IFP(sc);
! 804: printf("%s: address %s\n", sc->aue_dev.dv_xname,
! 805: ether_sprintf(eaddr));
! 806:
! 807: bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
! 808:
! 809: /* Initialize interface info.*/
! 810: ifp->if_softc = sc;
! 811: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
! 812: ifp->if_ioctl = aue_ioctl;
! 813: ifp->if_start = aue_start;
! 814: ifp->if_watchdog = aue_watchdog;
! 815: strlcpy(ifp->if_xname, sc->aue_dev.dv_xname, IFNAMSIZ);
! 816:
! 817: IFQ_SET_READY(&ifp->if_snd);
! 818:
! 819: /* Initialize MII/media info. */
! 820: mii = &sc->aue_mii;
! 821: mii->mii_ifp = ifp;
! 822: mii->mii_readreg = aue_miibus_readreg;
! 823: mii->mii_writereg = aue_miibus_writereg;
! 824: mii->mii_statchg = aue_miibus_statchg;
! 825: mii->mii_flags = MIIF_AUTOTSLEEP;
! 826: ifmedia_init(&mii->mii_media, 0, aue_ifmedia_upd, aue_ifmedia_sts);
! 827: mii_attach(self, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, 0);
! 828: if (LIST_FIRST(&mii->mii_phys) == NULL) {
! 829: ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_NONE, 0, NULL);
! 830: ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_NONE);
! 831: } else
! 832: ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO);
! 833:
! 834: /* Attach the interface. */
! 835: if_attach(ifp);
! 836: ether_ifattach(ifp);
! 837:
! 838: timeout_set(&sc->aue_stat_ch, NULL, NULL);
! 839:
! 840: sc->aue_attached = 1;
! 841: sc->sc_sdhook = shutdownhook_establish(aue_shutdown, sc);
! 842: splx(s);
! 843:
! 844: usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->aue_udev,
! 845: &sc->aue_dev);
! 846: }
! 847:
! 848: int
! 849: aue_detach(struct device *self, int flags)
! 850: {
! 851: struct aue_softc *sc = (struct aue_softc *)self;
! 852: struct ifnet *ifp = GET_IFP(sc);
! 853: int s;
! 854:
! 855: DPRINTFN(2,("%s: %s: enter\n", sc->aue_dev.dv_xname, __func__));
! 856:
! 857: if (!sc->aue_attached) {
! 858: /* Detached before attached finished, so just bail out. */
! 859: return (0);
! 860: }
! 861:
! 862: timeout_del(&sc->aue_stat_ch);
! 863: /*
! 864: * Remove any pending tasks. They cannot be executing because they run
! 865: * in the same thread as detach.
! 866: */
! 867: usb_rem_task(sc->aue_udev, &sc->aue_tick_task);
! 868: usb_rem_task(sc->aue_udev, &sc->aue_stop_task);
! 869:
! 870: s = splusb();
! 871:
! 872: if (ifp->if_flags & IFF_RUNNING)
! 873: aue_stop(sc);
! 874:
! 875: mii_detach(&sc->aue_mii, MII_PHY_ANY, MII_OFFSET_ANY);
! 876: ifmedia_delete_instance(&sc->aue_mii.mii_media, IFM_INST_ANY);
! 877: ether_ifdetach(ifp);
! 878: if_detach(ifp);
! 879:
! 880: #ifdef DIAGNOSTIC
! 881: if (sc->aue_ep[AUE_ENDPT_TX] != NULL ||
! 882: sc->aue_ep[AUE_ENDPT_RX] != NULL ||
! 883: sc->aue_ep[AUE_ENDPT_INTR] != NULL)
! 884: printf("%s: detach has active endpoints\n",
! 885: sc->aue_dev.dv_xname);
! 886: #endif
! 887:
! 888: sc->aue_attached = 0;
! 889: if (sc->sc_sdhook != NULL)
! 890: shutdownhook_disestablish(sc->sc_sdhook);
! 891:
! 892: if (--sc->aue_refcnt >= 0) {
! 893: /* Wait for processes to go away. */
! 894: usb_detach_wait(&sc->aue_dev);
! 895: }
! 896: splx(s);
! 897:
! 898: usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->aue_udev,
! 899: &sc->aue_dev);
! 900:
! 901: return (0);
! 902: }
! 903:
! 904: int
! 905: aue_activate(struct device *self, enum devact act)
! 906: {
! 907: struct aue_softc *sc = (struct aue_softc *)self;
! 908:
! 909: DPRINTFN(2,("%s: %s: enter\n", sc->aue_dev.dv_xname, __func__));
! 910:
! 911: switch (act) {
! 912: case DVACT_ACTIVATE:
! 913: break;
! 914:
! 915: case DVACT_DEACTIVATE:
! 916: sc->aue_dying = 1;
! 917: break;
! 918: }
! 919: return (0);
! 920: }
! 921:
! 922: /*
! 923: * Initialize an RX descriptor and attach an MBUF cluster.
! 924: */
! 925: int
! 926: aue_newbuf(struct aue_softc *sc, struct aue_chain *c, struct mbuf *m)
! 927: {
! 928: struct mbuf *m_new = NULL;
! 929:
! 930: DPRINTFN(10,("%s: %s: enter\n", sc->aue_dev.dv_xname,__func__));
! 931:
! 932: if (m == NULL) {
! 933: MGETHDR(m_new, M_DONTWAIT, MT_DATA);
! 934: if (m_new == NULL) {
! 935: printf("%s: no memory for rx list "
! 936: "-- packet dropped!\n", sc->aue_dev.dv_xname);
! 937: return (ENOBUFS);
! 938: }
! 939:
! 940: MCLGET(m_new, M_DONTWAIT);
! 941: if (!(m_new->m_flags & M_EXT)) {
! 942: printf("%s: no memory for rx list "
! 943: "-- packet dropped!\n", sc->aue_dev.dv_xname);
! 944: m_freem(m_new);
! 945: return (ENOBUFS);
! 946: }
! 947: m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
! 948: } else {
! 949: m_new = m;
! 950: m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
! 951: m_new->m_data = m_new->m_ext.ext_buf;
! 952: }
! 953:
! 954: m_adj(m_new, ETHER_ALIGN);
! 955: c->aue_mbuf = m_new;
! 956:
! 957: return (0);
! 958: }
! 959:
! 960: int
! 961: aue_rx_list_init(struct aue_softc *sc)
! 962: {
! 963: struct aue_cdata *cd;
! 964: struct aue_chain *c;
! 965: int i;
! 966:
! 967: DPRINTFN(5,("%s: %s: enter\n", sc->aue_dev.dv_xname, __func__));
! 968:
! 969: cd = &sc->aue_cdata;
! 970: for (i = 0; i < AUE_RX_LIST_CNT; i++) {
! 971: c = &cd->aue_rx_chain[i];
! 972: c->aue_sc = sc;
! 973: c->aue_idx = i;
! 974: if (aue_newbuf(sc, c, NULL) == ENOBUFS)
! 975: return (ENOBUFS);
! 976: if (c->aue_xfer == NULL) {
! 977: c->aue_xfer = usbd_alloc_xfer(sc->aue_udev);
! 978: if (c->aue_xfer == NULL)
! 979: return (ENOBUFS);
! 980: c->aue_buf = usbd_alloc_buffer(c->aue_xfer, AUE_BUFSZ);
! 981: if (c->aue_buf == NULL)
! 982: return (ENOBUFS); /* XXX free xfer */
! 983: }
! 984: }
! 985:
! 986: return (0);
! 987: }
! 988:
! 989: int
! 990: aue_tx_list_init(struct aue_softc *sc)
! 991: {
! 992: struct aue_cdata *cd;
! 993: struct aue_chain *c;
! 994: int i;
! 995:
! 996: DPRINTFN(5,("%s: %s: enter\n", sc->aue_dev.dv_xname, __func__));
! 997:
! 998: cd = &sc->aue_cdata;
! 999: for (i = 0; i < AUE_TX_LIST_CNT; i++) {
! 1000: c = &cd->aue_tx_chain[i];
! 1001: c->aue_sc = sc;
! 1002: c->aue_idx = i;
! 1003: c->aue_mbuf = NULL;
! 1004: if (c->aue_xfer == NULL) {
! 1005: c->aue_xfer = usbd_alloc_xfer(sc->aue_udev);
! 1006: if (c->aue_xfer == NULL)
! 1007: return (ENOBUFS);
! 1008: c->aue_buf = usbd_alloc_buffer(c->aue_xfer, AUE_BUFSZ);
! 1009: if (c->aue_buf == NULL)
! 1010: return (ENOBUFS);
! 1011: }
! 1012: }
! 1013:
! 1014: return (0);
! 1015: }
! 1016:
! 1017: void
! 1018: aue_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
! 1019: {
! 1020: struct aue_softc *sc = priv;
! 1021: struct ifnet *ifp = GET_IFP(sc);
! 1022: struct aue_intrpkt *p = &sc->aue_cdata.aue_ibuf;
! 1023:
! 1024: DPRINTFN(15,("%s: %s: enter\n", sc->aue_dev.dv_xname,__func__));
! 1025:
! 1026: if (sc->aue_dying)
! 1027: return;
! 1028:
! 1029: if (!(ifp->if_flags & IFF_RUNNING))
! 1030: return;
! 1031:
! 1032: if (status != USBD_NORMAL_COMPLETION) {
! 1033: if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
! 1034: return;
! 1035: }
! 1036: sc->aue_intr_errs++;
! 1037: if (usbd_ratecheck(&sc->aue_rx_notice)) {
! 1038: printf("%s: %u usb errors on intr: %s\n",
! 1039: sc->aue_dev.dv_xname, sc->aue_intr_errs,
! 1040: usbd_errstr(status));
! 1041: sc->aue_intr_errs = 0;
! 1042: }
! 1043: if (status == USBD_STALLED)
! 1044: usbd_clear_endpoint_stall_async(sc->aue_ep[AUE_ENDPT_RX]);
! 1045: return;
! 1046: }
! 1047:
! 1048: if (p->aue_txstat0)
! 1049: ifp->if_oerrors++;
! 1050:
! 1051: if (p->aue_txstat0 & (AUE_TXSTAT0_LATECOLL | AUE_TXSTAT0_EXCESSCOLL))
! 1052: ifp->if_collisions++;
! 1053: }
! 1054:
! 1055: /*
! 1056: * A frame has been uploaded: pass the resulting mbuf chain up to
! 1057: * the higher level protocols.
! 1058: */
! 1059: void
! 1060: aue_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
! 1061: {
! 1062: struct aue_chain *c = priv;
! 1063: struct aue_softc *sc = c->aue_sc;
! 1064: struct ifnet *ifp = GET_IFP(sc);
! 1065: struct mbuf *m;
! 1066: u_int32_t total_len;
! 1067: struct aue_rxpkt r;
! 1068: int s;
! 1069:
! 1070: DPRINTFN(10,("%s: %s: enter\n", sc->aue_dev.dv_xname,__func__));
! 1071:
! 1072: if (sc->aue_dying)
! 1073: return;
! 1074:
! 1075: if (!(ifp->if_flags & IFF_RUNNING))
! 1076: return;
! 1077:
! 1078: if (status != USBD_NORMAL_COMPLETION) {
! 1079: if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
! 1080: return;
! 1081: sc->aue_rx_errs++;
! 1082: if (usbd_ratecheck(&sc->aue_rx_notice)) {
! 1083: printf("%s: %u usb errors on rx: %s\n",
! 1084: sc->aue_dev.dv_xname, sc->aue_rx_errs,
! 1085: usbd_errstr(status));
! 1086: sc->aue_rx_errs = 0;
! 1087: }
! 1088: if (status == USBD_STALLED)
! 1089: usbd_clear_endpoint_stall_async(sc->aue_ep[AUE_ENDPT_RX]);
! 1090: goto done;
! 1091: }
! 1092:
! 1093: usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
! 1094:
! 1095: memcpy(mtod(c->aue_mbuf, char *), c->aue_buf, total_len);
! 1096:
! 1097: if (total_len <= 4 + ETHER_CRC_LEN) {
! 1098: ifp->if_ierrors++;
! 1099: goto done;
! 1100: }
! 1101:
! 1102: memcpy(&r, c->aue_buf + total_len - 4, sizeof(r));
! 1103:
! 1104: /* Turn off all the non-error bits in the rx status word. */
! 1105: r.aue_rxstat &= AUE_RXSTAT_MASK;
! 1106: if (r.aue_rxstat) {
! 1107: ifp->if_ierrors++;
! 1108: goto done;
! 1109: }
! 1110:
! 1111: /* No errors; receive the packet. */
! 1112: m = c->aue_mbuf;
! 1113: total_len -= ETHER_CRC_LEN + 4;
! 1114: m->m_pkthdr.len = m->m_len = total_len;
! 1115: ifp->if_ipackets++;
! 1116:
! 1117: m->m_pkthdr.rcvif = ifp;
! 1118:
! 1119: s = splnet();
! 1120:
! 1121: /* XXX ugly */
! 1122: if (aue_newbuf(sc, c, NULL) == ENOBUFS) {
! 1123: ifp->if_ierrors++;
! 1124: goto done1;
! 1125: }
! 1126:
! 1127: #if NBPFILTER > 0
! 1128: /*
! 1129: * Handle BPF listeners. Let the BPF user see the packet, but
! 1130: * don't pass it up to the ether_input() layer unless it's
! 1131: * a broadcast packet, multicast packet, matches our ethernet
! 1132: * address or the interface is in promiscuous mode.
! 1133: */
! 1134: if (ifp->if_bpf)
! 1135: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
! 1136: #endif
! 1137:
! 1138: DPRINTFN(10,("%s: %s: deliver %d\n", sc->aue_dev.dv_xname,
! 1139: __func__, m->m_len));
! 1140: ether_input_mbuf(ifp, m);
! 1141: done1:
! 1142: splx(s);
! 1143:
! 1144: done:
! 1145:
! 1146: /* Setup new transfer. */
! 1147: usbd_setup_xfer(xfer, sc->aue_ep[AUE_ENDPT_RX],
! 1148: c, c->aue_buf, AUE_BUFSZ,
! 1149: USBD_SHORT_XFER_OK | USBD_NO_COPY,
! 1150: USBD_NO_TIMEOUT, aue_rxeof);
! 1151: usbd_transfer(xfer);
! 1152:
! 1153: DPRINTFN(10,("%s: %s: start rx\n", sc->aue_dev.dv_xname,
! 1154: __func__));
! 1155: }
! 1156:
! 1157: /*
! 1158: * A frame was downloaded to the chip. It's safe for us to clean up
! 1159: * the list buffers.
! 1160: */
! 1161:
! 1162: void
! 1163: aue_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
! 1164: {
! 1165: struct aue_chain *c = priv;
! 1166: struct aue_softc *sc = c->aue_sc;
! 1167: struct ifnet *ifp = GET_IFP(sc);
! 1168: int s;
! 1169:
! 1170: if (sc->aue_dying)
! 1171: return;
! 1172:
! 1173: s = splnet();
! 1174:
! 1175: DPRINTFN(10,("%s: %s: enter status=%d\n", sc->aue_dev.dv_xname,
! 1176: __func__, status));
! 1177:
! 1178: ifp->if_timer = 0;
! 1179: ifp->if_flags &= ~IFF_OACTIVE;
! 1180:
! 1181: if (status != USBD_NORMAL_COMPLETION) {
! 1182: if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
! 1183: splx(s);
! 1184: return;
! 1185: }
! 1186: ifp->if_oerrors++;
! 1187: printf("%s: usb error on tx: %s\n", sc->aue_dev.dv_xname,
! 1188: usbd_errstr(status));
! 1189: if (status == USBD_STALLED)
! 1190: usbd_clear_endpoint_stall_async(sc->aue_ep[AUE_ENDPT_TX]);
! 1191: splx(s);
! 1192: return;
! 1193: }
! 1194:
! 1195: ifp->if_opackets++;
! 1196:
! 1197: m_freem(c->aue_mbuf);
! 1198: c->aue_mbuf = NULL;
! 1199:
! 1200: if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
! 1201: aue_start(ifp);
! 1202:
! 1203: splx(s);
! 1204: }
! 1205:
! 1206: void
! 1207: aue_tick(void *xsc)
! 1208: {
! 1209: struct aue_softc *sc = xsc;
! 1210:
! 1211: DPRINTFN(15,("%s: %s: enter\n", sc->aue_dev.dv_xname,__func__));
! 1212:
! 1213: if (sc == NULL)
! 1214: return;
! 1215:
! 1216: if (sc->aue_dying)
! 1217: return;
! 1218:
! 1219: /* Perform periodic stuff in process context. */
! 1220: usb_add_task(sc->aue_udev, &sc->aue_tick_task);
! 1221: }
! 1222:
! 1223: void
! 1224: aue_tick_task(void *xsc)
! 1225: {
! 1226: struct aue_softc *sc = xsc;
! 1227: struct ifnet *ifp;
! 1228: struct mii_data *mii;
! 1229: int s;
! 1230:
! 1231: DPRINTFN(15,("%s: %s: enter\n", sc->aue_dev.dv_xname,__func__));
! 1232:
! 1233: if (sc->aue_dying)
! 1234: return;
! 1235:
! 1236: ifp = GET_IFP(sc);
! 1237: mii = GET_MII(sc);
! 1238: if (mii == NULL)
! 1239: return;
! 1240:
! 1241: s = splnet();
! 1242:
! 1243: mii_tick(mii);
! 1244: if (!sc->aue_link && mii->mii_media_status & IFM_ACTIVE &&
! 1245: IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
! 1246: DPRINTFN(2,("%s: %s: got link\n",
! 1247: sc->aue_dev.dv_xname,__func__));
! 1248: sc->aue_link++;
! 1249: if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
! 1250: aue_start(ifp);
! 1251: }
! 1252:
! 1253: timeout_del(&sc->aue_stat_ch);
! 1254: timeout_set(&sc->aue_stat_ch, aue_tick, sc);
! 1255: timeout_add(&sc->aue_stat_ch, hz);
! 1256:
! 1257: splx(s);
! 1258: }
! 1259:
! 1260: int
! 1261: aue_send(struct aue_softc *sc, struct mbuf *m, int idx)
! 1262: {
! 1263: int total_len;
! 1264: struct aue_chain *c;
! 1265: usbd_status err;
! 1266:
! 1267: DPRINTFN(10,("%s: %s: enter\n", sc->aue_dev.dv_xname,__func__));
! 1268:
! 1269: c = &sc->aue_cdata.aue_tx_chain[idx];
! 1270:
! 1271: /*
! 1272: * Copy the mbuf data into a contiguous buffer, leaving two
! 1273: * bytes at the beginning to hold the frame length.
! 1274: */
! 1275: m_copydata(m, 0, m->m_pkthdr.len, c->aue_buf + 2);
! 1276: c->aue_mbuf = m;
! 1277:
! 1278: /*
! 1279: * The ADMtek documentation says that the packet length is
! 1280: * supposed to be specified in the first two bytes of the
! 1281: * transfer, however it actually seems to ignore this info
! 1282: * and base the frame size on the bulk transfer length.
! 1283: */
! 1284: c->aue_buf[0] = (u_int8_t)m->m_pkthdr.len;
! 1285: c->aue_buf[1] = (u_int8_t)(m->m_pkthdr.len >> 8);
! 1286: total_len = m->m_pkthdr.len + 2;
! 1287:
! 1288: usbd_setup_xfer(c->aue_xfer, sc->aue_ep[AUE_ENDPT_TX],
! 1289: c, c->aue_buf, total_len, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
! 1290: AUE_TX_TIMEOUT, aue_txeof);
! 1291:
! 1292: /* Transmit */
! 1293: err = usbd_transfer(c->aue_xfer);
! 1294: if (err != USBD_IN_PROGRESS) {
! 1295: printf("%s: aue_send error=%s\n", sc->aue_dev.dv_xname,
! 1296: usbd_errstr(err));
! 1297: /* Stop the interface from process context. */
! 1298: usb_add_task(sc->aue_udev, &sc->aue_stop_task);
! 1299: return (EIO);
! 1300: }
! 1301: DPRINTFN(5,("%s: %s: send %d bytes\n", sc->aue_dev.dv_xname,
! 1302: __func__, total_len));
! 1303:
! 1304: sc->aue_cdata.aue_tx_cnt++;
! 1305:
! 1306: return (0);
! 1307: }
! 1308:
! 1309: void
! 1310: aue_start(struct ifnet *ifp)
! 1311: {
! 1312: struct aue_softc *sc = ifp->if_softc;
! 1313: struct mbuf *m_head = NULL;
! 1314:
! 1315: DPRINTFN(5,("%s: %s: enter, link=%d\n", sc->aue_dev.dv_xname,
! 1316: __func__, sc->aue_link));
! 1317:
! 1318: if (sc->aue_dying)
! 1319: return;
! 1320:
! 1321: if (!sc->aue_link)
! 1322: return;
! 1323:
! 1324: if (ifp->if_flags & IFF_OACTIVE)
! 1325: return;
! 1326:
! 1327: IFQ_POLL(&ifp->if_snd, m_head);
! 1328: if (m_head == NULL)
! 1329: return;
! 1330:
! 1331: if (aue_send(sc, m_head, 0)) {
! 1332: ifp->if_flags |= IFF_OACTIVE;
! 1333: return;
! 1334: }
! 1335:
! 1336: IFQ_DEQUEUE(&ifp->if_snd, m_head);
! 1337:
! 1338: #if NBPFILTER > 0
! 1339: /*
! 1340: * If there's a BPF listener, bounce a copy of this frame
! 1341: * to him.
! 1342: */
! 1343: if (ifp->if_bpf)
! 1344: bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
! 1345: #endif
! 1346:
! 1347: ifp->if_flags |= IFF_OACTIVE;
! 1348:
! 1349: /*
! 1350: * Set a timeout in case the chip goes out to lunch.
! 1351: */
! 1352: ifp->if_timer = 5;
! 1353: }
! 1354:
! 1355: void
! 1356: aue_init(void *xsc)
! 1357: {
! 1358: struct aue_softc *sc = xsc;
! 1359: struct ifnet *ifp = GET_IFP(sc);
! 1360: struct mii_data *mii = GET_MII(sc);
! 1361: int i, s;
! 1362: u_char *eaddr;
! 1363:
! 1364: DPRINTFN(5,("%s: %s: enter\n", sc->aue_dev.dv_xname, __func__));
! 1365:
! 1366: if (sc->aue_dying)
! 1367: return;
! 1368:
! 1369: if (ifp->if_flags & IFF_RUNNING)
! 1370: return;
! 1371:
! 1372: s = splnet();
! 1373:
! 1374: /*
! 1375: * Cancel pending I/O and free all RX/TX buffers.
! 1376: */
! 1377: aue_reset(sc);
! 1378:
! 1379: eaddr = sc->arpcom.ac_enaddr;
! 1380: for (i = 0; i < ETHER_ADDR_LEN; i++)
! 1381: aue_csr_write_1(sc, AUE_PAR0 + i, eaddr[i]);
! 1382:
! 1383: /* If we want promiscuous mode, set the allframes bit. */
! 1384: if (ifp->if_flags & IFF_PROMISC)
! 1385: AUE_SETBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC);
! 1386: else
! 1387: AUE_CLRBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC);
! 1388:
! 1389: /* Init TX ring. */
! 1390: if (aue_tx_list_init(sc) == ENOBUFS) {
! 1391: printf("%s: tx list init failed\n", sc->aue_dev.dv_xname);
! 1392: splx(s);
! 1393: return;
! 1394: }
! 1395:
! 1396: /* Init RX ring. */
! 1397: if (aue_rx_list_init(sc) == ENOBUFS) {
! 1398: printf("%s: rx list init failed\n", sc->aue_dev.dv_xname);
! 1399: splx(s);
! 1400: return;
! 1401: }
! 1402:
! 1403: /* Load the multicast filter. */
! 1404: aue_setmulti(sc);
! 1405:
! 1406: /* Enable RX and TX */
! 1407: aue_csr_write_1(sc, AUE_CTL0, AUE_CTL0_RXSTAT_APPEND | AUE_CTL0_RX_ENB);
! 1408: AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_TX_ENB);
! 1409: AUE_SETBIT(sc, AUE_CTL2, AUE_CTL2_EP3_CLR);
! 1410:
! 1411: mii_mediachg(mii);
! 1412:
! 1413: if (sc->aue_ep[AUE_ENDPT_RX] == NULL) {
! 1414: if (aue_openpipes(sc)) {
! 1415: splx(s);
! 1416: return;
! 1417: }
! 1418: }
! 1419:
! 1420: ifp->if_flags |= IFF_RUNNING;
! 1421: ifp->if_flags &= ~IFF_OACTIVE;
! 1422:
! 1423: splx(s);
! 1424:
! 1425: timeout_del(&sc->aue_stat_ch);
! 1426: timeout_set(&sc->aue_stat_ch, aue_tick, sc);
! 1427: timeout_add(&sc->aue_stat_ch, hz);
! 1428: }
! 1429:
! 1430: int
! 1431: aue_openpipes(struct aue_softc *sc)
! 1432: {
! 1433: struct aue_chain *c;
! 1434: usbd_status err;
! 1435: int i;
! 1436:
! 1437: /* Open RX and TX pipes. */
! 1438: err = usbd_open_pipe(sc->aue_iface, sc->aue_ed[AUE_ENDPT_RX],
! 1439: USBD_EXCLUSIVE_USE, &sc->aue_ep[AUE_ENDPT_RX]);
! 1440: if (err) {
! 1441: printf("%s: open rx pipe failed: %s\n",
! 1442: sc->aue_dev.dv_xname, usbd_errstr(err));
! 1443: return (EIO);
! 1444: }
! 1445: err = usbd_open_pipe(sc->aue_iface, sc->aue_ed[AUE_ENDPT_TX],
! 1446: USBD_EXCLUSIVE_USE, &sc->aue_ep[AUE_ENDPT_TX]);
! 1447: if (err) {
! 1448: printf("%s: open tx pipe failed: %s\n",
! 1449: sc->aue_dev.dv_xname, usbd_errstr(err));
! 1450: return (EIO);
! 1451: }
! 1452: err = usbd_open_pipe_intr(sc->aue_iface, sc->aue_ed[AUE_ENDPT_INTR],
! 1453: USBD_EXCLUSIVE_USE, &sc->aue_ep[AUE_ENDPT_INTR], sc,
! 1454: &sc->aue_cdata.aue_ibuf, AUE_INTR_PKTLEN, aue_intr,
! 1455: AUE_INTR_INTERVAL);
! 1456: if (err) {
! 1457: printf("%s: open intr pipe failed: %s\n",
! 1458: sc->aue_dev.dv_xname, usbd_errstr(err));
! 1459: return (EIO);
! 1460: }
! 1461:
! 1462: /* Start up the receive pipe. */
! 1463: for (i = 0; i < AUE_RX_LIST_CNT; i++) {
! 1464: c = &sc->aue_cdata.aue_rx_chain[i];
! 1465: usbd_setup_xfer(c->aue_xfer, sc->aue_ep[AUE_ENDPT_RX],
! 1466: c, c->aue_buf, AUE_BUFSZ,
! 1467: USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
! 1468: aue_rxeof);
! 1469: (void)usbd_transfer(c->aue_xfer); /* XXX */
! 1470: DPRINTFN(5,("%s: %s: start read\n", sc->aue_dev.dv_xname,
! 1471: __func__));
! 1472:
! 1473: }
! 1474: return (0);
! 1475: }
! 1476:
! 1477: /*
! 1478: * Set media options.
! 1479: */
! 1480: int
! 1481: aue_ifmedia_upd(struct ifnet *ifp)
! 1482: {
! 1483: struct aue_softc *sc = ifp->if_softc;
! 1484: struct mii_data *mii = GET_MII(sc);
! 1485:
! 1486: DPRINTFN(5,("%s: %s: enter\n", sc->aue_dev.dv_xname, __func__));
! 1487:
! 1488: if (sc->aue_dying)
! 1489: return (0);
! 1490:
! 1491: sc->aue_link = 0;
! 1492: if (mii->mii_instance) {
! 1493: struct mii_softc *miisc;
! 1494: for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL;
! 1495: miisc = LIST_NEXT(miisc, mii_list))
! 1496: mii_phy_reset(miisc);
! 1497: }
! 1498: mii_mediachg(mii);
! 1499:
! 1500: return (0);
! 1501: }
! 1502:
! 1503: /*
! 1504: * Report current media status.
! 1505: */
! 1506: void
! 1507: aue_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
! 1508: {
! 1509: struct aue_softc *sc = ifp->if_softc;
! 1510: struct mii_data *mii = GET_MII(sc);
! 1511:
! 1512: DPRINTFN(5,("%s: %s: enter\n", sc->aue_dev.dv_xname, __func__));
! 1513:
! 1514: mii_pollstat(mii);
! 1515: ifmr->ifm_active = mii->mii_media_active;
! 1516: ifmr->ifm_status = mii->mii_media_status;
! 1517: }
! 1518:
! 1519: int
! 1520: aue_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
! 1521: {
! 1522: struct aue_softc *sc = ifp->if_softc;
! 1523: struct ifaddr *ifa = (struct ifaddr *)data;
! 1524: struct ifreq *ifr = (struct ifreq *)data;
! 1525: struct mii_data *mii;
! 1526: int s, error = 0;
! 1527:
! 1528: if (sc->aue_dying)
! 1529: return (EIO);
! 1530:
! 1531: s = splnet();
! 1532:
! 1533: switch(command) {
! 1534: case SIOCSIFADDR:
! 1535: ifp->if_flags |= IFF_UP;
! 1536: aue_init(sc);
! 1537:
! 1538: switch (ifa->ifa_addr->sa_family) {
! 1539: #ifdef INET
! 1540: case AF_INET:
! 1541: arp_ifinit(&sc->arpcom, ifa);
! 1542: break;
! 1543: #endif /* INET */
! 1544: }
! 1545: break;
! 1546:
! 1547: case SIOCSIFMTU:
! 1548: if (ifr->ifr_mtu > ETHERMTU)
! 1549: error = EINVAL;
! 1550: else
! 1551: ifp->if_mtu = ifr->ifr_mtu;
! 1552: break;
! 1553:
! 1554: case SIOCSIFFLAGS:
! 1555: if (ifp->if_flags & IFF_UP) {
! 1556: if (ifp->if_flags & IFF_RUNNING &&
! 1557: ifp->if_flags & IFF_PROMISC &&
! 1558: !(sc->aue_if_flags & IFF_PROMISC)) {
! 1559: AUE_SETBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC);
! 1560: } else if (ifp->if_flags & IFF_RUNNING &&
! 1561: !(ifp->if_flags & IFF_PROMISC) &&
! 1562: sc->aue_if_flags & IFF_PROMISC) {
! 1563: AUE_CLRBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC);
! 1564: } else if (!(ifp->if_flags & IFF_RUNNING))
! 1565: aue_init(sc);
! 1566: } else {
! 1567: if (ifp->if_flags & IFF_RUNNING)
! 1568: aue_stop(sc);
! 1569: }
! 1570: sc->aue_if_flags = ifp->if_flags;
! 1571: error = 0;
! 1572: break;
! 1573: case SIOCADDMULTI:
! 1574: case SIOCDELMULTI:
! 1575: error = (command == SIOCADDMULTI) ?
! 1576: ether_addmulti(ifr, &sc->arpcom) :
! 1577: ether_delmulti(ifr, &sc->arpcom);
! 1578:
! 1579: if (error == ENETRESET) {
! 1580: if (ifp->if_flags & IFF_RUNNING)
! 1581: aue_setmulti(sc);
! 1582: error = 0;
! 1583: }
! 1584: break;
! 1585: case SIOCGIFMEDIA:
! 1586: case SIOCSIFMEDIA:
! 1587: mii = GET_MII(sc);
! 1588: error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
! 1589: break;
! 1590: default:
! 1591: error = EINVAL;
! 1592: break;
! 1593: }
! 1594:
! 1595: splx(s);
! 1596:
! 1597: return (error);
! 1598: }
! 1599:
! 1600: void
! 1601: aue_watchdog(struct ifnet *ifp)
! 1602: {
! 1603: struct aue_softc *sc = ifp->if_softc;
! 1604: struct aue_chain *c;
! 1605: usbd_status stat;
! 1606: int s;
! 1607:
! 1608: DPRINTFN(5,("%s: %s: enter\n", sc->aue_dev.dv_xname, __func__));
! 1609:
! 1610: ifp->if_oerrors++;
! 1611: printf("%s: watchdog timeout\n", sc->aue_dev.dv_xname);
! 1612:
! 1613: s = splusb();
! 1614: c = &sc->aue_cdata.aue_tx_chain[0];
! 1615: usbd_get_xfer_status(c->aue_xfer, NULL, NULL, NULL, &stat);
! 1616: aue_txeof(c->aue_xfer, c, stat);
! 1617:
! 1618: if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
! 1619: aue_start(ifp);
! 1620: splx(s);
! 1621: }
! 1622:
! 1623: /*
! 1624: * Stop all chip I/O so that the kernel's probe routines don't
! 1625: * get confused by errant DMAs when rebooting.
! 1626: */
! 1627: void
! 1628: aue_shutdown(void *arg)
! 1629: {
! 1630: struct aue_softc *sc = (struct aue_softc *)arg;
! 1631:
! 1632: aue_reset(sc);
! 1633: aue_stop(sc);
! 1634: }
! 1635:
! 1636: /*
! 1637: * Stop the adapter and free any mbufs allocated to the
! 1638: * RX and TX lists.
! 1639: */
! 1640: void
! 1641: aue_stop(struct aue_softc *sc)
! 1642: {
! 1643: usbd_status err;
! 1644: struct ifnet *ifp;
! 1645: int i;
! 1646:
! 1647: DPRINTFN(5,("%s: %s: enter\n", sc->aue_dev.dv_xname, __func__));
! 1648:
! 1649: ifp = GET_IFP(sc);
! 1650: ifp->if_timer = 0;
! 1651: ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
! 1652:
! 1653: aue_csr_write_1(sc, AUE_CTL0, 0);
! 1654: aue_csr_write_1(sc, AUE_CTL1, 0);
! 1655: aue_reset(sc);
! 1656: timeout_del(&sc->aue_stat_ch);
! 1657:
! 1658: /* Stop transfers. */
! 1659: if (sc->aue_ep[AUE_ENDPT_RX] != NULL) {
! 1660: err = usbd_abort_pipe(sc->aue_ep[AUE_ENDPT_RX]);
! 1661: if (err) {
! 1662: printf("%s: abort rx pipe failed: %s\n",
! 1663: sc->aue_dev.dv_xname, usbd_errstr(err));
! 1664: }
! 1665: err = usbd_close_pipe(sc->aue_ep[AUE_ENDPT_RX]);
! 1666: if (err) {
! 1667: printf("%s: close rx pipe failed: %s\n",
! 1668: sc->aue_dev.dv_xname, usbd_errstr(err));
! 1669: }
! 1670: sc->aue_ep[AUE_ENDPT_RX] = NULL;
! 1671: }
! 1672:
! 1673: if (sc->aue_ep[AUE_ENDPT_TX] != NULL) {
! 1674: err = usbd_abort_pipe(sc->aue_ep[AUE_ENDPT_TX]);
! 1675: if (err) {
! 1676: printf("%s: abort tx pipe failed: %s\n",
! 1677: sc->aue_dev.dv_xname, usbd_errstr(err));
! 1678: }
! 1679: err = usbd_close_pipe(sc->aue_ep[AUE_ENDPT_TX]);
! 1680: if (err) {
! 1681: printf("%s: close tx pipe failed: %s\n",
! 1682: sc->aue_dev.dv_xname, usbd_errstr(err));
! 1683: }
! 1684: sc->aue_ep[AUE_ENDPT_TX] = NULL;
! 1685: }
! 1686:
! 1687: if (sc->aue_ep[AUE_ENDPT_INTR] != NULL) {
! 1688: err = usbd_abort_pipe(sc->aue_ep[AUE_ENDPT_INTR]);
! 1689: if (err) {
! 1690: printf("%s: abort intr pipe failed: %s\n",
! 1691: sc->aue_dev.dv_xname, usbd_errstr(err));
! 1692: }
! 1693: err = usbd_close_pipe(sc->aue_ep[AUE_ENDPT_INTR]);
! 1694: if (err) {
! 1695: printf("%s: close intr pipe failed: %s\n",
! 1696: sc->aue_dev.dv_xname, usbd_errstr(err));
! 1697: }
! 1698: sc->aue_ep[AUE_ENDPT_INTR] = NULL;
! 1699: }
! 1700:
! 1701: /* Free RX resources. */
! 1702: for (i = 0; i < AUE_RX_LIST_CNT; i++) {
! 1703: if (sc->aue_cdata.aue_rx_chain[i].aue_mbuf != NULL) {
! 1704: m_freem(sc->aue_cdata.aue_rx_chain[i].aue_mbuf);
! 1705: sc->aue_cdata.aue_rx_chain[i].aue_mbuf = NULL;
! 1706: }
! 1707: if (sc->aue_cdata.aue_rx_chain[i].aue_xfer != NULL) {
! 1708: usbd_free_xfer(sc->aue_cdata.aue_rx_chain[i].aue_xfer);
! 1709: sc->aue_cdata.aue_rx_chain[i].aue_xfer = NULL;
! 1710: }
! 1711: }
! 1712:
! 1713: /* Free TX resources. */
! 1714: for (i = 0; i < AUE_TX_LIST_CNT; i++) {
! 1715: if (sc->aue_cdata.aue_tx_chain[i].aue_mbuf != NULL) {
! 1716: m_freem(sc->aue_cdata.aue_tx_chain[i].aue_mbuf);
! 1717: sc->aue_cdata.aue_tx_chain[i].aue_mbuf = NULL;
! 1718: }
! 1719: if (sc->aue_cdata.aue_tx_chain[i].aue_xfer != NULL) {
! 1720: usbd_free_xfer(sc->aue_cdata.aue_tx_chain[i].aue_xfer);
! 1721: sc->aue_cdata.aue_tx_chain[i].aue_xfer = NULL;
! 1722: }
! 1723: }
! 1724:
! 1725: sc->aue_link = 0;
! 1726: }
CVSweb