1/* $NetBSD: if_malo_pcmcia.c,v 1.10 2016/03/11 22:09:54 macallan 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.10 2016/03/11 22:09:54 macallan 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
66int 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
72static int malo_pcmcia_match(device_t, cfdata_t, void *);
73static void malo_pcmcia_attach(device_t, device_t, void *);
74static int malo_pcmcia_detach(device_t, int);
75static int malo_pcmcia_activate(device_t, devact_t);
76
77static int malo_pcmcia_validate_config(struct pcmcia_config_entry *);
78
79static int malo_pcmcia_enable(struct malo_softc *);
80static void malo_pcmcia_disable(struct malo_softc *);
81
82static void cmalo_attach(void *);
83static void cmalo_detach(void *);
84static int cmalo_intr(void *);
85
86static void cmalo_start(struct ifnet *);
87static int cmalo_ioctl(struct ifnet *, u_long, void *);
88static int cmalo_init(struct ifnet *);
89static void cmalo_watchdog(struct ifnet *);
90static int cmalo_media_change(struct ifnet *);
91static int cmalo_newstate(struct ieee80211com *, enum ieee80211_state,
92 int);
93
94static int firmware_load(const char *, const char *, uint8_t **, size_t *);
95static int cmalo_fw_alloc(struct malo_softc *);
96static void cmalo_fw_free(struct malo_softc *);
97static int cmalo_fw_load_helper(struct malo_softc *);
98static int cmalo_fw_load_main(struct malo_softc *);
99
100static void cmalo_stop(struct malo_softc *);
101static void cmalo_intr_mask(struct malo_softc *, int);
102static void cmalo_rx(struct malo_softc *);
103static int cmalo_tx(struct malo_softc *, struct mbuf *);
104static void cmalo_tx_done(struct malo_softc *);
105static void cmalo_event(struct malo_softc *);
106static void cmalo_select_network(struct malo_softc *);
107static void cmalo_reflect_network(struct malo_softc *);
108static int cmalo_wep(struct malo_softc *);
109static int cmalo_rate2bitmap(int);
110
111static void cmalo_hexdump(void *, int);
112static int cmalo_cmd_get_hwspec(struct malo_softc *);
113static int cmalo_cmd_rsp_hwspec(struct malo_softc *);
114static int cmalo_cmd_set_reset(struct malo_softc *);
115static int cmalo_cmd_set_scan(struct malo_softc *);
116static int cmalo_cmd_rsp_scan(struct malo_softc *);
117static int cmalo_parse_elements(struct malo_softc *, uint8_t *, int, int);
118static int cmalo_cmd_set_auth(struct malo_softc *);
119static int cmalo_cmd_set_wep(struct malo_softc *, uint16_t,
120 struct ieee80211_key *);
121static int cmalo_cmd_set_snmp(struct malo_softc *, uint16_t);
122static int cmalo_cmd_set_radio(struct malo_softc *, uint16_t);
123static int cmalo_cmd_set_channel(struct malo_softc *, uint16_t);
124static int cmalo_cmd_set_txpower(struct malo_softc *, int16_t);
125static int cmalo_cmd_set_antenna(struct malo_softc *, uint16_t);
126static int cmalo_cmd_set_macctrl(struct malo_softc *);
127static int cmalo_cmd_set_macaddr(struct malo_softc *, uint8_t *);
128static int cmalo_cmd_set_assoc(struct malo_softc *);
129static int cmalo_cmd_rsp_assoc(struct malo_softc *);
130static int cmalo_cmd_set_rate(struct malo_softc *, int);
131static int cmalo_cmd_request(struct malo_softc *, uint16_t, int);
132static int cmalo_cmd_response(struct malo_softc *);
133
134/*
135 * PCMCIA bus.
136 */
137struct 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
146CFATTACH_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
151static int
152malo_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
163static void
164malo_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
196fail:
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
206static int
207malo_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
219static int
220malo_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
241int
242malo_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
253static int
254malo_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
275static void
276malo_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 */
291static void
292cmalo_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
375static void
376cmalo_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
412static int
413cmalo_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 */
465static void
466cmalo_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
488static int
489cmalo_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
540static int
541cmalo_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
623static void
624cmalo_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
632static int
633cmalo_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
646static int
647cmalo_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
693out:
694 return sc->sc_newstate(ic, nstate, arg);
695}
696
697
698static int
699firmware_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
719static int
720cmalo_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
753static void
754cmalo_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
768static int
769cmalo_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
828static int
829cmalo_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
912static void
913cmalo_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
934static void
935cmalo_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
956static void
957cmalo_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 if_percpuq_enqueue(ifp->if_percpuq, m);
1017 ifp->if_ipackets++;
1018 }
1019}
1020
1021static int
1022cmalo_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->dstaddr, 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
1063static void
1064cmalo_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
1076static void
1077cmalo_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
1109static void
1110cmalo_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
1146static void
1147cmalo_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
1168static int
1169cmalo_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
1189static int
1190cmalo_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
1214static void
1215cmalo_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
1233static int
1234cmalo_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
1261static int
1262cmalo_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
1278static int
1279cmalo_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
1299static int
1300cmalo_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
1361static int
1362cmalo_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
1408static int
1409cmalo_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
1447static int
1448cmalo_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
1474static int
1475cmalo_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
1532static int
1533cmalo_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
1584static int
1585cmalo_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
1615static int
1616cmalo_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
1644static int
1645cmalo_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
1671static int
1672cmalo_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
1714static int
1715cmalo_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
1746static int
1747cmalo_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
1773static int
1774cmalo_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
1850static int
1851cmalo_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
1869static int
1870cmalo_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
1902static int
1903cmalo_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
1941static int
1942cmalo_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
2092MODULE(MODULE_CLASS_DRIVER, malo_pcmcia, NULL);
2093
2094CFDRIVER_DECL(malo_pcmcia, DV_IFNET, NULL);
2095extern struct cfattach malo_pcmcia_ca;
2096static int malo_pcmcialoc[] = { -1 };
2097static struct cfparent pcmciaparent = {
2098 "pcmcia", NULL, DVUNIT_ANY
2099};
2100static 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
2113static int
2114malo_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