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