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