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