if_wi.c revision 111559
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 111559 2003-02-26 17:18:35Z sam $";
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		WI_UNLOCK(sc);
274		return ENXIO;		/* XXX */
275	}
276
277	/*
278	 * Read the station address.
279	 * And do it twice. I've seen PRISM-based cards that return
280	 * an error when trying to read it the first time, which causes
281	 * the probe to fail.
282	 */
283	buflen = IEEE80211_ADDR_LEN;
284	error = wi_read_rid(sc, WI_RID_MAC_NODE, ic->ic_myaddr, &buflen);
285	if (error != 0) {
286		buflen = IEEE80211_ADDR_LEN;
287		error = wi_read_rid(sc, WI_RID_MAC_NODE, ic->ic_myaddr, &buflen);
288	}
289	if (error || IEEE80211_ADDR_EQ(ic->ic_myaddr, empty_macaddr)) {
290		if (error != 0)
291			device_printf(dev, "mac read failed %d\n", error);
292		else
293			device_printf(dev, "mac read failed (all zeros)\n");
294		wi_free(dev);
295		return (error);
296	}
297	device_printf(dev, "802.11 address: %6D\n", ic->ic_myaddr, ":");
298
299	/* Read NIC identification */
300	wi_read_nicid(sc);
301
302	ifp->if_softc = sc;
303	ifp->if_unit = sc->sc_unit;
304	ifp->if_name = "wi";
305	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
306	ifp->if_ioctl = wi_ioctl;
307	ifp->if_start = wi_start;
308	ifp->if_watchdog = wi_watchdog;
309	ifp->if_init = wi_init;
310	ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
311
312	ic->ic_phytype = IEEE80211_T_DS;
313	ic->ic_opmode = IEEE80211_M_STA;
314	ic->ic_flags = IEEE80211_F_HASPMGT | IEEE80211_F_HASAHDEMO;
315	ic->ic_state = IEEE80211_S_INIT;
316	ic->ic_newstate = wi_newstate;
317
318	/* Find available channels */
319	buflen = sizeof(val);
320	if (wi_read_rid(sc, WI_RID_CHANNEL_LIST, &val, &buflen) != 0)
321		val = htole16(0x1fff);	/* assume 1-11 */
322	for (i = 0; i < 16; i++) {
323		if (isset((u_int8_t*)&val, i))
324			setbit(ic->ic_chan_avail, i + 1);
325	}
326	KASSERT(ic->ic_chan_avail != 0,
327		("wi_attach: no available channels listed!"));
328
329	/*
330	 * Read the default channel from the NIC. This may vary
331	 * depending on the country where the NIC was purchased, so
332	 * we can't hard-code a default and expect it to work for
333	 * everyone.
334	 */
335	buflen = sizeof(val);
336	if (wi_read_rid(sc, WI_RID_OWN_CHNL, &val, &buflen) == 0)
337		ic->ic_ibss_chan = le16toh(val);
338	else {
339		/* use lowest available channel */
340		for (i = 0; i < 16 && !isset(ic->ic_chan_avail, i); i++)
341			;
342		ic->ic_ibss_chan = i;
343	}
344
345	/*
346	 * Set flags based on firmware version.
347	 */
348	switch (sc->sc_firmware_type) {
349	case WI_LUCENT:
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_flags |= WI_FLAGS_HAS_FRAGTHR;
366		sc->sc_flags |= WI_FLAGS_HAS_ROAMING;
367		sc->sc_flags |= WI_FLAGS_HAS_SYSSCALE;
368		if (sc->sc_sta_firmware_ver > 10101)
369			sc->sc_flags |= WI_FLAGS_HAS_DBMADJUST;
370		if (sc->sc_sta_firmware_ver >= 800)
371			ic->ic_flags |= IEEE80211_F_HASIBSS;
372		/*
373		 * version 0.8.3 and newer are the only ones that are known
374		 * to currently work.  Earlier versions can be made to work,
375		 * at least according to the Linux driver.
376		 */
377		if (sc->sc_sta_firmware_ver >= 803)
378			ic->ic_flags |= IEEE80211_F_HASHOSTAP;
379		sc->sc_ibss_port = htole16(0);
380		break;
381
382	case WI_SYMBOL:
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	int i;
559	struct wi_softc *sc = arg;
560	struct ifnet *ifp = &sc->sc_ic.ic_if;
561	u_int16_t status, raw_status, last_status;
562	WI_LOCK_DECL();
563
564	WI_LOCK(sc);
565
566	if (sc->wi_gone || (ifp->if_flags & IFF_UP) == 0) {
567		CSR_WRITE_2(sc, WI_EVENT_ACK, ~0);
568		CSR_WRITE_2(sc, WI_INT_EN, 0);
569		WI_UNLOCK(sc);
570		return;
571	}
572
573	/* maximum 10 loops per interrupt */
574	last_status = 0;
575	for (i = 0; i < 10; i++) {
576		/*
577		 * Only believe a status bit when we enter wi_intr, or when
578		 * the bit was "off" the last time through the loop. This is
579		 * my strategy to avoid racing the hardware/firmware if I
580		 * can re-read the event status register more quickly than
581		 * it is updated.
582		 */
583		raw_status = CSR_READ_2(sc, WI_EVENT_STAT);
584		status = raw_status & ~last_status;
585		if ((status & WI_INTRS) == 0)
586			break;
587		last_status = raw_status;
588
589		if (status & WI_EV_RX)
590			wi_rx_intr(sc);
591
592		if (status & WI_EV_ALLOC)
593			wi_tx_intr(sc);
594
595		if (status & WI_EV_TX_EXC)
596			wi_tx_ex_intr(sc);
597
598		if (status & WI_EV_INFO)
599			wi_info_intr(sc);
600
601		if ((ifp->if_flags & IFF_OACTIVE) == 0 &&
602		    (sc->sc_flags & WI_FLAGS_OUTRANGE) == 0 &&
603		    _IF_QLEN(&ifp->if_snd) != 0)
604			wi_start(ifp);
605	}
606
607	WI_UNLOCK(sc);
608
609	return;
610}
611
612void
613wi_init(void *arg)
614{
615	struct wi_softc *sc = arg;
616	struct ifnet *ifp = &sc->sc_if;
617	struct ieee80211com *ic = &sc->sc_ic;
618	struct wi_joinreq join;
619	int i;
620	int error = 0, wasenabled;
621	struct ifaddr *ifa;
622	struct sockaddr_dl *sdl;
623	WI_LOCK_DECL();
624
625	WI_LOCK(sc);
626
627	if (sc->wi_gone) {
628		WI_UNLOCK(sc);
629		return;
630	}
631
632	wasenabled = sc->sc_enabled;
633	if (!sc->sc_enabled) {
634		sc->sc_enabled = 1;
635	} else
636		wi_stop(ifp, 0);
637
638	/* Symbol firmware cannot be initialized more than once */
639	if (sc->sc_firmware_type != WI_SYMBOL || !wasenabled)
640		wi_reset(sc);
641
642	/* common 802.11 configuration */
643	ic->ic_flags &= ~IEEE80211_F_IBSSON;
644	sc->sc_flags &= ~WI_FLAGS_OUTRANGE;
645	switch (ic->ic_opmode) {
646	case IEEE80211_M_STA:
647		wi_write_val(sc, WI_RID_PORTTYPE, WI_PORTTYPE_BSS);
648		break;
649	case IEEE80211_M_IBSS:
650		wi_write_val(sc, WI_RID_PORTTYPE, sc->sc_ibss_port);
651		ic->ic_flags |= IEEE80211_F_IBSSON;
652		break;
653	case IEEE80211_M_AHDEMO:
654		wi_write_val(sc, WI_RID_PORTTYPE, WI_PORTTYPE_ADHOC);
655		break;
656	case IEEE80211_M_HOSTAP:
657		wi_write_val(sc, WI_RID_PORTTYPE, WI_PORTTYPE_HOSTAP);
658		break;
659	}
660
661	/* Intersil interprets this RID as joining ESS even in IBSS mode */
662	if (sc->sc_firmware_type == WI_LUCENT &&
663	    (ic->ic_flags & IEEE80211_F_IBSSON) && ic->ic_des_esslen > 0)
664		wi_write_val(sc, WI_RID_CREATE_IBSS, 1);
665	else
666		wi_write_val(sc, WI_RID_CREATE_IBSS, 0);
667	wi_write_val(sc, WI_RID_MAX_SLEEP, ic->ic_lintval);
668	wi_write_ssid(sc, WI_RID_DESIRED_SSID, ic->ic_des_essid,
669	    ic->ic_des_esslen);
670	wi_write_val(sc, WI_RID_OWN_CHNL, ic->ic_ibss_chan);
671	wi_write_ssid(sc, WI_RID_OWN_SSID, ic->ic_des_essid, ic->ic_des_esslen);
672
673	ifa = ifaddr_byindex(ifp->if_index);
674	sdl = (struct sockaddr_dl *) ifa->ifa_addr;
675	IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(sdl));
676	wi_write_rid(sc, WI_RID_MAC_NODE, ic->ic_myaddr, IEEE80211_ADDR_LEN);
677
678	wi_write_val(sc, WI_RID_PM_ENABLED,
679	    (ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0);
680
681	/* not yet common 802.11 configuration */
682	wi_write_val(sc, WI_RID_MAX_DATALEN, sc->sc_max_datalen);
683	wi_write_val(sc, WI_RID_RTS_THRESH, sc->sc_rts_thresh);
684	if (sc->sc_flags & WI_FLAGS_HAS_FRAGTHR)
685		wi_write_val(sc, WI_RID_FRAG_THRESH, sc->sc_frag_thresh);
686
687	/* driver specific 802.11 configuration */
688	if (sc->sc_flags & WI_FLAGS_HAS_SYSSCALE)
689		wi_write_val(sc, WI_RID_SYSTEM_SCALE, sc->sc_system_scale);
690	if (sc->sc_flags & WI_FLAGS_HAS_ROAMING)
691		wi_write_val(sc, WI_RID_ROAMING_MODE, sc->sc_roaming_mode);
692	if (sc->sc_flags & WI_FLAGS_HAS_MOR)
693		wi_write_val(sc, WI_RID_MICROWAVE_OVEN, sc->sc_microwave_oven);
694	wi_write_txrate(sc);
695	wi_write_ssid(sc, WI_RID_NODENAME, sc->sc_nodename, sc->sc_nodelen);
696
697	if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
698	    sc->sc_firmware_type == WI_INTERSIL) {
699		wi_write_val(sc, WI_RID_OWN_BEACON_INT, ic->ic_lintval);
700		wi_write_val(sc, WI_RID_BASIC_RATE, 0x03);   /* 1, 2 */
701		wi_write_val(sc, WI_RID_SUPPORT_RATE, 0x0f); /* 1, 2, 5.5, 11 */
702		wi_write_val(sc, WI_RID_DTIM_PERIOD, 1);
703	}
704
705	/*
706	 * Initialize promisc mode.
707	 *	Being in the Host-AP mode causes a great
708	 *	deal of pain if primisc mode is set.
709	 *	Therefore we avoid confusing the firmware
710	 *	and always reset promisc mode in Host-AP
711	 *	mode.  Host-AP sees all the packets anyway.
712	 */
713	if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
714	    (ifp->if_flags & IFF_PROMISC) != 0) {
715		wi_write_val(sc, WI_RID_PROMISC, 1);
716	} else {
717		wi_write_val(sc, WI_RID_PROMISC, 0);
718	}
719
720	/* Configure WEP. */
721	if (ic->ic_flags & IEEE80211_F_HASWEP)
722		wi_write_wep(sc);
723
724	/* Set multicast filter. */
725	wi_write_multi(sc);
726
727	if (sc->sc_firmware_type != WI_SYMBOL || !wasenabled) {
728		sc->sc_buflen = IEEE80211_MAX_LEN + sizeof(struct wi_frame);
729		if (sc->sc_firmware_type == WI_SYMBOL)
730			sc->sc_buflen = 1585;	/* XXX */
731		for (i = 0; i < WI_NTXBUF; i++) {
732			error = wi_alloc_fid(sc, sc->sc_buflen,
733			    &sc->sc_txd[i].d_fid);
734			if (error) {
735				device_printf(sc->sc_dev,
736				    "tx buffer allocation failed (error %u)\n",
737				    error);
738				goto out;
739			}
740			sc->sc_txd[i].d_len = 0;
741		}
742	}
743	sc->sc_txcur = sc->sc_txnext = 0;
744
745	/* Enable desired port */
746	wi_cmd(sc, WI_CMD_ENABLE | sc->sc_portnum, 0, 0, 0);
747
748	ifp->if_flags |= IFF_RUNNING;
749	ifp->if_flags &= ~IFF_OACTIVE;
750	if (ic->ic_opmode == IEEE80211_M_AHDEMO ||
751	    ic->ic_opmode == IEEE80211_M_HOSTAP)
752		wi_newstate(sc, IEEE80211_S_RUN);
753
754	/* Enable interrupts */
755	CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
756
757	if (!wasenabled &&
758	    ic->ic_opmode == IEEE80211_M_HOSTAP &&
759	    sc->sc_firmware_type == WI_INTERSIL) {
760		/* XXX: some card need to be re-enabled for hostap */
761		wi_cmd(sc, WI_CMD_DISABLE | WI_PORT0, 0, 0, 0);
762		wi_cmd(sc, WI_CMD_ENABLE | WI_PORT0, 0, 0, 0);
763	}
764
765	if (ic->ic_opmode == IEEE80211_M_STA &&
766	    ((ic->ic_flags & IEEE80211_F_DESBSSID) ||
767	    ic->ic_des_chan != IEEE80211_CHAN_ANY)) {
768		memset(&join, 0, sizeof(join));
769		if (ic->ic_flags & IEEE80211_F_DESBSSID)
770			IEEE80211_ADDR_COPY(&join.wi_bssid, ic->ic_des_bssid);
771		if (ic->ic_des_chan != IEEE80211_CHAN_ANY)
772			join.wi_chan = htole16(ic->ic_des_chan);
773		/* Lucent firmware does not support the JOIN RID. */
774		if (sc->sc_firmware_type != WI_LUCENT)
775			wi_write_rid(sc, WI_RID_JOIN_REQ, &join, sizeof(join));
776	}
777
778	WI_UNLOCK(sc);
779	return;
780out:
781	if (error) {
782		if_printf(ifp, "interface not running\n");
783		wi_stop(ifp, 0);
784	}
785	WI_UNLOCK(sc);
786	DPRINTF(("wi_init: return %d\n", error));
787	return;
788}
789
790void
791wi_stop(struct ifnet *ifp, int disable)
792{
793	struct wi_softc *sc = ifp->if_softc;
794	WI_LOCK_DECL();
795
796	WI_LOCK(sc);
797
798	ieee80211_new_state(ifp, IEEE80211_S_INIT, -1);
799	if (sc->sc_enabled && !sc->wi_gone) {
800		CSR_WRITE_2(sc, WI_INT_EN, 0);
801		wi_cmd(sc, WI_CMD_DISABLE | sc->sc_portnum, 0, 0, 0);
802		if (disable) {
803#ifdef __NetBSD__
804			if (sc->sc_disable)
805				(*sc->sc_disable)(sc);
806#endif
807			sc->sc_enabled = 0;
808		}
809	}
810
811	sc->sc_tx_timer = 0;
812	sc->sc_scan_timer = 0;
813	sc->sc_syn_timer = 0;
814	sc->sc_false_syns = 0;
815	sc->sc_naps = 0;
816	ifp->if_flags &= ~(IFF_OACTIVE | IFF_RUNNING);
817	ifp->if_timer = 0;
818
819	WI_UNLOCK(sc);
820}
821
822static void
823wi_start(struct ifnet *ifp)
824{
825	struct wi_softc	*sc = ifp->if_softc;
826	struct ieee80211com *ic = &sc->sc_ic;
827	struct ieee80211_node *ni = NULL;
828	struct ieee80211_frame *wh;
829	struct mbuf *m0;
830	struct wi_frame frmhdr;
831	int cur, fid, off;
832	WI_LOCK_DECL();
833
834	WI_LOCK(sc);
835
836	if (sc->wi_gone) {
837		WI_UNLOCK(sc);
838		return;
839	}
840	if (sc->sc_flags & WI_FLAGS_OUTRANGE) {
841		WI_UNLOCK(sc);
842		return;
843	}
844	KASSERT((ifp->if_flags & IFF_OACTIVE) == 0,
845		("wi_start: if_flags %x\n", ifp->if_flags));
846
847	memset(&frmhdr, 0, sizeof(frmhdr));
848	cur = sc->sc_txnext;
849	for (;;) {
850		IF_POLL(&ic->ic_mgtq, m0);
851		if (m0 != NULL) {
852			if (sc->sc_txd[cur].d_len != 0) {
853				ifp->if_flags |= IFF_OACTIVE;
854				break;
855			}
856			IF_DEQUEUE(&ic->ic_mgtq, m0);
857			m_copydata(m0, 4, ETHER_ADDR_LEN * 2,
858			    (caddr_t)&frmhdr.wi_ehdr);
859			frmhdr.wi_ehdr.ether_type = 0;
860                        wh = mtod(m0, struct ieee80211_frame *);
861		} else {
862			if (ic->ic_state != IEEE80211_S_RUN)
863				break;
864			IFQ_POLL(&ifp->if_snd, m0);
865			if (m0 == NULL)
866				break;
867			if (sc->sc_txd[cur].d_len != 0) {
868				ifp->if_flags |= IFF_OACTIVE;
869				break;
870			}
871			IFQ_DEQUEUE(&ifp->if_snd, m0);
872			ifp->if_opackets++;
873			m_copydata(m0, 0, ETHER_HDR_LEN,
874			    (caddr_t)&frmhdr.wi_ehdr);
875#if NBPFILTER > 0
876			BPF_MTAP(ifp, m0);
877#endif
878
879			if ((m0 = ieee80211_encap(ifp, m0)) == NULL) {
880				ifp->if_oerrors++;
881				continue;
882			}
883                        wh = mtod(m0, struct ieee80211_frame *);
884			if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
885			    !IEEE80211_IS_MULTICAST(wh->i_addr1) &&
886			    (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
887			    IEEE80211_FC0_TYPE_DATA &&
888			    ((ni = ieee80211_find_node(ic, wh->i_addr1)) ==
889			    NULL || ni->ni_associd == 0)) {
890				m_freem(m0);
891				ifp->if_oerrors++;
892				continue;
893			}
894			if (ic->ic_flags & IEEE80211_F_WEPON)
895				wh->i_fc[1] |= IEEE80211_FC1_WEP;
896
897		}
898#if NBPFILTER > 0
899		if (ic->ic_rawbpf)
900			bpf_mtap(ic->ic_rawbpf, m0);
901#endif
902		frmhdr.wi_tx_ctl = htole16(WI_ENC_TX_802_11|WI_TXCNTL_TX_EX);
903		if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
904		    (wh->i_fc[1] & IEEE80211_FC1_WEP)) {
905			if ((m0 = ieee80211_wep_crypt(ifp, m0, 1)) == NULL) {
906				ifp->if_oerrors++;
907				continue;
908			}
909			frmhdr.wi_tx_ctl |= htole16(WI_TXCNTL_NOCRYPT);
910		}
911		m_copydata(m0, 0, sizeof(struct ieee80211_frame),
912		    (caddr_t)&frmhdr.wi_whdr);
913		m_adj(m0, sizeof(struct ieee80211_frame));
914		frmhdr.wi_dat_len = htole16(m0->m_pkthdr.len);
915#if NBPFILTER > 0
916		if (sc->sc_drvbpf) {
917			struct mbuf *mb;
918
919			MGETHDR(mb, M_DONTWAIT, m0->m_type);
920			if (mb != NULL) {
921				(void) m_dup_pkthdr(mb, m0, M_DONTWAIT);
922				mb->m_next = m0;
923				mb->m_data = (caddr_t)&frmhdr;
924				mb->m_len = sizeof(frmhdr);
925				mb->m_pkthdr.len += mb->m_len;
926				bpf_mtap(sc->sc_drvbpf, mb);
927				m_free(mb);
928			}
929		}
930#endif
931		if (IFF_DUMPPKTS(ifp))
932			wi_dump_pkt(&frmhdr, ni, -1);
933		fid = sc->sc_txd[cur].d_fid;
934		off = sizeof(frmhdr);
935		if (wi_write_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr)) != 0 ||
936		    wi_mwrite_bap(sc, fid, off, m0, m0->m_pkthdr.len) != 0) {
937			ifp->if_oerrors++;
938			m_freem(m0);
939			continue;
940		}
941		m_freem(m0);
942		sc->sc_txd[cur].d_len = off;
943		if (sc->sc_txcur == cur) {
944			if (wi_cmd(sc, WI_CMD_TX | WI_RECLAIM, fid, 0, 0)) {
945				if_printf(ifp, "xmit failed\n");
946				sc->sc_txd[cur].d_len = 0;
947				continue;
948			}
949			sc->sc_tx_timer = 5;
950			ifp->if_timer = 1;
951		}
952		sc->sc_txnext = cur = (cur + 1) % WI_NTXBUF;
953	}
954
955	WI_UNLOCK(sc);
956}
957
958static int
959wi_reset(struct wi_softc *sc)
960{
961#define WI_INIT_TRIES 5
962	int i, error;
963
964	for (i = 0; i < WI_INIT_TRIES; i++) {
965		if ((error = wi_cmd(sc, WI_CMD_INI, 0, 0, 0)) == 0)
966			break;
967		DELAY(WI_DELAY * 1000);
968	}
969
970	if (error) {
971		device_printf(sc->sc_dev, "init failed\n");
972		return error;
973	}
974
975	CSR_WRITE_2(sc, WI_INT_EN, 0);
976	CSR_WRITE_2(sc, WI_EVENT_ACK, ~0);
977
978	/* Calibrate timer. */
979	wi_write_val(sc, WI_RID_TICK_TIME, 0);
980	return 0;
981#undef WI_INIT_TRIES
982}
983
984static void
985wi_watchdog(struct ifnet *ifp)
986{
987	struct wi_softc	*sc = ifp->if_softc;
988
989	ifp->if_timer = 0;
990	if (!sc->sc_enabled)
991		return;
992
993	if (sc->sc_tx_timer) {
994		if (--sc->sc_tx_timer == 0) {
995			if_printf(ifp, "device timeout\n");
996			ifp->if_oerrors++;
997			wi_init(ifp->if_softc);
998			return;
999		}
1000		ifp->if_timer = 1;
1001	}
1002
1003	if (sc->sc_scan_timer) {
1004		if (--sc->sc_scan_timer <= WI_SCAN_WAIT - WI_SCAN_INQWAIT &&
1005		    sc->sc_firmware_type == WI_INTERSIL) {
1006			DPRINTF(("wi_watchdog: inquire scan\n"));
1007			wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_SCAN_RESULTS, 0, 0);
1008		}
1009		if (sc->sc_scan_timer)
1010			ifp->if_timer = 1;
1011	}
1012
1013	if (sc->sc_syn_timer) {
1014		if (--sc->sc_syn_timer == 0) {
1015			DPRINTF2(("wi_watchdog: %d false syns\n",
1016			    sc->sc_false_syns));
1017			sc->sc_false_syns = 0;
1018			ieee80211_new_state(ifp, IEEE80211_S_RUN, -1);
1019			sc->sc_syn_timer = 5;
1020		}
1021		ifp->if_timer = 1;
1022	}
1023
1024	/* TODO: rate control */
1025	ieee80211_watchdog(ifp);
1026}
1027
1028static int
1029wi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1030{
1031	struct wi_softc *sc = ifp->if_softc;
1032	struct ieee80211com *ic = &sc->sc_ic;
1033	struct ifreq *ifr = (struct ifreq *)data;
1034	struct ieee80211req *ireq;
1035	u_int8_t nodename[IEEE80211_NWID_LEN];
1036	int error = 0;
1037#if __FreeBSD_version >= 500000
1038	struct thread *td = curthread;
1039#else
1040	struct proc *td = curproc;		/* Little white lie */
1041#endif
1042	struct wi_req wreq;
1043	WI_LOCK_DECL();
1044
1045	WI_LOCK(sc);
1046
1047	if (sc->wi_gone) {
1048		error = ENODEV;
1049		goto out;
1050	}
1051
1052	switch (cmd) {
1053	case SIOCSIFFLAGS:
1054		/*
1055		 * Can't do promisc and hostap at the same time.  If all that's
1056		 * changing is the promisc flag, try to short-circuit a call to
1057		 * wi_init() by just setting PROMISC in the hardware.
1058		 */
1059		if (ifp->if_flags & IFF_UP) {
1060			if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
1061			    ifp->if_flags & IFF_RUNNING) {
1062				if (ifp->if_flags & IFF_PROMISC &&
1063				    !(sc->sc_if_flags & IFF_PROMISC)) {
1064					wi_write_val(sc, WI_RID_PROMISC, 1);
1065				} else if (!(ifp->if_flags & IFF_PROMISC) &&
1066				    sc->sc_if_flags & IFF_PROMISC) {
1067					wi_write_val(sc, WI_RID_PROMISC, 0);
1068				} else {
1069					wi_init(sc);
1070				}
1071			} else {
1072				wi_init(sc);
1073			}
1074		} else {
1075			if (ifp->if_flags & IFF_RUNNING) {
1076				wi_stop(ifp, 0);
1077			}
1078		}
1079		sc->sc_if_flags = ifp->if_flags;
1080		error = 0;
1081		break;
1082	case SIOCSIFMEDIA:
1083	case SIOCGIFMEDIA:
1084		error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
1085		break;
1086	case SIOCADDMULTI:
1087	case SIOCDELMULTI:
1088		error = wi_write_multi(sc);
1089		break;
1090	case SIOCGIFGENERIC:
1091		error = wi_get_cfg(ifp, cmd, data);
1092		break;
1093	case SIOCSIFGENERIC:
1094		error = suser(td);
1095		if (error)
1096			break;
1097		error = wi_set_cfg(ifp, cmd, data);
1098		break;
1099	case SIOCGPRISM2DEBUG:
1100		error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
1101		if (error)
1102			break;
1103		if (!(ifp->if_flags & IFF_RUNNING) ||
1104		    sc->sc_firmware_type == WI_LUCENT) {
1105			error = EIO;
1106			break;
1107		}
1108		error = wi_get_debug(sc, &wreq);
1109		if (error == 0)
1110			error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
1111		break;
1112	case SIOCSPRISM2DEBUG:
1113		if ((error = suser(td)))
1114			goto out;
1115		error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
1116		if (error)
1117			break;
1118		error = wi_set_debug(sc, &wreq);
1119		break;
1120	case SIOCG80211:
1121		ireq = (struct ieee80211req *) data;
1122		switch (ireq->i_type) {
1123		case IEEE80211_IOC_STATIONNAME:
1124			ireq->i_len = sc->sc_nodelen + 1;
1125			error = copyout(sc->sc_nodename, ireq->i_data,
1126					ireq->i_len);
1127			break;
1128		default:
1129			error = ieee80211_ioctl(ifp, cmd, data);
1130			break;
1131		}
1132		break;
1133	case SIOCS80211:
1134		error = suser(td);
1135		if (error)
1136			break;
1137		ireq = (struct ieee80211req *) data;
1138		switch (ireq->i_type) {
1139		case IEEE80211_IOC_STATIONNAME:
1140			if (ireq->i_val != 0 ||
1141			    ireq->i_len > IEEE80211_NWID_LEN) {
1142				error = EINVAL;
1143				break;
1144			}
1145			memset(nodename, 0, IEEE80211_NWID_LEN);
1146			error = copyin(ireq->i_data, nodename, ireq->i_len);
1147			if (error)
1148				break;
1149			if (sc->sc_enabled) {
1150				error = wi_write_ssid(sc, WI_RID_NODENAME,
1151					nodename, ireq->i_len);
1152				if (error)
1153					break;
1154			}
1155			memcpy(sc->sc_nodename, nodename, IEEE80211_NWID_LEN);
1156			sc->sc_nodelen = ireq->i_len;
1157			break;
1158		default:
1159			error = ieee80211_ioctl(ifp, cmd, data);
1160			break;
1161		}
1162		break;
1163	default:
1164		error = ieee80211_ioctl(ifp, cmd, data);
1165		break;
1166	}
1167	if (error == ENETRESET) {
1168		if (sc->sc_enabled)
1169			wi_init(ifp->if_softc);	/* XXX no error return */
1170		error = 0;
1171	}
1172out:
1173	WI_UNLOCK(sc);
1174
1175	return (error);
1176}
1177
1178static int
1179wi_media_change(struct ifnet *ifp)
1180{
1181	struct wi_softc *sc = ifp->if_softc;
1182	struct ieee80211com *ic = &sc->sc_ic;
1183	struct ifmedia_entry *ime;
1184	enum ieee80211_opmode newmode;
1185	int i, rate, error = 0;
1186
1187	ime = sc->sc_media.ifm_cur;
1188	if (IFM_SUBTYPE(ime->ifm_media) == IFM_AUTO) {
1189		i = -1;
1190	} else {
1191		rate = ieee80211_media2rate(ime->ifm_media, IEEE80211_T_DS);
1192		if (rate == 0)
1193			return EINVAL;
1194		for (i = 0; i < IEEE80211_RATE_SIZE; i++) {
1195			if ((ic->ic_sup_rates[i] & IEEE80211_RATE_VAL) == rate)
1196				break;
1197		}
1198		if (i == IEEE80211_RATE_SIZE)
1199			return EINVAL;
1200	}
1201	if (ic->ic_fixed_rate != i) {
1202		ic->ic_fixed_rate = i;
1203		error = ENETRESET;
1204	}
1205
1206	if ((ime->ifm_media & IFM_IEEE80211_ADHOC) &&
1207	    (ime->ifm_media & IFM_FLAG0))
1208		newmode = IEEE80211_M_AHDEMO;
1209	else if (ime->ifm_media & IFM_IEEE80211_ADHOC)
1210		newmode = IEEE80211_M_IBSS;
1211	else if (ime->ifm_media & IFM_IEEE80211_HOSTAP)
1212		newmode = IEEE80211_M_HOSTAP;
1213	else
1214		newmode = IEEE80211_M_STA;
1215	if (ic->ic_opmode != newmode) {
1216		ic->ic_opmode = newmode;
1217		error = ENETRESET;
1218	}
1219	if (error == ENETRESET) {
1220		if (sc->sc_enabled)
1221			wi_init(ifp->if_softc); /* XXX error code lost */
1222		error = 0;
1223	}
1224#if 0
1225	ifp->if_baudrate = ifmedia_baudrate(sc->sc_media.ifm_cur->ifm_media);
1226#endif
1227	return error;
1228}
1229
1230static void
1231wi_media_status(struct ifnet *ifp, struct ifmediareq *imr)
1232{
1233	struct wi_softc *sc = ifp->if_softc;
1234	struct ieee80211com *ic = &sc->sc_ic;
1235	u_int16_t val;
1236	int rate, len;
1237
1238	if (sc->wi_gone || !sc->sc_enabled) {
1239		imr->ifm_active = IFM_IEEE80211 | IFM_NONE;
1240		imr->ifm_status = 0;
1241		return;
1242	}
1243
1244	imr->ifm_status = IFM_AVALID;
1245	imr->ifm_active = IFM_IEEE80211;
1246	if (ic->ic_state == IEEE80211_S_RUN &&
1247	    (sc->sc_flags & WI_FLAGS_OUTRANGE) == 0)
1248		imr->ifm_status |= IFM_ACTIVE;
1249	len = sizeof(val);
1250	if (wi_read_rid(sc, WI_RID_CUR_TX_RATE, &val, &len) != 0)
1251		rate = 0;
1252	else {
1253		/* convert to 802.11 rate */
1254		rate = val * 2;
1255		if (sc->sc_firmware_type == WI_LUCENT) {
1256			if (rate == 10)
1257				rate = 11;	/* 5.5Mbps */
1258		} else {
1259			if (rate == 4*2)
1260				rate = 11;	/* 5.5Mbps */
1261			else if (rate == 8*2)
1262				rate = 22;	/* 11Mbps */
1263		}
1264	}
1265	imr->ifm_active |= ieee80211_rate2media(rate, IEEE80211_T_DS);
1266	switch (ic->ic_opmode) {
1267	case IEEE80211_M_STA:
1268		break;
1269	case IEEE80211_M_IBSS:
1270		imr->ifm_active |= IFM_IEEE80211_ADHOC;
1271		break;
1272	case IEEE80211_M_AHDEMO:
1273		imr->ifm_active |= IFM_IEEE80211_ADHOC | IFM_FLAG0;
1274		break;
1275	case IEEE80211_M_HOSTAP:
1276		imr->ifm_active |= IFM_IEEE80211_HOSTAP;
1277		break;
1278	}
1279}
1280
1281static void
1282wi_sync_bssid(struct wi_softc *sc, u_int8_t new_bssid[IEEE80211_ADDR_LEN])
1283{
1284	struct ieee80211com *ic = &sc->sc_ic;
1285	struct ieee80211_node *ni = &ic->ic_bss;
1286	struct ifnet *ifp = &ic->ic_if;
1287
1288	if (IEEE80211_ADDR_EQ(new_bssid, ni->ni_bssid))
1289		return;
1290
1291	DPRINTF(("wi_sync_bssid: bssid %s -> ", ether_sprintf(ni->ni_bssid)));
1292	DPRINTF(("%s ?\n", ether_sprintf(new_bssid)));
1293
1294	/* In promiscuous mode, the BSSID field is not a reliable
1295	 * indicator of the firmware's BSSID. Damp spurious
1296	 * change-of-BSSID indications.
1297	 */
1298	if ((ifp->if_flags & IFF_PROMISC) != 0 &&
1299	    sc->sc_false_syns >= WI_MAX_FALSE_SYNS)
1300		return;
1301
1302	ieee80211_new_state(ifp, IEEE80211_S_RUN, -1);
1303}
1304
1305static void
1306wi_rx_intr(struct wi_softc *sc)
1307{
1308	struct ieee80211com *ic = &sc->sc_ic;
1309	struct ifnet *ifp = &ic->ic_if;
1310	struct wi_frame frmhdr;
1311	struct mbuf *m;
1312	struct ieee80211_frame *wh;
1313	int fid, len, off, rssi;
1314	u_int8_t dir;
1315	u_int16_t status;
1316	u_int32_t rstamp;
1317
1318	fid = CSR_READ_2(sc, WI_RX_FID);
1319
1320	/* First read in the frame header */
1321	if (wi_read_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr))) {
1322		CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
1323		ifp->if_ierrors++;
1324		DPRINTF(("wi_rx_intr: read fid %x failed\n", fid));
1325		return;
1326	}
1327
1328	if (IFF_DUMPPKTS(ifp))
1329		wi_dump_pkt(&frmhdr, NULL, frmhdr.wi_rx_signal);
1330
1331	/*
1332	 * Drop undecryptable or packets with receive errors here
1333	 */
1334	status = le16toh(frmhdr.wi_status);
1335	if (status & WI_STAT_ERRSTAT) {
1336		CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
1337		ifp->if_ierrors++;
1338		DPRINTF(("wi_rx_intr: fid %x error status %x\n", fid, status));
1339		return;
1340	}
1341	rssi = frmhdr.wi_rx_signal;
1342	rstamp = (le16toh(frmhdr.wi_rx_tstamp0) << 16) |
1343	    le16toh(frmhdr.wi_rx_tstamp1);
1344
1345	len = le16toh(frmhdr.wi_dat_len);
1346	off = ALIGN(sizeof(struct ieee80211_frame));
1347
1348	MGETHDR(m, M_DONTWAIT, MT_DATA);
1349	if (m == NULL) {
1350		CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
1351		ifp->if_ierrors++;
1352		DPRINTF(("wi_rx_intr: MGET failed\n"));
1353		return;
1354	}
1355	if (off + len > MHLEN) {
1356		MCLGET(m, M_DONTWAIT);
1357		if ((m->m_flags & M_EXT) == 0) {
1358			CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
1359			m_freem(m);
1360			ifp->if_ierrors++;
1361			DPRINTF(("wi_rx_intr: MCLGET failed\n"));
1362			return;
1363		}
1364	}
1365
1366	m->m_data += off - sizeof(struct ieee80211_frame);
1367	memcpy(m->m_data, &frmhdr.wi_whdr, sizeof(struct ieee80211_frame));
1368	wi_read_bap(sc, fid, sizeof(frmhdr),
1369	    m->m_data + sizeof(struct ieee80211_frame), len);
1370	m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame) + len;
1371	m->m_pkthdr.rcvif = ifp;
1372
1373	CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
1374
1375#if NBPFILTER > 0
1376	if (sc->sc_drvbpf) {
1377		struct mbuf *mb;
1378
1379		MGETHDR(mb, M_DONTWAIT, m->m_type);
1380		if (mb != NULL) {
1381			(void) m_dup_pkthdr(mb, m, M_DONTWAIT);
1382			mb->m_next = m;
1383			mb->m_data = (caddr_t)&frmhdr;
1384			mb->m_len = sizeof(frmhdr);
1385			mb->m_pkthdr.len += mb->m_len;
1386			bpf_mtap(sc->sc_drvbpf, mb);
1387			m_free(mb);
1388		}
1389	}
1390#endif
1391	wh = mtod(m, struct ieee80211_frame *);
1392	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
1393		/*
1394		 * WEP is decrypted by hardware. Clear WEP bit
1395		 * header for ieee80211_input().
1396		 */
1397		wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
1398	}
1399
1400	/* synchronize driver's BSSID with firmware's BSSID */
1401	dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;
1402	if (ic->ic_opmode == IEEE80211_M_IBSS && dir == IEEE80211_FC1_DIR_NODS)
1403		wi_sync_bssid(sc, wh->i_addr3);
1404
1405	ieee80211_input(ifp, m, rssi, rstamp);
1406}
1407
1408static void
1409wi_tx_ex_intr(struct wi_softc *sc)
1410{
1411	struct ieee80211com *ic = &sc->sc_ic;
1412	struct ifnet *ifp = &ic->ic_if;
1413	struct wi_frame frmhdr;
1414	int fid;
1415
1416	fid = CSR_READ_2(sc, WI_TX_CMP_FID);
1417	/* Read in the frame header */
1418	if (wi_read_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr)) == 0) {
1419		u_int16_t status = le16toh(frmhdr.wi_status);
1420
1421		/*
1422		 * Spontaneous station disconnects appear as xmit
1423		 * errors.  Don't announce them and/or count them
1424		 * as an output error.
1425		 */
1426		if ((status & WI_TXSTAT_DISCONNECT) == 0) {
1427			if (ppsratecheck(&lasttxerror, &curtxeps, wi_txerate)) {
1428				if_printf(ifp, "tx failed");
1429				if (status & WI_TXSTAT_RET_ERR)
1430					printf(", retry limit exceeded");
1431				if (status & WI_TXSTAT_AGED_ERR)
1432					printf(", max transmit lifetime exceeded");
1433				if (status & WI_TXSTAT_DISCONNECT)
1434					printf(", port disconnected");
1435				if (status & WI_TXSTAT_FORM_ERR)
1436					printf(", invalid format (data len %u src %6D)",
1437						le16toh(frmhdr.wi_dat_len),
1438						frmhdr.wi_ehdr.ether_shost, ":");
1439				if (status & ~0xf)
1440					printf(", status=0x%x", status);
1441				printf("\n");
1442			}
1443			ifp->if_oerrors++;
1444		} else {
1445			DPRINTF(("port disconnected\n"));
1446			ifp->if_collisions++;	/* XXX */
1447		}
1448	} else
1449		DPRINTF(("wi_tx_ex_intr: read fid %x failed\n", fid));
1450	CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX_EXC);
1451}
1452
1453static void
1454wi_tx_intr(struct wi_softc *sc)
1455{
1456	struct ieee80211com *ic = &sc->sc_ic;
1457	struct ifnet *ifp = &ic->ic_if;
1458	int fid, cur;
1459
1460	fid = CSR_READ_2(sc, WI_ALLOC_FID);
1461	CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC);
1462
1463	cur = sc->sc_txcur;
1464	if (sc->sc_txd[cur].d_fid != fid) {
1465		if_printf(ifp, "bad alloc %x != %x, cur %d nxt %d\n",
1466		    fid, sc->sc_txd[cur].d_fid, cur, sc->sc_txnext);
1467		return;
1468	}
1469	sc->sc_tx_timer = 0;
1470	sc->sc_txd[cur].d_len = 0;
1471	sc->sc_txcur = cur = (cur + 1) % WI_NTXBUF;
1472	if (sc->sc_txd[cur].d_len == 0)
1473		ifp->if_flags &= ~IFF_OACTIVE;
1474	else {
1475		if (wi_cmd(sc, WI_CMD_TX | WI_RECLAIM, sc->sc_txd[cur].d_fid,
1476		    0, 0)) {
1477			if_printf(ifp, "xmit failed\n");
1478			sc->sc_txd[cur].d_len = 0;
1479		} else {
1480			sc->sc_tx_timer = 5;
1481			ifp->if_timer = 1;
1482		}
1483	}
1484}
1485
1486static void
1487wi_info_intr(struct wi_softc *sc)
1488{
1489	struct ieee80211com *ic = &sc->sc_ic;
1490	struct ifnet *ifp = &ic->ic_if;
1491	int i, fid, len, off;
1492	u_int16_t ltbuf[2];
1493	u_int16_t stat;
1494	u_int32_t *ptr;
1495
1496	fid = CSR_READ_2(sc, WI_INFO_FID);
1497	wi_read_bap(sc, fid, 0, ltbuf, sizeof(ltbuf));
1498
1499	switch (le16toh(ltbuf[1])) {
1500
1501	case WI_INFO_LINK_STAT:
1502		wi_read_bap(sc, fid, sizeof(ltbuf), &stat, sizeof(stat));
1503		DPRINTF(("wi_info_intr: LINK_STAT 0x%x\n", le16toh(stat)));
1504		switch (le16toh(stat)) {
1505		case WI_INFO_LINK_STAT_CONNECTED:
1506			sc->sc_flags &= ~WI_FLAGS_OUTRANGE;
1507			if (ic->ic_state == IEEE80211_S_RUN &&
1508			    ic->ic_opmode != IEEE80211_M_IBSS)
1509				break;
1510			/* FALLTHROUGH */
1511		case WI_INFO_LINK_STAT_AP_CHG:
1512			ieee80211_new_state(ifp, IEEE80211_S_RUN, -1);
1513			break;
1514		case WI_INFO_LINK_STAT_AP_INR:
1515			sc->sc_flags &= ~WI_FLAGS_OUTRANGE;
1516			break;
1517		case WI_INFO_LINK_STAT_AP_OOR:
1518			if (sc->sc_firmware_type == WI_SYMBOL &&
1519			    sc->sc_scan_timer > 0) {
1520				if (wi_cmd(sc, WI_CMD_INQUIRE,
1521				    WI_INFO_HOST_SCAN_RESULTS, 0, 0) != 0)
1522					sc->sc_scan_timer = 0;
1523				break;
1524			}
1525			if (ic->ic_opmode == IEEE80211_M_STA)
1526				sc->sc_flags |= WI_FLAGS_OUTRANGE;
1527			break;
1528		case WI_INFO_LINK_STAT_DISCONNECTED:
1529		case WI_INFO_LINK_STAT_ASSOC_FAILED:
1530			if (ic->ic_opmode == IEEE80211_M_STA)
1531				ieee80211_new_state(ifp, IEEE80211_S_INIT, -1);
1532			break;
1533		}
1534		break;
1535
1536	case WI_INFO_COUNTERS:
1537		/* some card versions have a larger stats structure */
1538		len = min(le16toh(ltbuf[0]) - 1, sizeof(sc->sc_stats) / 4);
1539		ptr = (u_int32_t *)&sc->sc_stats;
1540		off = sizeof(ltbuf);
1541		for (i = 0; i < len; i++, off += 2, ptr++) {
1542			wi_read_bap(sc, fid, off, &stat, sizeof(stat));
1543#ifdef WI_HERMES_STATS_WAR
1544			if (stat & 0xf000)
1545				stat = ~stat;
1546#endif
1547			*ptr += stat;
1548		}
1549		ifp->if_collisions = sc->sc_stats.wi_tx_single_retries +
1550		    sc->sc_stats.wi_tx_multi_retries +
1551		    sc->sc_stats.wi_tx_retry_limit;
1552		break;
1553
1554	case WI_INFO_SCAN_RESULTS:
1555	case WI_INFO_HOST_SCAN_RESULTS:
1556		wi_scan_result(sc, fid, le16toh(ltbuf[0]));
1557		break;
1558
1559	default:
1560		DPRINTF(("wi_info_intr: got fid %x type %x len %d\n", fid,
1561		    le16toh(ltbuf[1]), le16toh(ltbuf[0])));
1562		break;
1563	}
1564	CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO);
1565}
1566
1567static int
1568wi_write_multi(struct wi_softc *sc)
1569{
1570	struct ifnet *ifp = &sc->sc_ic.ic_if;
1571	int n;
1572	struct ifmultiaddr *ifma;
1573	struct wi_mcast mlist;
1574
1575	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
1576allmulti:
1577		memset(&mlist, 0, sizeof(mlist));
1578		return wi_write_rid(sc, WI_RID_MCAST_LIST, &mlist,
1579		    sizeof(mlist));
1580	}
1581
1582	n = 0;
1583#if __FreeBSD_version < 500000
1584	LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
1585#else
1586	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
1587#endif
1588		if (ifma->ifma_addr->sa_family != AF_LINK)
1589			continue;
1590		if (n >= 16)
1591			goto allmulti;
1592		IEEE80211_ADDR_COPY(&mlist.wi_mcast[n],
1593		    (LLADDR((struct sockaddr_dl *)ifma->ifma_addr)));
1594		n++;
1595	}
1596	return wi_write_rid(sc, WI_RID_MCAST_LIST, &mlist,
1597	    IEEE80211_ADDR_LEN * n);
1598}
1599
1600static void
1601wi_read_nicid(struct wi_softc *sc)
1602{
1603	struct wi_card_ident *id;
1604	char *p;
1605	int len;
1606	u_int16_t ver[4];
1607
1608	/* getting chip identity */
1609	memset(ver, 0, sizeof(ver));
1610	len = sizeof(ver);
1611	wi_read_rid(sc, WI_RID_CARD_ID, ver, &len);
1612	device_printf(sc->sc_dev, "using ");
1613
1614	sc->sc_firmware_type = WI_NOTYPE;
1615	for (id = wi_card_ident; id->card_name != NULL; id++) {
1616		if (le16toh(ver[0]) == id->card_id) {
1617			printf("%s", id->card_name);
1618			sc->sc_firmware_type = id->firm_type;
1619			break;
1620		}
1621	}
1622	if (sc->sc_firmware_type == WI_NOTYPE) {
1623		if (le16toh(ver[0]) & 0x8000) {
1624			printf("Unknown PRISM2 chip");
1625			sc->sc_firmware_type = WI_INTERSIL;
1626		} else {
1627			printf("Unknown Lucent chip");
1628			sc->sc_firmware_type = WI_LUCENT;
1629		}
1630	}
1631
1632	/* get primary firmware version (Only Prism chips) */
1633	if (sc->sc_firmware_type != WI_LUCENT) {
1634		memset(ver, 0, sizeof(ver));
1635		len = sizeof(ver);
1636		wi_read_rid(sc, WI_RID_PRI_IDENTITY, ver, &len);
1637		sc->sc_pri_firmware_ver = le16toh(ver[2]) * 10000 +
1638		    le16toh(ver[3]) * 100 + le16toh(ver[1]);
1639	}
1640
1641	/* get station firmware version */
1642	memset(ver, 0, sizeof(ver));
1643	len = sizeof(ver);
1644	wi_read_rid(sc, WI_RID_STA_IDENTITY, ver, &len);
1645	sc->sc_sta_firmware_ver = le16toh(ver[2]) * 10000 +
1646	    le16toh(ver[3]) * 100 + le16toh(ver[1]);
1647	if (sc->sc_firmware_type == WI_INTERSIL &&
1648	    (sc->sc_sta_firmware_ver == 10102 ||
1649	     sc->sc_sta_firmware_ver == 20102)) {
1650		char ident[12];
1651		memset(ident, 0, sizeof(ident));
1652		len = sizeof(ident);
1653		/* value should be the format like "V2.00-11" */
1654		if (wi_read_rid(sc, WI_RID_SYMBOL_IDENTITY, ident, &len) == 0 &&
1655		    *(p = (char *)ident) >= 'A' &&
1656		    p[2] == '.' && p[5] == '-' && p[8] == '\0') {
1657			sc->sc_firmware_type = WI_SYMBOL;
1658			sc->sc_sta_firmware_ver = (p[1] - '0') * 10000 +
1659			    (p[3] - '0') * 1000 + (p[4] - '0') * 100 +
1660			    (p[6] - '0') * 10 + (p[7] - '0');
1661		}
1662	}
1663	printf("\n");
1664	device_printf(sc->sc_dev, "%s Firmware: ",
1665	     sc->sc_firmware_type == WI_LUCENT ? "Lucent" :
1666	    (sc->sc_firmware_type == WI_SYMBOL ? "Symbol" : "Intersil"));
1667	if (sc->sc_firmware_type != WI_LUCENT)	/* XXX */
1668		printf("Primary (%u.%u.%u), ",
1669		    sc->sc_pri_firmware_ver / 10000,
1670		    (sc->sc_pri_firmware_ver % 10000) / 100,
1671		    sc->sc_pri_firmware_ver % 100);
1672	printf("Station (%u.%u.%u)\n",
1673	    sc->sc_sta_firmware_ver / 10000,
1674	    (sc->sc_sta_firmware_ver % 10000) / 100,
1675	    sc->sc_sta_firmware_ver % 100);
1676}
1677
1678static int
1679wi_write_ssid(struct wi_softc *sc, int rid, u_int8_t *buf, int buflen)
1680{
1681	struct wi_ssid ssid;
1682
1683	if (buflen > IEEE80211_NWID_LEN)
1684		return ENOBUFS;
1685	memset(&ssid, 0, sizeof(ssid));
1686	ssid.wi_len = htole16(buflen);
1687	memcpy(ssid.wi_ssid, buf, buflen);
1688	return wi_write_rid(sc, rid, &ssid, sizeof(ssid));
1689}
1690
1691static int
1692wi_get_cfg(struct ifnet *ifp, u_long cmd, caddr_t data)
1693{
1694	struct wi_softc *sc = ifp->if_softc;
1695	struct ieee80211com *ic = &sc->sc_ic;
1696	struct ifreq *ifr = (struct ifreq *)data;
1697	struct wi_req wreq;
1698	int len, n, error, mif, val;
1699
1700	error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
1701	if (error)
1702		return error;
1703	len = (wreq.wi_len - 1) * 2;
1704	if (len < sizeof(u_int16_t))
1705		return ENOSPC;
1706	if (len > sizeof(wreq.wi_val))
1707		len = sizeof(wreq.wi_val);
1708
1709	switch (wreq.wi_type) {
1710
1711	case WI_RID_IFACE_STATS:
1712		memcpy(wreq.wi_val, &sc->sc_stats, sizeof(sc->sc_stats));
1713		if (len < sizeof(sc->sc_stats))
1714			error = ENOSPC;
1715		else
1716			len = sizeof(sc->sc_stats);
1717		break;
1718
1719	case WI_RID_ENCRYPTION:
1720	case WI_RID_TX_CRYPT_KEY:
1721	case WI_RID_DEFLT_CRYPT_KEYS:
1722	case WI_RID_TX_RATE:
1723		return ieee80211_cfgget(ifp, cmd, data);
1724
1725	case WI_RID_MICROWAVE_OVEN:
1726		if (sc->sc_enabled && (sc->sc_flags & WI_FLAGS_HAS_MOR)) {
1727			error = wi_read_rid(sc, wreq.wi_type, wreq.wi_val,
1728			    &len);
1729			break;
1730		}
1731		wreq.wi_val[0] = htole16(sc->sc_microwave_oven);
1732		len = sizeof(u_int16_t);
1733		break;
1734
1735	case WI_RID_DBM_ADJUST:
1736		if (sc->sc_enabled && (sc->sc_flags & WI_FLAGS_HAS_DBMADJUST)) {
1737			error = wi_read_rid(sc, wreq.wi_type, wreq.wi_val,
1738			    &len);
1739			break;
1740		}
1741		wreq.wi_val[0] = htole16(sc->sc_dbm_adjust);
1742		len = sizeof(u_int16_t);
1743		break;
1744
1745	case WI_RID_ROAMING_MODE:
1746		if (sc->sc_enabled && (sc->sc_flags & WI_FLAGS_HAS_ROAMING)) {
1747			error = wi_read_rid(sc, wreq.wi_type, wreq.wi_val,
1748			    &len);
1749			break;
1750		}
1751		wreq.wi_val[0] = htole16(sc->sc_roaming_mode);
1752		len = sizeof(u_int16_t);
1753		break;
1754
1755	case WI_RID_SYSTEM_SCALE:
1756		if (sc->sc_enabled && (sc->sc_flags & WI_FLAGS_HAS_SYSSCALE)) {
1757			error = wi_read_rid(sc, wreq.wi_type, wreq.wi_val,
1758			    &len);
1759			break;
1760		}
1761		wreq.wi_val[0] = htole16(sc->sc_system_scale);
1762		len = sizeof(u_int16_t);
1763		break;
1764
1765	case WI_RID_FRAG_THRESH:
1766		if (sc->sc_enabled && (sc->sc_flags & WI_FLAGS_HAS_FRAGTHR)) {
1767			error = wi_read_rid(sc, wreq.wi_type, wreq.wi_val,
1768			    &len);
1769			break;
1770		}
1771		wreq.wi_val[0] = htole16(sc->sc_frag_thresh);
1772		len = sizeof(u_int16_t);
1773		break;
1774
1775	case WI_RID_READ_APS:
1776	case WI_RID_SCAN_RES:		/* XXX */
1777		if (ic->ic_opmode == IEEE80211_M_HOSTAP)
1778			return ieee80211_cfgget(ifp, cmd, data);
1779		if (sc->sc_scan_timer > 0) {
1780			error = EINPROGRESS;
1781			break;
1782		}
1783		n = sc->sc_naps;
1784		if (len < sizeof(n)) {
1785			error = ENOSPC;
1786			break;
1787		}
1788		if (len < sizeof(n) + sizeof(struct wi_apinfo) * n)
1789			n = (len - sizeof(n)) / sizeof(struct wi_apinfo);
1790		len = sizeof(n) + sizeof(struct wi_apinfo) * n;
1791		memcpy(wreq.wi_val, &n, sizeof(n));
1792		memcpy((caddr_t)wreq.wi_val + sizeof(n), sc->sc_aps,
1793		    sizeof(struct wi_apinfo) * n);
1794		break;
1795
1796	case WI_RID_PRISM2:
1797		wreq.wi_val[0] = sc->sc_firmware_type != WI_LUCENT;
1798		len = sizeof(u_int16_t);
1799		break;
1800
1801	case WI_RID_MIF:
1802		mif = wreq.wi_val[0];
1803		error = wi_cmd(sc, WI_CMD_READMIF, mif, 0, 0);
1804		val = CSR_READ_2(sc, WI_RESP0);
1805		wreq.wi_val[0] = val;
1806		len = sizeof(u_int16_t);
1807		break;
1808
1809	case WI_RID_ZERO_CACHE:
1810	case WI_RID_PROCFRAME:		/* ignore for compatibility */
1811		/* XXX ??? */
1812		break;
1813
1814	case WI_RID_READ_CACHE:
1815		return ieee80211_cfgget(ifp, cmd, data);
1816
1817	default:
1818		if (sc->sc_enabled) {
1819			error = wi_read_rid(sc, wreq.wi_type, wreq.wi_val,
1820			    &len);
1821			break;
1822		}
1823		switch (wreq.wi_type) {
1824		case WI_RID_MAX_DATALEN:
1825			wreq.wi_val[0] = htole16(sc->sc_max_datalen);
1826			len = sizeof(u_int16_t);
1827			break;
1828		case WI_RID_RTS_THRESH:
1829			wreq.wi_val[0] = htole16(sc->sc_rts_thresh);
1830			len = sizeof(u_int16_t);
1831			break;
1832		case WI_RID_CNFAUTHMODE:
1833			wreq.wi_val[0] = htole16(sc->sc_cnfauthmode);
1834			len = sizeof(u_int16_t);
1835			break;
1836		case WI_RID_NODENAME:
1837			if (len < sc->sc_nodelen + sizeof(u_int16_t)) {
1838				error = ENOSPC;
1839				break;
1840			}
1841			len = sc->sc_nodelen + sizeof(u_int16_t);
1842			wreq.wi_val[0] = htole16((sc->sc_nodelen + 1) / 2);
1843			memcpy(&wreq.wi_val[1], sc->sc_nodename,
1844			    sc->sc_nodelen);
1845			break;
1846		default:
1847			return ieee80211_cfgget(ifp, cmd, data);
1848		}
1849		break;
1850	}
1851	if (error)
1852		return error;
1853	wreq.wi_len = (len + 1) / 2 + 1;
1854	return copyout(&wreq, ifr->ifr_data, (wreq.wi_len + 1) * 2);
1855}
1856
1857static int
1858wi_set_cfg(struct ifnet *ifp, u_long cmd, caddr_t data)
1859{
1860	struct wi_softc *sc = ifp->if_softc;
1861	struct ieee80211com *ic = &sc->sc_ic;
1862	struct ifreq *ifr = (struct ifreq *)data;
1863	struct wi_req wreq;
1864	struct mbuf *m;
1865	int i, len, error, mif, val;
1866
1867	error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
1868	if (error)
1869		return error;
1870	len = (wreq.wi_len - 1) * 2;
1871	switch (wreq.wi_type) {
1872	case WI_RID_DBM_ADJUST:
1873		return ENODEV;
1874
1875	case WI_RID_NODENAME:
1876		if (le16toh(wreq.wi_val[0]) * 2 > len ||
1877		    le16toh(wreq.wi_val[0]) > sizeof(sc->sc_nodename)) {
1878			error = ENOSPC;
1879			break;
1880		}
1881		if (sc->sc_enabled) {
1882			error = wi_write_rid(sc, wreq.wi_type, wreq.wi_val,
1883			    len);
1884			if (error)
1885				break;
1886		}
1887		sc->sc_nodelen = le16toh(wreq.wi_val[0]) * 2;
1888		memcpy(sc->sc_nodename, &wreq.wi_val[1], sc->sc_nodelen);
1889		break;
1890
1891	case WI_RID_MICROWAVE_OVEN:
1892	case WI_RID_ROAMING_MODE:
1893	case WI_RID_SYSTEM_SCALE:
1894	case WI_RID_FRAG_THRESH:
1895		if (wreq.wi_type == WI_RID_MICROWAVE_OVEN &&
1896		    (sc->sc_flags & WI_FLAGS_HAS_MOR) == 0)
1897			break;
1898		if (wreq.wi_type == WI_RID_ROAMING_MODE &&
1899		    (sc->sc_flags & WI_FLAGS_HAS_ROAMING) == 0)
1900			break;
1901		if (wreq.wi_type == WI_RID_SYSTEM_SCALE &&
1902		    (sc->sc_flags & WI_FLAGS_HAS_SYSSCALE) == 0)
1903			break;
1904		if (wreq.wi_type == WI_RID_FRAG_THRESH &&
1905		    (sc->sc_flags & WI_FLAGS_HAS_FRAGTHR) == 0)
1906			break;
1907		/* FALLTHROUGH */
1908	case WI_RID_RTS_THRESH:
1909	case WI_RID_CNFAUTHMODE:
1910	case WI_RID_MAX_DATALEN:
1911		if (sc->sc_enabled) {
1912			error = wi_write_rid(sc, wreq.wi_type, wreq.wi_val,
1913			    sizeof(u_int16_t));
1914			if (error)
1915				break;
1916		}
1917		switch (wreq.wi_type) {
1918		case WI_RID_FRAG_THRESH:
1919			sc->sc_frag_thresh = le16toh(wreq.wi_val[0]);
1920			break;
1921		case WI_RID_RTS_THRESH:
1922			sc->sc_rts_thresh = le16toh(wreq.wi_val[0]);
1923			break;
1924		case WI_RID_MICROWAVE_OVEN:
1925			sc->sc_microwave_oven = le16toh(wreq.wi_val[0]);
1926			break;
1927		case WI_RID_ROAMING_MODE:
1928			sc->sc_roaming_mode = le16toh(wreq.wi_val[0]);
1929			break;
1930		case WI_RID_SYSTEM_SCALE:
1931			sc->sc_system_scale = le16toh(wreq.wi_val[0]);
1932			break;
1933		case WI_RID_CNFAUTHMODE:
1934			sc->sc_cnfauthmode = le16toh(wreq.wi_val[0]);
1935			break;
1936		case WI_RID_MAX_DATALEN:
1937			sc->sc_max_datalen = le16toh(wreq.wi_val[0]);
1938			break;
1939		}
1940		break;
1941
1942	case WI_RID_TX_RATE:
1943		switch (le16toh(wreq.wi_val[0])) {
1944		case 3:
1945			ic->ic_fixed_rate = -1;
1946			break;
1947		default:
1948			for (i = 0; i < IEEE80211_RATE_SIZE; i++) {
1949				if ((ic->ic_sup_rates[i] & IEEE80211_RATE_VAL)
1950				    / 2 == le16toh(wreq.wi_val[0]))
1951					break;
1952			}
1953			if (i == IEEE80211_RATE_SIZE)
1954				return EINVAL;
1955			ic->ic_fixed_rate = i;
1956		}
1957		if (sc->sc_enabled)
1958			error = wi_write_txrate(sc);
1959		break;
1960
1961	case WI_RID_SCAN_APS:
1962		if (sc->sc_enabled && ic->ic_opmode != IEEE80211_M_HOSTAP)
1963			error = wi_scan_ap(sc);
1964		break;
1965
1966	case WI_RID_MGMT_XMIT:
1967		if (!sc->sc_enabled) {
1968			error = ENETDOWN;
1969			break;
1970		}
1971		if (ic->ic_mgtq.ifq_len > 5) {
1972			error = EAGAIN;
1973			break;
1974		}
1975		/* XXX wi_len looks in u_int8_t, not in u_int16_t */
1976		m = m_devget((char *)&wreq.wi_val, wreq.wi_len, 0, ifp, NULL);
1977		if (m == NULL) {
1978			error = ENOMEM;
1979			break;
1980		}
1981		IF_ENQUEUE(&ic->ic_mgtq, m);
1982		break;
1983
1984	case WI_RID_MIF:
1985		mif = wreq.wi_val[0];
1986		val = wreq.wi_val[1];
1987		error = wi_cmd(sc, WI_CMD_WRITEMIF, mif, val, 0);
1988		break;
1989
1990	case WI_RID_PROCFRAME:		/* ignore for compatibility */
1991		break;
1992
1993	default:
1994		if (sc->sc_enabled) {
1995			error = wi_write_rid(sc, wreq.wi_type, wreq.wi_val,
1996			    len);
1997			if (error)
1998				break;
1999		}
2000		error = ieee80211_cfgset(ifp, cmd, data);
2001		break;
2002	}
2003	return error;
2004}
2005
2006static int
2007wi_write_txrate(struct wi_softc *sc)
2008{
2009	struct ieee80211com *ic = &sc->sc_ic;
2010	int i;
2011	u_int16_t rate;
2012
2013	if (ic->ic_fixed_rate < 0)
2014		rate = 0;	/* auto */
2015	else
2016		rate = (ic->ic_sup_rates[ic->ic_fixed_rate] &
2017		    IEEE80211_RATE_VAL) / 2;
2018
2019	/* rate: 0, 1, 2, 5, 11 */
2020
2021	switch (sc->sc_firmware_type) {
2022	case WI_LUCENT:
2023		if (rate == 0)
2024			rate = 3;	/* auto */
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