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