13737Shx147065 /* 2*6062Shx147065 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 33737Shx147065 * Use is subject to license terms. 43737Shx147065 */ 53737Shx147065 63737Shx147065 /* 73737Shx147065 * Copyright (c) 1997, 1998, 1999 83737Shx147065 * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 93737Shx147065 * 103737Shx147065 * Redistribution and use in source and binary forms, with or without 113737Shx147065 * modification, are permitted provided that the following conditions 123737Shx147065 * are met: 133737Shx147065 * 1. Redistributions of source code must retain the above copyright 143737Shx147065 * notice, this list of conditions and the following disclaimer. 153737Shx147065 * 2. Redistributions in binary form must reproduce the above copyright 163737Shx147065 * notice, this list of conditions and the following disclaimer in the 173737Shx147065 * documentation and/or other materials provided with the distribution. 183737Shx147065 * 3. All advertising materials mentioning features or use of this software 193737Shx147065 * must display the following acknowledgement: 203737Shx147065 * This product includes software developed by Bill Paul. 213737Shx147065 * 4. Neither the name of the author nor the names of any co-contributors 223737Shx147065 * may be used to endorse or promote products derived from this software 233737Shx147065 * without specific prior written permission. 243737Shx147065 * 253737Shx147065 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 263737Shx147065 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 273737Shx147065 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 283737Shx147065 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 293737Shx147065 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 303737Shx147065 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 313737Shx147065 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 323737Shx147065 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 333737Shx147065 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 343737Shx147065 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 353737Shx147065 * THE POSSIBILITY OF SUCH DAMAGE. 363737Shx147065 */ 373737Shx147065 383737Shx147065 #pragma ident "%Z%%M% %I% %E% SMI" 393737Shx147065 403737Shx147065 #include <sys/conf.h> 413737Shx147065 #include <sys/ddi.h> 423737Shx147065 #include <sys/sunddi.h> 433737Shx147065 #include <sys/dlpi.h> 443737Shx147065 #include <sys/ethernet.h> 453737Shx147065 #include <sys/strsun.h> 463737Shx147065 #include <sys/stat.h> 473737Shx147065 #include <sys/byteorder.h> 483737Shx147065 #include <sys/pccard.h> 493737Shx147065 #include <sys/pci.h> 503737Shx147065 #include <sys/policy.h> 513737Shx147065 #include <sys/mac.h> 523737Shx147065 #include <sys/stream.h> 533737Shx147065 #include <inet/common.h> 543737Shx147065 #include <inet/nd.h> 553737Shx147065 #include <inet/mi.h> 563737Shx147065 573737Shx147065 #include "pcwl.h" 583737Shx147065 #include <sys/mac_wifi.h> 593737Shx147065 #include <inet/wifi_ioctl.h> 603737Shx147065 613737Shx147065 #ifdef DEBUG 623737Shx147065 #define PCWL_DBG_BASIC 0x1 633737Shx147065 #define PCWL_DBG_INFO 0x2 643737Shx147065 #define PCWL_DBG_SEND 0x4 653737Shx147065 #define PCWL_DBG_RCV 0x8 663737Shx147065 #define PCWL_DBG_LINKINFO 0x10 673737Shx147065 uint32_t pcwl_debug = 0; 683737Shx147065 #define PCWLDBG(x) \ 693737Shx147065 if (pcwl_debug & PCWL_DBG_BASIC) cmn_err x 703737Shx147065 #else 713737Shx147065 #define PCWLDBG(x) 723737Shx147065 #endif 733737Shx147065 743737Shx147065 /* for pci card */ 753737Shx147065 static ddi_device_acc_attr_t accattr = { 763737Shx147065 DDI_DEVICE_ATTR_V0, 773737Shx147065 DDI_NEVERSWAP_ACC, 783737Shx147065 DDI_STRICTORDER_ACC, 793737Shx147065 DDI_DEFAULT_ACC 803737Shx147065 }; 813737Shx147065 823737Shx147065 void *pcwl_soft_state_p = NULL; 833737Shx147065 static int pcwl_device_type; 843737Shx147065 853737Shx147065 mac_callbacks_t pcwl_m_callbacks = { 863737Shx147065 MC_IOCTL, 873737Shx147065 pcwl_gstat, 883737Shx147065 pcwl_start, 893737Shx147065 pcwl_stop, 903737Shx147065 pcwl_prom, 913737Shx147065 pcwl_sdmulti, 923737Shx147065 pcwl_saddr, 933737Shx147065 pcwl_tx, 943737Shx147065 NULL, 953737Shx147065 pcwl_ioctl 963737Shx147065 }; 973737Shx147065 983737Shx147065 static char *pcwl_name_str = "pcwl"; 993737Shx147065 1003737Shx147065 DDI_DEFINE_STREAM_OPS(pcwl_dev_ops, nulldev, pcwl_probe, pcwl_attach, 1013737Shx147065 pcwl_detach, nodev, NULL, D_MP, NULL); 1023737Shx147065 1033737Shx147065 extern struct mod_ops mod_driverops; 1043737Shx147065 static struct modldrv modldrv = { 1053737Shx147065 &mod_driverops, 1063737Shx147065 "Lucent/PRISM-II 802.11b driver", 1073737Shx147065 &pcwl_dev_ops 1083737Shx147065 }; 1093737Shx147065 1103737Shx147065 static struct modlinkage modlinkage = { 1113737Shx147065 MODREV_1, (void *)&modldrv, NULL 1123737Shx147065 }; 1133737Shx147065 1143737Shx147065 int 1153737Shx147065 _init(void) 1163737Shx147065 { 1173737Shx147065 int stat; 1183737Shx147065 1193737Shx147065 /* Allocate soft state */ 1203737Shx147065 if ((stat = ddi_soft_state_init(&pcwl_soft_state_p, 1213737Shx147065 sizeof (pcwl_maci_t), N_PCWL)) != DDI_SUCCESS) 1223737Shx147065 return (stat); 1233737Shx147065 1243737Shx147065 mac_init_ops(&pcwl_dev_ops, "pcwl"); 1253737Shx147065 wl_frame_default.wl_dat[0] = htons(WL_SNAP_WORD0); 1263737Shx147065 wl_frame_default.wl_dat[1] = htons(WL_SNAP_WORD1); 1273737Shx147065 stat = mod_install(&modlinkage); 1283737Shx147065 if (stat != DDI_SUCCESS) { 1293737Shx147065 mac_fini_ops(&pcwl_dev_ops); 1303737Shx147065 ddi_soft_state_fini(&pcwl_soft_state_p); 1313737Shx147065 } 1323737Shx147065 return (stat); 1333737Shx147065 } 1343737Shx147065 1353737Shx147065 int 1363737Shx147065 _fini(void) 1373737Shx147065 { 1383737Shx147065 int stat; 1393737Shx147065 1403737Shx147065 if ((stat = mod_remove(&modlinkage)) != DDI_SUCCESS) 1413737Shx147065 return (stat); 1423737Shx147065 mac_fini_ops(&pcwl_dev_ops); 1433737Shx147065 ddi_soft_state_fini(&pcwl_soft_state_p); 1443737Shx147065 1453737Shx147065 return (stat); 1463737Shx147065 } 1473737Shx147065 1483737Shx147065 int 1493737Shx147065 _info(struct modinfo *modinfop) 1503737Shx147065 { 1513737Shx147065 return (mod_info(&modlinkage, modinfop)); 1523737Shx147065 } 1533737Shx147065 1543737Shx147065 static int 1553737Shx147065 pcwl_probe(dev_info_t *dip) 1563737Shx147065 { 1573737Shx147065 int len, ret; 1583737Shx147065 char *buf; 1593737Shx147065 dev_info_t *pdip = ddi_get_parent(dip); 1603737Shx147065 1613737Shx147065 ret = ddi_getlongprop(DDI_DEV_T_ANY, pdip, 0, "device_type", 1623737Shx147065 (caddr_t)&buf, &len); 1633737Shx147065 if (ret != DDI_SUCCESS) 1643737Shx147065 return (DDI_PROBE_FAILURE); 1653737Shx147065 1663737Shx147065 PCWLDBG((CE_NOTE, "pcwl probe: device_type %s\n", buf)); 1673737Shx147065 if ((strcmp(buf, "pccard") == 0) || (strcmp(buf, "pcmcia") == 0)) { 1683737Shx147065 pcwl_device_type = PCWL_DEVICE_PCCARD; 1693737Shx147065 ret = DDI_PROBE_SUCCESS; 1703737Shx147065 } else if (strcmp(buf, "pci") == 0) { 1713737Shx147065 pcwl_device_type = PCWL_DEVICE_PCI; 1723737Shx147065 ret = DDI_PROBE_SUCCESS; 1733737Shx147065 } else { 1743737Shx147065 ret = DDI_PROBE_FAILURE; 1753737Shx147065 } 1763737Shx147065 kmem_free(buf, len); 1773737Shx147065 return (ret); 1783737Shx147065 } 1793737Shx147065 1803737Shx147065 static int 1813737Shx147065 pcwl_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 1823737Shx147065 { 1833737Shx147065 int ret, i; 1843737Shx147065 int instance; 1853737Shx147065 uint16_t stat; 1863737Shx147065 uint32_t err; 1873737Shx147065 pcwl_maci_t *pcwl_p; 1883737Shx147065 wifi_data_t wd = { 0 }; 1893737Shx147065 mac_register_t *macp; 1903737Shx147065 modify_config_t cfgmod; 1913737Shx147065 char strbuf[256]; 1923737Shx147065 1933737Shx147065 PCWLDBG((CE_NOTE, "pcwl attach: dip=0x%p cmd=%x\n", (void *)dip, cmd)); 1943737Shx147065 if (cmd != DDI_ATTACH) 1953737Shx147065 goto attach_fail1; 1963737Shx147065 /* 1973737Shx147065 * Allocate soft state associated with this instance. 1983737Shx147065 */ 1993737Shx147065 if (ddi_soft_state_zalloc(pcwl_soft_state_p, 2003737Shx147065 ddi_get_instance(dip)) != DDI_SUCCESS) { 2013737Shx147065 cmn_err(CE_CONT, "pcwl attach: alloc softstate failed\n"); 2023737Shx147065 goto attach_fail1; 2033737Shx147065 } 2043737Shx147065 pcwl_p = (pcwl_maci_t *)ddi_get_soft_state(pcwl_soft_state_p, 2053737Shx147065 ddi_get_instance(dip)); 2063737Shx147065 pcwl_p->pcwl_device_type = pcwl_device_type; 2073737Shx147065 if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) { 2083737Shx147065 if (ddi_regs_map_setup(dip, 0, 2093737Shx147065 (caddr_t *)&pcwl_p->pcwl_cfg_base, 0, 0, 2103737Shx147065 &accattr, &pcwl_p->pcwl_cfg_handle) != DDI_SUCCESS) { 2113737Shx147065 cmn_err(CE_WARN, "pcwl(pci) attach: pci_regs_map_setup" 2123737Shx147065 " failed\n"); 2133737Shx147065 goto attach_fail2; 2143737Shx147065 } 2153737Shx147065 2163737Shx147065 stat = ddi_get16(pcwl_p->pcwl_cfg_handle, 2173737Shx147065 (uint16_t *)(pcwl_p->pcwl_cfg_base + PCI_CONF_COMM)); 2183737Shx147065 stat |= (PCI_COMM_IO | PCI_COMM_MAE); 2193737Shx147065 ddi_put16(pcwl_p->pcwl_cfg_handle, 2203737Shx147065 (uint16_t *)(pcwl_p->pcwl_cfg_base + PCI_CONF_COMM), stat); 2213737Shx147065 stat = ddi_get16(pcwl_p->pcwl_cfg_handle, 2223737Shx147065 (uint16_t *)(pcwl_p->pcwl_cfg_base + PCI_CONF_COMM)); 2233737Shx147065 if ((stat & (PCI_COMM_IO | PCI_COMM_MAE)) != 2243737Shx147065 (PCI_COMM_IO | PCI_COMM_MAE)) { 2253737Shx147065 cmn_err(CE_WARN, "pcwl(pci) attach: pci command" 2263737Shx147065 " reg enable failed\n"); 2273737Shx147065 goto attach_fail2a; 2283737Shx147065 } 2293737Shx147065 2303737Shx147065 2313737Shx147065 if (ddi_regs_map_setup(dip, 1, (caddr_t *)&pcwl_p->pcwl_bar, 2323737Shx147065 0, 0, &accattr, (ddi_acc_handle_t *)&pcwl_p->pcwl_handle) 2333737Shx147065 != DDI_SUCCESS) { 2343737Shx147065 cmn_err(CE_WARN, "pcwl(pci) attach: pci_regs_map_setup" 2353737Shx147065 " failed\n"); 2363737Shx147065 goto attach_fail2a; 2373737Shx147065 } 2383737Shx147065 PCWLDBG((CE_NOTE, "pcwl(pci): regs_map_setup,bar=%p\n", 2393737Shx147065 (void *)pcwl_p->pcwl_bar)); 2403737Shx147065 2413737Shx147065 /* 2423737Shx147065 * tricky! copy from freebsd code. 2433737Shx147065 */ 2443737Shx147065 PCWL_WRITE(pcwl_p, 0x26, 0x80); 2453737Shx147065 drv_usecwait(500000); 2463737Shx147065 PCWL_WRITE(pcwl_p, 0x26, 0x0); 2473737Shx147065 drv_usecwait(500000); 2483737Shx147065 2493737Shx147065 for (i = 0; i < WL_TIMEOUT; i++) { 2503737Shx147065 PCWL_READ(pcwl_p, 0x0, stat); 2513737Shx147065 if (stat & WL_CMD_BUSY) 2523737Shx147065 drv_usecwait(10); 2533737Shx147065 else 2543737Shx147065 break; 2553737Shx147065 } 2563737Shx147065 if (i == WL_TIMEOUT) { 2573737Shx147065 cmn_err(CE_WARN, "pcwl(pci) attach: hardware init" 2583737Shx147065 " failed\n"); 2593737Shx147065 goto attach_fail3; 2603737Shx147065 } 2613737Shx147065 2623737Shx147065 /* 2633737Shx147065 * magic number verification. 2643737Shx147065 * tricky! copy from freebsd code. 2653737Shx147065 */ 2663737Shx147065 PCWL_WRITE(pcwl_p, 0x28, 0x4a2d); 2673737Shx147065 PCWL_READ(pcwl_p, 0x28, stat); 2683737Shx147065 PCWLDBG((CE_NOTE, "pcwl(pci):magic number = %x\n", stat)); 2693737Shx147065 if (stat != 0x4a2d) { 2703737Shx147065 cmn_err(CE_WARN, "pcwl(pci) attach: magic verify" 2713737Shx147065 " failed\n"); 2723737Shx147065 goto attach_fail3; 2733737Shx147065 } 2743737Shx147065 } 2753737Shx147065 pcwl_p->pcwl_dip = dip; 2763737Shx147065 pcwl_p->pcwl_flag = 0; 2773737Shx147065 pcwl_p->pcwl_socket = ddi_getprop(DDI_DEV_T_NONE, dip, 2783737Shx147065 DDI_PROP_DONTPASS, "socket", -1); 2793737Shx147065 pcwl_p->pcwl_reschedule_need = B_FALSE; 2803737Shx147065 2813737Shx147065 if (ddi_get_iblock_cookie(dip, 2823737Shx147065 0, &pcwl_p->pcwl_ib_cookie) != DDI_SUCCESS) { 2833737Shx147065 cmn_err(CE_WARN, "pcwl attach: get_iblk_cookie failed\n"); 2843737Shx147065 goto attach_fail3; 2853737Shx147065 } 2863737Shx147065 2873737Shx147065 mutex_init(&pcwl_p->pcwl_glock, NULL, MUTEX_DRIVER, 2883737Shx147065 pcwl_p->pcwl_ib_cookie); 2893737Shx147065 mutex_init(&pcwl_p->pcwl_scanlist_lock, NULL, MUTEX_DRIVER, 2903737Shx147065 pcwl_p->pcwl_ib_cookie); 2913737Shx147065 mutex_init(&pcwl_p->pcwl_txring.wl_tx_lock, NULL, MUTEX_DRIVER, 2923737Shx147065 pcwl_p->pcwl_ib_cookie); 2933737Shx147065 2943737Shx147065 if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) { 2953737Shx147065 if (ret = ddi_add_intr(dip, 0, NULL, NULL, 2963737Shx147065 pcwl_intr, (caddr_t)pcwl_p)) { 2973737Shx147065 cmn_err(CE_NOTE, "pcwl(pci) attach: add intr failed\n"); 2983737Shx147065 goto attach_fail3a; 2993737Shx147065 } 3003737Shx147065 } else if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCCARD) { 3013737Shx147065 if (ret = pcwl_register_cs(dip, pcwl_p)) { 3023737Shx147065 cmn_err(CE_WARN, "pcwl attach(pccard): " 3033737Shx147065 "register_cs err %x\n", ret); 3043737Shx147065 goto attach_fail3a; 3053737Shx147065 } 3063737Shx147065 } else { 3073737Shx147065 cmn_err(CE_WARN, "pcwl attach: unsupported device type\n"); 3083737Shx147065 goto attach_fail3a; 3093737Shx147065 } 3103737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 3113737Shx147065 if (ret = pcwl_reset_backend(pcwl_p)) { 3123737Shx147065 cmn_err(CE_WARN, "pcwl attach: reset_backend failed %x\n", ret); 3133737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 3143737Shx147065 goto attach_fail4; 3153737Shx147065 } 3163737Shx147065 if (ret = pcwl_get_cap(pcwl_p)) { /* sets macaddr for mac_register */ 3173737Shx147065 cmn_err(CE_WARN, "pcwl attach: get_cap failed %x\n", ret); 3183737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 3193737Shx147065 goto attach_fail4; 3203737Shx147065 } 3213737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 3223737Shx147065 /* 3233737Shx147065 * Provide initial settings for the WiFi plugin; whenever this 3243737Shx147065 * information changes, we need to call mac_pdata_update() 3253737Shx147065 */ 3263737Shx147065 wd.wd_secalloc = WIFI_SEC_NONE; 3273737Shx147065 wd.wd_opmode = IEEE80211_M_STA; 3283737Shx147065 3293737Shx147065 macp = mac_alloc(MAC_VERSION); 3303737Shx147065 if (macp == NULL) { 3313737Shx147065 PCWLDBG((CE_NOTE, "pcwl attach: " 3323737Shx147065 "MAC version mismatch\n")); 3333737Shx147065 goto attach_fail4; 3343737Shx147065 } 3353737Shx147065 3363737Shx147065 macp->m_type_ident = MAC_PLUGIN_IDENT_WIFI; 3373737Shx147065 macp->m_driver = pcwl_p; 3383737Shx147065 macp->m_dip = dip; 3393737Shx147065 macp->m_src_addr = pcwl_p->pcwl_mac_addr; 3403737Shx147065 macp->m_callbacks = &pcwl_m_callbacks; 3413737Shx147065 macp->m_min_sdu = 0; 3423737Shx147065 macp->m_max_sdu = IEEE80211_MTU; 3433737Shx147065 macp->m_pdata = &wd; 3443737Shx147065 macp->m_pdata_size = sizeof (wd); 3453737Shx147065 3463737Shx147065 err = mac_register(macp, &pcwl_p->pcwl_mh); 3473737Shx147065 mac_free(macp); 3483737Shx147065 if (err != 0) { 3493737Shx147065 PCWLDBG((CE_NOTE, "pcwl attach: " 3503737Shx147065 "mac_register err\n")); 3513737Shx147065 goto attach_fail4; 3523737Shx147065 } 3533737Shx147065 3543737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 3553737Shx147065 if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCCARD) { 3563737Shx147065 /* 3573737Shx147065 * turn on CS interrupt 3583737Shx147065 */ 3593737Shx147065 cfgmod.Attributes = CONF_ENABLE_IRQ_STEERING | 3603737Shx147065 CONF_IRQ_CHANGE_VALID; 3613737Shx147065 cfgmod.Vpp1 = 0; 3623737Shx147065 cfgmod.Vpp2 = 0; 3633737Shx147065 (void) csx_ModifyConfiguration(pcwl_p->pcwl_chdl, &cfgmod); 3643737Shx147065 3653737Shx147065 } 3663737Shx147065 if (ret = pcwl_init_nicmem(pcwl_p)) { 3673737Shx147065 cmn_err(CE_WARN, "pcwl(pccard) attach: pcwl_init_nicmem" 3683737Shx147065 " failed %x\n", ret); 3693737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 3703737Shx147065 goto attach_fail5; 3713737Shx147065 } 3723737Shx147065 pcwl_chip_type(pcwl_p); 3733737Shx147065 if (ret = pcwl_loaddef_rf(pcwl_p)) { 3743737Shx147065 cmn_err(CE_WARN, "pcwl attach: config_rf failed%x\n", ret); 3753737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 3763737Shx147065 goto attach_fail5; 3773737Shx147065 } 3783737Shx147065 (void) pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0); 3793737Shx147065 pcwl_stop_locked(pcwl_p); /* leaves interface down */ 3803737Shx147065 list_create(&pcwl_p->pcwl_scan_list, sizeof (wl_scan_list_t), 3813737Shx147065 offsetof(wl_scan_list_t, wl_scan_node)); 3823737Shx147065 pcwl_p->pcwl_scan_num = 0; 3833737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 3843737Shx147065 pcwl_p->pcwl_scanlist_timeout_id = timeout(pcwl_scanlist_timeout, 3853737Shx147065 pcwl_p, drv_usectohz(1000000)); 3863737Shx147065 instance = ddi_get_instance(dip); 3873737Shx147065 (void) snprintf(strbuf, sizeof (strbuf), "pcwl%d", instance); 3883737Shx147065 if (ddi_create_minor_node(dip, strbuf, S_IFCHR, 3893737Shx147065 instance + 1, DDI_NT_NET_WIFI, 0) != DDI_SUCCESS) { 3903737Shx147065 goto attach_fail6; 3913737Shx147065 } 3923737Shx147065 pcwl_p->pcwl_flag |= PCWL_ATTACHED; 3933737Shx147065 if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) { 3943737Shx147065 pcwl_p->pcwl_flag |= PCWL_CARD_READY; 3953737Shx147065 } 3963737Shx147065 return (DDI_SUCCESS); 3973737Shx147065 attach_fail6: 3983737Shx147065 if (pcwl_p->pcwl_scanlist_timeout_id != 0) { 3993737Shx147065 (void) untimeout(pcwl_p->pcwl_scanlist_timeout_id); 4003737Shx147065 pcwl_p->pcwl_scanlist_timeout_id = 0; 4013737Shx147065 } 4023737Shx147065 list_destroy(&pcwl_p->pcwl_scan_list); 4033737Shx147065 attach_fail5: 4043737Shx147065 (void) mac_unregister(pcwl_p->pcwl_mh); 4053737Shx147065 attach_fail4: 4063737Shx147065 if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) { 4073737Shx147065 ddi_remove_intr(dip, 0, pcwl_p->pcwl_ib_cookie); 4083737Shx147065 } else if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCCARD) { 4093737Shx147065 pcwl_unregister_cs(pcwl_p); 4103737Shx147065 } 4113737Shx147065 attach_fail3a: 4123737Shx147065 pcwl_destroy_locks(pcwl_p); 4133737Shx147065 attach_fail3: 4143737Shx147065 if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) 4153737Shx147065 ddi_regs_map_free(&pcwl_p->pcwl_handle); 4163737Shx147065 attach_fail2a: 4173737Shx147065 if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) 4183737Shx147065 ddi_regs_map_free(&pcwl_p->pcwl_cfg_handle); 4193737Shx147065 attach_fail2: 4203737Shx147065 ddi_soft_state_free(pcwl_soft_state_p, ddi_get_instance(dip)); 4213737Shx147065 attach_fail1: 4223737Shx147065 return (DDI_FAILURE); 4233737Shx147065 } 4243737Shx147065 4253737Shx147065 static int 4263737Shx147065 pcwl_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 4273737Shx147065 { 4283737Shx147065 pcwl_maci_t *pcwl_p; 4293737Shx147065 wl_scan_list_t *scan_item0; 4303737Shx147065 int ret; 4313737Shx147065 pcwl_p = ddi_get_soft_state(pcwl_soft_state_p, ddi_get_instance(dip)); 4323737Shx147065 4333737Shx147065 PCWLDBG((CE_NOTE, "pcwl detach: dip=0x%p cmd=%x\n", (void *)dip, cmd)); 4343737Shx147065 if (cmd != DDI_DETACH) 4353737Shx147065 return (DDI_FAILURE); 4363737Shx147065 if (!(pcwl_p->pcwl_flag & PCWL_ATTACHED)) 4373737Shx147065 return (DDI_FAILURE); 4383737Shx147065 4393737Shx147065 if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) { 4403737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 4413737Shx147065 (void) pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0); 4423737Shx147065 PCWL_DISABLE_INTR(pcwl_p); 4433737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 4443737Shx147065 } 4453737Shx147065 if (pcwl_p->pcwl_scanlist_timeout_id != 0) { 4463737Shx147065 (void) untimeout(pcwl_p->pcwl_scanlist_timeout_id); 4473737Shx147065 pcwl_p->pcwl_scanlist_timeout_id = 0; 4483737Shx147065 } 4493737Shx147065 if (pcwl_p->pcwl_connect_timeout_id != 0) { 4503737Shx147065 (void) untimeout(pcwl_p->pcwl_connect_timeout_id); 4513737Shx147065 pcwl_p->pcwl_connect_timeout_id = 0; 4523737Shx147065 } 4533737Shx147065 mutex_enter(&pcwl_p->pcwl_scanlist_lock); 4543737Shx147065 scan_item0 = list_head(&pcwl_p->pcwl_scan_list); 4553737Shx147065 while (scan_item0) { 4563737Shx147065 pcwl_delete_scan_item(pcwl_p, scan_item0); 4573737Shx147065 scan_item0 = list_head(&pcwl_p->pcwl_scan_list); 4583737Shx147065 } 4593737Shx147065 list_destroy(&pcwl_p->pcwl_scan_list); 4603737Shx147065 mutex_exit(&pcwl_p->pcwl_scanlist_lock); 4613737Shx147065 ret = mac_unregister(pcwl_p->pcwl_mh); 4623737Shx147065 if (ret != 0) 4633737Shx147065 return (DDI_FAILURE); 4643737Shx147065 4653737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 4663737Shx147065 if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) { 4673737Shx147065 ddi_remove_intr(dip, 0, pcwl_p->pcwl_ib_cookie); 4683737Shx147065 ddi_regs_map_free(&pcwl_p->pcwl_handle); 4693737Shx147065 ddi_regs_map_free(&pcwl_p->pcwl_cfg_handle); 4703737Shx147065 } else if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCCARD) { 4713737Shx147065 pcwl_unregister_cs(pcwl_p); 4723737Shx147065 } 4733737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 4743737Shx147065 pcwl_destroy_locks(pcwl_p); 4753737Shx147065 ddi_remove_minor_node(dip, NULL); 4763737Shx147065 ddi_soft_state_free(pcwl_soft_state_p, ddi_get_instance(dip)); 4773737Shx147065 return (DDI_SUCCESS); 4783737Shx147065 } 4793737Shx147065 4803737Shx147065 /* 4813737Shx147065 * card services and event handlers 4823737Shx147065 */ 4833737Shx147065 static int 4843737Shx147065 pcwl_register_cs(dev_info_t *dip, pcwl_maci_t *pcwl_p) 4853737Shx147065 { 4863737Shx147065 int ret; 4873737Shx147065 client_reg_t cr; 4883737Shx147065 client_handle_t chdl; /* uint encoding of socket, function, client */ 4893737Shx147065 get_status_t card_status; 4903737Shx147065 request_socket_mask_t sock_req; 4913737Shx147065 4923737Shx147065 bzero(&cr, sizeof (cr)); 4933737Shx147065 cr.Attributes = INFO_IO_CLIENT|INFO_CARD_EXCL|INFO_CARD_SHARE; 4943737Shx147065 cr.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | 4953737Shx147065 CS_EVENT_REGISTRATION_COMPLETE | CS_EVENT_CARD_REMOVAL_LOWP | 4963737Shx147065 CS_EVENT_CARD_READY | CS_EVENT_PM_RESUME | 4973737Shx147065 CS_EVENT_PM_SUSPEND | CS_EVENT_CLIENT_INFO; 4983737Shx147065 cr.event_callback_args.client_data = pcwl_p; 4993737Shx147065 cr.Version = CS_VERSION; 5003737Shx147065 cr.event_handler = (csfunction_t *)pcwl_ev_hdlr; 5013737Shx147065 cr.dip = dip; 5023737Shx147065 (void) strcpy(cr.driver_name, pcwl_name_str); 5033737Shx147065 if (ret = csx_RegisterClient(&chdl, &cr)) { 5043737Shx147065 cmn_err(CE_WARN, "pcwl: RegisterClient failed %x\n", ret); 5053737Shx147065 goto regcs_ret; 5063737Shx147065 } 5073737Shx147065 pcwl_p->pcwl_chdl = chdl; 5083737Shx147065 5093737Shx147065 bzero(&card_status, sizeof (card_status)); 5103737Shx147065 (void) csx_GetStatus(chdl, &card_status); 5113737Shx147065 PCWLDBG((CE_NOTE, 5123737Shx147065 "pcwl: register_cs: Sock=%x CState=%x SState=%x rState=%x\n", 5133737Shx147065 card_status.Socket, card_status.CardState, 5143737Shx147065 card_status.SocketState, card_status.raw_CardState)); 5153737Shx147065 if (!(card_status.CardState & CS_STATUS_CARD_INSERTED)) { 5163737Shx147065 /* card is not present, why are we attaching ? */ 5173737Shx147065 ret = CS_NO_CARD; 5183737Shx147065 goto regcs_unreg; 5193737Shx147065 } 5203737Shx147065 cv_init(&pcwl_p->pcwl_cscv, NULL, CV_DRIVER, NULL); 5213737Shx147065 mutex_init(&pcwl_p->pcwl_cslock, NULL, MUTEX_DRIVER, *cr.iblk_cookie); 5223737Shx147065 mutex_enter(&pcwl_p->pcwl_cslock); 5233737Shx147065 if (ret = csx_MapLogSocket(chdl, &pcwl_p->pcwl_log_sock)) { 5243737Shx147065 cmn_err(CE_WARN, "pcwl: MapLogSocket failed %x\n", ret); 5253737Shx147065 goto regcs_fail; 5263737Shx147065 } 5273737Shx147065 PCWLDBG((CE_NOTE, 5283737Shx147065 "pcwl: register_cs: LogSock=%x PhyAdapter=%x PhySock=%x\n", 5293737Shx147065 pcwl_p->pcwl_log_sock.LogSocket, 5303737Shx147065 pcwl_p->pcwl_log_sock.PhyAdapter, 5313737Shx147065 pcwl_p->pcwl_log_sock.PhySocket)); 5323737Shx147065 /* turn on initialization events */ 5333737Shx147065 sock_req.Socket = 0; 5343737Shx147065 sock_req.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | 5353737Shx147065 CS_EVENT_REGISTRATION_COMPLETE; 5363737Shx147065 if (ret = csx_RequestSocketMask(chdl, &sock_req)) { 5373737Shx147065 cmn_err(CE_WARN, "pcwl: RequestSocketMask failed %x\n", ret); 5383737Shx147065 goto regcs_fail; 5393737Shx147065 } 5403737Shx147065 /* wait for and process card insertion events */ 5413737Shx147065 while (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) 5423737Shx147065 cv_wait(&pcwl_p->pcwl_cscv, &pcwl_p->pcwl_cslock); 5433737Shx147065 mutex_exit(&pcwl_p->pcwl_cslock); 5443737Shx147065 5453737Shx147065 pcwl_p->pcwl_flag |= PCWL_CS_REGISTERED; 5463737Shx147065 return (PCWL_SUCCESS); 5473737Shx147065 regcs_fail: 5483737Shx147065 mutex_destroy(&pcwl_p->pcwl_cslock); 5493737Shx147065 cv_destroy(&pcwl_p->pcwl_cscv); 5503737Shx147065 regcs_unreg: 5513737Shx147065 (void) csx_DeregisterClient(chdl); 5523737Shx147065 regcs_ret: 5533737Shx147065 pcwl_p->pcwl_flag &= ~PCWL_CS_REGISTERED; 5543737Shx147065 return (ret); 5553737Shx147065 } 5563737Shx147065 5573737Shx147065 static void 5583737Shx147065 pcwl_unregister_cs(pcwl_maci_t *pcwl_p) 5593737Shx147065 { 5603737Shx147065 int ret; 5613737Shx147065 release_socket_mask_t mask; 5623737Shx147065 mask.Socket = pcwl_p->pcwl_socket; 5633737Shx147065 5643737Shx147065 /* 5653737Shx147065 * The card service not registered means register_cs function 5663737Shx147065 * doesnot return TRUE. Then all the lelated resource has been 5673737Shx147065 * released in register_cs. 5683737Shx147065 */ 5693737Shx147065 if (!(pcwl_p->pcwl_flag | PCWL_CS_REGISTERED)) 5703737Shx147065 return; 5713737Shx147065 5723737Shx147065 if (ret = csx_ReleaseSocketMask(pcwl_p->pcwl_chdl, &mask)) 5733737Shx147065 cmn_err(CE_WARN, "pcwl: ReleaseSocket mask failed %x\n", ret); 5743737Shx147065 5753737Shx147065 if (pcwl_p->pcwl_flag & PCWL_CARD_READY) { 5763737Shx147065 pcwl_card_remove(pcwl_p); 5773737Shx147065 pcwl_p->pcwl_flag &= ~PCWL_CARD_READY; 5783737Shx147065 } 5793737Shx147065 mutex_destroy(&pcwl_p->pcwl_cslock); 5803737Shx147065 cv_destroy(&pcwl_p->pcwl_cscv); 5813737Shx147065 if (ret = csx_DeregisterClient(pcwl_p->pcwl_chdl)) 5823737Shx147065 cmn_err(CE_WARN, "pcwl: Deregister failed %x\n", ret); 5833737Shx147065 } 5843737Shx147065 5853737Shx147065 static void 5863737Shx147065 pcwl_destroy_locks(pcwl_maci_t *pcwl_p) 5873737Shx147065 { 5883737Shx147065 mutex_destroy(&pcwl_p->pcwl_txring.wl_tx_lock); 5893737Shx147065 mutex_destroy(&pcwl_p->pcwl_scanlist_lock); 5903737Shx147065 mutex_destroy(&pcwl_p->pcwl_glock); 5913737Shx147065 } 5923737Shx147065 5933737Shx147065 static int 5943737Shx147065 pcwl_ev_hdlr(event_t event, int priority, event_callback_args_t *arg) 5953737Shx147065 { 5963737Shx147065 int ret = CS_SUCCESS; 5973737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg->client_data; 5983737Shx147065 client_info_t *ci_p = (client_info_t *)&arg->client_info; 5993737Shx147065 6003737Shx147065 mutex_enter(&pcwl_p->pcwl_cslock); 6013737Shx147065 switch (event) { 6023737Shx147065 case CS_EVENT_CARD_INSERTION: 6033737Shx147065 ret = pcwl_card_insert(pcwl_p); 6043737Shx147065 cv_broadcast(&pcwl_p->pcwl_cscv); 6053737Shx147065 break; 6063737Shx147065 case CS_EVENT_REGISTRATION_COMPLETE: 6073737Shx147065 cv_broadcast(&pcwl_p->pcwl_cscv); 6083737Shx147065 break; 6093737Shx147065 case CS_EVENT_CARD_REMOVAL: 6103737Shx147065 if (priority & CS_EVENT_PRI_HIGH) 6113737Shx147065 break; 6123737Shx147065 pcwl_card_remove(pcwl_p); 6133737Shx147065 cv_broadcast(&pcwl_p->pcwl_cscv); 6143737Shx147065 break; 6153737Shx147065 case CS_EVENT_CLIENT_INFO: 6163737Shx147065 if (GET_CLIENT_INFO_SUBSVC(ci_p->Attributes) != 6173737Shx147065 CS_CLIENT_INFO_SUBSVC_CS) 6183737Shx147065 break; 6193737Shx147065 6203737Shx147065 ci_p->Revision = 0x0101; 6213737Shx147065 ci_p->CSLevel = CS_VERSION; 6223737Shx147065 ci_p->RevDate = CS_CLIENT_INFO_MAKE_DATE(9, 12, 14); 6233737Shx147065 (void) strcpy(ci_p->ClientName, PCWL_IDENT_STRING); 6243737Shx147065 (void) strcpy(ci_p->VendorName, CS_SUN_VENDOR_DESCRIPTION); 6253737Shx147065 ci_p->Attributes |= CS_CLIENT_INFO_VALID; 6263737Shx147065 break; 6273737Shx147065 default: 6283737Shx147065 ret = CS_UNSUPPORTED_EVENT; 6293737Shx147065 break; 6303737Shx147065 } 6313737Shx147065 mutex_exit(&pcwl_p->pcwl_cslock); 6323737Shx147065 return (ret); 6333737Shx147065 } 6343737Shx147065 6353737Shx147065 static int 6363737Shx147065 pcwl_card_insert(pcwl_maci_t *pcwl_p) 6373737Shx147065 { 6383737Shx147065 int ret, hi, lo; 6393737Shx147065 tuple_t tuple; 6403737Shx147065 cisparse_t cisparse; 6413737Shx147065 io_req_t io; 6423737Shx147065 irq_req_t irq; 6433737Shx147065 config_req_t cfg; 6443737Shx147065 cistpl_config_t config; 6453737Shx147065 cistpl_cftable_entry_t *tbl_p; 6463737Shx147065 register client_handle_t chdl = pcwl_p->pcwl_chdl; 6473737Shx147065 6483737Shx147065 bzero(&tuple, sizeof (tuple)); 6493737Shx147065 tuple.DesiredTuple = CISTPL_MANFID; 6503737Shx147065 if (ret = csx_GetFirstTuple(chdl, &tuple)) { 6513737Shx147065 cmn_err(CE_WARN, "pcwl: get manufacture id failed %x\n", ret); 6523737Shx147065 goto insert_ret; 6533737Shx147065 } 6543737Shx147065 bzero(&cisparse, sizeof (cisparse)); 6553737Shx147065 if (ret = csx_Parse_CISTPL_MANFID(chdl, &tuple, &cisparse.manfid)) { 6563737Shx147065 cmn_err(CE_WARN, "pcwl: parse manufacture id failed %x\n", ret); 6573737Shx147065 goto insert_ret; 6583737Shx147065 } 6593737Shx147065 6603737Shx147065 /* 6613737Shx147065 * verify manufacture ID 6623737Shx147065 */ 6633737Shx147065 PCWLDBG((CE_NOTE, "pcwl insert: manufacturer_id=%x card=%x\n", 6643737Shx147065 cisparse.manfid.manf, cisparse.manfid.card)); 6653737Shx147065 bzero(&tuple, sizeof (tuple)); 6663737Shx147065 tuple.DesiredTuple = CISTPL_FUNCID; 6673737Shx147065 if (ret = csx_GetFirstTuple(chdl, &tuple)) { 6683737Shx147065 cmn_err(CE_WARN, "pcwl: get function id failed %x\n", ret); 6693737Shx147065 goto insert_ret; 6703737Shx147065 } 6713737Shx147065 bzero(&cisparse, sizeof (cisparse)); 6723737Shx147065 if (ret = csx_Parse_CISTPL_FUNCID(chdl, &tuple, &cisparse.funcid)) { 6733737Shx147065 cmn_err(CE_WARN, "pcwl: parse function id failed %x\n", ret); 6743737Shx147065 goto insert_ret; 6753737Shx147065 } 6763737Shx147065 6773737Shx147065 /* 6783737Shx147065 * verify function ID 6793737Shx147065 */ 6803737Shx147065 PCWLDBG((CE_NOTE, "insert:fun_id=%x\n", cisparse.funcid.function)); 6813737Shx147065 bzero(&tuple, sizeof (tuple)); 6823737Shx147065 tuple.DesiredTuple = CISTPL_CONFIG; 6833737Shx147065 if (ret = csx_GetFirstTuple(chdl, &tuple)) { 6843737Shx147065 cmn_err(CE_WARN, "pcwl: get config failed %x\n", ret); 6853737Shx147065 goto insert_ret; 6863737Shx147065 } 6873737Shx147065 bzero(&config, sizeof (config)); 6883737Shx147065 if (ret = csx_Parse_CISTPL_CONFIG(chdl, &tuple, &config)) { 6893737Shx147065 cmn_err(CE_WARN, "pcwl: parse config failed %x\n", ret); 6903737Shx147065 goto insert_ret; 6913737Shx147065 } 6923737Shx147065 PCWLDBG((CE_NOTE, 6933737Shx147065 "pcwl: config present=%x nr=%x hr=%x regs[0]=%x base=%x last=%x\n", 6943737Shx147065 config.present, config.nr, config.hr, config.regs[0], 6953737Shx147065 config.base, config.last)); 6963737Shx147065 hi = 0; 6973737Shx147065 lo = (int)-1; /* really big number */ 6983737Shx147065 tbl_p = &cisparse.cftable; 6993737Shx147065 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; 7003737Shx147065 for (tbl_p->index = 0; tbl_p->index <= config.hr; ) { 7013737Shx147065 PCWLDBG((CE_NOTE, "pcwl insert:tuple idx=%x:\n", tbl_p->index)); 7023737Shx147065 if (ret = csx_GetNextTuple(chdl, &tuple)) { 7033737Shx147065 cmn_err(CE_WARN, "pcwl: get cftable failed %x\n", 7043737Shx147065 ret); 7053737Shx147065 break; 7063737Shx147065 } 7073737Shx147065 bzero((caddr_t)&cisparse, sizeof (cisparse)); 7083737Shx147065 if (ret = csx_Parse_CISTPL_CFTABLE_ENTRY(chdl, &tuple, tbl_p)) { 7093737Shx147065 cmn_err(CE_WARN, "pcwl: parse cftable failed %x\n", 7103737Shx147065 ret); 7113737Shx147065 break; 7123737Shx147065 } 7133737Shx147065 if (tbl_p->flags & CISTPL_CFTABLE_TPCE_FS_PWR && 714*6062Shx147065 tbl_p->pd.flags & CISTPL_CFTABLE_TPCE_FS_PWR_VCC) { 7153737Shx147065 if (tbl_p->pd.pd_vcc.avgI > hi) { 7163737Shx147065 hi = tbl_p->pd.pd_vcc.avgI; 7173737Shx147065 pcwl_p->pcwl_config_hi = tbl_p->index; 7183737Shx147065 } 7193737Shx147065 if (tbl_p->pd.pd_vcc.avgI < lo) { 7203737Shx147065 lo = tbl_p->pd.pd_vcc.avgI; 7213737Shx147065 pcwl_p->pcwl_config = tbl_p->index; 7223737Shx147065 } 7233737Shx147065 } 7243737Shx147065 if (tbl_p->flags & CISTPL_CFTABLE_TPCE_DEFAULT) { 7253737Shx147065 if (tbl_p->pd.flags & CISTPL_CFTABLE_TPCE_FS_PWR_VCC) 7263737Shx147065 pcwl_p->pcwl_vcc = tbl_p->pd.pd_vcc.nomV; 7273737Shx147065 if (tbl_p->flags & CISTPL_CFTABLE_TPCE_FS_IO) 7283737Shx147065 pcwl_p->pcwl_iodecode = tbl_p->io.addr_lines; 7293737Shx147065 } 7303737Shx147065 } 7313737Shx147065 PCWLDBG((CE_NOTE, "pcwl: insert:cfg_hi=%x cfg=%x vcc=%x iodecode=%x\n", 7323737Shx147065 pcwl_p->pcwl_config_hi, pcwl_p->pcwl_config, 7333737Shx147065 pcwl_p->pcwl_vcc, pcwl_p->pcwl_iodecode)); 7343737Shx147065 bzero(&io, sizeof (io)); 7353737Shx147065 io.BasePort1.base = 0; 7363737Shx147065 io.NumPorts1 = 1 << pcwl_p->pcwl_iodecode; 7373737Shx147065 io.Attributes1 = IO_DATA_PATH_WIDTH_16; 7383737Shx147065 io.IOAddrLines = pcwl_p->pcwl_iodecode; 7393737Shx147065 if (ret = csx_RequestIO(chdl, &io)) { 7403737Shx147065 cmn_err(CE_WARN, "pcwl: RequestIO failed %x\n", ret); 7413737Shx147065 goto insert_ret; 7423737Shx147065 } 7433737Shx147065 pcwl_p->pcwl_port = io.BasePort1.handle; 7443737Shx147065 if (ret = ddi_add_softintr(DIP(pcwl_p), DDI_SOFTINT_HIGH, 7453737Shx147065 &pcwl_p->pcwl_softint_id, &pcwl_p->pcwl_ib_cookie, NULL, 7463737Shx147065 pcwl_intr, (caddr_t)pcwl_p)) { 7473737Shx147065 cmn_err(CE_NOTE, "pcwl(pccard): add softintr failed\n"); 7483737Shx147065 goto insert_ret; 7493737Shx147065 } 7503737Shx147065 irq.Attributes = IRQ_TYPE_EXCLUSIVE; 7513737Shx147065 irq.irq_handler = ddi_intr_hilevel(DIP(pcwl_p), 0) ? 7523737Shx147065 (csfunction_t *)pcwl_intr_hi : (csfunction_t *)pcwl_intr; 7533737Shx147065 irq.irq_handler_arg = pcwl_p; 7543737Shx147065 if (ret = csx_RequestIRQ(pcwl_p->pcwl_chdl, &irq)) { 7553737Shx147065 cmn_err(CE_WARN, "pcwl: RequestIRQ failed %x\n", ret); 7563737Shx147065 goto un_io; 7573737Shx147065 } 7583737Shx147065 bzero(&cfg, sizeof (cfg)); 7593737Shx147065 cfg.Attributes = 0; /* not ready for CONF_ENABLE_IRQ_STEERING yet */ 7603737Shx147065 cfg.Vcc = 50; 7613737Shx147065 cfg.IntType = SOCKET_INTERFACE_MEMORY_AND_IO; 7623737Shx147065 cfg.ConfigBase = config.base; 7633737Shx147065 cfg.ConfigIndex = pcwl_p->pcwl_config; 7643737Shx147065 cfg.Status = CCSR_IO_IS_8; 7653737Shx147065 cfg.Present = config.present; 7663737Shx147065 pcwl_p->pcwl_flag |= PCWL_CARD_READY; 7673737Shx147065 if (ret = csx_RequestConfiguration(chdl, &cfg)) { 7683737Shx147065 cmn_err(CE_WARN, "pcwl: RequestConfiguration failed %x\n", ret); 7693737Shx147065 goto un_irq; 7703737Shx147065 } 7713737Shx147065 return (CS_SUCCESS); 7723737Shx147065 un_irq: 7733737Shx147065 (void) csx_ReleaseIRQ(chdl, &irq); 7743737Shx147065 un_io: 7753737Shx147065 ddi_remove_softintr(pcwl_p->pcwl_softint_id); 7763737Shx147065 (void) csx_ReleaseIO(chdl, &io); 7773737Shx147065 pcwl_p->pcwl_port = 0; 7783737Shx147065 insert_ret: 7793737Shx147065 pcwl_p->pcwl_flag &= ~PCWL_CARD_READY; 7803737Shx147065 return (ret); 7813737Shx147065 7823737Shx147065 } 7833737Shx147065 7843737Shx147065 /* 7853737Shx147065 * assume card is already removed, don't touch the hardware 7863737Shx147065 */ 7873737Shx147065 static void 7883737Shx147065 pcwl_card_remove(pcwl_maci_t *pcwl_p) 7893737Shx147065 { 7903737Shx147065 int ret; 7913737Shx147065 io_req_t io; 7923737Shx147065 irq_req_t irq; 7933737Shx147065 7943737Shx147065 /* 7953737Shx147065 * The card not ready means Insert function doesnot return TRUE. 7963737Shx147065 * then the IO and IRQ has been released in Insert 7973737Shx147065 */ 7983737Shx147065 if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) 7993737Shx147065 return; 8003737Shx147065 if (ret = csx_ReleaseConfiguration(pcwl_p->pcwl_chdl, NULL)) 8013737Shx147065 cmn_err(CE_WARN, "pcwl: ReleaseConfiguration failed %x\n", ret); 8023737Shx147065 8033737Shx147065 bzero(&irq, sizeof (irq)); 8043737Shx147065 if (ret = csx_ReleaseIRQ(pcwl_p->pcwl_chdl, &irq)) 8053737Shx147065 cmn_err(CE_WARN, "pcwl: ReleaseIRQ failed %x\n", ret); 8063737Shx147065 8073737Shx147065 ddi_remove_softintr(pcwl_p->pcwl_softint_id); 8083737Shx147065 8093737Shx147065 bzero(&io, sizeof (io)); 8103737Shx147065 io.BasePort1.handle = pcwl_p->pcwl_port; 8113737Shx147065 io.NumPorts1 = 16; 8123737Shx147065 if (ret = csx_ReleaseIO(pcwl_p->pcwl_chdl, &io)) 8133737Shx147065 cmn_err(CE_WARN, "pcwl: ReleaseIO failed %x\n", ret); 8143737Shx147065 8153737Shx147065 pcwl_p->pcwl_port = 0; 8163737Shx147065 pcwl_p->pcwl_flag &= ~PCWL_CARD_READY; 8173737Shx147065 } 8183737Shx147065 8193737Shx147065 /* 8203737Shx147065 * mac operation interface routines 8213737Shx147065 */ 8223737Shx147065 static int 8233737Shx147065 pcwl_start(void *arg) 8243737Shx147065 { 8253737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg; 8263737Shx147065 8273737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 8283737Shx147065 if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) { 8293737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 8303737Shx147065 return (PCWL_FAIL); 8313737Shx147065 } 8323737Shx147065 pcwl_start_locked(pcwl_p); 8333737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 8343737Shx147065 return (PCWL_SUCCESS); 8353737Shx147065 } 8363737Shx147065 8373737Shx147065 static void 8383737Shx147065 pcwl_stop(void *arg) 8393737Shx147065 { 8403737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg; 8413737Shx147065 8423737Shx147065 PCWLDBG((CE_NOTE, "pcwl_stop called\n")); 8433737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 8443737Shx147065 if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) { 8453737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 8463737Shx147065 return; 8473737Shx147065 } 8483737Shx147065 8493737Shx147065 pcwl_stop_locked(pcwl_p); 8503737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 8513737Shx147065 if (pcwl_p->pcwl_connect_timeout_id != 0) { 8523737Shx147065 (void) untimeout(pcwl_p->pcwl_connect_timeout_id); 8533737Shx147065 pcwl_p->pcwl_connect_timeout_id = 0; 8543737Shx147065 } 8553737Shx147065 } 8563737Shx147065 8573737Shx147065 static int 8583737Shx147065 pcwl_saddr(void *arg, const uint8_t *macaddr) 8593737Shx147065 { 8603737Shx147065 int ret = PCWL_SUCCESS; 8613737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg; 8623737Shx147065 8633737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 8643737Shx147065 if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) { 8653737Shx147065 ret = PCWL_FAIL; 8663737Shx147065 goto done; 8673737Shx147065 } 8683737Shx147065 ether_copy(macaddr, pcwl_p->pcwl_mac_addr); 8693737Shx147065 if (pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) { 8703737Shx147065 ret = PCWL_FAIL; 8713737Shx147065 goto done; 8723737Shx147065 } 8733737Shx147065 if (pcwl_saddr_locked(pcwl_p)) { 8743737Shx147065 ret = PCWL_FAIL; 8753737Shx147065 goto done; 8763737Shx147065 } 8773737Shx147065 if (pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) { 8783737Shx147065 ret = PCWL_FAIL; 8793737Shx147065 } 8803737Shx147065 done: 8813737Shx147065 if (ret) 8823737Shx147065 cmn_err(CE_WARN, "pcwl set_mac_addr: failed\n"); 8833737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 8843737Shx147065 return (ret); 8853737Shx147065 } 8863737Shx147065 8873737Shx147065 static int 8883737Shx147065 pcwl_send(pcwl_maci_t *pcwl_p, mblk_t *mblk_p) 8893737Shx147065 { 8903737Shx147065 int i = 0; 8913737Shx147065 char *buf, *buf_p; 8923737Shx147065 wl_frame_t *frm_p; 8933737Shx147065 uint16_t pkt_len, ret; 8943737Shx147065 uint16_t xmt_id, ring_idx; 8953737Shx147065 struct ieee80211_frame *wh; 8963737Shx147065 struct ieee80211_llc *llc; 8973737Shx147065 8983737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 8993737Shx147065 if ((pcwl_p->pcwl_flag & (PCWL_CARD_READY | PCWL_CARD_LINKUP)) != 9003737Shx147065 (PCWL_CARD_READY | PCWL_CARD_LINKUP)) { 9013737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 9023737Shx147065 freemsg(mblk_p); 9033737Shx147065 return (PCWL_SUCCESS); /* drop packet */ 9043737Shx147065 } 9053737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 9063737Shx147065 9073737Shx147065 if (pullupmsg(mblk_p, -1) == 0) { 9083737Shx147065 freemsg(mblk_p); 9093737Shx147065 return (PCWL_SUCCESS); /* drop packet */ 9103737Shx147065 } 9113737Shx147065 wh = (struct ieee80211_frame *)mblk_p->b_rptr; 9123737Shx147065 llc = (struct ieee80211_llc *)&wh[1]; 9133737Shx147065 9143737Shx147065 mutex_enter(&pcwl_p->pcwl_txring.wl_tx_lock); 9153737Shx147065 ring_idx = pcwl_p->pcwl_txring.wl_tx_prod; 9163737Shx147065 pcwl_p->pcwl_txring.wl_tx_prod = (ring_idx + 1) & (WL_XMT_BUF_NUM - 1); 9173737Shx147065 9183737Shx147065 /* 9193737Shx147065 * check whether there is a xmt buffer available 9203737Shx147065 */ 9213737Shx147065 while ((i < WL_XMT_BUF_NUM) && 9223737Shx147065 (pcwl_p->pcwl_txring.wl_tx_ring[ring_idx])) { 9233737Shx147065 ring_idx = pcwl_p->pcwl_txring.wl_tx_prod; 9243737Shx147065 pcwl_p->pcwl_txring.wl_tx_prod = 9253737Shx147065 (ring_idx + 1) & (WL_XMT_BUF_NUM - 1); 9263737Shx147065 i++; 9273737Shx147065 } 9283737Shx147065 if (i == WL_XMT_BUF_NUM) { 9293737Shx147065 mutex_exit(&pcwl_p->pcwl_txring.wl_tx_lock); 9303737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 9313737Shx147065 pcwl_p->pcwl_reschedule_need = B_TRUE; 9323737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 9333737Shx147065 pcwl_p->pcwl_noxmtbuf++; 9343737Shx147065 return (PCWL_FAIL); 9353737Shx147065 } 9363737Shx147065 xmt_id = pcwl_p->pcwl_txring.wl_tx_fids[ring_idx]; 9373737Shx147065 pcwl_p->pcwl_txring.wl_tx_ring[ring_idx] = xmt_id; 9383737Shx147065 mutex_exit(&pcwl_p->pcwl_txring.wl_tx_lock); 9393737Shx147065 9403737Shx147065 buf = kmem_zalloc(PCWL_NICMEM_SZ, KM_SLEEP); 9413737Shx147065 buf_p = (ulong_t)buf & 1 ? buf + 1 : buf; 9423737Shx147065 frm_p = (wl_frame_t *)buf_p; 9433737Shx147065 #ifdef DEBUG 9443737Shx147065 if (pcwl_debug & PCWL_DBG_SEND) { 9453737Shx147065 cmn_err(CE_NOTE, "pcwl send: packet"); 9463737Shx147065 for (i = 0; i < mblk_p->b_wptr - mblk_p->b_rptr; i++) 9473737Shx147065 cmn_err(CE_NOTE, "%x: %x\n", i, 9483737Shx147065 *((unsigned char *)mblk_p->b_rptr + i)); 9493737Shx147065 } 9503737Shx147065 #endif 9513737Shx147065 pkt_len = msgdsize(mblk_p); 9523737Shx147065 if (pkt_len > (PCWL_NICMEM_SZ - sizeof (wl_frame_t))) { 9533737Shx147065 cmn_err(CE_WARN, "pcwl: send mblk is too long"); 9543737Shx147065 kmem_free(buf, PCWL_NICMEM_SZ); 9553737Shx147065 freemsg(mblk_p); 9563737Shx147065 return (PCWL_SUCCESS); /* drop packet */ 9573737Shx147065 } 9583737Shx147065 if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) != 9593737Shx147065 IEEE80211_FC1_DIR_TODS) { 9603737Shx147065 kmem_free(buf, PCWL_NICMEM_SZ); 9613737Shx147065 freemsg(mblk_p); 9623737Shx147065 return (PCWL_SUCCESS); /* drop packet */ 9633737Shx147065 } 9643737Shx147065 bzero(frm_p, WL_802_11_HDRLEN); 9653737Shx147065 9663737Shx147065 frm_p->wl_tx_ctl = WL_TXCNTL_SET; 9673737Shx147065 bcopy(wh->i_addr3, frm_p->wl_dst_addr, ETHERADDRL); /* dst macaddr */ 9683737Shx147065 bcopy(wh->i_addr2, frm_p->wl_src_addr, ETHERADDRL); /* src macaddr */ 9693737Shx147065 frm_p->wl_len = htons(pkt_len - sizeof (*wh)); 9703737Shx147065 bcopy(llc, &frm_p->wl_dat[0], pkt_len - sizeof (*wh)); 9713737Shx147065 pkt_len = pkt_len - (sizeof (*wh) + sizeof (*llc)) + 9723737Shx147065 WL_802_11_HDRLEN; 9733737Shx147065 PCWLDBG((CE_NOTE, "send: DIX frmsz=%x pkt_len=%x\n", 9743737Shx147065 WL_802_11_HDRLEN, pkt_len)); 9753737Shx147065 9763737Shx147065 if (pkt_len & 1) /* round up to 16-bit boundary and pad 0 */ 9773737Shx147065 buf_p[pkt_len++] = 0; 9783737Shx147065 9793737Shx147065 ASSERT(pkt_len <= PCWL_NICMEM_SZ); 9803737Shx147065 #ifdef DEBUG 9813737Shx147065 if (pcwl_debug & PCWL_DBG_SEND) { 9823737Shx147065 cmn_err(CE_NOTE, "pkt_len = %x\n", pkt_len); 9833737Shx147065 for (i = 0; i < pkt_len; i++) 9843737Shx147065 cmn_err(CE_NOTE, "%x: %x\n", i, 9853737Shx147065 *((unsigned char *)buf + i)); 9863737Shx147065 } 9873737Shx147065 #endif 9883737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 9893737Shx147065 ret = (WRCH1(pcwl_p, xmt_id, 0, (uint16_t *)buf_p, 0x2e) || 9903737Shx147065 WRPKT(pcwl_p, xmt_id, 0x2e, (uint16_t *)(buf_p + 0x2e), 9913737Shx147065 pkt_len - 0x2e)); 9923737Shx147065 if (ret) { 9933737Shx147065 goto done; 9943737Shx147065 } 9953737Shx147065 PCWLDBG((CE_NOTE, "send: xmt_id=%x send=%x\n", xmt_id, pkt_len)); 9963737Shx147065 (void) pcwl_set_cmd(pcwl_p, WL_CMD_TX | WL_RECLAIM, xmt_id); 9973737Shx147065 9983737Shx147065 done: 9993737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 10003737Shx147065 kmem_free(buf, PCWL_NICMEM_SZ); 10013737Shx147065 freemsg(mblk_p); 10023737Shx147065 return (PCWL_SUCCESS); 10033737Shx147065 } 10043737Shx147065 10053737Shx147065 static mblk_t * 10063737Shx147065 pcwl_tx(void *arg, mblk_t *mp) 10073737Shx147065 { 10083737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg; 10093737Shx147065 mblk_t *next; 10103737Shx147065 10113737Shx147065 ASSERT(mp != NULL); 10123737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 10133737Shx147065 if ((pcwl_p->pcwl_flag & (PCWL_CARD_LINKUP | PCWL_CARD_READY)) != 10143737Shx147065 (PCWL_CARD_LINKUP | PCWL_CARD_READY)) { 10153737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 10163737Shx147065 return (mp); 10173737Shx147065 } 10183737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 10193737Shx147065 while (mp != NULL) { 10203737Shx147065 next = mp->b_next; 10213737Shx147065 mp->b_next = NULL; 10223737Shx147065 10233737Shx147065 if (pcwl_send(pcwl_p, mp)) { 10243737Shx147065 mp->b_next = next; 10253737Shx147065 break; 10263737Shx147065 } 10273737Shx147065 mp = next; 10283737Shx147065 } 10293737Shx147065 return (mp); 10303737Shx147065 } 10313737Shx147065 10323737Shx147065 static int 10333737Shx147065 pcwl_prom(void *arg, boolean_t on) 10343737Shx147065 { 10353737Shx147065 int ret = PCWL_SUCCESS; 10363737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg; 10373737Shx147065 10383737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 10393737Shx147065 if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) { 10403737Shx147065 ret = PCWL_FAIL; 10413737Shx147065 goto done; 10423737Shx147065 } 10433737Shx147065 10443737Shx147065 PCWLDBG((CE_NOTE, "pcwl_prom called %x\n", on)); 10453737Shx147065 10463737Shx147065 if (on) 10473737Shx147065 pcwl_p->pcwl_rf.rf_promiscuous = 1; 10483737Shx147065 else 10493737Shx147065 pcwl_p->pcwl_rf.rf_promiscuous = 0; 10503737Shx147065 if (ret = pcwl_fil_ltv(pcwl_p, 2, WL_RID_PROMISC, 10513737Shx147065 pcwl_p->pcwl_rf.rf_promiscuous)) { 10523737Shx147065 ret = PCWL_FAIL; 10533737Shx147065 } 10543737Shx147065 done: 10553737Shx147065 if (ret) 10563737Shx147065 cmn_err(CE_WARN, "pcwl promisc: failed\n"); 10573737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 10583737Shx147065 return (ret); 10593737Shx147065 } 10603737Shx147065 10613737Shx147065 static int 10623737Shx147065 pcwl_gstat(void *arg, uint_t statitem, uint64_t *val) 10633737Shx147065 { 10643737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg; 10653737Shx147065 int ret = PCWL_SUCCESS; 10663737Shx147065 uint64_t *cntr_p = pcwl_p->pcwl_cntrs_s; 10673737Shx147065 uint16_t rate = 0; 10683737Shx147065 uint64_t speed; 10693737Shx147065 10703737Shx147065 PCWLDBG((CE_NOTE, "pcwl_gstat called\n")); 10713737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 10723737Shx147065 if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) { 10733737Shx147065 ret = PCWL_FAIL; 10743737Shx147065 goto done; 10753737Shx147065 } 10763737Shx147065 10773737Shx147065 if (pcwl_get_ltv(pcwl_p, 2, WL_RID_CUR_TX_RATE, &rate)) { 10783737Shx147065 cmn_err(CE_WARN, "pcwl kstat: get speed failed\n"); 10793737Shx147065 ret = PCWL_FAIL; 10803737Shx147065 goto done; 10813737Shx147065 } 10823737Shx147065 switch (pcwl_p->pcwl_chip_type) { 10833737Shx147065 case PCWL_CHIP_PRISMII: 10843737Shx147065 switch (rate) { 10853737Shx147065 case WL_SPEED_1Mbps_P2: rate = 2; break; 10863737Shx147065 case WL_SPEED_2Mbps_P2: rate = 4; break; 10873737Shx147065 case WL_SPEED_55Mbps_P2: rate = 11; break; 10883737Shx147065 case WL_SPEED_11Mbps_P2: rate = 22; break; 10893737Shx147065 default: rate = 0; break; 10903737Shx147065 } 10913737Shx147065 speed = rate * 500000; 10923737Shx147065 break; 10933737Shx147065 case PCWL_CHIP_LUCENT: 10943737Shx147065 default: 10953737Shx147065 speed = rate * 1000000; 10963737Shx147065 if (rate == 6) 10973737Shx147065 speed = 5500000; 10983737Shx147065 break; 10993737Shx147065 } 11003737Shx147065 11013737Shx147065 switch (statitem) { 11023737Shx147065 case MAC_STAT_IFSPEED: 11033737Shx147065 *val = speed; 11043737Shx147065 break; 11053737Shx147065 case MAC_STAT_NOXMTBUF: 11063737Shx147065 *val = pcwl_p->pcwl_noxmtbuf; 11073737Shx147065 break; 11083737Shx147065 case MAC_STAT_NORCVBUF: 11093737Shx147065 *val = cntr_p[WLC_RX_DISCARDS_NOBUF]; 11103737Shx147065 break; 11113737Shx147065 case MAC_STAT_IERRORS: 11123737Shx147065 *val = 0; 11133737Shx147065 break; 11143737Shx147065 case MAC_STAT_OERRORS: 11153737Shx147065 *val = cntr_p[WLC_TX_DISCARDS] + 11163737Shx147065 cntr_p[WLC_TX_DISCARDS_WRONG_SA]; 11173737Shx147065 break; 11183737Shx147065 case MAC_STAT_RBYTES: 11193737Shx147065 *val = cntr_p[WLC_RX_UNICAST_OCTETS]; 11203737Shx147065 break; 11213737Shx147065 case MAC_STAT_IPACKETS: 11223737Shx147065 *val = cntr_p[WLC_RX_UNICAST_FRAMES]; 11233737Shx147065 break; 11243737Shx147065 case MAC_STAT_OBYTES: 11253737Shx147065 *val = cntr_p[WLC_TX_UNICAST_OCTETS]; 11263737Shx147065 break; 11273737Shx147065 case MAC_STAT_OPACKETS: 11283737Shx147065 *val = cntr_p[WLC_TX_UNICAST_FRAMES]; 11293737Shx147065 break; 11303737Shx147065 case WIFI_STAT_TX_FAILED: 11313737Shx147065 *val = cntr_p[WLC_TX_RETRY_LIMIT] + 11323737Shx147065 cntr_p[WLC_TX_DEFERRED_XMITS]; 11333737Shx147065 break; 11343737Shx147065 case WIFI_STAT_TX_RETRANS: 11353737Shx147065 *val = cntr_p[WLC_TX_SINGLE_RETRIES] + 11363737Shx147065 cntr_p[WLC_TX_MULTI_RETRIES]; 11373737Shx147065 break; 11383737Shx147065 case WIFI_STAT_FCS_ERRORS: 11393737Shx147065 *val = cntr_p[WLC_RX_FCS_ERRORS]; 11403737Shx147065 break; 11413737Shx147065 case WIFI_STAT_WEP_ERRORS: 11423737Shx147065 *val = cntr_p[WLC_RX_WEP_CANT_DECRYPT]; 11433737Shx147065 break; 11443737Shx147065 case WIFI_STAT_MCAST_TX: 11453737Shx147065 *val = cntr_p[WLC_TX_MULTICAST_FRAMES]; 11463737Shx147065 break; 11473737Shx147065 case WIFI_STAT_MCAST_RX: 11483737Shx147065 *val = cntr_p[WLC_RX_MULTICAST_FRAMES]; 11493737Shx147065 break; 11503737Shx147065 case WIFI_STAT_TX_FRAGS: 11513737Shx147065 *val = cntr_p[WLC_TX_FRAGMENTS]; 11523737Shx147065 break; 11533737Shx147065 case WIFI_STAT_RX_FRAGS: 11543737Shx147065 *val = cntr_p[WLC_RX_FRAGMENTS] + 11553737Shx147065 cntr_p[WLC_RX_MSG_IN_MSG_FRAGS] + 11563737Shx147065 cntr_p[WLC_RX_MSG_IN_BAD_MSG_FRAGS]; 11573737Shx147065 break; 11583737Shx147065 case WIFI_STAT_RTS_SUCCESS: 11593737Shx147065 case WIFI_STAT_RTS_FAILURE: 11603737Shx147065 case WIFI_STAT_ACK_FAILURE: 11613737Shx147065 case WIFI_STAT_RX_DUPS: 11623737Shx147065 *val = 0; 11633737Shx147065 break; 11643737Shx147065 default: 11653737Shx147065 ret = ENOTSUP; 11663737Shx147065 } 11673737Shx147065 done: 11683737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 11693737Shx147065 return (ret); 11703737Shx147065 } 11713737Shx147065 11723737Shx147065 static int 11733737Shx147065 pcwl_sdmulti(void *arg, boolean_t add, const uint8_t *eth_p) 11743737Shx147065 { 11753737Shx147065 int ret = PCWL_SUCCESS; 11763737Shx147065 uint16_t i; 11773737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg; 11783737Shx147065 uint16_t *mc_p = pcwl_p->pcwl_mcast; 11793737Shx147065 11803737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 11813737Shx147065 if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) { 11823737Shx147065 ret = PCWL_FAIL; 11833737Shx147065 goto done; 11843737Shx147065 } 11853737Shx147065 11863737Shx147065 if (add) { /* enable multicast on eth_p, search for available entries */ 11873737Shx147065 for (i = 0; i < 16; i++, mc_p += (ETHERADDRL >> 1)) { 11883737Shx147065 if (!ether_cmp(eth_p, mc_p)) 11893737Shx147065 break; 11903737Shx147065 } 11913737Shx147065 if (i < 16) /* already part of the filter */ 11923737Shx147065 goto done; 11933737Shx147065 mc_p = pcwl_p->pcwl_mcast; /* reset mc_p for 2nd scan */ 11943737Shx147065 for (i = 0; i < 16; i++, mc_p += (ETHERADDRL >> 1)) { 11953737Shx147065 PCWLDBG((CE_NOTE, "smulti: mc[%x]=%s\n", i, 11963737Shx147065 ether_sprintf((struct ether_addr *)mc_p))); 11973737Shx147065 if (mc_p[0] == 0 && mc_p[1] == 0 && mc_p[2] == 0) 11983737Shx147065 break; 11993737Shx147065 } 12003737Shx147065 if (i >= 16) /* can't find a vacant entry */ 12013737Shx147065 goto done; 12023737Shx147065 ether_copy(eth_p, mc_p); 12033737Shx147065 } else { /* disable multicast, locate the entry and clear it */ 12043737Shx147065 for (i = 0; i < 16; i++, mc_p += (ETHERADDRL >> 1)) { 12053737Shx147065 if (!ether_cmp(eth_p, mc_p)) 12063737Shx147065 break; 12073737Shx147065 } 12083737Shx147065 if (i >= 16) 12093737Shx147065 goto done; 12103737Shx147065 mc_p[0] = 0; 12113737Shx147065 mc_p[1] = 0; 12123737Shx147065 mc_p[2] = 0; 12133737Shx147065 } 12143737Shx147065 /* 12153737Shx147065 * re-blow the entire 16 entries buffer 12163737Shx147065 */ 12173737Shx147065 if (i = pcwl_put_ltv(pcwl_p, ETHERADDRL << 4, WL_RID_MCAST, 12183737Shx147065 pcwl_p->pcwl_mcast)) { 12193737Shx147065 ret = PCWL_FAIL; 12203737Shx147065 } 12213737Shx147065 done: 12223737Shx147065 if (ret) 12233737Shx147065 cmn_err(CE_WARN, "pcwl set multi addr: failed\n"); 12243737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 12253737Shx147065 return (ret); 12263737Shx147065 } 12273737Shx147065 12283737Shx147065 static uint_t 12293737Shx147065 pcwl_intr(caddr_t arg) 12303737Shx147065 { 12313737Shx147065 uint16_t stat; 12323737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg; 12333737Shx147065 12343737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 12353737Shx147065 if ((pcwl_p->pcwl_flag & (PCWL_CARD_READY | PCWL_CARD_INTREN)) != 12363737Shx147065 (PCWL_CARD_READY | PCWL_CARD_INTREN)) { 12373737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 12383737Shx147065 return (DDI_INTR_UNCLAIMED); 12393737Shx147065 } 12403737Shx147065 PCWL_READ(pcwl_p, WL_EVENT_STAT, stat); 12413737Shx147065 if (!(stat & WL_INTRS) || stat == WL_EV_ALL) { 12423737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 12433737Shx147065 return (DDI_INTR_UNCLAIMED); 12443737Shx147065 } 12453737Shx147065 12463737Shx147065 PCWL_WRITE(pcwl_p, WL_INT_EN, 0); 12473737Shx147065 if (stat & WL_EV_RX) { 12483737Shx147065 pcwl_rcv(pcwl_p); 12493737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_RX); 12503737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_RX); 12513737Shx147065 } 12523737Shx147065 if (stat & WL_EV_TX) { 12533737Shx147065 if (pcwl_txdone(pcwl_p) == PCWL_SUCCESS) { 12543737Shx147065 if (pcwl_p->pcwl_reschedule_need == B_TRUE) { 12553737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 12563737Shx147065 mac_tx_update(GLD3(pcwl_p)); 12573737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 12583737Shx147065 pcwl_p->pcwl_reschedule_need = B_FALSE; 12593737Shx147065 } 12603737Shx147065 } 12613737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX); 12623737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX); 12633737Shx147065 } 12643737Shx147065 if (stat & WL_EV_ALLOC) { 12653737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_ALLOC | 0x1000); 12663737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, 0x1000); 12673737Shx147065 } 12683737Shx147065 if (stat & WL_EV_INFO) { 12693737Shx147065 pcwl_infodone(pcwl_p); 12703737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_INFO); 12713737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_INFO); 12723737Shx147065 } 12733737Shx147065 if (stat & WL_EV_TX_EXC) { 12743737Shx147065 if (pcwl_txdone(pcwl_p) == PCWL_SUCCESS) { 12753737Shx147065 if (pcwl_p->pcwl_reschedule_need == B_TRUE) { 12763737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 12773737Shx147065 mac_tx_update(GLD3(pcwl_p)); 12783737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 12793737Shx147065 pcwl_p->pcwl_reschedule_need = B_FALSE; 12803737Shx147065 } 12813737Shx147065 } 12823737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX_EXC); 12833737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX_EXC); 12843737Shx147065 } 12853737Shx147065 if (stat & WL_EV_INFO_DROP) { 12863737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_INFO_DROP); 12873737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_INFO_DROP); 12883737Shx147065 } 12893737Shx147065 PCWL_ENABLE_INTR(pcwl_p); 12903737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 12913737Shx147065 12923737Shx147065 return (DDI_INTR_CLAIMED); 12933737Shx147065 } 12943737Shx147065 12953737Shx147065 static uint_t 12963737Shx147065 pcwl_intr_hi(caddr_t arg) 12973737Shx147065 { 12983737Shx147065 uint16_t stat; 12993737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg; 13003737Shx147065 13013737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 13023737Shx147065 if ((pcwl_p->pcwl_flag & (PCWL_CARD_READY | PCWL_CARD_INTREN)) != 13033737Shx147065 (PCWL_CARD_READY | PCWL_CARD_INTREN)) { 13043737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 13053737Shx147065 return (DDI_INTR_UNCLAIMED); 13063737Shx147065 } 13073737Shx147065 PCWL_READ(pcwl_p, WL_EVENT_STAT, stat); 13083737Shx147065 if (!(stat & WL_INTRS) || stat == WL_EV_ALL) { 13093737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 13103737Shx147065 return (DDI_INTR_UNCLAIMED); 13113737Shx147065 } 13123737Shx147065 PCWL_WRITE(pcwl_p, WL_INT_EN, 0); /* disable interrupt without ack */ 13133737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 13143737Shx147065 ddi_trigger_softintr(pcwl_p->pcwl_softint_id); 13153737Shx147065 return (DDI_INTR_CLAIMED); 13163737Shx147065 } 13173737Shx147065 13183737Shx147065 /* 13193737Shx147065 * called at interrupt context to retrieve data from card 13203737Shx147065 */ 13213737Shx147065 static void 13223737Shx147065 pcwl_rcv(pcwl_maci_t *pcwl_p) 13233737Shx147065 { 13243737Shx147065 uint16_t id, len, off, ret, frm_ctl; 13253737Shx147065 wl_frame_t frm; 13263737Shx147065 mblk_t *mp = allocb(PCWL_NICMEM_SZ, BPRI_MED); 13273737Shx147065 if (!mp) 13283737Shx147065 return; 13293737Shx147065 ASSERT(mp->b_rptr == mp->b_wptr); 13303737Shx147065 13313737Shx147065 PCWL_READ(pcwl_p, WL_RX_FID, id); 13323737Shx147065 PCWL_WRITE(pcwl_p, WL_RX_FID, 0); 13333737Shx147065 if (id == WL_INVALID_FID) { 13343737Shx147065 PCWLDBG((CE_NOTE, "pcwl rcv: get rx_fid failed\n")); 13353737Shx147065 ret = PCWL_FAIL; 13363737Shx147065 goto done; 13373737Shx147065 } 13383737Shx147065 if (ret = RDCH0(pcwl_p, id, 0, (uint16_t *)&frm, sizeof (frm))) { 13393737Shx147065 PCWLDBG((CE_NOTE, "pcwl rcv: read frm failed %x\n", ret)); 13403737Shx147065 goto done; 13413737Shx147065 } 13423737Shx147065 if (frm.wl_status & WL_STAT_ERRSTAT) { 13433737Shx147065 PCWLDBG((CE_NOTE, "pcwl rcv: errstat %x\n", frm.wl_status)); 13443737Shx147065 ret = frm.wl_status; 13453737Shx147065 goto done; 13463737Shx147065 } 13473737Shx147065 PCWLDBG((CE_NOTE, "pcwl rcv: frame type %x\n", frm.wl_status)); 13483737Shx147065 #ifdef DEBUG 13493737Shx147065 if (pcwl_debug & PCWL_DBG_RCV) { 13503737Shx147065 int i; 13513737Shx147065 cmn_err(CE_NOTE, "pcwl rcv: frm header\n"); 13523737Shx147065 for (i = 0; i < WL_802_11_HDRLEN; i++) 13533737Shx147065 cmn_err(CE_NOTE, "%x: %x\n", i, 13543737Shx147065 *((uint8_t *)&frm + i)); 13553737Shx147065 } 13563737Shx147065 #endif 13573737Shx147065 len = frm.wl_dat_len; 13583737Shx147065 /* 13593737Shx147065 * this driver deal with WEP by itself. so plugin always thinks no wep. 13603737Shx147065 */ 13613737Shx147065 frm.wl_frame_ctl &= ~(IEEE80211_FC1_WEP << 8); 13623737Shx147065 frm_ctl = frm.wl_frame_ctl; 13633737Shx147065 switch (frm.wl_status) { 13643737Shx147065 case WL_STAT_1042: 13653737Shx147065 case WL_STAT_TUNNEL: 13663737Shx147065 case WL_STAT_WMP_MSG: 13673737Shx147065 PCWL_SWAP16((uint16_t *)&frm.wl_frame_ctl, 13683737Shx147065 sizeof (struct ieee80211_frame)); 13693737Shx147065 /* 13703737Shx147065 * discard those frames which are not from the AP we connect or 13713737Shx147065 * without 'ap->sta' direction 13723737Shx147065 */ 13733737Shx147065 if ((pcwl_p->pcwl_rf.rf_porttype == WL_BSS_BSS) && 13743737Shx147065 ((((frm_ctl >> 8) & IEEE80211_FC1_DIR_MASK) != 13753737Shx147065 IEEE80211_FC1_DIR_FROMDS) || 13763737Shx147065 bcmp(pcwl_p->pcwl_bssid, frm.wl_addr2, 6) != 0)) { 13773737Shx147065 ret = PCWL_FAIL; 13783737Shx147065 goto done; 13793737Shx147065 } 13803737Shx147065 13813737Shx147065 bcopy(&frm.wl_frame_ctl, mp->b_wptr, 13823737Shx147065 sizeof (struct ieee80211_frame)); 13833737Shx147065 mp->b_wptr += sizeof (struct ieee80211_frame); 13843737Shx147065 13853737Shx147065 PCWL_SWAP16((uint16_t *)&frm.wl_dat[0], 13863737Shx147065 sizeof (struct ieee80211_llc)); 13873737Shx147065 bcopy(&frm.wl_dat[0], mp->b_wptr, 13883737Shx147065 sizeof (struct ieee80211_llc)); 13893737Shx147065 mp->b_wptr += sizeof (struct ieee80211_llc); 13903737Shx147065 13913737Shx147065 len -= (2 + WL_SNAPHDR_LEN); 13923737Shx147065 off = WL_802_11_HDRLEN; 13933737Shx147065 break; 13943737Shx147065 default: 13953737Shx147065 PCWLDBG((CE_NOTE, "pcwl rcv: incorrect pkt\n")); 13963737Shx147065 break; 13973737Shx147065 } 13983737Shx147065 if (len > MBLKSIZE(mp)) { 13993737Shx147065 PCWLDBG((CE_NOTE, "pcwl rcv: oversz pkt %x\n", len)); 14003737Shx147065 ret = PCWL_FAIL; 14013737Shx147065 goto done; 14023737Shx147065 } 14033737Shx147065 if (len & 1) 14043737Shx147065 len++; 14053737Shx147065 ret = RDPKT(pcwl_p, id, off, (uint16_t *)mp->b_wptr, len); 14063737Shx147065 done: 14073737Shx147065 if (ret) { 14083737Shx147065 PCWLDBG((CE_NOTE, "pcwl rcv: rd data %x\n", ret)); 14093737Shx147065 freemsg(mp); 14103737Shx147065 return; 14113737Shx147065 } 14123737Shx147065 mp->b_wptr = mp->b_wptr + len; 14133737Shx147065 #ifdef DEBUG 14143737Shx147065 if (pcwl_debug & PCWL_DBG_RCV) { 14153737Shx147065 int i; 14163737Shx147065 cmn_err(CE_NOTE, "pcwl rcv: len=0x%x\n", len); 14173737Shx147065 for (i = 0; i < len+14; i++) 14183737Shx147065 cmn_err(CE_NOTE, "%x: %x\n", i, 14193737Shx147065 *((uint8_t *)mp->b_rptr + i)); 14203737Shx147065 } 14213737Shx147065 #endif 14223737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 14233737Shx147065 mac_rx(GLD3(pcwl_p), NULL, mp); 14243737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 14253737Shx147065 } 14263737Shx147065 14273737Shx147065 static uint32_t 14283737Shx147065 pcwl_txdone(pcwl_maci_t *pcwl_p) 14293737Shx147065 { 14303737Shx147065 uint16_t fid, i; 14313737Shx147065 PCWL_READ(pcwl_p, WL_ALLOC_FID, fid); 14323737Shx147065 PCWL_WRITE(pcwl_p, WL_ALLOC_FID, 0); 14333737Shx147065 14343737Shx147065 mutex_enter(&pcwl_p->pcwl_txring.wl_tx_lock); 14353737Shx147065 for (i = 0; i < WL_XMT_BUF_NUM; i++) { 14363737Shx147065 if (fid == pcwl_p->pcwl_txring.wl_tx_ring[i]) { 14373737Shx147065 pcwl_p->pcwl_txring.wl_tx_ring[i] = 0; 14383737Shx147065 break; 14393737Shx147065 } 14403737Shx147065 } 14413737Shx147065 pcwl_p->pcwl_txring.wl_tx_cons = 14423737Shx147065 (pcwl_p->pcwl_txring.wl_tx_cons + 1) & (WL_XMT_BUF_NUM - 1); 14433737Shx147065 mutex_exit(&pcwl_p->pcwl_txring.wl_tx_lock); 14443737Shx147065 if (i == WL_XMT_BUF_NUM) 14453737Shx147065 return (PCWL_FAIL); 14463737Shx147065 return (PCWL_SUCCESS); 14473737Shx147065 14483737Shx147065 } 14493737Shx147065 14503737Shx147065 static void 14513737Shx147065 pcwl_infodone(pcwl_maci_t *pcwl_p) 14523737Shx147065 { 14533737Shx147065 uint16_t id, ret, i; 14543737Shx147065 uint16_t linkStatus[2]; 14553737Shx147065 uint16_t linkStat; 14563737Shx147065 wifi_data_t wd = { 0 }; 14573737Shx147065 14583737Shx147065 PCWL_READ(pcwl_p, WL_INFO_FID, id); 14593737Shx147065 if (id == WL_INVALID_FID) { 14603737Shx147065 cmn_err(CE_WARN, "pcwl infodone: read info_fid failed\n"); 14613737Shx147065 return; 14623737Shx147065 } 14633737Shx147065 if (ret = RDCH0(pcwl_p, id, 0, linkStatus, sizeof (linkStatus))) { 14643737Shx147065 PCWLDBG((CE_WARN, "pcwl infodone read infoFrm failed %x\n", 14653737Shx147065 ret)); 14663737Shx147065 return; 14673737Shx147065 } 14683737Shx147065 PCWLDBG((CE_NOTE, "pcwl infodone: Frame length= %x, Frame Type = %x\n", 14693737Shx147065 linkStatus[0], linkStatus[1])); 14703737Shx147065 14713737Shx147065 switch (linkStatus[1]) { 14723737Shx147065 case WL_INFO_LINK_STAT: 14733737Shx147065 (void) RDCH0(pcwl_p, id, sizeof (linkStatus), &linkStat, 14743737Shx147065 sizeof (linkStat)); 14753737Shx147065 PCWLDBG((CE_NOTE, "pcwl infodone: link status=%x\n", linkStat)); 14763737Shx147065 if (!(pcwl_p->pcwl_flag & PCWL_CARD_LINKUP) && 14773737Shx147065 linkStat == WL_LINK_CONNECT) { 14783737Shx147065 #ifdef DEBUG 14793737Shx147065 if (pcwl_debug & PCWL_DBG_LINKINFO) 14803737Shx147065 cmn_err(CE_NOTE, "pcwl: Link up \n"); 14813737Shx147065 #endif 14823737Shx147065 pcwl_p->pcwl_flag |= PCWL_CARD_LINKUP; 14833737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 14843737Shx147065 if (pcwl_p->pcwl_connect_timeout_id != 0) { 14853737Shx147065 (void) untimeout(pcwl_p-> 14863737Shx147065 pcwl_connect_timeout_id); 14873737Shx147065 pcwl_p->pcwl_connect_timeout_id = 0; 14883737Shx147065 } 14893737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 14903737Shx147065 mac_link_update(GLD3(pcwl_p), LINK_STATE_UP); 14913737Shx147065 (void) pcwl_get_ltv(pcwl_p, 6, 14923737Shx147065 WL_RID_BSSID, (uint16_t *)pcwl_p->pcwl_bssid); 14933737Shx147065 PCWL_SWAP16((uint16_t *)pcwl_p->pcwl_bssid, 6); 14943737Shx147065 pcwl_get_rssi(pcwl_p); 14953737Shx147065 bcopy(pcwl_p->pcwl_bssid, wd.wd_bssid, 6); 14963737Shx147065 wd.wd_secalloc = WIFI_SEC_NONE; 14973737Shx147065 wd.wd_opmode = IEEE80211_M_STA; 14983737Shx147065 (void) mac_pdata_update(pcwl_p->pcwl_mh, &wd, 14993737Shx147065 sizeof (wd)); 15003737Shx147065 } 15013737Shx147065 if ((pcwl_p->pcwl_flag & PCWL_CARD_LINKUP) && 15023737Shx147065 ((linkStat == WL_LINK_DISCONNECT) || 15033737Shx147065 (linkStat == WL_LINK_AP_OOR))) { 15043737Shx147065 #ifdef DEBUG 15053737Shx147065 if (pcwl_debug & PCWL_DBG_LINKINFO) 15063737Shx147065 cmn_err(CE_NOTE, "pcwl: Link down \n"); 15073737Shx147065 #endif 15083737Shx147065 PCWLDBG((CE_NOTE, "pcwl infodone: link status = %d\n", 15093737Shx147065 linkStat)); 15103737Shx147065 pcwl_p->pcwl_flag &= ~PCWL_CARD_LINKUP; 15113737Shx147065 if (linkStat == WL_LINK_AP_OOR) 15123737Shx147065 pcwl_p->pcwl_connect_timeout_id = 15133737Shx147065 timeout(pcwl_connect_timeout, 15143737Shx147065 pcwl_p, drv_usectohz(1000)); 15153737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 15163737Shx147065 mac_link_update(GLD3(pcwl_p), LINK_STATE_DOWN); 15173737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 15183737Shx147065 } 15193737Shx147065 break; 15203737Shx147065 case WL_INFO_SCAN_RESULTS: 15213737Shx147065 case WL_INFO_HSCAN_RESULTS: 15223737Shx147065 pcwl_ssid_scan(pcwl_p, id, linkStatus[0], linkStatus[1]); 15233737Shx147065 break; 15243737Shx147065 case WL_INFO_COUNTERS: 15253737Shx147065 linkStatus[0]--; 15263737Shx147065 if (linkStatus[0] > WLC_STAT_CNT) { 15273737Shx147065 linkStatus[0] = MIN(linkStatus[0], WLC_STAT_CNT); 15283737Shx147065 } 15293737Shx147065 (void) RDCH0(pcwl_p, id, sizeof (linkStatus), 15303737Shx147065 pcwl_p->pcwl_cntrs_t, linkStatus[0]<<1); 15313737Shx147065 /* 15323737Shx147065 * accumulate all the statistics items for kstat use. 15333737Shx147065 */ 15343737Shx147065 for (i = 0; i < WLC_STAT_CNT; i++) 15353737Shx147065 pcwl_p->pcwl_cntrs_s[i] += pcwl_p->pcwl_cntrs_t[i]; 15363737Shx147065 break; 15373737Shx147065 default: 15383737Shx147065 break; 15393737Shx147065 } 15403737Shx147065 } 15413737Shx147065 15423737Shx147065 static uint16_t 15433737Shx147065 pcwl_set_cmd(pcwl_maci_t *pcwl_p, uint16_t cmd, uint16_t param) 15443737Shx147065 { 15453737Shx147065 int i; 15463737Shx147065 uint16_t stat; 15473737Shx147065 15483737Shx147065 if (((cmd == WL_CMD_ENABLE) && 15493737Shx147065 ((pcwl_p->pcwl_flag & PCWL_ENABLED) != 0)) || 15503737Shx147065 ((cmd == WL_CMD_DISABLE) && 15513737Shx147065 ((pcwl_p->pcwl_flag & PCWL_ENABLED) == 0))) 15523737Shx147065 return (PCWL_SUCCESS); 15533737Shx147065 15543737Shx147065 for (i = 0; i < WL_TIMEOUT; i++) { 15553737Shx147065 PCWL_READ(pcwl_p, WL_COMMAND, stat); 15563737Shx147065 if (stat & WL_CMD_BUSY) { 15573737Shx147065 drv_usecwait(1); 15583737Shx147065 } else { 15593737Shx147065 break; 15603737Shx147065 } 15613737Shx147065 } 15623737Shx147065 if (i == WL_TIMEOUT) { 15633737Shx147065 cmn_err(CE_WARN, "pcwl: setcmd %x, %x timeout %x due to " 15643737Shx147065 "busy bit\n", cmd, param, stat); 15653737Shx147065 return (PCWL_TIMEDOUT_CMD); 15663737Shx147065 } 15673737Shx147065 15683737Shx147065 PCWL_WRITE(pcwl_p, WL_PARAM0, param); 15693737Shx147065 PCWL_WRITE(pcwl_p, WL_PARAM1, 0); 15703737Shx147065 PCWL_WRITE(pcwl_p, WL_PARAM2, 0); 15713737Shx147065 PCWL_WRITE(pcwl_p, WL_COMMAND, cmd); 15723737Shx147065 if (cmd == WL_CMD_INI) 15733737Shx147065 drv_usecwait(100000); /* wait .1 sec */ 15743737Shx147065 15753737Shx147065 for (i = 0; i < WL_TIMEOUT; i++) { 15763737Shx147065 PCWL_READ(pcwl_p, WL_EVENT_STAT, stat); 15773737Shx147065 if (!(stat & WL_EV_CMD)) { 15783737Shx147065 drv_usecwait(1); 15793737Shx147065 } else { 15803737Shx147065 break; 15813737Shx147065 } 15823737Shx147065 } 15833737Shx147065 if (i == WL_TIMEOUT) { 15843737Shx147065 cmn_err(CE_WARN, "pcwl: setcmd %x,%x timeout %x\n", 15853737Shx147065 cmd, param, stat); 15863737Shx147065 if (stat & (WL_EV_ALLOC | WL_EV_RX)) 15873737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, stat); 15883737Shx147065 return (PCWL_TIMEDOUT_CMD); 15893737Shx147065 } 15903737Shx147065 PCWL_READ(pcwl_p, WL_STATUS, stat); 15913737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_CMD); 15923737Shx147065 if (stat & WL_STAT_CMD_RESULT) { /* err in feedback status */ 15933737Shx147065 cmn_err(CE_WARN, "pcwl: set_cmd %x,%x failed %x\n", 15943737Shx147065 cmd, param, stat); 15953737Shx147065 return (PCWL_FAILURE_CMD); 15963737Shx147065 } 15973737Shx147065 if (cmd == WL_CMD_ENABLE) 15983737Shx147065 pcwl_p->pcwl_flag |= PCWL_ENABLED; 15993737Shx147065 if (cmd == WL_CMD_DISABLE) 16003737Shx147065 pcwl_p->pcwl_flag &= (~PCWL_ENABLED); 16013737Shx147065 return (PCWL_SUCCESS); 16023737Shx147065 } 16033737Shx147065 16043737Shx147065 static uint16_t 16053737Shx147065 pcwl_set_ch(pcwl_maci_t *pcwl_p, uint16_t type, uint16_t off, uint16_t channel) 16063737Shx147065 { 16073737Shx147065 int i; 16083737Shx147065 uint16_t stat, select, offset; 16093737Shx147065 16103737Shx147065 if (channel) { 16113737Shx147065 select = WL_SEL1; 16123737Shx147065 offset = WL_OFF1; 16133737Shx147065 } else { 16143737Shx147065 select = WL_SEL0; 16153737Shx147065 offset = WL_OFF0; 16163737Shx147065 } 16173737Shx147065 PCWL_WRITE(pcwl_p, select, type); 16183737Shx147065 PCWL_WRITE(pcwl_p, offset, off); 16193737Shx147065 for (stat = 0, i = 0; i < WL_TIMEOUT; i++) { 16203737Shx147065 PCWL_READ(pcwl_p, offset, stat); 16213737Shx147065 if (!(stat & (WL_OFF_BUSY|WL_OFF_ERR))) 16223737Shx147065 break; 16233737Shx147065 else { 16243737Shx147065 drv_usecwait(1); 16253737Shx147065 } 16263737Shx147065 } 16273737Shx147065 if (i == WL_TIMEOUT) { 16283737Shx147065 cmn_err(CE_WARN, "set_ch%d %x,%x failed %x\n", 16293737Shx147065 channel, type, off, stat); 16303737Shx147065 return (PCWL_TIMEDOUT_TARGET); 16313737Shx147065 } 16323737Shx147065 return (PCWL_SUCCESS); 16333737Shx147065 } 16343737Shx147065 16353737Shx147065 static uint16_t 16363737Shx147065 pcwl_get_ltv(pcwl_maci_t *pcwl_p, uint16_t len, uint16_t type, uint16_t *val_p) 16373737Shx147065 { 16383737Shx147065 uint16_t stat; 16393737Shx147065 16403737Shx147065 ASSERT(!(len & 1)); 16413737Shx147065 len >>= 1; /* convert bytes to 16-bit words */ 16423737Shx147065 16433737Shx147065 /* 16443737Shx147065 * 1. select read mode 16453737Shx147065 */ 16463737Shx147065 if (stat = pcwl_set_cmd(pcwl_p, WL_CMD_ACCESS | WL_ACCESS_READ, type)) 16473737Shx147065 return (stat); 16483737Shx147065 16493737Shx147065 /* 16503737Shx147065 * 2. select Buffer Access Path (channel) 1 for PIO 16513737Shx147065 */ 16523737Shx147065 if (stat = pcwl_set_ch(pcwl_p, type, 0, 1)) 16533737Shx147065 return (stat); 16543737Shx147065 16553737Shx147065 /* 16563737Shx147065 * 3. read length 16573737Shx147065 */ 16583737Shx147065 PCWL_READ(pcwl_p, WL_DATA1, stat); 16593737Shx147065 if (stat != (len + 1)) { 16603737Shx147065 PCWLDBG((CE_NOTE, "get_ltv 0x%x expected 0x%x+1, got 0x%x\n", 16613737Shx147065 type, (len + 1) << 1, stat)); 16623737Shx147065 stat = (stat >> 1) - 1; 16633737Shx147065 len = MIN(stat, len); 16643737Shx147065 } 16653737Shx147065 16663737Shx147065 /* 16673737Shx147065 * 4. read type 16683737Shx147065 */ 16693737Shx147065 PCWL_READ(pcwl_p, WL_DATA1, stat); 16703737Shx147065 if (stat != type) 16713737Shx147065 return (PCWL_BADTYPE); 16723737Shx147065 16733737Shx147065 /* 16743737Shx147065 * 5. read value 16753737Shx147065 */ 16763737Shx147065 for (stat = 0; stat < len; stat++, val_p++) { 16773737Shx147065 PCWL_READ_P(pcwl_p, WL_DATA1, val_p, 1); 16783737Shx147065 } 16793737Shx147065 return (PCWL_SUCCESS); 16803737Shx147065 } 16813737Shx147065 16823737Shx147065 static uint16_t 16833737Shx147065 pcwl_fil_ltv(pcwl_maci_t *pcwl_p, uint16_t len, uint16_t type, uint16_t val) 16843737Shx147065 { 16853737Shx147065 uint16_t stat; 16863737Shx147065 16873737Shx147065 ASSERT(!(len & 1)); 16883737Shx147065 16893737Shx147065 /* 16903737Shx147065 * 1. select Buffer Access Path (channel) 1 for PIO 16913737Shx147065 */ 16923737Shx147065 if (stat = pcwl_set_ch(pcwl_p, type, 0, 1)) 16933737Shx147065 return (stat); 16943737Shx147065 16953737Shx147065 /* 16963737Shx147065 * 2. write length 16973737Shx147065 */ 16983737Shx147065 len >>= 1; /* convert bytes to 16-bit words */ 16993737Shx147065 stat = len + 1; /* 1 extra word */ 17003737Shx147065 PCWL_WRITE(pcwl_p, WL_DATA1, stat); 17013737Shx147065 17023737Shx147065 /* 17033737Shx147065 * 3. write type 17043737Shx147065 */ 17053737Shx147065 PCWL_WRITE(pcwl_p, WL_DATA1, type); 17063737Shx147065 17073737Shx147065 /* 17083737Shx147065 * 4. fill value 17093737Shx147065 */ 17103737Shx147065 for (stat = 0; stat < len; stat++) { 17113737Shx147065 PCWL_WRITE(pcwl_p, WL_DATA1, val); 17123737Shx147065 } 17133737Shx147065 17143737Shx147065 /* 17153737Shx147065 * 5. select write mode 17163737Shx147065 */ 17173737Shx147065 return (pcwl_set_cmd(pcwl_p, WL_CMD_ACCESS|WL_ACCESS_WRITE, type)); 17183737Shx147065 } 17193737Shx147065 17203737Shx147065 static uint16_t 17213737Shx147065 pcwl_put_ltv(pcwl_maci_t *pcwl_p, uint16_t len, uint16_t type, uint16_t *val_p) 17223737Shx147065 { 17233737Shx147065 uint16_t stat; 17243737Shx147065 17253737Shx147065 ASSERT(!(len & 1)); 17263737Shx147065 17273737Shx147065 /* 17283737Shx147065 * 1. select Buffer Access Path (channel) 1 for PIO 17293737Shx147065 */ 17303737Shx147065 if (stat = pcwl_set_ch(pcwl_p, type, 0, 1)) 17313737Shx147065 return (stat); 17323737Shx147065 17333737Shx147065 /* 17343737Shx147065 * 2. write length 17353737Shx147065 */ 17363737Shx147065 len >>= 1; /* convert bytes to 16-bit words */ 17373737Shx147065 stat = len + 1; /* 1 extra word */ 17383737Shx147065 PCWL_WRITE(pcwl_p, WL_DATA1, stat); 17393737Shx147065 17403737Shx147065 /* 17413737Shx147065 * 3. write type 17423737Shx147065 */ 17433737Shx147065 PCWL_WRITE(pcwl_p, WL_DATA1, type); 17443737Shx147065 17453737Shx147065 /* 17463737Shx147065 * 4. write value 17473737Shx147065 */ 17483737Shx147065 for (stat = 0; stat < len; stat++, val_p++) { 17493737Shx147065 PCWL_WRITE_P(pcwl_p, WL_DATA1, val_p, 1); 17503737Shx147065 } 17513737Shx147065 17523737Shx147065 /* 17533737Shx147065 * 5. select write mode 17543737Shx147065 */ 17553737Shx147065 return (pcwl_set_cmd(pcwl_p, WL_CMD_ACCESS|WL_ACCESS_WRITE, type)); 17563737Shx147065 } 17573737Shx147065 17583737Shx147065 #define PCWL_COMPSTR_LEN 34 17593737Shx147065 static uint16_t 17603737Shx147065 pcwl_put_str(pcwl_maci_t *pcwl_p, uint16_t type, char *str_p) 17613737Shx147065 { 17623737Shx147065 uint16_t buf[PCWL_COMPSTR_LEN / 2]; 17633737Shx147065 uint8_t str_len = strlen(str_p); 17643737Shx147065 17653737Shx147065 bzero(buf, PCWL_COMPSTR_LEN); 17663737Shx147065 buf[0] = str_len; 17673737Shx147065 bcopy(str_p, (caddr_t)(buf + 1), str_len); 17683737Shx147065 PCWLDBG((CE_NOTE, "put_str: buf[0]=%x buf=%s\n", 17693737Shx147065 buf[0], (caddr_t)(buf + 1))); 17703737Shx147065 PCWL_SWAP16(buf + 1, PCWL_COMPSTR_LEN - 2); 17713737Shx147065 return (pcwl_put_ltv(pcwl_p, PCWL_COMPSTR_LEN, type, buf)); 17723737Shx147065 } 17733737Shx147065 17743737Shx147065 /*ARGSUSED*/ 17753737Shx147065 static uint16_t 17763737Shx147065 pcwl_rdch0(pcwl_maci_t *pcwl_p, uint16_t type, uint16_t off, uint16_t *buf_p, 17773737Shx147065 int len, int order) 17783737Shx147065 { 17793737Shx147065 uint16_t o; 17803737Shx147065 ASSERT(!(len & 1)); 17813737Shx147065 /* 17823737Shx147065 * It seems that for PrismII chip, frequently overlap use of path0 17833737Shx147065 * and path1 may hang the hardware. So for PrismII chip, just use 17843737Shx147065 * path1. Test proves this workaround is OK. 17853737Shx147065 */ 17863737Shx147065 if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) { 17873737Shx147065 if (type = pcwl_set_ch(pcwl_p, type, off, 1)) 17883737Shx147065 return (type); 17893737Shx147065 o = WL_DATA1; 17903737Shx147065 } else { 17913737Shx147065 if (type = pcwl_set_ch(pcwl_p, type, off, 0)) 17923737Shx147065 return (type); 17933737Shx147065 o = WL_DATA0; 17943737Shx147065 } 17953737Shx147065 len >>= 1; 17963737Shx147065 for (off = 0; off < len; off++, buf_p++) { 17973737Shx147065 PCWL_READ_P(pcwl_p, o, buf_p, order); 17983737Shx147065 } 17993737Shx147065 return (PCWL_SUCCESS); 18003737Shx147065 } 18013737Shx147065 18023737Shx147065 /*ARGSUSED*/ 18033737Shx147065 static uint16_t 18043737Shx147065 pcwl_wrch1(pcwl_maci_t *pcwl_p, uint16_t type, uint16_t off, uint16_t *buf_p, 18053737Shx147065 int len, int order) 18063737Shx147065 { 18073737Shx147065 ASSERT(!(len & 1)); 18083737Shx147065 if (type = pcwl_set_ch(pcwl_p, type, off, 1)) 18093737Shx147065 return (type); 18103737Shx147065 len >>= 1; 18113737Shx147065 for (off = 0; off < len; off++, buf_p++) { 18123737Shx147065 PCWL_WRITE_P(pcwl_p, WL_DATA1, buf_p, order); 18133737Shx147065 } 18143737Shx147065 return (PCWL_SUCCESS); 18153737Shx147065 } 18163737Shx147065 18173737Shx147065 static uint16_t 18183737Shx147065 pcwl_alloc_nicmem(pcwl_maci_t *pcwl_p, uint16_t len, uint16_t *id_p) 18193737Shx147065 { 18203737Shx147065 int i; 18213737Shx147065 uint16_t stat; 18223737Shx147065 18233737Shx147065 len = ((len + 1) >> 1) << 1; /* round up to 16-bit boundary */ 18243737Shx147065 18253737Shx147065 if (stat = pcwl_set_cmd(pcwl_p, WL_CMD_ALLOC_MEM, len)) 18263737Shx147065 return (stat); 18273737Shx147065 for (stat = 0, i = 0; i < WL_TIMEOUT; i++) { 18283737Shx147065 PCWL_READ(pcwl_p, WL_EVENT_STAT, stat); 18293737Shx147065 if (stat & WL_EV_ALLOC) 18303737Shx147065 break; 18313737Shx147065 else 18323737Shx147065 drv_usecwait(1); 18333737Shx147065 } 18343737Shx147065 if (i == WL_TIMEOUT) 18353737Shx147065 return (PCWL_TIMEDOUT_ALLOC); 18363737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_ALLOC); 18373737Shx147065 PCWL_READ(pcwl_p, WL_ALLOC_FID, stat); 18383737Shx147065 *id_p = stat; 18393737Shx147065 18403737Shx147065 /* 18413737Shx147065 * zero fill the allocated NIC mem - sort of pcwl_fill_ch 18423737Shx147065 */ 18433737Shx147065 (void) pcwl_set_ch(pcwl_p, stat, 0, 1); 18443737Shx147065 18453737Shx147065 for (len >>= 1, stat = 0; stat < len; stat++) { 18463737Shx147065 PCWL_WRITE(pcwl_p, WL_DATA1, 0); 18473737Shx147065 } 18483737Shx147065 return (PCWL_SUCCESS); 18493737Shx147065 } 18503737Shx147065 18513737Shx147065 static int 18523737Shx147065 pcwl_add_scan_item(pcwl_maci_t *pcwl_p, wl_scan_result_t s) 18533737Shx147065 { 18543737Shx147065 wl_scan_list_t *scan_item; 18553737Shx147065 18563737Shx147065 scan_item = kmem_zalloc(sizeof (wl_scan_list_t), KM_SLEEP); 18573737Shx147065 if (scan_item == NULL) { 18583737Shx147065 cmn_err(CE_WARN, "pcwl add_scan_item: zalloc failed\n"); 18593737Shx147065 return (PCWL_FAIL); 18603737Shx147065 } 18613737Shx147065 scan_item->wl_val = s; 18623737Shx147065 scan_item->wl_timeout = WL_SCAN_TIMEOUT_MAX; 18633737Shx147065 list_insert_tail(&pcwl_p->pcwl_scan_list, scan_item); 18643737Shx147065 pcwl_p->pcwl_scan_num++; 18653737Shx147065 return (PCWL_SUCCESS); 18663737Shx147065 } 18673737Shx147065 18683737Shx147065 static void 18693737Shx147065 pcwl_delete_scan_item(pcwl_maci_t *pcwl_p, wl_scan_list_t *s) 18703737Shx147065 { 18713737Shx147065 list_remove(&pcwl_p->pcwl_scan_list, s); 18723737Shx147065 kmem_free(s, sizeof (*s)); 18733737Shx147065 pcwl_p->pcwl_scan_num--; 18743737Shx147065 } 18753737Shx147065 18763737Shx147065 static void 18773737Shx147065 pcwl_scanlist_timeout(void *arg) 18783737Shx147065 { 18793737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg; 18803737Shx147065 wl_scan_list_t *scan_item0, *scan_item1; 18813737Shx147065 18823737Shx147065 mutex_enter(&pcwl_p->pcwl_scanlist_lock); 18833737Shx147065 scan_item0 = list_head(&pcwl_p->pcwl_scan_list); 18843737Shx147065 for (; scan_item0; ) { 18853737Shx147065 PCWLDBG((CE_NOTE, "ssid = %s\n", 18863737Shx147065 scan_item0->wl_val.wl_srt_ssid)); 18873737Shx147065 PCWLDBG((CE_NOTE, "timeout left: %ds", 18883737Shx147065 scan_item0->wl_timeout)); 18893737Shx147065 scan_item1 = list_next(&pcwl_p->pcwl_scan_list, scan_item0); 18903737Shx147065 if (scan_item0->wl_timeout == 0) { 18913737Shx147065 pcwl_delete_scan_item(pcwl_p, scan_item0); 18923737Shx147065 } else { 18933737Shx147065 scan_item0->wl_timeout--; 18943737Shx147065 } 18953737Shx147065 scan_item0 = scan_item1; 18963737Shx147065 } 18973737Shx147065 mutex_exit(&pcwl_p->pcwl_scanlist_lock); 18983737Shx147065 pcwl_p->pcwl_scanlist_timeout_id = timeout(pcwl_scanlist_timeout, 18993737Shx147065 pcwl_p, drv_usectohz(1000000)); 19003737Shx147065 } 19013737Shx147065 19023737Shx147065 static void 19033737Shx147065 pcwl_get_rssi(pcwl_maci_t *pcwl_p) 19043737Shx147065 { 19053737Shx147065 wl_scan_list_t *scan_item0; 19063737Shx147065 uint16_t cq[3]; 19073737Shx147065 19083737Shx147065 bzero(cq, sizeof (cq)); 19093737Shx147065 mutex_enter(&pcwl_p->pcwl_scanlist_lock); 19103737Shx147065 scan_item0 = list_head(&pcwl_p->pcwl_scan_list); 19113737Shx147065 for (; scan_item0; ) { 19123737Shx147065 if (bcmp(scan_item0->wl_val.wl_srt_bssid, 19133737Shx147065 pcwl_p->pcwl_bssid, 6) == 0) { 19143737Shx147065 pcwl_p->pcwl_rssi = scan_item0->wl_val.wl_srt_sl; 19153737Shx147065 } 19163737Shx147065 scan_item0 = list_next(&pcwl_p->pcwl_scan_list, scan_item0); 19173737Shx147065 } 19183737Shx147065 mutex_exit(&pcwl_p->pcwl_scanlist_lock); 19193737Shx147065 if (!pcwl_p->pcwl_rssi) { 19203737Shx147065 (void) pcwl_get_ltv(pcwl_p, 6, WL_RID_COMMQUAL, cq); 19213737Shx147065 pcwl_p->pcwl_rssi = cq[1]; 19223737Shx147065 } 19233737Shx147065 } 19243737Shx147065 19253737Shx147065 /* 19263737Shx147065 * Note: 19273737Shx147065 * PrismII chipset has 2 extra space for the reason why scan is initiated 19283737Shx147065 */ 19293737Shx147065 static void 19303737Shx147065 pcwl_ssid_scan(pcwl_maci_t *pcwl_p, uint16_t fid, uint16_t flen, uint16_t stype) 19313737Shx147065 { 19323737Shx147065 uint16_t stat; 19333737Shx147065 uint16_t ssidNum, i; 19343737Shx147065 uint16_t off, szbuf; 19353737Shx147065 uint16_t tmp[2]; 19363737Shx147065 wl_scan_list_t *scan_item0; 19373737Shx147065 uint32_t check_num; 19383737Shx147065 uint8_t bssid_t[6]; 19393737Shx147065 19403737Shx147065 wl_scan_result_t sctbl; 19413737Shx147065 19423737Shx147065 off = sizeof (uint16_t) * 2; 19433737Shx147065 switch (pcwl_p->pcwl_chip_type) { 19443737Shx147065 case PCWL_CHIP_PRISMII: 19453737Shx147065 (void) RDCH0(pcwl_p, fid, off, tmp, 4); 19463737Shx147065 off += 4; 19473737Shx147065 szbuf = (stype == WL_INFO_SCAN_RESULTS ? 31 : 32); 19483737Shx147065 PCWLDBG((CE_NOTE, "pcwl ssid_scan: PRISM chip\n")); 19493737Shx147065 break; 19503737Shx147065 case PCWL_CHIP_LUCENT: 19513737Shx147065 PCWLDBG((CE_NOTE, "pcwl ssid_scan LUCENT chip\n")); 19523737Shx147065 default: 19533737Shx147065 szbuf = 25; 19543737Shx147065 } 19553737Shx147065 19563737Shx147065 flen = flen + 1 - (off >> 1); 19573737Shx147065 ssidNum = flen/szbuf; 19583737Shx147065 ssidNum = min(WL_SRT_MAX_NUM, ssidNum); 19593737Shx147065 19603737Shx147065 PCWLDBG((CE_NOTE, "pcwl: ssid_scan frame length = %d\n", flen)); 19613737Shx147065 19623737Shx147065 PCWLDBG((CE_NOTE, "pcwl ssid_scan: %d ssid(s) available", ssidNum)); 19633737Shx147065 19643737Shx147065 bzero(bssid_t, sizeof (bssid_t)); 19653737Shx147065 for (i = 0; i < ssidNum; i++) { 19663737Shx147065 (void) RDCH0(pcwl_p, fid, off, (uint16_t *)&sctbl, 2*szbuf); 19673737Shx147065 19683737Shx147065 #ifdef DEBUG 19693737Shx147065 if (pcwl_debug & PCWL_DBG_INFO) { 19703737Shx147065 int j; 19713737Shx147065 for (j = 0; j < sizeof (sctbl); j++) 19723737Shx147065 cmn_err(CE_NOTE, "%d: %x\n", j, 19733737Shx147065 *((uint8_t *)&sctbl + j)); 19743737Shx147065 } 19753737Shx147065 #endif 19763737Shx147065 19773737Shx147065 off += (szbuf << 1); 19783737Shx147065 stat = min(sctbl.wl_srt_ssidlen, 31); 19793737Shx147065 PCWL_SWAP16((uint16_t *)(sctbl.wl_srt_bssid), 6); 19803737Shx147065 PCWL_SWAP16((uint16_t *)(sctbl.wl_srt_ssid), stat); 19813737Shx147065 sctbl.wl_srt_ssid[stat] = '\0'; 19823737Shx147065 sctbl.wl_srt_sl &= 0x7f; 19833737Shx147065 19843737Shx147065 /* 19853737Shx147065 * sometimes, those empty items are recorded by hardware, 19863737Shx147065 * this is wrong, just ignore those items here. 19873737Shx147065 */ 19883737Shx147065 if (bcmp(sctbl.wl_srt_bssid, 19893737Shx147065 bssid_t, 6) == 0) { 19903737Shx147065 continue; 19913737Shx147065 } 19923737Shx147065 if (bcmp(sctbl.wl_srt_bssid, 19933737Shx147065 pcwl_p->pcwl_bssid, 6) == 0) { 19943737Shx147065 pcwl_p->pcwl_rssi = sctbl.wl_srt_sl; 19953737Shx147065 } 19963737Shx147065 /* 19973737Shx147065 * save/update the scan item in scanlist 19983737Shx147065 */ 19993737Shx147065 mutex_enter(&pcwl_p->pcwl_scanlist_lock); 20003737Shx147065 check_num = 0; 20013737Shx147065 scan_item0 = list_head(&pcwl_p->pcwl_scan_list); 20023737Shx147065 if (scan_item0 == NULL) { 20033737Shx147065 if (pcwl_add_scan_item(pcwl_p, sctbl) 20043737Shx147065 != 0) { 20053737Shx147065 mutex_exit(&pcwl_p->pcwl_scanlist_lock); 20063737Shx147065 return; 20073737Shx147065 } 20083737Shx147065 } 20093737Shx147065 for (; scan_item0; ) { 20103737Shx147065 if (bcmp(sctbl.wl_srt_bssid, 20113737Shx147065 scan_item0->wl_val.wl_srt_bssid, 6) == 0) { 20123737Shx147065 scan_item0->wl_val = sctbl; 20133737Shx147065 scan_item0->wl_timeout = WL_SCAN_TIMEOUT_MAX; 20143737Shx147065 break; 20153737Shx147065 } else { 20163737Shx147065 check_num++; 20173737Shx147065 } 20183737Shx147065 scan_item0 = list_next(&pcwl_p->pcwl_scan_list, 20193737Shx147065 scan_item0); 20203737Shx147065 } 20213737Shx147065 if (check_num == pcwl_p->pcwl_scan_num) { 20223737Shx147065 if (pcwl_add_scan_item(pcwl_p, sctbl) 20233737Shx147065 != 0) { 20243737Shx147065 mutex_exit(&pcwl_p->pcwl_scanlist_lock); 20253737Shx147065 return; 20263737Shx147065 } 20273737Shx147065 } 20283737Shx147065 mutex_exit(&pcwl_p->pcwl_scanlist_lock); 20293737Shx147065 PCWLDBG((CE_NOTE, "pcwl ssid_scan: ssid%d = %s\n", i+1, 20303737Shx147065 sctbl.wl_srt_ssid)); 20313737Shx147065 PCWLDBG((CE_NOTE, "pcwl ssid_scan: channel = %d\n", 20323737Shx147065 sctbl.wl_srt_chid)); 20333737Shx147065 PCWLDBG((CE_NOTE, "pcwl ssid_scan: signal level= %d\n", 20343737Shx147065 sctbl.wl_srt_sl)); 20353737Shx147065 PCWLDBG((CE_NOTE, "pcwl ssid_scan: noise level = %d\n", 20363737Shx147065 sctbl.wl_srt_anl)); 20373737Shx147065 PCWLDBG((CE_NOTE, "pcwl ssid_scan: bssid%d =" 20383737Shx147065 " %x %x %x %x %x %x\n\n", i+1, 20393737Shx147065 sctbl.wl_srt_bssid[0], 20403737Shx147065 sctbl.wl_srt_bssid[1], 20413737Shx147065 sctbl.wl_srt_bssid[2], 20423737Shx147065 sctbl.wl_srt_bssid[3], 20433737Shx147065 sctbl.wl_srt_bssid[4], 20443737Shx147065 sctbl.wl_srt_bssid[5])); 20453737Shx147065 } 20463737Shx147065 20473737Shx147065 } 20483737Shx147065 20493737Shx147065 /* 20503737Shx147065 * delay in which the mutex is not hold. 20513737Shx147065 * assuming the mutex has already been hold. 20523737Shx147065 */ 20533737Shx147065 static void 20543737Shx147065 pcwl_delay(pcwl_maci_t *pcwl_p, clock_t microsecs) 20553737Shx147065 { 20563737Shx147065 ASSERT(mutex_owned(&pcwl_p->pcwl_glock)); 20573737Shx147065 20583737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 20593737Shx147065 delay(drv_usectohz(microsecs)); 20603737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 20613737Shx147065 } 20623737Shx147065 20633737Shx147065 static int 20643737Shx147065 pcwl_reset_backend(pcwl_maci_t *pcwl_p) 20653737Shx147065 { 20663737Shx147065 uint16_t ret = 0; 20673737Shx147065 20683737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_INI, 0)) { 20693737Shx147065 return ((int)ret); 20703737Shx147065 } 20713737Shx147065 20723737Shx147065 pcwl_delay(pcwl_p, 100000); /* wait .1 sec */ 20733737Shx147065 20743737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_INI, 0)) { 20753737Shx147065 return ((int)ret); 20763737Shx147065 } 20773737Shx147065 pcwl_delay(pcwl_p, 100000); /* wait .1 sec */ 20783737Shx147065 20793737Shx147065 PCWL_DISABLE_INTR(pcwl_p); 20803737Shx147065 return (PCWL_SUCCESS); 20813737Shx147065 } 20823737Shx147065 20833737Shx147065 20843737Shx147065 /* 20853737Shx147065 * get card capability (WEP, default channel), setup broadcast, mac addresses 20863737Shx147065 */ 20873737Shx147065 static int 20883737Shx147065 pcwl_get_cap(pcwl_maci_t *pcwl_p) 20893737Shx147065 { 20903737Shx147065 uint16_t stat, ch_no; 20913737Shx147065 uint16_t buf[ETHERADDRL >> 1]; 20923737Shx147065 20933737Shx147065 bzero(buf, ETHERADDRL); 20943737Shx147065 if (stat = pcwl_get_ltv(pcwl_p, 2, WL_RID_OWN_CHNL, &ch_no)) { 20953737Shx147065 cmn_err(CE_CONT, "pcwl get_cap: get def channel failed" 20963737Shx147065 " %x\n", stat); 20973737Shx147065 return ((int)stat); 20983737Shx147065 } 20993737Shx147065 if (stat = pcwl_get_ltv(pcwl_p, 2, WL_RID_WEP_AVAIL, 21003737Shx147065 &pcwl_p->pcwl_has_wep)) { 21013737Shx147065 cmn_err(CE_CONT, "pcwl get_cap: get WEP capability failed" 21023737Shx147065 " %x\n", stat); 21033737Shx147065 return ((int)stat); 21043737Shx147065 } 21053737Shx147065 if (stat = pcwl_get_ltv(pcwl_p, ETHERADDRL, WL_RID_MAC_NODE, buf)) { 21063737Shx147065 cmn_err(CE_CONT, "pcwl get_cap: get macaddr failed" 21073737Shx147065 " %x\n", stat); 21083737Shx147065 return ((int)stat); 21093737Shx147065 } 21103737Shx147065 21113737Shx147065 /* 21123737Shx147065 * don't assume m_xxx members are 16-bit aligned 21133737Shx147065 */ 21143737Shx147065 PCWL_SWAP16(buf, ETHERADDRL); 21153737Shx147065 ether_copy(buf, pcwl_p->pcwl_mac_addr); 21163737Shx147065 return (PCWL_SUCCESS); 21173737Shx147065 } 21183737Shx147065 21193737Shx147065 static int 21203737Shx147065 pcwl_init_nicmem(pcwl_maci_t *pcwl_p) 21213737Shx147065 { 21223737Shx147065 uint16_t ret, i; 21233737Shx147065 uint16_t rc; 21243737Shx147065 21253737Shx147065 for (i = 0; i < WL_XMT_BUF_NUM; i++) { 21263737Shx147065 ret = pcwl_alloc_nicmem(pcwl_p, PCWL_NICMEM_SZ, &rc); 21273737Shx147065 if (ret) { 21283737Shx147065 cmn_err(CE_WARN, 21293737Shx147065 "pcwl: alloc NIC Tx buf failed %x\n", ret); 21303737Shx147065 return (PCWL_FAIL); 21313737Shx147065 } 21323737Shx147065 pcwl_p->pcwl_txring.wl_tx_fids[i] = rc; 21333737Shx147065 pcwl_p->pcwl_txring.wl_tx_ring[i] = 0; 21343737Shx147065 PCWLDBG((CE_NOTE, "pcwl: alloc_nicmem_id[%d]=%x\n", i, rc)); 21353737Shx147065 } 21363737Shx147065 pcwl_p->pcwl_txring.wl_tx_prod = pcwl_p->pcwl_txring.wl_tx_cons = 0; 21373737Shx147065 21383737Shx147065 ret = pcwl_alloc_nicmem(pcwl_p, PCWL_NICMEM_SZ, &pcwl_p->pcwl_mgmt_id); 21393737Shx147065 if (ret) { 21403737Shx147065 cmn_err(CE_WARN, "pcwl: alloc NIC Mgmt buf failed %x\n", ret); 21413737Shx147065 return (PCWL_FAIL); 21423737Shx147065 } 21433737Shx147065 PCWLDBG((CE_NOTE, "pcwl: alloc_nicmem mgmt_id=%x\n", 21443737Shx147065 pcwl_p->pcwl_mgmt_id)); 21453737Shx147065 return (PCWL_SUCCESS); 21463737Shx147065 } 21473737Shx147065 21483737Shx147065 static int 21493737Shx147065 pcwl_loaddef_rf(pcwl_maci_t *pcwl_p) 21503737Shx147065 { 21513737Shx147065 pcwl_p->pcwl_rf.rf_max_datalen = WL_DEFAULT_DATALEN; 21523737Shx147065 pcwl_p->pcwl_rf.rf_create_ibss = WL_DEFAULT_CREATE_IBSS; 21533737Shx147065 pcwl_p->pcwl_rf.rf_porttype = WL_BSS_BSS; 21543737Shx147065 pcwl_p->pcwl_rf.rf_rts_thresh = WL_DEFAULT_RTS_THRESH; 21553737Shx147065 pcwl_p->pcwl_rf.rf_tx_rate = WL_TX_RATE_FIX_11M(pcwl_p); 21563737Shx147065 pcwl_p->pcwl_rf.rf_pm_enabled = WL_DEFAULT_PM_ENABLED; 21573737Shx147065 pcwl_p->pcwl_rf.rf_own_chnl = WL_DEFAULT_CHAN; 21583737Shx147065 (void) strcpy(pcwl_p->pcwl_rf.rf_own_ssid, ""); 21593737Shx147065 (void) strcpy(pcwl_p->pcwl_rf.rf_desired_ssid, ""); 21603737Shx147065 (void) strcpy(pcwl_p->pcwl_rf.rf_nodename, ""); 21613737Shx147065 pcwl_p->pcwl_rf.rf_encryption = WL_NOENCRYPTION; 21623737Shx147065 pcwl_p->pcwl_rf.rf_authtype = WL_OPENSYSTEM; 21633737Shx147065 pcwl_p->pcwl_rf.rf_tx_crypt_key = WL_DEFAULT_TX_CRYPT_KEY; 21643737Shx147065 bzero((pcwl_p->pcwl_rf.rf_ckeys), sizeof (rf_ckey_t) * 4); 21653737Shx147065 21663737Shx147065 pcwl_p->pcwl_rf.rf_promiscuous = 0; 21673737Shx147065 21683737Shx147065 return (pcwl_config_rf(pcwl_p)); 21693737Shx147065 } 21703737Shx147065 21713737Shx147065 static int 21723737Shx147065 pcwl_config_rf(pcwl_maci_t *pcwl_p) 21733737Shx147065 { 21743737Shx147065 pcwl_rf_t *rf_p = &pcwl_p->pcwl_rf; 21753737Shx147065 uint16_t create_ibss, porttype; 21763737Shx147065 21773737Shx147065 /* 21783737Shx147065 * Lucent card: 21793737Shx147065 * 0 Join ESS or IBSS; 1 Join ESS or join/create IBSS 21803737Shx147065 * PrismII card: 21813737Shx147065 * 3 Join ESS or IBSS(do not create IBSS); 21823737Shx147065 * 1 Join ESS or join/create IBSS 21833737Shx147065 */ 21843737Shx147065 create_ibss = rf_p->rf_create_ibss; 21853737Shx147065 if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) { 21863737Shx147065 if (rf_p->rf_create_ibss == 0) 21873737Shx147065 create_ibss = 3; 21883737Shx147065 } 21893737Shx147065 /* 21903737Shx147065 * Lucent card: 21913737Shx147065 * 1 BSS; 3 pseudo IBSS(only for test,not the 802.11 IBSS) 21923737Shx147065 * so porttype register should always be set to 1 21933737Shx147065 * PrismII card: 21943737Shx147065 * 0 IBSS; 1 BSS; 2 WDS; 3 pseudo IBSS; 6 hostAP 21953737Shx147065 */ 21963737Shx147065 switch (pcwl_p->pcwl_chip_type) { 21973737Shx147065 case PCWL_CHIP_PRISMII: 21983737Shx147065 if (rf_p->rf_porttype == WL_BSS_BSS) 21993737Shx147065 porttype = 1; 22003737Shx147065 else if (rf_p->rf_porttype == WL_BSS_IBSS) 22013737Shx147065 porttype = 0; 22023737Shx147065 else 22033737Shx147065 porttype = 0; 22043737Shx147065 break; 22053737Shx147065 case PCWL_CHIP_LUCENT: 22063737Shx147065 default: 22073737Shx147065 porttype = 1; 22083737Shx147065 } 22093737Shx147065 22103737Shx147065 22113737Shx147065 FIL_LTV(pcwl_p, PCWL_MCBUF_LEN, WL_RID_MCAST, 0); 22123737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_PROMISC, 0); 22133737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_TICK_TIME, 0); 22143737Shx147065 22153737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_MAX_DATALEN, rf_p->rf_max_datalen); 22163737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_CREATE_IBSS, create_ibss); 22173737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_PORTTYPE, porttype); 22183737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_RTS_THRESH, rf_p->rf_rts_thresh); 22193737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_TX_RATE, rf_p->rf_tx_rate); 22203737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_SYSTEM_SCALE, rf_p->rf_system_scale); 22213737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_PM_ENABLED, rf_p->rf_pm_enabled); 22223737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_MAX_SLEEP, rf_p->rf_max_sleep); 22233737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_OWN_CHNL, rf_p->rf_own_chnl); 22243737Shx147065 22253737Shx147065 PUT_STR(pcwl_p, WL_RID_OWN_SSID, rf_p->rf_own_ssid); 22263737Shx147065 PUT_STR(pcwl_p, WL_RID_DESIRED_SSID, rf_p->rf_desired_ssid); 22273737Shx147065 PUT_STR(pcwl_p, WL_RID_NODENAME, rf_p->rf_nodename); 22283737Shx147065 22293737Shx147065 if (!pcwl_p->pcwl_has_wep) 22303737Shx147065 goto done; 22313737Shx147065 22323737Shx147065 switch (pcwl_p->pcwl_chip_type) { 22333737Shx147065 case PCWL_CHIP_PRISMII: { 22343737Shx147065 int i; 22353737Shx147065 22363737Shx147065 for (i = 0; i < 4; i++) { 22373737Shx147065 int k_len = strlen((char *)rf_p->rf_ckeys[i].ckey_dat); 22383737Shx147065 if (k_len == 0) 22393737Shx147065 continue; 22403737Shx147065 k_len = k_len > 5 ? 14 : 6; 22413737Shx147065 PUT_LTV(pcwl_p, k_len, WL_RID_CRYPT_KEY0_P2 + i, 22423737Shx147065 (uint16_t *)&rf_p->rf_ckeys[i].ckey_dat); 22433737Shx147065 } 22443737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_TX_CRYPT_KEY_P2, 22453737Shx147065 rf_p->rf_tx_crypt_key); 22463737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_AUTHTYPE_P2, 22473737Shx147065 rf_p->rf_authtype); 22483737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_ENCRYPTION_P2, 22493737Shx147065 rf_p->rf_encryption); 22503737Shx147065 if (pcwl_p->pcwl_rf.rf_promiscuous) 22513737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_PROMISC, 1); 22523737Shx147065 } 22533737Shx147065 break; 22543737Shx147065 case PCWL_CHIP_LUCENT: 22553737Shx147065 default: 22563737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_ENCRYPTION, 22573737Shx147065 rf_p->rf_encryption); 22583737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_AUTHTYPE_L, 22593737Shx147065 rf_p->rf_authtype); 22603737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_TX_CRYPT_KEY, 22613737Shx147065 rf_p->rf_tx_crypt_key); 22623737Shx147065 PUT_LTV(pcwl_p, sizeof (rf_p->rf_ckeys), 22633737Shx147065 WL_RID_DEFLT_CRYPT_KEYS, 22643737Shx147065 (uint16_t *)rf_p->rf_ckeys); 22653737Shx147065 break; 22663737Shx147065 } 22673737Shx147065 done: 22683737Shx147065 return (PCWL_SUCCESS); 22693737Shx147065 } 22703737Shx147065 22713737Shx147065 static void 22723737Shx147065 pcwl_start_locked(pcwl_maci_t *pcwl_p) 22733737Shx147065 { 22743737Shx147065 pcwl_p->pcwl_flag |= PCWL_CARD_INTREN; 22753737Shx147065 PCWL_ENABLE_INTR(pcwl_p); 22763737Shx147065 } 22773737Shx147065 22783737Shx147065 static void 22793737Shx147065 pcwl_stop_locked(pcwl_maci_t *pcwl_p) 22803737Shx147065 { 22813737Shx147065 PCWL_DISABLE_INTR(pcwl_p); 22823737Shx147065 pcwl_p->pcwl_flag &= (~PCWL_CARD_INTREN); 22833737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX|WL_EV_RX|WL_EV_TX_EXC| 22843737Shx147065 WL_EV_ALLOC|WL_EV_INFO|WL_EV_INFO_DROP); 22853737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX|WL_EV_RX|WL_EV_TX_EXC| 22863737Shx147065 WL_EV_ALLOC| WL_EV_INFO|WL_EV_INFO_DROP); 22873737Shx147065 } 22883737Shx147065 22893737Shx147065 /*ARGSUSED*/ 22903737Shx147065 static int 22913737Shx147065 pcwl_saddr_locked(pcwl_maci_t *pcwl_p) 22923737Shx147065 { 22933737Shx147065 int ret; 22943737Shx147065 uint16_t buf[ETHERADDRL >> 1]; 22953737Shx147065 22963737Shx147065 ether_copy(pcwl_p->pcwl_mac_addr, buf); 22973737Shx147065 PCWL_SWAP16(buf, ETHERADDRL); 22983737Shx147065 ret = pcwl_put_ltv(pcwl_p, ETHERADDRL, WL_RID_MAC_NODE, buf); 22993737Shx147065 if (ret) { 23003737Shx147065 cmn_err(CE_WARN, "pcwl set_mac_addr: failed %x\n", ret); 23013737Shx147065 return (PCWL_FAIL); 23023737Shx147065 } 23033737Shx147065 return (PCWL_SUCCESS); 23043737Shx147065 } 23053737Shx147065 23063737Shx147065 static void 23073737Shx147065 pcwl_chip_type(pcwl_maci_t *pcwl_p) 23083737Shx147065 { 23093737Shx147065 pcwl_ltv_ver_t ver; 23103737Shx147065 pcwl_ltv_fwver_t f; 23113737Shx147065 23123737Shx147065 bzero(&ver, sizeof (ver)); 23133737Shx147065 (void) pcwl_get_ltv(pcwl_p, sizeof (ver), 23143737Shx147065 WL_RID_CARD_ID, (uint16_t *)&ver); 23153737Shx147065 PCWLDBG((CE_NOTE, "card id:%04x-%04x-%04x-%04x\n", 23163737Shx147065 ver.wl_compid, ver.wl_variant, ver.wl_major, ver.wl_minor)); 23173737Shx147065 if ((ver.wl_compid & 0xf000) != 0x8000) 23183737Shx147065 return; /* lucent */ 23193737Shx147065 23203737Shx147065 pcwl_p->pcwl_chip_type = PCWL_CHIP_PRISMII; 23213737Shx147065 (void) pcwl_get_ltv(pcwl_p, sizeof (ver), WL_RID_COMP_IDENT, 23223737Shx147065 (uint16_t *)&ver); 23233737Shx147065 PCWLDBG((CE_NOTE, "PRISM-II ver:%04x-%04x-%04x-%04x\n", 23243737Shx147065 ver.wl_compid, ver.wl_variant, ver.wl_major, ver.wl_minor)); 23253737Shx147065 23263737Shx147065 bzero(&f, sizeof (f)); 23273737Shx147065 (void) pcwl_get_ltv(pcwl_p, sizeof (f), WL_RID_FWVER, (uint16_t *)&f); 23283737Shx147065 PCWL_SWAP16((uint16_t *)&f, sizeof (f)); 23293737Shx147065 PCWLDBG((CE_NOTE, "Firmware Pri:%s 2,3:%s\n", 23303737Shx147065 (char *)f.pri, (char *)f.st)); 23313737Shx147065 } 23323737Shx147065 23333737Shx147065 /* 23343737Shx147065 * for wificonfig and dladm ioctl 23353737Shx147065 */ 23363737Shx147065 23373737Shx147065 static int 23383737Shx147065 pcwl_cfg_essid(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd) 23393737Shx147065 { 23403737Shx147065 char ssid[36]; 23413737Shx147065 uint16_t ret, i; 23423737Shx147065 uint16_t val; 23433737Shx147065 pcwl_rf_t *rf_p; 23443737Shx147065 char *value; 23453737Shx147065 wldp_t *infp; 23463737Shx147065 wldp_t *outfp; 23473737Shx147065 char *buf; 23483737Shx147065 int iret; 23493737Shx147065 23503737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 23513737Shx147065 if (buf == NULL) { 23523737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n", 23533737Shx147065 MAX_BUF_LEN)); 23543737Shx147065 return (ENOMEM); 23553737Shx147065 } 23563737Shx147065 outfp = (wldp_t *)buf; 23573737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 23583737Shx147065 infp = (wldp_t *)mp->b_rptr; 23593737Shx147065 rf_p = &pcwl_p->pcwl_rf; 23603737Shx147065 23613737Shx147065 bzero(ssid, sizeof (ssid)); 23623737Shx147065 if (cmd == WLAN_GET_PARAM) { 23633737Shx147065 ret = pcwl_get_ltv(pcwl_p, 2, 23643737Shx147065 WL_RID_PORTSTATUS, &val); 23653737Shx147065 if (ret) { 23663737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 23673737Shx147065 outfp->wldp_result = WL_HW_ERROR; 23683737Shx147065 PCWLDBG((CE_WARN, "cfg_essid_get_error\n")); 23693737Shx147065 goto done; 23703737Shx147065 } 23713737Shx147065 PCWLDBG((CE_NOTE, "PortStatus = %d\n", val)); 23723737Shx147065 23733737Shx147065 if (val == WL_PORT_DISABLED || val == WL_PORT_INITIAL) { 23743737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 23753737Shx147065 offsetof(wl_essid_t, wl_essid_essid) + 23763737Shx147065 mi_strlen(rf_p->rf_desired_ssid); 23773737Shx147065 ((wl_essid_t *)(outfp->wldp_buf))->wl_essid_length = 23783737Shx147065 mi_strlen(rf_p->rf_desired_ssid); 23793737Shx147065 bcopy(rf_p->rf_desired_ssid, buf + WIFI_BUF_OFFSET + 23803737Shx147065 offsetof(wl_essid_t, wl_essid_essid), 23813737Shx147065 mi_strlen(rf_p->rf_desired_ssid)); 23823737Shx147065 } else if (val == WL_PORT_TO_IBSS || 23833737Shx147065 val == WL_PORT_TO_BSS || 23843737Shx147065 val == WL_PORT_OOR) { 23853737Shx147065 (void) pcwl_get_ltv((pcwl_p), 34, 23863737Shx147065 WL_RID_SSID, (uint16_t *)ssid); 23873737Shx147065 PCWL_SWAP16((uint16_t *)(ssid+2), *(uint16_t *)ssid); 23883737Shx147065 ssid[*(uint16_t *)ssid + 2] = '\0'; 23893737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 23903737Shx147065 offsetof(wl_essid_t, wl_essid_essid) + 23913737Shx147065 mi_strlen(ssid+2); 23923737Shx147065 ((wl_essid_t *)(outfp->wldp_buf))->wl_essid_length = 23933737Shx147065 mi_strlen(ssid+2); 23943737Shx147065 bcopy(ssid + 2, buf + WIFI_BUF_OFFSET + 23953737Shx147065 offsetof(wl_essid_t, wl_essid_essid), 23963737Shx147065 mi_strlen(ssid+2)); 23973737Shx147065 } else { 23983737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 23993737Shx147065 } 24003737Shx147065 outfp->wldp_result = WL_SUCCESS; 24013737Shx147065 PCWLDBG((CE_CONT, "outfp->length=%d\n", outfp->wldp_length)); 24023737Shx147065 PCWLDBG((CE_CONT, "pcwl: get desired essid=%s\n", 24033737Shx147065 rf_p->rf_desired_ssid)); 24043737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 24053737Shx147065 value = ((wl_essid_t *)(infp->wldp_buf))->wl_essid_essid; 24063737Shx147065 (void) strncpy(rf_p->rf_desired_ssid, value, 24073737Shx147065 MIN(32, strlen(value))); 24083737Shx147065 rf_p->rf_desired_ssid[strlen(value)] = '\0'; 24093737Shx147065 (void) strncpy(rf_p->rf_own_ssid, value, 24103737Shx147065 MIN(32, strlen(value))); 24113737Shx147065 rf_p->rf_own_ssid[strlen(value)] = '\0'; 24123737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 24133737Shx147065 outfp->wldp_result = WL_SUCCESS; 24143737Shx147065 PCWLDBG((CE_CONT, "pcwl: set: desired essid=%s\n", 24153737Shx147065 rf_p->rf_desired_ssid)); 24163737Shx147065 } else { 24173737Shx147065 kmem_free(buf, MAX_BUF_LEN); 24183737Shx147065 return (EINVAL); 24193737Shx147065 } 24203737Shx147065 done: 24213737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 24223737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 24233737Shx147065 iret = (int)(outfp->wldp_result); 24243737Shx147065 kmem_free(buf, MAX_BUF_LEN); 24253737Shx147065 return (iret); 24263737Shx147065 } 24273737Shx147065 24283737Shx147065 static int 24293737Shx147065 pcwl_cfg_bssid(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd) 24303737Shx147065 { 24313737Shx147065 uint16_t ret, i; 24323737Shx147065 int iret; 24333737Shx147065 wldp_t *outfp; 24343737Shx147065 char *buf; 24353737Shx147065 uint8_t bssid[6]; 24363737Shx147065 24373737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 24383737Shx147065 if (buf == NULL) { 24393737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n", 24403737Shx147065 MAX_BUF_LEN)); 24413737Shx147065 return (ENOMEM); 24423737Shx147065 } 24433737Shx147065 outfp = (wldp_t *)buf; 24443737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 24453737Shx147065 24463737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_bssid_t); 24473737Shx147065 if (cmd == WLAN_GET_PARAM) { 24483737Shx147065 if (ret = pcwl_get_ltv(pcwl_p, 2, 24493737Shx147065 WL_RID_PORTSTATUS, &ret)) { 24503737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 24513737Shx147065 outfp->wldp_result = WL_HW_ERROR; 24523737Shx147065 goto done; 24533737Shx147065 } 24543737Shx147065 PCWLDBG((CE_NOTE, "PortStatus = %d\n", ret)); 24553737Shx147065 if (ret == WL_PORT_DISABLED || ret == WL_PORT_INITIAL) { 24563737Shx147065 bzero(buf + WIFI_BUF_OFFSET, 24573737Shx147065 sizeof (wl_bssid_t)); 24583737Shx147065 } else if (ret == WL_PORT_TO_IBSS || 2459*6062Shx147065 ret == WL_PORT_TO_BSS || ret == WL_PORT_OOR) { 24603737Shx147065 (void) pcwl_get_ltv(pcwl_p, 6, 24613737Shx147065 WL_RID_BSSID, (uint16_t *)bssid); 24623737Shx147065 PCWL_SWAP16((uint16_t *)bssid, 6); 24633737Shx147065 bcopy(bssid, buf + WIFI_BUF_OFFSET, 24643737Shx147065 sizeof (wl_bssid_t)); 24653737Shx147065 } 24663737Shx147065 outfp->wldp_result = WL_SUCCESS; 24673737Shx147065 24683737Shx147065 PCWLDBG((CE_CONT, "pcwl_getset: bssid=%x %x %x %x %x %x\n", 24693737Shx147065 bssid[0], bssid[1], bssid[2], 24703737Shx147065 bssid[3], bssid[4], bssid[5])); 24713737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 24723737Shx147065 outfp->wldp_result = WL_READONLY; 24733737Shx147065 } else { 24743737Shx147065 kmem_free(buf, MAX_BUF_LEN); 24753737Shx147065 return (EINVAL); 24763737Shx147065 } 24773737Shx147065 done: 24783737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 24793737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 24803737Shx147065 iret = (int)(outfp->wldp_result); 24813737Shx147065 kmem_free(buf, MAX_BUF_LEN); 24823737Shx147065 return (iret); 24833737Shx147065 } 24843737Shx147065 24853737Shx147065 /*ARGSUSED*/ 24863737Shx147065 static int 24873737Shx147065 pcwl_cmd_scan(pcwl_maci_t *pcwl_p) 24883737Shx147065 { 24893737Shx147065 uint16_t vall[18], ret = WL_SUCCESS; 24903737Shx147065 pcwl_rf_t *rf_p; 24913737Shx147065 uint32_t enable, i; 24923737Shx147065 size_t len; 24933737Shx147065 24943737Shx147065 rf_p = &pcwl_p->pcwl_rf; 24953737Shx147065 24963737Shx147065 /* 24973737Shx147065 * The logic of this funtion is really tricky. 24983737Shx147065 * Firstly, the chip can only scan in BSS mode, so necessary 24993737Shx147065 * backup and restore is required before and after the scan 25003737Shx147065 * command. 25013737Shx147065 * Secondly, for Lucent chip, Alrealy associated with an AP 25023737Shx147065 * can only scan the APes on the fixed channel, so we must 25033737Shx147065 * set the desired_ssid as "" before scan and restore after. 25043737Shx147065 * Thirdly, scan cmd is effective only when the card is enabled 25053737Shx147065 * and any 'set' operation(such as set bsstype, ssid)must disable 25063737Shx147065 * the card first and then enable the card after the 'set' 25073737Shx147065 */ 25083737Shx147065 enable = pcwl_p->pcwl_flag & PCWL_ENABLED; 25093737Shx147065 len = strlen(rf_p->rf_desired_ssid); 25103737Shx147065 25113737Shx147065 if (pcwl_p->pcwl_rf.rf_porttype != WL_BSS_BSS) { 25123737Shx147065 if ((enable) && 25133737Shx147065 (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0))) { 25143737Shx147065 ret = (int)WL_HW_ERROR; 25153737Shx147065 goto done; 25163737Shx147065 } 25173737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_PORTTYPE, WL_BSS_BSS); 25183737Shx147065 } 25193737Shx147065 25203737Shx147065 if ((pcwl_p->pcwl_chip_type == PCWL_CHIP_LUCENT) && (len != 0)) { 25213737Shx147065 if ((enable) && 25223737Shx147065 (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0))) { 25233737Shx147065 ret = (int)WL_HW_ERROR; 25243737Shx147065 goto done; 25253737Shx147065 } 25263737Shx147065 PUT_STR(pcwl_p, WL_RID_DESIRED_SSID, ""); 25273737Shx147065 } 25283737Shx147065 25293737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) { 25303737Shx147065 ret = (int)WL_HW_ERROR; 25313737Shx147065 goto done; 25323737Shx147065 } 25333737Shx147065 pcwl_delay(pcwl_p, 1000000); 25343737Shx147065 25353737Shx147065 switch (pcwl_p->pcwl_chip_type) { 25363737Shx147065 case PCWL_CHIP_PRISMII: 25373737Shx147065 bzero(vall, sizeof (vall)); 25383737Shx147065 vall[0] = 0x3fff; /* channel mask */ 25393737Shx147065 vall[1] = 0x1; /* tx rate */ 25403737Shx147065 for (i = 0; i < WL_MAX_SCAN_TIMES; i++) { 25413737Shx147065 PUT_LTV(pcwl_p, sizeof (vall), 25423737Shx147065 WL_RID_HSCAN_REQUEST, vall); 25433737Shx147065 pcwl_delay(pcwl_p, 1000000); 25443737Shx147065 if (pcwl_p->pcwl_scan_num >= WL_SCAN_AGAIN_THRESHOLD) 25453737Shx147065 break; 25463737Shx147065 } 25473737Shx147065 PCWLDBG((CE_NOTE, "PRISM chip\n")); 25483737Shx147065 break; 25493737Shx147065 25503737Shx147065 case PCWL_CHIP_LUCENT: 25513737Shx147065 PCWLDBG((CE_NOTE, "LUCENT chip\n")); 25523737Shx147065 default: 25533737Shx147065 for (i = 0; i < WL_MAX_SCAN_TIMES; i++) { 25543737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_INQUIRE, 25553737Shx147065 WL_INFO_SCAN_RESULTS)) { 25563737Shx147065 ret = (int)WL_HW_ERROR; 25573737Shx147065 goto done; 25583737Shx147065 } 25593737Shx147065 pcwl_delay(pcwl_p, 500000); 25603737Shx147065 if (pcwl_p->pcwl_scan_num >= WL_SCAN_AGAIN_THRESHOLD) 25613737Shx147065 break; 25623737Shx147065 } 25633737Shx147065 break; 25643737Shx147065 } 25653737Shx147065 if ((pcwl_p->pcwl_rf.rf_porttype != WL_BSS_BSS) || 25663737Shx147065 ((pcwl_p->pcwl_chip_type == PCWL_CHIP_LUCENT) && (len != 0))) { 25673737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) { 25683737Shx147065 ret = (int)WL_HW_ERROR; 25693737Shx147065 goto done; 25703737Shx147065 } 25713737Shx147065 if (ret = pcwl_config_rf(pcwl_p)) { 25723737Shx147065 ret = (int)WL_HW_ERROR; 25733737Shx147065 goto done; 25743737Shx147065 } 25753737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) { 25763737Shx147065 ret = (int)WL_HW_ERROR; 25773737Shx147065 goto done; 25783737Shx147065 } 25793737Shx147065 25803737Shx147065 pcwl_delay(pcwl_p, 1000000); 25813737Shx147065 } 25823737Shx147065 25833737Shx147065 if ((!enable) && (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0))) { 25843737Shx147065 ret = (int)WL_HW_ERROR; 25853737Shx147065 } 25863737Shx147065 done: 25873737Shx147065 if (ret) 25884196Syx209050 cmn_err(CE_WARN, "pcwl: scan failed due to hardware error"); 25893737Shx147065 return (ret); 25903737Shx147065 25913737Shx147065 } 25923737Shx147065 25933737Shx147065 /*ARGSUSED*/ 25943737Shx147065 static int 25953737Shx147065 pcwl_cfg_scan(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd) 25963737Shx147065 { 25973737Shx147065 wl_ess_conf_t *p_ess_conf; 25983737Shx147065 wldp_t *outfp; 25993737Shx147065 char *buf; 26003737Shx147065 uint16_t i; 26013737Shx147065 wl_scan_list_t *scan_item; 26023737Shx147065 26033737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 26043737Shx147065 if (buf == NULL) { 26053737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n", 26063737Shx147065 MAX_BUF_LEN)); 26073737Shx147065 return (ENOMEM); 26083737Shx147065 } 26093737Shx147065 outfp = (wldp_t *)buf; 26103737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 26113737Shx147065 26123737Shx147065 mutex_enter(&pcwl_p->pcwl_scanlist_lock); 26133737Shx147065 ((wl_ess_list_t *)(outfp->wldp_buf))->wl_ess_list_num = 26143737Shx147065 pcwl_p->pcwl_scan_num; 26153737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 26163737Shx147065 offsetof(wl_ess_list_t, wl_ess_list_ess) + 26173737Shx147065 pcwl_p->pcwl_scan_num * sizeof (wl_ess_conf_t); 26183737Shx147065 26193737Shx147065 scan_item = list_head(&pcwl_p->pcwl_scan_list); 26203737Shx147065 for (i = 0; i < pcwl_p->pcwl_scan_num; i++) { 26213737Shx147065 if (!scan_item) 26223737Shx147065 goto done; 26233737Shx147065 p_ess_conf = (wl_ess_conf_t *)(buf + WIFI_BUF_OFFSET + 26243737Shx147065 offsetof(wl_ess_list_t, wl_ess_list_ess) + 26253737Shx147065 i * sizeof (wl_ess_conf_t)); 26263737Shx147065 bcopy(scan_item->wl_val.wl_srt_ssid, 26273737Shx147065 p_ess_conf->wl_ess_conf_essid.wl_essid_essid, 26283737Shx147065 mi_strlen(scan_item->wl_val.wl_srt_ssid)); 26293737Shx147065 bcopy(scan_item->wl_val.wl_srt_bssid, 26303737Shx147065 p_ess_conf->wl_ess_conf_bssid, 6); 26313737Shx147065 (p_ess_conf->wl_phy_conf).wl_phy_dsss_conf.wl_dsss_subtype 26323737Shx147065 = WL_DSSS; 26333737Shx147065 p_ess_conf->wl_ess_conf_wepenabled = 26343737Shx147065 (scan_item->wl_val.wl_srt_cap & 0x10 ? 26353737Shx147065 WL_ENC_WEP : WL_NOENCRYPTION); 26363737Shx147065 p_ess_conf->wl_ess_conf_bsstype = 26373737Shx147065 (scan_item->wl_val.wl_srt_cap & 0x1 ? 26383737Shx147065 WL_BSS_BSS : WL_BSS_IBSS); 26393737Shx147065 p_ess_conf->wl_phy_conf.wl_phy_dsss_conf.wl_dsss_channel = 26403737Shx147065 scan_item->wl_val.wl_srt_chid; 26413737Shx147065 if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) { 26423737Shx147065 p_ess_conf->wl_ess_conf_sl = 26433737Shx147065 min(scan_item->wl_val.wl_srt_sl * 15 / 85 + 1, 26443737Shx147065 15); 26453737Shx147065 } else { 26463737Shx147065 if (scan_item->wl_val.wl_srt_sl <= 27) 26473737Shx147065 p_ess_conf->wl_ess_conf_sl = 1; 26483737Shx147065 else if (scan_item->wl_val.wl_srt_sl > 154) 26493737Shx147065 p_ess_conf->wl_ess_conf_sl = 15; 26503737Shx147065 else 26513737Shx147065 p_ess_conf->wl_ess_conf_sl = min(15, 26523737Shx147065 ((scan_item->wl_val.wl_srt_sl - 27) 26533737Shx147065 * 15 / 127)); 26543737Shx147065 } 26553737Shx147065 p_ess_conf->wl_supported_rates[0] = WL_RATE_1M; 26563737Shx147065 p_ess_conf->wl_supported_rates[1] = WL_RATE_2M; 26573737Shx147065 p_ess_conf->wl_supported_rates[2] = WL_RATE_5_5M; 26583737Shx147065 p_ess_conf->wl_supported_rates[3] = WL_RATE_11M; 26593737Shx147065 scan_item = list_next(&pcwl_p->pcwl_scan_list, scan_item); 26603737Shx147065 } 26613737Shx147065 done: 26623737Shx147065 mutex_exit(&pcwl_p->pcwl_scanlist_lock); 26633737Shx147065 outfp->wldp_result = WL_SUCCESS; 26643737Shx147065 26653737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 26663737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 26673737Shx147065 kmem_free(buf, MAX_BUF_LEN); 26683737Shx147065 return (WL_SUCCESS); 26693737Shx147065 } 26703737Shx147065 26713737Shx147065 /*ARGSUSED*/ 26723737Shx147065 static int 26733737Shx147065 pcwl_cfg_linkstatus(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd) 26743737Shx147065 { 26753737Shx147065 wldp_t *outfp; 26763737Shx147065 char *buf; 26773737Shx147065 uint16_t i, ret, val; 26783737Shx147065 int iret; 26793737Shx147065 26803737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 26813737Shx147065 if (buf == NULL) { 26823737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n", 26833737Shx147065 MAX_BUF_LEN)); 26843737Shx147065 return (ENOMEM); 26853737Shx147065 } 26863737Shx147065 outfp = (wldp_t *)buf; 26873737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 26883737Shx147065 26893737Shx147065 ret = pcwl_get_ltv(pcwl_p, 2, 26903737Shx147065 WL_RID_PORTSTATUS, &val); 26913737Shx147065 if (ret) { 26923737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 26933737Shx147065 outfp->wldp_result = WL_HW_ERROR; 26943737Shx147065 PCWLDBG((CE_WARN, "cfg_linkstatus_get_error\n")); 26953737Shx147065 goto done; 26963737Shx147065 } 26973737Shx147065 PCWLDBG((CE_NOTE, "PortStatus = %d\n", val)); 26983737Shx147065 if (val == WL_PORT_DISABLED || val == WL_PORT_INITIAL) { 26993737Shx147065 *(wl_linkstatus_t *)(outfp->wldp_buf) = WL_NOTCONNECTED; 27003737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 27013737Shx147065 sizeof (wl_linkstatus_t); 27023737Shx147065 } else if (val == WL_PORT_TO_IBSS || 27033737Shx147065 val == WL_PORT_TO_BSS || val == WL_PORT_OOR) { 27043737Shx147065 *(wl_linkstatus_t *)(outfp->wldp_buf) = WL_CONNECTED; 27053737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 27063737Shx147065 sizeof (wl_linkstatus_t); 27073737Shx147065 } else { 27083737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 27093737Shx147065 } 27103737Shx147065 outfp->wldp_result = WL_SUCCESS; 27113737Shx147065 done: 27123737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 27133737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 27143737Shx147065 iret = (int)(outfp->wldp_result); 27153737Shx147065 kmem_free(buf, MAX_BUF_LEN); 27163737Shx147065 return (iret); 27173737Shx147065 } 27183737Shx147065 27193737Shx147065 static int 27203737Shx147065 pcwl_cfg_bsstype(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd) 27213737Shx147065 { 27223737Shx147065 uint16_t ret, i; 27233737Shx147065 pcwl_rf_t *rf_p; 27243737Shx147065 wldp_t *infp; 27253737Shx147065 wldp_t *outfp; 27263737Shx147065 char *buf; 27273737Shx147065 int iret; 27283737Shx147065 27293737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 27303737Shx147065 if (buf == NULL) { 27313737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n", 27323737Shx147065 MAX_BUF_LEN)); 27333737Shx147065 return (ENOMEM); 27343737Shx147065 } 27353737Shx147065 outfp = (wldp_t *)buf; 27363737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 27373737Shx147065 infp = (wldp_t *)mp->b_rptr; 27383737Shx147065 rf_p = &pcwl_p->pcwl_rf; 27393737Shx147065 27403737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_bss_type_t); 27413737Shx147065 if (cmd == WLAN_GET_PARAM) { 27423737Shx147065 *(wl_bss_type_t *)(outfp->wldp_buf) = rf_p->rf_porttype; 27433737Shx147065 PCWLDBG((CE_CONT, "pcwl_getset: porttype=%d\n", 27443737Shx147065 rf_p->rf_porttype)); 27453737Shx147065 outfp->wldp_result = WL_SUCCESS; 27463737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 27473737Shx147065 ret = (uint16_t)(*(wl_bss_type_t *)(infp->wldp_buf)); 27483737Shx147065 if ((ret != WL_BSS_BSS) && 27493737Shx147065 (ret != WL_BSS_IBSS) && 27503737Shx147065 (ret != WL_BSS_ANY)) { 27513737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 27523737Shx147065 outfp->wldp_result = WL_NOTSUPPORTED; 27533737Shx147065 goto done; 27543737Shx147065 } 27553737Shx147065 rf_p->rf_porttype = ret; 27563737Shx147065 outfp->wldp_result = WL_SUCCESS; 27573737Shx147065 } else { 27583737Shx147065 kmem_free(buf, MAX_BUF_LEN); 27593737Shx147065 return (EINVAL); 27603737Shx147065 } 27613737Shx147065 done: 27623737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 27633737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 27643737Shx147065 iret = (int)(outfp->wldp_result); 27653737Shx147065 kmem_free(buf, MAX_BUF_LEN); 27663737Shx147065 return (iret); 27673737Shx147065 } 27683737Shx147065 27693737Shx147065 static int 27703737Shx147065 pcwl_cfg_phy(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd) 27713737Shx147065 { 2772*6062Shx147065 uint16_t ret, retval, i; 27733737Shx147065 pcwl_rf_t *rf_p; 27743737Shx147065 wldp_t *infp; 27753737Shx147065 wldp_t *outfp; 27763737Shx147065 char *buf; 27773737Shx147065 int iret; 27783737Shx147065 27793737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 27803737Shx147065 if (buf == NULL) { 27813737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n", 27823737Shx147065 MAX_BUF_LEN)); 27833737Shx147065 return (ENOMEM); 27843737Shx147065 } 27853737Shx147065 outfp = (wldp_t *)buf; 27863737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 27873737Shx147065 infp = (wldp_t *)mp->b_rptr; 27883737Shx147065 rf_p = &pcwl_p->pcwl_rf; 27893737Shx147065 27903737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_dsss_t); 27913737Shx147065 if (cmd == WLAN_GET_PARAM) { 27923737Shx147065 if (ret = pcwl_get_ltv(pcwl_p, 2, 2793*6062Shx147065 WL_RID_CURRENT_CHNL, &retval)) { 27943737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 27953737Shx147065 outfp->wldp_result = WL_HW_ERROR; 27963737Shx147065 goto done; 27973737Shx147065 } 2798*6062Shx147065 ((wl_dsss_t *)(outfp->wldp_buf))->wl_dsss_channel = retval; 2799*6062Shx147065 PCWLDBG((CE_CONT, "pcwl_getset: channel=%d\n", retval)); 28003737Shx147065 ((wl_dsss_t *)(outfp->wldp_buf))->wl_dsss_subtype = WL_DSSS; 28013737Shx147065 outfp->wldp_result = WL_SUCCESS; 28023737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 28033737Shx147065 ret = (uint16_t) 28043737Shx147065 (((wl_phy_conf_t *)(infp->wldp_buf)) 28053737Shx147065 ->wl_phy_dsss_conf.wl_dsss_channel); 28063737Shx147065 if (ret < 1 || ret > 14) { 28073737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 28083737Shx147065 outfp->wldp_result = WL_NOTSUPPORTED; 28093737Shx147065 goto done; 28103737Shx147065 } 28113737Shx147065 rf_p->rf_own_chnl = ret; 28123737Shx147065 PCWLDBG((CE_CONT, "pcwl: set channel=%d\n", rf_p->rf_own_chnl)); 28133737Shx147065 outfp->wldp_result = WL_SUCCESS; 28143737Shx147065 } else { 28153737Shx147065 kmem_free(buf, MAX_BUF_LEN); 28163737Shx147065 return (EINVAL); 28173737Shx147065 } 28183737Shx147065 done: 28193737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 28203737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 28213737Shx147065 iret = (int)(outfp->wldp_result); 28223737Shx147065 kmem_free(buf, MAX_BUF_LEN); 28233737Shx147065 return (iret); 28243737Shx147065 28253737Shx147065 } 28263737Shx147065 28273737Shx147065 static int 28283737Shx147065 pcwl_cfg_desiredrates(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd) 28293737Shx147065 { 28303737Shx147065 uint16_t rate; 28313737Shx147065 uint16_t i; 28323737Shx147065 pcwl_rf_t *rf_p; 28333737Shx147065 wldp_t *infp; 28343737Shx147065 wldp_t *outfp; 28353737Shx147065 char *buf; 28363737Shx147065 int iret; 28373737Shx147065 char rates[4]; 28383737Shx147065 char maxrate; 28393737Shx147065 28403737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 28413737Shx147065 if (buf == NULL) { 28423737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n", 28433737Shx147065 MAX_BUF_LEN)); 28443737Shx147065 return (ENOMEM); 28453737Shx147065 } 28463737Shx147065 outfp = (wldp_t *)buf; 28473737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 28483737Shx147065 infp = (wldp_t *)mp->b_rptr; 28493737Shx147065 rf_p = &pcwl_p->pcwl_rf; 28503737Shx147065 28513737Shx147065 if (cmd == WLAN_GET_PARAM) { 28523737Shx147065 if (i = pcwl_get_ltv(pcwl_p, 2, WL_RID_TX_RATE, &rate)) { 28533737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 28543737Shx147065 outfp->wldp_result = WL_HW_ERROR; 28553737Shx147065 goto done; 28563737Shx147065 } 28573737Shx147065 28583737Shx147065 if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) { 28593737Shx147065 ((wl_rates_t *)(outfp->wldp_buf))->wl_rates_num = 1; 28603737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 28613737Shx147065 offsetof(wl_rates_t, wl_rates_rates) + 28623737Shx147065 1 * sizeof (char); 28633737Shx147065 switch (rate) { 28643737Shx147065 case WL_SPEED_1Mbps_P2: 28653737Shx147065 (((wl_rates_t *)(outfp->wldp_buf))-> 28663737Shx147065 wl_rates_rates)[0] = WL_RATE_1M; 28673737Shx147065 break; 28683737Shx147065 case WL_SPEED_2Mbps_P2: 28693737Shx147065 (((wl_rates_t *)(outfp->wldp_buf))-> 28703737Shx147065 wl_rates_rates)[0] = WL_RATE_2M; 28713737Shx147065 break; 28723737Shx147065 case WL_SPEED_55Mbps_P2: 28733737Shx147065 (((wl_rates_t *)(outfp->wldp_buf))-> 28743737Shx147065 wl_rates_rates)[0] = WL_RATE_5_5M; 28753737Shx147065 break; 28763737Shx147065 case WL_SPEED_11Mbps_P2: 28773737Shx147065 (((wl_rates_t *)(outfp->wldp_buf))-> 28783737Shx147065 wl_rates_rates)[0] = WL_RATE_11M; 28793737Shx147065 break; 28803737Shx147065 default: 28813737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 28823737Shx147065 outfp->wldp_result = WL_HW_ERROR; 28833737Shx147065 goto done; 28843737Shx147065 } 28853737Shx147065 } else { 28863737Shx147065 switch (rate) { 28873737Shx147065 case WL_L_TX_RATE_FIX_1M: 28883737Shx147065 ((wl_rates_t *)(outfp->wldp_buf))-> 28893737Shx147065 wl_rates_num = 1; 28903737Shx147065 (((wl_rates_t *)(outfp->wldp_buf))-> 28913737Shx147065 wl_rates_rates)[0] = WL_RATE_1M; 28923737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 28933737Shx147065 offsetof(wl_rates_t, wl_rates_rates) + 28943737Shx147065 1 * sizeof (char); 28953737Shx147065 break; 28963737Shx147065 case WL_L_TX_RATE_FIX_2M: 28973737Shx147065 ((wl_rates_t *)(outfp->wldp_buf))-> 28983737Shx147065 wl_rates_num = 1; 28993737Shx147065 (((wl_rates_t *)(outfp->wldp_buf))-> 29003737Shx147065 wl_rates_rates)[0] = WL_RATE_2M; 29013737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 29023737Shx147065 offsetof(wl_rates_t, wl_rates_rates) + 29033737Shx147065 1 * sizeof (char); 29043737Shx147065 break; 29053737Shx147065 case WL_L_TX_RATE_AUTO_H: 29063737Shx147065 ((wl_rates_t *)(outfp->wldp_buf))-> 29073737Shx147065 wl_rates_num = 4; 29083737Shx147065 (((wl_rates_t *)(outfp->wldp_buf))-> 29093737Shx147065 wl_rates_rates)[0] = WL_RATE_1M; 29103737Shx147065 (((wl_rates_t *)(outfp->wldp_buf))-> 29113737Shx147065 wl_rates_rates)[1] = WL_RATE_2M; 29123737Shx147065 (((wl_rates_t *)(outfp->wldp_buf))-> 29133737Shx147065 wl_rates_rates)[2] = WL_RATE_5_5M; 29143737Shx147065 (((wl_rates_t *)(outfp->wldp_buf))-> 29153737Shx147065 wl_rates_rates)[3] = WL_RATE_11M; 29163737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 29173737Shx147065 offsetof(wl_rates_t, wl_rates_rates) + 29183737Shx147065 4 * sizeof (char); 29193737Shx147065 break; 29203737Shx147065 case WL_L_TX_RATE_FIX_5M: 29213737Shx147065 ((wl_rates_t *)(outfp->wldp_buf))-> 29223737Shx147065 wl_rates_num = 1; 29233737Shx147065 (((wl_rates_t *)(outfp->wldp_buf))-> 29243737Shx147065 wl_rates_rates)[0] = WL_RATE_5_5M; 29253737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 29263737Shx147065 offsetof(wl_rates_t, wl_rates_rates) + 29273737Shx147065 1 * sizeof (char); 29283737Shx147065 break; 29293737Shx147065 case WL_L_TX_RATE_FIX_11M: 29303737Shx147065 ((wl_rates_t *)(outfp->wldp_buf))-> 29313737Shx147065 wl_rates_num = 1; 29323737Shx147065 (((wl_rates_t *)(outfp->wldp_buf))-> 29333737Shx147065 wl_rates_rates)[0] = WL_RATE_11M; 29343737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 29353737Shx147065 offsetof(wl_rates_t, wl_rates_rates) + 29363737Shx147065 1 * sizeof (char); 29373737Shx147065 break; 29383737Shx147065 case WL_L_TX_RATE_AUTO_L: 29393737Shx147065 ((wl_rates_t *)(outfp->wldp_buf))-> 29403737Shx147065 wl_rates_num = 2; 29413737Shx147065 (((wl_rates_t *)(outfp->wldp_buf))-> 29423737Shx147065 wl_rates_rates)[0] = WL_RATE_1M; 29433737Shx147065 (((wl_rates_t *)(outfp->wldp_buf))-> 29443737Shx147065 wl_rates_rates)[1] = WL_RATE_2M; 29453737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 29463737Shx147065 offsetof(wl_rates_t, wl_rates_rates) + 29473737Shx147065 2 * sizeof (char); 29483737Shx147065 break; 29493737Shx147065 case WL_L_TX_RATE_AUTO_M: 29503737Shx147065 ((wl_rates_t *)(outfp->wldp_buf))-> 29513737Shx147065 wl_rates_num = 3; 29523737Shx147065 (((wl_rates_t *)(outfp->wldp_buf))-> 29533737Shx147065 wl_rates_rates)[0] = WL_RATE_1M; 29543737Shx147065 (((wl_rates_t *)(outfp->wldp_buf))-> 29553737Shx147065 wl_rates_rates)[1] = WL_RATE_2M; 29563737Shx147065 (((wl_rates_t *)(outfp->wldp_buf))-> 29573737Shx147065 wl_rates_rates)[2] = WL_RATE_5_5M; 29583737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 29593737Shx147065 offsetof(wl_rates_t, wl_rates_rates) + 29603737Shx147065 3 * sizeof (char); 29613737Shx147065 break; 29623737Shx147065 default: 29633737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 29643737Shx147065 outfp->wldp_result = WL_HW_ERROR; 29653737Shx147065 goto done; 29663737Shx147065 } 29673737Shx147065 } 29683737Shx147065 PCWLDBG((CE_CONT, "pcwl: get rate=%d\n", rate)); 2969*6062Shx147065 outfp->wldp_result = WL_SUCCESS; 29703737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 29713737Shx147065 bzero(rates, sizeof (rates)); 29723737Shx147065 for (i = 0; i < 4; i++) { 29733737Shx147065 rates[i] = (((wl_rates_t *) 29743737Shx147065 (infp->wldp_buf))->wl_rates_rates)[i]; 29753737Shx147065 PCWLDBG((CE_CONT, "pcwl: set tx_rate[%d]=%d\n", 29763737Shx147065 i, rates[i])); 29773737Shx147065 } 29783737Shx147065 PCWLDBG((CE_CONT, "pcwl: set rate_num=%d\n", 29793737Shx147065 ((wl_rates_t *)(infp->wldp_buf)) 29803737Shx147065 ->wl_rates_num)); 29813737Shx147065 switch (((wl_rates_t *) 29823737Shx147065 (infp->wldp_buf))->wl_rates_num) { 29833737Shx147065 case 1: 29843737Shx147065 switch (rates[0]) { 29853737Shx147065 case WL_RATE_1M: 29863737Shx147065 rf_p->rf_tx_rate = WL_TX_RATE_FIX_1M(pcwl_p); 29873737Shx147065 break; 29883737Shx147065 case WL_RATE_2M: 29893737Shx147065 rf_p->rf_tx_rate = WL_TX_RATE_FIX_2M(pcwl_p); 29903737Shx147065 break; 29913737Shx147065 case WL_RATE_11M: 29923737Shx147065 rf_p->rf_tx_rate = WL_TX_RATE_FIX_11M(pcwl_p); 29933737Shx147065 break; 29943737Shx147065 case WL_RATE_5_5M: 29953737Shx147065 rf_p->rf_tx_rate = WL_TX_RATE_FIX_5M(pcwl_p); 29963737Shx147065 break; 29973737Shx147065 default: 29983737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 29993737Shx147065 outfp->wldp_result = WL_NOTSUPPORTED; 30003737Shx147065 goto done; 30013737Shx147065 } 30023737Shx147065 break; 30033737Shx147065 case 2: 30043737Shx147065 maxrate = (rates[0] > rates[1] ? 30053737Shx147065 rates[0] : rates[1]); 30063737Shx147065 switch (maxrate) { 30073737Shx147065 case WL_RATE_2M: 30083737Shx147065 rf_p->rf_tx_rate = WL_TX_RATE_AUTO_L(pcwl_p); 30093737Shx147065 break; 30103737Shx147065 case WL_RATE_11M: 30113737Shx147065 rf_p->rf_tx_rate = WL_TX_RATE_AUTO_H(pcwl_p); 30123737Shx147065 break; 30133737Shx147065 case WL_RATE_5_5M: 30143737Shx147065 rf_p->rf_tx_rate = WL_TX_RATE_AUTO_M(pcwl_p); 30153737Shx147065 break; 30163737Shx147065 default: 30173737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 30183737Shx147065 outfp->wldp_result = WL_NOTSUPPORTED; 30193737Shx147065 goto done; 30203737Shx147065 } 30213737Shx147065 break; 30223737Shx147065 case 3: 30233737Shx147065 maxrate = (rates[0] > rates[1] ? 30243737Shx147065 rates[0] : rates[1]); 30253737Shx147065 maxrate = (rates[2] > maxrate ? 30263737Shx147065 rates[2] : maxrate); 30273737Shx147065 switch (maxrate) { 30283737Shx147065 case WL_RATE_11M: 30293737Shx147065 rf_p->rf_tx_rate = WL_TX_RATE_AUTO_H(pcwl_p); 30303737Shx147065 break; 30313737Shx147065 case WL_RATE_5_5M: 30323737Shx147065 rf_p->rf_tx_rate = WL_TX_RATE_AUTO_M(pcwl_p); 30333737Shx147065 break; 30343737Shx147065 default: 30353737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 30363737Shx147065 outfp->wldp_result = WL_NOTSUPPORTED; 30373737Shx147065 goto done; 30383737Shx147065 } 30393737Shx147065 break; 30403737Shx147065 case 4: 30413737Shx147065 rf_p->rf_tx_rate = WL_TX_RATE_AUTO_H(pcwl_p); 30423737Shx147065 break; 30433737Shx147065 default: 30443737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 30453737Shx147065 outfp->wldp_result = WL_LACK_FEATURE; 30463737Shx147065 goto done; 30473737Shx147065 } 30483737Shx147065 PCWLDBG((CE_CONT, "pcwl: set tx_rate=%d\n", rf_p->rf_tx_rate)); 30493737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 30503737Shx147065 outfp->wldp_result = WL_SUCCESS; 30513737Shx147065 } else { 30523737Shx147065 kmem_free(buf, MAX_BUF_LEN); 30533737Shx147065 return (EINVAL); 30543737Shx147065 } 30553737Shx147065 done: 30563737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 30573737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 30583737Shx147065 iret = (int)(outfp->wldp_result); 30593737Shx147065 kmem_free(buf, MAX_BUF_LEN); 30603737Shx147065 return (iret); 30613737Shx147065 } 30623737Shx147065 30633737Shx147065 /*ARGSUSED*/ 30643737Shx147065 static int 30653737Shx147065 pcwl_cfg_supportrates(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd) 30663737Shx147065 { 30673737Shx147065 uint16_t i; 30683737Shx147065 wldp_t *outfp; 30693737Shx147065 char *buf; 30703737Shx147065 30713737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 30723737Shx147065 if (buf == NULL) { 30733737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n", 30743737Shx147065 MAX_BUF_LEN)); 30753737Shx147065 return (ENOMEM); 30763737Shx147065 } 30773737Shx147065 outfp = (wldp_t *)buf; 30783737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 30793737Shx147065 30803737Shx147065 if (cmd == WLAN_GET_PARAM) { 30813737Shx147065 ((wl_rates_t *)(outfp->wldp_buf))->wl_rates_num = 4; 30823737Shx147065 (((wl_rates_t *)(outfp->wldp_buf))->wl_rates_rates)[0] 30833737Shx147065 = WL_RATE_1M; 30843737Shx147065 (((wl_rates_t *)(outfp->wldp_buf))->wl_rates_rates)[1] 30853737Shx147065 = WL_RATE_2M; 30863737Shx147065 (((wl_rates_t *)(outfp->wldp_buf))->wl_rates_rates)[2] 30873737Shx147065 = WL_RATE_5_5M; 30883737Shx147065 (((wl_rates_t *)(outfp->wldp_buf))->wl_rates_rates)[3] 30893737Shx147065 = WL_RATE_11M; 30903737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 30913737Shx147065 offsetof(wl_rates_t, wl_rates_rates) + 30923737Shx147065 4 * sizeof (char); 30933737Shx147065 outfp->wldp_result = WL_SUCCESS; 30943737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 30953737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 30963737Shx147065 kmem_free(buf, MAX_BUF_LEN); 30973737Shx147065 return (WL_SUCCESS); 30983737Shx147065 } else { 30993737Shx147065 kmem_free(buf, MAX_BUF_LEN); 31003737Shx147065 return (EINVAL); 31013737Shx147065 } 31023737Shx147065 } 31033737Shx147065 31043737Shx147065 static int 31053737Shx147065 pcwl_cfg_powermode(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd) 31063737Shx147065 { 31073737Shx147065 uint16_t i, ret; 31083737Shx147065 pcwl_rf_t *rf_p; 31093737Shx147065 wldp_t *infp; 31103737Shx147065 wldp_t *outfp; 31113737Shx147065 char *buf; 31123737Shx147065 int iret; 31133737Shx147065 31143737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 31153737Shx147065 if (buf == NULL) { 31163737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n", 31173737Shx147065 MAX_BUF_LEN)); 31183737Shx147065 return (ENOMEM); 31193737Shx147065 } 31203737Shx147065 outfp = (wldp_t *)buf; 31213737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 31223737Shx147065 infp = (wldp_t *)mp->b_rptr; 31233737Shx147065 rf_p = &pcwl_p->pcwl_rf; 31243737Shx147065 31253737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_ps_mode_t); 31263737Shx147065 if (cmd == WLAN_GET_PARAM) { 31273737Shx147065 ((wl_ps_mode_t *)(outfp->wldp_buf))->wl_ps_mode = 31283737Shx147065 rf_p->rf_pm_enabled; 31293737Shx147065 outfp->wldp_result = WL_SUCCESS; 31303737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 31313737Shx147065 ret = (uint16_t)(((wl_ps_mode_t *)(infp->wldp_buf)) 31323737Shx147065 ->wl_ps_mode); 31333737Shx147065 if (ret != WL_PM_AM && ret != WL_PM_MPS && ret != WL_PM_FAST) { 31343737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 31353737Shx147065 outfp->wldp_result = WL_NOTSUPPORTED; 31363737Shx147065 goto done; 31373737Shx147065 } 31383737Shx147065 rf_p->rf_pm_enabled = ret; 31393737Shx147065 outfp->wldp_result = WL_SUCCESS; 31403737Shx147065 } else { 31413737Shx147065 kmem_free(buf, MAX_BUF_LEN); 31423737Shx147065 return (EINVAL); 31433737Shx147065 } 31443737Shx147065 done: 31453737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 31463737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 31473737Shx147065 iret = (int)(outfp->wldp_result); 31483737Shx147065 kmem_free(buf, MAX_BUF_LEN); 31493737Shx147065 return (iret); 31503737Shx147065 31513737Shx147065 } 31523737Shx147065 31533737Shx147065 static int 31543737Shx147065 pcwl_cfg_authmode(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd) 31553737Shx147065 { 31563737Shx147065 uint16_t i, ret; 31573737Shx147065 pcwl_rf_t *rf_p; 31583737Shx147065 wldp_t *infp; 31593737Shx147065 wldp_t *outfp; 31603737Shx147065 char *buf; 31613737Shx147065 int iret; 31623737Shx147065 31633737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 31643737Shx147065 if (buf == NULL) { 31653737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n", 31663737Shx147065 MAX_BUF_LEN)); 31673737Shx147065 return (ENOMEM); 31683737Shx147065 } 31693737Shx147065 outfp = (wldp_t *)buf; 31703737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 31713737Shx147065 infp = (wldp_t *)mp->b_rptr; 31723737Shx147065 rf_p = &pcwl_p->pcwl_rf; 31733737Shx147065 31743737Shx147065 31753737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_authmode_t); 31763737Shx147065 if (cmd == WLAN_GET_PARAM) { 31773737Shx147065 *(wl_authmode_t *)(outfp->wldp_buf) = rf_p->rf_authtype; 31783737Shx147065 outfp->wldp_result = WL_SUCCESS; 31793737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 31803737Shx147065 ret = (uint16_t)(*(wl_authmode_t *)(infp->wldp_buf)); 31813737Shx147065 if (ret != WL_OPENSYSTEM && ret != WL_SHAREDKEY) { 31823737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 31833737Shx147065 outfp->wldp_result = WL_NOTSUPPORTED; 31843737Shx147065 goto done; 31853737Shx147065 } 31863737Shx147065 rf_p->rf_authtype = ret; 31873737Shx147065 outfp->wldp_result = WL_SUCCESS; 31883737Shx147065 } else { 31893737Shx147065 kmem_free(buf, MAX_BUF_LEN); 31903737Shx147065 return (EINVAL); 31913737Shx147065 } 31923737Shx147065 done: 31933737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 31943737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 31953737Shx147065 iret = (int)(outfp->wldp_result); 31963737Shx147065 kmem_free(buf, MAX_BUF_LEN); 31973737Shx147065 return (iret); 31983737Shx147065 } 31993737Shx147065 32003737Shx147065 static int 32013737Shx147065 pcwl_cfg_encryption(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd) 32023737Shx147065 { 32033737Shx147065 uint16_t i, ret; 32043737Shx147065 pcwl_rf_t *rf_p; 32053737Shx147065 wldp_t *infp; 32063737Shx147065 wldp_t *outfp; 32073737Shx147065 char *buf; 32083737Shx147065 int iret; 32093737Shx147065 32103737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 32113737Shx147065 if (buf == NULL) { 32123737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n", 32133737Shx147065 MAX_BUF_LEN)); 32143737Shx147065 return (ENOMEM); 32153737Shx147065 } 32163737Shx147065 outfp = (wldp_t *)buf; 32173737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 32183737Shx147065 infp = (wldp_t *)mp->b_rptr; 32193737Shx147065 rf_p = &pcwl_p->pcwl_rf; 32203737Shx147065 32213737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_encryption_t); 32223737Shx147065 if (cmd == WLAN_GET_PARAM) { 32233737Shx147065 *(wl_encryption_t *)(outfp->wldp_buf) = rf_p->rf_encryption; 32243737Shx147065 outfp->wldp_result = WL_SUCCESS; 32253737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 32263737Shx147065 ret = (uint16_t)(*(wl_encryption_t *)(infp->wldp_buf)); 32273737Shx147065 PCWLDBG((CE_NOTE, "set encryption: %d\n", ret)); 32283737Shx147065 if (ret != WL_NOENCRYPTION && ret != WL_ENC_WEP) { 32293737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 32303737Shx147065 outfp->wldp_result = WL_NOTSUPPORTED; 32313737Shx147065 goto done; 32323737Shx147065 } 32333737Shx147065 rf_p->rf_encryption = ret; 32343737Shx147065 outfp->wldp_result = WL_SUCCESS; 32353737Shx147065 } else { 32363737Shx147065 kmem_free(buf, MAX_BUF_LEN); 32373737Shx147065 return (EINVAL); 32383737Shx147065 } 32393737Shx147065 done: 32403737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 32413737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 32423737Shx147065 iret = (int)(outfp->wldp_result); 32433737Shx147065 kmem_free(buf, MAX_BUF_LEN); 32443737Shx147065 return (iret); 32453737Shx147065 } 32463737Shx147065 32473737Shx147065 static int 32483737Shx147065 pcwl_cfg_wepkeyid(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd) 32493737Shx147065 { 32503737Shx147065 uint16_t i, ret; 32513737Shx147065 pcwl_rf_t *rf_p; 32523737Shx147065 wldp_t *infp; 32533737Shx147065 wldp_t *outfp; 32543737Shx147065 char *buf; 32553737Shx147065 int iret; 32563737Shx147065 32573737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 32583737Shx147065 if (buf == NULL) { 32593737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n", 32603737Shx147065 MAX_BUF_LEN)); 32613737Shx147065 return (ENOMEM); 32623737Shx147065 } 32633737Shx147065 outfp = (wldp_t *)buf; 32643737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 32653737Shx147065 infp = (wldp_t *)mp->b_rptr; 32663737Shx147065 rf_p = &pcwl_p->pcwl_rf; 32673737Shx147065 32683737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_wep_key_id_t); 32693737Shx147065 if (cmd == WLAN_GET_PARAM) { 32703737Shx147065 *(wl_wep_key_id_t *)(outfp->wldp_buf) = rf_p->rf_tx_crypt_key; 32713737Shx147065 outfp->wldp_result = WL_SUCCESS; 32723737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 32733737Shx147065 ret = (uint16_t)(*(wl_wep_key_id_t *)(infp->wldp_buf)); 32743737Shx147065 if (ret >= MAX_NWEPKEYS) { 32753737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 32763737Shx147065 outfp->wldp_result = WL_NOTSUPPORTED; 32773737Shx147065 goto done; 32783737Shx147065 } 32793737Shx147065 rf_p->rf_tx_crypt_key = ret; 32803737Shx147065 outfp->wldp_result = WL_SUCCESS; 32813737Shx147065 } else { 32823737Shx147065 kmem_free(buf, MAX_BUF_LEN); 32833737Shx147065 return (EINVAL); 32843737Shx147065 } 32853737Shx147065 done: 32863737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 32873737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 32883737Shx147065 iret = (int)(outfp->wldp_result); 32893737Shx147065 kmem_free(buf, MAX_BUF_LEN); 32903737Shx147065 return (iret); 32913737Shx147065 } 32923737Shx147065 32933737Shx147065 static int 32943737Shx147065 pcwl_cfg_createibss(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd) 32953737Shx147065 { 32963737Shx147065 uint16_t i, ret; 32973737Shx147065 pcwl_rf_t *rf_p; 32983737Shx147065 wldp_t *infp; 32993737Shx147065 wldp_t *outfp; 33003737Shx147065 char *buf; 33013737Shx147065 int iret; 33023737Shx147065 33033737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 33043737Shx147065 if (buf == NULL) { 33053737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n", 33063737Shx147065 MAX_BUF_LEN)); 33073737Shx147065 return (ENOMEM); 33083737Shx147065 } 33093737Shx147065 outfp = (wldp_t *)buf; 33103737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 33113737Shx147065 infp = (wldp_t *)mp->b_rptr; 33123737Shx147065 rf_p = &pcwl_p->pcwl_rf; 33133737Shx147065 33143737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_create_ibss_t); 33153737Shx147065 if (cmd == WLAN_GET_PARAM) { 33163737Shx147065 *(wl_create_ibss_t *)(outfp->wldp_buf) = rf_p->rf_create_ibss; 33173737Shx147065 outfp->wldp_result = WL_SUCCESS; 33183737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 33193737Shx147065 ret = (uint16_t)(*(wl_create_ibss_t *)(infp->wldp_buf)); 33203737Shx147065 if (ret != 0 && ret != 1) { 33213737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 33223737Shx147065 outfp->wldp_result = WL_NOTSUPPORTED; 33233737Shx147065 goto done; 33243737Shx147065 } 33253737Shx147065 rf_p->rf_create_ibss = ret; 33263737Shx147065 outfp->wldp_result = WL_SUCCESS; 33273737Shx147065 } else { 33283737Shx147065 kmem_free(buf, MAX_BUF_LEN); 33293737Shx147065 return (EINVAL); 33303737Shx147065 } 33313737Shx147065 done: 33323737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 33333737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 33343737Shx147065 iret = (int)(outfp->wldp_result); 33353737Shx147065 kmem_free(buf, MAX_BUF_LEN); 33363737Shx147065 return (iret); 33373737Shx147065 } 33383737Shx147065 33393737Shx147065 static int 33403737Shx147065 pcwl_cfg_rssi(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd) 33413737Shx147065 { 33423737Shx147065 uint16_t i; 33433737Shx147065 int iret; 33443737Shx147065 wldp_t *outfp; 33453737Shx147065 char *buf; 33463737Shx147065 33473737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 33483737Shx147065 if (buf == NULL) { 33493737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n", 33503737Shx147065 MAX_BUF_LEN)); 33513737Shx147065 return (ENOMEM); 33523737Shx147065 } 33533737Shx147065 outfp = (wldp_t *)buf; 33543737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 33553737Shx147065 33563737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_rssi_t); 33573737Shx147065 33583737Shx147065 if (cmd == WLAN_GET_PARAM) { 33593737Shx147065 if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) { 33603737Shx147065 *(wl_rssi_t *)(outfp->wldp_buf) = 33613737Shx147065 min((pcwl_p->pcwl_rssi * 15 / 85 + 1), 15); 33623737Shx147065 } else { 33633737Shx147065 /* 33643737Shx147065 * According to the description of the 33653737Shx147065 * datasheet(Lucent card), the signal level 33663737Shx147065 * value is between 27 -- 154. 33673737Shx147065 * we reflect these value to 1-15 as rssi. 33683737Shx147065 */ 33693737Shx147065 if (pcwl_p->pcwl_rssi <= 27) 33703737Shx147065 *(wl_rssi_t *)(outfp->wldp_buf) = 1; 33713737Shx147065 else if (pcwl_p->pcwl_rssi > 154) 33723737Shx147065 *(wl_rssi_t *)(outfp->wldp_buf) = 15; 33733737Shx147065 else 33743737Shx147065 *(wl_rssi_t *)(outfp->wldp_buf) = 33753737Shx147065 min(15, ((pcwl_p->pcwl_rssi - 27) 33763737Shx147065 * 15 / 127)); 33773737Shx147065 } 33783737Shx147065 outfp->wldp_result = WL_SUCCESS; 33793737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 33803737Shx147065 outfp->wldp_result = WL_READONLY; 33813737Shx147065 } else { 33823737Shx147065 kmem_free(buf, MAX_BUF_LEN); 33833737Shx147065 return (EINVAL); 33843737Shx147065 } 33853737Shx147065 done: 33863737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 33873737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 33883737Shx147065 iret = (int)(outfp->wldp_result); 33893737Shx147065 kmem_free(buf, MAX_BUF_LEN); 33903737Shx147065 return (iret); 33913737Shx147065 } 33923737Shx147065 33933737Shx147065 /*ARGSUSED*/ 33943737Shx147065 static int 33953737Shx147065 pcwl_cfg_radio(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd) 33963737Shx147065 { 33973737Shx147065 uint16_t i; 33983737Shx147065 int iret; 33993737Shx147065 wldp_t *outfp; 34003737Shx147065 char *buf; 34013737Shx147065 34023737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 34033737Shx147065 if (buf == NULL) { 34043737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n", 34053737Shx147065 MAX_BUF_LEN)); 34063737Shx147065 return (ENOMEM); 34073737Shx147065 } 34083737Shx147065 outfp = (wldp_t *)buf; 34093737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 34103737Shx147065 34113737Shx147065 if (cmd == WLAN_GET_PARAM) { 34123737Shx147065 *(wl_radio_t *)(outfp->wldp_buf) = B_TRUE; 34133737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_radio_t); 34143737Shx147065 outfp->wldp_result = WL_SUCCESS; 34153737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 34163737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 34173737Shx147065 outfp->wldp_result = WL_LACK_FEATURE; 34183737Shx147065 } else { 34193737Shx147065 kmem_free(buf, MAX_BUF_LEN); 34203737Shx147065 return (EINVAL); 34213737Shx147065 } 34223737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 34233737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 34243737Shx147065 iret = (int)(outfp->wldp_result); 34253737Shx147065 kmem_free(buf, MAX_BUF_LEN); 34263737Shx147065 return (iret); 34273737Shx147065 } 34283737Shx147065 34293737Shx147065 static int 34303737Shx147065 pcwl_cfg_wepkey(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd) 34313737Shx147065 { 34323737Shx147065 uint16_t i; 34333737Shx147065 wl_wep_key_t *p_wepkey_tab; 34343737Shx147065 pcwl_rf_t *rf_p; 34353737Shx147065 wldp_t *infp; 34363737Shx147065 wldp_t *outfp; 34373737Shx147065 char *buf; 34383737Shx147065 int iret; 34393737Shx147065 34403737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 34413737Shx147065 if (buf == NULL) { 34423737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n", 34433737Shx147065 MAX_BUF_LEN)); 34443737Shx147065 return (ENOMEM); 34453737Shx147065 } 34463737Shx147065 outfp = (wldp_t *)buf; 34473737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 34483737Shx147065 infp = (wldp_t *)mp->b_rptr; 34493737Shx147065 rf_p = &pcwl_p->pcwl_rf; 34503737Shx147065 bzero((rf_p->rf_ckeys), sizeof (rf_ckey_t) * MAX_NWEPKEYS); 34513737Shx147065 34523737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_wep_key_tab_t); 34533737Shx147065 if (cmd == WLAN_GET_PARAM) { 34543737Shx147065 outfp->wldp_result = WL_WRITEONLY; 34553737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 34563737Shx147065 p_wepkey_tab = (wl_wep_key_t *)(infp->wldp_buf); 34573737Shx147065 for (i = 0; i < MAX_NWEPKEYS; i++) { 34583737Shx147065 if (p_wepkey_tab[i].wl_wep_operation == WL_ADD) { 34593737Shx147065 rf_p->rf_ckeys[i].ckey_len = 34603737Shx147065 p_wepkey_tab[i].wl_wep_length; 34613737Shx147065 bcopy(p_wepkey_tab[i].wl_wep_key, 34623737Shx147065 rf_p->rf_ckeys[i].ckey_dat, 34633737Shx147065 p_wepkey_tab[i].wl_wep_length); 34643737Shx147065 PCWL_SWAP16((uint16_t *) 34653737Shx147065 &rf_p->rf_ckeys[i].ckey_dat, 34663737Shx147065 rf_p->rf_ckeys[i].ckey_len + 1); 34673737Shx147065 PCWLDBG((CE_CONT, "%s, %d\n", 34683737Shx147065 rf_p->rf_ckeys[i].ckey_dat, i)); 34693737Shx147065 } 34703737Shx147065 PCWLDBG((CE_CONT, "pcwl: rf_ckeys[%d]=%s\n", i, 3471*6062Shx147065 (char *)(rf_p->rf_ckeys[i].ckey_dat))); 34723737Shx147065 } 34733737Shx147065 outfp->wldp_result = WL_SUCCESS; 34743737Shx147065 } else { 34753737Shx147065 kmem_free(buf, MAX_BUF_LEN); 34763737Shx147065 return (EINVAL); 34773737Shx147065 } 34783737Shx147065 done: 34793737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 34803737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 34813737Shx147065 iret = (int)(outfp->wldp_result); 34823737Shx147065 kmem_free(buf, MAX_BUF_LEN); 34833737Shx147065 return (iret); 34843737Shx147065 } 34853737Shx147065 34863737Shx147065 static void 34873737Shx147065 pcwl_connect_timeout(void *arg) 34883737Shx147065 { 34893737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg; 34903737Shx147065 uint16_t ret = 0; 34913737Shx147065 34923737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 34933737Shx147065 PCWL_DISABLE_INTR(pcwl_p); 34943737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) { 34953737Shx147065 goto done; 34963737Shx147065 } 34973737Shx147065 if (ret = pcwl_config_rf(pcwl_p)) { 34983737Shx147065 goto done; 34993737Shx147065 } 35003737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) { 35013737Shx147065 goto done; 35023737Shx147065 } 35033737Shx147065 PCWL_ENABLE_INTR(pcwl_p); 35043737Shx147065 done: 35053737Shx147065 if (ret) 35064196Syx209050 cmn_err(CE_WARN, "pcwl: connect failed due to hardware error"); 35073737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 35083737Shx147065 pcwl_p->pcwl_connect_timeout_id = 0; 35093737Shx147065 } 35103737Shx147065 35113737Shx147065 static int 35123737Shx147065 pcwl_getset(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd) 35133737Shx147065 { 35143737Shx147065 int ret = WL_SUCCESS; 35153737Shx147065 int connect = 0; 35163737Shx147065 35173737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 35183737Shx147065 if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) { 35193737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 35203737Shx147065 return (PCWL_FAIL); 35213737Shx147065 } 35223737Shx147065 switch (((wldp_t *)mp->b_rptr)->wldp_id) { 35233737Shx147065 case WL_ESSID: 35243737Shx147065 ret = pcwl_cfg_essid(mp, pcwl_p, cmd); 35253737Shx147065 connect = 1; 35263737Shx147065 PCWLDBG((CE_NOTE, "cfg_essid\n")); 35273737Shx147065 break; 35283737Shx147065 case WL_BSSID: 35293737Shx147065 ret = pcwl_cfg_bssid(mp, pcwl_p, cmd); 35303737Shx147065 connect = 1; 35313737Shx147065 PCWLDBG((CE_NOTE, "cfg_bssid\n")); 35323737Shx147065 break; 35333737Shx147065 case WL_ESS_LIST: 35343737Shx147065 ret = pcwl_cfg_scan(mp, pcwl_p, cmd); 35353737Shx147065 PCWLDBG((CE_NOTE, "cfg_scan\n")); 35363737Shx147065 break; 35373737Shx147065 case WL_LINKSTATUS: 35383737Shx147065 ret = pcwl_cfg_linkstatus(mp, pcwl_p, cmd); 35393737Shx147065 PCWLDBG((CE_NOTE, "cfg_linkstatus\n")); 35403737Shx147065 break; 35413737Shx147065 case WL_BSS_TYPE: 35423737Shx147065 ret = pcwl_cfg_bsstype(mp, pcwl_p, cmd); 35433737Shx147065 connect = 1; 35443737Shx147065 PCWLDBG((CE_NOTE, "cfg_bsstype\n")); 35453737Shx147065 break; 35463737Shx147065 case WL_PHY_CONFIG: 35473737Shx147065 ret = pcwl_cfg_phy(mp, pcwl_p, cmd); 35483737Shx147065 connect = 1; 35493737Shx147065 PCWLDBG((CE_NOTE, "cfg_phy\n")); 35503737Shx147065 break; 35513737Shx147065 case WL_DESIRED_RATES: 35523737Shx147065 ret = pcwl_cfg_desiredrates(mp, pcwl_p, cmd); 35533737Shx147065 connect = 1; 35543737Shx147065 PCWLDBG((CE_NOTE, "cfg_disred-rates\n")); 35553737Shx147065 break; 35563737Shx147065 case WL_SUPPORTED_RATES: 35573737Shx147065 ret = pcwl_cfg_supportrates(mp, pcwl_p, cmd); 35583737Shx147065 PCWLDBG((CE_NOTE, "cfg_supported-rates\n")); 35593737Shx147065 break; 35603737Shx147065 case WL_POWER_MODE: 35613737Shx147065 ret = pcwl_cfg_powermode(mp, pcwl_p, cmd); 35623737Shx147065 PCWLDBG((CE_NOTE, "cfg_powermode\n")); 35633737Shx147065 break; 35643737Shx147065 case WL_AUTH_MODE: 35653737Shx147065 ret = pcwl_cfg_authmode(mp, pcwl_p, cmd); 35663737Shx147065 connect = 1; 35673737Shx147065 PCWLDBG((CE_NOTE, "cfg_authmode\n")); 35683737Shx147065 break; 35693737Shx147065 case WL_ENCRYPTION: 35703737Shx147065 ret = pcwl_cfg_encryption(mp, pcwl_p, cmd); 35713737Shx147065 connect = 1; 35723737Shx147065 PCWLDBG((CE_NOTE, "cfg_encryption\n")); 35733737Shx147065 break; 35743737Shx147065 case WL_WEP_KEY_ID: 35753737Shx147065 ret = pcwl_cfg_wepkeyid(mp, pcwl_p, cmd); 35763737Shx147065 connect = 1; 35773737Shx147065 PCWLDBG((CE_NOTE, "cfg_wepkeyid\n")); 35783737Shx147065 break; 35793737Shx147065 case WL_CREATE_IBSS: 35803737Shx147065 ret = pcwl_cfg_createibss(mp, pcwl_p, cmd); 35813737Shx147065 connect = 1; 35823737Shx147065 PCWLDBG((CE_NOTE, "cfg_create-ibss\n")); 35833737Shx147065 break; 35843737Shx147065 case WL_RSSI: 35853737Shx147065 ret = pcwl_cfg_rssi(mp, pcwl_p, cmd); 35863737Shx147065 PCWLDBG((CE_NOTE, "cfg_rssi\n")); 35873737Shx147065 break; 35883737Shx147065 case WL_RADIO: 35893737Shx147065 ret = pcwl_cfg_radio(mp, pcwl_p, cmd); 35903737Shx147065 PCWLDBG((CE_NOTE, "cfg_radio\n")); 35913737Shx147065 break; 35923737Shx147065 case WL_WEP_KEY_TAB: 35933737Shx147065 ret = pcwl_cfg_wepkey(mp, pcwl_p, cmd); 35943737Shx147065 connect = 1; 35953737Shx147065 PCWLDBG((CE_NOTE, "cfg_wepkey\n")); 35963737Shx147065 break; 35973737Shx147065 case WL_SCAN: 35983737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 35993737Shx147065 if (pcwl_p->pcwl_connect_timeout_id != 0) { 36003737Shx147065 (void) untimeout(pcwl_p->pcwl_connect_timeout_id); 36013737Shx147065 pcwl_p->pcwl_connect_timeout_id = 0; 36023737Shx147065 } 36033737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 36043737Shx147065 ret = pcwl_cmd_scan(pcwl_p); 36053737Shx147065 break; 36063737Shx147065 case WL_LOAD_DEFAULTS: 36073737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 36083737Shx147065 if (pcwl_p->pcwl_connect_timeout_id != 0) { 36093737Shx147065 (void) untimeout(pcwl_p->pcwl_connect_timeout_id); 36103737Shx147065 pcwl_p->pcwl_connect_timeout_id = 0; 36113737Shx147065 } 36123737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 36133737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) { 36143737Shx147065 ret = (int)WL_HW_ERROR; 36153737Shx147065 break; 36163737Shx147065 } 36173737Shx147065 if (ret = pcwl_loaddef_rf(pcwl_p)) { 36183737Shx147065 ret = (int)WL_HW_ERROR; 36193737Shx147065 PCWLDBG((CE_WARN, "cfg_loaddef_err\n")); 36203737Shx147065 break; 36213737Shx147065 } 36223737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) { 36233737Shx147065 ret = (int)WL_HW_ERROR; 36243737Shx147065 break; 36253737Shx147065 } 36263737Shx147065 pcwl_delay(pcwl_p, 1000000); 36273737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) { 36283737Shx147065 ret = (int)WL_HW_ERROR; 36293737Shx147065 break; 36303737Shx147065 } 36313737Shx147065 PCWLDBG((CE_NOTE, "loaddef\n")); 36323737Shx147065 break; 36333737Shx147065 case WL_DISASSOCIATE: 36343737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 36353737Shx147065 if (pcwl_p->pcwl_connect_timeout_id != 0) { 36363737Shx147065 (void) untimeout(pcwl_p->pcwl_connect_timeout_id); 36373737Shx147065 pcwl_p->pcwl_connect_timeout_id = 0; 36383737Shx147065 } 36393737Shx147065 36403737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 36413737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) { 36423737Shx147065 ret = (int)WL_HW_ERROR; 36433737Shx147065 break; 36443737Shx147065 } 36453737Shx147065 /* 36463737Shx147065 * A workaround here: If the card is in ad-hoc mode, the 36473737Shx147065 * following scan will not work correctly, so any 36483737Shx147065 * 'dladm connect-wifi' which need a scan first will not 36493737Shx147065 * succeed. software reset the card here as a workround. 36503737Shx147065 */ 36513737Shx147065 if ((pcwl_p->pcwl_rf.rf_porttype == WL_BSS_IBSS) && 36523737Shx147065 (pcwl_p->pcwl_chip_type == PCWL_CHIP_LUCENT)) { 36533737Shx147065 if (ret = pcwl_reset_backend(pcwl_p)) { 36543737Shx147065 ret = (int)WL_HW_ERROR; 36553737Shx147065 break; 36563737Shx147065 } 36573737Shx147065 if (ret = pcwl_init_nicmem(pcwl_p)) { 36583737Shx147065 ret = (int)WL_HW_ERROR; 36593737Shx147065 break; 36603737Shx147065 } 36613737Shx147065 pcwl_start_locked(pcwl_p); 36623737Shx147065 } 36633737Shx147065 if (ret = pcwl_loaddef_rf(pcwl_p)) { 36643737Shx147065 ret = (int)WL_HW_ERROR; 36653737Shx147065 PCWLDBG((CE_WARN, "cfg_loaddef_err\n")); 36663737Shx147065 break; 36673737Shx147065 } 36683737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) { 36693737Shx147065 ret = (int)WL_HW_ERROR; 36703737Shx147065 break; 36713737Shx147065 } 36723737Shx147065 pcwl_delay(pcwl_p, 1000000); 36733737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) { 36743737Shx147065 ret = (int)WL_HW_ERROR; 36753737Shx147065 break; 36763737Shx147065 } 36773737Shx147065 PCWLDBG((CE_NOTE, "disassociate\n")); 36783737Shx147065 break; 36793737Shx147065 case WL_REASSOCIATE: 36803737Shx147065 case WL_ASSOCIAT: 36813737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 36823737Shx147065 if (pcwl_p->pcwl_connect_timeout_id != 0) { 36833737Shx147065 (void) untimeout(pcwl_p->pcwl_connect_timeout_id); 36843737Shx147065 pcwl_p->pcwl_connect_timeout_id = 0; 36853737Shx147065 } 36863737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 36873737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) { 36883737Shx147065 ret = (int)WL_HW_ERROR; 36893737Shx147065 break; 36903737Shx147065 } 36913737Shx147065 if (ret = pcwl_config_rf(pcwl_p)) { 36923737Shx147065 ret = (int)WL_HW_ERROR; 36933737Shx147065 break; 36943737Shx147065 } 36953737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) { 36963737Shx147065 ret = (int)WL_HW_ERROR; 36973737Shx147065 break; 36983737Shx147065 } 36993737Shx147065 PCWLDBG((CE_NOTE, "associate")); 37003737Shx147065 break; 37013737Shx147065 default: 37023737Shx147065 break; 37033737Shx147065 } 37043737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 37053737Shx147065 if ((cmd == WLAN_SET_PARAM) && (connect)) { 37063737Shx147065 (void) pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0); 37073737Shx147065 if (pcwl_p->pcwl_connect_timeout_id != 0) { 37083737Shx147065 (void) untimeout(pcwl_p->pcwl_connect_timeout_id); 37093737Shx147065 pcwl_p->pcwl_connect_timeout_id = 0; 37103737Shx147065 } 37113737Shx147065 pcwl_p->pcwl_connect_timeout_id = timeout(pcwl_connect_timeout, 37123737Shx147065 pcwl_p, 2 * drv_usectohz(1000000)); 37133737Shx147065 } 37143737Shx147065 return (ret); 37153737Shx147065 } 37163737Shx147065 37173737Shx147065 static void 37183737Shx147065 pcwl_wlan_ioctl(pcwl_maci_t *pcwl_p, queue_t *wq, mblk_t *mp, uint32_t cmd) 37193737Shx147065 { 37203737Shx147065 37213737Shx147065 struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 37223737Shx147065 wldp_t *infp; 37233737Shx147065 uint32_t len, ret; 37243737Shx147065 mblk_t *mp1; 37253737Shx147065 37263737Shx147065 /* 37273737Shx147065 * sanity check 37283737Shx147065 */ 37293737Shx147065 if (iocp->ioc_count == 0 || !(mp1 = mp->b_cont)) { 37303737Shx147065 miocnak(wq, mp, 0, EINVAL); 37313737Shx147065 return; 37323737Shx147065 } 37333737Shx147065 37343737Shx147065 /* 37353737Shx147065 * assuming single data block 37363737Shx147065 */ 37373737Shx147065 if (mp1->b_cont) { 37383737Shx147065 freemsg(mp1->b_cont); 37393737Shx147065 mp1->b_cont = NULL; 37403737Shx147065 } 37413737Shx147065 37423737Shx147065 /* 37433737Shx147065 * we will overwrite everything 37443737Shx147065 */ 37453737Shx147065 mp1->b_wptr = mp1->b_rptr; 37463737Shx147065 37473737Shx147065 infp = (wldp_t *)mp1->b_rptr; 37483737Shx147065 PCWLDBG((CE_NOTE, "pcwl: wldp->length=0x%x\n", infp->wldp_length)); 37493737Shx147065 PCWLDBG((CE_NOTE, "pcwl: wldp->type =:%s\n", 37503737Shx147065 infp->wldp_type == NET_802_11 ? "NET_802_11" : "Unknown")); 37513737Shx147065 PCWLDBG((CE_NOTE, "pcwl: wldp->id=0x%x\n", infp->wldp_id)); 37523737Shx147065 PCWLDBG((CE_NOTE, "pcwl: wldp->result=0x%x\n", infp->wldp_result)); 37533737Shx147065 37543737Shx147065 ret = pcwl_getset(mp1, pcwl_p, cmd); 37553737Shx147065 len = msgdsize(mp1); 37563737Shx147065 PCWLDBG((CE_CONT, "pcwl: ioctl message length = %d\n", len)); 37573737Shx147065 miocack(wq, mp, len, ret); 37583737Shx147065 37593737Shx147065 } 37603737Shx147065 37613737Shx147065 37623737Shx147065 static void 37633737Shx147065 pcwl_ioctl(void *arg, queue_t *wq, mblk_t *mp) 37643737Shx147065 { 37653737Shx147065 struct iocblk *iocp; 37663737Shx147065 uint32_t cmd, ret; 37673737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg; 37683737Shx147065 boolean_t need_privilege = B_TRUE; 37693737Shx147065 37703737Shx147065 /* 37713737Shx147065 * Validate the command before bothering with the mutexen ... 37723737Shx147065 */ 37733737Shx147065 iocp = (struct iocblk *)mp->b_rptr; 37743737Shx147065 iocp->ioc_error = 0; 37753737Shx147065 cmd = iocp->ioc_cmd; 37763737Shx147065 switch (cmd) { 37773737Shx147065 default: 37783737Shx147065 PCWLDBG((CE_CONT, "pcwl_ioctl: unknown cmd 0x%x", cmd)); 37793737Shx147065 miocnak(wq, mp, 0, EINVAL); 37803737Shx147065 return; 37813737Shx147065 case WLAN_GET_PARAM: 37823737Shx147065 need_privilege = B_TRUE; 37833737Shx147065 break; 37843737Shx147065 case WLAN_SET_PARAM: 37853737Shx147065 case WLAN_COMMAND: 37863737Shx147065 break; 37873737Shx147065 } 37883737Shx147065 /* 37893737Shx147065 * Check net_config privilege 37903737Shx147065 */ 37913737Shx147065 if (need_privilege) { 37923737Shx147065 if (ret = secpolicy_net_config(iocp->ioc_cr, B_FALSE)) { 37933737Shx147065 miocnak(wq, mp, 0, ret); 37943737Shx147065 return; 37953737Shx147065 } 37963737Shx147065 } 37973737Shx147065 pcwl_wlan_ioctl(pcwl_p, wq, mp, cmd); 37983737Shx147065 } 3799