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: releng/10.3/sys/dev/an/if_an.c 265614 2014-05-07 21:38:33Z gavin $"); 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> 10555992Swpaul#include <sys/bus.h> 10655992Swpaul#include <machine/bus.h> 10755992Swpaul#include <sys/rman.h> 10884811Sjhb#include <sys/lock.h> 10967365Sjhb#include <sys/mutex.h> 11055992Swpaul#include <machine/resource.h> 111108401Sambrisko#include <sys/malloc.h> 11255992Swpaul 11355992Swpaul#include <net/if.h> 11455992Swpaul#include <net/if_arp.h> 115152315Sru#include <net/if_dl.h> 11655992Swpaul#include <net/ethernet.h> 11755992Swpaul#include <net/if_types.h> 11877217Sphk#include <net/if_media.h> 11955992Swpaul 120116951Ssam#include <net80211/ieee80211_var.h> 121116951Ssam#include <net80211/ieee80211_ioctl.h> 122116951Ssam 12355992Swpaul#ifdef INET 12455992Swpaul#include <netinet/in.h> 12555992Swpaul#include <netinet/in_systm.h> 12655992Swpaul#include <netinet/in_var.h> 12755992Swpaul#include <netinet/ip.h> 12855992Swpaul#endif 12955992Swpaul 13055992Swpaul#include <net/bpf.h> 13155992Swpaul 13255992Swpaul#include <machine/md_var.h> 13355992Swpaul 13455992Swpaul#include <dev/an/if_aironet_ieee.h> 13555992Swpaul#include <dev/an/if_anreg.h> 13655992Swpaul 13755992Swpaul/* These are global because we need them in sys/pci/if_an_p.c. */ 138150446Simpstatic void an_reset(struct an_softc *); 139150446Simpstatic int an_init_mpi350_desc(struct an_softc *); 140150446Simpstatic int an_ioctl(struct ifnet *, u_long, caddr_t); 141150446Simpstatic void an_init(void *); 142199154Sjhbstatic void an_init_locked(struct an_softc *); 143150446Simpstatic int an_init_tx_ring(struct an_softc *); 144150446Simpstatic void an_start(struct ifnet *); 145199154Sjhbstatic void an_start_locked(struct ifnet *); 146199154Sjhbstatic void an_watchdog(struct an_softc *); 147150446Simpstatic void an_rxeof(struct an_softc *); 148150446Simpstatic void an_txeof(struct an_softc *, int); 14955992Swpaul 150150446Simpstatic void an_promisc(struct an_softc *, int); 151150446Simpstatic int an_cmd(struct an_softc *, int, int); 152150446Simpstatic int an_cmd_struct(struct an_softc *, struct an_command *, 153150446Simp struct an_reply *); 154150446Simpstatic int an_read_record(struct an_softc *, struct an_ltv_gen *); 155150446Simpstatic int an_write_record(struct an_softc *, struct an_ltv_gen *); 156150446Simpstatic int an_read_data(struct an_softc *, int, int, caddr_t, int); 157150446Simpstatic int an_write_data(struct an_softc *, int, int, caddr_t, int); 158150446Simpstatic int an_seek(struct an_softc *, int, int, int); 159150446Simpstatic int an_alloc_nicmem(struct an_softc *, int, int *); 160150446Simpstatic int an_dma_malloc(struct an_softc *, bus_size_t, struct an_dma_alloc *, 161150446Simp int); 162150446Simpstatic void an_dma_free(struct an_softc *, struct an_dma_alloc *); 163150446Simpstatic void an_dma_malloc_cb(void *, bus_dma_segment_t *, int, int); 164150446Simpstatic void an_stats_update(void *); 165150446Simpstatic void an_setdef(struct an_softc *, struct an_req *); 16655992Swpaul#ifdef ANCACHE 167150446Simpstatic void an_cache_store(struct an_softc *, struct ether_header *, 168150446Simp struct mbuf *, u_int8_t, u_int8_t); 16955992Swpaul#endif 17055992Swpaul 17188748Sambrisko/* function definitions for use with the Cisco's Linux configuration 17288748Sambrisko utilities 17388748Sambrisko*/ 17488748Sambrisko 17592739Salfredstatic int readrids(struct ifnet*, struct aironet_ioctl*); 17692739Salfredstatic int writerids(struct ifnet*, struct aironet_ioctl*); 17792739Salfredstatic int flashcard(struct ifnet*, struct aironet_ioctl*); 17888748Sambrisko 17992739Salfredstatic int cmdreset(struct ifnet *); 18092739Salfredstatic int setflashmode(struct ifnet *); 18192739Salfredstatic int flashgchar(struct ifnet *,int,int); 18292739Salfredstatic int flashpchar(struct ifnet *,int,int); 18392739Salfredstatic int flashputbuf(struct ifnet *); 18492739Salfredstatic int flashrestart(struct ifnet *); 18592739Salfredstatic int WaitBusy(struct ifnet *, int); 18692739Salfredstatic int unstickbusy(struct ifnet *); 18788748Sambrisko 18892739Salfredstatic void an_dump_record (struct an_softc *,struct an_ltv_gen *, 18992739Salfred char *); 19078639Sbrooks 19192739Salfredstatic int an_media_change (struct ifnet *); 19292739Salfredstatic void an_media_status (struct ifnet *, struct ifmediareq *); 19377217Sphk 19478639Sbrooksstatic int an_dump = 0; 195108401Sambriskostatic int an_cache_mode = 0; 19688748Sambrisko 197108401Sambrisko#define DBM 0 198108401Sambrisko#define PERCENT 1 199108401Sambrisko#define RAW 2 200108401Sambrisko 20183269Sbrooksstatic char an_conf[256]; 202108401Sambriskostatic char an_conf_cache[256]; 20383269Sbrooks 20483269Sbrooks/* sysctl vars */ 205108401Sambrisko 206227309Sedstatic SYSCTL_NODE(_hw, OID_AUTO, an, CTLFLAG_RD, 0, 207227309Sed "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 */ 35255992Swpaul ssid.an_len = sizeof(ssid); 35355992Swpaul ssid.an_type = AN_RID_SSIDLIST; 35455992Swpaul 355175446Sambrisko /* Make sure interrupts are disabled. */ 356119156Sambrisko sc->mpi350 = 0; 357175446Sambrisko CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0); 358175446Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), 0xFFFF); 35955992Swpaul 360265614Sgavin sc->an_dev = dev; 361175445Sambrisko mtx_init(&sc->an_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 362199154Sjhb MTX_DEF); 363175445Sambrisko AN_LOCK(sc); 36455992Swpaul an_reset(sc); 36555992Swpaul 366175445Sambrisko if (an_cmd(sc, AN_CMD_READCFG, 0)) { 367175445Sambrisko AN_UNLOCK(sc); 368175445Sambrisko goto fail; 369175445Sambrisko } 37055992Swpaul 371175445Sambrisko if (an_read_record(sc, (struct an_ltv_gen *)&ssid)) { 372175445Sambrisko AN_UNLOCK(sc); 373175445Sambrisko goto fail; 374175445Sambrisko } 37555992Swpaul 37668692Swpaul /* See if the ssid matches what we expect ... but doesn't have to */ 377175445Sambrisko if (strcmp(ssid.an_entry[0].an_ssid, AN_DEF_SSID)) { 378175445Sambrisko AN_UNLOCK(sc); 379175445Sambrisko goto fail; 380175445Sambrisko } 38183270Sbrooks 382175445Sambrisko AN_UNLOCK(sc); 38355992Swpaul return(AN_IOSIZ); 384175445Sambriskofail: 385175445Sambrisko mtx_destroy(&sc->an_mtx); 386175445Sambrisko return(0); 38755992Swpaul} 38855992Swpaul 38955992Swpaul/* 39055992Swpaul * Allocate a port resource with the given resource id. 39155992Swpaul */ 39255992Swpaulint 393150446Simpan_alloc_port(device_t dev, int rid, int size) 39455992Swpaul{ 39555992Swpaul struct an_softc *sc = device_get_softc(dev); 39655992Swpaul struct resource *res; 39755992Swpaul 39855992Swpaul res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 39955992Swpaul 0ul, ~0ul, size, RF_ACTIVE); 40055992Swpaul if (res) { 40155992Swpaul sc->port_rid = rid; 40255992Swpaul sc->port_res = res; 40355992Swpaul return (0); 40455992Swpaul } else { 40555992Swpaul return (ENOENT); 40655992Swpaul } 40755992Swpaul} 40855992Swpaul 40955992Swpaul/* 410108401Sambrisko * Allocate a memory resource with the given resource id. 411108401Sambrisko */ 412108401Sambriskoint an_alloc_memory(device_t dev, int rid, int size) 413108401Sambrisko{ 414108401Sambrisko struct an_softc *sc = device_get_softc(dev); 415108401Sambrisko struct resource *res; 416108401Sambrisko 417108401Sambrisko res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 418108401Sambrisko 0ul, ~0ul, size, RF_ACTIVE); 419108401Sambrisko if (res) { 420108401Sambrisko sc->mem_rid = rid; 421108401Sambrisko sc->mem_res = res; 422108401Sambrisko sc->mem_used = size; 423108401Sambrisko return (0); 424108401Sambrisko } else { 425108401Sambrisko return (ENOENT); 426108401Sambrisko } 427108401Sambrisko} 428108401Sambrisko 429108401Sambrisko/* 430108401Sambrisko * Allocate a auxilary memory resource with the given resource id. 431108401Sambrisko */ 432108401Sambriskoint an_alloc_aux_memory(device_t dev, int rid, int size) 433108401Sambrisko{ 434108401Sambrisko struct an_softc *sc = device_get_softc(dev); 435108401Sambrisko struct resource *res; 436108401Sambrisko 437108401Sambrisko res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 438108401Sambrisko 0ul, ~0ul, size, RF_ACTIVE); 439108401Sambrisko if (res) { 440108401Sambrisko sc->mem_aux_rid = rid; 441108401Sambrisko sc->mem_aux_res = res; 442108401Sambrisko sc->mem_aux_used = size; 443108401Sambrisko return (0); 444108401Sambrisko } else { 445108401Sambrisko return (ENOENT); 446108401Sambrisko } 447108401Sambrisko} 448108401Sambrisko 449108401Sambrisko/* 45055992Swpaul * Allocate an irq resource with the given resource id. 45155992Swpaul */ 45255992Swpaulint 453150446Simpan_alloc_irq(device_t dev, int rid, int flags) 45455992Swpaul{ 45555992Swpaul struct an_softc *sc = device_get_softc(dev); 45655992Swpaul struct resource *res; 45755992Swpaul 458127135Snjl res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 459127135Snjl (RF_ACTIVE | flags)); 46055992Swpaul if (res) { 46155992Swpaul sc->irq_rid = rid; 46255992Swpaul sc->irq_res = res; 46355992Swpaul return (0); 46455992Swpaul } else { 46555992Swpaul return (ENOENT); 46655992Swpaul } 46755992Swpaul} 46855992Swpaul 469108401Sambriskostatic void 470150446Simpan_dma_malloc_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) 471108401Sambrisko{ 472108401Sambrisko bus_addr_t *paddr = (bus_addr_t*) arg; 473108401Sambrisko *paddr = segs->ds_addr; 474108401Sambrisko} 475108401Sambrisko 47655992Swpaul/* 477108401Sambrisko * Alloc DMA memory and set the pointer to it 478108401Sambrisko */ 479108401Sambriskostatic int 480150446Simpan_dma_malloc(struct an_softc *sc, bus_size_t size, struct an_dma_alloc *dma, 481150446Simp int mapflags) 482108401Sambrisko{ 483108401Sambrisko int r; 484108401Sambrisko 485108401Sambrisko r = bus_dmamap_create(sc->an_dtag, BUS_DMA_NOWAIT, &dma->an_dma_map); 486108401Sambrisko if (r != 0) 487108401Sambrisko goto fail_0; 488108401Sambrisko 489108401Sambrisko r = bus_dmamem_alloc(sc->an_dtag, (void**) &dma->an_dma_vaddr, 490108401Sambrisko BUS_DMA_NOWAIT, &dma->an_dma_map); 491108401Sambrisko if (r != 0) 492108401Sambrisko goto fail_1; 493108401Sambrisko 494108401Sambrisko r = bus_dmamap_load(sc->an_dtag, dma->an_dma_map, dma->an_dma_vaddr, 495175446Sambrisko size, 496108401Sambrisko an_dma_malloc_cb, 497108401Sambrisko &dma->an_dma_paddr, 498108401Sambrisko mapflags | BUS_DMA_NOWAIT); 499108401Sambrisko if (r != 0) 500108401Sambrisko goto fail_2; 501108401Sambrisko 502108401Sambrisko dma->an_dma_size = size; 503108401Sambrisko return (0); 504108401Sambrisko 505108401Sambriskofail_2: 506108401Sambrisko bus_dmamap_unload(sc->an_dtag, dma->an_dma_map); 507108401Sambriskofail_1: 508108401Sambrisko bus_dmamem_free(sc->an_dtag, dma->an_dma_vaddr, dma->an_dma_map); 509108401Sambriskofail_0: 510108401Sambrisko bus_dmamap_destroy(sc->an_dtag, dma->an_dma_map); 511108401Sambrisko dma->an_dma_map = NULL; 512108401Sambrisko return (r); 513108401Sambrisko} 514108401Sambrisko 515108401Sambriskostatic void 516150446Simpan_dma_free(struct an_softc *sc, struct an_dma_alloc *dma) 517108401Sambrisko{ 518108401Sambrisko bus_dmamap_unload(sc->an_dtag, dma->an_dma_map); 519108401Sambrisko bus_dmamem_free(sc->an_dtag, dma->an_dma_vaddr, dma->an_dma_map); 520123978Sambrisko dma->an_dma_vaddr = 0; 521108401Sambrisko bus_dmamap_destroy(sc->an_dtag, dma->an_dma_map); 522108401Sambrisko} 523108401Sambrisko 524108401Sambrisko/* 52555992Swpaul * Release all resources 52655992Swpaul */ 52755992Swpaulvoid 528150446Simpan_release_resources(device_t dev) 52955992Swpaul{ 53055992Swpaul struct an_softc *sc = device_get_softc(dev); 531108401Sambrisko int i; 53255992Swpaul 53355992Swpaul if (sc->port_res) { 53455992Swpaul bus_release_resource(dev, SYS_RES_IOPORT, 53555992Swpaul sc->port_rid, sc->port_res); 53655992Swpaul sc->port_res = 0; 53755992Swpaul } 538108401Sambrisko if (sc->mem_res) { 539108401Sambrisko bus_release_resource(dev, SYS_RES_MEMORY, 540108401Sambrisko sc->mem_rid, sc->mem_res); 541108401Sambrisko sc->mem_res = 0; 542108401Sambrisko } 543108401Sambrisko if (sc->mem_aux_res) { 544108401Sambrisko bus_release_resource(dev, SYS_RES_MEMORY, 545108401Sambrisko sc->mem_aux_rid, sc->mem_aux_res); 546108401Sambrisko sc->mem_aux_res = 0; 547108401Sambrisko } 54855992Swpaul if (sc->irq_res) { 54955992Swpaul bus_release_resource(dev, SYS_RES_IRQ, 55055992Swpaul sc->irq_rid, sc->irq_res); 55155992Swpaul sc->irq_res = 0; 55255992Swpaul } 553108401Sambrisko if (sc->an_rid_buffer.an_dma_paddr) { 554108401Sambrisko an_dma_free(sc, &sc->an_rid_buffer); 555108401Sambrisko } 556108401Sambrisko for (i = 0; i < AN_MAX_RX_DESC; i++) 557108401Sambrisko if (sc->an_rx_buffer[i].an_dma_paddr) { 558108401Sambrisko an_dma_free(sc, &sc->an_rx_buffer[i]); 559108401Sambrisko } 560108401Sambrisko for (i = 0; i < AN_MAX_TX_DESC; i++) 561108401Sambrisko if (sc->an_tx_buffer[i].an_dma_paddr) { 562108401Sambrisko an_dma_free(sc, &sc->an_tx_buffer[i]); 563108401Sambrisko } 564108401Sambrisko if (sc->an_dtag) { 565108401Sambrisko bus_dma_tag_destroy(sc->an_dtag); 566108401Sambrisko } 567108401Sambrisko 56855992Swpaul} 56955992Swpaul 57083270Sbrooksint 571150446Simpan_init_mpi350_desc(struct an_softc *sc) 572108401Sambrisko{ 573108401Sambrisko struct an_command cmd_struct; 574108401Sambrisko struct an_reply reply; 575108401Sambrisko struct an_card_rid_desc an_rid_desc; 576108401Sambrisko struct an_card_rx_desc an_rx_desc; 577108401Sambrisko struct an_card_tx_desc an_tx_desc; 578108401Sambrisko int i, desc; 579108401Sambrisko 580175445Sambrisko AN_LOCK_ASSERT(sc); 581108401Sambrisko if(!sc->an_rid_buffer.an_dma_paddr) 582108401Sambrisko an_dma_malloc(sc, AN_RID_BUFFER_SIZE, 583108401Sambrisko &sc->an_rid_buffer, 0); 584108401Sambrisko for (i = 0; i < AN_MAX_RX_DESC; i++) 585108401Sambrisko if(!sc->an_rx_buffer[i].an_dma_paddr) 586108401Sambrisko an_dma_malloc(sc, AN_RX_BUFFER_SIZE, 587108401Sambrisko &sc->an_rx_buffer[i], 0); 588108401Sambrisko for (i = 0; i < AN_MAX_TX_DESC; i++) 589108401Sambrisko if(!sc->an_tx_buffer[i].an_dma_paddr) 590108401Sambrisko an_dma_malloc(sc, AN_TX_BUFFER_SIZE, 591108401Sambrisko &sc->an_tx_buffer[i], 0); 592108401Sambrisko 593108401Sambrisko /* 594108401Sambrisko * Allocate RX descriptor 595108401Sambrisko */ 596108401Sambrisko bzero(&reply,sizeof(reply)); 597108401Sambrisko cmd_struct.an_cmd = AN_CMD_ALLOC_DESC; 598108401Sambrisko cmd_struct.an_parm0 = AN_DESCRIPTOR_RX; 599108401Sambrisko cmd_struct.an_parm1 = AN_RX_DESC_OFFSET; 600108401Sambrisko cmd_struct.an_parm2 = AN_MAX_RX_DESC; 601108401Sambrisko if (an_cmd_struct(sc, &cmd_struct, &reply)) { 602198987Sjhb if_printf(sc->an_ifp, "failed to allocate RX descriptor\n"); 603108401Sambrisko return(EIO); 604108401Sambrisko } 605108401Sambrisko 606108401Sambrisko for (desc = 0; desc < AN_MAX_RX_DESC; desc++) { 607108401Sambrisko bzero(&an_rx_desc, sizeof(an_rx_desc)); 608108401Sambrisko an_rx_desc.an_valid = 1; 609108401Sambrisko an_rx_desc.an_len = AN_RX_BUFFER_SIZE; 610108401Sambrisko an_rx_desc.an_done = 0; 611108401Sambrisko an_rx_desc.an_phys = sc->an_rx_buffer[desc].an_dma_paddr; 612108401Sambrisko 613108401Sambrisko for (i = 0; i < sizeof(an_rx_desc) / 4; i++) 614155321Simp CSR_MEM_AUX_WRITE_4(sc, AN_RX_DESC_OFFSET 615155321Simp + (desc * sizeof(an_rx_desc)) 616155321Simp + (i * 4), 617155321Simp ((u_int32_t *)(void *)&an_rx_desc)[i]); 618108401Sambrisko } 619108401Sambrisko 620108401Sambrisko /* 621108401Sambrisko * Allocate TX descriptor 622108401Sambrisko */ 623108401Sambrisko 624108401Sambrisko bzero(&reply,sizeof(reply)); 625108401Sambrisko cmd_struct.an_cmd = AN_CMD_ALLOC_DESC; 626108401Sambrisko cmd_struct.an_parm0 = AN_DESCRIPTOR_TX; 627108401Sambrisko cmd_struct.an_parm1 = AN_TX_DESC_OFFSET; 628108401Sambrisko cmd_struct.an_parm2 = AN_MAX_TX_DESC; 629108401Sambrisko if (an_cmd_struct(sc, &cmd_struct, &reply)) { 630198987Sjhb if_printf(sc->an_ifp, "failed to allocate TX descriptor\n"); 631108401Sambrisko return(EIO); 632108401Sambrisko } 633108401Sambrisko 634108401Sambrisko for (desc = 0; desc < AN_MAX_TX_DESC; desc++) { 635108401Sambrisko bzero(&an_tx_desc, sizeof(an_tx_desc)); 636108401Sambrisko an_tx_desc.an_offset = 0; 637108401Sambrisko an_tx_desc.an_eoc = 0; 638108401Sambrisko an_tx_desc.an_valid = 0; 639108401Sambrisko an_tx_desc.an_len = 0; 640108401Sambrisko an_tx_desc.an_phys = sc->an_tx_buffer[desc].an_dma_paddr; 641108401Sambrisko 642108401Sambrisko for (i = 0; i < sizeof(an_tx_desc) / 4; i++) 643108401Sambrisko CSR_MEM_AUX_WRITE_4(sc, AN_TX_DESC_OFFSET 644155321Simp + (desc * sizeof(an_tx_desc)) 645155321Simp + (i * 4), 646155321Simp ((u_int32_t *)(void *)&an_tx_desc)[i]); 647108401Sambrisko } 648108401Sambrisko 649108401Sambrisko /* 650108401Sambrisko * Allocate RID descriptor 651108401Sambrisko */ 652108401Sambrisko 653108401Sambrisko bzero(&reply,sizeof(reply)); 654108401Sambrisko cmd_struct.an_cmd = AN_CMD_ALLOC_DESC; 655108401Sambrisko cmd_struct.an_parm0 = AN_DESCRIPTOR_HOSTRW; 656108401Sambrisko cmd_struct.an_parm1 = AN_HOST_DESC_OFFSET; 657108401Sambrisko cmd_struct.an_parm2 = 1; 658108401Sambrisko if (an_cmd_struct(sc, &cmd_struct, &reply)) { 659198987Sjhb if_printf(sc->an_ifp, "failed to allocate host descriptor\n"); 660108401Sambrisko return(EIO); 661108401Sambrisko } 662108401Sambrisko 663108401Sambrisko bzero(&an_rid_desc, sizeof(an_rid_desc)); 664108401Sambrisko an_rid_desc.an_valid = 1; 665108401Sambrisko an_rid_desc.an_len = AN_RID_BUFFER_SIZE; 666108401Sambrisko an_rid_desc.an_rid = 0; 667108401Sambrisko an_rid_desc.an_phys = sc->an_rid_buffer.an_dma_paddr; 668108401Sambrisko 669108401Sambrisko for (i = 0; i < sizeof(an_rid_desc) / 4; i++) 670175445Sambrisko CSR_MEM_AUX_WRITE_4(sc, AN_HOST_DESC_OFFSET + i * 4, 671155321Simp ((u_int32_t *)(void *)&an_rid_desc)[i]); 672108401Sambrisko 673108401Sambrisko return(0); 674108401Sambrisko} 675108401Sambrisko 676108401Sambriskoint 677198995Sjhban_attach(struct an_softc *sc, int flags) 67855992Swpaul{ 679147256Sbrooks struct ifnet *ifp; 680113316Simp int error = EIO; 681110253Sambrisko int i, nrate, mword; 682110253Sambrisko u_int8_t r; 68355992Swpaul 684147380Sdelphij ifp = sc->an_ifp = if_alloc(IFT_ETHER); 685147256Sbrooks if (ifp == NULL) { 686198987Sjhb device_printf(sc->an_dev, "can not if_alloc()\n"); 687147256Sbrooks goto fail; 688147256Sbrooks } 689265614Sgavin ifp->if_softc = sc; 690265614Sgavin if_initname(ifp, device_get_name(sc->an_dev), 691265614Sgavin device_get_unit(sc->an_dev)); 692175445Sambrisko 69355992Swpaul sc->an_gone = 0; 69455992Swpaul sc->an_associated = 0; 69583269Sbrooks sc->an_monitor = 0; 69683269Sbrooks sc->an_was_monitor = 0; 697108401Sambrisko sc->an_flash_buffer = NULL; 69855992Swpaul 69955992Swpaul /* Reset the NIC. */ 700175445Sambrisko AN_LOCK(sc); 70155992Swpaul an_reset(sc); 702110104Sambrisko if (sc->mpi350) { 703108401Sambrisko error = an_init_mpi350_desc(sc); 704108401Sambrisko if (error) 705113316Simp goto fail; 706108401Sambrisko } 70755992Swpaul 70855992Swpaul /* Load factory config */ 70955992Swpaul if (an_cmd(sc, AN_CMD_READCFG, 0)) { 710198987Sjhb device_printf(sc->an_dev, "failed to load config data\n"); 711113316Simp goto fail; 71255992Swpaul } 71355992Swpaul 71455992Swpaul /* Read the current configuration */ 71555992Swpaul sc->an_config.an_type = AN_RID_GENCONFIG; 71655992Swpaul sc->an_config.an_len = sizeof(struct an_ltv_genconfig); 71755992Swpaul if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_config)) { 718198987Sjhb device_printf(sc->an_dev, "read record failed\n"); 719113316Simp goto fail; 72055992Swpaul } 72155992Swpaul 72255992Swpaul /* Read the card capabilities */ 72355992Swpaul sc->an_caps.an_type = AN_RID_CAPABILITIES; 72455992Swpaul sc->an_caps.an_len = sizeof(struct an_ltv_caps); 72555992Swpaul if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_caps)) { 726198987Sjhb device_printf(sc->an_dev, "read record failed\n"); 727113316Simp goto fail; 72855992Swpaul } 72955992Swpaul 73055992Swpaul /* Read ssid list */ 73155992Swpaul sc->an_ssidlist.an_type = AN_RID_SSIDLIST; 732119156Sambrisko sc->an_ssidlist.an_len = sizeof(struct an_ltv_ssidlist_new); 73355992Swpaul if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_ssidlist)) { 734198987Sjhb device_printf(sc->an_dev, "read record failed\n"); 735113316Simp goto fail; 73655992Swpaul } 73755992Swpaul 73855992Swpaul /* Read AP list */ 73955992Swpaul sc->an_aplist.an_type = AN_RID_APLIST; 74055992Swpaul sc->an_aplist.an_len = sizeof(struct an_ltv_aplist); 74155992Swpaul if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_aplist)) { 742198987Sjhb device_printf(sc->an_dev, "read record failed\n"); 743113316Simp goto fail; 74455992Swpaul } 74555992Swpaul 746108401Sambrisko#ifdef ANCACHE 747108401Sambrisko /* Read the RSSI <-> dBm map */ 748108401Sambrisko sc->an_have_rssimap = 0; 749108401Sambrisko if (sc->an_caps.an_softcaps & 8) { 750108401Sambrisko sc->an_rssimap.an_type = AN_RID_RSSI_MAP; 751108401Sambrisko sc->an_rssimap.an_len = sizeof(struct an_ltv_rssi_map); 752108401Sambrisko if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_rssimap)) { 753198987Sjhb device_printf(sc->an_dev, 754198987Sjhb "unable to get RSSI <-> dBM map\n"); 755108401Sambrisko } else { 756198987Sjhb device_printf(sc->an_dev, "got RSSI <-> dBM map\n"); 757108401Sambrisko sc->an_have_rssimap = 1; 758108401Sambrisko } 759108401Sambrisko } else { 760198987Sjhb device_printf(sc->an_dev, "no RSSI <-> dBM map\n"); 761108401Sambrisko } 762108401Sambrisko#endif 763175445Sambrisko AN_UNLOCK(sc); 764108401Sambrisko 76555992Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 76655992Swpaul ifp->if_ioctl = an_ioctl; 76755992Swpaul ifp->if_start = an_start; 76855992Swpaul ifp->if_init = an_init; 76955992Swpaul ifp->if_baudrate = 10000000; 770207554Ssobomax IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 771207554Ssobomax ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; 772132986Smlaier IFQ_SET_READY(&ifp->if_snd); 77355992Swpaul 77455992Swpaul bzero(sc->an_config.an_nodename, sizeof(sc->an_config.an_nodename)); 77555992Swpaul bcopy(AN_DEFAULT_NODENAME, sc->an_config.an_nodename, 77655992Swpaul sizeof(AN_DEFAULT_NODENAME) - 1); 77755992Swpaul 778119156Sambrisko bzero(sc->an_ssidlist.an_entry[0].an_ssid, 779119156Sambrisko sizeof(sc->an_ssidlist.an_entry[0].an_ssid)); 780119156Sambrisko bcopy(AN_DEFAULT_NETNAME, sc->an_ssidlist.an_entry[0].an_ssid, 78155992Swpaul sizeof(AN_DEFAULT_NETNAME) - 1); 782119156Sambrisko sc->an_ssidlist.an_entry[0].an_len = strlen(AN_DEFAULT_NETNAME); 78355992Swpaul 78455992Swpaul sc->an_config.an_opmode = 78574144Sassar AN_OPMODE_INFRASTRUCTURE_STATION; 78655992Swpaul 78755992Swpaul sc->an_tx_rate = 0; 78855992Swpaul bzero((char *)&sc->an_stats, sizeof(sc->an_stats)); 78955992Swpaul 790110253Sambrisko nrate = 8; 791110253Sambrisko 79277217Sphk ifmedia_init(&sc->an_ifmedia, 0, an_media_change, an_media_status); 793110253Sambrisko if_printf(ifp, "supported rates: "); 794110253Sambrisko#define ADD(s, o) ifmedia_add(&sc->an_ifmedia, \ 795110253Sambrisko IFM_MAKEWORD(IFM_IEEE80211, (s), (o), 0), 0, NULL) 796110253Sambrisko ADD(IFM_AUTO, 0); 797110253Sambrisko ADD(IFM_AUTO, IFM_IEEE80211_ADHOC); 798110253Sambrisko for (i = 0; i < nrate; i++) { 799110253Sambrisko r = sc->an_caps.an_rates[i]; 800228621Sbschmidt mword = ieee80211_rate2media(NULL, r, IEEE80211_MODE_AUTO); 801110253Sambrisko if (mword == 0) 802110253Sambrisko continue; 803110253Sambrisko printf("%s%d%sMbps", (i != 0 ? " " : ""), 804110253Sambrisko (r & IEEE80211_RATE_VAL) / 2, ((r & 0x1) != 0 ? ".5" : "")); 805110253Sambrisko ADD(mword, 0); 806110253Sambrisko ADD(mword, IFM_IEEE80211_ADHOC); 80777217Sphk } 808110253Sambrisko printf("\n"); 809175445Sambrisko ifmedia_set(&sc->an_ifmedia, IFM_MAKEWORD(IFM_IEEE80211, 810110253Sambrisko IFM_AUTO, 0, 0)); 811110253Sambrisko#undef ADD 81277217Sphk 81355992Swpaul /* 81463090Sarchie * Call MI attach routine. 81555992Swpaul */ 816147256Sbrooks 817147256Sbrooks ether_ifattach(ifp, sc->an_caps.an_oemaddr); 818173668Savatar callout_init_mtx(&sc->an_stat_ch, &sc->an_mtx, 0); 81955992Swpaul 82055992Swpaul return(0); 821175445Sambriskofail: 822175445Sambrisko AN_UNLOCK(sc); 823113316Simp mtx_destroy(&sc->an_mtx); 824147256Sbrooks if (ifp != NULL) 825147256Sbrooks if_free(ifp); 826113316Simp return(error); 82755992Swpaul} 82855992Swpaul 829123978Sambriskoint 830123978Sambriskoan_detach(device_t dev) 831123978Sambrisko{ 832123978Sambrisko struct an_softc *sc = device_get_softc(dev); 833147256Sbrooks struct ifnet *ifp = sc->an_ifp; 834123978Sambrisko 835123978Sambrisko if (sc->an_gone) { 836123978Sambrisko device_printf(dev,"already unloaded\n"); 837123978Sambrisko return(0); 838123978Sambrisko } 839148639Semax AN_LOCK(sc); 840123978Sambrisko an_stop(sc); 841148454Semax sc->an_gone = 1; 842123978Sambrisko ifmedia_removeall(&sc->an_ifmedia); 843148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 844148454Semax AN_UNLOCK(sc); 845123978Sambrisko ether_ifdetach(ifp); 846150306Simp bus_teardown_intr(dev, sc->irq_res, sc->irq_handle); 847173668Savatar callout_drain(&sc->an_stat_ch); 848147256Sbrooks if_free(ifp); 849123978Sambrisko an_release_resources(dev); 850123978Sambrisko mtx_destroy(&sc->an_mtx); 851123978Sambrisko return (0); 852123978Sambrisko} 853123978Sambrisko 85483270Sbrooksstatic void 855150446Simpan_rxeof(struct an_softc *sc) 85655992Swpaul{ 85783269Sbrooks struct ifnet *ifp; 85883269Sbrooks struct ether_header *eh; 85983269Sbrooks struct ieee80211_frame *ih; 86083269Sbrooks struct an_rxframe rx_frame; 86183269Sbrooks struct an_rxframe_802_3 rx_frame_802_3; 86283269Sbrooks struct mbuf *m; 863108401Sambrisko int len, id, error = 0, i, count = 0; 864108401Sambrisko int ieee80211_header_len; 865108401Sambrisko u_char *bpf_buf; 866108401Sambrisko u_short fc1; 867108401Sambrisko struct an_card_rx_desc an_rx_desc; 868108401Sambrisko u_int8_t *buf; 86955992Swpaul 870122689Ssam AN_LOCK_ASSERT(sc); 871122689Ssam 872147256Sbrooks ifp = sc->an_ifp; 87355992Swpaul 874108401Sambrisko if (!sc->mpi350) { 875108401Sambrisko id = CSR_READ_2(sc, AN_RX_FID); 87655992Swpaul 877108401Sambrisko if (sc->an_monitor && (ifp->if_flags & IFF_PROMISC)) { 878108401Sambrisko /* read raw 802.11 packet */ 879108401Sambrisko bpf_buf = sc->buf_802_11; 88055992Swpaul 881108401Sambrisko /* read header */ 882108401Sambrisko if (an_read_data(sc, id, 0x0, (caddr_t)&rx_frame, 883108401Sambrisko sizeof(rx_frame))) { 884108401Sambrisko ifp->if_ierrors++; 885108401Sambrisko return; 886108401Sambrisko } 88755992Swpaul 888108401Sambrisko /* 889108401Sambrisko * skip beacon by default since this increases the 890108401Sambrisko * system load a lot 891108401Sambrisko */ 89283270Sbrooks 893108401Sambrisko if (!(sc->an_monitor & AN_MONITOR_INCLUDE_BEACON) && 894108401Sambrisko (rx_frame.an_frame_ctl & 895108401Sambrisko IEEE80211_FC0_SUBTYPE_BEACON)) { 89683269Sbrooks return; 89783269Sbrooks } 89855992Swpaul 899108401Sambrisko if (sc->an_monitor & AN_MONITOR_AIRONET_HEADER) { 900108401Sambrisko len = rx_frame.an_rx_payload_len 901108401Sambrisko + sizeof(rx_frame); 902108401Sambrisko /* Check for insane frame length */ 903108401Sambrisko if (len > sizeof(sc->buf_802_11)) { 904198987Sjhb if_printf(ifp, "oversized packet " 905108401Sambrisko "received (%d, %d)\n", 906198987Sjhb len, MCLBYTES); 907108401Sambrisko ifp->if_ierrors++; 908108401Sambrisko return; 909108401Sambrisko } 91055992Swpaul 911108401Sambrisko bcopy((char *)&rx_frame, 912108401Sambrisko bpf_buf, sizeof(rx_frame)); 913108401Sambrisko 914108401Sambrisko error = an_read_data(sc, id, sizeof(rx_frame), 915108401Sambrisko (caddr_t)bpf_buf+sizeof(rx_frame), 916108401Sambrisko rx_frame.an_rx_payload_len); 917108401Sambrisko } else { 918108401Sambrisko fc1=rx_frame.an_frame_ctl >> 8; 919175445Sambrisko ieee80211_header_len = 920108401Sambrisko sizeof(struct ieee80211_frame); 921108401Sambrisko if ((fc1 & IEEE80211_FC1_DIR_TODS) && 922108401Sambrisko (fc1 & IEEE80211_FC1_DIR_FROMDS)) { 923108401Sambrisko ieee80211_header_len += ETHER_ADDR_LEN; 924108401Sambrisko } 925108401Sambrisko 926108401Sambrisko len = rx_frame.an_rx_payload_len 927108401Sambrisko + ieee80211_header_len; 928108401Sambrisko /* Check for insane frame length */ 929108401Sambrisko if (len > sizeof(sc->buf_802_11)) { 930198987Sjhb if_printf(ifp, "oversized packet " 931108401Sambrisko "received (%d, %d)\n", 932198987Sjhb len, MCLBYTES); 933108401Sambrisko ifp->if_ierrors++; 934108401Sambrisko return; 935108401Sambrisko } 936108401Sambrisko 937108401Sambrisko ih = (struct ieee80211_frame *)bpf_buf; 938108401Sambrisko 939108401Sambrisko bcopy((char *)&rx_frame.an_frame_ctl, 940108401Sambrisko (char *)ih, ieee80211_header_len); 941108401Sambrisko 942108401Sambrisko error = an_read_data(sc, id, sizeof(rx_frame) + 943108401Sambrisko rx_frame.an_gaplen, 944108401Sambrisko (caddr_t)ih +ieee80211_header_len, 945108401Sambrisko rx_frame.an_rx_payload_len); 946108401Sambrisko } 947108401Sambrisko /* dump raw 802.11 packet to bpf and skip ip stack */ 948108401Sambrisko BPF_TAP(ifp, bpf_buf, len); 94983270Sbrooks } else { 950243857Sglebius MGETHDR(m, M_NOWAIT, MT_DATA); 951108401Sambrisko if (m == NULL) { 952108401Sambrisko ifp->if_ierrors++; 953108401Sambrisko return; 95483269Sbrooks } 955243857Sglebius MCLGET(m, M_NOWAIT); 956108401Sambrisko if (!(m->m_flags & M_EXT)) { 957108401Sambrisko m_freem(m); 958108401Sambrisko ifp->if_ierrors++; 959108401Sambrisko return; 960108401Sambrisko } 961108401Sambrisko m->m_pkthdr.rcvif = ifp; 962108401Sambrisko /* Read Ethernet encapsulated packet */ 96355992Swpaul 964108401Sambrisko#ifdef ANCACHE 965108401Sambrisko /* Read NIC frame header */ 966175445Sambrisko if (an_read_data(sc, id, 0, (caddr_t)&rx_frame, 967108401Sambrisko sizeof(rx_frame))) { 968154394Srwatson m_freem(m); 969108401Sambrisko ifp->if_ierrors++; 970108401Sambrisko return; 971108401Sambrisko } 972108401Sambrisko#endif 973108401Sambrisko /* Read in the 802_3 frame header */ 974175445Sambrisko if (an_read_data(sc, id, 0x34, 975108401Sambrisko (caddr_t)&rx_frame_802_3, 976108401Sambrisko sizeof(rx_frame_802_3))) { 977154394Srwatson m_freem(m); 978108401Sambrisko ifp->if_ierrors++; 979108401Sambrisko return; 980108401Sambrisko } 981108401Sambrisko if (rx_frame_802_3.an_rx_802_3_status != 0) { 982154394Srwatson m_freem(m); 983108401Sambrisko ifp->if_ierrors++; 984108401Sambrisko return; 985108401Sambrisko } 98683269Sbrooks /* Check for insane frame length */ 987108401Sambrisko len = rx_frame_802_3.an_rx_802_3_payload_len; 98883269Sbrooks if (len > sizeof(sc->buf_802_11)) { 989154394Srwatson m_freem(m); 990198987Sjhb if_printf(ifp, "oversized packet " 991108401Sambrisko "received (%d, %d)\n", 992198987Sjhb len, MCLBYTES); 99383269Sbrooks ifp->if_ierrors++; 99483269Sbrooks return; 99583269Sbrooks } 996108401Sambrisko m->m_pkthdr.len = m->m_len = 997108401Sambrisko rx_frame_802_3.an_rx_802_3_payload_len + 12; 99855992Swpaul 999108401Sambrisko eh = mtod(m, struct ether_header *); 100055992Swpaul 1001108401Sambrisko bcopy((char *)&rx_frame_802_3.an_rx_dst_addr, 1002108401Sambrisko (char *)&eh->ether_dhost, ETHER_ADDR_LEN); 1003108401Sambrisko bcopy((char *)&rx_frame_802_3.an_rx_src_addr, 1004108401Sambrisko (char *)&eh->ether_shost, ETHER_ADDR_LEN); 100555992Swpaul 1006108401Sambrisko /* in mbuf header type is just before payload */ 1007175445Sambrisko error = an_read_data(sc, id, 0x44, 1008108401Sambrisko (caddr_t)&(eh->ether_type), 1009108401Sambrisko rx_frame_802_3.an_rx_802_3_payload_len); 101055992Swpaul 1011108401Sambrisko if (error) { 1012108401Sambrisko m_freem(m); 1013108401Sambrisko ifp->if_ierrors++; 1014108401Sambrisko return; 1015108401Sambrisko } 1016108401Sambrisko ifp->if_ipackets++; 1017108401Sambrisko 1018108401Sambrisko /* Receive packet. */ 101983269Sbrooks#ifdef ANCACHE 1020175445Sambrisko an_cache_store(sc, eh, m, 1021110253Sambrisko rx_frame.an_rx_signal_strength, 1022110253Sambrisko rx_frame.an_rsvd0); 102383269Sbrooks#endif 1024122689Ssam AN_UNLOCK(sc); 1025108401Sambrisko (*ifp->if_input)(ifp, m); 1026122689Ssam AN_LOCK(sc); 102783269Sbrooks } 102855992Swpaul 1029108401Sambrisko } else { /* MPI-350 */ 1030108401Sambrisko for (count = 0; count < AN_MAX_RX_DESC; count++){ 1031108401Sambrisko for (i = 0; i < sizeof(an_rx_desc) / 4; i++) 1032175445Sambrisko ((u_int32_t *)(void *)&an_rx_desc)[i] 1033175445Sambrisko = CSR_MEM_AUX_READ_4(sc, 1034175445Sambrisko AN_RX_DESC_OFFSET 1035108401Sambrisko + (count * sizeof(an_rx_desc)) 1036108401Sambrisko + (i * 4)); 103783269Sbrooks 1038108401Sambrisko if (an_rx_desc.an_done && !an_rx_desc.an_valid) { 1039108401Sambrisko buf = sc->an_rx_buffer[count].an_dma_vaddr; 104083269Sbrooks 1041243857Sglebius MGETHDR(m, M_NOWAIT, MT_DATA); 1042108401Sambrisko if (m == NULL) { 1043108401Sambrisko ifp->if_ierrors++; 1044108401Sambrisko return; 1045108401Sambrisko } 1046243857Sglebius MCLGET(m, M_NOWAIT); 1047108401Sambrisko if (!(m->m_flags & M_EXT)) { 1048108401Sambrisko m_freem(m); 1049108401Sambrisko ifp->if_ierrors++; 1050108401Sambrisko return; 1051108401Sambrisko } 1052108401Sambrisko m->m_pkthdr.rcvif = ifp; 1053108401Sambrisko /* Read Ethernet encapsulated packet */ 105483269Sbrooks 1055175445Sambrisko /* 1056108401Sambrisko * No ANCACHE support since we just get back 1057108401Sambrisko * an Ethernet packet no 802.11 info 1058108401Sambrisko */ 1059108401Sambrisko#if 0 1060108401Sambrisko#ifdef ANCACHE 1061108401Sambrisko /* Read NIC frame header */ 1062175445Sambrisko bcopy(buf, (caddr_t)&rx_frame, 1063108401Sambrisko sizeof(rx_frame)); 1064108401Sambrisko#endif 1065108401Sambrisko#endif 1066108401Sambrisko /* Check for insane frame length */ 1067108401Sambrisko len = an_rx_desc.an_len + 12; 1068108401Sambrisko if (len > MCLBYTES) { 1069154393Srwatson m_freem(m); 1070198987Sjhb if_printf(ifp, "oversized packet " 1071108401Sambrisko "received (%d, %d)\n", 1072198987Sjhb len, MCLBYTES); 1073108401Sambrisko ifp->if_ierrors++; 1074108401Sambrisko return; 1075108401Sambrisko } 107683269Sbrooks 1077108401Sambrisko m->m_pkthdr.len = m->m_len = 1078108401Sambrisko an_rx_desc.an_len + 12; 1079175445Sambrisko 1080108401Sambrisko eh = mtod(m, struct ether_header *); 1081175445Sambrisko 1082108401Sambrisko bcopy(buf, (char *)eh, 1083108401Sambrisko m->m_pkthdr.len); 1084175445Sambrisko 1085108401Sambrisko ifp->if_ipackets++; 1086175445Sambrisko 1087108401Sambrisko /* Receive packet. */ 1088108401Sambrisko#if 0 108955992Swpaul#ifdef ANCACHE 1090175445Sambrisko an_cache_store(sc, eh, m, 1091110253Sambrisko rx_frame.an_rx_signal_strength, 1092110253Sambrisko rx_frame.an_rsvd0); 109355992Swpaul#endif 1094108401Sambrisko#endif 1095171775Savatar AN_UNLOCK(sc); 1096108401Sambrisko (*ifp->if_input)(ifp, m); 1097171775Savatar AN_LOCK(sc); 1098171775Savatar 1099108401Sambrisko an_rx_desc.an_valid = 1; 1100108401Sambrisko an_rx_desc.an_len = AN_RX_BUFFER_SIZE; 1101108401Sambrisko an_rx_desc.an_done = 0; 1102175445Sambrisko an_rx_desc.an_phys = 1103108401Sambrisko sc->an_rx_buffer[count].an_dma_paddr; 1104175445Sambrisko 1105108401Sambrisko for (i = 0; i < sizeof(an_rx_desc) / 4; i++) 1106175445Sambrisko CSR_MEM_AUX_WRITE_4(sc, 1107175445Sambrisko AN_RX_DESC_OFFSET 1108155321Simp + (count * sizeof(an_rx_desc)) 1109155321Simp + (i * 4), 1110155321Simp ((u_int32_t *)(void *)&an_rx_desc)[i]); 1111175445Sambrisko 1112108401Sambrisko } else { 1113198987Sjhb if_printf(ifp, "Didn't get valid RX packet " 1114108401Sambrisko "%x %x %d\n", 1115108401Sambrisko an_rx_desc.an_done, 1116108401Sambrisko an_rx_desc.an_valid, an_rx_desc.an_len); 1117108401Sambrisko } 1118108401Sambrisko } 111983269Sbrooks } 112055992Swpaul} 112155992Swpaul 112283270Sbrooksstatic void 1123150446Simpan_txeof(struct an_softc *sc, int status) 112455992Swpaul{ 112555992Swpaul struct ifnet *ifp; 112678639Sbrooks int id, i; 112755992Swpaul 1128175445Sambrisko AN_LOCK_ASSERT(sc); 1129147256Sbrooks ifp = sc->an_ifp; 113055992Swpaul 1131199154Sjhb sc->an_timer = 0; 1132148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 113355992Swpaul 1134108401Sambrisko if (!sc->mpi350) { 1135119156Sambrisko id = CSR_READ_2(sc, AN_TX_CMP_FID(sc->mpi350)); 113655992Swpaul 1137108401Sambrisko if (status & AN_EV_TX_EXC) { 1138108401Sambrisko ifp->if_oerrors++; 1139108401Sambrisko } else 1140108401Sambrisko ifp->if_opackets++; 114155992Swpaul 1142108401Sambrisko for (i = 0; i < AN_TX_RING_CNT; i++) { 1143108401Sambrisko if (id == sc->an_rdata.an_tx_ring[i]) { 1144108401Sambrisko sc->an_rdata.an_tx_ring[i] = 0; 1145108401Sambrisko break; 1146108401Sambrisko } 114778639Sbrooks } 1148108401Sambrisko 1149108401Sambrisko AN_INC(sc->an_rdata.an_tx_cons, AN_TX_RING_CNT); 1150108401Sambrisko } else { /* MPI 350 */ 1151119156Sambrisko id = CSR_READ_2(sc, AN_TX_CMP_FID(sc->mpi350)); 1152119156Sambrisko if (!sc->an_rdata.an_tx_empty){ 1153119156Sambrisko if (status & AN_EV_TX_EXC) { 1154119156Sambrisko ifp->if_oerrors++; 1155119156Sambrisko } else 1156119156Sambrisko ifp->if_opackets++; 1157119156Sambrisko AN_INC(sc->an_rdata.an_tx_cons, AN_MAX_TX_DESC); 1158119156Sambrisko if (sc->an_rdata.an_tx_prod == 1159119156Sambrisko sc->an_rdata.an_tx_cons) 1160119156Sambrisko sc->an_rdata.an_tx_empty = 1; 1161119156Sambrisko } 116278639Sbrooks } 116355992Swpaul 116455992Swpaul return; 116555992Swpaul} 116655992Swpaul 116755992Swpaul/* 116855992Swpaul * We abuse the stats updater to check the current NIC status. This 116955992Swpaul * is important because we don't want to allow transmissions until 117055992Swpaul * the NIC has synchronized to the current cell (either as the master 117155992Swpaul * in an ad-hoc group, or as a station connected to an access point). 1172173668Savatar * 1173173668Savatar * Note that this function will be called via callout(9) with a lock held. 117455992Swpaul */ 1175104094Sphkstatic void 1176150446Simpan_stats_update(void *xsc) 117755992Swpaul{ 117855992Swpaul struct an_softc *sc; 117955992Swpaul struct ifnet *ifp; 118055992Swpaul 118155992Swpaul sc = xsc; 1182173668Savatar AN_LOCK_ASSERT(sc); 1183147256Sbrooks ifp = sc->an_ifp; 1184199154Sjhb if (sc->an_timer > 0 && --sc->an_timer == 0) 1185199154Sjhb an_watchdog(sc); 118655992Swpaul 118755992Swpaul sc->an_status.an_type = AN_RID_STATUS; 118855992Swpaul sc->an_status.an_len = sizeof(struct an_ltv_status); 1189173668Savatar if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_status)) 1190173668Savatar return; 119155992Swpaul 119255992Swpaul if (sc->an_status.an_opmode & AN_STATUS_OPMODE_IN_SYNC) 119355992Swpaul sc->an_associated = 1; 119455992Swpaul else 119555992Swpaul sc->an_associated = 0; 119655992Swpaul 119755992Swpaul /* Don't do this while we're transmitting */ 1198148887Srwatson if (ifp->if_drv_flags & IFF_DRV_OACTIVE) { 1199173668Savatar callout_reset(&sc->an_stat_ch, hz, an_stats_update, sc); 120055992Swpaul return; 120155992Swpaul } 120255992Swpaul 120355992Swpaul sc->an_stats.an_len = sizeof(struct an_ltv_stats); 120455992Swpaul sc->an_stats.an_type = AN_RID_32BITS_CUM; 1205173668Savatar if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_stats.an_len)) 1206173668Savatar return; 120755992Swpaul 1208173668Savatar callout_reset(&sc->an_stat_ch, hz, an_stats_update, sc); 120955992Swpaul 121055992Swpaul return; 121155992Swpaul} 121255992Swpaul 121383270Sbrooksvoid 1214150446Simpan_intr(void *xsc) 121555992Swpaul{ 121655992Swpaul struct an_softc *sc; 121755992Swpaul struct ifnet *ifp; 121855992Swpaul u_int16_t status; 121955992Swpaul 122055992Swpaul sc = (struct an_softc*)xsc; 122155992Swpaul 122267094Swpaul AN_LOCK(sc); 122367094Swpaul 122467094Swpaul if (sc->an_gone) { 122567094Swpaul AN_UNLOCK(sc); 122655992Swpaul return; 122767094Swpaul } 122855992Swpaul 1229147256Sbrooks ifp = sc->an_ifp; 123055992Swpaul 123155992Swpaul /* Disable interrupts. */ 1232108401Sambrisko CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0); 123355992Swpaul 1234108401Sambrisko status = CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350)); 1235119156Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), ~AN_INTRS(sc->mpi350)); 123655992Swpaul 1237119156Sambrisko if (status & AN_EV_MIC) { 1238119156Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_MIC); 123955992Swpaul } 124055992Swpaul 124155992Swpaul if (status & AN_EV_LINKSTAT) { 1242175445Sambrisko if (CSR_READ_2(sc, AN_LINKSTAT(sc->mpi350)) 1243108401Sambrisko == AN_LINKSTAT_ASSOCIATED) 124455992Swpaul sc->an_associated = 1; 124555992Swpaul else 124655992Swpaul sc->an_associated = 0; 1247108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_LINKSTAT); 124855992Swpaul } 124955992Swpaul 125055992Swpaul if (status & AN_EV_RX) { 125155992Swpaul an_rxeof(sc); 1252108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_RX); 125355992Swpaul } 125455992Swpaul 1255119156Sambrisko if (sc->mpi350 && status & AN_EV_TX_CPY) { 1256119156Sambrisko an_txeof(sc, status); 1257150446Simp CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_TX_CPY); 1258119156Sambrisko } 1259119156Sambrisko 126055992Swpaul if (status & AN_EV_TX) { 126155992Swpaul an_txeof(sc, status); 1262150446Simp CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_TX); 126355992Swpaul } 126455992Swpaul 126555992Swpaul if (status & AN_EV_TX_EXC) { 126655992Swpaul an_txeof(sc, status); 1267108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_TX_EXC); 126855992Swpaul } 126955992Swpaul 127055992Swpaul if (status & AN_EV_ALLOC) 1271108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_ALLOC); 127255992Swpaul 127355992Swpaul /* Re-enable interrupts. */ 1274119156Sambrisko CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), AN_INTRS(sc->mpi350)); 127555992Swpaul 1276132986Smlaier if ((ifp->if_flags & IFF_UP) && !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1277199154Sjhb an_start_locked(ifp); 127855992Swpaul 127967094Swpaul AN_UNLOCK(sc); 128067094Swpaul 128155992Swpaul return; 128255992Swpaul} 128355992Swpaul 1284108401Sambrisko 128583270Sbrooksstatic int 1286150446Simpan_cmd_struct(struct an_softc *sc, struct an_command *cmd, 1287150446Simp struct an_reply *reply) 1288108401Sambrisko{ 1289108401Sambrisko int i; 1290108401Sambrisko 1291175445Sambrisko AN_LOCK_ASSERT(sc); 1292108401Sambrisko for (i = 0; i != AN_TIMEOUT; i++) { 1293108401Sambrisko if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY) { 1294110531Sambrisko DELAY(1000); 1295110104Sambrisko } else 1296108401Sambrisko break; 1297108401Sambrisko } 1298119156Sambrisko 1299108401Sambrisko if( i == AN_TIMEOUT) { 1300108401Sambrisko printf("BUSY\n"); 1301108401Sambrisko return(ETIMEDOUT); 1302108401Sambrisko } 1303108401Sambrisko 1304108401Sambrisko CSR_WRITE_2(sc, AN_PARAM0(sc->mpi350), cmd->an_parm0); 1305108401Sambrisko CSR_WRITE_2(sc, AN_PARAM1(sc->mpi350), cmd->an_parm1); 1306108401Sambrisko CSR_WRITE_2(sc, AN_PARAM2(sc->mpi350), cmd->an_parm2); 1307108401Sambrisko CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), cmd->an_cmd); 1308108401Sambrisko 1309108401Sambrisko for (i = 0; i < AN_TIMEOUT; i++) { 1310108401Sambrisko if (CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350)) & AN_EV_CMD) 1311108401Sambrisko break; 1312110531Sambrisko DELAY(1000); 1313108401Sambrisko } 1314108401Sambrisko 1315108401Sambrisko reply->an_resp0 = CSR_READ_2(sc, AN_RESP0(sc->mpi350)); 1316108401Sambrisko reply->an_resp1 = CSR_READ_2(sc, AN_RESP1(sc->mpi350)); 1317108401Sambrisko reply->an_resp2 = CSR_READ_2(sc, AN_RESP2(sc->mpi350)); 1318108401Sambrisko reply->an_status = CSR_READ_2(sc, AN_STATUS(sc->mpi350)); 1319108401Sambrisko 1320108401Sambrisko if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY) 1321175445Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), 1322119156Sambrisko AN_EV_CLR_STUCK_BUSY); 1323108401Sambrisko 1324108401Sambrisko /* Ack the command */ 1325108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_CMD); 1326108401Sambrisko 1327108401Sambrisko if (i == AN_TIMEOUT) 1328108401Sambrisko return(ETIMEDOUT); 1329108401Sambrisko 1330108401Sambrisko return(0); 1331108401Sambrisko} 1332108401Sambrisko 1333108401Sambriskostatic int 1334150446Simpan_cmd(struct an_softc *sc, int cmd, int val) 133555992Swpaul{ 133655992Swpaul int i, s = 0; 133755992Swpaul 1338175445Sambrisko AN_LOCK_ASSERT(sc); 1339108401Sambrisko CSR_WRITE_2(sc, AN_PARAM0(sc->mpi350), val); 1340108401Sambrisko CSR_WRITE_2(sc, AN_PARAM1(sc->mpi350), 0); 1341108401Sambrisko CSR_WRITE_2(sc, AN_PARAM2(sc->mpi350), 0); 1342108401Sambrisko CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), cmd); 134355992Swpaul 134455992Swpaul for (i = 0; i < AN_TIMEOUT; i++) { 1345108401Sambrisko if (CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350)) & AN_EV_CMD) 134655992Swpaul break; 134755992Swpaul else { 1348108401Sambrisko if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) == cmd) 1349108401Sambrisko CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), cmd); 135055992Swpaul } 135155992Swpaul } 135255992Swpaul 135355992Swpaul for (i = 0; i < AN_TIMEOUT; i++) { 1354108401Sambrisko CSR_READ_2(sc, AN_RESP0(sc->mpi350)); 1355108401Sambrisko CSR_READ_2(sc, AN_RESP1(sc->mpi350)); 1356108401Sambrisko CSR_READ_2(sc, AN_RESP2(sc->mpi350)); 1357108401Sambrisko s = CSR_READ_2(sc, AN_STATUS(sc->mpi350)); 135855992Swpaul if ((s & AN_STAT_CMD_CODE) == (cmd & AN_STAT_CMD_CODE)) 135955992Swpaul break; 136055992Swpaul } 136155992Swpaul 136255992Swpaul /* Ack the command */ 1363108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_CMD); 136455992Swpaul 1365108401Sambrisko if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY) 1366108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_CLR_STUCK_BUSY); 136755992Swpaul 136855992Swpaul if (i == AN_TIMEOUT) 136955992Swpaul return(ETIMEDOUT); 137055992Swpaul 137155992Swpaul return(0); 137255992Swpaul} 137355992Swpaul 137455992Swpaul/* 137555992Swpaul * This reset sequence may look a little strange, but this is the 137655992Swpaul * most reliable method I've found to really kick the NIC in the 137755992Swpaul * head and force it to reboot correctly. 137855992Swpaul */ 137983270Sbrooksstatic void 1380150446Simpan_reset(struct an_softc *sc) 138155992Swpaul{ 138255992Swpaul if (sc->an_gone) 138355992Swpaul return; 138483270Sbrooks 1385175445Sambrisko AN_LOCK_ASSERT(sc); 138655992Swpaul an_cmd(sc, AN_CMD_ENABLE, 0); 138755992Swpaul an_cmd(sc, AN_CMD_FW_RESTART, 0); 138855992Swpaul an_cmd(sc, AN_CMD_NOOP2, 0); 138955992Swpaul 139055992Swpaul if (an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0) == ETIMEDOUT) 1391265614Sgavin device_printf(sc->an_dev, "reset failed\n"); 139255992Swpaul 139355992Swpaul an_cmd(sc, AN_CMD_DISABLE, 0); 139455992Swpaul 139555992Swpaul return; 139655992Swpaul} 139755992Swpaul 139855992Swpaul/* 139955992Swpaul * Read an LTV record from the NIC. 140055992Swpaul */ 140183270Sbrooksstatic int 1402150446Simpan_read_record(struct an_softc *sc, struct an_ltv_gen *ltv) 140355992Swpaul{ 1404108401Sambrisko struct an_ltv_gen *an_ltv; 1405108401Sambrisko struct an_card_rid_desc an_rid_desc; 1406108401Sambrisko struct an_command cmd; 1407108401Sambrisko struct an_reply reply; 1408198987Sjhb struct ifnet *ifp; 140955992Swpaul u_int16_t *ptr; 141078639Sbrooks u_int8_t *ptr2; 141155992Swpaul int i, len; 141255992Swpaul 1413175445Sambrisko AN_LOCK_ASSERT(sc); 141478639Sbrooks if (ltv->an_len < 4 || ltv->an_type == 0) 141555992Swpaul return(EINVAL); 141655992Swpaul 1417198987Sjhb ifp = sc->an_ifp; 1418108401Sambrisko if (!sc->mpi350){ 1419108401Sambrisko /* Tell the NIC to enter record read mode. */ 1420108401Sambrisko if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type)) { 1421198987Sjhb if_printf(ifp, "RID access failed\n"); 1422108401Sambrisko return(EIO); 1423108401Sambrisko } 142455992Swpaul 1425108401Sambrisko /* Seek to the record. */ 1426108401Sambrisko if (an_seek(sc, ltv->an_type, 0, AN_BAP1)) { 1427198987Sjhb if_printf(ifp, "seek to record failed\n"); 1428108401Sambrisko return(EIO); 1429108401Sambrisko } 143055992Swpaul 1431108401Sambrisko /* 1432108401Sambrisko * Read the length and record type and make sure they 1433108401Sambrisko * match what we expect (this verifies that we have enough 1434108401Sambrisko * room to hold all of the returned data). 1435108401Sambrisko * Length includes type but not length. 1436108401Sambrisko */ 1437108401Sambrisko len = CSR_READ_2(sc, AN_DATA1); 1438108401Sambrisko if (len > (ltv->an_len - 2)) { 1439198987Sjhb if_printf(ifp, "record length mismatch -- expected %d, " 1440198987Sjhb "got %d for Rid %x\n", 1441108401Sambrisko ltv->an_len - 2, len, ltv->an_type); 1442108401Sambrisko len = ltv->an_len - 2; 1443108401Sambrisko } else { 1444108401Sambrisko ltv->an_len = len + 2; 1445108401Sambrisko } 1446108401Sambrisko 1447108401Sambrisko /* Now read the data. */ 1448108401Sambrisko len -= 2; /* skip the type */ 1449108401Sambrisko ptr = <v->an_val; 1450108401Sambrisko for (i = len; i > 1; i -= 2) 1451108401Sambrisko *ptr++ = CSR_READ_2(sc, AN_DATA1); 1452108401Sambrisko if (i) { 1453108401Sambrisko ptr2 = (u_int8_t *)ptr; 1454108401Sambrisko *ptr2 = CSR_READ_1(sc, AN_DATA1); 1455108401Sambrisko } 1456108401Sambrisko } else { /* MPI-350 */ 1457123978Sambrisko if (!sc->an_rid_buffer.an_dma_vaddr) 1458123978Sambrisko return(EIO); 1459108401Sambrisko an_rid_desc.an_valid = 1; 1460108401Sambrisko an_rid_desc.an_len = AN_RID_BUFFER_SIZE; 1461108401Sambrisko an_rid_desc.an_rid = 0; 1462108401Sambrisko an_rid_desc.an_phys = sc->an_rid_buffer.an_dma_paddr; 1463108401Sambrisko bzero(sc->an_rid_buffer.an_dma_vaddr, AN_RID_BUFFER_SIZE); 1464108401Sambrisko 1465108401Sambrisko bzero(&cmd, sizeof(cmd)); 1466108401Sambrisko bzero(&reply, sizeof(reply)); 1467108401Sambrisko cmd.an_cmd = AN_CMD_ACCESS|AN_ACCESS_READ; 1468108401Sambrisko cmd.an_parm0 = ltv->an_type; 1469108401Sambrisko 1470108401Sambrisko for (i = 0; i < sizeof(an_rid_desc) / 4; i++) 1471175445Sambrisko CSR_MEM_AUX_WRITE_4(sc, AN_HOST_DESC_OFFSET + i * 4, 1472155321Simp ((u_int32_t *)(void *)&an_rid_desc)[i]); 1473108401Sambrisko 1474108401Sambrisko if (an_cmd_struct(sc, &cmd, &reply) 1475108401Sambrisko || reply.an_status & AN_CMD_QUAL_MASK) { 1476198987Sjhb if_printf(ifp, "failed to read RID %x %x %x %x %x, %d\n", 1477198987Sjhb ltv->an_type, 1478108401Sambrisko reply.an_status, 1479108401Sambrisko reply.an_resp0, 1480108401Sambrisko reply.an_resp1, 1481108401Sambrisko reply.an_resp2, 1482108401Sambrisko i); 1483108401Sambrisko return(EIO); 1484108401Sambrisko } 1485108401Sambrisko 1486108401Sambrisko an_ltv = (struct an_ltv_gen *)sc->an_rid_buffer.an_dma_vaddr; 1487108401Sambrisko if (an_ltv->an_len + 2 < an_rid_desc.an_len) { 1488108401Sambrisko an_rid_desc.an_len = an_ltv->an_len; 1489108401Sambrisko } 1490108401Sambrisko 1491123978Sambrisko len = an_rid_desc.an_len; 1492123978Sambrisko if (len > (ltv->an_len - 2)) { 1493198987Sjhb if_printf(ifp, "record length mismatch -- expected %d, " 1494198987Sjhb "got %d for Rid %x\n", 1495123978Sambrisko ltv->an_len - 2, len, ltv->an_type); 1496123978Sambrisko len = ltv->an_len - 2; 1497123978Sambrisko } else { 1498123978Sambrisko ltv->an_len = len + 2; 1499123978Sambrisko } 1500123978Sambrisko bcopy(&an_ltv->an_type, 1501175445Sambrisko <v->an_val, 1502123978Sambrisko len); 150355992Swpaul } 150455992Swpaul 150578639Sbrooks if (an_dump) 150678639Sbrooks an_dump_record(sc, ltv, "Read"); 150755992Swpaul 150855992Swpaul return(0); 150955992Swpaul} 151055992Swpaul 151155992Swpaul/* 151255992Swpaul * Same as read, except we inject data instead of reading it. 151355992Swpaul */ 151483270Sbrooksstatic int 1515150446Simpan_write_record(struct an_softc *sc, struct an_ltv_gen *ltv) 151655992Swpaul{ 1517108401Sambrisko struct an_card_rid_desc an_rid_desc; 1518108401Sambrisko struct an_command cmd; 1519108401Sambrisko struct an_reply reply; 152055992Swpaul u_int16_t *ptr; 152178639Sbrooks u_int8_t *ptr2; 152278639Sbrooks int i, len; 152355992Swpaul 1524175445Sambrisko AN_LOCK_ASSERT(sc); 152578639Sbrooks if (an_dump) 152678639Sbrooks an_dump_record(sc, ltv, "Write"); 152778639Sbrooks 1528108401Sambrisko if (!sc->mpi350){ 1529108401Sambrisko if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type)) 1530108401Sambrisko return(EIO); 153183270Sbrooks 1532108401Sambrisko if (an_seek(sc, ltv->an_type, 0, AN_BAP1)) 1533108401Sambrisko return(EIO); 1534108401Sambrisko 1535108401Sambrisko /* 1536108401Sambrisko * Length includes type but not length. 1537108401Sambrisko */ 1538108401Sambrisko len = ltv->an_len - 2; 1539108401Sambrisko CSR_WRITE_2(sc, AN_DATA1, len); 1540108401Sambrisko 1541108401Sambrisko len -= 2; /* skip the type */ 1542108401Sambrisko ptr = <v->an_val; 1543108401Sambrisko for (i = len; i > 1; i -= 2) 1544108401Sambrisko CSR_WRITE_2(sc, AN_DATA1, *ptr++); 1545108401Sambrisko if (i) { 1546108401Sambrisko ptr2 = (u_int8_t *)ptr; 1547108401Sambrisko CSR_WRITE_1(sc, AN_DATA0, *ptr2); 1548108401Sambrisko } 1549108401Sambrisko 1550108401Sambrisko if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_WRITE, ltv->an_type)) 1551108401Sambrisko return(EIO); 1552175445Sambrisko } else { 1553110104Sambrisko /* MPI-350 */ 1554108401Sambrisko 1555108401Sambrisko for (i = 0; i != AN_TIMEOUT; i++) { 1556175445Sambrisko if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) 1557110104Sambrisko & AN_CMD_BUSY) { 1558108401Sambrisko DELAY(10); 1559110104Sambrisko } else 1560108401Sambrisko break; 1561108401Sambrisko } 1562108401Sambrisko if (i == AN_TIMEOUT) { 1563108401Sambrisko printf("BUSY\n"); 1564108401Sambrisko } 1565108401Sambrisko 1566108401Sambrisko an_rid_desc.an_valid = 1; 1567108401Sambrisko an_rid_desc.an_len = ltv->an_len - 2; 1568108401Sambrisko an_rid_desc.an_rid = ltv->an_type; 1569108401Sambrisko an_rid_desc.an_phys = sc->an_rid_buffer.an_dma_paddr; 1570108401Sambrisko 1571108401Sambrisko bcopy(<v->an_type, sc->an_rid_buffer.an_dma_vaddr, 1572108401Sambrisko an_rid_desc.an_len); 1573108401Sambrisko 1574108401Sambrisko bzero(&cmd,sizeof(cmd)); 1575108401Sambrisko bzero(&reply,sizeof(reply)); 1576108401Sambrisko cmd.an_cmd = AN_CMD_ACCESS|AN_ACCESS_WRITE; 1577108401Sambrisko cmd.an_parm0 = ltv->an_type; 1578108401Sambrisko 1579108401Sambrisko for (i = 0; i < sizeof(an_rid_desc) / 4; i++) 1580175445Sambrisko CSR_MEM_AUX_WRITE_4(sc, AN_HOST_DESC_OFFSET + i * 4, 1581155321Simp ((u_int32_t *)(void *)&an_rid_desc)[i]); 1582108401Sambrisko 1583110531Sambrisko DELAY(100000); 1584110531Sambrisko 1585108401Sambrisko if ((i = an_cmd_struct(sc, &cmd, &reply))) { 1586198987Sjhb if_printf(sc->an_ifp, 1587198987Sjhb "failed to write RID 1 %x %x %x %x %x, %d\n", 1588198987Sjhb ltv->an_type, 1589110104Sambrisko reply.an_status, 1590110104Sambrisko reply.an_resp0, 1591110104Sambrisko reply.an_resp1, 1592110104Sambrisko reply.an_resp2, 1593110104Sambrisko i); 1594110104Sambrisko return(EIO); 1595108401Sambrisko } 159655992Swpaul 159783270Sbrooks 1598108401Sambrisko if (reply.an_status & AN_CMD_QUAL_MASK) { 1599198987Sjhb if_printf(sc->an_ifp, 1600198987Sjhb "failed to write RID 2 %x %x %x %x %x, %d\n", 1601198987Sjhb ltv->an_type, 1602110104Sambrisko reply.an_status, 1603110104Sambrisko reply.an_resp0, 1604110104Sambrisko reply.an_resp1, 1605110104Sambrisko reply.an_resp2, 1606110104Sambrisko i); 1607108401Sambrisko return(EIO); 1608108401Sambrisko } 1609110531Sambrisko DELAY(100000); 161078639Sbrooks } 161155992Swpaul 161255992Swpaul return(0); 161355992Swpaul} 161455992Swpaul 161583270Sbrooksstatic void 1616150446Simpan_dump_record(struct an_softc *sc, struct an_ltv_gen *ltv, char *string) 161778639Sbrooks{ 161878639Sbrooks u_int8_t *ptr2; 161978639Sbrooks int len; 162078639Sbrooks int i; 162178639Sbrooks int count = 0; 162278639Sbrooks char buf[17], temp; 162378639Sbrooks 162478639Sbrooks len = ltv->an_len - 4; 1625198987Sjhb if_printf(sc->an_ifp, "RID %4x, Length %4d, Mode %s\n", 1626198987Sjhb ltv->an_type, ltv->an_len - 4, string); 162778639Sbrooks 162878639Sbrooks if (an_dump == 1 || (an_dump == ltv->an_type)) { 1629198987Sjhb if_printf(sc->an_ifp, "\t"); 163078639Sbrooks bzero(buf,sizeof(buf)); 163178639Sbrooks 163278639Sbrooks ptr2 = (u_int8_t *)<v->an_val; 163378639Sbrooks for (i = len; i > 0; i--) { 163478639Sbrooks printf("%02x ", *ptr2); 163578639Sbrooks 163678639Sbrooks temp = *ptr2++; 1637154866Snjl if (isprint(temp)) 163878639Sbrooks buf[count] = temp; 163978639Sbrooks else 164078639Sbrooks buf[count] = '.'; 164178639Sbrooks if (++count == 16) { 164278639Sbrooks count = 0; 164378639Sbrooks printf("%s\n",buf); 1644198987Sjhb if_printf(sc->an_ifp, "\t"); 164578639Sbrooks bzero(buf,sizeof(buf)); 164678639Sbrooks } 164778639Sbrooks } 164878639Sbrooks for (; count != 16; count++) { 164978639Sbrooks printf(" "); 165078639Sbrooks } 165178639Sbrooks printf(" %s\n",buf); 165278639Sbrooks } 165378639Sbrooks} 165478639Sbrooks 165583270Sbrooksstatic int 1656150446Simpan_seek(struct an_softc *sc, int id, int off, int chan) 165755992Swpaul{ 165855992Swpaul int i; 165955992Swpaul int selreg, offreg; 166055992Swpaul 166155992Swpaul switch (chan) { 166255992Swpaul case AN_BAP0: 166355992Swpaul selreg = AN_SEL0; 166455992Swpaul offreg = AN_OFF0; 166555992Swpaul break; 166655992Swpaul case AN_BAP1: 166755992Swpaul selreg = AN_SEL1; 166855992Swpaul offreg = AN_OFF1; 166955992Swpaul break; 167055992Swpaul default: 1671198987Sjhb if_printf(sc->an_ifp, "invalid data path: %x\n", chan); 167255992Swpaul return(EIO); 167355992Swpaul } 167455992Swpaul 167555992Swpaul CSR_WRITE_2(sc, selreg, id); 167655992Swpaul CSR_WRITE_2(sc, offreg, off); 167755992Swpaul 167855992Swpaul for (i = 0; i < AN_TIMEOUT; i++) { 167955992Swpaul if (!(CSR_READ_2(sc, offreg) & (AN_OFF_BUSY|AN_OFF_ERR))) 168055992Swpaul break; 168155992Swpaul } 168255992Swpaul 168355992Swpaul if (i == AN_TIMEOUT) 168455992Swpaul return(ETIMEDOUT); 168555992Swpaul 168655992Swpaul return(0); 168755992Swpaul} 168855992Swpaul 168983270Sbrooksstatic int 1690150446Simpan_read_data(struct an_softc *sc, int id, int off, caddr_t buf, int len) 169155992Swpaul{ 169255992Swpaul int i; 169355992Swpaul u_int16_t *ptr; 169455992Swpaul u_int8_t *ptr2; 169555992Swpaul 169655992Swpaul if (off != -1) { 169755992Swpaul if (an_seek(sc, id, off, AN_BAP1)) 169855992Swpaul return(EIO); 169955992Swpaul } 170055992Swpaul 170155992Swpaul ptr = (u_int16_t *)buf; 170278639Sbrooks for (i = len; i > 1; i -= 2) 170378639Sbrooks *ptr++ = CSR_READ_2(sc, AN_DATA1); 170478639Sbrooks if (i) { 170578639Sbrooks ptr2 = (u_int8_t *)ptr; 170678639Sbrooks *ptr2 = CSR_READ_1(sc, AN_DATA1); 170755992Swpaul } 170855992Swpaul 170955992Swpaul return(0); 171055992Swpaul} 171155992Swpaul 171283270Sbrooksstatic int 1713150446Simpan_write_data(struct an_softc *sc, int id, int off, caddr_t buf, int len) 171455992Swpaul{ 171555992Swpaul int i; 171655992Swpaul u_int16_t *ptr; 171755992Swpaul u_int8_t *ptr2; 171855992Swpaul 171955992Swpaul if (off != -1) { 172055992Swpaul if (an_seek(sc, id, off, AN_BAP0)) 172155992Swpaul return(EIO); 172255992Swpaul } 172355992Swpaul 172455992Swpaul ptr = (u_int16_t *)buf; 172578639Sbrooks for (i = len; i > 1; i -= 2) 172678639Sbrooks CSR_WRITE_2(sc, AN_DATA0, *ptr++); 172778639Sbrooks if (i) { 1728175446Sambrisko ptr2 = (u_int8_t *)ptr; 1729175446Sambrisko CSR_WRITE_1(sc, AN_DATA0, *ptr2); 173055992Swpaul } 173155992Swpaul 173255992Swpaul return(0); 173355992Swpaul} 173455992Swpaul 173555992Swpaul/* 173655992Swpaul * Allocate a region of memory inside the NIC and zero 173755992Swpaul * it out. 173855992Swpaul */ 173983270Sbrooksstatic int 1740150446Simpan_alloc_nicmem(struct an_softc *sc, int len, int *id) 174155992Swpaul{ 174255992Swpaul int i; 174355992Swpaul 174455992Swpaul if (an_cmd(sc, AN_CMD_ALLOC_MEM, len)) { 1745198987Sjhb if_printf(sc->an_ifp, "failed to allocate %d bytes on NIC\n", 1746198987Sjhb len); 174755992Swpaul return(ENOMEM); 174855992Swpaul } 174955992Swpaul 175055992Swpaul for (i = 0; i < AN_TIMEOUT; i++) { 1751108401Sambrisko if (CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350)) & AN_EV_ALLOC) 175255992Swpaul break; 175355992Swpaul } 175455992Swpaul 175555992Swpaul if (i == AN_TIMEOUT) 175655992Swpaul return(ETIMEDOUT); 175755992Swpaul 1758108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_ALLOC); 175955992Swpaul *id = CSR_READ_2(sc, AN_ALLOC_FID); 176055992Swpaul 176155992Swpaul if (an_seek(sc, *id, 0, AN_BAP0)) 176255992Swpaul return(EIO); 176355992Swpaul 176455992Swpaul for (i = 0; i < len / 2; i++) 176555992Swpaul CSR_WRITE_2(sc, AN_DATA0, 0); 176655992Swpaul 176755992Swpaul return(0); 176855992Swpaul} 176955992Swpaul 177083270Sbrooksstatic void 1771150446Simpan_setdef(struct an_softc *sc, struct an_req *areq) 177255992Swpaul{ 177355992Swpaul struct ifnet *ifp; 177455992Swpaul struct an_ltv_genconfig *cfg; 1775119156Sambrisko struct an_ltv_ssidlist_new *ssid; 177655992Swpaul struct an_ltv_aplist *ap; 177755992Swpaul struct an_ltv_gen *sp; 177855992Swpaul 1779147256Sbrooks ifp = sc->an_ifp; 178055992Swpaul 1781175445Sambrisko AN_LOCK_ASSERT(sc); 178255992Swpaul switch (areq->an_type) { 178355992Swpaul case AN_RID_GENCONFIG: 178455992Swpaul cfg = (struct an_ltv_genconfig *)areq; 178555992Swpaul 1786152315Sru bcopy((char *)&cfg->an_macaddr, IF_LLADDR(sc->an_ifp), 178755992Swpaul ETHER_ADDR_LEN); 178855992Swpaul 178955992Swpaul bcopy((char *)cfg, (char *)&sc->an_config, 179055992Swpaul sizeof(struct an_ltv_genconfig)); 179155992Swpaul break; 179255992Swpaul case AN_RID_SSIDLIST: 1793119156Sambrisko ssid = (struct an_ltv_ssidlist_new *)areq; 179455992Swpaul bcopy((char *)ssid, (char *)&sc->an_ssidlist, 1795119156Sambrisko sizeof(struct an_ltv_ssidlist_new)); 179655992Swpaul break; 179755992Swpaul case AN_RID_APLIST: 179855992Swpaul ap = (struct an_ltv_aplist *)areq; 179955992Swpaul bcopy((char *)ap, (char *)&sc->an_aplist, 180055992Swpaul sizeof(struct an_ltv_aplist)); 180155992Swpaul break; 180255992Swpaul case AN_RID_TX_SPEED: 180355992Swpaul sp = (struct an_ltv_gen *)areq; 180455992Swpaul sc->an_tx_rate = sp->an_val; 1805110253Sambrisko 1806110253Sambrisko /* Read the current configuration */ 1807110253Sambrisko sc->an_config.an_type = AN_RID_GENCONFIG; 1808110253Sambrisko sc->an_config.an_len = sizeof(struct an_ltv_genconfig); 1809110253Sambrisko an_read_record(sc, (struct an_ltv_gen *)&sc->an_config); 1810110253Sambrisko cfg = &sc->an_config; 1811110253Sambrisko 1812110253Sambrisko /* clear other rates and set the only one we want */ 1813110253Sambrisko bzero(cfg->an_rates, sizeof(cfg->an_rates)); 1814110253Sambrisko cfg->an_rates[0] = sc->an_tx_rate; 1815110253Sambrisko 1816110253Sambrisko /* Save the new rate */ 1817110253Sambrisko sc->an_config.an_type = AN_RID_GENCONFIG; 1818110253Sambrisko sc->an_config.an_len = sizeof(struct an_ltv_genconfig); 181955992Swpaul break; 182068692Swpaul case AN_RID_WEP_TEMP: 1821110531Sambrisko /* Cache the temp keys */ 1822175445Sambrisko bcopy(areq, 1823175445Sambrisko &sc->an_temp_keys[((struct an_ltv_key *)areq)->kindex], 1824110531Sambrisko sizeof(struct an_ltv_key)); 182568692Swpaul case AN_RID_WEP_PERM: 182688748Sambrisko case AN_RID_LEAPUSERNAME: 182788748Sambrisko case AN_RID_LEAPPASSWORD: 1828199154Sjhb an_init_locked(sc); 1829119156Sambrisko 183068692Swpaul /* Disable the MAC. */ 183168692Swpaul an_cmd(sc, AN_CMD_DISABLE, 0); 183283270Sbrooks 183383269Sbrooks /* Write the key */ 183468692Swpaul an_write_record(sc, (struct an_ltv_gen *)areq); 183583270Sbrooks 183683270Sbrooks /* Turn the MAC back on. */ 183768692Swpaul an_cmd(sc, AN_CMD_ENABLE, 0); 183883270Sbrooks 183968692Swpaul break; 184083269Sbrooks case AN_RID_MONITOR_MODE: 184183269Sbrooks cfg = (struct an_ltv_genconfig *)areq; 184283269Sbrooks bpfdetach(ifp); 184383269Sbrooks if (ng_ether_detach_p != NULL) 184483269Sbrooks (*ng_ether_detach_p) (ifp); 184583269Sbrooks sc->an_monitor = cfg->an_len; 184683269Sbrooks 184783270Sbrooks if (sc->an_monitor & AN_MONITOR) { 184883270Sbrooks if (sc->an_monitor & AN_MONITOR_AIRONET_HEADER) { 184983270Sbrooks bpfattach(ifp, DLT_AIRONET_HEADER, 185083269Sbrooks sizeof(struct ether_header)); 185183269Sbrooks } else { 185283270Sbrooks bpfattach(ifp, DLT_IEEE802_11, 185383269Sbrooks sizeof(struct ether_header)); 185483269Sbrooks } 185583269Sbrooks } else { 185683270Sbrooks bpfattach(ifp, DLT_EN10MB, 185783269Sbrooks sizeof(struct ether_header)); 185883269Sbrooks if (ng_ether_attach_p != NULL) 185983269Sbrooks (*ng_ether_attach_p) (ifp); 186083269Sbrooks } 186183269Sbrooks break; 186255992Swpaul default: 1863198987Sjhb if_printf(ifp, "unknown RID: %x\n", areq->an_type); 186455992Swpaul return; 186555992Swpaul } 186655992Swpaul 186755992Swpaul 186855992Swpaul /* Reinitialize the card. */ 1869199154Sjhb if (ifp->if_flags) 1870199154Sjhb an_init_locked(sc); 187155992Swpaul 187255992Swpaul return; 187355992Swpaul} 187455992Swpaul 187555992Swpaul/* 187683269Sbrooks * Derived from Linux driver to enable promiscious mode. 187755992Swpaul */ 187883269Sbrooks 187983270Sbrooksstatic void 1880150446Simpan_promisc(struct an_softc *sc, int promisc) 188155992Swpaul{ 1882175445Sambrisko AN_LOCK_ASSERT(sc); 1883150446Simp if (sc->an_was_monitor) { 188483269Sbrooks an_reset(sc); 1885108401Sambrisko if (sc->mpi350) 1886175445Sambrisko an_init_mpi350_desc(sc); 1887150446Simp } 1888199154Sjhb if (sc->an_monitor || sc->an_was_monitor) 1889199154Sjhb an_init_locked(sc); 189083269Sbrooks 189183269Sbrooks sc->an_was_monitor = sc->an_monitor; 189274698Sarchie an_cmd(sc, AN_CMD_SET_MODE, promisc ? 0xffff : 0); 189383270Sbrooks 189455992Swpaul return; 189555992Swpaul} 189655992Swpaul 189783270Sbrooksstatic int 1898150446Simpan_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 189955992Swpaul{ 190067094Swpaul int error = 0; 190177217Sphk int len; 1902119156Sambrisko int i, max; 190355992Swpaul struct an_softc *sc; 190455992Swpaul struct ifreq *ifr; 190593593Sjhb struct thread *td = curthread; 190677217Sphk struct ieee80211req *ireq; 1907172112Savatar struct ieee80211_channel ch; 190877217Sphk u_int8_t tmpstr[IEEE80211_NWID_LEN*2]; 190977217Sphk u_int8_t *tmpptr; 191077217Sphk struct an_ltv_genconfig *config; 191177217Sphk struct an_ltv_key *key; 191277217Sphk struct an_ltv_status *status; 1913119156Sambrisko struct an_ltv_ssidlist_new *ssids; 191488748Sambrisko int mode; 191588748Sambrisko struct aironet_ioctl l_ioctl; 191655992Swpaul 191755992Swpaul sc = ifp->if_softc; 191855992Swpaul ifr = (struct ifreq *)data; 191977217Sphk ireq = (struct ieee80211req *)data; 192055992Swpaul 192188749Sambrisko config = (struct an_ltv_genconfig *)&sc->areq; 192288749Sambrisko key = (struct an_ltv_key *)&sc->areq; 192388749Sambrisko status = (struct an_ltv_status *)&sc->areq; 1924119156Sambrisko ssids = (struct an_ltv_ssidlist_new *)&sc->areq; 192577217Sphk 192664429Speter if (sc->an_gone) { 192761816Sroberto error = ENODEV; 192861816Sroberto goto out; 192961816Sroberto } 193055992Swpaul 193183270Sbrooks switch (command) { 193255992Swpaul case SIOCSIFFLAGS: 1933175445Sambrisko AN_LOCK(sc); 193455992Swpaul if (ifp->if_flags & IFF_UP) { 1935148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING && 193655992Swpaul ifp->if_flags & IFF_PROMISC && 193755992Swpaul !(sc->an_if_flags & IFF_PROMISC)) { 193855992Swpaul an_promisc(sc, 1); 1939148887Srwatson } else if (ifp->if_drv_flags & IFF_DRV_RUNNING && 194055992Swpaul !(ifp->if_flags & IFF_PROMISC) && 194155992Swpaul sc->an_if_flags & IFF_PROMISC) { 194255992Swpaul an_promisc(sc, 0); 1943199154Sjhb } else 1944199154Sjhb an_init_locked(sc); 194555992Swpaul } else { 1946199154Sjhb if (ifp->if_drv_flags & IFF_DRV_RUNNING) 194755992Swpaul an_stop(sc); 194855992Swpaul } 1949199154Sjhb sc->an_if_flags = ifp->if_flags; 1950175445Sambrisko AN_UNLOCK(sc); 195155992Swpaul error = 0; 195255992Swpaul break; 195377217Sphk case SIOCSIFMEDIA: 195477217Sphk case SIOCGIFMEDIA: 195577217Sphk error = ifmedia_ioctl(ifp, ifr, &sc->an_ifmedia, command); 195677217Sphk break; 195755992Swpaul case SIOCADDMULTI: 195855992Swpaul case SIOCDELMULTI: 195955992Swpaul /* The Aironet has no multicast filter. */ 196055992Swpaul error = 0; 196155992Swpaul break; 196255992Swpaul case SIOCGAIRONET: 196388749Sambrisko error = copyin(ifr->ifr_data, &sc->areq, sizeof(sc->areq)); 196478639Sbrooks if (error != 0) 196555992Swpaul break; 1966175445Sambrisko AN_LOCK(sc); 196755992Swpaul#ifdef ANCACHE 196888749Sambrisko if (sc->areq.an_type == AN_RID_ZERO_CACHE) { 1969164033Srwatson error = priv_check(td, PRIV_DRIVER); 1970108259Srwatson if (error) 1971108259Srwatson break; 197255992Swpaul sc->an_sigitems = sc->an_nextitem = 0; 197355992Swpaul break; 197488749Sambrisko } else if (sc->areq.an_type == AN_RID_READ_CACHE) { 197588749Sambrisko char *pt = (char *)&sc->areq.an_val; 197655992Swpaul bcopy((char *)&sc->an_sigitems, (char *)pt, 197755992Swpaul sizeof(int)); 197855992Swpaul pt += sizeof(int); 197988749Sambrisko sc->areq.an_len = sizeof(int) / 2; 198055992Swpaul bcopy((char *)&sc->an_sigcache, (char *)pt, 198155992Swpaul sizeof(struct an_sigcache) * sc->an_sigitems); 198288749Sambrisko sc->areq.an_len += ((sizeof(struct an_sigcache) * 198355992Swpaul sc->an_sigitems) / 2) + 1; 198455992Swpaul } else 198555992Swpaul#endif 198688749Sambrisko if (an_read_record(sc, (struct an_ltv_gen *)&sc->areq)) { 1987175445Sambrisko AN_UNLOCK(sc); 198855992Swpaul error = EINVAL; 198955992Swpaul break; 199055992Swpaul } 1991171692Savatar AN_UNLOCK(sc); 199288749Sambrisko error = copyout(&sc->areq, ifr->ifr_data, sizeof(sc->areq)); 199355992Swpaul break; 199455992Swpaul case SIOCSAIRONET: 1995164033Srwatson if ((error = priv_check(td, PRIV_DRIVER))) 199664429Speter goto out; 1997175445Sambrisko AN_LOCK(sc); 199888749Sambrisko error = copyin(ifr->ifr_data, &sc->areq, sizeof(sc->areq)); 199978639Sbrooks if (error != 0) 200055992Swpaul break; 200188749Sambrisko an_setdef(sc, &sc->areq); 2002175445Sambrisko AN_UNLOCK(sc); 200355992Swpaul break; 2004175446Sambrisko case SIOCGPRIVATE_0: /* used by Cisco client utility */ 2005164033Srwatson if ((error = priv_check(td, PRIV_DRIVER))) 200692292Sambrisko goto out; 2007144242Ssam error = copyin(ifr->ifr_data, &l_ioctl, sizeof(l_ioctl)); 2008144242Ssam if (error) 2009144242Ssam goto out; 201088748Sambrisko mode = l_ioctl.command; 201188748Sambrisko 2012175445Sambrisko AN_LOCK(sc); 201388748Sambrisko if (mode >= AIROGCAP && mode <= AIROGSTATSD32) { 201488748Sambrisko error = readrids(ifp, &l_ioctl); 2015110104Sambrisko } else if (mode >= AIROPCAP && mode <= AIROPLEAPUSR) { 201688748Sambrisko error = writerids(ifp, &l_ioctl); 2017110104Sambrisko } else if (mode >= AIROFLSHRST && mode <= AIRORESTART) { 201888748Sambrisko error = flashcard(ifp, &l_ioctl); 2019110104Sambrisko } else { 202088748Sambrisko error =-1; 202188748Sambrisko } 2022175445Sambrisko AN_UNLOCK(sc); 2023144242Ssam if (!error) { 2024144242Ssam /* copy out the updated command info */ 2025144242Ssam error = copyout(&l_ioctl, ifr->ifr_data, sizeof(l_ioctl)); 2026144242Ssam } 202788748Sambrisko break; 2028175446Sambrisko case SIOCGPRIVATE_1: /* used by Cisco client utility */ 2029164033Srwatson if ((error = priv_check(td, PRIV_DRIVER))) 203092292Sambrisko goto out; 2031144242Ssam error = copyin(ifr->ifr_data, &l_ioctl, sizeof(l_ioctl)); 2032144242Ssam if (error) 2033144242Ssam goto out; 203488748Sambrisko l_ioctl.command = 0; 203588748Sambrisko error = AIROMAGIC; 2036144242Ssam (void) copyout(&error, l_ioctl.data, sizeof(error)); 2037175446Sambrisko error = 0; 203888748Sambrisko break; 203977217Sphk case SIOCG80211: 204088749Sambrisko sc->areq.an_len = sizeof(sc->areq); 204188748Sambrisko /* was that a good idea DJA we are doing a short-cut */ 204283270Sbrooks switch (ireq->i_type) { 204377217Sphk case IEEE80211_IOC_SSID: 2044175445Sambrisko AN_LOCK(sc); 204578639Sbrooks if (ireq->i_val == -1) { 204688749Sambrisko sc->areq.an_type = AN_RID_STATUS; 204777217Sphk if (an_read_record(sc, 204888749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 204977217Sphk error = EINVAL; 2050175445Sambrisko AN_UNLOCK(sc); 205177217Sphk break; 205277217Sphk } 205377217Sphk len = status->an_ssidlen; 205477217Sphk tmpptr = status->an_ssid; 205578639Sbrooks } else if (ireq->i_val >= 0) { 205688749Sambrisko sc->areq.an_type = AN_RID_SSIDLIST; 205777217Sphk if (an_read_record(sc, 205888749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 205977217Sphk error = EINVAL; 2060175445Sambrisko AN_UNLOCK(sc); 206177217Sphk break; 206277217Sphk } 2063119156Sambrisko max = (sc->areq.an_len - 4) 2064119156Sambrisko / sizeof(struct an_ltv_ssid_entry); 2065119156Sambrisko if ( max > MAX_SSIDS ) { 2066119156Sambrisko printf("To many SSIDs only using " 2067119156Sambrisko "%d of %d\n", 2068119156Sambrisko MAX_SSIDS, max); 2069119156Sambrisko max = MAX_SSIDS; 2070119156Sambrisko } 2071119156Sambrisko if (ireq->i_val > max) { 207277217Sphk error = EINVAL; 2073175445Sambrisko AN_UNLOCK(sc); 207477217Sphk break; 2075119156Sambrisko } else { 2076119156Sambrisko len = ssids->an_entry[ireq->i_val].an_len; 2077119156Sambrisko tmpptr = ssids->an_entry[ireq->i_val].an_ssid; 207877217Sphk } 207977217Sphk } else { 208077217Sphk error = EINVAL; 2081175445Sambrisko AN_UNLOCK(sc); 208277217Sphk break; 208377217Sphk } 208478639Sbrooks if (len > IEEE80211_NWID_LEN) { 208577217Sphk error = EINVAL; 2086175445Sambrisko AN_UNLOCK(sc); 208777217Sphk break; 208877217Sphk } 2089175445Sambrisko AN_UNLOCK(sc); 209077217Sphk ireq->i_len = len; 209177217Sphk bzero(tmpstr, IEEE80211_NWID_LEN); 209277217Sphk bcopy(tmpptr, tmpstr, len); 209377217Sphk error = copyout(tmpstr, ireq->i_data, 209477217Sphk IEEE80211_NWID_LEN); 209577217Sphk break; 209677217Sphk case IEEE80211_IOC_NUMSSIDS: 2097175445Sambrisko AN_LOCK(sc); 2098119156Sambrisko sc->areq.an_len = sizeof(sc->areq); 2099119156Sambrisko sc->areq.an_type = AN_RID_SSIDLIST; 2100119156Sambrisko if (an_read_record(sc, 2101119156Sambrisko (struct an_ltv_gen *)&sc->areq)) { 2102175445Sambrisko AN_UNLOCK(sc); 2103119156Sambrisko error = EINVAL; 2104119156Sambrisko break; 2105119156Sambrisko } 2106119156Sambrisko max = (sc->areq.an_len - 4) 2107119156Sambrisko / sizeof(struct an_ltv_ssid_entry); 2108175445Sambrisko AN_UNLOCK(sc); 2109119156Sambrisko if ( max > MAX_SSIDS ) { 2110119156Sambrisko printf("To many SSIDs only using " 2111119156Sambrisko "%d of %d\n", 2112119156Sambrisko MAX_SSIDS, max); 2113119156Sambrisko max = MAX_SSIDS; 2114119156Sambrisko } 2115119156Sambrisko ireq->i_val = max; 211677217Sphk break; 211777217Sphk case IEEE80211_IOC_WEP: 2118175445Sambrisko AN_LOCK(sc); 211988749Sambrisko sc->areq.an_type = AN_RID_ACTUALCFG; 212077217Sphk if (an_read_record(sc, 212188749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 212277217Sphk error = EINVAL; 2123175445Sambrisko AN_UNLOCK(sc); 212477217Sphk break; 212577217Sphk } 2126175445Sambrisko AN_UNLOCK(sc); 212778639Sbrooks if (config->an_authtype & AN_AUTHTYPE_PRIVACY_IN_USE) { 212878639Sbrooks if (config->an_authtype & 212977217Sphk AN_AUTHTYPE_ALLOW_UNENCRYPTED) 213077217Sphk ireq->i_val = IEEE80211_WEP_MIXED; 213177217Sphk else 213277217Sphk ireq->i_val = IEEE80211_WEP_ON; 213377217Sphk } else { 213477217Sphk ireq->i_val = IEEE80211_WEP_OFF; 213577217Sphk } 213677217Sphk break; 213777217Sphk case IEEE80211_IOC_WEPKEY: 213877217Sphk /* 213977217Sphk * XXX: I'm not entierly convinced this is 214077217Sphk * correct, but it's what is implemented in 214177217Sphk * ancontrol so it will have to do until we get 214277217Sphk * access to actual Cisco code. 214377217Sphk */ 214488748Sambrisko if (ireq->i_val < 0 || ireq->i_val > 8) { 214577217Sphk error = EINVAL; 214677217Sphk break; 214777217Sphk } 214877217Sphk len = 0; 214988748Sambrisko if (ireq->i_val < 5) { 2150175445Sambrisko AN_LOCK(sc); 215188749Sambrisko sc->areq.an_type = AN_RID_WEP_TEMP; 215278639Sbrooks for (i = 0; i < 5; i++) { 215377217Sphk if (an_read_record(sc, 215488749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 215577217Sphk error = EINVAL; 215677217Sphk break; 215777217Sphk } 215878639Sbrooks if (key->kindex == 0xffff) 215977217Sphk break; 216078639Sbrooks if (key->kindex == ireq->i_val) 216178639Sbrooks len = key->klen; 216277217Sphk /* Required to get next entry */ 216388749Sambrisko sc->areq.an_type = AN_RID_WEP_PERM; 216477217Sphk } 2165175445Sambrisko AN_UNLOCK(sc); 2166175445Sambrisko if (error != 0) { 216777217Sphk break; 2168175445Sambrisko } 216977217Sphk } 217077217Sphk /* We aren't allowed to read the value of the 217177217Sphk * key from the card so we just output zeros 217277217Sphk * like we would if we could read the card, but 217377217Sphk * denied the user access. 217477217Sphk */ 217577217Sphk bzero(tmpstr, len); 217677217Sphk ireq->i_len = len; 217777217Sphk error = copyout(tmpstr, ireq->i_data, len); 217877217Sphk break; 217977217Sphk case IEEE80211_IOC_NUMWEPKEYS: 218088748Sambrisko ireq->i_val = 9; /* include home key */ 218177217Sphk break; 218277217Sphk case IEEE80211_IOC_WEPTXKEY: 218378639Sbrooks /* 218478639Sbrooks * For some strange reason, you have to read all 218578639Sbrooks * keys before you can read the txkey. 218678639Sbrooks */ 2187175445Sambrisko AN_LOCK(sc); 218888749Sambrisko sc->areq.an_type = AN_RID_WEP_TEMP; 218978639Sbrooks for (i = 0; i < 5; i++) { 219078639Sbrooks if (an_read_record(sc, 219188749Sambrisko (struct an_ltv_gen *) &sc->areq)) { 219278639Sbrooks error = EINVAL; 219378639Sbrooks break; 219478639Sbrooks } 2195175445Sambrisko if (key->kindex == 0xffff) { 219678639Sbrooks break; 2197175445Sambrisko } 219878639Sbrooks /* Required to get next entry */ 219988749Sambrisko sc->areq.an_type = AN_RID_WEP_PERM; 220078639Sbrooks } 2201175445Sambrisko if (error != 0) { 2202175445Sambrisko AN_UNLOCK(sc); 220378639Sbrooks break; 2204175445Sambrisko } 220578639Sbrooks 220688749Sambrisko sc->areq.an_type = AN_RID_WEP_PERM; 220777217Sphk key->kindex = 0xffff; 220877217Sphk if (an_read_record(sc, 220988749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 221077217Sphk error = EINVAL; 2211175445Sambrisko AN_UNLOCK(sc); 221277217Sphk break; 221377217Sphk } 221477217Sphk ireq->i_val = key->mac[0]; 221588748Sambrisko /* 221688748Sambrisko * Check for home mode. Map home mode into 221788748Sambrisko * 5th key since that is how it is stored on 221888748Sambrisko * the card 221988748Sambrisko */ 222088749Sambrisko sc->areq.an_len = sizeof(struct an_ltv_genconfig); 222188749Sambrisko sc->areq.an_type = AN_RID_GENCONFIG; 222288748Sambrisko if (an_read_record(sc, 222388749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 222488748Sambrisko error = EINVAL; 2225175445Sambrisko AN_UNLOCK(sc); 222688748Sambrisko break; 222788748Sambrisko } 222888748Sambrisko if (config->an_home_product & AN_HOME_NETWORK) 222988748Sambrisko ireq->i_val = 4; 2230175445Sambrisko AN_UNLOCK(sc); 223177217Sphk break; 223277217Sphk case IEEE80211_IOC_AUTHMODE: 2233175445Sambrisko AN_LOCK(sc); 223488749Sambrisko sc->areq.an_type = AN_RID_ACTUALCFG; 223577217Sphk if (an_read_record(sc, 223688749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 223777217Sphk error = EINVAL; 2238175445Sambrisko AN_UNLOCK(sc); 223977217Sphk break; 224077217Sphk } 2241175445Sambrisko AN_UNLOCK(sc); 224277217Sphk if ((config->an_authtype & AN_AUTHTYPE_MASK) == 224377217Sphk AN_AUTHTYPE_NONE) { 224477217Sphk ireq->i_val = IEEE80211_AUTH_NONE; 224577217Sphk } else if ((config->an_authtype & AN_AUTHTYPE_MASK) == 224677217Sphk AN_AUTHTYPE_OPEN) { 224777217Sphk ireq->i_val = IEEE80211_AUTH_OPEN; 224877217Sphk } else if ((config->an_authtype & AN_AUTHTYPE_MASK) == 224977217Sphk AN_AUTHTYPE_SHAREDKEY) { 225077217Sphk ireq->i_val = IEEE80211_AUTH_SHARED; 225177217Sphk } else 225277217Sphk error = EINVAL; 225377217Sphk break; 225477217Sphk case IEEE80211_IOC_STATIONNAME: 2255175445Sambrisko AN_LOCK(sc); 225688749Sambrisko sc->areq.an_type = AN_RID_ACTUALCFG; 225777217Sphk if (an_read_record(sc, 225888749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 225977217Sphk error = EINVAL; 2260175445Sambrisko AN_UNLOCK(sc); 226177217Sphk break; 226277217Sphk } 2263175445Sambrisko AN_UNLOCK(sc); 226477217Sphk ireq->i_len = sizeof(config->an_nodename); 226577217Sphk tmpptr = config->an_nodename; 226677217Sphk bzero(tmpstr, IEEE80211_NWID_LEN); 226777217Sphk bcopy(tmpptr, tmpstr, ireq->i_len); 226877217Sphk error = copyout(tmpstr, ireq->i_data, 226977217Sphk IEEE80211_NWID_LEN); 227077217Sphk break; 227177217Sphk case IEEE80211_IOC_CHANNEL: 2272175445Sambrisko AN_LOCK(sc); 227388749Sambrisko sc->areq.an_type = AN_RID_STATUS; 227477217Sphk if (an_read_record(sc, 227588749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 227677217Sphk error = EINVAL; 2277175445Sambrisko AN_UNLOCK(sc); 227877217Sphk break; 227977217Sphk } 2280175445Sambrisko AN_UNLOCK(sc); 228177217Sphk ireq->i_val = status->an_cur_channel; 228277217Sphk break; 2283175445Sambrisko case IEEE80211_IOC_CURCHAN: 2284175445Sambrisko AN_LOCK(sc); 2285175445Sambrisko sc->areq.an_type = AN_RID_STATUS; 2286175445Sambrisko if (an_read_record(sc, 2287175445Sambrisko (struct an_ltv_gen *)&sc->areq)) { 2288172112Savatar error = EINVAL; 2289175445Sambrisko AN_UNLOCK(sc); 2290172112Savatar break; 2291172112Savatar } 2292175445Sambrisko AN_UNLOCK(sc); 2293172112Savatar bzero(&ch, sizeof(ch)); 2294172112Savatar ch.ic_freq = ieee80211_ieee2mhz(status->an_cur_channel, 2295172112Savatar IEEE80211_CHAN_B); 2296172112Savatar ch.ic_flags = IEEE80211_CHAN_B; 2297172112Savatar ch.ic_ieee = status->an_cur_channel; 2298172112Savatar error = copyout(&ch, ireq->i_data, sizeof(ch)); 2299172112Savatar break; 230077217Sphk case IEEE80211_IOC_POWERSAVE: 2301175445Sambrisko AN_LOCK(sc); 230288749Sambrisko sc->areq.an_type = AN_RID_ACTUALCFG; 230377217Sphk if (an_read_record(sc, 230488749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 230577217Sphk error = EINVAL; 2306175445Sambrisko AN_UNLOCK(sc); 230777217Sphk break; 230877217Sphk } 2309175445Sambrisko AN_UNLOCK(sc); 231078639Sbrooks if (config->an_psave_mode == AN_PSAVE_NONE) { 231177217Sphk ireq->i_val = IEEE80211_POWERSAVE_OFF; 231278639Sbrooks } else if (config->an_psave_mode == AN_PSAVE_CAM) { 231377217Sphk ireq->i_val = IEEE80211_POWERSAVE_CAM; 231478639Sbrooks } else if (config->an_psave_mode == AN_PSAVE_PSP) { 231577217Sphk ireq->i_val = IEEE80211_POWERSAVE_PSP; 231678639Sbrooks } else if (config->an_psave_mode == AN_PSAVE_PSP_CAM) { 231777217Sphk ireq->i_val = IEEE80211_POWERSAVE_PSP_CAM; 231877217Sphk } else 231977217Sphk error = EINVAL; 232077217Sphk break; 232177217Sphk case IEEE80211_IOC_POWERSAVESLEEP: 2322175445Sambrisko AN_LOCK(sc); 232388749Sambrisko sc->areq.an_type = AN_RID_ACTUALCFG; 232477217Sphk if (an_read_record(sc, 232588749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 232677217Sphk error = EINVAL; 2327175445Sambrisko AN_UNLOCK(sc); 232877217Sphk break; 232977217Sphk } 2330175445Sambrisko AN_UNLOCK(sc); 233177217Sphk ireq->i_val = config->an_listen_interval; 233277217Sphk break; 233383270Sbrooks } 233477217Sphk break; 233577217Sphk case SIOCS80211: 2336164033Srwatson if ((error = priv_check(td, PRIV_NET80211_MANAGE))) 233777217Sphk goto out; 2338175445Sambrisko AN_LOCK(sc); 233988749Sambrisko sc->areq.an_len = sizeof(sc->areq); 234077217Sphk /* 234177217Sphk * We need a config structure for everything but the WEP 234277217Sphk * key management and SSIDs so we get it now so avoid 234377217Sphk * duplicating this code every time. 234477217Sphk */ 234577217Sphk if (ireq->i_type != IEEE80211_IOC_SSID && 234677217Sphk ireq->i_type != IEEE80211_IOC_WEPKEY && 234777217Sphk ireq->i_type != IEEE80211_IOC_WEPTXKEY) { 234888749Sambrisko sc->areq.an_type = AN_RID_GENCONFIG; 234977217Sphk if (an_read_record(sc, 235088749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 235177217Sphk error = EINVAL; 2352175445Sambrisko AN_UNLOCK(sc); 235377217Sphk break; 235477217Sphk } 235577217Sphk } 235683270Sbrooks switch (ireq->i_type) { 235777217Sphk case IEEE80211_IOC_SSID: 2358119156Sambrisko sc->areq.an_len = sizeof(sc->areq); 235988749Sambrisko sc->areq.an_type = AN_RID_SSIDLIST; 236077217Sphk if (an_read_record(sc, 236188749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 236277217Sphk error = EINVAL; 2363175445Sambrisko AN_UNLOCK(sc); 236477217Sphk break; 236577217Sphk } 236678639Sbrooks if (ireq->i_len > IEEE80211_NWID_LEN) { 236777217Sphk error = EINVAL; 2368175445Sambrisko AN_UNLOCK(sc); 236977217Sphk break; 237077217Sphk } 2371119156Sambrisko max = (sc->areq.an_len - 4) 2372119156Sambrisko / sizeof(struct an_ltv_ssid_entry); 2373119156Sambrisko if ( max > MAX_SSIDS ) { 2374119156Sambrisko printf("To many SSIDs only using " 2375119156Sambrisko "%d of %d\n", 2376119156Sambrisko MAX_SSIDS, max); 2377119156Sambrisko max = MAX_SSIDS; 2378119156Sambrisko } 2379119156Sambrisko if (ireq->i_val > max) { 2380119156Sambrisko error = EINVAL; 2381175445Sambrisko AN_UNLOCK(sc); 238277217Sphk break; 2383119156Sambrisko } else { 238477217Sphk error = copyin(ireq->i_data, 2385175445Sambrisko ssids->an_entry[ireq->i_val].an_ssid, 2386119156Sambrisko ireq->i_len); 2387175445Sambrisko ssids->an_entry[ireq->i_val].an_len 2388119156Sambrisko = ireq->i_len; 2389175445Sambrisko sc->areq.an_len = sizeof(sc->areq); 2390175445Sambrisko sc->areq.an_type = AN_RID_SSIDLIST; 2391175445Sambrisko an_setdef(sc, &sc->areq); 2392175445Sambrisko AN_UNLOCK(sc); 239377217Sphk break; 239477217Sphk } 239577217Sphk break; 239677217Sphk case IEEE80211_IOC_WEP: 239777217Sphk switch (ireq->i_val) { 239877217Sphk case IEEE80211_WEP_OFF: 239977217Sphk config->an_authtype &= 240077217Sphk ~(AN_AUTHTYPE_PRIVACY_IN_USE | 240177217Sphk AN_AUTHTYPE_ALLOW_UNENCRYPTED); 240277217Sphk break; 240377217Sphk case IEEE80211_WEP_ON: 240477217Sphk config->an_authtype |= 240577217Sphk AN_AUTHTYPE_PRIVACY_IN_USE; 240677217Sphk config->an_authtype &= 240777217Sphk ~AN_AUTHTYPE_ALLOW_UNENCRYPTED; 240877217Sphk break; 240977217Sphk case IEEE80211_WEP_MIXED: 241077217Sphk config->an_authtype |= 241177217Sphk AN_AUTHTYPE_PRIVACY_IN_USE | 241277217Sphk AN_AUTHTYPE_ALLOW_UNENCRYPTED; 241377217Sphk break; 241477217Sphk default: 241577217Sphk error = EINVAL; 241677217Sphk break; 241777217Sphk } 2418175445Sambrisko if (error != EINVAL) 2419175445Sambrisko an_setdef(sc, &sc->areq); 2420175445Sambrisko AN_UNLOCK(sc); 242177217Sphk break; 242277217Sphk case IEEE80211_IOC_WEPKEY: 2423110531Sambrisko if (ireq->i_val < 0 || ireq->i_val > 8 || 242477217Sphk ireq->i_len > 13) { 242577217Sphk error = EINVAL; 2426175445Sambrisko AN_UNLOCK(sc); 242777217Sphk break; 242877217Sphk } 242977217Sphk error = copyin(ireq->i_data, tmpstr, 13); 2430175445Sambrisko if (error != 0) { 2431175445Sambrisko AN_UNLOCK(sc); 243277217Sphk break; 2433175445Sambrisko } 2434110531Sambrisko /* 2435110531Sambrisko * Map the 9th key into the home mode 2436110531Sambrisko * since that is how it is stored on 2437110531Sambrisko * the card 2438110531Sambrisko */ 243988749Sambrisko bzero(&sc->areq, sizeof(struct an_ltv_key)); 244088749Sambrisko sc->areq.an_len = sizeof(struct an_ltv_key); 244177217Sphk key->mac[0] = 1; /* The others are 0. */ 2442110531Sambrisko if (ireq->i_val < 4) { 244388749Sambrisko sc->areq.an_type = AN_RID_WEP_TEMP; 2444110531Sambrisko key->kindex = ireq->i_val; 2445110531Sambrisko } else { 244688749Sambrisko sc->areq.an_type = AN_RID_WEP_PERM; 2447110531Sambrisko key->kindex = ireq->i_val - 4; 2448110531Sambrisko } 244977217Sphk key->klen = ireq->i_len; 245077217Sphk bcopy(tmpstr, key->key, key->klen); 2451175445Sambrisko an_setdef(sc, &sc->areq); 2452175445Sambrisko AN_UNLOCK(sc); 245377217Sphk break; 245477217Sphk case IEEE80211_IOC_WEPTXKEY: 2455110531Sambrisko if (ireq->i_val < 0 || ireq->i_val > 4) { 2456110531Sambrisko error = EINVAL; 2457175445Sambrisko AN_UNLOCK(sc); 2458110531Sambrisko break; 2459110531Sambrisko } 2460110531Sambrisko 246188748Sambrisko /* 246288748Sambrisko * Map the 5th key into the home mode 246388748Sambrisko * since that is how it is stored on 246488748Sambrisko * the card 246588748Sambrisko */ 246688749Sambrisko sc->areq.an_len = sizeof(struct an_ltv_genconfig); 246788749Sambrisko sc->areq.an_type = AN_RID_ACTUALCFG; 246888748Sambrisko if (an_read_record(sc, 2469175445Sambrisko (struct an_ltv_gen *)&sc->areq)) { 2470175445Sambrisko error = EINVAL; 2471175445Sambrisko AN_UNLOCK(sc); 247288748Sambrisko break; 247388748Sambrisko } 247488748Sambrisko if (ireq->i_val == 4) { 247588748Sambrisko config->an_home_product |= AN_HOME_NETWORK; 247688748Sambrisko ireq->i_val = 0; 247788748Sambrisko } else { 247888748Sambrisko config->an_home_product &= ~AN_HOME_NETWORK; 247988748Sambrisko } 248088748Sambrisko 248188748Sambrisko sc->an_config.an_home_product 248288748Sambrisko = config->an_home_product; 248388748Sambrisko 2484110531Sambrisko /* update configuration */ 2485199154Sjhb an_init_locked(sc); 2486110531Sambrisko 248788749Sambrisko bzero(&sc->areq, sizeof(struct an_ltv_key)); 248888749Sambrisko sc->areq.an_len = sizeof(struct an_ltv_key); 248988749Sambrisko sc->areq.an_type = AN_RID_WEP_PERM; 249077217Sphk key->kindex = 0xffff; 249177217Sphk key->mac[0] = ireq->i_val; 2492175445Sambrisko an_setdef(sc, &sc->areq); 2493175445Sambrisko AN_UNLOCK(sc); 249477217Sphk break; 249577217Sphk case IEEE80211_IOC_AUTHMODE: 249677217Sphk switch (ireq->i_val) { 249777217Sphk case IEEE80211_AUTH_NONE: 249877217Sphk config->an_authtype = AN_AUTHTYPE_NONE | 249977217Sphk (config->an_authtype & ~AN_AUTHTYPE_MASK); 250077217Sphk break; 250177217Sphk case IEEE80211_AUTH_OPEN: 250277217Sphk config->an_authtype = AN_AUTHTYPE_OPEN | 250377217Sphk (config->an_authtype & ~AN_AUTHTYPE_MASK); 250477217Sphk break; 250577217Sphk case IEEE80211_AUTH_SHARED: 250677217Sphk config->an_authtype = AN_AUTHTYPE_SHAREDKEY | 250777217Sphk (config->an_authtype & ~AN_AUTHTYPE_MASK); 250877217Sphk break; 250977217Sphk default: 251077217Sphk error = EINVAL; 251177217Sphk } 2512175445Sambrisko if (error != EINVAL) { 2513175445Sambrisko an_setdef(sc, &sc->areq); 2514175445Sambrisko } 2515175445Sambrisko AN_UNLOCK(sc); 251677217Sphk break; 251777217Sphk case IEEE80211_IOC_STATIONNAME: 251878639Sbrooks if (ireq->i_len > 16) { 251977217Sphk error = EINVAL; 2520175445Sambrisko AN_UNLOCK(sc); 252177217Sphk break; 252277217Sphk } 252377217Sphk bzero(config->an_nodename, 16); 252477217Sphk error = copyin(ireq->i_data, 252577217Sphk config->an_nodename, ireq->i_len); 2526175445Sambrisko an_setdef(sc, &sc->areq); 2527175445Sambrisko AN_UNLOCK(sc); 252877217Sphk break; 252977217Sphk case IEEE80211_IOC_CHANNEL: 253077217Sphk /* 253177217Sphk * The actual range is 1-14, but if you set it 253277217Sphk * to 0 you get the default so we let that work 253377217Sphk * too. 253477217Sphk */ 253577217Sphk if (ireq->i_val < 0 || ireq->i_val >14) { 253677217Sphk error = EINVAL; 2537175445Sambrisko AN_UNLOCK(sc); 253877217Sphk break; 253977217Sphk } 254077217Sphk config->an_ds_channel = ireq->i_val; 2541175445Sambrisko an_setdef(sc, &sc->areq); 2542175445Sambrisko AN_UNLOCK(sc); 254377217Sphk break; 254477217Sphk case IEEE80211_IOC_POWERSAVE: 254577217Sphk switch (ireq->i_val) { 254677217Sphk case IEEE80211_POWERSAVE_OFF: 254777217Sphk config->an_psave_mode = AN_PSAVE_NONE; 254877217Sphk break; 254977217Sphk case IEEE80211_POWERSAVE_CAM: 255077217Sphk config->an_psave_mode = AN_PSAVE_CAM; 255177217Sphk break; 255277217Sphk case IEEE80211_POWERSAVE_PSP: 255377217Sphk config->an_psave_mode = AN_PSAVE_PSP; 255477217Sphk break; 255577217Sphk case IEEE80211_POWERSAVE_PSP_CAM: 255677217Sphk config->an_psave_mode = AN_PSAVE_PSP_CAM; 255777217Sphk break; 255877217Sphk default: 255977217Sphk error = EINVAL; 256077217Sphk break; 256177217Sphk } 2562175445Sambrisko an_setdef(sc, &sc->areq); 2563175445Sambrisko AN_UNLOCK(sc); 256477217Sphk break; 256577217Sphk case IEEE80211_IOC_POWERSAVESLEEP: 256677217Sphk config->an_listen_interval = ireq->i_val; 2567175445Sambrisko an_setdef(sc, &sc->areq); 2568175445Sambrisko AN_UNLOCK(sc); 256977217Sphk break; 2570199154Sjhb default: 2571199154Sjhb AN_UNLOCK(sc); 2572199154Sjhb break; 257377217Sphk } 257477217Sphk 2575175445Sambrisko /* 2576175445Sambrisko if (!error) { 2577175445Sambrisko AN_LOCK(sc); 257888749Sambrisko an_setdef(sc, &sc->areq); 2579175445Sambrisko AN_UNLOCK(sc); 2580175445Sambrisko } 2581175445Sambrisko */ 258277217Sphk break; 258355992Swpaul default: 2584106937Ssam error = ether_ioctl(ifp, command, data); 258555992Swpaul break; 258655992Swpaul } 258761816Srobertoout: 258855992Swpaul 258978639Sbrooks return(error != 0); 259055992Swpaul} 259155992Swpaul 259283270Sbrooksstatic int 2593150446Simpan_init_tx_ring(struct an_softc *sc) 259455992Swpaul{ 259555992Swpaul int i; 259655992Swpaul int id; 259755992Swpaul 259855992Swpaul if (sc->an_gone) 259955992Swpaul return (0); 260055992Swpaul 2601108401Sambrisko if (!sc->mpi350) { 2602108401Sambrisko for (i = 0; i < AN_TX_RING_CNT; i++) { 2603108401Sambrisko if (an_alloc_nicmem(sc, 1518 + 2604108401Sambrisko 0x44, &id)) 2605108401Sambrisko return(ENOMEM); 2606108401Sambrisko sc->an_rdata.an_tx_fids[i] = id; 2607108401Sambrisko sc->an_rdata.an_tx_ring[i] = 0; 2608108401Sambrisko } 260955992Swpaul } 261055992Swpaul 261155992Swpaul sc->an_rdata.an_tx_prod = 0; 261255992Swpaul sc->an_rdata.an_tx_cons = 0; 2613108401Sambrisko sc->an_rdata.an_tx_empty = 1; 261455992Swpaul 261555992Swpaul return(0); 261655992Swpaul} 261755992Swpaul 261883270Sbrooksstatic void 2619150446Simpan_init(void *xsc) 262055992Swpaul{ 262155992Swpaul struct an_softc *sc = xsc; 262255992Swpaul 262367094Swpaul AN_LOCK(sc); 2624199154Sjhb an_init_locked(sc); 2625199154Sjhb AN_UNLOCK(sc); 2626199154Sjhb} 262767094Swpaul 2628199154Sjhbstatic void 2629199154Sjhban_init_locked(struct an_softc *sc) 2630199154Sjhb{ 2631199154Sjhb struct ifnet *ifp; 2632199154Sjhb 2633199154Sjhb AN_LOCK_ASSERT(sc); 2634199154Sjhb ifp = sc->an_ifp; 2635199154Sjhb if (sc->an_gone) 263655992Swpaul return; 263755992Swpaul 2638148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 263955992Swpaul an_stop(sc); 264055992Swpaul 264155992Swpaul sc->an_associated = 0; 264255992Swpaul 264355992Swpaul /* Allocate the TX buffers */ 264455992Swpaul if (an_init_tx_ring(sc)) { 264555992Swpaul an_reset(sc); 2646108401Sambrisko if (sc->mpi350) 2647175445Sambrisko an_init_mpi350_desc(sc); 264855992Swpaul if (an_init_tx_ring(sc)) { 2649198987Sjhb if_printf(ifp, "tx buffer allocation failed\n"); 265055992Swpaul return; 265155992Swpaul } 265255992Swpaul } 265355992Swpaul 265455992Swpaul /* Set our MAC address. */ 2655152315Sru bcopy((char *)IF_LLADDR(sc->an_ifp), 265655992Swpaul (char *)&sc->an_config.an_macaddr, ETHER_ADDR_LEN); 265755992Swpaul 265855992Swpaul if (ifp->if_flags & IFF_BROADCAST) 265955992Swpaul sc->an_config.an_rxmode = AN_RXMODE_BC_ADDR; 266055992Swpaul else 266155992Swpaul sc->an_config.an_rxmode = AN_RXMODE_ADDR; 266255992Swpaul 266355992Swpaul if (ifp->if_flags & IFF_MULTICAST) 266455992Swpaul sc->an_config.an_rxmode = AN_RXMODE_BC_MC_ADDR; 266555992Swpaul 266683269Sbrooks if (ifp->if_flags & IFF_PROMISC) { 266783269Sbrooks if (sc->an_monitor & AN_MONITOR) { 266883269Sbrooks if (sc->an_monitor & AN_MONITOR_ANY_BSS) { 266983269Sbrooks sc->an_config.an_rxmode |= 267083269Sbrooks AN_RXMODE_80211_MONITOR_ANYBSS | 267183269Sbrooks AN_RXMODE_NO_8023_HEADER; 267283269Sbrooks } else { 267383269Sbrooks sc->an_config.an_rxmode |= 267483269Sbrooks AN_RXMODE_80211_MONITOR_CURBSS | 267583269Sbrooks AN_RXMODE_NO_8023_HEADER; 267683269Sbrooks } 267783269Sbrooks } 267883269Sbrooks } 267955992Swpaul 2680184708Sbz#ifdef ANCACHE 2681108401Sambrisko if (sc->an_have_rssimap) 2682108401Sambrisko sc->an_config.an_rxmode |= AN_RXMODE_NORMALIZED_RSSI; 2683184708Sbz#endif 2684108401Sambrisko 268555992Swpaul /* Set the ssid list */ 268655992Swpaul sc->an_ssidlist.an_type = AN_RID_SSIDLIST; 2687119156Sambrisko sc->an_ssidlist.an_len = sizeof(struct an_ltv_ssidlist_new); 268855992Swpaul if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_ssidlist)) { 2689198987Sjhb if_printf(ifp, "failed to set ssid list\n"); 269055992Swpaul return; 269155992Swpaul } 269255992Swpaul 269355992Swpaul /* Set the AP list */ 269455992Swpaul sc->an_aplist.an_type = AN_RID_APLIST; 269555992Swpaul sc->an_aplist.an_len = sizeof(struct an_ltv_aplist); 269655992Swpaul if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_aplist)) { 2697198987Sjhb if_printf(ifp, "failed to set AP list\n"); 269855992Swpaul return; 269955992Swpaul } 270055992Swpaul 270155992Swpaul /* Set the configuration in the NIC */ 270255992Swpaul sc->an_config.an_len = sizeof(struct an_ltv_genconfig); 270355992Swpaul sc->an_config.an_type = AN_RID_GENCONFIG; 270455992Swpaul if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_config)) { 2705198987Sjhb if_printf(ifp, "failed to set configuration\n"); 270655992Swpaul return; 270755992Swpaul } 270855992Swpaul 270955992Swpaul /* Enable the MAC */ 271055992Swpaul if (an_cmd(sc, AN_CMD_ENABLE, 0)) { 2711198987Sjhb if_printf(ifp, "failed to enable MAC\n"); 271255992Swpaul return; 271355992Swpaul } 271455992Swpaul 271574698Sarchie if (ifp->if_flags & IFF_PROMISC) 271674698Sarchie an_cmd(sc, AN_CMD_SET_MODE, 0xffff); 271774698Sarchie 271855992Swpaul /* enable interrupts */ 2719119156Sambrisko CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), AN_INTRS(sc->mpi350)); 272055992Swpaul 2721148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 2722148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 272355992Swpaul 2724173668Savatar callout_reset(&sc->an_stat_ch, hz, an_stats_update, sc); 272555992Swpaul 272655992Swpaul return; 272755992Swpaul} 272855992Swpaul 272983270Sbrooksstatic void 2730150446Simpan_start(struct ifnet *ifp) 273155992Swpaul{ 273255992Swpaul struct an_softc *sc; 2733199154Sjhb 2734199154Sjhb sc = ifp->if_softc; 2735199154Sjhb AN_LOCK(sc); 2736199154Sjhb an_start_locked(ifp); 2737199154Sjhb AN_UNLOCK(sc); 2738199154Sjhb} 2739199154Sjhb 2740199154Sjhbstatic void 2741199154Sjhban_start_locked(struct ifnet *ifp) 2742199154Sjhb{ 2743199154Sjhb struct an_softc *sc; 274455992Swpaul struct mbuf *m0 = NULL; 274555992Swpaul struct an_txframe_802_3 tx_frame_802_3; 274655992Swpaul struct ether_header *eh; 2747108401Sambrisko int id, idx, i; 2748175446Sambrisko unsigned char txcontrol; 2749108401Sambrisko struct an_card_tx_desc an_tx_desc; 2750108401Sambrisko u_int8_t *buf; 275155992Swpaul 275255992Swpaul sc = ifp->if_softc; 275355992Swpaul 2754199154Sjhb AN_LOCK_ASSERT(sc); 275555992Swpaul if (sc->an_gone) 275655992Swpaul return; 275755992Swpaul 2758148887Srwatson if (ifp->if_drv_flags & IFF_DRV_OACTIVE) 275955992Swpaul return; 276055992Swpaul 276155992Swpaul if (!sc->an_associated) 276255992Swpaul return; 276355992Swpaul 276490990Sbrooks /* We can't send in monitor mode so toss any attempts. */ 276583269Sbrooks if (sc->an_monitor && (ifp->if_flags & IFF_PROMISC)) { 276683270Sbrooks for (;;) { 2767132986Smlaier IFQ_DRV_DEQUEUE(&ifp->if_snd, m0); 276883269Sbrooks if (m0 == NULL) 276983269Sbrooks break; 277090990Sbrooks m_freem(m0); 277183269Sbrooks } 277283269Sbrooks return; 277383269Sbrooks } 277483269Sbrooks 277555992Swpaul idx = sc->an_rdata.an_tx_prod; 277655992Swpaul 2777108401Sambrisko if (!sc->mpi350) { 2778108401Sambrisko bzero((char *)&tx_frame_802_3, sizeof(tx_frame_802_3)); 277955992Swpaul 2780108401Sambrisko while (sc->an_rdata.an_tx_ring[idx] == 0) { 2781132986Smlaier IFQ_DRV_DEQUEUE(&ifp->if_snd, m0); 2782108401Sambrisko if (m0 == NULL) 2783108401Sambrisko break; 278455992Swpaul 2785108401Sambrisko id = sc->an_rdata.an_tx_fids[idx]; 2786108401Sambrisko eh = mtod(m0, struct ether_header *); 278783270Sbrooks 2788108401Sambrisko bcopy((char *)&eh->ether_dhost, 2789175445Sambrisko (char *)&tx_frame_802_3.an_tx_dst_addr, 2790108401Sambrisko ETHER_ADDR_LEN); 2791108401Sambrisko bcopy((char *)&eh->ether_shost, 2792175445Sambrisko (char *)&tx_frame_802_3.an_tx_src_addr, 2793108401Sambrisko ETHER_ADDR_LEN); 279455992Swpaul 2795108401Sambrisko /* minus src/dest mac & type */ 2796108401Sambrisko tx_frame_802_3.an_tx_802_3_payload_len = 2797175445Sambrisko m0->m_pkthdr.len - 12; 279855992Swpaul 2799108401Sambrisko m_copydata(m0, sizeof(struct ether_header) - 2 , 2800108401Sambrisko tx_frame_802_3.an_tx_802_3_payload_len, 2801108401Sambrisko (caddr_t)&sc->an_txbuf); 2802108401Sambrisko 2803199757Sjhb txcontrol = AN_TXCTL_8023 | AN_TXCTL_HW(sc->mpi350); 2804108401Sambrisko /* write the txcontrol only */ 2805108401Sambrisko an_write_data(sc, id, 0x08, (caddr_t)&txcontrol, 2806108401Sambrisko sizeof(txcontrol)); 2807108401Sambrisko 2808108401Sambrisko /* 802_3 header */ 2809108401Sambrisko an_write_data(sc, id, 0x34, (caddr_t)&tx_frame_802_3, 2810108401Sambrisko sizeof(struct an_txframe_802_3)); 2811108401Sambrisko 2812108401Sambrisko /* in mbuf header type is just before payload */ 2813108401Sambrisko an_write_data(sc, id, 0x44, (caddr_t)&sc->an_txbuf, 2814108401Sambrisko tx_frame_802_3.an_tx_802_3_payload_len); 2815108401Sambrisko 2816108401Sambrisko /* 2817108401Sambrisko * If there's a BPF listner, bounce a copy of 2818108401Sambrisko * this frame to him. 2819108401Sambrisko */ 2820108401Sambrisko BPF_MTAP(ifp, m0); 2821108401Sambrisko 2822108401Sambrisko m_freem(m0); 2823108401Sambrisko m0 = NULL; 2824108401Sambrisko 2825108401Sambrisko sc->an_rdata.an_tx_ring[idx] = id; 2826108401Sambrisko if (an_cmd(sc, AN_CMD_TX, id)) 2827198987Sjhb if_printf(ifp, "xmit failed\n"); 2828108401Sambrisko 2829108401Sambrisko AN_INC(idx, AN_TX_RING_CNT); 2830119156Sambrisko 2831119156Sambrisko /* 2832119156Sambrisko * Set a timeout in case the chip goes out to lunch. 2833119156Sambrisko */ 2834199154Sjhb sc->an_timer = 5; 2835108401Sambrisko } 2836108401Sambrisko } else { /* MPI-350 */ 2837130620Sambrisko /* Disable interrupts. */ 2838130620Sambrisko CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0); 2839130620Sambrisko 2840108401Sambrisko while (sc->an_rdata.an_tx_empty || 2841108401Sambrisko idx != sc->an_rdata.an_tx_cons) { 2842132986Smlaier IFQ_DRV_DEQUEUE(&ifp->if_snd, m0); 2843108401Sambrisko if (m0 == NULL) { 2844108401Sambrisko break; 2845108401Sambrisko } 2846108401Sambrisko buf = sc->an_tx_buffer[idx].an_dma_vaddr; 2847108401Sambrisko 2848108401Sambrisko eh = mtod(m0, struct ether_header *); 2849108401Sambrisko 2850108401Sambrisko /* DJA optimize this to limit bcopy */ 2851108401Sambrisko bcopy((char *)&eh->ether_dhost, 2852175445Sambrisko (char *)&tx_frame_802_3.an_tx_dst_addr, 2853108401Sambrisko ETHER_ADDR_LEN); 2854108401Sambrisko bcopy((char *)&eh->ether_shost, 2855175445Sambrisko (char *)&tx_frame_802_3.an_tx_src_addr, 2856108401Sambrisko ETHER_ADDR_LEN); 2857108401Sambrisko 2858108401Sambrisko /* minus src/dest mac & type */ 2859108401Sambrisko tx_frame_802_3.an_tx_802_3_payload_len = 2860175445Sambrisko m0->m_pkthdr.len - 12; 2861108401Sambrisko 2862108401Sambrisko m_copydata(m0, sizeof(struct ether_header) - 2 , 2863108401Sambrisko tx_frame_802_3.an_tx_802_3_payload_len, 2864108401Sambrisko (caddr_t)&sc->an_txbuf); 2865108401Sambrisko 2866199757Sjhb txcontrol = AN_TXCTL_8023 | AN_TXCTL_HW(sc->mpi350); 2867108401Sambrisko /* write the txcontrol only */ 2868108401Sambrisko bcopy((caddr_t)&txcontrol, &buf[0x08], 286955992Swpaul sizeof(txcontrol)); 287083270Sbrooks 2871108401Sambrisko /* 802_3 header */ 2872108401Sambrisko bcopy((caddr_t)&tx_frame_802_3, &buf[0x34], 287355992Swpaul sizeof(struct an_txframe_802_3)); 287483270Sbrooks 2875108401Sambrisko /* in mbuf header type is just before payload */ 2876108401Sambrisko bcopy((caddr_t)&sc->an_txbuf, &buf[0x44], 2877108401Sambrisko tx_frame_802_3.an_tx_802_3_payload_len); 287883270Sbrooks 287955992Swpaul 2880108401Sambrisko bzero(&an_tx_desc, sizeof(an_tx_desc)); 2881108401Sambrisko an_tx_desc.an_offset = 0; 2882108401Sambrisko an_tx_desc.an_eoc = 1; 2883108401Sambrisko an_tx_desc.an_valid = 1; 2884108401Sambrisko an_tx_desc.an_len = 0x44 + 2885119156Sambrisko tx_frame_802_3.an_tx_802_3_payload_len; 2886175445Sambrisko an_tx_desc.an_phys 2887119156Sambrisko = sc->an_tx_buffer[idx].an_dma_paddr; 2888199757Sjhb for (i = sizeof(an_tx_desc) / 4 - 1; i >= 0; i--) { 2889119156Sambrisko CSR_MEM_AUX_WRITE_4(sc, AN_TX_DESC_OFFSET 2890175445Sambrisko /* zero for now */ 2891119156Sambrisko + (0 * sizeof(an_tx_desc)) 2892119156Sambrisko + (i * 4), 2893155321Simp ((u_int32_t *)(void *)&an_tx_desc)[i]); 2894108401Sambrisko } 289555992Swpaul 2896108401Sambrisko /* 2897108401Sambrisko * If there's a BPF listner, bounce a copy of 2898108401Sambrisko * this frame to him. 2899108401Sambrisko */ 2900108401Sambrisko BPF_MTAP(ifp, m0); 290155992Swpaul 2902108401Sambrisko m_freem(m0); 2903108401Sambrisko m0 = NULL; 2904119156Sambrisko AN_INC(idx, AN_MAX_TX_DESC); 2905119156Sambrisko sc->an_rdata.an_tx_empty = 0; 2906108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_ALLOC); 2907108401Sambrisko 2908119156Sambrisko /* 2909119156Sambrisko * Set a timeout in case the chip goes out to lunch. 2910119156Sambrisko */ 2911199154Sjhb sc->an_timer = 5; 2912108401Sambrisko } 2913130620Sambrisko 2914130620Sambrisko /* Re-enable interrupts. */ 2915130620Sambrisko CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), AN_INTRS(sc->mpi350)); 291655992Swpaul } 291755992Swpaul 291855992Swpaul if (m0 != NULL) 2919148887Srwatson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 292055992Swpaul 292155992Swpaul sc->an_rdata.an_tx_prod = idx; 292255992Swpaul 292355992Swpaul return; 292455992Swpaul} 292555992Swpaul 292683270Sbrooksvoid 2927150446Simpan_stop(struct an_softc *sc) 292855992Swpaul{ 292955992Swpaul struct ifnet *ifp; 293055992Swpaul int i; 293155992Swpaul 2932199154Sjhb AN_LOCK_ASSERT(sc); 293367094Swpaul 2934199154Sjhb if (sc->an_gone) 293555992Swpaul return; 293655992Swpaul 2937147256Sbrooks ifp = sc->an_ifp; 293855992Swpaul 293955992Swpaul an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0); 2940108401Sambrisko CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0); 294155992Swpaul an_cmd(sc, AN_CMD_DISABLE, 0); 294255992Swpaul 294355992Swpaul for (i = 0; i < AN_TX_RING_CNT; i++) 294455992Swpaul an_cmd(sc, AN_CMD_DEALLOC_MEM, sc->an_rdata.an_tx_fids[i]); 294555992Swpaul 2946173668Savatar callout_stop(&sc->an_stat_ch); 294755992Swpaul 2948148887Srwatson ifp->if_drv_flags &= ~(IFF_DRV_RUNNING|IFF_DRV_OACTIVE); 294955992Swpaul 2950108401Sambrisko if (sc->an_flash_buffer) { 2951108401Sambrisko free(sc->an_flash_buffer, M_DEVBUF); 2952108401Sambrisko sc->an_flash_buffer = NULL; 2953108401Sambrisko } 295455992Swpaul} 295555992Swpaul 295683270Sbrooksstatic void 2957199154Sjhban_watchdog(struct an_softc *sc) 295855992Swpaul{ 2959199154Sjhb struct ifnet *ifp; 296055992Swpaul 2961199154Sjhb AN_LOCK_ASSERT(sc); 296255992Swpaul 2963199154Sjhb if (sc->an_gone) 296455992Swpaul return; 296555992Swpaul 2966199154Sjhb ifp = sc->an_ifp; 2967198987Sjhb if_printf(ifp, "device timeout\n"); 296855992Swpaul 296955992Swpaul an_reset(sc); 2970108401Sambrisko if (sc->mpi350) 2971175445Sambrisko an_init_mpi350_desc(sc); 2972199154Sjhb an_init_locked(sc); 297355992Swpaul 297455992Swpaul ifp->if_oerrors++; 297555992Swpaul} 297655992Swpaul 2977188128Simpint 2978150446Simpan_shutdown(device_t dev) 297955992Swpaul{ 298055992Swpaul struct an_softc *sc; 298155992Swpaul 298255992Swpaul sc = device_get_softc(dev); 2983199154Sjhb AN_LOCK(sc); 298455992Swpaul an_stop(sc); 2985110531Sambrisko sc->an_gone = 1; 2986199154Sjhb AN_UNLOCK(sc); 298755992Swpaul 2988199154Sjhb return (0); 298955992Swpaul} 299055992Swpaul 2991110362Sambriskovoid 2992150446Simpan_resume(device_t dev) 2993110362Sambrisko{ 2994110362Sambrisko struct an_softc *sc; 2995110362Sambrisko struct ifnet *ifp; 2996110531Sambrisko int i; 2997110531Sambrisko 2998110362Sambrisko sc = device_get_softc(dev); 2999110531Sambrisko AN_LOCK(sc); 3000147256Sbrooks ifp = sc->an_ifp; 3001110362Sambrisko 3002110531Sambrisko sc->an_gone = 0; 3003110362Sambrisko an_reset(sc); 3004110362Sambrisko if (sc->mpi350) 3005175445Sambrisko an_init_mpi350_desc(sc); 3006199154Sjhb an_init_locked(sc); 3007110362Sambrisko 3008110531Sambrisko /* Recovery temporary keys */ 3009110531Sambrisko for (i = 0; i < 4; i++) { 3010110531Sambrisko sc->areq.an_type = AN_RID_WEP_TEMP; 3011175445Sambrisko sc->areq.an_len = sizeof(struct an_ltv_key); 3012110531Sambrisko bcopy(&sc->an_temp_keys[i], 3013110531Sambrisko &sc->areq, sizeof(struct an_ltv_key)); 3014110531Sambrisko an_setdef(sc, &sc->areq); 3015110531Sambrisko } 3016110531Sambrisko 3017110362Sambrisko if (ifp->if_flags & IFF_UP) 3018199154Sjhb an_start_locked(ifp); 3019110531Sambrisko AN_UNLOCK(sc); 3020110362Sambrisko 3021110362Sambrisko return; 3022110362Sambrisko} 3023110362Sambrisko 302455992Swpaul#ifdef ANCACHE 302555992Swpaul/* Aironet signal strength cache code. 302655992Swpaul * store signal/noise/quality on per MAC src basis in 302755992Swpaul * a small fixed cache. The cache wraps if > MAX slots 302855992Swpaul * used. The cache may be zeroed out to start over. 302955992Swpaul * Two simple filters exist to reduce computation: 303088748Sambrisko * 1. ip only (literally 0x800, ETHERTYPE_IP) which may be used 303155992Swpaul * to ignore some packets. It defaults to ip only. 303255992Swpaul * it could be used to focus on broadcast, non-IP 802.11 beacons. 303355992Swpaul * 2. multicast/broadcast only. This may be used to 303455992Swpaul * ignore unicast packets and only cache signal strength 303555992Swpaul * for multicast/broadcast packets (beacons); e.g., Mobile-IP 303655992Swpaul * beacons and not unicast traffic. 303755992Swpaul * 303855992Swpaul * The cache stores (MAC src(index), IP src (major clue), signal, 303955992Swpaul * quality, noise) 304055992Swpaul * 304155992Swpaul * No apologies for storing IP src here. It's easy and saves much 304283270Sbrooks * trouble elsewhere. The cache is assumed to be INET dependent, 304355992Swpaul * although it need not be. 304455992Swpaul * 304555992Swpaul * Note: the Aironet only has a single byte of signal strength value 304655992Swpaul * in the rx frame header, and it's not scaled to anything sensible. 304755992Swpaul * This is kind of lame, but it's all we've got. 304855992Swpaul */ 304955992Swpaul 305055992Swpaul#ifdef documentation 305155992Swpaul 3052175446Sambriskoint an_sigitems; /* number of cached entries */ 3053175446Sambriskostruct an_sigcache an_sigcache[MAXANCACHE]; /* array of cache entries */ 3054175446Sambriskoint an_nextitem; /* index/# of entries */ 305555992Swpaul 305655992Swpaul 305755992Swpaul#endif 305855992Swpaul 305955992Swpaul/* control variables for cache filtering. Basic idea is 306055992Swpaul * to reduce cost (e.g., to only Mobile-IP agent beacons 306155992Swpaul * which are broadcast or multicast). Still you might 306255992Swpaul * want to measure signal strength anth unicast ping packets 306355992Swpaul * on a pt. to pt. ant. setup. 306455992Swpaul */ 306583270Sbrooks/* set true if you want to limit cache items to broadcast/mcast 306655992Swpaul * only packets (not unicast). Useful for mobile-ip beacons which 306755992Swpaul * are broadcast/multicast at network layer. Default is all packets 306855992Swpaul * so ping/unicast anll work say anth pt. to pt. antennae setup. 306955992Swpaul */ 307055992Swpaulstatic int an_cache_mcastonly = 0; 3071110531SambriskoSYSCTL_INT(_hw_an, OID_AUTO, an_cache_mcastonly, CTLFLAG_RW, 307255992Swpaul &an_cache_mcastonly, 0, ""); 307355992Swpaul 307455992Swpaul/* set true if you want to limit cache items to IP packets only 307555992Swpaul*/ 307655992Swpaulstatic int an_cache_iponly = 1; 3077110531SambriskoSYSCTL_INT(_hw_an, OID_AUTO, an_cache_iponly, CTLFLAG_RW, 307855992Swpaul &an_cache_iponly, 0, ""); 307955992Swpaul 308055992Swpaul/* 308155992Swpaul * an_cache_store, per rx packet store signal 308255992Swpaul * strength in MAC (src) indexed cache. 308355992Swpaul */ 308483270Sbrooksstatic void 3085150446Simpan_cache_store(struct an_softc *sc, struct ether_header *eh, struct mbuf *m, 3086150446Simp u_int8_t rx_rssi, u_int8_t rx_quality) 308755992Swpaul{ 308883270Sbrooks struct ip *ip = 0; 308955992Swpaul int i; 309055992Swpaul static int cache_slot = 0; /* use this cache entry */ 3091175446Sambrisko static int wrapindex = 0; /* next "free" cache entry */ 309288748Sambrisko int type_ipv4 = 0; 309355992Swpaul 309455992Swpaul /* filters: 309555992Swpaul * 1. ip only 309655992Swpaul * 2. configurable filter to throw out unicast packets, 309755992Swpaul * keep multicast only. 309855992Swpaul */ 309983270Sbrooks 310088748Sambrisko if ((ntohs(eh->ether_type) == ETHERTYPE_IP)) { 310188748Sambrisko type_ipv4 = 1; 310255992Swpaul } 310355992Swpaul 310483270Sbrooks /* filter for ip packets only 310555992Swpaul */ 310688748Sambrisko if ( an_cache_iponly && !type_ipv4) { 310755992Swpaul return; 310855992Swpaul } 310955992Swpaul 311055992Swpaul /* filter for broadcast/multicast only 311155992Swpaul */ 311255992Swpaul if (an_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) { 311355992Swpaul return; 311455992Swpaul } 311555992Swpaul 311655992Swpaul#ifdef SIGDEBUG 3117198987Sjhb if_printf(sc->an_ifp, "q value %x (MSB=0x%x, LSB=0x%x) \n", 3118108401Sambrisko rx_rssi & 0xffff, rx_rssi >> 8, rx_rssi & 0xff); 311955992Swpaul#endif 312055992Swpaul 312155992Swpaul /* find the ip header. we want to store the ip_src 312283270Sbrooks * address. 312355992Swpaul */ 312488748Sambrisko if (type_ipv4) { 312555992Swpaul ip = mtod(m, struct ip *); 312655992Swpaul } 312783270Sbrooks 312883270Sbrooks /* do a linear search for a matching MAC address 312955992Swpaul * in the cache table 313055992Swpaul * . MAC address is 6 bytes, 313155992Swpaul * . var w_nextitem holds total number of entries already cached 313255992Swpaul */ 313378639Sbrooks for (i = 0; i < sc->an_nextitem; i++) { 313455992Swpaul if (! bcmp(eh->ether_shost , sc->an_sigcache[i].macsrc, 6 )) { 313555992Swpaul /* Match!, 313655992Swpaul * so we already have this entry, 313755992Swpaul * update the data 313855992Swpaul */ 313983270Sbrooks break; 314055992Swpaul } 314155992Swpaul } 314255992Swpaul 314355992Swpaul /* did we find a matching mac address? 314455992Swpaul * if yes, then overwrite a previously existing cache entry 314555992Swpaul */ 314655992Swpaul if (i < sc->an_nextitem ) { 314783270Sbrooks cache_slot = i; 314855992Swpaul } 314955992Swpaul /* else, have a new address entry,so 315055992Swpaul * add this new entry, 315155992Swpaul * if table full, then we need to replace LRU entry 315255992Swpaul */ 315383270Sbrooks else { 315455992Swpaul 315583270Sbrooks /* check for space in cache table 315655992Swpaul * note: an_nextitem also holds number of entries 315783270Sbrooks * added in the cache table 315855992Swpaul */ 315955992Swpaul if ( sc->an_nextitem < MAXANCACHE ) { 316055992Swpaul cache_slot = sc->an_nextitem; 316183270Sbrooks sc->an_nextitem++; 316255992Swpaul sc->an_sigitems = sc->an_nextitem; 316355992Swpaul } 3164175446Sambrisko /* no space found, so simply wrap anth wrap index 316555992Swpaul * and "zap" the next entry 316655992Swpaul */ 316755992Swpaul else { 316855992Swpaul if (wrapindex == MAXANCACHE) { 316955992Swpaul wrapindex = 0; 317055992Swpaul } 317155992Swpaul cache_slot = wrapindex++; 317255992Swpaul } 317355992Swpaul } 317455992Swpaul 317555992Swpaul /* invariant: cache_slot now points at some slot 317655992Swpaul * in cache. 317755992Swpaul */ 317855992Swpaul if (cache_slot < 0 || cache_slot >= MAXANCACHE) { 317955992Swpaul log(LOG_ERR, "an_cache_store, bad index: %d of " 318055992Swpaul "[0..%d], gross cache error\n", 318155992Swpaul cache_slot, MAXANCACHE); 318255992Swpaul return; 318355992Swpaul } 318455992Swpaul 318555992Swpaul /* store items in cache 318655992Swpaul * .ip source address 318755992Swpaul * .mac src 318855992Swpaul * .signal, etc. 318955992Swpaul */ 319088748Sambrisko if (type_ipv4) { 319155992Swpaul sc->an_sigcache[cache_slot].ipsrc = ip->ip_src.s_addr; 319255992Swpaul } 319355992Swpaul bcopy( eh->ether_shost, sc->an_sigcache[cache_slot].macsrc, 6); 319455992Swpaul 319555992Swpaul 3196108401Sambrisko switch (an_cache_mode) { 3197108401Sambrisko case DBM: 3198108401Sambrisko if (sc->an_have_rssimap) { 3199175445Sambrisko sc->an_sigcache[cache_slot].signal = 3200108401Sambrisko - sc->an_rssimap.an_entries[rx_rssi].an_rss_dbm; 3201175445Sambrisko sc->an_sigcache[cache_slot].quality = 3202108401Sambrisko - sc->an_rssimap.an_entries[rx_quality].an_rss_dbm; 3203108401Sambrisko } else { 3204108401Sambrisko sc->an_sigcache[cache_slot].signal = rx_rssi - 100; 3205108401Sambrisko sc->an_sigcache[cache_slot].quality = rx_quality - 100; 3206108401Sambrisko } 3207108401Sambrisko break; 3208108401Sambrisko case PERCENT: 3209108401Sambrisko if (sc->an_have_rssimap) { 3210175445Sambrisko sc->an_sigcache[cache_slot].signal = 3211108401Sambrisko sc->an_rssimap.an_entries[rx_rssi].an_rss_pct; 3212175445Sambrisko sc->an_sigcache[cache_slot].quality = 3213108401Sambrisko sc->an_rssimap.an_entries[rx_quality].an_rss_pct; 3214108401Sambrisko } else { 3215108401Sambrisko if (rx_rssi > 100) 3216108401Sambrisko rx_rssi = 100; 3217108401Sambrisko if (rx_quality > 100) 3218108401Sambrisko rx_quality = 100; 3219108401Sambrisko sc->an_sigcache[cache_slot].signal = rx_rssi; 3220108401Sambrisko sc->an_sigcache[cache_slot].quality = rx_quality; 3221108401Sambrisko } 3222108401Sambrisko break; 3223108401Sambrisko case RAW: 3224108401Sambrisko sc->an_sigcache[cache_slot].signal = rx_rssi; 3225108401Sambrisko sc->an_sigcache[cache_slot].quality = rx_quality; 3226108401Sambrisko break; 3227108401Sambrisko } 3228108401Sambrisko 3229108401Sambrisko sc->an_sigcache[cache_slot].noise = 0; 3230108401Sambrisko 323155992Swpaul return; 323255992Swpaul} 323355992Swpaul#endif 323477217Sphk 323583270Sbrooksstatic int 3236150446Simpan_media_change(struct ifnet *ifp) 323777217Sphk{ 323877217Sphk struct an_softc *sc = ifp->if_softc; 3239110253Sambrisko struct an_ltv_genconfig *cfg; 324077217Sphk int otype = sc->an_config.an_opmode; 324177217Sphk int orate = sc->an_tx_rate; 324277217Sphk 3243199154Sjhb AN_LOCK(sc); 3244116951Ssam sc->an_tx_rate = ieee80211_media2rate( 3245116951Ssam IFM_SUBTYPE(sc->an_ifmedia.ifm_cur->ifm_media)); 3246119156Sambrisko if (sc->an_tx_rate < 0) 3247119156Sambrisko sc->an_tx_rate = 0; 3248110253Sambrisko 3249110253Sambrisko if (orate != sc->an_tx_rate) { 3250110253Sambrisko /* Read the current configuration */ 3251110253Sambrisko sc->an_config.an_type = AN_RID_GENCONFIG; 3252110253Sambrisko sc->an_config.an_len = sizeof(struct an_ltv_genconfig); 3253110253Sambrisko an_read_record(sc, (struct an_ltv_gen *)&sc->an_config); 3254110253Sambrisko cfg = &sc->an_config; 3255110253Sambrisko 3256110253Sambrisko /* clear other rates and set the only one we want */ 3257110253Sambrisko bzero(cfg->an_rates, sizeof(cfg->an_rates)); 3258110253Sambrisko cfg->an_rates[0] = sc->an_tx_rate; 3259110253Sambrisko 3260110253Sambrisko /* Save the new rate */ 3261110253Sambrisko sc->an_config.an_type = AN_RID_GENCONFIG; 3262110253Sambrisko sc->an_config.an_len = sizeof(struct an_ltv_genconfig); 326377217Sphk } 326477217Sphk 3265119156Sambrisko if ((sc->an_ifmedia.ifm_cur->ifm_media & IFM_IEEE80211_ADHOC) != 0) 3266119156Sambrisko sc->an_config.an_opmode &= ~AN_OPMODE_INFRASTRUCTURE_STATION; 3267119156Sambrisko else 3268119156Sambrisko sc->an_config.an_opmode |= AN_OPMODE_INFRASTRUCTURE_STATION; 3269119156Sambrisko 3270175445Sambrisko if (otype != sc->an_config.an_opmode || 3271110531Sambrisko orate != sc->an_tx_rate) 3272199154Sjhb an_init_locked(sc); 3273199154Sjhb AN_UNLOCK(sc); 327477217Sphk 327577217Sphk return(0); 327677217Sphk} 327777217Sphk 327883270Sbrooksstatic void 3279150446Simpan_media_status(struct ifnet *ifp, struct ifmediareq *imr) 328077217Sphk{ 328177217Sphk struct an_ltv_status status; 328277217Sphk struct an_softc *sc = ifp->if_softc; 328377217Sphk 3284110253Sambrisko imr->ifm_active = IFM_IEEE80211; 3285110253Sambrisko 3286175445Sambrisko AN_LOCK(sc); 328777217Sphk status.an_len = sizeof(status); 328877217Sphk status.an_type = AN_RID_STATUS; 328977217Sphk if (an_read_record(sc, (struct an_ltv_gen *)&status)) { 329077217Sphk /* If the status read fails, just lie. */ 329177217Sphk imr->ifm_active = sc->an_ifmedia.ifm_cur->ifm_media; 329277217Sphk imr->ifm_status = IFM_AVALID|IFM_ACTIVE; 329377217Sphk } 329477217Sphk 329578639Sbrooks if (sc->an_tx_rate == 0) { 329677217Sphk imr->ifm_active = IFM_IEEE80211|IFM_AUTO; 329777217Sphk } 329877217Sphk 3299110253Sambrisko if (sc->an_config.an_opmode == AN_OPMODE_IBSS_ADHOC) 3300110253Sambrisko imr->ifm_active |= IFM_IEEE80211_ADHOC; 3301116951Ssam imr->ifm_active |= ieee80211_rate2media(NULL, 3302228621Sbschmidt status.an_current_tx_rate, IEEE80211_MODE_AUTO); 330377217Sphk imr->ifm_status = IFM_AVALID; 330491283Sambrisko if (status.an_opmode & AN_STATUS_OPMODE_ASSOCIATED) 330577217Sphk imr->ifm_status |= IFM_ACTIVE; 3306199154Sjhb AN_UNLOCK(sc); 330777217Sphk} 330888748Sambrisko 330988748Sambrisko/********************** Cisco utility support routines *************/ 331088748Sambrisko 331188748Sambrisko/* 331288748Sambrisko * ReadRids & WriteRids derived from Cisco driver additions to Ben Reed's 331388748Sambrisko * Linux driver 331488748Sambrisko */ 331588748Sambrisko 331688748Sambriskostatic int 3317150446Simpreadrids(struct ifnet *ifp, struct aironet_ioctl *l_ioctl) 331888748Sambrisko{ 331988749Sambrisko unsigned short rid; 332088748Sambrisko struct an_softc *sc; 3321171692Savatar int error; 332288748Sambrisko 332388748Sambrisko switch (l_ioctl->command) { 332488748Sambrisko case AIROGCAP: 332588748Sambrisko rid = AN_RID_CAPABILITIES; 332688748Sambrisko break; 332788748Sambrisko case AIROGCFG: 332888748Sambrisko rid = AN_RID_GENCONFIG; 332988748Sambrisko break; 333088748Sambrisko case AIROGSLIST: 333188748Sambrisko rid = AN_RID_SSIDLIST; 333288748Sambrisko break; 333388748Sambrisko case AIROGVLIST: 333488748Sambrisko rid = AN_RID_APLIST; 333588748Sambrisko break; 333688748Sambrisko case AIROGDRVNAM: 333788748Sambrisko rid = AN_RID_DRVNAME; 333888748Sambrisko break; 333988748Sambrisko case AIROGEHTENC: 334088748Sambrisko rid = AN_RID_ENCAPPROTO; 334188748Sambrisko break; 334288748Sambrisko case AIROGWEPKTMP: 334388748Sambrisko rid = AN_RID_WEP_TEMP; 334488748Sambrisko break; 334588748Sambrisko case AIROGWEPKNV: 334688748Sambrisko rid = AN_RID_WEP_PERM; 334788748Sambrisko break; 334888748Sambrisko case AIROGSTAT: 334988748Sambrisko rid = AN_RID_STATUS; 335088748Sambrisko break; 335188748Sambrisko case AIROGSTATSD32: 335288748Sambrisko rid = AN_RID_32BITS_DELTA; 335388748Sambrisko break; 335488748Sambrisko case AIROGSTATSC32: 335588748Sambrisko rid = AN_RID_32BITS_CUM; 335688748Sambrisko break; 335788748Sambrisko default: 335888748Sambrisko rid = 999; 335988748Sambrisko break; 336088748Sambrisko } 336188748Sambrisko 336288748Sambrisko if (rid == 999) /* Is bad command */ 336388748Sambrisko return -EINVAL; 336488748Sambrisko 336588748Sambrisko sc = ifp->if_softc; 336688749Sambrisko sc->areq.an_len = AN_MAX_DATALEN; 336788749Sambrisko sc->areq.an_type = rid; 336888748Sambrisko 336988749Sambrisko an_read_record(sc, (struct an_ltv_gen *)&sc->areq); 337088748Sambrisko 337188749Sambrisko l_ioctl->len = sc->areq.an_len - 4; /* just data */ 337288748Sambrisko 3373171692Savatar AN_UNLOCK(sc); 337488748Sambrisko /* the data contains the length at first */ 337588749Sambrisko if (copyout(&(sc->areq.an_len), l_ioctl->data, 337688749Sambrisko sizeof(sc->areq.an_len))) { 3377171692Savatar error = -EFAULT; 3378171692Savatar goto lock_exit; 337988748Sambrisko } 338088748Sambrisko /* Just copy the data back */ 338188749Sambrisko if (copyout(&(sc->areq.an_val), l_ioctl->data + 2, 338288748Sambrisko l_ioctl->len)) { 3383171692Savatar error = -EFAULT; 3384171692Savatar goto lock_exit; 338588748Sambrisko } 3386171692Savatar error = 0; 3387171692Savatarlock_exit: 3388171692Savatar AN_LOCK(sc); 3389171692Savatar return (error); 339088748Sambrisko} 339188748Sambrisko 339288748Sambriskostatic int 3393150446Simpwriterids(struct ifnet *ifp, struct aironet_ioctl *l_ioctl) 339488748Sambrisko{ 339588748Sambrisko struct an_softc *sc; 3396175446Sambrisko int rid, command, error; 339788748Sambrisko 339888748Sambrisko sc = ifp->if_softc; 3399175445Sambrisko AN_LOCK_ASSERT(sc); 340088748Sambrisko rid = 0; 340188748Sambrisko command = l_ioctl->command; 340288748Sambrisko 340388748Sambrisko switch (command) { 340488748Sambrisko case AIROPSIDS: 340588748Sambrisko rid = AN_RID_SSIDLIST; 340688748Sambrisko break; 340788748Sambrisko case AIROPCAP: 340888748Sambrisko rid = AN_RID_CAPABILITIES; 340988748Sambrisko break; 341088748Sambrisko case AIROPAPLIST: 341188748Sambrisko rid = AN_RID_APLIST; 341288748Sambrisko break; 341388748Sambrisko case AIROPCFG: 341488748Sambrisko rid = AN_RID_GENCONFIG; 341588748Sambrisko break; 341688748Sambrisko case AIROPMACON: 341788748Sambrisko an_cmd(sc, AN_CMD_ENABLE, 0); 341888748Sambrisko return 0; 341988748Sambrisko break; 342088748Sambrisko case AIROPMACOFF: 342188748Sambrisko an_cmd(sc, AN_CMD_DISABLE, 0); 342288748Sambrisko return 0; 342388748Sambrisko break; 342488748Sambrisko case AIROPSTCLR: 342588748Sambrisko /* 342688748Sambrisko * This command merely clears the counts does not actually 342788748Sambrisko * store any data only reads rid. But as it changes the cards 342888748Sambrisko * state, I put it in the writerid routines. 342988748Sambrisko */ 343088748Sambrisko 343188748Sambrisko rid = AN_RID_32BITS_DELTACLR; 343288748Sambrisko sc = ifp->if_softc; 343388749Sambrisko sc->areq.an_len = AN_MAX_DATALEN; 343488749Sambrisko sc->areq.an_type = rid; 343588748Sambrisko 343688749Sambrisko an_read_record(sc, (struct an_ltv_gen *)&sc->areq); 343788749Sambrisko l_ioctl->len = sc->areq.an_len - 4; /* just data */ 343888748Sambrisko 3439171692Savatar AN_UNLOCK(sc); 344088748Sambrisko /* the data contains the length at first */ 3441171692Savatar error = copyout(&(sc->areq.an_len), l_ioctl->data, 3442171692Savatar sizeof(sc->areq.an_len)); 3443171692Savatar if (error) { 3444171692Savatar AN_LOCK(sc); 344588748Sambrisko return -EFAULT; 344688748Sambrisko } 344788748Sambrisko /* Just copy the data */ 3448171692Savatar error = copyout(&(sc->areq.an_val), l_ioctl->data + 2, 3449171692Savatar l_ioctl->len); 3450171692Savatar AN_LOCK(sc); 3451171692Savatar if (error) 345288748Sambrisko return -EFAULT; 345388748Sambrisko return 0; 345488748Sambrisko break; 345588748Sambrisko case AIROPWEPKEY: 345688748Sambrisko rid = AN_RID_WEP_TEMP; 345788748Sambrisko break; 345888748Sambrisko case AIROPWEPKEYNV: 345988748Sambrisko rid = AN_RID_WEP_PERM; 346088748Sambrisko break; 346188748Sambrisko case AIROPLEAPUSR: 346288748Sambrisko rid = AN_RID_LEAPUSERNAME; 346388748Sambrisko break; 346488748Sambrisko case AIROPLEAPPWD: 346588748Sambrisko rid = AN_RID_LEAPPASSWORD; 346688748Sambrisko break; 346788748Sambrisko default: 346888748Sambrisko return -EOPNOTSUPP; 346988748Sambrisko } 347088748Sambrisko 347188748Sambrisko if (rid) { 347288749Sambrisko if (l_ioctl->len > sizeof(sc->areq.an_val) + 4) 347388748Sambrisko return -EINVAL; 347488749Sambrisko sc->areq.an_len = l_ioctl->len + 4; /* add type & length */ 347588749Sambrisko sc->areq.an_type = rid; 347688748Sambrisko 347788748Sambrisko /* Just copy the data back */ 3478171692Savatar AN_UNLOCK(sc); 3479171692Savatar error = copyin((l_ioctl->data) + 2, &sc->areq.an_val, 3480171692Savatar l_ioctl->len); 3481171692Savatar AN_LOCK(sc); 3482171692Savatar if (error) 3483144242Ssam return -EFAULT; 3484171692Savatar 348588748Sambrisko an_cmd(sc, AN_CMD_DISABLE, 0); 348688749Sambrisko an_write_record(sc, (struct an_ltv_gen *)&sc->areq); 348788748Sambrisko an_cmd(sc, AN_CMD_ENABLE, 0); 348888748Sambrisko return 0; 348988748Sambrisko } 349088748Sambrisko return -EOPNOTSUPP; 349188748Sambrisko} 349288748Sambrisko 349388748Sambrisko/* 349488748Sambrisko * General Flash utilities derived from Cisco driver additions to Ben Reed's 349588748Sambrisko * Linux driver 349688748Sambrisko */ 349788748Sambrisko 3498123978Sambrisko#define FLASH_DELAY(_sc, x) msleep(ifp, &(_sc)->an_mtx, PZERO, \ 3499123978Sambrisko "flash", ((x) / hz) + 1); 3500108401Sambrisko#define FLASH_COMMAND 0x7e7e 3501108401Sambrisko#define FLASH_SIZE 32 * 1024 350288748Sambrisko 350388748Sambriskostatic int 3504150446Simpunstickbusy(struct ifnet *ifp) 350588748Sambrisko{ 350688748Sambrisko struct an_softc *sc = ifp->if_softc; 350788748Sambrisko 3508108401Sambrisko if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY) { 3509175445Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), 3510108401Sambrisko AN_EV_CLR_STUCK_BUSY); 351188748Sambrisko return 1; 351288748Sambrisko } 351388748Sambrisko return 0; 351488748Sambrisko} 351588748Sambrisko 351688748Sambrisko/* 351788748Sambrisko * Wait for busy completion from card wait for delay uSec's Return true for 351888748Sambrisko * success meaning command reg is clear 351988748Sambrisko */ 352088748Sambrisko 352188748Sambriskostatic int 3522150446SimpWaitBusy(struct ifnet *ifp, int uSec) 352388748Sambrisko{ 3524175446Sambrisko int statword = 0xffff; 3525175446Sambrisko int delay = 0; 3526175446Sambrisko struct an_softc *sc = ifp->if_softc; 352788748Sambrisko 352888748Sambrisko while ((statword & AN_CMD_BUSY) && delay <= (1000 * 100)) { 3529119163Sambrisko FLASH_DELAY(sc, 10); 353088748Sambrisko delay += 10; 3531108401Sambrisko statword = CSR_READ_2(sc, AN_COMMAND(sc->mpi350)); 353288748Sambrisko 353388748Sambrisko if ((AN_CMD_BUSY & statword) && (delay % 200)) { 353488748Sambrisko unstickbusy(ifp); 353588748Sambrisko } 353688748Sambrisko } 353788748Sambrisko 353888748Sambrisko return 0 == (AN_CMD_BUSY & statword); 353988748Sambrisko} 354088748Sambrisko 354188748Sambrisko/* 354288748Sambrisko * STEP 1) Disable MAC and do soft reset on card. 354388748Sambrisko */ 354488748Sambrisko 354588748Sambriskostatic int 3546150446Simpcmdreset(struct ifnet *ifp) 354788748Sambrisko{ 3548175446Sambrisko int status; 3549175446Sambrisko struct an_softc *sc = ifp->if_softc; 355088748Sambrisko 3551199154Sjhb AN_LOCK(sc); 355288748Sambrisko an_stop(sc); 355388748Sambrisko 355488748Sambrisko an_cmd(sc, AN_CMD_DISABLE, 0); 355588748Sambrisko 3556108401Sambrisko if (!(status = WaitBusy(ifp, AN_TIMEOUT))) { 3557198987Sjhb if_printf(ifp, "Waitbusy hang b4 RESET =%d\n", status); 3558175445Sambrisko AN_UNLOCK(sc); 355988748Sambrisko return -EBUSY; 356088748Sambrisko } 3561108401Sambrisko CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), AN_CMD_FW_RESTART); 356288748Sambrisko 3563119163Sambrisko FLASH_DELAY(sc, 1000); /* WAS 600 12/7/00 */ 356488748Sambrisko 356588748Sambrisko 356688748Sambrisko if (!(status = WaitBusy(ifp, 100))) { 3567198987Sjhb if_printf(ifp, "Waitbusy hang AFTER RESET =%d\n", status); 3568175445Sambrisko AN_UNLOCK(sc); 356988748Sambrisko return -EBUSY; 357088748Sambrisko } 3571175445Sambrisko AN_UNLOCK(sc); 357288748Sambrisko return 0; 357388748Sambrisko} 357488748Sambrisko 357588748Sambrisko/* 357688748Sambrisko * STEP 2) Put the card in legendary flash mode 357788748Sambrisko */ 357888748Sambrisko 357988748Sambriskostatic int 3580150446Simpsetflashmode(struct ifnet *ifp) 358188748Sambrisko{ 3582175446Sambrisko int status; 3583175446Sambrisko struct an_softc *sc = ifp->if_softc; 358488748Sambrisko 3585108401Sambrisko CSR_WRITE_2(sc, AN_SW0(sc->mpi350), FLASH_COMMAND); 3586108401Sambrisko CSR_WRITE_2(sc, AN_SW1(sc->mpi350), FLASH_COMMAND); 3587108401Sambrisko CSR_WRITE_2(sc, AN_SW0(sc->mpi350), FLASH_COMMAND); 3588108401Sambrisko CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), FLASH_COMMAND); 358988748Sambrisko 359088748Sambrisko /* 359188748Sambrisko * mdelay(500); // 500ms delay 359288748Sambrisko */ 359388748Sambrisko 3594119163Sambrisko FLASH_DELAY(sc, 500); 359588748Sambrisko 3596108401Sambrisko if (!(status = WaitBusy(ifp, AN_TIMEOUT))) { 359788748Sambrisko printf("Waitbusy hang after setflash mode\n"); 359888748Sambrisko return -EIO; 359988748Sambrisko } 360088748Sambrisko return 0; 360188748Sambrisko} 360288748Sambrisko 360388748Sambrisko/* 360488748Sambrisko * Get a character from the card matching matchbyte Step 3) 360588748Sambrisko */ 360688748Sambrisko 360788748Sambriskostatic int 3608150446Simpflashgchar(struct ifnet *ifp, int matchbyte, int dwelltime) 360988748Sambrisko{ 3610175446Sambrisko int rchar; 3611175446Sambrisko unsigned char rbyte = 0; 3612175446Sambrisko int success = -1; 3613175446Sambrisko struct an_softc *sc = ifp->if_softc; 361488748Sambrisko 361588748Sambrisko 361688748Sambrisko do { 3617108401Sambrisko rchar = CSR_READ_2(sc, AN_SW1(sc->mpi350)); 361888748Sambrisko 361988748Sambrisko if (dwelltime && !(0x8000 & rchar)) { 362088748Sambrisko dwelltime -= 10; 3621119163Sambrisko FLASH_DELAY(sc, 10); 362288748Sambrisko continue; 362388748Sambrisko } 362488748Sambrisko rbyte = 0xff & rchar; 362588748Sambrisko 362688748Sambrisko if ((rbyte == matchbyte) && (0x8000 & rchar)) { 3627108401Sambrisko CSR_WRITE_2(sc, AN_SW1(sc->mpi350), 0); 362888748Sambrisko success = 1; 362988748Sambrisko break; 363088748Sambrisko } 363188748Sambrisko if (rbyte == 0x81 || rbyte == 0x82 || rbyte == 0x83 || rbyte == 0x1a || 0xffff == rchar) 363288748Sambrisko break; 3633108401Sambrisko CSR_WRITE_2(sc, AN_SW1(sc->mpi350), 0); 363488748Sambrisko 363588748Sambrisko } while (dwelltime > 0); 363688748Sambrisko return success; 363788748Sambrisko} 363888748Sambrisko 363988748Sambrisko/* 364088748Sambrisko * Put character to SWS0 wait for dwelltime x 50us for echo . 364188748Sambrisko */ 364288748Sambrisko 364388748Sambriskostatic int 3644150446Simpflashpchar(struct ifnet *ifp, int byte, int dwelltime) 364588748Sambrisko{ 3646175446Sambrisko int echo; 3647175446Sambrisko int pollbusy, waittime; 3648175446Sambrisko struct an_softc *sc = ifp->if_softc; 364988748Sambrisko 365088748Sambrisko byte |= 0x8000; 365188748Sambrisko 365288748Sambrisko if (dwelltime == 0) 365388748Sambrisko dwelltime = 200; 365488748Sambrisko 365588748Sambrisko waittime = dwelltime; 365688748Sambrisko 365788748Sambrisko /* 365888748Sambrisko * Wait for busy bit d15 to go false indicating buffer empty 365988748Sambrisko */ 366088748Sambrisko do { 3661108401Sambrisko pollbusy = CSR_READ_2(sc, AN_SW0(sc->mpi350)); 366288748Sambrisko 366388748Sambrisko if (pollbusy & 0x8000) { 3664119163Sambrisko FLASH_DELAY(sc, 50); 366588748Sambrisko waittime -= 50; 366688748Sambrisko continue; 366788748Sambrisko } else 366888748Sambrisko break; 366988748Sambrisko } 367088748Sambrisko while (waittime >= 0); 367188748Sambrisko 367288748Sambrisko /* timeout for busy clear wait */ 367388748Sambrisko 367488748Sambrisko if (waittime <= 0) { 3675198987Sjhb if_printf(ifp, "flash putchar busywait timeout!\n"); 367688748Sambrisko return -1; 367788748Sambrisko } 367888748Sambrisko /* 367988748Sambrisko * Port is clear now write byte and wait for it to echo back 368088748Sambrisko */ 368188748Sambrisko do { 3682108401Sambrisko CSR_WRITE_2(sc, AN_SW0(sc->mpi350), byte); 3683119163Sambrisko FLASH_DELAY(sc, 50); 368488748Sambrisko dwelltime -= 50; 3685108401Sambrisko echo = CSR_READ_2(sc, AN_SW1(sc->mpi350)); 368688748Sambrisko } while (dwelltime >= 0 && echo != byte); 368788748Sambrisko 368888748Sambrisko 3689108401Sambrisko CSR_WRITE_2(sc, AN_SW1(sc->mpi350), 0); 369088748Sambrisko 369188748Sambrisko return echo == byte; 369288748Sambrisko} 369388748Sambrisko 369488748Sambrisko/* 369588748Sambrisko * Transfer 32k of firmware data from user buffer to our buffer and send to 369688748Sambrisko * the card 369788748Sambrisko */ 369888748Sambrisko 369988748Sambriskostatic int 3700150446Simpflashputbuf(struct ifnet *ifp) 370188748Sambrisko{ 370288748Sambrisko unsigned short *bufp; 3703175446Sambrisko int nwords; 3704175446Sambrisko struct an_softc *sc = ifp->if_softc; 370588748Sambrisko 370688748Sambrisko /* Write stuff */ 370788748Sambrisko 3708108401Sambrisko bufp = sc->an_flash_buffer; 370988748Sambrisko 3710108401Sambrisko if (!sc->mpi350) { 3711108401Sambrisko CSR_WRITE_2(sc, AN_AUX_PAGE, 0x100); 3712108401Sambrisko CSR_WRITE_2(sc, AN_AUX_OFFSET, 0); 371388748Sambrisko 3714108401Sambrisko for (nwords = 0; nwords != FLASH_SIZE / 2; nwords++) { 3715108401Sambrisko CSR_WRITE_2(sc, AN_AUX_DATA, bufp[nwords] & 0xffff); 3716108401Sambrisko } 3717108401Sambrisko } else { 3718108401Sambrisko for (nwords = 0; nwords != FLASH_SIZE / 4; nwords++) { 3719175445Sambrisko CSR_MEM_AUX_WRITE_4(sc, 0x8000, 3720108401Sambrisko ((u_int32_t *)bufp)[nwords] & 0xffff); 3721108401Sambrisko } 372288748Sambrisko } 372388748Sambrisko 3724108401Sambrisko CSR_WRITE_2(sc, AN_SW0(sc->mpi350), 0x8000); 372588748Sambrisko 372688748Sambrisko return 0; 372788748Sambrisko} 372888748Sambrisko 372988748Sambrisko/* 373088748Sambrisko * After flashing restart the card. 373188748Sambrisko */ 373288748Sambrisko 373388748Sambriskostatic int 3734150446Simpflashrestart(struct ifnet *ifp) 373588748Sambrisko{ 3736175446Sambrisko int status = 0; 3737175446Sambrisko struct an_softc *sc = ifp->if_softc; 373888748Sambrisko 3739119163Sambrisko FLASH_DELAY(sc, 1024); /* Added 12/7/00 */ 374088748Sambrisko 3741199154Sjhb an_init_locked(sc); 374288748Sambrisko 3743119163Sambrisko FLASH_DELAY(sc, 1024); /* Added 12/7/00 */ 374488748Sambrisko return status; 374588748Sambrisko} 374688748Sambrisko 374788748Sambrisko/* 374888748Sambrisko * Entry point for flash ioclt. 374988748Sambrisko */ 375088748Sambrisko 375188748Sambriskostatic int 3752150446Simpflashcard(struct ifnet *ifp, struct aironet_ioctl *l_ioctl) 375388748Sambrisko{ 3754175446Sambrisko int z = 0, status; 375588748Sambrisko struct an_softc *sc; 375688748Sambrisko 375788748Sambrisko sc = ifp->if_softc; 3758108401Sambrisko if (sc->mpi350) { 3759198987Sjhb if_printf(ifp, "flashing not supported on MPI 350 yet\n"); 3760108401Sambrisko return(-1); 3761108401Sambrisko } 376288748Sambrisko status = l_ioctl->command; 376388748Sambrisko 376488748Sambrisko switch (l_ioctl->command) { 376588748Sambrisko case AIROFLSHRST: 376688748Sambrisko return cmdreset(ifp); 376788748Sambrisko break; 376888748Sambrisko case AIROFLSHSTFL: 3769108401Sambrisko if (sc->an_flash_buffer) { 3770108401Sambrisko free(sc->an_flash_buffer, M_DEVBUF); 3771108401Sambrisko sc->an_flash_buffer = NULL; 3772108401Sambrisko } 3773111119Simp sc->an_flash_buffer = malloc(FLASH_SIZE, M_DEVBUF, M_WAITOK); 3774108401Sambrisko if (sc->an_flash_buffer) 3775108401Sambrisko return setflashmode(ifp); 3776108401Sambrisko else 3777108401Sambrisko return ENOBUFS; 377888748Sambrisko break; 377988748Sambrisko case AIROFLSHGCHR: /* Get char from aux */ 3780171692Savatar AN_UNLOCK(sc); 3781144242Ssam status = copyin(l_ioctl->data, &sc->areq, l_ioctl->len); 3782171692Savatar AN_LOCK(sc); 3783144242Ssam if (status) 3784144242Ssam return status; 378588749Sambrisko z = *(int *)&sc->areq; 378688748Sambrisko if ((status = flashgchar(ifp, z, 8000)) == 1) 378788748Sambrisko return 0; 378888748Sambrisko else 378988748Sambrisko return -1; 379088748Sambrisko case AIROFLSHPCHR: /* Send char to card. */ 3791171692Savatar AN_UNLOCK(sc); 3792144242Ssam status = copyin(l_ioctl->data, &sc->areq, l_ioctl->len); 3793171692Savatar AN_LOCK(sc); 3794144242Ssam if (status) 3795144242Ssam return status; 379688749Sambrisko z = *(int *)&sc->areq; 379788748Sambrisko if ((status = flashpchar(ifp, z, 8000)) == -1) 379888748Sambrisko return -EIO; 379988748Sambrisko else 380088748Sambrisko return 0; 380188748Sambrisko break; 380288748Sambrisko case AIROFLPUTBUF: /* Send 32k to card */ 3803108401Sambrisko if (l_ioctl->len > FLASH_SIZE) { 3804198987Sjhb if_printf(ifp, "Buffer to big, %x %x\n", 3805108401Sambrisko l_ioctl->len, FLASH_SIZE); 380688748Sambrisko return -EINVAL; 380788748Sambrisko } 3808171692Savatar AN_UNLOCK(sc); 3809144242Ssam status = copyin(l_ioctl->data, sc->an_flash_buffer, l_ioctl->len); 3810171692Savatar AN_LOCK(sc); 3811144242Ssam if (status) 3812144242Ssam return status; 381388748Sambrisko 381488748Sambrisko if ((status = flashputbuf(ifp)) != 0) 381588748Sambrisko return -EIO; 381688748Sambrisko else 381788748Sambrisko return 0; 381888748Sambrisko break; 381988748Sambrisko case AIRORESTART: 382088748Sambrisko if ((status = flashrestart(ifp)) != 0) { 3821198987Sjhb if_printf(ifp, "FLASHRESTART returned %d\n", status); 382288748Sambrisko return -EIO; 382388748Sambrisko } else 382488748Sambrisko return 0; 382588748Sambrisko 382688748Sambrisko break; 382788748Sambrisko default: 382888748Sambrisko return -EINVAL; 382988748Sambrisko } 383088748Sambrisko 383188748Sambrisko return -EINVAL; 383288748Sambrisko} 3833