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