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: stable/11/sys/dev/an/if_an.c 355934 2019-12-20 16:05:29Z markj $"); 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> 114257176Sglebius#include <net/if_var.h> 11555992Swpaul#include <net/if_arp.h> 116152315Sru#include <net/if_dl.h> 11755992Swpaul#include <net/ethernet.h> 11855992Swpaul#include <net/if_types.h> 11977217Sphk#include <net/if_media.h> 12055992Swpaul 121116951Ssam#include <net80211/ieee80211_var.h> 122116951Ssam#include <net80211/ieee80211_ioctl.h> 123116951Ssam 12455992Swpaul#ifdef INET 12555992Swpaul#include <netinet/in.h> 12655992Swpaul#include <netinet/in_systm.h> 12755992Swpaul#include <netinet/in_var.h> 12855992Swpaul#include <netinet/ip.h> 12955992Swpaul#endif 13055992Swpaul 13155992Swpaul#include <net/bpf.h> 13255992Swpaul 13355992Swpaul#include <machine/md_var.h> 13455992Swpaul 13555992Swpaul#include <dev/an/if_aironet_ieee.h> 13655992Swpaul#include <dev/an/if_anreg.h> 13755992Swpaul 13855992Swpaul/* These are global because we need them in sys/pci/if_an_p.c. */ 139150446Simpstatic void an_reset(struct an_softc *); 140150446Simpstatic int an_init_mpi350_desc(struct an_softc *); 141150446Simpstatic int an_ioctl(struct ifnet *, u_long, caddr_t); 142150446Simpstatic void an_init(void *); 143199154Sjhbstatic void an_init_locked(struct an_softc *); 144150446Simpstatic int an_init_tx_ring(struct an_softc *); 145150446Simpstatic void an_start(struct ifnet *); 146199154Sjhbstatic void an_start_locked(struct ifnet *); 147199154Sjhbstatic void an_watchdog(struct an_softc *); 148150446Simpstatic void an_rxeof(struct an_softc *); 149150446Simpstatic void an_txeof(struct an_softc *, int); 15055992Swpaul 151150446Simpstatic void an_promisc(struct an_softc *, int); 152150446Simpstatic int an_cmd(struct an_softc *, int, int); 153150446Simpstatic int an_cmd_struct(struct an_softc *, struct an_command *, 154150446Simp struct an_reply *); 155150446Simpstatic int an_read_record(struct an_softc *, struct an_ltv_gen *); 156150446Simpstatic int an_write_record(struct an_softc *, struct an_ltv_gen *); 157150446Simpstatic int an_read_data(struct an_softc *, int, int, caddr_t, int); 158150446Simpstatic int an_write_data(struct an_softc *, int, int, caddr_t, int); 159150446Simpstatic int an_seek(struct an_softc *, int, int, int); 160150446Simpstatic int an_alloc_nicmem(struct an_softc *, int, int *); 161150446Simpstatic int an_dma_malloc(struct an_softc *, bus_size_t, struct an_dma_alloc *, 162150446Simp int); 163150446Simpstatic void an_dma_free(struct an_softc *, struct an_dma_alloc *); 164150446Simpstatic void an_dma_malloc_cb(void *, bus_dma_segment_t *, int, int); 165150446Simpstatic void an_stats_update(void *); 166150446Simpstatic void an_setdef(struct an_softc *, struct an_req *); 16755992Swpaul#ifdef ANCACHE 168150446Simpstatic void an_cache_store(struct an_softc *, struct ether_header *, 169150446Simp struct mbuf *, u_int8_t, u_int8_t); 17055992Swpaul#endif 17155992Swpaul 17288748Sambrisko/* function definitions for use with the Cisco's Linux configuration 17388748Sambrisko utilities 17488748Sambrisko*/ 17588748Sambrisko 17692739Salfredstatic int readrids(struct ifnet*, struct aironet_ioctl*); 17792739Salfredstatic int writerids(struct ifnet*, struct aironet_ioctl*); 17892739Salfredstatic int flashcard(struct ifnet*, struct aironet_ioctl*); 17988748Sambrisko 18092739Salfredstatic int cmdreset(struct ifnet *); 18192739Salfredstatic int setflashmode(struct ifnet *); 18292739Salfredstatic int flashgchar(struct ifnet *,int,int); 18392739Salfredstatic int flashpchar(struct ifnet *,int,int); 18492739Salfredstatic int flashputbuf(struct ifnet *); 18592739Salfredstatic int flashrestart(struct ifnet *); 18692739Salfredstatic int WaitBusy(struct ifnet *, int); 18792739Salfredstatic int unstickbusy(struct ifnet *); 18888748Sambrisko 18992739Salfredstatic void an_dump_record (struct an_softc *,struct an_ltv_gen *, 19092739Salfred char *); 19178639Sbrooks 19292739Salfredstatic int an_media_change (struct ifnet *); 19392739Salfredstatic void an_media_status (struct ifnet *, struct ifmediareq *); 19477217Sphk 19578639Sbrooksstatic int an_dump = 0; 196108401Sambriskostatic int an_cache_mode = 0; 19788748Sambrisko 198108401Sambrisko#define DBM 0 199108401Sambrisko#define PERCENT 1 200108401Sambrisko#define RAW 2 201108401Sambrisko 20283269Sbrooksstatic char an_conf[256]; 203108401Sambriskostatic char an_conf_cache[256]; 20483269Sbrooks 20583269Sbrooks/* sysctl vars */ 206108401Sambrisko 207227309Sedstatic SYSCTL_NODE(_hw, OID_AUTO, an, CTLFLAG_RD, 0, 208227309Sed "Wireless driver parameters"); 20983269Sbrooks 210106937Ssam/* XXX violate ethernet/netgraph callback hooks */ 211106937Ssamextern void (*ng_ether_attach_p)(struct ifnet *ifp); 212106937Ssamextern void (*ng_ether_detach_p)(struct ifnet *ifp); 213106937Ssam 21483269Sbrooksstatic int 21583269Sbrookssysctl_an_dump(SYSCTL_HANDLER_ARGS) 21683269Sbrooks{ 21783269Sbrooks int error, r, last; 21883269Sbrooks char *s = an_conf; 21983270Sbrooks 22083269Sbrooks last = an_dump; 22183269Sbrooks 22283270Sbrooks switch (an_dump) { 22383269Sbrooks case 0: 224108401Sambrisko strcpy(an_conf, "off"); 22583269Sbrooks break; 22683269Sbrooks case 1: 227108401Sambrisko strcpy(an_conf, "type"); 22883269Sbrooks break; 22983269Sbrooks case 2: 230108401Sambrisko strcpy(an_conf, "dump"); 23183269Sbrooks break; 23283269Sbrooks default: 23383269Sbrooks snprintf(an_conf, 5, "%x", an_dump); 23483269Sbrooks break; 23583269Sbrooks } 23683269Sbrooks 23783269Sbrooks error = sysctl_handle_string(oidp, an_conf, sizeof(an_conf), req); 23883269Sbrooks 239108401Sambrisko if (strncmp(an_conf,"off", 3) == 0) { 24083269Sbrooks an_dump = 0; 24183269Sbrooks } 24283270Sbrooks if (strncmp(an_conf,"dump", 4) == 0) { 24383269Sbrooks an_dump = 1; 24483269Sbrooks } 24583270Sbrooks if (strncmp(an_conf,"type", 4) == 0) { 24683269Sbrooks an_dump = 2; 24783269Sbrooks } 24883270Sbrooks if (*s == 'f') { 24983269Sbrooks r = 0; 25083270Sbrooks for (;;s++) { 25183270Sbrooks if ((*s >= '0') && (*s <= '9')) { 25283269Sbrooks r = r * 16 + (*s - '0'); 25383270Sbrooks } else if ((*s >= 'a') && (*s <= 'f')) { 25483269Sbrooks r = r * 16 + (*s - 'a' + 10); 25583270Sbrooks } else { 25683270Sbrooks break; 25783269Sbrooks } 25883269Sbrooks } 25983269Sbrooks an_dump = r; 26083269Sbrooks } 26183269Sbrooks if (an_dump != last) 26283269Sbrooks printf("Sysctl changed for Aironet driver\n"); 26383269Sbrooks 26483269Sbrooks return error; 26583269Sbrooks} 26683269Sbrooks 267110531SambriskoSYSCTL_PROC(_hw_an, OID_AUTO, an_dump, CTLTYPE_STRING | CTLFLAG_RW, 268175446Sambrisko 0, sizeof(an_conf), sysctl_an_dump, "A", ""); 26983269Sbrooks 270108401Sambriskostatic int 271108401Sambriskosysctl_an_cache_mode(SYSCTL_HANDLER_ARGS) 272108401Sambrisko{ 273269712Simp int error; 274108401Sambrisko 275108401Sambrisko switch (an_cache_mode) { 276108401Sambrisko case 1: 277108401Sambrisko strcpy(an_conf_cache, "per"); 278108401Sambrisko break; 279108401Sambrisko case 2: 280108401Sambrisko strcpy(an_conf_cache, "raw"); 281108401Sambrisko break; 282108401Sambrisko default: 283108401Sambrisko strcpy(an_conf_cache, "dbm"); 284108401Sambrisko break; 285108401Sambrisko } 286108401Sambrisko 287175445Sambrisko error = sysctl_handle_string(oidp, an_conf_cache, 288108401Sambrisko sizeof(an_conf_cache), req); 289108401Sambrisko 290108401Sambrisko if (strncmp(an_conf_cache,"dbm", 3) == 0) { 291108401Sambrisko an_cache_mode = 0; 292108401Sambrisko } 293108401Sambrisko if (strncmp(an_conf_cache,"per", 3) == 0) { 294108401Sambrisko an_cache_mode = 1; 295108401Sambrisko } 296108401Sambrisko if (strncmp(an_conf_cache,"raw", 3) == 0) { 297108401Sambrisko an_cache_mode = 2; 298108401Sambrisko } 299108401Sambrisko 300108401Sambrisko return error; 301108401Sambrisko} 302108401Sambrisko 303110531SambriskoSYSCTL_PROC(_hw_an, OID_AUTO, an_cache_mode, CTLTYPE_STRING | CTLFLAG_RW, 304175446Sambrisko 0, sizeof(an_conf_cache), sysctl_an_cache_mode, "A", ""); 305108401Sambrisko 30683270Sbrooks/* 30755992Swpaul * We probe for an Aironet 4500/4800 card by attempting to 30855992Swpaul * read the default SSID list. On reset, the first entry in 30955992Swpaul * the SSID list will contain the name "tsunami." If we don't 31055992Swpaul * find this, then there's no card present. 31155992Swpaul */ 31283270Sbrooksint 313150446Simpan_probe(device_t dev) 31455992Swpaul{ 315175446Sambrisko struct an_softc *sc = device_get_softc(dev); 316119156Sambrisko struct an_ltv_ssidlist_new ssid; 31755992Swpaul int error; 31855992Swpaul 31955992Swpaul bzero((char *)&ssid, sizeof(ssid)); 32055992Swpaul 32155992Swpaul error = an_alloc_port(dev, 0, AN_IOSIZ); 32278639Sbrooks if (error != 0) 32355992Swpaul return (0); 32455992Swpaul 32555992Swpaul /* can't do autoprobing */ 32655992Swpaul if (rman_get_start(sc->port_res) == -1) 32755992Swpaul return(0); 32855992Swpaul 32955992Swpaul /* 33055992Swpaul * We need to fake up a softc structure long enough 33155992Swpaul * to be able to issue commands and call some of the 33255992Swpaul * other routines. 33355992Swpaul */ 33455992Swpaul ssid.an_len = sizeof(ssid); 33555992Swpaul ssid.an_type = AN_RID_SSIDLIST; 33655992Swpaul 337175446Sambrisko /* Make sure interrupts are disabled. */ 338119156Sambrisko sc->mpi350 = 0; 339175446Sambrisko CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0); 340175446Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), 0xFFFF); 34155992Swpaul 342259393Sgavin sc->an_dev = dev; 343175445Sambrisko mtx_init(&sc->an_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 344199154Sjhb MTX_DEF); 345175445Sambrisko AN_LOCK(sc); 34655992Swpaul an_reset(sc); 34755992Swpaul 348175445Sambrisko if (an_cmd(sc, AN_CMD_READCFG, 0)) { 349175445Sambrisko AN_UNLOCK(sc); 350175445Sambrisko goto fail; 351175445Sambrisko } 35255992Swpaul 353175445Sambrisko if (an_read_record(sc, (struct an_ltv_gen *)&ssid)) { 354175445Sambrisko AN_UNLOCK(sc); 355175445Sambrisko goto fail; 356175445Sambrisko } 35755992Swpaul 35868692Swpaul /* See if the ssid matches what we expect ... but doesn't have to */ 359175445Sambrisko if (strcmp(ssid.an_entry[0].an_ssid, AN_DEF_SSID)) { 360175445Sambrisko AN_UNLOCK(sc); 361175445Sambrisko goto fail; 362175445Sambrisko } 36383270Sbrooks 364175445Sambrisko AN_UNLOCK(sc); 36555992Swpaul return(AN_IOSIZ); 366175445Sambriskofail: 367175445Sambrisko mtx_destroy(&sc->an_mtx); 368175445Sambrisko return(0); 36955992Swpaul} 37055992Swpaul 37155992Swpaul/* 37255992Swpaul * Allocate a port resource with the given resource id. 37355992Swpaul */ 37455992Swpaulint 375150446Simpan_alloc_port(device_t dev, int rid, int size) 37655992Swpaul{ 37755992Swpaul struct an_softc *sc = device_get_softc(dev); 37855992Swpaul struct resource *res; 37955992Swpaul 380296137Sjhibbits res = bus_alloc_resource_anywhere(dev, SYS_RES_IOPORT, &rid, 381296137Sjhibbits size, RF_ACTIVE); 38255992Swpaul if (res) { 38355992Swpaul sc->port_rid = rid; 38455992Swpaul sc->port_res = res; 38555992Swpaul return (0); 38655992Swpaul } else { 38755992Swpaul return (ENOENT); 38855992Swpaul } 38955992Swpaul} 39055992Swpaul 39155992Swpaul/* 392108401Sambrisko * Allocate a memory resource with the given resource id. 393108401Sambrisko */ 394108401Sambriskoint an_alloc_memory(device_t dev, int rid, int size) 395108401Sambrisko{ 396108401Sambrisko struct an_softc *sc = device_get_softc(dev); 397108401Sambrisko struct resource *res; 398108401Sambrisko 399296137Sjhibbits res = bus_alloc_resource_anywhere(dev, SYS_RES_MEMORY, &rid, 400296137Sjhibbits size, RF_ACTIVE); 401108401Sambrisko if (res) { 402108401Sambrisko sc->mem_rid = rid; 403108401Sambrisko sc->mem_res = res; 404108401Sambrisko sc->mem_used = size; 405108401Sambrisko return (0); 406108401Sambrisko } else { 407108401Sambrisko return (ENOENT); 408108401Sambrisko } 409108401Sambrisko} 410108401Sambrisko 411108401Sambrisko/* 412298955Spfg * Allocate a auxiliary memory resource with the given resource id. 413108401Sambrisko */ 414108401Sambriskoint an_alloc_aux_memory(device_t dev, int rid, int size) 415108401Sambrisko{ 416108401Sambrisko struct an_softc *sc = device_get_softc(dev); 417108401Sambrisko struct resource *res; 418108401Sambrisko 419296137Sjhibbits res = bus_alloc_resource_anywhere(dev, SYS_RES_MEMORY, &rid, 420296137Sjhibbits size, RF_ACTIVE); 421108401Sambrisko if (res) { 422108401Sambrisko sc->mem_aux_rid = rid; 423108401Sambrisko sc->mem_aux_res = res; 424108401Sambrisko sc->mem_aux_used = size; 425108401Sambrisko return (0); 426108401Sambrisko } else { 427108401Sambrisko return (ENOENT); 428108401Sambrisko } 429108401Sambrisko} 430108401Sambrisko 431108401Sambrisko/* 43255992Swpaul * Allocate an irq resource with the given resource id. 43355992Swpaul */ 43455992Swpaulint 435150446Simpan_alloc_irq(device_t dev, int rid, int flags) 43655992Swpaul{ 43755992Swpaul struct an_softc *sc = device_get_softc(dev); 43855992Swpaul struct resource *res; 43955992Swpaul 440127135Snjl res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 441127135Snjl (RF_ACTIVE | flags)); 44255992Swpaul if (res) { 44355992Swpaul sc->irq_rid = rid; 44455992Swpaul sc->irq_res = res; 44555992Swpaul return (0); 44655992Swpaul } else { 44755992Swpaul return (ENOENT); 44855992Swpaul } 44955992Swpaul} 45055992Swpaul 451108401Sambriskostatic void 452150446Simpan_dma_malloc_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) 453108401Sambrisko{ 454108401Sambrisko bus_addr_t *paddr = (bus_addr_t*) arg; 455108401Sambrisko *paddr = segs->ds_addr; 456108401Sambrisko} 457108401Sambrisko 45855992Swpaul/* 459108401Sambrisko * Alloc DMA memory and set the pointer to it 460108401Sambrisko */ 461108401Sambriskostatic int 462150446Simpan_dma_malloc(struct an_softc *sc, bus_size_t size, struct an_dma_alloc *dma, 463150446Simp int mapflags) 464108401Sambrisko{ 465108401Sambrisko int r; 466108401Sambrisko 467108401Sambrisko r = bus_dmamem_alloc(sc->an_dtag, (void**) &dma->an_dma_vaddr, 468108401Sambrisko BUS_DMA_NOWAIT, &dma->an_dma_map); 469108401Sambrisko if (r != 0) 470108401Sambrisko goto fail_1; 471108401Sambrisko 472108401Sambrisko r = bus_dmamap_load(sc->an_dtag, dma->an_dma_map, dma->an_dma_vaddr, 473175446Sambrisko size, 474108401Sambrisko an_dma_malloc_cb, 475108401Sambrisko &dma->an_dma_paddr, 476108401Sambrisko mapflags | BUS_DMA_NOWAIT); 477108401Sambrisko if (r != 0) 478108401Sambrisko goto fail_2; 479108401Sambrisko 480108401Sambrisko dma->an_dma_size = size; 481108401Sambrisko return (0); 482108401Sambrisko 483108401Sambriskofail_2: 484108401Sambrisko bus_dmamap_unload(sc->an_dtag, dma->an_dma_map); 485108401Sambriskofail_1: 486108401Sambrisko bus_dmamem_free(sc->an_dtag, dma->an_dma_vaddr, dma->an_dma_map); 487108401Sambrisko return (r); 488108401Sambrisko} 489108401Sambrisko 490108401Sambriskostatic void 491150446Simpan_dma_free(struct an_softc *sc, struct an_dma_alloc *dma) 492108401Sambrisko{ 493108401Sambrisko bus_dmamap_unload(sc->an_dtag, dma->an_dma_map); 494108401Sambrisko bus_dmamem_free(sc->an_dtag, dma->an_dma_vaddr, dma->an_dma_map); 495123978Sambrisko dma->an_dma_vaddr = 0; 496108401Sambrisko} 497108401Sambrisko 498108401Sambrisko/* 49955992Swpaul * Release all resources 50055992Swpaul */ 50155992Swpaulvoid 502150446Simpan_release_resources(device_t dev) 50355992Swpaul{ 50455992Swpaul struct an_softc *sc = device_get_softc(dev); 505108401Sambrisko int i; 50655992Swpaul 50755992Swpaul if (sc->port_res) { 50855992Swpaul bus_release_resource(dev, SYS_RES_IOPORT, 50955992Swpaul sc->port_rid, sc->port_res); 51055992Swpaul sc->port_res = 0; 51155992Swpaul } 512108401Sambrisko if (sc->mem_res) { 513108401Sambrisko bus_release_resource(dev, SYS_RES_MEMORY, 514108401Sambrisko sc->mem_rid, sc->mem_res); 515108401Sambrisko sc->mem_res = 0; 516108401Sambrisko } 517108401Sambrisko if (sc->mem_aux_res) { 518108401Sambrisko bus_release_resource(dev, SYS_RES_MEMORY, 519108401Sambrisko sc->mem_aux_rid, sc->mem_aux_res); 520108401Sambrisko sc->mem_aux_res = 0; 521108401Sambrisko } 52255992Swpaul if (sc->irq_res) { 52355992Swpaul bus_release_resource(dev, SYS_RES_IRQ, 52455992Swpaul sc->irq_rid, sc->irq_res); 52555992Swpaul sc->irq_res = 0; 52655992Swpaul } 527108401Sambrisko if (sc->an_rid_buffer.an_dma_paddr) { 528108401Sambrisko an_dma_free(sc, &sc->an_rid_buffer); 529108401Sambrisko } 530108401Sambrisko for (i = 0; i < AN_MAX_RX_DESC; i++) 531108401Sambrisko if (sc->an_rx_buffer[i].an_dma_paddr) { 532108401Sambrisko an_dma_free(sc, &sc->an_rx_buffer[i]); 533108401Sambrisko } 534108401Sambrisko for (i = 0; i < AN_MAX_TX_DESC; i++) 535108401Sambrisko if (sc->an_tx_buffer[i].an_dma_paddr) { 536108401Sambrisko an_dma_free(sc, &sc->an_tx_buffer[i]); 537108401Sambrisko } 538108401Sambrisko if (sc->an_dtag) { 539108401Sambrisko bus_dma_tag_destroy(sc->an_dtag); 540108401Sambrisko } 541108401Sambrisko 54255992Swpaul} 54355992Swpaul 54483270Sbrooksint 545150446Simpan_init_mpi350_desc(struct an_softc *sc) 546108401Sambrisko{ 547108401Sambrisko struct an_command cmd_struct; 548108401Sambrisko struct an_reply reply; 549108401Sambrisko struct an_card_rid_desc an_rid_desc; 550108401Sambrisko struct an_card_rx_desc an_rx_desc; 551108401Sambrisko struct an_card_tx_desc an_tx_desc; 552108401Sambrisko int i, desc; 553108401Sambrisko 554175445Sambrisko AN_LOCK_ASSERT(sc); 555108401Sambrisko if(!sc->an_rid_buffer.an_dma_paddr) 556108401Sambrisko an_dma_malloc(sc, AN_RID_BUFFER_SIZE, 557108401Sambrisko &sc->an_rid_buffer, 0); 558108401Sambrisko for (i = 0; i < AN_MAX_RX_DESC; i++) 559108401Sambrisko if(!sc->an_rx_buffer[i].an_dma_paddr) 560108401Sambrisko an_dma_malloc(sc, AN_RX_BUFFER_SIZE, 561108401Sambrisko &sc->an_rx_buffer[i], 0); 562108401Sambrisko for (i = 0; i < AN_MAX_TX_DESC; i++) 563108401Sambrisko if(!sc->an_tx_buffer[i].an_dma_paddr) 564108401Sambrisko an_dma_malloc(sc, AN_TX_BUFFER_SIZE, 565108401Sambrisko &sc->an_tx_buffer[i], 0); 566108401Sambrisko 567108401Sambrisko /* 568108401Sambrisko * Allocate RX descriptor 569108401Sambrisko */ 570108401Sambrisko bzero(&reply,sizeof(reply)); 571108401Sambrisko cmd_struct.an_cmd = AN_CMD_ALLOC_DESC; 572108401Sambrisko cmd_struct.an_parm0 = AN_DESCRIPTOR_RX; 573108401Sambrisko cmd_struct.an_parm1 = AN_RX_DESC_OFFSET; 574108401Sambrisko cmd_struct.an_parm2 = AN_MAX_RX_DESC; 575108401Sambrisko if (an_cmd_struct(sc, &cmd_struct, &reply)) { 576198987Sjhb if_printf(sc->an_ifp, "failed to allocate RX descriptor\n"); 577108401Sambrisko return(EIO); 578108401Sambrisko } 579108401Sambrisko 580108401Sambrisko for (desc = 0; desc < AN_MAX_RX_DESC; desc++) { 581108401Sambrisko bzero(&an_rx_desc, sizeof(an_rx_desc)); 582108401Sambrisko an_rx_desc.an_valid = 1; 583108401Sambrisko an_rx_desc.an_len = AN_RX_BUFFER_SIZE; 584108401Sambrisko an_rx_desc.an_done = 0; 585108401Sambrisko an_rx_desc.an_phys = sc->an_rx_buffer[desc].an_dma_paddr; 586108401Sambrisko 587108401Sambrisko for (i = 0; i < sizeof(an_rx_desc) / 4; i++) 588155321Simp CSR_MEM_AUX_WRITE_4(sc, AN_RX_DESC_OFFSET 589155321Simp + (desc * sizeof(an_rx_desc)) 590155321Simp + (i * 4), 591155321Simp ((u_int32_t *)(void *)&an_rx_desc)[i]); 592108401Sambrisko } 593108401Sambrisko 594108401Sambrisko /* 595108401Sambrisko * Allocate TX descriptor 596108401Sambrisko */ 597108401Sambrisko 598108401Sambrisko bzero(&reply,sizeof(reply)); 599108401Sambrisko cmd_struct.an_cmd = AN_CMD_ALLOC_DESC; 600108401Sambrisko cmd_struct.an_parm0 = AN_DESCRIPTOR_TX; 601108401Sambrisko cmd_struct.an_parm1 = AN_TX_DESC_OFFSET; 602108401Sambrisko cmd_struct.an_parm2 = AN_MAX_TX_DESC; 603108401Sambrisko if (an_cmd_struct(sc, &cmd_struct, &reply)) { 604198987Sjhb if_printf(sc->an_ifp, "failed to allocate TX descriptor\n"); 605108401Sambrisko return(EIO); 606108401Sambrisko } 607108401Sambrisko 608108401Sambrisko for (desc = 0; desc < AN_MAX_TX_DESC; desc++) { 609108401Sambrisko bzero(&an_tx_desc, sizeof(an_tx_desc)); 610108401Sambrisko an_tx_desc.an_offset = 0; 611108401Sambrisko an_tx_desc.an_eoc = 0; 612108401Sambrisko an_tx_desc.an_valid = 0; 613108401Sambrisko an_tx_desc.an_len = 0; 614108401Sambrisko an_tx_desc.an_phys = sc->an_tx_buffer[desc].an_dma_paddr; 615108401Sambrisko 616108401Sambrisko for (i = 0; i < sizeof(an_tx_desc) / 4; i++) 617108401Sambrisko CSR_MEM_AUX_WRITE_4(sc, AN_TX_DESC_OFFSET 618155321Simp + (desc * sizeof(an_tx_desc)) 619155321Simp + (i * 4), 620155321Simp ((u_int32_t *)(void *)&an_tx_desc)[i]); 621108401Sambrisko } 622108401Sambrisko 623108401Sambrisko /* 624108401Sambrisko * Allocate RID descriptor 625108401Sambrisko */ 626108401Sambrisko 627108401Sambrisko bzero(&reply,sizeof(reply)); 628108401Sambrisko cmd_struct.an_cmd = AN_CMD_ALLOC_DESC; 629108401Sambrisko cmd_struct.an_parm0 = AN_DESCRIPTOR_HOSTRW; 630108401Sambrisko cmd_struct.an_parm1 = AN_HOST_DESC_OFFSET; 631108401Sambrisko cmd_struct.an_parm2 = 1; 632108401Sambrisko if (an_cmd_struct(sc, &cmd_struct, &reply)) { 633198987Sjhb if_printf(sc->an_ifp, "failed to allocate host descriptor\n"); 634108401Sambrisko return(EIO); 635108401Sambrisko } 636108401Sambrisko 637108401Sambrisko bzero(&an_rid_desc, sizeof(an_rid_desc)); 638108401Sambrisko an_rid_desc.an_valid = 1; 639108401Sambrisko an_rid_desc.an_len = AN_RID_BUFFER_SIZE; 640108401Sambrisko an_rid_desc.an_rid = 0; 641108401Sambrisko an_rid_desc.an_phys = sc->an_rid_buffer.an_dma_paddr; 642108401Sambrisko 643108401Sambrisko for (i = 0; i < sizeof(an_rid_desc) / 4; i++) 644175445Sambrisko CSR_MEM_AUX_WRITE_4(sc, AN_HOST_DESC_OFFSET + i * 4, 645155321Simp ((u_int32_t *)(void *)&an_rid_desc)[i]); 646108401Sambrisko 647108401Sambrisko return(0); 648108401Sambrisko} 649108401Sambrisko 650108401Sambriskoint 651198995Sjhban_attach(struct an_softc *sc, int flags) 65255992Swpaul{ 653147256Sbrooks struct ifnet *ifp; 654113316Simp int error = EIO; 655110253Sambrisko int i, nrate, mword; 656110253Sambrisko u_int8_t r; 65755992Swpaul 658147380Sdelphij ifp = sc->an_ifp = if_alloc(IFT_ETHER); 659147256Sbrooks if (ifp == NULL) { 660198987Sjhb device_printf(sc->an_dev, "can not if_alloc()\n"); 661147256Sbrooks goto fail; 662147256Sbrooks } 663259393Sgavin ifp->if_softc = sc; 664259393Sgavin if_initname(ifp, device_get_name(sc->an_dev), 665259393Sgavin device_get_unit(sc->an_dev)); 666175445Sambrisko 66755992Swpaul sc->an_gone = 0; 66855992Swpaul sc->an_associated = 0; 66983269Sbrooks sc->an_monitor = 0; 67083269Sbrooks sc->an_was_monitor = 0; 671108401Sambrisko sc->an_flash_buffer = NULL; 67255992Swpaul 67355992Swpaul /* Reset the NIC. */ 674175445Sambrisko AN_LOCK(sc); 67555992Swpaul an_reset(sc); 676110104Sambrisko if (sc->mpi350) { 677108401Sambrisko error = an_init_mpi350_desc(sc); 678108401Sambrisko if (error) 679113316Simp goto fail; 680108401Sambrisko } 68155992Swpaul 68255992Swpaul /* Load factory config */ 68355992Swpaul if (an_cmd(sc, AN_CMD_READCFG, 0)) { 684198987Sjhb device_printf(sc->an_dev, "failed to load config data\n"); 685113316Simp goto fail; 68655992Swpaul } 68755992Swpaul 68855992Swpaul /* Read the current configuration */ 68955992Swpaul sc->an_config.an_type = AN_RID_GENCONFIG; 69055992Swpaul sc->an_config.an_len = sizeof(struct an_ltv_genconfig); 69155992Swpaul if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_config)) { 692198987Sjhb device_printf(sc->an_dev, "read record failed\n"); 693113316Simp goto fail; 69455992Swpaul } 69555992Swpaul 69655992Swpaul /* Read the card capabilities */ 69755992Swpaul sc->an_caps.an_type = AN_RID_CAPABILITIES; 69855992Swpaul sc->an_caps.an_len = sizeof(struct an_ltv_caps); 69955992Swpaul if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_caps)) { 700198987Sjhb device_printf(sc->an_dev, "read record failed\n"); 701113316Simp goto fail; 70255992Swpaul } 70355992Swpaul 70455992Swpaul /* Read ssid list */ 70555992Swpaul sc->an_ssidlist.an_type = AN_RID_SSIDLIST; 706119156Sambrisko sc->an_ssidlist.an_len = sizeof(struct an_ltv_ssidlist_new); 70755992Swpaul if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_ssidlist)) { 708198987Sjhb device_printf(sc->an_dev, "read record failed\n"); 709113316Simp goto fail; 71055992Swpaul } 71155992Swpaul 71255992Swpaul /* Read AP list */ 71355992Swpaul sc->an_aplist.an_type = AN_RID_APLIST; 71455992Swpaul sc->an_aplist.an_len = sizeof(struct an_ltv_aplist); 71555992Swpaul if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_aplist)) { 716198987Sjhb device_printf(sc->an_dev, "read record failed\n"); 717113316Simp goto fail; 71855992Swpaul } 71955992Swpaul 720108401Sambrisko#ifdef ANCACHE 721108401Sambrisko /* Read the RSSI <-> dBm map */ 722108401Sambrisko sc->an_have_rssimap = 0; 723108401Sambrisko if (sc->an_caps.an_softcaps & 8) { 724108401Sambrisko sc->an_rssimap.an_type = AN_RID_RSSI_MAP; 725108401Sambrisko sc->an_rssimap.an_len = sizeof(struct an_ltv_rssi_map); 726108401Sambrisko if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_rssimap)) { 727198987Sjhb device_printf(sc->an_dev, 728198987Sjhb "unable to get RSSI <-> dBM map\n"); 729108401Sambrisko } else { 730198987Sjhb device_printf(sc->an_dev, "got RSSI <-> dBM map\n"); 731108401Sambrisko sc->an_have_rssimap = 1; 732108401Sambrisko } 733108401Sambrisko } else { 734198987Sjhb device_printf(sc->an_dev, "no RSSI <-> dBM map\n"); 735108401Sambrisko } 736108401Sambrisko#endif 737175445Sambrisko AN_UNLOCK(sc); 738108401Sambrisko 73955992Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 74055992Swpaul ifp->if_ioctl = an_ioctl; 74155992Swpaul ifp->if_start = an_start; 74255992Swpaul ifp->if_init = an_init; 74355992Swpaul ifp->if_baudrate = 10000000; 744207554Ssobomax IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 745207554Ssobomax ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; 746132986Smlaier IFQ_SET_READY(&ifp->if_snd); 74755992Swpaul 74855992Swpaul bzero(sc->an_config.an_nodename, sizeof(sc->an_config.an_nodename)); 74955992Swpaul bcopy(AN_DEFAULT_NODENAME, sc->an_config.an_nodename, 75055992Swpaul sizeof(AN_DEFAULT_NODENAME) - 1); 75155992Swpaul 752119156Sambrisko bzero(sc->an_ssidlist.an_entry[0].an_ssid, 753119156Sambrisko sizeof(sc->an_ssidlist.an_entry[0].an_ssid)); 754119156Sambrisko bcopy(AN_DEFAULT_NETNAME, sc->an_ssidlist.an_entry[0].an_ssid, 75555992Swpaul sizeof(AN_DEFAULT_NETNAME) - 1); 756119156Sambrisko sc->an_ssidlist.an_entry[0].an_len = strlen(AN_DEFAULT_NETNAME); 75755992Swpaul 75855992Swpaul sc->an_config.an_opmode = 75974144Sassar AN_OPMODE_INFRASTRUCTURE_STATION; 76055992Swpaul 76155992Swpaul sc->an_tx_rate = 0; 76255992Swpaul bzero((char *)&sc->an_stats, sizeof(sc->an_stats)); 76355992Swpaul 764110253Sambrisko nrate = 8; 765110253Sambrisko 76677217Sphk ifmedia_init(&sc->an_ifmedia, 0, an_media_change, an_media_status); 767110253Sambrisko if_printf(ifp, "supported rates: "); 768110253Sambrisko#define ADD(s, o) ifmedia_add(&sc->an_ifmedia, \ 769110253Sambrisko IFM_MAKEWORD(IFM_IEEE80211, (s), (o), 0), 0, NULL) 770110253Sambrisko ADD(IFM_AUTO, 0); 771110253Sambrisko ADD(IFM_AUTO, IFM_IEEE80211_ADHOC); 772110253Sambrisko for (i = 0; i < nrate; i++) { 773110253Sambrisko r = sc->an_caps.an_rates[i]; 774228621Sbschmidt mword = ieee80211_rate2media(NULL, r, IEEE80211_MODE_AUTO); 775110253Sambrisko if (mword == 0) 776110253Sambrisko continue; 777110253Sambrisko printf("%s%d%sMbps", (i != 0 ? " " : ""), 778110253Sambrisko (r & IEEE80211_RATE_VAL) / 2, ((r & 0x1) != 0 ? ".5" : "")); 779110253Sambrisko ADD(mword, 0); 780110253Sambrisko ADD(mword, IFM_IEEE80211_ADHOC); 78177217Sphk } 782110253Sambrisko printf("\n"); 783175445Sambrisko ifmedia_set(&sc->an_ifmedia, IFM_MAKEWORD(IFM_IEEE80211, 784110253Sambrisko IFM_AUTO, 0, 0)); 785110253Sambrisko#undef ADD 78677217Sphk 78755992Swpaul /* 78863090Sarchie * Call MI attach routine. 78955992Swpaul */ 790147256Sbrooks 791147256Sbrooks ether_ifattach(ifp, sc->an_caps.an_oemaddr); 792173668Savatar callout_init_mtx(&sc->an_stat_ch, &sc->an_mtx, 0); 79355992Swpaul 79455992Swpaul return(0); 795175445Sambriskofail: 796175445Sambrisko AN_UNLOCK(sc); 797113316Simp mtx_destroy(&sc->an_mtx); 798147256Sbrooks if (ifp != NULL) 799147256Sbrooks if_free(ifp); 800113316Simp return(error); 80155992Swpaul} 80255992Swpaul 803123978Sambriskoint 804123978Sambriskoan_detach(device_t dev) 805123978Sambrisko{ 806123978Sambrisko struct an_softc *sc = device_get_softc(dev); 807147256Sbrooks struct ifnet *ifp = sc->an_ifp; 808123978Sambrisko 809123978Sambrisko if (sc->an_gone) { 810123978Sambrisko device_printf(dev,"already unloaded\n"); 811123978Sambrisko return(0); 812123978Sambrisko } 813148639Semax AN_LOCK(sc); 814123978Sambrisko an_stop(sc); 815148454Semax sc->an_gone = 1; 816123978Sambrisko ifmedia_removeall(&sc->an_ifmedia); 817148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 818148454Semax AN_UNLOCK(sc); 819123978Sambrisko ether_ifdetach(ifp); 820150306Simp bus_teardown_intr(dev, sc->irq_res, sc->irq_handle); 821173668Savatar callout_drain(&sc->an_stat_ch); 822147256Sbrooks if_free(ifp); 823123978Sambrisko an_release_resources(dev); 824123978Sambrisko mtx_destroy(&sc->an_mtx); 825123978Sambrisko return (0); 826123978Sambrisko} 827123978Sambrisko 82883270Sbrooksstatic void 829150446Simpan_rxeof(struct an_softc *sc) 83055992Swpaul{ 83183269Sbrooks struct ifnet *ifp; 83283269Sbrooks struct ether_header *eh; 83383269Sbrooks struct ieee80211_frame *ih; 83483269Sbrooks struct an_rxframe rx_frame; 83583269Sbrooks struct an_rxframe_802_3 rx_frame_802_3; 83683269Sbrooks struct mbuf *m; 837108401Sambrisko int len, id, error = 0, i, count = 0; 838108401Sambrisko int ieee80211_header_len; 839108401Sambrisko u_char *bpf_buf; 840108401Sambrisko u_short fc1; 841108401Sambrisko struct an_card_rx_desc an_rx_desc; 842108401Sambrisko u_int8_t *buf; 84355992Swpaul 844122689Ssam AN_LOCK_ASSERT(sc); 845122689Ssam 846147256Sbrooks ifp = sc->an_ifp; 84755992Swpaul 848108401Sambrisko if (!sc->mpi350) { 849108401Sambrisko id = CSR_READ_2(sc, AN_RX_FID); 85055992Swpaul 851108401Sambrisko if (sc->an_monitor && (ifp->if_flags & IFF_PROMISC)) { 852108401Sambrisko /* read raw 802.11 packet */ 853108401Sambrisko bpf_buf = sc->buf_802_11; 85455992Swpaul 855108401Sambrisko /* read header */ 856108401Sambrisko if (an_read_data(sc, id, 0x0, (caddr_t)&rx_frame, 857108401Sambrisko sizeof(rx_frame))) { 858271849Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 859108401Sambrisko return; 860108401Sambrisko } 86155992Swpaul 862108401Sambrisko /* 863108401Sambrisko * skip beacon by default since this increases the 864108401Sambrisko * system load a lot 865108401Sambrisko */ 86683270Sbrooks 867108401Sambrisko if (!(sc->an_monitor & AN_MONITOR_INCLUDE_BEACON) && 868108401Sambrisko (rx_frame.an_frame_ctl & 869108401Sambrisko IEEE80211_FC0_SUBTYPE_BEACON)) { 87083269Sbrooks return; 87183269Sbrooks } 87255992Swpaul 873108401Sambrisko if (sc->an_monitor & AN_MONITOR_AIRONET_HEADER) { 874108401Sambrisko len = rx_frame.an_rx_payload_len 875108401Sambrisko + sizeof(rx_frame); 876108401Sambrisko /* Check for insane frame length */ 877108401Sambrisko if (len > sizeof(sc->buf_802_11)) { 878198987Sjhb if_printf(ifp, "oversized packet " 879108401Sambrisko "received (%d, %d)\n", 880198987Sjhb len, MCLBYTES); 881271849Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 882108401Sambrisko return; 883108401Sambrisko } 88455992Swpaul 885108401Sambrisko bcopy((char *)&rx_frame, 886108401Sambrisko bpf_buf, sizeof(rx_frame)); 887108401Sambrisko 888108401Sambrisko error = an_read_data(sc, id, sizeof(rx_frame), 889108401Sambrisko (caddr_t)bpf_buf+sizeof(rx_frame), 890108401Sambrisko rx_frame.an_rx_payload_len); 891108401Sambrisko } else { 892108401Sambrisko fc1=rx_frame.an_frame_ctl >> 8; 893175445Sambrisko ieee80211_header_len = 894108401Sambrisko sizeof(struct ieee80211_frame); 895108401Sambrisko if ((fc1 & IEEE80211_FC1_DIR_TODS) && 896108401Sambrisko (fc1 & IEEE80211_FC1_DIR_FROMDS)) { 897108401Sambrisko ieee80211_header_len += ETHER_ADDR_LEN; 898108401Sambrisko } 899108401Sambrisko 900108401Sambrisko len = rx_frame.an_rx_payload_len 901108401Sambrisko + ieee80211_header_len; 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); 907271849Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 908108401Sambrisko return; 909108401Sambrisko } 910108401Sambrisko 911108401Sambrisko ih = (struct ieee80211_frame *)bpf_buf; 912108401Sambrisko 913108401Sambrisko bcopy((char *)&rx_frame.an_frame_ctl, 914108401Sambrisko (char *)ih, ieee80211_header_len); 915108401Sambrisko 916108401Sambrisko error = an_read_data(sc, id, sizeof(rx_frame) + 917108401Sambrisko rx_frame.an_gaplen, 918108401Sambrisko (caddr_t)ih +ieee80211_header_len, 919108401Sambrisko rx_frame.an_rx_payload_len); 920108401Sambrisko } 921108401Sambrisko /* dump raw 802.11 packet to bpf and skip ip stack */ 922108401Sambrisko BPF_TAP(ifp, bpf_buf, len); 92383270Sbrooks } else { 924243857Sglebius MGETHDR(m, M_NOWAIT, MT_DATA); 925108401Sambrisko if (m == NULL) { 926271849Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 927108401Sambrisko return; 92883269Sbrooks } 929276750Srwatson if (!(MCLGET(m, M_NOWAIT))) { 930108401Sambrisko m_freem(m); 931271849Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 932108401Sambrisko return; 933108401Sambrisko } 934108401Sambrisko m->m_pkthdr.rcvif = ifp; 935108401Sambrisko /* Read Ethernet encapsulated packet */ 93655992Swpaul 937108401Sambrisko#ifdef ANCACHE 938108401Sambrisko /* Read NIC frame header */ 939175445Sambrisko if (an_read_data(sc, id, 0, (caddr_t)&rx_frame, 940108401Sambrisko sizeof(rx_frame))) { 941154394Srwatson m_freem(m); 942271849Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 943108401Sambrisko return; 944108401Sambrisko } 945108401Sambrisko#endif 946108401Sambrisko /* Read in the 802_3 frame header */ 947175445Sambrisko if (an_read_data(sc, id, 0x34, 948108401Sambrisko (caddr_t)&rx_frame_802_3, 949108401Sambrisko sizeof(rx_frame_802_3))) { 950154394Srwatson m_freem(m); 951271849Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 952108401Sambrisko return; 953108401Sambrisko } 954108401Sambrisko if (rx_frame_802_3.an_rx_802_3_status != 0) { 955154394Srwatson m_freem(m); 956271849Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 957108401Sambrisko return; 958108401Sambrisko } 95983269Sbrooks /* Check for insane frame length */ 960108401Sambrisko len = rx_frame_802_3.an_rx_802_3_payload_len; 96183269Sbrooks if (len > sizeof(sc->buf_802_11)) { 962154394Srwatson m_freem(m); 963198987Sjhb if_printf(ifp, "oversized packet " 964108401Sambrisko "received (%d, %d)\n", 965198987Sjhb len, MCLBYTES); 966271849Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 96783269Sbrooks return; 96883269Sbrooks } 969108401Sambrisko m->m_pkthdr.len = m->m_len = 970108401Sambrisko rx_frame_802_3.an_rx_802_3_payload_len + 12; 97155992Swpaul 972108401Sambrisko eh = mtod(m, struct ether_header *); 97355992Swpaul 974108401Sambrisko bcopy((char *)&rx_frame_802_3.an_rx_dst_addr, 975108401Sambrisko (char *)&eh->ether_dhost, ETHER_ADDR_LEN); 976108401Sambrisko bcopy((char *)&rx_frame_802_3.an_rx_src_addr, 977108401Sambrisko (char *)&eh->ether_shost, ETHER_ADDR_LEN); 97855992Swpaul 979108401Sambrisko /* in mbuf header type is just before payload */ 980175445Sambrisko error = an_read_data(sc, id, 0x44, 981108401Sambrisko (caddr_t)&(eh->ether_type), 982108401Sambrisko rx_frame_802_3.an_rx_802_3_payload_len); 98355992Swpaul 984108401Sambrisko if (error) { 985108401Sambrisko m_freem(m); 986271849Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 987108401Sambrisko return; 988108401Sambrisko } 989271849Sglebius if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 990108401Sambrisko 991108401Sambrisko /* Receive packet. */ 99283269Sbrooks#ifdef ANCACHE 993175445Sambrisko an_cache_store(sc, eh, m, 994110253Sambrisko rx_frame.an_rx_signal_strength, 995110253Sambrisko rx_frame.an_rsvd0); 99683269Sbrooks#endif 997122689Ssam AN_UNLOCK(sc); 998108401Sambrisko (*ifp->if_input)(ifp, m); 999122689Ssam AN_LOCK(sc); 100083269Sbrooks } 100155992Swpaul 1002108401Sambrisko } else { /* MPI-350 */ 1003108401Sambrisko for (count = 0; count < AN_MAX_RX_DESC; count++){ 1004108401Sambrisko for (i = 0; i < sizeof(an_rx_desc) / 4; i++) 1005175445Sambrisko ((u_int32_t *)(void *)&an_rx_desc)[i] 1006175445Sambrisko = CSR_MEM_AUX_READ_4(sc, 1007175445Sambrisko AN_RX_DESC_OFFSET 1008108401Sambrisko + (count * sizeof(an_rx_desc)) 1009108401Sambrisko + (i * 4)); 101083269Sbrooks 1011108401Sambrisko if (an_rx_desc.an_done && !an_rx_desc.an_valid) { 1012108401Sambrisko buf = sc->an_rx_buffer[count].an_dma_vaddr; 101383269Sbrooks 1014243857Sglebius MGETHDR(m, M_NOWAIT, MT_DATA); 1015108401Sambrisko if (m == NULL) { 1016271849Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 1017108401Sambrisko return; 1018108401Sambrisko } 1019276750Srwatson if (!(MCLGET(m, M_NOWAIT))) { 1020108401Sambrisko m_freem(m); 1021271849Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 1022108401Sambrisko return; 1023108401Sambrisko } 1024108401Sambrisko m->m_pkthdr.rcvif = ifp; 1025108401Sambrisko /* Read Ethernet encapsulated packet */ 102683269Sbrooks 1027175445Sambrisko /* 1028108401Sambrisko * No ANCACHE support since we just get back 1029108401Sambrisko * an Ethernet packet no 802.11 info 1030108401Sambrisko */ 1031108401Sambrisko#if 0 1032108401Sambrisko#ifdef ANCACHE 1033108401Sambrisko /* Read NIC frame header */ 1034175445Sambrisko bcopy(buf, (caddr_t)&rx_frame, 1035108401Sambrisko sizeof(rx_frame)); 1036108401Sambrisko#endif 1037108401Sambrisko#endif 1038108401Sambrisko /* Check for insane frame length */ 1039108401Sambrisko len = an_rx_desc.an_len + 12; 1040108401Sambrisko if (len > MCLBYTES) { 1041154393Srwatson m_freem(m); 1042198987Sjhb if_printf(ifp, "oversized packet " 1043108401Sambrisko "received (%d, %d)\n", 1044198987Sjhb len, MCLBYTES); 1045271849Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 1046108401Sambrisko return; 1047108401Sambrisko } 104883269Sbrooks 1049108401Sambrisko m->m_pkthdr.len = m->m_len = 1050108401Sambrisko an_rx_desc.an_len + 12; 1051175445Sambrisko 1052108401Sambrisko eh = mtod(m, struct ether_header *); 1053175445Sambrisko 1054108401Sambrisko bcopy(buf, (char *)eh, 1055108401Sambrisko m->m_pkthdr.len); 1056175445Sambrisko 1057271849Sglebius if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 1058175445Sambrisko 1059108401Sambrisko /* Receive packet. */ 1060108401Sambrisko#if 0 106155992Swpaul#ifdef ANCACHE 1062175445Sambrisko an_cache_store(sc, eh, m, 1063110253Sambrisko rx_frame.an_rx_signal_strength, 1064110253Sambrisko rx_frame.an_rsvd0); 106555992Swpaul#endif 1066108401Sambrisko#endif 1067171775Savatar AN_UNLOCK(sc); 1068108401Sambrisko (*ifp->if_input)(ifp, m); 1069171775Savatar AN_LOCK(sc); 1070171775Savatar 1071108401Sambrisko an_rx_desc.an_valid = 1; 1072108401Sambrisko an_rx_desc.an_len = AN_RX_BUFFER_SIZE; 1073108401Sambrisko an_rx_desc.an_done = 0; 1074175445Sambrisko an_rx_desc.an_phys = 1075108401Sambrisko sc->an_rx_buffer[count].an_dma_paddr; 1076175445Sambrisko 1077108401Sambrisko for (i = 0; i < sizeof(an_rx_desc) / 4; i++) 1078175445Sambrisko CSR_MEM_AUX_WRITE_4(sc, 1079175445Sambrisko AN_RX_DESC_OFFSET 1080155321Simp + (count * sizeof(an_rx_desc)) 1081155321Simp + (i * 4), 1082155321Simp ((u_int32_t *)(void *)&an_rx_desc)[i]); 1083175445Sambrisko 1084108401Sambrisko } else { 1085198987Sjhb if_printf(ifp, "Didn't get valid RX packet " 1086108401Sambrisko "%x %x %d\n", 1087108401Sambrisko an_rx_desc.an_done, 1088108401Sambrisko an_rx_desc.an_valid, an_rx_desc.an_len); 1089108401Sambrisko } 1090108401Sambrisko } 109183269Sbrooks } 109255992Swpaul} 109355992Swpaul 109483270Sbrooksstatic void 1095150446Simpan_txeof(struct an_softc *sc, int status) 109655992Swpaul{ 109755992Swpaul struct ifnet *ifp; 109878639Sbrooks int id, i; 109955992Swpaul 1100175445Sambrisko AN_LOCK_ASSERT(sc); 1101147256Sbrooks ifp = sc->an_ifp; 110255992Swpaul 1103199154Sjhb sc->an_timer = 0; 1104148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 110555992Swpaul 1106108401Sambrisko if (!sc->mpi350) { 1107119156Sambrisko id = CSR_READ_2(sc, AN_TX_CMP_FID(sc->mpi350)); 110855992Swpaul 1109108401Sambrisko if (status & AN_EV_TX_EXC) { 1110271849Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 1111108401Sambrisko } else 1112271849Sglebius if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 111355992Swpaul 1114108401Sambrisko for (i = 0; i < AN_TX_RING_CNT; i++) { 1115108401Sambrisko if (id == sc->an_rdata.an_tx_ring[i]) { 1116108401Sambrisko sc->an_rdata.an_tx_ring[i] = 0; 1117108401Sambrisko break; 1118108401Sambrisko } 111978639Sbrooks } 1120108401Sambrisko 1121108401Sambrisko AN_INC(sc->an_rdata.an_tx_cons, AN_TX_RING_CNT); 1122108401Sambrisko } else { /* MPI 350 */ 1123119156Sambrisko id = CSR_READ_2(sc, AN_TX_CMP_FID(sc->mpi350)); 1124119156Sambrisko if (!sc->an_rdata.an_tx_empty){ 1125119156Sambrisko if (status & AN_EV_TX_EXC) { 1126271849Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 1127119156Sambrisko } else 1128271849Sglebius if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 1129119156Sambrisko AN_INC(sc->an_rdata.an_tx_cons, AN_MAX_TX_DESC); 1130119156Sambrisko if (sc->an_rdata.an_tx_prod == 1131119156Sambrisko sc->an_rdata.an_tx_cons) 1132119156Sambrisko sc->an_rdata.an_tx_empty = 1; 1133119156Sambrisko } 113478639Sbrooks } 113555992Swpaul 113655992Swpaul return; 113755992Swpaul} 113855992Swpaul 113955992Swpaul/* 114055992Swpaul * We abuse the stats updater to check the current NIC status. This 114155992Swpaul * is important because we don't want to allow transmissions until 114255992Swpaul * the NIC has synchronized to the current cell (either as the master 114355992Swpaul * in an ad-hoc group, or as a station connected to an access point). 1144173668Savatar * 1145173668Savatar * Note that this function will be called via callout(9) with a lock held. 114655992Swpaul */ 1147104094Sphkstatic void 1148150446Simpan_stats_update(void *xsc) 114955992Swpaul{ 115055992Swpaul struct an_softc *sc; 115155992Swpaul struct ifnet *ifp; 115255992Swpaul 115355992Swpaul sc = xsc; 1154173668Savatar AN_LOCK_ASSERT(sc); 1155147256Sbrooks ifp = sc->an_ifp; 1156199154Sjhb if (sc->an_timer > 0 && --sc->an_timer == 0) 1157199154Sjhb an_watchdog(sc); 115855992Swpaul 115955992Swpaul sc->an_status.an_type = AN_RID_STATUS; 116055992Swpaul sc->an_status.an_len = sizeof(struct an_ltv_status); 1161173668Savatar if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_status)) 1162173668Savatar return; 116355992Swpaul 116455992Swpaul if (sc->an_status.an_opmode & AN_STATUS_OPMODE_IN_SYNC) 116555992Swpaul sc->an_associated = 1; 116655992Swpaul else 116755992Swpaul sc->an_associated = 0; 116855992Swpaul 116955992Swpaul /* Don't do this while we're transmitting */ 1170148887Srwatson if (ifp->if_drv_flags & IFF_DRV_OACTIVE) { 1171173668Savatar callout_reset(&sc->an_stat_ch, hz, an_stats_update, sc); 117255992Swpaul return; 117355992Swpaul } 117455992Swpaul 117555992Swpaul sc->an_stats.an_len = sizeof(struct an_ltv_stats); 117655992Swpaul sc->an_stats.an_type = AN_RID_32BITS_CUM; 1177173668Savatar if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_stats.an_len)) 1178173668Savatar return; 117955992Swpaul 1180173668Savatar callout_reset(&sc->an_stat_ch, hz, an_stats_update, sc); 118155992Swpaul 118255992Swpaul return; 118355992Swpaul} 118455992Swpaul 118583270Sbrooksvoid 1186150446Simpan_intr(void *xsc) 118755992Swpaul{ 118855992Swpaul struct an_softc *sc; 118955992Swpaul struct ifnet *ifp; 119055992Swpaul u_int16_t status; 119155992Swpaul 119255992Swpaul sc = (struct an_softc*)xsc; 119355992Swpaul 119467094Swpaul AN_LOCK(sc); 119567094Swpaul 119667094Swpaul if (sc->an_gone) { 119767094Swpaul AN_UNLOCK(sc); 119855992Swpaul return; 119967094Swpaul } 120055992Swpaul 1201147256Sbrooks ifp = sc->an_ifp; 120255992Swpaul 120355992Swpaul /* Disable interrupts. */ 1204108401Sambrisko CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0); 120555992Swpaul 1206108401Sambrisko status = CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350)); 1207119156Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), ~AN_INTRS(sc->mpi350)); 120855992Swpaul 1209119156Sambrisko if (status & AN_EV_MIC) { 1210119156Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_MIC); 121155992Swpaul } 121255992Swpaul 121355992Swpaul if (status & AN_EV_LINKSTAT) { 1214175445Sambrisko if (CSR_READ_2(sc, AN_LINKSTAT(sc->mpi350)) 1215108401Sambrisko == AN_LINKSTAT_ASSOCIATED) 121655992Swpaul sc->an_associated = 1; 121755992Swpaul else 121855992Swpaul sc->an_associated = 0; 1219108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_LINKSTAT); 122055992Swpaul } 122155992Swpaul 122255992Swpaul if (status & AN_EV_RX) { 122355992Swpaul an_rxeof(sc); 1224108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_RX); 122555992Swpaul } 122655992Swpaul 1227119156Sambrisko if (sc->mpi350 && status & AN_EV_TX_CPY) { 1228119156Sambrisko an_txeof(sc, status); 1229150446Simp CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_TX_CPY); 1230119156Sambrisko } 1231119156Sambrisko 123255992Swpaul if (status & AN_EV_TX) { 123355992Swpaul an_txeof(sc, status); 1234150446Simp CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_TX); 123555992Swpaul } 123655992Swpaul 123755992Swpaul if (status & AN_EV_TX_EXC) { 123855992Swpaul an_txeof(sc, status); 1239108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_TX_EXC); 124055992Swpaul } 124155992Swpaul 124255992Swpaul if (status & AN_EV_ALLOC) 1243108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_ALLOC); 124455992Swpaul 124555992Swpaul /* Re-enable interrupts. */ 1246119156Sambrisko CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), AN_INTRS(sc->mpi350)); 124755992Swpaul 1248132986Smlaier if ((ifp->if_flags & IFF_UP) && !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1249199154Sjhb an_start_locked(ifp); 125055992Swpaul 125167094Swpaul AN_UNLOCK(sc); 125267094Swpaul 125355992Swpaul return; 125455992Swpaul} 125555992Swpaul 1256108401Sambrisko 125783270Sbrooksstatic int 1258150446Simpan_cmd_struct(struct an_softc *sc, struct an_command *cmd, 1259150446Simp struct an_reply *reply) 1260108401Sambrisko{ 1261108401Sambrisko int i; 1262108401Sambrisko 1263175445Sambrisko AN_LOCK_ASSERT(sc); 1264108401Sambrisko for (i = 0; i != AN_TIMEOUT; i++) { 1265108401Sambrisko if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY) { 1266110531Sambrisko DELAY(1000); 1267110104Sambrisko } else 1268108401Sambrisko break; 1269108401Sambrisko } 1270119156Sambrisko 1271108401Sambrisko if( i == AN_TIMEOUT) { 1272108401Sambrisko printf("BUSY\n"); 1273108401Sambrisko return(ETIMEDOUT); 1274108401Sambrisko } 1275108401Sambrisko 1276108401Sambrisko CSR_WRITE_2(sc, AN_PARAM0(sc->mpi350), cmd->an_parm0); 1277108401Sambrisko CSR_WRITE_2(sc, AN_PARAM1(sc->mpi350), cmd->an_parm1); 1278108401Sambrisko CSR_WRITE_2(sc, AN_PARAM2(sc->mpi350), cmd->an_parm2); 1279108401Sambrisko CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), cmd->an_cmd); 1280108401Sambrisko 1281108401Sambrisko for (i = 0; i < AN_TIMEOUT; i++) { 1282108401Sambrisko if (CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350)) & AN_EV_CMD) 1283108401Sambrisko break; 1284110531Sambrisko DELAY(1000); 1285108401Sambrisko } 1286108401Sambrisko 1287108401Sambrisko reply->an_resp0 = CSR_READ_2(sc, AN_RESP0(sc->mpi350)); 1288108401Sambrisko reply->an_resp1 = CSR_READ_2(sc, AN_RESP1(sc->mpi350)); 1289108401Sambrisko reply->an_resp2 = CSR_READ_2(sc, AN_RESP2(sc->mpi350)); 1290108401Sambrisko reply->an_status = CSR_READ_2(sc, AN_STATUS(sc->mpi350)); 1291108401Sambrisko 1292108401Sambrisko if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY) 1293175445Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), 1294119156Sambrisko AN_EV_CLR_STUCK_BUSY); 1295108401Sambrisko 1296108401Sambrisko /* Ack the command */ 1297108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_CMD); 1298108401Sambrisko 1299108401Sambrisko if (i == AN_TIMEOUT) 1300108401Sambrisko return(ETIMEDOUT); 1301108401Sambrisko 1302108401Sambrisko return(0); 1303108401Sambrisko} 1304108401Sambrisko 1305108401Sambriskostatic int 1306150446Simpan_cmd(struct an_softc *sc, int cmd, int val) 130755992Swpaul{ 130855992Swpaul int i, s = 0; 130955992Swpaul 1310175445Sambrisko AN_LOCK_ASSERT(sc); 1311108401Sambrisko CSR_WRITE_2(sc, AN_PARAM0(sc->mpi350), val); 1312108401Sambrisko CSR_WRITE_2(sc, AN_PARAM1(sc->mpi350), 0); 1313108401Sambrisko CSR_WRITE_2(sc, AN_PARAM2(sc->mpi350), 0); 1314108401Sambrisko CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), cmd); 131555992Swpaul 131655992Swpaul for (i = 0; i < AN_TIMEOUT; i++) { 1317108401Sambrisko if (CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350)) & AN_EV_CMD) 131855992Swpaul break; 131955992Swpaul else { 1320108401Sambrisko if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) == cmd) 1321108401Sambrisko CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), cmd); 132255992Swpaul } 132355992Swpaul } 132455992Swpaul 132555992Swpaul for (i = 0; i < AN_TIMEOUT; i++) { 1326108401Sambrisko CSR_READ_2(sc, AN_RESP0(sc->mpi350)); 1327108401Sambrisko CSR_READ_2(sc, AN_RESP1(sc->mpi350)); 1328108401Sambrisko CSR_READ_2(sc, AN_RESP2(sc->mpi350)); 1329108401Sambrisko s = CSR_READ_2(sc, AN_STATUS(sc->mpi350)); 133055992Swpaul if ((s & AN_STAT_CMD_CODE) == (cmd & AN_STAT_CMD_CODE)) 133155992Swpaul break; 133255992Swpaul } 133355992Swpaul 133455992Swpaul /* Ack the command */ 1335108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_CMD); 133655992Swpaul 1337108401Sambrisko if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY) 1338108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_CLR_STUCK_BUSY); 133955992Swpaul 134055992Swpaul if (i == AN_TIMEOUT) 134155992Swpaul return(ETIMEDOUT); 134255992Swpaul 134355992Swpaul return(0); 134455992Swpaul} 134555992Swpaul 134655992Swpaul/* 134755992Swpaul * This reset sequence may look a little strange, but this is the 134855992Swpaul * most reliable method I've found to really kick the NIC in the 134955992Swpaul * head and force it to reboot correctly. 135055992Swpaul */ 135183270Sbrooksstatic void 1352150446Simpan_reset(struct an_softc *sc) 135355992Swpaul{ 135455992Swpaul if (sc->an_gone) 135555992Swpaul return; 135683270Sbrooks 1357175445Sambrisko AN_LOCK_ASSERT(sc); 135855992Swpaul an_cmd(sc, AN_CMD_ENABLE, 0); 135955992Swpaul an_cmd(sc, AN_CMD_FW_RESTART, 0); 136055992Swpaul an_cmd(sc, AN_CMD_NOOP2, 0); 136155992Swpaul 136255992Swpaul if (an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0) == ETIMEDOUT) 1363259393Sgavin device_printf(sc->an_dev, "reset failed\n"); 136455992Swpaul 136555992Swpaul an_cmd(sc, AN_CMD_DISABLE, 0); 136655992Swpaul 136755992Swpaul return; 136855992Swpaul} 136955992Swpaul 137055992Swpaul/* 137155992Swpaul * Read an LTV record from the NIC. 137255992Swpaul */ 137383270Sbrooksstatic int 1374150446Simpan_read_record(struct an_softc *sc, struct an_ltv_gen *ltv) 137555992Swpaul{ 1376108401Sambrisko struct an_ltv_gen *an_ltv; 1377108401Sambrisko struct an_card_rid_desc an_rid_desc; 1378108401Sambrisko struct an_command cmd; 1379108401Sambrisko struct an_reply reply; 1380198987Sjhb struct ifnet *ifp; 138155992Swpaul u_int16_t *ptr; 138278639Sbrooks u_int8_t *ptr2; 138355992Swpaul int i, len; 138455992Swpaul 1385175445Sambrisko AN_LOCK_ASSERT(sc); 138678639Sbrooks if (ltv->an_len < 4 || ltv->an_type == 0) 138755992Swpaul return(EINVAL); 138855992Swpaul 1389198987Sjhb ifp = sc->an_ifp; 1390108401Sambrisko if (!sc->mpi350){ 1391108401Sambrisko /* Tell the NIC to enter record read mode. */ 1392108401Sambrisko if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type)) { 1393198987Sjhb if_printf(ifp, "RID access failed\n"); 1394108401Sambrisko return(EIO); 1395108401Sambrisko } 139655992Swpaul 1397108401Sambrisko /* Seek to the record. */ 1398108401Sambrisko if (an_seek(sc, ltv->an_type, 0, AN_BAP1)) { 1399198987Sjhb if_printf(ifp, "seek to record failed\n"); 1400108401Sambrisko return(EIO); 1401108401Sambrisko } 140255992Swpaul 1403108401Sambrisko /* 1404108401Sambrisko * Read the length and record type and make sure they 1405108401Sambrisko * match what we expect (this verifies that we have enough 1406108401Sambrisko * room to hold all of the returned data). 1407108401Sambrisko * Length includes type but not length. 1408108401Sambrisko */ 1409108401Sambrisko len = CSR_READ_2(sc, AN_DATA1); 1410108401Sambrisko if (len > (ltv->an_len - 2)) { 1411198987Sjhb if_printf(ifp, "record length mismatch -- expected %d, " 1412198987Sjhb "got %d for Rid %x\n", 1413108401Sambrisko ltv->an_len - 2, len, ltv->an_type); 1414108401Sambrisko len = ltv->an_len - 2; 1415108401Sambrisko } else { 1416108401Sambrisko ltv->an_len = len + 2; 1417108401Sambrisko } 1418108401Sambrisko 1419108401Sambrisko /* Now read the data. */ 1420108401Sambrisko len -= 2; /* skip the type */ 1421108401Sambrisko ptr = <v->an_val; 1422108401Sambrisko for (i = len; i > 1; i -= 2) 1423108401Sambrisko *ptr++ = CSR_READ_2(sc, AN_DATA1); 1424108401Sambrisko if (i) { 1425108401Sambrisko ptr2 = (u_int8_t *)ptr; 1426108401Sambrisko *ptr2 = CSR_READ_1(sc, AN_DATA1); 1427108401Sambrisko } 1428108401Sambrisko } else { /* MPI-350 */ 1429123978Sambrisko if (!sc->an_rid_buffer.an_dma_vaddr) 1430123978Sambrisko return(EIO); 1431108401Sambrisko an_rid_desc.an_valid = 1; 1432108401Sambrisko an_rid_desc.an_len = AN_RID_BUFFER_SIZE; 1433108401Sambrisko an_rid_desc.an_rid = 0; 1434108401Sambrisko an_rid_desc.an_phys = sc->an_rid_buffer.an_dma_paddr; 1435108401Sambrisko bzero(sc->an_rid_buffer.an_dma_vaddr, AN_RID_BUFFER_SIZE); 1436108401Sambrisko 1437108401Sambrisko bzero(&cmd, sizeof(cmd)); 1438108401Sambrisko bzero(&reply, sizeof(reply)); 1439108401Sambrisko cmd.an_cmd = AN_CMD_ACCESS|AN_ACCESS_READ; 1440108401Sambrisko cmd.an_parm0 = ltv->an_type; 1441108401Sambrisko 1442108401Sambrisko for (i = 0; i < sizeof(an_rid_desc) / 4; i++) 1443175445Sambrisko CSR_MEM_AUX_WRITE_4(sc, AN_HOST_DESC_OFFSET + i * 4, 1444155321Simp ((u_int32_t *)(void *)&an_rid_desc)[i]); 1445108401Sambrisko 1446108401Sambrisko if (an_cmd_struct(sc, &cmd, &reply) 1447108401Sambrisko || reply.an_status & AN_CMD_QUAL_MASK) { 1448198987Sjhb if_printf(ifp, "failed to read RID %x %x %x %x %x, %d\n", 1449198987Sjhb ltv->an_type, 1450108401Sambrisko reply.an_status, 1451108401Sambrisko reply.an_resp0, 1452108401Sambrisko reply.an_resp1, 1453108401Sambrisko reply.an_resp2, 1454108401Sambrisko i); 1455108401Sambrisko return(EIO); 1456108401Sambrisko } 1457108401Sambrisko 1458108401Sambrisko an_ltv = (struct an_ltv_gen *)sc->an_rid_buffer.an_dma_vaddr; 1459108401Sambrisko if (an_ltv->an_len + 2 < an_rid_desc.an_len) { 1460108401Sambrisko an_rid_desc.an_len = an_ltv->an_len; 1461108401Sambrisko } 1462108401Sambrisko 1463123978Sambrisko len = an_rid_desc.an_len; 1464123978Sambrisko if (len > (ltv->an_len - 2)) { 1465198987Sjhb if_printf(ifp, "record length mismatch -- expected %d, " 1466198987Sjhb "got %d for Rid %x\n", 1467123978Sambrisko ltv->an_len - 2, len, ltv->an_type); 1468123978Sambrisko len = ltv->an_len - 2; 1469123978Sambrisko } else { 1470123978Sambrisko ltv->an_len = len + 2; 1471123978Sambrisko } 1472123978Sambrisko bcopy(&an_ltv->an_type, 1473175445Sambrisko <v->an_val, 1474123978Sambrisko len); 147555992Swpaul } 147655992Swpaul 147778639Sbrooks if (an_dump) 147878639Sbrooks an_dump_record(sc, ltv, "Read"); 147955992Swpaul 148055992Swpaul return(0); 148155992Swpaul} 148255992Swpaul 148355992Swpaul/* 148455992Swpaul * Same as read, except we inject data instead of reading it. 148555992Swpaul */ 148683270Sbrooksstatic int 1487150446Simpan_write_record(struct an_softc *sc, struct an_ltv_gen *ltv) 148855992Swpaul{ 1489108401Sambrisko struct an_card_rid_desc an_rid_desc; 1490108401Sambrisko struct an_command cmd; 1491108401Sambrisko struct an_reply reply; 149255992Swpaul u_int16_t *ptr; 149378639Sbrooks u_int8_t *ptr2; 149478639Sbrooks int i, len; 149555992Swpaul 1496175445Sambrisko AN_LOCK_ASSERT(sc); 149778639Sbrooks if (an_dump) 149878639Sbrooks an_dump_record(sc, ltv, "Write"); 149978639Sbrooks 1500108401Sambrisko if (!sc->mpi350){ 1501108401Sambrisko if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type)) 1502108401Sambrisko return(EIO); 150383270Sbrooks 1504108401Sambrisko if (an_seek(sc, ltv->an_type, 0, AN_BAP1)) 1505108401Sambrisko return(EIO); 1506108401Sambrisko 1507108401Sambrisko /* 1508108401Sambrisko * Length includes type but not length. 1509108401Sambrisko */ 1510108401Sambrisko len = ltv->an_len - 2; 1511108401Sambrisko CSR_WRITE_2(sc, AN_DATA1, len); 1512108401Sambrisko 1513108401Sambrisko len -= 2; /* skip the type */ 1514108401Sambrisko ptr = <v->an_val; 1515108401Sambrisko for (i = len; i > 1; i -= 2) 1516108401Sambrisko CSR_WRITE_2(sc, AN_DATA1, *ptr++); 1517108401Sambrisko if (i) { 1518108401Sambrisko ptr2 = (u_int8_t *)ptr; 1519108401Sambrisko CSR_WRITE_1(sc, AN_DATA0, *ptr2); 1520108401Sambrisko } 1521108401Sambrisko 1522108401Sambrisko if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_WRITE, ltv->an_type)) 1523108401Sambrisko return(EIO); 1524175445Sambrisko } else { 1525110104Sambrisko /* MPI-350 */ 1526108401Sambrisko 1527108401Sambrisko for (i = 0; i != AN_TIMEOUT; i++) { 1528175445Sambrisko if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) 1529110104Sambrisko & AN_CMD_BUSY) { 1530108401Sambrisko DELAY(10); 1531110104Sambrisko } else 1532108401Sambrisko break; 1533108401Sambrisko } 1534108401Sambrisko if (i == AN_TIMEOUT) { 1535108401Sambrisko printf("BUSY\n"); 1536108401Sambrisko } 1537108401Sambrisko 1538108401Sambrisko an_rid_desc.an_valid = 1; 1539108401Sambrisko an_rid_desc.an_len = ltv->an_len - 2; 1540108401Sambrisko an_rid_desc.an_rid = ltv->an_type; 1541108401Sambrisko an_rid_desc.an_phys = sc->an_rid_buffer.an_dma_paddr; 1542108401Sambrisko 1543108401Sambrisko bcopy(<v->an_type, sc->an_rid_buffer.an_dma_vaddr, 1544108401Sambrisko an_rid_desc.an_len); 1545108401Sambrisko 1546108401Sambrisko bzero(&cmd,sizeof(cmd)); 1547108401Sambrisko bzero(&reply,sizeof(reply)); 1548108401Sambrisko cmd.an_cmd = AN_CMD_ACCESS|AN_ACCESS_WRITE; 1549108401Sambrisko cmd.an_parm0 = ltv->an_type; 1550108401Sambrisko 1551108401Sambrisko for (i = 0; i < sizeof(an_rid_desc) / 4; i++) 1552175445Sambrisko CSR_MEM_AUX_WRITE_4(sc, AN_HOST_DESC_OFFSET + i * 4, 1553155321Simp ((u_int32_t *)(void *)&an_rid_desc)[i]); 1554108401Sambrisko 1555110531Sambrisko DELAY(100000); 1556110531Sambrisko 1557108401Sambrisko if ((i = an_cmd_struct(sc, &cmd, &reply))) { 1558198987Sjhb if_printf(sc->an_ifp, 1559198987Sjhb "failed to write RID 1 %x %x %x %x %x, %d\n", 1560198987Sjhb ltv->an_type, 1561110104Sambrisko reply.an_status, 1562110104Sambrisko reply.an_resp0, 1563110104Sambrisko reply.an_resp1, 1564110104Sambrisko reply.an_resp2, 1565110104Sambrisko i); 1566110104Sambrisko return(EIO); 1567108401Sambrisko } 156855992Swpaul 156983270Sbrooks 1570108401Sambrisko if (reply.an_status & AN_CMD_QUAL_MASK) { 1571198987Sjhb if_printf(sc->an_ifp, 1572198987Sjhb "failed to write RID 2 %x %x %x %x %x, %d\n", 1573198987Sjhb ltv->an_type, 1574110104Sambrisko reply.an_status, 1575110104Sambrisko reply.an_resp0, 1576110104Sambrisko reply.an_resp1, 1577110104Sambrisko reply.an_resp2, 1578110104Sambrisko i); 1579108401Sambrisko return(EIO); 1580108401Sambrisko } 1581110531Sambrisko DELAY(100000); 158278639Sbrooks } 158355992Swpaul 158455992Swpaul return(0); 158555992Swpaul} 158655992Swpaul 158783270Sbrooksstatic void 1588150446Simpan_dump_record(struct an_softc *sc, struct an_ltv_gen *ltv, char *string) 158978639Sbrooks{ 159078639Sbrooks u_int8_t *ptr2; 159178639Sbrooks int len; 159278639Sbrooks int i; 159378639Sbrooks int count = 0; 159478639Sbrooks char buf[17], temp; 159578639Sbrooks 159678639Sbrooks len = ltv->an_len - 4; 1597198987Sjhb if_printf(sc->an_ifp, "RID %4x, Length %4d, Mode %s\n", 1598198987Sjhb ltv->an_type, ltv->an_len - 4, string); 159978639Sbrooks 160078639Sbrooks if (an_dump == 1 || (an_dump == ltv->an_type)) { 1601198987Sjhb if_printf(sc->an_ifp, "\t"); 160278639Sbrooks bzero(buf,sizeof(buf)); 160378639Sbrooks 160478639Sbrooks ptr2 = (u_int8_t *)<v->an_val; 160578639Sbrooks for (i = len; i > 0; i--) { 160678639Sbrooks printf("%02x ", *ptr2); 160778639Sbrooks 160878639Sbrooks temp = *ptr2++; 1609154866Snjl if (isprint(temp)) 161078639Sbrooks buf[count] = temp; 161178639Sbrooks else 161278639Sbrooks buf[count] = '.'; 161378639Sbrooks if (++count == 16) { 161478639Sbrooks count = 0; 161578639Sbrooks printf("%s\n",buf); 1616198987Sjhb if_printf(sc->an_ifp, "\t"); 161778639Sbrooks bzero(buf,sizeof(buf)); 161878639Sbrooks } 161978639Sbrooks } 162078639Sbrooks for (; count != 16; count++) { 162178639Sbrooks printf(" "); 162278639Sbrooks } 162378639Sbrooks printf(" %s\n",buf); 162478639Sbrooks } 162578639Sbrooks} 162678639Sbrooks 162783270Sbrooksstatic int 1628150446Simpan_seek(struct an_softc *sc, int id, int off, int chan) 162955992Swpaul{ 163055992Swpaul int i; 163155992Swpaul int selreg, offreg; 163255992Swpaul 163355992Swpaul switch (chan) { 163455992Swpaul case AN_BAP0: 163555992Swpaul selreg = AN_SEL0; 163655992Swpaul offreg = AN_OFF0; 163755992Swpaul break; 163855992Swpaul case AN_BAP1: 163955992Swpaul selreg = AN_SEL1; 164055992Swpaul offreg = AN_OFF1; 164155992Swpaul break; 164255992Swpaul default: 1643198987Sjhb if_printf(sc->an_ifp, "invalid data path: %x\n", chan); 164455992Swpaul return(EIO); 164555992Swpaul } 164655992Swpaul 164755992Swpaul CSR_WRITE_2(sc, selreg, id); 164855992Swpaul CSR_WRITE_2(sc, offreg, off); 164955992Swpaul 165055992Swpaul for (i = 0; i < AN_TIMEOUT; i++) { 165155992Swpaul if (!(CSR_READ_2(sc, offreg) & (AN_OFF_BUSY|AN_OFF_ERR))) 165255992Swpaul break; 165355992Swpaul } 165455992Swpaul 165555992Swpaul if (i == AN_TIMEOUT) 165655992Swpaul return(ETIMEDOUT); 165755992Swpaul 165855992Swpaul return(0); 165955992Swpaul} 166055992Swpaul 166183270Sbrooksstatic int 1662150446Simpan_read_data(struct an_softc *sc, int id, int off, caddr_t buf, int len) 166355992Swpaul{ 166455992Swpaul int i; 166555992Swpaul u_int16_t *ptr; 166655992Swpaul u_int8_t *ptr2; 166755992Swpaul 166855992Swpaul if (off != -1) { 166955992Swpaul if (an_seek(sc, id, off, AN_BAP1)) 167055992Swpaul return(EIO); 167155992Swpaul } 167255992Swpaul 167355992Swpaul ptr = (u_int16_t *)buf; 167478639Sbrooks for (i = len; i > 1; i -= 2) 167578639Sbrooks *ptr++ = CSR_READ_2(sc, AN_DATA1); 167678639Sbrooks if (i) { 167778639Sbrooks ptr2 = (u_int8_t *)ptr; 167878639Sbrooks *ptr2 = CSR_READ_1(sc, AN_DATA1); 167955992Swpaul } 168055992Swpaul 168155992Swpaul return(0); 168255992Swpaul} 168355992Swpaul 168483270Sbrooksstatic int 1685150446Simpan_write_data(struct an_softc *sc, int id, int off, caddr_t buf, int len) 168655992Swpaul{ 168755992Swpaul int i; 168855992Swpaul u_int16_t *ptr; 168955992Swpaul u_int8_t *ptr2; 169055992Swpaul 169155992Swpaul if (off != -1) { 169255992Swpaul if (an_seek(sc, id, off, AN_BAP0)) 169355992Swpaul return(EIO); 169455992Swpaul } 169555992Swpaul 169655992Swpaul ptr = (u_int16_t *)buf; 169778639Sbrooks for (i = len; i > 1; i -= 2) 169878639Sbrooks CSR_WRITE_2(sc, AN_DATA0, *ptr++); 169978639Sbrooks if (i) { 1700175446Sambrisko ptr2 = (u_int8_t *)ptr; 1701175446Sambrisko CSR_WRITE_1(sc, AN_DATA0, *ptr2); 170255992Swpaul } 170355992Swpaul 170455992Swpaul return(0); 170555992Swpaul} 170655992Swpaul 170755992Swpaul/* 170855992Swpaul * Allocate a region of memory inside the NIC and zero 170955992Swpaul * it out. 171055992Swpaul */ 171183270Sbrooksstatic int 1712150446Simpan_alloc_nicmem(struct an_softc *sc, int len, int *id) 171355992Swpaul{ 171455992Swpaul int i; 171555992Swpaul 171655992Swpaul if (an_cmd(sc, AN_CMD_ALLOC_MEM, len)) { 1717198987Sjhb if_printf(sc->an_ifp, "failed to allocate %d bytes on NIC\n", 1718198987Sjhb len); 171955992Swpaul return(ENOMEM); 172055992Swpaul } 172155992Swpaul 172255992Swpaul for (i = 0; i < AN_TIMEOUT; i++) { 1723108401Sambrisko if (CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350)) & AN_EV_ALLOC) 172455992Swpaul break; 172555992Swpaul } 172655992Swpaul 172755992Swpaul if (i == AN_TIMEOUT) 172855992Swpaul return(ETIMEDOUT); 172955992Swpaul 1730108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_ALLOC); 173155992Swpaul *id = CSR_READ_2(sc, AN_ALLOC_FID); 173255992Swpaul 173355992Swpaul if (an_seek(sc, *id, 0, AN_BAP0)) 173455992Swpaul return(EIO); 173555992Swpaul 173655992Swpaul for (i = 0; i < len / 2; i++) 173755992Swpaul CSR_WRITE_2(sc, AN_DATA0, 0); 173855992Swpaul 173955992Swpaul return(0); 174055992Swpaul} 174155992Swpaul 174283270Sbrooksstatic void 1743150446Simpan_setdef(struct an_softc *sc, struct an_req *areq) 174455992Swpaul{ 174555992Swpaul struct ifnet *ifp; 174655992Swpaul struct an_ltv_genconfig *cfg; 1747119156Sambrisko struct an_ltv_ssidlist_new *ssid; 174855992Swpaul struct an_ltv_aplist *ap; 174955992Swpaul struct an_ltv_gen *sp; 175055992Swpaul 1751147256Sbrooks ifp = sc->an_ifp; 175255992Swpaul 1753175445Sambrisko AN_LOCK_ASSERT(sc); 175455992Swpaul switch (areq->an_type) { 175555992Swpaul case AN_RID_GENCONFIG: 175655992Swpaul cfg = (struct an_ltv_genconfig *)areq; 175755992Swpaul 1758152315Sru bcopy((char *)&cfg->an_macaddr, IF_LLADDR(sc->an_ifp), 175955992Swpaul ETHER_ADDR_LEN); 176055992Swpaul 176155992Swpaul bcopy((char *)cfg, (char *)&sc->an_config, 176255992Swpaul sizeof(struct an_ltv_genconfig)); 176355992Swpaul break; 176455992Swpaul case AN_RID_SSIDLIST: 1765119156Sambrisko ssid = (struct an_ltv_ssidlist_new *)areq; 176655992Swpaul bcopy((char *)ssid, (char *)&sc->an_ssidlist, 1767119156Sambrisko sizeof(struct an_ltv_ssidlist_new)); 176855992Swpaul break; 176955992Swpaul case AN_RID_APLIST: 177055992Swpaul ap = (struct an_ltv_aplist *)areq; 177155992Swpaul bcopy((char *)ap, (char *)&sc->an_aplist, 177255992Swpaul sizeof(struct an_ltv_aplist)); 177355992Swpaul break; 177455992Swpaul case AN_RID_TX_SPEED: 177555992Swpaul sp = (struct an_ltv_gen *)areq; 177655992Swpaul sc->an_tx_rate = sp->an_val; 1777110253Sambrisko 1778110253Sambrisko /* Read the current configuration */ 1779110253Sambrisko sc->an_config.an_type = AN_RID_GENCONFIG; 1780110253Sambrisko sc->an_config.an_len = sizeof(struct an_ltv_genconfig); 1781110253Sambrisko an_read_record(sc, (struct an_ltv_gen *)&sc->an_config); 1782110253Sambrisko cfg = &sc->an_config; 1783110253Sambrisko 1784110253Sambrisko /* clear other rates and set the only one we want */ 1785110253Sambrisko bzero(cfg->an_rates, sizeof(cfg->an_rates)); 1786110253Sambrisko cfg->an_rates[0] = sc->an_tx_rate; 1787110253Sambrisko 1788110253Sambrisko /* Save the new rate */ 1789110253Sambrisko sc->an_config.an_type = AN_RID_GENCONFIG; 1790110253Sambrisko sc->an_config.an_len = sizeof(struct an_ltv_genconfig); 179155992Swpaul break; 179268692Swpaul case AN_RID_WEP_TEMP: 1793110531Sambrisko /* Cache the temp keys */ 1794175445Sambrisko bcopy(areq, 1795175445Sambrisko &sc->an_temp_keys[((struct an_ltv_key *)areq)->kindex], 1796110531Sambrisko sizeof(struct an_ltv_key)); 179768692Swpaul case AN_RID_WEP_PERM: 179888748Sambrisko case AN_RID_LEAPUSERNAME: 179988748Sambrisko case AN_RID_LEAPPASSWORD: 1800199154Sjhb an_init_locked(sc); 1801119156Sambrisko 180268692Swpaul /* Disable the MAC. */ 180368692Swpaul an_cmd(sc, AN_CMD_DISABLE, 0); 180483270Sbrooks 180583269Sbrooks /* Write the key */ 180668692Swpaul an_write_record(sc, (struct an_ltv_gen *)areq); 180783270Sbrooks 180883270Sbrooks /* Turn the MAC back on. */ 180968692Swpaul an_cmd(sc, AN_CMD_ENABLE, 0); 181083270Sbrooks 181168692Swpaul break; 181283269Sbrooks case AN_RID_MONITOR_MODE: 181383269Sbrooks cfg = (struct an_ltv_genconfig *)areq; 181483269Sbrooks bpfdetach(ifp); 181583269Sbrooks if (ng_ether_detach_p != NULL) 181683269Sbrooks (*ng_ether_detach_p) (ifp); 181783269Sbrooks sc->an_monitor = cfg->an_len; 181883269Sbrooks 181983270Sbrooks if (sc->an_monitor & AN_MONITOR) { 182083270Sbrooks if (sc->an_monitor & AN_MONITOR_AIRONET_HEADER) { 182183270Sbrooks bpfattach(ifp, DLT_AIRONET_HEADER, 182283269Sbrooks sizeof(struct ether_header)); 182383269Sbrooks } else { 182483270Sbrooks bpfattach(ifp, DLT_IEEE802_11, 182583269Sbrooks sizeof(struct ether_header)); 182683269Sbrooks } 182783269Sbrooks } else { 182883270Sbrooks bpfattach(ifp, DLT_EN10MB, 182983269Sbrooks sizeof(struct ether_header)); 183083269Sbrooks if (ng_ether_attach_p != NULL) 183183269Sbrooks (*ng_ether_attach_p) (ifp); 183283269Sbrooks } 183383269Sbrooks break; 183455992Swpaul default: 1835198987Sjhb if_printf(ifp, "unknown RID: %x\n", areq->an_type); 183655992Swpaul return; 183755992Swpaul } 183855992Swpaul 183955992Swpaul 184055992Swpaul /* Reinitialize the card. */ 1841199154Sjhb if (ifp->if_flags) 1842199154Sjhb an_init_locked(sc); 184355992Swpaul 184455992Swpaul return; 184555992Swpaul} 184655992Swpaul 184755992Swpaul/* 184883269Sbrooks * Derived from Linux driver to enable promiscious mode. 184955992Swpaul */ 185083269Sbrooks 185183270Sbrooksstatic void 1852150446Simpan_promisc(struct an_softc *sc, int promisc) 185355992Swpaul{ 1854175445Sambrisko AN_LOCK_ASSERT(sc); 1855150446Simp if (sc->an_was_monitor) { 185683269Sbrooks an_reset(sc); 1857108401Sambrisko if (sc->mpi350) 1858175445Sambrisko an_init_mpi350_desc(sc); 1859150446Simp } 1860199154Sjhb if (sc->an_monitor || sc->an_was_monitor) 1861199154Sjhb an_init_locked(sc); 186283269Sbrooks 186383269Sbrooks sc->an_was_monitor = sc->an_monitor; 186474698Sarchie an_cmd(sc, AN_CMD_SET_MODE, promisc ? 0xffff : 0); 186583270Sbrooks 186655992Swpaul return; 186755992Swpaul} 186855992Swpaul 186983270Sbrooksstatic int 1870150446Simpan_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 187155992Swpaul{ 187267094Swpaul int error = 0; 187377217Sphk int len; 1874119156Sambrisko int i, max; 187555992Swpaul struct an_softc *sc; 1876355934Smarkj struct an_req *areq; 187755992Swpaul struct ifreq *ifr; 187893593Sjhb struct thread *td = curthread; 187977217Sphk struct ieee80211req *ireq; 1880172112Savatar struct ieee80211_channel ch; 188177217Sphk u_int8_t tmpstr[IEEE80211_NWID_LEN*2]; 188277217Sphk u_int8_t *tmpptr; 188377217Sphk struct an_ltv_genconfig *config; 188477217Sphk struct an_ltv_key *key; 188577217Sphk struct an_ltv_status *status; 1886119156Sambrisko struct an_ltv_ssidlist_new *ssids; 188788748Sambrisko int mode; 188888748Sambrisko struct aironet_ioctl l_ioctl; 188955992Swpaul 189055992Swpaul sc = ifp->if_softc; 189155992Swpaul ifr = (struct ifreq *)data; 189277217Sphk ireq = (struct ieee80211req *)data; 189355992Swpaul 189488749Sambrisko config = (struct an_ltv_genconfig *)&sc->areq; 189588749Sambrisko key = (struct an_ltv_key *)&sc->areq; 189688749Sambrisko status = (struct an_ltv_status *)&sc->areq; 1897119156Sambrisko ssids = (struct an_ltv_ssidlist_new *)&sc->areq; 189877217Sphk 189964429Speter if (sc->an_gone) { 190061816Sroberto error = ENODEV; 190161816Sroberto goto out; 190261816Sroberto } 190355992Swpaul 190483270Sbrooks switch (command) { 190555992Swpaul case SIOCSIFFLAGS: 1906175445Sambrisko AN_LOCK(sc); 190755992Swpaul if (ifp->if_flags & IFF_UP) { 1908148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING && 190955992Swpaul ifp->if_flags & IFF_PROMISC && 191055992Swpaul !(sc->an_if_flags & IFF_PROMISC)) { 191155992Swpaul an_promisc(sc, 1); 1912148887Srwatson } else if (ifp->if_drv_flags & IFF_DRV_RUNNING && 191355992Swpaul !(ifp->if_flags & IFF_PROMISC) && 191455992Swpaul sc->an_if_flags & IFF_PROMISC) { 191555992Swpaul an_promisc(sc, 0); 1916199154Sjhb } else 1917199154Sjhb an_init_locked(sc); 191855992Swpaul } else { 1919199154Sjhb if (ifp->if_drv_flags & IFF_DRV_RUNNING) 192055992Swpaul an_stop(sc); 192155992Swpaul } 1922199154Sjhb sc->an_if_flags = ifp->if_flags; 1923175445Sambrisko AN_UNLOCK(sc); 192455992Swpaul error = 0; 192555992Swpaul break; 192677217Sphk case SIOCSIFMEDIA: 192777217Sphk case SIOCGIFMEDIA: 192877217Sphk error = ifmedia_ioctl(ifp, ifr, &sc->an_ifmedia, command); 192977217Sphk break; 193055992Swpaul case SIOCADDMULTI: 193155992Swpaul case SIOCDELMULTI: 193255992Swpaul /* The Aironet has no multicast filter. */ 193355992Swpaul error = 0; 193455992Swpaul break; 193555992Swpaul case SIOCGAIRONET: 1936355934Smarkj error = priv_check(td, PRIV_DRIVER); 1937355934Smarkj if (error) 193855992Swpaul break; 1939355934Smarkj areq = malloc(sizeof(*areq), M_TEMP, M_WAITOK); 1940355934Smarkj error = copyin(ifr_data_get_ptr(ifr), areq, sizeof(*areq)); 1941355934Smarkj if (error != 0) { 1942355934Smarkj free(areq, M_TEMP); 1943355934Smarkj break; 1944355934Smarkj } 1945175445Sambrisko AN_LOCK(sc); 1946355934Smarkj memcpy(&sc->areq, areq, sizeof(sc->areq)); 194755992Swpaul#ifdef ANCACHE 194888749Sambrisko if (sc->areq.an_type == AN_RID_ZERO_CACHE) { 194955992Swpaul sc->an_sigitems = sc->an_nextitem = 0; 1950355934Smarkj free(areq, M_TEMP); 195155992Swpaul break; 195288749Sambrisko } else if (sc->areq.an_type == AN_RID_READ_CACHE) { 195388749Sambrisko char *pt = (char *)&sc->areq.an_val; 195455992Swpaul bcopy((char *)&sc->an_sigitems, (char *)pt, 195555992Swpaul sizeof(int)); 195655992Swpaul pt += sizeof(int); 195788749Sambrisko sc->areq.an_len = sizeof(int) / 2; 195855992Swpaul bcopy((char *)&sc->an_sigcache, (char *)pt, 195955992Swpaul sizeof(struct an_sigcache) * sc->an_sigitems); 196088749Sambrisko sc->areq.an_len += ((sizeof(struct an_sigcache) * 196155992Swpaul sc->an_sigitems) / 2) + 1; 196255992Swpaul } else 196355992Swpaul#endif 196488749Sambrisko if (an_read_record(sc, (struct an_ltv_gen *)&sc->areq)) { 1965175445Sambrisko AN_UNLOCK(sc); 1966355934Smarkj free(areq, M_TEMP); 196755992Swpaul error = EINVAL; 196855992Swpaul break; 196955992Swpaul } 1970355934Smarkj memcpy(areq, &sc->areq, sizeof(*areq)); 1971171692Savatar AN_UNLOCK(sc); 1972355934Smarkj error = copyout(areq, ifr_data_get_ptr(ifr), sizeof(*areq)); 1973355934Smarkj free(areq, M_TEMP); 197455992Swpaul break; 197555992Swpaul case SIOCSAIRONET: 1976164033Srwatson if ((error = priv_check(td, PRIV_DRIVER))) 197764429Speter goto out; 1978175445Sambrisko AN_LOCK(sc); 1979332288Sbrooks error = copyin(ifr_data_get_ptr(ifr), &sc->areq, 1980332288Sbrooks sizeof(sc->areq)); 198178639Sbrooks if (error != 0) 198255992Swpaul break; 198388749Sambrisko an_setdef(sc, &sc->areq); 1984175445Sambrisko AN_UNLOCK(sc); 198555992Swpaul break; 1986175446Sambrisko case SIOCGPRIVATE_0: /* used by Cisco client utility */ 1987164033Srwatson if ((error = priv_check(td, PRIV_DRIVER))) 198892292Sambrisko goto out; 1989332288Sbrooks error = copyin(ifr_data_get_ptr(ifr), &l_ioctl, 1990332288Sbrooks sizeof(l_ioctl)); 1991144242Ssam if (error) 1992144242Ssam goto out; 199388748Sambrisko mode = l_ioctl.command; 199488748Sambrisko 1995175445Sambrisko AN_LOCK(sc); 199688748Sambrisko if (mode >= AIROGCAP && mode <= AIROGSTATSD32) { 199788748Sambrisko error = readrids(ifp, &l_ioctl); 1998110104Sambrisko } else if (mode >= AIROPCAP && mode <= AIROPLEAPUSR) { 199988748Sambrisko error = writerids(ifp, &l_ioctl); 2000110104Sambrisko } else if (mode >= AIROFLSHRST && mode <= AIRORESTART) { 200188748Sambrisko error = flashcard(ifp, &l_ioctl); 2002110104Sambrisko } else { 200388748Sambrisko error =-1; 200488748Sambrisko } 2005175445Sambrisko AN_UNLOCK(sc); 2006144242Ssam if (!error) { 2007144242Ssam /* copy out the updated command info */ 2008332288Sbrooks error = copyout(&l_ioctl, ifr_data_get_ptr(ifr), 2009332288Sbrooks sizeof(l_ioctl)); 2010144242Ssam } 201188748Sambrisko break; 2012175446Sambrisko case SIOCGPRIVATE_1: /* used by Cisco client utility */ 2013164033Srwatson if ((error = priv_check(td, PRIV_DRIVER))) 201492292Sambrisko goto out; 2015332288Sbrooks error = copyin(ifr_data_get_ptr(ifr), &l_ioctl, 2016332288Sbrooks sizeof(l_ioctl)); 2017144242Ssam if (error) 2018144242Ssam goto out; 201988748Sambrisko l_ioctl.command = 0; 202088748Sambrisko error = AIROMAGIC; 2021144242Ssam (void) copyout(&error, l_ioctl.data, sizeof(error)); 2022175446Sambrisko error = 0; 202388748Sambrisko break; 202477217Sphk case SIOCG80211: 202588749Sambrisko sc->areq.an_len = sizeof(sc->areq); 202688748Sambrisko /* was that a good idea DJA we are doing a short-cut */ 202783270Sbrooks switch (ireq->i_type) { 202877217Sphk case IEEE80211_IOC_SSID: 2029175445Sambrisko AN_LOCK(sc); 203078639Sbrooks if (ireq->i_val == -1) { 203188749Sambrisko sc->areq.an_type = AN_RID_STATUS; 203277217Sphk if (an_read_record(sc, 203388749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 203477217Sphk error = EINVAL; 2035175445Sambrisko AN_UNLOCK(sc); 203677217Sphk break; 203777217Sphk } 203877217Sphk len = status->an_ssidlen; 203977217Sphk tmpptr = status->an_ssid; 204078639Sbrooks } else if (ireq->i_val >= 0) { 204188749Sambrisko sc->areq.an_type = AN_RID_SSIDLIST; 204277217Sphk if (an_read_record(sc, 204388749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 204477217Sphk error = EINVAL; 2045175445Sambrisko AN_UNLOCK(sc); 204677217Sphk break; 204777217Sphk } 2048119156Sambrisko max = (sc->areq.an_len - 4) 2049119156Sambrisko / sizeof(struct an_ltv_ssid_entry); 2050119156Sambrisko if ( max > MAX_SSIDS ) { 2051119156Sambrisko printf("To many SSIDs only using " 2052119156Sambrisko "%d of %d\n", 2053119156Sambrisko MAX_SSIDS, max); 2054119156Sambrisko max = MAX_SSIDS; 2055119156Sambrisko } 2056119156Sambrisko if (ireq->i_val > max) { 205777217Sphk error = EINVAL; 2058175445Sambrisko AN_UNLOCK(sc); 205977217Sphk break; 2060119156Sambrisko } else { 2061119156Sambrisko len = ssids->an_entry[ireq->i_val].an_len; 2062119156Sambrisko tmpptr = ssids->an_entry[ireq->i_val].an_ssid; 206377217Sphk } 206477217Sphk } else { 206577217Sphk error = EINVAL; 2066175445Sambrisko AN_UNLOCK(sc); 206777217Sphk break; 206877217Sphk } 206978639Sbrooks if (len > IEEE80211_NWID_LEN) { 207077217Sphk error = EINVAL; 2071175445Sambrisko AN_UNLOCK(sc); 207277217Sphk break; 207377217Sphk } 2074175445Sambrisko AN_UNLOCK(sc); 207577217Sphk ireq->i_len = len; 207677217Sphk bzero(tmpstr, IEEE80211_NWID_LEN); 207777217Sphk bcopy(tmpptr, tmpstr, len); 207877217Sphk error = copyout(tmpstr, ireq->i_data, 207977217Sphk IEEE80211_NWID_LEN); 208077217Sphk break; 208177217Sphk case IEEE80211_IOC_NUMSSIDS: 2082175445Sambrisko AN_LOCK(sc); 2083119156Sambrisko sc->areq.an_len = sizeof(sc->areq); 2084119156Sambrisko sc->areq.an_type = AN_RID_SSIDLIST; 2085119156Sambrisko if (an_read_record(sc, 2086119156Sambrisko (struct an_ltv_gen *)&sc->areq)) { 2087175445Sambrisko AN_UNLOCK(sc); 2088119156Sambrisko error = EINVAL; 2089119156Sambrisko break; 2090119156Sambrisko } 2091119156Sambrisko max = (sc->areq.an_len - 4) 2092119156Sambrisko / sizeof(struct an_ltv_ssid_entry); 2093175445Sambrisko AN_UNLOCK(sc); 2094119156Sambrisko if ( max > MAX_SSIDS ) { 2095119156Sambrisko printf("To many SSIDs only using " 2096119156Sambrisko "%d of %d\n", 2097119156Sambrisko MAX_SSIDS, max); 2098119156Sambrisko max = MAX_SSIDS; 2099119156Sambrisko } 2100119156Sambrisko ireq->i_val = max; 210177217Sphk break; 210277217Sphk case IEEE80211_IOC_WEP: 2103175445Sambrisko AN_LOCK(sc); 210488749Sambrisko sc->areq.an_type = AN_RID_ACTUALCFG; 210577217Sphk if (an_read_record(sc, 210688749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 210777217Sphk error = EINVAL; 2108175445Sambrisko AN_UNLOCK(sc); 210977217Sphk break; 211077217Sphk } 2111175445Sambrisko AN_UNLOCK(sc); 211278639Sbrooks if (config->an_authtype & AN_AUTHTYPE_PRIVACY_IN_USE) { 211378639Sbrooks if (config->an_authtype & 211477217Sphk AN_AUTHTYPE_ALLOW_UNENCRYPTED) 211577217Sphk ireq->i_val = IEEE80211_WEP_MIXED; 211677217Sphk else 211777217Sphk ireq->i_val = IEEE80211_WEP_ON; 211877217Sphk } else { 211977217Sphk ireq->i_val = IEEE80211_WEP_OFF; 212077217Sphk } 212177217Sphk break; 212277217Sphk case IEEE80211_IOC_WEPKEY: 212377217Sphk /* 212477217Sphk * XXX: I'm not entierly convinced this is 212577217Sphk * correct, but it's what is implemented in 212677217Sphk * ancontrol so it will have to do until we get 212777217Sphk * access to actual Cisco code. 212877217Sphk */ 212988748Sambrisko if (ireq->i_val < 0 || ireq->i_val > 8) { 213077217Sphk error = EINVAL; 213177217Sphk break; 213277217Sphk } 213377217Sphk len = 0; 213488748Sambrisko if (ireq->i_val < 5) { 2135175445Sambrisko AN_LOCK(sc); 213688749Sambrisko sc->areq.an_type = AN_RID_WEP_TEMP; 213778639Sbrooks for (i = 0; i < 5; i++) { 213877217Sphk if (an_read_record(sc, 213988749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 214077217Sphk error = EINVAL; 214177217Sphk break; 214277217Sphk } 214378639Sbrooks if (key->kindex == 0xffff) 214477217Sphk break; 214578639Sbrooks if (key->kindex == ireq->i_val) 214678639Sbrooks len = key->klen; 214777217Sphk /* Required to get next entry */ 214888749Sambrisko sc->areq.an_type = AN_RID_WEP_PERM; 214977217Sphk } 2150175445Sambrisko AN_UNLOCK(sc); 2151175445Sambrisko if (error != 0) { 215277217Sphk break; 2153175445Sambrisko } 215477217Sphk } 215577217Sphk /* We aren't allowed to read the value of the 215677217Sphk * key from the card so we just output zeros 215777217Sphk * like we would if we could read the card, but 215877217Sphk * denied the user access. 215977217Sphk */ 216077217Sphk bzero(tmpstr, len); 216177217Sphk ireq->i_len = len; 216277217Sphk error = copyout(tmpstr, ireq->i_data, len); 216377217Sphk break; 216477217Sphk case IEEE80211_IOC_NUMWEPKEYS: 216588748Sambrisko ireq->i_val = 9; /* include home key */ 216677217Sphk break; 216777217Sphk case IEEE80211_IOC_WEPTXKEY: 216878639Sbrooks /* 216978639Sbrooks * For some strange reason, you have to read all 217078639Sbrooks * keys before you can read the txkey. 217178639Sbrooks */ 2172175445Sambrisko AN_LOCK(sc); 217388749Sambrisko sc->areq.an_type = AN_RID_WEP_TEMP; 217478639Sbrooks for (i = 0; i < 5; i++) { 217578639Sbrooks if (an_read_record(sc, 217688749Sambrisko (struct an_ltv_gen *) &sc->areq)) { 217778639Sbrooks error = EINVAL; 217878639Sbrooks break; 217978639Sbrooks } 2180175445Sambrisko if (key->kindex == 0xffff) { 218178639Sbrooks break; 2182175445Sambrisko } 218378639Sbrooks /* Required to get next entry */ 218488749Sambrisko sc->areq.an_type = AN_RID_WEP_PERM; 218578639Sbrooks } 2186175445Sambrisko if (error != 0) { 2187175445Sambrisko AN_UNLOCK(sc); 218878639Sbrooks break; 2189175445Sambrisko } 219078639Sbrooks 219188749Sambrisko sc->areq.an_type = AN_RID_WEP_PERM; 219277217Sphk key->kindex = 0xffff; 219377217Sphk if (an_read_record(sc, 219488749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 219577217Sphk error = EINVAL; 2196175445Sambrisko AN_UNLOCK(sc); 219777217Sphk break; 219877217Sphk } 219977217Sphk ireq->i_val = key->mac[0]; 220088748Sambrisko /* 220188748Sambrisko * Check for home mode. Map home mode into 220288748Sambrisko * 5th key since that is how it is stored on 220388748Sambrisko * the card 220488748Sambrisko */ 220588749Sambrisko sc->areq.an_len = sizeof(struct an_ltv_genconfig); 220688749Sambrisko sc->areq.an_type = AN_RID_GENCONFIG; 220788748Sambrisko if (an_read_record(sc, 220888749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 220988748Sambrisko error = EINVAL; 2210175445Sambrisko AN_UNLOCK(sc); 221188748Sambrisko break; 221288748Sambrisko } 221388748Sambrisko if (config->an_home_product & AN_HOME_NETWORK) 221488748Sambrisko ireq->i_val = 4; 2215175445Sambrisko AN_UNLOCK(sc); 221677217Sphk break; 221777217Sphk case IEEE80211_IOC_AUTHMODE: 2218175445Sambrisko AN_LOCK(sc); 221988749Sambrisko sc->areq.an_type = AN_RID_ACTUALCFG; 222077217Sphk if (an_read_record(sc, 222188749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 222277217Sphk error = EINVAL; 2223175445Sambrisko AN_UNLOCK(sc); 222477217Sphk break; 222577217Sphk } 2226175445Sambrisko AN_UNLOCK(sc); 222777217Sphk if ((config->an_authtype & AN_AUTHTYPE_MASK) == 222877217Sphk AN_AUTHTYPE_NONE) { 222977217Sphk ireq->i_val = IEEE80211_AUTH_NONE; 223077217Sphk } else if ((config->an_authtype & AN_AUTHTYPE_MASK) == 223177217Sphk AN_AUTHTYPE_OPEN) { 223277217Sphk ireq->i_val = IEEE80211_AUTH_OPEN; 223377217Sphk } else if ((config->an_authtype & AN_AUTHTYPE_MASK) == 223477217Sphk AN_AUTHTYPE_SHAREDKEY) { 223577217Sphk ireq->i_val = IEEE80211_AUTH_SHARED; 223677217Sphk } else 223777217Sphk error = EINVAL; 223877217Sphk break; 223977217Sphk case IEEE80211_IOC_STATIONNAME: 2240175445Sambrisko AN_LOCK(sc); 224188749Sambrisko sc->areq.an_type = AN_RID_ACTUALCFG; 224277217Sphk if (an_read_record(sc, 224388749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 224477217Sphk error = EINVAL; 2245175445Sambrisko AN_UNLOCK(sc); 224677217Sphk break; 224777217Sphk } 2248175445Sambrisko AN_UNLOCK(sc); 224977217Sphk ireq->i_len = sizeof(config->an_nodename); 225077217Sphk tmpptr = config->an_nodename; 225177217Sphk bzero(tmpstr, IEEE80211_NWID_LEN); 225277217Sphk bcopy(tmpptr, tmpstr, ireq->i_len); 225377217Sphk error = copyout(tmpstr, ireq->i_data, 225477217Sphk IEEE80211_NWID_LEN); 225577217Sphk break; 225677217Sphk case IEEE80211_IOC_CHANNEL: 2257175445Sambrisko AN_LOCK(sc); 225888749Sambrisko sc->areq.an_type = AN_RID_STATUS; 225977217Sphk if (an_read_record(sc, 226088749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 226177217Sphk error = EINVAL; 2262175445Sambrisko AN_UNLOCK(sc); 226377217Sphk break; 226477217Sphk } 2265175445Sambrisko AN_UNLOCK(sc); 226677217Sphk ireq->i_val = status->an_cur_channel; 226777217Sphk break; 2268175445Sambrisko case IEEE80211_IOC_CURCHAN: 2269175445Sambrisko AN_LOCK(sc); 2270175445Sambrisko sc->areq.an_type = AN_RID_STATUS; 2271175445Sambrisko if (an_read_record(sc, 2272175445Sambrisko (struct an_ltv_gen *)&sc->areq)) { 2273172112Savatar error = EINVAL; 2274175445Sambrisko AN_UNLOCK(sc); 2275172112Savatar break; 2276172112Savatar } 2277175445Sambrisko AN_UNLOCK(sc); 2278172112Savatar bzero(&ch, sizeof(ch)); 2279172112Savatar ch.ic_freq = ieee80211_ieee2mhz(status->an_cur_channel, 2280172112Savatar IEEE80211_CHAN_B); 2281172112Savatar ch.ic_flags = IEEE80211_CHAN_B; 2282172112Savatar ch.ic_ieee = status->an_cur_channel; 2283172112Savatar error = copyout(&ch, ireq->i_data, sizeof(ch)); 2284172112Savatar break; 228577217Sphk case IEEE80211_IOC_POWERSAVE: 2286175445Sambrisko AN_LOCK(sc); 228788749Sambrisko sc->areq.an_type = AN_RID_ACTUALCFG; 228877217Sphk if (an_read_record(sc, 228988749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 229077217Sphk error = EINVAL; 2291175445Sambrisko AN_UNLOCK(sc); 229277217Sphk break; 229377217Sphk } 2294175445Sambrisko AN_UNLOCK(sc); 229578639Sbrooks if (config->an_psave_mode == AN_PSAVE_NONE) { 229677217Sphk ireq->i_val = IEEE80211_POWERSAVE_OFF; 229778639Sbrooks } else if (config->an_psave_mode == AN_PSAVE_CAM) { 229877217Sphk ireq->i_val = IEEE80211_POWERSAVE_CAM; 229978639Sbrooks } else if (config->an_psave_mode == AN_PSAVE_PSP) { 230077217Sphk ireq->i_val = IEEE80211_POWERSAVE_PSP; 230178639Sbrooks } else if (config->an_psave_mode == AN_PSAVE_PSP_CAM) { 230277217Sphk ireq->i_val = IEEE80211_POWERSAVE_PSP_CAM; 230377217Sphk } else 230477217Sphk error = EINVAL; 230577217Sphk break; 230677217Sphk case IEEE80211_IOC_POWERSAVESLEEP: 2307175445Sambrisko AN_LOCK(sc); 230888749Sambrisko sc->areq.an_type = AN_RID_ACTUALCFG; 230977217Sphk if (an_read_record(sc, 231088749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 231177217Sphk error = EINVAL; 2312175445Sambrisko AN_UNLOCK(sc); 231377217Sphk break; 231477217Sphk } 2315175445Sambrisko AN_UNLOCK(sc); 231677217Sphk ireq->i_val = config->an_listen_interval; 231777217Sphk break; 231883270Sbrooks } 231977217Sphk break; 232077217Sphk case SIOCS80211: 2321164033Srwatson if ((error = priv_check(td, PRIV_NET80211_MANAGE))) 232277217Sphk goto out; 2323175445Sambrisko AN_LOCK(sc); 232488749Sambrisko sc->areq.an_len = sizeof(sc->areq); 232577217Sphk /* 232677217Sphk * We need a config structure for everything but the WEP 232777217Sphk * key management and SSIDs so we get it now so avoid 232877217Sphk * duplicating this code every time. 232977217Sphk */ 233077217Sphk if (ireq->i_type != IEEE80211_IOC_SSID && 233177217Sphk ireq->i_type != IEEE80211_IOC_WEPKEY && 233277217Sphk ireq->i_type != IEEE80211_IOC_WEPTXKEY) { 233388749Sambrisko sc->areq.an_type = AN_RID_GENCONFIG; 233477217Sphk if (an_read_record(sc, 233588749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 233677217Sphk error = EINVAL; 2337175445Sambrisko AN_UNLOCK(sc); 233877217Sphk break; 233977217Sphk } 234077217Sphk } 234183270Sbrooks switch (ireq->i_type) { 234277217Sphk case IEEE80211_IOC_SSID: 2343119156Sambrisko sc->areq.an_len = sizeof(sc->areq); 234488749Sambrisko sc->areq.an_type = AN_RID_SSIDLIST; 234577217Sphk if (an_read_record(sc, 234688749Sambrisko (struct an_ltv_gen *)&sc->areq)) { 234777217Sphk error = EINVAL; 2348175445Sambrisko AN_UNLOCK(sc); 234977217Sphk break; 235077217Sphk } 235178639Sbrooks if (ireq->i_len > IEEE80211_NWID_LEN) { 235277217Sphk error = EINVAL; 2353175445Sambrisko AN_UNLOCK(sc); 235477217Sphk break; 235577217Sphk } 2356119156Sambrisko max = (sc->areq.an_len - 4) 2357119156Sambrisko / sizeof(struct an_ltv_ssid_entry); 2358119156Sambrisko if ( max > MAX_SSIDS ) { 2359119156Sambrisko printf("To many SSIDs only using " 2360119156Sambrisko "%d of %d\n", 2361119156Sambrisko MAX_SSIDS, max); 2362119156Sambrisko max = MAX_SSIDS; 2363119156Sambrisko } 2364119156Sambrisko if (ireq->i_val > max) { 2365119156Sambrisko error = EINVAL; 2366175445Sambrisko AN_UNLOCK(sc); 236777217Sphk break; 2368119156Sambrisko } else { 236977217Sphk error = copyin(ireq->i_data, 2370175445Sambrisko ssids->an_entry[ireq->i_val].an_ssid, 2371119156Sambrisko ireq->i_len); 2372175445Sambrisko ssids->an_entry[ireq->i_val].an_len 2373119156Sambrisko = ireq->i_len; 2374175445Sambrisko sc->areq.an_len = sizeof(sc->areq); 2375175445Sambrisko sc->areq.an_type = AN_RID_SSIDLIST; 2376175445Sambrisko an_setdef(sc, &sc->areq); 2377175445Sambrisko AN_UNLOCK(sc); 237877217Sphk break; 237977217Sphk } 238077217Sphk break; 238177217Sphk case IEEE80211_IOC_WEP: 238277217Sphk switch (ireq->i_val) { 238377217Sphk case IEEE80211_WEP_OFF: 238477217Sphk config->an_authtype &= 238577217Sphk ~(AN_AUTHTYPE_PRIVACY_IN_USE | 238677217Sphk AN_AUTHTYPE_ALLOW_UNENCRYPTED); 238777217Sphk break; 238877217Sphk case IEEE80211_WEP_ON: 238977217Sphk config->an_authtype |= 239077217Sphk AN_AUTHTYPE_PRIVACY_IN_USE; 239177217Sphk config->an_authtype &= 239277217Sphk ~AN_AUTHTYPE_ALLOW_UNENCRYPTED; 239377217Sphk break; 239477217Sphk case IEEE80211_WEP_MIXED: 239577217Sphk config->an_authtype |= 239677217Sphk AN_AUTHTYPE_PRIVACY_IN_USE | 239777217Sphk AN_AUTHTYPE_ALLOW_UNENCRYPTED; 239877217Sphk break; 239977217Sphk default: 240077217Sphk error = EINVAL; 240177217Sphk break; 240277217Sphk } 2403175445Sambrisko if (error != EINVAL) 2404175445Sambrisko an_setdef(sc, &sc->areq); 2405175445Sambrisko AN_UNLOCK(sc); 240677217Sphk break; 240777217Sphk case IEEE80211_IOC_WEPKEY: 2408110531Sambrisko if (ireq->i_val < 0 || ireq->i_val > 8 || 240977217Sphk ireq->i_len > 13) { 241077217Sphk error = EINVAL; 2411175445Sambrisko AN_UNLOCK(sc); 241277217Sphk break; 241377217Sphk } 241477217Sphk error = copyin(ireq->i_data, tmpstr, 13); 2415175445Sambrisko if (error != 0) { 2416175445Sambrisko AN_UNLOCK(sc); 241777217Sphk break; 2418175445Sambrisko } 2419110531Sambrisko /* 2420110531Sambrisko * Map the 9th key into the home mode 2421110531Sambrisko * since that is how it is stored on 2422110531Sambrisko * the card 2423110531Sambrisko */ 242488749Sambrisko bzero(&sc->areq, sizeof(struct an_ltv_key)); 242588749Sambrisko sc->areq.an_len = sizeof(struct an_ltv_key); 242677217Sphk key->mac[0] = 1; /* The others are 0. */ 2427110531Sambrisko if (ireq->i_val < 4) { 242888749Sambrisko sc->areq.an_type = AN_RID_WEP_TEMP; 2429110531Sambrisko key->kindex = ireq->i_val; 2430110531Sambrisko } else { 243188749Sambrisko sc->areq.an_type = AN_RID_WEP_PERM; 2432110531Sambrisko key->kindex = ireq->i_val - 4; 2433110531Sambrisko } 243477217Sphk key->klen = ireq->i_len; 243577217Sphk bcopy(tmpstr, key->key, key->klen); 2436175445Sambrisko an_setdef(sc, &sc->areq); 2437175445Sambrisko AN_UNLOCK(sc); 243877217Sphk break; 243977217Sphk case IEEE80211_IOC_WEPTXKEY: 2440110531Sambrisko if (ireq->i_val < 0 || ireq->i_val > 4) { 2441110531Sambrisko error = EINVAL; 2442175445Sambrisko AN_UNLOCK(sc); 2443110531Sambrisko break; 2444110531Sambrisko } 2445110531Sambrisko 244688748Sambrisko /* 244788748Sambrisko * Map the 5th key into the home mode 244888748Sambrisko * since that is how it is stored on 244988748Sambrisko * the card 245088748Sambrisko */ 245188749Sambrisko sc->areq.an_len = sizeof(struct an_ltv_genconfig); 245288749Sambrisko sc->areq.an_type = AN_RID_ACTUALCFG; 245388748Sambrisko if (an_read_record(sc, 2454175445Sambrisko (struct an_ltv_gen *)&sc->areq)) { 2455175445Sambrisko error = EINVAL; 2456175445Sambrisko AN_UNLOCK(sc); 245788748Sambrisko break; 245888748Sambrisko } 245988748Sambrisko if (ireq->i_val == 4) { 246088748Sambrisko config->an_home_product |= AN_HOME_NETWORK; 246188748Sambrisko ireq->i_val = 0; 246288748Sambrisko } else { 246388748Sambrisko config->an_home_product &= ~AN_HOME_NETWORK; 246488748Sambrisko } 246588748Sambrisko 246688748Sambrisko sc->an_config.an_home_product 246788748Sambrisko = config->an_home_product; 246888748Sambrisko 2469110531Sambrisko /* update configuration */ 2470199154Sjhb an_init_locked(sc); 2471110531Sambrisko 247288749Sambrisko bzero(&sc->areq, sizeof(struct an_ltv_key)); 247388749Sambrisko sc->areq.an_len = sizeof(struct an_ltv_key); 247488749Sambrisko sc->areq.an_type = AN_RID_WEP_PERM; 247577217Sphk key->kindex = 0xffff; 247677217Sphk key->mac[0] = ireq->i_val; 2477175445Sambrisko an_setdef(sc, &sc->areq); 2478175445Sambrisko AN_UNLOCK(sc); 247977217Sphk break; 248077217Sphk case IEEE80211_IOC_AUTHMODE: 248177217Sphk switch (ireq->i_val) { 248277217Sphk case IEEE80211_AUTH_NONE: 248377217Sphk config->an_authtype = AN_AUTHTYPE_NONE | 248477217Sphk (config->an_authtype & ~AN_AUTHTYPE_MASK); 248577217Sphk break; 248677217Sphk case IEEE80211_AUTH_OPEN: 248777217Sphk config->an_authtype = AN_AUTHTYPE_OPEN | 248877217Sphk (config->an_authtype & ~AN_AUTHTYPE_MASK); 248977217Sphk break; 249077217Sphk case IEEE80211_AUTH_SHARED: 249177217Sphk config->an_authtype = AN_AUTHTYPE_SHAREDKEY | 249277217Sphk (config->an_authtype & ~AN_AUTHTYPE_MASK); 249377217Sphk break; 249477217Sphk default: 249577217Sphk error = EINVAL; 249677217Sphk } 2497175445Sambrisko if (error != EINVAL) { 2498175445Sambrisko an_setdef(sc, &sc->areq); 2499175445Sambrisko } 2500175445Sambrisko AN_UNLOCK(sc); 250177217Sphk break; 250277217Sphk case IEEE80211_IOC_STATIONNAME: 250378639Sbrooks if (ireq->i_len > 16) { 250477217Sphk error = EINVAL; 2505175445Sambrisko AN_UNLOCK(sc); 250677217Sphk break; 250777217Sphk } 250877217Sphk bzero(config->an_nodename, 16); 250977217Sphk error = copyin(ireq->i_data, 251077217Sphk config->an_nodename, ireq->i_len); 2511175445Sambrisko an_setdef(sc, &sc->areq); 2512175445Sambrisko AN_UNLOCK(sc); 251377217Sphk break; 251477217Sphk case IEEE80211_IOC_CHANNEL: 251577217Sphk /* 251677217Sphk * The actual range is 1-14, but if you set it 251777217Sphk * to 0 you get the default so we let that work 251877217Sphk * too. 251977217Sphk */ 252077217Sphk if (ireq->i_val < 0 || ireq->i_val >14) { 252177217Sphk error = EINVAL; 2522175445Sambrisko AN_UNLOCK(sc); 252377217Sphk break; 252477217Sphk } 252577217Sphk config->an_ds_channel = ireq->i_val; 2526175445Sambrisko an_setdef(sc, &sc->areq); 2527175445Sambrisko AN_UNLOCK(sc); 252877217Sphk break; 252977217Sphk case IEEE80211_IOC_POWERSAVE: 253077217Sphk switch (ireq->i_val) { 253177217Sphk case IEEE80211_POWERSAVE_OFF: 253277217Sphk config->an_psave_mode = AN_PSAVE_NONE; 253377217Sphk break; 253477217Sphk case IEEE80211_POWERSAVE_CAM: 253577217Sphk config->an_psave_mode = AN_PSAVE_CAM; 253677217Sphk break; 253777217Sphk case IEEE80211_POWERSAVE_PSP: 253877217Sphk config->an_psave_mode = AN_PSAVE_PSP; 253977217Sphk break; 254077217Sphk case IEEE80211_POWERSAVE_PSP_CAM: 254177217Sphk config->an_psave_mode = AN_PSAVE_PSP_CAM; 254277217Sphk break; 254377217Sphk default: 254477217Sphk error = EINVAL; 254577217Sphk break; 254677217Sphk } 2547175445Sambrisko an_setdef(sc, &sc->areq); 2548175445Sambrisko AN_UNLOCK(sc); 254977217Sphk break; 255077217Sphk case IEEE80211_IOC_POWERSAVESLEEP: 255177217Sphk config->an_listen_interval = ireq->i_val; 2552175445Sambrisko an_setdef(sc, &sc->areq); 2553175445Sambrisko AN_UNLOCK(sc); 255477217Sphk break; 2555199154Sjhb default: 2556199154Sjhb AN_UNLOCK(sc); 2557199154Sjhb break; 255877217Sphk } 255977217Sphk 2560175445Sambrisko /* 2561175445Sambrisko if (!error) { 2562175445Sambrisko AN_LOCK(sc); 256388749Sambrisko an_setdef(sc, &sc->areq); 2564175445Sambrisko AN_UNLOCK(sc); 2565175445Sambrisko } 2566175445Sambrisko */ 256777217Sphk break; 256855992Swpaul default: 2569106937Ssam error = ether_ioctl(ifp, command, data); 257055992Swpaul break; 257155992Swpaul } 257261816Srobertoout: 257355992Swpaul 257478639Sbrooks return(error != 0); 257555992Swpaul} 257655992Swpaul 257783270Sbrooksstatic int 2578150446Simpan_init_tx_ring(struct an_softc *sc) 257955992Swpaul{ 258055992Swpaul int i; 258155992Swpaul int id; 258255992Swpaul 258355992Swpaul if (sc->an_gone) 258455992Swpaul return (0); 258555992Swpaul 2586108401Sambrisko if (!sc->mpi350) { 2587108401Sambrisko for (i = 0; i < AN_TX_RING_CNT; i++) { 2588108401Sambrisko if (an_alloc_nicmem(sc, 1518 + 2589108401Sambrisko 0x44, &id)) 2590108401Sambrisko return(ENOMEM); 2591108401Sambrisko sc->an_rdata.an_tx_fids[i] = id; 2592108401Sambrisko sc->an_rdata.an_tx_ring[i] = 0; 2593108401Sambrisko } 259455992Swpaul } 259555992Swpaul 259655992Swpaul sc->an_rdata.an_tx_prod = 0; 259755992Swpaul sc->an_rdata.an_tx_cons = 0; 2598108401Sambrisko sc->an_rdata.an_tx_empty = 1; 259955992Swpaul 260055992Swpaul return(0); 260155992Swpaul} 260255992Swpaul 260383270Sbrooksstatic void 2604150446Simpan_init(void *xsc) 260555992Swpaul{ 260655992Swpaul struct an_softc *sc = xsc; 260755992Swpaul 260867094Swpaul AN_LOCK(sc); 2609199154Sjhb an_init_locked(sc); 2610199154Sjhb AN_UNLOCK(sc); 2611199154Sjhb} 261267094Swpaul 2613199154Sjhbstatic void 2614199154Sjhban_init_locked(struct an_softc *sc) 2615199154Sjhb{ 2616199154Sjhb struct ifnet *ifp; 2617199154Sjhb 2618199154Sjhb AN_LOCK_ASSERT(sc); 2619199154Sjhb ifp = sc->an_ifp; 2620199154Sjhb if (sc->an_gone) 262155992Swpaul return; 262255992Swpaul 2623148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 262455992Swpaul an_stop(sc); 262555992Swpaul 262655992Swpaul sc->an_associated = 0; 262755992Swpaul 262855992Swpaul /* Allocate the TX buffers */ 262955992Swpaul if (an_init_tx_ring(sc)) { 263055992Swpaul an_reset(sc); 2631108401Sambrisko if (sc->mpi350) 2632175445Sambrisko an_init_mpi350_desc(sc); 263355992Swpaul if (an_init_tx_ring(sc)) { 2634198987Sjhb if_printf(ifp, "tx buffer allocation failed\n"); 263555992Swpaul return; 263655992Swpaul } 263755992Swpaul } 263855992Swpaul 263955992Swpaul /* Set our MAC address. */ 2640152315Sru bcopy((char *)IF_LLADDR(sc->an_ifp), 264155992Swpaul (char *)&sc->an_config.an_macaddr, ETHER_ADDR_LEN); 264255992Swpaul 264355992Swpaul if (ifp->if_flags & IFF_BROADCAST) 264455992Swpaul sc->an_config.an_rxmode = AN_RXMODE_BC_ADDR; 264555992Swpaul else 264655992Swpaul sc->an_config.an_rxmode = AN_RXMODE_ADDR; 264755992Swpaul 264855992Swpaul if (ifp->if_flags & IFF_MULTICAST) 264955992Swpaul sc->an_config.an_rxmode = AN_RXMODE_BC_MC_ADDR; 265055992Swpaul 265183269Sbrooks if (ifp->if_flags & IFF_PROMISC) { 265283269Sbrooks if (sc->an_monitor & AN_MONITOR) { 265383269Sbrooks if (sc->an_monitor & AN_MONITOR_ANY_BSS) { 265483269Sbrooks sc->an_config.an_rxmode |= 265583269Sbrooks AN_RXMODE_80211_MONITOR_ANYBSS | 265683269Sbrooks AN_RXMODE_NO_8023_HEADER; 265783269Sbrooks } else { 265883269Sbrooks sc->an_config.an_rxmode |= 265983269Sbrooks AN_RXMODE_80211_MONITOR_CURBSS | 266083269Sbrooks AN_RXMODE_NO_8023_HEADER; 266183269Sbrooks } 266283269Sbrooks } 266383269Sbrooks } 266455992Swpaul 2665184708Sbz#ifdef ANCACHE 2666108401Sambrisko if (sc->an_have_rssimap) 2667108401Sambrisko sc->an_config.an_rxmode |= AN_RXMODE_NORMALIZED_RSSI; 2668184708Sbz#endif 2669108401Sambrisko 267055992Swpaul /* Set the ssid list */ 267155992Swpaul sc->an_ssidlist.an_type = AN_RID_SSIDLIST; 2672119156Sambrisko sc->an_ssidlist.an_len = sizeof(struct an_ltv_ssidlist_new); 267355992Swpaul if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_ssidlist)) { 2674198987Sjhb if_printf(ifp, "failed to set ssid list\n"); 267555992Swpaul return; 267655992Swpaul } 267755992Swpaul 267855992Swpaul /* Set the AP list */ 267955992Swpaul sc->an_aplist.an_type = AN_RID_APLIST; 268055992Swpaul sc->an_aplist.an_len = sizeof(struct an_ltv_aplist); 268155992Swpaul if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_aplist)) { 2682198987Sjhb if_printf(ifp, "failed to set AP list\n"); 268355992Swpaul return; 268455992Swpaul } 268555992Swpaul 268655992Swpaul /* Set the configuration in the NIC */ 268755992Swpaul sc->an_config.an_len = sizeof(struct an_ltv_genconfig); 268855992Swpaul sc->an_config.an_type = AN_RID_GENCONFIG; 268955992Swpaul if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_config)) { 2690198987Sjhb if_printf(ifp, "failed to set configuration\n"); 269155992Swpaul return; 269255992Swpaul } 269355992Swpaul 269455992Swpaul /* Enable the MAC */ 269555992Swpaul if (an_cmd(sc, AN_CMD_ENABLE, 0)) { 2696198987Sjhb if_printf(ifp, "failed to enable MAC\n"); 269755992Swpaul return; 269855992Swpaul } 269955992Swpaul 270074698Sarchie if (ifp->if_flags & IFF_PROMISC) 270174698Sarchie an_cmd(sc, AN_CMD_SET_MODE, 0xffff); 270274698Sarchie 270355992Swpaul /* enable interrupts */ 2704119156Sambrisko CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), AN_INTRS(sc->mpi350)); 270555992Swpaul 2706148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 2707148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 270855992Swpaul 2709173668Savatar callout_reset(&sc->an_stat_ch, hz, an_stats_update, sc); 271055992Swpaul 271155992Swpaul return; 271255992Swpaul} 271355992Swpaul 271483270Sbrooksstatic void 2715150446Simpan_start(struct ifnet *ifp) 271655992Swpaul{ 271755992Swpaul struct an_softc *sc; 2718199154Sjhb 2719199154Sjhb sc = ifp->if_softc; 2720199154Sjhb AN_LOCK(sc); 2721199154Sjhb an_start_locked(ifp); 2722199154Sjhb AN_UNLOCK(sc); 2723199154Sjhb} 2724199154Sjhb 2725199154Sjhbstatic void 2726199154Sjhban_start_locked(struct ifnet *ifp) 2727199154Sjhb{ 2728199154Sjhb struct an_softc *sc; 272955992Swpaul struct mbuf *m0 = NULL; 273055992Swpaul struct an_txframe_802_3 tx_frame_802_3; 273155992Swpaul struct ether_header *eh; 2732108401Sambrisko int id, idx, i; 2733175446Sambrisko unsigned char txcontrol; 2734108401Sambrisko struct an_card_tx_desc an_tx_desc; 2735108401Sambrisko u_int8_t *buf; 273655992Swpaul 273755992Swpaul sc = ifp->if_softc; 273855992Swpaul 2739199154Sjhb AN_LOCK_ASSERT(sc); 274055992Swpaul if (sc->an_gone) 274155992Swpaul return; 274255992Swpaul 2743148887Srwatson if (ifp->if_drv_flags & IFF_DRV_OACTIVE) 274455992Swpaul return; 274555992Swpaul 274655992Swpaul if (!sc->an_associated) 274755992Swpaul return; 274855992Swpaul 274990990Sbrooks /* We can't send in monitor mode so toss any attempts. */ 275083269Sbrooks if (sc->an_monitor && (ifp->if_flags & IFF_PROMISC)) { 275183270Sbrooks for (;;) { 2752132986Smlaier IFQ_DRV_DEQUEUE(&ifp->if_snd, m0); 275383269Sbrooks if (m0 == NULL) 275483269Sbrooks break; 275590990Sbrooks m_freem(m0); 275683269Sbrooks } 275783269Sbrooks return; 275883269Sbrooks } 275983269Sbrooks 276055992Swpaul idx = sc->an_rdata.an_tx_prod; 276155992Swpaul 2762108401Sambrisko if (!sc->mpi350) { 2763108401Sambrisko bzero((char *)&tx_frame_802_3, sizeof(tx_frame_802_3)); 276455992Swpaul 2765108401Sambrisko while (sc->an_rdata.an_tx_ring[idx] == 0) { 2766132986Smlaier IFQ_DRV_DEQUEUE(&ifp->if_snd, m0); 2767108401Sambrisko if (m0 == NULL) 2768108401Sambrisko break; 276955992Swpaul 2770108401Sambrisko id = sc->an_rdata.an_tx_fids[idx]; 2771108401Sambrisko eh = mtod(m0, struct ether_header *); 277283270Sbrooks 2773108401Sambrisko bcopy((char *)&eh->ether_dhost, 2774175445Sambrisko (char *)&tx_frame_802_3.an_tx_dst_addr, 2775108401Sambrisko ETHER_ADDR_LEN); 2776108401Sambrisko bcopy((char *)&eh->ether_shost, 2777175445Sambrisko (char *)&tx_frame_802_3.an_tx_src_addr, 2778108401Sambrisko ETHER_ADDR_LEN); 277955992Swpaul 2780108401Sambrisko /* minus src/dest mac & type */ 2781108401Sambrisko tx_frame_802_3.an_tx_802_3_payload_len = 2782175445Sambrisko m0->m_pkthdr.len - 12; 278355992Swpaul 2784108401Sambrisko m_copydata(m0, sizeof(struct ether_header) - 2 , 2785108401Sambrisko tx_frame_802_3.an_tx_802_3_payload_len, 2786108401Sambrisko (caddr_t)&sc->an_txbuf); 2787108401Sambrisko 2788199757Sjhb txcontrol = AN_TXCTL_8023 | AN_TXCTL_HW(sc->mpi350); 2789108401Sambrisko /* write the txcontrol only */ 2790108401Sambrisko an_write_data(sc, id, 0x08, (caddr_t)&txcontrol, 2791108401Sambrisko sizeof(txcontrol)); 2792108401Sambrisko 2793108401Sambrisko /* 802_3 header */ 2794108401Sambrisko an_write_data(sc, id, 0x34, (caddr_t)&tx_frame_802_3, 2795108401Sambrisko sizeof(struct an_txframe_802_3)); 2796108401Sambrisko 2797108401Sambrisko /* in mbuf header type is just before payload */ 2798108401Sambrisko an_write_data(sc, id, 0x44, (caddr_t)&sc->an_txbuf, 2799108401Sambrisko tx_frame_802_3.an_tx_802_3_payload_len); 2800108401Sambrisko 2801108401Sambrisko /* 2802108401Sambrisko * If there's a BPF listner, bounce a copy of 2803108401Sambrisko * this frame to him. 2804108401Sambrisko */ 2805108401Sambrisko BPF_MTAP(ifp, m0); 2806108401Sambrisko 2807108401Sambrisko m_freem(m0); 2808108401Sambrisko m0 = NULL; 2809108401Sambrisko 2810108401Sambrisko sc->an_rdata.an_tx_ring[idx] = id; 2811108401Sambrisko if (an_cmd(sc, AN_CMD_TX, id)) 2812198987Sjhb if_printf(ifp, "xmit failed\n"); 2813108401Sambrisko 2814108401Sambrisko AN_INC(idx, AN_TX_RING_CNT); 2815119156Sambrisko 2816119156Sambrisko /* 2817119156Sambrisko * Set a timeout in case the chip goes out to lunch. 2818119156Sambrisko */ 2819199154Sjhb sc->an_timer = 5; 2820108401Sambrisko } 2821108401Sambrisko } else { /* MPI-350 */ 2822130620Sambrisko /* Disable interrupts. */ 2823130620Sambrisko CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0); 2824130620Sambrisko 2825108401Sambrisko while (sc->an_rdata.an_tx_empty || 2826108401Sambrisko idx != sc->an_rdata.an_tx_cons) { 2827132986Smlaier IFQ_DRV_DEQUEUE(&ifp->if_snd, m0); 2828108401Sambrisko if (m0 == NULL) { 2829108401Sambrisko break; 2830108401Sambrisko } 2831108401Sambrisko buf = sc->an_tx_buffer[idx].an_dma_vaddr; 2832108401Sambrisko 2833108401Sambrisko eh = mtod(m0, struct ether_header *); 2834108401Sambrisko 2835108401Sambrisko /* DJA optimize this to limit bcopy */ 2836108401Sambrisko bcopy((char *)&eh->ether_dhost, 2837175445Sambrisko (char *)&tx_frame_802_3.an_tx_dst_addr, 2838108401Sambrisko ETHER_ADDR_LEN); 2839108401Sambrisko bcopy((char *)&eh->ether_shost, 2840175445Sambrisko (char *)&tx_frame_802_3.an_tx_src_addr, 2841108401Sambrisko ETHER_ADDR_LEN); 2842108401Sambrisko 2843108401Sambrisko /* minus src/dest mac & type */ 2844108401Sambrisko tx_frame_802_3.an_tx_802_3_payload_len = 2845175445Sambrisko m0->m_pkthdr.len - 12; 2846108401Sambrisko 2847108401Sambrisko m_copydata(m0, sizeof(struct ether_header) - 2 , 2848108401Sambrisko tx_frame_802_3.an_tx_802_3_payload_len, 2849108401Sambrisko (caddr_t)&sc->an_txbuf); 2850108401Sambrisko 2851199757Sjhb txcontrol = AN_TXCTL_8023 | AN_TXCTL_HW(sc->mpi350); 2852108401Sambrisko /* write the txcontrol only */ 2853108401Sambrisko bcopy((caddr_t)&txcontrol, &buf[0x08], 285455992Swpaul sizeof(txcontrol)); 285583270Sbrooks 2856108401Sambrisko /* 802_3 header */ 2857108401Sambrisko bcopy((caddr_t)&tx_frame_802_3, &buf[0x34], 285855992Swpaul sizeof(struct an_txframe_802_3)); 285983270Sbrooks 2860108401Sambrisko /* in mbuf header type is just before payload */ 2861108401Sambrisko bcopy((caddr_t)&sc->an_txbuf, &buf[0x44], 2862108401Sambrisko tx_frame_802_3.an_tx_802_3_payload_len); 286383270Sbrooks 286455992Swpaul 2865108401Sambrisko bzero(&an_tx_desc, sizeof(an_tx_desc)); 2866108401Sambrisko an_tx_desc.an_offset = 0; 2867108401Sambrisko an_tx_desc.an_eoc = 1; 2868108401Sambrisko an_tx_desc.an_valid = 1; 2869108401Sambrisko an_tx_desc.an_len = 0x44 + 2870119156Sambrisko tx_frame_802_3.an_tx_802_3_payload_len; 2871175445Sambrisko an_tx_desc.an_phys 2872119156Sambrisko = sc->an_tx_buffer[idx].an_dma_paddr; 2873199757Sjhb for (i = sizeof(an_tx_desc) / 4 - 1; i >= 0; i--) { 2874119156Sambrisko CSR_MEM_AUX_WRITE_4(sc, AN_TX_DESC_OFFSET 2875175445Sambrisko /* zero for now */ 2876119156Sambrisko + (0 * sizeof(an_tx_desc)) 2877119156Sambrisko + (i * 4), 2878155321Simp ((u_int32_t *)(void *)&an_tx_desc)[i]); 2879108401Sambrisko } 288055992Swpaul 2881108401Sambrisko /* 2882108401Sambrisko * If there's a BPF listner, bounce a copy of 2883108401Sambrisko * this frame to him. 2884108401Sambrisko */ 2885108401Sambrisko BPF_MTAP(ifp, m0); 288655992Swpaul 2887108401Sambrisko m_freem(m0); 2888108401Sambrisko m0 = NULL; 2889119156Sambrisko AN_INC(idx, AN_MAX_TX_DESC); 2890119156Sambrisko sc->an_rdata.an_tx_empty = 0; 2891108401Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_ALLOC); 2892108401Sambrisko 2893119156Sambrisko /* 2894119156Sambrisko * Set a timeout in case the chip goes out to lunch. 2895119156Sambrisko */ 2896199154Sjhb sc->an_timer = 5; 2897108401Sambrisko } 2898130620Sambrisko 2899130620Sambrisko /* Re-enable interrupts. */ 2900130620Sambrisko CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), AN_INTRS(sc->mpi350)); 290155992Swpaul } 290255992Swpaul 290355992Swpaul if (m0 != NULL) 2904148887Srwatson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 290555992Swpaul 290655992Swpaul sc->an_rdata.an_tx_prod = idx; 290755992Swpaul 290855992Swpaul return; 290955992Swpaul} 291055992Swpaul 291183270Sbrooksvoid 2912150446Simpan_stop(struct an_softc *sc) 291355992Swpaul{ 291455992Swpaul struct ifnet *ifp; 291555992Swpaul int i; 291655992Swpaul 2917199154Sjhb AN_LOCK_ASSERT(sc); 291867094Swpaul 2919199154Sjhb if (sc->an_gone) 292055992Swpaul return; 292155992Swpaul 2922147256Sbrooks ifp = sc->an_ifp; 292355992Swpaul 292455992Swpaul an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0); 2925108401Sambrisko CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0); 292655992Swpaul an_cmd(sc, AN_CMD_DISABLE, 0); 292755992Swpaul 292855992Swpaul for (i = 0; i < AN_TX_RING_CNT; i++) 292955992Swpaul an_cmd(sc, AN_CMD_DEALLOC_MEM, sc->an_rdata.an_tx_fids[i]); 293055992Swpaul 2931173668Savatar callout_stop(&sc->an_stat_ch); 293255992Swpaul 2933148887Srwatson ifp->if_drv_flags &= ~(IFF_DRV_RUNNING|IFF_DRV_OACTIVE); 293455992Swpaul 2935108401Sambrisko if (sc->an_flash_buffer) { 2936108401Sambrisko free(sc->an_flash_buffer, M_DEVBUF); 2937108401Sambrisko sc->an_flash_buffer = NULL; 2938108401Sambrisko } 293955992Swpaul} 294055992Swpaul 294183270Sbrooksstatic void 2942199154Sjhban_watchdog(struct an_softc *sc) 294355992Swpaul{ 2944199154Sjhb struct ifnet *ifp; 294555992Swpaul 2946199154Sjhb AN_LOCK_ASSERT(sc); 294755992Swpaul 2948199154Sjhb if (sc->an_gone) 294955992Swpaul return; 295055992Swpaul 2951199154Sjhb ifp = sc->an_ifp; 2952198987Sjhb if_printf(ifp, "device timeout\n"); 295355992Swpaul 295455992Swpaul an_reset(sc); 2955108401Sambrisko if (sc->mpi350) 2956175445Sambrisko an_init_mpi350_desc(sc); 2957199154Sjhb an_init_locked(sc); 295855992Swpaul 2959271849Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 296055992Swpaul} 296155992Swpaul 2962188128Simpint 2963150446Simpan_shutdown(device_t dev) 296455992Swpaul{ 296555992Swpaul struct an_softc *sc; 296655992Swpaul 296755992Swpaul sc = device_get_softc(dev); 2968199154Sjhb AN_LOCK(sc); 296955992Swpaul an_stop(sc); 2970110531Sambrisko sc->an_gone = 1; 2971199154Sjhb AN_UNLOCK(sc); 297255992Swpaul 2973199154Sjhb return (0); 297455992Swpaul} 297555992Swpaul 2976110362Sambriskovoid 2977150446Simpan_resume(device_t dev) 2978110362Sambrisko{ 2979110362Sambrisko struct an_softc *sc; 2980110362Sambrisko struct ifnet *ifp; 2981110531Sambrisko int i; 2982110531Sambrisko 2983110362Sambrisko sc = device_get_softc(dev); 2984110531Sambrisko AN_LOCK(sc); 2985147256Sbrooks ifp = sc->an_ifp; 2986110362Sambrisko 2987110531Sambrisko sc->an_gone = 0; 2988110362Sambrisko an_reset(sc); 2989110362Sambrisko if (sc->mpi350) 2990175445Sambrisko an_init_mpi350_desc(sc); 2991199154Sjhb an_init_locked(sc); 2992110362Sambrisko 2993110531Sambrisko /* Recovery temporary keys */ 2994110531Sambrisko for (i = 0; i < 4; i++) { 2995110531Sambrisko sc->areq.an_type = AN_RID_WEP_TEMP; 2996175445Sambrisko sc->areq.an_len = sizeof(struct an_ltv_key); 2997110531Sambrisko bcopy(&sc->an_temp_keys[i], 2998110531Sambrisko &sc->areq, sizeof(struct an_ltv_key)); 2999110531Sambrisko an_setdef(sc, &sc->areq); 3000110531Sambrisko } 3001110531Sambrisko 3002110362Sambrisko if (ifp->if_flags & IFF_UP) 3003199154Sjhb an_start_locked(ifp); 3004110531Sambrisko AN_UNLOCK(sc); 3005110362Sambrisko 3006110362Sambrisko return; 3007110362Sambrisko} 3008110362Sambrisko 300955992Swpaul#ifdef ANCACHE 301055992Swpaul/* Aironet signal strength cache code. 301155992Swpaul * store signal/noise/quality on per MAC src basis in 301255992Swpaul * a small fixed cache. The cache wraps if > MAX slots 301355992Swpaul * used. The cache may be zeroed out to start over. 301455992Swpaul * Two simple filters exist to reduce computation: 301588748Sambrisko * 1. ip only (literally 0x800, ETHERTYPE_IP) which may be used 301655992Swpaul * to ignore some packets. It defaults to ip only. 301755992Swpaul * it could be used to focus on broadcast, non-IP 802.11 beacons. 301855992Swpaul * 2. multicast/broadcast only. This may be used to 301955992Swpaul * ignore unicast packets and only cache signal strength 302055992Swpaul * for multicast/broadcast packets (beacons); e.g., Mobile-IP 302155992Swpaul * beacons and not unicast traffic. 302255992Swpaul * 302355992Swpaul * The cache stores (MAC src(index), IP src (major clue), signal, 302455992Swpaul * quality, noise) 302555992Swpaul * 302655992Swpaul * No apologies for storing IP src here. It's easy and saves much 302783270Sbrooks * trouble elsewhere. The cache is assumed to be INET dependent, 302855992Swpaul * although it need not be. 302955992Swpaul * 303055992Swpaul * Note: the Aironet only has a single byte of signal strength value 303155992Swpaul * in the rx frame header, and it's not scaled to anything sensible. 303255992Swpaul * This is kind of lame, but it's all we've got. 303355992Swpaul */ 303455992Swpaul 303555992Swpaul#ifdef documentation 303655992Swpaul 3037175446Sambriskoint an_sigitems; /* number of cached entries */ 3038175446Sambriskostruct an_sigcache an_sigcache[MAXANCACHE]; /* array of cache entries */ 3039175446Sambriskoint an_nextitem; /* index/# of entries */ 304055992Swpaul 304155992Swpaul 304255992Swpaul#endif 304355992Swpaul 304455992Swpaul/* control variables for cache filtering. Basic idea is 304555992Swpaul * to reduce cost (e.g., to only Mobile-IP agent beacons 304655992Swpaul * which are broadcast or multicast). Still you might 304755992Swpaul * want to measure signal strength anth unicast ping packets 304855992Swpaul * on a pt. to pt. ant. setup. 304955992Swpaul */ 305083270Sbrooks/* set true if you want to limit cache items to broadcast/mcast 305155992Swpaul * only packets (not unicast). Useful for mobile-ip beacons which 305255992Swpaul * are broadcast/multicast at network layer. Default is all packets 305355992Swpaul * so ping/unicast anll work say anth pt. to pt. antennae setup. 305455992Swpaul */ 305555992Swpaulstatic int an_cache_mcastonly = 0; 3056110531SambriskoSYSCTL_INT(_hw_an, OID_AUTO, an_cache_mcastonly, CTLFLAG_RW, 305755992Swpaul &an_cache_mcastonly, 0, ""); 305855992Swpaul 305955992Swpaul/* set true if you want to limit cache items to IP packets only 306055992Swpaul*/ 306155992Swpaulstatic int an_cache_iponly = 1; 3062110531SambriskoSYSCTL_INT(_hw_an, OID_AUTO, an_cache_iponly, CTLFLAG_RW, 306355992Swpaul &an_cache_iponly, 0, ""); 306455992Swpaul 306555992Swpaul/* 306655992Swpaul * an_cache_store, per rx packet store signal 306755992Swpaul * strength in MAC (src) indexed cache. 306855992Swpaul */ 306983270Sbrooksstatic void 3070150446Simpan_cache_store(struct an_softc *sc, struct ether_header *eh, struct mbuf *m, 3071150446Simp u_int8_t rx_rssi, u_int8_t rx_quality) 307255992Swpaul{ 3073315221Spfg struct ip *ip = NULL; 307455992Swpaul int i; 307555992Swpaul static int cache_slot = 0; /* use this cache entry */ 3076175446Sambrisko static int wrapindex = 0; /* next "free" cache entry */ 307788748Sambrisko int type_ipv4 = 0; 307855992Swpaul 307955992Swpaul /* filters: 308055992Swpaul * 1. ip only 308155992Swpaul * 2. configurable filter to throw out unicast packets, 308255992Swpaul * keep multicast only. 308355992Swpaul */ 308483270Sbrooks 308588748Sambrisko if ((ntohs(eh->ether_type) == ETHERTYPE_IP)) { 308688748Sambrisko type_ipv4 = 1; 308755992Swpaul } 308855992Swpaul 308983270Sbrooks /* filter for ip packets only 309055992Swpaul */ 309188748Sambrisko if ( an_cache_iponly && !type_ipv4) { 309255992Swpaul return; 309355992Swpaul } 309455992Swpaul 309555992Swpaul /* filter for broadcast/multicast only 309655992Swpaul */ 309755992Swpaul if (an_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) { 309855992Swpaul return; 309955992Swpaul } 310055992Swpaul 310155992Swpaul#ifdef SIGDEBUG 3102198987Sjhb if_printf(sc->an_ifp, "q value %x (MSB=0x%x, LSB=0x%x) \n", 3103108401Sambrisko rx_rssi & 0xffff, rx_rssi >> 8, rx_rssi & 0xff); 310455992Swpaul#endif 310555992Swpaul 310655992Swpaul /* find the ip header. we want to store the ip_src 310783270Sbrooks * address. 310855992Swpaul */ 310988748Sambrisko if (type_ipv4) { 311055992Swpaul ip = mtod(m, struct ip *); 311155992Swpaul } 311283270Sbrooks 311383270Sbrooks /* do a linear search for a matching MAC address 311455992Swpaul * in the cache table 311555992Swpaul * . MAC address is 6 bytes, 311655992Swpaul * . var w_nextitem holds total number of entries already cached 311755992Swpaul */ 311878639Sbrooks for (i = 0; i < sc->an_nextitem; i++) { 311955992Swpaul if (! bcmp(eh->ether_shost , sc->an_sigcache[i].macsrc, 6 )) { 312055992Swpaul /* Match!, 312155992Swpaul * so we already have this entry, 312255992Swpaul * update the data 312355992Swpaul */ 312483270Sbrooks break; 312555992Swpaul } 312655992Swpaul } 312755992Swpaul 312855992Swpaul /* did we find a matching mac address? 312955992Swpaul * if yes, then overwrite a previously existing cache entry 313055992Swpaul */ 313155992Swpaul if (i < sc->an_nextitem ) { 313283270Sbrooks cache_slot = i; 313355992Swpaul } 313455992Swpaul /* else, have a new address entry,so 313555992Swpaul * add this new entry, 313655992Swpaul * if table full, then we need to replace LRU entry 313755992Swpaul */ 313883270Sbrooks else { 313955992Swpaul 314083270Sbrooks /* check for space in cache table 314155992Swpaul * note: an_nextitem also holds number of entries 314283270Sbrooks * added in the cache table 314355992Swpaul */ 314455992Swpaul if ( sc->an_nextitem < MAXANCACHE ) { 314555992Swpaul cache_slot = sc->an_nextitem; 314683270Sbrooks sc->an_nextitem++; 314755992Swpaul sc->an_sigitems = sc->an_nextitem; 314855992Swpaul } 3149175446Sambrisko /* no space found, so simply wrap anth wrap index 315055992Swpaul * and "zap" the next entry 315155992Swpaul */ 315255992Swpaul else { 315355992Swpaul if (wrapindex == MAXANCACHE) { 315455992Swpaul wrapindex = 0; 315555992Swpaul } 315655992Swpaul cache_slot = wrapindex++; 315755992Swpaul } 315855992Swpaul } 315955992Swpaul 316055992Swpaul /* invariant: cache_slot now points at some slot 316155992Swpaul * in cache. 316255992Swpaul */ 316355992Swpaul if (cache_slot < 0 || cache_slot >= MAXANCACHE) { 316455992Swpaul log(LOG_ERR, "an_cache_store, bad index: %d of " 316555992Swpaul "[0..%d], gross cache error\n", 316655992Swpaul cache_slot, MAXANCACHE); 316755992Swpaul return; 316855992Swpaul } 316955992Swpaul 317055992Swpaul /* store items in cache 317155992Swpaul * .ip source address 317255992Swpaul * .mac src 317355992Swpaul * .signal, etc. 317455992Swpaul */ 317588748Sambrisko if (type_ipv4) { 317655992Swpaul sc->an_sigcache[cache_slot].ipsrc = ip->ip_src.s_addr; 317755992Swpaul } 317855992Swpaul bcopy( eh->ether_shost, sc->an_sigcache[cache_slot].macsrc, 6); 317955992Swpaul 318055992Swpaul 3181108401Sambrisko switch (an_cache_mode) { 3182108401Sambrisko case DBM: 3183108401Sambrisko if (sc->an_have_rssimap) { 3184175445Sambrisko sc->an_sigcache[cache_slot].signal = 3185108401Sambrisko - sc->an_rssimap.an_entries[rx_rssi].an_rss_dbm; 3186175445Sambrisko sc->an_sigcache[cache_slot].quality = 3187108401Sambrisko - sc->an_rssimap.an_entries[rx_quality].an_rss_dbm; 3188108401Sambrisko } else { 3189108401Sambrisko sc->an_sigcache[cache_slot].signal = rx_rssi - 100; 3190108401Sambrisko sc->an_sigcache[cache_slot].quality = rx_quality - 100; 3191108401Sambrisko } 3192108401Sambrisko break; 3193108401Sambrisko case PERCENT: 3194108401Sambrisko if (sc->an_have_rssimap) { 3195175445Sambrisko sc->an_sigcache[cache_slot].signal = 3196108401Sambrisko sc->an_rssimap.an_entries[rx_rssi].an_rss_pct; 3197175445Sambrisko sc->an_sigcache[cache_slot].quality = 3198108401Sambrisko sc->an_rssimap.an_entries[rx_quality].an_rss_pct; 3199108401Sambrisko } else { 3200108401Sambrisko if (rx_rssi > 100) 3201108401Sambrisko rx_rssi = 100; 3202108401Sambrisko if (rx_quality > 100) 3203108401Sambrisko rx_quality = 100; 3204108401Sambrisko sc->an_sigcache[cache_slot].signal = rx_rssi; 3205108401Sambrisko sc->an_sigcache[cache_slot].quality = rx_quality; 3206108401Sambrisko } 3207108401Sambrisko break; 3208108401Sambrisko case RAW: 3209108401Sambrisko sc->an_sigcache[cache_slot].signal = rx_rssi; 3210108401Sambrisko sc->an_sigcache[cache_slot].quality = rx_quality; 3211108401Sambrisko break; 3212108401Sambrisko } 3213108401Sambrisko 3214108401Sambrisko sc->an_sigcache[cache_slot].noise = 0; 3215108401Sambrisko 321655992Swpaul return; 321755992Swpaul} 321855992Swpaul#endif 321977217Sphk 322083270Sbrooksstatic int 3221150446Simpan_media_change(struct ifnet *ifp) 322277217Sphk{ 322377217Sphk struct an_softc *sc = ifp->if_softc; 3224110253Sambrisko struct an_ltv_genconfig *cfg; 322577217Sphk int otype = sc->an_config.an_opmode; 322677217Sphk int orate = sc->an_tx_rate; 322777217Sphk 3228199154Sjhb AN_LOCK(sc); 3229116951Ssam sc->an_tx_rate = ieee80211_media2rate( 3230116951Ssam IFM_SUBTYPE(sc->an_ifmedia.ifm_cur->ifm_media)); 3231119156Sambrisko if (sc->an_tx_rate < 0) 3232119156Sambrisko sc->an_tx_rate = 0; 3233110253Sambrisko 3234110253Sambrisko if (orate != sc->an_tx_rate) { 3235110253Sambrisko /* Read the current configuration */ 3236110253Sambrisko sc->an_config.an_type = AN_RID_GENCONFIG; 3237110253Sambrisko sc->an_config.an_len = sizeof(struct an_ltv_genconfig); 3238110253Sambrisko an_read_record(sc, (struct an_ltv_gen *)&sc->an_config); 3239110253Sambrisko cfg = &sc->an_config; 3240110253Sambrisko 3241110253Sambrisko /* clear other rates and set the only one we want */ 3242110253Sambrisko bzero(cfg->an_rates, sizeof(cfg->an_rates)); 3243110253Sambrisko cfg->an_rates[0] = sc->an_tx_rate; 3244110253Sambrisko 3245110253Sambrisko /* Save the new rate */ 3246110253Sambrisko sc->an_config.an_type = AN_RID_GENCONFIG; 3247110253Sambrisko sc->an_config.an_len = sizeof(struct an_ltv_genconfig); 324877217Sphk } 324977217Sphk 3250119156Sambrisko if ((sc->an_ifmedia.ifm_cur->ifm_media & IFM_IEEE80211_ADHOC) != 0) 3251119156Sambrisko sc->an_config.an_opmode &= ~AN_OPMODE_INFRASTRUCTURE_STATION; 3252119156Sambrisko else 3253119156Sambrisko sc->an_config.an_opmode |= AN_OPMODE_INFRASTRUCTURE_STATION; 3254119156Sambrisko 3255175445Sambrisko if (otype != sc->an_config.an_opmode || 3256110531Sambrisko orate != sc->an_tx_rate) 3257199154Sjhb an_init_locked(sc); 3258199154Sjhb AN_UNLOCK(sc); 325977217Sphk 326077217Sphk return(0); 326177217Sphk} 326277217Sphk 326383270Sbrooksstatic void 3264150446Simpan_media_status(struct ifnet *ifp, struct ifmediareq *imr) 326577217Sphk{ 326677217Sphk struct an_ltv_status status; 326777217Sphk struct an_softc *sc = ifp->if_softc; 326877217Sphk 3269110253Sambrisko imr->ifm_active = IFM_IEEE80211; 3270110253Sambrisko 3271175445Sambrisko AN_LOCK(sc); 327277217Sphk status.an_len = sizeof(status); 327377217Sphk status.an_type = AN_RID_STATUS; 327477217Sphk if (an_read_record(sc, (struct an_ltv_gen *)&status)) { 327577217Sphk /* If the status read fails, just lie. */ 327677217Sphk imr->ifm_active = sc->an_ifmedia.ifm_cur->ifm_media; 327777217Sphk imr->ifm_status = IFM_AVALID|IFM_ACTIVE; 327877217Sphk } 327977217Sphk 328078639Sbrooks if (sc->an_tx_rate == 0) { 328177217Sphk imr->ifm_active = IFM_IEEE80211|IFM_AUTO; 328277217Sphk } 328377217Sphk 3284110253Sambrisko if (sc->an_config.an_opmode == AN_OPMODE_IBSS_ADHOC) 3285110253Sambrisko imr->ifm_active |= IFM_IEEE80211_ADHOC; 3286116951Ssam imr->ifm_active |= ieee80211_rate2media(NULL, 3287228621Sbschmidt status.an_current_tx_rate, IEEE80211_MODE_AUTO); 328877217Sphk imr->ifm_status = IFM_AVALID; 328991283Sambrisko if (status.an_opmode & AN_STATUS_OPMODE_ASSOCIATED) 329077217Sphk imr->ifm_status |= IFM_ACTIVE; 3291199154Sjhb AN_UNLOCK(sc); 329277217Sphk} 329388748Sambrisko 329488748Sambrisko/********************** Cisco utility support routines *************/ 329588748Sambrisko 329688748Sambrisko/* 329788748Sambrisko * ReadRids & WriteRids derived from Cisco driver additions to Ben Reed's 329888748Sambrisko * Linux driver 329988748Sambrisko */ 330088748Sambrisko 330188748Sambriskostatic int 3302150446Simpreadrids(struct ifnet *ifp, struct aironet_ioctl *l_ioctl) 330388748Sambrisko{ 330488749Sambrisko unsigned short rid; 330588748Sambrisko struct an_softc *sc; 3306171692Savatar int error; 330788748Sambrisko 330888748Sambrisko switch (l_ioctl->command) { 330988748Sambrisko case AIROGCAP: 331088748Sambrisko rid = AN_RID_CAPABILITIES; 331188748Sambrisko break; 331288748Sambrisko case AIROGCFG: 331388748Sambrisko rid = AN_RID_GENCONFIG; 331488748Sambrisko break; 331588748Sambrisko case AIROGSLIST: 331688748Sambrisko rid = AN_RID_SSIDLIST; 331788748Sambrisko break; 331888748Sambrisko case AIROGVLIST: 331988748Sambrisko rid = AN_RID_APLIST; 332088748Sambrisko break; 332188748Sambrisko case AIROGDRVNAM: 332288748Sambrisko rid = AN_RID_DRVNAME; 332388748Sambrisko break; 332488748Sambrisko case AIROGEHTENC: 332588748Sambrisko rid = AN_RID_ENCAPPROTO; 332688748Sambrisko break; 332788748Sambrisko case AIROGWEPKTMP: 332888748Sambrisko rid = AN_RID_WEP_TEMP; 332988748Sambrisko break; 333088748Sambrisko case AIROGWEPKNV: 333188748Sambrisko rid = AN_RID_WEP_PERM; 333288748Sambrisko break; 333388748Sambrisko case AIROGSTAT: 333488748Sambrisko rid = AN_RID_STATUS; 333588748Sambrisko break; 333688748Sambrisko case AIROGSTATSD32: 333788748Sambrisko rid = AN_RID_32BITS_DELTA; 333888748Sambrisko break; 333988748Sambrisko case AIROGSTATSC32: 334088748Sambrisko rid = AN_RID_32BITS_CUM; 334188748Sambrisko break; 334288748Sambrisko default: 334388748Sambrisko rid = 999; 334488748Sambrisko break; 334588748Sambrisko } 334688748Sambrisko 334788748Sambrisko if (rid == 999) /* Is bad command */ 334888748Sambrisko return -EINVAL; 334988748Sambrisko 335088748Sambrisko sc = ifp->if_softc; 335188749Sambrisko sc->areq.an_len = AN_MAX_DATALEN; 335288749Sambrisko sc->areq.an_type = rid; 335388748Sambrisko 335488749Sambrisko an_read_record(sc, (struct an_ltv_gen *)&sc->areq); 335588748Sambrisko 335688749Sambrisko l_ioctl->len = sc->areq.an_len - 4; /* just data */ 335788748Sambrisko 3358171692Savatar AN_UNLOCK(sc); 335988748Sambrisko /* the data contains the length at first */ 336088749Sambrisko if (copyout(&(sc->areq.an_len), l_ioctl->data, 336188749Sambrisko sizeof(sc->areq.an_len))) { 3362171692Savatar error = -EFAULT; 3363171692Savatar goto lock_exit; 336488748Sambrisko } 336588748Sambrisko /* Just copy the data back */ 336688749Sambrisko if (copyout(&(sc->areq.an_val), l_ioctl->data + 2, 336788748Sambrisko l_ioctl->len)) { 3368171692Savatar error = -EFAULT; 3369171692Savatar goto lock_exit; 337088748Sambrisko } 3371171692Savatar error = 0; 3372171692Savatarlock_exit: 3373171692Savatar AN_LOCK(sc); 3374171692Savatar return (error); 337588748Sambrisko} 337688748Sambrisko 337788748Sambriskostatic int 3378150446Simpwriterids(struct ifnet *ifp, struct aironet_ioctl *l_ioctl) 337988748Sambrisko{ 338088748Sambrisko struct an_softc *sc; 3381175446Sambrisko int rid, command, error; 338288748Sambrisko 338388748Sambrisko sc = ifp->if_softc; 3384175445Sambrisko AN_LOCK_ASSERT(sc); 338588748Sambrisko rid = 0; 338688748Sambrisko command = l_ioctl->command; 338788748Sambrisko 338888748Sambrisko switch (command) { 338988748Sambrisko case AIROPSIDS: 339088748Sambrisko rid = AN_RID_SSIDLIST; 339188748Sambrisko break; 339288748Sambrisko case AIROPCAP: 339388748Sambrisko rid = AN_RID_CAPABILITIES; 339488748Sambrisko break; 339588748Sambrisko case AIROPAPLIST: 339688748Sambrisko rid = AN_RID_APLIST; 339788748Sambrisko break; 339888748Sambrisko case AIROPCFG: 339988748Sambrisko rid = AN_RID_GENCONFIG; 340088748Sambrisko break; 340188748Sambrisko case AIROPMACON: 340288748Sambrisko an_cmd(sc, AN_CMD_ENABLE, 0); 340388748Sambrisko return 0; 340488748Sambrisko break; 340588748Sambrisko case AIROPMACOFF: 340688748Sambrisko an_cmd(sc, AN_CMD_DISABLE, 0); 340788748Sambrisko return 0; 340888748Sambrisko break; 340988748Sambrisko case AIROPSTCLR: 341088748Sambrisko /* 341188748Sambrisko * This command merely clears the counts does not actually 341288748Sambrisko * store any data only reads rid. But as it changes the cards 341388748Sambrisko * state, I put it in the writerid routines. 341488748Sambrisko */ 341588748Sambrisko 341688748Sambrisko rid = AN_RID_32BITS_DELTACLR; 341788748Sambrisko sc = ifp->if_softc; 341888749Sambrisko sc->areq.an_len = AN_MAX_DATALEN; 341988749Sambrisko sc->areq.an_type = rid; 342088748Sambrisko 342188749Sambrisko an_read_record(sc, (struct an_ltv_gen *)&sc->areq); 342288749Sambrisko l_ioctl->len = sc->areq.an_len - 4; /* just data */ 342388748Sambrisko 3424171692Savatar AN_UNLOCK(sc); 342588748Sambrisko /* the data contains the length at first */ 3426171692Savatar error = copyout(&(sc->areq.an_len), l_ioctl->data, 3427171692Savatar sizeof(sc->areq.an_len)); 3428171692Savatar if (error) { 3429171692Savatar AN_LOCK(sc); 343088748Sambrisko return -EFAULT; 343188748Sambrisko } 343288748Sambrisko /* Just copy the data */ 3433171692Savatar error = copyout(&(sc->areq.an_val), l_ioctl->data + 2, 3434171692Savatar l_ioctl->len); 3435171692Savatar AN_LOCK(sc); 3436171692Savatar if (error) 343788748Sambrisko return -EFAULT; 343888748Sambrisko return 0; 343988748Sambrisko break; 344088748Sambrisko case AIROPWEPKEY: 344188748Sambrisko rid = AN_RID_WEP_TEMP; 344288748Sambrisko break; 344388748Sambrisko case AIROPWEPKEYNV: 344488748Sambrisko rid = AN_RID_WEP_PERM; 344588748Sambrisko break; 344688748Sambrisko case AIROPLEAPUSR: 344788748Sambrisko rid = AN_RID_LEAPUSERNAME; 344888748Sambrisko break; 344988748Sambrisko case AIROPLEAPPWD: 345088748Sambrisko rid = AN_RID_LEAPPASSWORD; 345188748Sambrisko break; 345288748Sambrisko default: 345388748Sambrisko return -EOPNOTSUPP; 345488748Sambrisko } 345588748Sambrisko 345688748Sambrisko if (rid) { 345788749Sambrisko if (l_ioctl->len > sizeof(sc->areq.an_val) + 4) 345888748Sambrisko return -EINVAL; 345988749Sambrisko sc->areq.an_len = l_ioctl->len + 4; /* add type & length */ 346088749Sambrisko sc->areq.an_type = rid; 346188748Sambrisko 346288748Sambrisko /* Just copy the data back */ 3463171692Savatar AN_UNLOCK(sc); 3464171692Savatar error = copyin((l_ioctl->data) + 2, &sc->areq.an_val, 3465171692Savatar l_ioctl->len); 3466171692Savatar AN_LOCK(sc); 3467171692Savatar if (error) 3468144242Ssam return -EFAULT; 3469171692Savatar 347088748Sambrisko an_cmd(sc, AN_CMD_DISABLE, 0); 347188749Sambrisko an_write_record(sc, (struct an_ltv_gen *)&sc->areq); 347288748Sambrisko an_cmd(sc, AN_CMD_ENABLE, 0); 347388748Sambrisko return 0; 347488748Sambrisko } 347588748Sambrisko return -EOPNOTSUPP; 347688748Sambrisko} 347788748Sambrisko 347888748Sambrisko/* 347988748Sambrisko * General Flash utilities derived from Cisco driver additions to Ben Reed's 348088748Sambrisko * Linux driver 348188748Sambrisko */ 348288748Sambrisko 3483123978Sambrisko#define FLASH_DELAY(_sc, x) msleep(ifp, &(_sc)->an_mtx, PZERO, \ 3484123978Sambrisko "flash", ((x) / hz) + 1); 3485108401Sambrisko#define FLASH_COMMAND 0x7e7e 3486108401Sambrisko#define FLASH_SIZE 32 * 1024 348788748Sambrisko 348888748Sambriskostatic int 3489150446Simpunstickbusy(struct ifnet *ifp) 349088748Sambrisko{ 349188748Sambrisko struct an_softc *sc = ifp->if_softc; 349288748Sambrisko 3493108401Sambrisko if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY) { 3494175445Sambrisko CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), 3495108401Sambrisko AN_EV_CLR_STUCK_BUSY); 349688748Sambrisko return 1; 349788748Sambrisko } 349888748Sambrisko return 0; 349988748Sambrisko} 350088748Sambrisko 350188748Sambrisko/* 350288748Sambrisko * Wait for busy completion from card wait for delay uSec's Return true for 350388748Sambrisko * success meaning command reg is clear 350488748Sambrisko */ 350588748Sambrisko 350688748Sambriskostatic int 3507150446SimpWaitBusy(struct ifnet *ifp, int uSec) 350888748Sambrisko{ 3509175446Sambrisko int statword = 0xffff; 3510175446Sambrisko int delay = 0; 3511175446Sambrisko struct an_softc *sc = ifp->if_softc; 351288748Sambrisko 351388748Sambrisko while ((statword & AN_CMD_BUSY) && delay <= (1000 * 100)) { 3514119163Sambrisko FLASH_DELAY(sc, 10); 351588748Sambrisko delay += 10; 3516108401Sambrisko statword = CSR_READ_2(sc, AN_COMMAND(sc->mpi350)); 351788748Sambrisko 351888748Sambrisko if ((AN_CMD_BUSY & statword) && (delay % 200)) { 351988748Sambrisko unstickbusy(ifp); 352088748Sambrisko } 352188748Sambrisko } 352288748Sambrisko 352388748Sambrisko return 0 == (AN_CMD_BUSY & statword); 352488748Sambrisko} 352588748Sambrisko 352688748Sambrisko/* 352788748Sambrisko * STEP 1) Disable MAC and do soft reset on card. 352888748Sambrisko */ 352988748Sambrisko 353088748Sambriskostatic int 3531150446Simpcmdreset(struct ifnet *ifp) 353288748Sambrisko{ 3533175446Sambrisko int status; 3534175446Sambrisko struct an_softc *sc = ifp->if_softc; 353588748Sambrisko 3536199154Sjhb AN_LOCK(sc); 353788748Sambrisko an_stop(sc); 353888748Sambrisko 353988748Sambrisko an_cmd(sc, AN_CMD_DISABLE, 0); 354088748Sambrisko 3541108401Sambrisko if (!(status = WaitBusy(ifp, AN_TIMEOUT))) { 3542198987Sjhb if_printf(ifp, "Waitbusy hang b4 RESET =%d\n", status); 3543175445Sambrisko AN_UNLOCK(sc); 354488748Sambrisko return -EBUSY; 354588748Sambrisko } 3546108401Sambrisko CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), AN_CMD_FW_RESTART); 354788748Sambrisko 3548119163Sambrisko FLASH_DELAY(sc, 1000); /* WAS 600 12/7/00 */ 354988748Sambrisko 355088748Sambrisko 355188748Sambrisko if (!(status = WaitBusy(ifp, 100))) { 3552198987Sjhb if_printf(ifp, "Waitbusy hang AFTER RESET =%d\n", status); 3553175445Sambrisko AN_UNLOCK(sc); 355488748Sambrisko return -EBUSY; 355588748Sambrisko } 3556175445Sambrisko AN_UNLOCK(sc); 355788748Sambrisko return 0; 355888748Sambrisko} 355988748Sambrisko 356088748Sambrisko/* 356188748Sambrisko * STEP 2) Put the card in legendary flash mode 356288748Sambrisko */ 356388748Sambrisko 356488748Sambriskostatic int 3565150446Simpsetflashmode(struct ifnet *ifp) 356688748Sambrisko{ 3567175446Sambrisko int status; 3568175446Sambrisko struct an_softc *sc = ifp->if_softc; 356988748Sambrisko 3570108401Sambrisko CSR_WRITE_2(sc, AN_SW0(sc->mpi350), FLASH_COMMAND); 3571108401Sambrisko CSR_WRITE_2(sc, AN_SW1(sc->mpi350), FLASH_COMMAND); 3572108401Sambrisko CSR_WRITE_2(sc, AN_SW0(sc->mpi350), FLASH_COMMAND); 3573108401Sambrisko CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), FLASH_COMMAND); 357488748Sambrisko 357588748Sambrisko /* 357688748Sambrisko * mdelay(500); // 500ms delay 357788748Sambrisko */ 357888748Sambrisko 3579119163Sambrisko FLASH_DELAY(sc, 500); 358088748Sambrisko 3581108401Sambrisko if (!(status = WaitBusy(ifp, AN_TIMEOUT))) { 358288748Sambrisko printf("Waitbusy hang after setflash mode\n"); 358388748Sambrisko return -EIO; 358488748Sambrisko } 358588748Sambrisko return 0; 358688748Sambrisko} 358788748Sambrisko 358888748Sambrisko/* 358988748Sambrisko * Get a character from the card matching matchbyte Step 3) 359088748Sambrisko */ 359188748Sambrisko 359288748Sambriskostatic int 3593150446Simpflashgchar(struct ifnet *ifp, int matchbyte, int dwelltime) 359488748Sambrisko{ 3595175446Sambrisko int rchar; 3596175446Sambrisko unsigned char rbyte = 0; 3597175446Sambrisko int success = -1; 3598175446Sambrisko struct an_softc *sc = ifp->if_softc; 359988748Sambrisko 360088748Sambrisko 360188748Sambrisko do { 3602108401Sambrisko rchar = CSR_READ_2(sc, AN_SW1(sc->mpi350)); 360388748Sambrisko 360488748Sambrisko if (dwelltime && !(0x8000 & rchar)) { 360588748Sambrisko dwelltime -= 10; 3606119163Sambrisko FLASH_DELAY(sc, 10); 360788748Sambrisko continue; 360888748Sambrisko } 360988748Sambrisko rbyte = 0xff & rchar; 361088748Sambrisko 361188748Sambrisko if ((rbyte == matchbyte) && (0x8000 & rchar)) { 3612108401Sambrisko CSR_WRITE_2(sc, AN_SW1(sc->mpi350), 0); 361388748Sambrisko success = 1; 361488748Sambrisko break; 361588748Sambrisko } 361688748Sambrisko if (rbyte == 0x81 || rbyte == 0x82 || rbyte == 0x83 || rbyte == 0x1a || 0xffff == rchar) 361788748Sambrisko break; 3618108401Sambrisko CSR_WRITE_2(sc, AN_SW1(sc->mpi350), 0); 361988748Sambrisko 362088748Sambrisko } while (dwelltime > 0); 362188748Sambrisko return success; 362288748Sambrisko} 362388748Sambrisko 362488748Sambrisko/* 362588748Sambrisko * Put character to SWS0 wait for dwelltime x 50us for echo . 362688748Sambrisko */ 362788748Sambrisko 362888748Sambriskostatic int 3629150446Simpflashpchar(struct ifnet *ifp, int byte, int dwelltime) 363088748Sambrisko{ 3631175446Sambrisko int echo; 3632175446Sambrisko int pollbusy, waittime; 3633175446Sambrisko struct an_softc *sc = ifp->if_softc; 363488748Sambrisko 363588748Sambrisko byte |= 0x8000; 363688748Sambrisko 363788748Sambrisko if (dwelltime == 0) 363888748Sambrisko dwelltime = 200; 363988748Sambrisko 364088748Sambrisko waittime = dwelltime; 364188748Sambrisko 364288748Sambrisko /* 364388748Sambrisko * Wait for busy bit d15 to go false indicating buffer empty 364488748Sambrisko */ 364588748Sambrisko do { 3646108401Sambrisko pollbusy = CSR_READ_2(sc, AN_SW0(sc->mpi350)); 364788748Sambrisko 364888748Sambrisko if (pollbusy & 0x8000) { 3649119163Sambrisko FLASH_DELAY(sc, 50); 365088748Sambrisko waittime -= 50; 365188748Sambrisko continue; 365288748Sambrisko } else 365388748Sambrisko break; 365488748Sambrisko } 365588748Sambrisko while (waittime >= 0); 365688748Sambrisko 365788748Sambrisko /* timeout for busy clear wait */ 365888748Sambrisko 365988748Sambrisko if (waittime <= 0) { 3660198987Sjhb if_printf(ifp, "flash putchar busywait timeout!\n"); 366188748Sambrisko return -1; 366288748Sambrisko } 366388748Sambrisko /* 366488748Sambrisko * Port is clear now write byte and wait for it to echo back 366588748Sambrisko */ 366688748Sambrisko do { 3667108401Sambrisko CSR_WRITE_2(sc, AN_SW0(sc->mpi350), byte); 3668119163Sambrisko FLASH_DELAY(sc, 50); 366988748Sambrisko dwelltime -= 50; 3670108401Sambrisko echo = CSR_READ_2(sc, AN_SW1(sc->mpi350)); 367188748Sambrisko } while (dwelltime >= 0 && echo != byte); 367288748Sambrisko 367388748Sambrisko 3674108401Sambrisko CSR_WRITE_2(sc, AN_SW1(sc->mpi350), 0); 367588748Sambrisko 367688748Sambrisko return echo == byte; 367788748Sambrisko} 367888748Sambrisko 367988748Sambrisko/* 368088748Sambrisko * Transfer 32k of firmware data from user buffer to our buffer and send to 368188748Sambrisko * the card 368288748Sambrisko */ 368388748Sambrisko 368488748Sambriskostatic int 3685150446Simpflashputbuf(struct ifnet *ifp) 368688748Sambrisko{ 368788748Sambrisko unsigned short *bufp; 3688175446Sambrisko int nwords; 3689175446Sambrisko struct an_softc *sc = ifp->if_softc; 369088748Sambrisko 369188748Sambrisko /* Write stuff */ 369288748Sambrisko 3693108401Sambrisko bufp = sc->an_flash_buffer; 369488748Sambrisko 3695108401Sambrisko if (!sc->mpi350) { 3696108401Sambrisko CSR_WRITE_2(sc, AN_AUX_PAGE, 0x100); 3697108401Sambrisko CSR_WRITE_2(sc, AN_AUX_OFFSET, 0); 369888748Sambrisko 3699108401Sambrisko for (nwords = 0; nwords != FLASH_SIZE / 2; nwords++) { 3700108401Sambrisko CSR_WRITE_2(sc, AN_AUX_DATA, bufp[nwords] & 0xffff); 3701108401Sambrisko } 3702108401Sambrisko } else { 3703108401Sambrisko for (nwords = 0; nwords != FLASH_SIZE / 4; nwords++) { 3704175445Sambrisko CSR_MEM_AUX_WRITE_4(sc, 0x8000, 3705108401Sambrisko ((u_int32_t *)bufp)[nwords] & 0xffff); 3706108401Sambrisko } 370788748Sambrisko } 370888748Sambrisko 3709108401Sambrisko CSR_WRITE_2(sc, AN_SW0(sc->mpi350), 0x8000); 371088748Sambrisko 371188748Sambrisko return 0; 371288748Sambrisko} 371388748Sambrisko 371488748Sambrisko/* 371588748Sambrisko * After flashing restart the card. 371688748Sambrisko */ 371788748Sambrisko 371888748Sambriskostatic int 3719150446Simpflashrestart(struct ifnet *ifp) 372088748Sambrisko{ 3721175446Sambrisko int status = 0; 3722175446Sambrisko struct an_softc *sc = ifp->if_softc; 372388748Sambrisko 3724119163Sambrisko FLASH_DELAY(sc, 1024); /* Added 12/7/00 */ 372588748Sambrisko 3726199154Sjhb an_init_locked(sc); 372788748Sambrisko 3728119163Sambrisko FLASH_DELAY(sc, 1024); /* Added 12/7/00 */ 372988748Sambrisko return status; 373088748Sambrisko} 373188748Sambrisko 373288748Sambrisko/* 373388748Sambrisko * Entry point for flash ioclt. 373488748Sambrisko */ 373588748Sambrisko 373688748Sambriskostatic int 3737150446Simpflashcard(struct ifnet *ifp, struct aironet_ioctl *l_ioctl) 373888748Sambrisko{ 3739175446Sambrisko int z = 0, status; 374088748Sambrisko struct an_softc *sc; 374188748Sambrisko 374288748Sambrisko sc = ifp->if_softc; 3743108401Sambrisko if (sc->mpi350) { 3744198987Sjhb if_printf(ifp, "flashing not supported on MPI 350 yet\n"); 3745108401Sambrisko return(-1); 3746108401Sambrisko } 374788748Sambrisko status = l_ioctl->command; 374888748Sambrisko 374988748Sambrisko switch (l_ioctl->command) { 375088748Sambrisko case AIROFLSHRST: 375188748Sambrisko return cmdreset(ifp); 375288748Sambrisko break; 375388748Sambrisko case AIROFLSHSTFL: 3754108401Sambrisko if (sc->an_flash_buffer) { 3755108401Sambrisko free(sc->an_flash_buffer, M_DEVBUF); 3756108401Sambrisko sc->an_flash_buffer = NULL; 3757108401Sambrisko } 3758111119Simp sc->an_flash_buffer = malloc(FLASH_SIZE, M_DEVBUF, M_WAITOK); 3759108401Sambrisko if (sc->an_flash_buffer) 3760108401Sambrisko return setflashmode(ifp); 3761108401Sambrisko else 3762108401Sambrisko return ENOBUFS; 376388748Sambrisko break; 376488748Sambrisko case AIROFLSHGCHR: /* Get char from aux */ 3765300612Ssbruno if (l_ioctl->len > sizeof(sc->areq)) { 3766300612Ssbruno return -EINVAL; 3767300612Ssbruno } 3768171692Savatar AN_UNLOCK(sc); 3769144242Ssam status = copyin(l_ioctl->data, &sc->areq, l_ioctl->len); 3770171692Savatar AN_LOCK(sc); 3771144242Ssam if (status) 3772144242Ssam return status; 377388749Sambrisko z = *(int *)&sc->areq; 377488748Sambrisko if ((status = flashgchar(ifp, z, 8000)) == 1) 377588748Sambrisko return 0; 377688748Sambrisko else 377788748Sambrisko return -1; 377888748Sambrisko case AIROFLSHPCHR: /* Send char to card. */ 3779300612Ssbruno if (l_ioctl->len > sizeof(sc->areq)) { 3780300612Ssbruno return -EINVAL; 3781300612Ssbruno } 3782171692Savatar AN_UNLOCK(sc); 3783144242Ssam status = copyin(l_ioctl->data, &sc->areq, l_ioctl->len); 3784171692Savatar AN_LOCK(sc); 3785144242Ssam if (status) 3786144242Ssam return status; 378788749Sambrisko z = *(int *)&sc->areq; 378888748Sambrisko if ((status = flashpchar(ifp, z, 8000)) == -1) 378988748Sambrisko return -EIO; 379088748Sambrisko else 379188748Sambrisko return 0; 379288748Sambrisko break; 379388748Sambrisko case AIROFLPUTBUF: /* Send 32k to card */ 3794108401Sambrisko if (l_ioctl->len > FLASH_SIZE) { 3795198987Sjhb if_printf(ifp, "Buffer to big, %x %x\n", 3796108401Sambrisko l_ioctl->len, FLASH_SIZE); 379788748Sambrisko return -EINVAL; 379888748Sambrisko } 3799171692Savatar AN_UNLOCK(sc); 3800144242Ssam status = copyin(l_ioctl->data, sc->an_flash_buffer, l_ioctl->len); 3801171692Savatar AN_LOCK(sc); 3802144242Ssam if (status) 3803144242Ssam return status; 380488748Sambrisko 380588748Sambrisko if ((status = flashputbuf(ifp)) != 0) 380688748Sambrisko return -EIO; 380788748Sambrisko else 380888748Sambrisko return 0; 380988748Sambrisko break; 381088748Sambrisko case AIRORESTART: 381188748Sambrisko if ((status = flashrestart(ifp)) != 0) { 3812198987Sjhb if_printf(ifp, "FLASHRESTART returned %d\n", status); 381388748Sambrisko return -EIO; 381488748Sambrisko } else 381588748Sambrisko return 0; 381688748Sambrisko 381788748Sambrisko break; 381888748Sambrisko default: 381988748Sambrisko return -EINVAL; 382088748Sambrisko } 382188748Sambrisko 382288748Sambrisko return -EINVAL; 382388748Sambrisko} 3824