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