if_malo_pcmcia.c revision 1.11 1 /* $NetBSD: if_malo_pcmcia.c,v 1.11 2016/12/08 01:12:01 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.11 2016/12/08 01:12:01 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 if (ifp->if_bpf)
1013 bpf_ops->bpf_mtap(ifp->if_bpf, m);
1014
1015 /* push the frame up to the network stack if not in monitor mode */
1016 if (ic->ic_opmode != IEEE80211_M_MONITOR) {
1017 if_percpuq_enqueue(ifp->if_percpuq, m);
1018 ifp->if_ipackets++;
1019 }
1020 }
1021
1022 static int
1023 cmalo_tx(struct malo_softc *sc, struct mbuf *m)
1024 {
1025 struct ifnet *ifp = &sc->sc_if;
1026 struct malo_tx_desc *txdesc = (struct malo_tx_desc *)sc->sc_data;
1027 uint8_t *data;
1028 uint16_t psize;
1029
1030 memset(sc->sc_data, 0, sizeof(*txdesc));
1031 psize = sizeof(*txdesc) + m->m_pkthdr.len;
1032 data = mtod(m, uint8_t *);
1033
1034 /* prepare TX descriptor */
1035 txdesc->pkgoffset = htole32(sizeof(*txdesc));
1036 txdesc->pkglen = htole16(m->m_pkthdr.len);
1037 memcpy(txdesc->dstaddr, data, ETHER_ADDR_LEN);
1038
1039 /* copy mbuf data to the buffer */
1040 m_copydata(m, 0, m->m_pkthdr.len, sc->sc_data + sizeof(*txdesc));
1041 m_freem(m);
1042
1043 /* send TX packet to the device */
1044 MALO_WRITE_2(sc, MALO_REG_DATA_WRITE_LEN, psize);
1045 MALO_WRITE_MULTI_2(sc, MALO_REG_DATA_WRITE,
1046 (uint16_t *)sc->sc_data, psize / sizeof(uint16_t));
1047 if (psize & 0x0001) {
1048 data = sc->sc_data;
1049 MALO_WRITE_1(sc, MALO_REG_DATA_WRITE, data[psize - 1]);
1050 }
1051 MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_TX_DL_OVER);
1052 MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE, MALO_VAL_TX_DL_OVER);
1053
1054 ifp->if_flags |= IFF_OACTIVE;
1055 ifp->if_timer = 5;
1056
1057 DPRINTF(2, "%s: TX status=%d, pkglen=%d, pkgoffset=%zd\n",
1058 device_xname(sc->sc_dev), txdesc->status, le16toh(txdesc->pkglen),
1059 sizeof(*txdesc));
1060
1061 return 0;
1062 }
1063
1064 static void
1065 cmalo_tx_done(struct malo_softc *sc)
1066 {
1067 struct ifnet *ifp = &sc->sc_if;
1068
1069 DPRINTF(2, "%s: TX done\n", device_xname(sc->sc_dev));
1070
1071 ifp->if_opackets++;
1072 ifp->if_flags &= ~IFF_OACTIVE;
1073 ifp->if_timer = 0;
1074 if_schedule_deferred_start(ifp);
1075 }
1076
1077 static void
1078 cmalo_event(struct malo_softc *sc)
1079 {
1080 uint16_t event;
1081
1082 /* read event reason */
1083 event = MALO_READ_2(sc, MALO_REG_CARD_STATUS);
1084 event &= MALO_VAL_CARD_STATUS_MASK;
1085 event = event >> 8;
1086
1087 switch (event) {
1088 case MALO_EVENT_DEAUTH:
1089 DPRINTF(1, "%s: got deauthentication event (0x%04x)\n",
1090 device_xname(sc->sc_dev), event);
1091 /* try to associate again */
1092 cmalo_cmd_set_assoc(sc);
1093 break;
1094 case MALO_EVENT_DISASSOC:
1095 DPRINTF(1, "%s: got disassociation event (0x%04x)\n",
1096 device_xname(sc->sc_dev), event);
1097 /* try to associate again */
1098 cmalo_cmd_set_assoc(sc);
1099 break;
1100 default:
1101 DPRINTF(1, "%s: got unknown event (0x%04x)\n",
1102 device_xname(sc->sc_dev), event);
1103 break;
1104 }
1105
1106 /* acknowledge event */
1107 MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE, MALO_VAL_HOST_INTR_EVENT);
1108 }
1109
1110 static void
1111 cmalo_select_network(struct malo_softc *sc)
1112 {
1113 struct ieee80211com *ic = &sc->sc_ic;
1114 int i, best_rssi;
1115
1116 /* reset last selected network */
1117 sc->sc_net_cur = 0;
1118
1119 /* get desired network */
1120 if (ic->ic_des_esslen) {
1121 for (i = 0; i < sc->sc_net_num; i++) {
1122 if (!strcmp(ic->ic_des_essid, sc->sc_net[i].ssid)) {
1123 sc->sc_net_cur = i;
1124 DPRINTF(1, "%s: desired network found (%s)\n",
1125 device_xname(sc->sc_dev),
1126 ic->ic_des_essid);
1127 return;
1128 }
1129 }
1130 DPRINTF(1, "%s: desired network not found in scan results "
1131 "(%s)\n",
1132 device_xname(sc->sc_dev), ic->ic_des_essid);
1133 }
1134
1135 /* get network with best signal strength */
1136 best_rssi = sc->sc_net[0].rssi;
1137 for (i = 0; i < sc->sc_net_num; i++) {
1138 if (best_rssi < sc->sc_net[i].rssi) {
1139 best_rssi = sc->sc_net[i].rssi;
1140 sc->sc_net_cur = i;
1141 }
1142 }
1143 DPRINTF(1, "%s: best network found (%s)\n",
1144 device_xname(sc->sc_dev), sc->sc_net[sc->sc_net_cur].ssid);
1145 }
1146
1147 static void
1148 cmalo_reflect_network(struct malo_softc *sc)
1149 {
1150 struct ieee80211com *ic = &sc->sc_ic;
1151 uint8_t chan;
1152
1153 /* reflect active network to our 80211 stack */
1154
1155 /* BSSID */
1156 IEEE80211_ADDR_COPY(ic->ic_bss->ni_bssid,
1157 sc->sc_net[sc->sc_net_cur].bssid);
1158
1159 /* SSID */
1160 ic->ic_bss->ni_esslen = strlen(sc->sc_net[sc->sc_net_cur].ssid);
1161 memcpy(ic->ic_bss->ni_essid, sc->sc_net[sc->sc_net_cur].ssid,
1162 ic->ic_bss->ni_esslen);
1163
1164 /* channel */
1165 chan = sc->sc_net[sc->sc_net_cur].channel;
1166 ic->ic_curchan = &ic->ic_channels[chan];
1167 }
1168
1169 static int
1170 cmalo_wep(struct malo_softc *sc)
1171 {
1172 struct ieee80211com *ic = &sc->sc_ic;
1173 int i;
1174
1175 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1176 struct ieee80211_key *key = &ic->ic_crypto.cs_nw_keys[i];
1177
1178 if (!key->wk_keylen)
1179 continue;
1180
1181 DPRINTF(1, "%s: setting wep key for index %d\n",
1182 device_xname(sc->sc_dev), i);
1183
1184 cmalo_cmd_set_wep(sc, i, key);
1185 }
1186
1187 return 0;
1188 }
1189
1190 static int
1191 cmalo_rate2bitmap(int rate)
1192 {
1193 switch (rate) {
1194 /* CCK rates */
1195 case 0: return MALO_RATE_BITMAP_DS1;
1196 case 1: return MALO_RATE_BITMAP_DS2;
1197 case 2: return MALO_RATE_BITMAP_DS5;
1198 case 3: return MALO_RATE_BITMAP_DS11;
1199
1200 /* OFDM rates */
1201 case 4: return MALO_RATE_BITMAP_OFDM6;
1202 case 5: return MALO_RATE_BITMAP_OFDM9;
1203 case 6: return MALO_RATE_BITMAP_OFDM12;
1204 case 7: return MALO_RATE_BITMAP_OFDM18;
1205 case 8: return MALO_RATE_BITMAP_OFDM24;
1206 case 9: return MALO_RATE_BITMAP_OFDM36;
1207 case 10: return MALO_RATE_BITMAP_OFDM48;
1208 case 11: return MALO_RATE_BITMAP_OFDM54;
1209
1210 /* unknown rate: should not happen */
1211 default: return 0;
1212 }
1213 }
1214
1215 static void
1216 cmalo_hexdump(void *buf, int len)
1217 {
1218 #ifdef CMALO_DEBUG
1219 int i;
1220
1221 if (cmalo_d >= 2) {
1222 for (i = 0; i < len; i++) {
1223 if (i % 16 == 0)
1224 printf("%s%5i:", i ? "\n" : "", i);
1225 if (i % 4 == 0)
1226 printf(" ");
1227 printf("%02x", (int)*((u_char *)buf + i));
1228 }
1229 printf("\n");
1230 }
1231 #endif
1232 }
1233
1234 static int
1235 cmalo_cmd_get_hwspec(struct malo_softc *sc)
1236 {
1237 struct malo_cmd_header *hdr;
1238 struct malo_cmd_body_spec *body;
1239 const uint16_t psize = sizeof(*hdr) + sizeof(*body);
1240
1241 hdr = (struct malo_cmd_header *)sc->sc_cmd;
1242 hdr->cmd = htole16(MALO_CMD_HWSPEC);
1243 hdr->size = htole16(sizeof(*body));
1244 hdr->seqnum = htole16(1);
1245 hdr->result = 0;
1246
1247 body = (struct malo_cmd_body_spec *)(hdr + 1);
1248 memset(body, 0, sizeof(*body));
1249 /* set all bits for MAC address, otherwise we won't get one back */
1250 memset(body->macaddr, 0xff, ETHER_ADDR_LEN);
1251
1252 /* process command request */
1253 if (cmalo_cmd_request(sc, psize, 0) != 0)
1254 return EIO;
1255
1256 /* process command repsonse */
1257 cmalo_cmd_response(sc);
1258
1259 return 0;
1260 }
1261
1262 static int
1263 cmalo_cmd_rsp_hwspec(struct malo_softc *sc)
1264 {
1265 struct ieee80211com *ic = &sc->sc_ic;
1266 struct malo_cmd_header *hdr = (struct malo_cmd_header *)sc->sc_cmd;
1267 struct malo_cmd_body_spec *body;
1268 int i;
1269
1270 body = (struct malo_cmd_body_spec *)(hdr + 1);
1271
1272 /* get our MAC address */
1273 for (i = 0; i < ETHER_ADDR_LEN; i++)
1274 ic->ic_myaddr[i] = body->macaddr[i];
1275
1276 return 0;
1277 }
1278
1279 static int
1280 cmalo_cmd_set_reset(struct malo_softc *sc)
1281 {
1282 struct malo_cmd_header *hdr = (struct malo_cmd_header *)sc->sc_cmd;
1283 const uint16_t psize = sizeof(*hdr);
1284
1285 hdr->cmd = htole16(MALO_CMD_RESET);
1286 hdr->size = 0;
1287 hdr->seqnum = htole16(1);
1288 hdr->result = 0;
1289
1290 /* process command request */
1291 if (cmalo_cmd_request(sc, psize, 1) != 0)
1292 return EIO;
1293
1294 /* give the device some time to finish the reset */
1295 delay(100);
1296
1297 return 0;
1298 }
1299
1300 static int
1301 cmalo_cmd_set_scan(struct malo_softc *sc)
1302 {
1303 struct ieee80211com *ic = &sc->sc_ic;
1304 struct malo_cmd_header *hdr;
1305 struct malo_cmd_body_scan *body;
1306 struct malo_cmd_tlv_ssid *body_ssid;
1307 struct malo_cmd_tlv_chanlist *body_chanlist;
1308 struct malo_cmd_tlv_rates *body_rates;
1309 uint16_t psize;
1310 int i;
1311
1312 psize = sizeof(*hdr) + sizeof(*body) +
1313 sizeof(*body_ssid) + sizeof(*body_chanlist) + sizeof(*body_rates);
1314
1315 hdr = (struct malo_cmd_header *)sc->sc_cmd;
1316 hdr->cmd = htole16(MALO_CMD_SCAN);
1317 hdr->seqnum = htole16(1);
1318 hdr->result = 0;
1319
1320 body = (struct malo_cmd_body_scan *)(hdr + 1);
1321 body->bsstype = 0x03; /* any BSS */
1322 memset(body->bssid, 0xff, ETHER_ADDR_LEN);
1323
1324 body_ssid = (struct malo_cmd_tlv_ssid *)(body + 1);
1325 body_ssid->type = htole16(MALO_TLV_TYPE_SSID);
1326 body_ssid->size = htole16(0);
1327
1328 body_chanlist = (struct malo_cmd_tlv_chanlist *)(body_ssid + 1);
1329 body_chanlist->type = htole16(MALO_TLV_TYPE_CHANLIST);
1330 body_chanlist->size = htole16(sizeof(body_chanlist->data));
1331 for (i = 0; i < CHANNELS; i++) {
1332 body_chanlist->data[i].radiotype = 0x00;
1333 body_chanlist->data[i].channumber = (i + 1);
1334 body_chanlist->data[i].scantype = 0x00; /* active */
1335 body_chanlist->data[i].minscantime = htole16(0);
1336 body_chanlist->data[i].maxscantime = htole16(100);
1337 }
1338
1339 body_rates = (struct malo_cmd_tlv_rates *)(body_chanlist + 1);
1340 body_rates->type = htole16(MALO_TLV_TYPE_RATES);
1341 body_rates->size =
1342 htole16(ic->ic_sup_rates[IEEE80211_MODE_11B].rs_nrates);
1343 memcpy(body_rates->data, ic->ic_sup_rates[IEEE80211_MODE_11B].rs_rates,
1344 ic->ic_sup_rates[IEEE80211_MODE_11B].rs_nrates);
1345 psize += le16toh(body_rates->size);
1346
1347 memset((char *)(body_rates + 1) + le16toh(body_rates->size), 0,
1348 sizeof(struct malo_cmd_tlv_numprobes));
1349
1350 hdr->size = htole16(psize - sizeof(*hdr));
1351
1352 /* process command request */
1353 if (cmalo_cmd_request(sc, psize, 0) != 0)
1354 return EIO;
1355
1356 /* process command repsonse */
1357 cmalo_cmd_response(sc);
1358
1359 return 0;
1360 }
1361
1362 static int
1363 cmalo_cmd_rsp_scan(struct malo_softc *sc)
1364 {
1365 struct malo_cmd_header *hdr = (struct malo_cmd_header *)sc->sc_cmd;
1366 struct malo_cmd_body_rsp_scan *body;
1367 struct malo_cmd_body_rsp_scan_set *set;
1368 int i;
1369
1370 memset(sc->sc_net, 0, sizeof(sc->sc_net));
1371
1372 body = (struct malo_cmd_body_rsp_scan *)(hdr + 1);
1373 body->bufsize = le16toh(body->bufsize);
1374
1375 DPRINTF(1, "bufsize=%d, APs=%d\n", body->bufsize, body->numofset);
1376 sc->sc_net_num = body->numofset;
1377
1378 set = (struct malo_cmd_body_rsp_scan_set *)(body + 1);
1379
1380 /* cycle through found networks */
1381 for (i = 0; i < body->numofset; i++) {
1382 set->size = le16toh(set->size);
1383 set->beaconintvl = le16toh(set->beaconintvl);
1384 set->capinfo = le16toh(set->capinfo);
1385
1386 DPRINTF(1, "size=%d, bssid=%s, rssi=%d, beaconintvl=%d, "
1387 "capinfo=0x%04x\n",
1388 set->size, ether_sprintf(set->bssid), set->rssi,
1389 set->beaconintvl, set->capinfo);
1390
1391 /* save scan results */
1392 memcpy(sc->sc_net[i].bssid, set->bssid, sizeof(set->bssid));
1393 sc->sc_net[i].rssi = set->rssi;
1394 memcpy(sc->sc_net[i].timestamp, set->timestamp,
1395 sizeof(set->timestamp));
1396 sc->sc_net[i].beaconintvl = set->beaconintvl;
1397 sc->sc_net[i].capinfo = set->capinfo;
1398
1399 cmalo_parse_elements(sc, set->data,
1400 set->size - (sizeof(*set) - sizeof(set->size)), i);
1401
1402 set = (struct malo_cmd_body_rsp_scan_set *)
1403 ((char *)set + sizeof(set->size) + set->size);
1404 }
1405
1406 return 0;
1407 }
1408
1409 static int
1410 cmalo_parse_elements(struct malo_softc *sc, uint8_t *buf, int size, int pos)
1411 {
1412 uint8_t eid, len;
1413 int i;
1414
1415 DPRINTF(2, "element_size=%d, element_pos=%d\n", size, pos);
1416
1417 for (i = 0; i < size; ) {
1418 eid = *(uint8_t *)(buf + i);
1419 i++;
1420 len = *(uint8_t *)(buf + i);
1421 i++;
1422 DPRINTF(2, "eid=%d, len=%d, ", eid, len);
1423
1424 switch (eid) {
1425 case IEEE80211_ELEMID_SSID:
1426 memcpy(sc->sc_net[pos].ssid, buf + i, len);
1427 DPRINTF(2, "ssid=%s\n", sc->sc_net[pos].ssid);
1428 break;
1429 case IEEE80211_ELEMID_RATES:
1430 memcpy(sc->sc_net[pos].rates, buf + i, len);
1431 DPRINTF(2, "rates\n");
1432 break;
1433 case IEEE80211_ELEMID_DSPARMS:
1434 sc->sc_net[pos].channel = *(uint8_t *)(buf + i);
1435 DPRINTF(2, "chnl=%d\n", sc->sc_net[pos].channel);
1436 break;
1437 default:
1438 DPRINTF(2, "unknown\n");
1439 break;
1440 }
1441
1442 i += len;
1443 }
1444
1445 return 0;
1446 }
1447
1448 static int
1449 cmalo_cmd_set_auth(struct malo_softc *sc)
1450 {
1451 struct malo_cmd_header *hdr;
1452 struct malo_cmd_body_auth *body;
1453 const uint16_t psize = sizeof(*hdr) + sizeof(*body);
1454
1455 hdr = (struct malo_cmd_header *)sc->sc_cmd;
1456 hdr->cmd = htole16(MALO_CMD_AUTH);
1457 hdr->size = htole16(sizeof(*body));
1458 hdr->seqnum = htole16(1);
1459 hdr->result = 0;
1460
1461 body = (struct malo_cmd_body_auth *)(hdr + 1);
1462 memcpy(body->peermac, sc->sc_net[sc->sc_net_cur].bssid, ETHER_ADDR_LEN);
1463 body->authtype = 0;
1464
1465 /* process command request */
1466 if (cmalo_cmd_request(sc, psize, 0) != 0)
1467 return EIO;
1468
1469 /* process command repsonse */
1470 cmalo_cmd_response(sc);
1471
1472 return 0;
1473 }
1474
1475 static int
1476 cmalo_cmd_set_wep(struct malo_softc *sc, uint16_t index,
1477 struct ieee80211_key *key)
1478 {
1479 struct malo_cmd_header *hdr;
1480 struct malo_cmd_body_wep *body;
1481 const uint16_t psize = sizeof(*hdr) + sizeof(*body);
1482
1483 hdr = (struct malo_cmd_header *)sc->sc_cmd;
1484 hdr->cmd = htole16(MALO_CMD_WEP);
1485 hdr->size = htole16(sizeof(*body));
1486 hdr->seqnum = htole16(1);
1487 hdr->result = 0;
1488
1489 body = (struct malo_cmd_body_wep *)(hdr + 1);
1490 memset(body, 0, sizeof(*body));
1491 body->action = htole16(MALO_WEP_ACTION_TYPE_ADD);
1492 body->key_index = htole16(index);
1493
1494 if (body->key_index == 0) {
1495 if (key->wk_keylen > 5)
1496 body->key_type_1 = MALO_WEP_KEY_TYPE_104BIT;
1497 else
1498 body->key_type_1 = MALO_WEP_KEY_TYPE_40BIT;
1499 memcpy(body->key_value_1, key->wk_key, key->wk_keylen);
1500 }
1501 if (body->key_index == 1) {
1502 if (key->wk_keylen > 5)
1503 body->key_type_2 = MALO_WEP_KEY_TYPE_104BIT;
1504 else
1505 body->key_type_2 = MALO_WEP_KEY_TYPE_40BIT;
1506 memcpy(body->key_value_2, key->wk_key, key->wk_keylen);
1507 }
1508 if (body->key_index == 2) {
1509 if (key->wk_keylen > 5)
1510 body->key_type_3 = MALO_WEP_KEY_TYPE_104BIT;
1511 else
1512 body->key_type_3 = MALO_WEP_KEY_TYPE_40BIT;
1513 memcpy(body->key_value_3, key->wk_key, key->wk_keylen);
1514 }
1515 if (body->key_index == 3) {
1516 if (key->wk_keylen > 5)
1517 body->key_type_4 = MALO_WEP_KEY_TYPE_104BIT;
1518 else
1519 body->key_type_4 = MALO_WEP_KEY_TYPE_40BIT;
1520 memcpy(body->key_value_4, key->wk_key, key->wk_keylen);
1521 }
1522
1523 /* process command request */
1524 if (cmalo_cmd_request(sc, psize, 0) != 0)
1525 return EIO;
1526
1527 /* process command repsonse */
1528 cmalo_cmd_response(sc);
1529
1530 return 0;
1531 }
1532
1533 static int
1534 cmalo_cmd_set_snmp(struct malo_softc *sc, uint16_t oid)
1535 {
1536 struct malo_cmd_header *hdr;
1537 struct malo_cmd_body_snmp *body;
1538 const uint16_t psize = sizeof(*hdr) + sizeof(*body);
1539
1540 hdr = (struct malo_cmd_header *)sc->sc_cmd;
1541 hdr->cmd = htole16(MALO_CMD_SNMP);
1542 hdr->size = htole16(sizeof(*body));
1543 hdr->seqnum = htole16(1);
1544 hdr->result = 0;
1545
1546 body = (struct malo_cmd_body_snmp *)(hdr + 1);
1547 memset(body, 0, sizeof(*body));
1548 body->action = htole16(1);
1549
1550 switch (oid) {
1551 case MALO_OID_RTSTRESH:
1552 body->oid = htole16(MALO_OID_RTSTRESH);
1553 body->size = htole16(2);
1554 *(uint16_t *)body->data = htole16(2347);
1555 break;
1556 case MALO_OID_SHORTRETRY:
1557 body->oid = htole16(MALO_OID_SHORTRETRY);
1558 body->size = htole16(2);
1559 *(uint16_t *)body->data = htole16(4);
1560 break;
1561 case MALO_OID_FRAGTRESH:
1562 body->oid = htole16(MALO_OID_FRAGTRESH);
1563 body->size = htole16(2);
1564 *(uint16_t *)body->data = htole16(2346);
1565 break;
1566 case MALO_OID_80211D:
1567 body->oid = htole16(MALO_OID_80211D);
1568 body->size = htole16(2);
1569 *(uint16_t *)body->data = htole16(1);
1570 break;
1571 default:
1572 break;
1573 }
1574
1575 /* process command request */
1576 if (cmalo_cmd_request(sc, psize, 0) != 0)
1577 return EIO;
1578
1579 /* process command repsonse */
1580 cmalo_cmd_response(sc);
1581
1582 return 0;
1583 }
1584
1585 static int
1586 cmalo_cmd_set_radio(struct malo_softc *sc, uint16_t control)
1587 {
1588 struct malo_cmd_header *hdr;
1589 struct malo_cmd_body_radio *body;
1590 const uint16_t psize = sizeof(*hdr) + sizeof(*body);
1591
1592 hdr = (struct malo_cmd_header *)sc->sc_cmd;
1593 hdr->cmd = htole16(MALO_CMD_RADIO);
1594 hdr->size = htole16(sizeof(*body));
1595 hdr->seqnum = htole16(1);
1596 hdr->result = 0;
1597
1598 body = (struct malo_cmd_body_radio *)(hdr + 1);
1599 body->action = htole16(1);
1600 if (control)
1601 body->control =
1602 htole16(MALO_CMD_RADIO_ON | MALO_CMD_RADIO_AUTO_P);
1603 else
1604 body->control = 0;
1605
1606 /* process command request */
1607 if (cmalo_cmd_request(sc, psize, 0) != 0)
1608 return EIO;
1609
1610 /* process command repsonse */
1611 cmalo_cmd_response(sc);
1612
1613 return 0;
1614 }
1615
1616 static int
1617 cmalo_cmd_set_channel(struct malo_softc *sc, uint16_t channel)
1618 {
1619 struct malo_cmd_header *hdr;
1620 struct malo_cmd_body_channel *body;
1621 const uint16_t psize = sizeof(*hdr) + sizeof(*body);
1622
1623 hdr = (struct malo_cmd_header *)sc->sc_cmd;
1624 hdr->cmd = htole16(MALO_CMD_CHANNEL);
1625 hdr->size = htole16(sizeof(*body));
1626 hdr->seqnum = htole16(1);
1627 hdr->result = 0;
1628
1629 body = (struct malo_cmd_body_channel *)(hdr + 1);
1630 memset(body, 0, sizeof(*body));
1631 body->action = htole16(1);
1632 body->channel = htole16(channel);
1633
1634 /* process command request */
1635 if (cmalo_cmd_request(sc, psize, 0) != 0)
1636 return EIO;
1637
1638 /* process command repsonse */
1639 cmalo_cmd_response(sc);
1640
1641 return 0;
1642 }
1643
1644
1645 static int
1646 cmalo_cmd_set_txpower(struct malo_softc *sc, int16_t txpower)
1647 {
1648 struct malo_cmd_header *hdr;
1649 struct malo_cmd_body_txpower *body;
1650 const uint16_t psize = sizeof(*hdr) + sizeof(*body);
1651
1652 hdr = (struct malo_cmd_header *)sc->sc_cmd;
1653 hdr->cmd = htole16(MALO_CMD_TXPOWER);
1654 hdr->size = htole16(sizeof(*body));
1655 hdr->seqnum = htole16(1);
1656 hdr->result = 0;
1657
1658 body = (struct malo_cmd_body_txpower *)(hdr + 1);
1659 body->action = htole16(1);
1660 body->txpower = htole16(txpower);
1661
1662 /* process command request */
1663 if (cmalo_cmd_request(sc, psize, 0) != 0)
1664 return EIO;
1665
1666 /* process command repsonse */
1667 cmalo_cmd_response(sc);
1668
1669 return 0;
1670 }
1671
1672 static int
1673 cmalo_cmd_set_antenna(struct malo_softc *sc, uint16_t action)
1674 {
1675 struct malo_cmd_header *hdr;
1676 struct malo_cmd_body_antenna *body;
1677 const uint16_t psize = sizeof(*hdr) + sizeof(*body);
1678
1679 hdr = (struct malo_cmd_header *)sc->sc_cmd;
1680 hdr->cmd = htole16(MALO_CMD_ANTENNA);
1681 hdr->size = htole16(sizeof(*body));
1682 hdr->seqnum = htole16(1);
1683 hdr->result = 0;
1684
1685 body = (struct malo_cmd_body_antenna *)(hdr + 1);
1686 /* 1 = set RX, 2 = set TX */
1687 body->action = htole16(action);
1688
1689 switch (action) {
1690 case 1:
1691 /* set RX antenna */
1692 body->antenna_mode = htole16(0xffff);
1693 break;
1694
1695 case 2:
1696 /* set TX antenna */
1697 body->antenna_mode = htole16(2);
1698 break;
1699
1700 default:
1701 body->antenna_mode = 0;
1702 break;
1703 }
1704
1705 /* process command request */
1706 if (cmalo_cmd_request(sc, psize, 0) != 0)
1707 return EIO;
1708
1709 /* process command repsonse */
1710 cmalo_cmd_response(sc);
1711
1712 return 0;
1713 }
1714
1715 static int
1716 cmalo_cmd_set_macctrl(struct malo_softc *sc)
1717 {
1718 struct ieee80211com *ic = &sc->sc_ic;
1719 struct malo_cmd_header *hdr;
1720 struct malo_cmd_body_macctrl *body;
1721 uint16_t psize;
1722
1723 psize = sizeof(*hdr) + sizeof(*body);
1724
1725 hdr = (struct malo_cmd_header *)sc->sc_cmd;
1726 hdr->cmd = htole16(MALO_CMD_MACCTRL);
1727 hdr->size = htole16(sizeof(*body));
1728 hdr->seqnum = htole16(1);
1729 hdr->result = 0;
1730
1731 body = (struct malo_cmd_body_macctrl *)(hdr + 1);
1732 memset(body, 0, sizeof(*body));
1733 body->action = htole16(MALO_CMD_MACCTRL_RX_ON | MALO_CMD_MACCTRL_TX_ON);
1734 if (ic->ic_opmode == IEEE80211_M_MONITOR)
1735 body->action |= htole16(MALO_CMD_MACCTRL_PROMISC_ON);
1736
1737 /* process command request */
1738 if (cmalo_cmd_request(sc, psize, 0) != 0)
1739 return EIO;
1740
1741 /* process command repsonse */
1742 cmalo_cmd_response(sc);
1743
1744 return 0;
1745 }
1746
1747 static int
1748 cmalo_cmd_set_macaddr(struct malo_softc *sc, uint8_t *macaddr)
1749 {
1750 struct malo_cmd_header *hdr;
1751 struct malo_cmd_body_macaddr *body;
1752 const uint16_t psize = sizeof(*hdr) + sizeof(*body);
1753
1754 hdr = (struct malo_cmd_header *)sc->sc_cmd;
1755 hdr->cmd = htole16(MALO_CMD_MACADDR);
1756 hdr->size = htole16(sizeof(*body));
1757 hdr->seqnum = htole16(1);
1758 hdr->result = 0;
1759
1760 body = (struct malo_cmd_body_macaddr *)(hdr + 1);
1761 body->action = htole16(1);
1762 memcpy(body->macaddr, macaddr, ETHER_ADDR_LEN);
1763
1764 /* process command request */
1765 if (cmalo_cmd_request(sc, psize, 0) != 0)
1766 return EIO;
1767
1768 /* process command repsonse */
1769 cmalo_cmd_response(sc);
1770
1771 return 0;
1772 }
1773
1774 static int
1775 cmalo_cmd_set_assoc(struct malo_softc *sc)
1776 {
1777 struct malo_cmd_header *hdr;
1778 struct malo_cmd_body_assoc *body;
1779 struct malo_cmd_tlv_ssid *body_ssid;
1780 struct malo_cmd_tlv_phy *body_phy;
1781 struct malo_cmd_tlv_cf *body_cf;
1782 struct malo_cmd_tlv_rates *body_rates;
1783 struct malo_cmd_tlv_passeid *body_passeid;
1784 uint16_t psize;
1785
1786 psize = sizeof(*hdr) + sizeof(*body) + sizeof(*body_ssid) +
1787 sizeof(body_phy) + sizeof(*body_cf) + sizeof(*body_rates);
1788
1789 hdr = (struct malo_cmd_header *)sc->sc_cmd;
1790 hdr->cmd = htole16(MALO_CMD_ASSOC);
1791 hdr->seqnum = htole16(1);
1792 hdr->result = 0;
1793
1794 body = (struct malo_cmd_body_assoc *)(hdr + 1);
1795 memset(body, 0, sizeof(*body));
1796 memcpy(body->peermac, sc->sc_net[sc->sc_net_cur].bssid, ETHER_ADDR_LEN);
1797 body->capinfo = htole16(sc->sc_net[sc->sc_net_cur].capinfo);
1798 body->listenintrv = htole16(10);
1799
1800 body_ssid = (struct malo_cmd_tlv_ssid *)(body + 1);
1801 body_ssid->type = htole16(MALO_TLV_TYPE_SSID);
1802 body_ssid->size = htole16(strlen(sc->sc_net[sc->sc_net_cur].ssid));
1803 memcpy(body_ssid->data, sc->sc_net[sc->sc_net_cur].ssid,
1804 le16toh(body_ssid->size));
1805 psize += le16toh(body_ssid->size);
1806
1807 body_phy = (struct malo_cmd_tlv_phy *)
1808 ((char *)(body_ssid + 1) + le16toh(body_ssid->size));
1809 body_phy->type = htole16(MALO_TLV_TYPE_PHY);
1810 body_phy->size = htole16(1);
1811 body_phy->data[0] = sc->sc_net[sc->sc_net_cur].channel;
1812 psize += le16toh(body_phy->size);
1813
1814 body_cf = (struct malo_cmd_tlv_cf *)
1815 ((char *)(body_phy + 1) + le16toh(body_phy->size));
1816 body_cf->type = htole16(MALO_TLV_TYPE_CF);
1817 body_cf->size = htole16(0);
1818
1819 body_rates = (struct malo_cmd_tlv_rates *)(body_cf + 1);
1820 body_rates->type = htole16(MALO_TLV_TYPE_RATES);
1821 body_rates->size = htole16(strlen(sc->sc_net[sc->sc_net_cur].rates));
1822 memcpy(body_rates->data, sc->sc_net[sc->sc_net_cur].rates,
1823 le16toh(body_rates->size));
1824 psize += le16toh(body_rates->size);
1825
1826 /* hack to correct FW's wrong generated rates-element-id */
1827 body_passeid = (struct malo_cmd_tlv_passeid *)
1828 ((char *)(body_rates + 1) + le16toh(body_rates->size));
1829 body_passeid->type = htole16(MALO_TLV_TYPE_PASSEID);
1830 body_passeid->size = body_rates->size;
1831 memcpy(body_passeid->data, body_rates->data, le16toh(body_rates->size));
1832 psize += le16toh(body_passeid->size);
1833
1834 hdr->size = htole16(psize - sizeof(*hdr));
1835
1836 /* process command request */
1837 if (!sc->sc_cmd_ctxsave) {
1838 if (cmalo_cmd_request(sc, psize, 1) != 0)
1839 return EIO;
1840 return 0;
1841 }
1842 if (cmalo_cmd_request(sc, psize, 0) != 0)
1843 return EIO;
1844
1845 /* process command repsonse */
1846 cmalo_cmd_response(sc);
1847
1848 return 0;
1849 }
1850
1851 static int
1852 cmalo_cmd_rsp_assoc(struct malo_softc *sc)
1853 {
1854 struct malo_cmd_header *hdr = (struct malo_cmd_header *)sc->sc_cmd;
1855 struct malo_cmd_body_rsp_assoc *body;
1856
1857 body = (struct malo_cmd_body_rsp_assoc *)(hdr + 1);
1858
1859 if (body->status) {
1860 DPRINTF(1, "%s: association failed (status %d)\n",
1861 device_xname(sc->sc_dev), body->status);
1862 sc->sc_flags |= MALO_ASSOC_FAILED;
1863 } else
1864 DPRINTF(1, "%s: association successful\n",
1865 device_xname(sc->sc_dev));
1866
1867 return 0;
1868 }
1869
1870 static int
1871 cmalo_cmd_set_rate(struct malo_softc *sc, int rate)
1872 {
1873 struct malo_cmd_header *hdr;
1874 struct malo_cmd_body_rate *body;
1875 const uint16_t psize = sizeof(*hdr) + sizeof(*body);
1876
1877 hdr = (struct malo_cmd_header *)sc->sc_cmd;
1878 hdr->cmd = htole16(MALO_CMD_RATE);
1879 hdr->size = htole16(sizeof(*body));
1880 hdr->seqnum = htole16(1);
1881 hdr->result = 0;
1882
1883 body = (struct malo_cmd_body_rate *)(hdr + 1);
1884 body->action = htole16(1);
1885 if (rate == IEEE80211_FIXED_RATE_NONE) {
1886 body->hwauto = htole16(1);
1887 body->ratebitmap = htole16(MALO_RATE_BITMAP_AUTO);
1888 } else {
1889 body->hwauto = 0;
1890 body->ratebitmap = htole16(cmalo_rate2bitmap(rate));
1891 }
1892
1893 /* process command request */
1894 if (cmalo_cmd_request(sc, psize, 0) != 0)
1895 return EIO;
1896
1897 /* process command repsonse */
1898 cmalo_cmd_response(sc);
1899
1900 return 0;
1901 }
1902
1903 static int
1904 cmalo_cmd_request(struct malo_softc *sc, uint16_t psize, int no_response)
1905 {
1906 uint8_t *cmd;
1907
1908 mutex_enter(&sc->sc_mtx);
1909
1910 cmalo_hexdump(sc->sc_cmd, psize);
1911
1912 /* send command request */
1913 MALO_WRITE_2(sc, MALO_REG_CMD_WRITE_LEN, psize);
1914 MALO_WRITE_MULTI_2(sc, MALO_REG_CMD_WRITE,
1915 (uint16_t *)sc->sc_cmd, psize / sizeof(uint16_t));
1916 if (psize & 0x0001) {
1917 cmd = sc->sc_cmd;
1918 MALO_WRITE_1(sc, MALO_REG_CMD_WRITE, cmd[psize - 1]);
1919 }
1920 MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_CMD_DL_OVER);
1921 MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE, MALO_VAL_CMD_DL_OVER);
1922
1923 if (no_response) {
1924 mutex_exit(&sc->sc_mtx);
1925
1926 /* we don't expect a response */
1927 return 0;
1928 }
1929
1930 /* wait for the command response */
1931 if (cv_timedwait_sig(&sc->sc_cv, &sc->sc_mtx, 500) == EWOULDBLOCK) {
1932 mutex_exit(&sc->sc_mtx);
1933 aprint_error_dev(sc->sc_dev,
1934 "timeout while waiting for cmd response\n");
1935 return EIO;
1936 }
1937 mutex_exit(&sc->sc_mtx);
1938
1939 return 0;
1940 }
1941
1942 static int
1943 cmalo_cmd_response(struct malo_softc *sc)
1944 {
1945 struct malo_cmd_header *hdr = (struct malo_cmd_header *)sc->sc_cmd;
1946 uint16_t psize;
1947 int s;
1948
1949 s = splnet();
1950
1951 #ifdef CMALO_DEBUG
1952 memset(sc->sc_cmd, 0, MALO_CMD_BUFFER_SIZE);
1953 #endif
1954
1955 /* read the whole command response */
1956 psize = MALO_READ_2(sc, MALO_REG_CMD_READ_LEN);
1957 if (psize > MALO_CMD_BUFFER_SIZE) {
1958 aprint_error_dev(sc->sc_dev,
1959 "command response too large: %dbyte\n", psize);
1960 return EIO;
1961 }
1962
1963 MALO_READ_MULTI_2(sc, MALO_REG_CMD_READ,
1964 (uint16_t *)sc->sc_cmd, psize / sizeof(uint16_t));
1965 if (psize & 0x0001)
1966 sc->sc_cmd[psize - 1] = MALO_READ_1(sc, MALO_REG_CMD_READ);
1967
1968 cmalo_hexdump(sc->sc_cmd, psize);
1969
1970 /*
1971 * We convert the header values into the machines correct endianess,
1972 * so we don't have to le16toh() all over the code. The body is
1973 * kept in the cards order, little endian. We need to take care
1974 * about the body endianess in the corresponding response routines.
1975 */
1976 hdr->cmd = le16toh(hdr->cmd);
1977 hdr->size = le16toh(hdr->size);
1978 hdr->seqnum = le16toh(hdr->seqnum);
1979 hdr->result = le16toh(hdr->result);
1980
1981 /* check for a valid command response */
1982 if (!(hdr->cmd & MALO_CMD_RESP)) {
1983 aprint_error_dev(sc->sc_dev,
1984 "got invalid command response (0x%04x)\n", hdr->cmd);
1985 splx(s);
1986 return EIO;
1987 }
1988 hdr->cmd &= ~MALO_CMD_RESP;
1989
1990 /* association cmd response is special */
1991 if (hdr->cmd == 0x0012)
1992 hdr->cmd = MALO_CMD_ASSOC;
1993
1994 /* to which command does the response belong */
1995 switch (hdr->cmd) {
1996 case MALO_CMD_HWSPEC:
1997 DPRINTF(1, "%s: got hwspec cmd response\n",
1998 device_xname(sc->sc_dev));
1999 cmalo_cmd_rsp_hwspec(sc);
2000 break;
2001 case MALO_CMD_RESET:
2002 /* reset will not send back a response */
2003 break;
2004 case MALO_CMD_SCAN:
2005 DPRINTF(1, "%s: got scan cmd response\n",
2006 device_xname(sc->sc_dev));
2007 cmalo_cmd_rsp_scan(sc);
2008 break;
2009 case MALO_CMD_AUTH:
2010 /* do nothing */
2011 DPRINTF(1, "%s: got auth cmd response\n",
2012 device_xname(sc->sc_dev));
2013 break;
2014 case MALO_CMD_WEP:
2015 /* do nothing */
2016 DPRINTF(1, "%s: got wep cmd response\n",
2017 device_xname(sc->sc_dev));
2018 break;
2019 case MALO_CMD_SNMP:
2020 /* do nothing */
2021 DPRINTF(1, "%s: got snmp cmd response\n",
2022 device_xname(sc->sc_dev));
2023 break;
2024 case MALO_CMD_RADIO:
2025 /* do nothing */
2026 DPRINTF(1, "%s: got radio cmd response\n",
2027 device_xname(sc->sc_dev));
2028 break;
2029 case MALO_CMD_CHANNEL:
2030 /* do nothing */
2031 DPRINTF(1, "%s: got channel cmd response\n",
2032 device_xname(sc->sc_dev));
2033 break;
2034 case MALO_CMD_TXPOWER:
2035 /* do nothing */
2036 DPRINTF(1, "%s: got txpower cmd response\n",
2037 device_xname(sc->sc_dev));
2038 break;
2039 case MALO_CMD_ANTENNA:
2040 /* do nothing */
2041 DPRINTF(1, "%s: got antenna cmd response\n",
2042 device_xname(sc->sc_dev));
2043 break;
2044 case MALO_CMD_MACCTRL:
2045 /* do nothing */
2046 DPRINTF(1, "%s: got macctrl cmd response\n",
2047 device_xname(sc->sc_dev));
2048 break;
2049 case MALO_CMD_MACADDR:
2050 /* do nothing */
2051 DPRINTF(1, "%s: got macaddr cmd response\n",
2052 device_xname(sc->sc_dev));
2053 break;
2054 case MALO_CMD_ASSOC:
2055 /* do nothing */
2056 DPRINTF(1, "%s: got assoc cmd response\n",
2057 device_xname(sc->sc_dev));
2058 cmalo_cmd_rsp_assoc(sc);
2059 break;
2060 case MALO_CMD_80211D:
2061 /* do nothing */
2062 DPRINTF(1, "%s: got 80211d cmd response\n",
2063 device_xname(sc->sc_dev));
2064 break;
2065 case MALO_CMD_BGSCAN_CONFIG:
2066 /* do nothing */
2067 DPRINTF(1, "%s: got bgscan config cmd response\n",
2068 device_xname(sc->sc_dev));
2069 break;
2070 case MALO_CMD_BGSCAN_QUERY:
2071 /* do nothing */
2072 DPRINTF(1, "%s: got bgscan query cmd response\n",
2073 device_xname(sc->sc_dev));
2074 break;
2075 case MALO_CMD_RATE:
2076 /* do nothing */
2077 DPRINTF(1, "%s: got rate cmd response\n",
2078 device_xname(sc->sc_dev));
2079 break;
2080 default:
2081 aprint_error_dev(sc->sc_dev,
2082 "got unknown cmd response (0x%04x)\n", hdr->cmd);
2083 break;
2084 }
2085
2086 splx(s);
2087
2088 return 0;
2089 }
2090
2091 #ifdef _MODULE
2092
2093 MODULE(MODULE_CLASS_DRIVER, malo_pcmcia, NULL);
2094
2095 CFDRIVER_DECL(malo_pcmcia, DV_IFNET, NULL);
2096 extern struct cfattach malo_pcmcia_ca;
2097 static int malo_pcmcialoc[] = { -1 };
2098 static struct cfparent pcmciaparent = {
2099 "pcmcia", NULL, DVUNIT_ANY
2100 };
2101 static struct cfdata malo_pcmcia_cfdata[] = {
2102 {
2103 .cf_name = "malo_pcmcia",
2104 .cf_atname = "malo",
2105 .cf_unit = 0,
2106 .cf_fstate = FSTATE_STAR,
2107 .cf_loc = malo_pcmcialoc,
2108 .cf_flags = 0,
2109 .cf_pspec = &pcmciaparent,
2110 },
2111 { NULL }
2112 };
2113
2114 static int
2115 malo_pcmcia_modcmd(modcmd_t cmd, void *arg)
2116 {
2117 int err;
2118
2119 switch (cmd) {
2120 case MODULE_CMD_INIT:
2121 err = config_cfdriver_attach(&malo_pcmcia_cd);
2122 if (err)
2123 return err;
2124 err = config_cfattach_attach("malo_pcmcia", &malo_pcmcia_ca);
2125 if (err) {
2126 config_cfdriver_detach(&malo_pcmcia_cd);
2127 return err;
2128 }
2129 err = config_cfdata_attach(malo_pcmcia_cfdata, 1);
2130 if (err) {
2131 config_cfattach_detach("malo_pcmcia", &malo_pcmcia_ca);
2132 config_cfdriver_detach(&malo_pcmcia_cd);
2133 return err;
2134 }
2135 return 0;
2136 case MODULE_CMD_FINI:
2137 err = config_cfdata_detach(malo_pcmcia_cfdata);
2138 if (err)
2139 return err;
2140 config_cfattach_detach("malo_pcmcia", &malo_pcmcia_ca);
2141 config_cfdriver_detach(&malo_pcmcia_cd);
2142 return 0;
2143 default:
2144 return ENOTTY;
2145 }
2146 }
2147 #endif
2148