Annotation of sys/dev/ic/acx.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: acx.c,v 1.76 2007/08/05 22:40:38 claudio Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2006 Jonathan Gray <jsg@openbsd.org>
! 5: *
! 6: * Permission to use, copy, modify, and distribute this software for any
! 7: * purpose with or without fee is hereby granted, provided that the above
! 8: * copyright notice and this permission notice appear in all copies.
! 9: *
! 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 17: */
! 18:
! 19: /*
! 20: * Copyright (c) 2006 The DragonFly Project. All rights reserved.
! 21: *
! 22: * This code is derived from software contributed to The DragonFly Project
! 23: * by Sepherosa Ziehau <sepherosa@gmail.com>
! 24: *
! 25: * Redistribution and use in source and binary forms, with or without
! 26: * modification, are permitted provided that the following conditions
! 27: * are met:
! 28: *
! 29: * 1. Redistributions of source code must retain the above copyright
! 30: * notice, this list of conditions and the following disclaimer.
! 31: * 2. Redistributions in binary form must reproduce the above copyright
! 32: * notice, this list of conditions and the following disclaimer in
! 33: * the documentation and/or other materials provided with the
! 34: * distribution.
! 35: * 3. Neither the name of The DragonFly Project nor the names of its
! 36: * contributors may be used to endorse or promote products derived
! 37: * from this software without specific, prior written permission.
! 38: *
! 39: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
! 40: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
! 41: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
! 42: * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
! 43: * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
! 44: * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
! 45: * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
! 46: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
! 47: * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
! 48: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
! 49: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 50: * SUCH DAMAGE.
! 51: */
! 52:
! 53: /*
! 54: * Copyright (c) 2003-2004 wlan.kewl.org Project
! 55: * All rights reserved.
! 56: *
! 57: * Redistribution and use in source and binary forms, with or without
! 58: * modification, are permitted provided that the following conditions
! 59: * are met:
! 60: *
! 61: * 1. Redistributions of source code must retain the above copyright
! 62: * notice, this list of conditions and the following disclaimer.
! 63: *
! 64: * 2. Redistributions in binary form must reproduce the above copyright
! 65: * notice, this list of conditions and the following disclaimer in the
! 66: * documentation and/or other materials provided with the distribution.
! 67: *
! 68: * 3. All advertising materials mentioning features or use of this software
! 69: * must display the following acknowledgement:
! 70: *
! 71: * This product includes software developed by the wlan.kewl.org Project.
! 72: *
! 73: * 4. Neither the name of the wlan.kewl.org Project nor the names of its
! 74: * contributors may be used to endorse or promote products derived from
! 75: * this software without specific prior written permission.
! 76: *
! 77: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
! 78: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
! 79: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
! 80: * THE wlan.kewl.org Project BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
! 81: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
! 82: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
! 83: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
! 84: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
! 85: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
! 86: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 87: */
! 88:
! 89: #include <sys/cdefs.h>
! 90: #include "bpfilter.h"
! 91:
! 92: #include <sys/param.h>
! 93: #include <sys/systm.h>
! 94: #include <sys/kernel.h>
! 95: #include <sys/malloc.h>
! 96: #include <sys/mbuf.h>
! 97: #include <sys/proc.h>
! 98: #include <sys/socket.h>
! 99: #include <sys/sockio.h>
! 100: #include <sys/ioctl.h>
! 101: #include <sys/types.h>
! 102:
! 103: #include <machine/bus.h>
! 104: #include <machine/endian.h>
! 105: #include <machine/intr.h>
! 106:
! 107: #include <net/if.h>
! 108: #include <net/if_arp.h>
! 109: #include <net/if_dl.h>
! 110: #include <net/if_media.h>
! 111: #include <net/if_types.h>
! 112:
! 113: #if NBPFILTER > 0
! 114: #include <net/bpf.h>
! 115: #endif
! 116:
! 117: #ifdef INET
! 118: #include <netinet/in.h>
! 119: #include <netinet/in_systm.h>
! 120: #include <netinet/in_var.h>
! 121: #include <netinet/if_ether.h>
! 122: #include <netinet/ip.h>
! 123: #endif
! 124:
! 125: #include <net80211/ieee80211_var.h>
! 126: #include <net80211/ieee80211_amrr.h>
! 127: #include <net80211/ieee80211_radiotap.h>
! 128:
! 129: #include <dev/pci/pcireg.h>
! 130: #include <dev/pci/pcivar.h>
! 131: #include <dev/pci/pcidevs.h>
! 132:
! 133: #include <dev/ic/acxvar.h>
! 134: #include <dev/ic/acxreg.h>
! 135:
! 136: #ifdef ACX_DEBUG
! 137: int acxdebug = 0;
! 138: #endif
! 139:
! 140: int acx_attach(struct acx_softc *);
! 141: int acx_detach(void *);
! 142:
! 143: int acx_init(struct ifnet *);
! 144: int acx_stop(struct acx_softc *);
! 145: void acx_init_info_reg(struct acx_softc *);
! 146: int acx_config(struct acx_softc *);
! 147: int acx_read_config(struct acx_softc *, struct acx_config *);
! 148: int acx_write_config(struct acx_softc *, struct acx_config *);
! 149: int acx_rx_config(struct acx_softc *);
! 150: int acx_set_crypt_keys(struct acx_softc *);
! 151: void acx_next_scan(void *);
! 152:
! 153: void acx_start(struct ifnet *);
! 154: void acx_watchdog(struct ifnet *);
! 155:
! 156: int acx_ioctl(struct ifnet *, u_long, caddr_t);
! 157:
! 158: int acx_intr(void *);
! 159: void acx_disable_intr(struct acx_softc *);
! 160: void acx_enable_intr(struct acx_softc *);
! 161: void acx_txeof(struct acx_softc *);
! 162: void acx_txerr(struct acx_softc *, uint8_t);
! 163: void acx_rxeof(struct acx_softc *);
! 164:
! 165: int acx_dma_alloc(struct acx_softc *);
! 166: void acx_dma_free(struct acx_softc *);
! 167: int acx_init_tx_ring(struct acx_softc *);
! 168: int acx_init_rx_ring(struct acx_softc *);
! 169: int acx_newbuf(struct acx_softc *, struct acx_rxbuf *, int);
! 170: int acx_encap(struct acx_softc *, struct acx_txbuf *,
! 171: struct mbuf *, struct ieee80211_node *, int);
! 172:
! 173: int acx_reset(struct acx_softc *);
! 174:
! 175: int acx_set_null_tmplt(struct acx_softc *);
! 176: int acx_set_probe_req_tmplt(struct acx_softc *, const char *, int);
! 177: int acx_set_probe_resp_tmplt(struct acx_softc *, struct ieee80211_node *);
! 178: int acx_beacon_locate(struct mbuf *, u_int8_t);
! 179: int acx_set_beacon_tmplt(struct acx_softc *, struct ieee80211_node *);
! 180:
! 181: int acx_read_eeprom(struct acx_softc *, uint32_t, uint8_t *);
! 182: int acx_read_phyreg(struct acx_softc *, uint32_t, uint8_t *);
! 183: const char * acx_get_rf(int);
! 184: int acx_get_maxrssi(int);
! 185:
! 186: int acx_load_firmware(struct acx_softc *, uint32_t,
! 187: const uint8_t *, int);
! 188: int acx_load_radio_firmware(struct acx_softc *, const char *);
! 189: int acx_load_base_firmware(struct acx_softc *, const char *);
! 190:
! 191: struct ieee80211_node
! 192: *acx_node_alloc(struct ieee80211com *);
! 193: int acx_newstate(struct ieee80211com *, enum ieee80211_state, int);
! 194:
! 195: void acx_init_cmd_reg(struct acx_softc *);
! 196: int acx_join_bss(struct acx_softc *, uint8_t, struct ieee80211_node *);
! 197: int acx_set_channel(struct acx_softc *, uint8_t);
! 198: int acx_init_radio(struct acx_softc *, uint32_t, uint32_t);
! 199:
! 200: void acx_iter_func(void *, struct ieee80211_node *);
! 201: void acx_amrr_timeout(void *);
! 202: void acx_newassoc(struct ieee80211com *, struct ieee80211_node *, int);
! 203:
! 204: static int acx_chanscan_rate = 5; /* 5 channels per second */
! 205: int acx_beacon_intvl = 100; /* 100 TU */
! 206:
! 207: /*
! 208: * Possible values for the second parameter of acx_join_bss()
! 209: */
! 210: #define ACX_MODE_ADHOC 0
! 211: #define ACX_MODE_UNUSED 1
! 212: #define ACX_MODE_STA 2
! 213: #define ACX_MODE_AP 3
! 214:
! 215: struct cfdriver acx_cd = {
! 216: NULL, "acx", DV_IFNET
! 217: };
! 218:
! 219: int
! 220: acx_attach(struct acx_softc *sc)
! 221: {
! 222: struct ieee80211com *ic = &sc->sc_ic;
! 223: struct ifnet *ifp = &sc->sc_ic.ic_if;
! 224: int i, error;
! 225:
! 226: ifp->if_softc = sc;
! 227:
! 228: /* Initialize channel scanning timer */
! 229: timeout_set(&sc->sc_chanscan_timer, acx_next_scan, sc);
! 230:
! 231: /* Allocate busdma stuffs */
! 232: error = acx_dma_alloc(sc);
! 233: if (error)
! 234: return (error);
! 235:
! 236: /* Reset Hardware */
! 237: error = acx_reset(sc);
! 238: if (error)
! 239: return (error);
! 240:
! 241: /* Disable interrupts before firmware is loaded */
! 242: acx_disable_intr(sc);
! 243:
! 244: /* Get radio type and form factor */
! 245: #define EEINFO_RETRY_MAX 50
! 246: for (i = 0; i < EEINFO_RETRY_MAX; ++i) {
! 247: uint16_t ee_info;
! 248:
! 249: ee_info = CSR_READ_2(sc, ACXREG_EEPROM_INFO);
! 250: if (ACX_EEINFO_HAS_RADIO_TYPE(ee_info)) {
! 251: sc->sc_form_factor = ACX_EEINFO_FORM_FACTOR(ee_info);
! 252: sc->sc_radio_type = ACX_EEINFO_RADIO_TYPE(ee_info);
! 253: break;
! 254: }
! 255: DELAY(10000);
! 256: }
! 257: if (i == EEINFO_RETRY_MAX)
! 258: return (ENXIO);
! 259: #undef EEINFO_RETRY_MAX
! 260:
! 261: printf("%s: %s, radio %s (0x%02x)", sc->sc_dev.dv_xname,
! 262: (sc->sc_flags & ACX_FLAG_ACX111) ? "ACX111" : "ACX100",
! 263: acx_get_rf(sc->sc_radio_type), sc->sc_radio_type);
! 264:
! 265: #ifdef DUMP_EEPROM
! 266: for (i = 0; i < 0x40; ++i) {
! 267: uint8_t val;
! 268:
! 269: error = acx_read_eeprom(sc, i, &val);
! 270: if (i % 10 == 0)
! 271: printf("\n");
! 272: printf("%02x ", val);
! 273: }
! 274: printf("\n");
! 275: #endif /* DUMP_EEPROM */
! 276:
! 277: /* Get EEPROM version */
! 278: error = acx_read_eeprom(sc, ACX_EE_VERSION_OFS, &sc->sc_eeprom_ver);
! 279: if (error)
! 280: return (error);
! 281:
! 282: printf(", EEPROM ver %u", sc->sc_eeprom_ver);
! 283:
! 284: ifp->if_softc = sc;
! 285: ifp->if_init = acx_init;
! 286: ifp->if_ioctl = acx_ioctl;
! 287: ifp->if_start = acx_start;
! 288: ifp->if_watchdog = acx_watchdog;
! 289: ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST;
! 290: strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
! 291: IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
! 292: IFQ_SET_READY(&ifp->if_snd);
! 293:
! 294: /* Set channels */
! 295: for (i = 1; i <= 14; ++i) {
! 296: ic->ic_channels[i].ic_freq =
! 297: ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
! 298: ic->ic_channels[i].ic_flags = sc->chip_chan_flags;
! 299: }
! 300:
! 301: ic->ic_opmode = IEEE80211_M_STA;
! 302: ic->ic_state = IEEE80211_S_INIT;
! 303:
! 304: /*
! 305: * NOTE: Don't overwrite ic_caps set by chip specific code
! 306: */
! 307: ic->ic_caps =
! 308: IEEE80211_C_WEP | /* WEP */
! 309: IEEE80211_C_IBSS | /* IBSS mode */
! 310: IEEE80211_C_MONITOR | /* Monitor mode */
! 311: IEEE80211_C_HOSTAP | /* Access Point */
! 312: IEEE80211_C_SHPREAMBLE; /* Short preamble */
! 313:
! 314: /* Get station id */
! 315: for (i = 0; i < IEEE80211_ADDR_LEN; ++i) {
! 316: error = acx_read_eeprom(sc, sc->chip_ee_eaddr_ofs - i,
! 317: &ic->ic_myaddr[i]);
! 318: }
! 319:
! 320: printf(", address %s\n", ether_sprintf(ic->ic_myaddr));
! 321:
! 322: if_attach(ifp);
! 323: ieee80211_ifattach(ifp);
! 324:
! 325: /* Override node alloc */
! 326: ic->ic_node_alloc = acx_node_alloc;
! 327: ic->ic_newassoc = acx_newassoc;
! 328:
! 329: /* Override newstate */
! 330: sc->sc_newstate = ic->ic_newstate;
! 331: ic->ic_newstate = acx_newstate;
! 332:
! 333: /* Set maximal rssi */
! 334: ic->ic_max_rssi = acx_get_maxrssi(sc->sc_radio_type);
! 335:
! 336: ieee80211_media_init(ifp, ieee80211_media_change,
! 337: ieee80211_media_status);
! 338:
! 339: /* AMRR rate control */
! 340: sc->amrr.amrr_min_success_threshold = 1;
! 341: sc->amrr.amrr_max_success_threshold = 15;
! 342: timeout_set(&sc->amrr_ch, acx_amrr_timeout, sc);
! 343:
! 344: sc->sc_long_retry_limit = 4;
! 345: sc->sc_short_retry_limit = 7;
! 346: sc->sc_msdu_lifetime = 4096;
! 347:
! 348: #if NBPFILTER > 0
! 349: bpfattach(&sc->sc_drvbpf, ifp, DLT_IEEE802_11_RADIO,
! 350: sizeof(struct ieee80211_frame) + 64);
! 351:
! 352: sc->sc_rxtap_len = sizeof(sc->sc_rxtapu);
! 353: sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len);
! 354: sc->sc_rxtap.wr_ihdr.it_present = htole32(ACX_RX_RADIOTAP_PRESENT);
! 355:
! 356: sc->sc_txtap_len = sizeof(sc->sc_txtapu);
! 357: sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len);
! 358: sc->sc_txtap.wt_ihdr.it_present = htole32(ACX_TX_RADIOTAP_PRESENT);
! 359: #endif
! 360:
! 361: return (0);
! 362: }
! 363:
! 364: int
! 365: acx_detach(void *xsc)
! 366: {
! 367: struct acx_softc *sc = xsc;
! 368: struct ieee80211com *ic = &sc->sc_ic;
! 369: struct ifnet *ifp = &ic->ic_if;
! 370:
! 371: acx_stop(sc);
! 372: ieee80211_ifdetach(ifp);
! 373: if_detach(ifp);
! 374:
! 375: acx_dma_free(sc);
! 376:
! 377: return (0);
! 378: }
! 379:
! 380: int
! 381: acx_init(struct ifnet *ifp)
! 382: {
! 383: struct acx_softc *sc = ifp->if_softc;
! 384: struct ieee80211com *ic = &sc->sc_ic;
! 385: char fname[] = "tiacx111c16";
! 386: int error, combined = 0;
! 387:
! 388: error = acx_stop(sc);
! 389: if (error)
! 390: return (EIO);
! 391:
! 392: /* enable card if possible */
! 393: if (sc->sc_enable != NULL)
! 394: (*sc->sc_enable)(sc);
! 395:
! 396: error = acx_init_tx_ring(sc);
! 397: if (error) {
! 398: printf("%s: can't initialize TX ring\n",
! 399: sc->sc_dev.dv_xname);
! 400: goto back;
! 401: }
! 402:
! 403: error = acx_init_rx_ring(sc);
! 404: if (error) {
! 405: printf("%s: can't initialize RX ring\n",
! 406: sc->sc_dev.dv_xname);
! 407: goto back;
! 408: }
! 409:
! 410: if (sc->sc_flags & ACX_FLAG_ACX111) {
! 411: snprintf(fname, sizeof(fname), "tiacx111c%02X",
! 412: sc->sc_radio_type);
! 413: error = acx_load_base_firmware(sc, fname);
! 414:
! 415: if (!error)
! 416: combined = 1;
! 417: }
! 418:
! 419: if (!combined) {
! 420: snprintf(fname, sizeof(fname), "tiacx%s",
! 421: (sc->sc_flags & ACX_FLAG_ACX111) ? "111" : "100");
! 422: error = acx_load_base_firmware(sc, fname);
! 423: }
! 424:
! 425: if (error)
! 426: goto back;
! 427:
! 428: /*
! 429: * Initialize command and information registers
! 430: * NOTE: This should be done after base firmware is loaded
! 431: */
! 432: acx_init_cmd_reg(sc);
! 433: acx_init_info_reg(sc);
! 434:
! 435: sc->sc_flags |= ACX_FLAG_FW_LOADED;
! 436:
! 437: if (!combined) {
! 438: snprintf(fname, sizeof(fname), "tiacx%sr%02X",
! 439: (sc->sc_flags & ACX_FLAG_ACX111) ? "111" : "100",
! 440: sc->sc_radio_type);
! 441: error = acx_load_radio_firmware(sc, fname);
! 442:
! 443: if (error)
! 444: goto back;
! 445: }
! 446:
! 447: error = sc->chip_init(sc);
! 448: if (error)
! 449: goto back;
! 450:
! 451: /* Get and set device various configuration */
! 452: error = acx_config(sc);
! 453: if (error)
! 454: goto back;
! 455:
! 456: /* Setup crypto stuffs */
! 457: if (sc->sc_ic.ic_flags & IEEE80211_F_WEPON) {
! 458: error = acx_set_crypt_keys(sc);
! 459: if (error)
! 460: goto back;
! 461: }
! 462:
! 463: /* Turn on power led */
! 464: CSR_CLRB_2(sc, ACXREG_GPIO_OUT, sc->chip_gpio_pled);
! 465:
! 466: acx_enable_intr(sc);
! 467:
! 468: ifp->if_flags |= IFF_RUNNING;
! 469: ifp->if_flags &= ~IFF_OACTIVE;
! 470:
! 471: if (ic->ic_opmode != IEEE80211_M_MONITOR)
! 472: /* start background scanning */
! 473: ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
! 474: else
! 475: /* in monitor mode change directly into run state */
! 476: ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
! 477:
! 478: back:
! 479: if (error)
! 480: acx_stop(sc);
! 481:
! 482: return (0);
! 483: }
! 484:
! 485: void
! 486: acx_init_info_reg(struct acx_softc *sc)
! 487: {
! 488: sc->sc_info = CSR_READ_4(sc, ACXREG_INFO_REG_OFFSET);
! 489: sc->sc_info_param = sc->sc_info + ACX_INFO_REG_SIZE;
! 490: }
! 491:
! 492: int
! 493: acx_set_crypt_keys(struct acx_softc *sc)
! 494: {
! 495: struct ieee80211com *ic = &sc->sc_ic;
! 496: struct acx_conf_wep_txkey wep_txkey;
! 497: int i, error, got_wk = 0;
! 498:
! 499: for (i = 0; i < IEEE80211_WEP_NKID; ++i) {
! 500: struct ieee80211_key *k = &ic->ic_nw_keys[i];
! 501:
! 502: if (k->k_len == 0)
! 503: continue;
! 504:
! 505: if (sc->chip_hw_crypt) {
! 506: error = sc->chip_set_wepkey(sc, k, i);
! 507: if (error)
! 508: return (error);
! 509: got_wk = 1;
! 510: }
! 511: }
! 512:
! 513: if (!got_wk)
! 514: return (0);
! 515:
! 516: /* Set current WEP key index */
! 517: wep_txkey.wep_txkey = ic->ic_wep_txkey;
! 518: if (acx_set_conf(sc, ACX_CONF_WEP_TXKEY, &wep_txkey,
! 519: sizeof(wep_txkey)) != 0) {
! 520: printf("%s: set WEP txkey failed\n", sc->sc_dev.dv_xname);
! 521: return (ENXIO);
! 522: }
! 523:
! 524: return (0);
! 525: }
! 526:
! 527: void
! 528: acx_next_scan(void *arg)
! 529: {
! 530: struct acx_softc *sc = arg;
! 531: struct ieee80211com *ic = &sc->sc_ic;
! 532: struct ifnet *ifp = &ic->ic_if;
! 533:
! 534: if (ic->ic_state == IEEE80211_S_SCAN)
! 535: ieee80211_next_scan(ifp);
! 536: }
! 537:
! 538: int
! 539: acx_stop(struct acx_softc *sc)
! 540: {
! 541: struct ieee80211com *ic = &sc->sc_ic;
! 542: struct ifnet *ifp = &ic->ic_if;
! 543: struct acx_buf_data *bd = &sc->sc_buf_data;
! 544: struct acx_ring_data *rd = &sc->sc_ring_data;
! 545: int i, error;
! 546:
! 547: sc->sc_firmware_ver = 0;
! 548: sc->sc_hardware_id = 0;
! 549:
! 550: /* Reset hardware */
! 551: error = acx_reset(sc);
! 552: if (error)
! 553: return (error);
! 554:
! 555: /* Firmware no longer functions after hardware reset */
! 556: sc->sc_flags &= ~ACX_FLAG_FW_LOADED;
! 557:
! 558: acx_disable_intr(sc);
! 559:
! 560: /* Stop backgroud scanning */
! 561: timeout_del(&sc->sc_chanscan_timer);
! 562:
! 563: /* Turn off power led */
! 564: CSR_SETB_2(sc, ACXREG_GPIO_OUT, sc->chip_gpio_pled);
! 565:
! 566: /* Free TX mbuf */
! 567: for (i = 0; i < ACX_TX_DESC_CNT; ++i) {
! 568: struct acx_txbuf *buf;
! 569: struct ieee80211_node *ni;
! 570:
! 571: buf = &bd->tx_buf[i];
! 572:
! 573: if (buf->tb_mbuf != NULL) {
! 574: bus_dmamap_unload(sc->sc_dmat, buf->tb_mbuf_dmamap);
! 575: m_freem(buf->tb_mbuf);
! 576: buf->tb_mbuf = NULL;
! 577: }
! 578:
! 579: ni = (struct ieee80211_node *)buf->tb_node;
! 580: if (ni != NULL)
! 581: ieee80211_release_node(ic, ni);
! 582: buf->tb_node = NULL;
! 583: }
! 584:
! 585: /* Clear TX host descriptors */
! 586: bzero(rd->tx_ring, ACX_TX_RING_SIZE);
! 587:
! 588: /* Free RX mbuf */
! 589: for (i = 0; i < ACX_RX_DESC_CNT; ++i) {
! 590: if (bd->rx_buf[i].rb_mbuf != NULL) {
! 591: bus_dmamap_unload(sc->sc_dmat,
! 592: bd->rx_buf[i].rb_mbuf_dmamap);
! 593: m_freem(bd->rx_buf[i].rb_mbuf);
! 594: bd->rx_buf[i].rb_mbuf = NULL;
! 595: }
! 596: }
! 597:
! 598: /* Clear RX host descriptors */
! 599: bzero(rd->rx_ring, ACX_RX_RING_SIZE);
! 600:
! 601: ifp->if_timer = 0;
! 602: ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
! 603: ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
! 604:
! 605: /* disable card if possible */
! 606: if (sc->sc_disable != NULL)
! 607: (*sc->sc_disable)(sc);
! 608:
! 609: return (0);
! 610: }
! 611:
! 612: int
! 613: acx_config(struct acx_softc *sc)
! 614: {
! 615: struct acx_config conf;
! 616: int error;
! 617:
! 618: error = acx_read_config(sc, &conf);
! 619: if (error)
! 620: return (error);
! 621:
! 622: error = acx_write_config(sc, &conf);
! 623: if (error)
! 624: return (error);
! 625:
! 626: error = acx_rx_config(sc);
! 627: if (error)
! 628: return (error);
! 629:
! 630: if (acx_set_probe_req_tmplt(sc, "", 0) != 0) {
! 631: printf("%s: can't set probe req template "
! 632: "(empty ssid)\n", sc->sc_dev.dv_xname);
! 633: return (ENXIO);
! 634: }
! 635:
! 636: /* XXX for PM?? */
! 637: if (acx_set_null_tmplt(sc) != 0) {
! 638: printf("%s: can't set null data template\n",
! 639: sc->sc_dev.dv_xname);
! 640: return (ENXIO);
! 641: }
! 642:
! 643: return (0);
! 644: }
! 645:
! 646: int
! 647: acx_read_config(struct acx_softc *sc, struct acx_config *conf)
! 648: {
! 649: struct acx_conf_regdom reg_dom;
! 650: struct acx_conf_antenna ant;
! 651: struct acx_conf_fwrev fw_rev;
! 652: uint32_t fw_rev_no;
! 653: uint8_t sen;
! 654: int error;
! 655:
! 656: /* Get region domain */
! 657: if (acx_get_conf(sc, ACX_CONF_REGDOM, ®_dom, sizeof(reg_dom)) != 0) {
! 658: printf("%s: can't get region domain\n", sc->sc_dev.dv_xname);
! 659: return (ENXIO);
! 660: }
! 661: conf->regdom = reg_dom.regdom;
! 662: DPRINTF(("%s: regdom %02x\n", sc->sc_dev.dv_xname, reg_dom.regdom));
! 663:
! 664: /* Get antenna */
! 665: if (acx_get_conf(sc, ACX_CONF_ANTENNA, &ant, sizeof(ant)) != 0) {
! 666: printf("%s: can't get antenna\n", sc->sc_dev.dv_xname);
! 667: return (ENXIO);
! 668: }
! 669: conf->antenna = ant.antenna;
! 670: DPRINTF(("%s: antenna %02x\n", sc->sc_dev.dv_xname, ant.antenna));
! 671:
! 672: /* Get sensitivity XXX not used */
! 673: if (sc->sc_radio_type == ACX_RADIO_TYPE_MAXIM ||
! 674: sc->sc_radio_type == ACX_RADIO_TYPE_RFMD ||
! 675: sc->sc_radio_type == ACX_RADIO_TYPE_RALINK) {
! 676: error = acx_read_phyreg(sc, ACXRV_PHYREG_SENSITIVITY, &sen);
! 677: if (error) {
! 678: printf("%s: can't get sensitivity\n",
! 679: sc->sc_dev.dv_xname);
! 680: return (error);
! 681: }
! 682: } else
! 683: sen = 0;
! 684: DPRINTF(("%s: sensitivity %02x\n", sc->sc_dev.dv_xname, sen));
! 685:
! 686: /* Get firmware revision */
! 687: if (acx_get_conf(sc, ACX_CONF_FWREV, &fw_rev, sizeof(fw_rev)) != 0) {
! 688: printf("%s: can't get firmware revision\n",
! 689: sc->sc_dev.dv_xname);
! 690: return (ENXIO);
! 691: }
! 692:
! 693: if (strncmp(fw_rev.fw_rev, "Rev ", 4) != 0) {
! 694: printf("%s: strange revision string -- %s\n",
! 695: sc->sc_dev.dv_xname, fw_rev.fw_rev);
! 696: fw_rev_no = 0x01090407;
! 697: } else {
! 698: /*
! 699: * 01234
! 700: * "Rev xx.xx.xx.xx"
! 701: * ^ Start from here
! 702: */
! 703: fw_rev_no = fw_rev.fw_rev[0] << 24;
! 704: fw_rev_no |= fw_rev.fw_rev[1] << 16;
! 705: fw_rev_no |= fw_rev.fw_rev[2] << 8;
! 706: fw_rev_no |= fw_rev.fw_rev[3];
! 707: }
! 708: sc->sc_firmware_ver = fw_rev_no;
! 709: sc->sc_hardware_id = letoh32(fw_rev.hw_id);
! 710: DPRINTF(("%s: fw rev %08x, hw id %08x\n",
! 711: sc->sc_dev.dv_xname, sc->sc_firmware_ver, sc->sc_hardware_id));
! 712:
! 713: if (sc->chip_read_config != NULL) {
! 714: error = sc->chip_read_config(sc, conf);
! 715: if (error)
! 716: return (error);
! 717: }
! 718:
! 719: return (0);
! 720: }
! 721:
! 722: int
! 723: acx_write_config(struct acx_softc *sc, struct acx_config *conf)
! 724: {
! 725: struct acx_conf_nretry_short sretry;
! 726: struct acx_conf_nretry_long lretry;
! 727: struct acx_conf_msdu_lifetime msdu_lifetime;
! 728: struct acx_conf_rate_fallback rate_fb;
! 729: struct acx_conf_antenna ant;
! 730: struct acx_conf_regdom reg_dom;
! 731: struct ifnet *ifp = &sc->sc_ic.ic_if;
! 732: int error;
! 733:
! 734: /* Set number of long/short retry */
! 735: sretry.nretry = sc->sc_short_retry_limit;
! 736: if (acx_set_conf(sc, ACX_CONF_NRETRY_SHORT, &sretry,
! 737: sizeof(sretry)) != 0) {
! 738: printf("%s: can't set short retry limit\n", ifp->if_xname);
! 739: return (ENXIO);
! 740: }
! 741:
! 742: lretry.nretry = sc->sc_long_retry_limit;
! 743: if (acx_set_conf(sc, ACX_CONF_NRETRY_LONG, &lretry,
! 744: sizeof(lretry)) != 0) {
! 745: printf("%s: can't set long retry limit\n", ifp->if_xname);
! 746: return (ENXIO);
! 747: }
! 748:
! 749: /* Set MSDU lifetime */
! 750: msdu_lifetime.lifetime = htole32(sc->sc_msdu_lifetime);
! 751: if (acx_set_conf(sc, ACX_CONF_MSDU_LIFETIME, &msdu_lifetime,
! 752: sizeof(msdu_lifetime)) != 0) {
! 753: printf("%s: can't set MSDU lifetime\n", ifp->if_xname);
! 754: return (ENXIO);
! 755: }
! 756:
! 757: /* Enable rate fallback */
! 758: rate_fb.ratefb_enable = 1;
! 759: if (acx_set_conf(sc, ACX_CONF_RATE_FALLBACK, &rate_fb,
! 760: sizeof(rate_fb)) != 0) {
! 761: printf("%s: can't enable rate fallback\n", ifp->if_xname);
! 762: return (ENXIO);
! 763: }
! 764:
! 765: /* Set antenna */
! 766: ant.antenna = conf->antenna;
! 767: if (acx_set_conf(sc, ACX_CONF_ANTENNA, &ant, sizeof(ant)) != 0) {
! 768: printf("%s: can't set antenna\n", ifp->if_xname);
! 769: return (ENXIO);
! 770: }
! 771:
! 772: /* Set region domain */
! 773: reg_dom.regdom = conf->regdom;
! 774: if (acx_set_conf(sc, ACX_CONF_REGDOM, ®_dom, sizeof(reg_dom)) != 0) {
! 775: printf("%s: can't set region domain\n", ifp->if_xname);
! 776: return (ENXIO);
! 777: }
! 778:
! 779: if (sc->chip_write_config != NULL) {
! 780: error = sc->chip_write_config(sc, conf);
! 781: if (error)
! 782: return (error);
! 783: }
! 784:
! 785: return (0);
! 786: }
! 787:
! 788: int
! 789: acx_rx_config(struct acx_softc *sc)
! 790: {
! 791: struct ieee80211com *ic = &sc->sc_ic;
! 792: struct acx_conf_rxopt rx_opt;
! 793:
! 794: /* tell the RX receiver what frames we want to have */
! 795: rx_opt.opt1 = htole16(RXOPT1_INCL_RXBUF_HDR);
! 796: rx_opt.opt2 = htole16(
! 797: RXOPT2_RECV_ASSOC_REQ |
! 798: RXOPT2_RECV_AUTH |
! 799: RXOPT2_RECV_BEACON |
! 800: RXOPT2_RECV_CF |
! 801: RXOPT2_RECV_CTRL |
! 802: RXOPT2_RECV_DATA |
! 803: RXOPT2_RECV_MGMT |
! 804: RXOPT2_RECV_PROBE_REQ |
! 805: RXOPT2_RECV_PROBE_RESP |
! 806: RXOPT2_RECV_OTHER);
! 807:
! 808: /* in monitor mode go promiscuous */
! 809: if (ic->ic_opmode == IEEE80211_M_MONITOR) {
! 810: rx_opt.opt1 |= RXOPT1_PROMISC;
! 811: rx_opt.opt2 |= RXOPT2_RECV_BROKEN | RXOPT2_RECV_ACK;
! 812: } else
! 813: rx_opt.opt1 |= RXOPT1_FILT_FDEST;
! 814:
! 815: /* finally set the RX options */
! 816: if (acx_set_conf(sc, ACX_CONF_RXOPT, &rx_opt, sizeof(rx_opt)) != 0) {
! 817: printf("%s: can not set RX options!\n", sc->sc_dev.dv_xname);
! 818: return (ENXIO);
! 819: }
! 820:
! 821: return (0);
! 822: }
! 823:
! 824: int
! 825: acx_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
! 826: {
! 827: struct acx_softc *sc = ifp->if_softc;
! 828: struct ieee80211com *ic = &sc->sc_ic;
! 829: struct ifaddr *ifa;
! 830: struct ifreq *ifr;
! 831: int s, error = 0;
! 832: uint8_t chan;
! 833:
! 834: s = splnet();
! 835:
! 836: switch (cmd) {
! 837: case SIOCSIFADDR:
! 838: ifa = (struct ifaddr *)data;
! 839: ifp->if_flags |= IFF_UP;
! 840: #ifdef INET
! 841: if (ifa->ifa_addr->sa_family == AF_INET)
! 842: arp_ifinit(&ic->ic_ac, ifa);
! 843: #endif
! 844: /* FALLTHROUGH */
! 845: case SIOCSIFFLAGS:
! 846: if (ifp->if_flags & IFF_UP) {
! 847: if ((ifp->if_flags & IFF_RUNNING) == 0)
! 848: acx_init(ifp);
! 849: } else {
! 850: if (ifp->if_flags & IFF_RUNNING)
! 851: acx_stop(sc);
! 852: }
! 853: break;
! 854: case SIOCADDMULTI:
! 855: case SIOCDELMULTI:
! 856: ifr = (struct ifreq *)data;
! 857: error = (cmd == SIOCADDMULTI) ?
! 858: ether_addmulti(ifr, &ic->ic_ac) :
! 859: ether_delmulti(ifr, &ic->ic_ac);
! 860:
! 861: if (error == ENETRESET)
! 862: error = 0;
! 863: break;
! 864: case SIOCS80211CHANNEL:
! 865: /* allow fast channel switching in monitor mode */
! 866: error = ieee80211_ioctl(ifp, cmd, data);
! 867: if (error == ENETRESET &&
! 868: ic->ic_opmode == IEEE80211_M_MONITOR) {
! 869: if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
! 870: (IFF_UP | IFF_RUNNING)) {
! 871: ic->ic_bss->ni_chan = ic->ic_ibss_chan;
! 872: chan = ieee80211_chan2ieee(ic,
! 873: ic->ic_bss->ni_chan);
! 874: (void)acx_set_channel(sc, chan);
! 875: }
! 876: error = 0;
! 877: }
! 878: break;
! 879: default:
! 880: error = ieee80211_ioctl(ifp, cmd, data);
! 881: break;
! 882: }
! 883:
! 884: if (error == ENETRESET) {
! 885: if ((ifp->if_flags & (IFF_RUNNING | IFF_UP)) ==
! 886: (IFF_RUNNING | IFF_UP))
! 887: acx_init(ifp);
! 888: error = 0;
! 889: }
! 890:
! 891: splx(s);
! 892:
! 893: return (error);
! 894: }
! 895:
! 896: void
! 897: acx_start(struct ifnet *ifp)
! 898: {
! 899: struct acx_softc *sc = ifp->if_softc;
! 900: struct ieee80211com *ic = &sc->sc_ic;
! 901: struct acx_buf_data *bd = &sc->sc_buf_data;
! 902: struct acx_txbuf *buf;
! 903: int trans, idx;
! 904:
! 905: if ((sc->sc_flags & ACX_FLAG_FW_LOADED) == 0 ||
! 906: (ifp->if_flags & IFF_RUNNING) == 0 ||
! 907: (ifp->if_flags & IFF_OACTIVE))
! 908: return;
! 909:
! 910: /*
! 911: * NOTE:
! 912: * We can't start from a random position that TX descriptor
! 913: * is free, since hardware will be confused by that.
! 914: * We have to follow the order of the TX ring.
! 915: */
! 916: idx = bd->tx_free_start;
! 917: trans = 0;
! 918: for (buf = &bd->tx_buf[idx]; buf->tb_mbuf == NULL;
! 919: buf = &bd->tx_buf[idx]) {
! 920: struct ieee80211_frame *wh;
! 921: struct ieee80211_node *ni = NULL;
! 922: struct mbuf *m;
! 923: int rate;
! 924:
! 925: IF_DEQUEUE(&ic->ic_mgtq, m);
! 926: if (m != NULL) {
! 927: ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
! 928: m->m_pkthdr.rcvif = NULL;
! 929:
! 930: /*
! 931: * probe response mgmt frames are handled by the
! 932: * firmware already. So, don't send them twice.
! 933: */
! 934: wh = mtod(m, struct ieee80211_frame *);
! 935: if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
! 936: IEEE80211_FC0_SUBTYPE_PROBE_RESP) {
! 937: if (ni != NULL)
! 938: ieee80211_release_node(ic, ni);
! 939: m_freem(m);
! 940: continue;
! 941: }
! 942:
! 943: /*
! 944: * mgmt frames are sent at the lowest available
! 945: * bit-rate.
! 946: */
! 947: rate = ni->ni_rates.rs_rates[0];
! 948: rate &= IEEE80211_RATE_VAL;
! 949: } else if (!IFQ_IS_EMPTY(&ifp->if_snd)) {
! 950: struct ether_header *eh;
! 951:
! 952: IFQ_DEQUEUE(&ifp->if_snd, m);
! 953: if (m == NULL)
! 954: break;
! 955:
! 956: if (ic->ic_state != IEEE80211_S_RUN) {
! 957: DPRINTF(("%s: data packet dropped due to "
! 958: "not RUN. Current state %d\n",
! 959: ifp->if_xname, ic->ic_state));
! 960: m_freem(m);
! 961: break;
! 962: }
! 963:
! 964: if (m->m_len < sizeof(struct ether_header)) {
! 965: m = m_pullup(m, sizeof(struct ether_header));
! 966: if (m == NULL) {
! 967: ifp->if_oerrors++;
! 968: continue;
! 969: }
! 970: }
! 971: eh = mtod(m, struct ether_header *);
! 972:
! 973: /* TODO power save */
! 974:
! 975: #if NBPFILTER > 0
! 976: if (ifp->if_bpf != NULL)
! 977: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
! 978: #endif
! 979:
! 980: if ((m = ieee80211_encap(ifp, m, &ni)) == NULL) {
! 981: ifp->if_oerrors++;
! 982: continue;
! 983: }
! 984:
! 985: #if NBPFILTER > 0
! 986: if (ic->ic_rawbpf != NULL)
! 987: bpf_mtap(ic->ic_rawbpf, m, BPF_DIRECTION_OUT);
! 988: #endif
! 989:
! 990: if (ic->ic_fixed_rate != -1) {
! 991: rate = ic->ic_sup_rates[ic->ic_curmode].
! 992: rs_rates[ic->ic_fixed_rate];
! 993: } else
! 994: rate = ni->ni_rates.rs_rates[ni->ni_txrate];
! 995: rate &= IEEE80211_RATE_VAL;
! 996: } else
! 997: break;
! 998:
! 999: wh = mtod(m, struct ieee80211_frame *);
! 1000: if ((wh->i_fc[1] & IEEE80211_FC1_WEP) && !sc->chip_hw_crypt) {
! 1001: m = ieee80211_wep_crypt(ifp, m, 1);
! 1002: if (m == NULL) {
! 1003: ieee80211_release_node(ic, ni);
! 1004: m_freem(m);
! 1005: ifp->if_oerrors++;
! 1006: continue;
! 1007: }
! 1008: }
! 1009:
! 1010: #if NBPFILTER > 0
! 1011: if (sc->sc_drvbpf != NULL) {
! 1012: struct mbuf mb;
! 1013: struct acx_tx_radiotap_hdr *tap = &sc->sc_txtap;
! 1014:
! 1015: tap->wt_flags = 0;
! 1016: tap->wt_rate = rate;
! 1017: tap->wt_chan_freq =
! 1018: htole16(ic->ic_bss->ni_chan->ic_freq);
! 1019: tap->wt_chan_flags =
! 1020: htole16(ic->ic_bss->ni_chan->ic_flags);
! 1021:
! 1022: mb.m_data = (caddr_t)tap;
! 1023: mb.m_len = sc->sc_txtap_len;
! 1024: mb.m_next = m;
! 1025: mb.m_nextpkt = NULL;
! 1026: mb.m_type = 0;
! 1027: mb.m_flags = 0;
! 1028: bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_OUT);
! 1029: }
! 1030: #endif
! 1031:
! 1032: if (acx_encap(sc, buf, m, ni, rate) != 0) {
! 1033: /*
! 1034: * NOTE: `m' will be freed in acx_encap()
! 1035: * if we reach here.
! 1036: */
! 1037: if (ni != NULL)
! 1038: ieee80211_release_node(ic, ni);
! 1039: ifp->if_oerrors++;
! 1040: continue;
! 1041: }
! 1042:
! 1043: /*
! 1044: * NOTE:
! 1045: * 1) `m' should not be touched after acx_encap()
! 1046: * 2) `node' will be used to do TX rate control during
! 1047: * acx_txeof(), so it is not freed here. acx_txeof()
! 1048: * will free it for us
! 1049: */
! 1050: trans = 1;
! 1051: bd->tx_used_count++;
! 1052: idx = (idx + 1) % ACX_TX_DESC_CNT;
! 1053: }
! 1054: bd->tx_free_start = idx;
! 1055:
! 1056: if (bd->tx_used_count == ACX_TX_DESC_CNT)
! 1057: ifp->if_flags |= IFF_OACTIVE;
! 1058:
! 1059: if (trans && ifp->if_timer == 0)
! 1060: ifp->if_timer = 5;
! 1061: sc->sc_txtimer = 5;
! 1062: }
! 1063:
! 1064: void
! 1065: acx_watchdog(struct ifnet *ifp)
! 1066: {
! 1067: struct acx_softc *sc = ifp->if_softc;
! 1068:
! 1069: ifp->if_timer = 0;
! 1070:
! 1071: if ((ifp->if_flags & IFF_RUNNING) == 0)
! 1072: return;
! 1073:
! 1074: if (sc->sc_txtimer) {
! 1075: if (--sc->sc_txtimer == 0) {
! 1076: printf("%s: watchdog timeout\n", ifp->if_xname);
! 1077: acx_txeof(ifp->if_softc);
! 1078: ifp->if_oerrors++;
! 1079: return;
! 1080: }
! 1081: ifp->if_timer = 5;
! 1082: }
! 1083:
! 1084: ieee80211_watchdog(ifp);
! 1085: }
! 1086:
! 1087: int
! 1088: acx_intr(void *arg)
! 1089: {
! 1090: struct acx_softc *sc = arg;
! 1091: uint16_t intr_status;
! 1092:
! 1093: if ((sc->sc_flags & ACX_FLAG_FW_LOADED) == 0)
! 1094: return (0);
! 1095:
! 1096: intr_status = CSR_READ_2(sc, ACXREG_INTR_STATUS_CLR);
! 1097: if (intr_status == ACXRV_INTR_ALL) {
! 1098: /* not our interrupt */
! 1099: return (0);
! 1100: }
! 1101:
! 1102: intr_status &= sc->chip_intr_enable;
! 1103: if (intr_status == 0) {
! 1104: /* not interrupts we care about */
! 1105: return (1);
! 1106: }
! 1107:
! 1108: /* Acknowledge all interrupts */
! 1109: CSR_WRITE_2(sc, ACXREG_INTR_ACK, ACXRV_INTR_ALL);
! 1110:
! 1111: if (intr_status & ACXRV_INTR_TX_FINI)
! 1112: acx_txeof(sc);
! 1113:
! 1114: if (intr_status & ACXRV_INTR_RX_FINI)
! 1115: acx_rxeof(sc);
! 1116:
! 1117: return (1);
! 1118: }
! 1119:
! 1120: void
! 1121: acx_disable_intr(struct acx_softc *sc)
! 1122: {
! 1123: CSR_WRITE_2(sc, ACXREG_INTR_MASK, sc->chip_intr_disable);
! 1124: CSR_WRITE_2(sc, ACXREG_EVENT_MASK, 0);
! 1125: }
! 1126:
! 1127: void
! 1128: acx_enable_intr(struct acx_softc *sc)
! 1129: {
! 1130: /* Mask out interrupts that are not in the enable set */
! 1131: CSR_WRITE_2(sc, ACXREG_INTR_MASK, ~sc->chip_intr_enable);
! 1132: CSR_WRITE_2(sc, ACXREG_EVENT_MASK, ACXRV_EVENT_DISABLE);
! 1133: }
! 1134:
! 1135: void
! 1136: acx_txeof(struct acx_softc *sc)
! 1137: {
! 1138: struct acx_buf_data *bd;
! 1139: struct acx_txbuf *buf;
! 1140: struct ifnet *ifp;
! 1141: int idx;
! 1142:
! 1143: ifp = &sc->sc_ic.ic_if;
! 1144:
! 1145: bd = &sc->sc_buf_data;
! 1146: idx = bd->tx_used_start;
! 1147: for (buf = &bd->tx_buf[idx]; buf->tb_mbuf != NULL;
! 1148: buf = &bd->tx_buf[idx]) {
! 1149: uint8_t ctrl, error;
! 1150:
! 1151: ctrl = FW_TXDESC_GETFIELD_1(sc, buf, f_tx_ctrl);
! 1152: if ((ctrl & (DESC_CTRL_HOSTOWN | DESC_CTRL_ACXDONE)) !=
! 1153: (DESC_CTRL_HOSTOWN | DESC_CTRL_ACXDONE))
! 1154: break;
! 1155:
! 1156: bus_dmamap_unload(sc->sc_dmat, buf->tb_mbuf_dmamap);
! 1157: m_freem(buf->tb_mbuf);
! 1158: buf->tb_mbuf = NULL;
! 1159:
! 1160: error = FW_TXDESC_GETFIELD_1(sc, buf, f_tx_error);
! 1161: if (error) {
! 1162: acx_txerr(sc, error);
! 1163: ifp->if_oerrors++;
! 1164: } else
! 1165: ifp->if_opackets++;
! 1166:
! 1167: /* Update rate control statistics for the node */
! 1168: if (buf->tb_node != NULL) {
! 1169: struct ieee80211com *ic;
! 1170: struct ieee80211_node *ni;
! 1171: struct acx_node *wn;
! 1172: int ntries;
! 1173:
! 1174: ic = &sc->sc_ic;
! 1175: ni = (struct ieee80211_node *)buf->tb_node;
! 1176: wn = (struct acx_node *)ni;
! 1177: ntries = FW_TXDESC_GETFIELD_1(sc, buf, f_tx_rts_fail) +
! 1178: FW_TXDESC_GETFIELD_1(sc, buf, f_tx_ack_fail);
! 1179:
! 1180: wn->amn.amn_txcnt++;
! 1181: if (ntries > 0) {
! 1182: DPRINTFN(2, ("%s: tx intr ntries %d\n",
! 1183: sc->sc_dev.dv_xname, ntries));
! 1184: wn->amn.amn_retrycnt++;
! 1185: }
! 1186:
! 1187: ieee80211_release_node(ic, ni);
! 1188: buf->tb_node = NULL;
! 1189: }
! 1190:
! 1191: FW_TXDESC_SETFIELD_1(sc, buf, f_tx_ctrl, DESC_CTRL_HOSTOWN);
! 1192:
! 1193: bd->tx_used_count--;
! 1194:
! 1195: idx = (idx + 1) % ACX_TX_DESC_CNT;
! 1196: }
! 1197: bd->tx_used_start = idx;
! 1198:
! 1199: ifp->if_timer = bd->tx_used_count == 0 ? 0 : 5;
! 1200: sc->sc_txtimer = 0;
! 1201:
! 1202: if (bd->tx_used_count != ACX_TX_DESC_CNT) {
! 1203: ifp->if_flags &= ~IFF_OACTIVE;
! 1204: acx_start(ifp);
! 1205: }
! 1206: }
! 1207:
! 1208: void
! 1209: acx_txerr(struct acx_softc *sc, uint8_t err)
! 1210: {
! 1211: struct ifnet *ifp = &sc->sc_ic.ic_if;
! 1212: struct acx_stats *stats = &sc->sc_stats;
! 1213:
! 1214: if (err == DESC_ERR_EXCESSIVE_RETRY) {
! 1215: /*
! 1216: * This a common error (see comment below),
! 1217: * so print it using DPRINTF().
! 1218: */
! 1219: DPRINTF(("%s: TX failed -- excessive retry\n",
! 1220: sc->sc_dev.dv_xname));
! 1221: } else
! 1222: printf("%s: TX failed -- ", ifp->if_xname);
! 1223:
! 1224: /*
! 1225: * Although `err' looks like bitmask, it never
! 1226: * has multiple bits set.
! 1227: */
! 1228: switch (err) {
! 1229: #if 0
! 1230: case DESC_ERR_OTHER_FRAG:
! 1231: /* XXX what's this */
! 1232: printf("error in other fragment\n");
! 1233: stats->err_oth_frag++;
! 1234: break;
! 1235: #endif
! 1236: case DESC_ERR_ABORT:
! 1237: printf("aborted\n");
! 1238: stats->err_abort++;
! 1239: break;
! 1240: case DESC_ERR_PARAM:
! 1241: printf("wrong paramters in descriptor\n");
! 1242: stats->err_param++;
! 1243: break;
! 1244: case DESC_ERR_NO_WEPKEY:
! 1245: printf("WEP key missing\n");
! 1246: stats->err_no_wepkey++;
! 1247: break;
! 1248: case DESC_ERR_MSDU_TIMEOUT:
! 1249: printf("MSDU life timeout\n");
! 1250: stats->err_msdu_timeout++;
! 1251: break;
! 1252: case DESC_ERR_EXCESSIVE_RETRY:
! 1253: /*
! 1254: * Possible causes:
! 1255: * 1) Distance is too long
! 1256: * 2) Transmit failed (e.g. no MAC level ACK)
! 1257: * 3) Chip overheated (this should be rare)
! 1258: */
! 1259: stats->err_ex_retry++;
! 1260: break;
! 1261: case DESC_ERR_BUF_OVERFLOW:
! 1262: printf("buffer overflow\n");
! 1263: stats->err_buf_oflow++;
! 1264: break;
! 1265: case DESC_ERR_DMA:
! 1266: printf("DMA error\n");
! 1267: stats->err_dma++;
! 1268: break;
! 1269: default:
! 1270: printf("unknown error %d\n", err);
! 1271: stats->err_unkn++;
! 1272: break;
! 1273: }
! 1274: }
! 1275:
! 1276: void
! 1277: acx_rxeof(struct acx_softc *sc)
! 1278: {
! 1279: struct ieee80211com *ic = &sc->sc_ic;
! 1280: struct acx_ring_data *rd = &sc->sc_ring_data;
! 1281: struct acx_buf_data *bd = &sc->sc_buf_data;
! 1282: struct ifnet *ifp = &ic->ic_if;
! 1283: int idx, ready;
! 1284:
! 1285: bus_dmamap_sync(sc->sc_dmat, rd->rx_ring_dmamap, 0,
! 1286: rd->rx_ring_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD);
! 1287:
! 1288: /*
! 1289: * Locate first "ready" rx buffer,
! 1290: * start from last stopped position.
! 1291: */
! 1292: idx = bd->rx_scan_start;
! 1293: ready = 0;
! 1294: do {
! 1295: struct acx_rxbuf *buf;
! 1296:
! 1297: buf = &bd->rx_buf[idx];
! 1298: if ((buf->rb_desc->h_ctrl & htole16(DESC_CTRL_HOSTOWN)) &&
! 1299: (buf->rb_desc->h_status & htole32(DESC_STATUS_FULL))) {
! 1300: ready = 1;
! 1301: break;
! 1302: }
! 1303: idx = (idx + 1) % ACX_RX_DESC_CNT;
! 1304: } while (idx != bd->rx_scan_start);
! 1305:
! 1306: if (!ready)
! 1307: return;
! 1308:
! 1309: /*
! 1310: * NOTE: don't mess up `idx' here, it will
! 1311: * be used in the following code.
! 1312: */
! 1313: do {
! 1314: struct acx_rxbuf_hdr *head;
! 1315: struct acx_rxbuf *buf;
! 1316: struct mbuf *m;
! 1317: uint32_t desc_status;
! 1318: uint16_t desc_ctrl;
! 1319: int len, error;
! 1320:
! 1321: buf = &bd->rx_buf[idx];
! 1322:
! 1323: desc_ctrl = letoh16(buf->rb_desc->h_ctrl);
! 1324: desc_status = letoh32(buf->rb_desc->h_status);
! 1325: if (!(desc_ctrl & DESC_CTRL_HOSTOWN) ||
! 1326: !(desc_status & DESC_STATUS_FULL))
! 1327: break;
! 1328:
! 1329: bus_dmamap_sync(sc->sc_dmat, buf->rb_mbuf_dmamap, 0,
! 1330: buf->rb_mbuf_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD);
! 1331:
! 1332: m = buf->rb_mbuf;
! 1333:
! 1334: error = acx_newbuf(sc, buf, 0);
! 1335: if (error) {
! 1336: ifp->if_ierrors++;
! 1337: goto next;
! 1338: }
! 1339:
! 1340: head = mtod(m, struct acx_rxbuf_hdr *);
! 1341:
! 1342: len = letoh16(head->rbh_len) & ACX_RXBUF_LEN_MASK;
! 1343: if (len >= sizeof(struct ieee80211_frame_min) &&
! 1344: len < MCLBYTES) {
! 1345: struct ieee80211_frame *wh;
! 1346: struct ieee80211_node *ni;
! 1347:
! 1348: m_adj(m, sizeof(struct acx_rxbuf_hdr) +
! 1349: sc->chip_rxbuf_exhdr);
! 1350: wh = mtod(m, struct ieee80211_frame *);
! 1351:
! 1352: if ((wh->i_fc[1] & IEEE80211_FC1_WEP) &&
! 1353: sc->chip_hw_crypt) {
! 1354: /* Short circuit software WEP */
! 1355: wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
! 1356:
! 1357: /* Do chip specific RX buffer processing */
! 1358: if (sc->chip_proc_wep_rxbuf != NULL) {
! 1359: sc->chip_proc_wep_rxbuf(sc, m, &len);
! 1360: wh = mtod(m, struct ieee80211_frame *);
! 1361: }
! 1362: }
! 1363:
! 1364: m->m_len = m->m_pkthdr.len = len;
! 1365: m->m_pkthdr.rcvif = &ic->ic_if;
! 1366:
! 1367: #if NBPFILTER > 0
! 1368: if (sc->sc_drvbpf != NULL) {
! 1369: struct mbuf mb;
! 1370: struct acx_rx_radiotap_hdr *tap = &sc->sc_rxtap;
! 1371:
! 1372: tap->wr_flags = 0;
! 1373: tap->wr_chan_freq =
! 1374: htole16(ic->ic_bss->ni_chan->ic_freq);
! 1375: tap->wr_chan_flags =
! 1376: htole16(ic->ic_bss->ni_chan->ic_flags);
! 1377: tap->wr_rssi = head->rbh_level;
! 1378: tap->wr_max_rssi = ic->ic_max_rssi;
! 1379:
! 1380: mb.m_data = (caddr_t)tap;
! 1381: mb.m_len = sc->sc_rxtap_len;
! 1382: mb.m_next = m;
! 1383: mb.m_nextpkt = NULL;
! 1384: mb.m_type = 0;
! 1385: mb.m_flags = 0;
! 1386: bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_IN);
! 1387: }
! 1388: #endif
! 1389:
! 1390: ni = ieee80211_find_rxnode(ic, wh);
! 1391:
! 1392: ieee80211_input(ifp, m, ni, head->rbh_level,
! 1393: letoh32(head->rbh_time));
! 1394:
! 1395: ieee80211_release_node(ic, ni);
! 1396: ifp->if_ipackets++;
! 1397: } else {
! 1398: m_freem(m);
! 1399: ifp->if_ierrors++;
! 1400: }
! 1401:
! 1402: next:
! 1403: buf->rb_desc->h_ctrl = htole16(desc_ctrl & ~DESC_CTRL_HOSTOWN);
! 1404: buf->rb_desc->h_status = 0;
! 1405: bus_dmamap_sync(sc->sc_dmat, rd->rx_ring_dmamap, 0,
! 1406: rd->rx_ring_dmamap->dm_mapsize, BUS_DMASYNC_PREWRITE);
! 1407:
! 1408: idx = (idx + 1) % ACX_RX_DESC_CNT;
! 1409: } while (idx != bd->rx_scan_start);
! 1410:
! 1411: /*
! 1412: * Record the position so that next
! 1413: * time we can start from it.
! 1414: */
! 1415: bd->rx_scan_start = idx;
! 1416:
! 1417: /*
! 1418: * In HostAP mode, ieee80211_input() will enqueue packets in if_snd
! 1419: * without calling if_start().
! 1420: */
! 1421: if (!IFQ_IS_EMPTY(&ifp->if_snd) && !(ifp->if_flags & IFF_OACTIVE))
! 1422: (*ifp->if_start)(ifp);
! 1423: }
! 1424:
! 1425: int
! 1426: acx_reset(struct acx_softc *sc)
! 1427: {
! 1428: uint16_t reg;
! 1429:
! 1430: /* Halt ECPU */
! 1431: CSR_SETB_2(sc, ACXREG_ECPU_CTRL, ACXRV_ECPU_HALT);
! 1432:
! 1433: /* Software reset */
! 1434: reg = CSR_READ_2(sc, ACXREG_SOFT_RESET);
! 1435: CSR_WRITE_2(sc, ACXREG_SOFT_RESET, reg | ACXRV_SOFT_RESET);
! 1436: DELAY(100);
! 1437: CSR_WRITE_2(sc, ACXREG_SOFT_RESET, reg);
! 1438:
! 1439: /* Initialize EEPROM */
! 1440: CSR_SETB_2(sc, ACXREG_EEPROM_INIT, ACXRV_EEPROM_INIT);
! 1441: DELAY(50000);
! 1442:
! 1443: /* Test whether ECPU is stopped */
! 1444: reg = CSR_READ_2(sc, ACXREG_ECPU_CTRL);
! 1445: if (!(reg & ACXRV_ECPU_HALT)) {
! 1446: printf("%s: can't halt ECPU\n", sc->sc_dev.dv_xname);
! 1447: return (ENXIO);
! 1448: }
! 1449:
! 1450: return (0);
! 1451: }
! 1452:
! 1453: int
! 1454: acx_read_eeprom(struct acx_softc *sc, uint32_t offset, uint8_t *val)
! 1455: {
! 1456: int i;
! 1457: struct ifnet *ifp = &sc->sc_ic.ic_if;
! 1458:
! 1459: CSR_WRITE_4(sc, ACXREG_EEPROM_CONF, 0);
! 1460: CSR_WRITE_4(sc, ACXREG_EEPROM_ADDR, offset);
! 1461: CSR_WRITE_4(sc, ACXREG_EEPROM_CTRL, ACXRV_EEPROM_READ);
! 1462:
! 1463: #define EE_READ_RETRY_MAX 100
! 1464: for (i = 0; i < EE_READ_RETRY_MAX; ++i) {
! 1465: if (CSR_READ_2(sc, ACXREG_EEPROM_CTRL) == 0)
! 1466: break;
! 1467: DELAY(10000);
! 1468: }
! 1469: if (i == EE_READ_RETRY_MAX) {
! 1470: printf("%s: can't read EEPROM offset %x (timeout)\n",
! 1471: ifp->if_xname, offset);
! 1472: return (ETIMEDOUT);
! 1473: }
! 1474: #undef EE_READ_RETRY_MAX
! 1475:
! 1476: *val = CSR_READ_1(sc, ACXREG_EEPROM_DATA);
! 1477:
! 1478: return (0);
! 1479: }
! 1480:
! 1481: int
! 1482: acx_read_phyreg(struct acx_softc *sc, uint32_t reg, uint8_t *val)
! 1483: {
! 1484: struct ifnet *ifp = &sc->sc_ic.ic_if;
! 1485: int i;
! 1486:
! 1487: CSR_WRITE_4(sc, ACXREG_PHY_ADDR, reg);
! 1488: CSR_WRITE_4(sc, ACXREG_PHY_CTRL, ACXRV_PHY_READ);
! 1489:
! 1490: #define PHY_READ_RETRY_MAX 100
! 1491: for (i = 0; i < PHY_READ_RETRY_MAX; ++i) {
! 1492: if (CSR_READ_4(sc, ACXREG_PHY_CTRL) == 0)
! 1493: break;
! 1494: DELAY(10000);
! 1495: }
! 1496: if (i == PHY_READ_RETRY_MAX) {
! 1497: printf("%s: can't read phy reg %x (timeout)\n",
! 1498: ifp->if_xname, reg);
! 1499: return (ETIMEDOUT);
! 1500: }
! 1501: #undef PHY_READ_RETRY_MAX
! 1502:
! 1503: *val = CSR_READ_1(sc, ACXREG_PHY_DATA);
! 1504:
! 1505: return (0);
! 1506: }
! 1507:
! 1508: void
! 1509: acx_write_phyreg(struct acx_softc *sc, uint32_t reg, uint8_t val)
! 1510: {
! 1511: CSR_WRITE_4(sc, ACXREG_PHY_DATA, val);
! 1512: CSR_WRITE_4(sc, ACXREG_PHY_ADDR, reg);
! 1513: CSR_WRITE_4(sc, ACXREG_PHY_CTRL, ACXRV_PHY_WRITE);
! 1514: }
! 1515:
! 1516: int
! 1517: acx_load_base_firmware(struct acx_softc *sc, const char *name)
! 1518: {
! 1519: struct ifnet *ifp = &sc->sc_ic.ic_if;
! 1520: int i, error;
! 1521: uint8_t *ucode;
! 1522: size_t size;
! 1523:
! 1524: error = loadfirmware(name, &ucode, &size);
! 1525:
! 1526: if (error != 0) {
! 1527: printf("%s: error %d, could not read microcode %s!\n",
! 1528: ifp->if_xname, error, name);
! 1529: return (EIO);
! 1530: }
! 1531:
! 1532: /* Load base firmware */
! 1533: error = acx_load_firmware(sc, 0, ucode, size);
! 1534:
! 1535: free(ucode, M_DEVBUF);
! 1536:
! 1537: if (error) {
! 1538: printf("%s: can't load base firmware\n", ifp->if_xname);
! 1539: return error;
! 1540: }
! 1541: DPRINTF(("%s: base firmware loaded\n", sc->sc_dev.dv_xname));
! 1542:
! 1543: /* Start ECPU */
! 1544: CSR_WRITE_2(sc, ACXREG_ECPU_CTRL, ACXRV_ECPU_START);
! 1545:
! 1546: /* Wait for ECPU to be up */
! 1547: for (i = 0; i < 500; ++i) {
! 1548: uint16_t reg;
! 1549:
! 1550: reg = CSR_READ_2(sc, ACXREG_INTR_STATUS);
! 1551: if (reg & ACXRV_INTR_FCS_THRESH) {
! 1552: CSR_WRITE_2(sc, ACXREG_INTR_ACK, ACXRV_INTR_FCS_THRESH);
! 1553: return (0);
! 1554: }
! 1555: DELAY(10000);
! 1556: }
! 1557:
! 1558: printf("%s: can't initialize ECPU (timeout)\n", ifp->if_xname);
! 1559:
! 1560: return (ENXIO);
! 1561: }
! 1562:
! 1563: int
! 1564: acx_load_radio_firmware(struct acx_softc *sc, const char *name)
! 1565: {
! 1566: struct ifnet *ifp = &sc->sc_ic.ic_if;
! 1567: struct acx_conf_mmap mem_map;
! 1568: uint32_t radio_fw_ofs;
! 1569: int error;
! 1570: uint8_t *ucode;
! 1571: size_t size;
! 1572:
! 1573: error = loadfirmware(name, &ucode, &size);
! 1574:
! 1575: if (error != 0) {
! 1576: printf("%s: error %d, could not read microcode %s!\n",
! 1577: ifp->if_xname, error, name);
! 1578: return (EIO);
! 1579: }
! 1580:
! 1581: /*
! 1582: * Get the position, where base firmware is loaded, so that
! 1583: * radio firmware can be loaded after it.
! 1584: */
! 1585: if (acx_get_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) {
! 1586: free(ucode, M_DEVBUF);
! 1587: return (ENXIO);
! 1588: }
! 1589: radio_fw_ofs = letoh32(mem_map.code_end);
! 1590:
! 1591: /* Put ECPU into sleeping state, before loading radio firmware */
! 1592: if (acx_exec_command(sc, ACXCMD_SLEEP, NULL, 0, NULL, 0) != 0) {
! 1593: free(ucode, M_DEVBUF);
! 1594: return (ENXIO);
! 1595: }
! 1596:
! 1597: /* Load radio firmware */
! 1598: error = acx_load_firmware(sc, radio_fw_ofs, ucode, size);
! 1599:
! 1600: free(ucode, M_DEVBUF);
! 1601:
! 1602: if (error) {
! 1603: printf("%s: can't load radio firmware\n", ifp->if_xname);
! 1604: return (ENXIO);
! 1605: }
! 1606: DPRINTF(("%s: radio firmware loaded\n", sc->sc_dev.dv_xname));
! 1607:
! 1608: /* Wake up sleeping ECPU, after radio firmware is loaded */
! 1609: if (acx_exec_command(sc, ACXCMD_WAKEUP, NULL, 0, NULL, 0) != 0)
! 1610: return (ENXIO);
! 1611:
! 1612: /* Initialize radio */
! 1613: if (acx_init_radio(sc, radio_fw_ofs, size) != 0)
! 1614: return (ENXIO);
! 1615:
! 1616: /* Verify radio firmware's loading position */
! 1617: if (acx_get_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0)
! 1618: return (ENXIO);
! 1619:
! 1620: if (letoh32(mem_map.code_end) != radio_fw_ofs + size) {
! 1621: printf("%s: loaded radio firmware position mismatch\n",
! 1622: ifp->if_xname);
! 1623: return (ENXIO);
! 1624: }
! 1625:
! 1626: DPRINTF(("%s: radio firmware initialized\n", sc->sc_dev.dv_xname));
! 1627:
! 1628: return (0);
! 1629: }
! 1630:
! 1631: int
! 1632: acx_load_firmware(struct acx_softc *sc, uint32_t offset, const uint8_t *data,
! 1633: int data_len)
! 1634: {
! 1635: struct ifnet *ifp = &sc->sc_ic.ic_if;
! 1636: const uint32_t *fw;
! 1637: u_int32_t csum = 0;
! 1638: int i, fw_len;
! 1639:
! 1640: for (i = 4; i < data_len; i++)
! 1641: csum += data[i];
! 1642:
! 1643: fw = (const uint32_t *)data;
! 1644:
! 1645: if (*fw != htole32(csum)) {
! 1646: printf("%s: firmware checksum 0x%x does not match 0x%x!\n",
! 1647: ifp->if_xname, *fw, htole32(csum));
! 1648: return (ENXIO);
! 1649: }
! 1650:
! 1651: /* skip csum + length */
! 1652: data += 8;
! 1653: data_len -= 8;
! 1654:
! 1655: fw = (const uint32_t *)data;
! 1656: fw_len = data_len / sizeof(uint32_t);
! 1657:
! 1658: /*
! 1659: * LOADFW_AUTO_INC only works with some older firmware:
! 1660: * 1) acx100's firmware
! 1661: * 2) acx111's firmware whose rev is 0x00010011
! 1662: */
! 1663:
! 1664: /* Load firmware */
! 1665: CSR_WRITE_4(sc, ACXREG_FWMEM_START, ACXRV_FWMEM_START_OP);
! 1666: #ifndef LOADFW_AUTO_INC
! 1667: CSR_WRITE_4(sc, ACXREG_FWMEM_CTRL, 0);
! 1668: #else
! 1669: CSR_WRITE_4(sc, ACXREG_FWMEM_CTRL, ACXRV_FWMEM_ADDR_AUTOINC);
! 1670: CSR_WRITE_4(sc, ACXREG_FWMEM_ADDR, offset);
! 1671: #endif
! 1672:
! 1673: for (i = 0; i < fw_len; ++i) {
! 1674: #ifndef LOADFW_AUTO_INC
! 1675: CSR_WRITE_4(sc, ACXREG_FWMEM_ADDR, offset + (i * 4));
! 1676: #endif
! 1677: CSR_WRITE_4(sc, ACXREG_FWMEM_DATA, betoh32(fw[i]));
! 1678: }
! 1679:
! 1680: /* Verify firmware */
! 1681: CSR_WRITE_4(sc, ACXREG_FWMEM_START, ACXRV_FWMEM_START_OP);
! 1682: #ifndef LOADFW_AUTO_INC
! 1683: CSR_WRITE_4(sc, ACXREG_FWMEM_CTRL, 0);
! 1684: #else
! 1685: CSR_WRITE_4(sc, ACXREG_FWMEM_CTRL, ACXRV_FWMEM_ADDR_AUTOINC);
! 1686: CSR_WRITE_4(sc, ACXREG_FWMEM_ADDR, offset);
! 1687: #endif
! 1688:
! 1689: for (i = 0; i < fw_len; ++i) {
! 1690: uint32_t val;
! 1691:
! 1692: #ifndef LOADFW_AUTO_INC
! 1693: CSR_WRITE_4(sc, ACXREG_FWMEM_ADDR, offset + (i * 4));
! 1694: #endif
! 1695: val = CSR_READ_4(sc, ACXREG_FWMEM_DATA);
! 1696: if (betoh32(fw[i]) != val) {
! 1697: printf("%s: firmware mismatch fw %08x loaded %08x\n",
! 1698: ifp->if_xname, fw[i], val);
! 1699: return (ENXIO);
! 1700: }
! 1701: }
! 1702:
! 1703: return (0);
! 1704: }
! 1705:
! 1706: struct ieee80211_node *
! 1707: acx_node_alloc(struct ieee80211com *ic)
! 1708: {
! 1709: struct acx_node *wn;
! 1710:
! 1711: wn = malloc(sizeof(struct acx_node), M_DEVBUF, M_NOWAIT);
! 1712: if (wn == NULL)
! 1713: return (NULL);
! 1714:
! 1715: bzero(wn, sizeof(struct acx_node));
! 1716:
! 1717: return ((struct ieee80211_node *)wn);
! 1718: }
! 1719:
! 1720: int
! 1721: acx_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
! 1722: {
! 1723: struct acx_softc *sc = ic->ic_if.if_softc;
! 1724: struct ifnet *ifp = &ic->ic_if;
! 1725: int error = 0;
! 1726:
! 1727: timeout_del(&sc->amrr_ch);
! 1728:
! 1729: switch (nstate) {
! 1730: case IEEE80211_S_INIT:
! 1731: break;
! 1732: case IEEE80211_S_SCAN: {
! 1733: uint8_t chan;
! 1734:
! 1735: chan = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan);
! 1736: (void)acx_set_channel(sc, chan);
! 1737:
! 1738: timeout_add(&sc->sc_chanscan_timer,
! 1739: hz / acx_chanscan_rate);
! 1740: }
! 1741: break;
! 1742: case IEEE80211_S_AUTH:
! 1743: if (ic->ic_opmode == IEEE80211_M_STA) {
! 1744: struct ieee80211_node *ni;
! 1745: #ifdef ACX_DEBUG
! 1746: int i;
! 1747: #endif
! 1748:
! 1749: ni = ic->ic_bss;
! 1750:
! 1751: if (acx_join_bss(sc, ACX_MODE_STA, ni) != 0) {
! 1752: printf("%s: join BSS failed\n", ifp->if_xname);
! 1753: error = 1;
! 1754: goto back;
! 1755: }
! 1756:
! 1757: DPRINTF(("%s: join BSS\n", sc->sc_dev.dv_xname));
! 1758: if (ic->ic_state == IEEE80211_S_ASSOC) {
! 1759: DPRINTF(("%s: change from assoc to run\n",
! 1760: sc->sc_dev.dv_xname));
! 1761: ic->ic_state = IEEE80211_S_RUN;
! 1762: }
! 1763:
! 1764: #ifdef ACX_DEBUG
! 1765: printf("%s: AP rates: ", sc->sc_dev.dv_xname);
! 1766: for (i = 0; i < ni->ni_rates.rs_nrates; ++i)
! 1767: printf("%d ", ni->ni_rates.rs_rates[i]);
! 1768: ieee80211_print_essid(ni->ni_essid, ni->ni_esslen);
! 1769: printf(" %s\n", ether_sprintf(ni->ni_bssid));
! 1770: #endif
! 1771: }
! 1772: break;
! 1773: case IEEE80211_S_RUN:
! 1774: if (ic->ic_opmode == IEEE80211_M_IBSS ||
! 1775: ic->ic_opmode == IEEE80211_M_HOSTAP) {
! 1776: struct ieee80211_node *ni;
! 1777: uint8_t chan;
! 1778:
! 1779: ni = ic->ic_bss;
! 1780: chan = ieee80211_chan2ieee(ic, ni->ni_chan);
! 1781:
! 1782: error = 1;
! 1783:
! 1784: if (acx_set_channel(sc, chan) != 0)
! 1785: goto back;
! 1786:
! 1787: if (acx_set_beacon_tmplt(sc, ni) != 0) {
! 1788: printf("%s: set beacon template failed\n",
! 1789: ifp->if_xname);
! 1790: goto back;
! 1791: }
! 1792:
! 1793: if (acx_set_probe_resp_tmplt(sc, ni) != 0) {
! 1794: printf("%s: set probe response template "
! 1795: "failed\n", ifp->if_xname);
! 1796: goto back;
! 1797: }
! 1798:
! 1799: if (ic->ic_opmode == IEEE80211_M_IBSS) {
! 1800: if (acx_join_bss(sc, ACX_MODE_ADHOC, ni) != 0) {
! 1801: printf("%s: join IBSS failed\n",
! 1802: ifp->if_xname);
! 1803: goto back;
! 1804: }
! 1805: } else {
! 1806: if (acx_join_bss(sc, ACX_MODE_AP, ni) != 0) {
! 1807: printf("%s: join HOSTAP failed\n",
! 1808: ifp->if_xname);
! 1809: goto back;
! 1810: }
! 1811: }
! 1812:
! 1813: DPRINTF(("%s: join IBSS\n", sc->sc_dev.dv_xname));
! 1814: error = 0;
! 1815: }
! 1816:
! 1817: /* fake a join to init the tx rate */
! 1818: if (ic->ic_opmode == IEEE80211_M_STA)
! 1819: acx_newassoc(ic, ic->ic_bss, 1);
! 1820:
! 1821: /* start automatic rate control timer */
! 1822: if (ic->ic_fixed_rate == -1)
! 1823: timeout_add(&sc->amrr_ch, hz / 2);
! 1824: break;
! 1825: default:
! 1826: break;
! 1827: }
! 1828:
! 1829: back:
! 1830: if (error) {
! 1831: /* XXX */
! 1832: nstate = IEEE80211_S_INIT;
! 1833: arg = -1;
! 1834: }
! 1835:
! 1836: return (sc->sc_newstate(ic, nstate, arg));
! 1837: }
! 1838:
! 1839: int
! 1840: acx_init_tmplt_ordered(struct acx_softc *sc)
! 1841: {
! 1842: union {
! 1843: struct acx_tmplt_beacon beacon;
! 1844: struct acx_tmplt_null_data null;
! 1845: struct acx_tmplt_probe_req preq;
! 1846: struct acx_tmplt_probe_resp presp;
! 1847: struct acx_tmplt_tim tim;
! 1848: } data;
! 1849:
! 1850: bzero(&data, sizeof(data));
! 1851: /*
! 1852: * NOTE:
! 1853: * Order of templates initialization:
! 1854: * 1) Probe request
! 1855: * 2) NULL data
! 1856: * 3) Beacon
! 1857: * 4) TIM
! 1858: * 5) Probe response
! 1859: * Above order is critical to get a correct memory map.
! 1860: */
! 1861: if (acx_set_tmplt(sc, ACXCMD_TMPLT_PROBE_REQ, &data.preq,
! 1862: sizeof(data.preq)) != 0)
! 1863: return (1);
! 1864:
! 1865: if (acx_set_tmplt(sc, ACXCMD_TMPLT_NULL_DATA, &data.null,
! 1866: sizeof(data.null)) != 0)
! 1867: return (1);
! 1868:
! 1869: if (acx_set_tmplt(sc, ACXCMD_TMPLT_BEACON, &data.beacon,
! 1870: sizeof(data.beacon)) != 0)
! 1871: return (1);
! 1872:
! 1873: if (acx_set_tmplt(sc, ACXCMD_TMPLT_TIM, &data.tim,
! 1874: sizeof(data.tim)) != 0)
! 1875: return (1);
! 1876:
! 1877: if (acx_set_tmplt(sc, ACXCMD_TMPLT_PROBE_RESP, &data.presp,
! 1878: sizeof(data.presp)) != 0)
! 1879: return (1);
! 1880:
! 1881: return (0);
! 1882: }
! 1883:
! 1884: int
! 1885: acx_dma_alloc(struct acx_softc *sc)
! 1886: {
! 1887: struct acx_ring_data *rd = &sc->sc_ring_data;
! 1888: struct acx_buf_data *bd = &sc->sc_buf_data;
! 1889: struct ifnet *ifp = &sc->sc_ic.ic_if;
! 1890: int i, error, nsegs;
! 1891:
! 1892: /* Allocate DMA stuffs for RX descriptors */
! 1893: error = bus_dmamap_create(sc->sc_dmat, ACX_RX_RING_SIZE, 1,
! 1894: ACX_RX_RING_SIZE, 0, BUS_DMA_NOWAIT, &rd->rx_ring_dmamap);
! 1895:
! 1896: if (error) {
! 1897: printf("%s: can't create rx ring dma tag\n",
! 1898: sc->sc_dev.dv_xname);
! 1899: return (error);
! 1900: }
! 1901:
! 1902: error = bus_dmamem_alloc(sc->sc_dmat, ACX_RX_RING_SIZE, PAGE_SIZE,
! 1903: 0, &rd->rx_ring_seg, 1, &nsegs, BUS_DMA_NOWAIT);
! 1904:
! 1905: if (error != 0) {
! 1906: printf("%s: can't allocate rx ring dma memory\n",
! 1907: sc->sc_dev.dv_xname);
! 1908: return (error);
! 1909: }
! 1910:
! 1911: error = bus_dmamem_map(sc->sc_dmat, &rd->rx_ring_seg, nsegs,
! 1912: ACX_RX_RING_SIZE, (caddr_t *)&rd->rx_ring,
! 1913: BUS_DMA_NOWAIT);
! 1914:
! 1915: if (error != 0) {
! 1916: printf("%s: could not map rx desc DMA memory\n",
! 1917: sc->sc_dev.dv_xname);
! 1918: return (error);
! 1919: }
! 1920:
! 1921: error = bus_dmamap_load(sc->sc_dmat, rd->rx_ring_dmamap,
! 1922: rd->rx_ring, ACX_RX_RING_SIZE, NULL, BUS_DMA_WAITOK);
! 1923:
! 1924: if (error) {
! 1925: printf("%s: can't get rx ring dma address\n",
! 1926: sc->sc_dev.dv_xname);
! 1927: bus_dmamem_free(sc->sc_dmat, &rd->rx_ring_seg, 1);
! 1928: return (error);
! 1929: }
! 1930:
! 1931: rd->rx_ring_paddr = rd->rx_ring_dmamap->dm_segs[0].ds_addr;
! 1932:
! 1933: /* Allocate DMA stuffs for TX descriptors */
! 1934: error = bus_dmamap_create(sc->sc_dmat, ACX_TX_RING_SIZE, 1,
! 1935: ACX_TX_RING_SIZE, 0, BUS_DMA_NOWAIT, &rd->tx_ring_dmamap);
! 1936:
! 1937: if (error) {
! 1938: printf("%s: can't create tx ring dma tag\n", ifp->if_xname);
! 1939: return (error);
! 1940: }
! 1941:
! 1942: error = bus_dmamem_alloc(sc->sc_dmat, ACX_TX_RING_SIZE, PAGE_SIZE,
! 1943: 0, &rd->tx_ring_seg, 1, &nsegs, BUS_DMA_NOWAIT);
! 1944:
! 1945: if (error) {
! 1946: printf("%s: can't allocate tx ring dma memory\n",
! 1947: ifp->if_xname);
! 1948: return (error);
! 1949: }
! 1950:
! 1951: error = bus_dmamem_map(sc->sc_dmat, &rd->tx_ring_seg, nsegs,
! 1952: ACX_TX_RING_SIZE, (caddr_t *)&rd->tx_ring, BUS_DMA_NOWAIT);
! 1953:
! 1954: if (error != 0) {
! 1955: printf("%s: could not map tx desc DMA memory\n",
! 1956: sc->sc_dev.dv_xname);
! 1957: return (error);
! 1958: }
! 1959:
! 1960: error = bus_dmamap_load(sc->sc_dmat, rd->tx_ring_dmamap,
! 1961: rd->tx_ring, ACX_TX_RING_SIZE, NULL, BUS_DMA_WAITOK);
! 1962:
! 1963: if (error) {
! 1964: printf("%s: can't get tx ring dma address\n", ifp->if_xname);
! 1965: bus_dmamem_free(sc->sc_dmat, &rd->tx_ring_seg, 1);
! 1966: return (error);
! 1967: }
! 1968:
! 1969: rd->tx_ring_paddr = rd->tx_ring_dmamap->dm_segs[0].ds_addr;
! 1970:
! 1971: /* Create a spare RX DMA map */
! 1972: error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES,
! 1973: 0, 0, &bd->mbuf_tmp_dmamap);
! 1974:
! 1975: if (error) {
! 1976: printf("%s: can't create tmp mbuf dma map\n", ifp->if_xname);
! 1977: return (error);
! 1978: }
! 1979:
! 1980: /* Create DMA map for RX mbufs */
! 1981: for (i = 0; i < ACX_RX_DESC_CNT; ++i) {
! 1982: error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1,
! 1983: MCLBYTES, 0, 0, &bd->rx_buf[i].rb_mbuf_dmamap);
! 1984: if (error) {
! 1985: printf("%s: can't create rx mbuf dma map (%d)\n",
! 1986: ifp->if_xname, i);
! 1987: return (error);
! 1988: }
! 1989: bd->rx_buf[i].rb_desc = &rd->rx_ring[i];
! 1990: }
! 1991:
! 1992: /* Create DMA map for TX mbufs */
! 1993: for (i = 0; i < ACX_TX_DESC_CNT; ++i) {
! 1994: error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1,
! 1995: MCLBYTES, 0, 0, &bd->tx_buf[i].tb_mbuf_dmamap);
! 1996: if (error) {
! 1997: printf("%s: can't create tx mbuf dma map (%d)\n",
! 1998: ifp->if_xname, i);
! 1999: return (error);
! 2000: }
! 2001: bd->tx_buf[i].tb_desc1 = &rd->tx_ring[i * 2];
! 2002: bd->tx_buf[i].tb_desc2 = &rd->tx_ring[(i * 2) + 1];
! 2003: }
! 2004:
! 2005: return (0);
! 2006: }
! 2007:
! 2008: void
! 2009: acx_dma_free(struct acx_softc *sc)
! 2010: {
! 2011: struct acx_ring_data *rd = &sc->sc_ring_data;
! 2012: struct acx_buf_data *bd = &sc->sc_buf_data;
! 2013: int i;
! 2014:
! 2015: if (rd->rx_ring != NULL) {
! 2016: bus_dmamap_unload(sc->sc_dmat, rd->rx_ring_dmamap);
! 2017: bus_dmamem_free(sc->sc_dmat, &rd->rx_ring_seg, 1);
! 2018: }
! 2019:
! 2020: if (rd->tx_ring != NULL) {
! 2021: bus_dmamap_unload(sc->sc_dmat, rd->tx_ring_dmamap);
! 2022: bus_dmamem_free(sc->sc_dmat, &rd->tx_ring_seg, 1);
! 2023: }
! 2024:
! 2025: for (i = 0; i < ACX_RX_DESC_CNT; ++i) {
! 2026: if (bd->rx_buf[i].rb_desc != NULL) {
! 2027: if (bd->rx_buf[i].rb_mbuf != NULL) {
! 2028: bus_dmamap_unload(sc->sc_dmat,
! 2029: bd->rx_buf[i].rb_mbuf_dmamap);
! 2030: m_freem(bd->rx_buf[i].rb_mbuf);
! 2031: }
! 2032: bus_dmamap_destroy(sc->sc_dmat,
! 2033: bd->rx_buf[i].rb_mbuf_dmamap);
! 2034: }
! 2035: }
! 2036:
! 2037: for (i = 0; i < ACX_TX_DESC_CNT; ++i) {
! 2038: if (bd->tx_buf[i].tb_desc1 != NULL) {
! 2039: if (bd->tx_buf[i].tb_mbuf != NULL) {
! 2040: bus_dmamap_unload(sc->sc_dmat,
! 2041: bd->tx_buf[i].tb_mbuf_dmamap);
! 2042: m_freem(bd->tx_buf[i].tb_mbuf);
! 2043: }
! 2044: bus_dmamap_destroy(sc->sc_dmat,
! 2045: bd->tx_buf[i].tb_mbuf_dmamap);
! 2046: }
! 2047: }
! 2048:
! 2049: if (bd->mbuf_tmp_dmamap != NULL)
! 2050: bus_dmamap_destroy(sc->sc_dmat, bd->mbuf_tmp_dmamap);
! 2051: }
! 2052:
! 2053: int
! 2054: acx_init_tx_ring(struct acx_softc *sc)
! 2055: {
! 2056: struct acx_ring_data *rd;
! 2057: struct acx_buf_data *bd;
! 2058: uint32_t paddr;
! 2059: int i;
! 2060:
! 2061: rd = &sc->sc_ring_data;
! 2062: paddr = rd->tx_ring_paddr;
! 2063: for (i = 0; i < (ACX_TX_DESC_CNT * 2) - 1; ++i) {
! 2064: paddr += sizeof(struct acx_host_desc);
! 2065:
! 2066: bzero(&rd->tx_ring[i], sizeof(struct acx_host_desc));
! 2067: rd->tx_ring[i].h_ctrl = htole16(DESC_CTRL_HOSTOWN);
! 2068:
! 2069: if (i == (ACX_TX_DESC_CNT * 2) - 1)
! 2070: rd->tx_ring[i].h_next_desc = htole32(rd->tx_ring_paddr);
! 2071: else
! 2072: rd->tx_ring[i].h_next_desc = htole32(paddr);
! 2073: }
! 2074:
! 2075: bus_dmamap_sync(sc->sc_dmat, rd->tx_ring_dmamap, 0,
! 2076: rd->tx_ring_dmamap->dm_mapsize, BUS_DMASYNC_PREWRITE);
! 2077:
! 2078: bd = &sc->sc_buf_data;
! 2079: bd->tx_free_start = 0;
! 2080: bd->tx_used_start = 0;
! 2081: bd->tx_used_count = 0;
! 2082:
! 2083: return (0);
! 2084: }
! 2085:
! 2086: int
! 2087: acx_init_rx_ring(struct acx_softc *sc)
! 2088: {
! 2089: struct acx_ring_data *rd;
! 2090: struct acx_buf_data *bd;
! 2091: uint32_t paddr;
! 2092: int i;
! 2093:
! 2094: bd = &sc->sc_buf_data;
! 2095: rd = &sc->sc_ring_data;
! 2096: paddr = rd->rx_ring_paddr;
! 2097:
! 2098: for (i = 0; i < ACX_RX_DESC_CNT; ++i) {
! 2099: int error;
! 2100:
! 2101: paddr += sizeof(struct acx_host_desc);
! 2102: bzero(&rd->rx_ring[i], sizeof(struct acx_host_desc));
! 2103:
! 2104: error = acx_newbuf(sc, &bd->rx_buf[i], 1);
! 2105: if (error)
! 2106: return (error);
! 2107:
! 2108: if (i == ACX_RX_DESC_CNT - 1)
! 2109: rd->rx_ring[i].h_next_desc = htole32(rd->rx_ring_paddr);
! 2110: else
! 2111: rd->rx_ring[i].h_next_desc = htole32(paddr);
! 2112: }
! 2113:
! 2114: bus_dmamap_sync(sc->sc_dmat, rd->rx_ring_dmamap, 0,
! 2115: rd->rx_ring_dmamap->dm_mapsize, BUS_DMASYNC_PREWRITE);
! 2116:
! 2117: bd->rx_scan_start = 0;
! 2118:
! 2119: return (0);
! 2120: }
! 2121:
! 2122: int
! 2123: acx_newbuf(struct acx_softc *sc, struct acx_rxbuf *rb, int wait)
! 2124: {
! 2125: struct acx_buf_data *bd;
! 2126: struct mbuf *m;
! 2127: bus_dmamap_t map;
! 2128: uint32_t paddr;
! 2129: int error;
! 2130:
! 2131: bd = &sc->sc_buf_data;
! 2132:
! 2133: MGETHDR(m, wait ? M_WAITOK : M_DONTWAIT, MT_DATA);
! 2134: if (m == NULL)
! 2135: return (ENOBUFS);
! 2136:
! 2137: MCLGET(m, wait ? M_WAITOK : M_DONTWAIT);
! 2138: if (!(m->m_flags & M_EXT)) {
! 2139: m_freem(m);
! 2140: return (ENOBUFS);
! 2141: }
! 2142:
! 2143: m->m_len = m->m_pkthdr.len = MCLBYTES;
! 2144:
! 2145: error = bus_dmamap_load_mbuf(sc->sc_dmat, bd->mbuf_tmp_dmamap, m,
! 2146: wait ? BUS_DMA_WAITOK : BUS_DMA_NOWAIT);
! 2147: if (error) {
! 2148: m_freem(m);
! 2149: printf("%s: can't map rx mbuf %d\n",
! 2150: sc->sc_dev.dv_xname, error);
! 2151: return (error);
! 2152: }
! 2153:
! 2154: /* Unload originally mapped mbuf */
! 2155: if (rb->rb_mbuf != NULL)
! 2156: bus_dmamap_unload(sc->sc_dmat, rb->rb_mbuf_dmamap);
! 2157:
! 2158: /* Swap this dmamap with tmp dmamap */
! 2159: map = rb->rb_mbuf_dmamap;
! 2160: rb->rb_mbuf_dmamap = bd->mbuf_tmp_dmamap;
! 2161: bd->mbuf_tmp_dmamap = map;
! 2162: paddr = rb->rb_mbuf_dmamap->dm_segs[0].ds_addr;
! 2163:
! 2164: rb->rb_mbuf = m;
! 2165: rb->rb_desc->h_data_paddr = htole32(paddr);
! 2166: rb->rb_desc->h_data_len = htole16(m->m_len);
! 2167:
! 2168: bus_dmamap_sync(sc->sc_dmat, rb->rb_mbuf_dmamap, 0,
! 2169: rb->rb_mbuf_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD);
! 2170:
! 2171: return (0);
! 2172: }
! 2173:
! 2174: int
! 2175: acx_encap(struct acx_softc *sc, struct acx_txbuf *txbuf, struct mbuf *m,
! 2176: struct ieee80211_node *ni, int rate)
! 2177: {
! 2178: struct acx_ring_data *rd = &sc->sc_ring_data;
! 2179: struct acx_node *node = (struct acx_node *)ni;
! 2180: struct ifnet *ifp = &sc->sc_ic.ic_if;
! 2181: uint32_t paddr;
! 2182: uint8_t ctrl;
! 2183: int error;
! 2184:
! 2185: if (txbuf->tb_mbuf != NULL)
! 2186: panic("free TX buf has mbuf installed\n");
! 2187:
! 2188: error = 0;
! 2189:
! 2190: if (m->m_pkthdr.len > MCLBYTES) {
! 2191: printf("%s: mbuf too big\n", ifp->if_xname);
! 2192: error = E2BIG;
! 2193: goto back;
! 2194: } else if (m->m_pkthdr.len < ACX_FRAME_HDRLEN) {
! 2195: printf("%s: mbuf too small\n", ifp->if_xname);
! 2196: error = EINVAL;
! 2197: goto back;
! 2198: }
! 2199:
! 2200: error = bus_dmamap_load_mbuf(sc->sc_dmat, txbuf->tb_mbuf_dmamap, m,
! 2201: BUS_DMA_NOWAIT);
! 2202:
! 2203: if (error && error != EFBIG) {
! 2204: printf("%s: can't map tx mbuf1 %d\n",
! 2205: sc->sc_dev.dv_xname, error);
! 2206: goto back;
! 2207: }
! 2208:
! 2209: if (error) { /* error == EFBIG */
! 2210: /* too many fragments, linearize */
! 2211: struct mbuf *mnew;
! 2212:
! 2213: error = 0;
! 2214:
! 2215: MGETHDR(mnew, M_DONTWAIT, MT_DATA);
! 2216: if (mnew == NULL) {
! 2217: m_freem(m);
! 2218: error = ENOBUFS;
! 2219: printf("%s: can't defrag tx mbuf\n", ifp->if_xname);
! 2220: goto back;
! 2221: }
! 2222:
! 2223: M_DUP_PKTHDR(mnew, m);
! 2224: if (m->m_pkthdr.len > MHLEN) {
! 2225: MCLGET(mnew, M_DONTWAIT);
! 2226: if (!(mnew->m_flags & M_EXT)) {
! 2227: m_freem(m);
! 2228: m_freem(mnew);
! 2229: error = ENOBUFS;
! 2230: }
! 2231: }
! 2232:
! 2233: if (error) {
! 2234: printf("%s: can't defrag tx mbuf\n", ifp->if_xname);
! 2235: goto back;
! 2236: }
! 2237:
! 2238: m_copydata(m, 0, m->m_pkthdr.len, mtod(mnew, caddr_t));
! 2239: m_freem(m);
! 2240: mnew->m_len = mnew->m_pkthdr.len;
! 2241: m = mnew;
! 2242:
! 2243: error = bus_dmamap_load_mbuf(sc->sc_dmat,
! 2244: txbuf->tb_mbuf_dmamap, m, BUS_DMA_NOWAIT);
! 2245: if (error) {
! 2246: printf("%s: can't map tx mbuf2 %d\n",
! 2247: sc->sc_dev.dv_xname, error);
! 2248: goto back;
! 2249: }
! 2250: }
! 2251:
! 2252: error = 0;
! 2253:
! 2254: bus_dmamap_sync(sc->sc_dmat, txbuf->tb_mbuf_dmamap, 0,
! 2255: txbuf->tb_mbuf_dmamap->dm_mapsize, BUS_DMASYNC_PREWRITE);
! 2256:
! 2257: txbuf->tb_mbuf = m;
! 2258: txbuf->tb_node = node;
! 2259: txbuf->tb_rate = rate;
! 2260:
! 2261: /*
! 2262: * TX buffers are accessed in following way:
! 2263: * acx_fw_txdesc -> acx_host_desc -> buffer
! 2264: *
! 2265: * It is quite strange that acx also queries acx_host_desc next to
! 2266: * the one we have assigned to acx_fw_txdesc even if first one's
! 2267: * acx_host_desc.h_data_len == acx_fw_txdesc.f_tx_len
! 2268: *
! 2269: * So we allocate two acx_host_desc for one acx_fw_txdesc and
! 2270: * assign the first acx_host_desc to acx_fw_txdesc
! 2271: *
! 2272: * For acx111
! 2273: * host_desc1.h_data_len = buffer_len
! 2274: * host_desc2.h_data_len = buffer_len - mac_header_len
! 2275: *
! 2276: * For acx100
! 2277: * host_desc1.h_data_len = mac_header_len
! 2278: * host_desc2.h_data_len = buffer_len - mac_header_len
! 2279: */
! 2280: paddr = txbuf->tb_mbuf_dmamap->dm_segs[0].ds_addr;
! 2281: txbuf->tb_desc1->h_data_paddr = htole32(paddr);
! 2282: txbuf->tb_desc2->h_data_paddr = htole32(paddr + ACX_FRAME_HDRLEN);
! 2283:
! 2284: txbuf->tb_desc1->h_data_len =
! 2285: htole16(sc->chip_txdesc1_len ? sc->chip_txdesc1_len
! 2286: : m->m_pkthdr.len);
! 2287: txbuf->tb_desc2->h_data_len =
! 2288: htole16(m->m_pkthdr.len - ACX_FRAME_HDRLEN);
! 2289:
! 2290: /*
! 2291: * NOTE:
! 2292: * We can't simply assign f_tx_ctrl, we will first read it back
! 2293: * and change it bit by bit
! 2294: */
! 2295: ctrl = FW_TXDESC_GETFIELD_1(sc, txbuf, f_tx_ctrl);
! 2296: ctrl |= sc->chip_fw_txdesc_ctrl; /* extra chip specific flags */
! 2297: ctrl &= ~(DESC_CTRL_HOSTOWN | DESC_CTRL_ACXDONE);
! 2298:
! 2299: FW_TXDESC_SETFIELD_2(sc, txbuf, f_tx_len, m->m_pkthdr.len);
! 2300: FW_TXDESC_SETFIELD_1(sc, txbuf, f_tx_error, 0);
! 2301: FW_TXDESC_SETFIELD_1(sc, txbuf, f_tx_ack_fail, 0);
! 2302: FW_TXDESC_SETFIELD_1(sc, txbuf, f_tx_rts_fail, 0);
! 2303: FW_TXDESC_SETFIELD_1(sc, txbuf, f_tx_rts_ok, 0);
! 2304: sc->chip_set_fw_txdesc_rate(sc, txbuf, rate);
! 2305:
! 2306: txbuf->tb_desc1->h_ctrl = 0;
! 2307: txbuf->tb_desc2->h_ctrl = 0;
! 2308: bus_dmamap_sync(sc->sc_dmat, rd->tx_ring_dmamap, 0,
! 2309: rd->tx_ring_dmamap->dm_mapsize, BUS_DMASYNC_PREWRITE);
! 2310:
! 2311: FW_TXDESC_SETFIELD_1(sc, txbuf, f_tx_ctrl2, 0);
! 2312: FW_TXDESC_SETFIELD_1(sc, txbuf, f_tx_ctrl, ctrl);
! 2313:
! 2314: /* Tell chip to inform us about TX completion */
! 2315: CSR_WRITE_2(sc, ACXREG_INTR_TRIG, ACXRV_TRIG_TX_FINI);
! 2316: back:
! 2317: if (error)
! 2318: m_freem(m);
! 2319:
! 2320: return (error);
! 2321: }
! 2322:
! 2323: int
! 2324: acx_set_null_tmplt(struct acx_softc *sc)
! 2325: {
! 2326: struct ieee80211com *ic = &sc->sc_ic;
! 2327: struct acx_tmplt_null_data n;
! 2328: struct ieee80211_frame *wh;
! 2329:
! 2330: bzero(&n, sizeof(n));
! 2331:
! 2332: wh = &n.data;
! 2333: wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA |
! 2334: IEEE80211_FC0_SUBTYPE_NODATA;
! 2335: wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
! 2336: IEEE80211_ADDR_COPY(wh->i_addr1, etherbroadcastaddr);
! 2337: IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr);
! 2338: IEEE80211_ADDR_COPY(wh->i_addr3, etherbroadcastaddr);
! 2339:
! 2340: return (acx_set_tmplt(sc, ACXCMD_TMPLT_NULL_DATA, &n, sizeof(n)));
! 2341: }
! 2342:
! 2343: int
! 2344: acx_set_probe_req_tmplt(struct acx_softc *sc, const char *ssid, int ssid_len)
! 2345: {
! 2346: struct ieee80211com *ic = &sc->sc_ic;
! 2347: struct acx_tmplt_probe_req req;
! 2348: struct ieee80211_frame *wh;
! 2349: uint8_t *frm;
! 2350: int len;
! 2351:
! 2352: bzero(&req, sizeof(req));
! 2353:
! 2354: wh = &req.data.u_data.f;
! 2355: wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
! 2356: IEEE80211_FC0_SUBTYPE_PROBE_REQ;
! 2357: wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
! 2358: IEEE80211_ADDR_COPY(wh->i_addr1, etherbroadcastaddr);
! 2359: IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr);
! 2360: IEEE80211_ADDR_COPY(wh->i_addr3, etherbroadcastaddr);
! 2361:
! 2362: frm = req.data.u_data.var;
! 2363: frm = ieee80211_add_ssid(frm, ssid, ssid_len);
! 2364: frm = ieee80211_add_rates(frm, &ic->ic_sup_rates[sc->chip_phymode]);
! 2365: frm = ieee80211_add_xrates(frm, &ic->ic_sup_rates[sc->chip_phymode]);
! 2366: len = frm - req.data.u_data.var;
! 2367:
! 2368: return (acx_set_tmplt(sc, ACXCMD_TMPLT_PROBE_REQ, &req,
! 2369: ACX_TMPLT_PROBE_REQ_SIZ(len)));
! 2370: }
! 2371:
! 2372: struct mbuf *ieee80211_get_probe_resp(struct ieee80211com *,
! 2373: struct ieee80211_node *);
! 2374:
! 2375: int
! 2376: acx_set_probe_resp_tmplt(struct acx_softc *sc, struct ieee80211_node *ni)
! 2377: {
! 2378: struct ieee80211com *ic = &sc->sc_ic;
! 2379: struct acx_tmplt_probe_resp resp;
! 2380: struct ieee80211_frame *wh;
! 2381: struct mbuf *m;
! 2382: int len;
! 2383:
! 2384: bzero(&resp, sizeof(resp));
! 2385:
! 2386: m = ieee80211_get_probe_resp(ic, ni);
! 2387: if (m == NULL)
! 2388: return (1);
! 2389: M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT);
! 2390: if (m == NULL)
! 2391: return (1);
! 2392: wh = mtod(m, struct ieee80211_frame *);
! 2393: wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
! 2394: IEEE80211_FC0_SUBTYPE_PROBE_RESP;
! 2395: wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
! 2396: *(u_int16_t *)&wh->i_dur[0] = 0;
! 2397: IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr);
! 2398: IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr);
! 2399: IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid);
! 2400: *(u_int16_t *)wh->i_seq = 0;
! 2401:
! 2402: m_copydata(m, 0, m->m_pkthdr.len, (caddr_t)&resp.data);
! 2403: len = m->m_pkthdr.len + sizeof(resp.size);
! 2404: m_freem(m);
! 2405:
! 2406: return (acx_set_tmplt(sc, ACXCMD_TMPLT_PROBE_RESP, &resp, len));
! 2407: }
! 2408:
! 2409: int
! 2410: acx_beacon_locate(struct mbuf *m, u_int8_t type)
! 2411: {
! 2412: int off;
! 2413: u_int8_t *frm;
! 2414: /*
! 2415: * beacon frame format
! 2416: * [8] time stamp
! 2417: * [2] beacon interval
! 2418: * [2] cabability information
! 2419: * from here on [tlv] values
! 2420: */
! 2421:
! 2422: if (m->m_len != m->m_pkthdr.len)
! 2423: panic("beacon not in contiguous mbuf");
! 2424:
! 2425: off = sizeof(struct ieee80211_frame) + 8 + 2 + 2;
! 2426: frm = mtod(m, u_int8_t *);
! 2427: for (; off + 1 < m->m_len; off += frm[off + 1] + 2) {
! 2428: if (frm[off] == type)
! 2429: return (off);
! 2430: }
! 2431: /* type not found */
! 2432: return (m->m_len);
! 2433: }
! 2434:
! 2435: int
! 2436: acx_set_beacon_tmplt(struct acx_softc *sc, struct ieee80211_node *ni)
! 2437: {
! 2438: struct ieee80211com *ic = &sc->sc_ic;
! 2439: struct acx_tmplt_beacon beacon;
! 2440: struct acx_tmplt_tim tim;
! 2441: struct mbuf *m;
! 2442: int len, off;
! 2443:
! 2444: bzero(&beacon, sizeof(beacon));
! 2445: bzero(&tim, sizeof(tim));
! 2446:
! 2447: m = ieee80211_beacon_alloc(ic, ni);
! 2448: if (m == NULL)
! 2449: return (1);
! 2450:
! 2451: off = acx_beacon_locate(m, IEEE80211_ELEMID_TIM);
! 2452:
! 2453: m_copydata(m, 0, off, (caddr_t)&beacon.data);
! 2454: len = off + sizeof(beacon.size);
! 2455:
! 2456: if (acx_set_tmplt(sc, ACXCMD_TMPLT_BEACON, &beacon, len) != 0) {
! 2457: m_freem(m);
! 2458: return (1);
! 2459: }
! 2460:
! 2461: len = m->m_pkthdr.len - off;
! 2462: if (len == 0) {
! 2463: /* no TIM field */
! 2464: m_freem(m);
! 2465: return (0);
! 2466: }
! 2467:
! 2468: m_copydata(m, off, len, (caddr_t)&tim.data);
! 2469: len += sizeof(beacon.size);
! 2470: m_freem(m);
! 2471:
! 2472: return (acx_set_tmplt(sc, ACXCMD_TMPLT_TIM, &tim, len));
! 2473: }
! 2474:
! 2475: void
! 2476: acx_init_cmd_reg(struct acx_softc *sc)
! 2477: {
! 2478: sc->sc_cmd = CSR_READ_4(sc, ACXREG_CMD_REG_OFFSET);
! 2479: sc->sc_cmd_param = sc->sc_cmd + ACX_CMD_REG_SIZE;
! 2480:
! 2481: /* Clear command & status */
! 2482: CMD_WRITE_4(sc, 0);
! 2483: }
! 2484:
! 2485: int
! 2486: acx_join_bss(struct acx_softc *sc, uint8_t mode, struct ieee80211_node *node)
! 2487: {
! 2488: uint8_t bj_buf[BSS_JOIN_BUFLEN];
! 2489: struct bss_join_hdr *bj;
! 2490: int i, dtim_intvl;
! 2491:
! 2492: bzero(bj_buf, sizeof(bj_buf));
! 2493: bj = (struct bss_join_hdr *)bj_buf;
! 2494:
! 2495: for (i = 0; i < IEEE80211_ADDR_LEN; ++i)
! 2496: bj->bssid[i] = node->ni_bssid[IEEE80211_ADDR_LEN - i - 1];
! 2497:
! 2498: bj->beacon_intvl = htole16(acx_beacon_intvl);
! 2499:
! 2500: /* TODO tunable */
! 2501: dtim_intvl = sc->sc_ic.ic_opmode == IEEE80211_M_IBSS ? 1 : 10;
! 2502: sc->chip_set_bss_join_param(sc, bj->chip_spec, dtim_intvl);
! 2503:
! 2504: bj->ndata_txrate = ACX_NDATA_TXRATE_2;
! 2505: bj->ndata_txopt = 0;
! 2506: bj->mode = mode;
! 2507: bj->channel = ieee80211_chan2ieee(&sc->sc_ic, node->ni_chan);
! 2508: bj->esslen = node->ni_esslen;
! 2509: bcopy(node->ni_essid, bj->essid, node->ni_esslen);
! 2510:
! 2511: DPRINTF(("%s: join BSS/IBSS on channel %d\n", sc->sc_dev.dv_xname,
! 2512: bj->channel));
! 2513: return (acx_exec_command(sc, ACXCMD_JOIN_BSS,
! 2514: bj, BSS_JOIN_PARAM_SIZE(bj), NULL, 0));
! 2515: }
! 2516:
! 2517: int
! 2518: acx_set_channel(struct acx_softc *sc, uint8_t chan)
! 2519: {
! 2520: if (acx_exec_command(sc, ACXCMD_ENABLE_TXCHAN, &chan, sizeof(chan),
! 2521: NULL, 0) != 0) {
! 2522: DPRINTF(("%s: setting TX channel %d failed\n",
! 2523: sc->sc_dev.dv_xname, chan));
! 2524: return (ENXIO);
! 2525: }
! 2526:
! 2527: if (acx_exec_command(sc, ACXCMD_ENABLE_RXCHAN, &chan, sizeof(chan),
! 2528: NULL, 0) != 0) {
! 2529: DPRINTF(("%s: setting RX channel %d failed\n",
! 2530: sc->sc_dev.dv_xname, chan));
! 2531: return (ENXIO);
! 2532: }
! 2533:
! 2534: return (0);
! 2535: }
! 2536:
! 2537: int
! 2538: acx_get_conf(struct acx_softc *sc, uint16_t conf_id, void *conf,
! 2539: uint16_t conf_len)
! 2540: {
! 2541: struct acx_conf *confcom;
! 2542:
! 2543: if (conf_len < sizeof(*confcom)) {
! 2544: printf("%s: %s configure data is too short\n",
! 2545: sc->sc_dev.dv_xname, __func__);
! 2546: return (1);
! 2547: }
! 2548:
! 2549: confcom = conf;
! 2550: confcom->conf_id = htole16(conf_id);
! 2551: confcom->conf_data_len = htole16(conf_len - sizeof(*confcom));
! 2552:
! 2553: return (acx_exec_command(sc, ACXCMD_GET_CONF, confcom, sizeof(*confcom),
! 2554: conf, conf_len));
! 2555: }
! 2556:
! 2557: int
! 2558: acx_set_conf(struct acx_softc *sc, uint16_t conf_id, void *conf,
! 2559: uint16_t conf_len)
! 2560: {
! 2561: struct acx_conf *confcom;
! 2562:
! 2563: if (conf_len < sizeof(*confcom)) {
! 2564: printf("%s: %s configure data is too short\n",
! 2565: sc->sc_dev.dv_xname, __func__);
! 2566: return (1);
! 2567: }
! 2568:
! 2569: confcom = conf;
! 2570: confcom->conf_id = htole16(conf_id);
! 2571: confcom->conf_data_len = htole16(conf_len - sizeof(*confcom));
! 2572:
! 2573: return (acx_exec_command(sc, ACXCMD_SET_CONF, conf, conf_len, NULL, 0));
! 2574: }
! 2575:
! 2576: int
! 2577: acx_set_tmplt(struct acx_softc *sc, uint16_t cmd, void *tmplt,
! 2578: uint16_t tmplt_len)
! 2579: {
! 2580: uint16_t *size;
! 2581:
! 2582: if (tmplt_len < sizeof(*size)) {
! 2583: printf("%s: %s template is too short\n",
! 2584: sc->sc_dev.dv_xname, __func__);
! 2585: return (1);
! 2586: }
! 2587:
! 2588: size = tmplt;
! 2589: *size = htole16(tmplt_len - sizeof(*size));
! 2590:
! 2591: return (acx_exec_command(sc, cmd, tmplt, tmplt_len, NULL, 0));
! 2592: }
! 2593:
! 2594: int
! 2595: acx_init_radio(struct acx_softc *sc, uint32_t radio_ofs, uint32_t radio_len)
! 2596: {
! 2597: struct radio_init r;
! 2598:
! 2599: r.radio_ofs = htole32(radio_ofs);
! 2600: r.radio_len = htole32(radio_len);
! 2601:
! 2602: return (acx_exec_command(sc, ACXCMD_INIT_RADIO, &r, sizeof(r), NULL,
! 2603: 0));
! 2604: }
! 2605:
! 2606: int
! 2607: acx_exec_command(struct acx_softc *sc, uint16_t cmd, void *param,
! 2608: uint16_t param_len, void *result, uint16_t result_len)
! 2609: {
! 2610: uint16_t status;
! 2611: int i, ret;
! 2612:
! 2613: if ((sc->sc_flags & ACX_FLAG_FW_LOADED) == 0) {
! 2614: printf("%s: cmd 0x%04x failed (base firmware not loaded)\n",
! 2615: sc->sc_dev.dv_xname, cmd);
! 2616: return (1);
! 2617: }
! 2618:
! 2619: ret = 0;
! 2620:
! 2621: if (param != NULL && param_len != 0) {
! 2622: /* Set command param */
! 2623: CMDPRM_WRITE_REGION_1(sc, param, param_len);
! 2624: }
! 2625:
! 2626: /* Set command */
! 2627: CMD_WRITE_4(sc, cmd);
! 2628:
! 2629: /* Exec command */
! 2630: CSR_WRITE_2(sc, ACXREG_INTR_TRIG, ACXRV_TRIG_CMD_FINI);
! 2631: DELAY(50);
! 2632:
! 2633: /* Wait for command to complete */
! 2634: if (cmd == ACXCMD_INIT_RADIO) {
! 2635: /* radio initialization is extremely long */
! 2636: tsleep(&cmd, 0, "rdinit", (300 * hz) / 1000); /* 300ms */
! 2637: }
! 2638:
! 2639: #define CMDWAIT_RETRY_MAX 1000
! 2640: for (i = 0; i < CMDWAIT_RETRY_MAX; ++i) {
! 2641: uint16_t reg;
! 2642:
! 2643: reg = CSR_READ_2(sc, ACXREG_INTR_STATUS);
! 2644: if (reg & ACXRV_INTR_CMD_FINI) {
! 2645: CSR_WRITE_2(sc, ACXREG_INTR_ACK, ACXRV_INTR_CMD_FINI);
! 2646: break;
! 2647: }
! 2648: DELAY(50);
! 2649: }
! 2650: if (i == CMDWAIT_RETRY_MAX) {
! 2651: printf("%s: cmd %04x failed (timeout)\n",
! 2652: sc->sc_dev.dv_xname, cmd);
! 2653: ret = 1;
! 2654: goto back;
! 2655: }
! 2656: #undef CMDWAIT_RETRY_MAX
! 2657:
! 2658: /* Get command exec status */
! 2659: status = (CMD_READ_4(sc) >> ACX_CMD_STATUS_SHIFT);
! 2660: if (status != ACX_CMD_STATUS_OK) {
! 2661: DPRINTF(("%s: cmd %04x failed\n", sc->sc_dev.dv_xname, cmd));
! 2662: ret = 1;
! 2663: goto back;
! 2664: }
! 2665:
! 2666: if (result != NULL && result_len != 0) {
! 2667: /* Get command result */
! 2668: CMDPRM_READ_REGION_1(sc, result, result_len);
! 2669: }
! 2670:
! 2671: back:
! 2672: CMD_WRITE_4(sc, 0);
! 2673:
! 2674: return (ret);
! 2675: }
! 2676:
! 2677: const char *
! 2678: acx_get_rf(int rev)
! 2679: {
! 2680: switch (rev) {
! 2681: case ACX_RADIO_TYPE_MAXIM: return "MAX2820";
! 2682: case ACX_RADIO_TYPE_RFMD: return "RFMD";
! 2683: case ACX_RADIO_TYPE_RALINK: return "Ralink";
! 2684: case ACX_RADIO_TYPE_RADIA: return "Radia";
! 2685: default: return "unknown";
! 2686: }
! 2687: }
! 2688:
! 2689: int
! 2690: acx_get_maxrssi(int radio)
! 2691: {
! 2692: switch (radio) {
! 2693: case ACX_RADIO_TYPE_MAXIM: return ACX_RADIO_RSSI_MAXIM;
! 2694: case ACX_RADIO_TYPE_RFMD: return ACX_RADIO_RSSI_RFMD;
! 2695: case ACX_RADIO_TYPE_RALINK: return ACX_RADIO_RSSI_RALINK;
! 2696: case ACX_RADIO_TYPE_RADIA: return ACX_RADIO_RSSI_RADIA;
! 2697: default: return ACX_RADIO_RSSI_UNKN;
! 2698: }
! 2699: }
! 2700:
! 2701: void
! 2702: acx_iter_func(void *arg, struct ieee80211_node *ni)
! 2703: {
! 2704: struct acx_softc *sc = arg;
! 2705: struct acx_node *wn = (struct acx_node *)ni;
! 2706:
! 2707: ieee80211_amrr_choose(&sc->amrr, ni, &wn->amn);
! 2708: }
! 2709:
! 2710: void
! 2711: acx_amrr_timeout(void *arg)
! 2712: {
! 2713: struct acx_softc *sc = arg;
! 2714: struct ieee80211com *ic = &sc->sc_ic;
! 2715:
! 2716: if (ic->ic_opmode == IEEE80211_M_STA)
! 2717: acx_iter_func(sc, ic->ic_bss);
! 2718: else
! 2719: ieee80211_iterate_nodes(ic, acx_iter_func, sc);
! 2720:
! 2721: timeout_add(&sc->amrr_ch, hz / 2);
! 2722: }
! 2723:
! 2724: void
! 2725: acx_newassoc(struct ieee80211com *ic, struct ieee80211_node *ni, int isnew)
! 2726: {
! 2727: struct acx_softc *sc = ic->ic_if.if_softc;
! 2728: int i;
! 2729:
! 2730: ieee80211_amrr_node_init(&sc->amrr, &((struct acx_node *)ni)->amn);
! 2731:
! 2732: /* set rate to some reasonable initial value */
! 2733: for (i = ni->ni_rates.rs_nrates - 1;
! 2734: i > 0 && (ni->ni_rates.rs_rates[i] & IEEE80211_RATE_VAL) > 72;
! 2735: i--);
! 2736: ni->ni_txrate = i;
! 2737: }
CVSweb