Annotation of sys/dev/usb/if_uath.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_uath.c,v 1.27 2007/07/18 18:10:31 damien Exp $ */
! 2:
! 3: /*-
! 4: * Copyright (c) 2006
! 5: * Damien Bergamini <damien.bergamini@free.fr>
! 6: *
! 7: * Permission to use, copy, modify, and distribute this software for any
! 8: * purpose with or without fee is hereby granted, provided that the above
! 9: * copyright notice and this permission notice appear in all copies.
! 10: *
! 11: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 12: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 13: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 14: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 15: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 16: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 17: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 18: */
! 19:
! 20: /*-
! 21: * Driver for Atheros AR5005UG/AR5005UX chipsets.
! 22: * http://www.atheros.com/pt/bulletins/AR5005UGBulletin.pdf
! 23: * http://www.atheros.com/pt/bulletins/AR5005UXBulletin.pdf
! 24: *
! 25: * IMPORTANT NOTICE:
! 26: * This driver was written without any documentation or support from Atheros
! 27: * Communications. It is based on a black-box analysis of the Windows binary
! 28: * driver. It handles both pre and post-firmware devices.
! 29: */
! 30:
! 31: #include "bpfilter.h"
! 32:
! 33: #include <sys/param.h>
! 34: #include <sys/sockio.h>
! 35: #include <sys/sysctl.h>
! 36: #include <sys/mbuf.h>
! 37: #include <sys/kernel.h>
! 38: #include <sys/socket.h>
! 39: #include <sys/systm.h>
! 40: #include <sys/malloc.h>
! 41: #include <sys/timeout.h>
! 42: #include <sys/conf.h>
! 43: #include <sys/device.h>
! 44:
! 45: #include <machine/bus.h>
! 46: #include <machine/endian.h>
! 47: #include <machine/intr.h>
! 48:
! 49: #if NBPFILTER > 0
! 50: #include <net/bpf.h>
! 51: #endif
! 52: #include <net/if.h>
! 53: #include <net/if_arp.h>
! 54: #include <net/if_dl.h>
! 55: #include <net/if_media.h>
! 56: #include <net/if_types.h>
! 57:
! 58: #include <netinet/in.h>
! 59: #include <netinet/in_systm.h>
! 60: #include <netinet/in_var.h>
! 61: #include <netinet/if_ether.h>
! 62: #include <netinet/ip.h>
! 63:
! 64: #include <net80211/ieee80211_var.h>
! 65: #include <net80211/ieee80211_radiotap.h>
! 66:
! 67: #include <dev/rndvar.h>
! 68: #include <crypto/arc4.h>
! 69:
! 70: #include <dev/usb/usb.h>
! 71: #include <dev/usb/usbdi.h>
! 72: #include <dev/usb/usbdivar.h> /* needs_reattach() */
! 73: #include <dev/usb/usbdi_util.h>
! 74: #include <dev/usb/usbdevs.h>
! 75:
! 76: #include <dev/usb/if_uathreg.h>
! 77: #include <dev/usb/if_uathvar.h>
! 78:
! 79: #ifdef USB_DEBUG
! 80: #define UATH_DEBUG
! 81: #endif
! 82:
! 83: #ifdef UATH_DEBUG
! 84: #define DPRINTF(x) do { if (uath_debug) printf x; } while (0)
! 85: #define DPRINTFN(n, x) do { if (uath_debug >= (n)) printf x; } while (0)
! 86: int uath_debug = 1;
! 87: #else
! 88: #define DPRINTF(x)
! 89: #define DPRINTFN(n, x)
! 90: #endif
! 91:
! 92: /*-
! 93: * Various supported device vendors/products.
! 94: * UB51: AR5005UG 802.11b/g, UB52: AR5005UX 802.11a/b/g
! 95: */
! 96: #define UATH_DEV(v, p, f) \
! 97: { { USB_VENDOR_##v, USB_PRODUCT_##v##_##p }, (f) }, \
! 98: { { USB_VENDOR_##v, USB_PRODUCT_##v##_##p##_NF }, \
! 99: (f) | UATH_FLAG_PRE_FIRMWARE }
! 100: #define UATH_DEV_UG(v, p) UATH_DEV(v, p, 0)
! 101: #define UATH_DEV_UX(v, p) UATH_DEV(v, p, UATH_FLAG_ABG)
! 102: static const struct uath_type {
! 103: struct usb_devno dev;
! 104: unsigned int flags;
! 105: #define UATH_FLAG_PRE_FIRMWARE (1 << 0)
! 106: #define UATH_FLAG_ABG (1 << 1)
! 107: } uath_devs[] = {
! 108: UATH_DEV_UG(ATHEROS, AR5523),
! 109: UATH_DEV_UG(ATHEROS2, AR5523_1),
! 110: UATH_DEV_UG(ATHEROS2, AR5523_2),
! 111: UATH_DEV_UX(ATHEROS2, AR5523_3),
! 112: UATH_DEV_UG(CONCEPTRONIC, AR5523_1),
! 113: UATH_DEV_UX(CONCEPTRONIC, AR5523_2),
! 114: UATH_DEV_UX(DLINK, DWLAG122),
! 115: UATH_DEV_UX(DLINK, DWLAG132),
! 116: UATH_DEV_UG(DLINK, DWLG132),
! 117: UATH_DEV_UG(GIGASET, AR5523),
! 118: UATH_DEV_UG(GIGASET, SMCWUSBTG),
! 119: UATH_DEV_UG(GLOBALSUN, AR5523_1),
! 120: UATH_DEV_UX(GLOBALSUN, AR5523_2),
! 121: UATH_DEV_UX(NETGEAR, WG111U),
! 122: UATH_DEV_UG(NETGEAR3, WG111T),
! 123: UATH_DEV_UG(NETGEAR3, WPN111),
! 124: UATH_DEV_UG(UMEDIA, AR5523_1),
! 125: UATH_DEV_UX(UMEDIA, AR5523_2),
! 126: UATH_DEV_UG(UMEDIA, TEW444UBEU),
! 127: UATH_DEV_UG(WISTRONNEWEB, AR5523_1),
! 128: UATH_DEV_UX(WISTRONNEWEB, AR5523_2),
! 129: UATH_DEV_UG(ZCOM, AR5523)
! 130: };
! 131: #define uath_lookup(v, p) \
! 132: ((const struct uath_type *)usb_lookup(uath_devs, v, p))
! 133:
! 134: void uath_attachhook(void *);
! 135: int uath_open_pipes(struct uath_softc *);
! 136: void uath_close_pipes(struct uath_softc *);
! 137: int uath_alloc_tx_data_list(struct uath_softc *);
! 138: void uath_free_tx_data_list(struct uath_softc *);
! 139: int uath_alloc_rx_data_list(struct uath_softc *);
! 140: void uath_free_rx_data_list(struct uath_softc *);
! 141: void uath_free_rx_data(caddr_t, u_int, void *);
! 142: int uath_alloc_tx_cmd_list(struct uath_softc *);
! 143: void uath_free_tx_cmd_list(struct uath_softc *);
! 144: int uath_alloc_rx_cmd_list(struct uath_softc *);
! 145: void uath_free_rx_cmd_list(struct uath_softc *);
! 146: int uath_media_change(struct ifnet *);
! 147: void uath_stat(void *);
! 148: void uath_next_scan(void *);
! 149: void uath_task(void *);
! 150: int uath_newstate(struct ieee80211com *, enum ieee80211_state, int);
! 151: #ifdef UATH_DEBUG
! 152: void uath_dump_cmd(const uint8_t *, int, char);
! 153: #endif
! 154: int uath_cmd(struct uath_softc *, uint32_t, const void *, int, void *,
! 155: int);
! 156: int uath_cmd_write(struct uath_softc *, uint32_t, const void *, int, int);
! 157: int uath_cmd_read(struct uath_softc *, uint32_t, const void *, int, void *,
! 158: int);
! 159: int uath_write_reg(struct uath_softc *, uint32_t, uint32_t);
! 160: int uath_write_multi(struct uath_softc *, uint32_t, const void *, int);
! 161: int uath_read_reg(struct uath_softc *, uint32_t, uint32_t *);
! 162: int uath_read_eeprom(struct uath_softc *, uint32_t, void *);
! 163: void uath_cmd_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
! 164: void uath_data_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
! 165: void uath_data_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
! 166: int uath_tx_null(struct uath_softc *);
! 167: int uath_tx_data(struct uath_softc *, struct mbuf *,
! 168: struct ieee80211_node *);
! 169: void uath_start(struct ifnet *);
! 170: void uath_watchdog(struct ifnet *);
! 171: int uath_ioctl(struct ifnet *, u_long, caddr_t);
! 172: int uath_query_eeprom(struct uath_softc *);
! 173: int uath_reset(struct uath_softc *);
! 174: int uath_reset_tx_queues(struct uath_softc *);
! 175: int uath_wme_init(struct uath_softc *);
! 176: int uath_set_chan(struct uath_softc *, struct ieee80211_channel *);
! 177: int uath_set_key(struct uath_softc *, const struct ieee80211_key *, int);
! 178: int uath_set_keys(struct uath_softc *);
! 179: int uath_set_rates(struct uath_softc *, const struct ieee80211_rateset *);
! 180: int uath_set_rxfilter(struct uath_softc *, uint32_t, uint32_t);
! 181: int uath_set_led(struct uath_softc *, int, int);
! 182: int uath_switch_channel(struct uath_softc *, struct ieee80211_channel *);
! 183: int uath_init(struct ifnet *);
! 184: void uath_stop(struct ifnet *, int);
! 185: int uath_loadfirmware(struct uath_softc *, const u_char *, int);
! 186: int uath_activate(struct device *, enum devact);
! 187:
! 188: int uath_match(struct device *, void *, void *);
! 189: void uath_attach(struct device *, struct device *, void *);
! 190: int uath_detach(struct device *, int);
! 191: int uath_activate(struct device *, enum devact);
! 192:
! 193: struct cfdriver uath_cd = {
! 194: NULL, "uath", DV_DULL
! 195: };
! 196:
! 197: const struct cfattach uath_ca = {
! 198: sizeof(struct uath_softc),
! 199: uath_match,
! 200: uath_attach,
! 201: uath_detach,
! 202: uath_activate,
! 203: };
! 204:
! 205: int
! 206: uath_match(struct device *parent, void *match, void *aux)
! 207: {
! 208: struct usb_attach_arg *uaa = aux;
! 209:
! 210: if (uaa->iface != NULL)
! 211: return UMATCH_NONE;
! 212:
! 213: return (uath_lookup(uaa->vendor, uaa->product) != NULL) ?
! 214: UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
! 215: }
! 216:
! 217: void
! 218: uath_attachhook(void *xsc)
! 219: {
! 220: struct uath_softc *sc = xsc;
! 221: u_char *fw;
! 222: size_t size;
! 223: int error;
! 224:
! 225: if ((error = loadfirmware("uath-ar5523", &fw, &size)) != 0) {
! 226: printf("%s: could not read firmware (error=%d)\n",
! 227: sc->sc_dev.dv_xname, error);
! 228: return;
! 229: }
! 230:
! 231: error = uath_loadfirmware(sc, fw, size);
! 232: free(fw, M_DEVBUF);
! 233:
! 234: if (error == 0) {
! 235: usb_port_status_t status;
! 236:
! 237: /*
! 238: * Hack alert: the device doesn't always gracefully detach
! 239: * from the bus after a firmware upload. We need to force
! 240: * a port reset and a re-exploration on the parent hub.
! 241: */
! 242: usbd_reset_port(sc->sc_uhub, sc->sc_port, &status);
! 243: usb_needs_reattach(sc->sc_udev);
! 244: } else {
! 245: printf("%s: could not load firmware (error=%s)\n",
! 246: sc->sc_dev.dv_xname, usbd_errstr(error));
! 247: }
! 248: }
! 249:
! 250: void
! 251: uath_attach(struct device *parent, struct device *self, void *aux)
! 252: {
! 253: struct uath_softc *sc = (struct uath_softc *)self;
! 254: struct usb_attach_arg *uaa = aux;
! 255: struct ieee80211com *ic = &sc->sc_ic;
! 256: struct ifnet *ifp = &ic->ic_if;
! 257: usbd_status error;
! 258: char *devinfop;
! 259: int i;
! 260:
! 261: sc->sc_udev = uaa->device;
! 262: sc->sc_uhub = uaa->device->myhub;
! 263: sc->sc_port = uaa->port;
! 264:
! 265: devinfop = usbd_devinfo_alloc(uaa->device, 0);
! 266: printf("\n%s: %s\n", sc->sc_dev.dv_xname, devinfop);
! 267: usbd_devinfo_free(devinfop);
! 268:
! 269: sc->sc_flags = uath_lookup(uaa->vendor, uaa->product)->flags;
! 270:
! 271: if (usbd_set_config_no(sc->sc_udev, UATH_CONFIG_NO, 0) != 0) {
! 272: printf("%s: could not set configuration no\n",
! 273: sc->sc_dev.dv_xname);
! 274: return;
! 275: }
! 276:
! 277: /* get the first interface handle */
! 278: error = usbd_device2interface_handle(sc->sc_udev, UATH_IFACE_INDEX,
! 279: &sc->sc_iface);
! 280: if (error != 0) {
! 281: printf("%s: could not get interface handle\n",
! 282: sc->sc_dev.dv_xname);
! 283: return;
! 284: }
! 285:
! 286: /*
! 287: * We must open the pipes early because they're used to upload the
! 288: * firmware (pre-firmware devices) or to send firmware commands.
! 289: */
! 290: if (uath_open_pipes(sc) != 0) {
! 291: printf("%s: could not open pipes\n", sc->sc_dev.dv_xname);
! 292: return;
! 293: }
! 294:
! 295: if (sc->sc_flags & UATH_FLAG_PRE_FIRMWARE) {
! 296: if (rootvp == NULL)
! 297: mountroothook_establish(uath_attachhook, sc);
! 298: else
! 299: uath_attachhook(sc);
! 300: return;
! 301: }
! 302:
! 303: /*
! 304: * Only post-firmware devices here.
! 305: */
! 306: usb_init_task(&sc->sc_task, uath_task, sc);
! 307: timeout_set(&sc->scan_to, uath_next_scan, sc);
! 308: timeout_set(&sc->stat_to, uath_stat, sc);
! 309:
! 310: /*
! 311: * Allocate xfers for firmware commands.
! 312: */
! 313: if (uath_alloc_tx_cmd_list(sc) != 0) {
! 314: printf("%s: could not allocate Tx command list\n",
! 315: sc->sc_dev.dv_xname);
! 316: goto fail1;
! 317: }
! 318: if (uath_alloc_rx_cmd_list(sc) != 0) {
! 319: printf("%s: could not allocate Rx command list\n",
! 320: sc->sc_dev.dv_xname);
! 321: goto fail2;
! 322: }
! 323:
! 324: /*
! 325: * Queue Rx command xfers.
! 326: */
! 327: for (i = 0; i < UATH_RX_CMD_LIST_COUNT; i++) {
! 328: struct uath_rx_cmd *cmd = &sc->rx_cmd[i];
! 329:
! 330: usbd_setup_xfer(cmd->xfer, sc->cmd_rx_pipe, cmd, cmd->buf,
! 331: UATH_MAX_RXCMDSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
! 332: USBD_NO_TIMEOUT, uath_cmd_rxeof);
! 333: error = usbd_transfer(cmd->xfer);
! 334: if (error != USBD_IN_PROGRESS && error != 0) {
! 335: printf("%s: could not queue Rx command xfer\n",
! 336: sc->sc_dev.dv_xname);
! 337: goto fail3;
! 338: }
! 339: }
! 340:
! 341: /*
! 342: * We're now ready to send/receive firmware commands.
! 343: */
! 344: if (uath_reset(sc) != 0) {
! 345: printf("%s: could not initialize adapter\n",
! 346: sc->sc_dev.dv_xname);
! 347: goto fail3;
! 348: }
! 349: if (uath_query_eeprom(sc) != 0) {
! 350: printf("%s: could not read EEPROM\n", sc->sc_dev.dv_xname);
! 351: goto fail3;
! 352: }
! 353:
! 354: printf("%s: MAC/BBP AR5523, RF AR%c112, address %s\n",
! 355: sc->sc_dev.dv_xname, (sc->sc_flags & UATH_FLAG_ABG) ? '5': '2',
! 356: ether_sprintf(ic->ic_myaddr));
! 357:
! 358: /*
! 359: * Allocate xfers for Tx/Rx data pipes.
! 360: */
! 361: if (uath_alloc_tx_data_list(sc) != 0) {
! 362: printf("%s: could not allocate Tx data list\n",
! 363: sc->sc_dev.dv_xname);
! 364: goto fail3;
! 365: }
! 366: if (uath_alloc_rx_data_list(sc) != 0) {
! 367: printf("%s: could not allocate Rx data list\n",
! 368: sc->sc_dev.dv_xname);
! 369: goto fail4;
! 370: }
! 371:
! 372: ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */
! 373: ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */
! 374: ic->ic_state = IEEE80211_S_INIT;
! 375:
! 376: /* set device capabilities */
! 377: ic->ic_caps =
! 378: IEEE80211_C_TXPMGT | /* tx power management */
! 379: IEEE80211_C_SHPREAMBLE | /* short preamble supported */
! 380: IEEE80211_C_SHSLOT | /* short slot time supported */
! 381: IEEE80211_C_WEP; /* h/w WEP */
! 382:
! 383: /* set supported .11b and .11g rates */
! 384: ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
! 385: ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g;
! 386:
! 387: /* set supported .11b and .11g channels (1 through 14) */
! 388: for (i = 1; i <= 14; i++) {
! 389: ic->ic_channels[i].ic_freq =
! 390: ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
! 391: ic->ic_channels[i].ic_flags =
! 392: IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
! 393: IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
! 394: }
! 395:
! 396: ifp->if_softc = sc;
! 397: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
! 398: ifp->if_init = uath_init;
! 399: ifp->if_ioctl = uath_ioctl;
! 400: ifp->if_start = uath_start;
! 401: ifp->if_watchdog = uath_watchdog;
! 402: IFQ_SET_READY(&ifp->if_snd);
! 403: memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
! 404:
! 405: if_attach(ifp);
! 406: ieee80211_ifattach(ifp);
! 407:
! 408: /* override state transition machine */
! 409: sc->sc_newstate = ic->ic_newstate;
! 410: ic->ic_newstate = uath_newstate;
! 411: ieee80211_media_init(ifp, uath_media_change, ieee80211_media_status);
! 412:
! 413: #if NBPFILTER > 0
! 414: bpfattach(&sc->sc_drvbpf, ifp, DLT_IEEE802_11_RADIO,
! 415: sizeof (struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN);
! 416:
! 417: sc->sc_rxtap_len = sizeof sc->sc_rxtapu;
! 418: sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len);
! 419: sc->sc_rxtap.wr_ihdr.it_present = htole32(UATH_RX_RADIOTAP_PRESENT);
! 420:
! 421: sc->sc_txtap_len = sizeof sc->sc_txtapu;
! 422: sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len);
! 423: sc->sc_txtap.wt_ihdr.it_present = htole32(UATH_TX_RADIOTAP_PRESENT);
! 424: #endif
! 425:
! 426: usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
! 427: &sc->sc_dev);
! 428:
! 429: return;
! 430:
! 431: fail4: uath_free_tx_data_list(sc);
! 432: fail3: uath_free_rx_cmd_list(sc);
! 433: fail2: uath_free_tx_cmd_list(sc);
! 434: fail1: uath_close_pipes(sc);
! 435: }
! 436:
! 437: int
! 438: uath_detach(struct device *self, int flags)
! 439: {
! 440: struct uath_softc *sc = (struct uath_softc *)self;
! 441: struct ifnet *ifp = &sc->sc_ic.ic_if;
! 442: int s;
! 443:
! 444: s = splnet();
! 445:
! 446: if (sc->sc_flags & UATH_FLAG_PRE_FIRMWARE) {
! 447: uath_close_pipes(sc);
! 448: splx(s);
! 449: return 0;
! 450: }
! 451:
! 452: /* post-firmware device */
! 453:
! 454: usb_rem_task(sc->sc_udev, &sc->sc_task);
! 455: timeout_del(&sc->scan_to);
! 456: timeout_del(&sc->stat_to);
! 457:
! 458: ieee80211_ifdetach(ifp); /* free all nodes */
! 459: if_detach(ifp);
! 460:
! 461: sc->sc_dying = 1;
! 462: DPRINTF(("reclaiming %d references\n", sc->sc_refcnt));
! 463: while (sc->sc_refcnt > 0)
! 464: (void)tsleep(UATH_COND_NOREF(sc), 0, "uathdet", 0);
! 465: DPRINTF(("all references reclaimed\n"));
! 466:
! 467: /* abort and free xfers */
! 468: uath_free_tx_data_list(sc);
! 469: uath_free_rx_data_list(sc);
! 470: uath_free_tx_cmd_list(sc);
! 471: uath_free_rx_cmd_list(sc);
! 472:
! 473: /* close Tx/Rx pipes */
! 474: uath_close_pipes(sc);
! 475:
! 476: splx(s);
! 477:
! 478: usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
! 479: &sc->sc_dev);
! 480:
! 481: return 0;
! 482: }
! 483:
! 484: int
! 485: uath_open_pipes(struct uath_softc *sc)
! 486: {
! 487: int error;
! 488:
! 489: /*
! 490: * XXX pipes numbers are hardcoded because we don't have any way
! 491: * to distinguish the data pipes from the firmware command pipes
! 492: * (both are bulk pipes) using the endpoints descriptors.
! 493: */
! 494: error = usbd_open_pipe(sc->sc_iface, 0x01, USBD_EXCLUSIVE_USE,
! 495: &sc->cmd_tx_pipe);
! 496: if (error != 0) {
! 497: printf("%s: could not open Tx command pipe: %s\n",
! 498: sc->sc_dev.dv_xname, usbd_errstr(error));
! 499: goto fail;
! 500: }
! 501:
! 502: error = usbd_open_pipe(sc->sc_iface, 0x02, USBD_EXCLUSIVE_USE,
! 503: &sc->data_tx_pipe);
! 504: if (error != 0) {
! 505: printf("%s: could not open Tx data pipe: %s\n",
! 506: sc->sc_dev.dv_xname, usbd_errstr(error));
! 507: goto fail;
! 508: }
! 509:
! 510: error = usbd_open_pipe(sc->sc_iface, 0x81, USBD_EXCLUSIVE_USE,
! 511: &sc->cmd_rx_pipe);
! 512: if (error != 0) {
! 513: printf("%s: could not open Rx command pipe: %s\n",
! 514: sc->sc_dev.dv_xname, usbd_errstr(error));
! 515: goto fail;
! 516: }
! 517:
! 518: error = usbd_open_pipe(sc->sc_iface, 0x82, USBD_EXCLUSIVE_USE,
! 519: &sc->data_rx_pipe);
! 520: if (error != 0) {
! 521: printf("%s: could not open Rx data pipe: %s\n",
! 522: sc->sc_dev.dv_xname, usbd_errstr(error));
! 523: goto fail;
! 524: }
! 525:
! 526: return 0;
! 527:
! 528: fail: uath_close_pipes(sc);
! 529: return error;
! 530: }
! 531:
! 532: void
! 533: uath_close_pipes(struct uath_softc *sc)
! 534: {
! 535: /* assumes no transfers are pending on the pipes */
! 536:
! 537: if (sc->data_tx_pipe != NULL)
! 538: usbd_close_pipe(sc->data_tx_pipe);
! 539:
! 540: if (sc->data_rx_pipe != NULL)
! 541: usbd_close_pipe(sc->data_rx_pipe);
! 542:
! 543: if (sc->cmd_tx_pipe != NULL)
! 544: usbd_close_pipe(sc->cmd_tx_pipe);
! 545:
! 546: if (sc->cmd_rx_pipe != NULL)
! 547: usbd_close_pipe(sc->cmd_rx_pipe);
! 548: }
! 549:
! 550: int
! 551: uath_alloc_tx_data_list(struct uath_softc *sc)
! 552: {
! 553: int i, error;
! 554:
! 555: for (i = 0; i < UATH_TX_DATA_LIST_COUNT; i++) {
! 556: struct uath_tx_data *data = &sc->tx_data[i];
! 557:
! 558: data->sc = sc; /* backpointer for callbacks */
! 559:
! 560: data->xfer = usbd_alloc_xfer(sc->sc_udev);
! 561: if (data->xfer == NULL) {
! 562: printf("%s: could not allocate xfer\n",
! 563: sc->sc_dev.dv_xname);
! 564: error = ENOMEM;
! 565: goto fail;
! 566: }
! 567: data->buf = usbd_alloc_buffer(data->xfer, UATH_MAX_TXBUFSZ);
! 568: if (data->buf == NULL) {
! 569: printf("%s: could not allocate xfer buffer\n",
! 570: sc->sc_dev.dv_xname);
! 571: error = ENOMEM;
! 572: goto fail;
! 573: }
! 574: }
! 575: return 0;
! 576:
! 577: fail: uath_free_tx_data_list(sc);
! 578: return error;
! 579: }
! 580:
! 581: void
! 582: uath_free_tx_data_list(struct uath_softc *sc)
! 583: {
! 584: int i;
! 585:
! 586: /* make sure no transfers are pending */
! 587: usbd_abort_pipe(sc->data_tx_pipe);
! 588:
! 589: for (i = 0; i < UATH_TX_DATA_LIST_COUNT; i++)
! 590: if (sc->tx_data[i].xfer != NULL)
! 591: usbd_free_xfer(sc->tx_data[i].xfer);
! 592: }
! 593:
! 594: int
! 595: uath_alloc_rx_data_list(struct uath_softc *sc)
! 596: {
! 597: int i, error;
! 598:
! 599: SLIST_INIT(&sc->rx_freelist);
! 600: for (i = 0; i < UATH_RX_DATA_POOL_COUNT; i++) {
! 601: struct uath_rx_data *data = &sc->rx_data[i];
! 602:
! 603: data->sc = sc; /* backpointer for callbacks */
! 604:
! 605: data->xfer = usbd_alloc_xfer(sc->sc_udev);
! 606: if (data->xfer == NULL) {
! 607: printf("%s: could not allocate xfer\n",
! 608: sc->sc_dev.dv_xname);
! 609: error = ENOMEM;
! 610: goto fail;
! 611: }
! 612: data->buf = usbd_alloc_buffer(data->xfer, sc->rxbufsz);
! 613: if (data->buf == NULL) {
! 614: printf("%s: could not allocate xfer buffer\n",
! 615: sc->sc_dev.dv_xname);
! 616: error = ENOMEM;
! 617: goto fail;
! 618: }
! 619: SLIST_INSERT_HEAD(&sc->rx_freelist, data, next);
! 620: }
! 621: return 0;
! 622:
! 623: fail: uath_free_rx_data_list(sc);
! 624: return error;
! 625: }
! 626:
! 627: void
! 628: uath_free_rx_data_list(struct uath_softc *sc)
! 629: {
! 630: int i;
! 631:
! 632: /* make sure no transfers are pending */
! 633: usbd_abort_pipe(sc->data_rx_pipe);
! 634:
! 635: for (i = 0; i < UATH_RX_DATA_POOL_COUNT; i++)
! 636: if (sc->rx_data[i].xfer != NULL)
! 637: usbd_free_xfer(sc->rx_data[i].xfer);
! 638: }
! 639:
! 640: void
! 641: uath_free_rx_data(caddr_t buf, u_int size, void *arg)
! 642: {
! 643: struct uath_rx_data *data = arg;
! 644: struct uath_softc *sc = data->sc;
! 645:
! 646: /* put the buffer back in the free list */
! 647: SLIST_INSERT_HEAD(&sc->rx_freelist, data, next);
! 648:
! 649: /* release reference to softc */
! 650: if (--sc->sc_refcnt == 0 && sc->sc_dying)
! 651: wakeup(UATH_COND_NOREF(sc));
! 652: }
! 653:
! 654: int
! 655: uath_alloc_tx_cmd_list(struct uath_softc *sc)
! 656: {
! 657: int i, error;
! 658:
! 659: for (i = 0; i < UATH_TX_CMD_LIST_COUNT; i++) {
! 660: struct uath_tx_cmd *cmd = &sc->tx_cmd[i];
! 661:
! 662: cmd->sc = sc; /* backpointer for callbacks */
! 663:
! 664: cmd->xfer = usbd_alloc_xfer(sc->sc_udev);
! 665: if (cmd->xfer == NULL) {
! 666: printf("%s: could not allocate xfer\n",
! 667: sc->sc_dev.dv_xname);
! 668: error = ENOMEM;
! 669: goto fail;
! 670: }
! 671: cmd->buf = usbd_alloc_buffer(cmd->xfer, UATH_MAX_TXCMDSZ);
! 672: if (cmd->buf == NULL) {
! 673: printf("%s: could not allocate xfer buffer\n",
! 674: sc->sc_dev.dv_xname);
! 675: error = ENOMEM;
! 676: goto fail;
! 677: }
! 678: }
! 679: return 0;
! 680:
! 681: fail: uath_free_tx_cmd_list(sc);
! 682: return error;
! 683: }
! 684:
! 685: void
! 686: uath_free_tx_cmd_list(struct uath_softc *sc)
! 687: {
! 688: int i;
! 689:
! 690: /* make sure no transfers are pending */
! 691: usbd_abort_pipe(sc->cmd_tx_pipe);
! 692:
! 693: for (i = 0; i < UATH_TX_CMD_LIST_COUNT; i++)
! 694: if (sc->tx_cmd[i].xfer != NULL)
! 695: usbd_free_xfer(sc->tx_cmd[i].xfer);
! 696: }
! 697:
! 698: int
! 699: uath_alloc_rx_cmd_list(struct uath_softc *sc)
! 700: {
! 701: int i, error;
! 702:
! 703: for (i = 0; i < UATH_RX_CMD_LIST_COUNT; i++) {
! 704: struct uath_rx_cmd *cmd = &sc->rx_cmd[i];
! 705:
! 706: cmd->sc = sc; /* backpointer for callbacks */
! 707:
! 708: cmd->xfer = usbd_alloc_xfer(sc->sc_udev);
! 709: if (cmd->xfer == NULL) {
! 710: printf("%s: could not allocate xfer\n",
! 711: sc->sc_dev.dv_xname);
! 712: error = ENOMEM;
! 713: goto fail;
! 714: }
! 715: cmd->buf = usbd_alloc_buffer(cmd->xfer, UATH_MAX_RXCMDSZ);
! 716: if (cmd->buf == NULL) {
! 717: printf("%s: could not allocate xfer buffer\n",
! 718: sc->sc_dev.dv_xname);
! 719: error = ENOMEM;
! 720: goto fail;
! 721: }
! 722: }
! 723: return 0;
! 724:
! 725: fail: uath_free_rx_cmd_list(sc);
! 726: return error;
! 727: }
! 728:
! 729: void
! 730: uath_free_rx_cmd_list(struct uath_softc *sc)
! 731: {
! 732: int i;
! 733:
! 734: /* make sure no transfers are pending */
! 735: usbd_abort_pipe(sc->cmd_rx_pipe);
! 736:
! 737: for (i = 0; i < UATH_RX_CMD_LIST_COUNT; i++)
! 738: if (sc->rx_cmd[i].xfer != NULL)
! 739: usbd_free_xfer(sc->rx_cmd[i].xfer);
! 740: }
! 741:
! 742: int
! 743: uath_media_change(struct ifnet *ifp)
! 744: {
! 745: int error;
! 746:
! 747: error = ieee80211_media_change(ifp);
! 748: if (error != ENETRESET)
! 749: return error;
! 750:
! 751: if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING))
! 752: uath_init(ifp);
! 753:
! 754: return 0;
! 755: }
! 756:
! 757: /*
! 758: * This function is called periodically (every second) when associated to
! 759: * query device statistics.
! 760: */
! 761: void
! 762: uath_stat(void *arg)
! 763: {
! 764: struct uath_softc *sc = arg;
! 765: int error;
! 766:
! 767: /*
! 768: * Send request for statistics asynchronously. The timer will be
! 769: * restarted when we'll get the stats notification.
! 770: */
! 771: error = uath_cmd_write(sc, UATH_CMD_STATS, NULL, 0,
! 772: UATH_CMD_FLAG_ASYNC);
! 773: if (error != 0) {
! 774: printf("%s: could not query statistics (error=%d)\n",
! 775: sc->sc_dev.dv_xname, error);
! 776: }
! 777: }
! 778:
! 779: /*
! 780: * This function is called periodically (every 250ms) during scanning to
! 781: * switch from one channel to another.
! 782: */
! 783: void
! 784: uath_next_scan(void *arg)
! 785: {
! 786: struct uath_softc *sc = arg;
! 787: struct ieee80211com *ic = &sc->sc_ic;
! 788: struct ifnet *ifp = &ic->ic_if;
! 789:
! 790: if (ic->ic_state == IEEE80211_S_SCAN)
! 791: ieee80211_next_scan(ifp);
! 792: }
! 793:
! 794: void
! 795: uath_task(void *arg)
! 796: {
! 797: struct uath_softc *sc = arg;
! 798: struct ieee80211com *ic = &sc->sc_ic;
! 799: enum ieee80211_state ostate;
! 800:
! 801: ostate = ic->ic_state;
! 802:
! 803: switch (sc->sc_state) {
! 804: case IEEE80211_S_INIT:
! 805: if (ostate == IEEE80211_S_RUN) {
! 806: /* turn link and activity LEDs off */
! 807: (void)uath_set_led(sc, UATH_LED_LINK, 0);
! 808: (void)uath_set_led(sc, UATH_LED_ACTIVITY, 0);
! 809: }
! 810: break;
! 811:
! 812: case IEEE80211_S_SCAN:
! 813: if (uath_switch_channel(sc, ic->ic_bss->ni_chan) != 0) {
! 814: printf("%s: could not switch channel\n",
! 815: sc->sc_dev.dv_xname);
! 816: break;
! 817: }
! 818: timeout_add(&sc->scan_to, hz / 4);
! 819: break;
! 820:
! 821: case IEEE80211_S_AUTH:
! 822: {
! 823: struct ieee80211_node *ni = ic->ic_bss;
! 824: struct uath_cmd_bssid bssid;
! 825: struct uath_cmd_0b cmd0b;
! 826: struct uath_cmd_0c cmd0c;
! 827:
! 828: if (uath_switch_channel(sc, ni->ni_chan) != 0) {
! 829: printf("%s: could not switch channel\n",
! 830: sc->sc_dev.dv_xname);
! 831: break;
! 832: }
! 833:
! 834: (void)uath_cmd_write(sc, UATH_CMD_24, NULL, 0, 0);
! 835:
! 836: bzero(&bssid, sizeof bssid);
! 837: bssid.len = htobe32(IEEE80211_ADDR_LEN);
! 838: IEEE80211_ADDR_COPY(bssid.bssid, ni->ni_bssid);
! 839: (void)uath_cmd_write(sc, UATH_CMD_SET_BSSID, &bssid,
! 840: sizeof bssid, 0);
! 841:
! 842: bzero(&cmd0b, sizeof cmd0b);
! 843: cmd0b.code = htobe32(2);
! 844: cmd0b.size = htobe32(sizeof (cmd0b.data));
! 845: (void)uath_cmd_write(sc, UATH_CMD_0B, &cmd0b, sizeof cmd0b, 0);
! 846:
! 847: bzero(&cmd0c, sizeof cmd0c);
! 848: cmd0c.magic1 = htobe32(2);
! 849: cmd0c.magic2 = htobe32(7);
! 850: cmd0c.magic3 = htobe32(1);
! 851: (void)uath_cmd_write(sc, UATH_CMD_0C, &cmd0c, sizeof cmd0c, 0);
! 852:
! 853: if (uath_set_rates(sc, &ni->ni_rates) != 0) {
! 854: printf("%s: could not set negotiated rate set\n",
! 855: sc->sc_dev.dv_xname);
! 856: break;
! 857: }
! 858: break;
! 859: }
! 860:
! 861: case IEEE80211_S_ASSOC:
! 862: break;
! 863:
! 864: case IEEE80211_S_RUN:
! 865: {
! 866: struct ieee80211_node *ni = ic->ic_bss;
! 867: struct uath_cmd_bssid bssid;
! 868: struct uath_cmd_xled xled;
! 869: uint32_t val;
! 870:
! 871: if (ic->ic_opmode == IEEE80211_M_MONITOR) {
! 872: /* make both LEDs blink while monitoring */
! 873: bzero(&xled, sizeof xled);
! 874: xled.which = htobe32(0);
! 875: xled.rate = htobe32(1);
! 876: xled.mode = htobe32(2);
! 877: (void)uath_cmd_write(sc, UATH_CMD_SET_XLED, &xled,
! 878: sizeof xled, 0);
! 879: break;
! 880: }
! 881:
! 882: /*
! 883: * Tx rate is controlled by firmware, report the maximum
! 884: * negotiated rate in ifconfig output.
! 885: */
! 886: ni->ni_txrate = ni->ni_rates.rs_nrates - 1;
! 887:
! 888: val = htobe32(1);
! 889: (void)uath_cmd_write(sc, UATH_CMD_2E, &val, sizeof val, 0);
! 890:
! 891: bzero(&bssid, sizeof bssid);
! 892: bssid.flags1 = htobe32(0xc004);
! 893: bssid.flags2 = htobe32(0x003b);
! 894: bssid.len = htobe32(IEEE80211_ADDR_LEN);
! 895: IEEE80211_ADDR_COPY(bssid.bssid, ni->ni_bssid);
! 896: (void)uath_cmd_write(sc, UATH_CMD_SET_BSSID, &bssid,
! 897: sizeof bssid, 0);
! 898:
! 899: /* turn link LED on */
! 900: (void)uath_set_led(sc, UATH_LED_LINK, 1);
! 901:
! 902: /* make activity LED blink */
! 903: bzero(&xled, sizeof xled);
! 904: xled.which = htobe32(1);
! 905: xled.rate = htobe32(1);
! 906: xled.mode = htobe32(2);
! 907: (void)uath_cmd_write(sc, UATH_CMD_SET_XLED, &xled, sizeof xled,
! 908: 0);
! 909:
! 910: /* set state to associated */
! 911: val = htobe32(1);
! 912: (void)uath_cmd_write(sc, UATH_CMD_SET_STATE, &val, sizeof val,
! 913: 0);
! 914:
! 915: /* start statistics timer */
! 916: timeout_add(&sc->stat_to, hz);
! 917: break;
! 918: }
! 919: }
! 920: sc->sc_newstate(ic, sc->sc_state, sc->sc_arg);
! 921: }
! 922:
! 923: int
! 924: uath_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
! 925: {
! 926: struct uath_softc *sc = ic->ic_softc;
! 927:
! 928: usb_rem_task(sc->sc_udev, &sc->sc_task);
! 929: timeout_del(&sc->scan_to);
! 930: timeout_del(&sc->stat_to);
! 931:
! 932: /* do it in a process context */
! 933: sc->sc_state = nstate;
! 934: sc->sc_arg = arg;
! 935: usb_add_task(sc->sc_udev, &sc->sc_task);
! 936: return 0;
! 937: }
! 938:
! 939: #ifdef UATH_DEBUG
! 940: void
! 941: uath_dump_cmd(const uint8_t *buf, int len, char prefix)
! 942: {
! 943: int i;
! 944:
! 945: for (i = 0; i < len; i++) {
! 946: if ((i % 16) == 0)
! 947: printf("\n%c ", prefix);
! 948: else if ((i % 4) == 0)
! 949: printf(" ");
! 950: printf("%02x", buf[i]);
! 951: }
! 952: printf("\n");
! 953: }
! 954: #endif
! 955:
! 956: /*
! 957: * Low-level function to send read or write commands to the firmware.
! 958: */
! 959: int
! 960: uath_cmd(struct uath_softc *sc, uint32_t code, const void *idata, int ilen,
! 961: void *odata, int flags)
! 962: {
! 963: struct uath_cmd_hdr *hdr;
! 964: struct uath_tx_cmd *cmd;
! 965: uint16_t xferflags;
! 966: int s, xferlen, error;
! 967:
! 968: /* grab a xfer */
! 969: cmd = &sc->tx_cmd[sc->cmd_idx];
! 970:
! 971: /* always bulk-out a multiple of 4 bytes */
! 972: xferlen = (sizeof (struct uath_cmd_hdr) + ilen + 3) & ~3;
! 973:
! 974: hdr = (struct uath_cmd_hdr *)cmd->buf;
! 975: bzero(hdr, sizeof (struct uath_cmd_hdr));
! 976: hdr->len = htobe32(xferlen);
! 977: hdr->code = htobe32(code);
! 978: hdr->priv = sc->cmd_idx; /* don't care about endianness */
! 979: hdr->magic = htobe32((flags & UATH_CMD_FLAG_MAGIC) ? 1 << 24 : 0);
! 980: bcopy(idata, (uint8_t *)(hdr + 1), ilen);
! 981:
! 982: #ifdef UATH_DEBUG
! 983: if (uath_debug >= 5) {
! 984: printf("sending command code=0x%02x flags=0x%x index=%u",
! 985: code, flags, sc->cmd_idx);
! 986: uath_dump_cmd(cmd->buf, xferlen, '+');
! 987: }
! 988: #endif
! 989: xferflags = USBD_FORCE_SHORT_XFER | USBD_NO_COPY;
! 990: if (!(flags & UATH_CMD_FLAG_READ)) {
! 991: if (!(flags & UATH_CMD_FLAG_ASYNC))
! 992: xferflags |= USBD_SYNCHRONOUS;
! 993: } else
! 994: s = splusb();
! 995:
! 996: cmd->odata = odata;
! 997:
! 998: usbd_setup_xfer(cmd->xfer, sc->cmd_tx_pipe, cmd, cmd->buf, xferlen,
! 999: xferflags, UATH_CMD_TIMEOUT, NULL);
! 1000: error = usbd_transfer(cmd->xfer);
! 1001: if (error != USBD_IN_PROGRESS && error != 0) {
! 1002: if (flags & UATH_CMD_FLAG_READ)
! 1003: splx(s);
! 1004: printf("%s: could not send command 0x%x (error=%s)\n",
! 1005: sc->sc_dev.dv_xname, code, usbd_errstr(error));
! 1006: return error;
! 1007: }
! 1008: sc->cmd_idx = (sc->cmd_idx + 1) % UATH_TX_CMD_LIST_COUNT;
! 1009:
! 1010: if (!(flags & UATH_CMD_FLAG_READ))
! 1011: return 0; /* write: don't wait for reply */
! 1012:
! 1013: /* wait at most two seconds for command reply */
! 1014: error = tsleep(cmd, PCATCH, "uathcmd", 2 * hz);
! 1015: cmd->odata = NULL; /* in case answer is received too late */
! 1016: splx(s);
! 1017: if (error != 0) {
! 1018: printf("%s: timeout waiting for command reply\n",
! 1019: sc->sc_dev.dv_xname);
! 1020: }
! 1021: return error;
! 1022: }
! 1023:
! 1024: int
! 1025: uath_cmd_write(struct uath_softc *sc, uint32_t code, const void *data, int len,
! 1026: int flags)
! 1027: {
! 1028: flags &= ~UATH_CMD_FLAG_READ;
! 1029: return uath_cmd(sc, code, data, len, NULL, flags);
! 1030: }
! 1031:
! 1032: int
! 1033: uath_cmd_read(struct uath_softc *sc, uint32_t code, const void *idata,
! 1034: int ilen, void *odata, int flags)
! 1035: {
! 1036: flags |= UATH_CMD_FLAG_READ;
! 1037: return uath_cmd(sc, code, idata, ilen, odata, flags);
! 1038: }
! 1039:
! 1040: int
! 1041: uath_write_reg(struct uath_softc *sc, uint32_t reg, uint32_t val)
! 1042: {
! 1043: struct uath_write_mac write;
! 1044: int error;
! 1045:
! 1046: write.reg = htobe32(reg);
! 1047: write.len = htobe32(0); /* 0 = single write */
! 1048: *(uint32_t *)write.data = htobe32(val);
! 1049:
! 1050: error = uath_cmd_write(sc, UATH_CMD_WRITE_MAC, &write,
! 1051: 3 * sizeof (uint32_t), 0);
! 1052: if (error != 0) {
! 1053: printf("%s: could not write register 0x%02x\n",
! 1054: sc->sc_dev.dv_xname, reg);
! 1055: }
! 1056: return error;
! 1057: }
! 1058:
! 1059: int
! 1060: uath_write_multi(struct uath_softc *sc, uint32_t reg, const void *data,
! 1061: int len)
! 1062: {
! 1063: struct uath_write_mac write;
! 1064: int error;
! 1065:
! 1066: write.reg = htobe32(reg);
! 1067: write.len = htobe32(len);
! 1068: bcopy(data, write.data, len);
! 1069:
! 1070: /* properly handle the case where len is zero (reset) */
! 1071: error = uath_cmd_write(sc, UATH_CMD_WRITE_MAC, &write,
! 1072: (len == 0) ? sizeof (uint32_t) : 2 * sizeof (uint32_t) + len, 0);
! 1073: if (error != 0) {
! 1074: printf("%s: could not write %d bytes to register 0x%02x\n",
! 1075: sc->sc_dev.dv_xname, len, reg);
! 1076: }
! 1077: return error;
! 1078: }
! 1079:
! 1080: int
! 1081: uath_read_reg(struct uath_softc *sc, uint32_t reg, uint32_t *val)
! 1082: {
! 1083: struct uath_read_mac read;
! 1084: int error;
! 1085:
! 1086: reg = htobe32(reg);
! 1087: error = uath_cmd_read(sc, UATH_CMD_READ_MAC, ®, sizeof reg, &read,
! 1088: 0);
! 1089: if (error != 0) {
! 1090: printf("%s: could not read register 0x%02x\n",
! 1091: sc->sc_dev.dv_xname, betoh32(reg));
! 1092: return error;
! 1093: }
! 1094: *val = betoh32(*(uint32_t *)read.data);
! 1095: return error;
! 1096: }
! 1097:
! 1098: int
! 1099: uath_read_eeprom(struct uath_softc *sc, uint32_t reg, void *odata)
! 1100: {
! 1101: struct uath_read_mac read;
! 1102: int len, error;
! 1103:
! 1104: reg = htobe32(reg);
! 1105: error = uath_cmd_read(sc, UATH_CMD_READ_EEPROM, ®, sizeof reg,
! 1106: &read, 0);
! 1107: if (error != 0) {
! 1108: printf("%s: could not read EEPROM offset 0x%02x\n",
! 1109: sc->sc_dev.dv_xname, betoh32(reg));
! 1110: return error;
! 1111: }
! 1112: len = betoh32(read.len);
! 1113: bcopy(read.data, odata, (len == 0) ? sizeof (uint32_t) : len);
! 1114: return error;
! 1115: }
! 1116:
! 1117: void
! 1118: uath_cmd_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv,
! 1119: usbd_status status)
! 1120: {
! 1121: struct uath_rx_cmd *cmd = priv;
! 1122: struct uath_softc *sc = cmd->sc;
! 1123: struct uath_cmd_hdr *hdr;
! 1124:
! 1125: if (status != USBD_NORMAL_COMPLETION) {
! 1126: if (status == USBD_STALLED)
! 1127: usbd_clear_endpoint_stall_async(sc->cmd_rx_pipe);
! 1128: return;
! 1129: }
! 1130:
! 1131: hdr = (struct uath_cmd_hdr *)cmd->buf;
! 1132:
! 1133: #ifdef UATH_DEBUG
! 1134: if (uath_debug >= 5) {
! 1135: printf("received command code=0x%x index=%u len=%u",
! 1136: betoh32(hdr->code), hdr->priv, betoh32(hdr->len));
! 1137: uath_dump_cmd(cmd->buf, betoh32(hdr->len), '-');
! 1138: }
! 1139: #endif
! 1140:
! 1141: switch (betoh32(hdr->code) & 0xff) {
! 1142: /* reply to a read command */
! 1143: default:
! 1144: {
! 1145: struct uath_tx_cmd *txcmd = &sc->tx_cmd[hdr->priv];
! 1146:
! 1147: if (txcmd->odata != NULL) {
! 1148: /* copy answer into caller's supplied buffer */
! 1149: bcopy((uint8_t *)(hdr + 1), txcmd->odata,
! 1150: betoh32(hdr->len) - sizeof (struct uath_cmd_hdr));
! 1151: }
! 1152: wakeup(txcmd); /* wake up caller */
! 1153: break;
! 1154: }
! 1155: /* spontaneous firmware notifications */
! 1156: case UATH_NOTIF_READY:
! 1157: DPRINTF(("received device ready notification\n"));
! 1158: wakeup(UATH_COND_INIT(sc));
! 1159: break;
! 1160:
! 1161: case UATH_NOTIF_TX:
! 1162: /* this notification is sent when UATH_TX_NOTIFY is set */
! 1163: DPRINTF(("received Tx notification\n"));
! 1164: break;
! 1165:
! 1166: case UATH_NOTIF_STATS:
! 1167: DPRINTFN(2, ("received device statistics\n"));
! 1168: timeout_add(&sc->stat_to, hz);
! 1169: break;
! 1170: }
! 1171:
! 1172: /* setup a new transfer */
! 1173: usbd_setup_xfer(xfer, sc->cmd_rx_pipe, cmd, cmd->buf, UATH_MAX_RXCMDSZ,
! 1174: USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
! 1175: uath_cmd_rxeof);
! 1176: (void)usbd_transfer(xfer);
! 1177: }
! 1178:
! 1179: void
! 1180: uath_data_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv,
! 1181: usbd_status status)
! 1182: {
! 1183: struct uath_rx_data *data = priv;
! 1184: struct uath_softc *sc = data->sc;
! 1185: struct ieee80211com *ic = &sc->sc_ic;
! 1186: struct ifnet *ifp = &ic->ic_if;
! 1187: struct ieee80211_frame *wh;
! 1188: struct ieee80211_node *ni;
! 1189: struct uath_rx_data *ndata;
! 1190: struct uath_rx_desc *desc;
! 1191: struct mbuf *m;
! 1192: uint32_t hdr;
! 1193: int s, len;
! 1194:
! 1195: if (status != USBD_NORMAL_COMPLETION) {
! 1196: if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
! 1197: return;
! 1198:
! 1199: if (status == USBD_STALLED)
! 1200: usbd_clear_endpoint_stall_async(sc->data_rx_pipe);
! 1201:
! 1202: ifp->if_ierrors++;
! 1203: return;
! 1204: }
! 1205: usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL);
! 1206:
! 1207: if (len < UATH_MIN_RXBUFSZ) {
! 1208: DPRINTF(("wrong xfer size (len=%d)\n", len));
! 1209: ifp->if_ierrors++;
! 1210: goto skip;
! 1211: }
! 1212:
! 1213: hdr = betoh32(*(uint32_t *)data->buf);
! 1214:
! 1215: /* Rx descriptor is located at the end, 32-bit aligned */
! 1216: desc = (struct uath_rx_desc *)
! 1217: (data->buf + len - sizeof (struct uath_rx_desc));
! 1218:
! 1219: if (betoh32(desc->len) > sc->rxbufsz) {
! 1220: DPRINTF(("bad descriptor (len=%d)\n", betoh32(desc->len)));
! 1221: ifp->if_ierrors++;
! 1222: goto skip;
! 1223: }
! 1224:
! 1225: /* there's probably a "bad CRC" flag somewhere in the descriptor.. */
! 1226:
! 1227: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 1228: if (m == NULL) {
! 1229: ifp->if_ierrors++;
! 1230: goto skip;
! 1231: }
! 1232:
! 1233: /* grab a new Rx buffer */
! 1234: ndata = SLIST_FIRST(&sc->rx_freelist);
! 1235: if (ndata == NULL) {
! 1236: printf("%s: could not allocate Rx buffer\n",
! 1237: sc->sc_dev.dv_xname);
! 1238: m_freem(m);
! 1239: ifp->if_ierrors++;
! 1240: goto skip;
! 1241: }
! 1242: SLIST_REMOVE_HEAD(&sc->rx_freelist, next);
! 1243:
! 1244: MEXTADD(m, data->buf, sc->rxbufsz, 0, uath_free_rx_data, data);
! 1245:
! 1246: /* finalize mbuf */
! 1247: m->m_pkthdr.rcvif = ifp;
! 1248: m->m_data = data->buf + sizeof (uint32_t);
! 1249: m->m_pkthdr.len = m->m_len = betoh32(desc->len) -
! 1250: sizeof (struct uath_rx_desc) - IEEE80211_CRC_LEN;
! 1251:
! 1252: data = ndata;
! 1253:
! 1254: wh = mtod(m, struct ieee80211_frame *);
! 1255: if ((wh->i_fc[1] & IEEE80211_FC1_WEP) &&
! 1256: ic->ic_opmode != IEEE80211_M_MONITOR) {
! 1257: /*
! 1258: * Hardware decrypts the frame itself but leaves the WEP bit
! 1259: * set in the 802.11 header and doesn't remove the IV and CRC
! 1260: * fields.
! 1261: */
! 1262: wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
! 1263: ovbcopy(wh, (caddr_t)wh + IEEE80211_WEP_IVLEN +
! 1264: IEEE80211_WEP_KIDLEN, sizeof (struct ieee80211_frame));
! 1265: m_adj(m, IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN);
! 1266: m_adj(m, -IEEE80211_WEP_CRCLEN);
! 1267: wh = mtod(m, struct ieee80211_frame *);
! 1268: }
! 1269:
! 1270: #if NBPFILTER > 0
! 1271: /* there are a lot more fields in the Rx descriptor */
! 1272: if (sc->sc_drvbpf != NULL) {
! 1273: struct mbuf mb;
! 1274: struct uath_rx_radiotap_header *tap = &sc->sc_rxtap;
! 1275:
! 1276: tap->wr_flags = 0;
! 1277: tap->wr_chan_freq = htole16(betoh32(desc->freq));
! 1278: tap->wr_chan_flags = htole16(ic->ic_bss->ni_chan->ic_flags);
! 1279: tap->wr_dbm_antsignal = (int8_t)betoh32(desc->rssi);
! 1280:
! 1281: mb.m_data = (caddr_t)tap;
! 1282: mb.m_len = sc->sc_rxtap_len;
! 1283: mb.m_next = m;
! 1284: mb.m_nextpkt = NULL;
! 1285: mb.m_type = 0;
! 1286: mb.m_flags = 0;
! 1287: bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_IN);
! 1288: }
! 1289: #endif
! 1290:
! 1291: s = splnet();
! 1292: sc->sc_refcnt++;
! 1293: ni = ieee80211_find_rxnode(ic, wh);
! 1294: ieee80211_input(ifp, m, ni, (int)betoh32(desc->rssi), 0);
! 1295:
! 1296: /* node is no longer needed */
! 1297: ieee80211_release_node(ic, ni);
! 1298: splx(s);
! 1299:
! 1300: skip: /* setup a new transfer */
! 1301: usbd_setup_xfer(data->xfer, sc->data_rx_pipe, data, data->buf,
! 1302: sc->rxbufsz, USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
! 1303: uath_data_rxeof);
! 1304: (void)usbd_transfer(data->xfer);
! 1305: }
! 1306:
! 1307: int
! 1308: uath_tx_null(struct uath_softc *sc)
! 1309: {
! 1310: struct uath_tx_data *data;
! 1311: struct uath_tx_desc *desc;
! 1312:
! 1313: data = &sc->tx_data[sc->data_idx];
! 1314:
! 1315: data->ni = NULL;
! 1316:
! 1317: *(uint32_t *)data->buf = UATH_MAKECTL(1, sizeof (struct uath_tx_desc));
! 1318: desc = (struct uath_tx_desc *)(data->buf + sizeof (uint32_t));
! 1319:
! 1320: bzero(desc, sizeof (struct uath_tx_desc));
! 1321: desc->len = htobe32(sizeof (struct uath_tx_desc));
! 1322: desc->type = htobe32(UATH_TX_NULL);
! 1323:
! 1324: usbd_setup_xfer(data->xfer, sc->data_tx_pipe, data, data->buf,
! 1325: sizeof (uint32_t) + sizeof (struct uath_tx_desc), USBD_NO_COPY |
! 1326: USBD_FORCE_SHORT_XFER, UATH_DATA_TIMEOUT, NULL);
! 1327: if (usbd_sync_transfer(data->xfer) != 0)
! 1328: return EIO;
! 1329:
! 1330: sc->data_idx = (sc->data_idx + 1) % UATH_TX_DATA_LIST_COUNT;
! 1331:
! 1332: return uath_cmd_write(sc, UATH_CMD_0F, NULL, 0, UATH_CMD_FLAG_ASYNC);
! 1333: }
! 1334:
! 1335: void
! 1336: uath_data_txeof(usbd_xfer_handle xfer, usbd_private_handle priv,
! 1337: usbd_status status)
! 1338: {
! 1339: struct uath_tx_data *data = priv;
! 1340: struct uath_softc *sc = data->sc;
! 1341: struct ieee80211com *ic = &sc->sc_ic;
! 1342: struct ifnet *ifp = &ic->ic_if;
! 1343: int s;
! 1344:
! 1345: if (status != USBD_NORMAL_COMPLETION) {
! 1346: if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
! 1347: return;
! 1348:
! 1349: printf("%s: could not transmit buffer: %s\n",
! 1350: sc->sc_dev.dv_xname, usbd_errstr(status));
! 1351:
! 1352: if (status == USBD_STALLED)
! 1353: usbd_clear_endpoint_stall_async(sc->data_tx_pipe);
! 1354:
! 1355: ifp->if_oerrors++;
! 1356: return;
! 1357: }
! 1358:
! 1359: s = splnet();
! 1360:
! 1361: ieee80211_release_node(ic, data->ni);
! 1362: data->ni = NULL;
! 1363:
! 1364: sc->tx_queued--;
! 1365: ifp->if_opackets++;
! 1366:
! 1367: sc->sc_tx_timer = 0;
! 1368: ifp->if_flags &= ~IFF_OACTIVE;
! 1369: uath_start(ifp);
! 1370:
! 1371: splx(s);
! 1372: }
! 1373:
! 1374: int
! 1375: uath_tx_data(struct uath_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
! 1376: {
! 1377: struct ieee80211com *ic = &sc->sc_ic;
! 1378: struct uath_tx_data *data;
! 1379: struct uath_tx_desc *desc;
! 1380: const struct ieee80211_frame *wh;
! 1381: int paylen, totlen, xferlen, error;
! 1382:
! 1383: data = &sc->tx_data[sc->data_idx];
! 1384: desc = (struct uath_tx_desc *)(data->buf + sizeof (uint32_t));
! 1385:
! 1386: data->ni = ni;
! 1387:
! 1388: #if NBPFILTER > 0
! 1389: if (sc->sc_drvbpf != NULL) {
! 1390: struct mbuf mb;
! 1391: struct uath_tx_radiotap_header *tap = &sc->sc_txtap;
! 1392:
! 1393: tap->wt_flags = 0;
! 1394: tap->wt_chan_freq = htole16(ic->ic_bss->ni_chan->ic_freq);
! 1395: tap->wt_chan_flags = htole16(ic->ic_bss->ni_chan->ic_flags);
! 1396:
! 1397: mb.m_data = (caddr_t)tap;
! 1398: mb.m_len = sc->sc_txtap_len;
! 1399: mb.m_next = m0;
! 1400: mb.m_nextpkt = NULL;
! 1401: mb.m_type = 0;
! 1402: mb.m_flags = 0;
! 1403: bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_OUT);
! 1404: }
! 1405: #endif
! 1406:
! 1407: paylen = m0->m_pkthdr.len;
! 1408: xferlen = sizeof (uint32_t) + sizeof (struct uath_tx_desc) + paylen;
! 1409:
! 1410: wh = mtod(m0, struct ieee80211_frame *);
! 1411: if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
! 1412: uint8_t *frm = (uint8_t *)(desc + 1);
! 1413: uint32_t iv;
! 1414:
! 1415: /* h/w WEP: it's up to the host to fill the IV field */
! 1416: bcopy(wh, frm, sizeof (struct ieee80211_frame));
! 1417: frm += sizeof (struct ieee80211_frame);
! 1418:
! 1419: /* insert IV: code copied from net80211 */
! 1420: iv = (ic->ic_iv != 0) ? ic->ic_iv : arc4random();
! 1421: if (iv >= 0x03ff00 && (iv & 0xf8ff00) == 0x00ff00)
! 1422: iv += 0x000100;
! 1423: ic->ic_iv = iv + 1;
! 1424:
! 1425: *frm++ = iv & 0xff;
! 1426: *frm++ = (iv >> 8) & 0xff;
! 1427: *frm++ = (iv >> 16) & 0xff;
! 1428: *frm++ = ic->ic_wep_txkey << 6;
! 1429:
! 1430: m_copydata(m0, sizeof (struct ieee80211_frame),
! 1431: m0->m_pkthdr.len - sizeof (struct ieee80211_frame), frm);
! 1432:
! 1433: paylen += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN;
! 1434: xferlen += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN;
! 1435: totlen = xferlen + IEEE80211_WEP_CRCLEN;
! 1436: } else {
! 1437: m_copydata(m0, 0, m0->m_pkthdr.len, (uint8_t *)(desc + 1));
! 1438: totlen = xferlen;
! 1439: }
! 1440:
! 1441: /* fill Tx descriptor */
! 1442: *(uint32_t *)data->buf = UATH_MAKECTL(1, xferlen - sizeof (uint32_t));
! 1443:
! 1444: desc->len = htobe32(totlen);
! 1445: desc->priv = sc->data_idx; /* don't care about endianness */
! 1446: desc->paylen = htobe32(paylen);
! 1447: desc->type = htobe32(UATH_TX_DATA);
! 1448: desc->flags = htobe32(0);
! 1449: if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
! 1450: desc->dest = htobe32(UATH_ID_BROADCAST);
! 1451: desc->magic = htobe32(3);
! 1452: } else {
! 1453: desc->dest = htobe32(UATH_ID_BSS);
! 1454: desc->magic = htobe32(1);
! 1455: }
! 1456:
! 1457: m_freem(m0); /* mbuf is no longer needed */
! 1458:
! 1459: #ifdef UATH_DEBUG
! 1460: if (uath_debug >= 6) {
! 1461: printf("sending frame index=%u len=%d xferlen=%d",
! 1462: sc->data_idx, paylen, xferlen);
! 1463: uath_dump_cmd(data->buf, xferlen, '+');
! 1464: }
! 1465: #endif
! 1466: usbd_setup_xfer(data->xfer, sc->data_tx_pipe, data, data->buf, xferlen,
! 1467: USBD_FORCE_SHORT_XFER | USBD_NO_COPY, UATH_DATA_TIMEOUT,
! 1468: uath_data_txeof);
! 1469: error = usbd_transfer(data->xfer);
! 1470: if (error != USBD_IN_PROGRESS && error != 0) {
! 1471: ic->ic_if.if_oerrors++;
! 1472: return error;
! 1473: }
! 1474: sc->data_idx = (sc->data_idx + 1) % UATH_TX_DATA_LIST_COUNT;
! 1475: sc->tx_queued++;
! 1476:
! 1477: return 0;
! 1478: }
! 1479:
! 1480: void
! 1481: uath_start(struct ifnet *ifp)
! 1482: {
! 1483: struct uath_softc *sc = ifp->if_softc;
! 1484: struct ieee80211com *ic = &sc->sc_ic;
! 1485: struct ieee80211_node *ni;
! 1486: struct mbuf *m0;
! 1487:
! 1488: /*
! 1489: * net80211 may still try to send management frames even if the
! 1490: * IFF_RUNNING flag is not set...
! 1491: */
! 1492: if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
! 1493: return;
! 1494:
! 1495: for (;;) {
! 1496: IF_POLL(&ic->ic_mgtq, m0);
! 1497: if (m0 != NULL) {
! 1498: if (sc->tx_queued >= UATH_TX_DATA_LIST_COUNT) {
! 1499: ifp->if_flags |= IFF_OACTIVE;
! 1500: break;
! 1501: }
! 1502: IF_DEQUEUE(&ic->ic_mgtq, m0);
! 1503:
! 1504: ni = (struct ieee80211_node *)m0->m_pkthdr.rcvif;
! 1505: m0->m_pkthdr.rcvif = NULL;
! 1506: #if NBPFILTER > 0
! 1507: if (ic->ic_rawbpf != NULL)
! 1508: bpf_mtap(ic->ic_rawbpf, m0, BPF_DIRECTION_OUT);
! 1509: #endif
! 1510: if (uath_tx_data(sc, m0, ni) != 0)
! 1511: break;
! 1512: } else {
! 1513: if (ic->ic_state != IEEE80211_S_RUN)
! 1514: break;
! 1515: IFQ_POLL(&ifp->if_snd, m0);
! 1516: if (m0 == NULL)
! 1517: break;
! 1518: if (sc->tx_queued >= UATH_TX_DATA_LIST_COUNT) {
! 1519: ifp->if_flags |= IFF_OACTIVE;
! 1520: break;
! 1521: }
! 1522: IFQ_DEQUEUE(&ifp->if_snd, m0);
! 1523: #if NBPFILTER > 0
! 1524: if (ifp->if_bpf != NULL)
! 1525: bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT);
! 1526: #endif
! 1527: m0 = ieee80211_encap(ifp, m0, &ni);
! 1528: if (m0 == NULL)
! 1529: continue;
! 1530: #if NBPFILTER > 0
! 1531: if (ic->ic_rawbpf != NULL)
! 1532: bpf_mtap(ic->ic_rawbpf, m0, BPF_DIRECTION_OUT);
! 1533: #endif
! 1534: if (uath_tx_data(sc, m0, ni) != 0) {
! 1535: if (ni != NULL)
! 1536: ieee80211_release_node(ic, ni);
! 1537: ifp->if_oerrors++;
! 1538: break;
! 1539: }
! 1540: }
! 1541:
! 1542: sc->sc_tx_timer = 5;
! 1543: ifp->if_timer = 1;
! 1544: }
! 1545: }
! 1546:
! 1547: void
! 1548: uath_watchdog(struct ifnet *ifp)
! 1549: {
! 1550: struct uath_softc *sc = ifp->if_softc;
! 1551:
! 1552: ifp->if_timer = 0;
! 1553:
! 1554: if (sc->sc_tx_timer > 0) {
! 1555: if (--sc->sc_tx_timer == 0) {
! 1556: printf("%s: device timeout\n", sc->sc_dev.dv_xname);
! 1557: /*uath_init(ifp); XXX needs a process context! */
! 1558: ifp->if_oerrors++;
! 1559: return;
! 1560: }
! 1561: ifp->if_timer = 1;
! 1562: }
! 1563:
! 1564: ieee80211_watchdog(ifp);
! 1565: }
! 1566:
! 1567: int
! 1568: uath_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
! 1569: {
! 1570: struct uath_softc *sc = ifp->if_softc;
! 1571: struct ieee80211com *ic = &sc->sc_ic;
! 1572: struct ifaddr *ifa;
! 1573: struct ifreq *ifr;
! 1574: int s, error = 0;
! 1575:
! 1576: s = splnet();
! 1577:
! 1578: switch (cmd) {
! 1579: case SIOCSIFADDR:
! 1580: ifa = (struct ifaddr *)data;
! 1581: ifp->if_flags |= IFF_UP;
! 1582: #ifdef INET
! 1583: if (ifa->ifa_addr->sa_family == AF_INET)
! 1584: arp_ifinit(&ic->ic_ac, ifa);
! 1585: #endif
! 1586: /* FALLTHROUGH */
! 1587: case SIOCSIFFLAGS:
! 1588: if (ifp->if_flags & IFF_UP) {
! 1589: if (!(ifp->if_flags & IFF_RUNNING))
! 1590: uath_init(ifp);
! 1591: } else {
! 1592: if (ifp->if_flags & IFF_RUNNING)
! 1593: uath_stop(ifp, 1);
! 1594: }
! 1595: break;
! 1596:
! 1597: case SIOCADDMULTI:
! 1598: case SIOCDELMULTI:
! 1599: ifr = (struct ifreq *)data;
! 1600: error = (cmd == SIOCADDMULTI) ?
! 1601: ether_addmulti(ifr, &ic->ic_ac) :
! 1602: ether_delmulti(ifr, &ic->ic_ac);
! 1603: if (error == ENETRESET)
! 1604: error = 0;
! 1605: break;
! 1606:
! 1607: default:
! 1608: error = ieee80211_ioctl(ifp, cmd, data);
! 1609: }
! 1610:
! 1611: if (error == ENETRESET) {
! 1612: if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
! 1613: (IFF_UP | IFF_RUNNING))
! 1614: uath_init(ifp);
! 1615: error = 0;
! 1616: }
! 1617:
! 1618: splx(s);
! 1619:
! 1620: return error;
! 1621: }
! 1622:
! 1623: int
! 1624: uath_query_eeprom(struct uath_softc *sc)
! 1625: {
! 1626: uint32_t tmp;
! 1627: int error;
! 1628:
! 1629: /* retrieve MAC address */
! 1630: error = uath_read_eeprom(sc, UATH_EEPROM_MACADDR, sc->sc_ic.ic_myaddr);
! 1631: if (error != 0) {
! 1632: printf("%s: could not read MAC address\n",
! 1633: sc->sc_dev.dv_xname);
! 1634: return error;
! 1635: }
! 1636:
! 1637: /* retrieve the maximum frame size that the hardware can receive */
! 1638: error = uath_read_eeprom(sc, UATH_EEPROM_RXBUFSZ, &tmp);
! 1639: if (error != 0) {
! 1640: printf("%s: could not read maximum Rx buffer size\n",
! 1641: sc->sc_dev.dv_xname);
! 1642: return error;
! 1643: }
! 1644: sc->rxbufsz = betoh32(tmp) & 0xfff;
! 1645: DPRINTF(("maximum Rx buffer size %d\n", sc->rxbufsz));
! 1646: return 0;
! 1647: }
! 1648:
! 1649: int
! 1650: uath_reset(struct uath_softc *sc)
! 1651: {
! 1652: struct uath_cmd_setup setup;
! 1653: uint32_t reg, val;
! 1654: int s, error;
! 1655:
! 1656: /* init device with some voodoo incantations.. */
! 1657: setup.magic1 = htobe32(1);
! 1658: setup.magic2 = htobe32(5);
! 1659: setup.magic3 = htobe32(200);
! 1660: setup.magic4 = htobe32(27);
! 1661: s = splusb();
! 1662: error = uath_cmd_write(sc, UATH_CMD_SETUP, &setup, sizeof setup,
! 1663: UATH_CMD_FLAG_ASYNC);
! 1664: /* ..and wait until firmware notifies us that it is ready */
! 1665: if (error == 0)
! 1666: error = tsleep(UATH_COND_INIT(sc), PCATCH, "uathinit", 5 * hz);
! 1667: splx(s);
! 1668: if (error != 0)
! 1669: return error;
! 1670:
! 1671: /* read PHY registers */
! 1672: for (reg = 0x09; reg <= 0x24; reg++) {
! 1673: if (reg == 0x0b || reg == 0x0c)
! 1674: continue;
! 1675: DELAY(100);
! 1676: if ((error = uath_read_reg(sc, reg, &val)) != 0)
! 1677: return error;
! 1678: DPRINTFN(2, ("reg 0x%02x=0x%08x\n", reg, val));
! 1679: }
! 1680: return error;
! 1681: }
! 1682:
! 1683: int
! 1684: uath_reset_tx_queues(struct uath_softc *sc)
! 1685: {
! 1686: int ac, error;
! 1687:
! 1688: for (ac = 0; ac < 4; ac++) {
! 1689: const uint32_t qid = htobe32(UATH_AC_TO_QID(ac));
! 1690:
! 1691: DPRINTF(("resetting Tx queue %d\n", UATH_AC_TO_QID(ac)));
! 1692: error = uath_cmd_write(sc, UATH_CMD_RESET_QUEUE, &qid,
! 1693: sizeof qid, 0);
! 1694: if (error != 0)
! 1695: break;
! 1696: }
! 1697: return error;
! 1698: }
! 1699:
! 1700: int
! 1701: uath_wme_init(struct uath_softc *sc)
! 1702: {
! 1703: struct uath_qinfo qinfo;
! 1704: int ac, error;
! 1705: static const struct uath_wme_settings uath_wme_11g[4] = {
! 1706: { 7, 4, 10, 0, 0 }, /* Background */
! 1707: { 3, 4, 10, 0, 0 }, /* Best-Effort */
! 1708: { 3, 3, 4, 26, 0 }, /* Video */
! 1709: { 2, 2, 3, 47, 0 } /* Voice */
! 1710: };
! 1711:
! 1712: bzero(&qinfo, sizeof qinfo);
! 1713: qinfo.size = htobe32(32);
! 1714: qinfo.magic1 = htobe32(1); /* XXX ack policy? */
! 1715: qinfo.magic2 = htobe32(1);
! 1716: for (ac = 0; ac < 4; ac++) {
! 1717: qinfo.qid = htobe32(UATH_AC_TO_QID(ac));
! 1718: qinfo.ac = htobe32(ac);
! 1719: qinfo.aifsn = htobe32(uath_wme_11g[ac].aifsn);
! 1720: qinfo.logcwmin = htobe32(uath_wme_11g[ac].logcwmin);
! 1721: qinfo.logcwmax = htobe32(uath_wme_11g[ac].logcwmax);
! 1722: qinfo.txop = htobe32(UATH_TXOP_TO_US(
! 1723: uath_wme_11g[ac].txop));
! 1724: qinfo.acm = htobe32(uath_wme_11g[ac].acm);
! 1725:
! 1726: DPRINTF(("setting up Tx queue %d\n", UATH_AC_TO_QID(ac)));
! 1727: error = uath_cmd_write(sc, UATH_CMD_SET_QUEUE, &qinfo,
! 1728: sizeof qinfo, 0);
! 1729: if (error != 0)
! 1730: break;
! 1731: }
! 1732: return error;
! 1733: }
! 1734:
! 1735: int
! 1736: uath_set_chan(struct uath_softc *sc, struct ieee80211_channel *c)
! 1737: {
! 1738: struct uath_set_chan chan;
! 1739:
! 1740: bzero(&chan, sizeof chan);
! 1741: chan.flags = htobe32(0x1400);
! 1742: chan.freq = htobe32(c->ic_freq);
! 1743: chan.magic1 = htobe32(20);
! 1744: chan.magic2 = htobe32(50);
! 1745: chan.magic3 = htobe32(1);
! 1746:
! 1747: DPRINTF(("switching to channel %d\n",
! 1748: ieee80211_chan2ieee(&sc->sc_ic, c)));
! 1749: return uath_cmd_write(sc, UATH_CMD_SET_CHAN, &chan, sizeof chan, 0);
! 1750: }
! 1751:
! 1752: int
! 1753: uath_set_key(struct uath_softc *sc, const struct ieee80211_key *k, int index)
! 1754: {
! 1755: struct uath_cmd_crypto crypto;
! 1756: int i;
! 1757:
! 1758: bzero(&crypto, sizeof crypto);
! 1759: crypto.keyidx = htobe32(index);
! 1760: crypto.magic1 = htobe32(1);
! 1761: crypto.size = htobe32(368);
! 1762: crypto.mask = htobe32(0xffff);
! 1763: crypto.flags = htobe32(0x80000068);
! 1764: if (index != UATH_DEFAULT_KEY)
! 1765: crypto.flags |= htobe32(index << 16);
! 1766: memset(crypto.magic2, 0xff, sizeof crypto.magic2);
! 1767:
! 1768: /*
! 1769: * Each byte of the key must be XOR'ed with 10101010 before being
! 1770: * transmitted to the firmware.
! 1771: */
! 1772: for (i = 0; i < k->k_len; i++)
! 1773: crypto.key[i] = k->k_key[i] ^ 0xaa;
! 1774:
! 1775: DPRINTF(("setting crypto key index=%d len=%d\n", index, k->k_len));
! 1776: return uath_cmd_write(sc, UATH_CMD_CRYPTO, &crypto, sizeof crypto, 0);
! 1777: }
! 1778:
! 1779: int
! 1780: uath_set_keys(struct uath_softc *sc)
! 1781: {
! 1782: const struct ieee80211com *ic = &sc->sc_ic;
! 1783: int i, error;
! 1784:
! 1785: for (i = 0; i < IEEE80211_WEP_NKID; i++) {
! 1786: const struct ieee80211_key *k = &ic->ic_nw_keys[i];
! 1787:
! 1788: if (k->k_len > 0 && (error = uath_set_key(sc, k, i)) != 0)
! 1789: return error;
! 1790: }
! 1791: return uath_set_key(sc, &ic->ic_nw_keys[ic->ic_wep_txkey],
! 1792: UATH_DEFAULT_KEY);
! 1793: }
! 1794:
! 1795: int
! 1796: uath_set_rates(struct uath_softc *sc, const struct ieee80211_rateset *rs)
! 1797: {
! 1798: struct uath_cmd_rates rates;
! 1799:
! 1800: bzero(&rates, sizeof rates);
! 1801: rates.magic1 = htobe32(0x02);
! 1802: rates.size = htobe32(1 + sizeof rates.rates);
! 1803: rates.nrates = rs->rs_nrates;
! 1804: bcopy(rs->rs_rates, rates.rates, rs->rs_nrates);
! 1805:
! 1806: DPRINTF(("setting supported rates nrates=%d\n", rs->rs_nrates));
! 1807: return uath_cmd_write(sc, UATH_CMD_SET_RATES, &rates, sizeof rates, 0);
! 1808: }
! 1809:
! 1810: int
! 1811: uath_set_rxfilter(struct uath_softc *sc, uint32_t filter, uint32_t flags)
! 1812: {
! 1813: struct uath_cmd_filter rxfilter;
! 1814:
! 1815: rxfilter.filter = htobe32(filter);
! 1816: rxfilter.flags = htobe32(flags);
! 1817:
! 1818: DPRINTF(("setting Rx filter=0x%x flags=0x%x\n", filter, flags));
! 1819: return uath_cmd_write(sc, UATH_CMD_SET_FILTER, &rxfilter,
! 1820: sizeof rxfilter, 0);
! 1821: }
! 1822:
! 1823: int
! 1824: uath_set_led(struct uath_softc *sc, int which, int on)
! 1825: {
! 1826: struct uath_cmd_led led;
! 1827:
! 1828: led.which = htobe32(which);
! 1829: led.state = htobe32(on ? UATH_LED_ON : UATH_LED_OFF);
! 1830:
! 1831: DPRINTFN(2, ("switching %s led %s\n",
! 1832: (which == UATH_LED_LINK) ? "link" : "activity",
! 1833: on ? "on" : "off"));
! 1834: return uath_cmd_write(sc, UATH_CMD_SET_LED, &led, sizeof led, 0);
! 1835: }
! 1836:
! 1837: int
! 1838: uath_switch_channel(struct uath_softc *sc, struct ieee80211_channel *c)
! 1839: {
! 1840: uint32_t val;
! 1841: int error;
! 1842:
! 1843: /* set radio frequency */
! 1844: if ((error = uath_set_chan(sc, c)) != 0) {
! 1845: printf("%s: could not set channel\n", sc->sc_dev.dv_xname);
! 1846: return error;
! 1847: }
! 1848:
! 1849: /* reset Tx rings */
! 1850: if ((error = uath_reset_tx_queues(sc)) != 0) {
! 1851: printf("%s: could not reset Tx queues\n",
! 1852: sc->sc_dev.dv_xname);
! 1853: return error;
! 1854: }
! 1855:
! 1856: /* set Tx rings WME properties */
! 1857: if ((error = uath_wme_init(sc)) != 0) {
! 1858: printf("%s: could not init Tx queues\n",
! 1859: sc->sc_dev.dv_xname);
! 1860: return error;
! 1861: }
! 1862:
! 1863: val = htobe32(0);
! 1864: error = uath_cmd_write(sc, UATH_CMD_SET_STATE, &val, sizeof val, 0);
! 1865: if (error != 0) {
! 1866: printf("%s: could not set state\n", sc->sc_dev.dv_xname);
! 1867: return error;
! 1868: }
! 1869:
! 1870: return uath_tx_null(sc);
! 1871: }
! 1872:
! 1873: int
! 1874: uath_init(struct ifnet *ifp)
! 1875: {
! 1876: struct uath_softc *sc = ifp->if_softc;
! 1877: struct ieee80211com *ic = &sc->sc_ic;
! 1878: struct uath_cmd_31 cmd31;
! 1879: uint32_t val;
! 1880: int i, error;
! 1881:
! 1882: /* reset data and command rings */
! 1883: sc->tx_queued = sc->data_idx = sc->cmd_idx = 0;
! 1884:
! 1885: val = htobe32(0);
! 1886: (void)uath_cmd_write(sc, UATH_CMD_02, &val, sizeof val, 0);
! 1887:
! 1888: /* set MAC address */
! 1889: IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(ifp->if_sadl));
! 1890: (void)uath_write_multi(sc, 0x13, ic->ic_myaddr, IEEE80211_ADDR_LEN);
! 1891:
! 1892: (void)uath_write_reg(sc, 0x02, 0x00000001);
! 1893: (void)uath_write_reg(sc, 0x0e, 0x0000003f);
! 1894: (void)uath_write_reg(sc, 0x10, 0x00000001);
! 1895: (void)uath_write_reg(sc, 0x06, 0x0000001e);
! 1896:
! 1897: /*
! 1898: * Queue Rx data xfers.
! 1899: */
! 1900: for (i = 0; i < UATH_RX_DATA_LIST_COUNT; i++) {
! 1901: struct uath_rx_data *data = SLIST_FIRST(&sc->rx_freelist);
! 1902:
! 1903: usbd_setup_xfer(data->xfer, sc->data_rx_pipe, data, data->buf,
! 1904: sc->rxbufsz, USBD_SHORT_XFER_OK | USBD_NO_COPY,
! 1905: USBD_NO_TIMEOUT, uath_data_rxeof);
! 1906: error = usbd_transfer(data->xfer);
! 1907: if (error != USBD_IN_PROGRESS && error != 0) {
! 1908: printf("%s: could not queue Rx transfer\n",
! 1909: sc->sc_dev.dv_xname);
! 1910: goto fail;
! 1911: }
! 1912: SLIST_REMOVE_HEAD(&sc->rx_freelist, next);
! 1913: }
! 1914:
! 1915: error = uath_cmd_read(sc, UATH_CMD_07, 0, NULL, &val,
! 1916: UATH_CMD_FLAG_MAGIC);
! 1917: if (error != 0) {
! 1918: printf("%s: could not send read command 07h\n",
! 1919: sc->sc_dev.dv_xname);
! 1920: goto fail;
! 1921: }
! 1922: DPRINTF(("command 07h return code: %x\n", betoh32(val)));
! 1923:
! 1924: /* set default channel */
! 1925: ic->ic_bss->ni_chan = ic->ic_ibss_chan;
! 1926: if ((error = uath_set_chan(sc, ic->ic_bss->ni_chan)) != 0) {
! 1927: printf("%s: could not set channel\n", sc->sc_dev.dv_xname);
! 1928: goto fail;
! 1929: }
! 1930:
! 1931: if ((error = uath_wme_init(sc)) != 0) {
! 1932: printf("%s: could not setup WME parameters\n",
! 1933: sc->sc_dev.dv_xname);
! 1934: goto fail;
! 1935: }
! 1936:
! 1937: /* init MAC registers */
! 1938: (void)uath_write_reg(sc, 0x19, 0x00000000);
! 1939: (void)uath_write_reg(sc, 0x1a, 0x0000003c);
! 1940: (void)uath_write_reg(sc, 0x1b, 0x0000003c);
! 1941: (void)uath_write_reg(sc, 0x1c, 0x00000000);
! 1942: (void)uath_write_reg(sc, 0x1e, 0x00000000);
! 1943: (void)uath_write_reg(sc, 0x1f, 0x00000003);
! 1944: (void)uath_write_reg(sc, 0x0c, 0x00000000);
! 1945: (void)uath_write_reg(sc, 0x0f, 0x00000002);
! 1946: (void)uath_write_reg(sc, 0x0a, 0x00000007); /* XXX retry? */
! 1947: (void)uath_write_reg(sc, 0x09, ic->ic_rtsthreshold);
! 1948:
! 1949: val = htobe32(4);
! 1950: (void)uath_cmd_write(sc, UATH_CMD_27, &val, sizeof val, 0);
! 1951: (void)uath_cmd_write(sc, UATH_CMD_27, &val, sizeof val, 0);
! 1952: (void)uath_cmd_write(sc, UATH_CMD_1B, NULL, 0, 0);
! 1953:
! 1954: if ((error = uath_set_keys(sc)) != 0) {
! 1955: printf("%s: could not set crypto keys\n",
! 1956: sc->sc_dev.dv_xname);
! 1957: goto fail;
! 1958: }
! 1959:
! 1960: /* enable Rx */
! 1961: (void)uath_set_rxfilter(sc, 0x0000, 4);
! 1962: (void)uath_set_rxfilter(sc, 0x0817, 1);
! 1963:
! 1964: cmd31.magic1 = htobe32(0xffffffff);
! 1965: cmd31.magic2 = htobe32(0xffffffff);
! 1966: (void)uath_cmd_write(sc, UATH_CMD_31, &cmd31, sizeof cmd31, 0);
! 1967:
! 1968: ifp->if_flags &= ~IFF_OACTIVE;
! 1969: ifp->if_flags |= IFF_RUNNING;
! 1970:
! 1971: if (ic->ic_opmode == IEEE80211_M_MONITOR)
! 1972: ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
! 1973: else
! 1974: ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
! 1975:
! 1976: return 0;
! 1977:
! 1978: fail: uath_stop(ifp, 1);
! 1979: return error;
! 1980: }
! 1981:
! 1982: void
! 1983: uath_stop(struct ifnet *ifp, int disable)
! 1984: {
! 1985: struct uath_softc *sc = ifp->if_softc;
! 1986: struct ieee80211com *ic = &sc->sc_ic;
! 1987: uint32_t val;
! 1988: int s;
! 1989:
! 1990: s = splusb();
! 1991:
! 1992: sc->sc_tx_timer = 0;
! 1993: ifp->if_timer = 0;
! 1994: ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
! 1995:
! 1996: ieee80211_new_state(ic, IEEE80211_S_INIT, -1); /* free all nodes */
! 1997:
! 1998: val = htobe32(0);
! 1999: (void)uath_cmd_write(sc, UATH_CMD_SET_STATE, &val, sizeof val, 0);
! 2000: (void)uath_cmd_write(sc, UATH_CMD_RESET, NULL, 0, 0);
! 2001:
! 2002: val = htobe32(0);
! 2003: (void)uath_cmd_write(sc, UATH_CMD_15, &val, sizeof val, 0);
! 2004:
! 2005: #if 0
! 2006: (void)uath_cmd_read(sc, UATH_CMD_SHUTDOWN, NULL, 0, NULL,
! 2007: UATH_CMD_FLAG_MAGIC);
! 2008: #endif
! 2009:
! 2010: /* abort any pending transfers */
! 2011: usbd_abort_pipe(sc->data_tx_pipe);
! 2012: usbd_abort_pipe(sc->data_rx_pipe);
! 2013: usbd_abort_pipe(sc->cmd_tx_pipe);
! 2014:
! 2015: splx(s);
! 2016: }
! 2017:
! 2018: /*
! 2019: * Load the MIPS R4000 microcode into the device. Once the image is loaded,
! 2020: * the device will detach itself from the bus and reattach later with a new
! 2021: * product Id (a la ezusb). XXX this could also be implemented in userland
! 2022: * through /dev/ugen.
! 2023: */
! 2024: int
! 2025: uath_loadfirmware(struct uath_softc *sc, const u_char *fw, int len)
! 2026: {
! 2027: usbd_xfer_handle ctlxfer, txxfer, rxxfer;
! 2028: struct uath_fwblock *txblock, *rxblock;
! 2029: uint8_t *txdata;
! 2030: int error = 0;
! 2031:
! 2032: if ((ctlxfer = usbd_alloc_xfer(sc->sc_udev)) == NULL) {
! 2033: printf("%s: could not allocate Tx control xfer\n",
! 2034: sc->sc_dev.dv_xname);
! 2035: error = USBD_NOMEM;
! 2036: goto fail1;
! 2037: }
! 2038: txblock = usbd_alloc_buffer(ctlxfer, sizeof (struct uath_fwblock));
! 2039: if (txblock == NULL) {
! 2040: printf("%s: could not allocate Tx control block\n",
! 2041: sc->sc_dev.dv_xname);
! 2042: error = USBD_NOMEM;
! 2043: goto fail2;
! 2044: }
! 2045:
! 2046: if ((txxfer = usbd_alloc_xfer(sc->sc_udev)) == NULL) {
! 2047: printf("%s: could not allocate Tx xfer\n",
! 2048: sc->sc_dev.dv_xname);
! 2049: error = USBD_NOMEM;
! 2050: goto fail2;
! 2051: }
! 2052: txdata = usbd_alloc_buffer(txxfer, UATH_MAX_FWBLOCK_SIZE);
! 2053: if (txdata == NULL) {
! 2054: printf("%s: could not allocate Tx buffer\n",
! 2055: sc->sc_dev.dv_xname);
! 2056: error = USBD_NOMEM;
! 2057: goto fail3;
! 2058: }
! 2059:
! 2060: if ((rxxfer = usbd_alloc_xfer(sc->sc_udev)) == NULL) {
! 2061: printf("%s: could not allocate Rx control xfer\n",
! 2062: sc->sc_dev.dv_xname);
! 2063: error = USBD_NOMEM;
! 2064: goto fail3;
! 2065: }
! 2066: rxblock = usbd_alloc_buffer(rxxfer, sizeof (struct uath_fwblock));
! 2067: if (rxblock == NULL) {
! 2068: printf("%s: could not allocate Rx control block\n",
! 2069: sc->sc_dev.dv_xname);
! 2070: error = USBD_NOMEM;
! 2071: goto fail4;
! 2072: }
! 2073:
! 2074: bzero(txblock, sizeof (struct uath_fwblock));
! 2075: txblock->flags = htobe32(UATH_WRITE_BLOCK);
! 2076: txblock->total = htobe32(len);
! 2077:
! 2078: while (len > 0) {
! 2079: int mlen = min(len, UATH_MAX_FWBLOCK_SIZE);
! 2080:
! 2081: txblock->remain = htobe32(len - mlen);
! 2082: txblock->len = htobe32(mlen);
! 2083:
! 2084: DPRINTF(("sending firmware block: %d bytes remaining\n",
! 2085: len - mlen));
! 2086:
! 2087: /* send firmware block meta-data */
! 2088: usbd_setup_xfer(ctlxfer, sc->cmd_tx_pipe, sc, txblock,
! 2089: sizeof (struct uath_fwblock), USBD_NO_COPY,
! 2090: UATH_CMD_TIMEOUT, NULL);
! 2091: if ((error = usbd_sync_transfer(ctlxfer)) != 0) {
! 2092: printf("%s: could not send firmware block info\n",
! 2093: sc->sc_dev.dv_xname);
! 2094: break;
! 2095: }
! 2096:
! 2097: /* send firmware block data */
! 2098: bcopy(fw, txdata, mlen);
! 2099: usbd_setup_xfer(txxfer, sc->data_tx_pipe, sc, txdata, mlen,
! 2100: USBD_NO_COPY, UATH_DATA_TIMEOUT, NULL);
! 2101: if ((error = usbd_sync_transfer(txxfer)) != 0) {
! 2102: printf("%s: could not send firmware block data\n",
! 2103: sc->sc_dev.dv_xname);
! 2104: break;
! 2105: }
! 2106:
! 2107: /* wait for ack from firmware */
! 2108: usbd_setup_xfer(rxxfer, sc->cmd_rx_pipe, sc, rxblock,
! 2109: sizeof (struct uath_fwblock), USBD_SHORT_XFER_OK |
! 2110: USBD_NO_COPY, UATH_CMD_TIMEOUT, NULL);
! 2111: if ((error = usbd_sync_transfer(rxxfer)) != 0) {
! 2112: printf("%s: could not read firmware answer\n",
! 2113: sc->sc_dev.dv_xname);
! 2114: break;
! 2115: }
! 2116:
! 2117: DPRINTFN(2, ("rxblock flags=0x%x total=%d\n",
! 2118: betoh32(rxblock->flags), betoh32(rxblock->rxtotal)));
! 2119: fw += mlen;
! 2120: len -= mlen;
! 2121: }
! 2122:
! 2123: fail4: usbd_free_xfer(rxxfer);
! 2124: fail3: usbd_free_xfer(txxfer);
! 2125: fail2: usbd_free_xfer(ctlxfer);
! 2126: fail1: return error;
! 2127: }
! 2128:
! 2129: int
! 2130: uath_activate(struct device *self, enum devact act)
! 2131: {
! 2132: switch (act) {
! 2133: case DVACT_ACTIVATE:
! 2134: break;
! 2135:
! 2136: case DVACT_DEACTIVATE:
! 2137: break;
! 2138: }
! 2139: return 0;
! 2140: }
CVSweb