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