if_wi.c revision 109396
1/*	$NetBSD: wi.c,v 1.109 2003/01/09 08:52:19 dyoung Exp $	*/
2
3/*
4 * Copyright (c) 1997, 1998, 1999
5 *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *	This product includes software developed by Bill Paul.
18 * 4. Neither the name of the author nor the names of any co-contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32 * THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35/*
36 * Lucent WaveLAN/IEEE 802.11 PCMCIA driver.
37 *
38 * Original FreeBSD driver written by Bill Paul <wpaul@ctr.columbia.edu>
39 * Electrical Engineering Department
40 * Columbia University, New York City
41 */
42
43/*
44 * The WaveLAN/IEEE adapter is the second generation of the WaveLAN
45 * from Lucent. Unlike the older cards, the new ones are programmed
46 * entirely via a firmware-driven controller called the Hermes.
47 * Unfortunately, Lucent will not release the Hermes programming manual
48 * without an NDA (if at all). What they do release is an API library
49 * called the HCF (Hardware Control Functions) which is supposed to
50 * do the device-specific operations of a device driver for you. The
51 * publically available version of the HCF library (the 'HCF Light') is
52 * a) extremely gross, b) lacks certain features, particularly support
53 * for 802.11 frames, and c) is contaminated by the GNU Public License.
54 *
55 * This driver does not use the HCF or HCF Light at all. Instead, it
56 * programs the Hermes controller directly, using information gleaned
57 * from the HCF Light code and corresponding documentation.
58 *
59 * This driver supports the ISA, PCMCIA and PCI versions of the Lucent
60 * WaveLan cards (based on the Hermes chipset), as well as the newer
61 * Prism 2 chipsets with firmware from Intersil and Symbol.
62 */
63
64#define WI_HERMES_AUTOINC_WAR	/* Work around data write autoinc bug. */
65#define WI_HERMES_STATS_WAR	/* Work around stats counter bug. */
66
67#define	NBPFILTER	1
68
69#include <sys/param.h>
70#include <sys/systm.h>
71#if __FreeBSD_version >= 500033
72#include <sys/endian.h>
73#endif
74#include <sys/sockio.h>
75#include <sys/mbuf.h>
76#include <sys/proc.h>
77#include <sys/kernel.h>
78#include <sys/socket.h>
79#include <sys/module.h>
80#include <sys/bus.h>
81#include <sys/random.h>
82#include <sys/syslog.h>
83#include <sys/sysctl.h>
84
85#include <machine/bus.h>
86#include <machine/resource.h>
87#include <machine/clock.h>
88#include <sys/rman.h>
89
90#include <net/if.h>
91#include <net/if_arp.h>
92#include <net/ethernet.h>
93#include <net/if_dl.h>
94#include <net/if_media.h>
95#include <net/if_types.h>
96#include <net/if_ieee80211.h>
97
98#include <netinet/in.h>
99#include <netinet/in_systm.h>
100#include <netinet/in_var.h>
101#include <netinet/ip.h>
102#include <netinet/if_ether.h>
103
104#include <net/bpf.h>
105
106#include <dev/wi/if_wavelan_ieee.h>
107#include <dev/wi/if_wivar.h>
108#include <dev/wi/if_wireg.h>
109
110#define IF_POLL(ifq, m)		((m) = (ifq)->ifq_head)
111#define	IFQ_POLL(ifq, m)	IF_POLL((ifq), (m))
112#define IFQ_DEQUEUE(ifq, m)	IF_DEQUEUE((ifq), (m))
113
114#if !defined(lint)
115static const char rcsid[] =
116  "$FreeBSD: head/sys/dev/wi/if_wi.c 109396 2003-01-16 23:38:08Z imp $";
117#endif
118
119static void wi_start(struct ifnet *);
120static int  wi_reset(struct wi_softc *);
121static void wi_watchdog(struct ifnet *);
122static int  wi_ioctl(struct ifnet *, u_long, caddr_t);
123static int  wi_media_change(struct ifnet *);
124static void wi_media_status(struct ifnet *, struct ifmediareq *);
125
126static void wi_rx_intr(struct wi_softc *);
127static void wi_tx_intr(struct wi_softc *);
128static void wi_tx_ex_intr(struct wi_softc *);
129static void wi_info_intr(struct wi_softc *);
130
131static int  wi_get_cfg(struct ifnet *, u_long, caddr_t);
132static int  wi_set_cfg(struct ifnet *, u_long, caddr_t);
133static int  wi_write_txrate(struct wi_softc *);
134static int  wi_write_wep(struct wi_softc *);
135static int  wi_write_multi(struct wi_softc *);
136static int  wi_alloc_fid(struct wi_softc *, int, int *);
137static void wi_read_nicid(struct wi_softc *);
138static int  wi_write_ssid(struct wi_softc *, int, u_int8_t *, int);
139
140static int  wi_cmd(struct wi_softc *, int, int, int, int);
141static int  wi_seek_bap(struct wi_softc *, int, int);
142static int  wi_read_bap(struct wi_softc *, int, int, void *, int);
143static int  wi_write_bap(struct wi_softc *, int, int, void *, int);
144static int  wi_mwrite_bap(struct wi_softc *, int, int, struct mbuf *, int);
145static int  wi_read_rid(struct wi_softc *, int, void *, int *);
146static int  wi_write_rid(struct wi_softc *, int, void *, int);
147
148static int  wi_newstate(void *, enum ieee80211_state);
149
150static int  wi_scan_ap(struct wi_softc *);
151static void wi_scan_result(struct wi_softc *, int, int);
152
153static void wi_dump_pkt(struct wi_frame *, struct ieee80211_node *, int rssi);
154
155static int wi_get_debug(struct wi_softc *, struct wi_req *);
156static int wi_set_debug(struct wi_softc *, struct wi_req *);
157
158#if __FreeBSD_version >= 500000
159/* support to download firmware for symbol CF card */
160static int wi_symbol_write_firm(struct wi_softc *, const void *, int,
161		const void *, int);
162static int wi_symbol_set_hcr(struct wi_softc *, int);
163#endif
164
165static __inline int
166wi_write_val(struct wi_softc *sc, int rid, u_int16_t val)
167{
168
169	val = htole16(val);
170	return wi_write_rid(sc, rid, &val, sizeof(val));
171}
172
173static	struct timeval lasttxerror;	/* time of last tx error msg */
174static	int curtxeps;			/* current tx error msgs/sec */
175static	int wi_txerate = 10;		/* tx error rate: max msgs/sec */
176SYSCTL_INT(_kern, OID_AUTO, wi, CTLFLAG_RW, &wi_txerate,
177	    0, "Wireless driver max tx error msgs/sec; 0 disables msgs");
178
179#define	WI_DEBUG
180#ifdef WI_DEBUG
181static	int wi_debug = 0;
182SYSCTL_INT(_debug, OID_AUTO, wi, CTLFLAG_RW, &wi_debug,
183	    0, "Wireless driver debugging printfs");
184
185#define	DPRINTF(X)	if (wi_debug) printf X
186#define	DPRINTF2(X)	if (wi_debug > 1) printf X
187#define	IFF_DUMPPKTS(_ifp) \
188	(((_ifp)->if_flags & (IFF_DEBUG|IFF_LINK2)) == (IFF_DEBUG|IFF_LINK2))
189#else
190#define	DPRINTF(X)
191#define	DPRINTF2(X)
192#define	IFF_DUMPPKTS(_ifp)	0
193#endif
194
195#define WI_INTRS	(WI_EV_RX | WI_EV_ALLOC | WI_EV_INFO)
196
197struct wi_card_ident wi_card_ident[] = {
198	/* CARD_ID			CARD_NAME		FIRM_TYPE */
199	{ WI_NIC_LUCENT_ID,		WI_NIC_LUCENT_STR,	WI_LUCENT },
200	{ WI_NIC_SONY_ID,		WI_NIC_SONY_STR,	WI_LUCENT },
201	{ WI_NIC_LUCENT_EMB_ID,		WI_NIC_LUCENT_EMB_STR,	WI_LUCENT },
202	{ WI_NIC_EVB2_ID,		WI_NIC_EVB2_STR,	WI_INTERSIL },
203	{ WI_NIC_HWB3763_ID,		WI_NIC_HWB3763_STR,	WI_INTERSIL },
204	{ WI_NIC_HWB3163_ID,		WI_NIC_HWB3163_STR,	WI_INTERSIL },
205	{ WI_NIC_HWB3163B_ID,		WI_NIC_HWB3163B_STR,	WI_INTERSIL },
206	{ WI_NIC_EVB3_ID,		WI_NIC_EVB3_STR,	WI_INTERSIL },
207	{ WI_NIC_HWB1153_ID,		WI_NIC_HWB1153_STR,	WI_INTERSIL },
208	{ WI_NIC_P2_SST_ID,		WI_NIC_P2_SST_STR,	WI_INTERSIL },
209	{ WI_NIC_EVB2_SST_ID,		WI_NIC_EVB2_SST_STR,	WI_INTERSIL },
210	{ WI_NIC_3842_EVA_ID,		WI_NIC_3842_EVA_STR,	WI_INTERSIL },
211	{ WI_NIC_3842_PCMCIA_AMD_ID,	WI_NIC_3842_PCMCIA_STR,	WI_INTERSIL },
212	{ WI_NIC_3842_PCMCIA_SST_ID,	WI_NIC_3842_PCMCIA_STR,	WI_INTERSIL },
213	{ WI_NIC_3842_PCMCIA_ATL_ID,	WI_NIC_3842_PCMCIA_STR,	WI_INTERSIL },
214	{ WI_NIC_3842_PCMCIA_ATS_ID,	WI_NIC_3842_PCMCIA_STR,	WI_INTERSIL },
215	{ WI_NIC_3842_MINI_AMD_ID,	WI_NIC_3842_MINI_STR,	WI_INTERSIL },
216	{ WI_NIC_3842_MINI_SST_ID,	WI_NIC_3842_MINI_STR,	WI_INTERSIL },
217	{ WI_NIC_3842_MINI_ATL_ID,	WI_NIC_3842_MINI_STR,	WI_INTERSIL },
218	{ WI_NIC_3842_MINI_ATS_ID,	WI_NIC_3842_MINI_STR,	WI_INTERSIL },
219	{ WI_NIC_3842_PCI_AMD_ID,	WI_NIC_3842_PCI_STR,	WI_INTERSIL },
220	{ WI_NIC_3842_PCI_SST_ID,	WI_NIC_3842_PCI_STR,	WI_INTERSIL },
221	{ WI_NIC_3842_PCI_ATS_ID,	WI_NIC_3842_PCI_STR,	WI_INTERSIL },
222	{ WI_NIC_3842_PCI_ATL_ID,	WI_NIC_3842_PCI_STR,	WI_INTERSIL },
223	{ WI_NIC_P3_PCMCIA_AMD_ID,	WI_NIC_P3_PCMCIA_STR,	WI_INTERSIL },
224	{ WI_NIC_P3_PCMCIA_SST_ID,	WI_NIC_P3_PCMCIA_STR,	WI_INTERSIL },
225	{ WI_NIC_P3_PCMCIA_ATL_ID,	WI_NIC_P3_PCMCIA_STR,	WI_INTERSIL },
226	{ WI_NIC_P3_PCMCIA_ATS_ID,	WI_NIC_P3_PCMCIA_STR,	WI_INTERSIL },
227	{ WI_NIC_P3_MINI_AMD_ID,	WI_NIC_P3_MINI_STR,	WI_INTERSIL },
228	{ WI_NIC_P3_MINI_SST_ID,	WI_NIC_P3_MINI_STR,	WI_INTERSIL },
229	{ WI_NIC_P3_MINI_ATL_ID,	WI_NIC_P3_MINI_STR,	WI_INTERSIL },
230	{ WI_NIC_P3_MINI_ATS_ID,	WI_NIC_P3_MINI_STR,	WI_INTERSIL },
231	{ 0,	NULL,	0 },
232};
233
234devclass_t wi_devclass;
235
236int
237wi_attach(device_t dev)
238{
239	struct wi_softc	*sc = device_get_softc(dev);
240	struct ieee80211com *ic = &sc->sc_ic;
241	struct ifnet *ifp = &ic->ic_if;
242	int i, nrate, mword, buflen;
243	u_int8_t r;
244	u_int16_t val;
245	u_int8_t ratebuf[2 + IEEE80211_RATE_SIZE];
246	static const u_int8_t empty_macaddr[IEEE80211_ADDR_LEN] = {
247		0x00, 0x00, 0x00, 0x00, 0x00, 0x00
248	};
249	int error;
250
251	/*
252	 * NB: no locking is needed here; don't put it here
253	 *     unless you can prove it!
254	 */
255	error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET,
256	    wi_intr, sc, &sc->wi_intrhand);
257
258	if (error) {
259		device_printf(dev, "bus_setup_intr() failed! (%d)\n", error);
260		wi_free(dev);
261		return (error);
262	}
263
264#if __FreeBSD_version >= 500000
265	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
266	    MTX_DEF | MTX_RECURSE);
267#endif
268
269	/* Reset the NIC. */
270	if (wi_reset(sc) != 0) {
271		WI_UNLOCK(sc);
272		return ENXIO;		/* XXX */
273	}
274
275	/*
276	 * Read the station address.
277	 * And do it twice. I've seen PRISM-based cards that return
278	 * an error when trying to read it the first time, which causes
279	 * the probe to fail.
280	 */
281	buflen = IEEE80211_ADDR_LEN;
282	error = wi_read_rid(sc, WI_RID_MAC_NODE, ic->ic_myaddr, &buflen);
283	if (error != 0) {
284		buflen = IEEE80211_ADDR_LEN;
285		error = wi_read_rid(sc, WI_RID_MAC_NODE, ic->ic_myaddr, &buflen);
286	}
287	if (error || IEEE80211_ADDR_EQ(ic->ic_myaddr, empty_macaddr)) {
288		if (error != 0)
289			device_printf(dev, "mac read failed %d\n", error);
290		else
291			device_printf(dev, "mac read failed (all zeros)\n");
292		wi_free(dev);
293		return (error);
294	}
295	device_printf(dev, "802.11 address: %6D\n", ic->ic_myaddr, ":");
296
297	/* Read NIC identification */
298	wi_read_nicid(sc);
299
300	ifp->if_softc = sc;
301	ifp->if_unit = sc->sc_unit;
302	ifp->if_name = "wi";
303	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
304	ifp->if_ioctl = wi_ioctl;
305	ifp->if_start = wi_start;
306	ifp->if_watchdog = wi_watchdog;
307	ifp->if_init = wi_init;
308	ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
309
310	ic->ic_phytype = IEEE80211_T_DS;
311	ic->ic_opmode = IEEE80211_M_STA;
312	ic->ic_flags = IEEE80211_F_HASPMGT | IEEE80211_F_HASAHDEMO;
313	ic->ic_state = IEEE80211_S_INIT;
314	ic->ic_newstate = wi_newstate;
315
316	/* Find available channels */
317	buflen = sizeof(val);
318	if (wi_read_rid(sc, WI_RID_CHANNEL_LIST, &val, &buflen) != 0)
319		val = htole16(0x1fff);	/* assume 1-11 */
320	for (i = 0; i < 16; i++) {
321		if (isset((u_int8_t*)&val, i))
322			setbit(ic->ic_chan_avail, i + 1);
323	}
324	KASSERT(ic->ic_chan_avail != 0,
325		("wi_attach: no available channels listed!"));
326
327	/*
328	 * Read the default channel from the NIC. This may vary
329	 * depending on the country where the NIC was purchased, so
330	 * we can't hard-code a default and expect it to work for
331	 * everyone.
332	 */
333	buflen = sizeof(val);
334	if (wi_read_rid(sc, WI_RID_OWN_CHNL, &val, &buflen) == 0)
335		ic->ic_ibss_chan = le16toh(val);
336	else {
337		/* use lowest available channel */
338		for (i = 0; i < 16 && !isset(ic->ic_chan_avail, i); i++)
339			;
340		ic->ic_ibss_chan = i;
341	}
342
343	/*
344	 * Set flags based on firmware version.
345	 */
346	switch (sc->sc_firmware_type) {
347	case WI_LUCENT:
348		sc->sc_flags |= WI_FLAGS_HAS_SYSSCALE;
349#ifdef WI_HERMES_AUTOINC_WAR
350		/* XXX: not confirmed, but never seen for recent firmware */
351		if (sc->sc_sta_firmware_ver <  40000) {
352			sc->sc_flags |= WI_FLAGS_BUG_AUTOINC;
353		}
354#endif
355		if (sc->sc_sta_firmware_ver >= 60000)
356			sc->sc_flags |= WI_FLAGS_HAS_MOR;
357		if (sc->sc_sta_firmware_ver >= 60006)
358			ic->ic_flags |= IEEE80211_F_HASIBSS;
359		sc->sc_ibss_port = htole16(1);
360		break;
361
362	case WI_INTERSIL:
363		sc->sc_flags |= WI_FLAGS_HAS_FRAGTHR;
364		sc->sc_flags |= WI_FLAGS_HAS_ROAMING;
365		sc->sc_flags |= WI_FLAGS_HAS_SYSSCALE;
366		if (sc->sc_sta_firmware_ver > 10101)
367			sc->sc_flags |= WI_FLAGS_HAS_DBMADJUST;
368		if (sc->sc_sta_firmware_ver >= 800)
369			ic->ic_flags |= IEEE80211_F_HASIBSS;
370		/*
371		 * version 0.8.3 and newer are the only ones that are known
372		 * to currently work.  Earlier versions can be made to work,
373		 * at least according to the Linux driver.
374		 */
375		if (sc->sc_sta_firmware_ver >= 803)
376			ic->ic_flags |= IEEE80211_F_HASHOSTAP;
377		sc->sc_ibss_port = htole16(0);
378		break;
379
380	case WI_SYMBOL:
381		sc->sc_flags |= WI_FLAGS_HAS_DIVERSITY;
382		if (sc->sc_sta_firmware_ver >= 25000)
383			ic->ic_flags |= IEEE80211_F_HASIBSS;
384		sc->sc_ibss_port = htole16(4);
385		break;
386	}
387
388	/*
389	 * Find out if we support WEP on this card.
390	 */
391	buflen = sizeof(val);
392	if (wi_read_rid(sc, WI_RID_WEP_AVAIL, &val, &buflen) == 0 &&
393	    val != htole16(0))
394		ic->ic_flags |= IEEE80211_F_HASWEP;
395
396	/* Find supported rates. */
397	buflen = sizeof(ratebuf);
398	if (wi_read_rid(sc, WI_RID_DATA_RATES, ratebuf, &buflen) == 0) {
399		nrate = le16toh(*(u_int16_t *)ratebuf);
400		if (nrate > IEEE80211_RATE_SIZE)
401			nrate = IEEE80211_RATE_SIZE;
402		memcpy(ic->ic_sup_rates, ratebuf + 2, nrate);
403	} else {
404		/* XXX fallback on error? */
405		nrate = 0;
406	}
407
408	buflen = sizeof(val);
409	if ((sc->sc_flags & WI_FLAGS_HAS_DBMADJUST) &&
410	    wi_read_rid(sc, WI_RID_DBM_ADJUST, &val, &buflen) == 0) {
411		sc->sc_dbm_adjust = le16toh(val);
412	} else
413		sc->sc_dbm_adjust = 100;	/* default */
414
415	sc->sc_max_datalen = 2304;
416	sc->sc_rts_thresh = 2347;
417	sc->sc_frag_thresh = 2346;
418	sc->sc_system_scale = 1;
419	sc->sc_cnfauthmode = IEEE80211_AUTH_OPEN;
420	sc->sc_roaming_mode = 1;
421
422	sc->sc_portnum = WI_DEFAULT_PORT;
423	sc->sc_authtype = WI_DEFAULT_AUTHTYPE;
424
425	bzero(sc->sc_nodename, sizeof(sc->sc_nodename));
426	sc->sc_nodelen = sizeof(WI_DEFAULT_NODENAME) - 1;
427	bcopy(WI_DEFAULT_NODENAME, sc->sc_nodename, sc->sc_nodelen);
428
429	bzero(sc->sc_net_name, sizeof(sc->sc_net_name));
430	bcopy(WI_DEFAULT_NETNAME, sc->sc_net_name,
431	    sizeof(WI_DEFAULT_NETNAME) - 1);
432
433	ifmedia_init(&sc->sc_media, 0, wi_media_change, wi_media_status);
434	if_printf(ifp, "supported rates: ");
435#define	ADD(s, o)	ifmedia_add(&sc->sc_media, \
436	IFM_MAKEWORD(IFM_IEEE80211, (s), (o), 0), 0, NULL)
437	ADD(IFM_AUTO, 0);
438	if (ic->ic_flags & IEEE80211_F_HASHOSTAP)
439		ADD(IFM_AUTO, IFM_IEEE80211_HOSTAP);
440	if (ic->ic_flags & IEEE80211_F_HASIBSS)
441		ADD(IFM_AUTO, IFM_IEEE80211_ADHOC);
442	ADD(IFM_AUTO, IFM_IEEE80211_ADHOC | IFM_FLAG0);
443	for (i = 0; i < nrate; i++) {
444		r = ic->ic_sup_rates[i];
445		mword = ieee80211_rate2media(r, IEEE80211_T_DS);
446		if (mword == 0)
447			continue;
448		printf("%s%d%sMbps", (i != 0 ? " " : ""),
449		    (r & IEEE80211_RATE_VAL) / 2, ((r & 0x1) != 0 ? ".5" : ""));
450		ADD(mword, 0);
451		if (ic->ic_flags & IEEE80211_F_HASHOSTAP)
452			ADD(mword, IFM_IEEE80211_HOSTAP);
453		if (ic->ic_flags & IEEE80211_F_HASIBSS)
454			ADD(mword, IFM_IEEE80211_ADHOC);
455		ADD(mword, IFM_IEEE80211_ADHOC | IFM_FLAG0);
456	}
457	printf("\n");
458	ifmedia_set(&sc->sc_media, IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0));
459#undef ADD
460
461	/*
462	 * Call MI attach routine.
463	 */
464	ieee80211_ifattach(ifp);
465
466	return (0);
467}
468
469int
470wi_detach(device_t dev)
471{
472	struct wi_softc	*sc = device_get_softc(dev);
473	struct ifnet *ifp = &sc->sc_ic.ic_if;
474	WI_LOCK_DECL();
475
476	WI_LOCK(sc);
477
478	/* check if device was removed */
479	sc->wi_gone = !bus_child_present(dev);
480
481	wi_stop(ifp, 0);
482
483	/* Delete all remaining media. */
484	ifmedia_removeall(&sc->sc_media);
485
486	ieee80211_ifdetach(ifp);
487	bus_teardown_intr(dev, sc->irq, sc->wi_intrhand);
488	wi_free(dev);
489
490	WI_UNLOCK(sc);
491#if __FreeBSD_version >= 500000
492	mtx_destroy(&sc->sc_mtx);
493#endif
494	return (0);
495}
496
497#ifdef __NetBSD__
498int
499wi_activate(struct device *self, enum devact act)
500{
501	struct wi_softc *sc = (struct wi_softc *)self;
502	int rv = 0, s;
503
504	s = splnet();
505	switch (act) {
506	case DVACT_ACTIVATE:
507		rv = EOPNOTSUPP;
508		break;
509
510	case DVACT_DEACTIVATE:
511		if_deactivate(&sc->sc_ic.ic_if);
512		break;
513	}
514	splx(s);
515	return rv;
516}
517
518void
519wi_power(struct wi_softc *sc, int why)
520{
521	struct ifnet *ifp = &sc->sc_ic.ic_if;
522	int s;
523
524	s = splnet();
525	switch (why) {
526	case PWR_SUSPEND:
527	case PWR_STANDBY:
528		wi_stop(ifp, 1);
529		break;
530	case PWR_RESUME:
531		if (ifp->if_flags & IFF_UP) {
532			wi_init(ifp);
533			(void)wi_intr(sc);
534		}
535		break;
536	case PWR_SOFTSUSPEND:
537	case PWR_SOFTSTANDBY:
538	case PWR_SOFTRESUME:
539		break;
540	}
541	splx(s);
542}
543#endif /* __NetBSD__ */
544
545void
546wi_shutdown(device_t dev)
547{
548	struct wi_softc *sc = device_get_softc(dev);
549
550	wi_stop(&sc->sc_if, 1);
551}
552
553void
554wi_intr(void *arg)
555{
556	int i;
557	struct wi_softc *sc = arg;
558	struct ifnet *ifp = &sc->sc_ic.ic_if;
559	u_int16_t status, raw_status, last_status;
560	WI_LOCK_DECL();
561
562	WI_LOCK(sc);
563
564	if (sc->wi_gone || (ifp->if_flags & IFF_UP) == 0) {
565		CSR_WRITE_2(sc, WI_EVENT_ACK, ~0);
566		CSR_WRITE_2(sc, WI_INT_EN, 0);
567		WI_UNLOCK(sc);
568		return;
569	}
570
571	/* maximum 10 loops per interrupt */
572	last_status = 0;
573	for (i = 0; i < 10; i++) {
574		/*
575		 * Only believe a status bit when we enter wi_intr, or when
576		 * the bit was "off" the last time through the loop. This is
577		 * my strategy to avoid racing the hardware/firmware if I
578		 * can re-read the event status register more quickly than
579		 * it is updated.
580		 */
581		raw_status = CSR_READ_2(sc, WI_EVENT_STAT);
582		status = raw_status & ~last_status;
583		if ((status & WI_INTRS) == 0)
584			break;
585		last_status = raw_status;
586
587		if (status & WI_EV_RX)
588			wi_rx_intr(sc);
589
590		if (status & WI_EV_ALLOC)
591			wi_tx_intr(sc);
592
593		if (status & WI_EV_TX_EXC)
594			wi_tx_ex_intr(sc);
595
596		if (status & WI_EV_INFO)
597			wi_info_intr(sc);
598
599		if ((ifp->if_flags & IFF_OACTIVE) == 0 &&
600		    (sc->sc_flags & WI_FLAGS_OUTRANGE) == 0 &&
601		    _IF_QLEN(&ifp->if_snd) != 0)
602			wi_start(ifp);
603	}
604
605	WI_UNLOCK(sc);
606
607	return;
608}
609
610void
611wi_init(void *arg)
612{
613	struct wi_softc *sc = arg;
614	struct ifnet *ifp = &sc->sc_if;
615	struct ieee80211com *ic = &sc->sc_ic;
616	struct wi_joinreq join;
617	int i;
618	int error = 0, wasenabled;
619	struct ifaddr *ifa;
620	struct sockaddr_dl *sdl;
621	WI_LOCK_DECL();
622
623	WI_LOCK(sc);
624
625	if (sc->wi_gone) {
626		WI_UNLOCK(sc);
627		return;
628	}
629
630	wasenabled = sc->sc_enabled;
631	if (!sc->sc_enabled) {
632		sc->sc_enabled = 1;
633	} else
634		wi_stop(ifp, 0);
635
636	/* Symbol firmware cannot be initialized more than once */
637	if (sc->sc_firmware_type != WI_SYMBOL || !wasenabled)
638		wi_reset(sc);
639
640	/* common 802.11 configuration */
641	ic->ic_flags &= ~IEEE80211_F_IBSSON;
642	sc->sc_flags &= ~WI_FLAGS_OUTRANGE;
643	switch (ic->ic_opmode) {
644	case IEEE80211_M_STA:
645		wi_write_val(sc, WI_RID_PORTTYPE, WI_PORTTYPE_BSS);
646		break;
647	case IEEE80211_M_IBSS:
648		wi_write_val(sc, WI_RID_PORTTYPE, sc->sc_ibss_port);
649		ic->ic_flags |= IEEE80211_F_IBSSON;
650		break;
651	case IEEE80211_M_AHDEMO:
652		wi_write_val(sc, WI_RID_PORTTYPE, WI_PORTTYPE_ADHOC);
653		break;
654	case IEEE80211_M_HOSTAP:
655		wi_write_val(sc, WI_RID_PORTTYPE, WI_PORTTYPE_HOSTAP);
656		break;
657	}
658
659	/* Intersil interprets this RID as joining ESS even in IBSS mode */
660	if (sc->sc_firmware_type == WI_LUCENT &&
661	    (ic->ic_flags & IEEE80211_F_IBSSON) && ic->ic_des_esslen > 0)
662		wi_write_val(sc, WI_RID_CREATE_IBSS, 1);
663	else
664		wi_write_val(sc, WI_RID_CREATE_IBSS, 0);
665	wi_write_val(sc, WI_RID_MAX_SLEEP, ic->ic_lintval);
666	wi_write_ssid(sc, WI_RID_DESIRED_SSID, ic->ic_des_essid,
667	    ic->ic_des_esslen);
668	wi_write_val(sc, WI_RID_OWN_CHNL, ic->ic_ibss_chan);
669	wi_write_ssid(sc, WI_RID_OWN_SSID, ic->ic_des_essid, ic->ic_des_esslen);
670
671	ifa = ifaddr_byindex(ifp->if_index);
672	sdl = (struct sockaddr_dl *) ifa->ifa_addr;
673	IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(sdl));
674	wi_write_rid(sc, WI_RID_MAC_NODE, ic->ic_myaddr, IEEE80211_ADDR_LEN);
675
676	wi_write_val(sc, WI_RID_PM_ENABLED,
677	    (ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0);
678
679	/* not yet common 802.11 configuration */
680	wi_write_val(sc, WI_RID_MAX_DATALEN, sc->sc_max_datalen);
681	wi_write_val(sc, WI_RID_RTS_THRESH, sc->sc_rts_thresh);
682	if (sc->sc_flags & WI_FLAGS_HAS_FRAGTHR)
683		wi_write_val(sc, WI_RID_FRAG_THRESH, sc->sc_frag_thresh);
684
685	/* driver specific 802.11 configuration */
686	if (sc->sc_flags & WI_FLAGS_HAS_SYSSCALE)
687		wi_write_val(sc, WI_RID_SYSTEM_SCALE, sc->sc_system_scale);
688	if (sc->sc_flags & WI_FLAGS_HAS_ROAMING)
689		wi_write_val(sc, WI_RID_ROAMING_MODE, sc->sc_roaming_mode);
690	if (sc->sc_flags & WI_FLAGS_HAS_MOR)
691		wi_write_val(sc, WI_RID_MICROWAVE_OVEN, sc->sc_microwave_oven);
692	wi_write_txrate(sc);
693	wi_write_ssid(sc, WI_RID_NODENAME, sc->sc_nodename, sc->sc_nodelen);
694
695	if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
696	    sc->sc_firmware_type == WI_INTERSIL) {
697		wi_write_val(sc, WI_RID_OWN_BEACON_INT, ic->ic_lintval);
698		wi_write_val(sc, WI_RID_BASIC_RATE, 0x03);   /* 1, 2 */
699		wi_write_val(sc, WI_RID_SUPPORT_RATE, 0x0f); /* 1, 2, 5.5, 11 */
700		wi_write_val(sc, WI_RID_DTIM_PERIOD, 1);
701	}
702
703	/*
704	 * Initialize promisc mode.
705	 *	Being in the Host-AP mode causes a great
706	 *	deal of pain if primisc mode is set.
707	 *	Therefore we avoid confusing the firmware
708	 *	and always reset promisc mode in Host-AP
709	 *	mode.  Host-AP sees all the packets anyway.
710	 */
711	if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
712	    (ifp->if_flags & IFF_PROMISC) != 0) {
713		wi_write_val(sc, WI_RID_PROMISC, 1);
714	} else {
715		wi_write_val(sc, WI_RID_PROMISC, 0);
716	}
717
718	/* Configure WEP. */
719	if (ic->ic_flags & IEEE80211_F_HASWEP)
720		wi_write_wep(sc);
721
722	/* Set multicast filter. */
723	wi_write_multi(sc);
724
725	if (sc->sc_firmware_type != WI_SYMBOL || !wasenabled) {
726		sc->sc_buflen = IEEE80211_MAX_LEN + sizeof(struct wi_frame);
727		if (sc->sc_firmware_type == WI_SYMBOL)
728			sc->sc_buflen = 1585;	/* XXX */
729		for (i = 0; i < WI_NTXBUF; i++) {
730			error = wi_alloc_fid(sc, sc->sc_buflen,
731			    &sc->sc_txd[i].d_fid);
732			if (error) {
733				device_printf(sc->sc_dev,
734				    "tx buffer allocation failed (error %u)\n",
735				    error);
736				goto out;
737			}
738			sc->sc_txd[i].d_len = 0;
739		}
740	}
741	sc->sc_txcur = sc->sc_txnext = 0;
742
743	/* Enable desired port */
744	wi_cmd(sc, WI_CMD_ENABLE | sc->sc_portnum, 0, 0, 0);
745
746	ifp->if_flags |= IFF_RUNNING;
747	ifp->if_flags &= ~IFF_OACTIVE;
748	if (ic->ic_opmode == IEEE80211_M_AHDEMO ||
749	    ic->ic_opmode == IEEE80211_M_HOSTAP)
750		wi_newstate(sc, IEEE80211_S_RUN);
751
752	/* Enable interrupts */
753	CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
754
755	if (!wasenabled &&
756	    ic->ic_opmode == IEEE80211_M_HOSTAP &&
757	    sc->sc_firmware_type == WI_INTERSIL) {
758		/* XXX: some card need to be re-enabled for hostap */
759		wi_cmd(sc, WI_CMD_DISABLE | WI_PORT0, 0, 0, 0);
760		wi_cmd(sc, WI_CMD_ENABLE | WI_PORT0, 0, 0, 0);
761	}
762
763	if (ic->ic_opmode == IEEE80211_M_STA &&
764	    ((ic->ic_flags & IEEE80211_F_DESBSSID) ||
765	    ic->ic_des_chan != IEEE80211_CHAN_ANY)) {
766		memset(&join, 0, sizeof(join));
767		if (ic->ic_flags & IEEE80211_F_DESBSSID)
768			IEEE80211_ADDR_COPY(&join.wi_bssid, ic->ic_des_bssid);
769		if (ic->ic_des_chan != IEEE80211_CHAN_ANY)
770			join.wi_chan = htole16(ic->ic_des_chan);
771		/* Lucent firmware does not support the JOIN RID. */
772		if (sc->sc_firmware_type != WI_LUCENT)
773			wi_write_rid(sc, WI_RID_JOIN_REQ, &join, sizeof(join));
774	}
775
776	WI_UNLOCK(sc);
777	return;
778out:
779	if (error) {
780		if_printf(ifp, "interface not running\n");
781		wi_stop(ifp, 0);
782	}
783	DPRINTF(("wi_init: return %d\n", error));
784	return;
785}
786
787void
788wi_stop(struct ifnet *ifp, int disable)
789{
790	struct wi_softc *sc = ifp->if_softc;
791	WI_LOCK_DECL();
792
793	WI_LOCK(sc);
794
795	ieee80211_new_state(ifp, IEEE80211_S_INIT, -1);
796	if (sc->sc_enabled && !sc->wi_gone) {
797		CSR_WRITE_2(sc, WI_INT_EN, 0);
798		wi_cmd(sc, WI_CMD_DISABLE | sc->sc_portnum, 0, 0, 0);
799		if (disable) {
800#ifdef __NetBSD__
801			if (sc->sc_disable)
802				(*sc->sc_disable)(sc);
803#endif
804			sc->sc_enabled = 0;
805		}
806	}
807
808	sc->sc_tx_timer = 0;
809	sc->sc_scan_timer = 0;
810	sc->sc_syn_timer = 0;
811	sc->sc_false_syns = 0;
812	sc->sc_naps = 0;
813	ifp->if_flags &= ~(IFF_OACTIVE | IFF_RUNNING);
814	ifp->if_timer = 0;
815
816	WI_UNLOCK(sc);
817}
818
819static void
820wi_start(struct ifnet *ifp)
821{
822	struct wi_softc	*sc = ifp->if_softc;
823	struct ieee80211com *ic = &sc->sc_ic;
824	struct ieee80211_node *ni = NULL;
825	struct ieee80211_frame *wh;
826	struct mbuf *m0;
827	struct wi_frame frmhdr;
828	int cur, fid, off;
829	WI_LOCK_DECL();
830
831	WI_LOCK(sc);
832
833	if (sc->wi_gone) {
834		WI_UNLOCK(sc);
835		return;
836	}
837	if (sc->sc_flags & WI_FLAGS_OUTRANGE) {
838		WI_UNLOCK(sc);
839		return;
840	}
841	KASSERT((ifp->if_flags & IFF_OACTIVE) == 0,
842		("wi_start: if_flags %x\n", ifp->if_flags));
843
844	memset(&frmhdr, 0, sizeof(frmhdr));
845	cur = sc->sc_txnext;
846	for (;;) {
847		IF_POLL(&ic->ic_mgtq, m0);
848		if (m0 != NULL) {
849			if (sc->sc_txd[cur].d_len != 0) {
850				ifp->if_flags |= IFF_OACTIVE;
851				break;
852			}
853			IF_DEQUEUE(&ic->ic_mgtq, m0);
854			m_copydata(m0, 4, ETHER_ADDR_LEN * 2,
855			    (caddr_t)&frmhdr.wi_ehdr);
856			frmhdr.wi_ehdr.ether_type = 0;
857                        wh = mtod(m0, struct ieee80211_frame *);
858		} else {
859			if (ic->ic_state != IEEE80211_S_RUN)
860				break;
861			IFQ_POLL(&ifp->if_snd, m0);
862			if (m0 == NULL)
863				break;
864			if (sc->sc_txd[cur].d_len != 0) {
865				ifp->if_flags |= IFF_OACTIVE;
866				break;
867			}
868			IFQ_DEQUEUE(&ifp->if_snd, m0);
869			ifp->if_opackets++;
870			m_copydata(m0, 0, ETHER_HDR_LEN,
871			    (caddr_t)&frmhdr.wi_ehdr);
872#if NBPFILTER > 0
873			BPF_MTAP(ifp, m0);
874#endif
875
876			if ((m0 = ieee80211_encap(ifp, m0)) == NULL) {
877				ifp->if_oerrors++;
878				continue;
879			}
880                        wh = mtod(m0, struct ieee80211_frame *);
881			if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
882			    !IEEE80211_IS_MULTICAST(wh->i_addr1) &&
883			    (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
884			    IEEE80211_FC0_TYPE_DATA &&
885			    ((ni = ieee80211_find_node(ic, wh->i_addr1)) ==
886			    NULL || ni->ni_associd == 0)) {
887				m_freem(m0);
888				ifp->if_oerrors++;
889				continue;
890			}
891			if (ic->ic_flags & IEEE80211_F_WEPON)
892				wh->i_fc[1] |= IEEE80211_FC1_WEP;
893
894		}
895#if NBPFILTER > 0
896		if (ic->ic_rawbpf)
897			bpf_mtap(ic->ic_rawbpf, m0);
898#endif
899		frmhdr.wi_tx_ctl = htole16(WI_ENC_TX_802_11|WI_TXCNTL_TX_EX);
900		if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
901		    (wh->i_fc[1] & IEEE80211_FC1_WEP)) {
902			if ((m0 = ieee80211_wep_crypt(ifp, m0, 1)) == NULL) {
903				ifp->if_oerrors++;
904				continue;
905			}
906			frmhdr.wi_tx_ctl |= htole16(WI_TXCNTL_NOCRYPT);
907		}
908		m_copydata(m0, 0, sizeof(struct ieee80211_frame),
909		    (caddr_t)&frmhdr.wi_whdr);
910		m_adj(m0, sizeof(struct ieee80211_frame));
911		frmhdr.wi_dat_len = htole16(m0->m_pkthdr.len);
912#if NBPFILTER > 0
913		if (sc->sc_drvbpf) {
914			struct mbuf *mb;
915
916			MGETHDR(mb, M_DONTWAIT, m0->m_type);
917			if (mb != NULL) {
918				(void) m_dup_pkthdr(mb, m0, M_DONTWAIT);
919				mb->m_next = m0;
920				mb->m_data = (caddr_t)&frmhdr;
921				mb->m_len = sizeof(frmhdr);
922				mb->m_pkthdr.len += mb->m_len;
923				bpf_mtap(sc->sc_drvbpf, mb);
924				m_free(mb);
925			}
926		}
927#endif
928		if (IFF_DUMPPKTS(ifp))
929			wi_dump_pkt(&frmhdr, ni, -1);
930		fid = sc->sc_txd[cur].d_fid;
931		off = sizeof(frmhdr);
932		if (wi_write_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr)) != 0 ||
933		    wi_mwrite_bap(sc, fid, off, m0, m0->m_pkthdr.len) != 0) {
934			ifp->if_oerrors++;
935			m_freem(m0);
936			continue;
937		}
938		m_freem(m0);
939		sc->sc_txd[cur].d_len = off;
940		if (sc->sc_txcur == cur) {
941			if (wi_cmd(sc, WI_CMD_TX | WI_RECLAIM, fid, 0, 0)) {
942				if_printf(ifp, "xmit failed\n");
943				sc->sc_txd[cur].d_len = 0;
944				continue;
945			}
946			sc->sc_tx_timer = 5;
947			ifp->if_timer = 1;
948		}
949		sc->sc_txnext = cur = (cur + 1) % WI_NTXBUF;
950	}
951
952	WI_UNLOCK(sc);
953}
954
955static int
956wi_reset(struct wi_softc *sc)
957{
958#define WI_INIT_TRIES 5
959	int i, error;
960
961	for (i = 0; i < WI_INIT_TRIES; i++) {
962		if ((error = wi_cmd(sc, WI_CMD_INI, 0, 0, 0)) == 0)
963			break;
964		DELAY(WI_DELAY * 1000);
965	}
966
967	if (error) {
968		device_printf(sc->sc_dev, "init failed\n");
969		return error;
970	}
971
972	CSR_WRITE_2(sc, WI_INT_EN, 0);
973	CSR_WRITE_2(sc, WI_EVENT_ACK, ~0);
974
975	/* Calibrate timer. */
976	wi_write_val(sc, WI_RID_TICK_TIME, 0);
977	return 0;
978#undef WI_INIT_TRIES
979}
980
981static void
982wi_watchdog(struct ifnet *ifp)
983{
984	struct wi_softc	*sc = ifp->if_softc;
985
986	ifp->if_timer = 0;
987	if (!sc->sc_enabled)
988		return;
989
990	if (sc->sc_tx_timer) {
991		if (--sc->sc_tx_timer == 0) {
992			if_printf(ifp, "device timeout\n");
993			ifp->if_oerrors++;
994			wi_init(ifp->if_softc);
995			return;
996		}
997		ifp->if_timer = 1;
998	}
999
1000	if (sc->sc_scan_timer) {
1001		if (--sc->sc_scan_timer <= WI_SCAN_WAIT - WI_SCAN_INQWAIT &&
1002		    sc->sc_firmware_type == WI_INTERSIL) {
1003			DPRINTF(("wi_watchdog: inquire scan\n"));
1004			wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_SCAN_RESULTS, 0, 0);
1005		}
1006		if (sc->sc_scan_timer)
1007			ifp->if_timer = 1;
1008	}
1009
1010	if (sc->sc_syn_timer) {
1011		if (--sc->sc_syn_timer == 0) {
1012			DPRINTF2(("wi_watchdog: %d false syns\n",
1013			    sc->sc_false_syns));
1014			sc->sc_false_syns = 0;
1015			ieee80211_new_state(ifp, IEEE80211_S_RUN, -1);
1016			sc->sc_syn_timer = 5;
1017		}
1018		ifp->if_timer = 1;
1019	}
1020
1021	/* TODO: rate control */
1022	ieee80211_watchdog(ifp);
1023}
1024
1025static int
1026wi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1027{
1028	struct wi_softc *sc = ifp->if_softc;
1029	struct ieee80211com *ic = &sc->sc_ic;
1030	struct ifreq *ifr = (struct ifreq *)data;
1031	struct ieee80211req *ireq;
1032	u_int8_t nodename[IEEE80211_NWID_LEN];
1033	int error = 0;
1034#if __FreeBSD_version >= 500000
1035	struct thread *td = curthread;
1036#else
1037	struct proc *td = curproc;		/* Little white lie */
1038#endif
1039	struct wi_req wreq;
1040	WI_LOCK_DECL();
1041
1042	WI_LOCK(sc);
1043
1044	if (sc->wi_gone) {
1045		error = ENODEV;
1046		goto out;
1047	}
1048
1049	switch (cmd) {
1050	case SIOCSIFFLAGS:
1051		/*
1052		 * Can't do promisc and hostap at the same time.  If all that's
1053		 * changing is the promisc flag, try to short-circuit a call to
1054		 * wi_init() by just setting PROMISC in the hardware.
1055		 */
1056		if (ifp->if_flags & IFF_UP) {
1057			if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
1058			    ifp->if_flags & IFF_RUNNING) {
1059				if (ifp->if_flags & IFF_PROMISC &&
1060				    !(sc->sc_if_flags & IFF_PROMISC)) {
1061					wi_write_val(sc, WI_RID_PROMISC, 1);
1062				} else if (!(ifp->if_flags & IFF_PROMISC) &&
1063				    sc->sc_if_flags & IFF_PROMISC) {
1064					wi_write_val(sc, WI_RID_PROMISC, 0);
1065				} else {
1066					wi_init(sc);
1067				}
1068			} else {
1069				wi_init(sc);
1070			}
1071		} else {
1072			if (ifp->if_flags & IFF_RUNNING) {
1073				wi_stop(ifp, 0);
1074			}
1075		}
1076		sc->sc_if_flags = ifp->if_flags;
1077		error = 0;
1078		break;
1079	case SIOCSIFMEDIA:
1080	case SIOCGIFMEDIA:
1081		error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
1082		break;
1083	case SIOCADDMULTI:
1084	case SIOCDELMULTI:
1085		error = wi_write_multi(sc);
1086		break;
1087	case SIOCGIFGENERIC:
1088		error = wi_get_cfg(ifp, cmd, data);
1089		break;
1090	case SIOCSIFGENERIC:
1091		error = suser(td);
1092		if (error)
1093			break;
1094		error = wi_set_cfg(ifp, cmd, data);
1095		break;
1096	case SIOCGPRISM2DEBUG:
1097		error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
1098		if (error)
1099			break;
1100		if (!(ifp->if_flags & IFF_RUNNING) ||
1101		    sc->sc_firmware_type == WI_LUCENT) {
1102			error = EIO;
1103			break;
1104		}
1105		error = wi_get_debug(sc, &wreq);
1106		if (error == 0)
1107			error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
1108		break;
1109	case SIOCSPRISM2DEBUG:
1110		if ((error = suser(td)))
1111			goto out;
1112		error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
1113		if (error)
1114			break;
1115		error = wi_set_debug(sc, &wreq);
1116		break;
1117	case SIOCG80211:
1118		ireq = (struct ieee80211req *) data;
1119		switch (ireq->i_type) {
1120		case IEEE80211_IOC_STATIONNAME:
1121			ireq->i_len = sc->sc_nodelen + 1;
1122			error = copyout(sc->sc_nodename, ireq->i_data,
1123					ireq->i_len);
1124			break;
1125		default:
1126			error = ieee80211_ioctl(ifp, cmd, data);
1127			break;
1128		}
1129		break;
1130	case SIOCS80211:
1131		error = suser(td);
1132		if (error)
1133			break;
1134		ireq = (struct ieee80211req *) data;
1135		switch (ireq->i_type) {
1136		case IEEE80211_IOC_STATIONNAME:
1137			if (ireq->i_val != 0 ||
1138			    ireq->i_len > IEEE80211_NWID_LEN) {
1139				error = EINVAL;
1140				break;
1141			}
1142			memset(nodename, 0, IEEE80211_NWID_LEN);
1143			error = copyin(ireq->i_data, nodename, ireq->i_len);
1144			if (error)
1145				break;
1146			if (sc->sc_enabled) {
1147				error = wi_write_ssid(sc, WI_RID_NODENAME,
1148					nodename, ireq->i_len);
1149				if (error)
1150					break;
1151			}
1152			memcpy(sc->sc_nodename, nodename, IEEE80211_NWID_LEN);
1153			sc->sc_nodelen = ireq->i_len;
1154			break;
1155		default:
1156			error = ieee80211_ioctl(ifp, cmd, data);
1157			break;
1158		}
1159		break;
1160	default:
1161		error = ieee80211_ioctl(ifp, cmd, data);
1162		break;
1163	}
1164	if (error == ENETRESET) {
1165		if (sc->sc_enabled)
1166			wi_init(ifp->if_softc);	/* XXX no error return */
1167		error = 0;
1168	}
1169out:
1170	WI_UNLOCK(sc);
1171
1172	return (error);
1173}
1174
1175static int
1176wi_media_change(struct ifnet *ifp)
1177{
1178	struct wi_softc *sc = ifp->if_softc;
1179	struct ieee80211com *ic = &sc->sc_ic;
1180	struct ifmedia_entry *ime;
1181	enum ieee80211_opmode newmode;
1182	int i, rate, error = 0;
1183
1184	ime = sc->sc_media.ifm_cur;
1185	if (IFM_SUBTYPE(ime->ifm_media) == IFM_AUTO) {
1186		i = -1;
1187	} else {
1188		rate = ieee80211_media2rate(ime->ifm_media, IEEE80211_T_DS);
1189		if (rate == 0)
1190			return EINVAL;
1191		for (i = 0; i < IEEE80211_RATE_SIZE; i++) {
1192			if ((ic->ic_sup_rates[i] & IEEE80211_RATE_VAL) == rate)
1193				break;
1194		}
1195		if (i == IEEE80211_RATE_SIZE)
1196			return EINVAL;
1197	}
1198	if (ic->ic_fixed_rate != i) {
1199		ic->ic_fixed_rate = i;
1200		error = ENETRESET;
1201	}
1202
1203	if ((ime->ifm_media & IFM_IEEE80211_ADHOC) &&
1204	    (ime->ifm_media & IFM_FLAG0))
1205		newmode = IEEE80211_M_AHDEMO;
1206	else if (ime->ifm_media & IFM_IEEE80211_ADHOC)
1207		newmode = IEEE80211_M_IBSS;
1208	else if (ime->ifm_media & IFM_IEEE80211_HOSTAP)
1209		newmode = IEEE80211_M_HOSTAP;
1210	else
1211		newmode = IEEE80211_M_STA;
1212	if (ic->ic_opmode != newmode) {
1213		ic->ic_opmode = newmode;
1214		error = ENETRESET;
1215	}
1216	if (error == ENETRESET) {
1217		if (sc->sc_enabled)
1218			wi_init(ifp->if_softc); /* XXX error code lost */
1219		error = 0;
1220	}
1221#if 0
1222	ifp->if_baudrate = ifmedia_baudrate(sc->sc_media.ifm_cur->ifm_media);
1223#endif
1224	return error;
1225}
1226
1227static void
1228wi_media_status(struct ifnet *ifp, struct ifmediareq *imr)
1229{
1230	struct wi_softc *sc = ifp->if_softc;
1231	struct ieee80211com *ic = &sc->sc_ic;
1232	u_int16_t val;
1233	int rate, len;
1234
1235	if (sc->wi_gone || !sc->sc_enabled) {
1236		imr->ifm_active = IFM_IEEE80211 | IFM_NONE;
1237		imr->ifm_status = 0;
1238		return;
1239	}
1240
1241	imr->ifm_status = IFM_AVALID;
1242	imr->ifm_active = IFM_IEEE80211;
1243	if (ic->ic_state == IEEE80211_S_RUN &&
1244	    (sc->sc_flags & WI_FLAGS_OUTRANGE) == 0)
1245		imr->ifm_status |= IFM_ACTIVE;
1246	len = sizeof(val);
1247	if (wi_read_rid(sc, WI_RID_CUR_TX_RATE, &val, &len) != 0)
1248		rate = 0;
1249	else {
1250		/* convert to 802.11 rate */
1251		rate = val * 2;
1252		if (sc->sc_firmware_type == WI_LUCENT) {
1253			if (rate == 10)
1254				rate = 11;	/* 5.5Mbps */
1255		} else {
1256			if (rate == 4*2)
1257				rate = 11;	/* 5.5Mbps */
1258			else if (rate == 8*2)
1259				rate = 22;	/* 11Mbps */
1260		}
1261	}
1262	imr->ifm_active |= ieee80211_rate2media(rate, IEEE80211_T_DS);
1263	switch (ic->ic_opmode) {
1264	case IEEE80211_M_STA:
1265		break;
1266	case IEEE80211_M_IBSS:
1267		imr->ifm_active |= IFM_IEEE80211_ADHOC;
1268		break;
1269	case IEEE80211_M_AHDEMO:
1270		imr->ifm_active |= IFM_IEEE80211_ADHOC | IFM_FLAG0;
1271		break;
1272	case IEEE80211_M_HOSTAP:
1273		imr->ifm_active |= IFM_IEEE80211_HOSTAP;
1274		break;
1275	}
1276}
1277
1278static void
1279wi_sync_bssid(struct wi_softc *sc, u_int8_t new_bssid[IEEE80211_ADDR_LEN])
1280{
1281	struct ieee80211com *ic = &sc->sc_ic;
1282	struct ieee80211_node *ni = &ic->ic_bss;
1283	struct ifnet *ifp = &ic->ic_if;
1284
1285	if (IEEE80211_ADDR_EQ(new_bssid, ni->ni_bssid))
1286		return;
1287
1288	DPRINTF(("wi_sync_bssid: bssid %s -> ", ether_sprintf(ni->ni_bssid)));
1289	DPRINTF(("%s ?\n", ether_sprintf(new_bssid)));
1290
1291	/* In promiscuous mode, the BSSID field is not a reliable
1292	 * indicator of the firmware's BSSID. Damp spurious
1293	 * change-of-BSSID indications.
1294	 */
1295	if ((ifp->if_flags & IFF_PROMISC) != 0 &&
1296	    sc->sc_false_syns >= WI_MAX_FALSE_SYNS)
1297		return;
1298
1299	ieee80211_new_state(ifp, IEEE80211_S_RUN, -1);
1300}
1301
1302static void
1303wi_rx_intr(struct wi_softc *sc)
1304{
1305	struct ieee80211com *ic = &sc->sc_ic;
1306	struct ifnet *ifp = &ic->ic_if;
1307	struct wi_frame frmhdr;
1308	struct mbuf *m;
1309	struct ieee80211_frame *wh;
1310	int fid, len, off, rssi;
1311	u_int8_t dir;
1312	u_int16_t status;
1313	u_int32_t rstamp;
1314
1315	fid = CSR_READ_2(sc, WI_RX_FID);
1316
1317	/* First read in the frame header */
1318	if (wi_read_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr))) {
1319		CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
1320		ifp->if_ierrors++;
1321		DPRINTF(("wi_rx_intr: read fid %x failed\n", fid));
1322		return;
1323	}
1324
1325	if (IFF_DUMPPKTS(ifp))
1326		wi_dump_pkt(&frmhdr, NULL, frmhdr.wi_rx_signal);
1327
1328	/*
1329	 * Drop undecryptable or packets with receive errors here
1330	 */
1331	status = le16toh(frmhdr.wi_status);
1332	if (status & WI_STAT_ERRSTAT) {
1333		CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
1334		ifp->if_ierrors++;
1335		DPRINTF(("wi_rx_intr: fid %x error status %x\n", fid, status));
1336		return;
1337	}
1338	rssi = frmhdr.wi_rx_signal;
1339	rstamp = (le16toh(frmhdr.wi_rx_tstamp0) << 16) |
1340	    le16toh(frmhdr.wi_rx_tstamp1);
1341
1342	len = le16toh(frmhdr.wi_dat_len);
1343	off = ALIGN(sizeof(struct ieee80211_frame));
1344
1345	MGETHDR(m, M_DONTWAIT, MT_DATA);
1346	if (m == NULL) {
1347		CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
1348		ifp->if_ierrors++;
1349		DPRINTF(("wi_rx_intr: MGET failed\n"));
1350		return;
1351	}
1352	if (off + len > MHLEN) {
1353		MCLGET(m, M_DONTWAIT);
1354		if ((m->m_flags & M_EXT) == 0) {
1355			CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
1356			m_freem(m);
1357			ifp->if_ierrors++;
1358			DPRINTF(("wi_rx_intr: MCLGET failed\n"));
1359			return;
1360		}
1361	}
1362
1363	m->m_data += off - sizeof(struct ieee80211_frame);
1364	memcpy(m->m_data, &frmhdr.wi_whdr, sizeof(struct ieee80211_frame));
1365	wi_read_bap(sc, fid, sizeof(frmhdr),
1366	    m->m_data + sizeof(struct ieee80211_frame), len);
1367	m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame) + len;
1368	m->m_pkthdr.rcvif = ifp;
1369
1370	CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
1371
1372#if NBPFILTER > 0
1373	if (sc->sc_drvbpf) {
1374		struct mbuf *mb;
1375
1376		MGETHDR(mb, M_DONTWAIT, m->m_type);
1377		if (mb != NULL) {
1378			(void) m_dup_pkthdr(mb, m, M_DONTWAIT);
1379			mb->m_next = m;
1380			mb->m_data = (caddr_t)&frmhdr;
1381			mb->m_len = sizeof(frmhdr);
1382			mb->m_pkthdr.len += mb->m_len;
1383			bpf_mtap(sc->sc_drvbpf, mb);
1384			m_free(mb);
1385		}
1386	}
1387#endif
1388	wh = mtod(m, struct ieee80211_frame *);
1389	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
1390		/*
1391		 * WEP is decrypted by hardware. Clear WEP bit
1392		 * header for ieee80211_input().
1393		 */
1394		wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
1395	}
1396
1397	/* synchronize driver's BSSID with firmware's BSSID */
1398	dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;
1399	if (ic->ic_opmode == IEEE80211_M_IBSS && dir == IEEE80211_FC1_DIR_NODS)
1400		wi_sync_bssid(sc, wh->i_addr3);
1401
1402	ieee80211_input(ifp, m, rssi, rstamp);
1403}
1404
1405static void
1406wi_tx_ex_intr(struct wi_softc *sc)
1407{
1408	struct ieee80211com *ic = &sc->sc_ic;
1409	struct ifnet *ifp = &ic->ic_if;
1410	struct wi_frame frmhdr;
1411	int fid;
1412
1413	fid = CSR_READ_2(sc, WI_TX_CMP_FID);
1414	/* Read in the frame header */
1415	if (wi_read_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr)) == 0) {
1416		u_int16_t status = le16toh(frmhdr.wi_status);
1417
1418		/*
1419		 * Spontaneous station disconnects appear as xmit
1420		 * errors.  Don't announce them and/or count them
1421		 * as an output error.
1422		 */
1423		if ((status & WI_TXSTAT_DISCONNECT) == 0) {
1424			if (ppsratecheck(&lasttxerror, &curtxeps, wi_txerate)) {
1425				if_printf(ifp, "tx failed");
1426				if (status & WI_TXSTAT_RET_ERR)
1427					printf(", retry limit exceeded");
1428				if (status & WI_TXSTAT_AGED_ERR)
1429					printf(", max transmit lifetime exceeded");
1430				if (status & WI_TXSTAT_DISCONNECT)
1431					printf(", port disconnected");
1432				if (status & WI_TXSTAT_FORM_ERR)
1433					printf(", invalid format (data len %u src %6D)",
1434						le16toh(frmhdr.wi_dat_len),
1435						frmhdr.wi_ehdr.ether_shost, ":");
1436				if (status & ~0xf)
1437					printf(", status=0x%x", status);
1438				printf("\n");
1439			}
1440			ifp->if_oerrors++;
1441		} else {
1442			DPRINTF(("port disconnected\n"));
1443			ifp->if_collisions++;	/* XXX */
1444		}
1445	} else
1446		DPRINTF(("wi_tx_ex_intr: read fid %x failed\n", fid));
1447	CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX_EXC);
1448}
1449
1450static void
1451wi_tx_intr(struct wi_softc *sc)
1452{
1453	struct ieee80211com *ic = &sc->sc_ic;
1454	struct ifnet *ifp = &ic->ic_if;
1455	int fid, cur;
1456
1457	fid = CSR_READ_2(sc, WI_ALLOC_FID);
1458	CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC);
1459
1460	cur = sc->sc_txcur;
1461	if (sc->sc_txd[cur].d_fid != fid) {
1462		if_printf(ifp, "bad alloc %x != %x, cur %d nxt %d\n",
1463		    fid, sc->sc_txd[cur].d_fid, cur, sc->sc_txnext);
1464		return;
1465	}
1466	sc->sc_tx_timer = 0;
1467	sc->sc_txd[cur].d_len = 0;
1468	sc->sc_txcur = cur = (cur + 1) % WI_NTXBUF;
1469	if (sc->sc_txd[cur].d_len == 0)
1470		ifp->if_flags &= ~IFF_OACTIVE;
1471	else {
1472		if (wi_cmd(sc, WI_CMD_TX | WI_RECLAIM, sc->sc_txd[cur].d_fid,
1473		    0, 0)) {
1474			if_printf(ifp, "xmit failed\n");
1475			sc->sc_txd[cur].d_len = 0;
1476		} else {
1477			sc->sc_tx_timer = 5;
1478			ifp->if_timer = 1;
1479		}
1480	}
1481}
1482
1483static void
1484wi_info_intr(struct wi_softc *sc)
1485{
1486	struct ieee80211com *ic = &sc->sc_ic;
1487	struct ifnet *ifp = &ic->ic_if;
1488	int i, fid, len, off;
1489	u_int16_t ltbuf[2];
1490	u_int16_t stat;
1491	u_int32_t *ptr;
1492
1493	fid = CSR_READ_2(sc, WI_INFO_FID);
1494	wi_read_bap(sc, fid, 0, ltbuf, sizeof(ltbuf));
1495
1496	switch (le16toh(ltbuf[1])) {
1497
1498	case WI_INFO_LINK_STAT:
1499		wi_read_bap(sc, fid, sizeof(ltbuf), &stat, sizeof(stat));
1500		DPRINTF(("wi_info_intr: LINK_STAT 0x%x\n", le16toh(stat)));
1501		switch (le16toh(stat)) {
1502		case WI_INFO_LINK_STAT_CONNECTED:
1503			sc->sc_flags &= ~WI_FLAGS_OUTRANGE;
1504			if (ic->ic_state == IEEE80211_S_RUN &&
1505			    ic->ic_opmode != IEEE80211_M_IBSS)
1506				break;
1507			/* FALLTHROUGH */
1508		case WI_INFO_LINK_STAT_AP_CHG:
1509			ieee80211_new_state(ifp, IEEE80211_S_RUN, -1);
1510			break;
1511		case WI_INFO_LINK_STAT_AP_INR:
1512			sc->sc_flags &= ~WI_FLAGS_OUTRANGE;
1513			break;
1514		case WI_INFO_LINK_STAT_AP_OOR:
1515			if (sc->sc_firmware_type == WI_SYMBOL &&
1516			    sc->sc_scan_timer > 0) {
1517				if (wi_cmd(sc, WI_CMD_INQUIRE,
1518				    WI_INFO_HOST_SCAN_RESULTS, 0, 0) != 0)
1519					sc->sc_scan_timer = 0;
1520				break;
1521			}
1522			if (ic->ic_opmode == IEEE80211_M_STA)
1523				sc->sc_flags |= WI_FLAGS_OUTRANGE;
1524			break;
1525		case WI_INFO_LINK_STAT_DISCONNECTED:
1526		case WI_INFO_LINK_STAT_ASSOC_FAILED:
1527			if (ic->ic_opmode == IEEE80211_M_STA)
1528				ieee80211_new_state(ifp, IEEE80211_S_INIT, -1);
1529			break;
1530		}
1531		break;
1532
1533	case WI_INFO_COUNTERS:
1534		/* some card versions have a larger stats structure */
1535		len = min(le16toh(ltbuf[0]) - 1, sizeof(sc->sc_stats) / 4);
1536		ptr = (u_int32_t *)&sc->sc_stats;
1537		off = sizeof(ltbuf);
1538		for (i = 0; i < len; i++, off += 2, ptr++) {
1539			wi_read_bap(sc, fid, off, &stat, sizeof(stat));
1540#ifdef WI_HERMES_STATS_WAR
1541			if (stat & 0xf000)
1542				stat = ~stat;
1543#endif
1544			*ptr += stat;
1545		}
1546		ifp->if_collisions = sc->sc_stats.wi_tx_single_retries +
1547		    sc->sc_stats.wi_tx_multi_retries +
1548		    sc->sc_stats.wi_tx_retry_limit;
1549		break;
1550
1551	case WI_INFO_SCAN_RESULTS:
1552	case WI_INFO_HOST_SCAN_RESULTS:
1553		wi_scan_result(sc, fid, le16toh(ltbuf[0]));
1554		break;
1555
1556	default:
1557		DPRINTF(("wi_info_intr: got fid %x type %x len %d\n", fid,
1558		    le16toh(ltbuf[1]), le16toh(ltbuf[0])));
1559		break;
1560	}
1561	CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO);
1562}
1563
1564static int
1565wi_write_multi(struct wi_softc *sc)
1566{
1567	struct ifnet *ifp = &sc->sc_ic.ic_if;
1568	int n;
1569	struct ifmultiaddr *ifma;
1570	struct wi_mcast mlist;
1571
1572	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
1573allmulti:
1574		memset(&mlist, 0, sizeof(mlist));
1575		return wi_write_rid(sc, WI_RID_MCAST_LIST, &mlist,
1576		    sizeof(mlist));
1577	}
1578
1579	n = 0;
1580#if __FreeBSD_version < 500000
1581	LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
1582#else
1583	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
1584#endif
1585		if (ifma->ifma_addr->sa_family != AF_LINK)
1586			continue;
1587		if (n >= 16)
1588			goto allmulti;
1589		IEEE80211_ADDR_COPY(&mlist.wi_mcast[n],
1590		    (LLADDR((struct sockaddr_dl *)ifma->ifma_addr)));
1591		n++;
1592	}
1593	return wi_write_rid(sc, WI_RID_MCAST_LIST, &mlist,
1594	    IEEE80211_ADDR_LEN * n);
1595}
1596
1597static void
1598wi_read_nicid(struct wi_softc *sc)
1599{
1600	struct wi_card_ident *id;
1601	char *p;
1602	int len;
1603	u_int16_t ver[4];
1604
1605	/* getting chip identity */
1606	memset(ver, 0, sizeof(ver));
1607	len = sizeof(ver);
1608	wi_read_rid(sc, WI_RID_CARD_ID, ver, &len);
1609	device_printf(sc->sc_dev, "using ");
1610
1611	sc->sc_firmware_type = WI_NOTYPE;
1612	for (id = wi_card_ident; id->card_name != NULL; id++) {
1613		if (le16toh(ver[0]) == id->card_id) {
1614			printf("%s", id->card_name);
1615			sc->sc_firmware_type = id->firm_type;
1616			break;
1617		}
1618	}
1619	if (sc->sc_firmware_type == WI_NOTYPE) {
1620		if (le16toh(ver[0]) & 0x8000) {
1621			printf("Unknown PRISM2 chip");
1622			sc->sc_firmware_type = WI_INTERSIL;
1623		} else {
1624			printf("Unknown Lucent chip");
1625			sc->sc_firmware_type = WI_LUCENT;
1626		}
1627	}
1628
1629	/* get primary firmware version (Only Prism chips) */
1630	if (sc->sc_firmware_type != WI_LUCENT) {
1631		memset(ver, 0, sizeof(ver));
1632		len = sizeof(ver);
1633		wi_read_rid(sc, WI_RID_PRI_IDENTITY, ver, &len);
1634		sc->sc_pri_firmware_ver = le16toh(ver[2]) * 10000 +
1635		    le16toh(ver[3]) * 100 + le16toh(ver[1]);
1636	}
1637
1638	/* get station firmware version */
1639	memset(ver, 0, sizeof(ver));
1640	len = sizeof(ver);
1641	wi_read_rid(sc, WI_RID_STA_IDENTITY, ver, &len);
1642	sc->sc_sta_firmware_ver = le16toh(ver[2]) * 10000 +
1643	    le16toh(ver[3]) * 100 + le16toh(ver[1]);
1644	if (sc->sc_firmware_type == WI_INTERSIL &&
1645	    (sc->sc_sta_firmware_ver == 10102 ||
1646	     sc->sc_sta_firmware_ver == 20102)) {
1647		char ident[12];
1648		memset(ident, 0, sizeof(ident));
1649		len = sizeof(ident);
1650		/* value should be the format like "V2.00-11" */
1651		if (wi_read_rid(sc, WI_RID_SYMBOL_IDENTITY, ident, &len) == 0 &&
1652		    *(p = (char *)ident) >= 'A' &&
1653		    p[2] == '.' && p[5] == '-' && p[8] == '\0') {
1654			sc->sc_firmware_type = WI_SYMBOL;
1655			sc->sc_sta_firmware_ver = (p[1] - '0') * 10000 +
1656			    (p[3] - '0') * 1000 + (p[4] - '0') * 100 +
1657			    (p[6] - '0') * 10 + (p[7] - '0');
1658		}
1659	}
1660	printf("\n");
1661	device_printf(sc->sc_dev, "%s Firmware: ",
1662	     sc->sc_firmware_type == WI_LUCENT ? "Lucent" :
1663	    (sc->sc_firmware_type == WI_SYMBOL ? "Symbol" : "Intersil"));
1664	if (sc->sc_firmware_type != WI_LUCENT)	/* XXX */
1665		printf("Primary (%u.%u.%u), ",
1666		    sc->sc_pri_firmware_ver / 10000,
1667		    (sc->sc_pri_firmware_ver % 10000) / 100,
1668		    sc->sc_pri_firmware_ver % 100);
1669	printf("Station (%u.%u.%u)\n",
1670	    sc->sc_sta_firmware_ver / 10000,
1671	    (sc->sc_sta_firmware_ver % 10000) / 100,
1672	    sc->sc_sta_firmware_ver % 100);
1673}
1674
1675static int
1676wi_write_ssid(struct wi_softc *sc, int rid, u_int8_t *buf, int buflen)
1677{
1678	struct wi_ssid ssid;
1679
1680	if (buflen > IEEE80211_NWID_LEN)
1681		return ENOBUFS;
1682	memset(&ssid, 0, sizeof(ssid));
1683	ssid.wi_len = htole16(buflen);
1684	memcpy(ssid.wi_ssid, buf, buflen);
1685	return wi_write_rid(sc, rid, &ssid, sizeof(ssid));
1686}
1687
1688static int
1689wi_get_cfg(struct ifnet *ifp, u_long cmd, caddr_t data)
1690{
1691	struct wi_softc *sc = ifp->if_softc;
1692	struct ieee80211com *ic = &sc->sc_ic;
1693	struct ifreq *ifr = (struct ifreq *)data;
1694	struct wi_req wreq;
1695	int len, n, error, mif, val;
1696
1697	error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
1698	if (error)
1699		return error;
1700	len = (wreq.wi_len - 1) * 2;
1701	if (len < sizeof(u_int16_t))
1702		return ENOSPC;
1703	if (len > sizeof(wreq.wi_val))
1704		len = sizeof(wreq.wi_val);
1705
1706	switch (wreq.wi_type) {
1707
1708	case WI_RID_IFACE_STATS:
1709		memcpy(wreq.wi_val, &sc->sc_stats, sizeof(sc->sc_stats));
1710		if (len < sizeof(sc->sc_stats))
1711			error = ENOSPC;
1712		else
1713			len = sizeof(sc->sc_stats);
1714		break;
1715
1716	case WI_RID_ENCRYPTION:
1717	case WI_RID_TX_CRYPT_KEY:
1718	case WI_RID_DEFLT_CRYPT_KEYS:
1719	case WI_RID_TX_RATE:
1720		return ieee80211_cfgget(ifp, cmd, data);
1721
1722	case WI_RID_MICROWAVE_OVEN:
1723		if (sc->sc_enabled && (sc->sc_flags & WI_FLAGS_HAS_MOR)) {
1724			error = wi_read_rid(sc, wreq.wi_type, wreq.wi_val,
1725			    &len);
1726			break;
1727		}
1728		wreq.wi_val[0] = htole16(sc->sc_microwave_oven);
1729		len = sizeof(u_int16_t);
1730		break;
1731
1732	case WI_RID_DBM_ADJUST:
1733		if (sc->sc_enabled && (sc->sc_flags & WI_FLAGS_HAS_DBMADJUST)) {
1734			error = wi_read_rid(sc, wreq.wi_type, wreq.wi_val,
1735			    &len);
1736			break;
1737		}
1738		wreq.wi_val[0] = htole16(sc->sc_dbm_adjust);
1739		len = sizeof(u_int16_t);
1740		break;
1741
1742	case WI_RID_ROAMING_MODE:
1743		if (sc->sc_enabled && (sc->sc_flags & WI_FLAGS_HAS_ROAMING)) {
1744			error = wi_read_rid(sc, wreq.wi_type, wreq.wi_val,
1745			    &len);
1746			break;
1747		}
1748		wreq.wi_val[0] = htole16(sc->sc_roaming_mode);
1749		len = sizeof(u_int16_t);
1750		break;
1751
1752	case WI_RID_SYSTEM_SCALE:
1753		if (sc->sc_enabled && (sc->sc_flags & WI_FLAGS_HAS_SYSSCALE)) {
1754			error = wi_read_rid(sc, wreq.wi_type, wreq.wi_val,
1755			    &len);
1756			break;
1757		}
1758		wreq.wi_val[0] = htole16(sc->sc_system_scale);
1759		len = sizeof(u_int16_t);
1760		break;
1761
1762	case WI_RID_FRAG_THRESH:
1763		if (sc->sc_enabled && (sc->sc_flags & WI_FLAGS_HAS_FRAGTHR)) {
1764			error = wi_read_rid(sc, wreq.wi_type, wreq.wi_val,
1765			    &len);
1766			break;
1767		}
1768		wreq.wi_val[0] = htole16(sc->sc_frag_thresh);
1769		len = sizeof(u_int16_t);
1770		break;
1771
1772	case WI_RID_READ_APS:
1773	case WI_RID_SCAN_RES:		/* XXX */
1774		if (ic->ic_opmode == IEEE80211_M_HOSTAP)
1775			return ieee80211_cfgget(ifp, cmd, data);
1776		if (sc->sc_scan_timer > 0) {
1777			error = EINPROGRESS;
1778			break;
1779		}
1780		n = sc->sc_naps;
1781		if (len < sizeof(n)) {
1782			error = ENOSPC;
1783			break;
1784		}
1785		if (len < sizeof(n) + sizeof(struct wi_apinfo) * n)
1786			n = (len - sizeof(n)) / sizeof(struct wi_apinfo);
1787		len = sizeof(n) + sizeof(struct wi_apinfo) * n;
1788		memcpy(wreq.wi_val, &n, sizeof(n));
1789		memcpy((caddr_t)wreq.wi_val + sizeof(n), sc->sc_aps,
1790		    sizeof(struct wi_apinfo) * n);
1791		break;
1792
1793	case WI_RID_PRISM2:
1794		wreq.wi_val[0] = sc->sc_firmware_type != WI_LUCENT;
1795		len = sizeof(u_int16_t);
1796		break;
1797
1798	case WI_RID_MIF:
1799		mif = wreq.wi_val[0];
1800		error = wi_cmd(sc, WI_CMD_READMIF, mif, 0, 0);
1801		val = CSR_READ_2(sc, WI_RESP0);
1802		wreq.wi_val[0] = val;
1803		len = sizeof(u_int16_t);
1804		break;
1805
1806	case WI_RID_ZERO_CACHE:
1807	case WI_RID_PROCFRAME:		/* ignore for compatibility */
1808		/* XXX ??? */
1809		break;
1810
1811	case WI_RID_READ_CACHE:
1812		return ieee80211_cfgget(ifp, cmd, data);
1813
1814	default:
1815		if (sc->sc_enabled) {
1816			error = wi_read_rid(sc, wreq.wi_type, wreq.wi_val,
1817			    &len);
1818			break;
1819		}
1820		switch (wreq.wi_type) {
1821		case WI_RID_MAX_DATALEN:
1822			wreq.wi_val[0] = htole16(sc->sc_max_datalen);
1823			len = sizeof(u_int16_t);
1824			break;
1825		case WI_RID_RTS_THRESH:
1826			wreq.wi_val[0] = htole16(sc->sc_rts_thresh);
1827			len = sizeof(u_int16_t);
1828			break;
1829		case WI_RID_CNFAUTHMODE:
1830			wreq.wi_val[0] = htole16(sc->sc_cnfauthmode);
1831			len = sizeof(u_int16_t);
1832			break;
1833		case WI_RID_NODENAME:
1834			if (len < sc->sc_nodelen + sizeof(u_int16_t)) {
1835				error = ENOSPC;
1836				break;
1837			}
1838			len = sc->sc_nodelen + sizeof(u_int16_t);
1839			wreq.wi_val[0] = htole16((sc->sc_nodelen + 1) / 2);
1840			memcpy(&wreq.wi_val[1], sc->sc_nodename,
1841			    sc->sc_nodelen);
1842			break;
1843		default:
1844			return ieee80211_cfgget(ifp, cmd, data);
1845		}
1846		break;
1847	}
1848	if (error)
1849		return error;
1850	wreq.wi_len = (len + 1) / 2 + 1;
1851	return copyout(&wreq, ifr->ifr_data, (wreq.wi_len + 1) * 2);
1852}
1853
1854static int
1855wi_set_cfg(struct ifnet *ifp, u_long cmd, caddr_t data)
1856{
1857	struct wi_softc *sc = ifp->if_softc;
1858	struct ieee80211com *ic = &sc->sc_ic;
1859	struct ifreq *ifr = (struct ifreq *)data;
1860	struct wi_req wreq;
1861	struct mbuf *m;
1862	int i, len, error, mif, val;
1863
1864	error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
1865	if (error)
1866		return error;
1867	len = (wreq.wi_len - 1) * 2;
1868	switch (wreq.wi_type) {
1869	case WI_RID_DBM_ADJUST:
1870		return ENODEV;
1871
1872	case WI_RID_NODENAME:
1873		if (le16toh(wreq.wi_val[0]) * 2 > len ||
1874		    le16toh(wreq.wi_val[0]) > sizeof(sc->sc_nodename)) {
1875			error = ENOSPC;
1876			break;
1877		}
1878		if (sc->sc_enabled) {
1879			error = wi_write_rid(sc, wreq.wi_type, wreq.wi_val,
1880			    len);
1881			if (error)
1882				break;
1883		}
1884		sc->sc_nodelen = le16toh(wreq.wi_val[0]) * 2;
1885		memcpy(sc->sc_nodename, &wreq.wi_val[1], sc->sc_nodelen);
1886		break;
1887
1888	case WI_RID_MICROWAVE_OVEN:
1889	case WI_RID_ROAMING_MODE:
1890	case WI_RID_SYSTEM_SCALE:
1891	case WI_RID_FRAG_THRESH:
1892		if (wreq.wi_type == WI_RID_MICROWAVE_OVEN &&
1893		    (sc->sc_flags & WI_FLAGS_HAS_MOR) == 0)
1894			break;
1895		if (wreq.wi_type == WI_RID_ROAMING_MODE &&
1896		    (sc->sc_flags & WI_FLAGS_HAS_ROAMING) == 0)
1897			break;
1898		if (wreq.wi_type == WI_RID_SYSTEM_SCALE &&
1899		    (sc->sc_flags & WI_FLAGS_HAS_SYSSCALE) == 0)
1900			break;
1901		if (wreq.wi_type == WI_RID_FRAG_THRESH &&
1902		    (sc->sc_flags & WI_FLAGS_HAS_FRAGTHR) == 0)
1903			break;
1904		/* FALLTHROUGH */
1905	case WI_RID_RTS_THRESH:
1906	case WI_RID_CNFAUTHMODE:
1907	case WI_RID_MAX_DATALEN:
1908		if (sc->sc_enabled) {
1909			error = wi_write_rid(sc, wreq.wi_type, wreq.wi_val,
1910			    sizeof(u_int16_t));
1911			if (error)
1912				break;
1913		}
1914		switch (wreq.wi_type) {
1915		case WI_RID_FRAG_THRESH:
1916			sc->sc_frag_thresh = le16toh(wreq.wi_val[0]);
1917			break;
1918		case WI_RID_RTS_THRESH:
1919			sc->sc_rts_thresh = le16toh(wreq.wi_val[0]);
1920			break;
1921		case WI_RID_MICROWAVE_OVEN:
1922			sc->sc_microwave_oven = le16toh(wreq.wi_val[0]);
1923			break;
1924		case WI_RID_ROAMING_MODE:
1925			sc->sc_roaming_mode = le16toh(wreq.wi_val[0]);
1926			break;
1927		case WI_RID_SYSTEM_SCALE:
1928			sc->sc_system_scale = le16toh(wreq.wi_val[0]);
1929			break;
1930		case WI_RID_CNFAUTHMODE:
1931			sc->sc_cnfauthmode = le16toh(wreq.wi_val[0]);
1932			break;
1933		case WI_RID_MAX_DATALEN:
1934			sc->sc_max_datalen = le16toh(wreq.wi_val[0]);
1935			break;
1936		}
1937		break;
1938
1939	case WI_RID_TX_RATE:
1940		switch (le16toh(wreq.wi_val[0])) {
1941		case 3:
1942			ic->ic_fixed_rate = -1;
1943			break;
1944		default:
1945			for (i = 0; i < IEEE80211_RATE_SIZE; i++) {
1946				if ((ic->ic_sup_rates[i] & IEEE80211_RATE_VAL)
1947				    / 2 == le16toh(wreq.wi_val[0]))
1948					break;
1949			}
1950			if (i == IEEE80211_RATE_SIZE)
1951				return EINVAL;
1952			ic->ic_fixed_rate = i;
1953		}
1954		if (sc->sc_enabled)
1955			error = wi_write_txrate(sc);
1956		break;
1957
1958	case WI_RID_SCAN_APS:
1959		if (sc->sc_enabled && ic->ic_opmode != IEEE80211_M_HOSTAP)
1960			error = wi_scan_ap(sc);
1961		break;
1962
1963	case WI_RID_MGMT_XMIT:
1964		if (!sc->sc_enabled) {
1965			error = ENETDOWN;
1966			break;
1967		}
1968		if (ic->ic_mgtq.ifq_len > 5) {
1969			error = EAGAIN;
1970			break;
1971		}
1972		/* XXX wi_len looks in u_int8_t, not in u_int16_t */
1973		m = m_devget((char *)&wreq.wi_val, wreq.wi_len, 0, ifp, NULL);
1974		if (m == NULL) {
1975			error = ENOMEM;
1976			break;
1977		}
1978		IF_ENQUEUE(&ic->ic_mgtq, m);
1979		break;
1980
1981	case WI_RID_MIF:
1982		mif = wreq.wi_val[0];
1983		val = wreq.wi_val[1];
1984		error = wi_cmd(sc, WI_CMD_WRITEMIF, mif, val, 0);
1985		break;
1986
1987	case WI_RID_PROCFRAME:		/* ignore for compatibility */
1988		break;
1989
1990	case WI_RID_SCAN_REQ:
1991		if (!sc->sc_enabled) {
1992			error = ENETDOWN;
1993			break;
1994		}
1995		if (sc->sc_firmware_type == WI_LUCENT)
1996
1997	default:
1998		if (sc->sc_enabled) {
1999			error = wi_write_rid(sc, wreq.wi_type, wreq.wi_val,
2000			    len);
2001			if (error)
2002				break;
2003		}
2004		error = ieee80211_cfgset(ifp, cmd, data);
2005		break;
2006	}
2007	return error;
2008}
2009
2010static int
2011wi_write_txrate(struct wi_softc *sc)
2012{
2013	struct ieee80211com *ic = &sc->sc_ic;
2014	int i;
2015	u_int16_t rate;
2016
2017	if (ic->ic_fixed_rate < 0)
2018		rate = 0;	/* auto */
2019	else
2020		rate = (ic->ic_sup_rates[ic->ic_fixed_rate] &
2021		    IEEE80211_RATE_VAL) / 2;
2022
2023	/* rate: 0, 1, 2, 5, 11 */
2024
2025	switch (sc->sc_firmware_type) {
2026	case WI_LUCENT:
2027		if (rate == 0)
2028			rate = 3;	/* auto */
2029		break;
2030	default:
2031		/* Choose a bit according to this table.
2032		 *
2033		 * bit | data rate
2034		 * ----+-------------------
2035		 * 0   | 1Mbps
2036		 * 1   | 2Mbps
2037		 * 2   | 5.5Mbps
2038		 * 3   | 11Mbps
2039		 */
2040		for (i = 8; i > 0; i >>= 1) {
2041			if (rate >= i)
2042				break;
2043		}
2044		if (i == 0)
2045			rate = 0xf;	/* auto */
2046		else
2047			rate = i;
2048		break;
2049	}
2050	return wi_write_val(sc, WI_RID_TX_RATE, rate);
2051}
2052
2053static int
2054wi_write_wep(struct wi_softc *sc)
2055{
2056	struct ieee80211com *ic = &sc->sc_ic;
2057	int error = 0;
2058	int i, keylen;
2059	u_int16_t val;
2060	struct wi_key wkey[IEEE80211_WEP_NKID];
2061
2062	switch (sc->sc_firmware_type) {
2063	case WI_LUCENT:
2064		val = (ic->ic_flags & IEEE80211_F_WEPON) ? 1 : 0;
2065		error = wi_write_val(sc, WI_RID_ENCRYPTION, val);
2066		if (error)
2067			break;
2068		error = wi_write_val(sc, WI_RID_TX_CRYPT_KEY, ic->ic_wep_txkey);
2069		if (error)
2070			break;
2071		memset(wkey, 0, sizeof(wkey));
2072		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
2073			keylen = ic->ic_nw_keys[i].wk_len;
2074			wkey[i].wi_keylen = htole16(keylen);
2075			memcpy(wkey[i].wi_keydat, ic->ic_nw_keys[i].wk_key,
2076			    keylen);
2077		}
2078		error = wi_write_rid(sc, WI_RID_DEFLT_CRYPT_KEYS,
2079		    wkey, sizeof(wkey));
2080		break;
2081
2082	case WI_INTERSIL:
2083	case WI_SYMBOL:
2084		if (ic->ic_flags & IEEE80211_F_WEPON) {
2085			/*
2086			 * ONLY HWB3163 EVAL-CARD Firmware version
2087			 * less than 0.8 variant2
2088			 *
2089			 *   If promiscuous mode disable, Prism2 chip
2090			 *  does not work with WEP .
2091			 * It is under investigation for details.
2092			 * (ichiro@netbsd.org)
2093			 */
2094			if (sc->sc_firmware_type == WI_INTERSIL &&
2095			    sc->sc_sta_firmware_ver < 802 ) {
2096				/* firm ver < 0.8 variant 2 */
2097				wi_write_val(sc, WI_RID_PROMISC, 1);
2098			}
2099			wi_write_val(sc, WI_RID_CNFAUTHMODE,
2100			    sc->sc_cnfauthmode);
2101			val = PRIVACY_INVOKED | EXCLUDE_UNENCRYPTED;
2102			/*
2103			 * Encryption firmware has a bug for HostAP mode.
2104			 */
2105			if (sc->sc_firmware_type == WI_INTERSIL &&
2106			    ic->ic_opmode == IEEE80211_M_HOSTAP)
2107				val |= HOST_ENCRYPT;
2108		} else {
2109			wi_write_val(sc, WI_RID_CNFAUTHMODE,
2110			    IEEE80211_AUTH_OPEN);
2111			val = HOST_ENCRYPT | HOST_DECRYPT;
2112		}
2113		error = wi_write_val(sc, WI_RID_P2_ENCRYPTION, val);
2114		if (error)
2115			break;
2116		error = wi_write_val(sc, WI_RID_P2_TX_CRYPT_KEY,
2117		    ic->ic_wep_txkey);
2118		if (error)
2119			break;
2120		/*
2121		 * It seems that the firmware accept 104bit key only if
2122		 * all the keys have 104bit length.  We get the length of
2123		 * the transmit key and use it for all other keys.
2124		 * Perhaps we should use software WEP for such situation.
2125		 */
2126		keylen = ic->ic_nw_keys[ic->ic_wep_txkey].wk_len;
2127		if (keylen > IEEE80211_WEP_KEYLEN)
2128			keylen = 13;	/* 104bit keys */
2129		else
2130			keylen = IEEE80211_WEP_KEYLEN;
2131		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
2132			error = wi_write_rid(sc, WI_RID_P2_CRYPT_KEY0 + i,
2133			    ic->ic_nw_keys[i].wk_key, keylen);
2134			if (error)
2135				break;
2136		}
2137		break;
2138	}
2139	return error;
2140}
2141
2142static int
2143wi_cmd(struct wi_softc *sc, int cmd, int val0, int val1, int val2)
2144{
2145	int			i, s = 0;
2146	static volatile int count  = 0;
2147
2148	if (count > 0)
2149		panic("Hey partner, hold on there!");
2150	count++;
2151
2152	/* wait for the busy bit to clear */
2153	for (i = 500; i > 0; i--) {	/* 5s */
2154		if (!(CSR_READ_2(sc, WI_COMMAND) & WI_CMD_BUSY)) {
2155			break;
2156		}
2157		DELAY(10*1000);	/* 10 m sec */
2158	}
2159	if (i == 0) {
2160		device_printf(sc->sc_dev, "wi_cmd: busy bit won't clear.\n" );
2161		count--;
2162		return(ETIMEDOUT);
2163	}
2164
2165	CSR_WRITE_2(sc, WI_PARAM0, val0);
2166	CSR_WRITE_2(sc, WI_PARAM1, val1);
2167	CSR_WRITE_2(sc, WI_PARAM2, val2);
2168	CSR_WRITE_2(sc, WI_COMMAND, cmd);
2169
2170	if (cmd == WI_CMD_INI) {
2171		/* XXX: should sleep here. */
2172		DELAY(100*1000);
2173	}
2174	for (i = 0; i < WI_TIMEOUT; i++) {
2175		/*
2176		 * Wait for 'command complete' bit to be
2177		 * set in the event status register.
2178		 */
2179		s = CSR_READ_2(sc, WI_EVENT_STAT);
2180		if (s & WI_EV_CMD) {
2181			/* Ack the event and read result code. */
2182			s = CSR_READ_2(sc, WI_STATUS);
2183			CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_CMD);
2184#ifdef foo
2185			if ((s & WI_CMD_CODE_MASK) != (cmd & WI_CMD_CODE_MASK))
2186				return(EIO);
2187#endif
2188			if (s & WI_STAT_CMD_RESULT) {
2189				count--;
2190				return(EIO);
2191			}
2192			break;
2193		}
2194		DELAY(WI_DELAY);
2195	}
2196
2197	count--;
2198	if (i == WI_TIMEOUT) {
2199		device_printf(sc->sc_dev,
2200		    "timeout in wi_cmd 0x%04x; event status 0x%04x\n", cmd, s);
2201		return(ETIMEDOUT);
2202	}
2203	return (0);
2204}
2205
2206static int
2207wi_seek_bap(struct wi_softc *sc, int id, int off)
2208{
2209	int i, status;
2210
2211	CSR_WRITE_2(sc, WI_SEL0, id);
2212	CSR_WRITE_2(sc, WI_OFF0, off);
2213
2214	for (i = 0; ; i++) {
2215		status = CSR_READ_2(sc, WI_OFF0);
2216		if ((status & WI_OFF_BUSY) == 0)
2217			break;
2218		if (i == WI_TIMEOUT) {
2219			device_printf(sc->sc_dev, "timeout in wi_seek to %x/%x\n",
2220			    id, off);
2221			sc->sc_bap_off = WI_OFF_ERR;	/* invalidate */
2222			return ETIMEDOUT;
2223		}
2224		DELAY(1);
2225	}
2226	if (status & WI_OFF_ERR) {
2227		device_printf(sc->sc_dev, "failed in wi_seek to %x/%x\n", id, off);
2228		sc->sc_bap_off = WI_OFF_ERR;	/* invalidate */
2229		return EIO;
2230	}
2231	sc->sc_bap_id = id;
2232	sc->sc_bap_off = off;
2233	return 0;
2234}
2235
2236static int
2237wi_read_bap(struct wi_softc *sc, int id, int off, void *buf, int buflen)
2238{
2239	u_int16_t *ptr;
2240	int i, error, cnt;
2241
2242	if (buflen == 0)
2243		return 0;
2244	if (id != sc->sc_bap_id || off != sc->sc_bap_off) {
2245		if ((error = wi_seek_bap(sc, id, off)) != 0)
2246			return error;
2247	}
2248	cnt = (buflen + 1) / 2;
2249	ptr = (u_int16_t *)buf;
2250	for (i = 0; i < cnt; i++)
2251		*ptr++ = CSR_READ_2(sc, WI_DATA0);
2252	sc->sc_bap_off += cnt * 2;
2253	return 0;
2254}
2255
2256static int
2257wi_write_bap(struct wi_softc *sc, int id, int off, void *buf, int buflen)
2258{
2259	u_int16_t *ptr;
2260	int i, error, cnt;
2261
2262	if (buflen == 0)
2263		return 0;
2264
2265#ifdef WI_HERMES_AUTOINC_WAR
2266  again:
2267#endif
2268	if (id != sc->sc_bap_id || off != sc->sc_bap_off) {
2269		if ((error = wi_seek_bap(sc, id, off)) != 0)
2270			return error;
2271	}
2272	cnt = (buflen + 1) / 2;
2273	ptr = (u_int16_t *)buf;
2274	for (i = 0; i < cnt; i++)
2275		CSR_WRITE_2(sc, WI_DATA0, ptr[i]);
2276	sc->sc_bap_off += cnt * 2;
2277
2278#ifdef WI_HERMES_AUTOINC_WAR
2279	/*
2280	 * According to the comments in the HCF Light code, there is a bug
2281	 * in the Hermes (or possibly in certain Hermes firmware revisions)
2282	 * where the chip's internal autoincrement counter gets thrown off
2283	 * during data writes:  the autoincrement is missed, causing one
2284	 * data word to be overwritten and subsequent words to be written to
2285	 * the wrong memory locations. The end result is that we could end
2286	 * up transmitting bogus frames without realizing it. The workaround
2287	 * for this is to write a couple of extra guard words after the end
2288	 * of the transfer, then attempt to read then back. If we fail to
2289	 * locate the guard words where we expect them, we preform the
2290	 * transfer over again.
2291	 */
2292	if ((sc->sc_flags & WI_FLAGS_BUG_AUTOINC) && (id & 0xf000) == 0) {
2293		CSR_WRITE_2(sc, WI_DATA0, 0x1234);
2294		CSR_WRITE_2(sc, WI_DATA0, 0x5678);
2295		wi_seek_bap(sc, id, sc->sc_bap_off);
2296		sc->sc_bap_off = WI_OFF_ERR;	/* invalidate */
2297		if (CSR_READ_2(sc, WI_DATA0) != 0x1234 ||
2298		    CSR_READ_2(sc, WI_DATA0) != 0x5678) {
2299			device_printf(sc->sc_dev,
2300				"detect auto increment bug, try again\n");
2301			goto again;
2302		}
2303	}
2304#endif
2305	return 0;
2306}
2307
2308static int
2309wi_mwrite_bap(struct wi_softc *sc, int id, int off, struct mbuf *m0, int totlen)
2310{
2311	int error, len;
2312	struct mbuf *m;
2313
2314	for (m = m0; m != NULL && totlen > 0; m = m->m_next) {
2315		if (m->m_len == 0)
2316			continue;
2317
2318		len = min(m->m_len, totlen);
2319
2320		if (((u_long)m->m_data) % 2 != 0 || len % 2 != 0) {
2321			m_copydata(m, 0, totlen, (caddr_t)&sc->sc_txbuf);
2322			return wi_write_bap(sc, id, off, (caddr_t)&sc->sc_txbuf,
2323			    totlen);
2324		}
2325
2326		if ((error = wi_write_bap(sc, id, off, m->m_data, len)) != 0)
2327			return error;
2328
2329		off += m->m_len;
2330		totlen -= len;
2331	}
2332	return 0;
2333}
2334
2335static int
2336wi_alloc_fid(struct wi_softc *sc, int len, int *idp)
2337{
2338	int i;
2339
2340	if (wi_cmd(sc, WI_CMD_ALLOC_MEM, len, 0, 0)) {
2341		device_printf(sc->sc_dev, "failed to allocate %d bytes on NIC\n",
2342		    len);
2343		return ENOMEM;
2344	}
2345
2346	for (i = 0; i < WI_TIMEOUT; i++) {
2347		if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_ALLOC)
2348			break;
2349		if (i == WI_TIMEOUT) {
2350			device_printf(sc->sc_dev, "timeout in alloc\n");
2351			return ETIMEDOUT;
2352		}
2353		DELAY(1);
2354	}
2355	*idp = CSR_READ_2(sc, WI_ALLOC_FID);
2356	CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC);
2357	return 0;
2358}
2359
2360static int
2361wi_read_rid(struct wi_softc *sc, int rid, void *buf, int *buflenp)
2362{
2363	int error, len;
2364	u_int16_t ltbuf[2];
2365
2366	/* Tell the NIC to enter record read mode. */
2367	error = wi_cmd(sc, WI_CMD_ACCESS | WI_ACCESS_READ, rid, 0, 0);
2368	if (error)
2369		return error;
2370
2371	error = wi_read_bap(sc, rid, 0, ltbuf, sizeof(ltbuf));
2372	if (error)
2373		return error;
2374
2375	if (le16toh(ltbuf[1]) != rid) {
2376		device_printf(sc->sc_dev, "record read mismatch, rid=%x, got=%x\n",
2377		    rid, le16toh(ltbuf[1]));
2378		return EIO;
2379	}
2380	len = (le16toh(ltbuf[0]) - 1) * 2;	 /* already got rid */
2381	if (*buflenp < len) {
2382		device_printf(sc->sc_dev, "record buffer is too small, "
2383		    "rid=%x, size=%d, len=%d\n",
2384		    rid, *buflenp, len);
2385		return ENOSPC;
2386	}
2387	*buflenp = len;
2388	return wi_read_bap(sc, rid, sizeof(ltbuf), buf, len);
2389}
2390
2391static int
2392wi_write_rid(struct wi_softc *sc, int rid, void *buf, int buflen)
2393{
2394	int error;
2395	u_int16_t ltbuf[2];
2396
2397	ltbuf[0] = htole16((buflen + 1) / 2 + 1);	 /* includes rid */
2398	ltbuf[1] = htole16(rid);
2399
2400	error = wi_write_bap(sc, rid, 0, ltbuf, sizeof(ltbuf));
2401	if (error)
2402		return error;
2403	error = wi_write_bap(sc, rid, sizeof(ltbuf), buf, buflen);
2404	if (error)
2405		return error;
2406
2407	return wi_cmd(sc, WI_CMD_ACCESS | WI_ACCESS_WRITE, rid, 0, 0);
2408}
2409
2410static int
2411wi_newstate(void *arg, enum ieee80211_state nstate)
2412{
2413	struct wi_softc *sc = arg;
2414	struct ieee80211com *ic = &sc->sc_ic;
2415	struct ieee80211_node *ni = &ic->ic_bss;
2416	int i, buflen;
2417	u_int16_t val;
2418	struct wi_ssid ssid;
2419	u_int8_t old_bssid[IEEE80211_ADDR_LEN];
2420	enum ieee80211_state ostate;
2421#ifdef WI_DEBUG
2422	static const char *stname[] =
2423	    { "INIT", "SCAN", "AUTH", "ASSOC", "RUN" };
2424#endif /* WI_DEBUG */
2425
2426	ostate = ic->ic_state;
2427	DPRINTF(("wi_newstate: %s -> %s\n", stname[ostate], stname[nstate]));
2428
2429	ic->ic_state = nstate;
2430	switch (nstate) {
2431	case IEEE80211_S_INIT:
2432		ic->ic_flags &= ~IEEE80211_F_SIBSS;
2433		sc->sc_flags &= ~WI_FLAGS_OUTRANGE;
2434		return 0;
2435
2436	case IEEE80211_S_RUN:
2437		sc->sc_flags &= ~WI_FLAGS_OUTRANGE;
2438		buflen = IEEE80211_ADDR_LEN;
2439		wi_read_rid(sc, WI_RID_CURRENT_BSSID, ni->ni_bssid, &buflen);
2440		IEEE80211_ADDR_COPY(ni->ni_macaddr, ni->ni_bssid);
2441		buflen = sizeof(val);
2442		wi_read_rid(sc, WI_RID_CURRENT_CHAN, &val, &buflen);
2443		ni->ni_chan = le16toh(val);
2444
2445		if (IEEE80211_ADDR_EQ(old_bssid, ni->ni_bssid))
2446			sc->sc_false_syns++;
2447		else
2448			sc->sc_false_syns = 0;
2449
2450		if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
2451			ni->ni_esslen = ic->ic_des_esslen;
2452			memcpy(ni->ni_essid, ic->ic_des_essid, ni->ni_esslen);
2453			ni->ni_nrate = 0;
2454			for (i = 0; i < IEEE80211_RATE_SIZE; i++) {
2455				if (ic->ic_sup_rates[i])
2456					ni->ni_rates[ni->ni_nrate++] =
2457					    ic->ic_sup_rates[i];
2458			}
2459			ni->ni_intval = ic->ic_lintval;
2460			ni->ni_capinfo = IEEE80211_CAPINFO_ESS;
2461			if (ic->ic_flags & IEEE80211_F_WEPON)
2462				ni->ni_capinfo |= IEEE80211_CAPINFO_PRIVACY;
2463		} else {
2464			/* XXX check return value */
2465			buflen = sizeof(ssid);
2466			wi_read_rid(sc, WI_RID_CURRENT_SSID, &ssid, &buflen);
2467			ni->ni_esslen = le16toh(ssid.wi_len);
2468			if (ni->ni_esslen > IEEE80211_NWID_LEN)
2469				ni->ni_esslen = IEEE80211_NWID_LEN;	/*XXX*/
2470			memcpy(ni->ni_essid, ssid.wi_ssid, ni->ni_esslen);
2471		}
2472		break;
2473
2474	case IEEE80211_S_SCAN:
2475	case IEEE80211_S_AUTH:
2476	case IEEE80211_S_ASSOC:
2477		break;
2478	}
2479
2480	/* skip standard ieee80211 handling */
2481	return EINPROGRESS;
2482}
2483
2484static int
2485wi_scan_ap(struct wi_softc *sc)
2486{
2487	int error = 0;
2488	u_int16_t val[2];
2489
2490	if (!sc->sc_enabled)
2491		return ENXIO;
2492	switch (sc->sc_firmware_type) {
2493	case WI_LUCENT:
2494		(void)wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_SCAN_RESULTS, 0, 0);
2495		break;
2496	case WI_INTERSIL:
2497		val[0] = 0x3fff;	/* channel */
2498		val[1] = 0x000f;	/* tx rate */
2499		error = wi_write_rid(sc, WI_RID_SCAN_REQ, val, sizeof(val));
2500		break;
2501	case WI_SYMBOL:
2502		/*
2503		 * XXX only supported on 3.x ?
2504		 */
2505		val[0] = BSCAN_BCAST | BSCAN_ONETIME;
2506		error = wi_write_rid(sc, WI_RID_BCAST_SCAN_REQ,
2507		    val, sizeof(val[0]));
2508		break;
2509	}
2510	if (error == 0) {
2511		sc->sc_scan_timer = WI_SCAN_WAIT;
2512		sc->sc_ic.ic_if.if_timer = 1;
2513		DPRINTF(("wi_scan_ap: start scanning\n"));
2514	}
2515	return error;
2516}
2517
2518static void
2519wi_scan_result(struct wi_softc *sc, int fid, int cnt)
2520{
2521#define	N(a)	(sizeof (a) / sizeof (a[0]))
2522	int i, naps, off, szbuf;
2523	struct wi_scan_header ws_hdr;	/* Prism2 header */
2524	struct wi_scan_data_p2 ws_dat;	/* Prism2 scantable*/
2525	struct wi_apinfo *ap;
2526
2527	off = sizeof(u_int16_t) * 2;
2528	memset(&ws_hdr, 0, sizeof(ws_hdr));
2529	switch (sc->sc_firmware_type) {
2530	case WI_INTERSIL:
2531		wi_read_bap(sc, fid, off, &ws_hdr, sizeof(ws_hdr));
2532		off += sizeof(ws_hdr);
2533		szbuf = sizeof(struct wi_scan_data_p2);
2534		break;
2535	case WI_SYMBOL:
2536		szbuf = sizeof(struct wi_scan_data_p2) + 6;
2537		break;
2538	case WI_LUCENT:
2539		szbuf = sizeof(struct wi_scan_data);
2540		break;
2541	default:
2542		device_printf(sc->sc_dev,
2543			"wi_scan_result: unknown firmware type %u\n",
2544			sc->sc_firmware_type);
2545		naps = 0;
2546		goto done;
2547	}
2548	naps = (cnt * 2 + 2 - off) / szbuf;
2549	if (naps > N(sc->sc_aps))
2550		naps = N(sc->sc_aps);
2551	sc->sc_naps = naps;
2552	/* Read Data */
2553	ap = sc->sc_aps;
2554	memset(&ws_dat, 0, sizeof(ws_dat));
2555	for (i = 0; i < naps; i++, ap++) {
2556		wi_read_bap(sc, fid, off, &ws_dat,
2557		    (sizeof(ws_dat) < szbuf ? sizeof(ws_dat) : szbuf));
2558		DPRINTF2(("wi_scan_result: #%d: off %d bssid %s\n", i, off,
2559		    ether_sprintf(ws_dat.wi_bssid)));
2560		off += szbuf;
2561		ap->scanreason = le16toh(ws_hdr.wi_reason);
2562		memcpy(ap->bssid, ws_dat.wi_bssid, sizeof(ap->bssid));
2563		ap->channel = le16toh(ws_dat.wi_chid);
2564		ap->signal  = le16toh(ws_dat.wi_signal);
2565		ap->noise   = le16toh(ws_dat.wi_noise);
2566		ap->quality = ap->signal - ap->noise;
2567		ap->capinfo = le16toh(ws_dat.wi_capinfo);
2568		ap->interval = le16toh(ws_dat.wi_interval);
2569		ap->rate    = le16toh(ws_dat.wi_rate);
2570		ap->namelen = le16toh(ws_dat.wi_namelen);
2571		if (ap->namelen > sizeof(ap->name))
2572			ap->namelen = sizeof(ap->name);
2573		memcpy(ap->name, ws_dat.wi_name, ap->namelen);
2574	}
2575done:
2576	/* Done scanning */
2577	sc->sc_scan_timer = 0;
2578	DPRINTF(("wi_scan_result: scan complete: ap %d\n", naps));
2579#undef N
2580}
2581
2582static void
2583wi_dump_pkt(struct wi_frame *wh, struct ieee80211_node *ni, int rssi)
2584{
2585	ieee80211_dump_pkt((u_int8_t *) &wh->wi_whdr, sizeof(wh->wi_whdr),
2586	    ni ? ni->ni_rates[ni->ni_txrate] & IEEE80211_RATE_VAL : -1, rssi);
2587	printf(" status 0x%x rx_tstamp1 %u rx_tstamp0 0x%u rx_silence %u\n",
2588		le16toh(wh->wi_status), le16toh(wh->wi_rx_tstamp1),
2589		le16toh(wh->wi_rx_tstamp0), wh->wi_rx_silence);
2590	printf(" rx_signal %u rx_rate %u rx_flow %u\n",
2591		wh->wi_rx_signal, wh->wi_rx_rate, wh->wi_rx_flow);
2592	printf(" tx_rtry %u tx_rate %u tx_ctl 0x%x dat_len %u\n",
2593		wh->wi_tx_rtry, wh->wi_tx_rate,
2594		le16toh(wh->wi_tx_ctl), le16toh(wh->wi_dat_len));
2595	printf(" ehdr dst %6D src %6D type 0x%x\n",
2596		wh->wi_ehdr.ether_dhost, ":", wh->wi_ehdr.ether_shost, ":",
2597		wh->wi_ehdr.ether_type);
2598}
2599
2600int
2601wi_alloc(device_t dev, int rid)
2602{
2603	struct wi_softc	*sc = device_get_softc(dev);
2604
2605	if (sc->wi_bus_type != WI_BUS_PCI_NATIVE) {
2606		sc->iobase_rid = rid;
2607		sc->iobase = bus_alloc_resource(dev, SYS_RES_IOPORT,
2608		    &sc->iobase_rid, 0, ~0, (1 << 6),
2609		    rman_make_alignment_flags(1 << 6) | RF_ACTIVE);
2610		if (!sc->iobase) {
2611			device_printf(dev, "No I/O space?!\n");
2612			return (ENXIO);
2613		}
2614
2615		sc->wi_io_addr = rman_get_start(sc->iobase);
2616		sc->wi_btag = rman_get_bustag(sc->iobase);
2617		sc->wi_bhandle = rman_get_bushandle(sc->iobase);
2618	} else {
2619		sc->mem_rid = rid;
2620		sc->mem = bus_alloc_resource(dev, SYS_RES_MEMORY,
2621		    &sc->mem_rid, 0, ~0, 1, RF_ACTIVE);
2622
2623		if (!sc->mem) {
2624			device_printf(dev, "No Mem space on prism2.5?\n");
2625			return (ENXIO);
2626		}
2627
2628		sc->wi_btag = rman_get_bustag(sc->mem);
2629		sc->wi_bhandle = rman_get_bushandle(sc->mem);
2630	}
2631
2632
2633	sc->irq_rid = 0;
2634	sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irq_rid,
2635	    0, ~0, 1, RF_ACTIVE |
2636	    ((sc->wi_bus_type == WI_BUS_PCCARD) ? 0 : RF_SHAREABLE));
2637
2638	if (!sc->irq) {
2639		wi_free(dev);
2640		device_printf(dev, "No irq?!\n");
2641		return (ENXIO);
2642	}
2643
2644	sc->sc_dev = dev;
2645	sc->sc_unit = device_get_unit(dev);
2646
2647	return (0);
2648}
2649
2650void
2651wi_free(device_t dev)
2652{
2653	struct wi_softc	*sc = device_get_softc(dev);
2654
2655	if (sc->iobase != NULL) {
2656		bus_release_resource(dev, SYS_RES_IOPORT, sc->iobase_rid, sc->iobase);
2657		sc->iobase = NULL;
2658	}
2659	if (sc->irq != NULL) {
2660		bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq);
2661		sc->irq = NULL;
2662	}
2663	if (sc->mem != NULL) {
2664		bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem);
2665		sc->mem = NULL;
2666	}
2667
2668	return;
2669}
2670
2671static int
2672wi_get_debug(struct wi_softc *sc, struct wi_req *wreq)
2673{
2674	int error = 0;
2675
2676	wreq->wi_len = 1;
2677
2678	switch (wreq->wi_type) {
2679	case WI_DEBUG_SLEEP:
2680		wreq->wi_len++;
2681		wreq->wi_val[0] = sc->wi_debug.wi_sleep;
2682		break;
2683	case WI_DEBUG_DELAYSUPP:
2684		wreq->wi_len++;
2685		wreq->wi_val[0] = sc->wi_debug.wi_delaysupp;
2686		break;
2687	case WI_DEBUG_TXSUPP:
2688		wreq->wi_len++;
2689		wreq->wi_val[0] = sc->wi_debug.wi_txsupp;
2690		break;
2691	case WI_DEBUG_MONITOR:
2692		wreq->wi_len++;
2693		wreq->wi_val[0] = sc->wi_debug.wi_monitor;
2694		break;
2695	case WI_DEBUG_LEDTEST:
2696		wreq->wi_len += 3;
2697		wreq->wi_val[0] = sc->wi_debug.wi_ledtest;
2698		wreq->wi_val[1] = sc->wi_debug.wi_ledtest_param0;
2699		wreq->wi_val[2] = sc->wi_debug.wi_ledtest_param1;
2700		break;
2701	case WI_DEBUG_CONTTX:
2702		wreq->wi_len += 2;
2703		wreq->wi_val[0] = sc->wi_debug.wi_conttx;
2704		wreq->wi_val[1] = sc->wi_debug.wi_conttx_param0;
2705		break;
2706	case WI_DEBUG_CONTRX:
2707		wreq->wi_len++;
2708		wreq->wi_val[0] = sc->wi_debug.wi_contrx;
2709		break;
2710	case WI_DEBUG_SIGSTATE:
2711		wreq->wi_len += 2;
2712		wreq->wi_val[0] = sc->wi_debug.wi_sigstate;
2713		wreq->wi_val[1] = sc->wi_debug.wi_sigstate_param0;
2714		break;
2715	case WI_DEBUG_CONFBITS:
2716		wreq->wi_len += 2;
2717		wreq->wi_val[0] = sc->wi_debug.wi_confbits;
2718		wreq->wi_val[1] = sc->wi_debug.wi_confbits_param0;
2719		break;
2720	default:
2721		error = EIO;
2722		break;
2723	}
2724
2725	return (error);
2726}
2727
2728static int
2729wi_set_debug(struct wi_softc *sc, struct wi_req *wreq)
2730{
2731	int error = 0;
2732	u_int16_t		cmd, param0 = 0, param1 = 0;
2733
2734	switch (wreq->wi_type) {
2735	case WI_DEBUG_RESET:
2736	case WI_DEBUG_INIT:
2737	case WI_DEBUG_CALENABLE:
2738		break;
2739	case WI_DEBUG_SLEEP:
2740		sc->wi_debug.wi_sleep = 1;
2741		break;
2742	case WI_DEBUG_WAKE:
2743		sc->wi_debug.wi_sleep = 0;
2744		break;
2745	case WI_DEBUG_CHAN:
2746		param0 = wreq->wi_val[0];
2747		break;
2748	case WI_DEBUG_DELAYSUPP:
2749		sc->wi_debug.wi_delaysupp = 1;
2750		break;
2751	case WI_DEBUG_TXSUPP:
2752		sc->wi_debug.wi_txsupp = 1;
2753		break;
2754	case WI_DEBUG_MONITOR:
2755		sc->wi_debug.wi_monitor = 1;
2756		break;
2757	case WI_DEBUG_LEDTEST:
2758		param0 = wreq->wi_val[0];
2759		param1 = wreq->wi_val[1];
2760		sc->wi_debug.wi_ledtest = 1;
2761		sc->wi_debug.wi_ledtest_param0 = param0;
2762		sc->wi_debug.wi_ledtest_param1 = param1;
2763		break;
2764	case WI_DEBUG_CONTTX:
2765		param0 = wreq->wi_val[0];
2766		sc->wi_debug.wi_conttx = 1;
2767		sc->wi_debug.wi_conttx_param0 = param0;
2768		break;
2769	case WI_DEBUG_STOPTEST:
2770		sc->wi_debug.wi_delaysupp = 0;
2771		sc->wi_debug.wi_txsupp = 0;
2772		sc->wi_debug.wi_monitor = 0;
2773		sc->wi_debug.wi_ledtest = 0;
2774		sc->wi_debug.wi_ledtest_param0 = 0;
2775		sc->wi_debug.wi_ledtest_param1 = 0;
2776		sc->wi_debug.wi_conttx = 0;
2777		sc->wi_debug.wi_conttx_param0 = 0;
2778		sc->wi_debug.wi_contrx = 0;
2779		sc->wi_debug.wi_sigstate = 0;
2780		sc->wi_debug.wi_sigstate_param0 = 0;
2781		break;
2782	case WI_DEBUG_CONTRX:
2783		sc->wi_debug.wi_contrx = 1;
2784		break;
2785	case WI_DEBUG_SIGSTATE:
2786		param0 = wreq->wi_val[0];
2787		sc->wi_debug.wi_sigstate = 1;
2788		sc->wi_debug.wi_sigstate_param0 = param0;
2789		break;
2790	case WI_DEBUG_CONFBITS:
2791		param0 = wreq->wi_val[0];
2792		param1 = wreq->wi_val[1];
2793		sc->wi_debug.wi_confbits = param0;
2794		sc->wi_debug.wi_confbits_param0 = param1;
2795		break;
2796	default:
2797		error = EIO;
2798		break;
2799	}
2800
2801	if (error)
2802		return (error);
2803
2804	cmd = WI_CMD_DEBUG | (wreq->wi_type << 8);
2805	error = wi_cmd(sc, cmd, param0, param1, 0);
2806
2807	return (error);
2808}
2809
2810#if __FreeBSD_version >= 500000
2811/*
2812 * Special routines to download firmware for Symbol CF card.
2813 * XXX: This should be modified generic into any PRISM-2 based card.
2814 */
2815
2816#define	WI_SBCF_PDIADDR		0x3100
2817
2818/* unaligned load little endian */
2819#define	GETLE32(p)	((p)[0] | ((p)[1]<<8) | ((p)[2]<<16) | ((p)[3]<<24))
2820#define	GETLE16(p)	((p)[0] | ((p)[1]<<8))
2821
2822int
2823wi_symbol_load_firm(struct wi_softc *sc, const void *primsym, int primlen,
2824    const void *secsym, int seclen)
2825{
2826	uint8_t ebuf[256];
2827	int i;
2828
2829	/* load primary code and run it */
2830	wi_symbol_set_hcr(sc, WI_HCR_EEHOLD);
2831	if (wi_symbol_write_firm(sc, primsym, primlen, NULL, 0))
2832		return EIO;
2833	wi_symbol_set_hcr(sc, WI_HCR_RUN);
2834	for (i = 0; ; i++) {
2835		if (i == 10)
2836			return ETIMEDOUT;
2837		tsleep(sc, PWAIT, "wiinit", 1);
2838		if (CSR_READ_2(sc, WI_CNTL) == WI_CNTL_AUX_ENA_STAT)
2839			break;
2840		/* write the magic key value to unlock aux port */
2841		CSR_WRITE_2(sc, WI_PARAM0, WI_AUX_KEY0);
2842		CSR_WRITE_2(sc, WI_PARAM1, WI_AUX_KEY1);
2843		CSR_WRITE_2(sc, WI_PARAM2, WI_AUX_KEY2);
2844		CSR_WRITE_2(sc, WI_CNTL, WI_CNTL_AUX_ENA_CNTL);
2845	}
2846
2847	/* issue read EEPROM command: XXX copied from wi_cmd() */
2848	CSR_WRITE_2(sc, WI_PARAM0, 0);
2849	CSR_WRITE_2(sc, WI_PARAM1, 0);
2850	CSR_WRITE_2(sc, WI_PARAM2, 0);
2851	CSR_WRITE_2(sc, WI_COMMAND, WI_CMD_READEE);
2852        for (i = 0; i < WI_TIMEOUT; i++) {
2853                if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_CMD)
2854                        break;
2855                DELAY(1);
2856        }
2857        CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_CMD);
2858
2859	CSR_WRITE_2(sc, WI_AUX_PAGE, WI_SBCF_PDIADDR / WI_AUX_PGSZ);
2860	CSR_WRITE_2(sc, WI_AUX_OFFSET, WI_SBCF_PDIADDR % WI_AUX_PGSZ);
2861	CSR_READ_MULTI_STREAM_2(sc, WI_AUX_DATA,
2862	    (uint16_t *)ebuf, sizeof(ebuf) / 2);
2863	if (GETLE16(ebuf) > sizeof(ebuf))
2864		return EIO;
2865	if (wi_symbol_write_firm(sc, secsym, seclen, ebuf + 4, GETLE16(ebuf)))
2866		return EIO;
2867	return 0;
2868}
2869
2870static int
2871wi_symbol_write_firm(struct wi_softc *sc, const void *buf, int buflen,
2872    const void *ebuf, int ebuflen)
2873{
2874	const uint8_t *p, *ep, *q, *eq;
2875	char *tp;
2876	uint32_t addr, id, eid;
2877	int i, len, elen, nblk, pdrlen;
2878
2879	/*
2880	 * Parse the header of the firmware image.
2881	 */
2882	p = buf;
2883	ep = p + buflen;
2884	while (p < ep && *p++ != ' ');	/* FILE: */
2885	while (p < ep && *p++ != ' ');	/* filename */
2886	while (p < ep && *p++ != ' ');	/* type of the firmware */
2887	nblk = strtoul(p, &tp, 10);
2888	p = tp;
2889	pdrlen = strtoul(p + 1, &tp, 10);
2890	p = tp;
2891	while (p < ep && *p++ != 0x1a);	/* skip rest of header */
2892
2893	/*
2894	 * Block records: address[4], length[2], data[length];
2895	 */
2896	for (i = 0; i < nblk; i++) {
2897		addr = GETLE32(p);	p += 4;
2898		len  = GETLE16(p);	p += 2;
2899		CSR_WRITE_2(sc, WI_AUX_PAGE, addr / WI_AUX_PGSZ);
2900		CSR_WRITE_2(sc, WI_AUX_OFFSET, addr % WI_AUX_PGSZ);
2901		CSR_WRITE_MULTI_STREAM_2(sc, WI_AUX_DATA,
2902		    (const uint16_t *)p, len / 2);
2903		p += len;
2904	}
2905
2906	/*
2907	 * PDR: id[4], address[4], length[4];
2908	 */
2909	for (i = 0; i < pdrlen; ) {
2910		id   = GETLE32(p);	p += 4; i += 4;
2911		addr = GETLE32(p);	p += 4; i += 4;
2912		len  = GETLE32(p);	p += 4; i += 4;
2913		/* replace PDR entry with the values from EEPROM, if any */
2914		for (q = ebuf, eq = q + ebuflen; q < eq; q += elen * 2) {
2915			elen = GETLE16(q);	q += 2;
2916			eid  = GETLE16(q);	q += 2;
2917			elen--;		/* elen includes eid */
2918			if (eid == 0)
2919				break;
2920			if (eid != id)
2921				continue;
2922			CSR_WRITE_2(sc, WI_AUX_PAGE, addr / WI_AUX_PGSZ);
2923			CSR_WRITE_2(sc, WI_AUX_OFFSET, addr % WI_AUX_PGSZ);
2924			CSR_WRITE_MULTI_STREAM_2(sc, WI_AUX_DATA,
2925			    (const uint16_t *)q, len / 2);
2926			break;
2927		}
2928	}
2929	return 0;
2930}
2931
2932static int
2933wi_symbol_set_hcr(struct wi_softc *sc, int mode)
2934{
2935	uint16_t hcr;
2936
2937	CSR_WRITE_2(sc, WI_COR, WI_COR_RESET);
2938	tsleep(sc, PWAIT, "wiinit", 1);
2939	hcr = CSR_READ_2(sc, WI_HCR);
2940	hcr = (hcr & WI_HCR_4WIRE) | (mode & ~WI_HCR_4WIRE);
2941	CSR_WRITE_2(sc, WI_HCR, hcr);
2942	tsleep(sc, PWAIT, "wiinit", 1);
2943	CSR_WRITE_2(sc, WI_COR, WI_COR_IOMODE);
2944	tsleep(sc, PWAIT, "wiinit", 1);
2945	return 0;
2946}
2947#endif
2948