xref: /openbsd-src/sys/dev/pcmcia/if_malo.c (revision 2b0358df1d88d06ef4139321dd05bd5e05d91eaf)
1 /*      $OpenBSD: if_malo.c,v 1.65 2009/03/29 21:53:53 sthen Exp $ */
2 
3 /*
4  * Copyright (c) 2007 Marcus Glocker <mglocker@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include "bpfilter.h"
20 
21 #include <sys/param.h>
22 #include <sys/proc.h>
23 #include <sys/systm.h>
24 #include <sys/kernel.h>
25 #include <sys/device.h>
26 #include <sys/timeout.h>
27 #include <sys/socket.h>
28 #include <sys/tree.h>
29 #include <sys/malloc.h>
30 #include <sys/sockio.h>
31 #include <sys/mbuf.h>
32 
33 #if NBPFILTER > 0
34 #include <net/bpf.h>
35 #endif
36 
37 #include <net/if.h>
38 #include <net/if_dl.h>
39 #include <net/if_media.h>
40 #include <net/if_llc.h>
41 
42 #include <netinet/in.h>
43 #include <netinet/in_systm.h>
44 #include <netinet/if_ether.h>
45 
46 #include <net80211/ieee80211_var.h>
47 #include <net80211/ieee80211_radiotap.h>
48 
49 #include <machine/bus.h>
50 #include <machine/intr.h>
51 
52 #include <dev/pcmcia/pcmciareg.h>
53 #include <dev/pcmcia/pcmciavar.h>
54 #include <dev/pcmcia/pcmciadevs.h>
55 
56 #include <dev/pcmcia/if_malovar.h>
57 #include <dev/pcmcia/if_maloreg.h>
58 
59 /*
60  * Driver for the Marvell 88W8385 chip (Compact Flash).
61  */
62 
63 #ifdef CMALO_DEBUG
64 int cmalo_d = 1;
65 #define DPRINTF(l, x...)	do { if ((l) <= cmalo_d) printf(x); } while (0)
66 #else
67 #define DPRINTF(l, x...)
68 #endif
69 
70 int	malo_pcmcia_match(struct device *, void *, void *);
71 void	malo_pcmcia_attach(struct device *, struct device *, void *);
72 int	malo_pcmcia_detach(struct device *, int);
73 int	malo_pcmcia_activate(struct device *, enum devact);
74 
75 void	cmalo_attach(void *);
76 int	cmalo_ioctl(struct ifnet *, u_long, caddr_t);
77 int	cmalo_fw_alloc(struct malo_softc *);
78 void	cmalo_fw_free(struct malo_softc *);
79 int	cmalo_fw_load_helper(struct malo_softc *);
80 int	cmalo_fw_load_main(struct malo_softc *);
81 int	cmalo_init(struct ifnet *);
82 void	cmalo_stop(struct malo_softc *);
83 int	cmalo_media_change(struct ifnet *);
84 int	cmalo_newstate(struct ieee80211com *, enum ieee80211_state, int);
85 void	cmalo_detach(void *);
86 int	cmalo_intr(void *);
87 void	cmalo_intr_mask(struct malo_softc *, int);
88 void	cmalo_rx(struct malo_softc *);
89 void	cmalo_start(struct ifnet *);
90 void	cmalo_watchdog(struct ifnet *);
91 int	cmalo_tx(struct malo_softc *, struct mbuf *);
92 void	cmalo_tx_done(struct malo_softc *);
93 void	cmalo_event(struct malo_softc *);
94 void	cmalo_select_network(struct malo_softc *);
95 void	cmalo_reflect_network(struct malo_softc *);
96 int	cmalo_wep(struct malo_softc *);
97 int	cmalo_rate2bitmap(int);
98 
99 void	cmalo_hexdump(void *, int);
100 int	cmalo_cmd_get_hwspec(struct malo_softc *);
101 int	cmalo_cmd_rsp_hwspec(struct malo_softc *);
102 int	cmalo_cmd_set_reset(struct malo_softc *);
103 int	cmalo_cmd_set_scan(struct malo_softc *);
104 int	cmalo_cmd_rsp_scan(struct malo_softc *);
105 int	cmalo_parse_elements(struct malo_softc *, void *, int, int);
106 int	cmalo_cmd_set_auth(struct malo_softc *);
107 int	cmalo_cmd_set_wep(struct malo_softc *, uint16_t,
108 	    struct ieee80211_key *);
109 int	cmalo_cmd_set_snmp(struct malo_softc *, uint16_t);
110 int	cmalo_cmd_set_radio(struct malo_softc *, uint16_t);
111 int	cmalo_cmd_set_channel(struct malo_softc *, uint16_t);
112 int	cmalo_cmd_set_txpower(struct malo_softc *, int16_t);
113 int	cmalo_cmd_set_antenna(struct malo_softc *, uint16_t);
114 int	cmalo_cmd_set_macctrl(struct malo_softc *);
115 int	cmalo_cmd_set_macaddr(struct malo_softc *, uint8_t *);
116 int	cmalo_cmd_set_assoc(struct malo_softc *);
117 int	cmalo_cmd_rsp_assoc(struct malo_softc *);
118 int	cmalo_cmd_set_80211d(struct malo_softc *);
119 int	cmalo_cmd_set_bgscan_config(struct malo_softc *);
120 int	cmalo_cmd_set_bgscan_query(struct malo_softc *);
121 int	cmalo_cmd_set_rate(struct malo_softc *, int);
122 int	cmalo_cmd_request(struct malo_softc *, uint16_t, int);
123 int	cmalo_cmd_response(struct malo_softc *);
124 
125 /*
126  * PCMCIA bus.
127  */
128 struct malo_pcmcia_softc {
129 	struct malo_softc	 sc_malo;
130 
131 	struct pcmcia_function	*sc_pf;
132 	struct pcmcia_io_handle	 sc_pcioh;
133 	int			 sc_io_window;
134 	void			*sc_ih;
135 };
136 
137 struct cfattach malo_pcmcia_ca = {
138 	sizeof(struct malo_pcmcia_softc),
139 	malo_pcmcia_match,
140 	malo_pcmcia_attach,
141 	malo_pcmcia_detach,
142 	malo_pcmcia_activate
143 };
144 
145 int
146 malo_pcmcia_match(struct device *parent, void *match, void *aux)
147 {
148 	struct pcmcia_attach_args *pa = aux;
149 
150 	if (pa->manufacturer == PCMCIA_VENDOR_AMBICOM &&
151 	    pa->product == PCMCIA_PRODUCT_AMBICOM_WL54CF)
152 		return (1);
153 
154 	return (0);
155 }
156 
157 void
158 malo_pcmcia_attach(struct device *parent, struct device *self, void *aux)
159 {
160 	struct malo_pcmcia_softc *psc = (struct malo_pcmcia_softc *)self;
161 	struct malo_softc *sc = &psc->sc_malo;
162 	struct pcmcia_attach_args *pa = aux;
163 	struct pcmcia_config_entry *cfe;
164 	const char *intrstr = NULL;
165 
166 	psc->sc_pf = pa->pf;
167 	cfe = SIMPLEQ_FIRST(&pa->pf->cfe_head);
168 
169 	/* enable card */
170 	pcmcia_function_init(psc->sc_pf, cfe);
171 	if (pcmcia_function_enable(psc->sc_pf)) {
172 		printf(": can't enable function\n");
173 		return;
174 	}
175 
176 	/* allocate I/O space */
177 	if (pcmcia_io_alloc(psc->sc_pf, 0,
178 	    cfe->iospace[0].length, cfe->iospace[0].length, &psc->sc_pcioh)) {
179 		printf(": can't allocate i/o space\n");
180 		pcmcia_function_disable(psc->sc_pf);
181 		return;
182 	}
183 
184 	/* map I/O space */
185 	if (pcmcia_io_map(psc->sc_pf, PCMCIA_WIDTH_IO16, 0,
186 	    cfe->iospace[0].length, &psc->sc_pcioh, &psc->sc_io_window)) {
187 		printf(": can't map i/o space\n");
188 		pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
189 		pcmcia_function_disable(psc->sc_pf);
190 		return;
191 	}
192 	sc->sc_iot = psc->sc_pcioh.iot;
193 	sc->sc_ioh = psc->sc_pcioh.ioh;
194 
195 	printf(" port 0x%x/%d", psc->sc_pcioh.addr, psc->sc_pcioh.size);
196 
197 	/* establish interrupt */
198 	psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, cmalo_intr, sc,
199 	    sc->sc_dev.dv_xname);
200 	if (psc->sc_ih == NULL) {
201 		printf(": can't establish interrupt\n");
202 		return;
203 	}
204 	intrstr = pcmcia_intr_string(psc->sc_pf, psc->sc_ih);
205 	if (intrstr != NULL) {
206 		if (*intrstr != NULL)
207 			printf(", %s", intrstr);
208 	}
209 	printf("\n");
210 
211 	/* attach device */
212 	if (rootvp == NULL)
213 		mountroothook_establish(cmalo_attach, sc);
214 	else
215 		cmalo_attach(sc);
216 }
217 
218 int
219 malo_pcmcia_detach(struct device *dev, int flags)
220 {
221 	struct malo_pcmcia_softc *psc = (struct malo_pcmcia_softc *)dev;
222 	struct malo_softc *sc = &psc->sc_malo;
223 
224 	cmalo_detach(sc);
225 
226 	pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window);
227 	pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
228 
229 	return (0);
230 }
231 
232 int
233 malo_pcmcia_activate(struct device *dev, enum devact act)
234 {
235 	struct malo_pcmcia_softc *psc = (struct malo_pcmcia_softc *)dev;
236 	struct malo_softc *sc = &psc->sc_malo;
237 	struct ieee80211com *ic = &sc->sc_ic;
238 	struct ifnet *ifp = &ic->ic_if;
239 	int s;
240 
241 	s = splnet();
242 	switch (act) {
243 	case DVACT_ACTIVATE:
244 		pcmcia_function_enable(psc->sc_pf);
245 		psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET,
246 		    cmalo_intr, sc, sc->sc_dev.dv_xname);
247 		cmalo_init(ifp);
248 		break;
249 	case DVACT_DEACTIVATE:
250 		ifp->if_timer = 0;
251 		if (ifp->if_flags & IFF_RUNNING)
252 			cmalo_stop(sc);
253 		if (psc->sc_ih != NULL)
254 			pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih);
255 		pcmcia_function_disable(psc->sc_pf);
256 		break;
257 	}
258 	splx(s);
259 
260 	return (0);
261 }
262 
263 /*
264  * Driver.
265  */
266 void
267 cmalo_attach(void *arg)
268 {
269 	struct malo_softc *sc = arg;
270 	struct ieee80211com *ic = &sc->sc_ic;
271 	struct ifnet *ifp = &sc->sc_ic.ic_if;
272 	int i;
273 
274 	/* disable interrupts */
275 	cmalo_intr_mask(sc, 0);
276 
277 	/* load firmware */
278 	if (cmalo_fw_alloc(sc) != 0)
279 		return;
280 	if (cmalo_fw_load_helper(sc) != 0)
281 		return;
282 	if (cmalo_fw_load_main(sc) != 0)
283 		return;
284 	sc->sc_flags |= MALO_FW_LOADED;
285 
286 	/* allocate command buffer */
287 	sc->sc_cmd = malloc(MALO_CMD_BUFFER_SIZE, M_DEVBUF, M_NOWAIT);
288 
289 	/* allocate data buffer */
290 	sc->sc_data = malloc(MCLBYTES, M_DEVBUF, M_NOWAIT);
291 
292 	/* enable interrupts */
293 	cmalo_intr_mask(sc, 1);
294 
295 	/* we are context save here for FW commands */
296 	sc->sc_cmd_ctxsave = 1;
297 
298 	/* get hardware specs */
299 	cmalo_cmd_get_hwspec(sc);
300 
301 	/* setup interface */
302 	ifp->if_softc = sc;
303 	ifp->if_ioctl = cmalo_ioctl;
304 	ifp->if_init = cmalo_init;
305 	ifp->if_start = cmalo_start;
306 	ifp->if_watchdog = cmalo_watchdog;
307 	ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST;
308 	strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
309 	IFQ_SET_READY(&ifp->if_snd);
310 
311 	ic->ic_opmode = IEEE80211_M_STA;
312 	ic->ic_state = IEEE80211_S_INIT;
313 	ic->ic_caps = IEEE80211_C_MONITOR | IEEE80211_C_WEP;
314 
315 	ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
316 	ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g;
317 
318 	for (i = 0; i <= 14; i++) {
319 		ic->ic_channels[i].ic_freq =
320 		    ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
321 		ic->ic_channels[i].ic_flags =
322 		    IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
323 		    IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
324 	}
325 
326 	/* attach interface */
327 	if_attach(ifp);
328 	ieee80211_ifattach(ifp);
329 
330 	sc->sc_newstate = ic->ic_newstate;
331 	ic->ic_newstate = cmalo_newstate;
332 	ieee80211_media_init(ifp, cmalo_media_change, ieee80211_media_status);
333 
334 	/* second attach line */
335 	printf("%s: address %s\n",
336 	    sc->sc_dev.dv_xname, ether_sprintf(ic->ic_myaddr));
337 
338 	/* device attached */
339 	sc->sc_flags |= MALO_DEVICE_ATTACHED;
340 }
341 
342 int
343 cmalo_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
344 {
345 	struct malo_softc *sc = ifp->if_softc;
346 	struct ieee80211com *ic = &sc->sc_ic;
347 	struct ieee80211_nodereq_all *na;
348 	struct ieee80211_nodereq *nr;
349 	struct ifaddr *ifa;
350 	struct ifreq *ifr;
351 	int i, j, s, error = 0;
352 
353 	s = splnet();
354 
355 	switch (cmd) {
356 	case SIOCSIFADDR:
357 		ifa = (struct ifaddr *)data;
358 		ifp->if_flags |= IFF_UP;
359 #ifdef INET
360 		if (ifa->ifa_addr->sa_family == AF_INET)
361 			arp_ifinit(&ic->ic_ac, ifa);
362 #endif
363 		/* FALLTHROUGH */
364 	case SIOCSIFFLAGS:
365 		if (ifp->if_flags & IFF_UP) {
366 			if ((ifp->if_flags & IFF_RUNNING) == 0)
367 				cmalo_init(ifp);
368 		} else {
369 			if (ifp->if_flags & IFF_RUNNING)
370 				cmalo_stop(sc);
371 		}
372 		break;
373 	case SIOCADDMULTI:
374 	case SIOCDELMULTI:
375 		ifr = (struct ifreq *)data;
376 		error = (cmd == SIOCADDMULTI) ?
377 		    ether_addmulti(ifr, &ic->ic_ac) :
378 		    ether_delmulti(ifr, &ic->ic_ac);
379 		if (error == ENETRESET)
380 			error = 0;
381 		break;
382 	case SIOCS80211SCAN:
383 		cmalo_cmd_set_scan(sc);
384 		break;
385 	case SIOCG80211ALLNODES:
386 		nr = NULL;
387 		na = (struct ieee80211_nodereq_all *)data;
388 
389 		if ((nr = malloc(sizeof(*nr), M_DEVBUF, M_WAITOK)) == NULL)
390 			break;
391 
392 		for (na->na_nodes = i = j = 0; i < sc->sc_net_num &&
393 		    (na->na_size >= j + sizeof(struct ieee80211_nodereq));
394 		    i++) {
395 			bzero(nr, sizeof(*nr));
396 
397 			IEEE80211_ADDR_COPY(nr->nr_macaddr,
398 			    sc->sc_net[i].bssid);
399 			IEEE80211_ADDR_COPY(nr->nr_bssid,
400 			    sc->sc_net[i].bssid);
401 			nr->nr_channel = sc->sc_net[i].channel;
402 			nr->nr_chan_flags = IEEE80211_CHAN_B; /* XXX */
403 			nr->nr_rssi = sc->sc_net[i].rssi;
404 			nr->nr_max_rssi = 0; /* XXX */
405 			nr->nr_nwid_len = strlen(sc->sc_net[i].ssid);
406 			bcopy(sc->sc_net[i].ssid, nr->nr_nwid,
407 			    nr->nr_nwid_len);
408 			nr->nr_intval = sc->sc_net[i].beaconintvl;
409 			nr->nr_capinfo = sc->sc_net[i].capinfo;
410 			nr->nr_flags |= IEEE80211_NODEREQ_AP;
411 
412 			if (copyout(nr, (caddr_t)na->na_node + j,
413 			    sizeof(struct ieee80211_nodereq)))
414 				break;
415 
416 			j += sizeof(struct ieee80211_nodereq);
417 			na->na_nodes++;
418 		}
419 
420 		if (nr)
421 			free(nr, M_DEVBUF);
422 		break;
423 	default:
424 		error = ieee80211_ioctl(ifp, cmd, data);
425 		break;
426 	}
427 
428 	if (error == ENETRESET) {
429 		if (ifp->if_flags & (IFF_UP | IFF_RUNNING))
430 			cmalo_init(ifp);
431 		error = 0;
432 	}
433 
434 	splx(s);
435 
436 	return (error);
437 }
438 
439 int
440 cmalo_fw_alloc(struct malo_softc *sc)
441 {
442 	const char *name_h = "malo8385-h";
443 	const char *name_m = "malo8385-m";
444 	int error;
445 
446 	if (sc->sc_fw_h == NULL) {
447 		/* read helper firmware image */
448 		error = loadfirmware(name_h, &sc->sc_fw_h, &sc->sc_fw_h_size);
449 		if (error != 0) {
450 			printf("%s: error %d, could not read firmware %s\n",
451 			    sc->sc_dev.dv_xname, error, name_h);
452 			return (EIO);
453 		}
454 	}
455 
456 	if (sc->sc_fw_m == NULL) {
457 		/* read main firmware image */
458 		error = loadfirmware(name_m, &sc->sc_fw_m, &sc->sc_fw_m_size);
459 		if (error != 0) {
460 			printf("%s: error %d, could not read firmware %s\n",
461 			    sc->sc_dev.dv_xname, error, name_m);
462 			return (EIO);
463 		}
464 	}
465 
466 	return (0);
467 }
468 
469 void
470 cmalo_fw_free(struct malo_softc *sc)
471 {
472 	if (sc->sc_fw_h != NULL) {
473 		free(sc->sc_fw_h, M_DEVBUF);
474 		sc->sc_fw_h = NULL;
475 	}
476 
477 	if (sc->sc_fw_m != NULL) {
478 		free(sc->sc_fw_m, M_DEVBUF);
479 		sc->sc_fw_m = NULL;
480 	}
481 }
482 
483 int
484 cmalo_fw_load_helper(struct malo_softc *sc)
485 {
486 	uint8_t val8;
487 	uint16_t bsize, *uc;
488 	int offset, i;
489 
490 	/* verify if the card is ready for firmware download */
491 	val8 = MALO_READ_1(sc, MALO_REG_SCRATCH);
492 	if (val8 == MALO_VAL_SCRATCH_FW_LOADED)
493 		/* firmware already loaded */
494 		return (0);
495 	if (val8 != MALO_VAL_SCRATCH_READY) {
496 		/* bad register value */
497 		printf("%s: device not ready for FW download\n",
498 		    sc->sc_dev.dv_xname);
499 		return (EIO);
500 	}
501 
502 	/* download the helper firmware */
503 	for (offset = 0; offset < sc->sc_fw_h_size; offset += bsize) {
504 		if (sc->sc_fw_h_size - offset >= MALO_FW_HELPER_BSIZE)
505 			bsize = MALO_FW_HELPER_BSIZE;
506 		else
507 			bsize = sc->sc_fw_h_size - offset;
508 
509 		/* send a block in words and confirm it */
510 		DPRINTF(3, "%s: download helper FW block (%d bytes, %d off)\n",
511 		    sc->sc_dev.dv_xname, bsize, offset);
512 		MALO_WRITE_2(sc, MALO_REG_CMD_WRITE_LEN, bsize);
513 		uc = (uint16_t *)(sc->sc_fw_h + offset);
514 		for (i = 0; i < bsize / 2; i++)
515 			MALO_WRITE_2(sc, MALO_REG_CMD_WRITE, htole16(uc[i]));
516 		MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_CMD_DL_OVER);
517 		MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE,
518 		    MALO_VAL_CMD_DL_OVER);
519 
520 		/* poll for an acknowledgement */
521 		for (i = 0; i < 50; i++) {
522 			if (MALO_READ_1(sc, MALO_REG_CARD_STATUS) ==
523 			    MALO_VAL_CMD_DL_OVER)
524 				break;
525 			delay(1000);
526 		}
527 		if (i == 50) {
528 			printf("%s: timeout while helper FW block download\n",
529 			    sc->sc_dev.dv_xname);
530 			return (EIO);
531 		}
532 	}
533 
534 	/* helper firmware download done */
535 	MALO_WRITE_2(sc, MALO_REG_CMD_WRITE_LEN, 0);
536 	MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_CMD_DL_OVER);
537 	MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE, MALO_VAL_CMD_DL_OVER);
538 	DPRINTF(1, "%s: helper FW downloaded\n", sc->sc_dev.dv_xname);
539 
540 	return (0);
541 }
542 
543 int
544 cmalo_fw_load_main(struct malo_softc *sc)
545 {
546 	uint16_t val16, bsize, *uc;
547 	int offset, i, retry;
548 
549 	/* verify if the helper firmware has been loaded correctly */
550 	for (i = 0; i < 10; i++) {
551 		if (MALO_READ_1(sc, MALO_REG_RBAL) == MALO_FW_HELPER_LOADED)
552 			break;
553 		delay(1000);
554 	}
555 	if (i == 10) {
556 		printf("%s: helper FW not loaded\n", sc->sc_dev.dv_xname);
557 		return (EIO);
558 	}
559 	DPRINTF(1, "%s: helper FW loaded successfully\n", sc->sc_dev.dv_xname);
560 
561 	/* download the main firmware */
562 	for (offset = 0; offset < sc->sc_fw_m_size; offset += bsize) {
563 		val16 = MALO_READ_2(sc, MALO_REG_RBAL);
564 		/*
565 		 * If the helper firmware serves us an odd integer then
566 		 * something went wrong and we retry to download the last
567 		 * block until we receive a good integer again, or give up.
568 		 */
569 		if (val16 & 0x0001) {
570 			if (retry > MALO_FW_MAIN_MAXRETRY) {
571 				printf("%s: main FW download failed\n",
572 				    sc->sc_dev.dv_xname);
573 				return (EIO);
574 			}
575 			retry++;
576 			offset -= bsize;
577 		} else {
578 			retry = 0;
579 			bsize = val16;
580 		}
581 
582 		/* send a block in words and confirm it */
583 		DPRINTF(3, "%s: download main FW block (%d bytes, %d off)\n",
584 		    sc->sc_dev.dv_xname, bsize, offset);
585 		MALO_WRITE_2(sc, MALO_REG_CMD_WRITE_LEN, bsize);
586 		uc = (uint16_t *)(sc->sc_fw_m + offset);
587 		for (i = 0; i < bsize / 2; i++)
588 			MALO_WRITE_2(sc, MALO_REG_CMD_WRITE, htole16(uc[i]));
589 		MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_CMD_DL_OVER);
590                 MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE,
591 		    MALO_VAL_CMD_DL_OVER);
592 
593 		/* poll for an acknowledgement */
594 		for (i = 0; i < 5000; i++) {
595 			if (MALO_READ_1(sc, MALO_REG_CARD_STATUS) ==
596 			    MALO_VAL_CMD_DL_OVER)
597 				break;
598 		}
599 		if (i == 5000) {
600 			printf("%s: timeout while main FW block download\n",
601 			    sc->sc_dev.dv_xname);
602 			return (EIO);
603 		}
604 	}
605 
606 	DPRINTF(1, "%s: main FW downloaded\n", sc->sc_dev.dv_xname);
607 
608 	/* verify if the main firmware has been loaded correctly */
609 	for (i = 0; i < 500; i++) {
610 		if (MALO_READ_1(sc, MALO_REG_SCRATCH) ==
611 		    MALO_VAL_SCRATCH_FW_LOADED)
612 			break;
613 		delay(1000);
614 	}
615 	if (i == 500) {
616 		printf("%s: main FW not loaded\n", sc->sc_dev.dv_xname);
617 		return (EIO);
618 	}
619 
620 	DPRINTF(1, "%s: main FW loaded successfully\n", sc->sc_dev.dv_xname);
621 
622 	return (0);
623 }
624 
625 int
626 cmalo_init(struct ifnet *ifp)
627 {
628 	struct malo_softc *sc = ifp->if_softc;
629 	struct ieee80211com *ic = &sc->sc_ic;
630 
631 	/* reload the firmware if necessary */
632 	if (!(sc->sc_flags & MALO_FW_LOADED)) {
633 		/* disable interrupts */
634 		cmalo_intr_mask(sc, 0);
635 
636 		/* load firmware */
637 		if (cmalo_fw_load_helper(sc) != 0)
638 			return (EIO);
639 		if (cmalo_fw_load_main(sc) != 0)
640 			return (EIO);
641 		sc->sc_flags |= MALO_FW_LOADED;
642 
643 		/* enable interrupts */
644 		cmalo_intr_mask(sc, 1);
645 	}
646 
647 	/* reset association state flag */
648 	sc->sc_flags &= ~MALO_ASSOC_FAILED;
649 
650 	/* get current channel */
651         ic->ic_bss->ni_chan = ic->ic_ibss_chan;
652         sc->sc_curchan = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan);
653 	DPRINTF(1, "%s: current channel is %d\n",
654 	    sc->sc_dev.dv_xname, sc->sc_curchan);
655 
656 	/* setup device */
657 	if (cmalo_cmd_set_macctrl(sc) != 0)
658 		return (EIO);
659 	if (cmalo_cmd_set_txpower(sc, 15) != 0)
660 		return (EIO);
661 	if (cmalo_cmd_set_antenna(sc, 1) != 0)
662 		return (EIO);
663 	if (cmalo_cmd_set_antenna(sc, 2) != 0)
664 		return (EIO);
665 	if (cmalo_cmd_set_radio(sc, 1) != 0)
666 		return (EIO);
667 	if (cmalo_cmd_set_channel(sc, sc->sc_curchan) != 0)
668 		return (EIO);
669 	if (cmalo_cmd_set_rate(sc, ic->ic_fixed_rate) != 0)
670 		return (EIO);
671 	if (cmalo_cmd_set_snmp(sc, MALO_OID_RTSTRESH) != 0)
672 		return (EIO);
673 	if (cmalo_cmd_set_snmp(sc, MALO_OID_SHORTRETRY) != 0)
674 		return (EIO);
675 	if (cmalo_cmd_set_snmp(sc, MALO_OID_FRAGTRESH) != 0)
676 		return (EIO);
677 	IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(ifp->if_sadl));
678 	if (cmalo_cmd_set_macaddr(sc, ic->ic_myaddr) != 0)
679 		return (EIO);
680 	if (sc->sc_ic.ic_flags & IEEE80211_F_WEPON) {
681 		if (cmalo_wep(sc) != 0)
682 			return (EIO);
683 	}
684 
685 	/* device up */
686 	ifp->if_flags |= IFF_RUNNING;
687 	ifp->if_flags &= ~IFF_OACTIVE;
688 
689 	/* start network */
690 	if (ic->ic_opmode != IEEE80211_M_MONITOR)
691 		ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
692 	if (sc->sc_flags & MALO_ASSOC_FAILED)
693 		ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
694 	else
695 		ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
696 
697 	/* we are not context save anymore for FW commands */
698 	sc->sc_cmd_ctxsave = 0;
699 
700 	return (0);
701 }
702 
703 void
704 cmalo_stop(struct malo_softc *sc)
705 {
706 	struct ieee80211com *ic = &sc->sc_ic;
707         struct ifnet *ifp = &ic->ic_if;
708 
709 	/* device down */
710 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
711 
712 	/* change device back to initial state */
713 	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
714 
715 	/* reset device */
716 	cmalo_cmd_set_reset(sc);
717 	sc->sc_flags &= ~MALO_FW_LOADED;
718 
719 	DPRINTF(1, "%s: device down\n", sc->sc_dev.dv_xname);
720 }
721 
722 int
723 cmalo_media_change(struct ifnet *ifp)
724 {
725 	int error;
726 
727 	if ((error = ieee80211_media_change(ifp) != ENETRESET))
728 		return (error);
729 
730 	if (ifp->if_flags & (IFF_UP | IFF_RUNNING))
731 		cmalo_init(ifp);
732 
733 	return (0);
734 }
735 
736 int
737 cmalo_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
738 {
739 	struct malo_softc *sc = ic->ic_if.if_softc;
740 	enum ieee80211_state ostate;
741 
742 	ostate = ic->ic_state;
743 
744 	if (ostate == nstate)
745 		goto out;
746 
747 	switch (nstate) {
748 		case IEEE80211_S_INIT:
749 			DPRINTF(1, "%s: newstate is IEEE80211_S_INIT\n",
750 			    sc->sc_dev.dv_xname);
751 			break;
752 		case IEEE80211_S_SCAN:
753 			DPRINTF(1, "%s: newstate is IEEE80211_S_SCAN\n",
754 			    sc->sc_dev.dv_xname);
755 			cmalo_cmd_set_scan(sc);
756 			if (!sc->sc_net_num) {
757 				/* no networks found */
758 				DPRINTF(1, "%s: no networks found\n",
759 				    sc->sc_dev.dv_xname);
760 				break;
761 			}
762 			cmalo_select_network(sc);
763 			cmalo_cmd_set_auth(sc);
764 			cmalo_cmd_set_assoc(sc);
765 			break;
766 		case IEEE80211_S_AUTH:
767 			DPRINTF(1, "%s: newstate is IEEE80211_S_AUTH\n",
768 			    sc->sc_dev.dv_xname);
769 			break;
770 		case IEEE80211_S_ASSOC:
771 			DPRINTF(1, "%s: newstate is IEEE80211_S_ASSOC\n",
772 			    sc->sc_dev.dv_xname);
773 			break;
774 		case IEEE80211_S_RUN:
775 			DPRINTF(1, "%s: newstate is IEEE80211_S_RUN\n",
776 			    sc->sc_dev.dv_xname);
777 			cmalo_reflect_network(sc);
778 			break;
779 		default:
780 			break;
781 	}
782 
783 out:
784 	return (sc->sc_newstate(ic, nstate, arg));
785 }
786 
787 void
788 cmalo_detach(void *arg)
789 {
790 	struct malo_softc *sc = arg;
791 	struct ieee80211com *ic = &sc->sc_ic;
792 	struct ifnet *ifp = &ic->ic_if;
793 
794 	if (!(sc->sc_flags & MALO_DEVICE_ATTACHED))
795 		/* device was not properly attached */
796 		return;
797 
798 	/* free command buffer */
799 	if (sc->sc_cmd != NULL)
800 		free(sc->sc_cmd, M_DEVBUF);
801 
802 	/* free data buffer */
803 	if (sc->sc_data != NULL)
804 		free(sc->sc_data, M_DEVBUF);
805 
806 	/* free firmware */
807 	cmalo_fw_free(sc);
808 
809 	/* detach inferface */
810 	ieee80211_ifdetach(ifp);
811 	if_detach(ifp);
812 }
813 
814 int
815 cmalo_intr(void *arg)
816 {
817 	struct malo_softc *sc = arg;
818 	uint16_t intr = 0;
819 
820 	/* read interrupt reason */
821 	intr = MALO_READ_2(sc, MALO_REG_HOST_INTR_CAUSE);
822 	if (intr == 0) {
823 		/* interrupt not for us */
824 		return (0);
825 	}
826 	if (intr == 0xffff) {
827 		/* card has been detached */
828 		return (0);
829 	}
830 
831 	/* disable interrupts */
832 	cmalo_intr_mask(sc, 0);
833 
834 	/* acknowledge interrupt */
835 	MALO_WRITE_2(sc, MALO_REG_HOST_INTR_CAUSE,
836 	    intr & MALO_VAL_HOST_INTR_MASK_ON);
837 
838 	/* enable interrupts */
839 	cmalo_intr_mask(sc, 1);
840 
841 	DPRINTF(2, "%s: interrupt handler called (intr = 0x%04x)\n",
842 	    sc->sc_dev.dv_xname, intr);
843 
844 	if (intr & MALO_VAL_HOST_INTR_TX)
845 		/* TX frame sent */
846 		cmalo_tx_done(sc);
847 	if (intr & MALO_VAL_HOST_INTR_RX)
848 		/* RX frame received */
849 		cmalo_rx(sc);
850 	if (intr & MALO_VAL_HOST_INTR_CMD) {
851 		/* command response */
852 		wakeup(sc);
853 		if (!sc->sc_cmd_ctxsave)
854 			cmalo_cmd_response(sc);
855 	}
856 	if (intr & MALO_VAL_HOST_INTR_EVENT)
857 		/* event */
858 		cmalo_event(sc);
859 
860 	return (1);
861 }
862 
863 void
864 cmalo_intr_mask(struct malo_softc *sc, int enable)
865 {
866 	uint16_t val16;
867 
868 	val16 = MALO_READ_2(sc, MALO_REG_HOST_INTR_MASK);
869 
870 	DPRINTF(3, "%s: intr mask changed from 0x%04x ",
871 	    sc->sc_dev.dv_xname, val16);
872 
873 	if (enable)
874 		MALO_WRITE_2(sc, MALO_REG_HOST_INTR_MASK,
875 		    val16 & ~MALO_VAL_HOST_INTR_MASK_ON);
876 	else
877 		MALO_WRITE_2(sc, MALO_REG_HOST_INTR_MASK,
878 		    val16 | MALO_VAL_HOST_INTR_MASK_ON);
879 
880 	val16 = MALO_READ_2(sc, MALO_REG_HOST_INTR_MASK);
881 
882 	DPRINTF(3, "to 0x%04x\n", val16);
883 }
884 
885 void
886 cmalo_rx(struct malo_softc *sc)
887 {
888 	struct ieee80211com *ic = &sc->sc_ic;
889 	struct ifnet *ifp = &ic->ic_if;
890 	struct malo_rx_desc *rxdesc;
891 	struct mbuf *m;
892 	uint8_t *data;
893 	uint16_t psize;
894 	int i;
895 
896 	splassert(IPL_NET);
897 
898 	/* read the whole RX packet which is always 802.3 */
899 	psize = MALO_READ_2(sc, MALO_REG_DATA_READ_LEN);
900 	if (psize & 0x0001) {
901 		MALO_READ_MULTI_2(sc, MALO_REG_DATA_READ, sc->sc_data,
902 		    psize - 1);
903 		data = (uint8_t *)sc->sc_data;
904 		data[psize - 1] = MALO_READ_1(sc, MALO_REG_DATA_READ);
905 	} else
906 		MALO_READ_MULTI_2(sc, MALO_REG_DATA_READ, sc->sc_data, psize);
907 	MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_RX_DL_OVER);
908 	MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE, MALO_VAL_RX_DL_OVER);
909 
910 	/* access RX packet descriptor */
911 	rxdesc = (struct malo_rx_desc *)sc->sc_data;
912 	rxdesc->status = letoh16(rxdesc->status);
913 	rxdesc->pkglen = letoh16(rxdesc->pkglen);
914 	rxdesc->pkgoffset = letoh32(rxdesc->pkgoffset);
915 
916 	DPRINTF(2, "RX status=%d, pkglen=%d, pkgoffset=%d\n",
917 	    rxdesc->status, rxdesc->pkglen, rxdesc->pkgoffset);
918 
919 	if (rxdesc->status != MALO_RX_STATUS_OK)
920 		/* RX packet is not OK */
921 		return;
922 
923 	/* remove the LLC / SNAP header */
924 	data = sc->sc_data + rxdesc->pkgoffset;
925 	i = (ETHER_ADDR_LEN * 2) + sizeof(struct llc);
926 	bcopy(data + i, data + (ETHER_ADDR_LEN * 2), rxdesc->pkglen - i);
927 	rxdesc->pkglen -= sizeof(struct llc);
928 
929 	/* prepare mbuf */
930 	m = m_devget(sc->sc_data + rxdesc->pkgoffset,
931 	    rxdesc->pkglen, ETHER_ALIGN, ifp, NULL);
932 	if (m == NULL) {
933 		DPRINTF(1, "RX m_devget failed\n");
934 		ifp->if_ierrors++;
935 		return;
936 	}
937 
938 #if NBPFILTER > 0
939 	if (ifp->if_bpf)
940 		bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
941 #endif
942 
943 	/* push the frame up to the network stack if not in monitor mode */
944 	if (ic->ic_opmode != IEEE80211_M_MONITOR) {
945 		ether_input_mbuf(ifp, m);
946 		ifp->if_ipackets++;
947 	}
948 }
949 
950 void
951 cmalo_start(struct ifnet *ifp)
952 {
953 	struct malo_softc *sc = ifp->if_softc;
954 	struct mbuf *m;
955 
956 	/* don't transmit packets if interface is busy or down */
957 	if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
958 		return;
959 
960 	IFQ_POLL(&ifp->if_snd, m);
961 	if (m == NULL)
962 		return;
963 
964 	IFQ_DEQUEUE(&ifp->if_snd, m);
965 
966 #if NBPFILTER > 0
967 	if (ifp->if_bpf)
968 		bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
969 #endif
970 
971 	if (cmalo_tx(sc, m) != 0)
972 		ifp->if_oerrors++;
973 }
974 
975 void
976 cmalo_watchdog(struct ifnet *ifp)
977 {
978 	DPRINTF(2, "watchdog timeout\n");
979 
980 	/* accept TX packets again */
981 	ifp->if_flags &= ~IFF_OACTIVE;
982 }
983 
984 int
985 cmalo_tx(struct malo_softc *sc, struct mbuf *m)
986 {
987 	struct ifnet *ifp = &sc->sc_ic.ic_if;
988 	struct malo_tx_desc *txdesc = sc->sc_data;
989 	uint8_t *data;
990 	uint16_t psize;
991 
992 	splassert(IPL_NET);
993 
994 	bzero(sc->sc_data, sizeof(*txdesc));
995 	psize = sizeof(*txdesc) + m->m_pkthdr.len;
996 	data = mtod(m, uint8_t *);
997 
998 	/* prepare TX descriptor */
999 	txdesc->pkgoffset = htole32(sizeof(*txdesc));
1000 	txdesc->pkglen = htole16(m->m_pkthdr.len);
1001 	bcopy(data, txdesc->dstaddrhigh, ETHER_ADDR_LEN);
1002 
1003 	/* copy mbuf data to the buffer */
1004 	m_copydata(m, 0, m->m_pkthdr.len, sc->sc_data + sizeof(*txdesc));
1005 	m_freem(m);
1006 
1007 	/* send TX packet to the device */
1008 	MALO_WRITE_2(sc, MALO_REG_DATA_WRITE_LEN, psize);
1009 	if (psize & 0x0001) {
1010 		MALO_WRITE_MULTI_2(sc, MALO_REG_DATA_WRITE, sc->sc_data,
1011 		    psize - 1);
1012 		data = (uint8_t *)sc->sc_data;
1013 		MALO_WRITE_1(sc, MALO_REG_DATA_WRITE, data[psize - 1]);
1014 	} else
1015 		MALO_WRITE_MULTI_2(sc, MALO_REG_DATA_WRITE, sc->sc_data, psize);
1016 	MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_TX_DL_OVER);
1017 	MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE, MALO_VAL_TX_DL_OVER);
1018 
1019 	ifp->if_flags |= IFF_OACTIVE;
1020 	ifp->if_timer = 5;
1021 
1022 	DPRINTF(2, "%s: TX status=%d, pkglen=%d, pkgoffset=%d\n",
1023 	    sc->sc_dev.dv_xname, txdesc->status, letoh16(txdesc->pkglen),
1024 	    sizeof(*txdesc));
1025 
1026 	return (0);
1027 }
1028 
1029 void
1030 cmalo_tx_done(struct malo_softc *sc)
1031 {
1032 	struct ifnet *ifp = &sc->sc_ic.ic_if;
1033 
1034 	splassert(IPL_NET);
1035 
1036 	DPRINTF(2, "%s: TX done\n", sc->sc_dev.dv_xname);
1037 
1038 	ifp->if_opackets++;
1039 	ifp->if_flags &= ~IFF_OACTIVE;
1040 	ifp->if_timer = 0;
1041 	cmalo_start(ifp);
1042 }
1043 
1044 void
1045 cmalo_event(struct malo_softc *sc)
1046 {
1047 	uint16_t event;
1048 
1049 	/* read event reason */
1050 	event = MALO_READ_2(sc, MALO_REG_CARD_STATUS);
1051 	event &= MALO_VAL_CARD_STATUS_MASK;
1052 	event = event >> 8;
1053 
1054 	switch (event) {
1055 	case MALO_EVENT_DEAUTH:
1056 		DPRINTF(1, "%s: got deauthentication event (0x%04x)\n",
1057 		    sc->sc_dev.dv_xname, event);
1058 		/* try to associate again */
1059 		cmalo_cmd_set_assoc(sc);
1060 		break;
1061 	case MALO_EVENT_DISASSOC:
1062 		DPRINTF(1, "%s: got disassociation event (0x%04x)\n",
1063 		    sc->sc_dev.dv_xname, event);
1064 		/* try to associate again */
1065 		cmalo_cmd_set_assoc(sc);
1066 		break;
1067 	default:
1068 		DPRINTF(1, "%s: got unknown event (0x%04x)\n",
1069 		    sc->sc_dev.dv_xname, event);
1070 		break;
1071 	}
1072 
1073 	/* acknowledge event */
1074 	MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE, MALO_VAL_HOST_INTR_EVENT);
1075 }
1076 
1077 void
1078 cmalo_select_network(struct malo_softc *sc)
1079 {
1080 	struct ieee80211com *ic = &sc->sc_ic;
1081 	int i, best_rssi;
1082 
1083 	/* reset last selected network */
1084 	sc->sc_net_cur = 0;
1085 
1086 	/* get desired network */
1087 	if (ic->ic_des_esslen) {
1088 		for (i = 0; i < sc->sc_net_num; i++) {
1089 			if (!strcmp(ic->ic_des_essid, sc->sc_net[i].ssid)) {
1090 				sc->sc_net_cur = i;
1091 				DPRINTF(1, "%s: desired network found (%s)\n",
1092 				    sc->sc_dev.dv_xname, ic->ic_des_essid);
1093 				return;
1094 			}
1095 		}
1096 		DPRINTF(1, "%s: desired network not found in scan results "
1097 		    "(%s)\n",
1098 		    sc->sc_dev.dv_xname, ic->ic_des_essid);
1099 	}
1100 
1101 	/* get network with best signal strength */
1102 	best_rssi = sc->sc_net[0].rssi;
1103 	for (i = 0; i < sc->sc_net_num; i++) {
1104 		if (best_rssi < sc->sc_net[i].rssi) {
1105 			best_rssi = sc->sc_net[i].rssi;
1106 			sc->sc_net_cur = i;
1107 		}
1108 	}
1109 	DPRINTF(1, "%s: best network found (%s)\n",
1110 	    sc->sc_dev.dv_xname, sc->sc_net[sc->sc_net_cur].ssid);
1111 }
1112 
1113 void
1114 cmalo_reflect_network(struct malo_softc *sc)
1115 {
1116 	struct ieee80211com *ic = &sc->sc_ic;
1117 	uint8_t chan;
1118 
1119 	/* reflect active network to our 80211 stack */
1120 
1121 	/* BSSID */
1122 	IEEE80211_ADDR_COPY(ic->ic_bss->ni_bssid,
1123 	    sc->sc_net[sc->sc_net_cur].bssid);
1124 
1125 	/* SSID */
1126 	ic->ic_bss->ni_esslen = strlen(sc->sc_net[sc->sc_net_cur].ssid);
1127 	bcopy(sc->sc_net[sc->sc_net_cur].ssid, ic->ic_bss->ni_essid,
1128 	    ic->ic_bss->ni_esslen);
1129 
1130 	/* channel */
1131 	chan = sc->sc_net[sc->sc_net_cur].channel;
1132 	ic->ic_bss->ni_chan = &ic->ic_channels[chan];
1133 }
1134 
1135 int
1136 cmalo_wep(struct malo_softc *sc)
1137 {
1138 	struct ieee80211com *ic = &sc->sc_ic;
1139 	int i;
1140 
1141 	for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1142 		struct ieee80211_key *key = &ic->ic_nw_keys[i];
1143 
1144 		if (!key->k_len)
1145 			continue;
1146 
1147 		DPRINTF(1, "%s: setting wep key for index %d\n",
1148 		    sc->sc_dev.dv_xname, i);
1149 
1150 		cmalo_cmd_set_wep(sc, i, key);
1151 	}
1152 
1153 	return (0);
1154 }
1155 
1156 int
1157 cmalo_rate2bitmap(int rate)
1158 {
1159 	switch (rate) {
1160 	/* CCK rates */
1161 	case  0:	return (MALO_RATE_BITMAP_DS1);
1162 	case  1:	return (MALO_RATE_BITMAP_DS2);
1163 	case  2:	return (MALO_RATE_BITMAP_DS5);
1164 	case  3:	return (MALO_RATE_BITMAP_DS11);
1165 
1166 	/* OFDM rates */
1167 	case  4:	return (MALO_RATE_BITMAP_OFDM6);
1168 	case  5:	return (MALO_RATE_BITMAP_OFDM9);
1169 	case  6:	return (MALO_RATE_BITMAP_OFDM12);
1170 	case  7:	return (MALO_RATE_BITMAP_OFDM18);
1171 	case  8:	return (MALO_RATE_BITMAP_OFDM24);
1172 	case  9:	return (MALO_RATE_BITMAP_OFDM36);
1173 	case 10:	return (MALO_RATE_BITMAP_OFDM48);
1174 	case 11:	return (MALO_RATE_BITMAP_OFDM54);
1175 
1176 	/* unknown rate: should not happen */
1177 	default:	return (0);
1178 	}
1179 }
1180 
1181 void
1182 cmalo_hexdump(void *buf, int len)
1183 {
1184 #ifdef CMALO_DEBUG
1185 	int i;
1186 
1187 	if (cmalo_d >= 2) {
1188 		for (i = 0; i < len; i++) {
1189 			if (i % 16 == 0)
1190 				printf("%s%5i:", i ? "\n" : "", i);
1191 			if (i % 4 == 0)
1192 				printf(" ");
1193 			printf("%02x", (int)*((u_char *)buf + i));
1194 		}
1195 		printf("\n");
1196 	}
1197 #endif
1198 }
1199 
1200 int
1201 cmalo_cmd_get_hwspec(struct malo_softc *sc)
1202 {
1203 	struct malo_cmd_header *hdr = sc->sc_cmd;
1204 	struct malo_cmd_body_spec *body;
1205 	uint16_t psize;
1206 
1207 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1208 	psize = sizeof(*hdr) + sizeof(*body);
1209 
1210 	hdr->cmd = htole16(MALO_CMD_HWSPEC);
1211 	hdr->size = htole16(sizeof(*body));
1212 	hdr->seqnum = htole16(1);
1213 	hdr->result = 0;
1214 	body = (struct malo_cmd_body_spec *)(hdr + 1);
1215 
1216 	/* set all bits for MAC address, otherwise we won't get one back */
1217 	memset(body->macaddr, 0xff, ETHER_ADDR_LEN);
1218 
1219 	/* process command request */
1220 	if (cmalo_cmd_request(sc, psize, 0) != 0)
1221 		return (EIO);
1222 
1223 	/* process command repsonse */
1224 	cmalo_cmd_response(sc);
1225 
1226 	return (0);
1227 }
1228 
1229 int
1230 cmalo_cmd_rsp_hwspec(struct malo_softc *sc)
1231 {
1232 	struct ieee80211com *ic = &sc->sc_ic;
1233 	struct malo_cmd_header *hdr = sc->sc_cmd;
1234 	struct malo_cmd_body_spec *body;
1235 	int i;
1236 
1237 	body = (struct malo_cmd_body_spec *)(hdr + 1);
1238 
1239 	/* get our MAC address */
1240 	for (i = 0; i < ETHER_ADDR_LEN; i++)
1241 		ic->ic_myaddr[i] = body->macaddr[i];
1242 
1243 	return (0);
1244 }
1245 
1246 int
1247 cmalo_cmd_set_reset(struct malo_softc *sc)
1248 {
1249 	struct malo_cmd_header *hdr = sc->sc_cmd;
1250 	uint16_t psize;
1251 
1252 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1253 	psize = sizeof(*hdr);
1254 
1255 	hdr->cmd = htole16(MALO_CMD_RESET);
1256 	hdr->size = 0;
1257 	hdr->seqnum = htole16(1);
1258 	hdr->result = 0;
1259 
1260 	/* process command request */
1261 	if (cmalo_cmd_request(sc, psize, 1) != 0)
1262 		return (EIO);
1263 
1264 	/* give the device some time to finish the reset */
1265 	delay(100);
1266 
1267 	return (0);
1268 }
1269 
1270 int
1271 cmalo_cmd_set_scan(struct malo_softc *sc)
1272 {
1273 	struct ieee80211com *ic = &sc->sc_ic;
1274 	struct malo_cmd_header *hdr = sc->sc_cmd;
1275 	struct malo_cmd_body_scan *body;
1276 	struct malo_cmd_tlv_ssid *body_ssid;
1277 	struct malo_cmd_tlv_chanlist *body_chanlist;
1278 	struct malo_cmd_tlv_rates *body_rates;
1279 	//struct malo_cmd_tlv_numprobes *body_numprobes;
1280 	uint16_t psize;
1281 	int i;
1282 
1283 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1284 	psize = sizeof(*hdr) + sizeof(*body);
1285 
1286 	hdr->cmd = htole16(MALO_CMD_SCAN);
1287 	hdr->seqnum = htole16(1);
1288 	hdr->result = 0;
1289 	body = (struct malo_cmd_body_scan *)(hdr + 1);
1290 
1291 	body->bsstype = 0x03; /* any BSS */
1292 	memset(body->bssid, 0xff, ETHER_ADDR_LEN);
1293 
1294 	body_ssid = sc->sc_cmd + psize;
1295 	body_ssid->type = htole16(MALO_TLV_TYPE_SSID);
1296 	body_ssid->size = htole16(0);
1297 	psize += (sizeof(*body_ssid) - 1);
1298 
1299 	body_chanlist = sc->sc_cmd + psize;
1300 	body_chanlist->type = htole16(MALO_TLV_TYPE_CHANLIST);
1301 	body_chanlist->size = htole16(sizeof(body_chanlist->data));
1302 	for (i = 0; i < CHANNELS; i++) {
1303 		body_chanlist->data[i].radiotype = 0x00;
1304 		body_chanlist->data[i].channumber = (i + 1);
1305 		body_chanlist->data[i].scantype = 0x00; /* active */
1306 		body_chanlist->data[i].minscantime = htole16(0);
1307 		body_chanlist->data[i].maxscantime = htole16(100);
1308 	}
1309 	psize += sizeof(*body_chanlist);
1310 
1311 	body_rates = sc->sc_cmd + psize;
1312 	body_rates->type = htole16(MALO_TLV_TYPE_RATES);
1313 	body_rates->size =
1314 	    htole16(ic->ic_sup_rates[IEEE80211_MODE_11B].rs_nrates);
1315 	bcopy(ic->ic_sup_rates[IEEE80211_MODE_11B].rs_rates, body_rates->data,
1316 	    ic->ic_sup_rates[IEEE80211_MODE_11B].rs_nrates);
1317 	psize += (sizeof(*body_rates) - 1) + letoh16(body_rates->size);
1318 #if 0
1319 	body_numprobes = sc->sc_cmd + psize;
1320 	body_numprobes->type = htole16(MALO_TLV_TYPE_NUMPROBES);
1321 	body_numprobes->size = htole16(2);
1322 	body_numprobes->numprobes = htole16(1);
1323 	psize += sizeof(*body_numprobes);
1324 #endif
1325 	hdr->size = htole16(psize - sizeof(*hdr));
1326 
1327 	/* process command request */
1328 	if (cmalo_cmd_request(sc, psize, 0) != 0)
1329 		return (EIO);
1330 
1331 	/* process command repsonse */
1332 	cmalo_cmd_response(sc);
1333 
1334 	return (0);
1335 }
1336 
1337 int
1338 cmalo_cmd_rsp_scan(struct malo_softc *sc)
1339 {
1340 	struct malo_cmd_header *hdr = sc->sc_cmd;
1341 	struct malo_cmd_body_rsp_scan *body;
1342 	struct malo_cmd_body_rsp_scan_set *set;
1343 	uint16_t psize;
1344 	int i;
1345 
1346 	bzero(sc->sc_net, sizeof(sc->sc_net));
1347 	psize = sizeof(*hdr) + sizeof(*body);
1348 
1349 	body = (struct malo_cmd_body_rsp_scan *)(hdr + 1);
1350 
1351 	body->bufsize = letoh16(body->bufsize);
1352 
1353 	DPRINTF(1, "bufsize=%d, APs=%d\n", body->bufsize, body->numofset);
1354 	sc->sc_net_num = body->numofset;
1355 
1356 	/* cycle through found networks */
1357 	for (i = 0; i < body->numofset; i++) {
1358 		set = (struct malo_cmd_body_rsp_scan_set *)(sc->sc_cmd + psize);
1359 
1360 		set->size = letoh16(set->size);
1361 		set->beaconintvl = letoh16(set->beaconintvl);
1362 		set->capinfo = letoh16(set->capinfo);
1363 
1364 		DPRINTF(1, "size=%d, bssid=%s, rssi=%d, beaconintvl=%d, "
1365 		    "capinfo=0x%04x\n",
1366 		    set->size, ether_sprintf(set->bssid), set->rssi,
1367 		    set->beaconintvl, set->capinfo);
1368 
1369 		/* save scan results */
1370 		bcopy(set->bssid, sc->sc_net[i].bssid, sizeof(set->bssid));
1371 		bcopy(set->timestamp, sc->sc_net[i].timestamp,
1372 		    sizeof(set->timestamp));
1373 		sc->sc_net[i].rssi = set->rssi;
1374 		sc->sc_net[i].beaconintvl = set->beaconintvl;
1375 		sc->sc_net[i].capinfo = set->capinfo;
1376 		cmalo_parse_elements(sc, (set + 1),
1377 		    set->size - (sizeof(*set) - sizeof(set->size)), i);
1378 
1379 		psize += (set->size + sizeof(set->size));
1380 	}
1381 
1382 	return (0);
1383 }
1384 
1385 int
1386 cmalo_parse_elements(struct malo_softc *sc, void *buf, int size, int pos)
1387 {
1388 	uint8_t eid, len;
1389 	int i;
1390 
1391 	DPRINTF(2, "element_size=%d, element_pos=%d\n", size, pos);
1392 
1393 	for (i = 0; i < size; ) {
1394 		eid = *(uint8_t *)(buf + i);
1395 		i++;
1396 		len = *(uint8_t *)(buf + i);
1397 		i++;
1398 		DPRINTF(2, "eid=%d, len=%d, ", eid, len);
1399 
1400 		switch (eid) {
1401 		case IEEE80211_ELEMID_SSID:
1402 			bcopy(buf + i, sc->sc_net[pos].ssid, len);
1403 			DPRINTF(2, "ssid=%s\n", sc->sc_net[pos].ssid);
1404 			break;
1405 		case IEEE80211_ELEMID_RATES:
1406 			bcopy(buf + i, sc->sc_net[pos].rates, len);
1407 			DPRINTF(2, "rates\n");
1408 			break;
1409 		case IEEE80211_ELEMID_DSPARMS:
1410 			sc->sc_net[pos].channel = *(uint8_t *)(buf + i);
1411 			DPRINTF(2, "chnl=%d\n", sc->sc_net[pos].channel);
1412 			break;
1413 		default:
1414 			DPRINTF(2, "unknown\n");
1415 			break;
1416 		}
1417 
1418 		i += len;
1419 	}
1420 
1421 	return (0);
1422 }
1423 
1424 int
1425 cmalo_cmd_set_auth(struct malo_softc *sc)
1426 {
1427 	struct malo_cmd_header *hdr = sc->sc_cmd;
1428 	struct malo_cmd_body_auth *body;
1429 	uint16_t psize;
1430 
1431 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1432 	psize = sizeof(*hdr) + sizeof(*body);
1433 
1434 	hdr->cmd = htole16(MALO_CMD_AUTH);
1435 	hdr->size = htole16(sizeof(*body));
1436 	hdr->seqnum = htole16(1);
1437 	hdr->result = 0;
1438 	body = (struct malo_cmd_body_auth *)(hdr + 1);
1439 
1440 	bcopy(sc->sc_net[sc->sc_net_cur].bssid, body->peermac, ETHER_ADDR_LEN);
1441 	body->authtype = 0;
1442 
1443 	/* process command request */
1444 	if (cmalo_cmd_request(sc, psize, 0) != 0)
1445 		return (EIO);
1446 
1447 	/* process command repsonse */
1448 	cmalo_cmd_response(sc);
1449 
1450 	return (0);
1451 }
1452 
1453 int
1454 cmalo_cmd_set_wep(struct malo_softc *sc, uint16_t index,
1455     struct ieee80211_key *key)
1456 {
1457 	struct malo_cmd_header *hdr = sc->sc_cmd;
1458 	struct malo_cmd_body_wep *body;
1459 	uint16_t psize;
1460 
1461 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1462 	psize = sizeof(*hdr) + sizeof(*body);
1463 
1464 	hdr->cmd = htole16(MALO_CMD_WEP);
1465 	hdr->size = htole16(sizeof(*body));
1466 	hdr->seqnum = htole16(1);
1467 	hdr->result = 0;
1468 	body = (struct malo_cmd_body_wep *)(hdr + 1);
1469 
1470 	body->action = htole16(MALO_WEP_ACTION_TYPE_ADD);
1471 	body->key_index = htole16(index);
1472 
1473 	if (body->key_index == 0) {
1474 		if (key->k_len > 5)
1475 			body->key_type_1 = MALO_WEP_KEY_TYPE_104BIT;
1476 		else
1477 			body->key_type_1 = MALO_WEP_KEY_TYPE_40BIT;
1478 		bcopy(key->k_key, body->key_value_1, key->k_len);
1479 	}
1480 	if (body->key_index == 1) {
1481 		if (key->k_len > 5)
1482 			body->key_type_2 = MALO_WEP_KEY_TYPE_104BIT;
1483 		else
1484 			body->key_type_2 = MALO_WEP_KEY_TYPE_40BIT;
1485 		bcopy(key->k_key, body->key_value_2, key->k_len);
1486 	}
1487 	if (body->key_index == 2) {
1488 		if (key->k_len > 5)
1489 			body->key_type_3 = MALO_WEP_KEY_TYPE_104BIT;
1490 		else
1491 			body->key_type_3 = MALO_WEP_KEY_TYPE_40BIT;
1492 		bcopy(key->k_key, body->key_value_3, key->k_len);
1493 	}
1494 	if (body->key_index == 3) {
1495 		if (key->k_len > 5)
1496 			body->key_type_4 = MALO_WEP_KEY_TYPE_104BIT;
1497 		else
1498 			body->key_type_4 = MALO_WEP_KEY_TYPE_40BIT;
1499 		bcopy(key->k_key, body->key_value_4, key->k_len);
1500 	}
1501 
1502 	/* process command request */
1503 	if (cmalo_cmd_request(sc, psize, 0) != 0)
1504 		return (EIO);
1505 
1506 	/* process command repsonse */
1507 	cmalo_cmd_response(sc);
1508 
1509 	return (0);
1510 }
1511 
1512 int
1513 cmalo_cmd_set_snmp(struct malo_softc *sc, uint16_t oid)
1514 {
1515 	struct malo_cmd_header *hdr = sc->sc_cmd;
1516 	struct malo_cmd_body_snmp *body;
1517 	uint16_t psize;
1518 
1519 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1520 	psize = sizeof(*hdr) + sizeof(*body);
1521 
1522 	hdr->cmd = htole16(MALO_CMD_SNMP);
1523 	hdr->size = htole16(sizeof(*body));
1524 	hdr->seqnum = htole16(1);
1525 	hdr->result = 0;
1526 	body = (struct malo_cmd_body_snmp *)(hdr + 1);
1527 
1528 	body->action = htole16(1);
1529 
1530 	switch (oid) {
1531 	case MALO_OID_RTSTRESH:
1532 		body->oid = htole16(MALO_OID_RTSTRESH);
1533 		body->size = htole16(2);
1534 		*(uint16_t *)body->data = htole16(2347);
1535 		break;
1536 	case MALO_OID_SHORTRETRY:
1537 		body->oid = htole16(MALO_OID_SHORTRETRY);
1538 		body->size = htole16(2);
1539 		*(uint16_t *)body->data = htole16(4);
1540 		break;
1541 	case MALO_OID_FRAGTRESH:
1542 		body->oid = htole16(MALO_OID_FRAGTRESH);
1543 		body->size = htole16(2);
1544 		*(uint16_t *)body->data = htole16(2346);
1545 		break;
1546 	case MALO_OID_80211D:
1547 		body->oid = htole16(MALO_OID_80211D);
1548 		body->size = htole16(2);
1549 		*(uint16_t *)body->data = htole16(1);
1550 		break;
1551 	default:
1552 		break;
1553 	}
1554 
1555 	/* process command request */
1556 	if (cmalo_cmd_request(sc, psize, 0) != 0)
1557 		return (EIO);
1558 
1559 	/* process command repsonse */
1560 	cmalo_cmd_response(sc);
1561 
1562 	return (0);
1563 }
1564 
1565 int
1566 cmalo_cmd_set_radio(struct malo_softc *sc, uint16_t control)
1567 {
1568 	struct malo_cmd_header *hdr = sc->sc_cmd;
1569 	struct malo_cmd_body_radio *body;
1570 	uint16_t psize;
1571 
1572 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1573 	psize = sizeof(*hdr) + sizeof(*body);
1574 
1575 	hdr->cmd = htole16(MALO_CMD_RADIO);
1576 	hdr->size = htole16(sizeof(*body));
1577 	hdr->seqnum = htole16(1);
1578 	hdr->result = 0;
1579 	body = (struct malo_cmd_body_radio *)(hdr + 1);
1580 
1581 	body->action = htole16(1);
1582 
1583 	if (control) {
1584 		body->control  = htole16(MALO_CMD_RADIO_ON);
1585 		body->control |= htole16(MALO_CMD_RADIO_AUTO_P);
1586 	}
1587 
1588 	/* process command request */
1589 	if (cmalo_cmd_request(sc, psize, 0) != 0)
1590 		return (EIO);
1591 
1592 	/* process command repsonse */
1593 	cmalo_cmd_response(sc);
1594 
1595 	return (0);
1596 }
1597 
1598 int
1599 cmalo_cmd_set_channel(struct malo_softc *sc, uint16_t channel)
1600 {
1601 	struct malo_cmd_header *hdr = sc->sc_cmd;
1602 	struct malo_cmd_body_channel *body;
1603 	uint16_t psize;
1604 
1605 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1606 	psize = sizeof(*hdr) + sizeof(*body);
1607 
1608 	hdr->cmd = htole16(MALO_CMD_CHANNEL);
1609 	hdr->size = htole16(sizeof(*body));
1610 	hdr->seqnum = htole16(1);
1611 	hdr->result = 0;
1612 	body = (struct malo_cmd_body_channel *)(hdr + 1);
1613 
1614 	body->action = htole16(1);
1615 	body->channel = htole16(channel);
1616 
1617 	/* process command request */
1618 	if (cmalo_cmd_request(sc, psize, 0) != 0)
1619 		return (EIO);
1620 
1621 	/* process command repsonse */
1622 	cmalo_cmd_response(sc);
1623 
1624 	return (0);
1625 }
1626 
1627 
1628 int
1629 cmalo_cmd_set_txpower(struct malo_softc *sc, int16_t txpower)
1630 {
1631 	struct malo_cmd_header *hdr = sc->sc_cmd;
1632 	struct malo_cmd_body_txpower *body;
1633 	uint16_t psize;
1634 
1635 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1636 	psize = sizeof(*hdr) + sizeof(*body);
1637 
1638 	hdr->cmd = htole16(MALO_CMD_TXPOWER);
1639 	hdr->size = htole16(sizeof(*body));
1640 	hdr->seqnum = htole16(1);
1641 	hdr->result = 0;
1642 	body = (struct malo_cmd_body_txpower *)(hdr + 1);
1643 
1644 	body->action = htole16(1);
1645 	body->txpower = htole16(txpower);
1646 
1647 	/* process command request */
1648 	if (cmalo_cmd_request(sc, psize, 0) != 0)
1649 		return (EIO);
1650 
1651 	/* process command repsonse */
1652 	cmalo_cmd_response(sc);
1653 
1654 	return (0);
1655 }
1656 
1657 int
1658 cmalo_cmd_set_antenna(struct malo_softc *sc, uint16_t action)
1659 {
1660 	struct malo_cmd_header *hdr = sc->sc_cmd;
1661 	struct malo_cmd_body_antenna *body;
1662 	uint16_t psize;
1663 
1664 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1665 	psize = sizeof(*hdr) + sizeof(*body);
1666 
1667 	hdr->cmd = htole16(MALO_CMD_ANTENNA);
1668 	hdr->size = htole16(sizeof(*body));
1669 	hdr->seqnum = htole16(1);
1670 	hdr->result = 0;
1671 	body = (struct malo_cmd_body_antenna *)(hdr + 1);
1672 
1673 	/* 1 = set RX, 2 = set TX */
1674 	body->action = htole16(action);
1675 
1676 	if (action == 1)
1677 		/* set RX antenna */
1678 		body->antenna_mode = htole16(0xffff);
1679 	if (action == 2)
1680 		/* set TX antenna */
1681 		body->antenna_mode = htole16(2);
1682 
1683 	/* process command request */
1684 	if (cmalo_cmd_request(sc, psize, 0) != 0)
1685 		return (EIO);
1686 
1687 	/* process command repsonse */
1688 	cmalo_cmd_response(sc);
1689 
1690 	return (0);
1691 }
1692 
1693 int
1694 cmalo_cmd_set_macctrl(struct malo_softc *sc)
1695 {
1696 	struct ieee80211com *ic = &sc->sc_ic;
1697 	struct malo_cmd_header *hdr = sc->sc_cmd;
1698 	struct malo_cmd_body_macctrl *body;
1699 	uint16_t psize;
1700 
1701 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1702 	psize = sizeof(*hdr) + sizeof(*body);
1703 
1704 	hdr->cmd = htole16(MALO_CMD_MACCTRL);
1705 	hdr->size = htole16(sizeof(*body));
1706 	hdr->seqnum = htole16(1);
1707 	hdr->result = 0;
1708 	body = (struct malo_cmd_body_macctrl *)(hdr + 1);
1709 
1710 	body->action  = htole16(MALO_CMD_MACCTRL_RX_ON);
1711 	body->action |= htole16(MALO_CMD_MACCTRL_TX_ON);
1712 	if (ic->ic_opmode == IEEE80211_M_MONITOR)
1713 		body->action |= htole16(MALO_CMD_MACCTRL_PROMISC_ON);
1714 
1715 	/* process command request */
1716 	if (cmalo_cmd_request(sc, psize, 0) != 0)
1717 		return (EIO);
1718 
1719 	/* process command repsonse */
1720 	cmalo_cmd_response(sc);
1721 
1722 	return (0);
1723 }
1724 
1725 int
1726 cmalo_cmd_set_macaddr(struct malo_softc *sc, uint8_t *macaddr)
1727 {
1728 	struct malo_cmd_header *hdr = sc->sc_cmd;
1729 	struct malo_cmd_body_macaddr *body;
1730 	uint16_t psize;
1731 
1732 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1733 	psize = sizeof(*hdr) + sizeof(*body);
1734 
1735 	hdr->cmd = htole16(MALO_CMD_MACADDR);
1736 	hdr->size = htole16(sizeof(*body));
1737 	hdr->seqnum = htole16(1);
1738 	hdr->result = 0;
1739 	body = (struct malo_cmd_body_macaddr *)(hdr + 1);
1740 
1741 	body->action = htole16(1);
1742 	bcopy(macaddr, body->macaddr, ETHER_ADDR_LEN);
1743 
1744 	/* process command request */
1745 	if (cmalo_cmd_request(sc, psize, 0) != 0)
1746 		return (EIO);
1747 
1748 	/* process command repsonse */
1749 	cmalo_cmd_response(sc);
1750 
1751 	return (0);
1752 }
1753 
1754 int
1755 cmalo_cmd_set_assoc(struct malo_softc *sc)
1756 {
1757 	struct malo_cmd_header *hdr = sc->sc_cmd;
1758 	struct malo_cmd_body_assoc *body;
1759 	struct malo_cmd_tlv_ssid *body_ssid;
1760 	struct malo_cmd_tlv_phy *body_phy;
1761 	struct malo_cmd_tlv_cf *body_cf;
1762 	struct malo_cmd_tlv_rates *body_rates;
1763 	struct malo_cmd_tlv_passeid *body_passeid;
1764 	uint16_t psize;
1765 
1766 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1767 	psize = sizeof(*hdr) + sizeof(*body);
1768 
1769 	hdr->cmd = htole16(MALO_CMD_ASSOC);
1770 	hdr->seqnum = htole16(1);
1771 	hdr->result = 0;
1772 	body = (struct malo_cmd_body_assoc *)(hdr + 1);
1773 
1774 	bcopy(sc->sc_net[sc->sc_net_cur].bssid, body->peermac, ETHER_ADDR_LEN);
1775 	body->capinfo = htole16(sc->sc_net[sc->sc_net_cur].capinfo);
1776 	body->listenintrv = htole16(10);
1777 
1778 	body_ssid = sc->sc_cmd + psize;
1779 	body_ssid->type = htole16(MALO_TLV_TYPE_SSID);
1780 	body_ssid->size = htole16(strlen(sc->sc_net[sc->sc_net_cur].ssid));
1781 	bcopy(sc->sc_net[sc->sc_net_cur].ssid, body_ssid->data,
1782 	    letoh16(body_ssid->size));
1783 	psize += (sizeof(*body_ssid) - 1) + letoh16(body_ssid->size);
1784 
1785 	body_phy = sc->sc_cmd + psize;
1786 	body_phy->type = htole16(MALO_TLV_TYPE_PHY);
1787 	body_phy->size = htole16(1);
1788 	bcopy(&sc->sc_net[sc->sc_net_cur].channel, body_phy->data, 1);
1789 	psize += sizeof(*body_phy);
1790 
1791 	body_cf = sc->sc_cmd + psize;
1792 	body_cf->type = htole16(MALO_TLV_TYPE_CF);
1793 	body_cf->size = htole16(0);
1794 	psize += (sizeof(*body_cf) - 1);
1795 
1796 	body_rates = sc->sc_cmd + psize;
1797 	body_rates->type = htole16(MALO_TLV_TYPE_RATES);
1798 	body_rates->size = htole16(strlen(sc->sc_net[sc->sc_net_cur].rates));
1799 	bcopy(sc->sc_net[sc->sc_net_cur].rates, body_rates->data,
1800 	    letoh16(body_rates->size));
1801 	psize += (sizeof(*body_rates) - 1) + letoh16(body_rates->size);
1802 
1803 	/* hack to correct FW's wrong generated rates-element-id */
1804 	body_passeid = sc->sc_cmd + psize;
1805 	body_passeid->type = htole16(MALO_TLV_TYPE_PASSEID);
1806 	body_passeid->size = body_rates->size;
1807 	bcopy(body_rates->data, body_passeid->data, letoh16(body_rates->size));
1808 	psize += (sizeof(*body_passeid) - 1) + letoh16(body_passeid->size);
1809 
1810 	hdr->size = htole16(psize - sizeof(*hdr));
1811 
1812 	/* process command request */
1813 	if (!sc->sc_cmd_ctxsave) {
1814 		if (cmalo_cmd_request(sc, psize, 1) != 0)
1815 			return (EIO);
1816 		return (0);
1817 	}
1818 	if (cmalo_cmd_request(sc, psize, 0) != 0)
1819 		return (EIO);
1820 
1821 	/* process command repsonse */
1822 	cmalo_cmd_response(sc);
1823 
1824 	return (0);
1825 }
1826 
1827 int
1828 cmalo_cmd_rsp_assoc(struct malo_softc *sc)
1829 {
1830 	struct malo_cmd_header *hdr = sc->sc_cmd;
1831 	struct malo_cmd_body_rsp_assoc *body;
1832 
1833 	body = (struct malo_cmd_body_rsp_assoc *)(hdr + 1);
1834 
1835 	if (body->status) {
1836 		DPRINTF(1, "%s: association failed (status %d)\n",
1837 		    sc->sc_dev.dv_xname, body->status);
1838 		sc->sc_flags |= MALO_ASSOC_FAILED;
1839 	} else
1840 		DPRINTF(1, "%s: association successful\n",
1841 		    sc->sc_dev.dv_xname, body->status);
1842 
1843 	return (0);
1844 }
1845 
1846 int
1847 cmalo_cmd_set_80211d(struct malo_softc *sc)
1848 {
1849 	struct malo_cmd_header *hdr = sc->sc_cmd;
1850 	struct malo_cmd_body_80211d *body;
1851 	struct malo_cmd_tlv_80211d *body_80211d;
1852 	uint16_t psize;
1853 	int i;
1854 
1855 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1856 	psize = sizeof(*hdr) + sizeof(*body);
1857 
1858 	hdr->cmd = htole16(MALO_CMD_80211D);
1859 	hdr->seqnum = htole16(1);
1860 	hdr->result = 0;
1861 	body = (struct malo_cmd_body_80211d *)(hdr + 1);
1862 
1863 	body->action = htole16(1);
1864 
1865 	body_80211d = sc->sc_cmd + psize;
1866 	body_80211d->type = htole16(MALO_TLV_TYPE_80211D);
1867 	body_80211d->size = htole16(sizeof(body_80211d->data) +
1868 	    sizeof(body_80211d->countrycode));
1869 	bcopy("EU ", body_80211d->countrycode,
1870 	    sizeof(body_80211d->countrycode));
1871 	for (i = 0; i < CHANNELS; i++) {
1872 		body_80211d->data[i].firstchannel = 1;
1873 		body_80211d->data[i].numchannels = 12;
1874 		body_80211d->data[i].maxtxpower = 10;
1875 	}
1876 	psize += sizeof(*body_80211d);
1877 
1878 	hdr->size = htole16(psize - sizeof(*hdr));
1879 
1880 	/* process command request */
1881 	if (cmalo_cmd_request(sc, psize, 0) != 0)
1882 		return (EIO);
1883 
1884 	/* process command repsonse */
1885 	cmalo_cmd_response(sc);
1886 
1887 	return (0);
1888 }
1889 
1890 int
1891 cmalo_cmd_set_bgscan_config(struct malo_softc *sc)
1892 {
1893 	struct malo_cmd_header *hdr = sc->sc_cmd;
1894 	struct malo_cmd_body_bgscan_config *body;
1895 	uint16_t psize;
1896 
1897 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1898 	psize = sizeof(*hdr) + sizeof(*body);
1899 
1900 	hdr->cmd = htole16(MALO_CMD_BGSCAN_CONFIG);
1901 	hdr->size = htole16(sizeof(*body));
1902 	hdr->seqnum = htole16(1);
1903 	hdr->result = 0;
1904 	body = (struct malo_cmd_body_bgscan_config *)(hdr + 1);
1905 
1906 	body->action = htole16(1);
1907 	body->enable = 1;
1908 	body->bsstype = 0x03;
1909 	body->chperscan = 12;
1910 	body->scanintvl = htole32(100);
1911 	body->maxscanres = htole16(12);
1912 
1913 	/* process command request */
1914 	if (cmalo_cmd_request(sc, psize, 0) != 0)
1915 		return (EIO);
1916 
1917 	/* process command repsonse */
1918 	cmalo_cmd_response(sc);
1919 
1920 	return (0);
1921 }
1922 
1923 int
1924 cmalo_cmd_set_bgscan_query(struct malo_softc *sc)
1925 {
1926 	struct malo_cmd_header *hdr = sc->sc_cmd;
1927 	struct malo_cmd_body_bgscan_query *body;
1928 	uint16_t psize;
1929 
1930 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1931 	psize = sizeof(*hdr) + sizeof(*body);
1932 
1933 	hdr->cmd = htole16(MALO_CMD_BGSCAN_QUERY);
1934 	hdr->size = htole16(sizeof(*body));
1935 	hdr->seqnum = htole16(1);
1936 	hdr->result = 0;
1937 	body = (struct malo_cmd_body_bgscan_query *)(hdr + 1);
1938 
1939 	body->flush = 0;
1940 
1941 	/* process command request */
1942 	if (cmalo_cmd_request(sc, psize, 0) != 0)
1943 		return (EIO);
1944 
1945 	/* process command repsonse */
1946 	cmalo_cmd_response(sc);
1947 
1948 	return (0);
1949 }
1950 
1951 int
1952 cmalo_cmd_set_rate(struct malo_softc *sc, int rate)
1953 {
1954 	struct malo_cmd_header *hdr = sc->sc_cmd;
1955 	struct malo_cmd_body_rate *body;
1956 	uint16_t psize;
1957 
1958 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1959 	psize = sizeof(*hdr) + sizeof(*body);
1960 
1961 	hdr->cmd = htole16(MALO_CMD_RATE);
1962 	hdr->size = htole16(sizeof(*body));
1963 	hdr->seqnum = htole16(1);
1964 	hdr->result = 0;
1965 	body = (struct malo_cmd_body_rate *)(hdr + 1);
1966 
1967 	body->action = htole16(1);
1968 	if (rate == -1) {
1969  		body->hwauto = htole16(1);
1970 		body->ratebitmap = htole16(MALO_RATE_BITMAP_AUTO);
1971 	} else {
1972  		body->hwauto = 0;
1973 		body->ratebitmap = htole16(cmalo_rate2bitmap(rate));
1974 	}
1975 
1976 	/* process command request */
1977 	if (cmalo_cmd_request(sc, psize, 0) != 0)
1978 		return (EIO);
1979 
1980 	/* process command repsonse */
1981 	cmalo_cmd_response(sc);
1982 
1983 	return (0);
1984 }
1985 
1986 int
1987 cmalo_cmd_request(struct malo_softc *sc, uint16_t psize, int no_response)
1988 {
1989 	uint8_t *cmd;
1990 
1991 	cmalo_hexdump(sc->sc_cmd, psize);
1992 
1993 	/* send command request */
1994 	MALO_WRITE_2(sc, MALO_REG_CMD_WRITE_LEN, psize);
1995 	if (psize & 0x0001) {
1996 		MALO_WRITE_MULTI_2(sc, MALO_REG_CMD_WRITE, sc->sc_cmd,
1997 		    psize - 1);
1998 		cmd = (uint8_t *)sc->sc_cmd;
1999 		MALO_WRITE_1(sc, MALO_REG_CMD_WRITE, cmd[psize - 1]);
2000 	} else
2001 		MALO_WRITE_MULTI_2(sc, MALO_REG_CMD_WRITE, sc->sc_cmd, psize);
2002 	MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_CMD_DL_OVER);
2003 	MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE, MALO_VAL_CMD_DL_OVER);
2004 
2005 	if (no_response)
2006 		/* we don't expect a response */
2007 		return (0);
2008 
2009 	/* wait for the command response */
2010 	if (tsleep(sc, 0, "malocmd", 500)) {
2011 		printf("%s: timeout while waiting for cmd response\n",
2012 		    sc->sc_dev.dv_xname);
2013 		return (EIO);
2014 	}
2015 
2016 	return (0);
2017 }
2018 
2019 int
2020 cmalo_cmd_response(struct malo_softc *sc)
2021 {
2022 	struct malo_cmd_header *hdr = sc->sc_cmd;
2023 	uint16_t psize;
2024 	uint8_t *cmd;
2025 	int s;
2026 
2027 	s = splnet();
2028 
2029 	bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
2030 
2031 	/* read the whole command response */
2032 	psize = MALO_READ_2(sc, MALO_REG_CMD_READ_LEN);
2033 	if (psize & 0x0001) {
2034 		MALO_READ_MULTI_2(sc, MALO_REG_CMD_READ, sc->sc_cmd,
2035 		    psize - 1);
2036 		cmd = (uint8_t *)sc->sc_cmd;
2037 		cmd[psize - 1] = MALO_READ_1(sc, MALO_REG_CMD_READ);
2038 	} else
2039 		MALO_READ_MULTI_2(sc, MALO_REG_CMD_READ, sc->sc_cmd, psize);
2040 
2041 	cmalo_hexdump(sc->sc_cmd, psize);
2042 
2043 	/*
2044 	 * We convert the header values into the machines correct endianess,
2045 	 * so we don't have to letoh16() all over the code.  The body is
2046 	 * kept in the cards order, little endian.  We need to take care
2047 	 * about the body endianess in the corresponding response routines.
2048 	 */
2049 	hdr->cmd = letoh16(hdr->cmd);
2050 	hdr->size = letoh16(hdr->size);
2051 	hdr->seqnum = letoh16(hdr->seqnum);
2052 	hdr->result = letoh16(hdr->result);
2053 
2054 	/* check for a valid command response */
2055 	if (!(hdr->cmd & MALO_CMD_RESP)) {
2056 		printf("%s: got invalid command response (0x%04x)\n",
2057 		    sc->sc_dev.dv_xname, hdr->cmd);
2058 		splx(s);
2059 		return (EIO);
2060 	}
2061 	hdr->cmd &= ~MALO_CMD_RESP;
2062 
2063 	/* association cmd response is special */
2064 	if (hdr->cmd == 0x0012)
2065 		hdr->cmd = MALO_CMD_ASSOC;
2066 
2067 	/* to which command does the response belong */
2068 	switch (hdr->cmd) {
2069 	case MALO_CMD_HWSPEC:
2070 		DPRINTF(1, "%s: got hwspec cmd response\n",
2071 		    sc->sc_dev.dv_xname);
2072 		cmalo_cmd_rsp_hwspec(sc);
2073 		break;
2074 	case MALO_CMD_RESET:
2075 		/* reset will not send back a response */
2076 		break;
2077 	case MALO_CMD_SCAN:
2078 		DPRINTF(1, "%s: got scan cmd response\n",
2079 		    sc->sc_dev.dv_xname);
2080 		cmalo_cmd_rsp_scan(sc);
2081 		break;
2082 	case MALO_CMD_AUTH:
2083 		/* do nothing */
2084 		DPRINTF(1, "%s: got auth cmd response\n",
2085 		    sc->sc_dev.dv_xname);
2086 		break;
2087 	case MALO_CMD_WEP:
2088 		/* do nothing */
2089 		DPRINTF(1, "%s: got wep cmd response\n",
2090 		    sc->sc_dev.dv_xname);
2091 		break;
2092 	case MALO_CMD_SNMP:
2093 		/* do nothing */
2094 		DPRINTF(1, "%s: got snmp cmd response\n",
2095 		    sc->sc_dev.dv_xname);
2096 		break;
2097 	case MALO_CMD_RADIO:
2098 		/* do nothing */
2099 		DPRINTF(1, "%s: got radio cmd response\n",
2100 		    sc->sc_dev.dv_xname);
2101 		break;
2102 	case MALO_CMD_CHANNEL:
2103 		/* do nothing */
2104 		DPRINTF(1, "%s: got channel cmd response\n",
2105 		    sc->sc_dev.dv_xname);
2106 		break;
2107 	case MALO_CMD_TXPOWER:
2108 		/* do nothing */
2109 		DPRINTF(1, "%s: got txpower cmd response\n",
2110 		    sc->sc_dev.dv_xname);
2111 		break;
2112 	case MALO_CMD_ANTENNA:
2113 		/* do nothing */
2114 		DPRINTF(1, "%s: got antenna cmd response\n",
2115 		    sc->sc_dev.dv_xname);
2116 		break;
2117 	case MALO_CMD_MACCTRL:
2118 		/* do nothing */
2119 		DPRINTF(1, "%s: got macctrl cmd response\n",
2120 		    sc->sc_dev.dv_xname);
2121 		break;
2122 	case MALO_CMD_MACADDR:
2123 		/* do nothing */
2124 		DPRINTF(1, "%s: got macaddr cmd response\n",
2125 		    sc->sc_dev.dv_xname);
2126 		break;
2127 	case MALO_CMD_ASSOC:
2128 		/* do nothing */
2129 		DPRINTF(1, "%s: got assoc cmd response\n",
2130 		    sc->sc_dev.dv_xname);
2131 		cmalo_cmd_rsp_assoc(sc);
2132 		break;
2133 	case MALO_CMD_80211D:
2134 		/* do nothing */
2135 		DPRINTF(1, "%s: got 80211d cmd response\n",
2136 		    sc->sc_dev.dv_xname);
2137 		break;
2138 	case MALO_CMD_BGSCAN_CONFIG:
2139 		/* do nothing */
2140 		DPRINTF(1, "%s: got bgscan config cmd response\n",
2141 		    sc->sc_dev.dv_xname);
2142 		break;
2143 	case MALO_CMD_BGSCAN_QUERY:
2144 		/* do nothing */
2145 		DPRINTF(1, "%s: got bgscan query cmd response\n",
2146 		    sc->sc_dev.dv_xname);
2147 		break;
2148 	case MALO_CMD_RATE:
2149 		/* do nothing */
2150 		DPRINTF(1, "%s: got rate cmd response\n",
2151 		    sc->sc_dev.dv_xname);
2152 		break;
2153 	default:
2154 		printf("%s: got unknown cmd response (0x%04x)\n",
2155 		    sc->sc_dev.dv_xname, hdr->cmd);
2156 		break;
2157 	}
2158 
2159 	splx(s);
2160 
2161 	return (0);
2162 }
2163