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