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