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