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