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