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