if_an.c revision 199154
1139749Simp/*- 255992Swpaul * Copyright (c) 1997, 1998, 1999 355992Swpaul * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 455992Swpaul * 555992Swpaul * Redistribution and use in source and binary forms, with or without 655992Swpaul * modification, are permitted provided that the following conditions 755992Swpaul * are met: 855992Swpaul * 1. Redistributions of source code must retain the above copyright 955992Swpaul * notice, this list of conditions and the following disclaimer. 1055992Swpaul * 2. Redistributions in binary form must reproduce the above copyright 1155992Swpaul * notice, this list of conditions and the following disclaimer in the 1255992Swpaul * documentation and/or other materials provided with the distribution. 1355992Swpaul * 3. All advertising materials mentioning features or use of this software 1455992Swpaul * must display the following acknowledgement: 1555992Swpaul * This product includes software developed by Bill Paul. 1655992Swpaul * 4. Neither the name of the author nor the names of any co-contributors 1755992Swpaul * may be used to endorse or promote products derived from this software 1855992Swpaul * without specific prior written permission. 1955992Swpaul * 2055992Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 2155992Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2255992Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2355992Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 2455992Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2555992Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2655992Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2755992Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2855992Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2955992Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 3055992Swpaul * THE POSSIBILITY OF SUCH DAMAGE. 3155992Swpaul */ 3255992Swpaul/* 3355992Swpaul * Aironet 4500/4800 802.11 PCMCIA/ISA/PCI driver for FreeBSD. 3455992Swpaul * 3555992Swpaul * Written by Bill Paul <wpaul@ctr.columbia.edu> 3655992Swpaul * Electrical Engineering Department 3755992Swpaul * Columbia University, New York City 3855992Swpaul */ 3955992Swpaul 40119418Sobrien#include <sys/cdefs.h> 41119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/an/if_an.c 199154 2009-11-10 22:04:19Z jhb $"); 42119418Sobrien 4355992Swpaul/* 4486259Sphk * The Aironet 4500/4800 series cards come in PCMCIA, ISA and PCI form. 4555992Swpaul * This driver supports all three device types (PCI devices are supported 46100770Sfenner * through an extra PCI shim: /sys/dev/an/if_an_pci.c). ISA devices can be 4755992Swpaul * supported either using hard-coded IO port/IRQ settings or via Plug 4855992Swpaul * and Play. The 4500 series devices support 1Mbps and 2Mbps data rates. 4955992Swpaul * The 4800 devices support 1, 2, 5.5 and 11Mbps rates. 5055992Swpaul * 5155992Swpaul * Like the WaveLAN/IEEE cards, the Aironet NICs are all essentially 5255992Swpaul * PCMCIA devices. The ISA and PCI cards are a combination of a PCMCIA 5355992Swpaul * device and a PCMCIA to ISA or PCMCIA to PCI adapter card. There are 5455992Swpaul * a couple of important differences though: 5555992Swpaul * 5655992Swpaul * - Lucent ISA card looks to the host like a PCMCIA controller with 5755992Swpaul * a PCMCIA WaveLAN card inserted. This means that even desktop 5855992Swpaul * machines need to be configured with PCMCIA support in order to 5955992Swpaul * use WaveLAN/IEEE ISA cards. The Aironet cards on the other hand 6055992Swpaul * actually look like normal ISA and PCI devices to the host, so 6155992Swpaul * no PCMCIA controller support is needed 6255992Swpaul * 6355992Swpaul * The latter point results in a small gotcha. The Aironet PCMCIA 6455992Swpaul * cards can be configured for one of two operating modes depending 6555992Swpaul * on how the Vpp1 and Vpp2 programming voltages are set when the 6655992Swpaul * card is activated. In order to put the card in proper PCMCIA 6755992Swpaul * operation (where the CIS table is visible and the interface is 6855992Swpaul * programmed for PCMCIA operation), both Vpp1 and Vpp2 have to be 6955992Swpaul * set to 5 volts. FreeBSD by default doesn't set the Vpp voltages, 7055992Swpaul * which leaves the card in ISA/PCI mode, which prevents it from 7186381Simp * being activated as an PCMCIA device. 7255992Swpaul * 7355992Swpaul * Note that some PCMCIA controller software packages for Windows NT 7455992Swpaul * fail to set the voltages as well. 7583270Sbrooks * 7655992Swpaul * The Aironet devices can operate in both station mode and access point 7755992Swpaul * mode. Typically, when programmed for station mode, the card can be set 7855992Swpaul * to automatically perform encapsulation/decapsulation of Ethernet II 7955992Swpaul * and 802.3 frames within 802.11 frames so that the host doesn't have 8055992Swpaul * to do it itself. This driver doesn't program the card that way: the 8155992Swpaul * driver handles all of the encapsulation/decapsulation itself. 8255992Swpaul */ 8355992Swpaul 8455992Swpaul#include "opt_inet.h" 8555992Swpaul 8655992Swpaul#ifdef INET 8755992Swpaul#define ANCACHE /* enable signal strength cache */ 8855992Swpaul#endif 8955992Swpaul 9055992Swpaul#include <sys/param.h> 91154866Snjl#include <sys/ctype.h> 9255992Swpaul#include <sys/systm.h> 9355992Swpaul#include <sys/sockio.h> 9455992Swpaul#include <sys/mbuf.h> 95164033Srwatson#include <sys/priv.h> 9683366Sjulian#include <sys/proc.h> 9755992Swpaul#include <sys/kernel.h> 9855992Swpaul#include <sys/socket.h> 9955992Swpaul#ifdef ANCACHE 10055992Swpaul#include <sys/syslog.h> 101108401Sambrisko#endif 10255992Swpaul#include <sys/sysctl.h> 10355992Swpaul 10455992Swpaul#include <sys/module.h> 10583269Sbrooks#include <sys/sysctl.h> 10655992Swpaul#include <sys/bus.h> 10755992Swpaul#include <machine/bus.h> 10855992Swpaul#include <sys/rman.h> 10984811Sjhb#include <sys/lock.h> 11067365Sjhb#include <sys/mutex.h> 11155992Swpaul#include <machine/resource.h> 112108401Sambrisko#include <sys/malloc.h> 11355992Swpaul 11455992Swpaul#include <net/if.h> 11555992Swpaul#include <net/if_arp.h> 116152315Sru#include <net/if_dl.h> 11755992Swpaul#include <net/ethernet.h> 11855992Swpaul#include <net/if_types.h> 11977217Sphk#include <net/if_media.h> 12055992Swpaul 121116951Ssam#include <net80211/ieee80211_var.h> 122116951Ssam#include <net80211/ieee80211_ioctl.h> 123116951Ssam 12455992Swpaul#ifdef INET 12555992Swpaul#include <netinet/in.h> 12655992Swpaul#include <netinet/in_systm.h> 12755992Swpaul#include <netinet/in_var.h> 12855992Swpaul#include <netinet/ip.h> 12955992Swpaul#endif 13055992Swpaul 13155992Swpaul#include <net/bpf.h> 13255992Swpaul 13355992Swpaul#include <machine/md_var.h> 13455992Swpaul 13555992Swpaul#include <dev/an/if_aironet_ieee.h> 13655992Swpaul#include <dev/an/if_anreg.h> 13755992Swpaul 13855992Swpaul/* These are global because we need them in sys/pci/if_an_p.c. */ 139150446Simpstatic void an_reset(struct an_softc *); 140150446Simpstatic int an_init_mpi350_desc(struct an_softc *); 141150446Simpstatic int an_ioctl(struct ifnet *, u_long, caddr_t); 142150446Simpstatic void an_init(void *); 143199154Sjhbstatic void an_init_locked(struct an_softc *); 144150446Simpstatic int an_init_tx_ring(struct an_softc *); 145150446Simpstatic void an_start(struct ifnet *); 146199154Sjhbstatic void an_start_locked(struct ifnet *); 147199154Sjhbstatic void an_watchdog(struct an_softc *); 148150446Simpstatic void an_rxeof(struct an_softc *); 149150446Simpstatic void an_txeof(struct an_softc *, int); 15055992Swpaul 151150446Simpstatic void an_promisc(struct an_softc *, int); 152150446Simpstatic int an_cmd(struct an_softc *, int, int); 153150446Simpstatic int an_cmd_struct(struct an_softc *, struct an_command *, 154150446Simp struct an_reply *); 155150446Simpstatic int an_read_record(struct an_softc *, struct an_ltv_gen *); 156150446Simpstatic int an_write_record(struct an_softc *, struct an_ltv_gen *); 157150446Simpstatic int an_read_data(struct an_softc *, int, int, caddr_t, int); 158150446Simpstatic int an_write_data(struct an_softc *, int, int, caddr_t, int); 159150446Simpstatic int an_seek(struct an_softc *, int, int, int); 160150446Simpstatic int an_alloc_nicmem(struct an_softc *, int, int *); 161150446Simpstatic int an_dma_malloc(struct an_softc *, bus_size_t, struct an_dma_alloc *, 162150446Simp int); 163150446Simpstatic void an_dma_free(struct an_softc *, struct an_dma_alloc *); 164150446Simpstatic void an_dma_malloc_cb(void *, bus_dma_segment_t *, int, int); 165150446Simpstatic void an_stats_update(void *); 166150446Simpstatic void an_setdef(struct an_softc *, struct an_req *); 16755992Swpaul#ifdef ANCACHE 168150446Simpstatic void an_cache_store(struct an_softc *, struct ether_header *, 169150446Simp struct mbuf *, u_int8_t, u_int8_t); 17055992Swpaul#endif 17155992Swpaul 17288748Sambrisko/* function definitions for use with the Cisco's Linux configuration 17388748Sambrisko utilities 17488748Sambrisko*/ 17588748Sambrisko 17692739Salfredstatic int readrids(struct ifnet*, struct aironet_ioctl*); 17792739Salfredstatic int writerids(struct ifnet*, struct aironet_ioctl*); 17892739Salfredstatic int flashcard(struct ifnet*, struct aironet_ioctl*); 17988748Sambrisko 18092739Salfredstatic int cmdreset(struct ifnet *); 18192739Salfredstatic int setflashmode(struct ifnet *); 18292739Salfredstatic int flashgchar(struct ifnet *,int,int); 18392739Salfredstatic int flashpchar(struct ifnet *,int,int); 18492739Salfredstatic int flashputbuf(struct ifnet *); 18592739Salfredstatic int flashrestart(struct ifnet *); 18692739Salfredstatic int WaitBusy(struct ifnet *, int); 18792739Salfredstatic int unstickbusy(struct ifnet *); 18888748Sambrisko 18992739Salfredstatic void an_dump_record (struct an_softc *,struct an_ltv_gen *, 19092739Salfred char *); 19178639Sbrooks 19292739Salfredstatic int an_media_change (struct ifnet *); 19392739Salfredstatic void an_media_status (struct ifnet *, struct ifmediareq *); 19477217Sphk 19578639Sbrooksstatic int an_dump = 0; 196108401Sambriskostatic int an_cache_mode = 0; 19788748Sambrisko 198108401Sambrisko#define DBM 0 199108401Sambrisko#define PERCENT 1 200108401Sambrisko#define RAW 2 201108401Sambrisko 20283269Sbrooksstatic char an_conf[256]; 203108401Sambriskostatic char an_conf_cache[256]; 20483269Sbrooks 20583269Sbrooks/* sysctl vars */ 206108401Sambrisko 207110531SambriskoSYSCTL_NODE(_hw, OID_AUTO, an, CTLFLAG_RD, 0, "Wireless driver parameters"); 20883269Sbrooks 209106937Ssam/* XXX violate ethernet/netgraph callback hooks */ 210106937Ssamextern void (*ng_ether_attach_p)(struct ifnet *ifp); 211106937Ssamextern void (*ng_ether_detach_p)(struct ifnet *ifp); 212106937Ssam 21383269Sbrooksstatic int 21483269Sbrookssysctl_an_dump(SYSCTL_HANDLER_ARGS) 21583269Sbrooks{ 21683269Sbrooks int error, r, last; 21783269Sbrooks char *s = an_conf; 21883270Sbrooks 21983269Sbrooks last = an_dump; 22083269Sbrooks 22183270Sbrooks switch (an_dump) { 22283269Sbrooks case 0: 223108401Sambrisko strcpy(an_conf, "off"); 22483269Sbrooks break; 22583269Sbrooks case 1: 226108401Sambrisko strcpy(an_conf, "type"); 22783269Sbrooks break; 22883269Sbrooks case 2: 229108401Sambrisko strcpy(an_conf, "dump"); 23083269Sbrooks break; 23183269Sbrooks default: 23283269Sbrooks snprintf(an_conf, 5, "%x", an_dump); 23383269Sbrooks break; 23483269Sbrooks } 23583269Sbrooks 23683269Sbrooks error = sysctl_handle_string(oidp, an_conf, sizeof(an_conf), req); 23783269Sbrooks 238108401Sambrisko if (strncmp(an_conf,"off", 3) == 0) { 23983269Sbrooks an_dump = 0; 24083269Sbrooks } 24183270Sbrooks if (strncmp(an_conf,"dump", 4) == 0) { 24283269Sbrooks an_dump = 1; 24383269Sbrooks } 24483270Sbrooks if (strncmp(an_conf,"type", 4) == 0) { 24583269Sbrooks an_dump = 2; 24683269Sbrooks } 24783270Sbrooks if (*s == 'f') { 24883269Sbrooks r = 0; 24983270Sbrooks for (;;s++) { 25083270Sbrooks if ((*s >= '0') && (*s <= '9')) { 25183269Sbrooks r = r * 16 + (*s - '0'); 25283270Sbrooks } else if ((*s >= 'a') && (*s <= 'f')) { 25383269Sbrooks r = r * 16 + (*s - 'a' + 10); 25483270Sbrooks } else { 25583270Sbrooks break; 25683269Sbrooks } 25783269Sbrooks } 25883269Sbrooks an_dump = r; 25983269Sbrooks } 26083269Sbrooks if (an_dump != last) 26183269Sbrooks printf("Sysctl changed for Aironet driver\n"); 26283269Sbrooks 26383269Sbrooks return error; 26483269Sbrooks} 26583269Sbrooks 266110531SambriskoSYSCTL_PROC(_hw_an, OID_AUTO, an_dump, CTLTYPE_STRING | CTLFLAG_RW, 267175446Sambrisko 0, sizeof(an_conf), sysctl_an_dump, "A", ""); 26883269Sbrooks 269108401Sambriskostatic int 270108401Sambriskosysctl_an_cache_mode(SYSCTL_HANDLER_ARGS) 271108401Sambrisko{ 272108401Sambrisko int error, last; 273108401Sambrisko 274108401Sambrisko last = an_cache_mode; 275108401Sambrisko 276108401Sambrisko switch (an_cache_mode) { 277108401Sambrisko case 1: 278108401Sambrisko strcpy(an_conf_cache, "per"); 279108401Sambrisko break; 280108401Sambrisko case 2: 281108401Sambrisko strcpy(an_conf_cache, "raw"); 282108401Sambrisko break; 283108401Sambrisko default: 284108401Sambrisko strcpy(an_conf_cache, "dbm"); 285108401Sambrisko break; 286108401Sambrisko } 287108401Sambrisko 288175445Sambrisko error = sysctl_handle_string(oidp, an_conf_cache, 289108401Sambrisko sizeof(an_conf_cache), req); 290108401Sambrisko 291108401Sambrisko if (strncmp(an_conf_cache,"dbm", 3) == 0) { 292108401Sambrisko an_cache_mode = 0; 293108401Sambrisko } 294108401Sambrisko if (strncmp(an_conf_cache,"per", 3) == 0) { 295108401Sambrisko an_cache_mode = 1; 296108401Sambrisko } 297108401Sambrisko if (strncmp(an_conf_cache,"raw", 3) == 0) { 298108401Sambrisko an_cache_mode = 2; 299108401Sambrisko } 300108401Sambrisko 301108401Sambrisko return error; 302108401Sambrisko} 303108401Sambrisko 304110531SambriskoSYSCTL_PROC(_hw_an, OID_AUTO, an_cache_mode, CTLTYPE_STRING | CTLFLAG_RW, 305175446Sambrisko 0, sizeof(an_conf_cache), sysctl_an_cache_mode, "A", ""); 306108401Sambrisko 30783270Sbrooks/* 308175445Sambrisko * Setup the lock for PCI attachment since it skips the an_probe 309175445Sambrisko * function. We need to setup the lock in an_probe since some 310175445Sambrisko * operations need the lock. So we might as well create the 311175445Sambrisko * lock in the probe. 312175445Sambrisko */ 313175445Sambriskoint 314175445Sambriskoan_pci_probe(device_t dev) 315175445Sambrisko{ 316175446Sambrisko struct an_softc *sc = device_get_softc(dev); 317175445Sambrisko 318175445Sambrisko mtx_init(&sc->an_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 319199154Sjhb MTX_DEF); 320175445Sambrisko 321175445Sambrisko return(0); 322175445Sambrisko} 323175445Sambrisko 324175445Sambrisko/* 32555992Swpaul * We probe for an Aironet 4500/4800 card by attempting to 32655992Swpaul * read the default SSID list. On reset, the first entry in 32755992Swpaul * the SSID list will contain the name "tsunami." If we don't 32855992Swpaul * find this, then there's no card present. 32955992Swpaul */ 33083270Sbrooksint 331150446Simpan_probe(device_t dev) 33255992Swpaul{ 333175446Sambrisko struct an_softc *sc = device_get_softc(dev); 334119156Sambrisko struct an_ltv_ssidlist_new ssid; 33555992Swpaul int error; 33655992Swpaul 33755992Swpaul bzero((char *)&ssid, sizeof(ssid)); 33855992Swpaul 33955992Swpaul error = an_alloc_port(dev, 0, AN_IOSIZ); 34078639Sbrooks if (error != 0) 34155992Swpaul return (0); 34255992Swpaul 34355992Swpaul /* can't do autoprobing */ 34455992Swpaul if (rman_get_start(sc->port_res) == -1) 34555992Swpaul return(0); 34655992Swpaul 34755992Swpaul /* 34855992Swpaul * We need to fake up a softc structure long enough 34955992Swpaul * to be able to issue commands and call some of the 35055992Swpaul * other routines. 35155992Swpaul */ 35256094Swpaul sc->an_bhandle = rman_get_bushandle(sc->port_res); 35355992Swpaul sc->an_btag = rman_get_bustag(sc->port_res); 35455992Swpaul 35555992Swpaul ssid.an_len = sizeof(ssid); 35655992Swpaul ssid.an_type = AN_RID_SSIDLIST; 35755992Swpaul 358175446Sambrisko /* Make sure interrupts are disabled. */ 359119156Sambrisko sc->mpi350 = 0; 360175446Sambrisko CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0); 361175446Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), 0xFFFF); 36255992Swpaul 363175445Sambrisko mtx_init(&sc->an_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 364199154Sjhb MTX_DEF); 365175445Sambrisko AN_LOCK(sc); 36655992Swpaul an_reset(sc); 36755992Swpaul 368175445Sambrisko if (an_cmd(sc, AN_CMD_READCFG, 0)) { 369175445Sambrisko AN_UNLOCK(sc); 370175445Sambrisko goto fail; 371175445Sambrisko } 37255992Swpaul 373175445Sambrisko if (an_read_record(sc, (struct an_ltv_gen *)&ssid)) { 374175445Sambrisko AN_UNLOCK(sc); 375175445Sambrisko goto fail; 376175445Sambrisko } 37755992Swpaul 37868692Swpaul /* See if the ssid matches what we expect ... but doesn't have to */ 379175445Sambrisko if (strcmp(ssid.an_entry[0].an_ssid, AN_DEF_SSID)) { 380175445Sambrisko AN_UNLOCK(sc); 381175445Sambrisko goto fail; 382175445Sambrisko } 38383270Sbrooks 384175445Sambrisko AN_UNLOCK(sc); 38555992Swpaul return(AN_IOSIZ); 386175445Sambriskofail: 387175445Sambrisko mtx_destroy(&sc->an_mtx); 388175445Sambrisko return(0); 38955992Swpaul} 39055992Swpaul 39155992Swpaul/* 39255992Swpaul * Allocate a port resource with the given resource id. 39355992Swpaul */ 39455992Swpaulint 395150446Simpan_alloc_port(device_t dev, int rid, int size) 39655992Swpaul{ 39755992Swpaul struct an_softc *sc = device_get_softc(dev); 39855992Swpaul struct resource *res; 39955992Swpaul 40055992Swpaul res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 40155992Swpaul 0ul, ~0ul, size, RF_ACTIVE); 40255992Swpaul if (res) { 40355992Swpaul sc->port_rid = rid; 40455992Swpaul sc->port_res = res; 40555992Swpaul return (0); 40655992Swpaul } else { 40755992Swpaul return (ENOENT); 40855992Swpaul } 40955992Swpaul} 41055992Swpaul 41155992Swpaul/* 412108401Sambrisko * Allocate a memory resource with the given resource id. 413108401Sambrisko */ 414108401Sambriskoint an_alloc_memory(device_t dev, int rid, int size) 415108401Sambrisko{ 416108401Sambrisko struct an_softc *sc = device_get_softc(dev); 417108401Sambrisko struct resource *res; 418108401Sambrisko 419108401Sambrisko res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 420108401Sambrisko 0ul, ~0ul, size, RF_ACTIVE); 421108401Sambrisko if (res) { 422108401Sambrisko sc->mem_rid = rid; 423108401Sambrisko sc->mem_res = res; 424108401Sambrisko sc->mem_used = size; 425108401Sambrisko return (0); 426108401Sambrisko } else { 427108401Sambrisko return (ENOENT); 428108401Sambrisko } 429108401Sambrisko} 430108401Sambrisko 431108401Sambrisko/* 432108401Sambrisko * Allocate a auxilary memory resource with the given resource id. 433108401Sambrisko */ 434108401Sambriskoint an_alloc_aux_memory(device_t dev, int rid, int size) 435108401Sambrisko{ 436108401Sambrisko struct an_softc *sc = device_get_softc(dev); 437108401Sambrisko struct resource *res; 438108401Sambrisko 439108401Sambrisko res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 440108401Sambrisko 0ul, ~0ul, size, RF_ACTIVE); 441108401Sambrisko if (res) { 442108401Sambrisko sc->mem_aux_rid = rid; 443108401Sambrisko sc->mem_aux_res = res; 444108401Sambrisko sc->mem_aux_used = size; 445108401Sambrisko return (0); 446108401Sambrisko } else { 447108401Sambrisko return (ENOENT); 448108401Sambrisko } 449108401Sambrisko} 450108401Sambrisko 451108401Sambrisko/* 45255992Swpaul * Allocate an irq resource with the given resource id. 45355992Swpaul */ 45455992Swpaulint 455150446Simpan_alloc_irq(device_t dev, int rid, int flags) 45655992Swpaul{ 45755992Swpaul struct an_softc *sc = device_get_softc(dev); 45855992Swpaul struct resource *res; 45955992Swpaul 460127135Snjl res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 461127135Snjl (RF_ACTIVE | flags)); 46255992Swpaul if (res) { 46355992Swpaul sc->irq_rid = rid; 46455992Swpaul sc->irq_res = res; 46555992Swpaul return (0); 46655992Swpaul } else { 46755992Swpaul return (ENOENT); 46855992Swpaul } 46955992Swpaul} 47055992Swpaul 471108401Sambriskostatic void 472150446Simpan_dma_malloc_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) 473108401Sambrisko{ 474108401Sambrisko bus_addr_t *paddr = (bus_addr_t*) arg; 475108401Sambrisko *paddr = segs->ds_addr; 476108401Sambrisko} 477108401Sambrisko 47855992Swpaul/* 479108401Sambrisko * Alloc DMA memory and set the pointer to it 480108401Sambrisko */ 481108401Sambriskostatic int 482150446Simpan_dma_malloc(struct an_softc *sc, bus_size_t size, struct an_dma_alloc *dma, 483150446Simp int mapflags) 484108401Sambrisko{ 485108401Sambrisko int r; 486108401Sambrisko 487108401Sambrisko r = bus_dmamap_create(sc->an_dtag, BUS_DMA_NOWAIT, &dma->an_dma_map); 488108401Sambrisko if (r != 0) 489108401Sambrisko goto fail_0; 490108401Sambrisko 491108401Sambrisko r = bus_dmamem_alloc(sc->an_dtag, (void**) &dma->an_dma_vaddr, 492108401Sambrisko BUS_DMA_NOWAIT, &dma->an_dma_map); 493108401Sambrisko if (r != 0) 494108401Sambrisko goto fail_1; 495108401Sambrisko 496108401Sambrisko r = bus_dmamap_load(sc->an_dtag, dma->an_dma_map, dma->an_dma_vaddr, 497175446Sambrisko size, 498108401Sambrisko an_dma_malloc_cb, 499108401Sambrisko &dma->an_dma_paddr, 500108401Sambrisko mapflags | BUS_DMA_NOWAIT); 501108401Sambrisko if (r != 0) 502108401Sambrisko goto fail_2; 503108401Sambrisko 504108401Sambrisko dma->an_dma_size = size; 505108401Sambrisko return (0); 506108401Sambrisko 507108401Sambriskofail_2: 508108401Sambrisko bus_dmamap_unload(sc->an_dtag, dma->an_dma_map); 509108401Sambriskofail_1: 510108401Sambrisko bus_dmamem_free(sc->an_dtag, dma->an_dma_vaddr, dma->an_dma_map); 511108401Sambriskofail_0: 512108401Sambrisko bus_dmamap_destroy(sc->an_dtag, dma->an_dma_map); 513108401Sambrisko dma->an_dma_map = NULL; 514108401Sambrisko return (r); 515108401Sambrisko} 516108401Sambrisko 517108401Sambriskostatic void 518150446Simpan_dma_free(struct an_softc *sc, struct an_dma_alloc *dma) 519108401Sambrisko{ 520108401Sambrisko bus_dmamap_unload(sc->an_dtag, dma->an_dma_map); 521108401Sambrisko bus_dmamem_free(sc->an_dtag, dma->an_dma_vaddr, dma->an_dma_map); 522123978Sambrisko dma->an_dma_vaddr = 0; 523108401Sambrisko bus_dmamap_destroy(sc->an_dtag, dma->an_dma_map); 524108401Sambrisko} 525108401Sambrisko 526108401Sambrisko/* 52755992Swpaul * Release all resources 52855992Swpaul */ 52955992Swpaulvoid 530150446Simpan_release_resources(device_t dev) 53155992Swpaul{ 53255992Swpaul struct an_softc *sc = device_get_softc(dev); 533108401Sambrisko int i; 53455992Swpaul 53555992Swpaul if (sc->port_res) { 53655992Swpaul bus_release_resource(dev, SYS_RES_IOPORT, 53755992Swpaul sc->port_rid, sc->port_res); 53855992Swpaul sc->port_res = 0; 53955992Swpaul } 540108401Sambrisko if (sc->mem_res) { 541108401Sambrisko bus_release_resource(dev, SYS_RES_MEMORY, 542108401Sambrisko sc->mem_rid, sc->mem_res); 543108401Sambrisko sc->mem_res = 0; 544108401Sambrisko } 545108401Sambrisko if (sc->mem_aux_res) { 546108401Sambrisko bus_release_resource(dev, SYS_RES_MEMORY, 547108401Sambrisko sc->mem_aux_rid, sc->mem_aux_res); 548108401Sambrisko sc->mem_aux_res = 0; 549108401Sambrisko } 55055992Swpaul if (sc->irq_res) { 55155992Swpaul bus_release_resource(dev, SYS_RES_IRQ, 55255992Swpaul sc->irq_rid, sc->irq_res); 55355992Swpaul sc->irq_res = 0; 55455992Swpaul } 555108401Sambrisko if (sc->an_rid_buffer.an_dma_paddr) { 556108401Sambrisko an_dma_free(sc, &sc->an_rid_buffer); 557108401Sambrisko } 558108401Sambrisko for (i = 0; i < AN_MAX_RX_DESC; i++) 559108401Sambrisko if (sc->an_rx_buffer[i].an_dma_paddr) { 560108401Sambrisko an_dma_free(sc, &sc->an_rx_buffer[i]); 561108401Sambrisko } 562108401Sambrisko for (i = 0; i < AN_MAX_TX_DESC; i++) 563108401Sambrisko if (sc->an_tx_buffer[i].an_dma_paddr) { 564108401Sambrisko an_dma_free(sc, &sc->an_tx_buffer[i]); 565108401Sambrisko } 566108401Sambrisko if (sc->an_dtag) { 567108401Sambrisko bus_dma_tag_destroy(sc->an_dtag); 568108401Sambrisko } 569108401Sambrisko 57055992Swpaul} 57155992Swpaul 57283270Sbrooksint 573150446Simpan_init_mpi350_desc(struct an_softc *sc) 574108401Sambrisko{ 575108401Sambrisko struct an_command cmd_struct; 576108401Sambrisko struct an_reply reply; 577108401Sambrisko struct an_card_rid_desc an_rid_desc; 578108401Sambrisko struct an_card_rx_desc an_rx_desc; 579108401Sambrisko struct an_card_tx_desc an_tx_desc; 580108401Sambrisko int i, desc; 581108401Sambrisko 582175445Sambrisko AN_LOCK_ASSERT(sc); 583108401Sambrisko if(!sc->an_rid_buffer.an_dma_paddr) 584108401Sambrisko an_dma_malloc(sc, AN_RID_BUFFER_SIZE, 585108401Sambrisko &sc->an_rid_buffer, 0); 586108401Sambrisko for (i = 0; i < AN_MAX_RX_DESC; i++) 587108401Sambrisko if(!sc->an_rx_buffer[i].an_dma_paddr) 588108401Sambrisko an_dma_malloc(sc, AN_RX_BUFFER_SIZE, 589108401Sambrisko &sc->an_rx_buffer[i], 0); 590108401Sambrisko for (i = 0; i < AN_MAX_TX_DESC; i++) 591108401Sambrisko if(!sc->an_tx_buffer[i].an_dma_paddr) 592108401Sambrisko an_dma_malloc(sc, AN_TX_BUFFER_SIZE, 593108401Sambrisko &sc->an_tx_buffer[i], 0); 594108401Sambrisko 595108401Sambrisko /* 596108401Sambrisko * Allocate RX descriptor 597108401Sambrisko */ 598108401Sambrisko bzero(&reply,sizeof(reply)); 599108401Sambrisko cmd_struct.an_cmd = AN_CMD_ALLOC_DESC; 600108401Sambrisko cmd_struct.an_parm0 = AN_DESCRIPTOR_RX; 601108401Sambrisko cmd_struct.an_parm1 = AN_RX_DESC_OFFSET; 602108401Sambrisko cmd_struct.an_parm2 = AN_MAX_RX_DESC; 603108401Sambrisko if (an_cmd_struct(sc, &cmd_struct, &reply)) { 604198987Sjhb if_printf(sc->an_ifp, "failed to allocate RX descriptor\n"); 605108401Sambrisko return(EIO); 606108401Sambrisko } 607108401Sambrisko 608108401Sambrisko for (desc = 0; desc < AN_MAX_RX_DESC; desc++) { 609108401Sambrisko bzero(&an_rx_desc, sizeof(an_rx_desc)); 610108401Sambrisko an_rx_desc.an_valid = 1; 611108401Sambrisko an_rx_desc.an_len = AN_RX_BUFFER_SIZE; 612108401Sambrisko an_rx_desc.an_done = 0; 613108401Sambrisko an_rx_desc.an_phys = sc->an_rx_buffer[desc].an_dma_paddr; 614108401Sambrisko 615108401Sambrisko for (i = 0; i < sizeof(an_rx_desc) / 4; i++) 616155321Simp CSR_MEM_AUX_WRITE_4(sc, AN_RX_DESC_OFFSET 617155321Simp + (desc * sizeof(an_rx_desc)) 618155321Simp + (i * 4), 619155321Simp ((u_int32_t *)(void *)&an_rx_desc)[i]); 620108401Sambrisko } 621108401Sambrisko 622108401Sambrisko /* 623108401Sambrisko * Allocate TX descriptor 624108401Sambrisko */ 625108401Sambrisko 626108401Sambrisko bzero(&reply,sizeof(reply)); 627108401Sambrisko cmd_struct.an_cmd = AN_CMD_ALLOC_DESC; 628108401Sambrisko cmd_struct.an_parm0 = AN_DESCRIPTOR_TX; 629108401Sambrisko cmd_struct.an_parm1 = AN_TX_DESC_OFFSET; 630108401Sambrisko cmd_struct.an_parm2 = AN_MAX_TX_DESC; 631108401Sambrisko if (an_cmd_struct(sc, &cmd_struct, &reply)) { 632198987Sjhb if_printf(sc->an_ifp, "failed to allocate TX descriptor\n"); 633108401Sambrisko return(EIO); 634108401Sambrisko } 635108401Sambrisko 636108401Sambrisko for (desc = 0; desc < AN_MAX_TX_DESC; desc++) { 637108401Sambrisko bzero(&an_tx_desc, sizeof(an_tx_desc)); 638108401Sambrisko an_tx_desc.an_offset = 0; 639108401Sambrisko an_tx_desc.an_eoc = 0; 640108401Sambrisko an_tx_desc.an_valid = 0; 641108401Sambrisko an_tx_desc.an_len = 0; 642108401Sambrisko an_tx_desc.an_phys = sc->an_tx_buffer[desc].an_dma_paddr; 643108401Sambrisko 644108401Sambrisko for (i = 0; i < sizeof(an_tx_desc) / 4; i++) 645108401Sambrisko CSR_MEM_AUX_WRITE_4(sc, AN_TX_DESC_OFFSET 646155321Simp + (desc * sizeof(an_tx_desc)) 647155321Simp + (i * 4), 648155321Simp ((u_int32_t *)(void *)&an_tx_desc)[i]); 649108401Sambrisko } 650108401Sambrisko 651108401Sambrisko /* 652108401Sambrisko * Allocate RID descriptor 653108401Sambrisko */ 654108401Sambrisko 655108401Sambrisko bzero(&reply,sizeof(reply)); 656108401Sambrisko cmd_struct.an_cmd = AN_CMD_ALLOC_DESC; 657108401Sambrisko cmd_struct.an_parm0 = AN_DESCRIPTOR_HOSTRW; 658108401Sambrisko cmd_struct.an_parm1 = AN_HOST_DESC_OFFSET; 659108401Sambrisko cmd_struct.an_parm2 = 1; 660108401Sambrisko if (an_cmd_struct(sc, &cmd_struct, &reply)) { 661198987Sjhb if_printf(sc->an_ifp, "failed to allocate host descriptor\n"); 662108401Sambrisko return(EIO); 663108401Sambrisko } 664108401Sambrisko 665108401Sambrisko bzero(&an_rid_desc, sizeof(an_rid_desc)); 666108401Sambrisko an_rid_desc.an_valid = 1; 667108401Sambrisko an_rid_desc.an_len = AN_RID_BUFFER_SIZE; 668108401Sambrisko an_rid_desc.an_rid = 0; 669108401Sambrisko an_rid_desc.an_phys = sc->an_rid_buffer.an_dma_paddr; 670108401Sambrisko 671108401Sambrisko for (i = 0; i < sizeof(an_rid_desc) / 4; i++) 672175445Sambrisko CSR_MEM_AUX_WRITE_4(sc, AN_HOST_DESC_OFFSET + i * 4, 673155321Simp ((u_int32_t *)(void *)&an_rid_desc)[i]); 674108401Sambrisko 675108401Sambrisko return(0); 676108401Sambrisko} 677108401Sambrisko 678108401Sambriskoint 679198995Sjhban_attach(struct an_softc *sc, int flags) 68055992Swpaul{ 681147256Sbrooks struct ifnet *ifp; 682113316Simp int error = EIO; 683110253Sambrisko int i, nrate, mword; 684110253Sambrisko u_int8_t r; 68555992Swpaul 686147380Sdelphij ifp = sc->an_ifp = if_alloc(IFT_ETHER); 687147256Sbrooks if (ifp == NULL) { 688198987Sjhb device_printf(sc->an_dev, "can not if_alloc()\n"); 689147256Sbrooks goto fail; 690147256Sbrooks } 691175445Sambrisko 69255992Swpaul sc->an_gone = 0; 69355992Swpaul sc->an_associated = 0; 69483269Sbrooks sc->an_monitor = 0; 69583269Sbrooks sc->an_was_monitor = 0; 696108401Sambrisko sc->an_flash_buffer = NULL; 69755992Swpaul 69855992Swpaul /* Reset the NIC. */ 699175445Sambrisko AN_LOCK(sc); 70055992Swpaul an_reset(sc); 701110104Sambrisko if (sc->mpi350) { 702108401Sambrisko error = an_init_mpi350_desc(sc); 703108401Sambrisko if (error) 704113316Simp goto fail; 705108401Sambrisko } 70655992Swpaul 70755992Swpaul /* Load factory config */ 70855992Swpaul if (an_cmd(sc, AN_CMD_READCFG, 0)) { 709198987Sjhb device_printf(sc->an_dev, "failed to load config data\n"); 710113316Simp goto fail; 71155992Swpaul } 71255992Swpaul 71355992Swpaul /* Read the current configuration */ 71455992Swpaul sc->an_config.an_type = AN_RID_GENCONFIG; 71555992Swpaul sc->an_config.an_len = sizeof(struct an_ltv_genconfig); 71655992Swpaul if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_config)) { 717198987Sjhb device_printf(sc->an_dev, "read record failed\n"); 718113316Simp goto fail; 71955992Swpaul } 72055992Swpaul 72155992Swpaul /* Read the card capabilities */ 72255992Swpaul sc->an_caps.an_type = AN_RID_CAPABILITIES; 72355992Swpaul sc->an_caps.an_len = sizeof(struct an_ltv_caps); 72455992Swpaul if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_caps)) { 725198987Sjhb device_printf(sc->an_dev, "read record failed\n"); 726113316Simp goto fail; 72755992Swpaul } 72855992Swpaul 72955992Swpaul /* Read ssid list */ 73055992Swpaul sc->an_ssidlist.an_type = AN_RID_SSIDLIST; 731119156Sambrisko sc->an_ssidlist.an_len = sizeof(struct an_ltv_ssidlist_new); 73255992Swpaul if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_ssidlist)) { 733198987Sjhb device_printf(sc->an_dev, "read record failed\n"); 734113316Simp goto fail; 73555992Swpaul } 73655992Swpaul 73755992Swpaul /* Read AP list */ 73855992Swpaul sc->an_aplist.an_type = AN_RID_APLIST; 73955992Swpaul sc->an_aplist.an_len = sizeof(struct an_ltv_aplist); 74055992Swpaul if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_aplist)) { 741198987Sjhb device_printf(sc->an_dev, "read record failed\n"); 742113316Simp goto fail; 74355992Swpaul } 74455992Swpaul 745108401Sambrisko#ifdef ANCACHE 746108401Sambrisko /* Read the RSSI <-> dBm map */ 747108401Sambrisko sc->an_have_rssimap = 0; 748108401Sambrisko if (sc->an_caps.an_softcaps & 8) { 749108401Sambrisko sc->an_rssimap.an_type = AN_RID_RSSI_MAP; 750108401Sambrisko sc->an_rssimap.an_len = sizeof(struct an_ltv_rssi_map); 751108401Sambrisko if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_rssimap)) { 752198987Sjhb device_printf(sc->an_dev, 753198987Sjhb "unable to get RSSI <-> dBM map\n"); 754108401Sambrisko } else { 755198987Sjhb device_printf(sc->an_dev, "got RSSI <-> dBM map\n"); 756108401Sambrisko sc->an_have_rssimap = 1; 757108401Sambrisko } 758108401Sambrisko } else { 759198987Sjhb device_printf(sc->an_dev, "no RSSI <-> dBM map\n"); 760108401Sambrisko } 761108401Sambrisko#endif 762175445Sambrisko AN_UNLOCK(sc); 763108401Sambrisko 76455992Swpaul ifp->if_softc = sc; 765121816Sbrooks if_initname(ifp, device_get_name(sc->an_dev), 766121816Sbrooks device_get_unit(sc->an_dev)); 76755992Swpaul ifp->if_mtu = ETHERMTU; 76855992Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 76955992Swpaul ifp->if_ioctl = an_ioctl; 77055992Swpaul ifp->if_start = an_start; 77155992Swpaul ifp->if_init = an_init; 77255992Swpaul ifp->if_baudrate = 10000000; 773132986Smlaier IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); 774132986Smlaier ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; 775132986Smlaier IFQ_SET_READY(&ifp->if_snd); 77655992Swpaul 77755992Swpaul bzero(sc->an_config.an_nodename, sizeof(sc->an_config.an_nodename)); 77855992Swpaul bcopy(AN_DEFAULT_NODENAME, sc->an_config.an_nodename, 77955992Swpaul sizeof(AN_DEFAULT_NODENAME) - 1); 78055992Swpaul 781119156Sambrisko bzero(sc->an_ssidlist.an_entry[0].an_ssid, 782119156Sambrisko sizeof(sc->an_ssidlist.an_entry[0].an_ssid)); 783119156Sambrisko bcopy(AN_DEFAULT_NETNAME, sc->an_ssidlist.an_entry[0].an_ssid, 78455992Swpaul sizeof(AN_DEFAULT_NETNAME) - 1); 785119156Sambrisko sc->an_ssidlist.an_entry[0].an_len = strlen(AN_DEFAULT_NETNAME); 78655992Swpaul 78755992Swpaul sc->an_config.an_opmode = 78874144Sassar AN_OPMODE_INFRASTRUCTURE_STATION; 78955992Swpaul 79055992Swpaul sc->an_tx_rate = 0; 79155992Swpaul bzero((char *)&sc->an_stats, sizeof(sc->an_stats)); 79255992Swpaul 793110253Sambrisko nrate = 8; 794110253Sambrisko 79577217Sphk ifmedia_init(&sc->an_ifmedia, 0, an_media_change, an_media_status); 796110253Sambrisko if_printf(ifp, "supported rates: "); 797110253Sambrisko#define ADD(s, o) ifmedia_add(&sc->an_ifmedia, \ 798110253Sambrisko IFM_MAKEWORD(IFM_IEEE80211, (s), (o), 0), 0, NULL) 799110253Sambrisko ADD(IFM_AUTO, 0); 800110253Sambrisko ADD(IFM_AUTO, IFM_IEEE80211_ADHOC); 801110253Sambrisko for (i = 0; i < nrate; i++) { 802110253Sambrisko r = sc->an_caps.an_rates[i]; 803116951Ssam mword = ieee80211_rate2media(NULL, r, IEEE80211_T_DS); 804110253Sambrisko if (mword == 0) 805110253Sambrisko continue; 806110253Sambrisko printf("%s%d%sMbps", (i != 0 ? " " : ""), 807110253Sambrisko (r & IEEE80211_RATE_VAL) / 2, ((r & 0x1) != 0 ? ".5" : "")); 808110253Sambrisko ADD(mword, 0); 809110253Sambrisko ADD(mword, IFM_IEEE80211_ADHOC); 81077217Sphk } 811110253Sambrisko printf("\n"); 812175445Sambrisko ifmedia_set(&sc->an_ifmedia, IFM_MAKEWORD(IFM_IEEE80211, 813110253Sambrisko IFM_AUTO, 0, 0)); 814110253Sambrisko#undef ADD 81577217Sphk 81655992Swpaul /* 81763090Sarchie * Call MI attach routine. 81855992Swpaul */ 819147256Sbrooks 820147256Sbrooks ether_ifattach(ifp, sc->an_caps.an_oemaddr); 821173668Savatar callout_init_mtx(&sc->an_stat_ch, &sc->an_mtx, 0); 82255992Swpaul 82355992Swpaul return(0); 824175445Sambriskofail: 825175445Sambrisko AN_UNLOCK(sc); 826113316Simp mtx_destroy(&sc->an_mtx); 827147256Sbrooks if (ifp != NULL) 828147256Sbrooks if_free(ifp); 829113316Simp return(error); 83055992Swpaul} 83155992Swpaul 832123978Sambriskoint 833123978Sambriskoan_detach(device_t dev) 834123978Sambrisko{ 835123978Sambrisko struct an_softc *sc = device_get_softc(dev); 836147256Sbrooks struct ifnet *ifp = sc->an_ifp; 837123978Sambrisko 838123978Sambrisko if (sc->an_gone) { 839123978Sambrisko device_printf(dev,"already unloaded\n"); 840123978Sambrisko return(0); 841123978Sambrisko } 842148639Semax AN_LOCK(sc); 843123978Sambrisko an_stop(sc); 844148454Semax sc->an_gone = 1; 845123978Sambrisko ifmedia_removeall(&sc->an_ifmedia); 846148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 847148454Semax AN_UNLOCK(sc); 848123978Sambrisko ether_ifdetach(ifp); 849150306Simp bus_teardown_intr(dev, sc->irq_res, sc->irq_handle); 850173668Savatar callout_drain(&sc->an_stat_ch); 851147256Sbrooks if_free(ifp); 852123978Sambrisko an_release_resources(dev); 853123978Sambrisko mtx_destroy(&sc->an_mtx); 854123978Sambrisko return (0); 855123978Sambrisko} 856123978Sambrisko 85783270Sbrooksstatic void 858150446Simpan_rxeof(struct an_softc *sc) 85955992Swpaul{ 86083269Sbrooks struct ifnet *ifp; 86183269Sbrooks struct ether_header *eh; 86283269Sbrooks struct ieee80211_frame *ih; 86383269Sbrooks struct an_rxframe rx_frame; 86483269Sbrooks struct an_rxframe_802_3 rx_frame_802_3; 86583269Sbrooks struct mbuf *m; 866108401Sambrisko int len, id, error = 0, i, count = 0; 867108401Sambrisko int ieee80211_header_len; 868108401Sambrisko u_char *bpf_buf; 869108401Sambrisko u_short fc1; 870108401Sambrisko struct an_card_rx_desc an_rx_desc; 871108401Sambrisko u_int8_t *buf; 87255992Swpaul 873122689Ssam AN_LOCK_ASSERT(sc); 874122689Ssam 875147256Sbrooks ifp = sc->an_ifp; 87655992Swpaul 877108401Sambrisko if (!sc->mpi350) { 878108401Sambrisko id = CSR_READ_2(sc, AN_RX_FID); 87955992Swpaul 880108401Sambrisko if (sc->an_monitor && (ifp->if_flags & IFF_PROMISC)) { 881108401Sambrisko /* read raw 802.11 packet */ 882108401Sambrisko bpf_buf = sc->buf_802_11; 88355992Swpaul 884108401Sambrisko /* read header */ 885108401Sambrisko if (an_read_data(sc, id, 0x0, (caddr_t)&rx_frame, 886108401Sambrisko sizeof(rx_frame))) { 887108401Sambrisko ifp->if_ierrors++; 888108401Sambrisko return; 889108401Sambrisko } 89055992Swpaul 891108401Sambrisko /* 892108401Sambrisko * skip beacon by default since this increases the 893108401Sambrisko * system load a lot 894108401Sambrisko */ 89583270Sbrooks 896108401Sambrisko if (!(sc->an_monitor & AN_MONITOR_INCLUDE_BEACON) && 897108401Sambrisko (rx_frame.an_frame_ctl & 898108401Sambrisko IEEE80211_FC0_SUBTYPE_BEACON)) { 89983269Sbrooks return; 90083269Sbrooks } 90155992Swpaul 902108401Sambrisko if (sc->an_monitor & AN_MONITOR_AIRONET_HEADER) { 903108401Sambrisko len = rx_frame.an_rx_payload_len 904108401Sambrisko + sizeof(rx_frame); 905108401Sambrisko /* Check for insane frame length */ 906108401Sambrisko if (len > sizeof(sc->buf_802_11)) { 907198987Sjhb if_printf(ifp, "oversized packet " 908108401Sambrisko "received (%d, %d)\n", 909198987Sjhb len, MCLBYTES); 910108401Sambrisko ifp->if_ierrors++; 911108401Sambrisko return; 912108401Sambrisko } 91355992Swpaul 914108401Sambrisko bcopy((char *)&rx_frame, 915108401Sambrisko bpf_buf, sizeof(rx_frame)); 916108401Sambrisko 917108401Sambrisko error = an_read_data(sc, id, sizeof(rx_frame), 918108401Sambrisko (caddr_t)bpf_buf+sizeof(rx_frame), 919108401Sambrisko rx_frame.an_rx_payload_len); 920108401Sambrisko } else { 921108401Sambrisko fc1=rx_frame.an_frame_ctl >> 8; 922175445Sambrisko ieee80211_header_len = 923108401Sambrisko sizeof(struct ieee80211_frame); 924108401Sambrisko if ((fc1 & IEEE80211_FC1_DIR_TODS) && 925108401Sambrisko (fc1 & IEEE80211_FC1_DIR_FROMDS)) { 926108401Sambrisko ieee80211_header_len += ETHER_ADDR_LEN; 927108401Sambrisko } 928108401Sambrisko 929108401Sambrisko len = rx_frame.an_rx_payload_len 930108401Sambrisko + ieee80211_header_len; 931108401Sambrisko /* Check for insane frame length */ 932108401Sambrisko if (len > sizeof(sc->buf_802_11)) { 933198987Sjhb if_printf(ifp, "oversized packet " 934108401Sambrisko "received (%d, %d)\n", 935198987Sjhb len, MCLBYTES); 936108401Sambrisko ifp->if_ierrors++; 937108401Sambrisko return; 938108401Sambrisko } 939108401Sambrisko 940108401Sambrisko ih = (struct ieee80211_frame *)bpf_buf; 941108401Sambrisko 942108401Sambrisko bcopy((char *)&rx_frame.an_frame_ctl, 943108401Sambrisko (char *)ih, ieee80211_header_len); 944108401Sambrisko 945108401Sambrisko error = an_read_data(sc, id, sizeof(rx_frame) + 946108401Sambrisko rx_frame.an_gaplen, 947108401Sambrisko (caddr_t)ih +ieee80211_header_len, 948108401Sambrisko rx_frame.an_rx_payload_len); 949108401Sambrisko } 950108401Sambrisko /* dump raw 802.11 packet to bpf and skip ip stack */ 951108401Sambrisko BPF_TAP(ifp, bpf_buf, len); 95283270Sbrooks } else { 953111119Simp MGETHDR(m, M_DONTWAIT, MT_DATA); 954108401Sambrisko if (m == NULL) { 955108401Sambrisko ifp->if_ierrors++; 956108401Sambrisko return; 95783269Sbrooks } 958111119Simp MCLGET(m, M_DONTWAIT); 959108401Sambrisko if (!(m->m_flags & M_EXT)) { 960108401Sambrisko m_freem(m); 961108401Sambrisko ifp->if_ierrors++; 962108401Sambrisko return; 963108401Sambrisko } 964108401Sambrisko m->m_pkthdr.rcvif = ifp; 965108401Sambrisko /* Read Ethernet encapsulated packet */ 96655992Swpaul 967108401Sambrisko#ifdef ANCACHE 968108401Sambrisko /* Read NIC frame header */ 969175445Sambrisko if (an_read_data(sc, id, 0, (caddr_t)&rx_frame, 970108401Sambrisko sizeof(rx_frame))) { 971154394Srwatson m_freem(m); 972108401Sambrisko ifp->if_ierrors++; 973108401Sambrisko return; 974108401Sambrisko } 975108401Sambrisko#endif 976108401Sambrisko /* Read in the 802_3 frame header */ 977175445Sambrisko if (an_read_data(sc, id, 0x34, 978108401Sambrisko (caddr_t)&rx_frame_802_3, 979108401Sambrisko sizeof(rx_frame_802_3))) { 980154394Srwatson m_freem(m); 981108401Sambrisko ifp->if_ierrors++; 982108401Sambrisko return; 983108401Sambrisko } 984108401Sambrisko if (rx_frame_802_3.an_rx_802_3_status != 0) { 985154394Srwatson m_freem(m); 986108401Sambrisko ifp->if_ierrors++; 987108401Sambrisko return; 988108401Sambrisko } 98983269Sbrooks /* Check for insane frame length */ 990108401Sambrisko len = rx_frame_802_3.an_rx_802_3_payload_len; 99183269Sbrooks if (len > sizeof(sc->buf_802_11)) { 992154394Srwatson m_freem(m); 993198987Sjhb if_printf(ifp, "oversized packet " 994108401Sambrisko "received (%d, %d)\n", 995198987Sjhb len, MCLBYTES); 99683269Sbrooks ifp->if_ierrors++; 99783269Sbrooks return; 99883269Sbrooks } 999108401Sambrisko m->m_pkthdr.len = m->m_len = 1000108401Sambrisko rx_frame_802_3.an_rx_802_3_payload_len + 12; 100155992Swpaul 1002108401Sambrisko eh = mtod(m, struct ether_header *); 100355992Swpaul 1004108401Sambrisko bcopy((char *)&rx_frame_802_3.an_rx_dst_addr, 1005108401Sambrisko (char *)&eh->ether_dhost, ETHER_ADDR_LEN); 1006108401Sambrisko bcopy((char *)&rx_frame_802_3.an_rx_src_addr, 1007108401Sambrisko (char *)&eh->ether_shost, ETHER_ADDR_LEN); 100855992Swpaul 1009108401Sambrisko /* in mbuf header type is just before payload */ 1010175445Sambrisko error = an_read_data(sc, id, 0x44, 1011108401Sambrisko (caddr_t)&(eh->ether_type), 1012108401Sambrisko rx_frame_802_3.an_rx_802_3_payload_len); 101355992Swpaul 1014108401Sambrisko if (error) { 1015108401Sambrisko m_freem(m); 1016108401Sambrisko ifp->if_ierrors++; 1017108401Sambrisko return; 1018108401Sambrisko } 1019108401Sambrisko ifp->if_ipackets++; 1020108401Sambrisko 1021108401Sambrisko /* Receive packet. */ 102283269Sbrooks#ifdef ANCACHE 1023175445Sambrisko an_cache_store(sc, eh, m, 1024110253Sambrisko rx_frame.an_rx_signal_strength, 1025110253Sambrisko rx_frame.an_rsvd0); 102683269Sbrooks#endif 1027122689Ssam AN_UNLOCK(sc); 1028108401Sambrisko (*ifp->if_input)(ifp, m); 1029122689Ssam AN_LOCK(sc); 103083269Sbrooks } 103155992Swpaul 1032108401Sambrisko } else { /* MPI-350 */ 1033108401Sambrisko for (count = 0; count < AN_MAX_RX_DESC; count++){ 1034108401Sambrisko for (i = 0; i < sizeof(an_rx_desc) / 4; i++) 1035175445Sambrisko ((u_int32_t *)(void *)&an_rx_desc)[i] 1036175445Sambrisko = CSR_MEM_AUX_READ_4(sc, 1037175445Sambrisko AN_RX_DESC_OFFSET 1038108401Sambrisko + (count * sizeof(an_rx_desc)) 1039108401Sambrisko + (i * 4)); 104083269Sbrooks 1041108401Sambrisko if (an_rx_desc.an_done && !an_rx_desc.an_valid) { 1042108401Sambrisko buf = sc->an_rx_buffer[count].an_dma_vaddr; 104383269Sbrooks 1044111119Simp MGETHDR(m, M_DONTWAIT, MT_DATA); 1045108401Sambrisko if (m == NULL) { 1046108401Sambrisko ifp->if_ierrors++; 1047108401Sambrisko return; 1048108401Sambrisko } 1049111119Simp MCLGET(m, M_DONTWAIT); 1050108401Sambrisko if (!(m->m_flags & M_EXT)) { 1051108401Sambrisko m_freem(m); 1052108401Sambrisko ifp->if_ierrors++; 1053108401Sambrisko return; 1054108401Sambrisko } 1055108401Sambrisko m->m_pkthdr.rcvif = ifp; 1056108401Sambrisko /* Read Ethernet encapsulated packet */ 105783269Sbrooks 1058175445Sambrisko /* 1059108401Sambrisko * No ANCACHE support since we just get back 1060108401Sambrisko * an Ethernet packet no 802.11 info 1061108401Sambrisko */ 1062108401Sambrisko#if 0 1063108401Sambrisko#ifdef ANCACHE 1064108401Sambrisko /* Read NIC frame header */ 1065175445Sambrisko bcopy(buf, (caddr_t)&rx_frame, 1066108401Sambrisko sizeof(rx_frame)); 1067108401Sambrisko#endif 1068108401Sambrisko#endif 1069108401Sambrisko /* Check for insane frame length */ 1070108401Sambrisko len = an_rx_desc.an_len + 12; 1071108401Sambrisko if (len > MCLBYTES) { 1072154393Srwatson m_freem(m); 1073198987Sjhb if_printf(ifp, "oversized packet " 1074108401Sambrisko "received (%d, %d)\n", 1075198987Sjhb len, MCLBYTES); 1076108401Sambrisko ifp->if_ierrors++; 1077108401Sambrisko return; 1078108401Sambrisko } 107983269Sbrooks 1080108401Sambrisko m->m_pkthdr.len = m->m_len = 1081108401Sambrisko an_rx_desc.an_len + 12; 1082175445Sambrisko 1083108401Sambrisko eh = mtod(m, struct ether_header *); 1084175445Sambrisko 1085108401Sambrisko bcopy(buf, (char *)eh, 1086108401Sambrisko m->m_pkthdr.len); 1087175445Sambrisko 1088108401Sambrisko ifp->if_ipackets++; 1089175445Sambrisko 1090108401Sambrisko /* Receive packet. */ 1091108401Sambrisko#if 0 109255992Swpaul#ifdef ANCACHE 1093175445Sambrisko an_cache_store(sc, eh, m, 1094110253Sambrisko rx_frame.an_rx_signal_strength, 1095110253Sambrisko rx_frame.an_rsvd0); 109655992Swpaul#endif 1097108401Sambrisko#endif 1098171775Savatar AN_UNLOCK(sc); 1099108401Sambrisko (*ifp->if_input)(ifp, m); 1100171775Savatar AN_LOCK(sc); 1101171775Savatar 1102108401Sambrisko an_rx_desc.an_valid = 1; 1103108401Sambrisko an_rx_desc.an_len = AN_RX_BUFFER_SIZE; 1104108401Sambrisko an_rx_desc.an_done = 0; 1105175445Sambrisko an_rx_desc.an_phys = 1106108401Sambrisko sc->an_rx_buffer[count].an_dma_paddr; 1107175445Sambrisko 1108108401Sambrisko for (i = 0; i < sizeof(an_rx_desc) / 4; i++) 1109175445Sambrisko CSR_MEM_AUX_WRITE_4(sc, 1110175445Sambrisko AN_RX_DESC_OFFSET 1111155321Simp + (count * sizeof(an_rx_desc)) 1112155321Simp + (i * 4), 1113155321Simp ((u_int32_t *)(void *)&an_rx_desc)[i]); 1114175445Sambrisko 1115108401Sambrisko } else { 1116198987Sjhb if_printf(ifp, "Didn't get valid RX packet " 1117108401Sambrisko "%x %x %d\n", 1118108401Sambrisko an_rx_desc.an_done, 1119108401Sambrisko an_rx_desc.an_valid, an_rx_desc.an_len); 1120108401Sambrisko } 1121108401Sambrisko } 112283269Sbrooks } 112355992Swpaul} 112455992Swpaul 112583270Sbrooksstatic void 1126150446Simpan_txeof(struct an_softc *sc, int status) 112755992Swpaul{ 112855992Swpaul struct ifnet *ifp; 112978639Sbrooks int id, i; 113055992Swpaul 1131175445Sambrisko AN_LOCK_ASSERT(sc); 1132147256Sbrooks ifp = sc->an_ifp; 113355992Swpaul 1134199154Sjhb sc->an_timer = 0; 1135148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 113655992Swpaul 1137108401Sambrisko if (!sc->mpi350) { 1138119156Sambrisko id = CSR_READ_2(sc, AN_TX_CMP_FID(sc->mpi350)); 113955992Swpaul 1140108401Sambrisko if (status & AN_EV_TX_EXC) { 1141108401Sambrisko ifp->if_oerrors++; 1142108401Sambrisko } else 1143108401Sambrisko ifp->if_opackets++; 114455992Swpaul 1145108401Sambrisko for (i = 0; i < AN_TX_RING_CNT; i++) { 1146108401Sambrisko if (id == sc->an_rdata.an_tx_ring[i]) { 1147108401Sambrisko sc->an_rdata.an_tx_ring[i] = 0; 1148108401Sambrisko break; 1149108401Sambrisko } 115078639Sbrooks } 1151108401Sambrisko 1152108401Sambrisko AN_INC(sc->an_rdata.an_tx_cons, AN_TX_RING_CNT); 1153108401Sambrisko } else { /* MPI 350 */ 1154119156Sambrisko id = CSR_READ_2(sc, AN_TX_CMP_FID(sc->mpi350)); 1155119156Sambrisko if (!sc->an_rdata.an_tx_empty){ 1156119156Sambrisko if (status & AN_EV_TX_EXC) { 1157119156Sambrisko ifp->if_oerrors++; 1158119156Sambrisko } else 1159119156Sambrisko ifp->if_opackets++; 1160119156Sambrisko AN_INC(sc->an_rdata.an_tx_cons, AN_MAX_TX_DESC); 1161119156Sambrisko if (sc->an_rdata.an_tx_prod == 1162119156Sambrisko sc->an_rdata.an_tx_cons) 1163119156Sambrisko sc->an_rdata.an_tx_empty = 1; 1164119156Sambrisko } 116578639Sbrooks } 116655992Swpaul 116755992Swpaul return; 116855992Swpaul} 116955992Swpaul 117055992Swpaul/* 117155992Swpaul * We abuse the stats updater to check the current NIC status. This 117255992Swpaul * is important because we don't want to allow transmissions until 117355992Swpaul * the NIC has synchronized to the current cell (either as the master 117455992Swpaul * in an ad-hoc group, or as a station connected to an access point). 1175173668Savatar * 1176173668Savatar * Note that this function will be called via callout(9) with a lock held. 117755992Swpaul */ 1178104094Sphkstatic void 1179150446Simpan_stats_update(void *xsc) 118055992Swpaul{ 118155992Swpaul struct an_softc *sc; 118255992Swpaul struct ifnet *ifp; 118355992Swpaul 118455992Swpaul sc = xsc; 1185173668Savatar AN_LOCK_ASSERT(sc); 1186147256Sbrooks ifp = sc->an_ifp; 1187199154Sjhb if (sc->an_timer > 0 && --sc->an_timer == 0) 1188199154Sjhb an_watchdog(sc); 118955992Swpaul 119055992Swpaul sc->an_status.an_type = AN_RID_STATUS; 119155992Swpaul sc->an_status.an_len = sizeof(struct an_ltv_status); 1192173668Savatar if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_status)) 1193173668Savatar return; 119455992Swpaul 119555992Swpaul if (sc->an_status.an_opmode & AN_STATUS_OPMODE_IN_SYNC) 119655992Swpaul sc->an_associated = 1; 119755992Swpaul else 119855992Swpaul sc->an_associated = 0; 119955992Swpaul 120055992Swpaul /* Don't do this while we're transmitting */ 1201148887Srwatson if (ifp->if_drv_flags & IFF_DRV_OACTIVE) { 1202173668Savatar callout_reset(&sc->an_stat_ch, hz, an_stats_update, sc); 120355992Swpaul return; 120455992Swpaul } 120555992Swpaul 120655992Swpaul sc->an_stats.an_len = sizeof(struct an_ltv_stats); 120755992Swpaul sc->an_stats.an_type = AN_RID_32BITS_CUM; 1208173668Savatar if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_stats.an_len)) 1209173668Savatar return; 121055992Swpaul 1211173668Savatar callout_reset(&sc->an_stat_ch, hz, an_stats_update, sc); 121255992Swpaul 121355992Swpaul return; 121455992Swpaul} 121555992Swpaul 121683270Sbrooksvoid 1217150446Simpan_intr(void *xsc) 121855992Swpaul{ 121955992Swpaul struct an_softc *sc; 122055992Swpaul struct ifnet *ifp; 122155992Swpaul u_int16_t status; 122255992Swpaul 122355992Swpaul sc = (struct an_softc*)xsc; 122455992Swpaul 122567094Swpaul AN_LOCK(sc); 122667094Swpaul 122767094Swpaul if (sc->an_gone) { 122867094Swpaul AN_UNLOCK(sc); 122955992Swpaul return; 123067094Swpaul } 123155992Swpaul 1232147256Sbrooks ifp = sc->an_ifp; 123355992Swpaul 123455992Swpaul /* Disable interrupts. */ 1235108401Sambrisko CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0); 123655992Swpaul 1237108401Sambrisko status = CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350)); 1238119156Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), ~AN_INTRS(sc->mpi350)); 123955992Swpaul 1240119156Sambrisko if (status & AN_EV_MIC) { 1241119156Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_MIC); 124255992Swpaul } 124355992Swpaul 124455992Swpaul if (status & AN_EV_LINKSTAT) { 1245175445Sambrisko if (CSR_READ_2(sc, AN_LINKSTAT(sc->mpi350)) 1246108401Sambrisko == AN_LINKSTAT_ASSOCIATED) 124755992Swpaul sc->an_associated = 1; 124855992Swpaul else 124955992Swpaul sc->an_associated = 0; 1250108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_LINKSTAT); 125155992Swpaul } 125255992Swpaul 125355992Swpaul if (status & AN_EV_RX) { 125455992Swpaul an_rxeof(sc); 1255108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_RX); 125655992Swpaul } 125755992Swpaul 1258119156Sambrisko if (sc->mpi350 && status & AN_EV_TX_CPY) { 1259119156Sambrisko an_txeof(sc, status); 1260150446Simp CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_TX_CPY); 1261119156Sambrisko } 1262119156Sambrisko 126355992Swpaul if (status & AN_EV_TX) { 126455992Swpaul an_txeof(sc, status); 1265150446Simp CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_TX); 126655992Swpaul } 126755992Swpaul 126855992Swpaul if (status & AN_EV_TX_EXC) { 126955992Swpaul an_txeof(sc, status); 1270108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_TX_EXC); 127155992Swpaul } 127255992Swpaul 127355992Swpaul if (status & AN_EV_ALLOC) 1274108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_ALLOC); 127555992Swpaul 127655992Swpaul /* Re-enable interrupts. */ 1277119156Sambrisko CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), AN_INTRS(sc->mpi350)); 127855992Swpaul 1279132986Smlaier if ((ifp->if_flags & IFF_UP) && !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1280199154Sjhb an_start_locked(ifp); 128155992Swpaul 128267094Swpaul AN_UNLOCK(sc); 128367094Swpaul 128455992Swpaul return; 128555992Swpaul} 128655992Swpaul 1287108401Sambrisko 128883270Sbrooksstatic int 1289150446Simpan_cmd_struct(struct an_softc *sc, struct an_command *cmd, 1290150446Simp struct an_reply *reply) 1291108401Sambrisko{ 1292108401Sambrisko int i; 1293108401Sambrisko 1294175445Sambrisko AN_LOCK_ASSERT(sc); 1295108401Sambrisko for (i = 0; i != AN_TIMEOUT; i++) { 1296108401Sambrisko if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY) { 1297110531Sambrisko DELAY(1000); 1298110104Sambrisko } else 1299108401Sambrisko break; 1300108401Sambrisko } 1301119156Sambrisko 1302108401Sambrisko if( i == AN_TIMEOUT) { 1303108401Sambrisko printf("BUSY\n"); 1304108401Sambrisko return(ETIMEDOUT); 1305108401Sambrisko } 1306108401Sambrisko 1307108401Sambrisko CSR_WRITE_2(sc, AN_PARAM0(sc->mpi350), cmd->an_parm0); 1308108401Sambrisko CSR_WRITE_2(sc, AN_PARAM1(sc->mpi350), cmd->an_parm1); 1309108401Sambrisko CSR_WRITE_2(sc, AN_PARAM2(sc->mpi350), cmd->an_parm2); 1310108401Sambrisko CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), cmd->an_cmd); 1311108401Sambrisko 1312108401Sambrisko for (i = 0; i < AN_TIMEOUT; i++) { 1313108401Sambrisko if (CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350)) & AN_EV_CMD) 1314108401Sambrisko break; 1315110531Sambrisko DELAY(1000); 1316108401Sambrisko } 1317108401Sambrisko 1318108401Sambrisko reply->an_resp0 = CSR_READ_2(sc, AN_RESP0(sc->mpi350)); 1319108401Sambrisko reply->an_resp1 = CSR_READ_2(sc, AN_RESP1(sc->mpi350)); 1320108401Sambrisko reply->an_resp2 = CSR_READ_2(sc, AN_RESP2(sc->mpi350)); 1321108401Sambrisko reply->an_status = CSR_READ_2(sc, AN_STATUS(sc->mpi350)); 1322108401Sambrisko 1323108401Sambrisko if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY) 1324175445Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), 1325119156Sambrisko AN_EV_CLR_STUCK_BUSY); 1326108401Sambrisko 1327108401Sambrisko /* Ack the command */ 1328108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_CMD); 1329108401Sambrisko 1330108401Sambrisko if (i == AN_TIMEOUT) 1331108401Sambrisko return(ETIMEDOUT); 1332108401Sambrisko 1333108401Sambrisko return(0); 1334108401Sambrisko} 1335108401Sambrisko 1336108401Sambriskostatic int 1337150446Simpan_cmd(struct an_softc *sc, int cmd, int val) 133855992Swpaul{ 133955992Swpaul int i, s = 0; 134055992Swpaul 1341175445Sambrisko AN_LOCK_ASSERT(sc); 1342108401Sambrisko CSR_WRITE_2(sc, AN_PARAM0(sc->mpi350), val); 1343108401Sambrisko CSR_WRITE_2(sc, AN_PARAM1(sc->mpi350), 0); 1344108401Sambrisko CSR_WRITE_2(sc, AN_PARAM2(sc->mpi350), 0); 1345108401Sambrisko CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), cmd); 134655992Swpaul 134755992Swpaul for (i = 0; i < AN_TIMEOUT; i++) { 1348108401Sambrisko if (CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350)) & AN_EV_CMD) 134955992Swpaul break; 135055992Swpaul else { 1351108401Sambrisko if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) == cmd) 1352108401Sambrisko CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), cmd); 135355992Swpaul } 135455992Swpaul } 135555992Swpaul 135655992Swpaul for (i = 0; i < AN_TIMEOUT; i++) { 1357108401Sambrisko CSR_READ_2(sc, AN_RESP0(sc->mpi350)); 1358108401Sambrisko CSR_READ_2(sc, AN_RESP1(sc->mpi350)); 1359108401Sambrisko CSR_READ_2(sc, AN_RESP2(sc->mpi350)); 1360108401Sambrisko s = CSR_READ_2(sc, AN_STATUS(sc->mpi350)); 136155992Swpaul if ((s & AN_STAT_CMD_CODE) == (cmd & AN_STAT_CMD_CODE)) 136255992Swpaul break; 136355992Swpaul } 136455992Swpaul 136555992Swpaul /* Ack the command */ 1366108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_CMD); 136755992Swpaul 1368108401Sambrisko if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY) 1369108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_CLR_STUCK_BUSY); 137055992Swpaul 137155992Swpaul if (i == AN_TIMEOUT) 137255992Swpaul return(ETIMEDOUT); 137355992Swpaul 137455992Swpaul return(0); 137555992Swpaul} 137655992Swpaul 137755992Swpaul/* 137855992Swpaul * This reset sequence may look a little strange, but this is the 137955992Swpaul * most reliable method I've found to really kick the NIC in the 138055992Swpaul * head and force it to reboot correctly. 138155992Swpaul */ 138283270Sbrooksstatic void 1383150446Simpan_reset(struct an_softc *sc) 138455992Swpaul{ 138555992Swpaul if (sc->an_gone) 138655992Swpaul return; 138783270Sbrooks 1388175445Sambrisko AN_LOCK_ASSERT(sc); 138955992Swpaul an_cmd(sc, AN_CMD_ENABLE, 0); 139055992Swpaul an_cmd(sc, AN_CMD_FW_RESTART, 0); 139155992Swpaul an_cmd(sc, AN_CMD_NOOP2, 0); 139255992Swpaul 139355992Swpaul if (an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0) == ETIMEDOUT) 1394198987Sjhb if_printf(sc->an_ifp, "reset failed\n"); 139555992Swpaul 139655992Swpaul an_cmd(sc, AN_CMD_DISABLE, 0); 139755992Swpaul 139855992Swpaul return; 139955992Swpaul} 140055992Swpaul 140155992Swpaul/* 140255992Swpaul * Read an LTV record from the NIC. 140355992Swpaul */ 140483270Sbrooksstatic int 1405150446Simpan_read_record(struct an_softc *sc, struct an_ltv_gen *ltv) 140655992Swpaul{ 1407108401Sambrisko struct an_ltv_gen *an_ltv; 1408108401Sambrisko struct an_card_rid_desc an_rid_desc; 1409108401Sambrisko struct an_command cmd; 1410108401Sambrisko struct an_reply reply; 1411198987Sjhb struct ifnet *ifp; 141255992Swpaul u_int16_t *ptr; 141378639Sbrooks u_int8_t *ptr2; 141455992Swpaul int i, len; 141555992Swpaul 1416175445Sambrisko AN_LOCK_ASSERT(sc); 141778639Sbrooks if (ltv->an_len < 4 || ltv->an_type == 0) 141855992Swpaul return(EINVAL); 141955992Swpaul 1420198987Sjhb ifp = sc->an_ifp; 1421108401Sambrisko if (!sc->mpi350){ 1422108401Sambrisko /* Tell the NIC to enter record read mode. */ 1423108401Sambrisko if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type)) { 1424198987Sjhb if_printf(ifp, "RID access failed\n"); 1425108401Sambrisko return(EIO); 1426108401Sambrisko } 142755992Swpaul 1428108401Sambrisko /* Seek to the record. */ 1429108401Sambrisko if (an_seek(sc, ltv->an_type, 0, AN_BAP1)) { 1430198987Sjhb if_printf(ifp, "seek to record failed\n"); 1431108401Sambrisko return(EIO); 1432108401Sambrisko } 143355992Swpaul 1434108401Sambrisko /* 1435108401Sambrisko * Read the length and record type and make sure they 1436108401Sambrisko * match what we expect (this verifies that we have enough 1437108401Sambrisko * room to hold all of the returned data). 1438108401Sambrisko * Length includes type but not length. 1439108401Sambrisko */ 1440108401Sambrisko len = CSR_READ_2(sc, AN_DATA1); 1441108401Sambrisko if (len > (ltv->an_len - 2)) { 1442198987Sjhb if_printf(ifp, "record length mismatch -- expected %d, " 1443198987Sjhb "got %d for Rid %x\n", 1444108401Sambrisko ltv->an_len - 2, len, ltv->an_type); 1445108401Sambrisko len = ltv->an_len - 2; 1446108401Sambrisko } else { 1447108401Sambrisko ltv->an_len = len + 2; 1448108401Sambrisko } 1449108401Sambrisko 1450108401Sambrisko /* Now read the data. */ 1451108401Sambrisko len -= 2; /* skip the type */ 1452108401Sambrisko ptr = <v->an_val; 1453108401Sambrisko for (i = len; i > 1; i -= 2) 1454108401Sambrisko *ptr++ = CSR_READ_2(sc, AN_DATA1); 1455108401Sambrisko if (i) { 1456108401Sambrisko ptr2 = (u_int8_t *)ptr; 1457108401Sambrisko *ptr2 = CSR_READ_1(sc, AN_DATA1); 1458108401Sambrisko } 1459108401Sambrisko } else { /* MPI-350 */ 1460123978Sambrisko if (!sc->an_rid_buffer.an_dma_vaddr) 1461123978Sambrisko return(EIO); 1462108401Sambrisko an_rid_desc.an_valid = 1; 1463108401Sambrisko an_rid_desc.an_len = AN_RID_BUFFER_SIZE; 1464108401Sambrisko an_rid_desc.an_rid = 0; 1465108401Sambrisko an_rid_desc.an_phys = sc->an_rid_buffer.an_dma_paddr; 1466108401Sambrisko bzero(sc->an_rid_buffer.an_dma_vaddr, AN_RID_BUFFER_SIZE); 1467108401Sambrisko 1468108401Sambrisko bzero(&cmd, sizeof(cmd)); 1469108401Sambrisko bzero(&reply, sizeof(reply)); 1470108401Sambrisko cmd.an_cmd = AN_CMD_ACCESS|AN_ACCESS_READ; 1471108401Sambrisko cmd.an_parm0 = ltv->an_type; 1472108401Sambrisko 1473108401Sambrisko for (i = 0; i < sizeof(an_rid_desc) / 4; i++) 1474175445Sambrisko CSR_MEM_AUX_WRITE_4(sc, AN_HOST_DESC_OFFSET + i * 4, 1475155321Simp ((u_int32_t *)(void *)&an_rid_desc)[i]); 1476108401Sambrisko 1477108401Sambrisko if (an_cmd_struct(sc, &cmd, &reply) 1478108401Sambrisko || reply.an_status & AN_CMD_QUAL_MASK) { 1479198987Sjhb if_printf(ifp, "failed to read RID %x %x %x %x %x, %d\n", 1480198987Sjhb ltv->an_type, 1481108401Sambrisko reply.an_status, 1482108401Sambrisko reply.an_resp0, 1483108401Sambrisko reply.an_resp1, 1484108401Sambrisko reply.an_resp2, 1485108401Sambrisko i); 1486108401Sambrisko return(EIO); 1487108401Sambrisko } 1488108401Sambrisko 1489108401Sambrisko an_ltv = (struct an_ltv_gen *)sc->an_rid_buffer.an_dma_vaddr; 1490108401Sambrisko if (an_ltv->an_len + 2 < an_rid_desc.an_len) { 1491108401Sambrisko an_rid_desc.an_len = an_ltv->an_len; 1492108401Sambrisko } 1493108401Sambrisko 1494123978Sambrisko len = an_rid_desc.an_len; 1495123978Sambrisko if (len > (ltv->an_len - 2)) { 1496198987Sjhb if_printf(ifp, "record length mismatch -- expected %d, " 1497198987Sjhb "got %d for Rid %x\n", 1498123978Sambrisko ltv->an_len - 2, len, ltv->an_type); 1499123978Sambrisko len = ltv->an_len - 2; 1500123978Sambrisko } else { 1501123978Sambrisko ltv->an_len = len + 2; 1502123978Sambrisko } 1503123978Sambrisko bcopy(&an_ltv->an_type, 1504175445Sambrisko <v->an_val, 1505123978Sambrisko len); 150655992Swpaul } 150755992Swpaul 150878639Sbrooks if (an_dump) 150978639Sbrooks an_dump_record(sc, ltv, "Read"); 151055992Swpaul 151155992Swpaul return(0); 151255992Swpaul} 151355992Swpaul 151455992Swpaul/* 151555992Swpaul * Same as read, except we inject data instead of reading it. 151655992Swpaul */ 151783270Sbrooksstatic int 1518150446Simpan_write_record(struct an_softc *sc, struct an_ltv_gen *ltv) 151955992Swpaul{ 1520108401Sambrisko struct an_card_rid_desc an_rid_desc; 1521108401Sambrisko struct an_command cmd; 1522108401Sambrisko struct an_reply reply; 152355992Swpaul u_int16_t *ptr; 152478639Sbrooks u_int8_t *ptr2; 152578639Sbrooks int i, len; 152655992Swpaul 1527175445Sambrisko AN_LOCK_ASSERT(sc); 152878639Sbrooks if (an_dump) 152978639Sbrooks an_dump_record(sc, ltv, "Write"); 153078639Sbrooks 1531108401Sambrisko if (!sc->mpi350){ 1532108401Sambrisko if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type)) 1533108401Sambrisko return(EIO); 153483270Sbrooks 1535108401Sambrisko if (an_seek(sc, ltv->an_type, 0, AN_BAP1)) 1536108401Sambrisko return(EIO); 1537108401Sambrisko 1538108401Sambrisko /* 1539108401Sambrisko * Length includes type but not length. 1540108401Sambrisko */ 1541108401Sambrisko len = ltv->an_len - 2; 1542108401Sambrisko CSR_WRITE_2(sc, AN_DATA1, len); 1543108401Sambrisko 1544108401Sambrisko len -= 2; /* skip the type */ 1545108401Sambrisko ptr = <v->an_val; 1546108401Sambrisko for (i = len; i > 1; i -= 2) 1547108401Sambrisko CSR_WRITE_2(sc, AN_DATA1, *ptr++); 1548108401Sambrisko if (i) { 1549108401Sambrisko ptr2 = (u_int8_t *)ptr; 1550108401Sambrisko CSR_WRITE_1(sc, AN_DATA0, *ptr2); 1551108401Sambrisko } 1552108401Sambrisko 1553108401Sambrisko if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_WRITE, ltv->an_type)) 1554108401Sambrisko return(EIO); 1555175445Sambrisko } else { 1556110104Sambrisko /* MPI-350 */ 1557108401Sambrisko 1558108401Sambrisko for (i = 0; i != AN_TIMEOUT; i++) { 1559175445Sambrisko if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) 1560110104Sambrisko & AN_CMD_BUSY) { 1561108401Sambrisko DELAY(10); 1562110104Sambrisko } else 1563108401Sambrisko break; 1564108401Sambrisko } 1565108401Sambrisko if (i == AN_TIMEOUT) { 1566108401Sambrisko printf("BUSY\n"); 1567108401Sambrisko } 1568108401Sambrisko 1569108401Sambrisko an_rid_desc.an_valid = 1; 1570108401Sambrisko an_rid_desc.an_len = ltv->an_len - 2; 1571108401Sambrisko an_rid_desc.an_rid = ltv->an_type; 1572108401Sambrisko an_rid_desc.an_phys = sc->an_rid_buffer.an_dma_paddr; 1573108401Sambrisko 1574108401Sambrisko bcopy(<v->an_type, sc->an_rid_buffer.an_dma_vaddr, 1575108401Sambrisko an_rid_desc.an_len); 1576108401Sambrisko 1577108401Sambrisko bzero(&cmd,sizeof(cmd)); 1578108401Sambrisko bzero(&reply,sizeof(reply)); 1579108401Sambrisko cmd.an_cmd = AN_CMD_ACCESS|AN_ACCESS_WRITE; 1580108401Sambrisko cmd.an_parm0 = ltv->an_type; 1581108401Sambrisko 1582108401Sambrisko for (i = 0; i < sizeof(an_rid_desc) / 4; i++) 1583175445Sambrisko CSR_MEM_AUX_WRITE_4(sc, AN_HOST_DESC_OFFSET + i * 4, 1584155321Simp ((u_int32_t *)(void *)&an_rid_desc)[i]); 1585108401Sambrisko 1586110531Sambrisko DELAY(100000); 1587110531Sambrisko 1588108401Sambrisko if ((i = an_cmd_struct(sc, &cmd, &reply))) { 1589198987Sjhb if_printf(sc->an_ifp, 1590198987Sjhb "failed to write RID 1 %x %x %x %x %x, %d\n", 1591198987Sjhb ltv->an_type, 1592110104Sambrisko reply.an_status, 1593110104Sambrisko reply.an_resp0, 1594110104Sambrisko reply.an_resp1, 1595110104Sambrisko reply.an_resp2, 1596110104Sambrisko i); 1597110104Sambrisko return(EIO); 1598108401Sambrisko } 159955992Swpaul 160083270Sbrooks 1601108401Sambrisko if (reply.an_status & AN_CMD_QUAL_MASK) { 1602198987Sjhb if_printf(sc->an_ifp, 1603198987Sjhb "failed to write RID 2 %x %x %x %x %x, %d\n", 1604198987Sjhb ltv->an_type, 1605110104Sambrisko reply.an_status, 1606110104Sambrisko reply.an_resp0, 1607110104Sambrisko reply.an_resp1, 1608110104Sambrisko reply.an_resp2, 1609110104Sambrisko i); 1610108401Sambrisko return(EIO); 1611108401Sambrisko } 1612110531Sambrisko DELAY(100000); 161378639Sbrooks } 161455992Swpaul 161555992Swpaul return(0); 161655992Swpaul} 161755992Swpaul 161883270Sbrooksstatic void 1619150446Simpan_dump_record(struct an_softc *sc, struct an_ltv_gen *ltv, char *string) 162078639Sbrooks{ 162178639Sbrooks u_int8_t *ptr2; 162278639Sbrooks int len; 162378639Sbrooks int i; 162478639Sbrooks int count = 0; 162578639Sbrooks char buf[17], temp; 162678639Sbrooks 162778639Sbrooks len = ltv->an_len - 4; 1628198987Sjhb if_printf(sc->an_ifp, "RID %4x, Length %4d, Mode %s\n", 1629198987Sjhb ltv->an_type, ltv->an_len - 4, string); 163078639Sbrooks 163178639Sbrooks if (an_dump == 1 || (an_dump == ltv->an_type)) { 1632198987Sjhb if_printf(sc->an_ifp, "\t"); 163378639Sbrooks bzero(buf,sizeof(buf)); 163478639Sbrooks 163578639Sbrooks ptr2 = (u_int8_t *)<v->an_val; 163678639Sbrooks for (i = len; i > 0; i--) { 163778639Sbrooks printf("%02x ", *ptr2); 163878639Sbrooks 163978639Sbrooks temp = *ptr2++; 1640154866Snjl if (isprint(temp)) 164178639Sbrooks buf[count] = temp; 164278639Sbrooks else 164378639Sbrooks buf[count] = '.'; 164478639Sbrooks if (++count == 16) { 164578639Sbrooks count = 0; 164678639Sbrooks printf("%s\n",buf); 1647198987Sjhb if_printf(sc->an_ifp, "\t"); 164878639Sbrooks bzero(buf,sizeof(buf)); 164978639Sbrooks } 165078639Sbrooks } 165178639Sbrooks for (; count != 16; count++) { 165278639Sbrooks printf(" "); 165378639Sbrooks } 165478639Sbrooks printf(" %s\n",buf); 165578639Sbrooks } 165678639Sbrooks} 165778639Sbrooks 165883270Sbrooksstatic int 1659150446Simpan_seek(struct an_softc *sc, int id, int off, int chan) 166055992Swpaul{ 166155992Swpaul int i; 166255992Swpaul int selreg, offreg; 166355992Swpaul 166455992Swpaul switch (chan) { 166555992Swpaul case AN_BAP0: 166655992Swpaul selreg = AN_SEL0; 166755992Swpaul offreg = AN_OFF0; 166855992Swpaul break; 166955992Swpaul case AN_BAP1: 167055992Swpaul selreg = AN_SEL1; 167155992Swpaul offreg = AN_OFF1; 167255992Swpaul break; 167355992Swpaul default: 1674198987Sjhb if_printf(sc->an_ifp, "invalid data path: %x\n", chan); 167555992Swpaul return(EIO); 167655992Swpaul } 167755992Swpaul 167855992Swpaul CSR_WRITE_2(sc, selreg, id); 167955992Swpaul CSR_WRITE_2(sc, offreg, off); 168055992Swpaul 168155992Swpaul for (i = 0; i < AN_TIMEOUT; i++) { 168255992Swpaul if (!(CSR_READ_2(sc, offreg) & (AN_OFF_BUSY|AN_OFF_ERR))) 168355992Swpaul break; 168455992Swpaul } 168555992Swpaul 168655992Swpaul if (i == AN_TIMEOUT) 168755992Swpaul return(ETIMEDOUT); 168855992Swpaul 168955992Swpaul return(0); 169055992Swpaul} 169155992Swpaul 169283270Sbrooksstatic int 1693150446Simpan_read_data(struct an_softc *sc, int id, int off, caddr_t buf, int len) 169455992Swpaul{ 169555992Swpaul int i; 169655992Swpaul u_int16_t *ptr; 169755992Swpaul u_int8_t *ptr2; 169855992Swpaul 169955992Swpaul if (off != -1) { 170055992Swpaul if (an_seek(sc, id, off, AN_BAP1)) 170155992Swpaul return(EIO); 170255992Swpaul } 170355992Swpaul 170455992Swpaul ptr = (u_int16_t *)buf; 170578639Sbrooks for (i = len; i > 1; i -= 2) 170678639Sbrooks *ptr++ = CSR_READ_2(sc, AN_DATA1); 170778639Sbrooks if (i) { 170878639Sbrooks ptr2 = (u_int8_t *)ptr; 170978639Sbrooks *ptr2 = CSR_READ_1(sc, AN_DATA1); 171055992Swpaul } 171155992Swpaul 171255992Swpaul return(0); 171355992Swpaul} 171455992Swpaul 171583270Sbrooksstatic int 1716150446Simpan_write_data(struct an_softc *sc, int id, int off, caddr_t buf, int len) 171755992Swpaul{ 171855992Swpaul int i; 171955992Swpaul u_int16_t *ptr; 172055992Swpaul u_int8_t *ptr2; 172155992Swpaul 172255992Swpaul if (off != -1) { 172355992Swpaul if (an_seek(sc, id, off, AN_BAP0)) 172455992Swpaul return(EIO); 172555992Swpaul } 172655992Swpaul 172755992Swpaul ptr = (u_int16_t *)buf; 172878639Sbrooks for (i = len; i > 1; i -= 2) 172978639Sbrooks CSR_WRITE_2(sc, AN_DATA0, *ptr++); 173078639Sbrooks if (i) { 1731175446Sambrisko ptr2 = (u_int8_t *)ptr; 1732175446Sambrisko CSR_WRITE_1(sc, AN_DATA0, *ptr2); 173355992Swpaul } 173455992Swpaul 173555992Swpaul return(0); 173655992Swpaul} 173755992Swpaul 173855992Swpaul/* 173955992Swpaul * Allocate a region of memory inside the NIC and zero 174055992Swpaul * it out. 174155992Swpaul */ 174283270Sbrooksstatic int 1743150446Simpan_alloc_nicmem(struct an_softc *sc, int len, int *id) 174455992Swpaul{ 174555992Swpaul int i; 174655992Swpaul 174755992Swpaul if (an_cmd(sc, AN_CMD_ALLOC_MEM, len)) { 1748198987Sjhb if_printf(sc->an_ifp, "failed to allocate %d bytes on NIC\n", 1749198987Sjhb len); 175055992Swpaul return(ENOMEM); 175155992Swpaul } 175255992Swpaul 175355992Swpaul for (i = 0; i < AN_TIMEOUT; i++) { 1754108401Sambrisko if (CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350)) & AN_EV_ALLOC) 175555992Swpaul break; 175655992Swpaul } 175755992Swpaul 175855992Swpaul if (i == AN_TIMEOUT) 175955992Swpaul return(ETIMEDOUT); 176055992Swpaul 1761108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_ALLOC); 176255992Swpaul *id = CSR_READ_2(sc, AN_ALLOC_FID); 176355992Swpaul 176455992Swpaul if (an_seek(sc, *id, 0, AN_BAP0)) 176555992Swpaul return(EIO); 176655992Swpaul 176755992Swpaul for (i = 0; i < len / 2; i++) 176855992Swpaul CSR_WRITE_2(sc, AN_DATA0, 0); 176955992Swpaul 177055992Swpaul return(0); 177155992Swpaul} 177255992Swpaul 177383270Sbrooksstatic void 1774150446Simpan_setdef(struct an_softc *sc, struct an_req *areq) 177555992Swpaul{ 177655992Swpaul struct ifnet *ifp; 177755992Swpaul struct an_ltv_genconfig *cfg; 1778119156Sambrisko struct an_ltv_ssidlist_new *ssid; 177955992Swpaul struct an_ltv_aplist *ap; 178055992Swpaul struct an_ltv_gen *sp; 178155992Swpaul 1782147256Sbrooks ifp = sc->an_ifp; 178355992Swpaul 1784175445Sambrisko AN_LOCK_ASSERT(sc); 178555992Swpaul switch (areq->an_type) { 178655992Swpaul case AN_RID_GENCONFIG: 178755992Swpaul cfg = (struct an_ltv_genconfig *)areq; 178855992Swpaul 1789152315Sru bcopy((char *)&cfg->an_macaddr, IF_LLADDR(sc->an_ifp), 179055992Swpaul ETHER_ADDR_LEN); 179155992Swpaul 179255992Swpaul bcopy((char *)cfg, (char *)&sc->an_config, 179355992Swpaul sizeof(struct an_ltv_genconfig)); 179455992Swpaul break; 179555992Swpaul case AN_RID_SSIDLIST: 1796119156Sambrisko ssid = (struct an_ltv_ssidlist_new *)areq; 179755992Swpaul bcopy((char *)ssid, (char *)&sc->an_ssidlist, 1798119156Sambrisko sizeof(struct an_ltv_ssidlist_new)); 179955992Swpaul break; 180055992Swpaul case AN_RID_APLIST: 180155992Swpaul ap = (struct an_ltv_aplist *)areq; 180255992Swpaul bcopy((char *)ap, (char *)&sc->an_aplist, 180355992Swpaul sizeof(struct an_ltv_aplist)); 180455992Swpaul break; 180555992Swpaul case AN_RID_TX_SPEED: 180655992Swpaul sp = (struct an_ltv_gen *)areq; 180755992Swpaul sc->an_tx_rate = sp->an_val; 1808110253Sambrisko 1809110253Sambrisko /* Read the current configuration */ 1810110253Sambrisko sc->an_config.an_type = AN_RID_GENCONFIG; 1811110253Sambrisko sc->an_config.an_len = sizeof(struct an_ltv_genconfig); 1812110253Sambrisko an_read_record(sc, (struct an_ltv_gen *)&sc->an_config); 1813110253Sambrisko cfg = &sc->an_config; 1814110253Sambrisko 1815110253Sambrisko /* clear other rates and set the only one we want */ 1816110253Sambrisko bzero(cfg->an_rates, sizeof(cfg->an_rates)); 1817110253Sambrisko cfg->an_rates[0] = sc->an_tx_rate; 1818110253Sambrisko 1819110253Sambrisko /* Save the new rate */ 1820110253Sambrisko sc->an_config.an_type = AN_RID_GENCONFIG; 1821110253Sambrisko sc->an_config.an_len = sizeof(struct an_ltv_genconfig); 182255992Swpaul break; 182368692Swpaul case AN_RID_WEP_TEMP: 1824110531Sambrisko /* Cache the temp keys */ 1825175445Sambrisko bcopy(areq, 1826175445Sambrisko &sc->an_temp_keys[((struct an_ltv_key *)areq)->kindex], 1827110531Sambrisko sizeof(struct an_ltv_key)); 182868692Swpaul case AN_RID_WEP_PERM: 182988748Sambrisko case AN_RID_LEAPUSERNAME: 183088748Sambrisko case AN_RID_LEAPPASSWORD: 1831199154Sjhb an_init_locked(sc); 1832119156Sambrisko 183368692Swpaul /* Disable the MAC. */ 183468692Swpaul an_cmd(sc, AN_CMD_DISABLE, 0); 183583270Sbrooks 183683269Sbrooks /* Write the key */ 183768692Swpaul an_write_record(sc, (struct an_ltv_gen *)areq); 183883270Sbrooks 183983270Sbrooks /* Turn the MAC back on. */ 184068692Swpaul an_cmd(sc, AN_CMD_ENABLE, 0); 184183270Sbrooks 184268692Swpaul break; 184383269Sbrooks case AN_RID_MONITOR_MODE: 184483269Sbrooks cfg = (struct an_ltv_genconfig *)areq; 184583269Sbrooks bpfdetach(ifp); 184683269Sbrooks if (ng_ether_detach_p != NULL) 184783269Sbrooks (*ng_ether_detach_p) (ifp); 184883269Sbrooks sc->an_monitor = cfg->an_len; 184983269Sbrooks 185083270Sbrooks if (sc->an_monitor & AN_MONITOR) { 185183270Sbrooks if (sc->an_monitor & AN_MONITOR_AIRONET_HEADER) { 185283270Sbrooks bpfattach(ifp, DLT_AIRONET_HEADER, 185383269Sbrooks sizeof(struct ether_header)); 185483269Sbrooks } else { 185583270Sbrooks bpfattach(ifp, DLT_IEEE802_11, 185683269Sbrooks sizeof(struct ether_header)); 185783269Sbrooks } 185883269Sbrooks } else { 185983270Sbrooks bpfattach(ifp, DLT_EN10MB, 186083269Sbrooks sizeof(struct ether_header)); 186183269Sbrooks if (ng_ether_attach_p != NULL) 186283269Sbrooks (*ng_ether_attach_p) (ifp); 186383269Sbrooks } 186483269Sbrooks break; 186555992Swpaul default: 1866198987Sjhb if_printf(ifp, "unknown RID: %x\n", areq->an_type); 186755992Swpaul return; 186855992Swpaul } 186955992Swpaul 187055992Swpaul 187155992Swpaul /* Reinitialize the card. */ 1872199154Sjhb if (ifp->if_flags) 1873199154Sjhb an_init_locked(sc); 187455992Swpaul 187555992Swpaul return; 187655992Swpaul} 187755992Swpaul 187855992Swpaul/* 187983269Sbrooks * Derived from Linux driver to enable promiscious mode. 188055992Swpaul */ 188183269Sbrooks 188283270Sbrooksstatic void 1883150446Simpan_promisc(struct an_softc *sc, int promisc) 188455992Swpaul{ 1885175445Sambrisko AN_LOCK_ASSERT(sc); 1886150446Simp if (sc->an_was_monitor) { 188783269Sbrooks an_reset(sc); 1888108401Sambrisko if (sc->mpi350) 1889175445Sambrisko an_init_mpi350_desc(sc); 1890150446Simp } 1891199154Sjhb if (sc->an_monitor || sc->an_was_monitor) 1892199154Sjhb an_init_locked(sc); 189383269Sbrooks 189483269Sbrooks sc->an_was_monitor = sc->an_monitor; 189574698Sarchie an_cmd(sc, AN_CMD_SET_MODE, promisc ? 0xffff : 0); 189683270Sbrooks 189755992Swpaul return; 189855992Swpaul} 189955992Swpaul 190083270Sbrooksstatic int 1901150446Simpan_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 190255992Swpaul{ 190367094Swpaul int error = 0; 190477217Sphk int len; 1905119156Sambrisko int i, max; 190655992Swpaul struct an_softc *sc; 190755992Swpaul struct ifreq *ifr; 190893593Sjhb struct thread *td = curthread; 190977217Sphk struct ieee80211req *ireq; 1910172112Savatar struct ieee80211_channel ch; 191177217Sphk u_int8_t tmpstr[IEEE80211_NWID_LEN*2]; 191277217Sphk u_int8_t *tmpptr; 191377217Sphk struct an_ltv_genconfig *config; 191477217Sphk struct an_ltv_key *key; 191577217Sphk struct an_ltv_status *status; 1916119156Sambrisko struct an_ltv_ssidlist_new *ssids; 191788748Sambrisko int mode; 191888748Sambrisko struct aironet_ioctl l_ioctl; 191955992Swpaul 192055992Swpaul sc = ifp->if_softc; 192155992Swpaul ifr = (struct ifreq *)data; 192277217Sphk ireq = (struct ieee80211req *)data; 192355992Swpaul 192488749Sambrisko config = (struct an_ltv_genconfig *)&sc->areq; 192588749Sambrisko key = (struct an_ltv_key *)&sc->areq; 192688749Sambrisko status = (struct an_ltv_status *)&sc->areq; 1927119156Sambrisko ssids = (struct an_ltv_ssidlist_new *)&sc->areq; 192877217Sphk 192964429Speter if (sc->an_gone) { 193061816Sroberto error = ENODEV; 193161816Sroberto goto out; 193261816Sroberto } 193355992Swpaul 193483270Sbrooks switch (command) { 193555992Swpaul case SIOCSIFFLAGS: 1936175445Sambrisko AN_LOCK(sc); 193755992Swpaul if (ifp->if_flags & IFF_UP) { 1938148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING && 193955992Swpaul ifp->if_flags & IFF_PROMISC && 194055992Swpaul !(sc->an_if_flags & IFF_PROMISC)) { 194155992Swpaul an_promisc(sc, 1); 1942148887Srwatson } else if (ifp->if_drv_flags & IFF_DRV_RUNNING && 194355992Swpaul !(ifp->if_flags & IFF_PROMISC) && 194455992Swpaul sc->an_if_flags & IFF_PROMISC) { 194555992Swpaul an_promisc(sc, 0); 1946199154Sjhb } else 1947199154Sjhb an_init_locked(sc); 194855992Swpaul } else { 1949199154Sjhb if (ifp->if_drv_flags & IFF_DRV_RUNNING) 195055992Swpaul an_stop(sc); 195155992Swpaul } 1952199154Sjhb sc->an_if_flags = ifp->if_flags; 1953175445Sambrisko AN_UNLOCK(sc); 195455992Swpaul error = 0; 195555992Swpaul break; 195677217Sphk case SIOCSIFMEDIA: 195777217Sphk case SIOCGIFMEDIA: 195877217Sphk error = ifmedia_ioctl(ifp, ifr, &sc->an_ifmedia, command); 195977217Sphk break; 196055992Swpaul case SIOCADDMULTI: 196155992Swpaul case SIOCDELMULTI: 196255992Swpaul /* The Aironet has no multicast filter. */ 196355992Swpaul error = 0; 196455992Swpaul break; 196555992Swpaul case SIOCGAIRONET: 196688749Sambrisko error = copyin(ifr->ifr_data, &sc->areq, sizeof(sc->areq)); 196778639Sbrooks if (error != 0) 196855992Swpaul break; 1969175445Sambrisko AN_LOCK(sc); 197055992Swpaul#ifdef ANCACHE 197188749Sambrisko if (sc->areq.an_type == AN_RID_ZERO_CACHE) { 1972164033Srwatson error = priv_check(td, PRIV_DRIVER); 1973108259Srwatson if (error) 1974108259Srwatson break; 197555992Swpaul sc->an_sigitems = sc->an_nextitem = 0; 197655992Swpaul break; 197788749Sambrisko } else if (sc->areq.an_type == AN_RID_READ_CACHE) { 197888749Sambrisko char *pt = (char *)&sc->areq.an_val; 197955992Swpaul bcopy((char *)&sc->an_sigitems, (char *)pt, 198055992Swpaul sizeof(int)); 198155992Swpaul pt += sizeof(int); 198288749Sambrisko sc->areq.an_len = sizeof(int) / 2; 198355992Swpaul bcopy((char *)&sc->an_sigcache, (char *)pt, 198455992Swpaul sizeof(struct an_sigcache) * sc->an_sigitems); 198588749Sambrisko sc->areq.an_len += ((sizeof(struct an_sigcache) * 198655992Swpaul sc->an_sigitems) / 2) + 1; 198755992Swpaul } else 198855992Swpaul#endif 198988749Sambrisko if (an_read_record(sc, (struct an_ltv_gen *)&sc->areq)) { 1990175445Sambrisko AN_UNLOCK(sc); 199155992Swpaul error = EINVAL; 199255992Swpaul break; 199355992Swpaul } 1994171692Savatar AN_UNLOCK(sc); 199588749Sambrisko error = copyout(&sc->areq, ifr->ifr_data, sizeof(sc->areq)); 199655992Swpaul break; 199755992Swpaul case SIOCSAIRONET: 1998164033Srwatson if ((error = priv_check(td, PRIV_DRIVER))) 199964429Speter goto out; 2000175445Sambrisko AN_LOCK(sc); 200188749Sambrisko error = copyin(ifr->ifr_data, &sc->areq, sizeof(sc->areq)); 200278639Sbrooks if (error != 0) 200355992Swpaul break; 200488749Sambrisko an_setdef(sc, &sc->areq); 2005175445Sambrisko AN_UNLOCK(sc); 200655992Swpaul break; 2007175446Sambrisko case SIOCGPRIVATE_0: /* used by Cisco client utility */ 2008164033Srwatson if ((error = priv_check(td, PRIV_DRIVER))) 200992292Sambrisko goto out; 2010144242Ssam error = copyin(ifr->ifr_data, &l_ioctl, sizeof(l_ioctl)); 2011144242Ssam if (error) 2012144242Ssam goto out; 201388748Sambrisko mode = l_ioctl.command; 201488748Sambrisko 2015175445Sambrisko AN_LOCK(sc); 201688748Sambrisko if (mode >= AIROGCAP && mode <= AIROGSTATSD32) { 201788748Sambrisko error = readrids(ifp, &l_ioctl); 2018110104Sambrisko } else if (mode >= AIROPCAP && mode <= AIROPLEAPUSR) { 201988748Sambrisko error = writerids(ifp, &l_ioctl); 2020110104Sambrisko } else if (mode >= AIROFLSHRST && mode <= AIRORESTART) { 202188748Sambrisko error = flashcard(ifp, &l_ioctl); 2022110104Sambrisko } else { 202388748Sambrisko error =-1; 202488748Sambrisko } 2025175445Sambrisko AN_UNLOCK(sc); 2026144242Ssam if (!error) { 2027144242Ssam /* copy out the updated command info */ 2028144242Ssam error = copyout(&l_ioctl, ifr->ifr_data, sizeof(l_ioctl)); 2029144242Ssam } 203088748Sambrisko break; 2031175446Sambrisko case SIOCGPRIVATE_1: /* used by Cisco client utility */ 2032164033Srwatson if ((error = priv_check(td, PRIV_DRIVER))) 203392292Sambrisko goto out; 2034144242Ssam error = copyin(ifr->ifr_data, &l_ioctl, sizeof(l_ioctl)); 2035144242Ssam if (error) 2036144242Ssam goto out; 203788748Sambrisko l_ioctl.command = 0; 203888748Sambrisko error = AIROMAGIC; 2039144242Ssam (void) copyout(&error, l_ioctl.data, sizeof(error)); 2040175446Sambrisko error = 0; 204188748Sambrisko break; 204277217Sphk case SIOCG80211: 204388749Sambrisko sc->areq.an_len = sizeof(sc->areq); 204488748Sambrisko /* was that a good idea DJA we are doing a short-cut */ 204583270Sbrooks switch (ireq->i_type) { 204677217Sphk case IEEE80211_IOC_SSID: 2047175445Sambrisko AN_LOCK(sc); 204878639Sbrooks if (ireq->i_val == -1) { 204988749Sambrisko sc->areq.an_type = AN_RID_STATUS; 205077217Sphk if (an_read_record(sc, 205188749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 205277217Sphk error = EINVAL; 2053175445Sambrisko AN_UNLOCK(sc); 205477217Sphk break; 205577217Sphk } 205677217Sphk len = status->an_ssidlen; 205777217Sphk tmpptr = status->an_ssid; 205878639Sbrooks } else if (ireq->i_val >= 0) { 205988749Sambrisko sc->areq.an_type = AN_RID_SSIDLIST; 206077217Sphk if (an_read_record(sc, 206188749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 206277217Sphk error = EINVAL; 2063175445Sambrisko AN_UNLOCK(sc); 206477217Sphk break; 206577217Sphk } 2066119156Sambrisko max = (sc->areq.an_len - 4) 2067119156Sambrisko / sizeof(struct an_ltv_ssid_entry); 2068119156Sambrisko if ( max > MAX_SSIDS ) { 2069119156Sambrisko printf("To many SSIDs only using " 2070119156Sambrisko "%d of %d\n", 2071119156Sambrisko MAX_SSIDS, max); 2072119156Sambrisko max = MAX_SSIDS; 2073119156Sambrisko } 2074119156Sambrisko if (ireq->i_val > max) { 207577217Sphk error = EINVAL; 2076175445Sambrisko AN_UNLOCK(sc); 207777217Sphk break; 2078119156Sambrisko } else { 2079119156Sambrisko len = ssids->an_entry[ireq->i_val].an_len; 2080119156Sambrisko tmpptr = ssids->an_entry[ireq->i_val].an_ssid; 208177217Sphk } 208277217Sphk } else { 208377217Sphk error = EINVAL; 2084175445Sambrisko AN_UNLOCK(sc); 208577217Sphk break; 208677217Sphk } 208778639Sbrooks if (len > IEEE80211_NWID_LEN) { 208877217Sphk error = EINVAL; 2089175445Sambrisko AN_UNLOCK(sc); 209077217Sphk break; 209177217Sphk } 2092175445Sambrisko AN_UNLOCK(sc); 209377217Sphk ireq->i_len = len; 209477217Sphk bzero(tmpstr, IEEE80211_NWID_LEN); 209577217Sphk bcopy(tmpptr, tmpstr, len); 209677217Sphk error = copyout(tmpstr, ireq->i_data, 209777217Sphk IEEE80211_NWID_LEN); 209877217Sphk break; 209977217Sphk case IEEE80211_IOC_NUMSSIDS: 2100175445Sambrisko AN_LOCK(sc); 2101119156Sambrisko sc->areq.an_len = sizeof(sc->areq); 2102119156Sambrisko sc->areq.an_type = AN_RID_SSIDLIST; 2103119156Sambrisko if (an_read_record(sc, 2104119156Sambrisko (struct an_ltv_gen *)&sc->areq)) { 2105175445Sambrisko AN_UNLOCK(sc); 2106119156Sambrisko error = EINVAL; 2107119156Sambrisko break; 2108119156Sambrisko } 2109119156Sambrisko max = (sc->areq.an_len - 4) 2110119156Sambrisko / sizeof(struct an_ltv_ssid_entry); 2111175445Sambrisko AN_UNLOCK(sc); 2112119156Sambrisko if ( max > MAX_SSIDS ) { 2113119156Sambrisko printf("To many SSIDs only using " 2114119156Sambrisko "%d of %d\n", 2115119156Sambrisko MAX_SSIDS, max); 2116119156Sambrisko max = MAX_SSIDS; 2117119156Sambrisko } 2118119156Sambrisko ireq->i_val = max; 211977217Sphk break; 212077217Sphk case IEEE80211_IOC_WEP: 2121175445Sambrisko AN_LOCK(sc); 212288749Sambrisko sc->areq.an_type = AN_RID_ACTUALCFG; 212377217Sphk if (an_read_record(sc, 212488749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 212577217Sphk error = EINVAL; 2126175445Sambrisko AN_UNLOCK(sc); 212777217Sphk break; 212877217Sphk } 2129175445Sambrisko AN_UNLOCK(sc); 213078639Sbrooks if (config->an_authtype & AN_AUTHTYPE_PRIVACY_IN_USE) { 213178639Sbrooks if (config->an_authtype & 213277217Sphk AN_AUTHTYPE_ALLOW_UNENCRYPTED) 213377217Sphk ireq->i_val = IEEE80211_WEP_MIXED; 213477217Sphk else 213577217Sphk ireq->i_val = IEEE80211_WEP_ON; 213677217Sphk } else { 213777217Sphk ireq->i_val = IEEE80211_WEP_OFF; 213877217Sphk } 213977217Sphk break; 214077217Sphk case IEEE80211_IOC_WEPKEY: 214177217Sphk /* 214277217Sphk * XXX: I'm not entierly convinced this is 214377217Sphk * correct, but it's what is implemented in 214477217Sphk * ancontrol so it will have to do until we get 214577217Sphk * access to actual Cisco code. 214677217Sphk */ 214788748Sambrisko if (ireq->i_val < 0 || ireq->i_val > 8) { 214877217Sphk error = EINVAL; 214977217Sphk break; 215077217Sphk } 215177217Sphk len = 0; 215288748Sambrisko if (ireq->i_val < 5) { 2153175445Sambrisko AN_LOCK(sc); 215488749Sambrisko sc->areq.an_type = AN_RID_WEP_TEMP; 215578639Sbrooks for (i = 0; i < 5; i++) { 215677217Sphk if (an_read_record(sc, 215788749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 215877217Sphk error = EINVAL; 215977217Sphk break; 216077217Sphk } 216178639Sbrooks if (key->kindex == 0xffff) 216277217Sphk break; 216378639Sbrooks if (key->kindex == ireq->i_val) 216478639Sbrooks len = key->klen; 216577217Sphk /* Required to get next entry */ 216688749Sambrisko sc->areq.an_type = AN_RID_WEP_PERM; 216777217Sphk } 2168175445Sambrisko AN_UNLOCK(sc); 2169175445Sambrisko if (error != 0) { 217077217Sphk break; 2171175445Sambrisko } 217277217Sphk } 217377217Sphk /* We aren't allowed to read the value of the 217477217Sphk * key from the card so we just output zeros 217577217Sphk * like we would if we could read the card, but 217677217Sphk * denied the user access. 217777217Sphk */ 217877217Sphk bzero(tmpstr, len); 217977217Sphk ireq->i_len = len; 218077217Sphk error = copyout(tmpstr, ireq->i_data, len); 218177217Sphk break; 218277217Sphk case IEEE80211_IOC_NUMWEPKEYS: 218388748Sambrisko ireq->i_val = 9; /* include home key */ 218477217Sphk break; 218577217Sphk case IEEE80211_IOC_WEPTXKEY: 218678639Sbrooks /* 218778639Sbrooks * For some strange reason, you have to read all 218878639Sbrooks * keys before you can read the txkey. 218978639Sbrooks */ 2190175445Sambrisko AN_LOCK(sc); 219188749Sambrisko sc->areq.an_type = AN_RID_WEP_TEMP; 219278639Sbrooks for (i = 0; i < 5; i++) { 219378639Sbrooks if (an_read_record(sc, 219488749Sambrisko (struct an_ltv_gen *) &sc->areq)) { 219578639Sbrooks error = EINVAL; 219678639Sbrooks break; 219778639Sbrooks } 2198175445Sambrisko if (key->kindex == 0xffff) { 219978639Sbrooks break; 2200175445Sambrisko } 220178639Sbrooks /* Required to get next entry */ 220288749Sambrisko sc->areq.an_type = AN_RID_WEP_PERM; 220378639Sbrooks } 2204175445Sambrisko if (error != 0) { 2205175445Sambrisko AN_UNLOCK(sc); 220678639Sbrooks break; 2207175445Sambrisko } 220878639Sbrooks 220988749Sambrisko sc->areq.an_type = AN_RID_WEP_PERM; 221077217Sphk key->kindex = 0xffff; 221177217Sphk if (an_read_record(sc, 221288749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 221377217Sphk error = EINVAL; 2214175445Sambrisko AN_UNLOCK(sc); 221577217Sphk break; 221677217Sphk } 221777217Sphk ireq->i_val = key->mac[0]; 221888748Sambrisko /* 221988748Sambrisko * Check for home mode. Map home mode into 222088748Sambrisko * 5th key since that is how it is stored on 222188748Sambrisko * the card 222288748Sambrisko */ 222388749Sambrisko sc->areq.an_len = sizeof(struct an_ltv_genconfig); 222488749Sambrisko sc->areq.an_type = AN_RID_GENCONFIG; 222588748Sambrisko if (an_read_record(sc, 222688749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 222788748Sambrisko error = EINVAL; 2228175445Sambrisko AN_UNLOCK(sc); 222988748Sambrisko break; 223088748Sambrisko } 223188748Sambrisko if (config->an_home_product & AN_HOME_NETWORK) 223288748Sambrisko ireq->i_val = 4; 2233175445Sambrisko AN_UNLOCK(sc); 223477217Sphk break; 223577217Sphk case IEEE80211_IOC_AUTHMODE: 2236175445Sambrisko AN_LOCK(sc); 223788749Sambrisko sc->areq.an_type = AN_RID_ACTUALCFG; 223877217Sphk if (an_read_record(sc, 223988749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 224077217Sphk error = EINVAL; 2241175445Sambrisko AN_UNLOCK(sc); 224277217Sphk break; 224377217Sphk } 2244175445Sambrisko AN_UNLOCK(sc); 224577217Sphk if ((config->an_authtype & AN_AUTHTYPE_MASK) == 224677217Sphk AN_AUTHTYPE_NONE) { 224777217Sphk ireq->i_val = IEEE80211_AUTH_NONE; 224877217Sphk } else if ((config->an_authtype & AN_AUTHTYPE_MASK) == 224977217Sphk AN_AUTHTYPE_OPEN) { 225077217Sphk ireq->i_val = IEEE80211_AUTH_OPEN; 225177217Sphk } else if ((config->an_authtype & AN_AUTHTYPE_MASK) == 225277217Sphk AN_AUTHTYPE_SHAREDKEY) { 225377217Sphk ireq->i_val = IEEE80211_AUTH_SHARED; 225477217Sphk } else 225577217Sphk error = EINVAL; 225677217Sphk break; 225777217Sphk case IEEE80211_IOC_STATIONNAME: 2258175445Sambrisko AN_LOCK(sc); 225988749Sambrisko sc->areq.an_type = AN_RID_ACTUALCFG; 226077217Sphk if (an_read_record(sc, 226188749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 226277217Sphk error = EINVAL; 2263175445Sambrisko AN_UNLOCK(sc); 226477217Sphk break; 226577217Sphk } 2266175445Sambrisko AN_UNLOCK(sc); 226777217Sphk ireq->i_len = sizeof(config->an_nodename); 226877217Sphk tmpptr = config->an_nodename; 226977217Sphk bzero(tmpstr, IEEE80211_NWID_LEN); 227077217Sphk bcopy(tmpptr, tmpstr, ireq->i_len); 227177217Sphk error = copyout(tmpstr, ireq->i_data, 227277217Sphk IEEE80211_NWID_LEN); 227377217Sphk break; 227477217Sphk case IEEE80211_IOC_CHANNEL: 2275175445Sambrisko AN_LOCK(sc); 227688749Sambrisko sc->areq.an_type = AN_RID_STATUS; 227777217Sphk if (an_read_record(sc, 227888749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 227977217Sphk error = EINVAL; 2280175445Sambrisko AN_UNLOCK(sc); 228177217Sphk break; 228277217Sphk } 2283175445Sambrisko AN_UNLOCK(sc); 228477217Sphk ireq->i_val = status->an_cur_channel; 228577217Sphk break; 2286175445Sambrisko case IEEE80211_IOC_CURCHAN: 2287175445Sambrisko AN_LOCK(sc); 2288175445Sambrisko sc->areq.an_type = AN_RID_STATUS; 2289175445Sambrisko if (an_read_record(sc, 2290175445Sambrisko (struct an_ltv_gen *)&sc->areq)) { 2291172112Savatar error = EINVAL; 2292175445Sambrisko AN_UNLOCK(sc); 2293172112Savatar break; 2294172112Savatar } 2295175445Sambrisko AN_UNLOCK(sc); 2296172112Savatar bzero(&ch, sizeof(ch)); 2297172112Savatar ch.ic_freq = ieee80211_ieee2mhz(status->an_cur_channel, 2298172112Savatar IEEE80211_CHAN_B); 2299172112Savatar ch.ic_flags = IEEE80211_CHAN_B; 2300172112Savatar ch.ic_ieee = status->an_cur_channel; 2301172112Savatar error = copyout(&ch, ireq->i_data, sizeof(ch)); 2302172112Savatar break; 230377217Sphk case IEEE80211_IOC_POWERSAVE: 2304175445Sambrisko AN_LOCK(sc); 230588749Sambrisko sc->areq.an_type = AN_RID_ACTUALCFG; 230677217Sphk if (an_read_record(sc, 230788749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 230877217Sphk error = EINVAL; 2309175445Sambrisko AN_UNLOCK(sc); 231077217Sphk break; 231177217Sphk } 2312175445Sambrisko AN_UNLOCK(sc); 231378639Sbrooks if (config->an_psave_mode == AN_PSAVE_NONE) { 231477217Sphk ireq->i_val = IEEE80211_POWERSAVE_OFF; 231578639Sbrooks } else if (config->an_psave_mode == AN_PSAVE_CAM) { 231677217Sphk ireq->i_val = IEEE80211_POWERSAVE_CAM; 231778639Sbrooks } else if (config->an_psave_mode == AN_PSAVE_PSP) { 231877217Sphk ireq->i_val = IEEE80211_POWERSAVE_PSP; 231978639Sbrooks } else if (config->an_psave_mode == AN_PSAVE_PSP_CAM) { 232077217Sphk ireq->i_val = IEEE80211_POWERSAVE_PSP_CAM; 232177217Sphk } else 232277217Sphk error = EINVAL; 232377217Sphk break; 232477217Sphk case IEEE80211_IOC_POWERSAVESLEEP: 2325175445Sambrisko AN_LOCK(sc); 232688749Sambrisko sc->areq.an_type = AN_RID_ACTUALCFG; 232777217Sphk if (an_read_record(sc, 232888749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 232977217Sphk error = EINVAL; 2330175445Sambrisko AN_UNLOCK(sc); 233177217Sphk break; 233277217Sphk } 2333175445Sambrisko AN_UNLOCK(sc); 233477217Sphk ireq->i_val = config->an_listen_interval; 233577217Sphk break; 233683270Sbrooks } 233777217Sphk break; 233877217Sphk case SIOCS80211: 2339164033Srwatson if ((error = priv_check(td, PRIV_NET80211_MANAGE))) 234077217Sphk goto out; 2341175445Sambrisko AN_LOCK(sc); 234288749Sambrisko sc->areq.an_len = sizeof(sc->areq); 234377217Sphk /* 234477217Sphk * We need a config structure for everything but the WEP 234577217Sphk * key management and SSIDs so we get it now so avoid 234677217Sphk * duplicating this code every time. 234777217Sphk */ 234877217Sphk if (ireq->i_type != IEEE80211_IOC_SSID && 234977217Sphk ireq->i_type != IEEE80211_IOC_WEPKEY && 235077217Sphk ireq->i_type != IEEE80211_IOC_WEPTXKEY) { 235188749Sambrisko sc->areq.an_type = AN_RID_GENCONFIG; 235277217Sphk if (an_read_record(sc, 235388749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 235477217Sphk error = EINVAL; 2355175445Sambrisko AN_UNLOCK(sc); 235677217Sphk break; 235777217Sphk } 235877217Sphk } 235983270Sbrooks switch (ireq->i_type) { 236077217Sphk case IEEE80211_IOC_SSID: 2361119156Sambrisko sc->areq.an_len = sizeof(sc->areq); 236288749Sambrisko sc->areq.an_type = AN_RID_SSIDLIST; 236377217Sphk if (an_read_record(sc, 236488749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 236577217Sphk error = EINVAL; 2366175445Sambrisko AN_UNLOCK(sc); 236777217Sphk break; 236877217Sphk } 236978639Sbrooks if (ireq->i_len > IEEE80211_NWID_LEN) { 237077217Sphk error = EINVAL; 2371175445Sambrisko AN_UNLOCK(sc); 237277217Sphk break; 237377217Sphk } 2374119156Sambrisko max = (sc->areq.an_len - 4) 2375119156Sambrisko / sizeof(struct an_ltv_ssid_entry); 2376119156Sambrisko if ( max > MAX_SSIDS ) { 2377119156Sambrisko printf("To many SSIDs only using " 2378119156Sambrisko "%d of %d\n", 2379119156Sambrisko MAX_SSIDS, max); 2380119156Sambrisko max = MAX_SSIDS; 2381119156Sambrisko } 2382119156Sambrisko if (ireq->i_val > max) { 2383119156Sambrisko error = EINVAL; 2384175445Sambrisko AN_UNLOCK(sc); 238577217Sphk break; 2386119156Sambrisko } else { 238777217Sphk error = copyin(ireq->i_data, 2388175445Sambrisko ssids->an_entry[ireq->i_val].an_ssid, 2389119156Sambrisko ireq->i_len); 2390175445Sambrisko ssids->an_entry[ireq->i_val].an_len 2391119156Sambrisko = ireq->i_len; 2392175445Sambrisko sc->areq.an_len = sizeof(sc->areq); 2393175445Sambrisko sc->areq.an_type = AN_RID_SSIDLIST; 2394175445Sambrisko an_setdef(sc, &sc->areq); 2395175445Sambrisko AN_UNLOCK(sc); 239677217Sphk break; 239777217Sphk } 239877217Sphk break; 239977217Sphk case IEEE80211_IOC_WEP: 240077217Sphk switch (ireq->i_val) { 240177217Sphk case IEEE80211_WEP_OFF: 240277217Sphk config->an_authtype &= 240377217Sphk ~(AN_AUTHTYPE_PRIVACY_IN_USE | 240477217Sphk AN_AUTHTYPE_ALLOW_UNENCRYPTED); 240577217Sphk break; 240677217Sphk case IEEE80211_WEP_ON: 240777217Sphk config->an_authtype |= 240877217Sphk AN_AUTHTYPE_PRIVACY_IN_USE; 240977217Sphk config->an_authtype &= 241077217Sphk ~AN_AUTHTYPE_ALLOW_UNENCRYPTED; 241177217Sphk break; 241277217Sphk case IEEE80211_WEP_MIXED: 241377217Sphk config->an_authtype |= 241477217Sphk AN_AUTHTYPE_PRIVACY_IN_USE | 241577217Sphk AN_AUTHTYPE_ALLOW_UNENCRYPTED; 241677217Sphk break; 241777217Sphk default: 241877217Sphk error = EINVAL; 241977217Sphk break; 242077217Sphk } 2421175445Sambrisko if (error != EINVAL) 2422175445Sambrisko an_setdef(sc, &sc->areq); 2423175445Sambrisko AN_UNLOCK(sc); 242477217Sphk break; 242577217Sphk case IEEE80211_IOC_WEPKEY: 2426110531Sambrisko if (ireq->i_val < 0 || ireq->i_val > 8 || 242777217Sphk ireq->i_len > 13) { 242877217Sphk error = EINVAL; 2429175445Sambrisko AN_UNLOCK(sc); 243077217Sphk break; 243177217Sphk } 243277217Sphk error = copyin(ireq->i_data, tmpstr, 13); 2433175445Sambrisko if (error != 0) { 2434175445Sambrisko AN_UNLOCK(sc); 243577217Sphk break; 2436175445Sambrisko } 2437110531Sambrisko /* 2438110531Sambrisko * Map the 9th key into the home mode 2439110531Sambrisko * since that is how it is stored on 2440110531Sambrisko * the card 2441110531Sambrisko */ 244288749Sambrisko bzero(&sc->areq, sizeof(struct an_ltv_key)); 244388749Sambrisko sc->areq.an_len = sizeof(struct an_ltv_key); 244477217Sphk key->mac[0] = 1; /* The others are 0. */ 2445110531Sambrisko if (ireq->i_val < 4) { 244688749Sambrisko sc->areq.an_type = AN_RID_WEP_TEMP; 2447110531Sambrisko key->kindex = ireq->i_val; 2448110531Sambrisko } else { 244988749Sambrisko sc->areq.an_type = AN_RID_WEP_PERM; 2450110531Sambrisko key->kindex = ireq->i_val - 4; 2451110531Sambrisko } 245277217Sphk key->klen = ireq->i_len; 245377217Sphk bcopy(tmpstr, key->key, key->klen); 2454175445Sambrisko an_setdef(sc, &sc->areq); 2455175445Sambrisko AN_UNLOCK(sc); 245677217Sphk break; 245777217Sphk case IEEE80211_IOC_WEPTXKEY: 2458110531Sambrisko if (ireq->i_val < 0 || ireq->i_val > 4) { 2459110531Sambrisko error = EINVAL; 2460175445Sambrisko AN_UNLOCK(sc); 2461110531Sambrisko break; 2462110531Sambrisko } 2463110531Sambrisko 246488748Sambrisko /* 246588748Sambrisko * Map the 5th key into the home mode 246688748Sambrisko * since that is how it is stored on 246788748Sambrisko * the card 246888748Sambrisko */ 246988749Sambrisko sc->areq.an_len = sizeof(struct an_ltv_genconfig); 247088749Sambrisko sc->areq.an_type = AN_RID_ACTUALCFG; 247188748Sambrisko if (an_read_record(sc, 2472175445Sambrisko (struct an_ltv_gen *)&sc->areq)) { 2473175445Sambrisko error = EINVAL; 2474175445Sambrisko AN_UNLOCK(sc); 247588748Sambrisko break; 247688748Sambrisko } 247788748Sambrisko if (ireq->i_val == 4) { 247888748Sambrisko config->an_home_product |= AN_HOME_NETWORK; 247988748Sambrisko ireq->i_val = 0; 248088748Sambrisko } else { 248188748Sambrisko config->an_home_product &= ~AN_HOME_NETWORK; 248288748Sambrisko } 248388748Sambrisko 248488748Sambrisko sc->an_config.an_home_product 248588748Sambrisko = config->an_home_product; 248688748Sambrisko 2487110531Sambrisko /* update configuration */ 2488199154Sjhb an_init_locked(sc); 2489110531Sambrisko 249088749Sambrisko bzero(&sc->areq, sizeof(struct an_ltv_key)); 249188749Sambrisko sc->areq.an_len = sizeof(struct an_ltv_key); 249288749Sambrisko sc->areq.an_type = AN_RID_WEP_PERM; 249377217Sphk key->kindex = 0xffff; 249477217Sphk key->mac[0] = ireq->i_val; 2495175445Sambrisko an_setdef(sc, &sc->areq); 2496175445Sambrisko AN_UNLOCK(sc); 249777217Sphk break; 249877217Sphk case IEEE80211_IOC_AUTHMODE: 249977217Sphk switch (ireq->i_val) { 250077217Sphk case IEEE80211_AUTH_NONE: 250177217Sphk config->an_authtype = AN_AUTHTYPE_NONE | 250277217Sphk (config->an_authtype & ~AN_AUTHTYPE_MASK); 250377217Sphk break; 250477217Sphk case IEEE80211_AUTH_OPEN: 250577217Sphk config->an_authtype = AN_AUTHTYPE_OPEN | 250677217Sphk (config->an_authtype & ~AN_AUTHTYPE_MASK); 250777217Sphk break; 250877217Sphk case IEEE80211_AUTH_SHARED: 250977217Sphk config->an_authtype = AN_AUTHTYPE_SHAREDKEY | 251077217Sphk (config->an_authtype & ~AN_AUTHTYPE_MASK); 251177217Sphk break; 251277217Sphk default: 251377217Sphk error = EINVAL; 251477217Sphk } 2515175445Sambrisko if (error != EINVAL) { 2516175445Sambrisko an_setdef(sc, &sc->areq); 2517175445Sambrisko } 2518175445Sambrisko AN_UNLOCK(sc); 251977217Sphk break; 252077217Sphk case IEEE80211_IOC_STATIONNAME: 252178639Sbrooks if (ireq->i_len > 16) { 252277217Sphk error = EINVAL; 2523175445Sambrisko AN_UNLOCK(sc); 252477217Sphk break; 252577217Sphk } 252677217Sphk bzero(config->an_nodename, 16); 252777217Sphk error = copyin(ireq->i_data, 252877217Sphk config->an_nodename, ireq->i_len); 2529175445Sambrisko an_setdef(sc, &sc->areq); 2530175445Sambrisko AN_UNLOCK(sc); 253177217Sphk break; 253277217Sphk case IEEE80211_IOC_CHANNEL: 253377217Sphk /* 253477217Sphk * The actual range is 1-14, but if you set it 253577217Sphk * to 0 you get the default so we let that work 253677217Sphk * too. 253777217Sphk */ 253877217Sphk if (ireq->i_val < 0 || ireq->i_val >14) { 253977217Sphk error = EINVAL; 2540175445Sambrisko AN_UNLOCK(sc); 254177217Sphk break; 254277217Sphk } 254377217Sphk config->an_ds_channel = ireq->i_val; 2544175445Sambrisko an_setdef(sc, &sc->areq); 2545175445Sambrisko AN_UNLOCK(sc); 254677217Sphk break; 254777217Sphk case IEEE80211_IOC_POWERSAVE: 254877217Sphk switch (ireq->i_val) { 254977217Sphk case IEEE80211_POWERSAVE_OFF: 255077217Sphk config->an_psave_mode = AN_PSAVE_NONE; 255177217Sphk break; 255277217Sphk case IEEE80211_POWERSAVE_CAM: 255377217Sphk config->an_psave_mode = AN_PSAVE_CAM; 255477217Sphk break; 255577217Sphk case IEEE80211_POWERSAVE_PSP: 255677217Sphk config->an_psave_mode = AN_PSAVE_PSP; 255777217Sphk break; 255877217Sphk case IEEE80211_POWERSAVE_PSP_CAM: 255977217Sphk config->an_psave_mode = AN_PSAVE_PSP_CAM; 256077217Sphk break; 256177217Sphk default: 256277217Sphk error = EINVAL; 256377217Sphk break; 256477217Sphk } 2565175445Sambrisko an_setdef(sc, &sc->areq); 2566175445Sambrisko AN_UNLOCK(sc); 256777217Sphk break; 256877217Sphk case IEEE80211_IOC_POWERSAVESLEEP: 256977217Sphk config->an_listen_interval = ireq->i_val; 2570175445Sambrisko an_setdef(sc, &sc->areq); 2571175445Sambrisko AN_UNLOCK(sc); 257277217Sphk break; 2573199154Sjhb default: 2574199154Sjhb AN_UNLOCK(sc); 2575199154Sjhb break; 257677217Sphk } 257777217Sphk 2578175445Sambrisko /* 2579175445Sambrisko if (!error) { 2580175445Sambrisko AN_LOCK(sc); 258188749Sambrisko an_setdef(sc, &sc->areq); 2582175445Sambrisko AN_UNLOCK(sc); 2583175445Sambrisko } 2584175445Sambrisko */ 258577217Sphk break; 258655992Swpaul default: 2587106937Ssam error = ether_ioctl(ifp, command, data); 258855992Swpaul break; 258955992Swpaul } 259061816Srobertoout: 259155992Swpaul 259278639Sbrooks return(error != 0); 259355992Swpaul} 259455992Swpaul 259583270Sbrooksstatic int 2596150446Simpan_init_tx_ring(struct an_softc *sc) 259755992Swpaul{ 259855992Swpaul int i; 259955992Swpaul int id; 260055992Swpaul 260155992Swpaul if (sc->an_gone) 260255992Swpaul return (0); 260355992Swpaul 2604108401Sambrisko if (!sc->mpi350) { 2605108401Sambrisko for (i = 0; i < AN_TX_RING_CNT; i++) { 2606108401Sambrisko if (an_alloc_nicmem(sc, 1518 + 2607108401Sambrisko 0x44, &id)) 2608108401Sambrisko return(ENOMEM); 2609108401Sambrisko sc->an_rdata.an_tx_fids[i] = id; 2610108401Sambrisko sc->an_rdata.an_tx_ring[i] = 0; 2611108401Sambrisko } 261255992Swpaul } 261355992Swpaul 261455992Swpaul sc->an_rdata.an_tx_prod = 0; 261555992Swpaul sc->an_rdata.an_tx_cons = 0; 2616108401Sambrisko sc->an_rdata.an_tx_empty = 1; 261755992Swpaul 261855992Swpaul return(0); 261955992Swpaul} 262055992Swpaul 262183270Sbrooksstatic void 2622150446Simpan_init(void *xsc) 262355992Swpaul{ 262455992Swpaul struct an_softc *sc = xsc; 262555992Swpaul 262667094Swpaul AN_LOCK(sc); 2627199154Sjhb an_init_locked(sc); 2628199154Sjhb AN_UNLOCK(sc); 2629199154Sjhb} 263067094Swpaul 2631199154Sjhbstatic void 2632199154Sjhban_init_locked(struct an_softc *sc) 2633199154Sjhb{ 2634199154Sjhb struct ifnet *ifp; 2635199154Sjhb 2636199154Sjhb AN_LOCK_ASSERT(sc); 2637199154Sjhb ifp = sc->an_ifp; 2638199154Sjhb if (sc->an_gone) 263955992Swpaul return; 264055992Swpaul 2641148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 264255992Swpaul an_stop(sc); 264355992Swpaul 264455992Swpaul sc->an_associated = 0; 264555992Swpaul 264655992Swpaul /* Allocate the TX buffers */ 264755992Swpaul if (an_init_tx_ring(sc)) { 264855992Swpaul an_reset(sc); 2649108401Sambrisko if (sc->mpi350) 2650175445Sambrisko an_init_mpi350_desc(sc); 265155992Swpaul if (an_init_tx_ring(sc)) { 2652198987Sjhb if_printf(ifp, "tx buffer allocation failed\n"); 265355992Swpaul return; 265455992Swpaul } 265555992Swpaul } 265655992Swpaul 265755992Swpaul /* Set our MAC address. */ 2658152315Sru bcopy((char *)IF_LLADDR(sc->an_ifp), 265955992Swpaul (char *)&sc->an_config.an_macaddr, ETHER_ADDR_LEN); 266055992Swpaul 266155992Swpaul if (ifp->if_flags & IFF_BROADCAST) 266255992Swpaul sc->an_config.an_rxmode = AN_RXMODE_BC_ADDR; 266355992Swpaul else 266455992Swpaul sc->an_config.an_rxmode = AN_RXMODE_ADDR; 266555992Swpaul 266655992Swpaul if (ifp->if_flags & IFF_MULTICAST) 266755992Swpaul sc->an_config.an_rxmode = AN_RXMODE_BC_MC_ADDR; 266855992Swpaul 266983269Sbrooks if (ifp->if_flags & IFF_PROMISC) { 267083269Sbrooks if (sc->an_monitor & AN_MONITOR) { 267183269Sbrooks if (sc->an_monitor & AN_MONITOR_ANY_BSS) { 267283269Sbrooks sc->an_config.an_rxmode |= 267383269Sbrooks AN_RXMODE_80211_MONITOR_ANYBSS | 267483269Sbrooks AN_RXMODE_NO_8023_HEADER; 267583269Sbrooks } else { 267683269Sbrooks sc->an_config.an_rxmode |= 267783269Sbrooks AN_RXMODE_80211_MONITOR_CURBSS | 267883269Sbrooks AN_RXMODE_NO_8023_HEADER; 267983269Sbrooks } 268083269Sbrooks } 268183269Sbrooks } 268255992Swpaul 2683184708Sbz#ifdef ANCACHE 2684108401Sambrisko if (sc->an_have_rssimap) 2685108401Sambrisko sc->an_config.an_rxmode |= AN_RXMODE_NORMALIZED_RSSI; 2686184708Sbz#endif 2687108401Sambrisko 268855992Swpaul /* Set the ssid list */ 268955992Swpaul sc->an_ssidlist.an_type = AN_RID_SSIDLIST; 2690119156Sambrisko sc->an_ssidlist.an_len = sizeof(struct an_ltv_ssidlist_new); 269155992Swpaul if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_ssidlist)) { 2692198987Sjhb if_printf(ifp, "failed to set ssid list\n"); 269355992Swpaul return; 269455992Swpaul } 269555992Swpaul 269655992Swpaul /* Set the AP list */ 269755992Swpaul sc->an_aplist.an_type = AN_RID_APLIST; 269855992Swpaul sc->an_aplist.an_len = sizeof(struct an_ltv_aplist); 269955992Swpaul if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_aplist)) { 2700198987Sjhb if_printf(ifp, "failed to set AP list\n"); 270155992Swpaul return; 270255992Swpaul } 270355992Swpaul 270455992Swpaul /* Set the configuration in the NIC */ 270555992Swpaul sc->an_config.an_len = sizeof(struct an_ltv_genconfig); 270655992Swpaul sc->an_config.an_type = AN_RID_GENCONFIG; 270755992Swpaul if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_config)) { 2708198987Sjhb if_printf(ifp, "failed to set configuration\n"); 270955992Swpaul return; 271055992Swpaul } 271155992Swpaul 271255992Swpaul /* Enable the MAC */ 271355992Swpaul if (an_cmd(sc, AN_CMD_ENABLE, 0)) { 2714198987Sjhb if_printf(ifp, "failed to enable MAC\n"); 271555992Swpaul return; 271655992Swpaul } 271755992Swpaul 271874698Sarchie if (ifp->if_flags & IFF_PROMISC) 271974698Sarchie an_cmd(sc, AN_CMD_SET_MODE, 0xffff); 272074698Sarchie 272155992Swpaul /* enable interrupts */ 2722119156Sambrisko CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), AN_INTRS(sc->mpi350)); 272355992Swpaul 2724148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 2725148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 272655992Swpaul 2727173668Savatar callout_reset(&sc->an_stat_ch, hz, an_stats_update, sc); 272855992Swpaul 272955992Swpaul return; 273055992Swpaul} 273155992Swpaul 273283270Sbrooksstatic void 2733150446Simpan_start(struct ifnet *ifp) 273455992Swpaul{ 273555992Swpaul struct an_softc *sc; 2736199154Sjhb 2737199154Sjhb sc = ifp->if_softc; 2738199154Sjhb AN_LOCK(sc); 2739199154Sjhb an_start_locked(ifp); 2740199154Sjhb AN_UNLOCK(sc); 2741199154Sjhb} 2742199154Sjhb 2743199154Sjhbstatic void 2744199154Sjhban_start_locked(struct ifnet *ifp) 2745199154Sjhb{ 2746199154Sjhb struct an_softc *sc; 274755992Swpaul struct mbuf *m0 = NULL; 274855992Swpaul struct an_txframe_802_3 tx_frame_802_3; 274955992Swpaul struct ether_header *eh; 2750108401Sambrisko int id, idx, i; 2751175446Sambrisko unsigned char txcontrol; 2752108401Sambrisko struct an_card_tx_desc an_tx_desc; 2753108401Sambrisko u_int8_t *buf; 275455992Swpaul 275555992Swpaul sc = ifp->if_softc; 275655992Swpaul 2757199154Sjhb AN_LOCK_ASSERT(sc); 275855992Swpaul if (sc->an_gone) 275955992Swpaul return; 276055992Swpaul 2761148887Srwatson if (ifp->if_drv_flags & IFF_DRV_OACTIVE) 276255992Swpaul return; 276355992Swpaul 276455992Swpaul if (!sc->an_associated) 276555992Swpaul return; 276655992Swpaul 276790990Sbrooks /* We can't send in monitor mode so toss any attempts. */ 276883269Sbrooks if (sc->an_monitor && (ifp->if_flags & IFF_PROMISC)) { 276983270Sbrooks for (;;) { 2770132986Smlaier IFQ_DRV_DEQUEUE(&ifp->if_snd, m0); 277183269Sbrooks if (m0 == NULL) 277283269Sbrooks break; 277390990Sbrooks m_freem(m0); 277483269Sbrooks } 277583269Sbrooks return; 277683269Sbrooks } 277783269Sbrooks 277855992Swpaul idx = sc->an_rdata.an_tx_prod; 277955992Swpaul 2780108401Sambrisko if (!sc->mpi350) { 2781108401Sambrisko bzero((char *)&tx_frame_802_3, sizeof(tx_frame_802_3)); 278255992Swpaul 2783108401Sambrisko while (sc->an_rdata.an_tx_ring[idx] == 0) { 2784132986Smlaier IFQ_DRV_DEQUEUE(&ifp->if_snd, m0); 2785108401Sambrisko if (m0 == NULL) 2786108401Sambrisko break; 278755992Swpaul 2788108401Sambrisko id = sc->an_rdata.an_tx_fids[idx]; 2789108401Sambrisko eh = mtod(m0, struct ether_header *); 279083270Sbrooks 2791108401Sambrisko bcopy((char *)&eh->ether_dhost, 2792175445Sambrisko (char *)&tx_frame_802_3.an_tx_dst_addr, 2793108401Sambrisko ETHER_ADDR_LEN); 2794108401Sambrisko bcopy((char *)&eh->ether_shost, 2795175445Sambrisko (char *)&tx_frame_802_3.an_tx_src_addr, 2796108401Sambrisko ETHER_ADDR_LEN); 279755992Swpaul 2798108401Sambrisko /* minus src/dest mac & type */ 2799108401Sambrisko tx_frame_802_3.an_tx_802_3_payload_len = 2800175445Sambrisko m0->m_pkthdr.len - 12; 280155992Swpaul 2802108401Sambrisko m_copydata(m0, sizeof(struct ether_header) - 2 , 2803108401Sambrisko tx_frame_802_3.an_tx_802_3_payload_len, 2804108401Sambrisko (caddr_t)&sc->an_txbuf); 2805108401Sambrisko 2806108401Sambrisko txcontrol = AN_TXCTL_8023; 2807108401Sambrisko /* write the txcontrol only */ 2808108401Sambrisko an_write_data(sc, id, 0x08, (caddr_t)&txcontrol, 2809108401Sambrisko sizeof(txcontrol)); 2810108401Sambrisko 2811108401Sambrisko /* 802_3 header */ 2812108401Sambrisko an_write_data(sc, id, 0x34, (caddr_t)&tx_frame_802_3, 2813108401Sambrisko sizeof(struct an_txframe_802_3)); 2814108401Sambrisko 2815108401Sambrisko /* in mbuf header type is just before payload */ 2816108401Sambrisko an_write_data(sc, id, 0x44, (caddr_t)&sc->an_txbuf, 2817108401Sambrisko tx_frame_802_3.an_tx_802_3_payload_len); 2818108401Sambrisko 2819108401Sambrisko /* 2820108401Sambrisko * If there's a BPF listner, bounce a copy of 2821108401Sambrisko * this frame to him. 2822108401Sambrisko */ 2823108401Sambrisko BPF_MTAP(ifp, m0); 2824108401Sambrisko 2825108401Sambrisko m_freem(m0); 2826108401Sambrisko m0 = NULL; 2827108401Sambrisko 2828108401Sambrisko sc->an_rdata.an_tx_ring[idx] = id; 2829108401Sambrisko if (an_cmd(sc, AN_CMD_TX, id)) 2830198987Sjhb if_printf(ifp, "xmit failed\n"); 2831108401Sambrisko 2832108401Sambrisko AN_INC(idx, AN_TX_RING_CNT); 2833119156Sambrisko 2834119156Sambrisko /* 2835119156Sambrisko * Set a timeout in case the chip goes out to lunch. 2836119156Sambrisko */ 2837199154Sjhb sc->an_timer = 5; 2838108401Sambrisko } 2839108401Sambrisko } else { /* MPI-350 */ 2840130620Sambrisko /* Disable interrupts. */ 2841130620Sambrisko CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0); 2842130620Sambrisko 2843108401Sambrisko while (sc->an_rdata.an_tx_empty || 2844108401Sambrisko idx != sc->an_rdata.an_tx_cons) { 2845132986Smlaier IFQ_DRV_DEQUEUE(&ifp->if_snd, m0); 2846108401Sambrisko if (m0 == NULL) { 2847108401Sambrisko break; 2848108401Sambrisko } 2849108401Sambrisko buf = sc->an_tx_buffer[idx].an_dma_vaddr; 2850108401Sambrisko 2851108401Sambrisko eh = mtod(m0, struct ether_header *); 2852108401Sambrisko 2853108401Sambrisko /* DJA optimize this to limit bcopy */ 2854108401Sambrisko bcopy((char *)&eh->ether_dhost, 2855175445Sambrisko (char *)&tx_frame_802_3.an_tx_dst_addr, 2856108401Sambrisko ETHER_ADDR_LEN); 2857108401Sambrisko bcopy((char *)&eh->ether_shost, 2858175445Sambrisko (char *)&tx_frame_802_3.an_tx_src_addr, 2859108401Sambrisko ETHER_ADDR_LEN); 2860108401Sambrisko 2861108401Sambrisko /* minus src/dest mac & type */ 2862108401Sambrisko tx_frame_802_3.an_tx_802_3_payload_len = 2863175445Sambrisko m0->m_pkthdr.len - 12; 2864108401Sambrisko 2865108401Sambrisko m_copydata(m0, sizeof(struct ether_header) - 2 , 2866108401Sambrisko tx_frame_802_3.an_tx_802_3_payload_len, 2867108401Sambrisko (caddr_t)&sc->an_txbuf); 2868108401Sambrisko 2869108401Sambrisko txcontrol = AN_TXCTL_8023; 2870108401Sambrisko /* write the txcontrol only */ 2871108401Sambrisko bcopy((caddr_t)&txcontrol, &buf[0x08], 287255992Swpaul sizeof(txcontrol)); 287383270Sbrooks 2874108401Sambrisko /* 802_3 header */ 2875108401Sambrisko bcopy((caddr_t)&tx_frame_802_3, &buf[0x34], 287655992Swpaul sizeof(struct an_txframe_802_3)); 287783270Sbrooks 2878108401Sambrisko /* in mbuf header type is just before payload */ 2879108401Sambrisko bcopy((caddr_t)&sc->an_txbuf, &buf[0x44], 2880108401Sambrisko tx_frame_802_3.an_tx_802_3_payload_len); 288183270Sbrooks 288255992Swpaul 2883108401Sambrisko bzero(&an_tx_desc, sizeof(an_tx_desc)); 2884108401Sambrisko an_tx_desc.an_offset = 0; 2885108401Sambrisko an_tx_desc.an_eoc = 1; 2886108401Sambrisko an_tx_desc.an_valid = 1; 2887108401Sambrisko an_tx_desc.an_len = 0x44 + 2888119156Sambrisko tx_frame_802_3.an_tx_802_3_payload_len; 2889175445Sambrisko an_tx_desc.an_phys 2890119156Sambrisko = sc->an_tx_buffer[idx].an_dma_paddr; 2891119156Sambrisko for (i = 0; i < sizeof(an_tx_desc) / 4 ; i++) { 2892119156Sambrisko CSR_MEM_AUX_WRITE_4(sc, AN_TX_DESC_OFFSET 2893175445Sambrisko /* zero for now */ 2894119156Sambrisko + (0 * sizeof(an_tx_desc)) 2895119156Sambrisko + (i * 4), 2896155321Simp ((u_int32_t *)(void *)&an_tx_desc)[i]); 2897108401Sambrisko } 289855992Swpaul 2899108401Sambrisko /* 2900108401Sambrisko * If there's a BPF listner, bounce a copy of 2901108401Sambrisko * this frame to him. 2902108401Sambrisko */ 2903108401Sambrisko BPF_MTAP(ifp, m0); 290455992Swpaul 2905108401Sambrisko m_freem(m0); 2906108401Sambrisko m0 = NULL; 2907119156Sambrisko AN_INC(idx, AN_MAX_TX_DESC); 2908119156Sambrisko sc->an_rdata.an_tx_empty = 0; 2909108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_ALLOC); 2910108401Sambrisko 2911119156Sambrisko /* 2912119156Sambrisko * Set a timeout in case the chip goes out to lunch. 2913119156Sambrisko */ 2914199154Sjhb sc->an_timer = 5; 2915108401Sambrisko } 2916130620Sambrisko 2917130620Sambrisko /* Re-enable interrupts. */ 2918130620Sambrisko CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), AN_INTRS(sc->mpi350)); 291955992Swpaul } 292055992Swpaul 292155992Swpaul if (m0 != NULL) 2922148887Srwatson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 292355992Swpaul 292455992Swpaul sc->an_rdata.an_tx_prod = idx; 292555992Swpaul 292655992Swpaul return; 292755992Swpaul} 292855992Swpaul 292983270Sbrooksvoid 2930150446Simpan_stop(struct an_softc *sc) 293155992Swpaul{ 293255992Swpaul struct ifnet *ifp; 293355992Swpaul int i; 293455992Swpaul 2935199154Sjhb AN_LOCK_ASSERT(sc); 293667094Swpaul 2937199154Sjhb if (sc->an_gone) 293855992Swpaul return; 293955992Swpaul 2940147256Sbrooks ifp = sc->an_ifp; 294155992Swpaul 294255992Swpaul an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0); 2943108401Sambrisko CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0); 294455992Swpaul an_cmd(sc, AN_CMD_DISABLE, 0); 294555992Swpaul 294655992Swpaul for (i = 0; i < AN_TX_RING_CNT; i++) 294755992Swpaul an_cmd(sc, AN_CMD_DEALLOC_MEM, sc->an_rdata.an_tx_fids[i]); 294855992Swpaul 2949173668Savatar callout_stop(&sc->an_stat_ch); 295055992Swpaul 2951148887Srwatson ifp->if_drv_flags &= ~(IFF_DRV_RUNNING|IFF_DRV_OACTIVE); 295255992Swpaul 2953108401Sambrisko if (sc->an_flash_buffer) { 2954108401Sambrisko free(sc->an_flash_buffer, M_DEVBUF); 2955108401Sambrisko sc->an_flash_buffer = NULL; 2956108401Sambrisko } 295755992Swpaul} 295855992Swpaul 295983270Sbrooksstatic void 2960199154Sjhban_watchdog(struct an_softc *sc) 296155992Swpaul{ 2962199154Sjhb struct ifnet *ifp; 296355992Swpaul 2964199154Sjhb AN_LOCK_ASSERT(sc); 296555992Swpaul 2966199154Sjhb if (sc->an_gone) 296755992Swpaul return; 296855992Swpaul 2969199154Sjhb ifp = sc->an_ifp; 2970198987Sjhb if_printf(ifp, "device timeout\n"); 297155992Swpaul 297255992Swpaul an_reset(sc); 2973108401Sambrisko if (sc->mpi350) 2974175445Sambrisko an_init_mpi350_desc(sc); 2975199154Sjhb an_init_locked(sc); 297655992Swpaul 297755992Swpaul ifp->if_oerrors++; 297855992Swpaul} 297955992Swpaul 2980188128Simpint 2981150446Simpan_shutdown(device_t dev) 298255992Swpaul{ 298355992Swpaul struct an_softc *sc; 298455992Swpaul 298555992Swpaul sc = device_get_softc(dev); 2986199154Sjhb AN_LOCK(sc); 298755992Swpaul an_stop(sc); 2988110531Sambrisko sc->an_gone = 1; 2989199154Sjhb AN_UNLOCK(sc); 299055992Swpaul 2991199154Sjhb return (0); 299255992Swpaul} 299355992Swpaul 2994110362Sambriskovoid 2995150446Simpan_resume(device_t dev) 2996110362Sambrisko{ 2997110362Sambrisko struct an_softc *sc; 2998110362Sambrisko struct ifnet *ifp; 2999110531Sambrisko int i; 3000110531Sambrisko 3001110362Sambrisko sc = device_get_softc(dev); 3002110531Sambrisko AN_LOCK(sc); 3003147256Sbrooks ifp = sc->an_ifp; 3004110362Sambrisko 3005110531Sambrisko sc->an_gone = 0; 3006110362Sambrisko an_reset(sc); 3007110362Sambrisko if (sc->mpi350) 3008175445Sambrisko an_init_mpi350_desc(sc); 3009199154Sjhb an_init_locked(sc); 3010110362Sambrisko 3011110531Sambrisko /* Recovery temporary keys */ 3012110531Sambrisko for (i = 0; i < 4; i++) { 3013110531Sambrisko sc->areq.an_type = AN_RID_WEP_TEMP; 3014175445Sambrisko sc->areq.an_len = sizeof(struct an_ltv_key); 3015110531Sambrisko bcopy(&sc->an_temp_keys[i], 3016110531Sambrisko &sc->areq, sizeof(struct an_ltv_key)); 3017110531Sambrisko an_setdef(sc, &sc->areq); 3018110531Sambrisko } 3019110531Sambrisko 3020110362Sambrisko if (ifp->if_flags & IFF_UP) 3021199154Sjhb an_start_locked(ifp); 3022110531Sambrisko AN_UNLOCK(sc); 3023110362Sambrisko 3024110362Sambrisko return; 3025110362Sambrisko} 3026110362Sambrisko 302755992Swpaul#ifdef ANCACHE 302855992Swpaul/* Aironet signal strength cache code. 302955992Swpaul * store signal/noise/quality on per MAC src basis in 303055992Swpaul * a small fixed cache. The cache wraps if > MAX slots 303155992Swpaul * used. The cache may be zeroed out to start over. 303255992Swpaul * Two simple filters exist to reduce computation: 303388748Sambrisko * 1. ip only (literally 0x800, ETHERTYPE_IP) which may be used 303455992Swpaul * to ignore some packets. It defaults to ip only. 303555992Swpaul * it could be used to focus on broadcast, non-IP 802.11 beacons. 303655992Swpaul * 2. multicast/broadcast only. This may be used to 303755992Swpaul * ignore unicast packets and only cache signal strength 303855992Swpaul * for multicast/broadcast packets (beacons); e.g., Mobile-IP 303955992Swpaul * beacons and not unicast traffic. 304055992Swpaul * 304155992Swpaul * The cache stores (MAC src(index), IP src (major clue), signal, 304255992Swpaul * quality, noise) 304355992Swpaul * 304455992Swpaul * No apologies for storing IP src here. It's easy and saves much 304583270Sbrooks * trouble elsewhere. The cache is assumed to be INET dependent, 304655992Swpaul * although it need not be. 304755992Swpaul * 304855992Swpaul * Note: the Aironet only has a single byte of signal strength value 304955992Swpaul * in the rx frame header, and it's not scaled to anything sensible. 305055992Swpaul * This is kind of lame, but it's all we've got. 305155992Swpaul */ 305255992Swpaul 305355992Swpaul#ifdef documentation 305455992Swpaul 3055175446Sambriskoint an_sigitems; /* number of cached entries */ 3056175446Sambriskostruct an_sigcache an_sigcache[MAXANCACHE]; /* array of cache entries */ 3057175446Sambriskoint an_nextitem; /* index/# of entries */ 305855992Swpaul 305955992Swpaul 306055992Swpaul#endif 306155992Swpaul 306255992Swpaul/* control variables for cache filtering. Basic idea is 306355992Swpaul * to reduce cost (e.g., to only Mobile-IP agent beacons 306455992Swpaul * which are broadcast or multicast). Still you might 306555992Swpaul * want to measure signal strength anth unicast ping packets 306655992Swpaul * on a pt. to pt. ant. setup. 306755992Swpaul */ 306883270Sbrooks/* set true if you want to limit cache items to broadcast/mcast 306955992Swpaul * only packets (not unicast). Useful for mobile-ip beacons which 307055992Swpaul * are broadcast/multicast at network layer. Default is all packets 307155992Swpaul * so ping/unicast anll work say anth pt. to pt. antennae setup. 307255992Swpaul */ 307355992Swpaulstatic int an_cache_mcastonly = 0; 3074110531SambriskoSYSCTL_INT(_hw_an, OID_AUTO, an_cache_mcastonly, CTLFLAG_RW, 307555992Swpaul &an_cache_mcastonly, 0, ""); 307655992Swpaul 307755992Swpaul/* set true if you want to limit cache items to IP packets only 307855992Swpaul*/ 307955992Swpaulstatic int an_cache_iponly = 1; 3080110531SambriskoSYSCTL_INT(_hw_an, OID_AUTO, an_cache_iponly, CTLFLAG_RW, 308155992Swpaul &an_cache_iponly, 0, ""); 308255992Swpaul 308355992Swpaul/* 308455992Swpaul * an_cache_store, per rx packet store signal 308555992Swpaul * strength in MAC (src) indexed cache. 308655992Swpaul */ 308783270Sbrooksstatic void 3088150446Simpan_cache_store(struct an_softc *sc, struct ether_header *eh, struct mbuf *m, 3089150446Simp u_int8_t rx_rssi, u_int8_t rx_quality) 309055992Swpaul{ 309183270Sbrooks struct ip *ip = 0; 309255992Swpaul int i; 309355992Swpaul static int cache_slot = 0; /* use this cache entry */ 3094175446Sambrisko static int wrapindex = 0; /* next "free" cache entry */ 309588748Sambrisko int type_ipv4 = 0; 309655992Swpaul 309755992Swpaul /* filters: 309855992Swpaul * 1. ip only 309955992Swpaul * 2. configurable filter to throw out unicast packets, 310055992Swpaul * keep multicast only. 310155992Swpaul */ 310283270Sbrooks 310388748Sambrisko if ((ntohs(eh->ether_type) == ETHERTYPE_IP)) { 310488748Sambrisko type_ipv4 = 1; 310555992Swpaul } 310655992Swpaul 310783270Sbrooks /* filter for ip packets only 310855992Swpaul */ 310988748Sambrisko if ( an_cache_iponly && !type_ipv4) { 311055992Swpaul return; 311155992Swpaul } 311255992Swpaul 311355992Swpaul /* filter for broadcast/multicast only 311455992Swpaul */ 311555992Swpaul if (an_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) { 311655992Swpaul return; 311755992Swpaul } 311855992Swpaul 311955992Swpaul#ifdef SIGDEBUG 3120198987Sjhb if_printf(sc->an_ifp, "q value %x (MSB=0x%x, LSB=0x%x) \n", 3121108401Sambrisko rx_rssi & 0xffff, rx_rssi >> 8, rx_rssi & 0xff); 312255992Swpaul#endif 312355992Swpaul 312455992Swpaul /* find the ip header. we want to store the ip_src 312583270Sbrooks * address. 312655992Swpaul */ 312788748Sambrisko if (type_ipv4) { 312855992Swpaul ip = mtod(m, struct ip *); 312955992Swpaul } 313083270Sbrooks 313183270Sbrooks /* do a linear search for a matching MAC address 313255992Swpaul * in the cache table 313355992Swpaul * . MAC address is 6 bytes, 313455992Swpaul * . var w_nextitem holds total number of entries already cached 313555992Swpaul */ 313678639Sbrooks for (i = 0; i < sc->an_nextitem; i++) { 313755992Swpaul if (! bcmp(eh->ether_shost , sc->an_sigcache[i].macsrc, 6 )) { 313855992Swpaul /* Match!, 313955992Swpaul * so we already have this entry, 314055992Swpaul * update the data 314155992Swpaul */ 314283270Sbrooks break; 314355992Swpaul } 314455992Swpaul } 314555992Swpaul 314655992Swpaul /* did we find a matching mac address? 314755992Swpaul * if yes, then overwrite a previously existing cache entry 314855992Swpaul */ 314955992Swpaul if (i < sc->an_nextitem ) { 315083270Sbrooks cache_slot = i; 315155992Swpaul } 315255992Swpaul /* else, have a new address entry,so 315355992Swpaul * add this new entry, 315455992Swpaul * if table full, then we need to replace LRU entry 315555992Swpaul */ 315683270Sbrooks else { 315755992Swpaul 315883270Sbrooks /* check for space in cache table 315955992Swpaul * note: an_nextitem also holds number of entries 316083270Sbrooks * added in the cache table 316155992Swpaul */ 316255992Swpaul if ( sc->an_nextitem < MAXANCACHE ) { 316355992Swpaul cache_slot = sc->an_nextitem; 316483270Sbrooks sc->an_nextitem++; 316555992Swpaul sc->an_sigitems = sc->an_nextitem; 316655992Swpaul } 3167175446Sambrisko /* no space found, so simply wrap anth wrap index 316855992Swpaul * and "zap" the next entry 316955992Swpaul */ 317055992Swpaul else { 317155992Swpaul if (wrapindex == MAXANCACHE) { 317255992Swpaul wrapindex = 0; 317355992Swpaul } 317455992Swpaul cache_slot = wrapindex++; 317555992Swpaul } 317655992Swpaul } 317755992Swpaul 317855992Swpaul /* invariant: cache_slot now points at some slot 317955992Swpaul * in cache. 318055992Swpaul */ 318155992Swpaul if (cache_slot < 0 || cache_slot >= MAXANCACHE) { 318255992Swpaul log(LOG_ERR, "an_cache_store, bad index: %d of " 318355992Swpaul "[0..%d], gross cache error\n", 318455992Swpaul cache_slot, MAXANCACHE); 318555992Swpaul return; 318655992Swpaul } 318755992Swpaul 318855992Swpaul /* store items in cache 318955992Swpaul * .ip source address 319055992Swpaul * .mac src 319155992Swpaul * .signal, etc. 319255992Swpaul */ 319388748Sambrisko if (type_ipv4) { 319455992Swpaul sc->an_sigcache[cache_slot].ipsrc = ip->ip_src.s_addr; 319555992Swpaul } 319655992Swpaul bcopy( eh->ether_shost, sc->an_sigcache[cache_slot].macsrc, 6); 319755992Swpaul 319855992Swpaul 3199108401Sambrisko switch (an_cache_mode) { 3200108401Sambrisko case DBM: 3201108401Sambrisko if (sc->an_have_rssimap) { 3202175445Sambrisko sc->an_sigcache[cache_slot].signal = 3203108401Sambrisko - sc->an_rssimap.an_entries[rx_rssi].an_rss_dbm; 3204175445Sambrisko sc->an_sigcache[cache_slot].quality = 3205108401Sambrisko - sc->an_rssimap.an_entries[rx_quality].an_rss_dbm; 3206108401Sambrisko } else { 3207108401Sambrisko sc->an_sigcache[cache_slot].signal = rx_rssi - 100; 3208108401Sambrisko sc->an_sigcache[cache_slot].quality = rx_quality - 100; 3209108401Sambrisko } 3210108401Sambrisko break; 3211108401Sambrisko case PERCENT: 3212108401Sambrisko if (sc->an_have_rssimap) { 3213175445Sambrisko sc->an_sigcache[cache_slot].signal = 3214108401Sambrisko sc->an_rssimap.an_entries[rx_rssi].an_rss_pct; 3215175445Sambrisko sc->an_sigcache[cache_slot].quality = 3216108401Sambrisko sc->an_rssimap.an_entries[rx_quality].an_rss_pct; 3217108401Sambrisko } else { 3218108401Sambrisko if (rx_rssi > 100) 3219108401Sambrisko rx_rssi = 100; 3220108401Sambrisko if (rx_quality > 100) 3221108401Sambrisko rx_quality = 100; 3222108401Sambrisko sc->an_sigcache[cache_slot].signal = rx_rssi; 3223108401Sambrisko sc->an_sigcache[cache_slot].quality = rx_quality; 3224108401Sambrisko } 3225108401Sambrisko break; 3226108401Sambrisko case RAW: 3227108401Sambrisko sc->an_sigcache[cache_slot].signal = rx_rssi; 3228108401Sambrisko sc->an_sigcache[cache_slot].quality = rx_quality; 3229108401Sambrisko break; 3230108401Sambrisko } 3231108401Sambrisko 3232108401Sambrisko sc->an_sigcache[cache_slot].noise = 0; 3233108401Sambrisko 323455992Swpaul return; 323555992Swpaul} 323655992Swpaul#endif 323777217Sphk 323883270Sbrooksstatic int 3239150446Simpan_media_change(struct ifnet *ifp) 324077217Sphk{ 324177217Sphk struct an_softc *sc = ifp->if_softc; 3242110253Sambrisko struct an_ltv_genconfig *cfg; 324377217Sphk int otype = sc->an_config.an_opmode; 324477217Sphk int orate = sc->an_tx_rate; 324577217Sphk 3246199154Sjhb AN_LOCK(sc); 3247116951Ssam sc->an_tx_rate = ieee80211_media2rate( 3248116951Ssam IFM_SUBTYPE(sc->an_ifmedia.ifm_cur->ifm_media)); 3249119156Sambrisko if (sc->an_tx_rate < 0) 3250119156Sambrisko sc->an_tx_rate = 0; 3251110253Sambrisko 3252110253Sambrisko if (orate != sc->an_tx_rate) { 3253110253Sambrisko /* Read the current configuration */ 3254110253Sambrisko sc->an_config.an_type = AN_RID_GENCONFIG; 3255110253Sambrisko sc->an_config.an_len = sizeof(struct an_ltv_genconfig); 3256110253Sambrisko an_read_record(sc, (struct an_ltv_gen *)&sc->an_config); 3257110253Sambrisko cfg = &sc->an_config; 3258110253Sambrisko 3259110253Sambrisko /* clear other rates and set the only one we want */ 3260110253Sambrisko bzero(cfg->an_rates, sizeof(cfg->an_rates)); 3261110253Sambrisko cfg->an_rates[0] = sc->an_tx_rate; 3262110253Sambrisko 3263110253Sambrisko /* Save the new rate */ 3264110253Sambrisko sc->an_config.an_type = AN_RID_GENCONFIG; 3265110253Sambrisko sc->an_config.an_len = sizeof(struct an_ltv_genconfig); 326677217Sphk } 326777217Sphk 3268119156Sambrisko if ((sc->an_ifmedia.ifm_cur->ifm_media & IFM_IEEE80211_ADHOC) != 0) 3269119156Sambrisko sc->an_config.an_opmode &= ~AN_OPMODE_INFRASTRUCTURE_STATION; 3270119156Sambrisko else 3271119156Sambrisko sc->an_config.an_opmode |= AN_OPMODE_INFRASTRUCTURE_STATION; 3272119156Sambrisko 3273175445Sambrisko if (otype != sc->an_config.an_opmode || 3274110531Sambrisko orate != sc->an_tx_rate) 3275199154Sjhb an_init_locked(sc); 3276199154Sjhb AN_UNLOCK(sc); 327777217Sphk 327877217Sphk return(0); 327977217Sphk} 328077217Sphk 328183270Sbrooksstatic void 3282150446Simpan_media_status(struct ifnet *ifp, struct ifmediareq *imr) 328377217Sphk{ 328477217Sphk struct an_ltv_status status; 328577217Sphk struct an_softc *sc = ifp->if_softc; 328677217Sphk 3287110253Sambrisko imr->ifm_active = IFM_IEEE80211; 3288110253Sambrisko 3289175445Sambrisko AN_LOCK(sc); 329077217Sphk status.an_len = sizeof(status); 329177217Sphk status.an_type = AN_RID_STATUS; 329277217Sphk if (an_read_record(sc, (struct an_ltv_gen *)&status)) { 329377217Sphk /* If the status read fails, just lie. */ 329477217Sphk imr->ifm_active = sc->an_ifmedia.ifm_cur->ifm_media; 329577217Sphk imr->ifm_status = IFM_AVALID|IFM_ACTIVE; 329677217Sphk } 329777217Sphk 329878639Sbrooks if (sc->an_tx_rate == 0) { 329977217Sphk imr->ifm_active = IFM_IEEE80211|IFM_AUTO; 330077217Sphk } 330177217Sphk 3302110253Sambrisko if (sc->an_config.an_opmode == AN_OPMODE_IBSS_ADHOC) 3303110253Sambrisko imr->ifm_active |= IFM_IEEE80211_ADHOC; 3304116951Ssam imr->ifm_active |= ieee80211_rate2media(NULL, 3305116951Ssam status.an_current_tx_rate, IEEE80211_T_DS); 330677217Sphk imr->ifm_status = IFM_AVALID; 330791283Sambrisko if (status.an_opmode & AN_STATUS_OPMODE_ASSOCIATED) 330877217Sphk imr->ifm_status |= IFM_ACTIVE; 3309199154Sjhb AN_UNLOCK(sc); 331077217Sphk} 331188748Sambrisko 331288748Sambrisko/********************** Cisco utility support routines *************/ 331388748Sambrisko 331488748Sambrisko/* 331588748Sambrisko * ReadRids & WriteRids derived from Cisco driver additions to Ben Reed's 331688748Sambrisko * Linux driver 331788748Sambrisko */ 331888748Sambrisko 331988748Sambriskostatic int 3320150446Simpreadrids(struct ifnet *ifp, struct aironet_ioctl *l_ioctl) 332188748Sambrisko{ 332288749Sambrisko unsigned short rid; 332388748Sambrisko struct an_softc *sc; 3324171692Savatar int error; 332588748Sambrisko 332688748Sambrisko switch (l_ioctl->command) { 332788748Sambrisko case AIROGCAP: 332888748Sambrisko rid = AN_RID_CAPABILITIES; 332988748Sambrisko break; 333088748Sambrisko case AIROGCFG: 333188748Sambrisko rid = AN_RID_GENCONFIG; 333288748Sambrisko break; 333388748Sambrisko case AIROGSLIST: 333488748Sambrisko rid = AN_RID_SSIDLIST; 333588748Sambrisko break; 333688748Sambrisko case AIROGVLIST: 333788748Sambrisko rid = AN_RID_APLIST; 333888748Sambrisko break; 333988748Sambrisko case AIROGDRVNAM: 334088748Sambrisko rid = AN_RID_DRVNAME; 334188748Sambrisko break; 334288748Sambrisko case AIROGEHTENC: 334388748Sambrisko rid = AN_RID_ENCAPPROTO; 334488748Sambrisko break; 334588748Sambrisko case AIROGWEPKTMP: 334688748Sambrisko rid = AN_RID_WEP_TEMP; 334788748Sambrisko break; 334888748Sambrisko case AIROGWEPKNV: 334988748Sambrisko rid = AN_RID_WEP_PERM; 335088748Sambrisko break; 335188748Sambrisko case AIROGSTAT: 335288748Sambrisko rid = AN_RID_STATUS; 335388748Sambrisko break; 335488748Sambrisko case AIROGSTATSD32: 335588748Sambrisko rid = AN_RID_32BITS_DELTA; 335688748Sambrisko break; 335788748Sambrisko case AIROGSTATSC32: 335888748Sambrisko rid = AN_RID_32BITS_CUM; 335988748Sambrisko break; 336088748Sambrisko default: 336188748Sambrisko rid = 999; 336288748Sambrisko break; 336388748Sambrisko } 336488748Sambrisko 336588748Sambrisko if (rid == 999) /* Is bad command */ 336688748Sambrisko return -EINVAL; 336788748Sambrisko 336888748Sambrisko sc = ifp->if_softc; 336988749Sambrisko sc->areq.an_len = AN_MAX_DATALEN; 337088749Sambrisko sc->areq.an_type = rid; 337188748Sambrisko 337288749Sambrisko an_read_record(sc, (struct an_ltv_gen *)&sc->areq); 337388748Sambrisko 337488749Sambrisko l_ioctl->len = sc->areq.an_len - 4; /* just data */ 337588748Sambrisko 3376171692Savatar AN_UNLOCK(sc); 337788748Sambrisko /* the data contains the length at first */ 337888749Sambrisko if (copyout(&(sc->areq.an_len), l_ioctl->data, 337988749Sambrisko sizeof(sc->areq.an_len))) { 3380171692Savatar error = -EFAULT; 3381171692Savatar goto lock_exit; 338288748Sambrisko } 338388748Sambrisko /* Just copy the data back */ 338488749Sambrisko if (copyout(&(sc->areq.an_val), l_ioctl->data + 2, 338588748Sambrisko l_ioctl->len)) { 3386171692Savatar error = -EFAULT; 3387171692Savatar goto lock_exit; 338888748Sambrisko } 3389171692Savatar error = 0; 3390171692Savatarlock_exit: 3391171692Savatar AN_LOCK(sc); 3392171692Savatar return (error); 339388748Sambrisko} 339488748Sambrisko 339588748Sambriskostatic int 3396150446Simpwriterids(struct ifnet *ifp, struct aironet_ioctl *l_ioctl) 339788748Sambrisko{ 339888748Sambrisko struct an_softc *sc; 3399175446Sambrisko int rid, command, error; 340088748Sambrisko 340188748Sambrisko sc = ifp->if_softc; 3402175445Sambrisko AN_LOCK_ASSERT(sc); 340388748Sambrisko rid = 0; 340488748Sambrisko command = l_ioctl->command; 340588748Sambrisko 340688748Sambrisko switch (command) { 340788748Sambrisko case AIROPSIDS: 340888748Sambrisko rid = AN_RID_SSIDLIST; 340988748Sambrisko break; 341088748Sambrisko case AIROPCAP: 341188748Sambrisko rid = AN_RID_CAPABILITIES; 341288748Sambrisko break; 341388748Sambrisko case AIROPAPLIST: 341488748Sambrisko rid = AN_RID_APLIST; 341588748Sambrisko break; 341688748Sambrisko case AIROPCFG: 341788748Sambrisko rid = AN_RID_GENCONFIG; 341888748Sambrisko break; 341988748Sambrisko case AIROPMACON: 342088748Sambrisko an_cmd(sc, AN_CMD_ENABLE, 0); 342188748Sambrisko return 0; 342288748Sambrisko break; 342388748Sambrisko case AIROPMACOFF: 342488748Sambrisko an_cmd(sc, AN_CMD_DISABLE, 0); 342588748Sambrisko return 0; 342688748Sambrisko break; 342788748Sambrisko case AIROPSTCLR: 342888748Sambrisko /* 342988748Sambrisko * This command merely clears the counts does not actually 343088748Sambrisko * store any data only reads rid. But as it changes the cards 343188748Sambrisko * state, I put it in the writerid routines. 343288748Sambrisko */ 343388748Sambrisko 343488748Sambrisko rid = AN_RID_32BITS_DELTACLR; 343588748Sambrisko sc = ifp->if_softc; 343688749Sambrisko sc->areq.an_len = AN_MAX_DATALEN; 343788749Sambrisko sc->areq.an_type = rid; 343888748Sambrisko 343988749Sambrisko an_read_record(sc, (struct an_ltv_gen *)&sc->areq); 344088749Sambrisko l_ioctl->len = sc->areq.an_len - 4; /* just data */ 344188748Sambrisko 3442171692Savatar AN_UNLOCK(sc); 344388748Sambrisko /* the data contains the length at first */ 3444171692Savatar error = copyout(&(sc->areq.an_len), l_ioctl->data, 3445171692Savatar sizeof(sc->areq.an_len)); 3446171692Savatar if (error) { 3447171692Savatar AN_LOCK(sc); 344888748Sambrisko return -EFAULT; 344988748Sambrisko } 345088748Sambrisko /* Just copy the data */ 3451171692Savatar error = copyout(&(sc->areq.an_val), l_ioctl->data + 2, 3452171692Savatar l_ioctl->len); 3453171692Savatar AN_LOCK(sc); 3454171692Savatar if (error) 345588748Sambrisko return -EFAULT; 345688748Sambrisko return 0; 345788748Sambrisko break; 345888748Sambrisko case AIROPWEPKEY: 345988748Sambrisko rid = AN_RID_WEP_TEMP; 346088748Sambrisko break; 346188748Sambrisko case AIROPWEPKEYNV: 346288748Sambrisko rid = AN_RID_WEP_PERM; 346388748Sambrisko break; 346488748Sambrisko case AIROPLEAPUSR: 346588748Sambrisko rid = AN_RID_LEAPUSERNAME; 346688748Sambrisko break; 346788748Sambrisko case AIROPLEAPPWD: 346888748Sambrisko rid = AN_RID_LEAPPASSWORD; 346988748Sambrisko break; 347088748Sambrisko default: 347188748Sambrisko return -EOPNOTSUPP; 347288748Sambrisko } 347388748Sambrisko 347488748Sambrisko if (rid) { 347588749Sambrisko if (l_ioctl->len > sizeof(sc->areq.an_val) + 4) 347688748Sambrisko return -EINVAL; 347788749Sambrisko sc->areq.an_len = l_ioctl->len + 4; /* add type & length */ 347888749Sambrisko sc->areq.an_type = rid; 347988748Sambrisko 348088748Sambrisko /* Just copy the data back */ 3481171692Savatar AN_UNLOCK(sc); 3482171692Savatar error = copyin((l_ioctl->data) + 2, &sc->areq.an_val, 3483171692Savatar l_ioctl->len); 3484171692Savatar AN_LOCK(sc); 3485171692Savatar if (error) 3486144242Ssam return -EFAULT; 3487171692Savatar 348888748Sambrisko an_cmd(sc, AN_CMD_DISABLE, 0); 348988749Sambrisko an_write_record(sc, (struct an_ltv_gen *)&sc->areq); 349088748Sambrisko an_cmd(sc, AN_CMD_ENABLE, 0); 349188748Sambrisko return 0; 349288748Sambrisko } 349388748Sambrisko return -EOPNOTSUPP; 349488748Sambrisko} 349588748Sambrisko 349688748Sambrisko/* 349788748Sambrisko * General Flash utilities derived from Cisco driver additions to Ben Reed's 349888748Sambrisko * Linux driver 349988748Sambrisko */ 350088748Sambrisko 3501123978Sambrisko#define FLASH_DELAY(_sc, x) msleep(ifp, &(_sc)->an_mtx, PZERO, \ 3502123978Sambrisko "flash", ((x) / hz) + 1); 3503108401Sambrisko#define FLASH_COMMAND 0x7e7e 3504108401Sambrisko#define FLASH_SIZE 32 * 1024 350588748Sambrisko 350688748Sambriskostatic int 3507150446Simpunstickbusy(struct ifnet *ifp) 350888748Sambrisko{ 350988748Sambrisko struct an_softc *sc = ifp->if_softc; 351088748Sambrisko 3511108401Sambrisko if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY) { 3512175445Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), 3513108401Sambrisko AN_EV_CLR_STUCK_BUSY); 351488748Sambrisko return 1; 351588748Sambrisko } 351688748Sambrisko return 0; 351788748Sambrisko} 351888748Sambrisko 351988748Sambrisko/* 352088748Sambrisko * Wait for busy completion from card wait for delay uSec's Return true for 352188748Sambrisko * success meaning command reg is clear 352288748Sambrisko */ 352388748Sambrisko 352488748Sambriskostatic int 3525150446SimpWaitBusy(struct ifnet *ifp, int uSec) 352688748Sambrisko{ 3527175446Sambrisko int statword = 0xffff; 3528175446Sambrisko int delay = 0; 3529175446Sambrisko struct an_softc *sc = ifp->if_softc; 353088748Sambrisko 353188748Sambrisko while ((statword & AN_CMD_BUSY) && delay <= (1000 * 100)) { 3532119163Sambrisko FLASH_DELAY(sc, 10); 353388748Sambrisko delay += 10; 3534108401Sambrisko statword = CSR_READ_2(sc, AN_COMMAND(sc->mpi350)); 353588748Sambrisko 353688748Sambrisko if ((AN_CMD_BUSY & statword) && (delay % 200)) { 353788748Sambrisko unstickbusy(ifp); 353888748Sambrisko } 353988748Sambrisko } 354088748Sambrisko 354188748Sambrisko return 0 == (AN_CMD_BUSY & statword); 354288748Sambrisko} 354388748Sambrisko 354488748Sambrisko/* 354588748Sambrisko * STEP 1) Disable MAC and do soft reset on card. 354688748Sambrisko */ 354788748Sambrisko 354888748Sambriskostatic int 3549150446Simpcmdreset(struct ifnet *ifp) 355088748Sambrisko{ 3551175446Sambrisko int status; 3552175446Sambrisko struct an_softc *sc = ifp->if_softc; 355388748Sambrisko 3554199154Sjhb AN_LOCK(sc); 355588748Sambrisko an_stop(sc); 355688748Sambrisko 355788748Sambrisko an_cmd(sc, AN_CMD_DISABLE, 0); 355888748Sambrisko 3559108401Sambrisko if (!(status = WaitBusy(ifp, AN_TIMEOUT))) { 3560198987Sjhb if_printf(ifp, "Waitbusy hang b4 RESET =%d\n", status); 3561175445Sambrisko AN_UNLOCK(sc); 356288748Sambrisko return -EBUSY; 356388748Sambrisko } 3564108401Sambrisko CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), AN_CMD_FW_RESTART); 356588748Sambrisko 3566119163Sambrisko FLASH_DELAY(sc, 1000); /* WAS 600 12/7/00 */ 356788748Sambrisko 356888748Sambrisko 356988748Sambrisko if (!(status = WaitBusy(ifp, 100))) { 3570198987Sjhb if_printf(ifp, "Waitbusy hang AFTER RESET =%d\n", status); 3571175445Sambrisko AN_UNLOCK(sc); 357288748Sambrisko return -EBUSY; 357388748Sambrisko } 3574175445Sambrisko AN_UNLOCK(sc); 357588748Sambrisko return 0; 357688748Sambrisko} 357788748Sambrisko 357888748Sambrisko/* 357988748Sambrisko * STEP 2) Put the card in legendary flash mode 358088748Sambrisko */ 358188748Sambrisko 358288748Sambriskostatic int 3583150446Simpsetflashmode(struct ifnet *ifp) 358488748Sambrisko{ 3585175446Sambrisko int status; 3586175446Sambrisko struct an_softc *sc = ifp->if_softc; 358788748Sambrisko 3588108401Sambrisko CSR_WRITE_2(sc, AN_SW0(sc->mpi350), FLASH_COMMAND); 3589108401Sambrisko CSR_WRITE_2(sc, AN_SW1(sc->mpi350), FLASH_COMMAND); 3590108401Sambrisko CSR_WRITE_2(sc, AN_SW0(sc->mpi350), FLASH_COMMAND); 3591108401Sambrisko CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), FLASH_COMMAND); 359288748Sambrisko 359388748Sambrisko /* 359488748Sambrisko * mdelay(500); // 500ms delay 359588748Sambrisko */ 359688748Sambrisko 3597119163Sambrisko FLASH_DELAY(sc, 500); 359888748Sambrisko 3599108401Sambrisko if (!(status = WaitBusy(ifp, AN_TIMEOUT))) { 360088748Sambrisko printf("Waitbusy hang after setflash mode\n"); 360188748Sambrisko return -EIO; 360288748Sambrisko } 360388748Sambrisko return 0; 360488748Sambrisko} 360588748Sambrisko 360688748Sambrisko/* 360788748Sambrisko * Get a character from the card matching matchbyte Step 3) 360888748Sambrisko */ 360988748Sambrisko 361088748Sambriskostatic int 3611150446Simpflashgchar(struct ifnet *ifp, int matchbyte, int dwelltime) 361288748Sambrisko{ 3613175446Sambrisko int rchar; 3614175446Sambrisko unsigned char rbyte = 0; 3615175446Sambrisko int success = -1; 3616175446Sambrisko struct an_softc *sc = ifp->if_softc; 361788748Sambrisko 361888748Sambrisko 361988748Sambrisko do { 3620108401Sambrisko rchar = CSR_READ_2(sc, AN_SW1(sc->mpi350)); 362188748Sambrisko 362288748Sambrisko if (dwelltime && !(0x8000 & rchar)) { 362388748Sambrisko dwelltime -= 10; 3624119163Sambrisko FLASH_DELAY(sc, 10); 362588748Sambrisko continue; 362688748Sambrisko } 362788748Sambrisko rbyte = 0xff & rchar; 362888748Sambrisko 362988748Sambrisko if ((rbyte == matchbyte) && (0x8000 & rchar)) { 3630108401Sambrisko CSR_WRITE_2(sc, AN_SW1(sc->mpi350), 0); 363188748Sambrisko success = 1; 363288748Sambrisko break; 363388748Sambrisko } 363488748Sambrisko if (rbyte == 0x81 || rbyte == 0x82 || rbyte == 0x83 || rbyte == 0x1a || 0xffff == rchar) 363588748Sambrisko break; 3636108401Sambrisko CSR_WRITE_2(sc, AN_SW1(sc->mpi350), 0); 363788748Sambrisko 363888748Sambrisko } while (dwelltime > 0); 363988748Sambrisko return success; 364088748Sambrisko} 364188748Sambrisko 364288748Sambrisko/* 364388748Sambrisko * Put character to SWS0 wait for dwelltime x 50us for echo . 364488748Sambrisko */ 364588748Sambrisko 364688748Sambriskostatic int 3647150446Simpflashpchar(struct ifnet *ifp, int byte, int dwelltime) 364888748Sambrisko{ 3649175446Sambrisko int echo; 3650175446Sambrisko int pollbusy, waittime; 3651175446Sambrisko struct an_softc *sc = ifp->if_softc; 365288748Sambrisko 365388748Sambrisko byte |= 0x8000; 365488748Sambrisko 365588748Sambrisko if (dwelltime == 0) 365688748Sambrisko dwelltime = 200; 365788748Sambrisko 365888748Sambrisko waittime = dwelltime; 365988748Sambrisko 366088748Sambrisko /* 366188748Sambrisko * Wait for busy bit d15 to go false indicating buffer empty 366288748Sambrisko */ 366388748Sambrisko do { 3664108401Sambrisko pollbusy = CSR_READ_2(sc, AN_SW0(sc->mpi350)); 366588748Sambrisko 366688748Sambrisko if (pollbusy & 0x8000) { 3667119163Sambrisko FLASH_DELAY(sc, 50); 366888748Sambrisko waittime -= 50; 366988748Sambrisko continue; 367088748Sambrisko } else 367188748Sambrisko break; 367288748Sambrisko } 367388748Sambrisko while (waittime >= 0); 367488748Sambrisko 367588748Sambrisko /* timeout for busy clear wait */ 367688748Sambrisko 367788748Sambrisko if (waittime <= 0) { 3678198987Sjhb if_printf(ifp, "flash putchar busywait timeout!\n"); 367988748Sambrisko return -1; 368088748Sambrisko } 368188748Sambrisko /* 368288748Sambrisko * Port is clear now write byte and wait for it to echo back 368388748Sambrisko */ 368488748Sambrisko do { 3685108401Sambrisko CSR_WRITE_2(sc, AN_SW0(sc->mpi350), byte); 3686119163Sambrisko FLASH_DELAY(sc, 50); 368788748Sambrisko dwelltime -= 50; 3688108401Sambrisko echo = CSR_READ_2(sc, AN_SW1(sc->mpi350)); 368988748Sambrisko } while (dwelltime >= 0 && echo != byte); 369088748Sambrisko 369188748Sambrisko 3692108401Sambrisko CSR_WRITE_2(sc, AN_SW1(sc->mpi350), 0); 369388748Sambrisko 369488748Sambrisko return echo == byte; 369588748Sambrisko} 369688748Sambrisko 369788748Sambrisko/* 369888748Sambrisko * Transfer 32k of firmware data from user buffer to our buffer and send to 369988748Sambrisko * the card 370088748Sambrisko */ 370188748Sambrisko 370288748Sambriskostatic int 3703150446Simpflashputbuf(struct ifnet *ifp) 370488748Sambrisko{ 370588748Sambrisko unsigned short *bufp; 3706175446Sambrisko int nwords; 3707175446Sambrisko struct an_softc *sc = ifp->if_softc; 370888748Sambrisko 370988748Sambrisko /* Write stuff */ 371088748Sambrisko 3711108401Sambrisko bufp = sc->an_flash_buffer; 371288748Sambrisko 3713108401Sambrisko if (!sc->mpi350) { 3714108401Sambrisko CSR_WRITE_2(sc, AN_AUX_PAGE, 0x100); 3715108401Sambrisko CSR_WRITE_2(sc, AN_AUX_OFFSET, 0); 371688748Sambrisko 3717108401Sambrisko for (nwords = 0; nwords != FLASH_SIZE / 2; nwords++) { 3718108401Sambrisko CSR_WRITE_2(sc, AN_AUX_DATA, bufp[nwords] & 0xffff); 3719108401Sambrisko } 3720108401Sambrisko } else { 3721108401Sambrisko for (nwords = 0; nwords != FLASH_SIZE / 4; nwords++) { 3722175445Sambrisko CSR_MEM_AUX_WRITE_4(sc, 0x8000, 3723108401Sambrisko ((u_int32_t *)bufp)[nwords] & 0xffff); 3724108401Sambrisko } 372588748Sambrisko } 372688748Sambrisko 3727108401Sambrisko CSR_WRITE_2(sc, AN_SW0(sc->mpi350), 0x8000); 372888748Sambrisko 372988748Sambrisko return 0; 373088748Sambrisko} 373188748Sambrisko 373288748Sambrisko/* 373388748Sambrisko * After flashing restart the card. 373488748Sambrisko */ 373588748Sambrisko 373688748Sambriskostatic int 3737150446Simpflashrestart(struct ifnet *ifp) 373888748Sambrisko{ 3739175446Sambrisko int status = 0; 3740175446Sambrisko struct an_softc *sc = ifp->if_softc; 374188748Sambrisko 3742119163Sambrisko FLASH_DELAY(sc, 1024); /* Added 12/7/00 */ 374388748Sambrisko 3744199154Sjhb an_init_locked(sc); 374588748Sambrisko 3746119163Sambrisko FLASH_DELAY(sc, 1024); /* Added 12/7/00 */ 374788748Sambrisko return status; 374888748Sambrisko} 374988748Sambrisko 375088748Sambrisko/* 375188748Sambrisko * Entry point for flash ioclt. 375288748Sambrisko */ 375388748Sambrisko 375488748Sambriskostatic int 3755150446Simpflashcard(struct ifnet *ifp, struct aironet_ioctl *l_ioctl) 375688748Sambrisko{ 3757175446Sambrisko int z = 0, status; 375888748Sambrisko struct an_softc *sc; 375988748Sambrisko 376088748Sambrisko sc = ifp->if_softc; 3761108401Sambrisko if (sc->mpi350) { 3762198987Sjhb if_printf(ifp, "flashing not supported on MPI 350 yet\n"); 3763108401Sambrisko return(-1); 3764108401Sambrisko } 376588748Sambrisko status = l_ioctl->command; 376688748Sambrisko 376788748Sambrisko switch (l_ioctl->command) { 376888748Sambrisko case AIROFLSHRST: 376988748Sambrisko return cmdreset(ifp); 377088748Sambrisko break; 377188748Sambrisko case AIROFLSHSTFL: 3772108401Sambrisko if (sc->an_flash_buffer) { 3773108401Sambrisko free(sc->an_flash_buffer, M_DEVBUF); 3774108401Sambrisko sc->an_flash_buffer = NULL; 3775108401Sambrisko } 3776111119Simp sc->an_flash_buffer = malloc(FLASH_SIZE, M_DEVBUF, M_WAITOK); 3777108401Sambrisko if (sc->an_flash_buffer) 3778108401Sambrisko return setflashmode(ifp); 3779108401Sambrisko else 3780108401Sambrisko return ENOBUFS; 378188748Sambrisko break; 378288748Sambrisko case AIROFLSHGCHR: /* Get char from aux */ 3783171692Savatar AN_UNLOCK(sc); 3784144242Ssam status = copyin(l_ioctl->data, &sc->areq, l_ioctl->len); 3785171692Savatar AN_LOCK(sc); 3786144242Ssam if (status) 3787144242Ssam return status; 378888749Sambrisko z = *(int *)&sc->areq; 378988748Sambrisko if ((status = flashgchar(ifp, z, 8000)) == 1) 379088748Sambrisko return 0; 379188748Sambrisko else 379288748Sambrisko return -1; 379388748Sambrisko case AIROFLSHPCHR: /* Send char to card. */ 3794171692Savatar AN_UNLOCK(sc); 3795144242Ssam status = copyin(l_ioctl->data, &sc->areq, l_ioctl->len); 3796171692Savatar AN_LOCK(sc); 3797144242Ssam if (status) 3798144242Ssam return status; 379988749Sambrisko z = *(int *)&sc->areq; 380088748Sambrisko if ((status = flashpchar(ifp, z, 8000)) == -1) 380188748Sambrisko return -EIO; 380288748Sambrisko else 380388748Sambrisko return 0; 380488748Sambrisko break; 380588748Sambrisko case AIROFLPUTBUF: /* Send 32k to card */ 3806108401Sambrisko if (l_ioctl->len > FLASH_SIZE) { 3807198987Sjhb if_printf(ifp, "Buffer to big, %x %x\n", 3808108401Sambrisko l_ioctl->len, FLASH_SIZE); 380988748Sambrisko return -EINVAL; 381088748Sambrisko } 3811171692Savatar AN_UNLOCK(sc); 3812144242Ssam status = copyin(l_ioctl->data, sc->an_flash_buffer, l_ioctl->len); 3813171692Savatar AN_LOCK(sc); 3814144242Ssam if (status) 3815144242Ssam return status; 381688748Sambrisko 381788748Sambrisko if ((status = flashputbuf(ifp)) != 0) 381888748Sambrisko return -EIO; 381988748Sambrisko else 382088748Sambrisko return 0; 382188748Sambrisko break; 382288748Sambrisko case AIRORESTART: 382388748Sambrisko if ((status = flashrestart(ifp)) != 0) { 3824198987Sjhb if_printf(ifp, "FLASHRESTART returned %d\n", status); 382588748Sambrisko return -EIO; 382688748Sambrisko } else 382788748Sambrisko return 0; 382888748Sambrisko 382988748Sambrisko break; 383088748Sambrisko default: 383188748Sambrisko return -EINVAL; 383288748Sambrisko } 383388748Sambrisko 383488748Sambrisko return -EINVAL; 383588748Sambrisko} 3836