1 /* 2 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * Copyright (c) 1997, 1998, 1999 8 * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by Bill Paul. 21 * 4. Neither the name of the author nor the names of any co-contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 35 * THE POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 #include <sys/conf.h> 39 #include <sys/ddi.h> 40 #include <sys/sunddi.h> 41 #include <sys/dlpi.h> 42 #include <sys/ethernet.h> 43 #include <sys/strsubr.h> 44 #include <sys/strsun.h> 45 #include <sys/stat.h> 46 #include <sys/byteorder.h> 47 #include <sys/pccard.h> 48 #include <sys/pci.h> 49 #include <sys/policy.h> 50 #include <sys/mac_provider.h> 51 #include <sys/stream.h> 52 #include <inet/common.h> 53 #include <inet/nd.h> 54 #include <inet/mi.h> 55 56 #include "pcan.h" 57 #include <sys/mac_wifi.h> 58 #include <inet/wifi_ioctl.h> 59 60 #ifdef DEBUG 61 #define PCAN_DBG_BASIC 0x1 62 #define PCAN_DBG_INFO 0x2 63 #define PCAN_DBG_SEND 0x4 64 #define PCAN_DBG_RCV 0x8 65 #define PCAN_DBG_LINKINFO 0x10 66 #define PCAN_DBG_FW_VERSION 0x20 67 #define PCAN_DBG_CMD 0x40 68 uint32_t pcan_debug = 0; 69 #define PCANDBG(x) \ 70 if (pcan_debug & PCAN_DBG_BASIC) cmn_err x 71 #else 72 #define PCANDBG(x) 73 #endif 74 75 static ddi_device_acc_attr_t accattr = { 76 DDI_DEVICE_ATTR_V0, 77 DDI_STRUCTURE_LE_ACC, 78 DDI_STRICTORDER_ACC, 79 }; 80 81 static ddi_dma_attr_t control_cmd_dma_attr = { 82 DMA_ATTR_V0, /* version of this structure */ 83 0, /* lowest usable address */ 84 0xffffffffffffffffull, /* highest usable address */ 85 0xffffffffull, /* maximum DMAable byte count */ 86 4, /* alignment in bytes */ 87 0xfff, /* burst sizes (any) */ 88 1, /* minimum transfer */ 89 0xffffull, /* maximum transfer */ 90 0xffffffffffffffffull, /* maximum segment length */ 91 1, /* maximum number of segments */ 92 1, /* granularity */ 93 0, /* flags (reserved) */ 94 }; 95 96 void *pcan_soft_state_p = NULL; 97 static int pcan_device_type; 98 99 /* 100 * brussels 101 */ 102 static int pcan_m_setprop(void *arg, const char *pr_name, 103 mac_prop_id_t wldp_pr_num, uint_t wldp_length, 104 const void *wldp_buf); 105 static int pcan_m_getprop(void *arg, const char *pr_name, 106 mac_prop_id_t wldp_pr_num, uint_t wldp_length, void *wldp_buf); 107 static void pcan_m_propinfo(void *arg, const char *pr_name, 108 mac_prop_id_t wldp_pr_num, mac_prop_info_handle_t mph); 109 110 mac_callbacks_t pcan_m_callbacks = { 111 MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO, 112 pcan_gstat, 113 pcan_start, 114 pcan_stop, 115 pcan_prom, 116 pcan_sdmulti, 117 pcan_saddr, 118 pcan_tx, 119 NULL, 120 pcan_ioctl, 121 NULL, 122 NULL, 123 NULL, 124 pcan_m_setprop, 125 pcan_m_getprop, 126 pcan_m_propinfo 127 }; 128 129 static char *pcan_name_str = "pcan"; 130 131 #ifdef __sparc 132 #define pcan_quiesce ddi_quiesce_not_supported 133 #else 134 static int pcan_quiesce(dev_info_t *); 135 #endif 136 137 DDI_DEFINE_STREAM_OPS(pcan_dev_ops, nulldev, pcan_probe, pcan_attach, 138 pcan_detach, nodev, NULL, D_MP, NULL, pcan_quiesce); 139 140 extern struct mod_ops mod_driverops; 141 static struct modldrv modldrv = { 142 &mod_driverops, 143 "Cisco-Aironet 802.11b driver", 144 &pcan_dev_ops 145 }; 146 147 static struct modlinkage modlinkage = { 148 MODREV_1, (void *)&modldrv, NULL 149 }; 150 151 int 152 _init(void) 153 { 154 int stat; 155 156 /* Allocate soft state */ 157 if ((stat = ddi_soft_state_init(&pcan_soft_state_p, 158 sizeof (pcan_maci_t), 2)) != DDI_SUCCESS) 159 return (stat); 160 161 mac_init_ops(&pcan_dev_ops, "pcan"); 162 stat = mod_install(&modlinkage); 163 if (stat != 0) { 164 mac_fini_ops(&pcan_dev_ops); 165 ddi_soft_state_fini(&pcan_soft_state_p); 166 } 167 168 return (stat); 169 } 170 171 int 172 _fini(void) 173 { 174 int stat; 175 176 stat = mod_remove(&modlinkage); 177 if (stat != DDI_SUCCESS) 178 return (stat); 179 mac_fini_ops(&pcan_dev_ops); 180 ddi_soft_state_fini(&pcan_soft_state_p); 181 return (stat); 182 } 183 184 int 185 _info(struct modinfo *modinfop) 186 { 187 return (mod_info(&modlinkage, modinfop)); 188 } 189 190 static int 191 pcan_probe(dev_info_t *dip) 192 { 193 int len, ret; 194 char *buf; 195 dev_info_t *pdip = ddi_get_parent(dip); 196 197 PCANDBG((CE_NOTE, "pcan probe: parent dip=0x%p-%s(%d)\n", (void *)pdip, 198 ddi_driver_name(pdip), ddi_get_instance(pdip))); 199 200 ret = ddi_getlongprop(DDI_DEV_T_ANY, pdip, 0, "device_type", 201 (caddr_t)&buf, &len); 202 if (ret != DDI_SUCCESS) 203 return (DDI_PROBE_FAILURE); 204 205 PCANDBG((CE_NOTE, "pcan probe: device_type %s\n", buf)); 206 if ((strcmp(buf, "pccard") == 0) || (strcmp(buf, "pcmcia") == 0)) { 207 pcan_device_type = PCAN_DEVICE_PCCARD; 208 #ifdef DEBUG 209 if (pcan_debug & PCAN_DBG_FW_VERSION) { 210 cmn_err(CE_NOTE, "Cisco 802.11 pccard\n"); 211 } 212 #endif 213 ret = DDI_PROBE_SUCCESS; 214 } else if (strcmp(buf, "pci") == 0) { 215 pcan_device_type = PCAN_DEVICE_PCI; 216 #ifdef DEBUG 217 if (pcan_debug & PCAN_DBG_FW_VERSION) { 218 cmn_err(CE_NOTE, "Cisco 802.11 minipci card\n"); 219 } 220 #endif 221 ret = DDI_PROBE_SUCCESS; 222 } else { 223 cmn_err(CE_NOTE, "pcan probe: unsupported card\n"); 224 ret = DDI_PROBE_FAILURE; 225 } 226 227 kmem_free(buf, len); 228 return (ret); 229 } 230 231 static int 232 pcan_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 233 { 234 int ret; 235 int instance; 236 uint16_t stat; 237 uint32_t err; 238 pcan_maci_t *pcan_p; 239 wifi_data_t wd = { 0 }; 240 mac_register_t *macp; 241 modify_config_t cfgmod; 242 char strbuf[256]; 243 244 PCANDBG((CE_NOTE, "dip=0x%p cmd=%x\n", (void *)dip, cmd)); 245 if (cmd != DDI_ATTACH) 246 goto attach_fail1; 247 248 /* 249 * Since this driver is porting from freebsd, so just like 250 * the original driver, the minipci card doesn't work on amd64 251 * machine. 252 * For sparc, since no pci card is available for the test, so this 253 * version doesn't support sparc. If there is card available and 254 * requirement, future version will try to support sparc. 255 * This driver works well for minipci card on 32bit x86 256 * machine, so keep the code to just support minipci card on 32bit 257 * mode. 258 */ 259 #if defined(sparc) || defined(__sparc) 260 if (pcan_device_type == PCAN_DEVICE_PCI) { 261 cmn_err(CE_NOTE, "pcan attach: this driver does not support " 262 "PCI/MiniPCI card on Sparc\n"); 263 goto attach_fail1; 264 } 265 #endif /* sparc */ 266 #if defined(__amd64) 267 if (pcan_device_type == PCAN_DEVICE_PCI) { 268 cmn_err(CE_NOTE, "pcan attach: this driver does not support " 269 "PCI/MiniPCI card on amd64\n"); 270 goto attach_fail1; 271 } 272 #endif /* amd64 */ 273 274 /* Allocate soft state associated with this instance. */ 275 if (ddi_soft_state_zalloc(pcan_soft_state_p, 276 ddi_get_instance(dip)) != DDI_SUCCESS) { 277 cmn_err(CE_CONT, "pcan attach: alloc softstate failed\n"); 278 goto attach_fail1; 279 } 280 pcan_p = (pcan_maci_t *)ddi_get_soft_state(pcan_soft_state_p, 281 ddi_get_instance(dip)); 282 283 pcan_p->pcan_device_type = pcan_device_type; 284 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 285 if (ddi_regs_map_setup(dip, 0, 286 (caddr_t *)&pcan_p->pcan_cfg_base, 0, 0, 287 &accattr, &pcan_p->pcan_cfg_handle) != DDI_SUCCESS) 288 goto attach_fail2; 289 290 stat = ddi_get16(pcan_p->pcan_cfg_handle, 291 (uint16_t *)(pcan_p->pcan_cfg_base + PCI_CONF_COMM)); 292 stat |= (PCI_COMM_IO | PCI_COMM_MAE); 293 ddi_put16(pcan_p->pcan_cfg_handle, 294 (uint16_t *)(pcan_p->pcan_cfg_base + PCI_CONF_COMM), stat); 295 296 ddi_regs_map_free(&pcan_p->pcan_cfg_handle); 297 if (ddi_regs_map_setup(dip, 1, (caddr_t *)&pcan_p->pcan_bar0, 298 0, 0, &accattr, &pcan_p->pcan_handle0) != DDI_SUCCESS) 299 goto attach_fail3; 300 if (ddi_regs_map_setup(dip, 2, (caddr_t *)&pcan_p->pcan_bar1, 301 0, 0, &accattr, &pcan_p->pcan_handle1) != DDI_SUCCESS) 302 goto attach_fail3; 303 if (ddi_regs_map_setup(dip, 3, (caddr_t *)&pcan_p->pcan_bar2, 304 0, 0, &accattr, &pcan_p->pcan_handle2) != DDI_SUCCESS) 305 goto attach_fail3; 306 } 307 308 pcan_p->pcan_dip = dip; 309 pcan_p->pcan_flag = 0; 310 pcan_p->glds_nocarrier = 0; 311 pcan_p->glds_noxmtbuf = 0; 312 pcan_p->glds_norcvbuf = 0; 313 pcan_p->pcan_socket = ddi_getprop(DDI_DEV_T_NONE, dip, 314 DDI_PROP_DONTPASS, "socket", -1); 315 316 pcan_p->pcan_reschedule_need = B_FALSE; 317 pcan_p->pcan_info_softint_pending = 0; 318 pcan_p->pcan_reset_delay = ddi_getprop(DDI_DEV_T_ANY, dip, 319 DDI_PROP_DONTPASS, "reset-delay", 5000); 320 321 if (ddi_get_iblock_cookie(dip, 322 0, &pcan_p->pcan_ib_cookie) != DDI_SUCCESS) { 323 cmn_err(CE_WARN, "pcan attach: get_iblk_cookie failed\n"); 324 goto attach_fail3; 325 } 326 327 mutex_init(&pcan_p->pcan_glock, NULL, 328 MUTEX_DRIVER, pcan_p->pcan_ib_cookie); 329 mutex_init(&pcan_p->pcan_scanlist_lock, NULL, 330 MUTEX_DRIVER, pcan_p->pcan_ib_cookie); 331 mutex_init(&pcan_p->pcan_txring.an_tx_lock, NULL, 332 MUTEX_DRIVER, pcan_p->pcan_ib_cookie); 333 334 if (ret = ddi_add_softintr(dip, DDI_SOFTINT_LOW, 335 &pcan_p->pcan_info_softint_id, &pcan_p->pcan_ib_cookie, NULL, 336 pcan_info_softint, (caddr_t)pcan_p)) { 337 cmn_err(CE_WARN, "pcan attach: add info_softintr failed\n"); 338 goto attach_fail3a; 339 } 340 341 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 342 if (ret = ddi_add_intr(dip, 0, NULL, NULL, 343 pcan_intr, (caddr_t)pcan_p)) { 344 cmn_err(CE_WARN, "pcan attach: add intr failed\n"); 345 goto attach_fail4; 346 } 347 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) { 348 if (ret = pcan_register_cs(dip, pcan_p)) { 349 PCANDBG((CE_NOTE, "pcan attach: register_cs failed" 350 " %x\n", ret)); 351 goto attach_fail4; 352 } 353 } else { 354 cmn_err(CE_WARN, "pcan attach: unsupported device type\n"); 355 goto attach_fail4; 356 } 357 358 mutex_enter(&pcan_p->pcan_glock); 359 pcan_reset_backend(pcan_p, pcan_p->pcan_reset_delay); 360 /* leaves IF down, intr disabled */ 361 362 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 363 if (ret = pcan_init_dma(dip, pcan_p)) { 364 cmn_err(CE_WARN, "pcan init_dma: failed\n"); 365 mutex_exit(&pcan_p->pcan_glock); 366 goto attach_fail5; 367 } 368 } 369 if (ret = pcan_get_cap(pcan_p)) { /* sets macaddr for gld_register */ 370 cmn_err(CE_WARN, "pcan attach: get_cap failed %x\n", ret); 371 mutex_exit(&pcan_p->pcan_glock); 372 goto attach_fail6; 373 } 374 375 mutex_exit(&pcan_p->pcan_glock); 376 /* 377 * Provide initial settings for the WiFi plugin; whenever this 378 * information changes, we need to call mac_pdata_update() 379 */ 380 wd.wd_secalloc = WIFI_SEC_NONE; 381 wd.wd_opmode = IEEE80211_M_STA; 382 383 macp = mac_alloc(MAC_VERSION); 384 if (macp == NULL) { 385 PCANDBG((CE_NOTE, "pcan attach: " 386 "MAC version mismatch\n")); 387 goto attach_fail6; 388 } 389 390 macp->m_type_ident = MAC_PLUGIN_IDENT_WIFI; 391 macp->m_driver = pcan_p; 392 macp->m_dip = dip; 393 macp->m_src_addr = pcan_p->pcan_mac_addr; 394 macp->m_callbacks = &pcan_m_callbacks; 395 macp->m_min_sdu = 0; 396 macp->m_max_sdu = IEEE80211_MTU; 397 macp->m_pdata = &wd; 398 macp->m_pdata_size = sizeof (wd); 399 400 err = mac_register(macp, &pcan_p->pcan_mh); 401 mac_free(macp); 402 if (err != 0) { 403 PCANDBG((CE_NOTE, "pcan attach: " 404 "mac_register err\n")); 405 goto attach_fail6; 406 } 407 408 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) { 409 /* turn on CS interrupt */ 410 cfgmod.Attributes = CONF_ENABLE_IRQ_STEERING | 411 CONF_IRQ_CHANGE_VALID; 412 cfgmod.Vpp1 = 50; 413 cfgmod.Vpp2 = 50; 414 (void) csx_ModifyConfiguration(pcan_p->pcan_chdl, &cfgmod); 415 416 mutex_enter(&pcan_p->pcan_glock); 417 if (ret = pcan_init_nicmem(pcan_p)) { 418 cmn_err(CE_WARN, "pcan attach: init_nicmem failed %x\n", 419 ret); 420 mutex_exit(&pcan_p->pcan_glock); 421 goto attach_fail7; 422 } 423 mutex_exit(&pcan_p->pcan_glock); 424 } 425 (void) ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 426 "bad-rids", (caddr_t)&pcan_p->pcan_badrids, 427 &pcan_p->pcan_badrids_len); 428 429 pcan_p->an_config.an_rxmode = AN_NORMAL_RXMODE; 430 ether_copy(pcan_p->pcan_mac_addr, pcan_p->an_config.an_macaddr); 431 mutex_enter(&pcan_p->pcan_glock); 432 list_create(&pcan_p->an_scan_list, sizeof (an_scan_list_t), 433 offsetof(an_scan_list_t, an_scan_node)); 434 pcan_p->an_scan_num = 0; 435 mutex_exit(&pcan_p->pcan_glock); 436 pcan_p->an_scanlist_timeout_id = timeout(pcan_scanlist_timeout, 437 pcan_p, drv_usectohz(1000000)); 438 439 instance = ddi_get_instance(dip); 440 (void) snprintf(strbuf, sizeof (strbuf), "pcan%d", instance); 441 if (ddi_create_minor_node(dip, strbuf, S_IFCHR, 442 instance + 1, DDI_NT_NET_WIFI, 0) != DDI_SUCCESS) { 443 goto attach_fail8; 444 } 445 mutex_enter(&pcan_p->pcan_glock); 446 PCAN_DISABLE_INTR_CLEAR(pcan_p); 447 (void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0); 448 pcan_p->pcan_flag |= PCAN_ATTACHED; 449 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 450 pcan_p->pcan_flag |= PCAN_CARD_READY; 451 } 452 mutex_exit(&pcan_p->pcan_glock); 453 return (DDI_SUCCESS); 454 attach_fail8: 455 if (pcan_p->an_scanlist_timeout_id != 0) { 456 (void) untimeout(pcan_p->an_scanlist_timeout_id); 457 pcan_p->an_scanlist_timeout_id = 0; 458 } 459 list_destroy(&pcan_p->an_scan_list); 460 attach_fail7: 461 (void) mac_unregister(pcan_p->pcan_mh); 462 attach_fail6: 463 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) 464 pcan_free_dma(pcan_p); 465 attach_fail5: 466 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 467 ddi_remove_intr(dip, 0, pcan_p->pcan_ib_cookie); 468 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) { 469 pcan_unregister_cs(pcan_p); 470 } 471 attach_fail4: 472 if (pcan_p->pcan_info_softint_id) 473 ddi_remove_softintr(pcan_p->pcan_info_softint_id); 474 attach_fail3a: 475 pcan_destroy_locks(pcan_p); 476 attach_fail3: 477 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 478 if (pcan_p->pcan_handle0) 479 ddi_regs_map_free(&pcan_p->pcan_handle0); 480 if (pcan_p->pcan_handle1) 481 ddi_regs_map_free(&pcan_p->pcan_handle1); 482 if (pcan_p->pcan_handle2) 483 ddi_regs_map_free(&pcan_p->pcan_handle2); 484 } 485 attach_fail2: 486 ddi_soft_state_free(pcan_soft_state_p, ddi_get_instance(dip)); 487 attach_fail1: 488 return (DDI_FAILURE); 489 } 490 491 static int 492 pcan_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 493 { 494 pcan_maci_t *pcan_p; 495 an_scan_list_t *scan_item0; 496 int ret; 497 pcan_p = ddi_get_soft_state(pcan_soft_state_p, ddi_get_instance(dip)); 498 499 if (cmd != DDI_DETACH) 500 return (DDI_FAILURE); 501 if (!(pcan_p->pcan_flag & PCAN_ATTACHED)) 502 return (DDI_FAILURE); 503 504 ret = mac_disable(pcan_p->pcan_mh); 505 if (ret != 0) 506 return (DDI_FAILURE); 507 508 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 509 mutex_enter(&pcan_p->pcan_glock); 510 pcan_stop_locked(pcan_p); 511 PCAN_DISABLE_INTR(pcan_p); 512 mutex_exit(&pcan_p->pcan_glock); 513 } 514 if (pcan_p->an_scanlist_timeout_id != 0) { 515 (void) untimeout(pcan_p->an_scanlist_timeout_id); 516 pcan_p->an_scanlist_timeout_id = 0; 517 } 518 if (pcan_p->pcan_connect_timeout_id != 0) { 519 (void) untimeout(pcan_p->pcan_connect_timeout_id); 520 pcan_p->pcan_connect_timeout_id = 0; 521 } 522 mutex_enter(&pcan_p->pcan_scanlist_lock); 523 scan_item0 = list_head(&pcan_p->an_scan_list); 524 while (scan_item0) { 525 pcan_delete_scan_item(pcan_p, scan_item0); 526 scan_item0 = list_head(&pcan_p->an_scan_list); 527 } 528 list_destroy(&pcan_p->an_scan_list); 529 mutex_exit(&pcan_p->pcan_scanlist_lock); 530 531 (void) mac_unregister(pcan_p->pcan_mh); 532 533 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 534 mutex_enter(&pcan_p->pcan_glock); 535 ddi_remove_intr(dip, 0, pcan_p->pcan_ib_cookie); 536 pcan_free_dma(pcan_p); 537 if (pcan_p->pcan_handle0) 538 ddi_regs_map_free(&pcan_p->pcan_handle0); 539 if (pcan_p->pcan_handle1) 540 ddi_regs_map_free(&pcan_p->pcan_handle1); 541 if (pcan_p->pcan_handle2) 542 ddi_regs_map_free(&pcan_p->pcan_handle2); 543 mutex_exit(&pcan_p->pcan_glock); 544 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) { 545 pcan_unregister_cs(pcan_p); 546 } else { 547 cmn_err(CE_WARN, "pcan detach: unsupported device type\n"); 548 } 549 pcan_destroy_locks(pcan_p); 550 if (pcan_p->pcan_info_softint_id) 551 ddi_remove_softintr(pcan_p->pcan_info_softint_id); 552 553 if (pcan_p->pcan_badrids_len) 554 kmem_free(pcan_p->pcan_badrids, pcan_p->pcan_badrids_len); 555 556 ddi_soft_state_free(pcan_soft_state_p, ddi_get_instance(dip)); 557 ddi_remove_minor_node(dip, NULL); 558 559 return (DDI_SUCCESS); 560 } 561 562 /* 563 * card services and event handlers 564 */ 565 566 static int 567 pcan_register_cs(dev_info_t *dip, pcan_maci_t *pcan_p) 568 { 569 int ret; 570 client_reg_t cr; 571 client_handle_t chdl; /* uint encoding of socket, function, client */ 572 get_status_t card_status; 573 request_socket_mask_t sock_req; 574 575 bzero(&cr, sizeof (cr)); 576 cr.Attributes = INFO_IO_CLIENT|INFO_CARD_EXCL|INFO_CARD_SHARE; 577 cr.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | 578 CS_EVENT_REGISTRATION_COMPLETE | CS_EVENT_CARD_REMOVAL_LOWP | 579 CS_EVENT_CARD_READY | CS_EVENT_PM_RESUME | CS_EVENT_PM_SUSPEND | 580 CS_EVENT_CLIENT_INFO; 581 cr.event_callback_args.client_data = pcan_p; 582 cr.Version = CS_VERSION; 583 cr.event_handler = (csfunction_t *)pcan_ev_hdlr; 584 cr.dip = dip; 585 (void) strcpy(cr.driver_name, pcan_name_str); 586 if (ret = csx_RegisterClient(&chdl, &cr)) { 587 cmn_err(CE_WARN, "pcan: RegisterClient failed %x", ret); 588 goto regcs_ret; 589 } 590 591 pcan_p->pcan_chdl = chdl; 592 593 bzero(&card_status, sizeof (card_status)); 594 (void) csx_GetStatus(chdl, &card_status); 595 PCANDBG((CE_NOTE, "pcan: getstat Sock=%x CState=%x SState=%x rState=%x", 596 card_status.Socket, card_status.CardState, 597 card_status.SocketState, card_status.raw_CardState)); 598 if (!(card_status.CardState & CS_STATUS_CARD_INSERTED)) { 599 /* card is not present, why are we attaching ? */ 600 ret = CS_NO_CARD; 601 goto unreg; 602 } 603 cv_init(&pcan_p->pcan_cscv, NULL, CV_DRIVER, NULL); 604 mutex_init(&pcan_p->pcan_cslock, NULL, MUTEX_DRIVER, *cr.iblk_cookie); 605 mutex_enter(&pcan_p->pcan_cslock); 606 if (ret = csx_MapLogSocket(chdl, &pcan_p->pcan_log_sock)) { 607 cmn_err(CE_WARN, "pcan: MapLogSocket failed %x", ret); 608 goto fail; 609 } 610 PCANDBG((CE_NOTE, "pcan: logsock: LogSock=%x PhyAdapter=%x PhySock=%x", 611 pcan_p->pcan_log_sock.LogSocket, 612 pcan_p->pcan_log_sock.PhyAdapter, 613 pcan_p->pcan_log_sock.PhySocket)); 614 615 /* turn on initialization events */ 616 sock_req.Socket = 0; 617 sock_req.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | 618 CS_EVENT_REGISTRATION_COMPLETE; 619 if (ret = csx_RequestSocketMask(chdl, &sock_req)) { 620 cmn_err(CE_WARN, "pcan: RequestSocketMask failed %x\n", ret); 621 goto fail; 622 } 623 624 /* wait for and process card insertion events */ 625 while (!(pcan_p->pcan_flag & PCAN_CARD_READY)) 626 cv_wait(&pcan_p->pcan_cscv, &pcan_p->pcan_cslock); 627 mutex_exit(&pcan_p->pcan_cslock); 628 629 pcan_p->pcan_flag |= PCAN_CS_REGISTERED; 630 return (CS_SUCCESS); 631 fail: 632 mutex_destroy(&pcan_p->pcan_cslock); 633 cv_destroy(&pcan_p->pcan_cscv); 634 unreg: 635 (void) csx_DeregisterClient(chdl); 636 regcs_ret: 637 pcan_p->pcan_flag &= ~PCAN_CS_REGISTERED; 638 return (ret); 639 } 640 641 static void 642 pcan_unregister_cs(pcan_maci_t *pcan_p) 643 { 644 int ret; 645 release_socket_mask_t mask; 646 mask.Socket = pcan_p->pcan_socket; 647 648 /* 649 * The card service not registered means register_cs function 650 * doesnot return TRUE. Then all the lelated resource has been 651 * released in register_cs. 652 */ 653 if (!(pcan_p->pcan_flag | PCAN_CS_REGISTERED)) 654 return; 655 (void) csx_ReleaseSocketMask(pcan_p->pcan_chdl, &mask); 656 657 if (pcan_p->pcan_flag & PCAN_CARD_READY) { 658 pcan_card_remove(pcan_p); 659 } 660 mutex_destroy(&pcan_p->pcan_cslock); 661 cv_destroy(&pcan_p->pcan_cscv); 662 if (ret = csx_DeregisterClient(pcan_p->pcan_chdl)) 663 cmn_err(CE_WARN, "pcan: deregister failed %x\n", ret); 664 } 665 static void 666 pcan_destroy_locks(pcan_maci_t *pcan_p) 667 { 668 mutex_destroy(&pcan_p->pcan_txring.an_tx_lock); 669 mutex_destroy(&pcan_p->pcan_scanlist_lock); 670 mutex_destroy(&pcan_p->pcan_glock); 671 } 672 673 static int 674 pcan_ev_hdlr(event_t event, int priority, event_callback_args_t *arg) 675 { 676 int ret = CS_SUCCESS; 677 pcan_maci_t *pcan_p = (pcan_maci_t *)arg->client_data; 678 client_info_t *ci_p = (client_info_t *)&arg->client_info; 679 680 mutex_enter(&pcan_p->pcan_cslock); 681 switch (event) { 682 case CS_EVENT_CARD_INSERTION: 683 ret = pcan_card_insert(pcan_p); 684 cv_broadcast(&pcan_p->pcan_cscv); 685 break; 686 case CS_EVENT_REGISTRATION_COMPLETE: 687 cv_broadcast(&pcan_p->pcan_cscv); 688 break; 689 case CS_EVENT_CARD_REMOVAL: 690 if (priority & CS_EVENT_PRI_HIGH) 691 break; 692 pcan_card_remove(pcan_p); 693 cv_broadcast(&pcan_p->pcan_cscv); 694 break; 695 case CS_EVENT_CLIENT_INFO: 696 if (GET_CLIENT_INFO_SUBSVC(ci_p->Attributes) != 697 CS_CLIENT_INFO_SUBSVC_CS) 698 break; 699 700 ci_p->Revision = 0x0101; 701 ci_p->CSLevel = CS_VERSION; 702 ci_p->RevDate = CS_CLIENT_INFO_MAKE_DATE(9, 12, 14); 703 (void) strcpy(ci_p->ClientName, PCAN_IDENT_STRING); 704 (void) strcpy(ci_p->VendorName, CS_SUN_VENDOR_DESCRIPTION); 705 ci_p->Attributes |= CS_CLIENT_INFO_VALID; 706 break; 707 case CS_EVENT_PM_SUSPEND: 708 pcan_do_suspend(pcan_p); 709 break; 710 default: 711 ret = CS_UNSUPPORTED_EVENT; 712 break; 713 } 714 mutex_exit(&pcan_p->pcan_cslock); 715 return (ret); 716 } 717 718 static int 719 pcan_card_insert(pcan_maci_t *pcan_p) 720 { 721 int ret, hi, lo; 722 tuple_t tuple; 723 cisparse_t cisparse; 724 io_req_t io; 725 irq_req_t irq; 726 config_req_t cfg; 727 cistpl_config_t config; 728 cistpl_cftable_entry_t *tbl_p; 729 register client_handle_t chdl = pcan_p->pcan_chdl; 730 modify_config_t cfgmod; 731 732 bzero(&tuple, sizeof (tuple)); 733 tuple.DesiredTuple = CISTPL_MANFID; 734 if (ret = csx_GetFirstTuple(chdl, &tuple)) { 735 cmn_err(CE_WARN, "pcan: get manufacture id failed %x\n", ret); 736 goto insert_ret; 737 } 738 bzero(&cisparse, sizeof (cisparse)); 739 if (ret = csx_Parse_CISTPL_MANFID(chdl, &tuple, &cisparse.manfid)) { 740 cmn_err(CE_WARN, "pcan: parse manufacture id failed %x\n", ret); 741 goto insert_ret; 742 } 743 /* verify manufacture ID */ 744 PCANDBG((CE_NOTE, "pcan: manufacturer_id=%x card=%x\n", 745 cisparse.manfid.manf, cisparse.manfid.card)); 746 747 bzero(&tuple, sizeof (tuple)); 748 tuple.DesiredTuple = CISTPL_FUNCID; 749 if (ret = csx_GetFirstTuple(chdl, &tuple)) { 750 cmn_err(CE_WARN, "pcan: get function id failed %x\n", ret); 751 goto insert_ret; 752 } 753 bzero(&cisparse, sizeof (cisparse)); 754 if (ret = csx_Parse_CISTPL_FUNCID(chdl, &tuple, &cisparse.funcid)) { 755 cmn_err(CE_WARN, "pcan: parse function id failed %x\n", ret); 756 goto insert_ret; 757 } 758 /* verify function ID */ 759 PCANDBG((CE_NOTE, "funcid=%x\n", cisparse.funcid.function)); 760 761 bzero(&tuple, sizeof (tuple)); 762 tuple.DesiredTuple = CISTPL_CONFIG; 763 if (ret = csx_GetFirstTuple(chdl, &tuple)) { 764 cmn_err(CE_WARN, "pcan: get config failed %x\n", ret); 765 goto insert_ret; 766 } 767 bzero(&config, sizeof (config)); 768 if (ret = csx_Parse_CISTPL_CONFIG(chdl, &tuple, &config)) { 769 cmn_err(CE_WARN, "pcan: parse config failed %x\n", ret); 770 goto insert_ret; 771 } 772 PCANDBG((CE_NOTE, 773 "pcan: config present=%x nr=%x hr=%x regs[0]=%x base=%x last=%x\n", 774 config.present, config.nr, config.hr, config.regs[0], 775 config.base, config.last)); 776 777 hi = 0; 778 lo = (int)-1; /* really big number */ 779 tbl_p = &cisparse.cftable; 780 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; 781 for (tbl_p->index = 0; tbl_p->index <= config.hr; ) { 782 PCANDBG((CE_NOTE, "pcan: tuple idx=%x:\n", tbl_p->index)); 783 if (ret = csx_GetNextTuple(chdl, &tuple)) { 784 cmn_err(CE_WARN, "pcan: get cftable failed %x\n", ret); 785 break; 786 } 787 bzero((caddr_t)&cisparse, sizeof (cisparse)); 788 if (ret = csx_Parse_CISTPL_CFTABLE_ENTRY(chdl, &tuple, tbl_p)) { 789 cmn_err(CE_WARN, "pcan: parse cftable failed%x\n", ret); 790 break; 791 } 792 if (tbl_p->flags & CISTPL_CFTABLE_TPCE_FS_PWR && 793 tbl_p->pd.flags & CISTPL_CFTABLE_TPCE_FS_PWR_VCC) { 794 if (tbl_p->pd.pd_vcc.avgI > hi) { 795 hi = tbl_p->pd.pd_vcc.avgI; 796 pcan_p->pcan_config_hi = tbl_p->index; 797 } 798 if (tbl_p->pd.pd_vcc.avgI < lo) { 799 lo = tbl_p->pd.pd_vcc.avgI; 800 pcan_p->pcan_config = tbl_p->index; 801 } 802 } 803 if (tbl_p->flags & CISTPL_CFTABLE_TPCE_DEFAULT) { 804 if (tbl_p->pd.flags & CISTPL_CFTABLE_TPCE_FS_PWR_VCC) 805 pcan_p->pcan_vcc = tbl_p->pd.pd_vcc.nomV; 806 if (tbl_p->flags & CISTPL_CFTABLE_TPCE_FS_IO) 807 pcan_p->pcan_iodecode = tbl_p->io.addr_lines; 808 } 809 } 810 PCANDBG((CE_NOTE, "pcan: cfg_hi=%x cfg=%x vcc=%x iodecode=%x\n", 811 pcan_p->pcan_config_hi, pcan_p->pcan_config, 812 pcan_p->pcan_vcc, pcan_p->pcan_iodecode)); 813 814 bzero(&io, sizeof (io)); 815 io.BasePort1.base = 0; 816 io.NumPorts1 = 1 << pcan_p->pcan_iodecode; 817 io.Attributes1 = IO_DATA_PATH_WIDTH_16; 818 io.IOAddrLines = pcan_p->pcan_iodecode; 819 if (ret = csx_RequestIO(chdl, &io)) { 820 cmn_err(CE_WARN, "pcan: RequestIO failed %x\n", ret); 821 goto insert_ret; 822 } 823 pcan_p->pcan_port = io.BasePort1.handle; 824 825 if (ret = ddi_add_softintr(DIP(pcan_p), DDI_SOFTINT_HIGH, 826 &pcan_p->pcan_softint_id, &pcan_p->pcan_ib_cookie, NULL, 827 pcan_intr, (caddr_t)pcan_p)) { 828 cmn_err(CE_NOTE, "pcan: Add softintr failed\n"); 829 goto insert_ret; 830 } 831 irq.Attributes = IRQ_TYPE_EXCLUSIVE; 832 irq.irq_handler = ddi_intr_hilevel(DIP(pcan_p), 0) ? 833 (csfunction_t *)pcan_intr_hi : (csfunction_t *)pcan_intr; 834 irq.irq_handler_arg = pcan_p; 835 if (ret = csx_RequestIRQ(chdl, &irq)) { 836 cmn_err(CE_WARN, "pcan: RequestIRQ failed %x\n", ret); 837 goto un_io; 838 } 839 840 bzero(&cfg, sizeof (cfg)); 841 cfg.Attributes = 0; /* not ready for CONF_ENABLE_IRQ_STEERING yet */ 842 cfg.Vcc = 50; /* pcan_vcc == 0 */ 843 cfg.Vpp1 = 50; 844 cfg.Vpp2 = 50; 845 cfg.IntType = SOCKET_INTERFACE_MEMORY_AND_IO; 846 cfg.ConfigBase = config.base; 847 cfg.ConfigIndex = pcan_p->pcan_config; 848 cfg.Status = CCSR_IO_IS_8; /* no use */ 849 cfg.Present = config.present; 850 pcan_p->pcan_flag |= PCAN_CARD_READY; 851 if (ret = csx_RequestConfiguration(chdl, &cfg)) { 852 cmn_err(CE_WARN, "pcan: RequestConfiguration failed %x\n", ret); 853 goto un_irq; 854 } 855 856 if (pcan_p->pcan_flag & PCAN_SUSPENDED) { 857 mutex_enter(&pcan_p->pcan_glock); 858 pcan_reset_backend(pcan_p, pcan_p->pcan_reset_delay); 859 /* turn on CS interrupt */ 860 cfgmod.Attributes = CONF_ENABLE_IRQ_STEERING | 861 CONF_IRQ_CHANGE_VALID; 862 cfgmod.Vpp1 = 50; 863 cfgmod.Vpp2 = 50; 864 (void) csx_ModifyConfiguration(pcan_p->pcan_chdl, &cfgmod); 865 866 if (ret = pcan_init_nicmem(pcan_p)) { 867 cmn_err(CE_WARN, "pcan insert: init_nicmem failed %x\n", 868 ret); 869 } 870 PCAN_DISABLE_INTR_CLEAR(pcan_p); 871 ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0); 872 PCANDBG((CE_NOTE, "pcan insert set cmd ret =%x\n", ret)); 873 pcan_p->pcan_flag &= ~PCAN_SUSPENDED; 874 mutex_exit(&pcan_p->pcan_glock); 875 } 876 877 if (pcan_p->pcan_flag & PCAN_PLUMBED) { 878 (void) pcan_start(pcan_p); 879 pcan_p->pcan_flag &= ~PCAN_PLUMBED; 880 PCANDBG((CE_NOTE, "pcan insert: active interrupt\n")); 881 } 882 return (CS_SUCCESS); 883 un_irq: 884 (void) csx_ReleaseIRQ(chdl, &irq); 885 un_io: 886 ddi_remove_softintr(pcan_p->pcan_softint_id); 887 888 (void) csx_ReleaseIO(chdl, &io); 889 pcan_p->pcan_port = 0; 890 insert_ret: 891 pcan_p->pcan_flag &= ~PCAN_CARD_READY; 892 return (ret); 893 } 894 895 /* 896 * assume card is already removed, don't touch the hardware 897 */ 898 static void 899 pcan_do_suspend(pcan_maci_t *pcan_p) 900 { 901 int ret; 902 if (pcan_p->pcan_flag & PCAN_CARD_LINKUP) { 903 if (pcan_p->pcan_connect_timeout_id != 0) { 904 (void) untimeout(pcan_p->pcan_connect_timeout_id); 905 pcan_p->pcan_connect_timeout_id = 0; 906 } 907 mutex_enter(&pcan_p->pcan_glock); 908 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP; 909 if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) 910 PCANDBG((CE_NOTE, "pcan: disable failed, ret %d\n", 911 ret)); 912 if (ret = pcan_loaddef(pcan_p)) 913 PCANDBG((CE_NOTE, "pcan: loaddef failed, ret %d\n", 914 ret)); 915 mac_link_update(GLD3(pcan_p), LINK_STATE_DOWN); 916 mutex_exit(&pcan_p->pcan_glock); 917 } 918 pcan_p->pcan_flag |= PCAN_SUSPENDED; 919 } 920 921 922 /* 923 * assume card is already removed, don't touch the hardware 924 */ 925 static void 926 pcan_card_remove(pcan_maci_t *pcan_p) 927 { 928 int ret; 929 io_req_t io; 930 irq_req_t irq; 931 932 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) 933 return; 934 if (pcan_p->pcan_connect_timeout_id != 0) { 935 (void) untimeout(pcan_p->pcan_connect_timeout_id); 936 pcan_p->pcan_connect_timeout_id = 0; 937 } 938 939 if (pcan_p->pcan_flag & PCAN_CARD_LINKUP) { 940 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP; 941 mac_link_update(GLD3(pcan_p), LINK_STATE_DOWN); 942 } 943 mutex_enter(&pcan_p->pcan_glock); 944 if (pcan_p->pcan_flag & PCAN_CARD_INTREN) { 945 pcan_stop_locked(pcan_p); 946 pcan_p->pcan_flag |= PCAN_PLUMBED; 947 } 948 pcan_p->pcan_flag &= ~PCAN_CARD_READY; 949 mutex_exit(&pcan_p->pcan_glock); 950 951 if (ret = csx_ReleaseConfiguration(pcan_p->pcan_chdl, NULL)) 952 cmn_err(CE_WARN, "pcan: ReleaseConfiguration failed %x\n", ret); 953 954 bzero(&irq, sizeof (irq)); 955 if (ret = csx_ReleaseIRQ(pcan_p->pcan_chdl, &irq)) 956 cmn_err(CE_WARN, "pcan: ReleaseIRQ failed %x\n", ret); 957 958 ddi_remove_softintr(pcan_p->pcan_softint_id); 959 pcan_p->pcan_softint_id = 0; 960 961 bzero(&io, sizeof (io)); 962 io.BasePort1.handle = pcan_p->pcan_port; 963 io.NumPorts1 = 16; 964 if (ret = csx_ReleaseIO(pcan_p->pcan_chdl, &io)) 965 cmn_err(CE_WARN, "pcan: Release IO failed %x\n", ret); 966 967 pcan_p->pcan_port = 0; 968 PCANDBG((CE_NOTE, "pcan: removed\n")); 969 } 970 971 /* 972 * gld operation interface routines 973 */ 974 static int 975 pcan_start(void *arg) 976 { 977 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 978 979 mutex_enter(&pcan_p->pcan_glock); 980 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) { 981 mutex_exit(&pcan_p->pcan_glock); 982 return (PCAN_FAIL); 983 } 984 (void) pcan_loaddef(pcan_p); 985 pcan_start_locked(pcan_p); 986 mutex_exit(&pcan_p->pcan_glock); 987 return (PCAN_SUCCESS); 988 } 989 990 static void 991 pcan_stop(void *arg) 992 { 993 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 994 995 mutex_enter(&pcan_p->pcan_glock); 996 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) { 997 mutex_exit(&pcan_p->pcan_glock); 998 return; 999 } 1000 pcan_stop_locked(pcan_p); 1001 mutex_exit(&pcan_p->pcan_glock); 1002 if (pcan_p->pcan_connect_timeout_id != 0) { 1003 (void) untimeout(pcan_p->pcan_connect_timeout_id); 1004 pcan_p->pcan_connect_timeout_id = 0; 1005 } 1006 } 1007 1008 /* 1009 * mac address can only be set in 'disable' state and 1010 * be effective after 'enable' state. 1011 */ 1012 static int 1013 pcan_saddr(void *arg, const uint8_t *macaddr) 1014 { 1015 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 1016 int ret = PCAN_SUCCESS; 1017 ether_copy(macaddr, pcan_p->pcan_mac_addr); 1018 1019 mutex_enter(&pcan_p->pcan_glock); 1020 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) { 1021 ret = PCAN_FAIL; 1022 goto done; 1023 } 1024 ether_copy(pcan_p->pcan_mac_addr, pcan_p->an_config.an_macaddr); 1025 if (pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) { 1026 cmn_err(CE_WARN, "pcan set mac addr: failed\n"); 1027 ret = PCAN_FAIL; 1028 goto done; 1029 } 1030 if (pcan_config_mac(pcan_p)) { 1031 cmn_err(CE_WARN, "pcan set mac addr: config_mac failed\n"); 1032 ret = PCAN_FAIL; 1033 goto done; 1034 } 1035 if (pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0)) { 1036 cmn_err(CE_WARN, "pcan set mac addr: failed\n"); 1037 ret = PCAN_FAIL; 1038 } 1039 done: 1040 mutex_exit(&pcan_p->pcan_glock); 1041 return (ret); 1042 } 1043 1044 /* 1045 * send a packet out for pccard 1046 */ 1047 static int 1048 pcan_send(pcan_maci_t *pcan_p, mblk_t *mblk_p) 1049 { 1050 char *buf, *buf_p; 1051 an_txfrm_t *frm_p; 1052 #ifdef PCAN_SEND_DEBUG 1053 struct an_ltv_status radio_status; 1054 #endif /* PCAN_SEND_DEBUG */ 1055 uint16_t pkt_len, xmt_id, ring_idx, r = 0; 1056 struct ieee80211_frame *wh; 1057 int i = 0; 1058 1059 mutex_enter(&pcan_p->pcan_glock); 1060 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) { 1061 mutex_exit(&pcan_p->pcan_glock); 1062 freemsg(mblk_p); 1063 return (PCAN_SUCCESS); /* drop packet */ 1064 } 1065 if (!(pcan_p->pcan_flag & PCAN_CARD_LINKUP)) { /* link down */ 1066 PCANDBG((CE_NOTE, "pcan: link down, dropped\n")); 1067 pcan_p->glds_nocarrier++; 1068 mutex_exit(&pcan_p->pcan_glock); 1069 freemsg(mblk_p); 1070 return (PCAN_SUCCESS); /* drop packet */ 1071 } 1072 mutex_exit(&pcan_p->pcan_glock); 1073 if (pullupmsg(mblk_p, -1) == 0) { 1074 cmn_err(CE_NOTE, "pcan send: pullupmsg failed\n"); 1075 freemsg(mblk_p); 1076 return (PCAN_SUCCESS); /* drop packet */ 1077 } 1078 wh = (struct ieee80211_frame *)mblk_p->b_rptr; 1079 1080 mutex_enter(&pcan_p->pcan_txring.an_tx_lock); 1081 ring_idx = pcan_p->pcan_txring.an_tx_prod; 1082 pcan_p->pcan_txring.an_tx_prod = (ring_idx + 1) & AN_TX_RING_MASK; 1083 1084 /* check whether there is a xmt buffer available */ 1085 while ((i < AN_TX_RING_CNT) && 1086 (pcan_p->pcan_txring.an_tx_ring[ring_idx])) { 1087 ring_idx = pcan_p->pcan_txring.an_tx_prod; 1088 pcan_p->pcan_txring.an_tx_prod = 1089 (ring_idx + 1) & AN_TX_RING_MASK; 1090 i++; 1091 } 1092 1093 if (i == AN_TX_RING_CNT) { 1094 mutex_exit(&pcan_p->pcan_txring.an_tx_lock); 1095 PCANDBG((CE_NOTE, "pcan: ring full, retrying\n")); 1096 mutex_enter(&pcan_p->pcan_glock); 1097 pcan_p->pcan_reschedule_need = B_TRUE; 1098 mutex_exit(&pcan_p->pcan_glock); 1099 pcan_p->glds_noxmtbuf++; 1100 return (PCAN_FAIL); 1101 } 1102 xmt_id = pcan_p->pcan_txring.an_tx_fids[ring_idx]; 1103 pcan_p->pcan_txring.an_tx_ring[ring_idx] = xmt_id; 1104 mutex_exit(&pcan_p->pcan_txring.an_tx_lock); 1105 1106 buf = kmem_zalloc(PCAN_NICMEM_SZ, KM_SLEEP); /* too big for stack */ 1107 buf_p = (ulong_t)buf & 1 ? buf + 1 : buf; /* 16-bit round up */ 1108 frm_p = (an_txfrm_t *)buf_p; 1109 1110 #ifdef DEBUG 1111 if (pcan_debug & PCAN_DBG_SEND) { 1112 cmn_err(CE_NOTE, "pcan send: packet from plugin"); 1113 for (i = 0; i < MBLKL(mblk_p); i++) 1114 cmn_err(CE_NOTE, "%x: %x\n", i, 1115 *((unsigned char *)mblk_p->b_rptr + i)); 1116 } 1117 #endif 1118 pkt_len = msgdsize(mblk_p); 1119 if (pkt_len > PCAN_NICMEM_SZ - sizeof (an_txfrm_t)) { 1120 cmn_err(CE_WARN, "pcan send: mblk is too long"); 1121 kmem_free(buf, PCAN_NICMEM_SZ); 1122 freemsg(mblk_p); 1123 return (PCAN_SUCCESS); /* drop packet */ 1124 } 1125 if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) != 1126 IEEE80211_FC1_DIR_TODS) { 1127 kmem_free(buf, PCAN_NICMEM_SZ); 1128 freemsg(mblk_p); 1129 return (PCAN_SUCCESS); /* drop packet */ 1130 } 1131 1132 /* initialize xmt frame header, payload_len must be stored in LE */ 1133 bzero(frm_p, sizeof (an_txfrm_t) + 2); 1134 frm_p->an_tx_ctl = AN_TXCTL_8023; 1135 1136 /* 1137 * mblk sent down from plugin includes station mode 802.11 frame and 1138 * llc, so we here need to remove them and add an ethernet header. 1139 */ 1140 pkt_len = pkt_len - (sizeof (*wh) + sizeof (struct ieee80211_llc)) 1141 + 2; 1142 bcopy(wh->i_addr3, buf_p + 0x38, ETHERADDRL); /* dst macaddr */ 1143 bcopy(wh->i_addr2, buf_p + 0x3e, ETHERADDRL); /* src macaddr */ 1144 *((uint16_t *)(buf_p + 0x36)) = pkt_len; 1145 bcopy(mblk_p->b_rptr + sizeof (*wh) + sizeof (struct ieee80211_llc) 1146 - 2, buf_p + 0x44, pkt_len); 1147 1148 if (pkt_len & 1) { /* round up to 16-bit boundary and pad 0 */ 1149 buf_p[pkt_len + 0x44] = 0; 1150 pkt_len++; 1151 } 1152 ASSERT(pkt_len <= PCAN_NICMEM_SZ); 1153 #ifdef DEBUG 1154 if (pcan_debug & PCAN_DBG_SEND) { 1155 cmn_err(CE_NOTE, "pcan send: packet to hardware--pkt_len=%x", 1156 pkt_len); 1157 for (i = 0; i < pkt_len + 4; i++) 1158 cmn_err(CE_NOTE, "%x: %x\n", i, 1159 *((unsigned char *)buf_p + 0x36 + i)); 1160 } 1161 #endif 1162 mutex_enter(&pcan_p->pcan_glock); 1163 (void) WRCH1(pcan_p, xmt_id, 0, (uint16_t *)buf_p, 0x38); /* frm */ 1164 (void) WRPKT(pcan_p, xmt_id, 0x38, (uint16_t *)(buf_p + 0x38), 1165 pkt_len + 12); 1166 r = pcan_set_cmd(pcan_p, AN_CMD_TX, xmt_id); 1167 mutex_exit(&pcan_p->pcan_glock); 1168 1169 PCANDBG((CE_NOTE, "pcan: pkt_len=0x44+%x=%x xmt=%x ret=%x\n", 1170 pkt_len, 0x44 + pkt_len, xmt_id, ring_idx)); 1171 kmem_free(buf, PCAN_NICMEM_SZ); 1172 #ifdef PCAN_SEND_DEBUG 1173 if (pkt_len = pcan_status_ltv(PCAN_READ_LTV, pcan_p, &radio_status)) { 1174 PCANDBG((CE_NOTE, "pcan: bad radio status %x\n", pkt_len)); 1175 } else { 1176 PCANDBG((CE_NOTE, "pcan: radio status:\n")); 1177 } 1178 #endif /* PCAN_SEND_DEBUG */ 1179 if (r) 1180 return (PCAN_FAIL); 1181 else { 1182 freemsg(mblk_p); 1183 return (PCAN_SUCCESS); 1184 } 1185 } 1186 1187 /* 1188 * send a packet out for PCI/MiniPCI card 1189 */ 1190 static int 1191 pcian_send(pcan_maci_t *pcan_p, mblk_t *mblk_p) 1192 { 1193 char *buf; 1194 uint16_t pkt_len = msgdsize(mblk_p), ring_idx; 1195 uint32_t i; 1196 struct ieee80211_frame *wh; 1197 struct an_card_tx_desc an_tx_desc; 1198 1199 ring_idx = pcan_p->pcan_txring.an_tx_prod; 1200 1201 mutex_enter(&pcan_p->pcan_glock); 1202 if (!(pcan_p->pcan_flag & PCAN_CARD_LINKUP)) { /* link down */ 1203 mutex_exit(&pcan_p->pcan_glock); 1204 pcan_p->glds_nocarrier++; 1205 freemsg(mblk_p); 1206 return (PCAN_SUCCESS); /* drop packet */ 1207 } 1208 mutex_exit(&pcan_p->pcan_glock); 1209 if (pullupmsg(mblk_p, -1) == 0) { 1210 cmn_err(CE_NOTE, "pcan(pci) send: pullupmsg failed\n"); 1211 freemsg(mblk_p); 1212 return (PCAN_SUCCESS); /* drop packet */ 1213 } 1214 wh = (struct ieee80211_frame *)mblk_p->b_rptr; 1215 1216 mutex_enter(&pcan_p->pcan_txring.an_tx_lock); 1217 if ((pcan_p->pcan_flag & PCAN_CARD_SEND) && 1218 (ring_idx == pcan_p->pcan_txring.an_tx_cons)) { 1219 pcan_p->glds_noxmtbuf++; 1220 pcan_p->pcan_reschedule_need = B_TRUE; 1221 mutex_exit(&pcan_p->pcan_txring.an_tx_lock); 1222 return (PCAN_FAIL); 1223 } 1224 mutex_exit(&pcan_p->pcan_txring.an_tx_lock); 1225 1226 #ifdef DEBUG 1227 if (pcan_debug & PCAN_DBG_SEND) { 1228 cmn_err(CE_NOTE, "pcan(pci) send: packet from plugin"); 1229 for (i = 0; i < MBLKL(mblk_p); i++) 1230 cmn_err(CE_NOTE, "%x: %x\n", i, 1231 *((unsigned char *)mblk_p->b_rptr + i)); 1232 } 1233 #endif 1234 mutex_enter(&pcan_p->pcan_glock); 1235 1236 buf = pcan_p->pcan_tx[ring_idx].dma_virtaddr; 1237 bzero(buf, AN_TX_BUFFER_SIZE); 1238 1239 /* 1240 * mblk sent down from plugin includes station mode 802.11 frame and 1241 * llc, so we here need to remove them and add an ethernet header. 1242 */ 1243 *((uint16_t *)(buf + 8)) = htons(AN_TXCTL_8023); 1244 pkt_len = pkt_len - (sizeof (*wh) + sizeof (struct ieee80211_llc)) 1245 + 2; 1246 bcopy(wh->i_addr3, buf + 0x38, ETHERADDRL); /* dst macaddr */ 1247 bcopy(wh->i_addr2, buf + 0x3e, ETHERADDRL); /* src macaddr */ 1248 *((uint16_t *)(buf + 0x36)) = pkt_len; 1249 bcopy(mblk_p->b_rptr + sizeof (*wh) + sizeof (struct ieee80211_llc) 1250 - 2, buf + 0x44, pkt_len); 1251 1252 #ifdef DEBUG 1253 if (pcan_debug & PCAN_DBG_SEND) { 1254 cmn_err(CE_NOTE, "pcan(pci) send: packet to hardware " 1255 "pkt_len=%x", pkt_len); 1256 for (i = 0; i < pkt_len + 14; i++) 1257 cmn_err(CE_NOTE, "%x: %x\n", i, 1258 *((unsigned char *)buf + 0x36 + i)); 1259 } 1260 #endif 1261 bzero(&an_tx_desc, sizeof (an_tx_desc)); 1262 an_tx_desc.an_offset = 0; 1263 an_tx_desc.an_eoc = (ring_idx == (AN_MAX_TX_DESC-1) ? 1 : 0); 1264 an_tx_desc.an_valid = 1; 1265 an_tx_desc.an_len = 0x44 + pkt_len; 1266 an_tx_desc.an_phys = pcan_p->pcan_tx[ring_idx].dma_physaddr; 1267 for (i = 0; i < sizeof (an_tx_desc) / 4; i++) { 1268 PCAN_AUX_PUT32(pcan_p, AN_TX_DESC_OFFSET + 1269 (ring_idx * sizeof (an_tx_desc)) + (i * 4), 1270 ((uint32_t *)&an_tx_desc)[i]); 1271 } 1272 1273 mutex_enter(&pcan_p->pcan_txring.an_tx_lock); 1274 pcan_p->pcan_txring.an_tx_prod = (ring_idx + 1) % AN_MAX_TX_DESC; 1275 pcan_p->pcan_flag |= PCAN_CARD_SEND; 1276 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_ALLOC); 1277 mutex_exit(&pcan_p->pcan_txring.an_tx_lock); 1278 1279 freemsg(mblk_p); 1280 mutex_exit(&pcan_p->pcan_glock); 1281 return (PCAN_SUCCESS); 1282 } 1283 1284 static mblk_t * 1285 pcan_tx(void *arg, mblk_t *mp) 1286 { 1287 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 1288 mblk_t *next; 1289 int ret = 0; 1290 1291 ASSERT(mp != NULL); 1292 mutex_enter(&pcan_p->pcan_glock); 1293 if ((pcan_p->pcan_flag & (PCAN_CARD_LINKUP | PCAN_CARD_READY)) != 1294 (PCAN_CARD_LINKUP | PCAN_CARD_READY)) { 1295 mutex_exit(&pcan_p->pcan_glock); 1296 freemsgchain(mp); 1297 return (NULL); 1298 } 1299 mutex_exit(&pcan_p->pcan_glock); 1300 while (mp != NULL) { 1301 next = mp->b_next; 1302 mp->b_next = NULL; 1303 1304 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 1305 ret = pcian_send(pcan_p, mp); 1306 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) { 1307 ret = pcan_send(pcan_p, mp); 1308 } 1309 if (ret) { 1310 mp->b_next = next; 1311 break; 1312 } 1313 mp = next; 1314 } 1315 return (mp); 1316 } 1317 1318 /* 1319 * this driver is porting from freebsd, the code in freebsd 1320 * doesn't show how to set promiscous mode. 1321 */ 1322 /*ARGSUSED*/ 1323 static int 1324 pcan_prom(void *arg, boolean_t on) 1325 { 1326 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 1327 int ret = PCAN_SUCCESS; 1328 1329 mutex_enter(&pcan_p->pcan_glock); 1330 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) { 1331 ret = PCAN_FAIL; 1332 } 1333 mutex_exit(&pcan_p->pcan_glock); 1334 return (ret); 1335 } 1336 1337 /*ARGSUSED*/ 1338 static int 1339 pcan_gstat(void *arg, uint_t statitem, uint64_t *val) 1340 { 1341 uint16_t i; 1342 int ret = PCAN_SUCCESS; 1343 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 1344 uint64_t *cntr_p = pcan_p->pcan_cntrs_s; 1345 1346 PCANDBG((CE_NOTE, "pcan: gstat called\n")); 1347 1348 mutex_enter(&pcan_p->pcan_glock); 1349 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) { 1350 ret = PCAN_FAIL; 1351 goto done; 1352 } 1353 if (pcan_get_ltv(pcan_p, sizeof (pcan_p->an_stats), 1354 AN_RID_16BITS_DELTACLR, (uint16_t *)&pcan_p->an_stats)) { 1355 cmn_err(CE_WARN, "pcan kstat: get ltv(32 delta statistics)" 1356 " failed \n"); 1357 ret = PCAN_FAIL; 1358 goto done; 1359 } 1360 for (i = 0; i < ANC_STAT_CNT; i++) { 1361 cntr_p[i] += *((uint16_t *)&pcan_p->an_stats + 1 + i); 1362 } 1363 if (pcan_status_ltv(PCAN_READ_LTV, pcan_p, &pcan_p->an_status)) { 1364 cmn_err(CE_WARN, "pcan kstat: read status failed \n"); 1365 ret = PCAN_FAIL; 1366 goto done; 1367 } 1368 1369 switch (statitem) { 1370 case MAC_STAT_IFSPEED: 1371 *val = 500000 * pcan_p->an_status.an_cur_tx_rate; 1372 break; 1373 case MAC_STAT_NOXMTBUF: 1374 *val = pcan_p->glds_noxmtbuf; 1375 break; 1376 case MAC_STAT_NORCVBUF: 1377 *val = pcan_p->glds_norcvbuf; 1378 break; 1379 case MAC_STAT_IERRORS: 1380 *val = cntr_p[ANC_RX_OVERRUNS] + 1381 cntr_p[ANC_RX_PLCP_CSUM_ERRS] + 1382 cntr_p[ANC_RX_PLCP_FORMAT_ERRS] + 1383 cntr_p[ANC_RX_PLCP_LEN_ERRS] + 1384 cntr_p[ANC_RX_MAC_CRC_ERRS] + 1385 cntr_p[ANC_RX_WEP_ERRS]; 1386 break; 1387 case MAC_STAT_OERRORS: 1388 *val = cntr_p[ANC_TX_HOST_FAILED]; 1389 break; 1390 case MAC_STAT_RBYTES: 1391 *val = cntr_p[ANC_HOST_RX_BYTES]; 1392 break; 1393 case MAC_STAT_IPACKETS: 1394 *val = cntr_p[ANC_RX_HOST_UCASTS]; 1395 break; 1396 case MAC_STAT_OBYTES: 1397 *val = cntr_p[ANC_HOST_TX_BYTES]; 1398 break; 1399 case MAC_STAT_OPACKETS: 1400 *val = cntr_p[ANC_TX_HOST_UCASTS]; 1401 break; 1402 case WIFI_STAT_TX_FAILED: 1403 *val = cntr_p[ANC_TX_HOST_FAILED]; 1404 break; 1405 case WIFI_STAT_TX_RETRANS: 1406 *val = cntr_p[ANC_HOST_RETRIES]; 1407 break; 1408 case WIFI_STAT_FCS_ERRORS: 1409 *val = cntr_p[ANC_RX_MAC_CRC_ERRS]; 1410 break; 1411 case WIFI_STAT_WEP_ERRORS: 1412 *val = cntr_p[ANC_RX_WEP_ERRS]; 1413 break; 1414 case WIFI_STAT_MCAST_TX: 1415 *val = cntr_p[ANC_TX_HOST_MCASTS]; 1416 break; 1417 case WIFI_STAT_MCAST_RX: 1418 *val = cntr_p[ANC_RX_HOST_MCASTS]; 1419 break; 1420 case WIFI_STAT_TX_FRAGS: 1421 case WIFI_STAT_RX_FRAGS: 1422 *val = 0; 1423 break; 1424 case WIFI_STAT_RTS_SUCCESS: 1425 *val = cntr_p[ANC_TX_RTS_OK]; 1426 break; 1427 case WIFI_STAT_RTS_FAILURE: 1428 *val = cntr_p[ANC_NO_CTS]; 1429 break; 1430 case WIFI_STAT_ACK_FAILURE: 1431 *val = cntr_p[ANC_NO_ACK]; 1432 break; 1433 case WIFI_STAT_RX_DUPS: 1434 *val = cntr_p[ANC_RX_DUPS]; 1435 break; 1436 default: 1437 ret = ENOTSUP; 1438 } 1439 1440 1441 done: 1442 mutex_exit(&pcan_p->pcan_glock); 1443 return (ret); 1444 } 1445 1446 /* 1447 * this driver is porting from freebsd, the code in freebsd 1448 * doesn't show how to set multi address. 1449 */ 1450 /*ARGSUSED*/ 1451 static int 1452 pcan_sdmulti(void *arg, boolean_t add, const uint8_t *eth_p) 1453 { 1454 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 1455 1456 mutex_enter(&pcan_p->pcan_glock); 1457 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) { 1458 mutex_exit(&pcan_p->pcan_glock); 1459 return (PCAN_FAIL); 1460 } 1461 mutex_exit(&pcan_p->pcan_glock); 1462 return (PCAN_SUCCESS); 1463 } 1464 1465 static uint_t 1466 pcan_info_softint(caddr_t arg) 1467 { 1468 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 1469 wifi_data_t wd = { 0 }; 1470 uint16_t link; 1471 uint32_t link_up; 1472 1473 mutex_enter(&pcan_p->pcan_glock); 1474 if (pcan_p->pcan_info_softint_pending != 1) { 1475 mutex_exit(&pcan_p->pcan_glock); 1476 return (DDI_INTR_UNCLAIMED); 1477 } 1478 1479 PCAN_READ(pcan_p, AN_LINKSTAT(pcan_p), link); 1480 link_up = pcan_p->pcan_flag & PCAN_CARD_LINKUP; 1481 if ((link == AN_LINKSTAT_ASSOCIATED) && !link_up) { 1482 pcan_p->pcan_flag |= PCAN_CARD_LINKUP; 1483 mutex_exit(&pcan_p->pcan_glock); 1484 if (pcan_p->pcan_connect_timeout_id != 0) { 1485 (void) untimeout(pcan_p->pcan_connect_timeout_id); 1486 pcan_p->pcan_connect_timeout_id = 0; 1487 } 1488 mac_link_update(GLD3(pcan_p), LINK_STATE_UP); 1489 mutex_enter(&pcan_p->pcan_glock); 1490 (void) pcan_status_ltv(PCAN_READ_LTV, pcan_p, 1491 &pcan_p->an_status); 1492 bcopy(pcan_p->an_status.an_cur_bssid, wd.wd_bssid, 6); 1493 wd.wd_secalloc = WIFI_SEC_NONE; 1494 wd.wd_opmode = IEEE80211_M_STA; 1495 (void) mac_pdata_update(pcan_p->pcan_mh, &wd, 1496 sizeof (wd)); 1497 #ifdef DEBUG 1498 if (pcan_debug & PCAN_DBG_LINKINFO) { 1499 cmn_err(CE_NOTE, "pcan: link Up, chan=%d, " 1500 "ssid=\"%s\"" 1501 " (%02x:%02x:%02x:%02x:%02x:%02x)\n", 1502 pcan_p->an_status.an_channel_set, 1503 pcan_p->an_status.an_ssid, 1504 pcan_p->an_status.an_cur_bssid[0], 1505 pcan_p->an_status.an_cur_bssid[1], 1506 pcan_p->an_status.an_cur_bssid[2], 1507 pcan_p->an_status.an_cur_bssid[3], 1508 pcan_p->an_status.an_cur_bssid[4], 1509 pcan_p->an_status.an_cur_bssid[5]); 1510 } 1511 #endif 1512 } 1513 if ((link != AN_LINKSTAT_ASSOCIATED) && link_up) { 1514 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP; 1515 #ifdef DEBUG 1516 if (pcan_debug & PCAN_DBG_LINKINFO) { 1517 cmn_err(CE_NOTE, "pcan: link Down 0x%x\n", link); 1518 } 1519 #endif 1520 if (link != AN_LINKSTAT_SYNCLOST_HOSTREQ) { 1521 pcan_p->pcan_connect_timeout_id = 1522 timeout(pcan_connect_timeout, 1523 pcan_p, drv_usectohz(1000)); 1524 } 1525 mutex_exit(&pcan_p->pcan_glock); 1526 mac_link_update(GLD3(pcan_p), LINK_STATE_DOWN); 1527 mutex_enter(&pcan_p->pcan_glock); 1528 } 1529 1530 pcan_p->pcan_info_softint_pending = 0; 1531 mutex_exit(&pcan_p->pcan_glock); 1532 return (DDI_INTR_CLAIMED); 1533 } 1534 1535 static uint_t 1536 pcan_intr(caddr_t arg) 1537 { 1538 uint16_t stat; 1539 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 1540 1541 mutex_enter(&pcan_p->pcan_glock); 1542 if ((pcan_p->pcan_flag & (PCAN_CARD_READY | PCAN_CARD_INTREN)) != 1543 (PCAN_CARD_READY | PCAN_CARD_INTREN)) { 1544 mutex_exit(&pcan_p->pcan_glock); 1545 return (DDI_INTR_UNCLAIMED); 1546 } 1547 PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat); 1548 1549 if (!(stat & AN_INTRS(pcan_p)) || stat == AN_EV_ALL) { 1550 mutex_exit(&pcan_p->pcan_glock); 1551 return (DDI_INTR_UNCLAIMED); 1552 } 1553 1554 PCAN_DISABLE_INTR(pcan_p); 1555 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), ~AN_INTRS(pcan_p)); 1556 1557 PCANDBG((CE_NOTE, "pcan intr: stat=%x pcan_flags=%x\n", stat, 1558 pcan_p->pcan_flag)); 1559 1560 if (stat & AN_EV_AWAKE) { 1561 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_AWAKE); 1562 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_AWAKE); 1563 } 1564 if (stat & AN_EV_LINKSTAT) { 1565 pcan_p->pcan_info_softint_pending = 1; 1566 ddi_trigger_softintr(pcan_p->pcan_info_softint_id); 1567 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_LINKSTAT); 1568 } 1569 if (stat & AN_EV_RX) { 1570 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 1571 pcian_rcv(pcan_p); 1572 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) { 1573 pcan_rcv(pcan_p); 1574 } 1575 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_RX); 1576 } 1577 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 1578 if (stat & AN_EV_TX_CPY) { 1579 (void) pcan_txdone(pcan_p, stat & AN_EV_TX_CPY); 1580 if (pcan_p->pcan_reschedule_need == B_TRUE) { 1581 mac_tx_update(GLD3(pcan_p)); 1582 pcan_p->pcan_reschedule_need = B_FALSE; 1583 } 1584 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_TX_CPY); 1585 } 1586 } 1587 if (stat & AN_EV_TX) { 1588 if (pcan_txdone(pcan_p, stat & AN_EV_TX) == 0) { 1589 if (pcan_p->pcan_reschedule_need == B_TRUE) { 1590 mac_tx_update(GLD3(pcan_p)); 1591 pcan_p->pcan_reschedule_need = B_FALSE; 1592 } 1593 } 1594 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_TX); 1595 } 1596 if (stat & AN_EV_TX_EXC) { 1597 if (pcan_txdone(pcan_p, stat & AN_EV_TX_EXC) == 0) { 1598 if (pcan_p->pcan_reschedule_need == B_TRUE) { 1599 mutex_exit(&pcan_p->pcan_glock); 1600 mac_tx_update(GLD3(pcan_p)); 1601 mutex_enter(&pcan_p->pcan_glock); 1602 pcan_p->pcan_reschedule_need = B_FALSE; 1603 } 1604 } 1605 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_TX_EXC); 1606 } 1607 if (stat & AN_EV_ALLOC) { 1608 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_ALLOC); 1609 PCANDBG((CE_NOTE, "pcan intr: nicmem alloc done\n")); 1610 } 1611 if (stat & AN_EV_MIC) { 1612 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_MIC); 1613 } 1614 PCAN_ENABLE_INTR(pcan_p); 1615 mutex_exit(&pcan_p->pcan_glock); 1616 return (DDI_INTR_CLAIMED); 1617 } 1618 1619 static uint_t 1620 pcan_intr_hi(caddr_t arg) 1621 { 1622 uint16_t stat; 1623 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 1624 1625 mutex_enter(&pcan_p->pcan_glock); 1626 if ((pcan_p->pcan_flag & (PCAN_CARD_READY | PCAN_CARD_INTREN)) != 1627 (PCAN_CARD_READY | PCAN_CARD_INTREN)) { 1628 mutex_exit(&pcan_p->pcan_glock); 1629 return (DDI_INTR_UNCLAIMED); 1630 } 1631 PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat); 1632 PCANDBG((CE_NOTE, "pcan intr(hi): stat=%x pcan_flags=%x\n", stat, 1633 pcan_p->pcan_flag)); 1634 1635 if (!(stat & AN_INTRS(pcan_p)) || stat == AN_EV_ALL) { 1636 mutex_exit(&pcan_p->pcan_glock); 1637 return (DDI_INTR_UNCLAIMED); 1638 } 1639 /* disable interrupt without ack */ 1640 PCAN_WRITE(pcan_p, AN_INT_EN(pcan_p), 0); 1641 mutex_exit(&pcan_p->pcan_glock); 1642 ddi_trigger_softintr(pcan_p->pcan_softint_id); 1643 return (DDI_INTR_CLAIMED); 1644 } 1645 1646 /* 1647 * retrieve data from pccard 1648 */ 1649 static void 1650 pcan_rcv(pcan_maci_t *pcan_p) 1651 { 1652 uint16_t id, off, ret, data_len, pkt_stat, frm_ctl; 1653 an_rxfrm_t frm; 1654 struct ieee80211_llc *llc; 1655 1656 mblk_t *mp = allocb(PCAN_NICMEM_SZ, BPRI_MED); 1657 if (!mp) { 1658 cmn_err(CE_WARN, "pcan: failed to alloc rcv buf"); 1659 pcan_p->glds_norcvbuf++; 1660 return; 1661 } 1662 ASSERT(mp->b_rptr == mp->b_wptr); 1663 1664 PCAN_READ(pcan_p, AN_RX_FID, id); 1665 if (id == AN_INVALID_FID) { 1666 PCANDBG((CE_NOTE, "pcan rcv: can't get rx_fid\n")); 1667 pcan_p->glds_norcvbuf++; 1668 ret = PCAN_FAIL; 1669 goto done; 1670 } 1671 if (ret = RDCH0(pcan_p, id, 0, (uint16_t *)&frm, sizeof (frm))) { 1672 PCANDBG((CE_NOTE, "pcan rcv: read frm err %x\n", ret)); 1673 goto done; 1674 } 1675 off = sizeof (frm); 1676 if (frm.an_rx_status) { 1677 PCANDBG((CE_NOTE, "pcan rcv: err stat %x\n", frm.an_rx_status)); 1678 ret = frm.an_rx_status; 1679 goto done; 1680 } 1681 PCANDBG((CE_NOTE, "pcan rcv: payload_len=%x gap_len=%x\n", 1682 frm.an_rx_payload_len, frm.an_gaplen)); 1683 if (frm.an_rx_payload_len > PCAN_NICMEM_SZ || 1684 frm.an_gaplen > AN_RXGAP_MAX) { 1685 PCANDBG((CE_NOTE, "pcan rcv: bad len\n")); 1686 ret = PCAN_FAIL; 1687 goto done; 1688 } 1689 if (ret = RDCH0(pcan_p, id, off, &pkt_stat, sizeof (pkt_stat))) { 1690 PCANDBG((CE_NOTE, "pcan rcv: pkt status err %x\n", ret)); 1691 ret = PCAN_FAIL; 1692 goto done; 1693 } 1694 off += sizeof (pkt_stat); 1695 if (ret = RDCH0(pcan_p, id, off, &data_len, sizeof (data_len))) { 1696 PCANDBG((CE_NOTE, "pcan rcv: payload len err %x\n", ret)); 1697 ret = PCAN_FAIL; 1698 goto done; 1699 } 1700 off += sizeof (data_len); 1701 off += ETHERADDRL << 1; 1702 PCANDBG((CE_NOTE, "pcan rcv: pkt_stat=%x payload_len=%x+c off=%x\n", 1703 pkt_stat, data_len, off)); 1704 1705 #ifdef DEBUG 1706 if (pcan_debug & PCAN_DBG_RCV) { 1707 int i; 1708 cmn_err(CE_NOTE, "pcan rcv: frm header\n"); 1709 for (i = 0; i < sizeof (frm); i++) 1710 cmn_err(CE_NOTE, "%x: %x\n", i, 1711 *((uint8_t *)&frm + i)); 1712 } 1713 #endif 1714 /* 1715 * this driver deal with WEP by itself. so plugin always thinks no wep. 1716 */ 1717 frm.an_frame_ctl &= ~(IEEE80211_FC1_WEP << 8); 1718 frm_ctl = frm.an_frame_ctl; 1719 PCAN_SWAP16((uint16_t *)&frm.an_frame_ctl, 1720 sizeof (struct ieee80211_frame)); 1721 /* 1722 * discard those frames which are not from the AP we connect or 1723 * without 'ap->sta' direction 1724 */ 1725 if (((pcan_p->an_config.an_opmode == AN_OPMODE_INFR_STATION)) && 1726 ((((frm_ctl >> 8) & IEEE80211_FC1_DIR_MASK) != 1727 IEEE80211_FC1_DIR_FROMDS) || 1728 bcmp(pcan_p->an_status.an_cur_bssid, frm.an_addr2, 6) != 0)) { 1729 ret = PCAN_FAIL; 1730 goto done; 1731 } 1732 bcopy(&frm.an_frame_ctl, mp->b_wptr, 1733 sizeof (struct ieee80211_frame)); 1734 mp->b_wptr += sizeof (struct ieee80211_frame); 1735 1736 /* the plugin need a llc here */ 1737 llc = (struct ieee80211_llc *)mp->b_wptr; 1738 llc->illc_dsap = llc->illc_ssap = AN_SNAP_K1; 1739 llc->illc_control = AN_SNAP_CONTROL; 1740 bzero(llc->illc_oc, sizeof (llc->illc_oc)); 1741 mp->b_wptr += AN_SNAPHDR_LEN; 1742 1743 /* read in the rest of data */ 1744 data_len += data_len & 1; /* adjust to word boundary */ 1745 if (data_len > MBLKSIZE(mp)) { 1746 cmn_err(CE_NOTE, "pcan rcv: data over length%x\n", data_len); 1747 ret = PCAN_FAIL; 1748 goto done; 1749 } 1750 1751 if (ret = RDPKT(pcan_p, id, off, (uint16_t *)mp->b_wptr, data_len)) { 1752 PCANDBG((CE_NOTE, "pcan rcv: err read data %x\n", ret)); 1753 } 1754 done: 1755 if (ret) { 1756 PCANDBG((CE_NOTE, "pcan rcv: rd data %x\n", ret)); 1757 freemsg(mp); 1758 return; 1759 } 1760 mp->b_wptr += data_len; 1761 #ifdef DEBUG 1762 if (pcan_debug & PCAN_DBG_RCV) { 1763 int i; 1764 cmn_err(CE_NOTE, "pcan rcv: len=0x%x\n", data_len); 1765 for (i = 0; i < data_len + sizeof (frm); i++) 1766 cmn_err(CE_NOTE, "%x: %x\n", i, 1767 *((uint8_t *)mp->b_rptr + i)); 1768 } 1769 #endif 1770 mutex_exit(&pcan_p->pcan_glock); 1771 mac_rx(GLD3(pcan_p), NULL, mp); 1772 mutex_enter(&pcan_p->pcan_glock); 1773 } 1774 1775 /* 1776 * retrieve data from mini-pci card 1777 */ 1778 static void 1779 pcian_rcv(pcan_maci_t *pcan_p) 1780 { 1781 struct an_card_rx_desc an_rx_desc; 1782 char *buf; 1783 uint16_t ret = 0, data_len; 1784 int i, j; 1785 struct ieee80211_frame *frm; 1786 struct ieee80211_llc *llc; 1787 1788 mblk_t *mp = allocb(AN_RX_BUFFER_SIZE, BPRI_MED); 1789 if (!mp) { 1790 cmn_err(CE_WARN, "pcan(pci): failed to alloc rcv buf"); 1791 pcan_p->glds_norcvbuf++; 1792 return; 1793 } 1794 ASSERT(mp->b_rptr == mp->b_wptr); 1795 1796 for (i = 0; i < sizeof (an_rx_desc) / 4; i++) 1797 PCAN_AUX_GET32(pcan_p, AN_RX_DESC_OFFSET + (i * 4), 1798 ((uint32_t *)&an_rx_desc)[i]); 1799 if (an_rx_desc.an_done && !an_rx_desc.an_valid) { 1800 buf = pcan_p->pcan_rx[0].dma_virtaddr; 1801 data_len = an_rx_desc.an_len; 1802 #ifdef DEBUG 1803 if (pcan_debug & PCAN_DBG_RCV) { 1804 cmn_err(CE_NOTE, "pcan(pci) rcv: data_len=%x", 1805 data_len); 1806 for (j = 0; j < data_len + 14; j++) 1807 cmn_err(CE_NOTE, "pcan_rcv %d: %x", j, 1808 *((uint8_t *)buf + j)); 1809 } 1810 #endif 1811 if (data_len > MBLKSIZE(mp)) { 1812 cmn_err(CE_NOTE, "pcan(pci) rcv: data over length%x\n", 1813 data_len); 1814 ret = PCAN_FAIL; 1815 goto done; 1816 } 1817 /* 1818 * minipci card receive an ethernet frame, so assembly a 802.11 1819 * frame here manually. 1820 */ 1821 frm = (struct ieee80211_frame *)mp->b_wptr; 1822 bzero(frm, sizeof (*frm)); 1823 frm->i_fc[0] |= IEEE80211_FC0_TYPE_DATA; 1824 frm->i_fc[1] |= IEEE80211_FC1_DIR_FROMDS; 1825 bcopy(pcan_p->an_status.an_cur_bssid, frm->i_addr2, 6); 1826 bcopy(buf, frm->i_addr1, 6); 1827 bcopy(buf + 6, frm->i_addr3, 6); 1828 mp->b_wptr += sizeof (struct ieee80211_frame); 1829 1830 llc = (struct ieee80211_llc *)mp->b_wptr; 1831 llc->illc_dsap = llc->illc_ssap = AN_SNAP_K1; 1832 llc->illc_control = AN_SNAP_CONTROL; 1833 bzero(llc->illc_oc, sizeof (llc->illc_oc)); 1834 mp->b_wptr += AN_SNAPHDR_LEN; 1835 1836 bcopy(buf + 12, mp->b_wptr, data_len); 1837 mp->b_wptr += data_len; 1838 #ifdef DEBUG 1839 if (pcan_debug & PCAN_DBG_RCV) { 1840 int i; 1841 cmn_err(CE_NOTE, "pcan(pci) rcv: len=0x%x\n", data_len); 1842 for (i = 0; i < data_len + sizeof (*frm) 1843 + sizeof (*llc); i++) 1844 cmn_err(CE_NOTE, "%x: %x\n", i, 1845 *((uint8_t *)mp->b_rptr + i)); 1846 } 1847 #endif 1848 mutex_exit(&pcan_p->pcan_glock); 1849 mac_rx(GLD3(pcan_p), NULL, mp); 1850 mutex_enter(&pcan_p->pcan_glock); 1851 } 1852 done: 1853 bzero(&an_rx_desc, sizeof (an_rx_desc)); 1854 an_rx_desc.an_valid = 1; 1855 an_rx_desc.an_len = AN_RX_BUFFER_SIZE; 1856 an_rx_desc.an_done = 0; 1857 an_rx_desc.an_phys = pcan_p->pcan_rx[0].dma_physaddr; 1858 1859 for (i = 0; i < sizeof (an_rx_desc) / 4; i++) 1860 PCAN_AUX_PUT32(pcan_p, AN_RX_DESC_OFFSET + (i * 4), 1861 ((uint32_t *)&an_rx_desc)[i]); 1862 if (ret) { 1863 freemsg(mp); 1864 } 1865 } 1866 1867 /*ARGSUSED*/ 1868 static uint32_t 1869 pcan_txdone(pcan_maci_t *pcan_p, uint16_t err) 1870 { 1871 uint16_t fid, i, ring_idx; 1872 uint32_t ret = 0; 1873 1874 PCAN_READ(pcan_p, AN_TX_CMP_FID(pcan_p), fid); 1875 mutex_enter(&pcan_p->pcan_txring.an_tx_lock); 1876 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 1877 if (pcan_p->pcan_flag & PCAN_CARD_SEND) { 1878 ring_idx = pcan_p->pcan_txring.an_tx_cons; 1879 pcan_p->pcan_txring.an_tx_cons = 1880 (ring_idx + 1) % AN_MAX_TX_DESC; 1881 if (pcan_p->pcan_txring.an_tx_prod == 1882 pcan_p->pcan_txring.an_tx_cons) { 1883 pcan_p->pcan_flag &= ~PCAN_CARD_SEND; 1884 } 1885 } 1886 ret = 0; 1887 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) { 1888 for (i = 0; i < AN_TX_RING_CNT; i++) { 1889 if (fid == pcan_p->pcan_txring.an_tx_ring[i]) { 1890 pcan_p->pcan_txring.an_tx_ring[i] = 0; 1891 break; 1892 } 1893 } 1894 pcan_p->pcan_txring.an_tx_cons = 1895 (pcan_p->pcan_txring.an_tx_cons + 1) & AN_TX_RING_MASK; 1896 ret = (i == AN_TX_RING_CNT ? 1 : 0); 1897 } 1898 mutex_exit(&pcan_p->pcan_txring.an_tx_lock); 1899 return (ret); 1900 } 1901 1902 /* 1903 * delay in which the mutex is not hold. 1904 * assuming the mutex has already been hold. 1905 */ 1906 static void 1907 pcan_delay(pcan_maci_t *pcan_p, clock_t microsecs) 1908 { 1909 ASSERT(mutex_owned(&pcan_p->pcan_glock)); 1910 1911 mutex_exit(&pcan_p->pcan_glock); 1912 delay(drv_usectohz(microsecs)); 1913 mutex_enter(&pcan_p->pcan_glock); 1914 } 1915 1916 static void 1917 pcan_reset_backend(pcan_maci_t *pcan_p, int timeout) 1918 { 1919 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 1920 (void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0); 1921 PCAN_DISABLE_INTR_CLEAR(pcan_p); 1922 (void) pcan_set_cmd(pcan_p, AN_CMD_FW_RESTART, 0); 1923 (void) pcan_set_cmd(pcan_p, AN_CMD_NOOP2, 0); 1924 (void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0); 1925 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) { 1926 (void) pcan_set_cmd0(pcan_p, AN_CMD_DISABLE, 0, 0, 0); 1927 (void) pcan_set_cmd0(pcan_p, AN_CMD_NOOP2, 0, 0, 0); 1928 PCAN_WRITE(pcan_p, AN_COMMAND(pcan_p), AN_CMD_FW_RESTART); 1929 pcan_delay(pcan_p, timeout); /* wait for firmware restart */ 1930 1931 (void) pcan_set_cmd(pcan_p, AN_CMD_NOOP, 0); 1932 (void) pcan_set_cmd0(pcan_p, AN_CMD_DISABLE, 0, 0, 0); 1933 1934 PCAN_DISABLE_INTR_CLEAR(pcan_p); 1935 } 1936 } 1937 1938 /* 1939 * set command without the need of ACK. 1940 */ 1941 static uint16_t 1942 pcan_set_cmd0(pcan_maci_t *pcan_p, uint16_t cmd, uint16_t p0, 1943 uint16_t p1, uint16_t p2) 1944 { 1945 int i; 1946 uint16_t stat, r0, r1, r2; 1947 1948 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 1949 for (i = 0; i < AN_TIMEOUT; i++) { 1950 PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat); 1951 if (!(stat & AN_CMD_BUSY)) 1952 break; 1953 } 1954 if (i == AN_TIMEOUT) { 1955 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), 1956 AN_EV_CLR_STUCK_BUSY); 1957 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD); 1958 drv_usecwait(10); 1959 } 1960 PCAN_WRITE(pcan_p, AN_PARAM0(pcan_p), p0); 1961 PCAN_WRITE(pcan_p, AN_PARAM1(pcan_p), p1); 1962 PCAN_WRITE(pcan_p, AN_PARAM2(pcan_p), p2); 1963 } 1964 PCAN_WRITE(pcan_p, AN_COMMAND(pcan_p), cmd); 1965 for (i = 0; i < AN_TIMEOUT; i++) { 1966 PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat); 1967 if (stat & AN_EV_CMD) 1968 break; 1969 } 1970 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 1971 PCAN_READ(pcan_p, AN_RESP0(pcan_p), r0); 1972 PCAN_READ(pcan_p, AN_RESP1(pcan_p), r1); 1973 PCAN_READ(pcan_p, AN_RESP2(pcan_p), r2); 1974 PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat); 1975 if (stat & AN_CMD_BUSY) 1976 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), 1977 AN_EV_CLR_STUCK_BUSY); 1978 PCANDBG((CE_NOTE, "pcan set_cmd0: " 1979 "stat=%x, r0=%x, r1=%x, r2=%x\n", 1980 stat, r0, r1, r2)); 1981 } 1982 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD); 1983 return (i == AN_TIMEOUT ? PCAN_TIMEDOUT_ACCESS : PCAN_SUCCESS); 1984 } 1985 1986 static uint16_t 1987 pcan_set_cmd(pcan_maci_t *pcan_p, uint16_t cmd, uint16_t param) 1988 { 1989 int i; 1990 uint16_t stat, r0, r1, r2; 1991 uint16_t ret; 1992 1993 if (((cmd == AN_CMD_ENABLE) && 1994 ((pcan_p->pcan_flag & PCAN_ENABLED) != 0)) || 1995 ((cmd == AN_CMD_DISABLE) && 1996 ((pcan_p->pcan_flag & PCAN_ENABLED) == 0))) 1997 return (PCAN_SUCCESS); 1998 for (i = 0; i < AN_TIMEOUT; i++) { 1999 PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat); 2000 if (!(stat & AN_CMD_BUSY)) { 2001 break; 2002 } 2003 } 2004 if (i == AN_TIMEOUT) { 2005 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CLR_STUCK_BUSY); 2006 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD); 2007 drv_usecwait(10); 2008 } 2009 2010 PCAN_WRITE(pcan_p, AN_PARAM0(pcan_p), param); 2011 PCAN_WRITE(pcan_p, AN_PARAM1(pcan_p), 0); 2012 PCAN_WRITE(pcan_p, AN_PARAM2(pcan_p), 0); 2013 PCAN_WRITE(pcan_p, AN_COMMAND(pcan_p), cmd); 2014 2015 for (i = 0; i < AN_TIMEOUT; i++) { 2016 PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat); 2017 if (stat & AN_EV_CMD) { 2018 break; 2019 } 2020 PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat); 2021 if (stat == cmd) 2022 PCAN_WRITE(pcan_p, AN_COMMAND(pcan_p), cmd); 2023 } 2024 if (i == AN_TIMEOUT) { 2025 if (cmd == AN_CMD_FW_RESTART) { 2026 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD); 2027 return (PCAN_SUCCESS); 2028 } 2029 #ifdef DEBUG 2030 if (pcan_debug & PCAN_DBG_CMD) { 2031 cmn_err(CE_WARN, "pcan set_cmd: %x timeout stat=%x\n", 2032 cmd, stat); 2033 } 2034 #endif 2035 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD); 2036 return (PCAN_TIMEDOUT_CMD); 2037 } 2038 2039 for (i = 0; i < AN_TIMEOUT; i++) { 2040 PCAN_READ(pcan_p, AN_STATUS(pcan_p), stat); 2041 PCAN_READ(pcan_p, AN_RESP0(pcan_p), r0); 2042 PCAN_READ(pcan_p, AN_RESP1(pcan_p), r1); 2043 PCAN_READ(pcan_p, AN_RESP2(pcan_p), r2); 2044 if ((stat & AN_STAT_CMD_CODE) == (cmd & AN_STAT_CMD_CODE)) 2045 break; 2046 } 2047 if (cmd == AN_CMD_FW_RESTART) { 2048 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD); 2049 return (PCAN_SUCCESS); 2050 } 2051 if (i == AN_TIMEOUT) { 2052 #ifdef DEBUG 2053 if (pcan_debug & PCAN_DBG_CMD) { 2054 cmn_err(CE_WARN, "pcan set_cmd<%x,%x>: timeout " 2055 "%x,%x,%x,%x\n", cmd, param, stat, r0, r1, r2); 2056 } 2057 #endif 2058 ret = PCAN_TIMEDOUT_ACCESS; 2059 } else { 2060 if (stat & AN_STAT_CMD_RESULT) { 2061 #ifdef DEBUG 2062 if (pcan_debug & PCAN_DBG_CMD) { 2063 cmn_err(CE_WARN, "pcan set_cmd<%x,%x>: failed " 2064 "%x,%x,%x,%x\n", 2065 cmd, param, stat, r0, r1, r2); 2066 } 2067 #endif 2068 ret = PCAN_TIMEDOUT_ACCESS; 2069 } else { 2070 ret = PCAN_SUCCESS; 2071 } 2072 } 2073 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD); 2074 PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat); 2075 if (stat & AN_CMD_BUSY) 2076 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CLR_STUCK_BUSY); 2077 if (ret == PCAN_SUCCESS) { 2078 if (cmd == AN_CMD_ENABLE) 2079 pcan_p->pcan_flag |= PCAN_ENABLED; 2080 if (cmd == AN_CMD_DISABLE) 2081 pcan_p->pcan_flag &= (~PCAN_ENABLED); 2082 } 2083 return (ret); 2084 } 2085 2086 static uint16_t 2087 pcan_set_ch(pcan_maci_t *pcan_p, uint16_t type, uint16_t off, uint16_t channel) 2088 { 2089 int i; 2090 uint16_t stat, select, offset; 2091 2092 if (channel) { 2093 select = AN_SEL1; 2094 offset = AN_OFF1; 2095 } else { 2096 select = AN_SEL0; 2097 offset = AN_OFF0; 2098 } 2099 PCAN_WRITE(pcan_p, select, type); 2100 PCAN_WRITE(pcan_p, offset, off); 2101 for (i = 0; i < AN_TIMEOUT; i++) { 2102 PCAN_READ(pcan_p, offset, stat); 2103 if (!(stat & (AN_OFF_BUSY|AN_OFF_ERR))) 2104 break; 2105 } 2106 if (stat & (AN_OFF_BUSY|AN_OFF_ERR)) { /* time out */ 2107 PCANDBG((CE_WARN, "pcan: set_ch%d %x %x TO %x\n", 2108 channel, type, off, stat)); 2109 return (PCAN_TIMEDOUT_TARGET); 2110 } 2111 return (PCAN_SUCCESS); 2112 } 2113 2114 static uint16_t 2115 pcan_get_ltv(pcan_maci_t *pcan_p, uint16_t len, uint16_t type, uint16_t *val_p) 2116 { 2117 uint16_t stat; 2118 2119 PCANDBG((CE_NOTE, "pcan: get_ltv(%p,%x,%x,%p)\n", 2120 (void *)pcan_p, len, type, (void *)val_p)); 2121 ASSERT(!(len & 1)); 2122 2123 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 2124 uint32_t i; 2125 struct an_card_rid_desc an_rid_desc; 2126 struct an_ltv_gen *an_ltv; 2127 if (!pcan_p->pcan_cmd.dma_virtaddr) 2128 return (EIO); 2129 an_rid_desc.an_valid = 1; 2130 an_rid_desc.an_len = AN_RID_BUFFER_SIZE; 2131 an_rid_desc.an_rid = 0; 2132 an_rid_desc.an_phys = pcan_p->pcan_cmd.dma_physaddr; 2133 bzero(pcan_p->pcan_cmd.dma_virtaddr, AN_RID_BUFFER_SIZE); 2134 2135 for (i = 0; i < sizeof (an_rid_desc) / 4; i++) 2136 PCAN_AUX_PUT32(pcan_p, AN_HOST_DESC_OFFSET + i * 4, 2137 ((uint32_t *)&an_rid_desc)[i]); 2138 2139 if (pcan_set_cmd0(pcan_p, AN_CMD_ACCESS | 2140 AN_ACCESS_READ, type, 0, 0)) { 2141 cmn_err(CE_WARN, "pcan get_ltv: set cmd error"); 2142 return (EIO); 2143 } 2144 2145 an_ltv = (struct an_ltv_gen *)pcan_p->pcan_cmd.dma_virtaddr; 2146 #ifdef DEBUG 2147 if (pcan_debug & PCAN_DBG_INFO) { 2148 cmn_err(CE_NOTE, "pcan get_ltv: type=%x," 2149 "expected len=%d," "actual len=%d", 2150 type, len, an_ltv->an_len); 2151 for (i = 0; i < an_ltv->an_len; i++) 2152 cmn_err(CE_NOTE, "%d: %x", i, 2153 *(((uint8_t *)an_ltv) + i)); 2154 } 2155 #endif 2156 if (an_ltv->an_len != len) { 2157 PCANDBG((CE_WARN, "pcan get_ltv: rid=%x expected len=%d" 2158 "actual: len=%d", type, 2159 len, an_ltv->an_len)); 2160 /* return (EIO); */ 2161 } 2162 bcopy(an_ltv, val_p, len); 2163 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) { 2164 len >>= 1; /* convert bytes to 16-bit words */ 2165 2166 /* 1. select read mode */ 2167 if (stat = pcan_set_cmd(pcan_p, AN_CMD_ACCESS | 2168 AN_ACCESS_READ, type)) 2169 return (stat); 2170 2171 /* 2. select Buffer Access Path (channel) 1 for PIO */ 2172 if (stat = pcan_set_ch(pcan_p, type, 0, 1)) 2173 return (stat); 2174 2175 /* 3. read length */ 2176 PCAN_READ(pcan_p, AN_DATA1, stat); 2177 *val_p++ = stat; 2178 if (stat != (len << 1)) { 2179 PCANDBG((CE_NOTE, "pcan get_ltv[%x]:expect %x," 2180 "got %x\n", type, (len + 1) << 1, stat)); 2181 stat = (stat >> 1) - 1; 2182 len = MIN(stat, len); 2183 } 2184 /* 4. read value */ 2185 for (stat = 0; stat < len - 1; stat++, val_p++) { 2186 PCAN_READ_P(pcan_p, AN_DATA1, val_p, 1); 2187 } 2188 } 2189 return (PCAN_SUCCESS); 2190 } 2191 2192 static uint16_t 2193 pcan_put_ltv(pcan_maci_t *pcan_p, uint16_t len, uint16_t type, uint16_t *val_p) 2194 { 2195 uint16_t stat; 2196 int i; 2197 2198 ASSERT(!(len & 1)); 2199 2200 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 2201 struct an_card_rid_desc an_rid_desc; 2202 2203 for (i = 0; i < AN_TIMEOUT; i++) { 2204 PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat); 2205 if (!(stat & AN_CMD_BUSY)) { 2206 break; 2207 } 2208 } 2209 if (i == AN_TIMEOUT) { 2210 cmn_err(CE_WARN, "pcan put_ltv: busy"); 2211 } 2212 2213 an_rid_desc.an_valid = 1; 2214 an_rid_desc.an_len = len; 2215 an_rid_desc.an_rid = type; 2216 an_rid_desc.an_phys = pcan_p->pcan_cmd.dma_physaddr; 2217 2218 bcopy(val_p, pcan_p->pcan_cmd.dma_virtaddr, 2219 an_rid_desc.an_len); 2220 2221 for (i = 0; i < sizeof (an_rid_desc) / 4; i++) 2222 PCAN_AUX_PUT32(pcan_p, AN_HOST_DESC_OFFSET + i * 4, 2223 ((uint32_t *)&an_rid_desc)[i]); 2224 pcan_delay(pcan_p, 100000); 2225 stat = pcan_set_cmd0(pcan_p, AN_CMD_ACCESS | 2226 AN_ACCESS_WRITE, type, 0, 0); 2227 pcan_delay(pcan_p, 100000); 2228 return (stat); 2229 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) { 2230 /* 0. select read mode first */ 2231 if (stat = pcan_set_cmd(pcan_p, AN_CMD_ACCESS | 2232 AN_ACCESS_READ, type)) 2233 return (stat); 2234 2235 /* 1. select Buffer Access Path (channel) 1 for PIO */ 2236 if (stat = pcan_set_ch(pcan_p, type, 0, 1)) 2237 return (stat); 2238 2239 /* 2. write length */ 2240 len >>= 1; /* convert bytes to 16-bit words */ 2241 stat = len; 2242 PCAN_WRITE(pcan_p, AN_DATA1, stat); 2243 2244 /* 3. write value */ 2245 val_p++; 2246 for (stat = 0; stat < len-1; stat++, val_p++) { 2247 PCAN_WRITE_P(pcan_p, AN_DATA1, val_p, 1); 2248 } 2249 2250 /* 4. select write mode */ 2251 return (pcan_set_cmd(pcan_p, AN_CMD_ACCESS | 2252 AN_ACCESS_WRITE, type)); 2253 } 2254 return (PCAN_FAIL); 2255 } 2256 2257 /*ARGSUSED*/ 2258 static uint16_t 2259 pcan_rdch0(pcan_maci_t *pcan_p, uint16_t type, uint16_t off, uint16_t *buf_p, 2260 int len, int order) 2261 { 2262 ASSERT(!(len & 1)); 2263 2264 if (pcan_set_ch(pcan_p, type, off, 0) != PCAN_SUCCESS) 2265 return (PCAN_FAIL); 2266 len >>= 1; 2267 for (off = 0; off < len; off++, buf_p++) { 2268 PCAN_READ_P(pcan_p, AN_DATA0, buf_p, order); 2269 } 2270 return (PCAN_SUCCESS); 2271 } 2272 2273 /*ARGSUSED*/ 2274 static uint16_t 2275 pcan_wrch1(pcan_maci_t *pcan_p, uint16_t type, uint16_t off, uint16_t *buf_p, 2276 int len, int order) 2277 { 2278 ASSERT(!(len & 1)); 2279 2280 if (pcan_set_ch(pcan_p, type, off, 1) != PCAN_SUCCESS) 2281 return (PCAN_FAIL); 2282 len >>= 1; 2283 for (off = 0; off < len; off++, buf_p++) { 2284 PCAN_WRITE_P(pcan_p, AN_DATA1, buf_p, order); 2285 } 2286 return (PCAN_SUCCESS); 2287 } 2288 2289 static uint16_t 2290 pcan_status_ltv(int rw, pcan_maci_t *pcan_p, struct an_ltv_status *status_p) 2291 { 2292 uint16_t ret, len; 2293 2294 if (rw != PCAN_READ_LTV) { 2295 cmn_err(CE_WARN, "pcan status_ltv: unsupported op %x", rw); 2296 return (PCAN_FAIL); 2297 } 2298 if (ret = pcan_get_ltv(pcan_p, sizeof (*status_p), AN_RID_STATUS, 2299 (uint16_t *)status_p)) 2300 return (ret); 2301 2302 PCAN_SWAP16_BUF(status_p->an_macaddr); 2303 PCAN_SWAP16_BUF(status_p->an_ssid); 2304 len = min(status_p->an_ssidlen, 31); 2305 status_p->an_ssid[len] = '\0'; 2306 PCAN_SWAP16_BUF(status_p->an_ap_name); 2307 PCAN_SWAP16_BUF(status_p->an_cur_bssid); 2308 PCAN_SWAP16_BUF(status_p->an_prev_bssid1); 2309 PCAN_SWAP16_BUF(status_p->an_prev_bssid2); 2310 PCAN_SWAP16_BUF(status_p->an_prev_bssid3); 2311 PCAN_SWAP16_BUF(status_p->an_ap_ip_address); 2312 PCAN_SWAP16_BUF(status_p->an_carrier); 2313 return (PCAN_SUCCESS); 2314 } 2315 2316 static uint16_t 2317 pcan_cfg_ltv(int rw, pcan_maci_t *pcan_p, struct an_ltv_genconfig *cfg_p) 2318 { 2319 uint16_t ret; 2320 uint16_t rid = cfg_p == &pcan_p->an_config ? 2321 AN_RID_GENCONFIG : AN_RID_ACTUALCFG; 2322 2323 if (rw == PCAN_READ_LTV) { 2324 if (ret = pcan_get_ltv(pcan_p, sizeof (*cfg_p), rid, 2325 (uint16_t *)cfg_p)) 2326 return (ret); 2327 goto done; 2328 } 2329 PCAN_SWAP16_BUF(cfg_p->an_macaddr); 2330 PCAN_SWAP16_BUF(cfg_p->an_rates); 2331 if (ret = pcan_put_ltv(pcan_p, sizeof (*cfg_p), 2332 rid, (uint16_t *)cfg_p)) 2333 return (ret); 2334 done: 2335 PCAN_SWAP16_BUF(cfg_p->an_macaddr); 2336 PCAN_SWAP16_BUF(cfg_p->an_rates); 2337 return (ret); 2338 } 2339 2340 static uint16_t 2341 pcan_cap_ltv(int rw, pcan_maci_t *pcan_p) 2342 { 2343 uint16_t ret; 2344 2345 if (rw != PCAN_READ_LTV) { 2346 cmn_err(CE_WARN, "pcan cap_ltv: unsupported op %x", rw); 2347 return (PCAN_FAIL); 2348 } 2349 if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_caps), 2350 AN_RID_CAPABILITIES, (uint16_t *)&pcan_p->an_caps)) 2351 return (ret); 2352 2353 PCAN_SWAP16_BUF(pcan_p->an_caps.an_oui); 2354 PCAN_SWAP16_BUF(pcan_p->an_caps.an_manufname); 2355 PCAN_SWAP16_BUF(pcan_p->an_caps.an_prodname); 2356 PCAN_SWAP16_BUF(pcan_p->an_caps.an_prodvers); 2357 PCAN_SWAP16_BUF(pcan_p->an_caps.an_oemaddr); 2358 PCAN_SWAP16_BUF(pcan_p->an_caps.an_aironetaddr); 2359 PCAN_SWAP16_BUF(pcan_p->an_caps.an_callid); 2360 PCAN_SWAP16_BUF(pcan_p->an_caps.an_supported_rates); 2361 return (PCAN_SUCCESS); 2362 } 2363 2364 static uint16_t 2365 pcan_ssid_ltv(int rw, pcan_maci_t *pcan_p) 2366 { 2367 uint16_t ret; 2368 2369 if (rw == PCAN_READ_LTV) { 2370 if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_ssidlist), 2371 AN_RID_SSIDLIST, (uint16_t *)&pcan_p->an_ssidlist)) 2372 return (ret); 2373 goto done; 2374 } 2375 PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid1); 2376 PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid2); 2377 PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid3); 2378 if (ret = pcan_put_ltv(pcan_p, sizeof (struct an_ltv_ssidlist), 2379 AN_RID_SSIDLIST, (uint16_t *)&pcan_p->an_ssidlist)) 2380 return (ret); 2381 done: 2382 PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid1); 2383 PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid2); 2384 PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid3); 2385 return (ret); 2386 } 2387 2388 static uint16_t 2389 pcan_aplist_ltv(int rw, pcan_maci_t *pcan_p) 2390 { 2391 uint16_t ret; 2392 2393 if (rw == PCAN_READ_LTV) { 2394 if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_aplist), 2395 AN_RID_APLIST, (uint16_t *)&pcan_p->an_aplist)) 2396 return (ret); 2397 goto done; 2398 } 2399 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap1); 2400 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap2); 2401 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap3); 2402 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap4); 2403 if (ret = pcan_put_ltv(pcan_p, sizeof (struct an_ltv_aplist), 2404 AN_RID_APLIST, (uint16_t *)&pcan_p->an_aplist)) 2405 return (ret); 2406 done: 2407 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap1); 2408 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap2); 2409 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap3); 2410 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap4); 2411 return (ret); 2412 } 2413 2414 static uint16_t 2415 pcan_scanresult_ltv(int rw, pcan_maci_t *pcan_p, uint16_t type, 2416 struct an_ltv_scanresult *scanresult_p) 2417 { 2418 uint16_t ret, len; 2419 if (rw != PCAN_READ_LTV) { 2420 cmn_err(CE_WARN, "pcan scan_ltv: readonly rid %x\n", type); 2421 return (PCAN_FAIL); 2422 } 2423 if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_scanresult), 2424 type, (uint16_t *)scanresult_p)) 2425 return (ret); 2426 PCAN_SWAP16_BUF(scanresult_p->an_bssid); 2427 PCAN_SWAP16_BUF(scanresult_p->an_ssid); 2428 len = min(scanresult_p->an_ssidlen, 31); 2429 scanresult_p->an_ssid[len] = '\0'; 2430 PCAN_SWAP16_BUF(scanresult_p->an_rates); 2431 return (PCAN_SUCCESS); 2432 } 2433 2434 static uint16_t 2435 pcan_one_wepkey(int rw, pcan_maci_t *pcan_p, struct an_ltv_wepkey *wkp, 2436 uint16_t rid) 2437 { 2438 uint16_t ret; 2439 2440 if (rw == PCAN_READ_LTV) { 2441 if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_wepkey), 2442 rid, (uint16_t *)wkp)) { 2443 return (ret); 2444 } 2445 goto done; 2446 } 2447 PCAN_SWAP16_BUF(wkp->an_macaddr); 2448 PCAN_SWAP16_BUF(wkp->an_key); 2449 if (ret = pcan_put_ltv(pcan_p, sizeof (struct an_ltv_wepkey), 2450 rid, (uint16_t *)wkp)) 2451 return (ret); 2452 done: 2453 PCAN_SWAP16_BUF(wkp->an_macaddr); 2454 PCAN_SWAP16_BUF(wkp->an_key); 2455 return (ret); 2456 } 2457 2458 static uint16_t 2459 pcan_wepkey_ltv(int rw, pcan_maci_t *pcan_p) 2460 { 2461 uint16_t ret, i; 2462 struct an_ltv_wepkey wk; 2463 2464 if (rw == PCAN_READ_LTV) { 2465 uint16_t rid = AN_RID_WEPKEY2; 2466 2467 if (ret = pcan_one_wepkey(rw, pcan_p, &wk, rid)) 2468 return (ret); 2469 for (i = 0; i < 5; i++) { 2470 if (wk.an_index < 4) 2471 pcan_p->an_wepkey[wk.an_index] = wk; 2472 else if (wk.an_index == 0xffff) 2473 pcan_p->an_cur_wepkey = wk.an_macaddr[0]; 2474 rid = AN_RID_WEPKEY; 2475 } 2476 return (PCAN_SUCCESS); 2477 } 2478 for (i = 0; i < MAX_NWEPKEYS; i++) { 2479 if (pcan_p->an_wepkey[i].an_index == i) { 2480 if (ret = pcan_one_wepkey(rw, pcan_p, 2481 &pcan_p->an_wepkey[i], AN_RID_WEPKEY2)) 2482 return (ret); 2483 } 2484 } 2485 /* Now set the default key */ 2486 (void) memset(&wk, 0, sizeof (wk)); 2487 wk.an_index = 0xffff; 2488 wk.an_macaddr[0] = pcan_p->an_cur_wepkey; 2489 ret = pcan_one_wepkey(rw, pcan_p, &wk, AN_RID_WEPKEY2); 2490 return (ret); 2491 } 2492 2493 static uint16_t 2494 pcan_alloc_nicmem(pcan_maci_t *pcan_p, uint16_t len, uint16_t *id_p) 2495 { 2496 int i; 2497 uint16_t stat; 2498 2499 len = ((len + 1) >> 1) << 1; /* round up to 16-bit boundary */ 2500 2501 if (stat = pcan_set_cmd(pcan_p, AN_CMD_ALLOC_MEM, len)) 2502 return (stat); 2503 for (i = 0; !(stat & AN_EV_ALLOC) && (i < AN_TIMEOUT); i++) { 2504 PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat); 2505 } 2506 if (!(stat & AN_EV_ALLOC)) 2507 return (PCAN_TIMEDOUT_ALLOC); 2508 PCAN_READ(pcan_p, AN_ALLOC_FID, stat); 2509 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_ALLOC); 2510 *id_p = stat; 2511 2512 /* zero fill the allocated NIC mem - sort of pcan_fill_ch0 */ 2513 (void) pcan_set_ch(pcan_p, stat, 0, 0); 2514 for (len >>= 1, stat = 0; stat < len; stat++) { 2515 PCAN_WRITE(pcan_p, AN_DATA0, 0); 2516 } 2517 return (PCAN_SUCCESS); 2518 } 2519 2520 static void 2521 pcan_stop_rx_dma(pcan_maci_t *pcan_p) 2522 { 2523 int i, j; 2524 struct an_card_rx_desc an_rx_desc; 2525 2526 for (i = 0; i < AN_MAX_RX_DESC; i++) { 2527 bzero(&an_rx_desc, sizeof (an_rx_desc)); 2528 an_rx_desc.an_valid = 0; 2529 an_rx_desc.an_len = AN_RX_BUFFER_SIZE; 2530 an_rx_desc.an_done = 1; 2531 an_rx_desc.an_phys = pcan_p->pcan_rx[i].dma_physaddr; 2532 for (j = 0; j < sizeof (an_rx_desc) / 4; j++) 2533 PCAN_AUX_PUT32(pcan_p, AN_RX_DESC_OFFSET 2534 + (i * sizeof (an_rx_desc)) 2535 + (j * 4), ((uint32_t *)&an_rx_desc)[j]); 2536 } 2537 } 2538 2539 static int 2540 pcan_init_dma_desc(pcan_maci_t *pcan_p) 2541 { 2542 int i, j; 2543 struct an_card_rid_desc an_rid_desc; 2544 struct an_card_rx_desc an_rx_desc; 2545 struct an_card_tx_desc an_tx_desc; 2546 2547 /* Allocate DMA for rx */ 2548 if (pcan_set_cmd0(pcan_p, AN_CMD_ALLOC_DESC, 2549 AN_DESCRIPTOR_RX, AN_RX_DESC_OFFSET, 2550 AN_MAX_RX_DESC) != PCAN_SUCCESS) { 2551 cmn_err(CE_WARN, "pcan init_dma: fail to alloc rx descriptor"); 2552 goto error; 2553 } 2554 for (i = 0; i < AN_MAX_RX_DESC; i++) { 2555 bzero(&an_rx_desc, sizeof (an_rx_desc)); 2556 an_rx_desc.an_valid = 1; 2557 an_rx_desc.an_len = AN_RX_BUFFER_SIZE; 2558 an_rx_desc.an_done = 0; 2559 an_rx_desc.an_phys = pcan_p->pcan_rx[i].dma_physaddr; 2560 for (j = 0; j < sizeof (an_rx_desc) / 4; j++) 2561 PCAN_AUX_PUT32(pcan_p, AN_RX_DESC_OFFSET 2562 + (i * sizeof (an_rx_desc)) 2563 + (j * 4), ((uint32_t *)&an_rx_desc)[j]); 2564 } 2565 2566 2567 /* Allocate DMA for tx */ 2568 if (pcan_set_cmd0(pcan_p, AN_CMD_ALLOC_DESC, 2569 AN_DESCRIPTOR_TX, AN_TX_DESC_OFFSET, 2570 AN_MAX_TX_DESC) != PCAN_SUCCESS) { 2571 cmn_err(CE_WARN, "pcan init_dma: fail to alloc tx descriptor"); 2572 goto error; 2573 } 2574 2575 for (i = 0; i < AN_MAX_TX_DESC; i++) { 2576 an_tx_desc.an_offset = 0; 2577 an_tx_desc.an_eoc = 0; 2578 an_tx_desc.an_valid = 0; 2579 an_tx_desc.an_len = 0; 2580 an_tx_desc.an_phys = pcan_p->pcan_tx[i].dma_physaddr; 2581 2582 for (j = 0; j < sizeof (an_tx_desc) / 4; j++) 2583 PCAN_AUX_PUT32(pcan_p, AN_TX_DESC_OFFSET 2584 + (i * sizeof (an_tx_desc)) 2585 + (j * 4), ((uint32_t *)&an_tx_desc)[j]); 2586 } 2587 2588 /* Allocate DMA for rid */ 2589 if (pcan_set_cmd0(pcan_p, AN_CMD_ALLOC_DESC, 2590 AN_DESCRIPTOR_HOSTRW, AN_HOST_DESC_OFFSET, 1) != PCAN_SUCCESS) { 2591 cmn_err(CE_WARN, "pcan init_dma: fail to alloc rid descriptor"); 2592 goto error; 2593 } 2594 bzero(&an_rid_desc, sizeof (an_rid_desc)); 2595 an_rid_desc.an_valid = 1; 2596 an_rid_desc.an_len = AN_RID_BUFFER_SIZE; 2597 an_rid_desc.an_rid = 0; 2598 an_rid_desc.an_phys = pcan_p->pcan_cmd.dma_physaddr; 2599 2600 for (i = 0; i < sizeof (an_rid_desc) / 4; i++) 2601 PCAN_AUX_PUT32(pcan_p, AN_HOST_DESC_OFFSET + i * 4, 2602 ((uint32_t *)&an_rid_desc)[i]); 2603 2604 pcan_p->pcan_txring.an_tx_prod = 0; 2605 pcan_p->pcan_txring.an_tx_cons = 0; 2606 pcan_p->pcan_flag &= ~PCAN_CARD_SEND; 2607 return (PCAN_SUCCESS); 2608 error: 2609 return (PCAN_FAIL); 2610 } 2611 2612 static int 2613 pcan_init_dma(dev_info_t *dip, pcan_maci_t *pcan_p) 2614 { 2615 int i, ret = PCAN_FAIL; 2616 ddi_dma_cookie_t dma_cookie; 2617 size_t len; 2618 2619 /* Allocate DMA for rx */ 2620 for (i = 0; i < AN_MAX_RX_DESC; i++) { 2621 if (ddi_dma_alloc_handle(dip, &control_cmd_dma_attr, 2622 DDI_DMA_SLEEP, 0, 2623 &pcan_p->pcan_rx[i].dma_handle) != DDI_SUCCESS) 2624 goto error; 2625 2626 if (ddi_dma_mem_alloc(pcan_p->pcan_rx[i].dma_handle, 2627 AN_RX_BUFFER_SIZE, &accattr, 2628 DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0, 2629 (caddr_t *)&pcan_p->pcan_rx[i].dma_virtaddr, &len, 2630 &pcan_p->pcan_rx[i].dma_acc_handle) != DDI_SUCCESS) { 2631 goto error; 2632 } 2633 if (ddi_dma_addr_bind_handle( 2634 pcan_p->pcan_rx[i].dma_handle, 2635 NULL, (caddr_t)pcan_p->pcan_rx[i].dma_virtaddr, 2636 len, DDI_DMA_READ | 2637 DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0, &dma_cookie, 2638 &pcan_p->pcan_rx[i].ncookies) != DDI_DMA_MAPPED) { 2639 goto error; 2640 } 2641 ASSERT(pcan_p->pcan_rx[i].ncookies == 1); 2642 pcan_p->pcan_rx[i].dma_physaddr = dma_cookie.dmac_address; 2643 } 2644 2645 /* Allocate DMA for tx */ 2646 for (i = 0; i < AN_MAX_TX_DESC; i++) { 2647 if (ddi_dma_alloc_handle(dip, &control_cmd_dma_attr, 2648 DDI_DMA_SLEEP, 0, 2649 &pcan_p->pcan_tx[i].dma_handle) != DDI_SUCCESS) 2650 goto error; 2651 2652 if (ddi_dma_mem_alloc(pcan_p->pcan_tx[i].dma_handle, 2653 AN_TX_BUFFER_SIZE, &accattr, 2654 DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0, 2655 (caddr_t *)&pcan_p->pcan_tx[i].dma_virtaddr, &len, 2656 &pcan_p->pcan_tx[i].dma_acc_handle) != DDI_SUCCESS) { 2657 goto error; 2658 } 2659 if (ddi_dma_addr_bind_handle( 2660 pcan_p->pcan_tx[i].dma_handle, 2661 NULL, (caddr_t)pcan_p->pcan_tx[i].dma_virtaddr, 2662 len, DDI_DMA_WRITE | 2663 DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0, &dma_cookie, 2664 &pcan_p->pcan_tx[i].ncookies) != DDI_DMA_MAPPED) { 2665 goto error; 2666 } 2667 ASSERT(pcan_p->pcan_tx[i].ncookies == 1); 2668 pcan_p->pcan_tx[i].dma_physaddr = dma_cookie.dmac_address; 2669 } 2670 2671 /* Allocate DMA for rid */ 2672 if (ddi_dma_alloc_handle(dip, &control_cmd_dma_attr, 2673 DDI_DMA_SLEEP, 0, 2674 &pcan_p->pcan_cmd.dma_handle) != DDI_SUCCESS) 2675 goto error; 2676 2677 if (ddi_dma_mem_alloc(pcan_p->pcan_cmd.dma_handle, 2678 AN_RID_BUFFER_SIZE, &accattr, 2679 DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0, 2680 (caddr_t *)&pcan_p->pcan_cmd.dma_virtaddr, &len, 2681 &pcan_p->pcan_cmd.dma_acc_handle) != DDI_SUCCESS) { 2682 goto error; 2683 } 2684 if (ddi_dma_addr_bind_handle( 2685 pcan_p->pcan_cmd.dma_handle, 2686 NULL, (caddr_t)pcan_p->pcan_cmd.dma_virtaddr, 2687 len, DDI_DMA_RDWR | 2688 DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0, &dma_cookie, 2689 &pcan_p->pcan_cmd.ncookies) != DDI_DMA_MAPPED) { 2690 goto error; 2691 } 2692 ASSERT(pcan_p->pcan_cmd.ncookies == 1); 2693 pcan_p->pcan_cmd.dma_physaddr = dma_cookie.dmac_address; 2694 2695 if (ret = pcan_init_dma_desc(pcan_p)) { 2696 cmn_err(CE_WARN, "pcan init_dma_desc: failed\n"); 2697 goto error; 2698 } 2699 2700 return (PCAN_SUCCESS); 2701 error: 2702 pcan_free_dma(pcan_p); 2703 return (ret); 2704 } 2705 2706 static void 2707 pcan_free_dma(pcan_maci_t *pcan_p) 2708 { 2709 int i; 2710 2711 /* free RX dma */ 2712 pcan_stop_rx_dma(pcan_p); 2713 for (i = 0; i < AN_MAX_RX_DESC; i++) { 2714 if (pcan_p->pcan_rx[i].dma_handle != NULL) { 2715 if (pcan_p->pcan_rx[i].ncookies) { 2716 (void) ddi_dma_unbind_handle( 2717 pcan_p->pcan_rx[i].dma_handle); 2718 pcan_p->pcan_rx[i].ncookies = 0; 2719 } 2720 ddi_dma_free_handle( 2721 &pcan_p->pcan_rx[i].dma_handle); 2722 pcan_p->pcan_rx[i].dma_handle = NULL; 2723 } 2724 if (pcan_p->pcan_rx[i].dma_acc_handle != NULL) { 2725 ddi_dma_mem_free( 2726 &pcan_p->pcan_rx[i].dma_acc_handle); 2727 pcan_p->pcan_rx[i].dma_acc_handle = NULL; 2728 } 2729 } 2730 2731 /* free TX dma */ 2732 for (i = 0; i < AN_MAX_TX_DESC; i++) { 2733 if (pcan_p->pcan_tx[i].dma_handle != NULL) { 2734 if (pcan_p->pcan_tx[i].ncookies) { 2735 (void) ddi_dma_unbind_handle( 2736 pcan_p->pcan_tx[i].dma_handle); 2737 pcan_p->pcan_tx[i].ncookies = 0; 2738 } 2739 ddi_dma_free_handle( 2740 &pcan_p->pcan_tx[i].dma_handle); 2741 pcan_p->pcan_tx[i].dma_handle = NULL; 2742 } 2743 if (pcan_p->pcan_tx[i].dma_acc_handle != NULL) { 2744 ddi_dma_mem_free( 2745 &pcan_p->pcan_tx[i].dma_acc_handle); 2746 pcan_p->pcan_tx[i].dma_acc_handle = NULL; 2747 } 2748 } 2749 2750 /* free cmd dma */ 2751 if (pcan_p->pcan_cmd.dma_handle != NULL) { 2752 if (pcan_p->pcan_cmd.ncookies) { 2753 (void) ddi_dma_unbind_handle( 2754 pcan_p->pcan_cmd.dma_handle); 2755 pcan_p->pcan_cmd.ncookies = 0; 2756 } 2757 ddi_dma_free_handle( 2758 &pcan_p->pcan_cmd.dma_handle); 2759 pcan_p->pcan_cmd.dma_handle = NULL; 2760 } 2761 if (pcan_p->pcan_cmd.dma_acc_handle != NULL) { 2762 ddi_dma_mem_free( 2763 &pcan_p->pcan_cmd.dma_acc_handle); 2764 pcan_p->pcan_cmd.dma_acc_handle = NULL; 2765 } 2766 } 2767 2768 /* 2769 * get card capability (WEP, default channel), setup broadcast, mac addresses 2770 */ 2771 static uint32_t 2772 pcan_get_cap(pcan_maci_t *pcan_p) 2773 { 2774 uint16_t stat; 2775 2776 if (stat = pcan_cfg_ltv(PCAN_READ_LTV, pcan_p, &pcan_p->an_config)) { 2777 PCANDBG((CE_NOTE, "pcan get_cap: read cfg fail %x", stat)); 2778 return ((uint32_t)AN_RID_GENCONFIG << 16 | stat); 2779 } 2780 2781 if (stat = pcan_cap_ltv(PCAN_READ_LTV, pcan_p)) { 2782 PCANDBG((CE_NOTE, "pcan get_cap: read cap fail %x", stat)); 2783 return ((uint32_t)AN_RID_CAPABILITIES << 16 | stat); 2784 } 2785 #ifdef DEBUG 2786 if (pcan_debug & PCAN_DBG_FW_VERSION) { 2787 cmn_err(CE_NOTE, "the version of the firmware in the wifi card " 2788 "'%s %s %s' is %s\n", 2789 pcan_p->an_caps.an_manufname, 2790 pcan_p->an_caps.an_prodname, 2791 pcan_p->pcan_device_type == PCAN_DEVICE_PCI ? 2792 "minipci" : "pccard", 2793 pcan_p->an_caps.an_prodvers); 2794 } 2795 #endif 2796 2797 if (stat = pcan_ssid_ltv(PCAN_READ_LTV, pcan_p)) { 2798 PCANDBG((CE_NOTE, "pcan get_cap: read ssid fail %x", stat)); 2799 return ((uint32_t)AN_RID_SSIDLIST << 16 | stat); 2800 } 2801 2802 if (stat = pcan_aplist_ltv(PCAN_READ_LTV, pcan_p)) { 2803 PCANDBG((CE_NOTE, "pcan get_cap: read aplist fail %x", stat)); 2804 return ((uint32_t)AN_RID_APLIST << 16 | stat); 2805 } 2806 if (stat = pcan_wepkey_ltv(PCAN_READ_LTV, pcan_p)) { 2807 PCANDBG((CE_NOTE, "pcan get_cap: read wepkey fail %x", stat)); 2808 return ((uint32_t)AN_RID_WEPKEY2 << 16 | stat); 2809 } 2810 ether_copy(pcan_p->an_caps.an_oemaddr, pcan_p->pcan_mac_addr); 2811 return (PCAN_SUCCESS); 2812 } 2813 2814 static int 2815 pcan_config_mac(pcan_maci_t *pcan_p) 2816 { 2817 uint16_t stat; 2818 2819 if (stat = pcan_ssid_ltv(PCAN_WRITE_LTV, pcan_p)) { 2820 PCANDBG((CE_NOTE, "pcan config_mac: write SSID failed%x\n", 2821 stat)); 2822 return ((int)stat); 2823 } 2824 2825 if (stat = pcan_aplist_ltv(PCAN_WRITE_LTV, pcan_p)) { 2826 PCANDBG((CE_NOTE, "pcan config_mac: write APlist failed%x\n", 2827 stat)); 2828 return ((int)stat); 2829 } 2830 if (stat = pcan_wepkey_ltv(PCAN_WRITE_LTV, pcan_p)) { 2831 PCANDBG((CE_NOTE, "pcan config_mac: write wepkey failed%x\n", 2832 stat)); 2833 return ((int)stat); 2834 } 2835 if (pcan_p->pcan_usewep) 2836 pcan_p->an_config.an_authtype |= 2837 AN_AUTHTYPE_ENABLEWEP | AN_AUTHTYPE_ALLOW_UNENCRYPTED; 2838 PCANDBG((CE_NOTE, "pcan config_mac: usewep=%x authtype=%x opmode=%x\n", 2839 pcan_p->pcan_usewep, pcan_p->an_config.an_authtype, 2840 pcan_p->an_config.an_opmode)); 2841 2842 pcan_p->an_config.an_assoc_timeout = 5000; /* stop assoc seq in 5 sec */ 2843 if (stat = pcan_cfg_ltv(PCAN_WRITE_LTV, pcan_p, &pcan_p->an_config)) { 2844 PCANDBG((CE_NOTE, "pcan config_mac: write cfg failed %x\n", 2845 stat)); 2846 return ((int)stat); 2847 } 2848 2849 if (stat = pcan_cfg_ltv(PCAN_READ_LTV, pcan_p, 2850 &pcan_p->an_actual_config)) { 2851 PCANDBG((CE_NOTE, "pcan config_mac: read cfg failed%x\n", 2852 stat)); 2853 return ((int)stat); 2854 } 2855 PCANDBG((CE_NOTE, "pcan config_mac: optionmask=%x authtype=%x\n", 0, 2856 pcan_p->an_actual_config.an_authtype)); 2857 2858 if (stat = pcan_status_ltv(PCAN_READ_LTV, pcan_p, &pcan_p->an_status)) { 2859 PCANDBG((CE_NOTE, "pcan config_mac: read status failed %x\n", 2860 stat)); 2861 return ((int)stat); 2862 } 2863 return (PCAN_SUCCESS); 2864 } 2865 2866 static int 2867 pcan_loaddef(pcan_maci_t *pcan_p) 2868 { 2869 int i; 2870 2871 pcan_p->an_ssidlist.an_ssid1_len = 0; 2872 bzero(pcan_p->an_ssidlist.an_ssid1, 2873 sizeof (pcan_p->an_ssidlist.an_ssid1)); 2874 for (i = 0; i < MAX_NWEPKEYS; i++) { 2875 pcan_p->an_wepkey[i].an_index = 0xffff; 2876 bzero(pcan_p->an_wepkey[i].an_key, 2877 sizeof (pcan_p->an_wepkey[i].an_key)); 2878 pcan_p->an_wepkey[i].an_keylen = 0; 2879 bzero(pcan_p->an_wepkey[i].an_macaddr, 2880 sizeof (pcan_p->an_wepkey[i].an_macaddr)); 2881 pcan_p->an_wepkey[i].an_macaddr[0] = 1; 2882 } 2883 pcan_p->an_cur_wepkey = 0; 2884 2885 pcan_p->pcan_usewep = 0; 2886 pcan_p->an_config.an_opmode = AN_OPMODE_INFR_STATION; 2887 pcan_p->an_config.an_authtype = AN_AUTHTYPE_OPEN; 2888 pcan_p->an_config.an_stationary = 1; 2889 pcan_p->an_config.an_max_beacon_lost_time = 0xffff; 2890 i = pcan_config_mac(pcan_p); 2891 2892 return (i); 2893 } 2894 2895 static int 2896 pcan_init_nicmem(pcan_maci_t *pcan_p) 2897 { 2898 int i; 2899 uint16_t ret; 2900 pcan_txring_t *ring_p = &pcan_p->pcan_txring; 2901 2902 for (i = 0; i < AN_TX_RING_CNT; i++) { 2903 uint16_t rc; 2904 ret = pcan_alloc_nicmem(pcan_p, PCAN_NICMEM_SZ, &rc); 2905 if (ret) { 2906 cmn_err(CE_WARN, "pcan alloc NIC Tx buf[%x]: failed " 2907 "%x\n", i, ret); 2908 return (DDI_FAILURE); 2909 } 2910 ring_p->an_tx_fids[i] = rc; 2911 ring_p->an_tx_ring[i] = 0; 2912 PCANDBG((CE_NOTE, "pcan: NIC tx_id[%x]=%x\n", i, rc)); 2913 } 2914 ring_p->an_tx_prod = ring_p->an_tx_cons = 0; 2915 return (PCAN_SUCCESS); 2916 } 2917 2918 2919 2920 static void 2921 pcan_start_locked(pcan_maci_t *pcan_p) 2922 { 2923 pcan_p->pcan_flag |= PCAN_CARD_INTREN; 2924 PCAN_ENABLE_INTR(pcan_p); 2925 } 2926 2927 static void 2928 pcan_stop_locked(pcan_maci_t *pcan_p) 2929 { 2930 PCAN_DISABLE_INTR_CLEAR(pcan_p); 2931 pcan_p->pcan_flag &= ~PCAN_CARD_INTREN; 2932 } 2933 2934 /* 2935 * for scan result 2936 */ 2937 static int 2938 pcan_add_scan_item(pcan_maci_t *pcan_p, struct an_ltv_scanresult s) 2939 { 2940 an_scan_list_t *scan_item; 2941 2942 scan_item = kmem_zalloc(sizeof (an_scan_list_t), KM_SLEEP); 2943 if (scan_item == NULL) { 2944 cmn_err(CE_WARN, "pcan add_scan_item: zalloc failed\n"); 2945 return (PCAN_FAIL); 2946 } 2947 scan_item->an_val = s; 2948 scan_item->an_timeout = AN_SCAN_TIMEOUT_MAX; 2949 list_insert_tail(&pcan_p->an_scan_list, scan_item); 2950 pcan_p->an_scan_num++; 2951 return (PCAN_SUCCESS); 2952 } 2953 2954 static void 2955 pcan_delete_scan_item(pcan_maci_t *pcan_p, an_scan_list_t *s) 2956 { 2957 list_remove(&pcan_p->an_scan_list, s); 2958 kmem_free(s, sizeof (*s)); 2959 pcan_p->an_scan_num--; 2960 } 2961 2962 static void 2963 pcan_scanlist_timeout(void *arg) 2964 { 2965 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 2966 an_scan_list_t *scan_item0, *scan_item1; 2967 2968 mutex_enter(&pcan_p->pcan_scanlist_lock); 2969 scan_item0 = list_head(&pcan_p->an_scan_list); 2970 for (; scan_item0; ) { 2971 PCANDBG((CE_NOTE, "pcan scanlist: ssid = %s\n", 2972 scan_item0->an_val.an_ssid)); 2973 PCANDBG((CE_NOTE, "pcan scanlist: timeout left: %ds", 2974 scan_item0->an_timeout)); 2975 scan_item1 = list_next(&pcan_p->an_scan_list, scan_item0); 2976 if (scan_item0->an_timeout == 0) { 2977 pcan_delete_scan_item(pcan_p, scan_item0); 2978 } else { 2979 scan_item0->an_timeout--; 2980 } 2981 scan_item0 = scan_item1; 2982 } 2983 mutex_exit(&pcan_p->pcan_scanlist_lock); 2984 pcan_p->an_scanlist_timeout_id = timeout(pcan_scanlist_timeout, 2985 pcan_p, drv_usectohz(1000000)); 2986 } 2987 2988 /* 2989 * Brussels support 2990 */ 2991 /* 2992 * MAC_PROP_WL_ESSID 2993 */ 2994 static int 2995 pcan_set_essid(pcan_maci_t *pcan_p, const void *wldp_buf) 2996 { 2997 char *value; 2998 struct an_ltv_ssidlist *ssidlist_p; 2999 wl_essid_t *iw_essid = (wl_essid_t *)wldp_buf; 3000 3001 ssidlist_p = &pcan_p->an_ssidlist; 3002 bzero(ssidlist_p, sizeof (*ssidlist_p)); 3003 value = iw_essid->wl_essid_essid; 3004 (void) strncpy(ssidlist_p->an_ssid1, value, 3005 MIN(32, strlen(value))); 3006 ssidlist_p->an_ssid1_len = strlen(value); 3007 3008 return (ENETRESET); 3009 } 3010 3011 static int 3012 pcan_get_essid(pcan_maci_t *pcan_p, void *wldp_buf) 3013 { 3014 int err = 0; 3015 struct an_ltv_status *status_p; 3016 wl_essid_t *ow_essid = (wl_essid_t *)wldp_buf; 3017 3018 status_p = &pcan_p->an_status; 3019 3020 if (pcan_status_ltv(PCAN_READ_LTV, pcan_p, status_p)) { 3021 err = EIO; 3022 return (err); 3023 } 3024 ow_essid->wl_essid_length = status_p->an_ssidlen; 3025 bcopy(status_p->an_ssid, ow_essid->wl_essid_essid, 3026 status_p->an_ssidlen); 3027 3028 return (err); 3029 } 3030 3031 /* 3032 * MAC_PROP_WL_BSSID 3033 */ 3034 static int 3035 pcan_set_bssid(pcan_maci_t *pcan_p, const void *wldp_buf) 3036 { 3037 wl_bssid_t *value; 3038 struct an_ltv_aplist *aplist_p; 3039 3040 aplist_p = &pcan_p->an_aplist; 3041 3042 value = (wl_bssid_t *)wldp_buf; 3043 (void) strncpy((char *)aplist_p->an_ap1, (char *)value, 6); 3044 3045 return (ENETRESET); 3046 } 3047 3048 static int 3049 pcan_get_bssid(pcan_maci_t *pcan_p, void *wldp_buf) 3050 { 3051 int err = 0; 3052 struct an_ltv_status *status_p; 3053 3054 status_p = &pcan_p->an_status; 3055 3056 if (pcan_status_ltv(PCAN_READ_LTV, pcan_p, status_p)) { 3057 err = EIO; 3058 return (err); 3059 } 3060 3061 bcopy(status_p->an_cur_bssid, wldp_buf, sizeof (wl_bssid_t)); 3062 PCANDBG((CE_CONT, 3063 "pcan: cfg_bssid: bssid=%x %x %x %x %x %x\n", 3064 status_p->an_cur_bssid[0], 3065 status_p->an_cur_bssid[1], 3066 status_p->an_cur_bssid[2], 3067 status_p->an_cur_bssid[3], 3068 status_p->an_cur_bssid[4], 3069 status_p->an_cur_bssid[5])); 3070 3071 return (err); 3072 } 3073 3074 /* 3075 * MAC_PROP_WL_LINKSTATUS 3076 */ 3077 static void 3078 pcan_get_linkstatus(pcan_maci_t *pcan_p, void *wldp_buf) 3079 { 3080 if (pcan_p->pcan_flag & PCAN_CARD_LINKUP) 3081 *(wl_linkstatus_t *)wldp_buf = WL_CONNECTED; 3082 else 3083 *(wl_linkstatus_t *)wldp_buf = WL_NOTCONNECTED; 3084 3085 } 3086 3087 /* 3088 * MAC_PROP_WL_BSSTYP 3089 */ 3090 static int 3091 pcan_set_bsstype(pcan_maci_t *pcan_p, const void *wldp_buf) 3092 { 3093 struct an_ltv_genconfig *cfg_p; 3094 3095 cfg_p = &pcan_p->an_config; 3096 3097 if (*(wl_bss_type_t *)wldp_buf == WL_BSS_BSS) 3098 cfg_p->an_opmode = AN_OPMODE_INFR_STATION; 3099 if (*(wl_bss_type_t *)wldp_buf == WL_BSS_IBSS) 3100 cfg_p->an_opmode = AN_OPMODE_IBSS_ADHOC; 3101 if (*(wl_bss_type_t *)wldp_buf == WL_BSS_ANY) 3102 cfg_p->an_opmode = AN_OPMODE_INFR_STATION; 3103 cfg_p->an_assoc_timeout = 5000; 3104 3105 return (ENETRESET); 3106 } 3107 3108 static void 3109 pcan_get_bsstype(pcan_maci_t *pcan_p, void *wldp_buf) 3110 { 3111 struct an_ltv_genconfig *cfg_p; 3112 3113 cfg_p = &pcan_p->an_config; 3114 3115 if (cfg_p->an_opmode == AN_OPMODE_INFR_STATION) { 3116 *(wl_bss_type_t *)wldp_buf = WL_BSS_BSS; 3117 } else if (cfg_p->an_opmode == AN_OPMODE_IBSS_ADHOC) { 3118 *(wl_bss_type_t *)wldp_buf = WL_BSS_IBSS; 3119 } 3120 } 3121 3122 /* 3123 * MAC_PROP_WL_PHY_CONFIG 3124 */ 3125 static int 3126 pcan_set_phy(pcan_maci_t *pcan_p, const void *wldp_buf) 3127 { 3128 uint16_t ret; 3129 int err = ENETRESET; 3130 wl_phy_conf_t *phy = (wl_phy_conf_t *)wldp_buf; 3131 struct an_ltv_genconfig *cfg_p; 3132 3133 cfg_p = &pcan_p->an_config; 3134 3135 ret = (uint16_t)(phy->wl_phy_dsss_conf.wl_dsss_channel); 3136 if (ret < 1 || ret > 14) { 3137 err = ENOTSUP; 3138 return (err); 3139 } 3140 cfg_p->an_ds_channel = ret; 3141 cfg_p->an_assoc_timeout = 5000; 3142 3143 return (err); 3144 } 3145 3146 static int 3147 pcan_get_phy(pcan_maci_t *pcan_p, void *wldp_buf) 3148 { 3149 int err = 0; 3150 struct an_ltv_status *status_p; 3151 wl_dsss_t *dsss = (wl_dsss_t *)wldp_buf; 3152 3153 status_p = &pcan_p->an_status; 3154 3155 if (pcan_status_ltv(PCAN_READ_LTV, pcan_p, status_p)) { 3156 err = EIO; 3157 return (err); 3158 } 3159 3160 dsss->wl_dsss_channel = status_p->an_channel_set; 3161 dsss->wl_dsss_subtype = WL_DSSS; 3162 3163 return (err); 3164 } 3165 3166 /* 3167 * MAC_PROP_WL_DESIRED_RATESa 3168 */ 3169 static int 3170 pcan_set_desrates(pcan_maci_t *pcan_p, const void *wldp_buf) 3171 { 3172 uint16_t i; 3173 struct an_ltv_genconfig *cfg_p; 3174 3175 cfg_p = &pcan_p->an_config; 3176 3177 bzero(cfg_p->an_rates, sizeof (cfg_p->an_rates)); 3178 for (i = 0; i < ((wl_rates_t *)wldp_buf)->wl_rates_num; i++) { 3179 cfg_p->an_rates[i] = 3180 (((wl_rates_t *)wldp_buf)->wl_rates_rates)[i]; 3181 } 3182 cfg_p->an_assoc_timeout = 5000; 3183 3184 return (ENETRESET); 3185 } 3186 3187 static int 3188 pcan_get_desrates(pcan_maci_t *pcan_p, void *wldp_buf) 3189 { 3190 uint16_t i; 3191 uint8_t rates = 0; 3192 int err = 0; 3193 struct an_ltv_genconfig *actcfg_p; 3194 3195 actcfg_p = &pcan_p->an_actual_config; 3196 3197 if (pcan_cfg_ltv(PCAN_READ_LTV, pcan_p, actcfg_p)) { 3198 err = EIO; 3199 return (err); 3200 } 3201 3202 for (i = 0; i < sizeof (actcfg_p->an_rates); i++) { 3203 if (actcfg_p->an_rates[i] == 0) 3204 break; 3205 rates = MAX(rates, actcfg_p->an_rates[i]); 3206 } 3207 (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] = rates; 3208 ((wl_rates_t *)wldp_buf)->wl_rates_num = 1; 3209 3210 return (err); 3211 } 3212 3213 /* 3214 * MAC_PROP_WL_SUP_RATE 3215 */ 3216 static void 3217 pcan_get_suprates(void *wldp_buf) 3218 { 3219 wl_rates_t *wl_rates = (wl_rates_t *)wldp_buf; 3220 3221 wl_rates->wl_rates_num = 4; 3222 wl_rates->wl_rates_rates[0] = WL_RATE_1M; 3223 wl_rates->wl_rates_rates[1] = WL_RATE_2M; 3224 wl_rates->wl_rates_rates[2] = WL_RATE_5_5M; 3225 wl_rates->wl_rates_rates[3] = WL_RATE_11M; 3226 } 3227 3228 /* 3229 * MAC_PROP_WL_POWER_MODE 3230 */ 3231 static int 3232 pcan_get_powermode(pcan_maci_t *pcan_p, void *wldp_buf) 3233 { 3234 int err = 0; 3235 wl_ps_mode_t *powermode = (wl_ps_mode_t *)wldp_buf; 3236 struct an_ltv_genconfig *actcfg_p; 3237 3238 actcfg_p = &pcan_p->an_actual_config; 3239 if (pcan_cfg_ltv(PCAN_READ_LTV, pcan_p, actcfg_p)) { 3240 err = EIO; 3241 return (err); 3242 } 3243 powermode->wl_ps_mode = actcfg_p->an_psave_mode; 3244 3245 return (err); 3246 } 3247 3248 /* 3249 * MAC_PROP_AUTH_MODE 3250 */ 3251 static int 3252 pcan_set_authmode(pcan_maci_t *pcan_p, const void *wldp_buf) 3253 { 3254 struct an_ltv_genconfig *cfg_p; 3255 int err = ENETRESET; 3256 3257 cfg_p = &pcan_p->an_config; 3258 if (*(wl_authmode_t *)wldp_buf == WL_OPENSYSTEM) { 3259 cfg_p->an_authtype |= AN_AUTHTYPE_OPEN; 3260 cfg_p->an_assoc_timeout = 5000; 3261 } else { 3262 err = EINVAL; 3263 } 3264 3265 return (err); 3266 } 3267 3268 static void 3269 pcan_get_authmode(pcan_maci_t *pcan_p, void *wldp_buf) 3270 { 3271 struct an_ltv_genconfig *cfg_p; 3272 3273 cfg_p = &pcan_p->an_config; 3274 if (cfg_p->an_authtype & AN_AUTHTYPE_SHAREDKEY) { 3275 *(wl_bss_type_t *)wldp_buf = WL_SHAREDKEY; 3276 } else { 3277 *(wl_bss_type_t *)wldp_buf = WL_OPENSYSTEM; 3278 } 3279 } 3280 3281 /* 3282 * MAC_PROP_WL_ENCRYPTION 3283 */ 3284 static int 3285 pcan_set_encrypt(pcan_maci_t *pcan_p, const void *wldp_buf) 3286 { 3287 struct an_ltv_genconfig *cfg_p; 3288 3289 cfg_p = &pcan_p->an_config; 3290 if (*(wl_encryption_t *)wldp_buf == WL_ENC_WEP) { 3291 cfg_p->an_authtype |= (AN_AUTHTYPE_ENABLEWEP | 3292 AN_AUTHTYPE_ALLOW_UNENCRYPTED); 3293 pcan_p->pcan_usewep = 1; 3294 } 3295 if (*(wl_authmode_t *)wldp_buf == WL_NOENCRYPTION) { 3296 cfg_p->an_authtype &= (~(AN_AUTHTYPE_ENABLEWEP | 3297 AN_AUTHTYPE_ALLOW_UNENCRYPTED)); 3298 pcan_p->pcan_usewep = 0; 3299 } 3300 cfg_p->an_assoc_timeout = 5000; 3301 3302 return (ENETRESET); 3303 } 3304 3305 static void 3306 pcan_get_encrypt(pcan_maci_t *pcan_p, void *wldp_buf) 3307 { 3308 struct an_ltv_genconfig *cfg_p; 3309 3310 cfg_p = &pcan_p->an_config; 3311 if (cfg_p->an_authtype & AN_AUTHTYPE_ENABLEWEP) { 3312 *(wl_bss_type_t *)wldp_buf = WL_ENC_WEP; 3313 } else { 3314 *(wl_bss_type_t *)wldp_buf = WL_NOENCRYPTION; 3315 } 3316 } 3317 3318 /* 3319 * MAC_PROP_WL_KEY_TAB 3320 */ 3321 static int 3322 pcan_set_wepkey(pcan_maci_t *pcan_p, const void *wldp_buf) 3323 { 3324 uint16_t i; 3325 wl_wep_key_t *p_wepkey_tab; 3326 struct an_ltv_wepkey *wepkey_p; 3327 3328 p_wepkey_tab = (wl_wep_key_t *)wldp_buf; 3329 for (i = 0; i < MAX_NWEPKEYS; i++) { 3330 if (p_wepkey_tab[i].wl_wep_operation == WL_ADD) { 3331 wepkey_p = &pcan_p->an_wepkey[i]; 3332 bzero(wepkey_p, sizeof (*wepkey_p)); 3333 wepkey_p->an_keylen = 3334 p_wepkey_tab[i].wl_wep_length; 3335 bcopy(p_wepkey_tab[i].wl_wep_key, 3336 wepkey_p->an_key, 3337 p_wepkey_tab[i].wl_wep_length); 3338 wepkey_p->an_index = i; 3339 wepkey_p->an_macaddr[0] = 1; 3340 } 3341 } 3342 3343 return (ENETRESET); 3344 } 3345 3346 /* 3347 * MAC_PROP_WL_RSSI 3348 */ 3349 static int 3350 pcan_get_rssi(pcan_maci_t *pcan_p, void *wldp_buf) 3351 { 3352 uint16_t val; 3353 int err = 0; 3354 wl_rssi_t *rssi = (wl_rssi_t *)wldp_buf; 3355 struct an_ltv_status *status_p; 3356 3357 status_p = &pcan_p->an_status; 3358 3359 if (val = pcan_status_ltv(PCAN_READ_LTV, pcan_p, status_p)) { 3360 err = EIO; 3361 return (err); 3362 } 3363 val = status_p->an_cur_signal_quality; 3364 PCANDBG((CE_NOTE, "pcan cfg_rssi: sl=%x", val)); 3365 /* 3366 * we reflect the value to 1-15 as rssi 3367 */ 3368 *rssi = 15 - ((val & 0xff) * 15 / 128 + 1); 3369 3370 return (err); 3371 } 3372 3373 /* 3374 * MAC_PROP_WL_RADIO 3375 */ 3376 static void 3377 pcan_get_radio(void *wldp_buf) 3378 { 3379 wl_radio_t *radio = (wl_radio_t *)wldp_buf; 3380 3381 *radio = B_TRUE; 3382 } 3383 3384 /* 3385 * MAC_PROP_WL_ESSLIST 3386 */ 3387 static void 3388 pcan_get_esslist(pcan_maci_t *pcan_p, void *wldp_buf) 3389 { 3390 uint16_t i; 3391 wl_ess_conf_t *p_ess_conf; 3392 an_scan_list_t *scan_item; 3393 3394 mutex_enter(&pcan_p->pcan_scanlist_lock); 3395 3396 ((wl_ess_list_t *)wldp_buf)->wl_ess_list_num = 3397 pcan_p->an_scan_num; 3398 scan_item = list_head(&pcan_p->an_scan_list); 3399 for (i = 0; i < pcan_p->an_scan_num; i++) { 3400 if (!scan_item) 3401 break; 3402 p_ess_conf = (wl_ess_conf_t *)((char *)wldp_buf + 3403 offsetof(wl_ess_list_t, wl_ess_list_ess) + 3404 i * sizeof (wl_ess_conf_t)); 3405 bcopy(scan_item->an_val.an_ssid, 3406 p_ess_conf->wl_ess_conf_essid.wl_essid_essid, 3407 mi_strlen(scan_item->an_val.an_ssid)); 3408 bcopy(scan_item->an_val.an_bssid, 3409 p_ess_conf->wl_ess_conf_bssid, 6); 3410 (p_ess_conf->wl_phy_conf).wl_phy_dsss_conf.wl_dsss_subtype 3411 = WL_DSSS; 3412 p_ess_conf->wl_ess_conf_wepenabled = 3413 (scan_item->an_val.an_cap & 0x10 ? 3414 WL_ENC_WEP : WL_NOENCRYPTION); 3415 p_ess_conf->wl_ess_conf_bsstype = 3416 (scan_item->an_val.an_cap & 0x1 ? 3417 WL_BSS_BSS : WL_BSS_IBSS); 3418 p_ess_conf->wl_phy_conf.wl_phy_dsss_conf.wl_dsss_channel = 3419 scan_item->an_val.an_dschannel; 3420 p_ess_conf->wl_ess_conf_sl = 15 - 3421 ((scan_item->an_val.an_rssi & 0xff) * 15 / 128); 3422 p_ess_conf->wl_supported_rates[0] = WL_RATE_1M; 3423 p_ess_conf->wl_supported_rates[1] = WL_RATE_2M; 3424 p_ess_conf->wl_supported_rates[2] = WL_RATE_5_5M; 3425 p_ess_conf->wl_supported_rates[3] = WL_RATE_11M; 3426 scan_item = list_next(&pcan_p->an_scan_list, scan_item); 3427 } 3428 3429 mutex_exit(&pcan_p->pcan_scanlist_lock); 3430 } 3431 3432 /* 3433 * for wificonfig and dlamd ioctl 3434 */ 3435 static int 3436 pcan_cfg_essid(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 3437 { 3438 uint16_t i; 3439 wldp_t *infp; 3440 wldp_t *outfp; 3441 char *buf; 3442 int iret; 3443 int err = 0; 3444 3445 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 3446 if (buf == NULL) { 3447 PCANDBG((CE_NOTE, "pcan cfg_essid: failed to alloc " 3448 "memory(%d)\n", MAX_BUF_LEN)); 3449 return (ENOMEM); 3450 } 3451 outfp = (wldp_t *)buf; 3452 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 3453 infp = (wldp_t *)mp->b_rptr; 3454 3455 if (cmd == WLAN_GET_PARAM) { 3456 err = pcan_get_essid(pcan_p, outfp->wldp_buf); 3457 if (err == EIO) { 3458 outfp->wldp_length = WIFI_BUF_OFFSET; 3459 outfp->wldp_result = WL_HW_ERROR; 3460 goto done; 3461 } 3462 outfp->wldp_result = WL_SUCCESS; 3463 } else if (cmd == WLAN_SET_PARAM) { 3464 (void) pcan_set_essid(pcan_p, infp->wldp_buf); 3465 outfp->wldp_length = WIFI_BUF_OFFSET; 3466 outfp->wldp_result = WL_SUCCESS; 3467 } else { 3468 kmem_free(buf, MAX_BUF_LEN); 3469 return (EINVAL); 3470 } 3471 3472 done: 3473 for (i = 0; i < (outfp->wldp_length); i++) { 3474 (void) mi_mpprintf_putc((char *)mp, buf[i]); 3475 } 3476 iret = (int)(outfp->wldp_result); 3477 kmem_free(buf, MAX_BUF_LEN); 3478 return (iret); 3479 } 3480 3481 static int 3482 pcan_cfg_bssid(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 3483 { 3484 uint16_t i; 3485 wldp_t *infp; 3486 wldp_t *outfp; 3487 char *buf; 3488 int iret; 3489 int err = 0; 3490 3491 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 3492 if (buf == NULL) { 3493 PCANDBG((CE_NOTE, "pcan cfg_bssid: failed to alloc " 3494 "memory(%d)\n", MAX_BUF_LEN)); 3495 return (ENOMEM); 3496 } 3497 outfp = (wldp_t *)buf; 3498 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 3499 infp = (wldp_t *)mp->b_rptr; 3500 3501 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_bssid_t); 3502 3503 if (cmd == WLAN_GET_PARAM) { 3504 err = pcan_get_bssid(pcan_p, outfp->wldp_buf); 3505 if (err == EIO) { 3506 outfp->wldp_length = WIFI_BUF_OFFSET; 3507 outfp->wldp_result = WL_HW_ERROR; 3508 goto done; 3509 } 3510 outfp->wldp_result = WL_SUCCESS; 3511 } else if (cmd == WLAN_SET_PARAM) { 3512 (void) pcan_set_bssid(pcan_p, infp->wldp_buf); 3513 outfp->wldp_length = WIFI_BUF_OFFSET; 3514 outfp->wldp_result = WL_SUCCESS; 3515 } else { 3516 kmem_free(buf, MAX_BUF_LEN); 3517 return (EINVAL); 3518 } 3519 3520 done: 3521 for (i = 0; i < (outfp->wldp_length); i++) { 3522 (void) mi_mpprintf_putc((char *)mp, buf[i]); 3523 } 3524 iret = (int)(outfp->wldp_result); 3525 kmem_free(buf, MAX_BUF_LEN); 3526 return (iret); 3527 } 3528 3529 /*ARGSUSED*/ 3530 static int 3531 pcan_cmd_scan(pcan_maci_t *pcan_p) 3532 { 3533 uint16_t i = 0, j, ret = WL_SUCCESS; 3534 uint8_t bssid_t[6]; 3535 uint32_t check_num, enable; 3536 an_scan_list_t *scan_item0; 3537 3538 enable = pcan_p->pcan_flag & PCAN_ENABLED; 3539 if ((!enable) && 3540 (ret = pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0))) { 3541 ret = (int)WL_HW_ERROR; 3542 goto exit; 3543 } 3544 if (ret = pcan_set_cmd(pcan_p, AN_CMD_SCAN, 0)) { 3545 ret = (int)WL_HW_ERROR; 3546 goto exit; 3547 } 3548 3549 pcan_delay(pcan_p, 500000); 3550 ret = pcan_scanresult_ltv(PCAN_READ_LTV, 3551 pcan_p, AN_RID_ESSIDLIST_FIRST, &pcan_p->an_scanresult[i]); 3552 if ((ret) || pcan_p->an_scanresult[i].an_index == 0xffff) { 3553 goto done; 3554 } 3555 do 3556 { 3557 i++; 3558 ret = pcan_scanresult_ltv(PCAN_READ_LTV, 3559 pcan_p, AN_RID_ESSIDLIST_NEXT, &pcan_p->an_scanresult[i]); 3560 } while ((!ret) && (i < 32) && 3561 (pcan_p->an_scanresult[i].an_index != 0xffff)); 3562 done: 3563 if ((!enable) && 3564 (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0))) { 3565 ret = (int)WL_HW_ERROR; 3566 goto exit; 3567 } 3568 /* record the scan result for future use */ 3569 bzero(bssid_t, sizeof (bssid_t)); 3570 for (j = 0; j < i; j++) { 3571 /* 3572 * sometimes, those empty items are recorded by hardware, 3573 * this is wrong, just ignore those items here. 3574 */ 3575 if (bcmp(pcan_p->an_scanresult[j].an_bssid, 3576 bssid_t, 6) == 0) { 3577 continue; 3578 } 3579 /* 3580 * save/update the scan item in scanlist 3581 */ 3582 mutex_enter(&pcan_p->pcan_scanlist_lock); 3583 check_num = 0; 3584 scan_item0 = list_head(&pcan_p->an_scan_list); 3585 if (scan_item0 == NULL) { 3586 if (pcan_add_scan_item(pcan_p, 3587 pcan_p->an_scanresult[j]) != 0) { 3588 mutex_exit(&pcan_p->pcan_scanlist_lock); 3589 return (WL_SUCCESS); 3590 } 3591 } 3592 for (; scan_item0; ) { 3593 if (bcmp(pcan_p->an_scanresult[j].an_bssid, 3594 scan_item0->an_val.an_bssid, 6) == 0) { 3595 scan_item0->an_val = pcan_p->an_scanresult[j]; 3596 scan_item0->an_timeout = AN_SCAN_TIMEOUT_MAX; 3597 break; 3598 } else { 3599 check_num++; 3600 } 3601 scan_item0 = list_next(&pcan_p->an_scan_list, 3602 scan_item0); 3603 } 3604 if (check_num == pcan_p->an_scan_num) { 3605 if (pcan_add_scan_item(pcan_p, 3606 pcan_p->an_scanresult[j]) != 0) { 3607 mutex_exit(&pcan_p->pcan_scanlist_lock); 3608 return (WL_SUCCESS); 3609 } 3610 } 3611 mutex_exit(&pcan_p->pcan_scanlist_lock); 3612 } 3613 exit: 3614 if (ret) 3615 cmn_err(CE_WARN, "pcan: scan failed due to hardware error"); 3616 return (ret); 3617 } 3618 3619 /*ARGSUSED*/ 3620 static int 3621 pcan_cfg_scan(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 3622 { 3623 wldp_t *outfp; 3624 char *buf; 3625 uint16_t i; 3626 3627 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 3628 if (buf == NULL) { 3629 PCANDBG((CE_NOTE, "pcan cfg_scanlist: failed to alloc " 3630 "memory(%d)\n", MAX_BUF_LEN)); 3631 return (ENOMEM); 3632 } 3633 outfp = (wldp_t *)buf; 3634 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 3635 3636 pcan_get_esslist(pcan_p, outfp->wldp_buf); 3637 3638 outfp->wldp_length = WIFI_BUF_OFFSET + 3639 offsetof(wl_ess_list_t, wl_ess_list_ess) + 3640 pcan_p->an_scan_num * sizeof (wl_ess_conf_t); 3641 outfp->wldp_result = WL_SUCCESS; 3642 for (i = 0; i < (outfp->wldp_length); i++) 3643 (void) mi_mpprintf_putc((char *)mp, buf[i]); 3644 kmem_free(buf, MAX_BUF_LEN); 3645 return (WL_SUCCESS); 3646 } 3647 3648 /*ARGSUSED*/ 3649 static int 3650 pcan_cfg_linkstatus(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 3651 { 3652 wldp_t *outfp; 3653 char *buf; 3654 uint16_t i; 3655 3656 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 3657 if (buf == NULL) { 3658 PCANDBG((CE_NOTE, "pcan cfg_linkstatus: failed to alloc " 3659 "memory(%d)\n", MAX_BUF_LEN)); 3660 return (ENOMEM); 3661 } 3662 outfp = (wldp_t *)buf; 3663 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 3664 3665 pcan_get_linkstatus(pcan_p, outfp->wldp_buf); 3666 3667 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_linkstatus_t); 3668 outfp->wldp_result = WL_SUCCESS; 3669 for (i = 0; i < (outfp->wldp_length); i++) 3670 (void) mi_mpprintf_putc((char *)mp, buf[i]); 3671 kmem_free(buf, MAX_BUF_LEN); 3672 return (WL_SUCCESS); 3673 } 3674 3675 static int 3676 pcan_cfg_bsstype(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 3677 { 3678 uint16_t i; 3679 wldp_t *infp; 3680 wldp_t *outfp; 3681 char *buf; 3682 int iret; 3683 3684 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 3685 if (buf == NULL) { 3686 PCANDBG((CE_NOTE, "pcan cfg_bsstype: failed to alloc " 3687 "memory(%d)\n", MAX_BUF_LEN)); 3688 return (ENOMEM); 3689 } 3690 outfp = (wldp_t *)buf; 3691 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 3692 infp = (wldp_t *)mp->b_rptr; 3693 3694 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_bss_type_t); 3695 3696 if (cmd == WLAN_GET_PARAM) { 3697 pcan_get_bsstype(pcan_p, outfp->wldp_buf); 3698 outfp->wldp_result = WL_SUCCESS; 3699 } else if (cmd == WLAN_SET_PARAM) { 3700 (void) pcan_set_bsstype(pcan_p, infp->wldp_buf); 3701 outfp->wldp_result = WL_SUCCESS; 3702 } else { 3703 kmem_free(buf, MAX_BUF_LEN); 3704 return (EINVAL); 3705 } 3706 3707 for (i = 0; i < (outfp->wldp_length); i++) 3708 (void) mi_mpprintf_putc((char *)mp, buf[i]); 3709 iret = (int)(outfp->wldp_result); 3710 kmem_free(buf, MAX_BUF_LEN); 3711 return (iret); 3712 } 3713 3714 static int 3715 pcan_cfg_phy(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 3716 { 3717 uint16_t i; 3718 wldp_t *infp; 3719 wldp_t *outfp; 3720 char *buf; 3721 int iret; 3722 int err = 0; 3723 3724 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 3725 if (buf == NULL) { 3726 PCANDBG((CE_NOTE, "pcan cfg_phy: failed to alloc " 3727 "memory(%d)\n", MAX_BUF_LEN)); 3728 return (ENOMEM); 3729 } 3730 outfp = (wldp_t *)buf; 3731 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 3732 infp = (wldp_t *)mp->b_rptr; 3733 3734 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_dsss_t); 3735 3736 if (cmd == WLAN_GET_PARAM) { 3737 err = pcan_get_phy(pcan_p, outfp->wldp_buf); 3738 if (err == EIO) { 3739 outfp->wldp_length = WIFI_BUF_OFFSET; 3740 outfp->wldp_result = WL_HW_ERROR; 3741 goto done; 3742 } 3743 outfp->wldp_result = WL_SUCCESS; 3744 } else if (cmd == WLAN_SET_PARAM) { 3745 err = pcan_set_phy(pcan_p, infp->wldp_buf); 3746 if (err == ENOTSUP) { 3747 outfp->wldp_result = WL_NOTSUPPORTED; 3748 goto done; 3749 } 3750 outfp->wldp_result = WL_SUCCESS; 3751 } else { 3752 kmem_free(buf, MAX_BUF_LEN); 3753 return (EINVAL); 3754 } 3755 3756 done: 3757 for (i = 0; i < (outfp->wldp_length); i++) 3758 (void) mi_mpprintf_putc((char *)mp, buf[i]); 3759 iret = (int)(outfp->wldp_result); 3760 kmem_free(buf, MAX_BUF_LEN); 3761 return (iret); 3762 3763 } 3764 3765 /*ARGSUSED*/ 3766 static int 3767 pcan_cfg_desiredrates(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 3768 { 3769 uint16_t i; 3770 wldp_t *infp; 3771 wldp_t *outfp; 3772 char *buf; 3773 int iret; 3774 int err = 0; 3775 3776 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 3777 if (buf == NULL) { 3778 PCANDBG((CE_NOTE, "pcan cfg_rates: failed to alloc " 3779 "memory(%d)\n", MAX_BUF_LEN)); 3780 return (ENOMEM); 3781 } 3782 outfp = (wldp_t *)buf; 3783 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 3784 infp = (wldp_t *)mp->b_rptr; 3785 3786 if (cmd == WLAN_GET_PARAM) { 3787 err = pcan_get_desrates(pcan_p, outfp->wldp_buf); 3788 if (err == EIO) { 3789 outfp->wldp_length = WIFI_BUF_OFFSET; 3790 outfp->wldp_result = WL_HW_ERROR; 3791 goto done; 3792 } 3793 outfp->wldp_length = WIFI_BUF_OFFSET + 3794 offsetof(wl_rates_t, wl_rates_rates) + sizeof (char); 3795 outfp->wldp_result = WL_SUCCESS; 3796 } else if (cmd == WLAN_SET_PARAM) { 3797 (void) pcan_set_desrates(pcan_p, infp->wldp_buf); 3798 outfp->wldp_length = WIFI_BUF_OFFSET; 3799 outfp->wldp_result = WL_SUCCESS; 3800 } else { 3801 kmem_free(buf, MAX_BUF_LEN); 3802 return (EINVAL); 3803 } 3804 3805 done: 3806 for (i = 0; i < (outfp->wldp_length); i++) 3807 (void) mi_mpprintf_putc((char *)mp, buf[i]); 3808 iret = (int)(outfp->wldp_result); 3809 kmem_free(buf, MAX_BUF_LEN); 3810 return (iret); 3811 } 3812 3813 /*ARGSUSED*/ 3814 static int 3815 pcan_cfg_supportrates(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 3816 { 3817 uint16_t i; 3818 int iret; 3819 wldp_t *outfp; 3820 char *buf; 3821 3822 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 3823 if (buf == NULL) { 3824 PCANDBG((CE_NOTE, "pcan cfg_supportedrates: failed to alloc " 3825 "memory(%d)\n", MAX_BUF_LEN)); 3826 return (ENOMEM); 3827 } 3828 outfp = (wldp_t *)buf; 3829 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 3830 3831 if (cmd == WLAN_GET_PARAM) { 3832 pcan_get_suprates(outfp->wldp_buf); 3833 outfp->wldp_length = WIFI_BUF_OFFSET + 3834 offsetof(wl_rates_t, wl_rates_rates) + 3835 4 * sizeof (char); 3836 outfp->wldp_result = WL_SUCCESS; 3837 } else { 3838 kmem_free(buf, MAX_BUF_LEN); 3839 return (EINVAL); 3840 } 3841 3842 done: 3843 for (i = 0; i < (outfp->wldp_length); i++) 3844 (void) mi_mpprintf_putc((char *)mp, buf[i]); 3845 iret = (int)(outfp->wldp_result); 3846 kmem_free(buf, MAX_BUF_LEN); 3847 return (iret); 3848 } 3849 3850 /*ARGSUSED*/ 3851 static int 3852 pcan_cfg_powermode(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 3853 { 3854 uint16_t i; 3855 wldp_t *outfp; 3856 char *buf; 3857 int iret; 3858 int err = 0; 3859 3860 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 3861 if (buf == NULL) { 3862 PCANDBG((CE_NOTE, "pcan cfg_powermode: failed to alloc " 3863 "memory(%d)\n", MAX_BUF_LEN)); 3864 return (ENOMEM); 3865 } 3866 outfp = (wldp_t *)buf; 3867 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 3868 3869 if (cmd == WLAN_GET_PARAM) { 3870 err = pcan_get_powermode(pcan_p, outfp->wldp_buf); 3871 if (err == EIO) { 3872 outfp->wldp_length = WIFI_BUF_OFFSET; 3873 outfp->wldp_result = WL_HW_ERROR; 3874 goto done; 3875 } 3876 outfp->wldp_length = WIFI_BUF_OFFSET + 3877 sizeof (wl_ps_mode_t); 3878 outfp->wldp_result = WL_SUCCESS; 3879 } else if (cmd == WLAN_SET_PARAM) { 3880 outfp->wldp_length = WIFI_BUF_OFFSET; 3881 outfp->wldp_result = WL_LACK_FEATURE; 3882 } else { 3883 kmem_free(buf, MAX_BUF_LEN); 3884 return (EINVAL); 3885 } 3886 3887 done: 3888 for (i = 0; i < (outfp->wldp_length); i++) 3889 (void) mi_mpprintf_putc((char *)mp, buf[i]); 3890 iret = (int)(outfp->wldp_result); 3891 kmem_free(buf, MAX_BUF_LEN); 3892 return (iret); 3893 3894 } 3895 3896 static int 3897 pcan_cfg_authmode(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 3898 { 3899 uint16_t i; 3900 wldp_t *outfp; 3901 char *buf; 3902 int iret; 3903 int err = 0; 3904 struct an_ltv_genconfig *actcfg_p; 3905 3906 actcfg_p = &pcan_p->an_actual_config; 3907 3908 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 3909 if (buf == NULL) { 3910 PCANDBG((CE_NOTE, "pcan cfg_autymode: failed to alloc " 3911 "memory(%d)\n", MAX_BUF_LEN)); 3912 return (ENOMEM); 3913 } 3914 outfp = (wldp_t *)buf; 3915 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 3916 3917 if (cmd == WLAN_GET_PARAM) { 3918 pcan_get_authmode(pcan_p, outfp->wldp_buf); 3919 outfp->wldp_result = WL_SUCCESS; 3920 } else if (cmd == WLAN_SET_PARAM) { 3921 err = pcan_set_authmode(pcan_p, outfp->wldp_buf); 3922 if (err == EINVAL) { 3923 outfp->wldp_length = WIFI_BUF_OFFSET; 3924 outfp->wldp_result = WL_LACK_FEATURE; 3925 } else { 3926 outfp->wldp_length = WIFI_BUF_OFFSET; 3927 outfp->wldp_result = WL_SUCCESS; 3928 } 3929 } else { 3930 kmem_free(buf, MAX_BUF_LEN); 3931 return (EINVAL); 3932 } 3933 PCANDBG((CE_NOTE, "pcan cfg_authmode: actual.authmode=%x", 3934 actcfg_p->an_authtype)); 3935 PCANDBG((CE_NOTE, "pcan cfg_authmode: actual.home_product=%x", 3936 actcfg_p->an_rsvd6[2])); 3937 3938 for (i = 0; i < (outfp->wldp_length); i++) 3939 (void) mi_mpprintf_putc((char *)mp, buf[i]); 3940 iret = (int)(outfp->wldp_result); 3941 kmem_free(buf, MAX_BUF_LEN); 3942 return (iret); 3943 } 3944 3945 static int 3946 pcan_cfg_encryption(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 3947 { 3948 uint16_t i; 3949 wldp_t *outfp; 3950 char *buf; 3951 int iret; 3952 3953 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 3954 if (buf == NULL) { 3955 PCANDBG((CE_NOTE, "pcan cfg_encryption: failed to alloc " 3956 "memory(%d)\n", MAX_BUF_LEN)); 3957 return (ENOMEM); 3958 } 3959 outfp = (wldp_t *)buf; 3960 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 3961 3962 if (cmd == WLAN_GET_PARAM) { 3963 pcan_get_encrypt(pcan_p, outfp->wldp_buf); 3964 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_encryption_t); 3965 outfp->wldp_result = WL_SUCCESS; 3966 } else if (cmd == WLAN_SET_PARAM) { 3967 (void) pcan_set_encrypt(pcan_p, outfp->wldp_buf); 3968 outfp->wldp_length = WIFI_BUF_OFFSET; 3969 outfp->wldp_result = WL_SUCCESS; 3970 } else { 3971 kmem_free(buf, MAX_BUF_LEN); 3972 return (EINVAL); 3973 } 3974 3975 for (i = 0; i < (outfp->wldp_length); i++) 3976 (void) mi_mpprintf_putc((char *)mp, buf[i]); 3977 iret = (int)(outfp->wldp_result); 3978 kmem_free(buf, MAX_BUF_LEN); 3979 return (iret); 3980 } 3981 3982 static int 3983 pcan_cfg_wepkeyid(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 3984 { 3985 uint16_t i, ret; 3986 wldp_t *infp; 3987 wldp_t *outfp; 3988 char *buf; 3989 int iret; 3990 struct an_ltv_wepkey wepkey; 3991 3992 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 3993 if (buf == NULL) { 3994 PCANDBG((CE_NOTE, "pcan cfg_wepkeyid: failed to alloc " 3995 "memory(%d)\n", MAX_BUF_LEN)); 3996 return (ENOMEM); 3997 } 3998 outfp = (wldp_t *)buf; 3999 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 4000 infp = (wldp_t *)mp->b_rptr; 4001 4002 if (cmd == WLAN_GET_PARAM) { 4003 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_wep_key_id_t); 4004 outfp->wldp_result = WL_SUCCESS; 4005 *(wl_wep_key_id_t *)(outfp->wldp_buf) = pcan_p->an_cur_wepkey; 4006 } else if (cmd == WLAN_SET_PARAM) { 4007 ret = (uint16_t)(*(wl_wep_key_id_t *)(infp->wldp_buf)); 4008 if (ret > 3) { 4009 kmem_free(buf, MAX_BUF_LEN); 4010 return (EINVAL); 4011 } 4012 wepkey.an_index = 0xffff; 4013 wepkey.an_macaddr[0] = ret & 0xff; 4014 pcan_p->an_cur_wepkey = ret; 4015 outfp->wldp_length = WIFI_BUF_OFFSET; 4016 outfp->wldp_result = WL_SUCCESS; 4017 } else { 4018 kmem_free(buf, MAX_BUF_LEN); 4019 return (EINVAL); 4020 } 4021 for (i = 0; i < (outfp->wldp_length); i++) 4022 (void) mi_mpprintf_putc((char *)mp, buf[i]); 4023 iret = (int)(outfp->wldp_result); 4024 kmem_free(buf, MAX_BUF_LEN); 4025 return (iret); 4026 } 4027 4028 /*ARGSUSED*/ 4029 static int 4030 pcan_cfg_createibss(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 4031 { 4032 uint16_t i; 4033 wldp_t *outfp; 4034 char *buf; 4035 int iret; 4036 4037 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 4038 if (buf == NULL) { 4039 PCANDBG((CE_NOTE, "pcan cfg_createibss: failed to alloc " 4040 "memory(%d)\n", MAX_BUF_LEN)); 4041 return (ENOMEM); 4042 } 4043 outfp = (wldp_t *)buf; 4044 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 4045 4046 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_create_ibss_t); 4047 outfp->wldp_result = WL_LACK_FEATURE; 4048 for (i = 0; i < (outfp->wldp_length); i++) 4049 (void) mi_mpprintf_putc((char *)mp, buf[i]); 4050 iret = (int)(outfp->wldp_result); 4051 kmem_free(buf, MAX_BUF_LEN); 4052 return (iret); 4053 } 4054 4055 static int 4056 pcan_cfg_rssi(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 4057 { 4058 uint16_t i; 4059 int iret; 4060 wldp_t *outfp; 4061 char *buf; 4062 int err = 0; 4063 4064 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 4065 if (buf == NULL) { 4066 PCANDBG((CE_NOTE, "pcan cfg_rssi: failed to alloc " 4067 "memory(%d)\n", MAX_BUF_LEN)); 4068 return (ENOMEM); 4069 } 4070 outfp = (wldp_t *)buf; 4071 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 4072 4073 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_rssi_t); 4074 4075 if (cmd == WLAN_GET_PARAM) { 4076 err = pcan_get_rssi(pcan_p, outfp->wldp_buf); 4077 if (err == EIO) { 4078 outfp->wldp_length = WIFI_BUF_OFFSET; 4079 outfp->wldp_result = WL_HW_ERROR; 4080 goto done; 4081 } 4082 outfp->wldp_result = WL_SUCCESS; 4083 } else if (cmd == WLAN_SET_PARAM) { 4084 outfp->wldp_result = WL_READONLY; 4085 } else { 4086 kmem_free(buf, MAX_BUF_LEN); 4087 return (EINVAL); 4088 } 4089 4090 done: 4091 for (i = 0; i < (outfp->wldp_length); i++) 4092 (void) mi_mpprintf_putc((char *)mp, buf[i]); 4093 iret = (int)(outfp->wldp_result); 4094 kmem_free(buf, MAX_BUF_LEN); 4095 return (iret); 4096 } 4097 4098 /*ARGSUSED*/ 4099 static int 4100 pcan_cfg_radio(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 4101 { 4102 uint16_t i; 4103 int iret; 4104 wldp_t *outfp; 4105 char *buf; 4106 4107 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 4108 if (buf == NULL) { 4109 PCANDBG((CE_NOTE, "pcan cfg_radio: failed to alloc " 4110 "memory(%d)\n", MAX_BUF_LEN)); 4111 return (ENOMEM); 4112 } 4113 outfp = (wldp_t *)buf; 4114 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 4115 4116 if (cmd == WLAN_GET_PARAM) { 4117 *(wl_radio_t *)(outfp->wldp_buf) = B_TRUE; 4118 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_radio_t); 4119 outfp->wldp_result = WL_SUCCESS; 4120 } else if (cmd == WLAN_SET_PARAM) { 4121 outfp->wldp_length = WIFI_BUF_OFFSET; 4122 outfp->wldp_result = WL_LACK_FEATURE; 4123 } else { 4124 kmem_free(buf, MAX_BUF_LEN); 4125 return (EINVAL); 4126 } 4127 4128 for (i = 0; i < (outfp->wldp_length); i++) 4129 (void) mi_mpprintf_putc((char *)mp, buf[i]); 4130 iret = (int)(outfp->wldp_result); 4131 kmem_free(buf, MAX_BUF_LEN); 4132 return (iret); 4133 } 4134 4135 static int 4136 pcan_cfg_wepkey(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 4137 { 4138 uint16_t i; 4139 wldp_t *outfp; 4140 char *buf; 4141 int iret; 4142 wldp_t *infp; 4143 4144 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 4145 if (buf == NULL) { 4146 PCANDBG((CE_NOTE, "pcan cfg_wep: failed to alloc " 4147 "memory(%d)\n", MAX_BUF_LEN)); 4148 return (ENOMEM); 4149 } 4150 outfp = (wldp_t *)buf; 4151 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 4152 infp = (wldp_t *)mp->b_rptr; 4153 4154 if (cmd == WLAN_GET_PARAM) { 4155 outfp->wldp_length = WIFI_BUF_OFFSET + 4156 sizeof (wl_wep_key_tab_t); 4157 outfp->wldp_result = WL_WRITEONLY; 4158 } else if (cmd == WLAN_SET_PARAM) { 4159 (void) pcan_set_wepkey(pcan_p, infp->wldp_buf); 4160 outfp->wldp_length = WIFI_BUF_OFFSET; 4161 outfp->wldp_result = WL_SUCCESS; 4162 } else { 4163 kmem_free(buf, MAX_BUF_LEN); 4164 return (EINVAL); 4165 } 4166 4167 for (i = 0; i < (outfp->wldp_length); i++) 4168 (void) mi_mpprintf_putc((char *)mp, buf[i]); 4169 iret = (int)(outfp->wldp_result); 4170 kmem_free(buf, MAX_BUF_LEN); 4171 return (iret); 4172 } 4173 4174 static void 4175 pcan_connect_timeout(void *arg) 4176 { 4177 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 4178 uint16_t ret; 4179 4180 mutex_enter(&pcan_p->pcan_glock); 4181 if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) 4182 goto done; 4183 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP; 4184 if (ret = pcan_config_mac(pcan_p)) 4185 goto done; 4186 ret = pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0); 4187 done: 4188 if (ret) 4189 cmn_err(CE_WARN, "pcan: connect failed due to hardware error"); 4190 mutex_exit(&pcan_p->pcan_glock); 4191 pcan_p->pcan_connect_timeout_id = 0; 4192 } 4193 4194 static int 4195 pcan_getset(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 4196 { 4197 int ret = WL_SUCCESS; 4198 int connect = 0; 4199 4200 mutex_enter(&pcan_p->pcan_glock); 4201 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) { 4202 mutex_exit(&pcan_p->pcan_glock); 4203 return (PCAN_FAIL); 4204 } 4205 4206 switch (((wldp_t *)mp->b_rptr)->wldp_id) { 4207 case WL_ESSID: 4208 ret = pcan_cfg_essid(mp, pcan_p, cmd); 4209 connect = 1; 4210 PCANDBG((CE_NOTE, "cfg_essid\n")); 4211 break; 4212 case WL_BSSID: 4213 ret = pcan_cfg_bssid(mp, pcan_p, cmd); 4214 connect = 1; 4215 PCANDBG((CE_NOTE, "cfg_bssid\n")); 4216 break; 4217 case WL_ESS_LIST: 4218 ret = pcan_cfg_scan(mp, pcan_p, cmd); 4219 PCANDBG((CE_NOTE, "cfg_scan\n")); 4220 break; 4221 case WL_LINKSTATUS: 4222 ret = pcan_cfg_linkstatus(mp, pcan_p, cmd); 4223 PCANDBG((CE_NOTE, "cfg_linkstatus\n")); 4224 break; 4225 case WL_BSS_TYPE: 4226 ret = pcan_cfg_bsstype(mp, pcan_p, cmd); 4227 connect = 1; 4228 PCANDBG((CE_NOTE, "cfg_bsstype\n")); 4229 break; 4230 case WL_PHY_CONFIG: 4231 ret = pcan_cfg_phy(mp, pcan_p, cmd); 4232 connect = 1; 4233 PCANDBG((CE_NOTE, "cfg_phy\n")); 4234 break; 4235 case WL_DESIRED_RATES: 4236 ret = pcan_cfg_desiredrates(mp, pcan_p, cmd); 4237 connect = 1; 4238 PCANDBG((CE_NOTE, "cfg_disred-rates\n")); 4239 break; 4240 case WL_SUPPORTED_RATES: 4241 ret = pcan_cfg_supportrates(mp, pcan_p, cmd); 4242 PCANDBG((CE_NOTE, "cfg_supported-rates\n")); 4243 break; 4244 case WL_POWER_MODE: 4245 ret = pcan_cfg_powermode(mp, pcan_p, cmd); 4246 PCANDBG((CE_NOTE, "cfg_powermode\n")); 4247 break; 4248 case WL_AUTH_MODE: 4249 ret = pcan_cfg_authmode(mp, pcan_p, cmd); 4250 connect = 1; 4251 PCANDBG((CE_NOTE, "cfg_authmode\n")); 4252 break; 4253 case WL_ENCRYPTION: 4254 ret = pcan_cfg_encryption(mp, pcan_p, cmd); 4255 connect = 1; 4256 PCANDBG((CE_NOTE, "cfg_encryption\n")); 4257 break; 4258 case WL_WEP_KEY_ID: 4259 ret = pcan_cfg_wepkeyid(mp, pcan_p, cmd); 4260 connect = 1; 4261 PCANDBG((CE_NOTE, "cfg_wepkeyid\n")); 4262 break; 4263 case WL_CREATE_IBSS: 4264 ret = pcan_cfg_createibss(mp, pcan_p, cmd); 4265 connect = 1; 4266 PCANDBG((CE_NOTE, "cfg_create-ibss\n")); 4267 break; 4268 case WL_RSSI: 4269 ret = pcan_cfg_rssi(mp, pcan_p, cmd); 4270 PCANDBG((CE_NOTE, "cfg_rssi\n")); 4271 break; 4272 case WL_RADIO: 4273 ret = pcan_cfg_radio(mp, pcan_p, cmd); 4274 PCANDBG((CE_NOTE, "cfg_radio\n")); 4275 break; 4276 case WL_WEP_KEY_TAB: 4277 ret = pcan_cfg_wepkey(mp, pcan_p, cmd); 4278 connect = 1; 4279 PCANDBG((CE_NOTE, "cfg_wepkey\n")); 4280 break; 4281 case WL_SCAN: 4282 mutex_exit(&pcan_p->pcan_glock); 4283 if (pcan_p->pcan_connect_timeout_id != 0) { 4284 (void) untimeout(pcan_p->pcan_connect_timeout_id); 4285 pcan_p->pcan_connect_timeout_id = 0; 4286 } 4287 mutex_enter(&pcan_p->pcan_glock); 4288 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) { 4289 mutex_exit(&pcan_p->pcan_glock); 4290 return (PCAN_FAIL); 4291 } 4292 ret = pcan_cmd_scan(pcan_p); 4293 /* 4294 * a trick here. 4295 * since the scan doesn't return too many items due to hardware 4296 * reason, so the current scan result is an accumulation of 4297 * several scans. For the first time or after many of the items 4298 * aged, we scan again if too few items now in the scan table. 4299 */ 4300 if (pcan_p->an_scan_num < AN_SCAN_AGAIN_THRESHOLD) 4301 ret = pcan_cmd_scan(pcan_p); 4302 break; 4303 case WL_LOAD_DEFAULTS: 4304 if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) { 4305 ret = (int)WL_HW_ERROR; 4306 break; 4307 } 4308 if (ret = pcan_loaddef(pcan_p)) { 4309 ret = (int)WL_HW_ERROR; 4310 break; 4311 } 4312 if (ret = pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0)) { 4313 ret = (int)WL_HW_ERROR; 4314 break; 4315 } 4316 PCANDBG((CE_NOTE, "loaddef\n")); 4317 break; 4318 case WL_DISASSOCIATE: 4319 mutex_exit(&pcan_p->pcan_glock); 4320 if (pcan_p->pcan_connect_timeout_id != 0) { 4321 (void) untimeout(pcan_p->pcan_connect_timeout_id); 4322 pcan_p->pcan_connect_timeout_id = 0; 4323 } 4324 mutex_enter(&pcan_p->pcan_glock); 4325 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) { 4326 mutex_exit(&pcan_p->pcan_glock); 4327 return (PCAN_FAIL); 4328 } 4329 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP; 4330 if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) { 4331 ret = (int)WL_HW_ERROR; 4332 break; 4333 } 4334 if (ret = pcan_loaddef(pcan_p)) { 4335 ret = (int)WL_HW_ERROR; 4336 break; 4337 } 4338 PCANDBG((CE_NOTE, "disassociate\n")); 4339 break; 4340 case WL_REASSOCIATE: 4341 case WL_ASSOCIAT: 4342 mutex_exit(&pcan_p->pcan_glock); 4343 if (pcan_p->pcan_connect_timeout_id != 0) { 4344 (void) untimeout(pcan_p->pcan_connect_timeout_id); 4345 pcan_p->pcan_connect_timeout_id = 0; 4346 } 4347 mutex_enter(&pcan_p->pcan_glock); 4348 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) { 4349 mutex_exit(&pcan_p->pcan_glock); 4350 return (PCAN_FAIL); 4351 } 4352 if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) { 4353 ret = (int)WL_HW_ERROR; 4354 break; 4355 } 4356 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP; 4357 if (ret = pcan_config_mac(pcan_p)) { 4358 ret = (int)WL_HW_ERROR; 4359 break; 4360 } 4361 if (ret = pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0)) { 4362 ret = (int)WL_HW_ERROR; 4363 break; 4364 } 4365 PCANDBG((CE_NOTE, "associate")); 4366 break; 4367 4368 default: 4369 break; 4370 } 4371 mutex_exit(&pcan_p->pcan_glock); 4372 if ((cmd == WLAN_SET_PARAM) && (ret == WL_SUCCESS) && (connect)) { 4373 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP; 4374 (void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0); 4375 if (pcan_p->pcan_connect_timeout_id != 0) { 4376 (void) untimeout(pcan_p->pcan_connect_timeout_id); 4377 pcan_p->pcan_connect_timeout_id = 0; 4378 } 4379 pcan_p->pcan_connect_timeout_id = timeout(pcan_connect_timeout, 4380 pcan_p, drv_usectohz(1000000)); 4381 } 4382 return (ret); 4383 } 4384 4385 static void 4386 pcan_wlan_ioctl(pcan_maci_t *pcan_p, queue_t *wq, mblk_t *mp, uint32_t cmd) 4387 { 4388 4389 struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 4390 uint32_t len, ret; 4391 mblk_t *mp1; 4392 4393 /* sanity check */ 4394 if (iocp->ioc_count == 0 || !(mp1 = mp->b_cont)) { 4395 miocnak(wq, mp, 0, EINVAL); 4396 return; 4397 } 4398 4399 /* assuming single data block */ 4400 if (mp1->b_cont) { 4401 freemsg(mp1->b_cont); 4402 mp1->b_cont = NULL; 4403 } 4404 4405 /* we will overwrite everything */ 4406 mp1->b_wptr = mp1->b_rptr; 4407 4408 ret = pcan_getset(mp1, pcan_p, cmd); 4409 len = msgdsize(mp1); 4410 miocack(wq, mp, len, ret); 4411 } 4412 4413 static void 4414 pcan_ioctl(void *arg, queue_t *wq, mblk_t *mp) 4415 { 4416 struct iocblk *iocp; 4417 uint32_t cmd, ret; 4418 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 4419 boolean_t need_privilege = B_TRUE; 4420 4421 iocp = (struct iocblk *)mp->b_rptr; 4422 iocp->ioc_error = 0; 4423 cmd = iocp->ioc_cmd; 4424 switch (cmd) { 4425 default: 4426 miocnak(wq, mp, 0, EINVAL); 4427 return; 4428 case WLAN_GET_PARAM: 4429 need_privilege = B_FALSE; 4430 break; 4431 case WLAN_SET_PARAM: 4432 case WLAN_COMMAND: 4433 break; 4434 } 4435 4436 if (need_privilege && (ret = secpolicy_dl_config(iocp->ioc_cr)) != 0) 4437 miocnak(wq, mp, 0, ret); 4438 else 4439 pcan_wlan_ioctl(pcan_p, wq, mp, cmd); 4440 } 4441 /* 4442 * brussels 4443 */ 4444 /* ARGSUSED */ 4445 static int 4446 pcan_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num, 4447 uint_t wldp_length, const void *wldp_buf) 4448 { 4449 int err = 0; 4450 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 4451 4452 mutex_enter(&pcan_p->pcan_glock); 4453 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) { 4454 mutex_exit(&pcan_p->pcan_glock); 4455 err = EINVAL; 4456 return (err); 4457 } 4458 4459 switch (wldp_pr_num) { 4460 /* mac_prop_id */ 4461 case MAC_PROP_WL_ESSID: 4462 err = pcan_set_essid(pcan_p, wldp_buf); 4463 break; 4464 case MAC_PROP_WL_BSSID: 4465 err = pcan_set_bssid(pcan_p, wldp_buf); 4466 break; 4467 case MAC_PROP_WL_PHY_CONFIG: 4468 err = pcan_set_phy(pcan_p, wldp_buf); 4469 break; 4470 case MAC_PROP_WL_KEY_TAB: 4471 err = pcan_set_wepkey(pcan_p, wldp_buf); 4472 break; 4473 case MAC_PROP_WL_AUTH_MODE: 4474 err = pcan_set_authmode(pcan_p, wldp_buf); 4475 break; 4476 case MAC_PROP_WL_ENCRYPTION: 4477 err = pcan_set_encrypt(pcan_p, wldp_buf); 4478 break; 4479 case MAC_PROP_WL_BSSTYPE: 4480 err = pcan_set_bsstype(pcan_p, wldp_buf); 4481 break; 4482 case MAC_PROP_WL_DESIRED_RATES: 4483 err = pcan_set_desrates(pcan_p, wldp_buf); 4484 break; 4485 case MAC_PROP_WL_POWER_MODE: 4486 case MAC_PROP_WL_CREATE_IBSS: 4487 case MAC_PROP_WL_RADIO: 4488 case MAC_PROP_WL_WPA: 4489 case MAC_PROP_WL_KEY: 4490 case MAC_PROP_WL_DELKEY: 4491 case MAC_PROP_WL_SETOPTIE: 4492 case MAC_PROP_WL_MLME: 4493 case MAC_PROP_WL_LINKSTATUS: 4494 case MAC_PROP_WL_ESS_LIST: 4495 case MAC_PROP_WL_SUPPORTED_RATES: 4496 case MAC_PROP_WL_RSSI: 4497 case MAC_PROP_WL_CAPABILITY: 4498 case MAC_PROP_WL_SCANRESULTS: 4499 cmn_err(CE_WARN, "pcan_setprop:" 4500 "opmode not support\n"); 4501 err = ENOTSUP; 4502 break; 4503 default: 4504 cmn_err(CE_WARN, "pcan_setprop:" 4505 "opmode err\n"); 4506 err = EINVAL; 4507 break; 4508 } 4509 4510 mutex_exit(&pcan_p->pcan_glock); 4511 4512 if (err == ENETRESET) { 4513 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP; 4514 (void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0); 4515 if (pcan_p->pcan_connect_timeout_id != 0) { 4516 (void) untimeout(pcan_p->pcan_connect_timeout_id); 4517 pcan_p->pcan_connect_timeout_id = 0; 4518 } 4519 pcan_p->pcan_connect_timeout_id = timeout(pcan_connect_timeout, 4520 pcan_p, drv_usectohz(1000000)); 4521 4522 err = 0; 4523 } 4524 4525 return (err); 4526 } /* ARGSUSED */ 4527 4528 /* ARGSUSED */ 4529 static int 4530 pcan_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num, 4531 uint_t wldp_length, void *wldp_buf) 4532 { 4533 int err = 0; 4534 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 4535 4536 mutex_enter(&pcan_p->pcan_glock); 4537 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) { 4538 mutex_exit(&pcan_p->pcan_glock); 4539 err = EINVAL; 4540 return (err); 4541 } 4542 4543 switch (wldp_pr_num) { 4544 /* mac_prop_id */ 4545 case MAC_PROP_WL_ESSID: 4546 err = pcan_get_essid(pcan_p, wldp_buf); 4547 break; 4548 case MAC_PROP_WL_BSSID: 4549 err = pcan_get_bssid(pcan_p, wldp_buf); 4550 break; 4551 case MAC_PROP_WL_PHY_CONFIG: 4552 err = pcan_get_phy(pcan_p, wldp_buf); 4553 break; 4554 case MAC_PROP_WL_AUTH_MODE: 4555 pcan_get_authmode(pcan_p, wldp_buf); 4556 break; 4557 case MAC_PROP_WL_ENCRYPTION: 4558 pcan_get_encrypt(pcan_p, wldp_buf); 4559 break; 4560 case MAC_PROP_WL_BSSTYPE: 4561 pcan_get_bsstype(pcan_p, wldp_buf); 4562 break; 4563 case MAC_PROP_WL_LINKSTATUS: 4564 pcan_get_linkstatus(pcan_p, wldp_buf); 4565 break; 4566 case MAC_PROP_WL_ESS_LIST: 4567 pcan_get_esslist(pcan_p, wldp_buf); 4568 break; 4569 case MAC_PROP_WL_SUPPORTED_RATES: 4570 pcan_get_suprates(wldp_buf); 4571 break; 4572 case MAC_PROP_WL_RSSI: 4573 err = pcan_get_rssi(pcan_p, wldp_buf); 4574 break; 4575 case MAC_PROP_WL_RADIO: 4576 pcan_get_radio(wldp_buf); 4577 break; 4578 case MAC_PROP_WL_POWER_MODE: 4579 err = pcan_get_powermode(pcan_p, wldp_buf); 4580 break; 4581 case MAC_PROP_WL_DESIRED_RATES: 4582 err = pcan_get_desrates(pcan_p, wldp_buf); 4583 break; 4584 case MAC_PROP_WL_CREATE_IBSS: 4585 case MAC_PROP_WL_CAPABILITY: 4586 case MAC_PROP_WL_WPA: 4587 case MAC_PROP_WL_SCANRESULTS: 4588 case MAC_PROP_WL_KEY_TAB: 4589 case MAC_PROP_WL_KEY: 4590 case MAC_PROP_WL_DELKEY: 4591 case MAC_PROP_WL_SETOPTIE: 4592 case MAC_PROP_WL_MLME: 4593 cmn_err(CE_WARN, "pcan_getprop:" 4594 "opmode not support %x\n", wldp_pr_num); 4595 err = ENOTSUP; 4596 break; 4597 default: 4598 cmn_err(CE_WARN, "pcan_getprop:" 4599 "opmode err\n"); 4600 err = EINVAL; 4601 break; 4602 } 4603 4604 mutex_exit(&pcan_p->pcan_glock); 4605 4606 return (err); 4607 } 4608 4609 static void 4610 pcan_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num, 4611 mac_prop_info_handle_t mph) 4612 { 4613 _NOTE(ARGUNUSED(arg, pr_name)); 4614 4615 switch (wldp_pr_num) { 4616 case MAC_PROP_WL_BSSTYPE: 4617 case MAC_PROP_WL_ESS_LIST: 4618 case MAC_PROP_WL_SUPPORTED_RATES: 4619 case MAC_PROP_WL_RSSI: 4620 mac_prop_info_set_perm(mph, MAC_PROP_PERM_READ); 4621 break; 4622 } 4623 } 4624 4625 4626 /* 4627 * quiesce(9E) entry point. 4628 * 4629 * This function is called when the system is single-threaded at high 4630 * PIL with preemption disabled. Therefore, this function must not be 4631 * blocked. 4632 * 4633 * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure. 4634 * DDI_FAILURE indicates an error condition and should almost never happen. 4635 */ 4636 #ifndef __sparc 4637 static int 4638 pcan_quiesce(dev_info_t *dip) 4639 { 4640 pcan_maci_t *pcan_p; 4641 4642 pcan_p = ddi_get_soft_state(pcan_soft_state_p, ddi_get_instance(dip)); 4643 if (pcan_p == NULL) 4644 return (DDI_FAILURE); 4645 4646 if (pcan_p->pcan_flag & PCAN_CARD_READY) 4647 pcan_stop_locked(pcan_p); 4648 4649 return (DDI_SUCCESS); 4650 } 4651 #endif