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