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