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