if_an.c revision 171775
1139749Simp/*-
255992Swpaul * Copyright (c) 1997, 1998, 1999
355992Swpaul *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
455992Swpaul *
555992Swpaul * Redistribution and use in source and binary forms, with or without
655992Swpaul * modification, are permitted provided that the following conditions
755992Swpaul * are met:
855992Swpaul * 1. Redistributions of source code must retain the above copyright
955992Swpaul *    notice, this list of conditions and the following disclaimer.
1055992Swpaul * 2. Redistributions in binary form must reproduce the above copyright
1155992Swpaul *    notice, this list of conditions and the following disclaimer in the
1255992Swpaul *    documentation and/or other materials provided with the distribution.
1355992Swpaul * 3. All advertising materials mentioning features or use of this software
1455992Swpaul *    must display the following acknowledgement:
1555992Swpaul *	This product includes software developed by Bill Paul.
1655992Swpaul * 4. Neither the name of the author nor the names of any co-contributors
1755992Swpaul *    may be used to endorse or promote products derived from this software
1855992Swpaul *    without specific prior written permission.
1955992Swpaul *
2055992Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
2155992Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2255992Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2355992Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
2455992Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2555992Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2655992Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2755992Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2855992Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2955992Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
3055992Swpaul * THE POSSIBILITY OF SUCH DAMAGE.
3155992Swpaul */
3255992Swpaul/*
3355992Swpaul * Aironet 4500/4800 802.11 PCMCIA/ISA/PCI driver for FreeBSD.
3455992Swpaul *
3555992Swpaul * Written by Bill Paul <wpaul@ctr.columbia.edu>
3655992Swpaul * Electrical Engineering Department
3755992Swpaul * Columbia University, New York City
3855992Swpaul */
3955992Swpaul
40119418Sobrien#include <sys/cdefs.h>
41119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/an/if_an.c 171775 2007-08-07 12:26:19Z avatar $");
42119418Sobrien
4355992Swpaul/*
4486259Sphk * The Aironet 4500/4800 series cards come in PCMCIA, ISA and PCI form.
4555992Swpaul * This driver supports all three device types (PCI devices are supported
46100770Sfenner * through an extra PCI shim: /sys/dev/an/if_an_pci.c). ISA devices can be
4755992Swpaul * supported either using hard-coded IO port/IRQ settings or via Plug
4855992Swpaul * and Play. The 4500 series devices support 1Mbps and 2Mbps data rates.
4955992Swpaul * The 4800 devices support 1, 2, 5.5 and 11Mbps rates.
5055992Swpaul *
5155992Swpaul * Like the WaveLAN/IEEE cards, the Aironet NICs are all essentially
5255992Swpaul * PCMCIA devices. The ISA and PCI cards are a combination of a PCMCIA
5355992Swpaul * device and a PCMCIA to ISA or PCMCIA to PCI adapter card. There are
5455992Swpaul * a couple of important differences though:
5555992Swpaul *
5655992Swpaul * - Lucent ISA card looks to the host like a PCMCIA controller with
5755992Swpaul *   a PCMCIA WaveLAN card inserted. This means that even desktop
5855992Swpaul *   machines need to be configured with PCMCIA support in order to
5955992Swpaul *   use WaveLAN/IEEE ISA cards. The Aironet cards on the other hand
6055992Swpaul *   actually look like normal ISA and PCI devices to the host, so
6155992Swpaul *   no PCMCIA controller support is needed
6255992Swpaul *
6355992Swpaul * The latter point results in a small gotcha. The Aironet PCMCIA
6455992Swpaul * cards can be configured for one of two operating modes depending
6555992Swpaul * on how the Vpp1 and Vpp2 programming voltages are set when the
6655992Swpaul * card is activated. In order to put the card in proper PCMCIA
6755992Swpaul * operation (where the CIS table is visible and the interface is
6855992Swpaul * programmed for PCMCIA operation), both Vpp1 and Vpp2 have to be
6955992Swpaul * set to 5 volts. FreeBSD by default doesn't set the Vpp voltages,
7055992Swpaul * which leaves the card in ISA/PCI mode, which prevents it from
7186381Simp * being activated as an PCMCIA device.
7255992Swpaul *
7355992Swpaul * Note that some PCMCIA controller software packages for Windows NT
7455992Swpaul * fail to set the voltages as well.
7583270Sbrooks *
7655992Swpaul * The Aironet devices can operate in both station mode and access point
7755992Swpaul * mode. Typically, when programmed for station mode, the card can be set
7855992Swpaul * to automatically perform encapsulation/decapsulation of Ethernet II
7955992Swpaul * and 802.3 frames within 802.11 frames so that the host doesn't have
8055992Swpaul * to do it itself. This driver doesn't program the card that way: the
8155992Swpaul * driver handles all of the encapsulation/decapsulation itself.
8255992Swpaul */
8355992Swpaul
8455992Swpaul#include "opt_inet.h"
8555992Swpaul
8655992Swpaul#ifdef INET
8755992Swpaul#define ANCACHE			/* enable signal strength cache */
8855992Swpaul#endif
8955992Swpaul
9055992Swpaul#include <sys/param.h>
91154866Snjl#include <sys/ctype.h>
9255992Swpaul#include <sys/systm.h>
9355992Swpaul#include <sys/sockio.h>
9455992Swpaul#include <sys/mbuf.h>
95164033Srwatson#include <sys/priv.h>
9683366Sjulian#include <sys/proc.h>
9755992Swpaul#include <sys/kernel.h>
9855992Swpaul#include <sys/socket.h>
9955992Swpaul#ifdef ANCACHE
10055992Swpaul#include <sys/syslog.h>
101108401Sambrisko#endif
10255992Swpaul#include <sys/sysctl.h>
10355992Swpaul
10455992Swpaul#include <sys/module.h>
10583269Sbrooks#include <sys/sysctl.h>
10655992Swpaul#include <sys/bus.h>
10755992Swpaul#include <machine/bus.h>
10855992Swpaul#include <sys/rman.h>
10984811Sjhb#include <sys/lock.h>
11067365Sjhb#include <sys/mutex.h>
11155992Swpaul#include <machine/resource.h>
112108401Sambrisko#include <sys/malloc.h>
11355992Swpaul
11455992Swpaul#include <net/if.h>
11555992Swpaul#include <net/if_arp.h>
116152315Sru#include <net/if_dl.h>
11755992Swpaul#include <net/ethernet.h>
11855992Swpaul#include <net/if_types.h>
11977217Sphk#include <net/if_media.h>
12055992Swpaul
121116951Ssam#include <net80211/ieee80211_var.h>
122116951Ssam#include <net80211/ieee80211_ioctl.h>
123116951Ssam
12455992Swpaul#ifdef INET
12555992Swpaul#include <netinet/in.h>
12655992Swpaul#include <netinet/in_systm.h>
12755992Swpaul#include <netinet/in_var.h>
12855992Swpaul#include <netinet/ip.h>
12955992Swpaul#endif
13055992Swpaul
13155992Swpaul#include <net/bpf.h>
13255992Swpaul
13355992Swpaul#include <machine/md_var.h>
13455992Swpaul
13555992Swpaul#include <dev/an/if_aironet_ieee.h>
13655992Swpaul#include <dev/an/if_anreg.h>
13755992Swpaul
13855992Swpaul/* These are global because we need them in sys/pci/if_an_p.c. */
139150446Simpstatic void an_reset(struct an_softc *);
140150446Simpstatic int an_init_mpi350_desc(struct an_softc *);
141150446Simpstatic int an_ioctl(struct ifnet *, u_long, caddr_t);
142150446Simpstatic void an_init(void *);
143150446Simpstatic int an_init_tx_ring(struct an_softc *);
144150446Simpstatic void an_start(struct ifnet *);
145150446Simpstatic void an_watchdog(struct ifnet *);
146150446Simpstatic void an_rxeof(struct an_softc *);
147150446Simpstatic void an_txeof(struct an_softc *, int);
14855992Swpaul
149150446Simpstatic void an_promisc(struct an_softc *, int);
150150446Simpstatic int an_cmd(struct an_softc *, int, int);
151150446Simpstatic int an_cmd_struct(struct an_softc *, struct an_command *,
152150446Simp    struct an_reply *);
153150446Simpstatic int an_read_record(struct an_softc *, struct an_ltv_gen *);
154150446Simpstatic int an_write_record(struct an_softc *, struct an_ltv_gen *);
155150446Simpstatic int an_read_data(struct an_softc *, int, int, caddr_t, int);
156150446Simpstatic int an_write_data(struct an_softc *, int, int, caddr_t, int);
157150446Simpstatic int an_seek(struct an_softc *, int, int, int);
158150446Simpstatic int an_alloc_nicmem(struct an_softc *, int, int *);
159150446Simpstatic int an_dma_malloc(struct an_softc *, bus_size_t, struct an_dma_alloc *,
160150446Simp    int);
161150446Simpstatic void an_dma_free(struct an_softc *, struct an_dma_alloc *);
162150446Simpstatic void an_dma_malloc_cb(void *, bus_dma_segment_t *, int, int);
163150446Simpstatic void an_stats_update(void *);
164150446Simpstatic void an_setdef(struct an_softc *, struct an_req *);
16555992Swpaul#ifdef ANCACHE
166150446Simpstatic void an_cache_store(struct an_softc *, struct ether_header *,
167150446Simp    struct mbuf *, u_int8_t, u_int8_t);
16855992Swpaul#endif
16955992Swpaul
17088748Sambrisko/* function definitions for use with the Cisco's Linux configuration
17188748Sambrisko   utilities
17288748Sambrisko*/
17388748Sambrisko
17492739Salfredstatic int readrids(struct ifnet*, struct aironet_ioctl*);
17592739Salfredstatic int writerids(struct ifnet*, struct aironet_ioctl*);
17692739Salfredstatic int flashcard(struct ifnet*, struct aironet_ioctl*);
17788748Sambrisko
17892739Salfredstatic int cmdreset(struct ifnet *);
17992739Salfredstatic int setflashmode(struct ifnet *);
18092739Salfredstatic int flashgchar(struct ifnet *,int,int);
18192739Salfredstatic int flashpchar(struct ifnet *,int,int);
18292739Salfredstatic int flashputbuf(struct ifnet *);
18392739Salfredstatic int flashrestart(struct ifnet *);
18492739Salfredstatic int WaitBusy(struct ifnet *, int);
18592739Salfredstatic int unstickbusy(struct ifnet *);
18688748Sambrisko
18792739Salfredstatic void an_dump_record	(struct an_softc *,struct an_ltv_gen *,
18892739Salfred				    char *);
18978639Sbrooks
19092739Salfredstatic int an_media_change	(struct ifnet *);
19192739Salfredstatic void an_media_status	(struct ifnet *, struct ifmediareq *);
19277217Sphk
19378639Sbrooksstatic int	an_dump = 0;
194108401Sambriskostatic int	an_cache_mode = 0;
19588748Sambrisko
196108401Sambrisko#define DBM 0
197108401Sambrisko#define PERCENT 1
198108401Sambrisko#define RAW 2
199108401Sambrisko
20083269Sbrooksstatic char an_conf[256];
201108401Sambriskostatic char an_conf_cache[256];
20283269Sbrooks
20383269Sbrooks/* sysctl vars */
204108401Sambrisko
205110531SambriskoSYSCTL_NODE(_hw, OID_AUTO, an, CTLFLAG_RD, 0, "Wireless driver parameters");
20683269Sbrooks
207106937Ssam/* XXX violate ethernet/netgraph callback hooks */
208106937Ssamextern	void	(*ng_ether_attach_p)(struct ifnet *ifp);
209106937Ssamextern	void	(*ng_ether_detach_p)(struct ifnet *ifp);
210106937Ssam
21183269Sbrooksstatic int
21283269Sbrookssysctl_an_dump(SYSCTL_HANDLER_ARGS)
21383269Sbrooks{
21483269Sbrooks	int	error, r, last;
21583269Sbrooks	char 	*s = an_conf;
21683270Sbrooks
21783269Sbrooks	last = an_dump;
21883269Sbrooks
21983270Sbrooks	switch (an_dump) {
22083269Sbrooks	case 0:
221108401Sambrisko		strcpy(an_conf, "off");
22283269Sbrooks		break;
22383269Sbrooks	case 1:
224108401Sambrisko		strcpy(an_conf, "type");
22583269Sbrooks		break;
22683269Sbrooks	case 2:
227108401Sambrisko		strcpy(an_conf, "dump");
22883269Sbrooks		break;
22983269Sbrooks	default:
23083269Sbrooks		snprintf(an_conf, 5, "%x", an_dump);
23183269Sbrooks		break;
23283269Sbrooks	}
23383269Sbrooks
23483269Sbrooks	error = sysctl_handle_string(oidp, an_conf, sizeof(an_conf), req);
23583269Sbrooks
236108401Sambrisko	if (strncmp(an_conf,"off", 3) == 0) {
23783269Sbrooks		an_dump = 0;
23883269Sbrooks 	}
23983270Sbrooks	if (strncmp(an_conf,"dump", 4) == 0) {
24083269Sbrooks		an_dump = 1;
24183269Sbrooks	}
24283270Sbrooks	if (strncmp(an_conf,"type", 4) == 0) {
24383269Sbrooks		an_dump = 2;
24483269Sbrooks	}
24583270Sbrooks	if (*s == 'f') {
24683269Sbrooks		r = 0;
24783270Sbrooks		for (;;s++) {
24883270Sbrooks			if ((*s >= '0') && (*s <= '9')) {
24983269Sbrooks				r = r * 16 + (*s - '0');
25083270Sbrooks			} else if ((*s >= 'a') && (*s <= 'f')) {
25183269Sbrooks				r = r * 16 + (*s - 'a' + 10);
25283270Sbrooks			} else {
25383270Sbrooks				break;
25483269Sbrooks			}
25583269Sbrooks		}
25683269Sbrooks		an_dump = r;
25783269Sbrooks	}
25883269Sbrooks	if (an_dump != last)
25983269Sbrooks		printf("Sysctl changed for Aironet driver\n");
26083269Sbrooks
26183269Sbrooks	return error;
26283269Sbrooks}
26383269Sbrooks
264110531SambriskoSYSCTL_PROC(_hw_an, OID_AUTO, an_dump, CTLTYPE_STRING | CTLFLAG_RW,
26583269Sbrooks            0, sizeof(an_conf), sysctl_an_dump, "A", "");
26683269Sbrooks
267108401Sambriskostatic int
268108401Sambriskosysctl_an_cache_mode(SYSCTL_HANDLER_ARGS)
269108401Sambrisko{
270108401Sambrisko	int	error, last;
271108401Sambrisko
272108401Sambrisko	last = an_cache_mode;
273108401Sambrisko
274108401Sambrisko	switch (an_cache_mode) {
275108401Sambrisko	case 1:
276108401Sambrisko		strcpy(an_conf_cache, "per");
277108401Sambrisko		break;
278108401Sambrisko	case 2:
279108401Sambrisko		strcpy(an_conf_cache, "raw");
280108401Sambrisko		break;
281108401Sambrisko	default:
282108401Sambrisko		strcpy(an_conf_cache, "dbm");
283108401Sambrisko		break;
284108401Sambrisko	}
285108401Sambrisko
286108401Sambrisko	error = sysctl_handle_string(oidp, an_conf_cache,
287108401Sambrisko			sizeof(an_conf_cache), req);
288108401Sambrisko
289108401Sambrisko	if (strncmp(an_conf_cache,"dbm", 3) == 0) {
290108401Sambrisko		an_cache_mode = 0;
291108401Sambrisko	}
292108401Sambrisko	if (strncmp(an_conf_cache,"per", 3) == 0) {
293108401Sambrisko		an_cache_mode = 1;
294108401Sambrisko 	}
295108401Sambrisko	if (strncmp(an_conf_cache,"raw", 3) == 0) {
296108401Sambrisko		an_cache_mode = 2;
297108401Sambrisko	}
298108401Sambrisko
299108401Sambrisko	return error;
300108401Sambrisko}
301108401Sambrisko
302110531SambriskoSYSCTL_PROC(_hw_an, OID_AUTO, an_cache_mode, CTLTYPE_STRING | CTLFLAG_RW,
303108401Sambrisko            0, sizeof(an_conf_cache), sysctl_an_cache_mode, "A", "");
304108401Sambrisko
30583270Sbrooks/*
30655992Swpaul * We probe for an Aironet 4500/4800 card by attempting to
30755992Swpaul * read the default SSID list. On reset, the first entry in
30855992Swpaul * the SSID list will contain the name "tsunami." If we don't
30955992Swpaul * find this, then there's no card present.
31055992Swpaul */
31183270Sbrooksint
312150446Simpan_probe(device_t dev)
31355992Swpaul{
31455992Swpaul        struct an_softc *sc = device_get_softc(dev);
315119156Sambrisko	struct an_ltv_ssidlist_new	ssid;
31655992Swpaul	int	error;
31755992Swpaul
31855992Swpaul	bzero((char *)&ssid, sizeof(ssid));
31955992Swpaul
32055992Swpaul	error = an_alloc_port(dev, 0, AN_IOSIZ);
32178639Sbrooks	if (error != 0)
32255992Swpaul		return (0);
32355992Swpaul
32455992Swpaul	/* can't do autoprobing */
32555992Swpaul	if (rman_get_start(sc->port_res) == -1)
32655992Swpaul		return(0);
32755992Swpaul
32855992Swpaul	/*
32955992Swpaul	 * We need to fake up a softc structure long enough
33055992Swpaul	 * to be able to issue commands and call some of the
33155992Swpaul	 * other routines.
33255992Swpaul	 */
33356094Swpaul	sc->an_bhandle = rman_get_bushandle(sc->port_res);
33455992Swpaul	sc->an_btag = rman_get_bustag(sc->port_res);
33555992Swpaul	sc->an_unit = device_get_unit(dev);
33655992Swpaul
33755992Swpaul	ssid.an_len = sizeof(ssid);
33855992Swpaul	ssid.an_type = AN_RID_SSIDLIST;
33955992Swpaul
34055992Swpaul        /* Make sure interrupts are disabled. */
341119156Sambrisko	sc->mpi350 = 0;
342108401Sambrisko        CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0);
343108401Sambrisko        CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), 0xFFFF);
34455992Swpaul
34555992Swpaul	an_reset(sc);
34655992Swpaul
34755992Swpaul	if (an_cmd(sc, AN_CMD_READCFG, 0))
34855992Swpaul		return(0);
34955992Swpaul
35055992Swpaul	if (an_read_record(sc, (struct an_ltv_gen *)&ssid))
35155992Swpaul		return(0);
35255992Swpaul
35368692Swpaul	/* See if the ssid matches what we expect ... but doesn't have to */
354119156Sambrisko	if (strcmp(ssid.an_entry[0].an_ssid, AN_DEF_SSID))
35555992Swpaul		return(0);
35683270Sbrooks
35755992Swpaul	return(AN_IOSIZ);
35855992Swpaul}
35955992Swpaul
36055992Swpaul/*
36155992Swpaul * Allocate a port resource with the given resource id.
36255992Swpaul */
36355992Swpaulint
364150446Simpan_alloc_port(device_t dev, int rid, int size)
36555992Swpaul{
36655992Swpaul	struct an_softc *sc = device_get_softc(dev);
36755992Swpaul	struct resource *res;
36855992Swpaul
36955992Swpaul	res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
37055992Swpaul				 0ul, ~0ul, size, RF_ACTIVE);
37155992Swpaul	if (res) {
37255992Swpaul		sc->port_rid = rid;
37355992Swpaul		sc->port_res = res;
37455992Swpaul		return (0);
37555992Swpaul	} else {
37655992Swpaul		return (ENOENT);
37755992Swpaul	}
37855992Swpaul}
37955992Swpaul
38055992Swpaul/*
381108401Sambrisko * Allocate a memory resource with the given resource id.
382108401Sambrisko */
383108401Sambriskoint an_alloc_memory(device_t dev, int rid, int size)
384108401Sambrisko{
385108401Sambrisko	struct an_softc *sc = device_get_softc(dev);
386108401Sambrisko	struct resource *res;
387108401Sambrisko
388108401Sambrisko	res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
389108401Sambrisko				 0ul, ~0ul, size, RF_ACTIVE);
390108401Sambrisko	if (res) {
391108401Sambrisko		sc->mem_rid = rid;
392108401Sambrisko		sc->mem_res = res;
393108401Sambrisko		sc->mem_used = size;
394108401Sambrisko		return (0);
395108401Sambrisko	} else {
396108401Sambrisko		return (ENOENT);
397108401Sambrisko	}
398108401Sambrisko}
399108401Sambrisko
400108401Sambrisko/*
401108401Sambrisko * Allocate a auxilary memory resource with the given resource id.
402108401Sambrisko */
403108401Sambriskoint an_alloc_aux_memory(device_t dev, int rid, int size)
404108401Sambrisko{
405108401Sambrisko	struct an_softc *sc = device_get_softc(dev);
406108401Sambrisko	struct resource *res;
407108401Sambrisko
408108401Sambrisko	res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
409108401Sambrisko				 0ul, ~0ul, size, RF_ACTIVE);
410108401Sambrisko	if (res) {
411108401Sambrisko		sc->mem_aux_rid = rid;
412108401Sambrisko		sc->mem_aux_res = res;
413108401Sambrisko		sc->mem_aux_used = size;
414108401Sambrisko		return (0);
415108401Sambrisko	} else {
416108401Sambrisko		return (ENOENT);
417108401Sambrisko	}
418108401Sambrisko}
419108401Sambrisko
420108401Sambrisko/*
42155992Swpaul * Allocate an irq resource with the given resource id.
42255992Swpaul */
42355992Swpaulint
424150446Simpan_alloc_irq(device_t dev, int rid, int flags)
42555992Swpaul{
42655992Swpaul	struct an_softc *sc = device_get_softc(dev);
42755992Swpaul	struct resource *res;
42855992Swpaul
429127135Snjl	res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
430127135Snjl				     (RF_ACTIVE | flags));
43155992Swpaul	if (res) {
43255992Swpaul		sc->irq_rid = rid;
43355992Swpaul		sc->irq_res = res;
43455992Swpaul		return (0);
43555992Swpaul	} else {
43655992Swpaul		return (ENOENT);
43755992Swpaul	}
43855992Swpaul}
43955992Swpaul
440108401Sambriskostatic void
441150446Simpan_dma_malloc_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
442108401Sambrisko{
443108401Sambrisko	bus_addr_t *paddr = (bus_addr_t*) arg;
444108401Sambrisko	*paddr = segs->ds_addr;
445108401Sambrisko}
446108401Sambrisko
44755992Swpaul/*
448108401Sambrisko * Alloc DMA memory and set the pointer to it
449108401Sambrisko */
450108401Sambriskostatic int
451150446Simpan_dma_malloc(struct an_softc *sc, bus_size_t size, struct an_dma_alloc *dma,
452150446Simp    int mapflags)
453108401Sambrisko{
454108401Sambrisko	int r;
455108401Sambrisko
456108401Sambrisko	r = bus_dmamap_create(sc->an_dtag, BUS_DMA_NOWAIT, &dma->an_dma_map);
457108401Sambrisko	if (r != 0)
458108401Sambrisko		goto fail_0;
459108401Sambrisko
460108401Sambrisko	r = bus_dmamem_alloc(sc->an_dtag, (void**) &dma->an_dma_vaddr,
461108401Sambrisko			     BUS_DMA_NOWAIT, &dma->an_dma_map);
462108401Sambrisko	if (r != 0)
463108401Sambrisko		goto fail_1;
464108401Sambrisko
465108401Sambrisko	r = bus_dmamap_load(sc->an_dtag, dma->an_dma_map, dma->an_dma_vaddr,
466108401Sambrisko		            size,
467108401Sambrisko			    an_dma_malloc_cb,
468108401Sambrisko			    &dma->an_dma_paddr,
469108401Sambrisko			    mapflags | BUS_DMA_NOWAIT);
470108401Sambrisko	if (r != 0)
471108401Sambrisko		goto fail_2;
472108401Sambrisko
473108401Sambrisko	dma->an_dma_size = size;
474108401Sambrisko	return (0);
475108401Sambrisko
476108401Sambriskofail_2:
477108401Sambrisko	bus_dmamap_unload(sc->an_dtag, dma->an_dma_map);
478108401Sambriskofail_1:
479108401Sambrisko	bus_dmamem_free(sc->an_dtag, dma->an_dma_vaddr, dma->an_dma_map);
480108401Sambriskofail_0:
481108401Sambrisko	bus_dmamap_destroy(sc->an_dtag, dma->an_dma_map);
482108401Sambrisko	dma->an_dma_map = NULL;
483108401Sambrisko	return (r);
484108401Sambrisko}
485108401Sambrisko
486108401Sambriskostatic void
487150446Simpan_dma_free(struct an_softc *sc, struct an_dma_alloc *dma)
488108401Sambrisko{
489108401Sambrisko	bus_dmamap_unload(sc->an_dtag, dma->an_dma_map);
490108401Sambrisko	bus_dmamem_free(sc->an_dtag, dma->an_dma_vaddr, dma->an_dma_map);
491123978Sambrisko	dma->an_dma_vaddr = 0;
492108401Sambrisko	bus_dmamap_destroy(sc->an_dtag, dma->an_dma_map);
493108401Sambrisko}
494108401Sambrisko
495108401Sambrisko/*
49655992Swpaul * Release all resources
49755992Swpaul */
49855992Swpaulvoid
499150446Simpan_release_resources(device_t dev)
50055992Swpaul{
50155992Swpaul	struct an_softc *sc = device_get_softc(dev);
502108401Sambrisko	int i;
50355992Swpaul
50455992Swpaul	if (sc->port_res) {
50555992Swpaul		bus_release_resource(dev, SYS_RES_IOPORT,
50655992Swpaul				     sc->port_rid, sc->port_res);
50755992Swpaul		sc->port_res = 0;
50855992Swpaul	}
509108401Sambrisko	if (sc->mem_res) {
510108401Sambrisko		bus_release_resource(dev, SYS_RES_MEMORY,
511108401Sambrisko				     sc->mem_rid, sc->mem_res);
512108401Sambrisko		sc->mem_res = 0;
513108401Sambrisko	}
514108401Sambrisko	if (sc->mem_aux_res) {
515108401Sambrisko		bus_release_resource(dev, SYS_RES_MEMORY,
516108401Sambrisko				     sc->mem_aux_rid, sc->mem_aux_res);
517108401Sambrisko		sc->mem_aux_res = 0;
518108401Sambrisko	}
51955992Swpaul	if (sc->irq_res) {
52055992Swpaul		bus_release_resource(dev, SYS_RES_IRQ,
52155992Swpaul				     sc->irq_rid, sc->irq_res);
52255992Swpaul		sc->irq_res = 0;
52355992Swpaul	}
524108401Sambrisko	if (sc->an_rid_buffer.an_dma_paddr) {
525108401Sambrisko		an_dma_free(sc, &sc->an_rid_buffer);
526108401Sambrisko	}
527108401Sambrisko	for (i = 0; i < AN_MAX_RX_DESC; i++)
528108401Sambrisko		if (sc->an_rx_buffer[i].an_dma_paddr) {
529108401Sambrisko			an_dma_free(sc, &sc->an_rx_buffer[i]);
530108401Sambrisko		}
531108401Sambrisko	for (i = 0; i < AN_MAX_TX_DESC; i++)
532108401Sambrisko		if (sc->an_tx_buffer[i].an_dma_paddr) {
533108401Sambrisko			an_dma_free(sc, &sc->an_tx_buffer[i]);
534108401Sambrisko		}
535108401Sambrisko	if (sc->an_dtag) {
536108401Sambrisko		bus_dma_tag_destroy(sc->an_dtag);
537108401Sambrisko	}
538108401Sambrisko
53955992Swpaul}
54055992Swpaul
54183270Sbrooksint
542150446Simpan_init_mpi350_desc(struct an_softc *sc)
543108401Sambrisko{
544108401Sambrisko	struct an_command	cmd_struct;
545108401Sambrisko	struct an_reply		reply;
546108401Sambrisko	struct an_card_rid_desc an_rid_desc;
547108401Sambrisko	struct an_card_rx_desc	an_rx_desc;
548108401Sambrisko	struct an_card_tx_desc	an_tx_desc;
549108401Sambrisko	int			i, desc;
550108401Sambrisko
551108401Sambrisko	if(!sc->an_rid_buffer.an_dma_paddr)
552108401Sambrisko		an_dma_malloc(sc, AN_RID_BUFFER_SIZE,
553108401Sambrisko				 &sc->an_rid_buffer, 0);
554108401Sambrisko	for (i = 0; i < AN_MAX_RX_DESC; i++)
555108401Sambrisko		if(!sc->an_rx_buffer[i].an_dma_paddr)
556108401Sambrisko			an_dma_malloc(sc, AN_RX_BUFFER_SIZE,
557108401Sambrisko				      &sc->an_rx_buffer[i], 0);
558108401Sambrisko	for (i = 0; i < AN_MAX_TX_DESC; i++)
559108401Sambrisko		if(!sc->an_tx_buffer[i].an_dma_paddr)
560108401Sambrisko			an_dma_malloc(sc, AN_TX_BUFFER_SIZE,
561108401Sambrisko				      &sc->an_tx_buffer[i], 0);
562108401Sambrisko
563108401Sambrisko	/*
564108401Sambrisko	 * Allocate RX descriptor
565108401Sambrisko	 */
566108401Sambrisko	bzero(&reply,sizeof(reply));
567108401Sambrisko	cmd_struct.an_cmd   = AN_CMD_ALLOC_DESC;
568108401Sambrisko	cmd_struct.an_parm0 = AN_DESCRIPTOR_RX;
569108401Sambrisko	cmd_struct.an_parm1 = AN_RX_DESC_OFFSET;
570108401Sambrisko	cmd_struct.an_parm2 = AN_MAX_RX_DESC;
571108401Sambrisko	if (an_cmd_struct(sc, &cmd_struct, &reply)) {
572108401Sambrisko		printf("an%d: failed to allocate RX descriptor\n",
573108401Sambrisko		       sc->an_unit);
574108401Sambrisko		return(EIO);
575108401Sambrisko	}
576108401Sambrisko
577108401Sambrisko	for (desc = 0; desc < AN_MAX_RX_DESC; desc++) {
578108401Sambrisko		bzero(&an_rx_desc, sizeof(an_rx_desc));
579108401Sambrisko		an_rx_desc.an_valid = 1;
580108401Sambrisko		an_rx_desc.an_len = AN_RX_BUFFER_SIZE;
581108401Sambrisko		an_rx_desc.an_done = 0;
582108401Sambrisko		an_rx_desc.an_phys = sc->an_rx_buffer[desc].an_dma_paddr;
583108401Sambrisko
584108401Sambrisko		for (i = 0; i < sizeof(an_rx_desc) / 4; i++)
585155321Simp			CSR_MEM_AUX_WRITE_4(sc, AN_RX_DESC_OFFSET
586155321Simp			    + (desc * sizeof(an_rx_desc))
587155321Simp			    + (i * 4),
588155321Simp			    ((u_int32_t *)(void *)&an_rx_desc)[i]);
589108401Sambrisko	}
590108401Sambrisko
591108401Sambrisko	/*
592108401Sambrisko	 * Allocate TX descriptor
593108401Sambrisko	 */
594108401Sambrisko
595108401Sambrisko	bzero(&reply,sizeof(reply));
596108401Sambrisko	cmd_struct.an_cmd   = AN_CMD_ALLOC_DESC;
597108401Sambrisko	cmd_struct.an_parm0 = AN_DESCRIPTOR_TX;
598108401Sambrisko	cmd_struct.an_parm1 = AN_TX_DESC_OFFSET;
599108401Sambrisko	cmd_struct.an_parm2 = AN_MAX_TX_DESC;
600108401Sambrisko	if (an_cmd_struct(sc, &cmd_struct, &reply)) {
601108401Sambrisko		printf("an%d: failed to allocate TX descriptor\n",
602108401Sambrisko		       sc->an_unit);
603108401Sambrisko		return(EIO);
604108401Sambrisko	}
605108401Sambrisko
606108401Sambrisko	for (desc = 0; desc < AN_MAX_TX_DESC; desc++) {
607108401Sambrisko		bzero(&an_tx_desc, sizeof(an_tx_desc));
608108401Sambrisko		an_tx_desc.an_offset = 0;
609108401Sambrisko		an_tx_desc.an_eoc = 0;
610108401Sambrisko		an_tx_desc.an_valid = 0;
611108401Sambrisko		an_tx_desc.an_len = 0;
612108401Sambrisko		an_tx_desc.an_phys = sc->an_tx_buffer[desc].an_dma_paddr;
613108401Sambrisko
614108401Sambrisko		for (i = 0; i < sizeof(an_tx_desc) / 4; i++)
615108401Sambrisko			CSR_MEM_AUX_WRITE_4(sc, AN_TX_DESC_OFFSET
616155321Simp			    + (desc * sizeof(an_tx_desc))
617155321Simp			    + (i * 4),
618155321Simp			    ((u_int32_t *)(void *)&an_tx_desc)[i]);
619108401Sambrisko	}
620108401Sambrisko
621108401Sambrisko	/*
622108401Sambrisko	 * Allocate RID descriptor
623108401Sambrisko	 */
624108401Sambrisko
625108401Sambrisko	bzero(&reply,sizeof(reply));
626108401Sambrisko	cmd_struct.an_cmd   = AN_CMD_ALLOC_DESC;
627108401Sambrisko	cmd_struct.an_parm0 = AN_DESCRIPTOR_HOSTRW;
628108401Sambrisko	cmd_struct.an_parm1 = AN_HOST_DESC_OFFSET;
629108401Sambrisko	cmd_struct.an_parm2 = 1;
630108401Sambrisko	if (an_cmd_struct(sc, &cmd_struct, &reply)) {
631108401Sambrisko		printf("an%d: failed to allocate host descriptor\n",
632108401Sambrisko		       sc->an_unit);
633108401Sambrisko		return(EIO);
634108401Sambrisko	}
635108401Sambrisko
636108401Sambrisko	bzero(&an_rid_desc, sizeof(an_rid_desc));
637108401Sambrisko	an_rid_desc.an_valid = 1;
638108401Sambrisko	an_rid_desc.an_len = AN_RID_BUFFER_SIZE;
639108401Sambrisko	an_rid_desc.an_rid = 0;
640108401Sambrisko	an_rid_desc.an_phys = sc->an_rid_buffer.an_dma_paddr;
641108401Sambrisko
642108401Sambrisko	for (i = 0; i < sizeof(an_rid_desc) / 4; i++)
643108401Sambrisko		CSR_MEM_AUX_WRITE_4(sc, AN_HOST_DESC_OFFSET + i * 4,
644155321Simp				    ((u_int32_t *)(void *)&an_rid_desc)[i]);
645108401Sambrisko
646108401Sambrisko	return(0);
647108401Sambrisko}
648108401Sambrisko
649108401Sambriskoint
650150446Simpan_attach(struct an_softc *sc, int unit, int flags)
65155992Swpaul{
652147256Sbrooks	struct ifnet		*ifp;
653113316Simp	int			error = EIO;
654110253Sambrisko	int			i, nrate, mword;
655110253Sambrisko	u_int8_t		r;
65655992Swpaul
65793818Sjhb	mtx_init(&sc->an_mtx, device_get_nameunit(sc->an_dev), MTX_NETWORK_LOCK,
65893818Sjhb	    MTX_DEF | MTX_RECURSE);
659147380Sdelphij	ifp = sc->an_ifp = if_alloc(IFT_ETHER);
660147256Sbrooks	if (ifp == NULL) {
661147256Sbrooks		printf("an%d: can not if_alloc()\n", sc->an_unit);
662147256Sbrooks		goto fail;
663147256Sbrooks	}
664147256Sbrooks
66555992Swpaul	sc->an_gone = 0;
66655992Swpaul	sc->an_associated = 0;
66783269Sbrooks	sc->an_monitor = 0;
66883269Sbrooks	sc->an_was_monitor = 0;
669108401Sambrisko	sc->an_flash_buffer = NULL;
67055992Swpaul
67155992Swpaul	/* Reset the NIC. */
67255992Swpaul	an_reset(sc);
673110104Sambrisko	if (sc->mpi350) {
674108401Sambrisko		error = an_init_mpi350_desc(sc);
675108401Sambrisko		if (error)
676113316Simp			goto fail;
677108401Sambrisko	}
67855992Swpaul
67955992Swpaul	/* Load factory config */
68055992Swpaul	if (an_cmd(sc, AN_CMD_READCFG, 0)) {
68155992Swpaul		printf("an%d: failed to load config data\n", sc->an_unit);
682113316Simp		goto fail;
68355992Swpaul	}
68455992Swpaul
68555992Swpaul	/* Read the current configuration */
68655992Swpaul	sc->an_config.an_type = AN_RID_GENCONFIG;
68755992Swpaul	sc->an_config.an_len = sizeof(struct an_ltv_genconfig);
68855992Swpaul	if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_config)) {
68955992Swpaul		printf("an%d: read record failed\n", sc->an_unit);
690113316Simp		goto fail;
69155992Swpaul	}
69255992Swpaul
69355992Swpaul	/* Read the card capabilities */
69455992Swpaul	sc->an_caps.an_type = AN_RID_CAPABILITIES;
69555992Swpaul	sc->an_caps.an_len = sizeof(struct an_ltv_caps);
69655992Swpaul	if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_caps)) {
69755992Swpaul		printf("an%d: read record failed\n", sc->an_unit);
698113316Simp		goto fail;
69955992Swpaul	}
70055992Swpaul
70155992Swpaul	/* Read ssid list */
70255992Swpaul	sc->an_ssidlist.an_type = AN_RID_SSIDLIST;
703119156Sambrisko	sc->an_ssidlist.an_len = sizeof(struct an_ltv_ssidlist_new);
70455992Swpaul	if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_ssidlist)) {
70555992Swpaul		printf("an%d: read record failed\n", sc->an_unit);
706113316Simp		goto fail;
70755992Swpaul	}
70855992Swpaul
70955992Swpaul	/* Read AP list */
71055992Swpaul	sc->an_aplist.an_type = AN_RID_APLIST;
71155992Swpaul	sc->an_aplist.an_len = sizeof(struct an_ltv_aplist);
71255992Swpaul	if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_aplist)) {
71355992Swpaul		printf("an%d: read record failed\n", sc->an_unit);
714113316Simp		goto fail;
71555992Swpaul	}
71655992Swpaul
717108401Sambrisko#ifdef ANCACHE
718108401Sambrisko	/* Read the RSSI <-> dBm map */
719108401Sambrisko	sc->an_have_rssimap = 0;
720108401Sambrisko	if (sc->an_caps.an_softcaps & 8) {
721108401Sambrisko		sc->an_rssimap.an_type = AN_RID_RSSI_MAP;
722108401Sambrisko		sc->an_rssimap.an_len = sizeof(struct an_ltv_rssi_map);
723108401Sambrisko		if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_rssimap)) {
724108401Sambrisko			printf("an%d: unable to get RSSI <-> dBM map\n", sc->an_unit);
725108401Sambrisko		} else {
726108401Sambrisko			printf("an%d: got RSSI <-> dBM map\n", sc->an_unit);
727108401Sambrisko			sc->an_have_rssimap = 1;
728108401Sambrisko		}
729108401Sambrisko	} else {
730108401Sambrisko		printf("an%d: no RSSI <-> dBM map\n", sc->an_unit);
731108401Sambrisko	}
732108401Sambrisko#endif
733108401Sambrisko
73455992Swpaul	ifp->if_softc = sc;
735121816Sbrooks	sc->an_unit = unit;
736121816Sbrooks	if_initname(ifp, device_get_name(sc->an_dev),
737121816Sbrooks	    device_get_unit(sc->an_dev));
73855992Swpaul	ifp->if_mtu = ETHERMTU;
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_watchdog = an_watchdog;
74355992Swpaul	ifp->if_init = an_init;
74455992Swpaul	ifp->if_baudrate = 10000000;
745132986Smlaier	IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
746132986Smlaier	ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
747132986Smlaier	IFQ_SET_READY(&ifp->if_snd);
74855992Swpaul
74955992Swpaul	bzero(sc->an_config.an_nodename, sizeof(sc->an_config.an_nodename));
75055992Swpaul	bcopy(AN_DEFAULT_NODENAME, sc->an_config.an_nodename,
75155992Swpaul	    sizeof(AN_DEFAULT_NODENAME) - 1);
75255992Swpaul
753119156Sambrisko	bzero(sc->an_ssidlist.an_entry[0].an_ssid,
754119156Sambrisko	      sizeof(sc->an_ssidlist.an_entry[0].an_ssid));
755119156Sambrisko	bcopy(AN_DEFAULT_NETNAME, sc->an_ssidlist.an_entry[0].an_ssid,
75655992Swpaul	    sizeof(AN_DEFAULT_NETNAME) - 1);
757119156Sambrisko	sc->an_ssidlist.an_entry[0].an_len = strlen(AN_DEFAULT_NETNAME);
75855992Swpaul
75955992Swpaul	sc->an_config.an_opmode =
76074144Sassar	    AN_OPMODE_INFRASTRUCTURE_STATION;
76155992Swpaul
76255992Swpaul	sc->an_tx_rate = 0;
76355992Swpaul	bzero((char *)&sc->an_stats, sizeof(sc->an_stats));
76455992Swpaul
765110253Sambrisko	nrate = 8;
766110253Sambrisko
76777217Sphk	ifmedia_init(&sc->an_ifmedia, 0, an_media_change, an_media_status);
768110253Sambrisko	if_printf(ifp, "supported rates: ");
769110253Sambrisko#define	ADD(s, o)	ifmedia_add(&sc->an_ifmedia, \
770110253Sambrisko	IFM_MAKEWORD(IFM_IEEE80211, (s), (o), 0), 0, NULL)
771110253Sambrisko	ADD(IFM_AUTO, 0);
772110253Sambrisko	ADD(IFM_AUTO, IFM_IEEE80211_ADHOC);
773110253Sambrisko	for (i = 0; i < nrate; i++) {
774110253Sambrisko		r = sc->an_caps.an_rates[i];
775116951Ssam		mword = ieee80211_rate2media(NULL, r, IEEE80211_T_DS);
776110253Sambrisko		if (mword == 0)
777110253Sambrisko			continue;
778110253Sambrisko		printf("%s%d%sMbps", (i != 0 ? " " : ""),
779110253Sambrisko		    (r & IEEE80211_RATE_VAL) / 2, ((r & 0x1) != 0 ? ".5" : ""));
780110253Sambrisko		ADD(mword, 0);
781110253Sambrisko		ADD(mword, IFM_IEEE80211_ADHOC);
78277217Sphk	}
783110253Sambrisko	printf("\n");
784110253Sambrisko	ifmedia_set(&sc->an_ifmedia, IFM_MAKEWORD(IFM_IEEE80211,
785110253Sambrisko	    IFM_AUTO, 0, 0));
786110253Sambrisko#undef ADD
78777217Sphk
78855992Swpaul	/*
78963090Sarchie	 * Call MI attach routine.
79055992Swpaul	 */
791147256Sbrooks
792147256Sbrooks	ether_ifattach(ifp, sc->an_caps.an_oemaddr);
79355992Swpaul	callout_handle_init(&sc->an_stat_ch);
79455992Swpaul
79555992Swpaul	return(0);
796113316Simpfail:;
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);
821147256Sbrooks	if_free(ifp);
822123978Sambrisko	an_release_resources(dev);
823123978Sambrisko	mtx_destroy(&sc->an_mtx);
824123978Sambrisko	return (0);
825123978Sambrisko}
826123978Sambrisko
82783270Sbrooksstatic void
828150446Simpan_rxeof(struct an_softc *sc)
82955992Swpaul{
83083269Sbrooks	struct ifnet   *ifp;
83183269Sbrooks	struct ether_header *eh;
83283269Sbrooks	struct ieee80211_frame *ih;
83383269Sbrooks	struct an_rxframe rx_frame;
83483269Sbrooks	struct an_rxframe_802_3 rx_frame_802_3;
83583269Sbrooks	struct mbuf    *m;
836108401Sambrisko	int		len, id, error = 0, i, count = 0;
837108401Sambrisko	int		ieee80211_header_len;
838108401Sambrisko	u_char		*bpf_buf;
839108401Sambrisko	u_short		fc1;
840108401Sambrisko	struct an_card_rx_desc an_rx_desc;
841108401Sambrisko	u_int8_t	*buf;
84255992Swpaul
843122689Ssam	AN_LOCK_ASSERT(sc);
844122689Ssam
845147256Sbrooks	ifp = sc->an_ifp;
84655992Swpaul
847108401Sambrisko	if (!sc->mpi350) {
848108401Sambrisko		id = CSR_READ_2(sc, AN_RX_FID);
84955992Swpaul
850108401Sambrisko		if (sc->an_monitor && (ifp->if_flags & IFF_PROMISC)) {
851108401Sambrisko			/* read raw 802.11 packet */
852108401Sambrisko			bpf_buf = sc->buf_802_11;
85355992Swpaul
854108401Sambrisko			/* read header */
855108401Sambrisko			if (an_read_data(sc, id, 0x0, (caddr_t)&rx_frame,
856108401Sambrisko					 sizeof(rx_frame))) {
857108401Sambrisko				ifp->if_ierrors++;
858108401Sambrisko				return;
859108401Sambrisko			}
86055992Swpaul
861108401Sambrisko			/*
862108401Sambrisko			 * skip beacon by default since this increases the
863108401Sambrisko			 * system load a lot
864108401Sambrisko			 */
86583270Sbrooks
866108401Sambrisko			if (!(sc->an_monitor & AN_MONITOR_INCLUDE_BEACON) &&
867108401Sambrisko			    (rx_frame.an_frame_ctl &
868108401Sambrisko			     IEEE80211_FC0_SUBTYPE_BEACON)) {
86983269Sbrooks				return;
87083269Sbrooks			}
87155992Swpaul
872108401Sambrisko			if (sc->an_monitor & AN_MONITOR_AIRONET_HEADER) {
873108401Sambrisko				len = rx_frame.an_rx_payload_len
874108401Sambrisko					+ sizeof(rx_frame);
875108401Sambrisko				/* Check for insane frame length */
876108401Sambrisko				if (len > sizeof(sc->buf_802_11)) {
877108401Sambrisko					printf("an%d: oversized packet "
878108401Sambrisko					       "received (%d, %d)\n",
879108401Sambrisko					       sc->an_unit, len, MCLBYTES);
880108401Sambrisko					ifp->if_ierrors++;
881108401Sambrisko					return;
882108401Sambrisko				}
88355992Swpaul
884108401Sambrisko				bcopy((char *)&rx_frame,
885108401Sambrisko				      bpf_buf, sizeof(rx_frame));
886108401Sambrisko
887108401Sambrisko				error = an_read_data(sc, id, sizeof(rx_frame),
888108401Sambrisko					    (caddr_t)bpf_buf+sizeof(rx_frame),
889108401Sambrisko					    rx_frame.an_rx_payload_len);
890108401Sambrisko			} else {
891108401Sambrisko				fc1=rx_frame.an_frame_ctl >> 8;
892108401Sambrisko				ieee80211_header_len =
893108401Sambrisko					sizeof(struct ieee80211_frame);
894108401Sambrisko				if ((fc1 & IEEE80211_FC1_DIR_TODS) &&
895108401Sambrisko				    (fc1 & IEEE80211_FC1_DIR_FROMDS)) {
896108401Sambrisko					ieee80211_header_len += ETHER_ADDR_LEN;
897108401Sambrisko				}
898108401Sambrisko
899108401Sambrisko				len = rx_frame.an_rx_payload_len
900108401Sambrisko					+ ieee80211_header_len;
901108401Sambrisko				/* Check for insane frame length */
902108401Sambrisko				if (len > sizeof(sc->buf_802_11)) {
903108401Sambrisko					printf("an%d: oversized packet "
904108401Sambrisko					       "received (%d, %d)\n",
905108401Sambrisko					       sc->an_unit, len, MCLBYTES);
906108401Sambrisko					ifp->if_ierrors++;
907108401Sambrisko					return;
908108401Sambrisko				}
909108401Sambrisko
910108401Sambrisko				ih = (struct ieee80211_frame *)bpf_buf;
911108401Sambrisko
912108401Sambrisko				bcopy((char *)&rx_frame.an_frame_ctl,
913108401Sambrisko				      (char *)ih, ieee80211_header_len);
914108401Sambrisko
915108401Sambrisko				error = an_read_data(sc, id, sizeof(rx_frame) +
916108401Sambrisko					    rx_frame.an_gaplen,
917108401Sambrisko					    (caddr_t)ih +ieee80211_header_len,
918108401Sambrisko					    rx_frame.an_rx_payload_len);
919108401Sambrisko			}
920108401Sambrisko			/* dump raw 802.11 packet to bpf and skip ip stack */
921108401Sambrisko			BPF_TAP(ifp, bpf_buf, len);
92283270Sbrooks		} else {
923111119Simp			MGETHDR(m, M_DONTWAIT, MT_DATA);
924108401Sambrisko			if (m == NULL) {
925108401Sambrisko				ifp->if_ierrors++;
926108401Sambrisko				return;
92783269Sbrooks			}
928111119Simp			MCLGET(m, M_DONTWAIT);
929108401Sambrisko			if (!(m->m_flags & M_EXT)) {
930108401Sambrisko				m_freem(m);
931108401Sambrisko				ifp->if_ierrors++;
932108401Sambrisko				return;
933108401Sambrisko			}
934108401Sambrisko			m->m_pkthdr.rcvif = ifp;
935108401Sambrisko			/* Read Ethernet encapsulated packet */
93655992Swpaul
937108401Sambrisko#ifdef ANCACHE
938108401Sambrisko			/* Read NIC frame header */
939108401Sambrisko			if (an_read_data(sc, id, 0, (caddr_t)&rx_frame,
940108401Sambrisko					 sizeof(rx_frame))) {
941154394Srwatson				m_freem(m);
942108401Sambrisko				ifp->if_ierrors++;
943108401Sambrisko				return;
944108401Sambrisko			}
945108401Sambrisko#endif
946108401Sambrisko			/* Read in the 802_3 frame header */
947108401Sambrisko			if (an_read_data(sc, id, 0x34,
948108401Sambrisko					 (caddr_t)&rx_frame_802_3,
949108401Sambrisko					 sizeof(rx_frame_802_3))) {
950154394Srwatson				m_freem(m);
951108401Sambrisko				ifp->if_ierrors++;
952108401Sambrisko				return;
953108401Sambrisko			}
954108401Sambrisko			if (rx_frame_802_3.an_rx_802_3_status != 0) {
955154394Srwatson				m_freem(m);
956108401Sambrisko				ifp->if_ierrors++;
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);
963108401Sambrisko				printf("an%d: oversized packet "
964108401Sambrisko				       "received (%d, %d)\n",
96583269Sbrooks				       sc->an_unit, len, MCLBYTES);
96683269Sbrooks				ifp->if_ierrors++;
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 */
980108401Sambrisko			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);
986108401Sambrisko				ifp->if_ierrors++;
987108401Sambrisko				return;
988108401Sambrisko			}
989108401Sambrisko			ifp->if_ipackets++;
990108401Sambrisko
991108401Sambrisko			/* Receive packet. */
99283269Sbrooks#ifdef ANCACHE
993108401Sambrisko			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++)
1005155321Simp				((u_int32_t *)(void *)&an_rx_desc)[i]
1006108401Sambrisko					= CSR_MEM_AUX_READ_4(sc,
1007108401Sambrisko						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
1014111119Simp				MGETHDR(m, M_DONTWAIT, MT_DATA);
1015108401Sambrisko				if (m == NULL) {
1016108401Sambrisko					ifp->if_ierrors++;
1017108401Sambrisko					return;
1018108401Sambrisko				}
1019111119Simp				MCLGET(m, M_DONTWAIT);
1020108401Sambrisko				if (!(m->m_flags & M_EXT)) {
1021108401Sambrisko					m_freem(m);
1022108401Sambrisko					ifp->if_ierrors++;
1023108401Sambrisko					return;
1024108401Sambrisko				}
1025108401Sambrisko				m->m_pkthdr.rcvif = ifp;
1026108401Sambrisko				/* Read Ethernet encapsulated packet */
102783269Sbrooks
1028108401Sambrisko				/*
1029108401Sambrisko				 * No ANCACHE support since we just get back
1030108401Sambrisko				 * an Ethernet packet no 802.11 info
1031108401Sambrisko				 */
1032108401Sambrisko#if 0
1033108401Sambrisko#ifdef ANCACHE
1034108401Sambrisko				/* Read NIC frame header */
1035108401Sambrisko				bcopy(buf, (caddr_t)&rx_frame,
1036108401Sambrisko				      sizeof(rx_frame));
1037108401Sambrisko#endif
1038108401Sambrisko#endif
1039108401Sambrisko				/* Check for insane frame length */
1040108401Sambrisko				len = an_rx_desc.an_len + 12;
1041108401Sambrisko				if (len > MCLBYTES) {
1042154393Srwatson					m_freem(m);
1043108401Sambrisko					printf("an%d: oversized packet "
1044108401Sambrisko					       "received (%d, %d)\n",
1045108401Sambrisko					       sc->an_unit, len, MCLBYTES);
1046108401Sambrisko					ifp->if_ierrors++;
1047108401Sambrisko					return;
1048108401Sambrisko				}
104983269Sbrooks
1050108401Sambrisko				m->m_pkthdr.len = m->m_len =
1051108401Sambrisko					an_rx_desc.an_len + 12;
1052108401Sambrisko
1053108401Sambrisko				eh = mtod(m, struct ether_header *);
1054108401Sambrisko
1055108401Sambrisko				bcopy(buf, (char *)eh,
1056108401Sambrisko				      m->m_pkthdr.len);
1057108401Sambrisko
1058108401Sambrisko				ifp->if_ipackets++;
1059108401Sambrisko
1060108401Sambrisko				/* Receive packet. */
1061108401Sambrisko#if 0
106255992Swpaul#ifdef ANCACHE
1063108401Sambrisko				an_cache_store(sc, eh, m,
1064110253Sambrisko					rx_frame.an_rx_signal_strength,
1065110253Sambrisko					rx_frame.an_rsvd0);
106655992Swpaul#endif
1067108401Sambrisko#endif
1068171775Savatar				AN_UNLOCK(sc);
1069108401Sambrisko				(*ifp->if_input)(ifp, m);
1070171775Savatar				AN_LOCK(sc);
1071171775Savatar
1072108401Sambrisko				an_rx_desc.an_valid = 1;
1073108401Sambrisko				an_rx_desc.an_len = AN_RX_BUFFER_SIZE;
1074108401Sambrisko				an_rx_desc.an_done = 0;
1075108401Sambrisko				an_rx_desc.an_phys =
1076108401Sambrisko					sc->an_rx_buffer[count].an_dma_paddr;
1077108401Sambrisko
1078108401Sambrisko				for (i = 0; i < sizeof(an_rx_desc) / 4; i++)
1079108401Sambrisko					CSR_MEM_AUX_WRITE_4(sc,
1080155321Simp					    AN_RX_DESC_OFFSET
1081155321Simp					    + (count * sizeof(an_rx_desc))
1082155321Simp					    + (i * 4),
1083155321Simp					    ((u_int32_t *)(void *)&an_rx_desc)[i]);
1084108401Sambrisko
1085108401Sambrisko			} else {
1086108401Sambrisko				printf("an%d: Didn't get valid RX packet "
1087108401Sambrisko				       "%x %x %d\n",
1088108401Sambrisko				       sc->an_unit,
1089108401Sambrisko				       an_rx_desc.an_done,
1090108401Sambrisko				       an_rx_desc.an_valid, an_rx_desc.an_len);
1091108401Sambrisko			}
1092108401Sambrisko		}
109383269Sbrooks	}
109455992Swpaul}
109555992Swpaul
109683270Sbrooksstatic void
1097150446Simpan_txeof(struct an_softc *sc, int status)
109855992Swpaul{
109955992Swpaul	struct ifnet		*ifp;
110078639Sbrooks	int			id, i;
110155992Swpaul
1102147256Sbrooks	ifp = sc->an_ifp;
110355992Swpaul
110455992Swpaul	ifp->if_timer = 0;
1105148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
110655992Swpaul
1107108401Sambrisko	if (!sc->mpi350) {
1108119156Sambrisko		id = CSR_READ_2(sc, AN_TX_CMP_FID(sc->mpi350));
110955992Swpaul
1110108401Sambrisko		if (status & AN_EV_TX_EXC) {
1111108401Sambrisko			ifp->if_oerrors++;
1112108401Sambrisko		} else
1113108401Sambrisko			ifp->if_opackets++;
111455992Swpaul
1115108401Sambrisko		for (i = 0; i < AN_TX_RING_CNT; i++) {
1116108401Sambrisko			if (id == sc->an_rdata.an_tx_ring[i]) {
1117108401Sambrisko				sc->an_rdata.an_tx_ring[i] = 0;
1118108401Sambrisko				break;
1119108401Sambrisko			}
112078639Sbrooks		}
1121108401Sambrisko
1122108401Sambrisko		AN_INC(sc->an_rdata.an_tx_cons, AN_TX_RING_CNT);
1123108401Sambrisko	} else { /* MPI 350 */
1124119156Sambrisko		id = CSR_READ_2(sc, AN_TX_CMP_FID(sc->mpi350));
1125119156Sambrisko		if (!sc->an_rdata.an_tx_empty){
1126119156Sambrisko			if (status & AN_EV_TX_EXC) {
1127119156Sambrisko				ifp->if_oerrors++;
1128119156Sambrisko			} else
1129119156Sambrisko				ifp->if_opackets++;
1130119156Sambrisko			AN_INC(sc->an_rdata.an_tx_cons, AN_MAX_TX_DESC);
1131119156Sambrisko			if (sc->an_rdata.an_tx_prod ==
1132119156Sambrisko			    sc->an_rdata.an_tx_cons)
1133119156Sambrisko				sc->an_rdata.an_tx_empty = 1;
1134119156Sambrisko		}
113578639Sbrooks	}
113655992Swpaul
113755992Swpaul	return;
113855992Swpaul}
113955992Swpaul
114055992Swpaul/*
114155992Swpaul * We abuse the stats updater to check the current NIC status. This
114255992Swpaul * is important because we don't want to allow transmissions until
114355992Swpaul * the NIC has synchronized to the current cell (either as the master
114455992Swpaul * in an ad-hoc group, or as a station connected to an access point).
114555992Swpaul */
1146104094Sphkstatic void
1147150446Simpan_stats_update(void *xsc)
114855992Swpaul{
114955992Swpaul	struct an_softc		*sc;
115055992Swpaul	struct ifnet		*ifp;
115155992Swpaul
115255992Swpaul	sc = xsc;
115367094Swpaul	AN_LOCK(sc);
1154147256Sbrooks	ifp = sc->an_ifp;
115555992Swpaul
115655992Swpaul	sc->an_status.an_type = AN_RID_STATUS;
115755992Swpaul	sc->an_status.an_len = sizeof(struct an_ltv_status);
115855992Swpaul	an_read_record(sc, (struct an_ltv_gen *)&sc->an_status);
115955992Swpaul
116055992Swpaul	if (sc->an_status.an_opmode & AN_STATUS_OPMODE_IN_SYNC)
116155992Swpaul		sc->an_associated = 1;
116255992Swpaul	else
116355992Swpaul		sc->an_associated = 0;
116455992Swpaul
116555992Swpaul	/* Don't do this while we're transmitting */
1166148887Srwatson	if (ifp->if_drv_flags & IFF_DRV_OACTIVE) {
116755992Swpaul		sc->an_stat_ch = timeout(an_stats_update, sc, hz);
116867094Swpaul		AN_UNLOCK(sc);
116955992Swpaul		return;
117055992Swpaul	}
117155992Swpaul
117255992Swpaul	sc->an_stats.an_len = sizeof(struct an_ltv_stats);
117355992Swpaul	sc->an_stats.an_type = AN_RID_32BITS_CUM;
117455992Swpaul	an_read_record(sc, (struct an_ltv_gen *)&sc->an_stats.an_len);
117555992Swpaul
117655992Swpaul	sc->an_stat_ch = timeout(an_stats_update, sc, hz);
117767094Swpaul	AN_UNLOCK(sc);
117855992Swpaul
117955992Swpaul	return;
118055992Swpaul}
118155992Swpaul
118283270Sbrooksvoid
1183150446Simpan_intr(void *xsc)
118455992Swpaul{
118555992Swpaul	struct an_softc		*sc;
118655992Swpaul	struct ifnet		*ifp;
118755992Swpaul	u_int16_t		status;
118855992Swpaul
118955992Swpaul	sc = (struct an_softc*)xsc;
119055992Swpaul
119167094Swpaul	AN_LOCK(sc);
119267094Swpaul
119367094Swpaul	if (sc->an_gone) {
119467094Swpaul		AN_UNLOCK(sc);
119555992Swpaul		return;
119667094Swpaul	}
119755992Swpaul
1198147256Sbrooks	ifp = sc->an_ifp;
119955992Swpaul
120055992Swpaul	/* Disable interrupts. */
1201108401Sambrisko	CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0);
120255992Swpaul
1203108401Sambrisko	status = CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350));
1204119156Sambrisko	CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), ~AN_INTRS(sc->mpi350));
120555992Swpaul
1206119156Sambrisko	if (status & AN_EV_MIC) {
1207119156Sambrisko		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_MIC);
120855992Swpaul	}
120955992Swpaul
121055992Swpaul	if (status & AN_EV_LINKSTAT) {
1211108401Sambrisko		if (CSR_READ_2(sc, AN_LINKSTAT(sc->mpi350))
1212108401Sambrisko		    == AN_LINKSTAT_ASSOCIATED)
121355992Swpaul			sc->an_associated = 1;
121455992Swpaul		else
121555992Swpaul			sc->an_associated = 0;
1216108401Sambrisko		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_LINKSTAT);
121755992Swpaul	}
121855992Swpaul
121955992Swpaul	if (status & AN_EV_RX) {
122055992Swpaul		an_rxeof(sc);
1221108401Sambrisko		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_RX);
122255992Swpaul	}
122355992Swpaul
1224119156Sambrisko	if (sc->mpi350 && status & AN_EV_TX_CPY) {
1225119156Sambrisko		an_txeof(sc, status);
1226150446Simp		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_TX_CPY);
1227119156Sambrisko	}
1228119156Sambrisko
122955992Swpaul	if (status & AN_EV_TX) {
123055992Swpaul		an_txeof(sc, status);
1231150446Simp		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_TX);
123255992Swpaul	}
123355992Swpaul
123455992Swpaul	if (status & AN_EV_TX_EXC) {
123555992Swpaul		an_txeof(sc, status);
1236108401Sambrisko		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_TX_EXC);
123755992Swpaul	}
123855992Swpaul
123955992Swpaul	if (status & AN_EV_ALLOC)
1240108401Sambrisko		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_ALLOC);
124155992Swpaul
124255992Swpaul	/* Re-enable interrupts. */
1243119156Sambrisko	CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), AN_INTRS(sc->mpi350));
124455992Swpaul
1245132986Smlaier	if ((ifp->if_flags & IFF_UP) && !IFQ_DRV_IS_EMPTY(&ifp->if_snd))
124655992Swpaul		an_start(ifp);
124755992Swpaul
124867094Swpaul	AN_UNLOCK(sc);
124967094Swpaul
125055992Swpaul	return;
125155992Swpaul}
125255992Swpaul
1253108401Sambrisko
125483270Sbrooksstatic int
1255150446Simpan_cmd_struct(struct an_softc *sc, struct an_command *cmd,
1256150446Simp    struct an_reply *reply)
1257108401Sambrisko{
1258108401Sambrisko	int			i;
1259108401Sambrisko
1260108401Sambrisko	for (i = 0; i != AN_TIMEOUT; i++) {
1261108401Sambrisko		if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY) {
1262110531Sambrisko			DELAY(1000);
1263110104Sambrisko		} else
1264108401Sambrisko			break;
1265108401Sambrisko	}
1266119156Sambrisko
1267108401Sambrisko	if( i == AN_TIMEOUT) {
1268108401Sambrisko		printf("BUSY\n");
1269108401Sambrisko		return(ETIMEDOUT);
1270108401Sambrisko	}
1271108401Sambrisko
1272108401Sambrisko	CSR_WRITE_2(sc, AN_PARAM0(sc->mpi350), cmd->an_parm0);
1273108401Sambrisko	CSR_WRITE_2(sc, AN_PARAM1(sc->mpi350), cmd->an_parm1);
1274108401Sambrisko	CSR_WRITE_2(sc, AN_PARAM2(sc->mpi350), cmd->an_parm2);
1275108401Sambrisko	CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), cmd->an_cmd);
1276108401Sambrisko
1277108401Sambrisko	for (i = 0; i < AN_TIMEOUT; i++) {
1278108401Sambrisko		if (CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350)) & AN_EV_CMD)
1279108401Sambrisko			break;
1280110531Sambrisko		DELAY(1000);
1281108401Sambrisko	}
1282108401Sambrisko
1283108401Sambrisko	reply->an_resp0 = CSR_READ_2(sc, AN_RESP0(sc->mpi350));
1284108401Sambrisko	reply->an_resp1 = CSR_READ_2(sc, AN_RESP1(sc->mpi350));
1285108401Sambrisko	reply->an_resp2 = CSR_READ_2(sc, AN_RESP2(sc->mpi350));
1286108401Sambrisko	reply->an_status = CSR_READ_2(sc, AN_STATUS(sc->mpi350));
1287108401Sambrisko
1288108401Sambrisko	if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY)
1289119156Sambrisko		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350),
1290119156Sambrisko		    AN_EV_CLR_STUCK_BUSY);
1291108401Sambrisko
1292108401Sambrisko	/* Ack the command */
1293108401Sambrisko	CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_CMD);
1294108401Sambrisko
1295108401Sambrisko	if (i == AN_TIMEOUT)
1296108401Sambrisko		return(ETIMEDOUT);
1297108401Sambrisko
1298108401Sambrisko	return(0);
1299108401Sambrisko}
1300108401Sambrisko
1301108401Sambriskostatic int
1302150446Simpan_cmd(struct an_softc *sc, int cmd, int val)
130355992Swpaul{
130455992Swpaul	int			i, s = 0;
130555992Swpaul
1306108401Sambrisko	CSR_WRITE_2(sc, AN_PARAM0(sc->mpi350), val);
1307108401Sambrisko	CSR_WRITE_2(sc, AN_PARAM1(sc->mpi350), 0);
1308108401Sambrisko	CSR_WRITE_2(sc, AN_PARAM2(sc->mpi350), 0);
1309108401Sambrisko	CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), cmd);
131055992Swpaul
131155992Swpaul	for (i = 0; i < AN_TIMEOUT; i++) {
1312108401Sambrisko		if (CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350)) & AN_EV_CMD)
131355992Swpaul			break;
131455992Swpaul		else {
1315108401Sambrisko			if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) == cmd)
1316108401Sambrisko				CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), cmd);
131755992Swpaul		}
131855992Swpaul	}
131955992Swpaul
132055992Swpaul	for (i = 0; i < AN_TIMEOUT; i++) {
1321108401Sambrisko		CSR_READ_2(sc, AN_RESP0(sc->mpi350));
1322108401Sambrisko		CSR_READ_2(sc, AN_RESP1(sc->mpi350));
1323108401Sambrisko		CSR_READ_2(sc, AN_RESP2(sc->mpi350));
1324108401Sambrisko		s = CSR_READ_2(sc, AN_STATUS(sc->mpi350));
132555992Swpaul		if ((s & AN_STAT_CMD_CODE) == (cmd & AN_STAT_CMD_CODE))
132655992Swpaul			break;
132755992Swpaul	}
132855992Swpaul
132955992Swpaul	/* Ack the command */
1330108401Sambrisko	CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_CMD);
133155992Swpaul
1332108401Sambrisko	if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY)
1333108401Sambrisko		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_CLR_STUCK_BUSY);
133455992Swpaul
133555992Swpaul	if (i == AN_TIMEOUT)
133655992Swpaul		return(ETIMEDOUT);
133755992Swpaul
133855992Swpaul	return(0);
133955992Swpaul}
134055992Swpaul
134155992Swpaul/*
134255992Swpaul * This reset sequence may look a little strange, but this is the
134355992Swpaul * most reliable method I've found to really kick the NIC in the
134455992Swpaul * head and force it to reboot correctly.
134555992Swpaul */
134683270Sbrooksstatic void
1347150446Simpan_reset(struct an_softc *sc)
134855992Swpaul{
134955992Swpaul	if (sc->an_gone)
135055992Swpaul		return;
135183270Sbrooks
135255992Swpaul	an_cmd(sc, AN_CMD_ENABLE, 0);
135355992Swpaul	an_cmd(sc, AN_CMD_FW_RESTART, 0);
135455992Swpaul	an_cmd(sc, AN_CMD_NOOP2, 0);
135555992Swpaul
135655992Swpaul	if (an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0) == ETIMEDOUT)
135755992Swpaul		printf("an%d: reset failed\n", sc->an_unit);
135855992Swpaul
135955992Swpaul	an_cmd(sc, AN_CMD_DISABLE, 0);
136055992Swpaul
136155992Swpaul	return;
136255992Swpaul}
136355992Swpaul
136455992Swpaul/*
136555992Swpaul * Read an LTV record from the NIC.
136655992Swpaul */
136783270Sbrooksstatic int
1368150446Simpan_read_record(struct an_softc *sc, struct an_ltv_gen *ltv)
136955992Swpaul{
1370108401Sambrisko	struct an_ltv_gen	*an_ltv;
1371108401Sambrisko	struct an_card_rid_desc an_rid_desc;
1372108401Sambrisko	struct an_command	cmd;
1373108401Sambrisko	struct an_reply		reply;
137455992Swpaul	u_int16_t		*ptr;
137578639Sbrooks	u_int8_t		*ptr2;
137655992Swpaul	int			i, len;
137755992Swpaul
137878639Sbrooks	if (ltv->an_len < 4 || ltv->an_type == 0)
137955992Swpaul		return(EINVAL);
138055992Swpaul
1381108401Sambrisko	if (!sc->mpi350){
1382108401Sambrisko		/* Tell the NIC to enter record read mode. */
1383108401Sambrisko		if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type)) {
1384108401Sambrisko			printf("an%d: RID access failed\n", sc->an_unit);
1385108401Sambrisko			return(EIO);
1386108401Sambrisko		}
138755992Swpaul
1388108401Sambrisko		/* Seek to the record. */
1389108401Sambrisko		if (an_seek(sc, ltv->an_type, 0, AN_BAP1)) {
1390108401Sambrisko			printf("an%d: seek to record failed\n", sc->an_unit);
1391108401Sambrisko			return(EIO);
1392108401Sambrisko		}
139355992Swpaul
1394108401Sambrisko		/*
1395108401Sambrisko		 * Read the length and record type and make sure they
1396108401Sambrisko		 * match what we expect (this verifies that we have enough
1397108401Sambrisko		 * room to hold all of the returned data).
1398108401Sambrisko		 * Length includes type but not length.
1399108401Sambrisko		 */
1400108401Sambrisko		len = CSR_READ_2(sc, AN_DATA1);
1401108401Sambrisko		if (len > (ltv->an_len - 2)) {
1402108401Sambrisko			printf("an%d: record length mismatch -- expected %d, "
1403108401Sambrisko			       "got %d for Rid %x\n", sc->an_unit,
1404108401Sambrisko			       ltv->an_len - 2, len, ltv->an_type);
1405108401Sambrisko			len = ltv->an_len - 2;
1406108401Sambrisko		} else {
1407108401Sambrisko			ltv->an_len = len + 2;
1408108401Sambrisko		}
1409108401Sambrisko
1410108401Sambrisko		/* Now read the data. */
1411108401Sambrisko		len -= 2;	/* skip the type */
1412108401Sambrisko		ptr = &ltv->an_val;
1413108401Sambrisko		for (i = len; i > 1; i -= 2)
1414108401Sambrisko			*ptr++ = CSR_READ_2(sc, AN_DATA1);
1415108401Sambrisko		if (i) {
1416108401Sambrisko			ptr2 = (u_int8_t *)ptr;
1417108401Sambrisko			*ptr2 = CSR_READ_1(sc, AN_DATA1);
1418108401Sambrisko		}
1419108401Sambrisko	} else { /* MPI-350 */
1420123978Sambrisko		if (!sc->an_rid_buffer.an_dma_vaddr)
1421123978Sambrisko			return(EIO);
1422108401Sambrisko		an_rid_desc.an_valid = 1;
1423108401Sambrisko		an_rid_desc.an_len = AN_RID_BUFFER_SIZE;
1424108401Sambrisko		an_rid_desc.an_rid = 0;
1425108401Sambrisko		an_rid_desc.an_phys = sc->an_rid_buffer.an_dma_paddr;
1426108401Sambrisko		bzero(sc->an_rid_buffer.an_dma_vaddr, AN_RID_BUFFER_SIZE);
1427108401Sambrisko
1428108401Sambrisko		bzero(&cmd, sizeof(cmd));
1429108401Sambrisko		bzero(&reply, sizeof(reply));
1430108401Sambrisko		cmd.an_cmd = AN_CMD_ACCESS|AN_ACCESS_READ;
1431108401Sambrisko		cmd.an_parm0 = ltv->an_type;
1432108401Sambrisko
1433108401Sambrisko		for (i = 0; i < sizeof(an_rid_desc) / 4; i++)
1434108401Sambrisko			CSR_MEM_AUX_WRITE_4(sc, AN_HOST_DESC_OFFSET + i * 4,
1435155321Simp			    ((u_int32_t *)(void *)&an_rid_desc)[i]);
1436108401Sambrisko
1437108401Sambrisko		if (an_cmd_struct(sc, &cmd, &reply)
1438108401Sambrisko		    || reply.an_status & AN_CMD_QUAL_MASK) {
1439108401Sambrisko			printf("an%d: failed to read RID %x %x %x %x %x, %d\n",
1440108401Sambrisko			       sc->an_unit, ltv->an_type,
1441108401Sambrisko			       reply.an_status,
1442108401Sambrisko			       reply.an_resp0,
1443108401Sambrisko			       reply.an_resp1,
1444108401Sambrisko			       reply.an_resp2,
1445108401Sambrisko			       i);
1446108401Sambrisko			return(EIO);
1447108401Sambrisko		}
1448108401Sambrisko
1449108401Sambrisko		an_ltv = (struct an_ltv_gen *)sc->an_rid_buffer.an_dma_vaddr;
1450108401Sambrisko		if (an_ltv->an_len + 2 < an_rid_desc.an_len) {
1451108401Sambrisko			an_rid_desc.an_len = an_ltv->an_len;
1452108401Sambrisko		}
1453108401Sambrisko
1454123978Sambrisko		len = an_rid_desc.an_len;
1455123978Sambrisko		if (len > (ltv->an_len - 2)) {
1456123978Sambrisko			printf("an%d: record length mismatch -- expected %d, "
1457123978Sambrisko			       "got %d for Rid %x\n", sc->an_unit,
1458123978Sambrisko			       ltv->an_len - 2, len, ltv->an_type);
1459123978Sambrisko			len = ltv->an_len - 2;
1460123978Sambrisko		} else {
1461123978Sambrisko			ltv->an_len = len + 2;
1462123978Sambrisko		}
1463123978Sambrisko		bcopy(&an_ltv->an_type,
1464123978Sambrisko		    &ltv->an_val,
1465123978Sambrisko		    len);
146655992Swpaul	}
146755992Swpaul
146878639Sbrooks	if (an_dump)
146978639Sbrooks		an_dump_record(sc, ltv, "Read");
147055992Swpaul
147155992Swpaul	return(0);
147255992Swpaul}
147355992Swpaul
147455992Swpaul/*
147555992Swpaul * Same as read, except we inject data instead of reading it.
147655992Swpaul */
147783270Sbrooksstatic int
1478150446Simpan_write_record(struct an_softc *sc, struct an_ltv_gen *ltv)
147955992Swpaul{
1480108401Sambrisko	struct an_card_rid_desc an_rid_desc;
1481108401Sambrisko	struct an_command	cmd;
1482108401Sambrisko	struct an_reply		reply;
148355992Swpaul	u_int16_t		*ptr;
148478639Sbrooks	u_int8_t		*ptr2;
148578639Sbrooks	int			i, len;
148655992Swpaul
148778639Sbrooks	if (an_dump)
148878639Sbrooks		an_dump_record(sc, ltv, "Write");
148978639Sbrooks
1490108401Sambrisko	if (!sc->mpi350){
1491108401Sambrisko		if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type))
1492108401Sambrisko			return(EIO);
149383270Sbrooks
1494108401Sambrisko		if (an_seek(sc, ltv->an_type, 0, AN_BAP1))
1495108401Sambrisko			return(EIO);
1496108401Sambrisko
1497108401Sambrisko		/*
1498108401Sambrisko		 * Length includes type but not length.
1499108401Sambrisko		 */
1500108401Sambrisko		len = ltv->an_len - 2;
1501108401Sambrisko		CSR_WRITE_2(sc, AN_DATA1, len);
1502108401Sambrisko
1503108401Sambrisko		len -= 2;	/* skip the type */
1504108401Sambrisko		ptr = &ltv->an_val;
1505108401Sambrisko		for (i = len; i > 1; i -= 2)
1506108401Sambrisko			CSR_WRITE_2(sc, AN_DATA1, *ptr++);
1507108401Sambrisko		if (i) {
1508108401Sambrisko			ptr2 = (u_int8_t *)ptr;
1509108401Sambrisko			CSR_WRITE_1(sc, AN_DATA0, *ptr2);
1510108401Sambrisko		}
1511108401Sambrisko
1512108401Sambrisko		if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_WRITE, ltv->an_type))
1513108401Sambrisko			return(EIO);
1514110104Sambrisko	} else {
1515110104Sambrisko		/* MPI-350 */
1516108401Sambrisko
1517108401Sambrisko		for (i = 0; i != AN_TIMEOUT; i++) {
1518110104Sambrisko			if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350))
1519110104Sambrisko			    & AN_CMD_BUSY) {
1520108401Sambrisko				DELAY(10);
1521110104Sambrisko			} else
1522108401Sambrisko				break;
1523108401Sambrisko		}
1524108401Sambrisko		if (i == AN_TIMEOUT) {
1525108401Sambrisko			printf("BUSY\n");
1526108401Sambrisko		}
1527108401Sambrisko
1528108401Sambrisko		an_rid_desc.an_valid = 1;
1529108401Sambrisko		an_rid_desc.an_len = ltv->an_len - 2;
1530108401Sambrisko		an_rid_desc.an_rid = ltv->an_type;
1531108401Sambrisko		an_rid_desc.an_phys = sc->an_rid_buffer.an_dma_paddr;
1532108401Sambrisko
1533108401Sambrisko		bcopy(&ltv->an_type, sc->an_rid_buffer.an_dma_vaddr,
1534108401Sambrisko		      an_rid_desc.an_len);
1535108401Sambrisko
1536108401Sambrisko		bzero(&cmd,sizeof(cmd));
1537108401Sambrisko		bzero(&reply,sizeof(reply));
1538108401Sambrisko		cmd.an_cmd = AN_CMD_ACCESS|AN_ACCESS_WRITE;
1539108401Sambrisko		cmd.an_parm0 = ltv->an_type;
1540108401Sambrisko
1541108401Sambrisko		for (i = 0; i < sizeof(an_rid_desc) / 4; i++)
1542108401Sambrisko			CSR_MEM_AUX_WRITE_4(sc, AN_HOST_DESC_OFFSET + i * 4,
1543155321Simp			    ((u_int32_t *)(void *)&an_rid_desc)[i]);
1544108401Sambrisko
1545110531Sambrisko		DELAY(100000);
1546110531Sambrisko
1547108401Sambrisko		if ((i = an_cmd_struct(sc, &cmd, &reply))) {
1548110531Sambrisko			printf("an%d: failed to write RID 1 %x %x %x %x %x, %d\n",
1549110104Sambrisko			    sc->an_unit, ltv->an_type,
1550110104Sambrisko			    reply.an_status,
1551110104Sambrisko			    reply.an_resp0,
1552110104Sambrisko			    reply.an_resp1,
1553110104Sambrisko			    reply.an_resp2,
1554110104Sambrisko			    i);
1555110104Sambrisko			return(EIO);
1556108401Sambrisko		}
155755992Swpaul
155883270Sbrooks
1559108401Sambrisko		if (reply.an_status & AN_CMD_QUAL_MASK) {
1560110531Sambrisko			printf("an%d: failed to write RID 2 %x %x %x %x %x, %d\n",
1561110104Sambrisko			    sc->an_unit, ltv->an_type,
1562110104Sambrisko			    reply.an_status,
1563110104Sambrisko			    reply.an_resp0,
1564110104Sambrisko			    reply.an_resp1,
1565110104Sambrisko			    reply.an_resp2,
1566110104Sambrisko			    i);
1567108401Sambrisko			return(EIO);
1568108401Sambrisko		}
1569110531Sambrisko		DELAY(100000);
157078639Sbrooks	}
157155992Swpaul
157255992Swpaul	return(0);
157355992Swpaul}
157455992Swpaul
157583270Sbrooksstatic void
1576150446Simpan_dump_record(struct an_softc *sc, struct an_ltv_gen *ltv, char *string)
157778639Sbrooks{
157878639Sbrooks	u_int8_t		*ptr2;
157978639Sbrooks	int			len;
158078639Sbrooks	int			i;
158178639Sbrooks	int			count = 0;
158278639Sbrooks	char			buf[17], temp;
158378639Sbrooks
158478639Sbrooks	len = ltv->an_len - 4;
158583270Sbrooks	printf("an%d: RID %4x, Length %4d, Mode %s\n",
158678639Sbrooks		sc->an_unit, ltv->an_type, ltv->an_len - 4, string);
158778639Sbrooks
158878639Sbrooks	if (an_dump == 1 || (an_dump == ltv->an_type)) {
158978639Sbrooks		printf("an%d:\t", sc->an_unit);
159078639Sbrooks		bzero(buf,sizeof(buf));
159178639Sbrooks
159278639Sbrooks		ptr2 = (u_int8_t *)&ltv->an_val;
159378639Sbrooks		for (i = len; i > 0; i--) {
159478639Sbrooks			printf("%02x ", *ptr2);
159578639Sbrooks
159678639Sbrooks			temp = *ptr2++;
1597154866Snjl			if (isprint(temp))
159878639Sbrooks				buf[count] = temp;
159978639Sbrooks			else
160078639Sbrooks				buf[count] = '.';
160178639Sbrooks			if (++count == 16) {
160278639Sbrooks				count = 0;
160378639Sbrooks				printf("%s\n",buf);
160478639Sbrooks				printf("an%d:\t", sc->an_unit);
160578639Sbrooks				bzero(buf,sizeof(buf));
160678639Sbrooks			}
160778639Sbrooks		}
160878639Sbrooks		for (; count != 16; count++) {
160978639Sbrooks			printf("   ");
161078639Sbrooks		}
161178639Sbrooks		printf(" %s\n",buf);
161278639Sbrooks	}
161378639Sbrooks}
161478639Sbrooks
161583270Sbrooksstatic int
1616150446Simpan_seek(struct an_softc *sc, int id, int off, int chan)
161755992Swpaul{
161855992Swpaul	int			i;
161955992Swpaul	int			selreg, offreg;
162055992Swpaul
162155992Swpaul	switch (chan) {
162255992Swpaul	case AN_BAP0:
162355992Swpaul		selreg = AN_SEL0;
162455992Swpaul		offreg = AN_OFF0;
162555992Swpaul		break;
162655992Swpaul	case AN_BAP1:
162755992Swpaul		selreg = AN_SEL1;
162855992Swpaul		offreg = AN_OFF1;
162955992Swpaul		break;
163055992Swpaul	default:
163155992Swpaul		printf("an%d: invalid data path: %x\n", sc->an_unit, chan);
163255992Swpaul		return(EIO);
163355992Swpaul	}
163455992Swpaul
163555992Swpaul	CSR_WRITE_2(sc, selreg, id);
163655992Swpaul	CSR_WRITE_2(sc, offreg, off);
163755992Swpaul
163855992Swpaul	for (i = 0; i < AN_TIMEOUT; i++) {
163955992Swpaul		if (!(CSR_READ_2(sc, offreg) & (AN_OFF_BUSY|AN_OFF_ERR)))
164055992Swpaul			break;
164155992Swpaul	}
164255992Swpaul
164355992Swpaul	if (i == AN_TIMEOUT)
164455992Swpaul		return(ETIMEDOUT);
164555992Swpaul
164655992Swpaul	return(0);
164755992Swpaul}
164855992Swpaul
164983270Sbrooksstatic int
1650150446Simpan_read_data(struct an_softc *sc, int id, int off, caddr_t buf, int len)
165155992Swpaul{
165255992Swpaul	int			i;
165355992Swpaul	u_int16_t		*ptr;
165455992Swpaul	u_int8_t		*ptr2;
165555992Swpaul
165655992Swpaul	if (off != -1) {
165755992Swpaul		if (an_seek(sc, id, off, AN_BAP1))
165855992Swpaul			return(EIO);
165955992Swpaul	}
166055992Swpaul
166155992Swpaul	ptr = (u_int16_t *)buf;
166278639Sbrooks	for (i = len; i > 1; i -= 2)
166378639Sbrooks		*ptr++ = CSR_READ_2(sc, AN_DATA1);
166478639Sbrooks	if (i) {
166578639Sbrooks		ptr2 = (u_int8_t *)ptr;
166678639Sbrooks		*ptr2 = CSR_READ_1(sc, AN_DATA1);
166755992Swpaul	}
166855992Swpaul
166955992Swpaul	return(0);
167055992Swpaul}
167155992Swpaul
167283270Sbrooksstatic int
1673150446Simpan_write_data(struct an_softc *sc, int id, int off, caddr_t buf, int len)
167455992Swpaul{
167555992Swpaul	int			i;
167655992Swpaul	u_int16_t		*ptr;
167755992Swpaul	u_int8_t		*ptr2;
167855992Swpaul
167955992Swpaul	if (off != -1) {
168055992Swpaul		if (an_seek(sc, id, off, AN_BAP0))
168155992Swpaul			return(EIO);
168255992Swpaul	}
168355992Swpaul
168455992Swpaul	ptr = (u_int16_t *)buf;
168578639Sbrooks	for (i = len; i > 1; i -= 2)
168678639Sbrooks		CSR_WRITE_2(sc, AN_DATA0, *ptr++);
168778639Sbrooks	if (i) {
168878639Sbrooks	        ptr2 = (u_int8_t *)ptr;
168978639Sbrooks	        CSR_WRITE_1(sc, AN_DATA0, *ptr2);
169055992Swpaul	}
169155992Swpaul
169255992Swpaul	return(0);
169355992Swpaul}
169455992Swpaul
169555992Swpaul/*
169655992Swpaul * Allocate a region of memory inside the NIC and zero
169755992Swpaul * it out.
169855992Swpaul */
169983270Sbrooksstatic int
1700150446Simpan_alloc_nicmem(struct an_softc *sc, int len, int *id)
170155992Swpaul{
170255992Swpaul	int			i;
170355992Swpaul
170455992Swpaul	if (an_cmd(sc, AN_CMD_ALLOC_MEM, len)) {
170555992Swpaul		printf("an%d: failed to allocate %d bytes on NIC\n",
170655992Swpaul		    sc->an_unit, len);
170755992Swpaul		return(ENOMEM);
170855992Swpaul	}
170955992Swpaul
171055992Swpaul	for (i = 0; i < AN_TIMEOUT; i++) {
1711108401Sambrisko		if (CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350)) & AN_EV_ALLOC)
171255992Swpaul			break;
171355992Swpaul	}
171455992Swpaul
171555992Swpaul	if (i == AN_TIMEOUT)
171655992Swpaul		return(ETIMEDOUT);
171755992Swpaul
1718108401Sambrisko	CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_ALLOC);
171955992Swpaul	*id = CSR_READ_2(sc, AN_ALLOC_FID);
172055992Swpaul
172155992Swpaul	if (an_seek(sc, *id, 0, AN_BAP0))
172255992Swpaul		return(EIO);
172355992Swpaul
172455992Swpaul	for (i = 0; i < len / 2; i++)
172555992Swpaul		CSR_WRITE_2(sc, AN_DATA0, 0);
172655992Swpaul
172755992Swpaul	return(0);
172855992Swpaul}
172955992Swpaul
173083270Sbrooksstatic void
1731150446Simpan_setdef(struct an_softc *sc, struct an_req *areq)
173255992Swpaul{
173355992Swpaul	struct ifnet		*ifp;
173455992Swpaul	struct an_ltv_genconfig	*cfg;
1735119156Sambrisko	struct an_ltv_ssidlist_new	*ssid;
173655992Swpaul	struct an_ltv_aplist	*ap;
173755992Swpaul	struct an_ltv_gen	*sp;
173855992Swpaul
1739147256Sbrooks	ifp = sc->an_ifp;
174055992Swpaul
174155992Swpaul	switch (areq->an_type) {
174255992Swpaul	case AN_RID_GENCONFIG:
174355992Swpaul		cfg = (struct an_ltv_genconfig *)areq;
174455992Swpaul
1745152315Sru		bcopy((char *)&cfg->an_macaddr, IF_LLADDR(sc->an_ifp),
174655992Swpaul		    ETHER_ADDR_LEN);
174755992Swpaul
174855992Swpaul		bcopy((char *)cfg, (char *)&sc->an_config,
174955992Swpaul			sizeof(struct an_ltv_genconfig));
175055992Swpaul		break;
175155992Swpaul	case AN_RID_SSIDLIST:
1752119156Sambrisko		ssid = (struct an_ltv_ssidlist_new *)areq;
175355992Swpaul		bcopy((char *)ssid, (char *)&sc->an_ssidlist,
1754119156Sambrisko			sizeof(struct an_ltv_ssidlist_new));
175555992Swpaul		break;
175655992Swpaul	case AN_RID_APLIST:
175755992Swpaul		ap = (struct an_ltv_aplist *)areq;
175855992Swpaul		bcopy((char *)ap, (char *)&sc->an_aplist,
175955992Swpaul			sizeof(struct an_ltv_aplist));
176055992Swpaul		break;
176155992Swpaul	case AN_RID_TX_SPEED:
176255992Swpaul		sp = (struct an_ltv_gen *)areq;
176355992Swpaul		sc->an_tx_rate = sp->an_val;
1764110253Sambrisko
1765110253Sambrisko		/* Read the current configuration */
1766110253Sambrisko		sc->an_config.an_type = AN_RID_GENCONFIG;
1767110253Sambrisko		sc->an_config.an_len = sizeof(struct an_ltv_genconfig);
1768110253Sambrisko		an_read_record(sc, (struct an_ltv_gen *)&sc->an_config);
1769110253Sambrisko		cfg = &sc->an_config;
1770110253Sambrisko
1771110253Sambrisko		/* clear other rates and set the only one we want */
1772110253Sambrisko		bzero(cfg->an_rates, sizeof(cfg->an_rates));
1773110253Sambrisko		cfg->an_rates[0] = sc->an_tx_rate;
1774110253Sambrisko
1775110253Sambrisko		/* Save the new rate */
1776110253Sambrisko		sc->an_config.an_type = AN_RID_GENCONFIG;
1777110253Sambrisko		sc->an_config.an_len = sizeof(struct an_ltv_genconfig);
177855992Swpaul		break;
177968692Swpaul	case AN_RID_WEP_TEMP:
1780110531Sambrisko		/* Cache the temp keys */
1781110531Sambrisko		bcopy(areq,
1782110531Sambrisko		    &sc->an_temp_keys[((struct an_ltv_key *)areq)->kindex],
1783110531Sambrisko		    sizeof(struct an_ltv_key));
178468692Swpaul	case AN_RID_WEP_PERM:
178588748Sambrisko	case AN_RID_LEAPUSERNAME:
178688748Sambrisko	case AN_RID_LEAPPASSWORD:
1787119156Sambrisko		an_init(sc);
1788119156Sambrisko
178968692Swpaul		/* Disable the MAC. */
179068692Swpaul		an_cmd(sc, AN_CMD_DISABLE, 0);
179183270Sbrooks
179283269Sbrooks		/* Write the key */
179368692Swpaul		an_write_record(sc, (struct an_ltv_gen *)areq);
179483270Sbrooks
179583270Sbrooks		/* Turn the MAC back on. */
179668692Swpaul		an_cmd(sc, AN_CMD_ENABLE, 0);
179783270Sbrooks
179868692Swpaul		break;
179983269Sbrooks	case AN_RID_MONITOR_MODE:
180083269Sbrooks		cfg = (struct an_ltv_genconfig *)areq;
180183269Sbrooks		bpfdetach(ifp);
180283269Sbrooks		if (ng_ether_detach_p != NULL)
180383269Sbrooks			(*ng_ether_detach_p) (ifp);
180483269Sbrooks		sc->an_monitor = cfg->an_len;
180583269Sbrooks
180683270Sbrooks		if (sc->an_monitor & AN_MONITOR) {
180783270Sbrooks			if (sc->an_monitor & AN_MONITOR_AIRONET_HEADER) {
180883270Sbrooks				bpfattach(ifp, DLT_AIRONET_HEADER,
180983269Sbrooks					sizeof(struct ether_header));
181083269Sbrooks			} else {
181183270Sbrooks				bpfattach(ifp, DLT_IEEE802_11,
181283269Sbrooks					sizeof(struct ether_header));
181383269Sbrooks			}
181483269Sbrooks		} else {
181583270Sbrooks			bpfattach(ifp, DLT_EN10MB,
181683269Sbrooks				  sizeof(struct ether_header));
181783269Sbrooks			if (ng_ether_attach_p != NULL)
181883269Sbrooks				(*ng_ether_attach_p) (ifp);
181983269Sbrooks		}
182083269Sbrooks		break;
182155992Swpaul	default:
182255992Swpaul		printf("an%d: unknown RID: %x\n", sc->an_unit, areq->an_type);
182355992Swpaul		return;
182455992Swpaul	}
182555992Swpaul
182655992Swpaul
182755992Swpaul	/* Reinitialize the card. */
182874698Sarchie	if (ifp->if_flags)
182955992Swpaul		an_init(sc);
183055992Swpaul
183155992Swpaul	return;
183255992Swpaul}
183355992Swpaul
183455992Swpaul/*
183583269Sbrooks * Derived from Linux driver to enable promiscious mode.
183655992Swpaul */
183783269Sbrooks
183883270Sbrooksstatic void
1839150446Simpan_promisc(struct an_softc *sc, int promisc)
184055992Swpaul{
1841150446Simp	if (sc->an_was_monitor) {
184283269Sbrooks		an_reset(sc);
1843108401Sambrisko		if (sc->mpi350)
1844108401Sambrisko			an_init_mpi350_desc(sc);
1845150446Simp	}
184683270Sbrooks	if (sc->an_monitor || sc->an_was_monitor)
184783269Sbrooks		an_init(sc);
184883269Sbrooks
184983269Sbrooks	sc->an_was_monitor = sc->an_monitor;
185074698Sarchie	an_cmd(sc, AN_CMD_SET_MODE, promisc ? 0xffff : 0);
185183270Sbrooks
185255992Swpaul	return;
185355992Swpaul}
185455992Swpaul
185583270Sbrooksstatic int
1856150446Simpan_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
185755992Swpaul{
185867094Swpaul	int			error = 0;
185977217Sphk	int			len;
1860119156Sambrisko	int			i, max;
186155992Swpaul	struct an_softc		*sc;
186255992Swpaul	struct ifreq		*ifr;
186393593Sjhb	struct thread		*td = curthread;
186477217Sphk	struct ieee80211req	*ireq;
186577217Sphk	u_int8_t		tmpstr[IEEE80211_NWID_LEN*2];
186677217Sphk	u_int8_t		*tmpptr;
186777217Sphk	struct an_ltv_genconfig	*config;
186877217Sphk	struct an_ltv_key	*key;
186977217Sphk	struct an_ltv_status	*status;
1870119156Sambrisko	struct an_ltv_ssidlist_new	*ssids;
187188748Sambrisko	int			mode;
187288748Sambrisko	struct aironet_ioctl	l_ioctl;
187355992Swpaul
187455992Swpaul	sc = ifp->if_softc;
187567094Swpaul	AN_LOCK(sc);
187655992Swpaul	ifr = (struct ifreq *)data;
187777217Sphk	ireq = (struct ieee80211req *)data;
187855992Swpaul
187988749Sambrisko	config = (struct an_ltv_genconfig *)&sc->areq;
188088749Sambrisko	key = (struct an_ltv_key *)&sc->areq;
188188749Sambrisko	status = (struct an_ltv_status *)&sc->areq;
1882119156Sambrisko	ssids = (struct an_ltv_ssidlist_new *)&sc->areq;
188377217Sphk
188464429Speter	if (sc->an_gone) {
188561816Sroberto		error = ENODEV;
188661816Sroberto		goto out;
188761816Sroberto	}
188855992Swpaul
188983270Sbrooks	switch (command) {
189055992Swpaul	case SIOCSIFFLAGS:
189155992Swpaul		if (ifp->if_flags & IFF_UP) {
1892148887Srwatson			if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
189355992Swpaul			    ifp->if_flags & IFF_PROMISC &&
189455992Swpaul			    !(sc->an_if_flags & IFF_PROMISC)) {
189555992Swpaul				an_promisc(sc, 1);
1896148887Srwatson			} else if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
189755992Swpaul			    !(ifp->if_flags & IFF_PROMISC) &&
189855992Swpaul			    sc->an_if_flags & IFF_PROMISC) {
189955992Swpaul				an_promisc(sc, 0);
190055992Swpaul			} else
190155992Swpaul				an_init(sc);
190255992Swpaul		} else {
1903148887Srwatson			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
190455992Swpaul				an_stop(sc);
190555992Swpaul		}
190655992Swpaul		sc->an_if_flags = ifp->if_flags;
190755992Swpaul		error = 0;
190855992Swpaul		break;
190977217Sphk	case SIOCSIFMEDIA:
191077217Sphk	case SIOCGIFMEDIA:
191177217Sphk		error = ifmedia_ioctl(ifp, ifr, &sc->an_ifmedia, command);
191277217Sphk		break;
191355992Swpaul	case SIOCADDMULTI:
191455992Swpaul	case SIOCDELMULTI:
191555992Swpaul		/* The Aironet has no multicast filter. */
191655992Swpaul		error = 0;
191755992Swpaul		break;
191855992Swpaul	case SIOCGAIRONET:
1919171692Savatar		AN_UNLOCK(sc);
192088749Sambrisko		error = copyin(ifr->ifr_data, &sc->areq, sizeof(sc->areq));
1921171692Savatar		AN_LOCK(sc);
192278639Sbrooks		if (error != 0)
192355992Swpaul			break;
192455992Swpaul#ifdef ANCACHE
192588749Sambrisko		if (sc->areq.an_type == AN_RID_ZERO_CACHE) {
1926164033Srwatson			error = priv_check(td, PRIV_DRIVER);
1927108259Srwatson			if (error)
1928108259Srwatson				break;
192955992Swpaul			sc->an_sigitems = sc->an_nextitem = 0;
193055992Swpaul			break;
193188749Sambrisko		} else if (sc->areq.an_type == AN_RID_READ_CACHE) {
193288749Sambrisko			char *pt = (char *)&sc->areq.an_val;
193355992Swpaul			bcopy((char *)&sc->an_sigitems, (char *)pt,
193455992Swpaul			    sizeof(int));
193555992Swpaul			pt += sizeof(int);
193688749Sambrisko			sc->areq.an_len = sizeof(int) / 2;
193755992Swpaul			bcopy((char *)&sc->an_sigcache, (char *)pt,
193855992Swpaul			    sizeof(struct an_sigcache) * sc->an_sigitems);
193988749Sambrisko			sc->areq.an_len += ((sizeof(struct an_sigcache) *
194055992Swpaul			    sc->an_sigitems) / 2) + 1;
194155992Swpaul		} else
194255992Swpaul#endif
194388749Sambrisko		if (an_read_record(sc, (struct an_ltv_gen *)&sc->areq)) {
194455992Swpaul			error = EINVAL;
194555992Swpaul			break;
194655992Swpaul		}
1947171692Savatar		AN_UNLOCK(sc);
194888749Sambrisko		error = copyout(&sc->areq, ifr->ifr_data, sizeof(sc->areq));
1949171692Savatar		AN_LOCK(sc);
195055992Swpaul		break;
195155992Swpaul	case SIOCSAIRONET:
1952164033Srwatson		if ((error = priv_check(td, PRIV_DRIVER)))
195364429Speter			goto out;
1954171692Savatar		AN_UNLOCK(sc);
195588749Sambrisko		error = copyin(ifr->ifr_data, &sc->areq, sizeof(sc->areq));
1956171692Savatar		AN_LOCK(sc);
195778639Sbrooks		if (error != 0)
195855992Swpaul			break;
195988749Sambrisko		an_setdef(sc, &sc->areq);
196055992Swpaul		break;
196188748Sambrisko	case SIOCGPRIVATE_0:              /* used by Cisco client utility */
1962164033Srwatson		if ((error = priv_check(td, PRIV_DRIVER)))
196392292Sambrisko			goto out;
1964171692Savatar		AN_UNLOCK(sc);
1965144242Ssam		error = copyin(ifr->ifr_data, &l_ioctl, sizeof(l_ioctl));
1966171692Savatar		AN_LOCK(sc);
1967144242Ssam		if (error)
1968144242Ssam			goto out;
196988748Sambrisko		mode = l_ioctl.command;
197088748Sambrisko
197188748Sambrisko		if (mode >= AIROGCAP && mode <= AIROGSTATSD32) {
197288748Sambrisko			error = readrids(ifp, &l_ioctl);
1973110104Sambrisko		} else if (mode >= AIROPCAP && mode <= AIROPLEAPUSR) {
197488748Sambrisko			error = writerids(ifp, &l_ioctl);
1975110104Sambrisko		} else if (mode >= AIROFLSHRST && mode <= AIRORESTART) {
197688748Sambrisko			error = flashcard(ifp, &l_ioctl);
1977110104Sambrisko		} else {
197888748Sambrisko			error =-1;
197988748Sambrisko		}
1980144242Ssam		if (!error) {
1981144242Ssam			/* copy out the updated command info */
1982171692Savatar			AN_UNLOCK(sc);
1983144242Ssam			error = copyout(&l_ioctl, ifr->ifr_data, sizeof(l_ioctl));
1984171692Savatar			AN_LOCK(sc);
1985144242Ssam		}
198688748Sambrisko		break;
198788748Sambrisko	case SIOCGPRIVATE_1:              /* used by Cisco client utility */
1988164033Srwatson		if ((error = priv_check(td, PRIV_DRIVER)))
198992292Sambrisko			goto out;
1990171692Savatar		AN_UNLOCK(sc);
1991144242Ssam		error = copyin(ifr->ifr_data, &l_ioctl, sizeof(l_ioctl));
1992171692Savatar		AN_LOCK(sc);
1993144242Ssam		if (error)
1994144242Ssam			goto out;
199588748Sambrisko		l_ioctl.command = 0;
199688748Sambrisko		error = AIROMAGIC;
1997171692Savatar		AN_UNLOCK(sc);
1998144242Ssam		(void) copyout(&error, l_ioctl.data, sizeof(error));
1999171692Savatar		AN_LOCK(sc);
200088748Sambrisko	        error = 0;
200188748Sambrisko		break;
200277217Sphk	case SIOCG80211:
200388749Sambrisko		sc->areq.an_len = sizeof(sc->areq);
200488748Sambrisko		/* was that a good idea DJA we are doing a short-cut */
200583270Sbrooks		switch (ireq->i_type) {
200677217Sphk		case IEEE80211_IOC_SSID:
200778639Sbrooks			if (ireq->i_val == -1) {
200888749Sambrisko				sc->areq.an_type = AN_RID_STATUS;
200977217Sphk				if (an_read_record(sc,
201088749Sambrisko				    (struct an_ltv_gen *)&sc->areq)) {
201177217Sphk					error = EINVAL;
201277217Sphk					break;
201377217Sphk				}
201477217Sphk				len = status->an_ssidlen;
201577217Sphk				tmpptr = status->an_ssid;
201678639Sbrooks			} else if (ireq->i_val >= 0) {
201788749Sambrisko				sc->areq.an_type = AN_RID_SSIDLIST;
201877217Sphk				if (an_read_record(sc,
201988749Sambrisko				    (struct an_ltv_gen *)&sc->areq)) {
202077217Sphk					error = EINVAL;
202177217Sphk					break;
202277217Sphk				}
2023119156Sambrisko				max = (sc->areq.an_len - 4)
2024119156Sambrisko				    / sizeof(struct an_ltv_ssid_entry);
2025119156Sambrisko				if ( max > MAX_SSIDS ) {
2026119156Sambrisko					printf("To many SSIDs only using "
2027119156Sambrisko					    "%d of %d\n",
2028119156Sambrisko					    MAX_SSIDS, max);
2029119156Sambrisko					max = MAX_SSIDS;
2030119156Sambrisko				}
2031119156Sambrisko				if (ireq->i_val > max) {
203277217Sphk					error = EINVAL;
203377217Sphk					break;
2034119156Sambrisko				} else {
2035119156Sambrisko					len = ssids->an_entry[ireq->i_val].an_len;
2036119156Sambrisko					tmpptr = ssids->an_entry[ireq->i_val].an_ssid;
203777217Sphk				}
203877217Sphk			} else {
203977217Sphk				error = EINVAL;
204077217Sphk				break;
204177217Sphk			}
204278639Sbrooks			if (len > IEEE80211_NWID_LEN) {
204377217Sphk				error = EINVAL;
204477217Sphk				break;
204577217Sphk			}
204677217Sphk			ireq->i_len = len;
204777217Sphk			bzero(tmpstr, IEEE80211_NWID_LEN);
204877217Sphk			bcopy(tmpptr, tmpstr, len);
2049171692Savatar			AN_UNLOCK(sc);
205077217Sphk			error = copyout(tmpstr, ireq->i_data,
205177217Sphk			    IEEE80211_NWID_LEN);
2052171692Savatar			AN_LOCK(sc);
205377217Sphk			break;
205477217Sphk		case IEEE80211_IOC_NUMSSIDS:
2055119156Sambrisko			sc->areq.an_len = sizeof(sc->areq);
2056119156Sambrisko			sc->areq.an_type = AN_RID_SSIDLIST;
2057119156Sambrisko			if (an_read_record(sc,
2058119156Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
2059119156Sambrisko				error = EINVAL;
2060119156Sambrisko				break;
2061119156Sambrisko			}
2062119156Sambrisko			max = (sc->areq.an_len - 4)
2063119156Sambrisko			    / sizeof(struct an_ltv_ssid_entry);
2064119156Sambrisko			if ( max > MAX_SSIDS ) {
2065119156Sambrisko				printf("To many SSIDs only using "
2066119156Sambrisko				    "%d of %d\n",
2067119156Sambrisko				    MAX_SSIDS, max);
2068119156Sambrisko				max = MAX_SSIDS;
2069119156Sambrisko			}
2070119156Sambrisko			ireq->i_val = max;
207177217Sphk			break;
207277217Sphk		case IEEE80211_IOC_WEP:
207388749Sambrisko			sc->areq.an_type = AN_RID_ACTUALCFG;
207477217Sphk			if (an_read_record(sc,
207588749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
207677217Sphk				error = EINVAL;
207777217Sphk				break;
207877217Sphk			}
207978639Sbrooks			if (config->an_authtype & AN_AUTHTYPE_PRIVACY_IN_USE) {
208078639Sbrooks				if (config->an_authtype &
208177217Sphk				    AN_AUTHTYPE_ALLOW_UNENCRYPTED)
208277217Sphk					ireq->i_val = IEEE80211_WEP_MIXED;
208377217Sphk				else
208477217Sphk					ireq->i_val = IEEE80211_WEP_ON;
208577217Sphk			} else {
208677217Sphk				ireq->i_val = IEEE80211_WEP_OFF;
208777217Sphk			}
208877217Sphk			break;
208977217Sphk		case IEEE80211_IOC_WEPKEY:
209077217Sphk			/*
209177217Sphk			 * XXX: I'm not entierly convinced this is
209277217Sphk			 * correct, but it's what is implemented in
209377217Sphk			 * ancontrol so it will have to do until we get
209477217Sphk			 * access to actual Cisco code.
209577217Sphk			 */
209688748Sambrisko			if (ireq->i_val < 0 || ireq->i_val > 8) {
209777217Sphk				error = EINVAL;
209877217Sphk				break;
209977217Sphk			}
210077217Sphk			len = 0;
210188748Sambrisko			if (ireq->i_val < 5) {
210288749Sambrisko				sc->areq.an_type = AN_RID_WEP_TEMP;
210378639Sbrooks				for (i = 0; i < 5; i++) {
210477217Sphk					if (an_read_record(sc,
210588749Sambrisko					    (struct an_ltv_gen *)&sc->areq)) {
210677217Sphk						error = EINVAL;
210777217Sphk						break;
210877217Sphk					}
210978639Sbrooks					if (key->kindex == 0xffff)
211077217Sphk						break;
211178639Sbrooks					if (key->kindex == ireq->i_val)
211278639Sbrooks						len = key->klen;
211377217Sphk					/* Required to get next entry */
211488749Sambrisko					sc->areq.an_type = AN_RID_WEP_PERM;
211577217Sphk				}
211678639Sbrooks				if (error != 0)
211777217Sphk					break;
211877217Sphk			}
211977217Sphk			/* We aren't allowed to read the value of the
212077217Sphk			 * key from the card so we just output zeros
212177217Sphk			 * like we would if we could read the card, but
212277217Sphk			 * denied the user access.
212377217Sphk			 */
212477217Sphk			bzero(tmpstr, len);
212577217Sphk			ireq->i_len = len;
2126171692Savatar			AN_UNLOCK(sc);
212777217Sphk			error = copyout(tmpstr, ireq->i_data, len);
2128171692Savatar			AN_LOCK(sc);
212977217Sphk			break;
213077217Sphk		case IEEE80211_IOC_NUMWEPKEYS:
213188748Sambrisko			ireq->i_val = 9; /* include home key */
213277217Sphk			break;
213377217Sphk		case IEEE80211_IOC_WEPTXKEY:
213478639Sbrooks			/*
213578639Sbrooks			 * For some strange reason, you have to read all
213678639Sbrooks			 * keys before you can read the txkey.
213778639Sbrooks			 */
213888749Sambrisko			sc->areq.an_type = AN_RID_WEP_TEMP;
213978639Sbrooks			for (i = 0; i < 5; i++) {
214078639Sbrooks				if (an_read_record(sc,
214188749Sambrisko				    (struct an_ltv_gen *) &sc->areq)) {
214278639Sbrooks					error = EINVAL;
214378639Sbrooks					break;
214478639Sbrooks				}
214578639Sbrooks				if (key->kindex == 0xffff)
214678639Sbrooks					break;
214778639Sbrooks				/* Required to get next entry */
214888749Sambrisko				sc->areq.an_type = AN_RID_WEP_PERM;
214978639Sbrooks			}
215078639Sbrooks			if (error != 0)
215178639Sbrooks				break;
215278639Sbrooks
215388749Sambrisko			sc->areq.an_type = AN_RID_WEP_PERM;
215477217Sphk			key->kindex = 0xffff;
215577217Sphk			if (an_read_record(sc,
215688749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
215777217Sphk				error = EINVAL;
215877217Sphk				break;
215977217Sphk			}
216077217Sphk			ireq->i_val = key->mac[0];
216188748Sambrisko			/*
216288748Sambrisko			 * Check for home mode.  Map home mode into
216388748Sambrisko			 * 5th key since that is how it is stored on
216488748Sambrisko			 * the card
216588748Sambrisko			 */
216688749Sambrisko			sc->areq.an_len  = sizeof(struct an_ltv_genconfig);
216788749Sambrisko			sc->areq.an_type = AN_RID_GENCONFIG;
216888748Sambrisko			if (an_read_record(sc,
216988749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
217088748Sambrisko				error = EINVAL;
217188748Sambrisko				break;
217288748Sambrisko			}
217388748Sambrisko			if (config->an_home_product & AN_HOME_NETWORK)
217488748Sambrisko				ireq->i_val = 4;
217577217Sphk			break;
217677217Sphk		case IEEE80211_IOC_AUTHMODE:
217788749Sambrisko			sc->areq.an_type = AN_RID_ACTUALCFG;
217877217Sphk			if (an_read_record(sc,
217988749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
218077217Sphk				error = EINVAL;
218177217Sphk				break;
218277217Sphk			}
218377217Sphk			if ((config->an_authtype & AN_AUTHTYPE_MASK) ==
218477217Sphk			    AN_AUTHTYPE_NONE) {
218577217Sphk			    ireq->i_val = IEEE80211_AUTH_NONE;
218677217Sphk			} else if ((config->an_authtype & AN_AUTHTYPE_MASK) ==
218777217Sphk			    AN_AUTHTYPE_OPEN) {
218877217Sphk			    ireq->i_val = IEEE80211_AUTH_OPEN;
218977217Sphk			} else if ((config->an_authtype & AN_AUTHTYPE_MASK) ==
219077217Sphk			    AN_AUTHTYPE_SHAREDKEY) {
219177217Sphk			    ireq->i_val = IEEE80211_AUTH_SHARED;
219277217Sphk			} else
219377217Sphk				error = EINVAL;
219477217Sphk			break;
219577217Sphk		case IEEE80211_IOC_STATIONNAME:
219688749Sambrisko			sc->areq.an_type = AN_RID_ACTUALCFG;
219777217Sphk			if (an_read_record(sc,
219888749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
219977217Sphk				error = EINVAL;
220077217Sphk				break;
220177217Sphk			}
220277217Sphk			ireq->i_len = sizeof(config->an_nodename);
220377217Sphk			tmpptr = config->an_nodename;
220477217Sphk			bzero(tmpstr, IEEE80211_NWID_LEN);
220577217Sphk			bcopy(tmpptr, tmpstr, ireq->i_len);
2206171692Savatar			AN_UNLOCK(sc);
220777217Sphk			error = copyout(tmpstr, ireq->i_data,
220877217Sphk			    IEEE80211_NWID_LEN);
2209171692Savatar			AN_LOCK(sc);
221077217Sphk			break;
221177217Sphk		case IEEE80211_IOC_CHANNEL:
221288749Sambrisko			sc->areq.an_type = AN_RID_STATUS;
221377217Sphk			if (an_read_record(sc,
221488749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
221577217Sphk				error = EINVAL;
221677217Sphk				break;
221777217Sphk			}
221877217Sphk			ireq->i_val = status->an_cur_channel;
221977217Sphk			break;
222077217Sphk		case IEEE80211_IOC_POWERSAVE:
222188749Sambrisko			sc->areq.an_type = AN_RID_ACTUALCFG;
222277217Sphk			if (an_read_record(sc,
222388749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
222477217Sphk				error = EINVAL;
222577217Sphk				break;
222677217Sphk			}
222778639Sbrooks			if (config->an_psave_mode == AN_PSAVE_NONE) {
222877217Sphk				ireq->i_val = IEEE80211_POWERSAVE_OFF;
222978639Sbrooks			} else if (config->an_psave_mode == AN_PSAVE_CAM) {
223077217Sphk				ireq->i_val = IEEE80211_POWERSAVE_CAM;
223178639Sbrooks			} else if (config->an_psave_mode == AN_PSAVE_PSP) {
223277217Sphk				ireq->i_val = IEEE80211_POWERSAVE_PSP;
223378639Sbrooks			} else if (config->an_psave_mode == AN_PSAVE_PSP_CAM) {
223477217Sphk				ireq->i_val = IEEE80211_POWERSAVE_PSP_CAM;
223577217Sphk			} else
223677217Sphk				error = EINVAL;
223777217Sphk			break;
223877217Sphk		case IEEE80211_IOC_POWERSAVESLEEP:
223988749Sambrisko			sc->areq.an_type = AN_RID_ACTUALCFG;
224077217Sphk			if (an_read_record(sc,
224188749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
224277217Sphk				error = EINVAL;
224377217Sphk				break;
224477217Sphk			}
224577217Sphk			ireq->i_val = config->an_listen_interval;
224677217Sphk			break;
224783270Sbrooks		}
224877217Sphk		break;
224977217Sphk	case SIOCS80211:
2250164033Srwatson		if ((error = priv_check(td, PRIV_NET80211_MANAGE)))
225177217Sphk			goto out;
225288749Sambrisko		sc->areq.an_len = sizeof(sc->areq);
225377217Sphk		/*
225477217Sphk		 * We need a config structure for everything but the WEP
225577217Sphk		 * key management and SSIDs so we get it now so avoid
225677217Sphk		 * duplicating this code every time.
225777217Sphk		 */
225877217Sphk		if (ireq->i_type != IEEE80211_IOC_SSID &&
225977217Sphk		    ireq->i_type != IEEE80211_IOC_WEPKEY &&
226077217Sphk		    ireq->i_type != IEEE80211_IOC_WEPTXKEY) {
226188749Sambrisko			sc->areq.an_type = AN_RID_GENCONFIG;
226277217Sphk			if (an_read_record(sc,
226388749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
226477217Sphk				error = EINVAL;
226577217Sphk				break;
226677217Sphk			}
226777217Sphk		}
226883270Sbrooks		switch (ireq->i_type) {
226977217Sphk		case IEEE80211_IOC_SSID:
2270119156Sambrisko			sc->areq.an_len = sizeof(sc->areq);
227188749Sambrisko			sc->areq.an_type = AN_RID_SSIDLIST;
227277217Sphk			if (an_read_record(sc,
227388749Sambrisko			    (struct an_ltv_gen *)&sc->areq)) {
227477217Sphk				error = EINVAL;
227577217Sphk				break;
227677217Sphk			}
227778639Sbrooks			if (ireq->i_len > IEEE80211_NWID_LEN) {
227877217Sphk				error = EINVAL;
227977217Sphk				break;
228077217Sphk			}
2281119156Sambrisko			max = (sc->areq.an_len - 4)
2282119156Sambrisko			    / sizeof(struct an_ltv_ssid_entry);
2283119156Sambrisko			if ( max > MAX_SSIDS ) {
2284119156Sambrisko				printf("To many SSIDs only using "
2285119156Sambrisko				    "%d of %d\n",
2286119156Sambrisko				    MAX_SSIDS, max);
2287119156Sambrisko				max = MAX_SSIDS;
2288119156Sambrisko			}
2289119156Sambrisko			if (ireq->i_val > max) {
2290119156Sambrisko				error = EINVAL;
229177217Sphk				break;
2292119156Sambrisko			} else {
2293171692Savatar				AN_UNLOCK(sc);
229477217Sphk				error = copyin(ireq->i_data,
2295119156Sambrisko				    ssids->an_entry[ireq->i_val].an_ssid,
2296119156Sambrisko				    ireq->i_len);
2297171692Savatar				AN_LOCK(sc);
2298119156Sambrisko				ssids->an_entry[ireq->i_val].an_len
2299119156Sambrisko				    = ireq->i_len;
230077217Sphk				break;
230177217Sphk			}
230277217Sphk			break;
230377217Sphk		case IEEE80211_IOC_WEP:
230477217Sphk			switch (ireq->i_val) {
230577217Sphk			case IEEE80211_WEP_OFF:
230677217Sphk				config->an_authtype &=
230777217Sphk				    ~(AN_AUTHTYPE_PRIVACY_IN_USE |
230877217Sphk				    AN_AUTHTYPE_ALLOW_UNENCRYPTED);
230977217Sphk				break;
231077217Sphk			case IEEE80211_WEP_ON:
231177217Sphk				config->an_authtype |=
231277217Sphk				    AN_AUTHTYPE_PRIVACY_IN_USE;
231377217Sphk				config->an_authtype &=
231477217Sphk				    ~AN_AUTHTYPE_ALLOW_UNENCRYPTED;
231577217Sphk				break;
231677217Sphk			case IEEE80211_WEP_MIXED:
231777217Sphk				config->an_authtype |=
231877217Sphk				    AN_AUTHTYPE_PRIVACY_IN_USE |
231977217Sphk				    AN_AUTHTYPE_ALLOW_UNENCRYPTED;
232077217Sphk				break;
232177217Sphk			default:
232277217Sphk				error = EINVAL;
232377217Sphk				break;
232477217Sphk			}
232577217Sphk			break;
232677217Sphk		case IEEE80211_IOC_WEPKEY:
2327110531Sambrisko			if (ireq->i_val < 0 || ireq->i_val > 8 ||
232877217Sphk			    ireq->i_len > 13) {
232977217Sphk				error = EINVAL;
233077217Sphk				break;
233177217Sphk			}
2332171692Savatar			AN_UNLOCK(sc);
233377217Sphk			error = copyin(ireq->i_data, tmpstr, 13);
2334171692Savatar			AN_LOCK(sc);
233578639Sbrooks			if (error != 0)
233677217Sphk				break;
2337110531Sambrisko			/*
2338110531Sambrisko			 * Map the 9th key into the home mode
2339110531Sambrisko			 * since that is how it is stored on
2340110531Sambrisko			 * the card
2341110531Sambrisko			 */
234288749Sambrisko			bzero(&sc->areq, sizeof(struct an_ltv_key));
234388749Sambrisko			sc->areq.an_len = sizeof(struct an_ltv_key);
234477217Sphk			key->mac[0] = 1;	/* The others are 0. */
2345110531Sambrisko			if (ireq->i_val < 4) {
234688749Sambrisko				sc->areq.an_type = AN_RID_WEP_TEMP;
2347110531Sambrisko				key->kindex = ireq->i_val;
2348110531Sambrisko			} else {
234988749Sambrisko				sc->areq.an_type = AN_RID_WEP_PERM;
2350110531Sambrisko				key->kindex = ireq->i_val - 4;
2351110531Sambrisko			}
235277217Sphk			key->klen = ireq->i_len;
235377217Sphk			bcopy(tmpstr, key->key, key->klen);
235477217Sphk			break;
235577217Sphk		case IEEE80211_IOC_WEPTXKEY:
2356110531Sambrisko			if (ireq->i_val < 0 || ireq->i_val > 4) {
2357110531Sambrisko				error = EINVAL;
2358110531Sambrisko				break;
2359110531Sambrisko			}
2360110531Sambrisko
236188748Sambrisko			/*
236288748Sambrisko			 * Map the 5th key into the home mode
236388748Sambrisko			 * since that is how it is stored on
236488748Sambrisko			 * the card
236588748Sambrisko			 */
236688749Sambrisko			sc->areq.an_len  = sizeof(struct an_ltv_genconfig);
236788749Sambrisko			sc->areq.an_type = AN_RID_ACTUALCFG;
236888748Sambrisko			if (an_read_record(sc,
236988749Sambrisko	       		    (struct an_ltv_gen *)&sc->areq)) {
237088748Sambrisko	       			error = EINVAL;
237188748Sambrisko				break;
237288748Sambrisko			}
237388748Sambrisko			if (ireq->i_val ==  4) {
237488748Sambrisko				config->an_home_product |= AN_HOME_NETWORK;
237588748Sambrisko				ireq->i_val = 0;
237688748Sambrisko			} else {
237788748Sambrisko				config->an_home_product &= ~AN_HOME_NETWORK;
237888748Sambrisko			}
237988748Sambrisko
238088748Sambrisko			sc->an_config.an_home_product
238188748Sambrisko				= config->an_home_product;
238288748Sambrisko
2383110531Sambrisko			/* update configuration */
2384110531Sambrisko			an_init(sc);
2385110531Sambrisko
238688749Sambrisko			bzero(&sc->areq, sizeof(struct an_ltv_key));
238788749Sambrisko			sc->areq.an_len = sizeof(struct an_ltv_key);
238888749Sambrisko			sc->areq.an_type = AN_RID_WEP_PERM;
238977217Sphk			key->kindex = 0xffff;
239077217Sphk			key->mac[0] = ireq->i_val;
239177217Sphk			break;
239277217Sphk		case IEEE80211_IOC_AUTHMODE:
239377217Sphk			switch (ireq->i_val) {
239477217Sphk			case IEEE80211_AUTH_NONE:
239577217Sphk				config->an_authtype = AN_AUTHTYPE_NONE |
239677217Sphk				    (config->an_authtype & ~AN_AUTHTYPE_MASK);
239777217Sphk				break;
239877217Sphk			case IEEE80211_AUTH_OPEN:
239977217Sphk				config->an_authtype = AN_AUTHTYPE_OPEN |
240077217Sphk				    (config->an_authtype & ~AN_AUTHTYPE_MASK);
240177217Sphk				break;
240277217Sphk			case IEEE80211_AUTH_SHARED:
240377217Sphk				config->an_authtype = AN_AUTHTYPE_SHAREDKEY |
240477217Sphk				    (config->an_authtype & ~AN_AUTHTYPE_MASK);
240577217Sphk				break;
240677217Sphk			default:
240777217Sphk				error = EINVAL;
240877217Sphk			}
240977217Sphk			break;
241077217Sphk		case IEEE80211_IOC_STATIONNAME:
241178639Sbrooks			if (ireq->i_len > 16) {
241277217Sphk				error = EINVAL;
241377217Sphk				break;
241477217Sphk			}
241577217Sphk			bzero(config->an_nodename, 16);
2416171692Savatar			AN_UNLOCK(sc);
241777217Sphk			error = copyin(ireq->i_data,
241877217Sphk			    config->an_nodename, ireq->i_len);
2419171692Savatar			AN_LOCK(sc);
242077217Sphk			break;
242177217Sphk		case IEEE80211_IOC_CHANNEL:
242277217Sphk			/*
242377217Sphk			 * The actual range is 1-14, but if you set it
242477217Sphk			 * to 0 you get the default so we let that work
242577217Sphk			 * too.
242677217Sphk			 */
242777217Sphk			if (ireq->i_val < 0 || ireq->i_val >14) {
242877217Sphk				error = EINVAL;
242977217Sphk				break;
243077217Sphk			}
243177217Sphk			config->an_ds_channel = ireq->i_val;
243277217Sphk			break;
243377217Sphk		case IEEE80211_IOC_POWERSAVE:
243477217Sphk			switch (ireq->i_val) {
243577217Sphk			case IEEE80211_POWERSAVE_OFF:
243677217Sphk				config->an_psave_mode = AN_PSAVE_NONE;
243777217Sphk				break;
243877217Sphk			case IEEE80211_POWERSAVE_CAM:
243977217Sphk				config->an_psave_mode = AN_PSAVE_CAM;
244077217Sphk				break;
244177217Sphk			case IEEE80211_POWERSAVE_PSP:
244277217Sphk				config->an_psave_mode = AN_PSAVE_PSP;
244377217Sphk				break;
244477217Sphk			case IEEE80211_POWERSAVE_PSP_CAM:
244577217Sphk				config->an_psave_mode = AN_PSAVE_PSP_CAM;
244677217Sphk				break;
244777217Sphk			default:
244877217Sphk				error = EINVAL;
244977217Sphk				break;
245077217Sphk			}
245177217Sphk			break;
245277217Sphk		case IEEE80211_IOC_POWERSAVESLEEP:
245377217Sphk			config->an_listen_interval = ireq->i_val;
245477217Sphk			break;
245577217Sphk		}
245677217Sphk
245777217Sphk		if (!error)
245888749Sambrisko			an_setdef(sc, &sc->areq);
245977217Sphk		break;
246055992Swpaul	default:
2461171692Savatar		AN_UNLOCK(sc);
2462106937Ssam		error = ether_ioctl(ifp, command, data);
2463171692Savatar		AN_LOCK(sc);
246455992Swpaul		break;
246555992Swpaul	}
246661816Srobertoout:
246767094Swpaul	AN_UNLOCK(sc);
246855992Swpaul
246978639Sbrooks	return(error != 0);
247055992Swpaul}
247155992Swpaul
247283270Sbrooksstatic int
2473150446Simpan_init_tx_ring(struct an_softc *sc)
247455992Swpaul{
247555992Swpaul	int			i;
247655992Swpaul	int			id;
247755992Swpaul
247855992Swpaul	if (sc->an_gone)
247955992Swpaul		return (0);
248055992Swpaul
2481108401Sambrisko	if (!sc->mpi350) {
2482108401Sambrisko		for (i = 0; i < AN_TX_RING_CNT; i++) {
2483108401Sambrisko			if (an_alloc_nicmem(sc, 1518 +
2484108401Sambrisko			    0x44, &id))
2485108401Sambrisko				return(ENOMEM);
2486108401Sambrisko			sc->an_rdata.an_tx_fids[i] = id;
2487108401Sambrisko			sc->an_rdata.an_tx_ring[i] = 0;
2488108401Sambrisko		}
248955992Swpaul	}
249055992Swpaul
249155992Swpaul	sc->an_rdata.an_tx_prod = 0;
249255992Swpaul	sc->an_rdata.an_tx_cons = 0;
2493108401Sambrisko	sc->an_rdata.an_tx_empty = 1;
249455992Swpaul
249555992Swpaul	return(0);
249655992Swpaul}
249755992Swpaul
249883270Sbrooksstatic void
2499150446Simpan_init(void *xsc)
250055992Swpaul{
250155992Swpaul	struct an_softc		*sc = xsc;
2502147256Sbrooks	struct ifnet		*ifp = sc->an_ifp;
250355992Swpaul
250467094Swpaul	AN_LOCK(sc);
250567094Swpaul
250667094Swpaul	if (sc->an_gone) {
250767094Swpaul		AN_UNLOCK(sc);
250855992Swpaul		return;
250967094Swpaul	}
251055992Swpaul
2511148887Srwatson	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
251255992Swpaul		an_stop(sc);
251355992Swpaul
251455992Swpaul	sc->an_associated = 0;
251555992Swpaul
251655992Swpaul	/* Allocate the TX buffers */
251755992Swpaul	if (an_init_tx_ring(sc)) {
251855992Swpaul		an_reset(sc);
2519108401Sambrisko		if (sc->mpi350)
2520108401Sambrisko			an_init_mpi350_desc(sc);
252155992Swpaul		if (an_init_tx_ring(sc)) {
252255992Swpaul			printf("an%d: tx buffer allocation "
252355992Swpaul			    "failed\n", sc->an_unit);
252467094Swpaul			AN_UNLOCK(sc);
252555992Swpaul			return;
252655992Swpaul		}
252755992Swpaul	}
252855992Swpaul
252955992Swpaul	/* Set our MAC address. */
2530152315Sru	bcopy((char *)IF_LLADDR(sc->an_ifp),
253155992Swpaul	    (char *)&sc->an_config.an_macaddr, ETHER_ADDR_LEN);
253255992Swpaul
253355992Swpaul	if (ifp->if_flags & IFF_BROADCAST)
253455992Swpaul		sc->an_config.an_rxmode = AN_RXMODE_BC_ADDR;
253555992Swpaul	else
253655992Swpaul		sc->an_config.an_rxmode = AN_RXMODE_ADDR;
253755992Swpaul
253855992Swpaul	if (ifp->if_flags & IFF_MULTICAST)
253955992Swpaul		sc->an_config.an_rxmode = AN_RXMODE_BC_MC_ADDR;
254055992Swpaul
254183269Sbrooks	if (ifp->if_flags & IFF_PROMISC) {
254283269Sbrooks		if (sc->an_monitor & AN_MONITOR) {
254383269Sbrooks			if (sc->an_monitor & AN_MONITOR_ANY_BSS) {
254483269Sbrooks				sc->an_config.an_rxmode |=
254583269Sbrooks				    AN_RXMODE_80211_MONITOR_ANYBSS |
254683269Sbrooks				    AN_RXMODE_NO_8023_HEADER;
254783269Sbrooks			} else {
254883269Sbrooks				sc->an_config.an_rxmode |=
254983269Sbrooks				    AN_RXMODE_80211_MONITOR_CURBSS |
255083269Sbrooks				    AN_RXMODE_NO_8023_HEADER;
255183269Sbrooks			}
255283269Sbrooks		}
255383269Sbrooks	}
255455992Swpaul
2555108401Sambrisko	if (sc->an_have_rssimap)
2556108401Sambrisko		sc->an_config.an_rxmode |= AN_RXMODE_NORMALIZED_RSSI;
2557108401Sambrisko
255855992Swpaul	/* Set the ssid list */
255955992Swpaul	sc->an_ssidlist.an_type = AN_RID_SSIDLIST;
2560119156Sambrisko	sc->an_ssidlist.an_len = sizeof(struct an_ltv_ssidlist_new);
256155992Swpaul	if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_ssidlist)) {
256255992Swpaul		printf("an%d: failed to set ssid list\n", sc->an_unit);
256367094Swpaul		AN_UNLOCK(sc);
256455992Swpaul		return;
256555992Swpaul	}
256655992Swpaul
256755992Swpaul	/* Set the AP list */
256855992Swpaul	sc->an_aplist.an_type = AN_RID_APLIST;
256955992Swpaul	sc->an_aplist.an_len = sizeof(struct an_ltv_aplist);
257055992Swpaul	if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_aplist)) {
257155992Swpaul		printf("an%d: failed to set AP list\n", sc->an_unit);
257267094Swpaul		AN_UNLOCK(sc);
257355992Swpaul		return;
257455992Swpaul	}
257555992Swpaul
257655992Swpaul	/* Set the configuration in the NIC */
257755992Swpaul	sc->an_config.an_len = sizeof(struct an_ltv_genconfig);
257855992Swpaul	sc->an_config.an_type = AN_RID_GENCONFIG;
257955992Swpaul	if (an_write_record(sc, (struct an_ltv_gen *)&sc->an_config)) {
258055992Swpaul		printf("an%d: failed to set configuration\n", sc->an_unit);
258167094Swpaul		AN_UNLOCK(sc);
258255992Swpaul		return;
258355992Swpaul	}
258455992Swpaul
258555992Swpaul	/* Enable the MAC */
258655992Swpaul	if (an_cmd(sc, AN_CMD_ENABLE, 0)) {
258755992Swpaul		printf("an%d: failed to enable MAC\n", sc->an_unit);
258867094Swpaul		AN_UNLOCK(sc);
258955992Swpaul		return;
259055992Swpaul	}
259155992Swpaul
259274698Sarchie	if (ifp->if_flags & IFF_PROMISC)
259374698Sarchie		an_cmd(sc, AN_CMD_SET_MODE, 0xffff);
259474698Sarchie
259555992Swpaul	/* enable interrupts */
2596119156Sambrisko	CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), AN_INTRS(sc->mpi350));
259755992Swpaul
2598148887Srwatson	ifp->if_drv_flags |= IFF_DRV_RUNNING;
2599148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
260055992Swpaul
260155992Swpaul	sc->an_stat_ch = timeout(an_stats_update, sc, hz);
260267094Swpaul	AN_UNLOCK(sc);
260355992Swpaul
260455992Swpaul	return;
260555992Swpaul}
260655992Swpaul
260783270Sbrooksstatic void
2608150446Simpan_start(struct ifnet *ifp)
260955992Swpaul{
261055992Swpaul	struct an_softc		*sc;
261155992Swpaul	struct mbuf		*m0 = NULL;
261255992Swpaul	struct an_txframe_802_3	tx_frame_802_3;
261355992Swpaul	struct ether_header	*eh;
2614108401Sambrisko	int			id, idx, i;
261555992Swpaul	unsigned char           txcontrol;
2616108401Sambrisko	struct an_card_tx_desc an_tx_desc;
2617108401Sambrisko	u_int8_t		*buf;
261855992Swpaul
261955992Swpaul	sc = ifp->if_softc;
262055992Swpaul
262155992Swpaul	if (sc->an_gone)
262255992Swpaul		return;
262355992Swpaul
2624148887Srwatson	if (ifp->if_drv_flags & IFF_DRV_OACTIVE)
262555992Swpaul		return;
262655992Swpaul
262755992Swpaul	if (!sc->an_associated)
262855992Swpaul		return;
262955992Swpaul
263090990Sbrooks	/* We can't send in monitor mode so toss any attempts. */
263183269Sbrooks	if (sc->an_monitor && (ifp->if_flags & IFF_PROMISC)) {
263283270Sbrooks		for (;;) {
2633132986Smlaier			IFQ_DRV_DEQUEUE(&ifp->if_snd, m0);
263483269Sbrooks			if (m0 == NULL)
263583269Sbrooks				break;
263690990Sbrooks			m_freem(m0);
263783269Sbrooks		}
263883269Sbrooks		return;
263983269Sbrooks	}
264083269Sbrooks
264155992Swpaul	idx = sc->an_rdata.an_tx_prod;
264255992Swpaul
2643108401Sambrisko	if (!sc->mpi350) {
2644108401Sambrisko		bzero((char *)&tx_frame_802_3, sizeof(tx_frame_802_3));
264555992Swpaul
2646108401Sambrisko		while (sc->an_rdata.an_tx_ring[idx] == 0) {
2647132986Smlaier			IFQ_DRV_DEQUEUE(&ifp->if_snd, m0);
2648108401Sambrisko			if (m0 == NULL)
2649108401Sambrisko				break;
265055992Swpaul
2651108401Sambrisko			id = sc->an_rdata.an_tx_fids[idx];
2652108401Sambrisko			eh = mtod(m0, struct ether_header *);
265383270Sbrooks
2654108401Sambrisko			bcopy((char *)&eh->ether_dhost,
2655108401Sambrisko			      (char *)&tx_frame_802_3.an_tx_dst_addr,
2656108401Sambrisko			      ETHER_ADDR_LEN);
2657108401Sambrisko			bcopy((char *)&eh->ether_shost,
2658108401Sambrisko			      (char *)&tx_frame_802_3.an_tx_src_addr,
2659108401Sambrisko			      ETHER_ADDR_LEN);
266055992Swpaul
2661108401Sambrisko			/* minus src/dest mac & type */
2662108401Sambrisko			tx_frame_802_3.an_tx_802_3_payload_len =
2663108401Sambrisko				m0->m_pkthdr.len - 12;
266455992Swpaul
2665108401Sambrisko			m_copydata(m0, sizeof(struct ether_header) - 2 ,
2666108401Sambrisko				   tx_frame_802_3.an_tx_802_3_payload_len,
2667108401Sambrisko				   (caddr_t)&sc->an_txbuf);
2668108401Sambrisko
2669108401Sambrisko			txcontrol = AN_TXCTL_8023;
2670108401Sambrisko			/* write the txcontrol only */
2671108401Sambrisko			an_write_data(sc, id, 0x08, (caddr_t)&txcontrol,
2672108401Sambrisko				      sizeof(txcontrol));
2673108401Sambrisko
2674108401Sambrisko			/* 802_3 header */
2675108401Sambrisko			an_write_data(sc, id, 0x34, (caddr_t)&tx_frame_802_3,
2676108401Sambrisko				      sizeof(struct an_txframe_802_3));
2677108401Sambrisko
2678108401Sambrisko			/* in mbuf header type is just before payload */
2679108401Sambrisko			an_write_data(sc, id, 0x44, (caddr_t)&sc->an_txbuf,
2680108401Sambrisko				      tx_frame_802_3.an_tx_802_3_payload_len);
2681108401Sambrisko
2682108401Sambrisko			/*
2683108401Sambrisko			 * If there's a BPF listner, bounce a copy of
2684108401Sambrisko			 * this frame to him.
2685108401Sambrisko			 */
2686108401Sambrisko			BPF_MTAP(ifp, m0);
2687108401Sambrisko
2688108401Sambrisko			m_freem(m0);
2689108401Sambrisko			m0 = NULL;
2690108401Sambrisko
2691108401Sambrisko			sc->an_rdata.an_tx_ring[idx] = id;
2692108401Sambrisko			if (an_cmd(sc, AN_CMD_TX, id))
2693108401Sambrisko				printf("an%d: xmit failed\n", sc->an_unit);
2694108401Sambrisko
2695108401Sambrisko			AN_INC(idx, AN_TX_RING_CNT);
2696119156Sambrisko
2697119156Sambrisko			/*
2698119156Sambrisko			 * Set a timeout in case the chip goes out to lunch.
2699119156Sambrisko			 */
2700119156Sambrisko			ifp->if_timer = 5;
2701108401Sambrisko		}
2702108401Sambrisko	} else { /* MPI-350 */
2703130620Sambrisko		/* Disable interrupts. */
2704130620Sambrisko		CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0);
2705130620Sambrisko
2706108401Sambrisko		while (sc->an_rdata.an_tx_empty ||
2707108401Sambrisko		    idx != sc->an_rdata.an_tx_cons) {
2708132986Smlaier			IFQ_DRV_DEQUEUE(&ifp->if_snd, m0);
2709108401Sambrisko			if (m0 == NULL) {
2710108401Sambrisko				break;
2711108401Sambrisko			}
2712108401Sambrisko			buf = sc->an_tx_buffer[idx].an_dma_vaddr;
2713108401Sambrisko
2714108401Sambrisko			eh = mtod(m0, struct ether_header *);
2715108401Sambrisko
2716108401Sambrisko			/* DJA optimize this to limit bcopy */
2717108401Sambrisko			bcopy((char *)&eh->ether_dhost,
2718108401Sambrisko			      (char *)&tx_frame_802_3.an_tx_dst_addr,
2719108401Sambrisko			      ETHER_ADDR_LEN);
2720108401Sambrisko			bcopy((char *)&eh->ether_shost,
2721108401Sambrisko			      (char *)&tx_frame_802_3.an_tx_src_addr,
2722108401Sambrisko			      ETHER_ADDR_LEN);
2723108401Sambrisko
2724108401Sambrisko			/* minus src/dest mac & type */
2725108401Sambrisko			tx_frame_802_3.an_tx_802_3_payload_len =
2726108401Sambrisko				m0->m_pkthdr.len - 12;
2727108401Sambrisko
2728108401Sambrisko			m_copydata(m0, sizeof(struct ether_header) - 2 ,
2729108401Sambrisko				   tx_frame_802_3.an_tx_802_3_payload_len,
2730108401Sambrisko				   (caddr_t)&sc->an_txbuf);
2731108401Sambrisko
2732108401Sambrisko			txcontrol = AN_TXCTL_8023;
2733108401Sambrisko			/* write the txcontrol only */
2734108401Sambrisko			bcopy((caddr_t)&txcontrol, &buf[0x08],
273555992Swpaul			      sizeof(txcontrol));
273683270Sbrooks
2737108401Sambrisko			/* 802_3 header */
2738108401Sambrisko			bcopy((caddr_t)&tx_frame_802_3, &buf[0x34],
273955992Swpaul			      sizeof(struct an_txframe_802_3));
274083270Sbrooks
2741108401Sambrisko			/* in mbuf header type is just before payload */
2742108401Sambrisko			bcopy((caddr_t)&sc->an_txbuf, &buf[0x44],
2743108401Sambrisko			      tx_frame_802_3.an_tx_802_3_payload_len);
274483270Sbrooks
274555992Swpaul
2746108401Sambrisko			bzero(&an_tx_desc, sizeof(an_tx_desc));
2747108401Sambrisko			an_tx_desc.an_offset = 0;
2748108401Sambrisko			an_tx_desc.an_eoc = 1;
2749108401Sambrisko			an_tx_desc.an_valid = 1;
2750108401Sambrisko			an_tx_desc.an_len =  0x44 +
2751119156Sambrisko			    tx_frame_802_3.an_tx_802_3_payload_len;
2752119156Sambrisko			an_tx_desc.an_phys
2753119156Sambrisko			    = sc->an_tx_buffer[idx].an_dma_paddr;
2754119156Sambrisko			for (i = 0; i < sizeof(an_tx_desc) / 4 ; i++) {
2755119156Sambrisko				CSR_MEM_AUX_WRITE_4(sc, AN_TX_DESC_OFFSET
2756119156Sambrisko				    /* zero for now */
2757119156Sambrisko				    + (0 * sizeof(an_tx_desc))
2758119156Sambrisko				    + (i * 4),
2759155321Simp				    ((u_int32_t *)(void *)&an_tx_desc)[i]);
2760108401Sambrisko			}
276155992Swpaul
2762108401Sambrisko			/*
2763108401Sambrisko			 * If there's a BPF listner, bounce a copy of
2764108401Sambrisko			 * this frame to him.
2765108401Sambrisko			 */
2766108401Sambrisko			BPF_MTAP(ifp, m0);
276755992Swpaul
2768108401Sambrisko			m_freem(m0);
2769108401Sambrisko			m0 = NULL;
2770119156Sambrisko			AN_INC(idx, AN_MAX_TX_DESC);
2771119156Sambrisko			sc->an_rdata.an_tx_empty = 0;
2772108401Sambrisko			CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_ALLOC);
2773108401Sambrisko
2774119156Sambrisko			/*
2775119156Sambrisko			 * Set a timeout in case the chip goes out to lunch.
2776119156Sambrisko			 */
2777119156Sambrisko			ifp->if_timer = 5;
2778108401Sambrisko		}
2779130620Sambrisko
2780130620Sambrisko		/* Re-enable interrupts. */
2781130620Sambrisko		CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), AN_INTRS(sc->mpi350));
278255992Swpaul	}
278355992Swpaul
278455992Swpaul	if (m0 != NULL)
2785148887Srwatson		ifp->if_drv_flags |= IFF_DRV_OACTIVE;
278655992Swpaul
278755992Swpaul	sc->an_rdata.an_tx_prod = idx;
278855992Swpaul
278955992Swpaul	return;
279055992Swpaul}
279155992Swpaul
279283270Sbrooksvoid
2793150446Simpan_stop(struct an_softc *sc)
279455992Swpaul{
279555992Swpaul	struct ifnet		*ifp;
279655992Swpaul	int			i;
279755992Swpaul
279867094Swpaul	AN_LOCK(sc);
279967094Swpaul
280067094Swpaul	if (sc->an_gone) {
280167094Swpaul		AN_UNLOCK(sc);
280255992Swpaul		return;
280367094Swpaul	}
280455992Swpaul
2805147256Sbrooks	ifp = sc->an_ifp;
280655992Swpaul
280755992Swpaul	an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0);
2808108401Sambrisko	CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0);
280955992Swpaul	an_cmd(sc, AN_CMD_DISABLE, 0);
281055992Swpaul
281155992Swpaul	for (i = 0; i < AN_TX_RING_CNT; i++)
281255992Swpaul		an_cmd(sc, AN_CMD_DEALLOC_MEM, sc->an_rdata.an_tx_fids[i]);
281355992Swpaul
281455992Swpaul	untimeout(an_stats_update, sc, sc->an_stat_ch);
281555992Swpaul
2816148887Srwatson	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING|IFF_DRV_OACTIVE);
281755992Swpaul
2818108401Sambrisko	if (sc->an_flash_buffer) {
2819108401Sambrisko		free(sc->an_flash_buffer, M_DEVBUF);
2820108401Sambrisko		sc->an_flash_buffer = NULL;
2821108401Sambrisko	}
2822108401Sambrisko
282367094Swpaul	AN_UNLOCK(sc);
282467094Swpaul
282555992Swpaul	return;
282655992Swpaul}
282755992Swpaul
282883270Sbrooksstatic void
2829150446Simpan_watchdog(struct ifnet *ifp)
283055992Swpaul{
283155992Swpaul	struct an_softc		*sc;
283255992Swpaul
283355992Swpaul	sc = ifp->if_softc;
283467094Swpaul	AN_LOCK(sc);
283555992Swpaul
283667094Swpaul	if (sc->an_gone) {
283767094Swpaul		AN_UNLOCK(sc);
283855992Swpaul		return;
283967094Swpaul	}
284055992Swpaul
284155992Swpaul	printf("an%d: device timeout\n", sc->an_unit);
284255992Swpaul
284355992Swpaul	an_reset(sc);
2844108401Sambrisko	if (sc->mpi350)
2845108401Sambrisko		an_init_mpi350_desc(sc);
284655992Swpaul	an_init(sc);
284755992Swpaul
284855992Swpaul	ifp->if_oerrors++;
284967094Swpaul	AN_UNLOCK(sc);
285055992Swpaul
285155992Swpaul	return;
285255992Swpaul}
285355992Swpaul
285483270Sbrooksvoid
2855150446Simpan_shutdown(device_t dev)
285655992Swpaul{
285755992Swpaul	struct an_softc		*sc;
285855992Swpaul
285955992Swpaul	sc = device_get_softc(dev);
286055992Swpaul	an_stop(sc);
2861110531Sambrisko	sc->an_gone = 1;
286255992Swpaul
286355992Swpaul	return;
286455992Swpaul}
286555992Swpaul
2866110362Sambriskovoid
2867150446Simpan_resume(device_t dev)
2868110362Sambrisko{
2869110362Sambrisko	struct an_softc		*sc;
2870110362Sambrisko	struct ifnet		*ifp;
2871110531Sambrisko	int			i;
2872110531Sambrisko
2873110362Sambrisko	sc = device_get_softc(dev);
2874110531Sambrisko	AN_LOCK(sc);
2875147256Sbrooks	ifp = sc->an_ifp;
2876110362Sambrisko
2877110531Sambrisko	sc->an_gone = 0;
2878110362Sambrisko	an_reset(sc);
2879110362Sambrisko	if (sc->mpi350)
2880110362Sambrisko		an_init_mpi350_desc(sc);
2881110362Sambrisko	an_init(sc);
2882110362Sambrisko
2883110531Sambrisko	/* Recovery temporary keys */
2884110531Sambrisko	for (i = 0; i < 4; i++) {
2885110531Sambrisko		sc->areq.an_type = AN_RID_WEP_TEMP;
2886110531Sambrisko		sc->areq.an_len = sizeof(struct an_ltv_key);
2887110531Sambrisko		bcopy(&sc->an_temp_keys[i],
2888110531Sambrisko		    &sc->areq, sizeof(struct an_ltv_key));
2889110531Sambrisko		an_setdef(sc, &sc->areq);
2890110531Sambrisko	}
2891110531Sambrisko
2892110362Sambrisko	if (ifp->if_flags & IFF_UP)
2893110362Sambrisko		an_start(ifp);
2894110531Sambrisko	AN_UNLOCK(sc);
2895110362Sambrisko
2896110362Sambrisko	return;
2897110362Sambrisko}
2898110362Sambrisko
289955992Swpaul#ifdef ANCACHE
290055992Swpaul/* Aironet signal strength cache code.
290155992Swpaul * store signal/noise/quality on per MAC src basis in
290255992Swpaul * a small fixed cache.  The cache wraps if > MAX slots
290355992Swpaul * used.  The cache may be zeroed out to start over.
290455992Swpaul * Two simple filters exist to reduce computation:
290588748Sambrisko * 1. ip only (literally 0x800, ETHERTYPE_IP) which may be used
290655992Swpaul * to ignore some packets.  It defaults to ip only.
290755992Swpaul * it could be used to focus on broadcast, non-IP 802.11 beacons.
290855992Swpaul * 2. multicast/broadcast only.  This may be used to
290955992Swpaul * ignore unicast packets and only cache signal strength
291055992Swpaul * for multicast/broadcast packets (beacons); e.g., Mobile-IP
291155992Swpaul * beacons and not unicast traffic.
291255992Swpaul *
291355992Swpaul * The cache stores (MAC src(index), IP src (major clue), signal,
291455992Swpaul *	quality, noise)
291555992Swpaul *
291655992Swpaul * No apologies for storing IP src here.  It's easy and saves much
291783270Sbrooks * trouble elsewhere.  The cache is assumed to be INET dependent,
291855992Swpaul * although it need not be.
291955992Swpaul *
292055992Swpaul * Note: the Aironet only has a single byte of signal strength value
292155992Swpaul * in the rx frame header, and it's not scaled to anything sensible.
292255992Swpaul * This is kind of lame, but it's all we've got.
292355992Swpaul */
292455992Swpaul
292555992Swpaul#ifdef documentation
292655992Swpaul
292755992Swpaulint an_sigitems;                                /* number of cached entries */
292855992Swpaulstruct an_sigcache an_sigcache[MAXANCACHE];  /*  array of cache entries */
292955992Swpaulint an_nextitem;                                /*  index/# of entries */
293055992Swpaul
293155992Swpaul
293255992Swpaul#endif
293355992Swpaul
293455992Swpaul/* control variables for cache filtering.  Basic idea is
293555992Swpaul * to reduce cost (e.g., to only Mobile-IP agent beacons
293655992Swpaul * which are broadcast or multicast).  Still you might
293755992Swpaul * want to measure signal strength anth unicast ping packets
293855992Swpaul * on a pt. to pt. ant. setup.
293955992Swpaul */
294083270Sbrooks/* set true if you want to limit cache items to broadcast/mcast
294155992Swpaul * only packets (not unicast).  Useful for mobile-ip beacons which
294255992Swpaul * are broadcast/multicast at network layer.  Default is all packets
294355992Swpaul * so ping/unicast anll work say anth pt. to pt. antennae setup.
294455992Swpaul */
294555992Swpaulstatic int an_cache_mcastonly = 0;
2946110531SambriskoSYSCTL_INT(_hw_an, OID_AUTO, an_cache_mcastonly, CTLFLAG_RW,
294755992Swpaul	&an_cache_mcastonly, 0, "");
294855992Swpaul
294955992Swpaul/* set true if you want to limit cache items to IP packets only
295055992Swpaul*/
295155992Swpaulstatic int an_cache_iponly = 1;
2952110531SambriskoSYSCTL_INT(_hw_an, OID_AUTO, an_cache_iponly, CTLFLAG_RW,
295355992Swpaul	&an_cache_iponly, 0, "");
295455992Swpaul
295555992Swpaul/*
295655992Swpaul * an_cache_store, per rx packet store signal
295755992Swpaul * strength in MAC (src) indexed cache.
295855992Swpaul */
295983270Sbrooksstatic void
2960150446Simpan_cache_store(struct an_softc *sc, struct ether_header *eh, struct mbuf *m,
2961150446Simp    u_int8_t rx_rssi, u_int8_t rx_quality)
296255992Swpaul{
296383270Sbrooks	struct ip *ip = 0;
296455992Swpaul	int i;
296555992Swpaul	static int cache_slot = 0; 	/* use this cache entry */
296655992Swpaul	static int wrapindex = 0;       /* next "free" cache entry */
296788748Sambrisko	int type_ipv4 = 0;
296855992Swpaul
296955992Swpaul	/* filters:
297055992Swpaul	 * 1. ip only
297155992Swpaul	 * 2. configurable filter to throw out unicast packets,
297255992Swpaul	 * keep multicast only.
297355992Swpaul	 */
297483270Sbrooks
297588748Sambrisko	if ((ntohs(eh->ether_type) == ETHERTYPE_IP)) {
297688748Sambrisko		type_ipv4 = 1;
297755992Swpaul	}
297855992Swpaul
297983270Sbrooks	/* filter for ip packets only
298055992Swpaul	*/
298188748Sambrisko	if ( an_cache_iponly && !type_ipv4) {
298255992Swpaul		return;
298355992Swpaul	}
298455992Swpaul
298555992Swpaul	/* filter for broadcast/multicast only
298655992Swpaul	 */
298755992Swpaul	if (an_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) {
298855992Swpaul		return;
298955992Swpaul	}
299055992Swpaul
299155992Swpaul#ifdef SIGDEBUG
299255992Swpaul	printf("an: q value %x (MSB=0x%x, LSB=0x%x) \n",
2993108401Sambrisko		rx_rssi & 0xffff, rx_rssi >> 8, rx_rssi & 0xff);
299455992Swpaul#endif
299555992Swpaul
299655992Swpaul	/* find the ip header.  we want to store the ip_src
299783270Sbrooks	 * address.
299855992Swpaul	 */
299988748Sambrisko	if (type_ipv4) {
300055992Swpaul		ip = mtod(m, struct ip *);
300155992Swpaul	}
300283270Sbrooks
300383270Sbrooks	/* do a linear search for a matching MAC address
300455992Swpaul	 * in the cache table
300555992Swpaul	 * . MAC address is 6 bytes,
300655992Swpaul	 * . var w_nextitem holds total number of entries already cached
300755992Swpaul	 */
300878639Sbrooks	for (i = 0; i < sc->an_nextitem; i++) {
300955992Swpaul		if (! bcmp(eh->ether_shost , sc->an_sigcache[i].macsrc,  6 )) {
301055992Swpaul			/* Match!,
301155992Swpaul			 * so we already have this entry,
301255992Swpaul			 * update the data
301355992Swpaul			 */
301483270Sbrooks			break;
301555992Swpaul		}
301655992Swpaul	}
301755992Swpaul
301855992Swpaul	/* did we find a matching mac address?
301955992Swpaul	 * if yes, then overwrite a previously existing cache entry
302055992Swpaul	 */
302155992Swpaul	if (i < sc->an_nextitem )   {
302283270Sbrooks		cache_slot = i;
302355992Swpaul	}
302455992Swpaul	/* else, have a new address entry,so
302555992Swpaul	 * add this new entry,
302655992Swpaul	 * if table full, then we need to replace LRU entry
302755992Swpaul	 */
302883270Sbrooks	else    {
302955992Swpaul
303083270Sbrooks		/* check for space in cache table
303155992Swpaul		 * note: an_nextitem also holds number of entries
303283270Sbrooks		 * added in the cache table
303355992Swpaul		 */
303455992Swpaul		if ( sc->an_nextitem < MAXANCACHE ) {
303555992Swpaul			cache_slot = sc->an_nextitem;
303683270Sbrooks			sc->an_nextitem++;
303755992Swpaul			sc->an_sigitems = sc->an_nextitem;
303855992Swpaul		}
303955992Swpaul        	/* no space found, so simply wrap anth wrap index
304055992Swpaul		 * and "zap" the next entry
304155992Swpaul		 */
304255992Swpaul		else {
304355992Swpaul			if (wrapindex == MAXANCACHE) {
304455992Swpaul				wrapindex = 0;
304555992Swpaul			}
304655992Swpaul			cache_slot = wrapindex++;
304755992Swpaul		}
304855992Swpaul	}
304955992Swpaul
305055992Swpaul	/* invariant: cache_slot now points at some slot
305155992Swpaul	 * in cache.
305255992Swpaul	 */
305355992Swpaul	if (cache_slot < 0 || cache_slot >= MAXANCACHE) {
305455992Swpaul		log(LOG_ERR, "an_cache_store, bad index: %d of "
305555992Swpaul		    "[0..%d], gross cache error\n",
305655992Swpaul		    cache_slot, MAXANCACHE);
305755992Swpaul		return;
305855992Swpaul	}
305955992Swpaul
306055992Swpaul	/*  store items in cache
306155992Swpaul	 *  .ip source address
306255992Swpaul	 *  .mac src
306355992Swpaul	 *  .signal, etc.
306455992Swpaul	 */
306588748Sambrisko	if (type_ipv4) {
306655992Swpaul		sc->an_sigcache[cache_slot].ipsrc = ip->ip_src.s_addr;
306755992Swpaul	}
306855992Swpaul	bcopy( eh->ether_shost, sc->an_sigcache[cache_slot].macsrc,  6);
306955992Swpaul
307055992Swpaul
3071108401Sambrisko	switch (an_cache_mode) {
3072108401Sambrisko	case DBM:
3073108401Sambrisko		if (sc->an_have_rssimap) {
3074108401Sambrisko			sc->an_sigcache[cache_slot].signal =
3075108401Sambrisko				- sc->an_rssimap.an_entries[rx_rssi].an_rss_dbm;
3076108401Sambrisko			sc->an_sigcache[cache_slot].quality =
3077108401Sambrisko				- sc->an_rssimap.an_entries[rx_quality].an_rss_dbm;
3078108401Sambrisko		} else {
3079108401Sambrisko			sc->an_sigcache[cache_slot].signal = rx_rssi - 100;
3080108401Sambrisko			sc->an_sigcache[cache_slot].quality = rx_quality - 100;
3081108401Sambrisko		}
3082108401Sambrisko		break;
3083108401Sambrisko	case PERCENT:
3084108401Sambrisko		if (sc->an_have_rssimap) {
3085108401Sambrisko			sc->an_sigcache[cache_slot].signal =
3086108401Sambrisko				sc->an_rssimap.an_entries[rx_rssi].an_rss_pct;
3087108401Sambrisko			sc->an_sigcache[cache_slot].quality =
3088108401Sambrisko				sc->an_rssimap.an_entries[rx_quality].an_rss_pct;
3089108401Sambrisko		} else {
3090108401Sambrisko			if (rx_rssi > 100)
3091108401Sambrisko				rx_rssi = 100;
3092108401Sambrisko			if (rx_quality > 100)
3093108401Sambrisko				rx_quality = 100;
3094108401Sambrisko			sc->an_sigcache[cache_slot].signal = rx_rssi;
3095108401Sambrisko			sc->an_sigcache[cache_slot].quality = rx_quality;
3096108401Sambrisko		}
3097108401Sambrisko		break;
3098108401Sambrisko	case RAW:
3099108401Sambrisko		sc->an_sigcache[cache_slot].signal = rx_rssi;
3100108401Sambrisko		sc->an_sigcache[cache_slot].quality = rx_quality;
3101108401Sambrisko		break;
3102108401Sambrisko	}
3103108401Sambrisko
3104108401Sambrisko	sc->an_sigcache[cache_slot].noise = 0;
3105108401Sambrisko
310655992Swpaul	return;
310755992Swpaul}
310855992Swpaul#endif
310977217Sphk
311083270Sbrooksstatic int
3111150446Simpan_media_change(struct ifnet *ifp)
311277217Sphk{
311377217Sphk	struct an_softc *sc = ifp->if_softc;
3114110253Sambrisko	struct an_ltv_genconfig	*cfg;
311577217Sphk	int otype = sc->an_config.an_opmode;
311677217Sphk	int orate = sc->an_tx_rate;
311777217Sphk
3118116951Ssam	sc->an_tx_rate = ieee80211_media2rate(
3119116951Ssam		IFM_SUBTYPE(sc->an_ifmedia.ifm_cur->ifm_media));
3120119156Sambrisko	if (sc->an_tx_rate < 0)
3121119156Sambrisko		sc->an_tx_rate = 0;
3122110253Sambrisko
3123110253Sambrisko	if (orate != sc->an_tx_rate) {
3124110253Sambrisko		/* Read the current configuration */
3125110253Sambrisko		sc->an_config.an_type = AN_RID_GENCONFIG;
3126110253Sambrisko		sc->an_config.an_len = sizeof(struct an_ltv_genconfig);
3127110253Sambrisko		an_read_record(sc, (struct an_ltv_gen *)&sc->an_config);
3128110253Sambrisko		cfg = &sc->an_config;
3129110253Sambrisko
3130110253Sambrisko		/* clear other rates and set the only one we want */
3131110253Sambrisko		bzero(cfg->an_rates, sizeof(cfg->an_rates));
3132110253Sambrisko		cfg->an_rates[0] = sc->an_tx_rate;
3133110253Sambrisko
3134110253Sambrisko		/* Save the new rate */
3135110253Sambrisko		sc->an_config.an_type = AN_RID_GENCONFIG;
3136110253Sambrisko		sc->an_config.an_len = sizeof(struct an_ltv_genconfig);
313777217Sphk	}
313877217Sphk
3139119156Sambrisko	if ((sc->an_ifmedia.ifm_cur->ifm_media & IFM_IEEE80211_ADHOC) != 0)
3140119156Sambrisko		sc->an_config.an_opmode &= ~AN_OPMODE_INFRASTRUCTURE_STATION;
3141119156Sambrisko	else
3142119156Sambrisko		sc->an_config.an_opmode |= AN_OPMODE_INFRASTRUCTURE_STATION;
3143119156Sambrisko
3144110531Sambrisko	if (otype != sc->an_config.an_opmode ||
3145110531Sambrisko	    orate != sc->an_tx_rate)
314677217Sphk		an_init(sc);
314777217Sphk
314877217Sphk	return(0);
314977217Sphk}
315077217Sphk
315183270Sbrooksstatic void
3152150446Simpan_media_status(struct ifnet *ifp, struct ifmediareq *imr)
315377217Sphk{
315477217Sphk	struct an_ltv_status	status;
315577217Sphk	struct an_softc		*sc = ifp->if_softc;
315677217Sphk
3157110253Sambrisko	imr->ifm_active = IFM_IEEE80211;
3158110253Sambrisko
315977217Sphk	status.an_len = sizeof(status);
316077217Sphk	status.an_type = AN_RID_STATUS;
316177217Sphk	if (an_read_record(sc, (struct an_ltv_gen *)&status)) {
316277217Sphk		/* If the status read fails, just lie. */
316377217Sphk		imr->ifm_active = sc->an_ifmedia.ifm_cur->ifm_media;
316477217Sphk		imr->ifm_status = IFM_AVALID|IFM_ACTIVE;
316577217Sphk	}
316677217Sphk
316778639Sbrooks	if (sc->an_tx_rate == 0) {
316877217Sphk		imr->ifm_active = IFM_IEEE80211|IFM_AUTO;
316977217Sphk	}
317077217Sphk
3171110253Sambrisko	if (sc->an_config.an_opmode == AN_OPMODE_IBSS_ADHOC)
3172110253Sambrisko		imr->ifm_active |= IFM_IEEE80211_ADHOC;
3173116951Ssam	imr->ifm_active |= ieee80211_rate2media(NULL,
3174116951Ssam		status.an_current_tx_rate, IEEE80211_T_DS);
317577217Sphk	imr->ifm_status = IFM_AVALID;
317691283Sambrisko	if (status.an_opmode & AN_STATUS_OPMODE_ASSOCIATED)
317777217Sphk		imr->ifm_status |= IFM_ACTIVE;
317877217Sphk}
317988748Sambrisko
318088748Sambrisko/********************** Cisco utility support routines *************/
318188748Sambrisko
318288748Sambrisko/*
318388748Sambrisko * ReadRids & WriteRids derived from Cisco driver additions to Ben Reed's
318488748Sambrisko * Linux driver
318588748Sambrisko */
318688748Sambrisko
318788748Sambriskostatic int
3188150446Simpreadrids(struct ifnet *ifp, struct aironet_ioctl *l_ioctl)
318988748Sambrisko{
319088749Sambrisko	unsigned short  rid;
319188748Sambrisko	struct an_softc *sc;
3192171692Savatar	int error;
319388748Sambrisko
319488748Sambrisko	switch (l_ioctl->command) {
319588748Sambrisko	case AIROGCAP:
319688748Sambrisko		rid = AN_RID_CAPABILITIES;
319788748Sambrisko		break;
319888748Sambrisko	case AIROGCFG:
319988748Sambrisko		rid = AN_RID_GENCONFIG;
320088748Sambrisko		break;
320188748Sambrisko	case AIROGSLIST:
320288748Sambrisko		rid = AN_RID_SSIDLIST;
320388748Sambrisko		break;
320488748Sambrisko	case AIROGVLIST:
320588748Sambrisko		rid = AN_RID_APLIST;
320688748Sambrisko		break;
320788748Sambrisko	case AIROGDRVNAM:
320888748Sambrisko		rid = AN_RID_DRVNAME;
320988748Sambrisko		break;
321088748Sambrisko	case AIROGEHTENC:
321188748Sambrisko		rid = AN_RID_ENCAPPROTO;
321288748Sambrisko		break;
321388748Sambrisko	case AIROGWEPKTMP:
321488748Sambrisko		rid = AN_RID_WEP_TEMP;
321588748Sambrisko		break;
321688748Sambrisko	case AIROGWEPKNV:
321788748Sambrisko		rid = AN_RID_WEP_PERM;
321888748Sambrisko		break;
321988748Sambrisko	case AIROGSTAT:
322088748Sambrisko		rid = AN_RID_STATUS;
322188748Sambrisko		break;
322288748Sambrisko	case AIROGSTATSD32:
322388748Sambrisko		rid = AN_RID_32BITS_DELTA;
322488748Sambrisko		break;
322588748Sambrisko	case AIROGSTATSC32:
322688748Sambrisko		rid = AN_RID_32BITS_CUM;
322788748Sambrisko		break;
322888748Sambrisko	default:
322988748Sambrisko		rid = 999;
323088748Sambrisko		break;
323188748Sambrisko	}
323288748Sambrisko
323388748Sambrisko	if (rid == 999)	/* Is bad command */
323488748Sambrisko		return -EINVAL;
323588748Sambrisko
323688748Sambrisko	sc = ifp->if_softc;
323788749Sambrisko	sc->areq.an_len  = AN_MAX_DATALEN;
323888749Sambrisko	sc->areq.an_type = rid;
323988748Sambrisko
324088749Sambrisko	an_read_record(sc, (struct an_ltv_gen *)&sc->areq);
324188748Sambrisko
324288749Sambrisko	l_ioctl->len = sc->areq.an_len - 4;	/* just data */
324388748Sambrisko
3244171692Savatar	AN_UNLOCK(sc);
324588748Sambrisko	/* the data contains the length at first */
324688749Sambrisko	if (copyout(&(sc->areq.an_len), l_ioctl->data,
324788749Sambrisko		    sizeof(sc->areq.an_len))) {
3248171692Savatar		error = -EFAULT;
3249171692Savatar		goto lock_exit;
325088748Sambrisko	}
325188748Sambrisko	/* Just copy the data back */
325288749Sambrisko	if (copyout(&(sc->areq.an_val), l_ioctl->data + 2,
325388748Sambrisko		    l_ioctl->len)) {
3254171692Savatar		error = -EFAULT;
3255171692Savatar		goto lock_exit;
325688748Sambrisko	}
3257171692Savatar	error = 0;
3258171692Savatarlock_exit:
3259171692Savatar	AN_LOCK(sc);
3260171692Savatar	return (error);
326188748Sambrisko}
326288748Sambrisko
326388748Sambriskostatic int
3264150446Simpwriterids(struct ifnet *ifp, struct aironet_ioctl *l_ioctl)
326588748Sambrisko{
326688748Sambrisko	struct an_softc *sc;
3267171692Savatar	int             rid, command, error;
326888748Sambrisko
326988748Sambrisko	sc = ifp->if_softc;
327088748Sambrisko	rid = 0;
327188748Sambrisko	command = l_ioctl->command;
327288748Sambrisko
327388748Sambrisko	switch (command) {
327488748Sambrisko	case AIROPSIDS:
327588748Sambrisko		rid = AN_RID_SSIDLIST;
327688748Sambrisko		break;
327788748Sambrisko	case AIROPCAP:
327888748Sambrisko		rid = AN_RID_CAPABILITIES;
327988748Sambrisko		break;
328088748Sambrisko	case AIROPAPLIST:
328188748Sambrisko		rid = AN_RID_APLIST;
328288748Sambrisko		break;
328388748Sambrisko	case AIROPCFG:
328488748Sambrisko		rid = AN_RID_GENCONFIG;
328588748Sambrisko		break;
328688748Sambrisko	case AIROPMACON:
328788748Sambrisko		an_cmd(sc, AN_CMD_ENABLE, 0);
328888748Sambrisko		return 0;
328988748Sambrisko		break;
329088748Sambrisko	case AIROPMACOFF:
329188748Sambrisko		an_cmd(sc, AN_CMD_DISABLE, 0);
329288748Sambrisko		return 0;
329388748Sambrisko		break;
329488748Sambrisko	case AIROPSTCLR:
329588748Sambrisko		/*
329688748Sambrisko		 * This command merely clears the counts does not actually
329788748Sambrisko		 * store any data only reads rid. But as it changes the cards
329888748Sambrisko		 * state, I put it in the writerid routines.
329988748Sambrisko		 */
330088748Sambrisko
330188748Sambrisko		rid = AN_RID_32BITS_DELTACLR;
330288748Sambrisko		sc = ifp->if_softc;
330388749Sambrisko		sc->areq.an_len = AN_MAX_DATALEN;
330488749Sambrisko		sc->areq.an_type = rid;
330588748Sambrisko
330688749Sambrisko		an_read_record(sc, (struct an_ltv_gen *)&sc->areq);
330788749Sambrisko		l_ioctl->len = sc->areq.an_len - 4;	/* just data */
330888748Sambrisko
3309171692Savatar		AN_UNLOCK(sc);
331088748Sambrisko		/* the data contains the length at first */
3311171692Savatar		error = copyout(&(sc->areq.an_len), l_ioctl->data,
3312171692Savatar			    sizeof(sc->areq.an_len));
3313171692Savatar		if (error) {
3314171692Savatar			AN_LOCK(sc);
331588748Sambrisko			return -EFAULT;
331688748Sambrisko		}
331788748Sambrisko		/* Just copy the data */
3318171692Savatar		error = copyout(&(sc->areq.an_val), l_ioctl->data + 2,
3319171692Savatar			    l_ioctl->len);
3320171692Savatar		AN_LOCK(sc);
3321171692Savatar		if (error)
332288748Sambrisko			return -EFAULT;
332388748Sambrisko		return 0;
332488748Sambrisko		break;
332588748Sambrisko	case AIROPWEPKEY:
332688748Sambrisko		rid = AN_RID_WEP_TEMP;
332788748Sambrisko		break;
332888748Sambrisko	case AIROPWEPKEYNV:
332988748Sambrisko		rid = AN_RID_WEP_PERM;
333088748Sambrisko		break;
333188748Sambrisko	case AIROPLEAPUSR:
333288748Sambrisko		rid = AN_RID_LEAPUSERNAME;
333388748Sambrisko		break;
333488748Sambrisko	case AIROPLEAPPWD:
333588748Sambrisko		rid = AN_RID_LEAPPASSWORD;
333688748Sambrisko		break;
333788748Sambrisko	default:
333888748Sambrisko		return -EOPNOTSUPP;
333988748Sambrisko	}
334088748Sambrisko
334188748Sambrisko	if (rid) {
334288749Sambrisko		if (l_ioctl->len > sizeof(sc->areq.an_val) + 4)
334388748Sambrisko			return -EINVAL;
334488749Sambrisko		sc->areq.an_len = l_ioctl->len + 4;	/* add type & length */
334588749Sambrisko		sc->areq.an_type = rid;
334688748Sambrisko
334788748Sambrisko		/* Just copy the data back */
3348171692Savatar		AN_UNLOCK(sc);
3349171692Savatar		error = copyin((l_ioctl->data) + 2, &sc->areq.an_val,
3350171692Savatar		       l_ioctl->len);
3351171692Savatar		AN_LOCK(sc);
3352171692Savatar		if (error)
3353144242Ssam			return -EFAULT;
3354171692Savatar
335588748Sambrisko		an_cmd(sc, AN_CMD_DISABLE, 0);
335688749Sambrisko		an_write_record(sc, (struct an_ltv_gen *)&sc->areq);
335788748Sambrisko		an_cmd(sc, AN_CMD_ENABLE, 0);
335888748Sambrisko		return 0;
335988748Sambrisko	}
336088748Sambrisko	return -EOPNOTSUPP;
336188748Sambrisko}
336288748Sambrisko
336388748Sambrisko/*
336488748Sambrisko * General Flash utilities derived from Cisco driver additions to Ben Reed's
336588748Sambrisko * Linux driver
336688748Sambrisko */
336788748Sambrisko
3368123978Sambrisko#define FLASH_DELAY(_sc, x)	msleep(ifp, &(_sc)->an_mtx, PZERO, \
3369123978Sambrisko	"flash", ((x) / hz) + 1);
3370108401Sambrisko#define FLASH_COMMAND	0x7e7e
3371108401Sambrisko#define FLASH_SIZE	32 * 1024
337288748Sambrisko
337388748Sambriskostatic int
3374150446Simpunstickbusy(struct ifnet *ifp)
337588748Sambrisko{
337688748Sambrisko	struct an_softc *sc = ifp->if_softc;
337788748Sambrisko
3378108401Sambrisko	if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY) {
3379108401Sambrisko		CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350),
3380108401Sambrisko			    AN_EV_CLR_STUCK_BUSY);
338188748Sambrisko		return 1;
338288748Sambrisko	}
338388748Sambrisko	return 0;
338488748Sambrisko}
338588748Sambrisko
338688748Sambrisko/*
338788748Sambrisko * Wait for busy completion from card wait for delay uSec's Return true for
338888748Sambrisko * success meaning command reg is clear
338988748Sambrisko */
339088748Sambrisko
339188748Sambriskostatic int
3392150446SimpWaitBusy(struct ifnet *ifp, int uSec)
339388748Sambrisko{
339488748Sambrisko	int             statword = 0xffff;
339588748Sambrisko	int             delay = 0;
339688748Sambrisko	struct an_softc *sc = ifp->if_softc;
339788748Sambrisko
339888748Sambrisko	while ((statword & AN_CMD_BUSY) && delay <= (1000 * 100)) {
3399119163Sambrisko		FLASH_DELAY(sc, 10);
340088748Sambrisko		delay += 10;
3401108401Sambrisko		statword = CSR_READ_2(sc, AN_COMMAND(sc->mpi350));
340288748Sambrisko
340388748Sambrisko		if ((AN_CMD_BUSY & statword) && (delay % 200)) {
340488748Sambrisko			unstickbusy(ifp);
340588748Sambrisko		}
340688748Sambrisko	}
340788748Sambrisko
340888748Sambrisko	return 0 == (AN_CMD_BUSY & statword);
340988748Sambrisko}
341088748Sambrisko
341188748Sambrisko/*
341288748Sambrisko * STEP 1) Disable MAC and do soft reset on card.
341388748Sambrisko */
341488748Sambrisko
341588748Sambriskostatic int
3416150446Simpcmdreset(struct ifnet *ifp)
341788748Sambrisko{
341888748Sambrisko	int             status;
341988748Sambrisko	struct an_softc *sc = ifp->if_softc;
342088748Sambrisko
342188748Sambrisko	an_stop(sc);
342288748Sambrisko
342388748Sambrisko	an_cmd(sc, AN_CMD_DISABLE, 0);
342488748Sambrisko
3425108401Sambrisko	if (!(status = WaitBusy(ifp, AN_TIMEOUT))) {
342688748Sambrisko		printf("an%d: Waitbusy hang b4 RESET =%d\n",
342788748Sambrisko		       sc->an_unit, status);
342888748Sambrisko		return -EBUSY;
342988748Sambrisko	}
3430108401Sambrisko	CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), AN_CMD_FW_RESTART);
343188748Sambrisko
3432119163Sambrisko	FLASH_DELAY(sc, 1000);	/* WAS 600 12/7/00 */
343388748Sambrisko
343488748Sambrisko
343588748Sambrisko	if (!(status = WaitBusy(ifp, 100))) {
343688748Sambrisko		printf("an%d: Waitbusy hang AFTER RESET =%d\n",
343788748Sambrisko		       sc->an_unit, status);
343888748Sambrisko		return -EBUSY;
343988748Sambrisko	}
344088748Sambrisko	return 0;
344188748Sambrisko}
344288748Sambrisko
344388748Sambrisko/*
344488748Sambrisko * STEP 2) Put the card in legendary flash mode
344588748Sambrisko */
344688748Sambrisko
344788748Sambriskostatic int
3448150446Simpsetflashmode(struct ifnet *ifp)
344988748Sambrisko{
345088748Sambrisko	int             status;
345188748Sambrisko	struct an_softc *sc = ifp->if_softc;
345288748Sambrisko
3453108401Sambrisko	CSR_WRITE_2(sc, AN_SW0(sc->mpi350), FLASH_COMMAND);
3454108401Sambrisko	CSR_WRITE_2(sc, AN_SW1(sc->mpi350), FLASH_COMMAND);
3455108401Sambrisko	CSR_WRITE_2(sc, AN_SW0(sc->mpi350), FLASH_COMMAND);
3456108401Sambrisko	CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), FLASH_COMMAND);
345788748Sambrisko
345888748Sambrisko	/*
345988748Sambrisko	 * mdelay(500); // 500ms delay
346088748Sambrisko	 */
346188748Sambrisko
3462119163Sambrisko	FLASH_DELAY(sc, 500);
346388748Sambrisko
3464108401Sambrisko	if (!(status = WaitBusy(ifp, AN_TIMEOUT))) {
346588748Sambrisko		printf("Waitbusy hang after setflash mode\n");
346688748Sambrisko		return -EIO;
346788748Sambrisko	}
346888748Sambrisko	return 0;
346988748Sambrisko}
347088748Sambrisko
347188748Sambrisko/*
347288748Sambrisko * Get a character from the card matching matchbyte Step 3)
347388748Sambrisko */
347488748Sambrisko
347588748Sambriskostatic int
3476150446Simpflashgchar(struct ifnet *ifp, int matchbyte, int dwelltime)
347788748Sambrisko{
347888748Sambrisko	int             rchar;
347988748Sambrisko	unsigned char   rbyte = 0;
348088748Sambrisko	int             success = -1;
348188748Sambrisko	struct an_softc *sc = ifp->if_softc;
348288748Sambrisko
348388748Sambrisko
348488748Sambrisko	do {
3485108401Sambrisko		rchar = CSR_READ_2(sc, AN_SW1(sc->mpi350));
348688748Sambrisko
348788748Sambrisko		if (dwelltime && !(0x8000 & rchar)) {
348888748Sambrisko			dwelltime -= 10;
3489119163Sambrisko			FLASH_DELAY(sc, 10);
349088748Sambrisko			continue;
349188748Sambrisko		}
349288748Sambrisko		rbyte = 0xff & rchar;
349388748Sambrisko
349488748Sambrisko		if ((rbyte == matchbyte) && (0x8000 & rchar)) {
3495108401Sambrisko			CSR_WRITE_2(sc, AN_SW1(sc->mpi350), 0);
349688748Sambrisko			success = 1;
349788748Sambrisko			break;
349888748Sambrisko		}
349988748Sambrisko		if (rbyte == 0x81 || rbyte == 0x82 || rbyte == 0x83 || rbyte == 0x1a || 0xffff == rchar)
350088748Sambrisko			break;
3501108401Sambrisko		CSR_WRITE_2(sc, AN_SW1(sc->mpi350), 0);
350288748Sambrisko
350388748Sambrisko	} while (dwelltime > 0);
350488748Sambrisko	return success;
350588748Sambrisko}
350688748Sambrisko
350788748Sambrisko/*
350888748Sambrisko * Put character to SWS0 wait for dwelltime x 50us for  echo .
350988748Sambrisko */
351088748Sambrisko
351188748Sambriskostatic int
3512150446Simpflashpchar(struct ifnet *ifp, int byte, int dwelltime)
351388748Sambrisko{
351488748Sambrisko	int             echo;
351588748Sambrisko	int             pollbusy, waittime;
351688748Sambrisko	struct an_softc *sc = ifp->if_softc;
351788748Sambrisko
351888748Sambrisko	byte |= 0x8000;
351988748Sambrisko
352088748Sambrisko	if (dwelltime == 0)
352188748Sambrisko		dwelltime = 200;
352288748Sambrisko
352388748Sambrisko	waittime = dwelltime;
352488748Sambrisko
352588748Sambrisko	/*
352688748Sambrisko	 * Wait for busy bit d15 to go false indicating buffer empty
352788748Sambrisko	 */
352888748Sambrisko	do {
3529108401Sambrisko		pollbusy = CSR_READ_2(sc, AN_SW0(sc->mpi350));
353088748Sambrisko
353188748Sambrisko		if (pollbusy & 0x8000) {
3532119163Sambrisko			FLASH_DELAY(sc, 50);
353388748Sambrisko			waittime -= 50;
353488748Sambrisko			continue;
353588748Sambrisko		} else
353688748Sambrisko			break;
353788748Sambrisko	}
353888748Sambrisko	while (waittime >= 0);
353988748Sambrisko
354088748Sambrisko	/* timeout for busy clear wait */
354188748Sambrisko
354288748Sambrisko	if (waittime <= 0) {
354388748Sambrisko		printf("an%d: flash putchar busywait timeout! \n",
354488748Sambrisko		       sc->an_unit);
354588748Sambrisko		return -1;
354688748Sambrisko	}
354788748Sambrisko	/*
354888748Sambrisko	 * Port is clear now write byte and wait for it to echo back
354988748Sambrisko	 */
355088748Sambrisko	do {
3551108401Sambrisko		CSR_WRITE_2(sc, AN_SW0(sc->mpi350), byte);
3552119163Sambrisko		FLASH_DELAY(sc, 50);
355388748Sambrisko		dwelltime -= 50;
3554108401Sambrisko		echo = CSR_READ_2(sc, AN_SW1(sc->mpi350));
355588748Sambrisko	} while (dwelltime >= 0 && echo != byte);
355688748Sambrisko
355788748Sambrisko
3558108401Sambrisko	CSR_WRITE_2(sc, AN_SW1(sc->mpi350), 0);
355988748Sambrisko
356088748Sambrisko	return echo == byte;
356188748Sambrisko}
356288748Sambrisko
356388748Sambrisko/*
356488748Sambrisko * Transfer 32k of firmware data from user buffer to our buffer and send to
356588748Sambrisko * the card
356688748Sambrisko */
356788748Sambrisko
356888748Sambriskostatic int
3569150446Simpflashputbuf(struct ifnet *ifp)
357088748Sambrisko{
357188748Sambrisko	unsigned short *bufp;
357288748Sambrisko	int             nwords;
357388748Sambrisko	struct an_softc *sc = ifp->if_softc;
357488748Sambrisko
357588748Sambrisko	/* Write stuff */
357688748Sambrisko
3577108401Sambrisko	bufp = sc->an_flash_buffer;
357888748Sambrisko
3579108401Sambrisko	if (!sc->mpi350) {
3580108401Sambrisko		CSR_WRITE_2(sc, AN_AUX_PAGE, 0x100);
3581108401Sambrisko		CSR_WRITE_2(sc, AN_AUX_OFFSET, 0);
358288748Sambrisko
3583108401Sambrisko		for (nwords = 0; nwords != FLASH_SIZE / 2; nwords++) {
3584108401Sambrisko			CSR_WRITE_2(sc, AN_AUX_DATA, bufp[nwords] & 0xffff);
3585108401Sambrisko		}
3586108401Sambrisko	} else {
3587108401Sambrisko		for (nwords = 0; nwords != FLASH_SIZE / 4; nwords++) {
3588108401Sambrisko			CSR_MEM_AUX_WRITE_4(sc, 0x8000,
3589108401Sambrisko				((u_int32_t *)bufp)[nwords] & 0xffff);
3590108401Sambrisko		}
359188748Sambrisko	}
359288748Sambrisko
3593108401Sambrisko	CSR_WRITE_2(sc, AN_SW0(sc->mpi350), 0x8000);
359488748Sambrisko
359588748Sambrisko	return 0;
359688748Sambrisko}
359788748Sambrisko
359888748Sambrisko/*
359988748Sambrisko * After flashing restart the card.
360088748Sambrisko */
360188748Sambrisko
360288748Sambriskostatic int
3603150446Simpflashrestart(struct ifnet *ifp)
360488748Sambrisko{
360588748Sambrisko	int             status = 0;
360688748Sambrisko	struct an_softc *sc = ifp->if_softc;
360788748Sambrisko
3608119163Sambrisko	FLASH_DELAY(sc, 1024);		/* Added 12/7/00 */
360988748Sambrisko
361088748Sambrisko	an_init(sc);
361188748Sambrisko
3612119163Sambrisko	FLASH_DELAY(sc, 1024);		/* Added 12/7/00 */
361388748Sambrisko	return status;
361488748Sambrisko}
361588748Sambrisko
361688748Sambrisko/*
361788748Sambrisko * Entry point for flash ioclt.
361888748Sambrisko */
361988748Sambrisko
362088748Sambriskostatic int
3621150446Simpflashcard(struct ifnet *ifp, struct aironet_ioctl *l_ioctl)
362288748Sambrisko{
362388749Sambrisko	int             z = 0, status;
362488748Sambrisko	struct an_softc	*sc;
362588748Sambrisko
362688748Sambrisko	sc = ifp->if_softc;
3627108401Sambrisko	if (sc->mpi350) {
3628108401Sambrisko		printf("an%d: flashing not supported on MPI 350 yet\n",
3629108401Sambrisko		       sc->an_unit);
3630108401Sambrisko		return(-1);
3631108401Sambrisko	}
363288748Sambrisko	status = l_ioctl->command;
363388748Sambrisko
363488748Sambrisko	switch (l_ioctl->command) {
363588748Sambrisko	case AIROFLSHRST:
363688748Sambrisko		return cmdreset(ifp);
363788748Sambrisko		break;
363888748Sambrisko	case AIROFLSHSTFL:
3639108401Sambrisko		if (sc->an_flash_buffer) {
3640108401Sambrisko			free(sc->an_flash_buffer, M_DEVBUF);
3641108401Sambrisko			sc->an_flash_buffer = NULL;
3642108401Sambrisko		}
3643111119Simp		sc->an_flash_buffer = malloc(FLASH_SIZE, M_DEVBUF, M_WAITOK);
3644108401Sambrisko		if (sc->an_flash_buffer)
3645108401Sambrisko			return setflashmode(ifp);
3646108401Sambrisko		else
3647108401Sambrisko			return ENOBUFS;
364888748Sambrisko		break;
364988748Sambrisko	case AIROFLSHGCHR:	/* Get char from aux */
3650171692Savatar		AN_UNLOCK(sc);
3651144242Ssam		status = copyin(l_ioctl->data, &sc->areq, l_ioctl->len);
3652171692Savatar		AN_LOCK(sc);
3653144242Ssam		if (status)
3654144242Ssam			return status;
365588749Sambrisko		z = *(int *)&sc->areq;
365688748Sambrisko		if ((status = flashgchar(ifp, z, 8000)) == 1)
365788748Sambrisko			return 0;
365888748Sambrisko		else
365988748Sambrisko			return -1;
366088748Sambrisko	case AIROFLSHPCHR:	/* Send char to card. */
3661171692Savatar		AN_UNLOCK(sc);
3662144242Ssam		status = copyin(l_ioctl->data, &sc->areq, l_ioctl->len);
3663171692Savatar		AN_LOCK(sc);
3664144242Ssam		if (status)
3665144242Ssam			return status;
366688749Sambrisko		z = *(int *)&sc->areq;
366788748Sambrisko		if ((status = flashpchar(ifp, z, 8000)) == -1)
366888748Sambrisko			return -EIO;
366988748Sambrisko		else
367088748Sambrisko			return 0;
367188748Sambrisko		break;
367288748Sambrisko	case AIROFLPUTBUF:	/* Send 32k to card */
3673108401Sambrisko		if (l_ioctl->len > FLASH_SIZE) {
3674108401Sambrisko			printf("an%d: Buffer to big, %x %x\n", sc->an_unit,
3675108401Sambrisko			       l_ioctl->len, FLASH_SIZE);
367688748Sambrisko			return -EINVAL;
367788748Sambrisko		}
3678171692Savatar		AN_UNLOCK(sc);
3679144242Ssam		status = copyin(l_ioctl->data, sc->an_flash_buffer, l_ioctl->len);
3680171692Savatar		AN_LOCK(sc);
3681144242Ssam		if (status)
3682144242Ssam			return status;
368388748Sambrisko
368488748Sambrisko		if ((status = flashputbuf(ifp)) != 0)
368588748Sambrisko			return -EIO;
368688748Sambrisko		else
368788748Sambrisko			return 0;
368888748Sambrisko		break;
368988748Sambrisko	case AIRORESTART:
369088748Sambrisko		if ((status = flashrestart(ifp)) != 0) {
369188748Sambrisko			printf("an%d: FLASHRESTART returned %d\n",
369288748Sambrisko			       sc->an_unit, status);
369388748Sambrisko			return -EIO;
369488748Sambrisko		} else
369588748Sambrisko			return 0;
369688748Sambrisko
369788748Sambrisko		break;
369888748Sambrisko	default:
369988748Sambrisko		return -EINVAL;
370088748Sambrisko	}
370188748Sambrisko
370288748Sambrisko	return -EINVAL;
370388748Sambrisko}
3704