13737Shx147065 /* 2*8801SQuaker.Fang@Sun.COM * Copyright 2009 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 #include <sys/conf.h> 393737Shx147065 #include <sys/ddi.h> 403737Shx147065 #include <sys/sunddi.h> 413737Shx147065 #include <sys/dlpi.h> 423737Shx147065 #include <sys/ethernet.h> 433737Shx147065 #include <sys/strsun.h> 443737Shx147065 #include <sys/stat.h> 453737Shx147065 #include <sys/byteorder.h> 463737Shx147065 #include <sys/pccard.h> 473737Shx147065 #include <sys/pci.h> 483737Shx147065 #include <sys/policy.h> 498275SEric Cheng #include <sys/mac_provider.h> 503737Shx147065 #include <sys/stream.h> 513737Shx147065 #include <inet/common.h> 523737Shx147065 #include <inet/nd.h> 533737Shx147065 #include <inet/mi.h> 543737Shx147065 553737Shx147065 #include "pcwl.h" 563737Shx147065 #include <sys/mac_wifi.h> 573737Shx147065 #include <inet/wifi_ioctl.h> 583737Shx147065 593737Shx147065 #ifdef DEBUG 603737Shx147065 #define PCWL_DBG_BASIC 0x1 613737Shx147065 #define PCWL_DBG_INFO 0x2 623737Shx147065 #define PCWL_DBG_SEND 0x4 633737Shx147065 #define PCWL_DBG_RCV 0x8 643737Shx147065 #define PCWL_DBG_LINKINFO 0x10 653737Shx147065 uint32_t pcwl_debug = 0; 663737Shx147065 #define PCWLDBG(x) \ 673737Shx147065 if (pcwl_debug & PCWL_DBG_BASIC) cmn_err x 683737Shx147065 #else 693737Shx147065 #define PCWLDBG(x) 703737Shx147065 #endif 713737Shx147065 723737Shx147065 /* for pci card */ 733737Shx147065 static ddi_device_acc_attr_t accattr = { 743737Shx147065 DDI_DEVICE_ATTR_V0, 753737Shx147065 DDI_NEVERSWAP_ACC, 763737Shx147065 DDI_STRICTORDER_ACC, 773737Shx147065 DDI_DEFAULT_ACC 783737Shx147065 }; 793737Shx147065 803737Shx147065 void *pcwl_soft_state_p = NULL; 813737Shx147065 static int pcwl_device_type; 823737Shx147065 838410SWang.Lin@Sun.COM static int pcwl_m_setprop(void *arg, const char *pr_name, 848410SWang.Lin@Sun.COM mac_prop_id_t wldp_pr_num, uint_t wldp_length, 858410SWang.Lin@Sun.COM const void *wldp_buf); 868410SWang.Lin@Sun.COM static int pcwl_m_getprop(void *arg, const char *pr_name, 878410SWang.Lin@Sun.COM mac_prop_id_t wldp_pr_num, uint_t pr_flags, 888410SWang.Lin@Sun.COM uint_t wldp_length, void *wldp_buf, uint_t *perm); 898410SWang.Lin@Sun.COM 903737Shx147065 mac_callbacks_t pcwl_m_callbacks = { 918410SWang.Lin@Sun.COM MC_IOCTL | MC_SETPROP | MC_GETPROP, 923737Shx147065 pcwl_gstat, 933737Shx147065 pcwl_start, 943737Shx147065 pcwl_stop, 953737Shx147065 pcwl_prom, 963737Shx147065 pcwl_sdmulti, 973737Shx147065 pcwl_saddr, 983737Shx147065 pcwl_tx, 998410SWang.Lin@Sun.COM pcwl_ioctl, 1008410SWang.Lin@Sun.COM NULL, 1018410SWang.Lin@Sun.COM NULL, 1028410SWang.Lin@Sun.COM NULL, 1038410SWang.Lin@Sun.COM pcwl_m_setprop, 1048410SWang.Lin@Sun.COM pcwl_m_getprop 1053737Shx147065 }; 1063737Shx147065 1073737Shx147065 static char *pcwl_name_str = "pcwl"; 1083737Shx147065 109*8801SQuaker.Fang@Sun.COM #ifdef __sparc 110*8801SQuaker.Fang@Sun.COM #define pcwl_quiesce ddi_quiesce_not_supported 111*8801SQuaker.Fang@Sun.COM #else 112*8801SQuaker.Fang@Sun.COM static int pcwl_quiesce(dev_info_t *); 113*8801SQuaker.Fang@Sun.COM #endif 114*8801SQuaker.Fang@Sun.COM 1153737Shx147065 DDI_DEFINE_STREAM_OPS(pcwl_dev_ops, nulldev, pcwl_probe, pcwl_attach, 116*8801SQuaker.Fang@Sun.COM pcwl_detach, nodev, NULL, D_MP, NULL, pcwl_quiesce); 1173737Shx147065 1183737Shx147065 extern struct mod_ops mod_driverops; 1193737Shx147065 static struct modldrv modldrv = { 1203737Shx147065 &mod_driverops, 1213737Shx147065 "Lucent/PRISM-II 802.11b driver", 1223737Shx147065 &pcwl_dev_ops 1233737Shx147065 }; 1243737Shx147065 1253737Shx147065 static struct modlinkage modlinkage = { 1263737Shx147065 MODREV_1, (void *)&modldrv, NULL 1273737Shx147065 }; 1283737Shx147065 1293737Shx147065 int 1303737Shx147065 _init(void) 1313737Shx147065 { 1323737Shx147065 int stat; 1333737Shx147065 1343737Shx147065 /* Allocate soft state */ 1353737Shx147065 if ((stat = ddi_soft_state_init(&pcwl_soft_state_p, 1363737Shx147065 sizeof (pcwl_maci_t), N_PCWL)) != DDI_SUCCESS) 1373737Shx147065 return (stat); 1383737Shx147065 1393737Shx147065 mac_init_ops(&pcwl_dev_ops, "pcwl"); 1403737Shx147065 wl_frame_default.wl_dat[0] = htons(WL_SNAP_WORD0); 1413737Shx147065 wl_frame_default.wl_dat[1] = htons(WL_SNAP_WORD1); 1423737Shx147065 stat = mod_install(&modlinkage); 1433737Shx147065 if (stat != DDI_SUCCESS) { 1443737Shx147065 mac_fini_ops(&pcwl_dev_ops); 1453737Shx147065 ddi_soft_state_fini(&pcwl_soft_state_p); 1463737Shx147065 } 1473737Shx147065 return (stat); 1483737Shx147065 } 1493737Shx147065 1503737Shx147065 int 1513737Shx147065 _fini(void) 1523737Shx147065 { 1533737Shx147065 int stat; 1543737Shx147065 1553737Shx147065 if ((stat = mod_remove(&modlinkage)) != DDI_SUCCESS) 1563737Shx147065 return (stat); 1573737Shx147065 mac_fini_ops(&pcwl_dev_ops); 1583737Shx147065 ddi_soft_state_fini(&pcwl_soft_state_p); 1593737Shx147065 1603737Shx147065 return (stat); 1613737Shx147065 } 1623737Shx147065 1633737Shx147065 int 1643737Shx147065 _info(struct modinfo *modinfop) 1653737Shx147065 { 1663737Shx147065 return (mod_info(&modlinkage, modinfop)); 1673737Shx147065 } 1683737Shx147065 1693737Shx147065 static int 1703737Shx147065 pcwl_probe(dev_info_t *dip) 1713737Shx147065 { 1723737Shx147065 int len, ret; 1733737Shx147065 char *buf; 1743737Shx147065 dev_info_t *pdip = ddi_get_parent(dip); 1753737Shx147065 1763737Shx147065 ret = ddi_getlongprop(DDI_DEV_T_ANY, pdip, 0, "device_type", 1773737Shx147065 (caddr_t)&buf, &len); 1783737Shx147065 if (ret != DDI_SUCCESS) 1793737Shx147065 return (DDI_PROBE_FAILURE); 1803737Shx147065 1813737Shx147065 PCWLDBG((CE_NOTE, "pcwl probe: device_type %s\n", buf)); 1823737Shx147065 if ((strcmp(buf, "pccard") == 0) || (strcmp(buf, "pcmcia") == 0)) { 1833737Shx147065 pcwl_device_type = PCWL_DEVICE_PCCARD; 1843737Shx147065 ret = DDI_PROBE_SUCCESS; 1853737Shx147065 } else if (strcmp(buf, "pci") == 0) { 1863737Shx147065 pcwl_device_type = PCWL_DEVICE_PCI; 1873737Shx147065 ret = DDI_PROBE_SUCCESS; 1883737Shx147065 } else { 1893737Shx147065 ret = DDI_PROBE_FAILURE; 1903737Shx147065 } 1913737Shx147065 kmem_free(buf, len); 1923737Shx147065 return (ret); 1933737Shx147065 } 1943737Shx147065 1953737Shx147065 static int 1963737Shx147065 pcwl_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 1973737Shx147065 { 1983737Shx147065 int ret, i; 1993737Shx147065 int instance; 2003737Shx147065 uint16_t stat; 2013737Shx147065 uint32_t err; 2023737Shx147065 pcwl_maci_t *pcwl_p; 2033737Shx147065 wifi_data_t wd = { 0 }; 2043737Shx147065 mac_register_t *macp; 2053737Shx147065 modify_config_t cfgmod; 2063737Shx147065 char strbuf[256]; 2073737Shx147065 2083737Shx147065 PCWLDBG((CE_NOTE, "pcwl attach: dip=0x%p cmd=%x\n", (void *)dip, cmd)); 2093737Shx147065 if (cmd != DDI_ATTACH) 2103737Shx147065 goto attach_fail1; 2113737Shx147065 /* 2123737Shx147065 * Allocate soft state associated with this instance. 2133737Shx147065 */ 2143737Shx147065 if (ddi_soft_state_zalloc(pcwl_soft_state_p, 2153737Shx147065 ddi_get_instance(dip)) != DDI_SUCCESS) { 2163737Shx147065 cmn_err(CE_CONT, "pcwl attach: alloc softstate failed\n"); 2173737Shx147065 goto attach_fail1; 2183737Shx147065 } 2193737Shx147065 pcwl_p = (pcwl_maci_t *)ddi_get_soft_state(pcwl_soft_state_p, 2203737Shx147065 ddi_get_instance(dip)); 2213737Shx147065 pcwl_p->pcwl_device_type = pcwl_device_type; 2223737Shx147065 if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) { 2233737Shx147065 if (ddi_regs_map_setup(dip, 0, 2243737Shx147065 (caddr_t *)&pcwl_p->pcwl_cfg_base, 0, 0, 2253737Shx147065 &accattr, &pcwl_p->pcwl_cfg_handle) != DDI_SUCCESS) { 2263737Shx147065 cmn_err(CE_WARN, "pcwl(pci) attach: pci_regs_map_setup" 2273737Shx147065 " failed\n"); 2283737Shx147065 goto attach_fail2; 2293737Shx147065 } 2303737Shx147065 2313737Shx147065 stat = ddi_get16(pcwl_p->pcwl_cfg_handle, 2323737Shx147065 (uint16_t *)(pcwl_p->pcwl_cfg_base + PCI_CONF_COMM)); 2333737Shx147065 stat |= (PCI_COMM_IO | PCI_COMM_MAE); 2343737Shx147065 ddi_put16(pcwl_p->pcwl_cfg_handle, 2353737Shx147065 (uint16_t *)(pcwl_p->pcwl_cfg_base + PCI_CONF_COMM), stat); 2363737Shx147065 stat = ddi_get16(pcwl_p->pcwl_cfg_handle, 2373737Shx147065 (uint16_t *)(pcwl_p->pcwl_cfg_base + PCI_CONF_COMM)); 2383737Shx147065 if ((stat & (PCI_COMM_IO | PCI_COMM_MAE)) != 2393737Shx147065 (PCI_COMM_IO | PCI_COMM_MAE)) { 2403737Shx147065 cmn_err(CE_WARN, "pcwl(pci) attach: pci command" 2413737Shx147065 " reg enable failed\n"); 2423737Shx147065 goto attach_fail2a; 2433737Shx147065 } 2443737Shx147065 2453737Shx147065 2463737Shx147065 if (ddi_regs_map_setup(dip, 1, (caddr_t *)&pcwl_p->pcwl_bar, 2473737Shx147065 0, 0, &accattr, (ddi_acc_handle_t *)&pcwl_p->pcwl_handle) 2483737Shx147065 != DDI_SUCCESS) { 2493737Shx147065 cmn_err(CE_WARN, "pcwl(pci) attach: pci_regs_map_setup" 2503737Shx147065 " failed\n"); 2513737Shx147065 goto attach_fail2a; 2523737Shx147065 } 2533737Shx147065 PCWLDBG((CE_NOTE, "pcwl(pci): regs_map_setup,bar=%p\n", 2543737Shx147065 (void *)pcwl_p->pcwl_bar)); 2553737Shx147065 2563737Shx147065 /* 2573737Shx147065 * tricky! copy from freebsd code. 2583737Shx147065 */ 2593737Shx147065 PCWL_WRITE(pcwl_p, 0x26, 0x80); 2603737Shx147065 drv_usecwait(500000); 2613737Shx147065 PCWL_WRITE(pcwl_p, 0x26, 0x0); 2623737Shx147065 drv_usecwait(500000); 2633737Shx147065 2643737Shx147065 for (i = 0; i < WL_TIMEOUT; i++) { 2653737Shx147065 PCWL_READ(pcwl_p, 0x0, stat); 2663737Shx147065 if (stat & WL_CMD_BUSY) 2673737Shx147065 drv_usecwait(10); 2683737Shx147065 else 2693737Shx147065 break; 2703737Shx147065 } 2713737Shx147065 if (i == WL_TIMEOUT) { 2723737Shx147065 cmn_err(CE_WARN, "pcwl(pci) attach: hardware init" 2733737Shx147065 " failed\n"); 2743737Shx147065 goto attach_fail3; 2753737Shx147065 } 2763737Shx147065 2773737Shx147065 /* 2783737Shx147065 * magic number verification. 2793737Shx147065 * tricky! copy from freebsd code. 2803737Shx147065 */ 2813737Shx147065 PCWL_WRITE(pcwl_p, 0x28, 0x4a2d); 2823737Shx147065 PCWL_READ(pcwl_p, 0x28, stat); 2833737Shx147065 PCWLDBG((CE_NOTE, "pcwl(pci):magic number = %x\n", stat)); 2843737Shx147065 if (stat != 0x4a2d) { 2853737Shx147065 cmn_err(CE_WARN, "pcwl(pci) attach: magic verify" 2863737Shx147065 " failed\n"); 2873737Shx147065 goto attach_fail3; 2883737Shx147065 } 2893737Shx147065 } 2903737Shx147065 pcwl_p->pcwl_dip = dip; 2913737Shx147065 pcwl_p->pcwl_flag = 0; 2923737Shx147065 pcwl_p->pcwl_socket = ddi_getprop(DDI_DEV_T_NONE, dip, 2933737Shx147065 DDI_PROP_DONTPASS, "socket", -1); 2943737Shx147065 pcwl_p->pcwl_reschedule_need = B_FALSE; 2953737Shx147065 2963737Shx147065 if (ddi_get_iblock_cookie(dip, 2973737Shx147065 0, &pcwl_p->pcwl_ib_cookie) != DDI_SUCCESS) { 2983737Shx147065 cmn_err(CE_WARN, "pcwl attach: get_iblk_cookie failed\n"); 2993737Shx147065 goto attach_fail3; 3003737Shx147065 } 3013737Shx147065 3023737Shx147065 mutex_init(&pcwl_p->pcwl_glock, NULL, MUTEX_DRIVER, 3033737Shx147065 pcwl_p->pcwl_ib_cookie); 3043737Shx147065 mutex_init(&pcwl_p->pcwl_scanlist_lock, NULL, MUTEX_DRIVER, 3053737Shx147065 pcwl_p->pcwl_ib_cookie); 3063737Shx147065 mutex_init(&pcwl_p->pcwl_txring.wl_tx_lock, NULL, MUTEX_DRIVER, 3073737Shx147065 pcwl_p->pcwl_ib_cookie); 3083737Shx147065 3093737Shx147065 if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) { 3103737Shx147065 if (ret = ddi_add_intr(dip, 0, NULL, NULL, 3113737Shx147065 pcwl_intr, (caddr_t)pcwl_p)) { 3123737Shx147065 cmn_err(CE_NOTE, "pcwl(pci) attach: add intr failed\n"); 3133737Shx147065 goto attach_fail3a; 3143737Shx147065 } 3153737Shx147065 } else if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCCARD) { 3163737Shx147065 if (ret = pcwl_register_cs(dip, pcwl_p)) { 3173737Shx147065 cmn_err(CE_WARN, "pcwl attach(pccard): " 3183737Shx147065 "register_cs err %x\n", ret); 3193737Shx147065 goto attach_fail3a; 3203737Shx147065 } 3213737Shx147065 } else { 3223737Shx147065 cmn_err(CE_WARN, "pcwl attach: unsupported device type\n"); 3233737Shx147065 goto attach_fail3a; 3243737Shx147065 } 3253737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 3263737Shx147065 if (ret = pcwl_reset_backend(pcwl_p)) { 3273737Shx147065 cmn_err(CE_WARN, "pcwl attach: reset_backend failed %x\n", ret); 3283737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 3293737Shx147065 goto attach_fail4; 3303737Shx147065 } 3313737Shx147065 if (ret = pcwl_get_cap(pcwl_p)) { /* sets macaddr for mac_register */ 3323737Shx147065 cmn_err(CE_WARN, "pcwl attach: get_cap failed %x\n", ret); 3333737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 3343737Shx147065 goto attach_fail4; 3353737Shx147065 } 3363737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 3373737Shx147065 /* 3383737Shx147065 * Provide initial settings for the WiFi plugin; whenever this 3393737Shx147065 * information changes, we need to call mac_pdata_update() 3403737Shx147065 */ 3413737Shx147065 wd.wd_secalloc = WIFI_SEC_NONE; 3423737Shx147065 wd.wd_opmode = IEEE80211_M_STA; 3433737Shx147065 3443737Shx147065 macp = mac_alloc(MAC_VERSION); 3453737Shx147065 if (macp == NULL) { 3463737Shx147065 PCWLDBG((CE_NOTE, "pcwl attach: " 3473737Shx147065 "MAC version mismatch\n")); 3483737Shx147065 goto attach_fail4; 3493737Shx147065 } 3503737Shx147065 3513737Shx147065 macp->m_type_ident = MAC_PLUGIN_IDENT_WIFI; 3523737Shx147065 macp->m_driver = pcwl_p; 3533737Shx147065 macp->m_dip = dip; 3543737Shx147065 macp->m_src_addr = pcwl_p->pcwl_mac_addr; 3553737Shx147065 macp->m_callbacks = &pcwl_m_callbacks; 3563737Shx147065 macp->m_min_sdu = 0; 3573737Shx147065 macp->m_max_sdu = IEEE80211_MTU; 3583737Shx147065 macp->m_pdata = &wd; 3593737Shx147065 macp->m_pdata_size = sizeof (wd); 3603737Shx147065 3613737Shx147065 err = mac_register(macp, &pcwl_p->pcwl_mh); 3623737Shx147065 mac_free(macp); 3633737Shx147065 if (err != 0) { 3643737Shx147065 PCWLDBG((CE_NOTE, "pcwl attach: " 3653737Shx147065 "mac_register err\n")); 3663737Shx147065 goto attach_fail4; 3673737Shx147065 } 3683737Shx147065 3693737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 3703737Shx147065 if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCCARD) { 3713737Shx147065 /* 3723737Shx147065 * turn on CS interrupt 3733737Shx147065 */ 3743737Shx147065 cfgmod.Attributes = CONF_ENABLE_IRQ_STEERING | 3753737Shx147065 CONF_IRQ_CHANGE_VALID; 3763737Shx147065 cfgmod.Vpp1 = 0; 3773737Shx147065 cfgmod.Vpp2 = 0; 3783737Shx147065 (void) csx_ModifyConfiguration(pcwl_p->pcwl_chdl, &cfgmod); 3793737Shx147065 3803737Shx147065 } 3813737Shx147065 if (ret = pcwl_init_nicmem(pcwl_p)) { 3823737Shx147065 cmn_err(CE_WARN, "pcwl(pccard) attach: pcwl_init_nicmem" 3833737Shx147065 " failed %x\n", ret); 3843737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 3853737Shx147065 goto attach_fail5; 3863737Shx147065 } 3873737Shx147065 pcwl_chip_type(pcwl_p); 3883737Shx147065 if (ret = pcwl_loaddef_rf(pcwl_p)) { 3893737Shx147065 cmn_err(CE_WARN, "pcwl attach: config_rf failed%x\n", ret); 3903737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 3913737Shx147065 goto attach_fail5; 3923737Shx147065 } 3933737Shx147065 (void) pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0); 3943737Shx147065 pcwl_stop_locked(pcwl_p); /* leaves interface down */ 3953737Shx147065 list_create(&pcwl_p->pcwl_scan_list, sizeof (wl_scan_list_t), 3963737Shx147065 offsetof(wl_scan_list_t, wl_scan_node)); 3973737Shx147065 pcwl_p->pcwl_scan_num = 0; 3983737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 3993737Shx147065 pcwl_p->pcwl_scanlist_timeout_id = timeout(pcwl_scanlist_timeout, 4003737Shx147065 pcwl_p, drv_usectohz(1000000)); 4013737Shx147065 instance = ddi_get_instance(dip); 4023737Shx147065 (void) snprintf(strbuf, sizeof (strbuf), "pcwl%d", instance); 4033737Shx147065 if (ddi_create_minor_node(dip, strbuf, S_IFCHR, 4043737Shx147065 instance + 1, DDI_NT_NET_WIFI, 0) != DDI_SUCCESS) { 4053737Shx147065 goto attach_fail6; 4063737Shx147065 } 4073737Shx147065 pcwl_p->pcwl_flag |= PCWL_ATTACHED; 4083737Shx147065 if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) { 4093737Shx147065 pcwl_p->pcwl_flag |= PCWL_CARD_READY; 4103737Shx147065 } 4113737Shx147065 return (DDI_SUCCESS); 4123737Shx147065 attach_fail6: 4133737Shx147065 if (pcwl_p->pcwl_scanlist_timeout_id != 0) { 4143737Shx147065 (void) untimeout(pcwl_p->pcwl_scanlist_timeout_id); 4153737Shx147065 pcwl_p->pcwl_scanlist_timeout_id = 0; 4163737Shx147065 } 4173737Shx147065 list_destroy(&pcwl_p->pcwl_scan_list); 4183737Shx147065 attach_fail5: 4193737Shx147065 (void) mac_unregister(pcwl_p->pcwl_mh); 4203737Shx147065 attach_fail4: 4213737Shx147065 if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) { 4223737Shx147065 ddi_remove_intr(dip, 0, pcwl_p->pcwl_ib_cookie); 4233737Shx147065 } else if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCCARD) { 4243737Shx147065 pcwl_unregister_cs(pcwl_p); 4253737Shx147065 } 4263737Shx147065 attach_fail3a: 4273737Shx147065 pcwl_destroy_locks(pcwl_p); 4283737Shx147065 attach_fail3: 4293737Shx147065 if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) 4303737Shx147065 ddi_regs_map_free(&pcwl_p->pcwl_handle); 4313737Shx147065 attach_fail2a: 4323737Shx147065 if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) 4333737Shx147065 ddi_regs_map_free(&pcwl_p->pcwl_cfg_handle); 4343737Shx147065 attach_fail2: 4353737Shx147065 ddi_soft_state_free(pcwl_soft_state_p, ddi_get_instance(dip)); 4363737Shx147065 attach_fail1: 4373737Shx147065 return (DDI_FAILURE); 4383737Shx147065 } 4393737Shx147065 4403737Shx147065 static int 4413737Shx147065 pcwl_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 4423737Shx147065 { 4433737Shx147065 pcwl_maci_t *pcwl_p; 4443737Shx147065 wl_scan_list_t *scan_item0; 4453737Shx147065 int ret; 4463737Shx147065 pcwl_p = ddi_get_soft_state(pcwl_soft_state_p, ddi_get_instance(dip)); 4473737Shx147065 4483737Shx147065 PCWLDBG((CE_NOTE, "pcwl detach: dip=0x%p cmd=%x\n", (void *)dip, cmd)); 4493737Shx147065 if (cmd != DDI_DETACH) 4503737Shx147065 return (DDI_FAILURE); 4513737Shx147065 if (!(pcwl_p->pcwl_flag & PCWL_ATTACHED)) 4523737Shx147065 return (DDI_FAILURE); 4533737Shx147065 4547507SXinghua.Wen@Sun.COM ret = mac_disable(pcwl_p->pcwl_mh); 4557507SXinghua.Wen@Sun.COM if (ret != 0) 4567507SXinghua.Wen@Sun.COM return (DDI_FAILURE); 4577507SXinghua.Wen@Sun.COM 4583737Shx147065 if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) { 4593737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 4603737Shx147065 (void) pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0); 4613737Shx147065 PCWL_DISABLE_INTR(pcwl_p); 4623737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 4633737Shx147065 } 4643737Shx147065 if (pcwl_p->pcwl_scanlist_timeout_id != 0) { 4653737Shx147065 (void) untimeout(pcwl_p->pcwl_scanlist_timeout_id); 4663737Shx147065 pcwl_p->pcwl_scanlist_timeout_id = 0; 4673737Shx147065 } 4683737Shx147065 if (pcwl_p->pcwl_connect_timeout_id != 0) { 4693737Shx147065 (void) untimeout(pcwl_p->pcwl_connect_timeout_id); 4703737Shx147065 pcwl_p->pcwl_connect_timeout_id = 0; 4713737Shx147065 } 4723737Shx147065 mutex_enter(&pcwl_p->pcwl_scanlist_lock); 4733737Shx147065 scan_item0 = list_head(&pcwl_p->pcwl_scan_list); 4743737Shx147065 while (scan_item0) { 4753737Shx147065 pcwl_delete_scan_item(pcwl_p, scan_item0); 4763737Shx147065 scan_item0 = list_head(&pcwl_p->pcwl_scan_list); 4773737Shx147065 } 4783737Shx147065 list_destroy(&pcwl_p->pcwl_scan_list); 4793737Shx147065 mutex_exit(&pcwl_p->pcwl_scanlist_lock); 4807507SXinghua.Wen@Sun.COM (void) mac_unregister(pcwl_p->pcwl_mh); 4813737Shx147065 4823737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 4833737Shx147065 if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) { 4843737Shx147065 ddi_remove_intr(dip, 0, pcwl_p->pcwl_ib_cookie); 4853737Shx147065 ddi_regs_map_free(&pcwl_p->pcwl_handle); 4863737Shx147065 ddi_regs_map_free(&pcwl_p->pcwl_cfg_handle); 4873737Shx147065 } else if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCCARD) { 4883737Shx147065 pcwl_unregister_cs(pcwl_p); 4893737Shx147065 } 4903737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 4913737Shx147065 pcwl_destroy_locks(pcwl_p); 4923737Shx147065 ddi_remove_minor_node(dip, NULL); 4933737Shx147065 ddi_soft_state_free(pcwl_soft_state_p, ddi_get_instance(dip)); 4943737Shx147065 return (DDI_SUCCESS); 4953737Shx147065 } 4963737Shx147065 4973737Shx147065 /* 4983737Shx147065 * card services and event handlers 4993737Shx147065 */ 5003737Shx147065 static int 5013737Shx147065 pcwl_register_cs(dev_info_t *dip, pcwl_maci_t *pcwl_p) 5023737Shx147065 { 5033737Shx147065 int ret; 5043737Shx147065 client_reg_t cr; 5053737Shx147065 client_handle_t chdl; /* uint encoding of socket, function, client */ 5063737Shx147065 get_status_t card_status; 5073737Shx147065 request_socket_mask_t sock_req; 5083737Shx147065 5093737Shx147065 bzero(&cr, sizeof (cr)); 5103737Shx147065 cr.Attributes = INFO_IO_CLIENT|INFO_CARD_EXCL|INFO_CARD_SHARE; 5113737Shx147065 cr.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | 5123737Shx147065 CS_EVENT_REGISTRATION_COMPLETE | CS_EVENT_CARD_REMOVAL_LOWP | 5133737Shx147065 CS_EVENT_CARD_READY | CS_EVENT_PM_RESUME | 5143737Shx147065 CS_EVENT_PM_SUSPEND | CS_EVENT_CLIENT_INFO; 5153737Shx147065 cr.event_callback_args.client_data = pcwl_p; 5163737Shx147065 cr.Version = CS_VERSION; 5173737Shx147065 cr.event_handler = (csfunction_t *)pcwl_ev_hdlr; 5183737Shx147065 cr.dip = dip; 5193737Shx147065 (void) strcpy(cr.driver_name, pcwl_name_str); 5203737Shx147065 if (ret = csx_RegisterClient(&chdl, &cr)) { 5213737Shx147065 cmn_err(CE_WARN, "pcwl: RegisterClient failed %x\n", ret); 5223737Shx147065 goto regcs_ret; 5233737Shx147065 } 5243737Shx147065 pcwl_p->pcwl_chdl = chdl; 5253737Shx147065 5263737Shx147065 bzero(&card_status, sizeof (card_status)); 5273737Shx147065 (void) csx_GetStatus(chdl, &card_status); 5283737Shx147065 PCWLDBG((CE_NOTE, 5293737Shx147065 "pcwl: register_cs: Sock=%x CState=%x SState=%x rState=%x\n", 5303737Shx147065 card_status.Socket, card_status.CardState, 5313737Shx147065 card_status.SocketState, card_status.raw_CardState)); 5323737Shx147065 if (!(card_status.CardState & CS_STATUS_CARD_INSERTED)) { 5333737Shx147065 /* card is not present, why are we attaching ? */ 5343737Shx147065 ret = CS_NO_CARD; 5353737Shx147065 goto regcs_unreg; 5363737Shx147065 } 5373737Shx147065 cv_init(&pcwl_p->pcwl_cscv, NULL, CV_DRIVER, NULL); 5383737Shx147065 mutex_init(&pcwl_p->pcwl_cslock, NULL, MUTEX_DRIVER, *cr.iblk_cookie); 5393737Shx147065 mutex_enter(&pcwl_p->pcwl_cslock); 5403737Shx147065 if (ret = csx_MapLogSocket(chdl, &pcwl_p->pcwl_log_sock)) { 5413737Shx147065 cmn_err(CE_WARN, "pcwl: MapLogSocket failed %x\n", ret); 5423737Shx147065 goto regcs_fail; 5433737Shx147065 } 5443737Shx147065 PCWLDBG((CE_NOTE, 5453737Shx147065 "pcwl: register_cs: LogSock=%x PhyAdapter=%x PhySock=%x\n", 5463737Shx147065 pcwl_p->pcwl_log_sock.LogSocket, 5473737Shx147065 pcwl_p->pcwl_log_sock.PhyAdapter, 5483737Shx147065 pcwl_p->pcwl_log_sock.PhySocket)); 5493737Shx147065 /* turn on initialization events */ 5503737Shx147065 sock_req.Socket = 0; 5513737Shx147065 sock_req.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | 5523737Shx147065 CS_EVENT_REGISTRATION_COMPLETE; 5533737Shx147065 if (ret = csx_RequestSocketMask(chdl, &sock_req)) { 5543737Shx147065 cmn_err(CE_WARN, "pcwl: RequestSocketMask failed %x\n", ret); 5553737Shx147065 goto regcs_fail; 5563737Shx147065 } 5573737Shx147065 /* wait for and process card insertion events */ 5583737Shx147065 while (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) 5593737Shx147065 cv_wait(&pcwl_p->pcwl_cscv, &pcwl_p->pcwl_cslock); 5603737Shx147065 mutex_exit(&pcwl_p->pcwl_cslock); 5613737Shx147065 5623737Shx147065 pcwl_p->pcwl_flag |= PCWL_CS_REGISTERED; 5633737Shx147065 return (PCWL_SUCCESS); 5643737Shx147065 regcs_fail: 5653737Shx147065 mutex_destroy(&pcwl_p->pcwl_cslock); 5663737Shx147065 cv_destroy(&pcwl_p->pcwl_cscv); 5673737Shx147065 regcs_unreg: 5683737Shx147065 (void) csx_DeregisterClient(chdl); 5693737Shx147065 regcs_ret: 5703737Shx147065 pcwl_p->pcwl_flag &= ~PCWL_CS_REGISTERED; 5713737Shx147065 return (ret); 5723737Shx147065 } 5733737Shx147065 5743737Shx147065 static void 5753737Shx147065 pcwl_unregister_cs(pcwl_maci_t *pcwl_p) 5763737Shx147065 { 5773737Shx147065 int ret; 5783737Shx147065 release_socket_mask_t mask; 5793737Shx147065 mask.Socket = pcwl_p->pcwl_socket; 5803737Shx147065 5813737Shx147065 /* 5823737Shx147065 * The card service not registered means register_cs function 5833737Shx147065 * doesnot return TRUE. Then all the lelated resource has been 5843737Shx147065 * released in register_cs. 5853737Shx147065 */ 5863737Shx147065 if (!(pcwl_p->pcwl_flag | PCWL_CS_REGISTERED)) 5873737Shx147065 return; 5883737Shx147065 5893737Shx147065 if (ret = csx_ReleaseSocketMask(pcwl_p->pcwl_chdl, &mask)) 5903737Shx147065 cmn_err(CE_WARN, "pcwl: ReleaseSocket mask failed %x\n", ret); 5913737Shx147065 5923737Shx147065 if (pcwl_p->pcwl_flag & PCWL_CARD_READY) { 5933737Shx147065 pcwl_card_remove(pcwl_p); 5943737Shx147065 pcwl_p->pcwl_flag &= ~PCWL_CARD_READY; 5953737Shx147065 } 5963737Shx147065 mutex_destroy(&pcwl_p->pcwl_cslock); 5973737Shx147065 cv_destroy(&pcwl_p->pcwl_cscv); 5983737Shx147065 if (ret = csx_DeregisterClient(pcwl_p->pcwl_chdl)) 5993737Shx147065 cmn_err(CE_WARN, "pcwl: Deregister failed %x\n", ret); 6003737Shx147065 } 6013737Shx147065 6023737Shx147065 static void 6033737Shx147065 pcwl_destroy_locks(pcwl_maci_t *pcwl_p) 6043737Shx147065 { 6053737Shx147065 mutex_destroy(&pcwl_p->pcwl_txring.wl_tx_lock); 6063737Shx147065 mutex_destroy(&pcwl_p->pcwl_scanlist_lock); 6073737Shx147065 mutex_destroy(&pcwl_p->pcwl_glock); 6083737Shx147065 } 6093737Shx147065 6103737Shx147065 static int 6113737Shx147065 pcwl_ev_hdlr(event_t event, int priority, event_callback_args_t *arg) 6123737Shx147065 { 6133737Shx147065 int ret = CS_SUCCESS; 6143737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg->client_data; 6153737Shx147065 client_info_t *ci_p = (client_info_t *)&arg->client_info; 6163737Shx147065 6173737Shx147065 mutex_enter(&pcwl_p->pcwl_cslock); 6183737Shx147065 switch (event) { 6193737Shx147065 case CS_EVENT_CARD_INSERTION: 6203737Shx147065 ret = pcwl_card_insert(pcwl_p); 6213737Shx147065 cv_broadcast(&pcwl_p->pcwl_cscv); 6223737Shx147065 break; 6233737Shx147065 case CS_EVENT_REGISTRATION_COMPLETE: 6243737Shx147065 cv_broadcast(&pcwl_p->pcwl_cscv); 6253737Shx147065 break; 6263737Shx147065 case CS_EVENT_CARD_REMOVAL: 6273737Shx147065 if (priority & CS_EVENT_PRI_HIGH) 6283737Shx147065 break; 6293737Shx147065 pcwl_card_remove(pcwl_p); 6303737Shx147065 cv_broadcast(&pcwl_p->pcwl_cscv); 6313737Shx147065 break; 6323737Shx147065 case CS_EVENT_CLIENT_INFO: 6333737Shx147065 if (GET_CLIENT_INFO_SUBSVC(ci_p->Attributes) != 6343737Shx147065 CS_CLIENT_INFO_SUBSVC_CS) 6353737Shx147065 break; 6363737Shx147065 6373737Shx147065 ci_p->Revision = 0x0101; 6383737Shx147065 ci_p->CSLevel = CS_VERSION; 6393737Shx147065 ci_p->RevDate = CS_CLIENT_INFO_MAKE_DATE(9, 12, 14); 6403737Shx147065 (void) strcpy(ci_p->ClientName, PCWL_IDENT_STRING); 6413737Shx147065 (void) strcpy(ci_p->VendorName, CS_SUN_VENDOR_DESCRIPTION); 6423737Shx147065 ci_p->Attributes |= CS_CLIENT_INFO_VALID; 6433737Shx147065 break; 6443737Shx147065 default: 6453737Shx147065 ret = CS_UNSUPPORTED_EVENT; 6463737Shx147065 break; 6473737Shx147065 } 6483737Shx147065 mutex_exit(&pcwl_p->pcwl_cslock); 6493737Shx147065 return (ret); 6503737Shx147065 } 6513737Shx147065 6523737Shx147065 static int 6533737Shx147065 pcwl_card_insert(pcwl_maci_t *pcwl_p) 6543737Shx147065 { 6553737Shx147065 int ret, hi, lo; 6563737Shx147065 tuple_t tuple; 6573737Shx147065 cisparse_t cisparse; 6583737Shx147065 io_req_t io; 6593737Shx147065 irq_req_t irq; 6603737Shx147065 config_req_t cfg; 6613737Shx147065 cistpl_config_t config; 6623737Shx147065 cistpl_cftable_entry_t *tbl_p; 6633737Shx147065 register client_handle_t chdl = pcwl_p->pcwl_chdl; 6643737Shx147065 6653737Shx147065 bzero(&tuple, sizeof (tuple)); 6663737Shx147065 tuple.DesiredTuple = CISTPL_MANFID; 6673737Shx147065 if (ret = csx_GetFirstTuple(chdl, &tuple)) { 6683737Shx147065 cmn_err(CE_WARN, "pcwl: get manufacture id failed %x\n", ret); 6693737Shx147065 goto insert_ret; 6703737Shx147065 } 6713737Shx147065 bzero(&cisparse, sizeof (cisparse)); 6723737Shx147065 if (ret = csx_Parse_CISTPL_MANFID(chdl, &tuple, &cisparse.manfid)) { 6733737Shx147065 cmn_err(CE_WARN, "pcwl: parse manufacture id failed %x\n", ret); 6743737Shx147065 goto insert_ret; 6753737Shx147065 } 6763737Shx147065 6773737Shx147065 /* 6783737Shx147065 * verify manufacture ID 6793737Shx147065 */ 6803737Shx147065 PCWLDBG((CE_NOTE, "pcwl insert: manufacturer_id=%x card=%x\n", 6813737Shx147065 cisparse.manfid.manf, cisparse.manfid.card)); 6823737Shx147065 bzero(&tuple, sizeof (tuple)); 6833737Shx147065 tuple.DesiredTuple = CISTPL_FUNCID; 6843737Shx147065 if (ret = csx_GetFirstTuple(chdl, &tuple)) { 6853737Shx147065 cmn_err(CE_WARN, "pcwl: get function id failed %x\n", ret); 6863737Shx147065 goto insert_ret; 6873737Shx147065 } 6883737Shx147065 bzero(&cisparse, sizeof (cisparse)); 6893737Shx147065 if (ret = csx_Parse_CISTPL_FUNCID(chdl, &tuple, &cisparse.funcid)) { 6903737Shx147065 cmn_err(CE_WARN, "pcwl: parse function id failed %x\n", ret); 6913737Shx147065 goto insert_ret; 6923737Shx147065 } 6933737Shx147065 6943737Shx147065 /* 6953737Shx147065 * verify function ID 6963737Shx147065 */ 6973737Shx147065 PCWLDBG((CE_NOTE, "insert:fun_id=%x\n", cisparse.funcid.function)); 6983737Shx147065 bzero(&tuple, sizeof (tuple)); 6993737Shx147065 tuple.DesiredTuple = CISTPL_CONFIG; 7003737Shx147065 if (ret = csx_GetFirstTuple(chdl, &tuple)) { 7013737Shx147065 cmn_err(CE_WARN, "pcwl: get config failed %x\n", ret); 7023737Shx147065 goto insert_ret; 7033737Shx147065 } 7043737Shx147065 bzero(&config, sizeof (config)); 7053737Shx147065 if (ret = csx_Parse_CISTPL_CONFIG(chdl, &tuple, &config)) { 7063737Shx147065 cmn_err(CE_WARN, "pcwl: parse config failed %x\n", ret); 7073737Shx147065 goto insert_ret; 7083737Shx147065 } 7093737Shx147065 PCWLDBG((CE_NOTE, 7103737Shx147065 "pcwl: config present=%x nr=%x hr=%x regs[0]=%x base=%x last=%x\n", 7113737Shx147065 config.present, config.nr, config.hr, config.regs[0], 7123737Shx147065 config.base, config.last)); 7133737Shx147065 hi = 0; 7143737Shx147065 lo = (int)-1; /* really big number */ 7153737Shx147065 tbl_p = &cisparse.cftable; 7163737Shx147065 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; 7173737Shx147065 for (tbl_p->index = 0; tbl_p->index <= config.hr; ) { 7183737Shx147065 PCWLDBG((CE_NOTE, "pcwl insert:tuple idx=%x:\n", tbl_p->index)); 7193737Shx147065 if (ret = csx_GetNextTuple(chdl, &tuple)) { 7203737Shx147065 cmn_err(CE_WARN, "pcwl: get cftable failed %x\n", 7213737Shx147065 ret); 7223737Shx147065 break; 7233737Shx147065 } 7243737Shx147065 bzero((caddr_t)&cisparse, sizeof (cisparse)); 7253737Shx147065 if (ret = csx_Parse_CISTPL_CFTABLE_ENTRY(chdl, &tuple, tbl_p)) { 7263737Shx147065 cmn_err(CE_WARN, "pcwl: parse cftable failed %x\n", 7273737Shx147065 ret); 7283737Shx147065 break; 7293737Shx147065 } 7303737Shx147065 if (tbl_p->flags & CISTPL_CFTABLE_TPCE_FS_PWR && 7316062Shx147065 tbl_p->pd.flags & CISTPL_CFTABLE_TPCE_FS_PWR_VCC) { 7323737Shx147065 if (tbl_p->pd.pd_vcc.avgI > hi) { 7333737Shx147065 hi = tbl_p->pd.pd_vcc.avgI; 7343737Shx147065 pcwl_p->pcwl_config_hi = tbl_p->index; 7353737Shx147065 } 7363737Shx147065 if (tbl_p->pd.pd_vcc.avgI < lo) { 7373737Shx147065 lo = tbl_p->pd.pd_vcc.avgI; 7383737Shx147065 pcwl_p->pcwl_config = tbl_p->index; 7393737Shx147065 } 7403737Shx147065 } 7413737Shx147065 if (tbl_p->flags & CISTPL_CFTABLE_TPCE_DEFAULT) { 7423737Shx147065 if (tbl_p->pd.flags & CISTPL_CFTABLE_TPCE_FS_PWR_VCC) 7433737Shx147065 pcwl_p->pcwl_vcc = tbl_p->pd.pd_vcc.nomV; 7443737Shx147065 if (tbl_p->flags & CISTPL_CFTABLE_TPCE_FS_IO) 7453737Shx147065 pcwl_p->pcwl_iodecode = tbl_p->io.addr_lines; 7463737Shx147065 } 7473737Shx147065 } 7483737Shx147065 PCWLDBG((CE_NOTE, "pcwl: insert:cfg_hi=%x cfg=%x vcc=%x iodecode=%x\n", 7493737Shx147065 pcwl_p->pcwl_config_hi, pcwl_p->pcwl_config, 7503737Shx147065 pcwl_p->pcwl_vcc, pcwl_p->pcwl_iodecode)); 7513737Shx147065 bzero(&io, sizeof (io)); 7523737Shx147065 io.BasePort1.base = 0; 7533737Shx147065 io.NumPorts1 = 1 << pcwl_p->pcwl_iodecode; 7543737Shx147065 io.Attributes1 = IO_DATA_PATH_WIDTH_16; 7553737Shx147065 io.IOAddrLines = pcwl_p->pcwl_iodecode; 7563737Shx147065 if (ret = csx_RequestIO(chdl, &io)) { 7573737Shx147065 cmn_err(CE_WARN, "pcwl: RequestIO failed %x\n", ret); 7583737Shx147065 goto insert_ret; 7593737Shx147065 } 7603737Shx147065 pcwl_p->pcwl_port = io.BasePort1.handle; 7613737Shx147065 if (ret = ddi_add_softintr(DIP(pcwl_p), DDI_SOFTINT_HIGH, 7623737Shx147065 &pcwl_p->pcwl_softint_id, &pcwl_p->pcwl_ib_cookie, NULL, 7633737Shx147065 pcwl_intr, (caddr_t)pcwl_p)) { 7643737Shx147065 cmn_err(CE_NOTE, "pcwl(pccard): add softintr failed\n"); 7653737Shx147065 goto insert_ret; 7663737Shx147065 } 7673737Shx147065 irq.Attributes = IRQ_TYPE_EXCLUSIVE; 7683737Shx147065 irq.irq_handler = ddi_intr_hilevel(DIP(pcwl_p), 0) ? 7693737Shx147065 (csfunction_t *)pcwl_intr_hi : (csfunction_t *)pcwl_intr; 7703737Shx147065 irq.irq_handler_arg = pcwl_p; 7713737Shx147065 if (ret = csx_RequestIRQ(pcwl_p->pcwl_chdl, &irq)) { 7723737Shx147065 cmn_err(CE_WARN, "pcwl: RequestIRQ failed %x\n", ret); 7733737Shx147065 goto un_io; 7743737Shx147065 } 7753737Shx147065 bzero(&cfg, sizeof (cfg)); 7763737Shx147065 cfg.Attributes = 0; /* not ready for CONF_ENABLE_IRQ_STEERING yet */ 7773737Shx147065 cfg.Vcc = 50; 7783737Shx147065 cfg.IntType = SOCKET_INTERFACE_MEMORY_AND_IO; 7793737Shx147065 cfg.ConfigBase = config.base; 7803737Shx147065 cfg.ConfigIndex = pcwl_p->pcwl_config; 7813737Shx147065 cfg.Status = CCSR_IO_IS_8; 7823737Shx147065 cfg.Present = config.present; 7833737Shx147065 pcwl_p->pcwl_flag |= PCWL_CARD_READY; 7843737Shx147065 if (ret = csx_RequestConfiguration(chdl, &cfg)) { 7853737Shx147065 cmn_err(CE_WARN, "pcwl: RequestConfiguration failed %x\n", ret); 7863737Shx147065 goto un_irq; 7873737Shx147065 } 7883737Shx147065 return (CS_SUCCESS); 7893737Shx147065 un_irq: 7903737Shx147065 (void) csx_ReleaseIRQ(chdl, &irq); 7913737Shx147065 un_io: 7923737Shx147065 ddi_remove_softintr(pcwl_p->pcwl_softint_id); 7933737Shx147065 (void) csx_ReleaseIO(chdl, &io); 7943737Shx147065 pcwl_p->pcwl_port = 0; 7953737Shx147065 insert_ret: 7963737Shx147065 pcwl_p->pcwl_flag &= ~PCWL_CARD_READY; 7973737Shx147065 return (ret); 7983737Shx147065 7993737Shx147065 } 8003737Shx147065 8013737Shx147065 /* 8023737Shx147065 * assume card is already removed, don't touch the hardware 8033737Shx147065 */ 8043737Shx147065 static void 8053737Shx147065 pcwl_card_remove(pcwl_maci_t *pcwl_p) 8063737Shx147065 { 8073737Shx147065 int ret; 8083737Shx147065 io_req_t io; 8093737Shx147065 irq_req_t irq; 8103737Shx147065 8113737Shx147065 /* 8123737Shx147065 * The card not ready means Insert function doesnot return TRUE. 8133737Shx147065 * then the IO and IRQ has been released in Insert 8143737Shx147065 */ 8153737Shx147065 if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) 8163737Shx147065 return; 8173737Shx147065 if (ret = csx_ReleaseConfiguration(pcwl_p->pcwl_chdl, NULL)) 8183737Shx147065 cmn_err(CE_WARN, "pcwl: ReleaseConfiguration failed %x\n", ret); 8193737Shx147065 8203737Shx147065 bzero(&irq, sizeof (irq)); 8213737Shx147065 if (ret = csx_ReleaseIRQ(pcwl_p->pcwl_chdl, &irq)) 8223737Shx147065 cmn_err(CE_WARN, "pcwl: ReleaseIRQ failed %x\n", ret); 8233737Shx147065 8243737Shx147065 ddi_remove_softintr(pcwl_p->pcwl_softint_id); 8253737Shx147065 8263737Shx147065 bzero(&io, sizeof (io)); 8273737Shx147065 io.BasePort1.handle = pcwl_p->pcwl_port; 8283737Shx147065 io.NumPorts1 = 16; 8293737Shx147065 if (ret = csx_ReleaseIO(pcwl_p->pcwl_chdl, &io)) 8303737Shx147065 cmn_err(CE_WARN, "pcwl: ReleaseIO failed %x\n", ret); 8313737Shx147065 8323737Shx147065 pcwl_p->pcwl_port = 0; 8333737Shx147065 pcwl_p->pcwl_flag &= ~PCWL_CARD_READY; 8343737Shx147065 } 8353737Shx147065 8363737Shx147065 /* 8373737Shx147065 * mac operation interface routines 8383737Shx147065 */ 8393737Shx147065 static int 8403737Shx147065 pcwl_start(void *arg) 8413737Shx147065 { 8423737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg; 8433737Shx147065 8443737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 8453737Shx147065 if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) { 8463737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 8473737Shx147065 return (PCWL_FAIL); 8483737Shx147065 } 8493737Shx147065 pcwl_start_locked(pcwl_p); 8503737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 8513737Shx147065 return (PCWL_SUCCESS); 8523737Shx147065 } 8533737Shx147065 8543737Shx147065 static void 8553737Shx147065 pcwl_stop(void *arg) 8563737Shx147065 { 8573737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg; 8583737Shx147065 8593737Shx147065 PCWLDBG((CE_NOTE, "pcwl_stop called\n")); 8603737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 8613737Shx147065 if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) { 8623737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 8633737Shx147065 return; 8643737Shx147065 } 8653737Shx147065 8663737Shx147065 pcwl_stop_locked(pcwl_p); 8673737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 8683737Shx147065 if (pcwl_p->pcwl_connect_timeout_id != 0) { 8693737Shx147065 (void) untimeout(pcwl_p->pcwl_connect_timeout_id); 8703737Shx147065 pcwl_p->pcwl_connect_timeout_id = 0; 8713737Shx147065 } 8723737Shx147065 } 8733737Shx147065 8743737Shx147065 static int 8753737Shx147065 pcwl_saddr(void *arg, const uint8_t *macaddr) 8763737Shx147065 { 8773737Shx147065 int ret = PCWL_SUCCESS; 8783737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg; 8793737Shx147065 8803737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 8813737Shx147065 if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) { 8823737Shx147065 ret = PCWL_FAIL; 8833737Shx147065 goto done; 8843737Shx147065 } 8853737Shx147065 ether_copy(macaddr, pcwl_p->pcwl_mac_addr); 8863737Shx147065 if (pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) { 8873737Shx147065 ret = PCWL_FAIL; 8883737Shx147065 goto done; 8893737Shx147065 } 8903737Shx147065 if (pcwl_saddr_locked(pcwl_p)) { 8913737Shx147065 ret = PCWL_FAIL; 8923737Shx147065 goto done; 8933737Shx147065 } 8943737Shx147065 if (pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) { 8953737Shx147065 ret = PCWL_FAIL; 8963737Shx147065 } 8973737Shx147065 done: 8983737Shx147065 if (ret) 8993737Shx147065 cmn_err(CE_WARN, "pcwl set_mac_addr: failed\n"); 9003737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 9013737Shx147065 return (ret); 9023737Shx147065 } 9033737Shx147065 9043737Shx147065 static int 9053737Shx147065 pcwl_send(pcwl_maci_t *pcwl_p, mblk_t *mblk_p) 9063737Shx147065 { 9073737Shx147065 int i = 0; 9083737Shx147065 char *buf, *buf_p; 9093737Shx147065 wl_frame_t *frm_p; 9103737Shx147065 uint16_t pkt_len, ret; 9113737Shx147065 uint16_t xmt_id, ring_idx; 9123737Shx147065 struct ieee80211_frame *wh; 9133737Shx147065 struct ieee80211_llc *llc; 9143737Shx147065 9153737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 9163737Shx147065 if ((pcwl_p->pcwl_flag & (PCWL_CARD_READY | PCWL_CARD_LINKUP)) != 9173737Shx147065 (PCWL_CARD_READY | PCWL_CARD_LINKUP)) { 9183737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 9193737Shx147065 freemsg(mblk_p); 9203737Shx147065 return (PCWL_SUCCESS); /* drop packet */ 9213737Shx147065 } 9223737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 9233737Shx147065 9243737Shx147065 if (pullupmsg(mblk_p, -1) == 0) { 9253737Shx147065 freemsg(mblk_p); 9263737Shx147065 return (PCWL_SUCCESS); /* drop packet */ 9273737Shx147065 } 9283737Shx147065 wh = (struct ieee80211_frame *)mblk_p->b_rptr; 9293737Shx147065 llc = (struct ieee80211_llc *)&wh[1]; 9303737Shx147065 9313737Shx147065 mutex_enter(&pcwl_p->pcwl_txring.wl_tx_lock); 9323737Shx147065 ring_idx = pcwl_p->pcwl_txring.wl_tx_prod; 9333737Shx147065 pcwl_p->pcwl_txring.wl_tx_prod = (ring_idx + 1) & (WL_XMT_BUF_NUM - 1); 9343737Shx147065 9353737Shx147065 /* 9363737Shx147065 * check whether there is a xmt buffer available 9373737Shx147065 */ 9383737Shx147065 while ((i < WL_XMT_BUF_NUM) && 9393737Shx147065 (pcwl_p->pcwl_txring.wl_tx_ring[ring_idx])) { 9403737Shx147065 ring_idx = pcwl_p->pcwl_txring.wl_tx_prod; 9413737Shx147065 pcwl_p->pcwl_txring.wl_tx_prod = 9423737Shx147065 (ring_idx + 1) & (WL_XMT_BUF_NUM - 1); 9433737Shx147065 i++; 9443737Shx147065 } 9453737Shx147065 if (i == WL_XMT_BUF_NUM) { 9463737Shx147065 mutex_exit(&pcwl_p->pcwl_txring.wl_tx_lock); 9473737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 9483737Shx147065 pcwl_p->pcwl_reschedule_need = B_TRUE; 9493737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 9503737Shx147065 pcwl_p->pcwl_noxmtbuf++; 9513737Shx147065 return (PCWL_FAIL); 9523737Shx147065 } 9533737Shx147065 xmt_id = pcwl_p->pcwl_txring.wl_tx_fids[ring_idx]; 9543737Shx147065 pcwl_p->pcwl_txring.wl_tx_ring[ring_idx] = xmt_id; 9553737Shx147065 mutex_exit(&pcwl_p->pcwl_txring.wl_tx_lock); 9563737Shx147065 9573737Shx147065 buf = kmem_zalloc(PCWL_NICMEM_SZ, KM_SLEEP); 9583737Shx147065 buf_p = (ulong_t)buf & 1 ? buf + 1 : buf; 9593737Shx147065 frm_p = (wl_frame_t *)buf_p; 9603737Shx147065 #ifdef DEBUG 9613737Shx147065 if (pcwl_debug & PCWL_DBG_SEND) { 9623737Shx147065 cmn_err(CE_NOTE, "pcwl send: packet"); 9636990Sgd78059 for (i = 0; i < MBLKL(mblk_p); i++) 9643737Shx147065 cmn_err(CE_NOTE, "%x: %x\n", i, 9653737Shx147065 *((unsigned char *)mblk_p->b_rptr + i)); 9663737Shx147065 } 9673737Shx147065 #endif 9683737Shx147065 pkt_len = msgdsize(mblk_p); 9693737Shx147065 if (pkt_len > (PCWL_NICMEM_SZ - sizeof (wl_frame_t))) { 9703737Shx147065 cmn_err(CE_WARN, "pcwl: send mblk is too long"); 9713737Shx147065 kmem_free(buf, PCWL_NICMEM_SZ); 9723737Shx147065 freemsg(mblk_p); 9733737Shx147065 return (PCWL_SUCCESS); /* drop packet */ 9743737Shx147065 } 9753737Shx147065 if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) != 9763737Shx147065 IEEE80211_FC1_DIR_TODS) { 9773737Shx147065 kmem_free(buf, PCWL_NICMEM_SZ); 9783737Shx147065 freemsg(mblk_p); 9793737Shx147065 return (PCWL_SUCCESS); /* drop packet */ 9803737Shx147065 } 9813737Shx147065 bzero(frm_p, WL_802_11_HDRLEN); 9823737Shx147065 9833737Shx147065 frm_p->wl_tx_ctl = WL_TXCNTL_SET; 9843737Shx147065 bcopy(wh->i_addr3, frm_p->wl_dst_addr, ETHERADDRL); /* dst macaddr */ 9853737Shx147065 bcopy(wh->i_addr2, frm_p->wl_src_addr, ETHERADDRL); /* src macaddr */ 9863737Shx147065 frm_p->wl_len = htons(pkt_len - sizeof (*wh)); 9873737Shx147065 bcopy(llc, &frm_p->wl_dat[0], pkt_len - sizeof (*wh)); 9883737Shx147065 pkt_len = pkt_len - (sizeof (*wh) + sizeof (*llc)) + 9893737Shx147065 WL_802_11_HDRLEN; 9903737Shx147065 PCWLDBG((CE_NOTE, "send: DIX frmsz=%x pkt_len=%x\n", 9913737Shx147065 WL_802_11_HDRLEN, pkt_len)); 9923737Shx147065 9933737Shx147065 if (pkt_len & 1) /* round up to 16-bit boundary and pad 0 */ 9943737Shx147065 buf_p[pkt_len++] = 0; 9953737Shx147065 9963737Shx147065 ASSERT(pkt_len <= PCWL_NICMEM_SZ); 9973737Shx147065 #ifdef DEBUG 9983737Shx147065 if (pcwl_debug & PCWL_DBG_SEND) { 9993737Shx147065 cmn_err(CE_NOTE, "pkt_len = %x\n", pkt_len); 10003737Shx147065 for (i = 0; i < pkt_len; i++) 10013737Shx147065 cmn_err(CE_NOTE, "%x: %x\n", i, 10023737Shx147065 *((unsigned char *)buf + i)); 10033737Shx147065 } 10043737Shx147065 #endif 10053737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 10063737Shx147065 ret = (WRCH1(pcwl_p, xmt_id, 0, (uint16_t *)buf_p, 0x2e) || 10073737Shx147065 WRPKT(pcwl_p, xmt_id, 0x2e, (uint16_t *)(buf_p + 0x2e), 10083737Shx147065 pkt_len - 0x2e)); 10093737Shx147065 if (ret) { 10103737Shx147065 goto done; 10113737Shx147065 } 10123737Shx147065 PCWLDBG((CE_NOTE, "send: xmt_id=%x send=%x\n", xmt_id, pkt_len)); 10133737Shx147065 (void) pcwl_set_cmd(pcwl_p, WL_CMD_TX | WL_RECLAIM, xmt_id); 10143737Shx147065 10153737Shx147065 done: 10163737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 10173737Shx147065 kmem_free(buf, PCWL_NICMEM_SZ); 10183737Shx147065 freemsg(mblk_p); 10193737Shx147065 return (PCWL_SUCCESS); 10203737Shx147065 } 10213737Shx147065 10223737Shx147065 static mblk_t * 10233737Shx147065 pcwl_tx(void *arg, mblk_t *mp) 10243737Shx147065 { 10253737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg; 10263737Shx147065 mblk_t *next; 10273737Shx147065 10283737Shx147065 ASSERT(mp != NULL); 10293737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 10303737Shx147065 if ((pcwl_p->pcwl_flag & (PCWL_CARD_LINKUP | PCWL_CARD_READY)) != 10313737Shx147065 (PCWL_CARD_LINKUP | PCWL_CARD_READY)) { 10323737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 10333737Shx147065 return (mp); 10343737Shx147065 } 10353737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 10363737Shx147065 while (mp != NULL) { 10373737Shx147065 next = mp->b_next; 10383737Shx147065 mp->b_next = NULL; 10393737Shx147065 10403737Shx147065 if (pcwl_send(pcwl_p, mp)) { 10413737Shx147065 mp->b_next = next; 10423737Shx147065 break; 10433737Shx147065 } 10443737Shx147065 mp = next; 10453737Shx147065 } 10463737Shx147065 return (mp); 10473737Shx147065 } 10483737Shx147065 10493737Shx147065 static int 10503737Shx147065 pcwl_prom(void *arg, boolean_t on) 10513737Shx147065 { 10523737Shx147065 int ret = PCWL_SUCCESS; 10533737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg; 10543737Shx147065 10553737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 10563737Shx147065 if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) { 10573737Shx147065 ret = PCWL_FAIL; 10583737Shx147065 goto done; 10593737Shx147065 } 10603737Shx147065 10613737Shx147065 PCWLDBG((CE_NOTE, "pcwl_prom called %x\n", on)); 10623737Shx147065 10633737Shx147065 if (on) 10643737Shx147065 pcwl_p->pcwl_rf.rf_promiscuous = 1; 10653737Shx147065 else 10663737Shx147065 pcwl_p->pcwl_rf.rf_promiscuous = 0; 10673737Shx147065 if (ret = pcwl_fil_ltv(pcwl_p, 2, WL_RID_PROMISC, 10683737Shx147065 pcwl_p->pcwl_rf.rf_promiscuous)) { 10693737Shx147065 ret = PCWL_FAIL; 10703737Shx147065 } 10713737Shx147065 done: 10723737Shx147065 if (ret) 10733737Shx147065 cmn_err(CE_WARN, "pcwl promisc: failed\n"); 10743737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 10753737Shx147065 return (ret); 10763737Shx147065 } 10773737Shx147065 10783737Shx147065 static int 10793737Shx147065 pcwl_gstat(void *arg, uint_t statitem, uint64_t *val) 10803737Shx147065 { 10813737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg; 10823737Shx147065 int ret = PCWL_SUCCESS; 10833737Shx147065 uint64_t *cntr_p = pcwl_p->pcwl_cntrs_s; 10843737Shx147065 uint16_t rate = 0; 10853737Shx147065 uint64_t speed; 10863737Shx147065 10873737Shx147065 PCWLDBG((CE_NOTE, "pcwl_gstat called\n")); 10883737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 10893737Shx147065 if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) { 10903737Shx147065 ret = PCWL_FAIL; 10913737Shx147065 goto done; 10923737Shx147065 } 10933737Shx147065 10943737Shx147065 if (pcwl_get_ltv(pcwl_p, 2, WL_RID_CUR_TX_RATE, &rate)) { 10953737Shx147065 cmn_err(CE_WARN, "pcwl kstat: get speed failed\n"); 10963737Shx147065 ret = PCWL_FAIL; 10973737Shx147065 goto done; 10983737Shx147065 } 10993737Shx147065 switch (pcwl_p->pcwl_chip_type) { 11003737Shx147065 case PCWL_CHIP_PRISMII: 11013737Shx147065 switch (rate) { 11023737Shx147065 case WL_SPEED_1Mbps_P2: rate = 2; break; 11033737Shx147065 case WL_SPEED_2Mbps_P2: rate = 4; break; 11043737Shx147065 case WL_SPEED_55Mbps_P2: rate = 11; break; 11053737Shx147065 case WL_SPEED_11Mbps_P2: rate = 22; break; 11063737Shx147065 default: rate = 0; break; 11073737Shx147065 } 11083737Shx147065 speed = rate * 500000; 11093737Shx147065 break; 11103737Shx147065 case PCWL_CHIP_LUCENT: 11113737Shx147065 default: 11123737Shx147065 speed = rate * 1000000; 11133737Shx147065 if (rate == 6) 11143737Shx147065 speed = 5500000; 11153737Shx147065 break; 11163737Shx147065 } 11173737Shx147065 11183737Shx147065 switch (statitem) { 11193737Shx147065 case MAC_STAT_IFSPEED: 11203737Shx147065 *val = speed; 11213737Shx147065 break; 11223737Shx147065 case MAC_STAT_NOXMTBUF: 11233737Shx147065 *val = pcwl_p->pcwl_noxmtbuf; 11243737Shx147065 break; 11253737Shx147065 case MAC_STAT_NORCVBUF: 11263737Shx147065 *val = cntr_p[WLC_RX_DISCARDS_NOBUF]; 11273737Shx147065 break; 11283737Shx147065 case MAC_STAT_IERRORS: 11293737Shx147065 *val = 0; 11303737Shx147065 break; 11313737Shx147065 case MAC_STAT_OERRORS: 11323737Shx147065 *val = cntr_p[WLC_TX_DISCARDS] + 11333737Shx147065 cntr_p[WLC_TX_DISCARDS_WRONG_SA]; 11343737Shx147065 break; 11353737Shx147065 case MAC_STAT_RBYTES: 11363737Shx147065 *val = cntr_p[WLC_RX_UNICAST_OCTETS]; 11373737Shx147065 break; 11383737Shx147065 case MAC_STAT_IPACKETS: 11393737Shx147065 *val = cntr_p[WLC_RX_UNICAST_FRAMES]; 11403737Shx147065 break; 11413737Shx147065 case MAC_STAT_OBYTES: 11423737Shx147065 *val = cntr_p[WLC_TX_UNICAST_OCTETS]; 11433737Shx147065 break; 11443737Shx147065 case MAC_STAT_OPACKETS: 11453737Shx147065 *val = cntr_p[WLC_TX_UNICAST_FRAMES]; 11463737Shx147065 break; 11473737Shx147065 case WIFI_STAT_TX_FAILED: 11483737Shx147065 *val = cntr_p[WLC_TX_RETRY_LIMIT] + 11493737Shx147065 cntr_p[WLC_TX_DEFERRED_XMITS]; 11503737Shx147065 break; 11513737Shx147065 case WIFI_STAT_TX_RETRANS: 11523737Shx147065 *val = cntr_p[WLC_TX_SINGLE_RETRIES] + 11533737Shx147065 cntr_p[WLC_TX_MULTI_RETRIES]; 11543737Shx147065 break; 11553737Shx147065 case WIFI_STAT_FCS_ERRORS: 11563737Shx147065 *val = cntr_p[WLC_RX_FCS_ERRORS]; 11573737Shx147065 break; 11583737Shx147065 case WIFI_STAT_WEP_ERRORS: 11593737Shx147065 *val = cntr_p[WLC_RX_WEP_CANT_DECRYPT]; 11603737Shx147065 break; 11613737Shx147065 case WIFI_STAT_MCAST_TX: 11623737Shx147065 *val = cntr_p[WLC_TX_MULTICAST_FRAMES]; 11633737Shx147065 break; 11643737Shx147065 case WIFI_STAT_MCAST_RX: 11653737Shx147065 *val = cntr_p[WLC_RX_MULTICAST_FRAMES]; 11663737Shx147065 break; 11673737Shx147065 case WIFI_STAT_TX_FRAGS: 11683737Shx147065 *val = cntr_p[WLC_TX_FRAGMENTS]; 11693737Shx147065 break; 11703737Shx147065 case WIFI_STAT_RX_FRAGS: 11713737Shx147065 *val = cntr_p[WLC_RX_FRAGMENTS] + 11723737Shx147065 cntr_p[WLC_RX_MSG_IN_MSG_FRAGS] + 11733737Shx147065 cntr_p[WLC_RX_MSG_IN_BAD_MSG_FRAGS]; 11743737Shx147065 break; 11753737Shx147065 case WIFI_STAT_RTS_SUCCESS: 11763737Shx147065 case WIFI_STAT_RTS_FAILURE: 11773737Shx147065 case WIFI_STAT_ACK_FAILURE: 11783737Shx147065 case WIFI_STAT_RX_DUPS: 11793737Shx147065 *val = 0; 11803737Shx147065 break; 11813737Shx147065 default: 11823737Shx147065 ret = ENOTSUP; 11833737Shx147065 } 11843737Shx147065 done: 11853737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 11863737Shx147065 return (ret); 11873737Shx147065 } 11883737Shx147065 11893737Shx147065 static int 11903737Shx147065 pcwl_sdmulti(void *arg, boolean_t add, const uint8_t *eth_p) 11913737Shx147065 { 11923737Shx147065 int ret = PCWL_SUCCESS; 11933737Shx147065 uint16_t i; 11943737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg; 11953737Shx147065 uint16_t *mc_p = pcwl_p->pcwl_mcast; 11963737Shx147065 11973737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 11983737Shx147065 if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) { 11993737Shx147065 ret = PCWL_FAIL; 12003737Shx147065 goto done; 12013737Shx147065 } 12023737Shx147065 12033737Shx147065 if (add) { /* enable multicast on eth_p, search for available entries */ 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) /* already part of the filter */ 12093737Shx147065 goto done; 12103737Shx147065 mc_p = pcwl_p->pcwl_mcast; /* reset mc_p for 2nd scan */ 12113737Shx147065 for (i = 0; i < 16; i++, mc_p += (ETHERADDRL >> 1)) { 12123737Shx147065 PCWLDBG((CE_NOTE, "smulti: mc[%x]=%s\n", i, 12133737Shx147065 ether_sprintf((struct ether_addr *)mc_p))); 12143737Shx147065 if (mc_p[0] == 0 && mc_p[1] == 0 && mc_p[2] == 0) 12153737Shx147065 break; 12163737Shx147065 } 12173737Shx147065 if (i >= 16) /* can't find a vacant entry */ 12183737Shx147065 goto done; 12193737Shx147065 ether_copy(eth_p, mc_p); 12203737Shx147065 } else { /* disable multicast, locate the entry and clear it */ 12213737Shx147065 for (i = 0; i < 16; i++, mc_p += (ETHERADDRL >> 1)) { 12223737Shx147065 if (!ether_cmp(eth_p, mc_p)) 12233737Shx147065 break; 12243737Shx147065 } 12253737Shx147065 if (i >= 16) 12263737Shx147065 goto done; 12273737Shx147065 mc_p[0] = 0; 12283737Shx147065 mc_p[1] = 0; 12293737Shx147065 mc_p[2] = 0; 12303737Shx147065 } 12313737Shx147065 /* 12323737Shx147065 * re-blow the entire 16 entries buffer 12333737Shx147065 */ 12343737Shx147065 if (i = pcwl_put_ltv(pcwl_p, ETHERADDRL << 4, WL_RID_MCAST, 12353737Shx147065 pcwl_p->pcwl_mcast)) { 12363737Shx147065 ret = PCWL_FAIL; 12373737Shx147065 } 12383737Shx147065 done: 12393737Shx147065 if (ret) 12403737Shx147065 cmn_err(CE_WARN, "pcwl set multi addr: failed\n"); 12413737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 12423737Shx147065 return (ret); 12433737Shx147065 } 12443737Shx147065 12453737Shx147065 static uint_t 12463737Shx147065 pcwl_intr(caddr_t arg) 12473737Shx147065 { 12483737Shx147065 uint16_t stat; 12493737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg; 12503737Shx147065 12513737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 12523737Shx147065 if ((pcwl_p->pcwl_flag & (PCWL_CARD_READY | PCWL_CARD_INTREN)) != 12533737Shx147065 (PCWL_CARD_READY | PCWL_CARD_INTREN)) { 12543737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 12553737Shx147065 return (DDI_INTR_UNCLAIMED); 12563737Shx147065 } 12573737Shx147065 PCWL_READ(pcwl_p, WL_EVENT_STAT, stat); 12583737Shx147065 if (!(stat & WL_INTRS) || stat == WL_EV_ALL) { 12593737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 12603737Shx147065 return (DDI_INTR_UNCLAIMED); 12613737Shx147065 } 12623737Shx147065 12633737Shx147065 PCWL_WRITE(pcwl_p, WL_INT_EN, 0); 12643737Shx147065 if (stat & WL_EV_RX) { 12653737Shx147065 pcwl_rcv(pcwl_p); 12663737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_RX); 12673737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_RX); 12683737Shx147065 } 12693737Shx147065 if (stat & WL_EV_TX) { 12703737Shx147065 if (pcwl_txdone(pcwl_p) == PCWL_SUCCESS) { 12713737Shx147065 if (pcwl_p->pcwl_reschedule_need == B_TRUE) { 12723737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 12733737Shx147065 mac_tx_update(GLD3(pcwl_p)); 12743737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 12753737Shx147065 pcwl_p->pcwl_reschedule_need = B_FALSE; 12763737Shx147065 } 12773737Shx147065 } 12783737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX); 12793737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX); 12803737Shx147065 } 12813737Shx147065 if (stat & WL_EV_ALLOC) { 12823737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_ALLOC | 0x1000); 12833737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, 0x1000); 12843737Shx147065 } 12853737Shx147065 if (stat & WL_EV_INFO) { 12863737Shx147065 pcwl_infodone(pcwl_p); 12873737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_INFO); 12883737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_INFO); 12893737Shx147065 } 12903737Shx147065 if (stat & WL_EV_TX_EXC) { 12913737Shx147065 if (pcwl_txdone(pcwl_p) == PCWL_SUCCESS) { 12923737Shx147065 if (pcwl_p->pcwl_reschedule_need == B_TRUE) { 12933737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 12943737Shx147065 mac_tx_update(GLD3(pcwl_p)); 12953737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 12963737Shx147065 pcwl_p->pcwl_reschedule_need = B_FALSE; 12973737Shx147065 } 12983737Shx147065 } 12993737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX_EXC); 13003737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX_EXC); 13013737Shx147065 } 13023737Shx147065 if (stat & WL_EV_INFO_DROP) { 13033737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_INFO_DROP); 13043737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_INFO_DROP); 13053737Shx147065 } 13063737Shx147065 PCWL_ENABLE_INTR(pcwl_p); 13073737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 13083737Shx147065 13093737Shx147065 return (DDI_INTR_CLAIMED); 13103737Shx147065 } 13113737Shx147065 13123737Shx147065 static uint_t 13133737Shx147065 pcwl_intr_hi(caddr_t arg) 13143737Shx147065 { 13153737Shx147065 uint16_t stat; 13163737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg; 13173737Shx147065 13183737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 13193737Shx147065 if ((pcwl_p->pcwl_flag & (PCWL_CARD_READY | PCWL_CARD_INTREN)) != 13203737Shx147065 (PCWL_CARD_READY | PCWL_CARD_INTREN)) { 13213737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 13223737Shx147065 return (DDI_INTR_UNCLAIMED); 13233737Shx147065 } 13243737Shx147065 PCWL_READ(pcwl_p, WL_EVENT_STAT, stat); 13253737Shx147065 if (!(stat & WL_INTRS) || stat == WL_EV_ALL) { 13263737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 13273737Shx147065 return (DDI_INTR_UNCLAIMED); 13283737Shx147065 } 13293737Shx147065 PCWL_WRITE(pcwl_p, WL_INT_EN, 0); /* disable interrupt without ack */ 13303737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 13313737Shx147065 ddi_trigger_softintr(pcwl_p->pcwl_softint_id); 13323737Shx147065 return (DDI_INTR_CLAIMED); 13333737Shx147065 } 13343737Shx147065 13353737Shx147065 /* 13363737Shx147065 * called at interrupt context to retrieve data from card 13373737Shx147065 */ 13383737Shx147065 static void 13393737Shx147065 pcwl_rcv(pcwl_maci_t *pcwl_p) 13403737Shx147065 { 13413737Shx147065 uint16_t id, len, off, ret, frm_ctl; 13423737Shx147065 wl_frame_t frm; 13433737Shx147065 mblk_t *mp = allocb(PCWL_NICMEM_SZ, BPRI_MED); 13443737Shx147065 if (!mp) 13453737Shx147065 return; 13463737Shx147065 ASSERT(mp->b_rptr == mp->b_wptr); 13473737Shx147065 13483737Shx147065 PCWL_READ(pcwl_p, WL_RX_FID, id); 13493737Shx147065 PCWL_WRITE(pcwl_p, WL_RX_FID, 0); 13503737Shx147065 if (id == WL_INVALID_FID) { 13513737Shx147065 PCWLDBG((CE_NOTE, "pcwl rcv: get rx_fid failed\n")); 13523737Shx147065 ret = PCWL_FAIL; 13533737Shx147065 goto done; 13543737Shx147065 } 13553737Shx147065 if (ret = RDCH0(pcwl_p, id, 0, (uint16_t *)&frm, sizeof (frm))) { 13563737Shx147065 PCWLDBG((CE_NOTE, "pcwl rcv: read frm failed %x\n", ret)); 13573737Shx147065 goto done; 13583737Shx147065 } 13593737Shx147065 if (frm.wl_status & WL_STAT_ERRSTAT) { 13603737Shx147065 PCWLDBG((CE_NOTE, "pcwl rcv: errstat %x\n", frm.wl_status)); 13613737Shx147065 ret = frm.wl_status; 13623737Shx147065 goto done; 13633737Shx147065 } 13643737Shx147065 PCWLDBG((CE_NOTE, "pcwl rcv: frame type %x\n", frm.wl_status)); 13653737Shx147065 #ifdef DEBUG 13663737Shx147065 if (pcwl_debug & PCWL_DBG_RCV) { 13673737Shx147065 int i; 13683737Shx147065 cmn_err(CE_NOTE, "pcwl rcv: frm header\n"); 13693737Shx147065 for (i = 0; i < WL_802_11_HDRLEN; i++) 13703737Shx147065 cmn_err(CE_NOTE, "%x: %x\n", i, 13713737Shx147065 *((uint8_t *)&frm + i)); 13723737Shx147065 } 13733737Shx147065 #endif 13743737Shx147065 len = frm.wl_dat_len; 13753737Shx147065 /* 13763737Shx147065 * this driver deal with WEP by itself. so plugin always thinks no wep. 13773737Shx147065 */ 13783737Shx147065 frm.wl_frame_ctl &= ~(IEEE80211_FC1_WEP << 8); 13793737Shx147065 frm_ctl = frm.wl_frame_ctl; 13803737Shx147065 switch (frm.wl_status) { 13813737Shx147065 case WL_STAT_1042: 13823737Shx147065 case WL_STAT_TUNNEL: 13833737Shx147065 case WL_STAT_WMP_MSG: 13843737Shx147065 PCWL_SWAP16((uint16_t *)&frm.wl_frame_ctl, 13853737Shx147065 sizeof (struct ieee80211_frame)); 13863737Shx147065 /* 13873737Shx147065 * discard those frames which are not from the AP we connect or 13883737Shx147065 * without 'ap->sta' direction 13893737Shx147065 */ 13903737Shx147065 if ((pcwl_p->pcwl_rf.rf_porttype == WL_BSS_BSS) && 13913737Shx147065 ((((frm_ctl >> 8) & IEEE80211_FC1_DIR_MASK) != 13923737Shx147065 IEEE80211_FC1_DIR_FROMDS) || 13933737Shx147065 bcmp(pcwl_p->pcwl_bssid, frm.wl_addr2, 6) != 0)) { 13943737Shx147065 ret = PCWL_FAIL; 13953737Shx147065 goto done; 13963737Shx147065 } 13973737Shx147065 13983737Shx147065 bcopy(&frm.wl_frame_ctl, mp->b_wptr, 13993737Shx147065 sizeof (struct ieee80211_frame)); 14003737Shx147065 mp->b_wptr += sizeof (struct ieee80211_frame); 14013737Shx147065 14023737Shx147065 PCWL_SWAP16((uint16_t *)&frm.wl_dat[0], 14033737Shx147065 sizeof (struct ieee80211_llc)); 14043737Shx147065 bcopy(&frm.wl_dat[0], mp->b_wptr, 14053737Shx147065 sizeof (struct ieee80211_llc)); 14063737Shx147065 mp->b_wptr += sizeof (struct ieee80211_llc); 14073737Shx147065 14083737Shx147065 len -= (2 + WL_SNAPHDR_LEN); 14093737Shx147065 off = WL_802_11_HDRLEN; 14103737Shx147065 break; 14113737Shx147065 default: 14123737Shx147065 PCWLDBG((CE_NOTE, "pcwl rcv: incorrect pkt\n")); 14133737Shx147065 break; 14143737Shx147065 } 14153737Shx147065 if (len > MBLKSIZE(mp)) { 14163737Shx147065 PCWLDBG((CE_NOTE, "pcwl rcv: oversz pkt %x\n", len)); 14173737Shx147065 ret = PCWL_FAIL; 14183737Shx147065 goto done; 14193737Shx147065 } 14203737Shx147065 if (len & 1) 14213737Shx147065 len++; 14223737Shx147065 ret = RDPKT(pcwl_p, id, off, (uint16_t *)mp->b_wptr, len); 14233737Shx147065 done: 14243737Shx147065 if (ret) { 14253737Shx147065 PCWLDBG((CE_NOTE, "pcwl rcv: rd data %x\n", ret)); 14263737Shx147065 freemsg(mp); 14273737Shx147065 return; 14283737Shx147065 } 14293737Shx147065 mp->b_wptr = mp->b_wptr + len; 14303737Shx147065 #ifdef DEBUG 14313737Shx147065 if (pcwl_debug & PCWL_DBG_RCV) { 14323737Shx147065 int i; 14333737Shx147065 cmn_err(CE_NOTE, "pcwl rcv: len=0x%x\n", len); 14343737Shx147065 for (i = 0; i < len+14; i++) 14353737Shx147065 cmn_err(CE_NOTE, "%x: %x\n", i, 14363737Shx147065 *((uint8_t *)mp->b_rptr + i)); 14373737Shx147065 } 14383737Shx147065 #endif 14393737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 14403737Shx147065 mac_rx(GLD3(pcwl_p), NULL, mp); 14413737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 14423737Shx147065 } 14433737Shx147065 14443737Shx147065 static uint32_t 14453737Shx147065 pcwl_txdone(pcwl_maci_t *pcwl_p) 14463737Shx147065 { 14473737Shx147065 uint16_t fid, i; 14483737Shx147065 PCWL_READ(pcwl_p, WL_ALLOC_FID, fid); 14493737Shx147065 PCWL_WRITE(pcwl_p, WL_ALLOC_FID, 0); 14503737Shx147065 14513737Shx147065 mutex_enter(&pcwl_p->pcwl_txring.wl_tx_lock); 14523737Shx147065 for (i = 0; i < WL_XMT_BUF_NUM; i++) { 14533737Shx147065 if (fid == pcwl_p->pcwl_txring.wl_tx_ring[i]) { 14543737Shx147065 pcwl_p->pcwl_txring.wl_tx_ring[i] = 0; 14553737Shx147065 break; 14563737Shx147065 } 14573737Shx147065 } 14583737Shx147065 pcwl_p->pcwl_txring.wl_tx_cons = 14593737Shx147065 (pcwl_p->pcwl_txring.wl_tx_cons + 1) & (WL_XMT_BUF_NUM - 1); 14603737Shx147065 mutex_exit(&pcwl_p->pcwl_txring.wl_tx_lock); 14613737Shx147065 if (i == WL_XMT_BUF_NUM) 14623737Shx147065 return (PCWL_FAIL); 14633737Shx147065 return (PCWL_SUCCESS); 14643737Shx147065 14653737Shx147065 } 14663737Shx147065 14673737Shx147065 static void 14683737Shx147065 pcwl_infodone(pcwl_maci_t *pcwl_p) 14693737Shx147065 { 14703737Shx147065 uint16_t id, ret, i; 14713737Shx147065 uint16_t linkStatus[2]; 14723737Shx147065 uint16_t linkStat; 14733737Shx147065 wifi_data_t wd = { 0 }; 14743737Shx147065 14753737Shx147065 PCWL_READ(pcwl_p, WL_INFO_FID, id); 14763737Shx147065 if (id == WL_INVALID_FID) { 14773737Shx147065 cmn_err(CE_WARN, "pcwl infodone: read info_fid failed\n"); 14783737Shx147065 return; 14793737Shx147065 } 14803737Shx147065 if (ret = RDCH0(pcwl_p, id, 0, linkStatus, sizeof (linkStatus))) { 14813737Shx147065 PCWLDBG((CE_WARN, "pcwl infodone read infoFrm failed %x\n", 14823737Shx147065 ret)); 14833737Shx147065 return; 14843737Shx147065 } 14853737Shx147065 PCWLDBG((CE_NOTE, "pcwl infodone: Frame length= %x, Frame Type = %x\n", 14863737Shx147065 linkStatus[0], linkStatus[1])); 14873737Shx147065 14883737Shx147065 switch (linkStatus[1]) { 14893737Shx147065 case WL_INFO_LINK_STAT: 14903737Shx147065 (void) RDCH0(pcwl_p, id, sizeof (linkStatus), &linkStat, 14913737Shx147065 sizeof (linkStat)); 14923737Shx147065 PCWLDBG((CE_NOTE, "pcwl infodone: link status=%x\n", linkStat)); 14933737Shx147065 if (!(pcwl_p->pcwl_flag & PCWL_CARD_LINKUP) && 14943737Shx147065 linkStat == WL_LINK_CONNECT) { 14953737Shx147065 #ifdef DEBUG 14963737Shx147065 if (pcwl_debug & PCWL_DBG_LINKINFO) 14973737Shx147065 cmn_err(CE_NOTE, "pcwl: Link up \n"); 14983737Shx147065 #endif 14993737Shx147065 pcwl_p->pcwl_flag |= PCWL_CARD_LINKUP; 15003737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 15013737Shx147065 if (pcwl_p->pcwl_connect_timeout_id != 0) { 15023737Shx147065 (void) untimeout(pcwl_p-> 15033737Shx147065 pcwl_connect_timeout_id); 15043737Shx147065 pcwl_p->pcwl_connect_timeout_id = 0; 15053737Shx147065 } 15063737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 15073737Shx147065 mac_link_update(GLD3(pcwl_p), LINK_STATE_UP); 15083737Shx147065 (void) pcwl_get_ltv(pcwl_p, 6, 15093737Shx147065 WL_RID_BSSID, (uint16_t *)pcwl_p->pcwl_bssid); 15103737Shx147065 PCWL_SWAP16((uint16_t *)pcwl_p->pcwl_bssid, 6); 15113737Shx147065 pcwl_get_rssi(pcwl_p); 15123737Shx147065 bcopy(pcwl_p->pcwl_bssid, wd.wd_bssid, 6); 15133737Shx147065 wd.wd_secalloc = WIFI_SEC_NONE; 15143737Shx147065 wd.wd_opmode = IEEE80211_M_STA; 15153737Shx147065 (void) mac_pdata_update(pcwl_p->pcwl_mh, &wd, 15163737Shx147065 sizeof (wd)); 15173737Shx147065 } 15183737Shx147065 if ((pcwl_p->pcwl_flag & PCWL_CARD_LINKUP) && 15193737Shx147065 ((linkStat == WL_LINK_DISCONNECT) || 15203737Shx147065 (linkStat == WL_LINK_AP_OOR))) { 15213737Shx147065 #ifdef DEBUG 15223737Shx147065 if (pcwl_debug & PCWL_DBG_LINKINFO) 15233737Shx147065 cmn_err(CE_NOTE, "pcwl: Link down \n"); 15243737Shx147065 #endif 15253737Shx147065 PCWLDBG((CE_NOTE, "pcwl infodone: link status = %d\n", 15263737Shx147065 linkStat)); 15273737Shx147065 pcwl_p->pcwl_flag &= ~PCWL_CARD_LINKUP; 15283737Shx147065 if (linkStat == WL_LINK_AP_OOR) 15293737Shx147065 pcwl_p->pcwl_connect_timeout_id = 15303737Shx147065 timeout(pcwl_connect_timeout, 15313737Shx147065 pcwl_p, drv_usectohz(1000)); 15323737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 15333737Shx147065 mac_link_update(GLD3(pcwl_p), LINK_STATE_DOWN); 15343737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 15353737Shx147065 } 15363737Shx147065 break; 15373737Shx147065 case WL_INFO_SCAN_RESULTS: 15383737Shx147065 case WL_INFO_HSCAN_RESULTS: 15393737Shx147065 pcwl_ssid_scan(pcwl_p, id, linkStatus[0], linkStatus[1]); 15403737Shx147065 break; 15413737Shx147065 case WL_INFO_COUNTERS: 15423737Shx147065 linkStatus[0]--; 15433737Shx147065 if (linkStatus[0] > WLC_STAT_CNT) { 15443737Shx147065 linkStatus[0] = MIN(linkStatus[0], WLC_STAT_CNT); 15453737Shx147065 } 15463737Shx147065 (void) RDCH0(pcwl_p, id, sizeof (linkStatus), 15473737Shx147065 pcwl_p->pcwl_cntrs_t, linkStatus[0]<<1); 15483737Shx147065 /* 15493737Shx147065 * accumulate all the statistics items for kstat use. 15503737Shx147065 */ 15513737Shx147065 for (i = 0; i < WLC_STAT_CNT; i++) 15523737Shx147065 pcwl_p->pcwl_cntrs_s[i] += pcwl_p->pcwl_cntrs_t[i]; 15533737Shx147065 break; 15543737Shx147065 default: 15553737Shx147065 break; 15563737Shx147065 } 15573737Shx147065 } 15583737Shx147065 15593737Shx147065 static uint16_t 15603737Shx147065 pcwl_set_cmd(pcwl_maci_t *pcwl_p, uint16_t cmd, uint16_t param) 15613737Shx147065 { 15623737Shx147065 int i; 15633737Shx147065 uint16_t stat; 15643737Shx147065 15653737Shx147065 if (((cmd == WL_CMD_ENABLE) && 15663737Shx147065 ((pcwl_p->pcwl_flag & PCWL_ENABLED) != 0)) || 15673737Shx147065 ((cmd == WL_CMD_DISABLE) && 15683737Shx147065 ((pcwl_p->pcwl_flag & PCWL_ENABLED) == 0))) 15693737Shx147065 return (PCWL_SUCCESS); 15703737Shx147065 15713737Shx147065 for (i = 0; i < WL_TIMEOUT; i++) { 15723737Shx147065 PCWL_READ(pcwl_p, WL_COMMAND, stat); 15733737Shx147065 if (stat & WL_CMD_BUSY) { 15743737Shx147065 drv_usecwait(1); 15753737Shx147065 } else { 15763737Shx147065 break; 15773737Shx147065 } 15783737Shx147065 } 15793737Shx147065 if (i == WL_TIMEOUT) { 15803737Shx147065 cmn_err(CE_WARN, "pcwl: setcmd %x, %x timeout %x due to " 15813737Shx147065 "busy bit\n", cmd, param, stat); 15823737Shx147065 return (PCWL_TIMEDOUT_CMD); 15833737Shx147065 } 15843737Shx147065 15853737Shx147065 PCWL_WRITE(pcwl_p, WL_PARAM0, param); 15863737Shx147065 PCWL_WRITE(pcwl_p, WL_PARAM1, 0); 15873737Shx147065 PCWL_WRITE(pcwl_p, WL_PARAM2, 0); 15883737Shx147065 PCWL_WRITE(pcwl_p, WL_COMMAND, cmd); 15893737Shx147065 if (cmd == WL_CMD_INI) 15903737Shx147065 drv_usecwait(100000); /* wait .1 sec */ 15913737Shx147065 15923737Shx147065 for (i = 0; i < WL_TIMEOUT; i++) { 15933737Shx147065 PCWL_READ(pcwl_p, WL_EVENT_STAT, stat); 15943737Shx147065 if (!(stat & WL_EV_CMD)) { 15953737Shx147065 drv_usecwait(1); 15963737Shx147065 } else { 15973737Shx147065 break; 15983737Shx147065 } 15993737Shx147065 } 16003737Shx147065 if (i == WL_TIMEOUT) { 16013737Shx147065 cmn_err(CE_WARN, "pcwl: setcmd %x,%x timeout %x\n", 16023737Shx147065 cmd, param, stat); 16033737Shx147065 if (stat & (WL_EV_ALLOC | WL_EV_RX)) 16043737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, stat); 16053737Shx147065 return (PCWL_TIMEDOUT_CMD); 16063737Shx147065 } 16073737Shx147065 PCWL_READ(pcwl_p, WL_STATUS, stat); 16083737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_CMD); 16093737Shx147065 if (stat & WL_STAT_CMD_RESULT) { /* err in feedback status */ 16103737Shx147065 cmn_err(CE_WARN, "pcwl: set_cmd %x,%x failed %x\n", 16113737Shx147065 cmd, param, stat); 16123737Shx147065 return (PCWL_FAILURE_CMD); 16133737Shx147065 } 16143737Shx147065 if (cmd == WL_CMD_ENABLE) 16153737Shx147065 pcwl_p->pcwl_flag |= PCWL_ENABLED; 16163737Shx147065 if (cmd == WL_CMD_DISABLE) 16173737Shx147065 pcwl_p->pcwl_flag &= (~PCWL_ENABLED); 16183737Shx147065 return (PCWL_SUCCESS); 16193737Shx147065 } 16203737Shx147065 16213737Shx147065 static uint16_t 16223737Shx147065 pcwl_set_ch(pcwl_maci_t *pcwl_p, uint16_t type, uint16_t off, uint16_t channel) 16233737Shx147065 { 16243737Shx147065 int i; 16253737Shx147065 uint16_t stat, select, offset; 16263737Shx147065 16273737Shx147065 if (channel) { 16283737Shx147065 select = WL_SEL1; 16293737Shx147065 offset = WL_OFF1; 16303737Shx147065 } else { 16313737Shx147065 select = WL_SEL0; 16323737Shx147065 offset = WL_OFF0; 16333737Shx147065 } 16343737Shx147065 PCWL_WRITE(pcwl_p, select, type); 16353737Shx147065 PCWL_WRITE(pcwl_p, offset, off); 16363737Shx147065 for (stat = 0, i = 0; i < WL_TIMEOUT; i++) { 16373737Shx147065 PCWL_READ(pcwl_p, offset, stat); 16383737Shx147065 if (!(stat & (WL_OFF_BUSY|WL_OFF_ERR))) 16393737Shx147065 break; 16403737Shx147065 else { 16413737Shx147065 drv_usecwait(1); 16423737Shx147065 } 16433737Shx147065 } 16443737Shx147065 if (i == WL_TIMEOUT) { 16453737Shx147065 cmn_err(CE_WARN, "set_ch%d %x,%x failed %x\n", 16463737Shx147065 channel, type, off, stat); 16473737Shx147065 return (PCWL_TIMEDOUT_TARGET); 16483737Shx147065 } 16493737Shx147065 return (PCWL_SUCCESS); 16503737Shx147065 } 16513737Shx147065 16523737Shx147065 static uint16_t 16533737Shx147065 pcwl_get_ltv(pcwl_maci_t *pcwl_p, uint16_t len, uint16_t type, uint16_t *val_p) 16543737Shx147065 { 16553737Shx147065 uint16_t stat; 16563737Shx147065 16573737Shx147065 ASSERT(!(len & 1)); 16583737Shx147065 len >>= 1; /* convert bytes to 16-bit words */ 16593737Shx147065 16603737Shx147065 /* 16613737Shx147065 * 1. select read mode 16623737Shx147065 */ 16633737Shx147065 if (stat = pcwl_set_cmd(pcwl_p, WL_CMD_ACCESS | WL_ACCESS_READ, type)) 16643737Shx147065 return (stat); 16653737Shx147065 16663737Shx147065 /* 16673737Shx147065 * 2. select Buffer Access Path (channel) 1 for PIO 16683737Shx147065 */ 16693737Shx147065 if (stat = pcwl_set_ch(pcwl_p, type, 0, 1)) 16703737Shx147065 return (stat); 16713737Shx147065 16723737Shx147065 /* 16733737Shx147065 * 3. read length 16743737Shx147065 */ 16753737Shx147065 PCWL_READ(pcwl_p, WL_DATA1, stat); 16763737Shx147065 if (stat != (len + 1)) { 16773737Shx147065 PCWLDBG((CE_NOTE, "get_ltv 0x%x expected 0x%x+1, got 0x%x\n", 16783737Shx147065 type, (len + 1) << 1, stat)); 16793737Shx147065 stat = (stat >> 1) - 1; 16803737Shx147065 len = MIN(stat, len); 16813737Shx147065 } 16823737Shx147065 16833737Shx147065 /* 16843737Shx147065 * 4. read type 16853737Shx147065 */ 16863737Shx147065 PCWL_READ(pcwl_p, WL_DATA1, stat); 16873737Shx147065 if (stat != type) 16883737Shx147065 return (PCWL_BADTYPE); 16893737Shx147065 16903737Shx147065 /* 16913737Shx147065 * 5. read value 16923737Shx147065 */ 16933737Shx147065 for (stat = 0; stat < len; stat++, val_p++) { 16943737Shx147065 PCWL_READ_P(pcwl_p, WL_DATA1, val_p, 1); 16953737Shx147065 } 16963737Shx147065 return (PCWL_SUCCESS); 16973737Shx147065 } 16983737Shx147065 16993737Shx147065 static uint16_t 17003737Shx147065 pcwl_fil_ltv(pcwl_maci_t *pcwl_p, uint16_t len, uint16_t type, uint16_t val) 17013737Shx147065 { 17023737Shx147065 uint16_t stat; 17033737Shx147065 17043737Shx147065 ASSERT(!(len & 1)); 17053737Shx147065 17063737Shx147065 /* 17073737Shx147065 * 1. select Buffer Access Path (channel) 1 for PIO 17083737Shx147065 */ 17093737Shx147065 if (stat = pcwl_set_ch(pcwl_p, type, 0, 1)) 17103737Shx147065 return (stat); 17113737Shx147065 17123737Shx147065 /* 17133737Shx147065 * 2. write length 17143737Shx147065 */ 17153737Shx147065 len >>= 1; /* convert bytes to 16-bit words */ 17163737Shx147065 stat = len + 1; /* 1 extra word */ 17173737Shx147065 PCWL_WRITE(pcwl_p, WL_DATA1, stat); 17183737Shx147065 17193737Shx147065 /* 17203737Shx147065 * 3. write type 17213737Shx147065 */ 17223737Shx147065 PCWL_WRITE(pcwl_p, WL_DATA1, type); 17233737Shx147065 17243737Shx147065 /* 17253737Shx147065 * 4. fill value 17263737Shx147065 */ 17273737Shx147065 for (stat = 0; stat < len; stat++) { 17283737Shx147065 PCWL_WRITE(pcwl_p, WL_DATA1, val); 17293737Shx147065 } 17303737Shx147065 17313737Shx147065 /* 17323737Shx147065 * 5. select write mode 17333737Shx147065 */ 17343737Shx147065 return (pcwl_set_cmd(pcwl_p, WL_CMD_ACCESS|WL_ACCESS_WRITE, type)); 17353737Shx147065 } 17363737Shx147065 17373737Shx147065 static uint16_t 17383737Shx147065 pcwl_put_ltv(pcwl_maci_t *pcwl_p, uint16_t len, uint16_t type, uint16_t *val_p) 17393737Shx147065 { 17403737Shx147065 uint16_t stat; 17413737Shx147065 17423737Shx147065 ASSERT(!(len & 1)); 17433737Shx147065 17443737Shx147065 /* 17453737Shx147065 * 1. select Buffer Access Path (channel) 1 for PIO 17463737Shx147065 */ 17473737Shx147065 if (stat = pcwl_set_ch(pcwl_p, type, 0, 1)) 17483737Shx147065 return (stat); 17493737Shx147065 17503737Shx147065 /* 17513737Shx147065 * 2. write length 17523737Shx147065 */ 17533737Shx147065 len >>= 1; /* convert bytes to 16-bit words */ 17543737Shx147065 stat = len + 1; /* 1 extra word */ 17553737Shx147065 PCWL_WRITE(pcwl_p, WL_DATA1, stat); 17563737Shx147065 17573737Shx147065 /* 17583737Shx147065 * 3. write type 17593737Shx147065 */ 17603737Shx147065 PCWL_WRITE(pcwl_p, WL_DATA1, type); 17613737Shx147065 17623737Shx147065 /* 17633737Shx147065 * 4. write value 17643737Shx147065 */ 17653737Shx147065 for (stat = 0; stat < len; stat++, val_p++) { 17663737Shx147065 PCWL_WRITE_P(pcwl_p, WL_DATA1, val_p, 1); 17673737Shx147065 } 17683737Shx147065 17693737Shx147065 /* 17703737Shx147065 * 5. select write mode 17713737Shx147065 */ 17723737Shx147065 return (pcwl_set_cmd(pcwl_p, WL_CMD_ACCESS|WL_ACCESS_WRITE, type)); 17733737Shx147065 } 17743737Shx147065 17753737Shx147065 #define PCWL_COMPSTR_LEN 34 17763737Shx147065 static uint16_t 17773737Shx147065 pcwl_put_str(pcwl_maci_t *pcwl_p, uint16_t type, char *str_p) 17783737Shx147065 { 17793737Shx147065 uint16_t buf[PCWL_COMPSTR_LEN / 2]; 17803737Shx147065 uint8_t str_len = strlen(str_p); 17813737Shx147065 17823737Shx147065 bzero(buf, PCWL_COMPSTR_LEN); 17833737Shx147065 buf[0] = str_len; 17843737Shx147065 bcopy(str_p, (caddr_t)(buf + 1), str_len); 17853737Shx147065 PCWLDBG((CE_NOTE, "put_str: buf[0]=%x buf=%s\n", 17863737Shx147065 buf[0], (caddr_t)(buf + 1))); 17873737Shx147065 PCWL_SWAP16(buf + 1, PCWL_COMPSTR_LEN - 2); 17883737Shx147065 return (pcwl_put_ltv(pcwl_p, PCWL_COMPSTR_LEN, type, buf)); 17893737Shx147065 } 17903737Shx147065 17913737Shx147065 /*ARGSUSED*/ 17923737Shx147065 static uint16_t 17933737Shx147065 pcwl_rdch0(pcwl_maci_t *pcwl_p, uint16_t type, uint16_t off, uint16_t *buf_p, 17943737Shx147065 int len, int order) 17953737Shx147065 { 17963737Shx147065 uint16_t o; 17973737Shx147065 ASSERT(!(len & 1)); 17983737Shx147065 /* 17993737Shx147065 * It seems that for PrismII chip, frequently overlap use of path0 18003737Shx147065 * and path1 may hang the hardware. So for PrismII chip, just use 18013737Shx147065 * path1. Test proves this workaround is OK. 18023737Shx147065 */ 18033737Shx147065 if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) { 18043737Shx147065 if (type = pcwl_set_ch(pcwl_p, type, off, 1)) 18053737Shx147065 return (type); 18063737Shx147065 o = WL_DATA1; 18073737Shx147065 } else { 18083737Shx147065 if (type = pcwl_set_ch(pcwl_p, type, off, 0)) 18093737Shx147065 return (type); 18103737Shx147065 o = WL_DATA0; 18113737Shx147065 } 18123737Shx147065 len >>= 1; 18133737Shx147065 for (off = 0; off < len; off++, buf_p++) { 18143737Shx147065 PCWL_READ_P(pcwl_p, o, buf_p, order); 18153737Shx147065 } 18163737Shx147065 return (PCWL_SUCCESS); 18173737Shx147065 } 18183737Shx147065 18193737Shx147065 /*ARGSUSED*/ 18203737Shx147065 static uint16_t 18213737Shx147065 pcwl_wrch1(pcwl_maci_t *pcwl_p, uint16_t type, uint16_t off, uint16_t *buf_p, 18223737Shx147065 int len, int order) 18233737Shx147065 { 18243737Shx147065 ASSERT(!(len & 1)); 18253737Shx147065 if (type = pcwl_set_ch(pcwl_p, type, off, 1)) 18263737Shx147065 return (type); 18273737Shx147065 len >>= 1; 18283737Shx147065 for (off = 0; off < len; off++, buf_p++) { 18293737Shx147065 PCWL_WRITE_P(pcwl_p, WL_DATA1, buf_p, order); 18303737Shx147065 } 18313737Shx147065 return (PCWL_SUCCESS); 18323737Shx147065 } 18333737Shx147065 18343737Shx147065 static uint16_t 18353737Shx147065 pcwl_alloc_nicmem(pcwl_maci_t *pcwl_p, uint16_t len, uint16_t *id_p) 18363737Shx147065 { 18373737Shx147065 int i; 18383737Shx147065 uint16_t stat; 18393737Shx147065 18403737Shx147065 len = ((len + 1) >> 1) << 1; /* round up to 16-bit boundary */ 18413737Shx147065 18423737Shx147065 if (stat = pcwl_set_cmd(pcwl_p, WL_CMD_ALLOC_MEM, len)) 18433737Shx147065 return (stat); 18443737Shx147065 for (stat = 0, i = 0; i < WL_TIMEOUT; i++) { 18453737Shx147065 PCWL_READ(pcwl_p, WL_EVENT_STAT, stat); 18463737Shx147065 if (stat & WL_EV_ALLOC) 18473737Shx147065 break; 18483737Shx147065 else 18493737Shx147065 drv_usecwait(1); 18503737Shx147065 } 18513737Shx147065 if (i == WL_TIMEOUT) 18523737Shx147065 return (PCWL_TIMEDOUT_ALLOC); 18533737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_ALLOC); 18543737Shx147065 PCWL_READ(pcwl_p, WL_ALLOC_FID, stat); 18553737Shx147065 *id_p = stat; 18563737Shx147065 18573737Shx147065 /* 18583737Shx147065 * zero fill the allocated NIC mem - sort of pcwl_fill_ch 18593737Shx147065 */ 18603737Shx147065 (void) pcwl_set_ch(pcwl_p, stat, 0, 1); 18613737Shx147065 18623737Shx147065 for (len >>= 1, stat = 0; stat < len; stat++) { 18633737Shx147065 PCWL_WRITE(pcwl_p, WL_DATA1, 0); 18643737Shx147065 } 18653737Shx147065 return (PCWL_SUCCESS); 18663737Shx147065 } 18673737Shx147065 18683737Shx147065 static int 18693737Shx147065 pcwl_add_scan_item(pcwl_maci_t *pcwl_p, wl_scan_result_t s) 18703737Shx147065 { 18713737Shx147065 wl_scan_list_t *scan_item; 18723737Shx147065 18733737Shx147065 scan_item = kmem_zalloc(sizeof (wl_scan_list_t), KM_SLEEP); 18743737Shx147065 if (scan_item == NULL) { 18753737Shx147065 cmn_err(CE_WARN, "pcwl add_scan_item: zalloc failed\n"); 18763737Shx147065 return (PCWL_FAIL); 18773737Shx147065 } 18783737Shx147065 scan_item->wl_val = s; 18793737Shx147065 scan_item->wl_timeout = WL_SCAN_TIMEOUT_MAX; 18803737Shx147065 list_insert_tail(&pcwl_p->pcwl_scan_list, scan_item); 18813737Shx147065 pcwl_p->pcwl_scan_num++; 18823737Shx147065 return (PCWL_SUCCESS); 18833737Shx147065 } 18843737Shx147065 18853737Shx147065 static void 18863737Shx147065 pcwl_delete_scan_item(pcwl_maci_t *pcwl_p, wl_scan_list_t *s) 18873737Shx147065 { 18883737Shx147065 list_remove(&pcwl_p->pcwl_scan_list, s); 18893737Shx147065 kmem_free(s, sizeof (*s)); 18903737Shx147065 pcwl_p->pcwl_scan_num--; 18913737Shx147065 } 18923737Shx147065 18933737Shx147065 static void 18943737Shx147065 pcwl_scanlist_timeout(void *arg) 18953737Shx147065 { 18963737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg; 18973737Shx147065 wl_scan_list_t *scan_item0, *scan_item1; 18983737Shx147065 18993737Shx147065 mutex_enter(&pcwl_p->pcwl_scanlist_lock); 19003737Shx147065 scan_item0 = list_head(&pcwl_p->pcwl_scan_list); 19013737Shx147065 for (; scan_item0; ) { 19023737Shx147065 PCWLDBG((CE_NOTE, "ssid = %s\n", 19033737Shx147065 scan_item0->wl_val.wl_srt_ssid)); 19043737Shx147065 PCWLDBG((CE_NOTE, "timeout left: %ds", 19053737Shx147065 scan_item0->wl_timeout)); 19063737Shx147065 scan_item1 = list_next(&pcwl_p->pcwl_scan_list, scan_item0); 19073737Shx147065 if (scan_item0->wl_timeout == 0) { 19083737Shx147065 pcwl_delete_scan_item(pcwl_p, scan_item0); 19093737Shx147065 } else { 19103737Shx147065 scan_item0->wl_timeout--; 19113737Shx147065 } 19123737Shx147065 scan_item0 = scan_item1; 19133737Shx147065 } 19143737Shx147065 mutex_exit(&pcwl_p->pcwl_scanlist_lock); 19153737Shx147065 pcwl_p->pcwl_scanlist_timeout_id = timeout(pcwl_scanlist_timeout, 19163737Shx147065 pcwl_p, drv_usectohz(1000000)); 19173737Shx147065 } 19183737Shx147065 19193737Shx147065 static void 19203737Shx147065 pcwl_get_rssi(pcwl_maci_t *pcwl_p) 19213737Shx147065 { 19223737Shx147065 wl_scan_list_t *scan_item0; 19233737Shx147065 uint16_t cq[3]; 19243737Shx147065 19253737Shx147065 bzero(cq, sizeof (cq)); 19263737Shx147065 mutex_enter(&pcwl_p->pcwl_scanlist_lock); 19273737Shx147065 scan_item0 = list_head(&pcwl_p->pcwl_scan_list); 19283737Shx147065 for (; scan_item0; ) { 19293737Shx147065 if (bcmp(scan_item0->wl_val.wl_srt_bssid, 19303737Shx147065 pcwl_p->pcwl_bssid, 6) == 0) { 19313737Shx147065 pcwl_p->pcwl_rssi = scan_item0->wl_val.wl_srt_sl; 19323737Shx147065 } 19333737Shx147065 scan_item0 = list_next(&pcwl_p->pcwl_scan_list, scan_item0); 19343737Shx147065 } 19353737Shx147065 mutex_exit(&pcwl_p->pcwl_scanlist_lock); 19363737Shx147065 if (!pcwl_p->pcwl_rssi) { 19373737Shx147065 (void) pcwl_get_ltv(pcwl_p, 6, WL_RID_COMMQUAL, cq); 19383737Shx147065 pcwl_p->pcwl_rssi = cq[1]; 19393737Shx147065 } 19403737Shx147065 } 19413737Shx147065 19423737Shx147065 /* 19433737Shx147065 * Note: 19443737Shx147065 * PrismII chipset has 2 extra space for the reason why scan is initiated 19453737Shx147065 */ 19463737Shx147065 static void 19473737Shx147065 pcwl_ssid_scan(pcwl_maci_t *pcwl_p, uint16_t fid, uint16_t flen, uint16_t stype) 19483737Shx147065 { 19493737Shx147065 uint16_t stat; 19503737Shx147065 uint16_t ssidNum, i; 19513737Shx147065 uint16_t off, szbuf; 19523737Shx147065 uint16_t tmp[2]; 19533737Shx147065 wl_scan_list_t *scan_item0; 19543737Shx147065 uint32_t check_num; 19553737Shx147065 uint8_t bssid_t[6]; 19563737Shx147065 19573737Shx147065 wl_scan_result_t sctbl; 19583737Shx147065 19593737Shx147065 off = sizeof (uint16_t) * 2; 19603737Shx147065 switch (pcwl_p->pcwl_chip_type) { 19613737Shx147065 case PCWL_CHIP_PRISMII: 19623737Shx147065 (void) RDCH0(pcwl_p, fid, off, tmp, 4); 19633737Shx147065 off += 4; 19643737Shx147065 szbuf = (stype == WL_INFO_SCAN_RESULTS ? 31 : 32); 19653737Shx147065 PCWLDBG((CE_NOTE, "pcwl ssid_scan: PRISM chip\n")); 19663737Shx147065 break; 19673737Shx147065 case PCWL_CHIP_LUCENT: 19683737Shx147065 PCWLDBG((CE_NOTE, "pcwl ssid_scan LUCENT chip\n")); 19693737Shx147065 default: 19703737Shx147065 szbuf = 25; 19713737Shx147065 } 19723737Shx147065 19733737Shx147065 flen = flen + 1 - (off >> 1); 19743737Shx147065 ssidNum = flen/szbuf; 19753737Shx147065 ssidNum = min(WL_SRT_MAX_NUM, ssidNum); 19763737Shx147065 19773737Shx147065 PCWLDBG((CE_NOTE, "pcwl: ssid_scan frame length = %d\n", flen)); 19783737Shx147065 19793737Shx147065 PCWLDBG((CE_NOTE, "pcwl ssid_scan: %d ssid(s) available", ssidNum)); 19803737Shx147065 19813737Shx147065 bzero(bssid_t, sizeof (bssid_t)); 19823737Shx147065 for (i = 0; i < ssidNum; i++) { 19833737Shx147065 (void) RDCH0(pcwl_p, fid, off, (uint16_t *)&sctbl, 2*szbuf); 19843737Shx147065 19853737Shx147065 #ifdef DEBUG 19863737Shx147065 if (pcwl_debug & PCWL_DBG_INFO) { 19873737Shx147065 int j; 19883737Shx147065 for (j = 0; j < sizeof (sctbl); j++) 19893737Shx147065 cmn_err(CE_NOTE, "%d: %x\n", j, 19903737Shx147065 *((uint8_t *)&sctbl + j)); 19913737Shx147065 } 19923737Shx147065 #endif 19933737Shx147065 19943737Shx147065 off += (szbuf << 1); 19953737Shx147065 stat = min(sctbl.wl_srt_ssidlen, 31); 19963737Shx147065 PCWL_SWAP16((uint16_t *)(sctbl.wl_srt_bssid), 6); 19973737Shx147065 PCWL_SWAP16((uint16_t *)(sctbl.wl_srt_ssid), stat); 19983737Shx147065 sctbl.wl_srt_ssid[stat] = '\0'; 19993737Shx147065 sctbl.wl_srt_sl &= 0x7f; 20003737Shx147065 20013737Shx147065 /* 20023737Shx147065 * sometimes, those empty items are recorded by hardware, 20033737Shx147065 * this is wrong, just ignore those items here. 20043737Shx147065 */ 20053737Shx147065 if (bcmp(sctbl.wl_srt_bssid, 20063737Shx147065 bssid_t, 6) == 0) { 20073737Shx147065 continue; 20083737Shx147065 } 20093737Shx147065 if (bcmp(sctbl.wl_srt_bssid, 20103737Shx147065 pcwl_p->pcwl_bssid, 6) == 0) { 20113737Shx147065 pcwl_p->pcwl_rssi = sctbl.wl_srt_sl; 20123737Shx147065 } 20133737Shx147065 /* 20143737Shx147065 * save/update the scan item in scanlist 20153737Shx147065 */ 20163737Shx147065 mutex_enter(&pcwl_p->pcwl_scanlist_lock); 20173737Shx147065 check_num = 0; 20183737Shx147065 scan_item0 = list_head(&pcwl_p->pcwl_scan_list); 20193737Shx147065 if (scan_item0 == NULL) { 20203737Shx147065 if (pcwl_add_scan_item(pcwl_p, sctbl) 20213737Shx147065 != 0) { 20223737Shx147065 mutex_exit(&pcwl_p->pcwl_scanlist_lock); 20233737Shx147065 return; 20243737Shx147065 } 20253737Shx147065 } 20263737Shx147065 for (; scan_item0; ) { 20273737Shx147065 if (bcmp(sctbl.wl_srt_bssid, 20283737Shx147065 scan_item0->wl_val.wl_srt_bssid, 6) == 0) { 20293737Shx147065 scan_item0->wl_val = sctbl; 20303737Shx147065 scan_item0->wl_timeout = WL_SCAN_TIMEOUT_MAX; 20313737Shx147065 break; 20323737Shx147065 } else { 20333737Shx147065 check_num++; 20343737Shx147065 } 20353737Shx147065 scan_item0 = list_next(&pcwl_p->pcwl_scan_list, 20363737Shx147065 scan_item0); 20373737Shx147065 } 20383737Shx147065 if (check_num == pcwl_p->pcwl_scan_num) { 20393737Shx147065 if (pcwl_add_scan_item(pcwl_p, sctbl) 20403737Shx147065 != 0) { 20413737Shx147065 mutex_exit(&pcwl_p->pcwl_scanlist_lock); 20423737Shx147065 return; 20433737Shx147065 } 20443737Shx147065 } 20453737Shx147065 mutex_exit(&pcwl_p->pcwl_scanlist_lock); 20463737Shx147065 PCWLDBG((CE_NOTE, "pcwl ssid_scan: ssid%d = %s\n", i+1, 20473737Shx147065 sctbl.wl_srt_ssid)); 20483737Shx147065 PCWLDBG((CE_NOTE, "pcwl ssid_scan: channel = %d\n", 20493737Shx147065 sctbl.wl_srt_chid)); 20503737Shx147065 PCWLDBG((CE_NOTE, "pcwl ssid_scan: signal level= %d\n", 20513737Shx147065 sctbl.wl_srt_sl)); 20523737Shx147065 PCWLDBG((CE_NOTE, "pcwl ssid_scan: noise level = %d\n", 20533737Shx147065 sctbl.wl_srt_anl)); 20543737Shx147065 PCWLDBG((CE_NOTE, "pcwl ssid_scan: bssid%d =" 20553737Shx147065 " %x %x %x %x %x %x\n\n", i+1, 20563737Shx147065 sctbl.wl_srt_bssid[0], 20573737Shx147065 sctbl.wl_srt_bssid[1], 20583737Shx147065 sctbl.wl_srt_bssid[2], 20593737Shx147065 sctbl.wl_srt_bssid[3], 20603737Shx147065 sctbl.wl_srt_bssid[4], 20613737Shx147065 sctbl.wl_srt_bssid[5])); 20623737Shx147065 } 20633737Shx147065 20643737Shx147065 } 20653737Shx147065 20663737Shx147065 /* 20673737Shx147065 * delay in which the mutex is not hold. 20683737Shx147065 * assuming the mutex has already been hold. 20693737Shx147065 */ 20703737Shx147065 static void 20713737Shx147065 pcwl_delay(pcwl_maci_t *pcwl_p, clock_t microsecs) 20723737Shx147065 { 20733737Shx147065 ASSERT(mutex_owned(&pcwl_p->pcwl_glock)); 20743737Shx147065 20753737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 20763737Shx147065 delay(drv_usectohz(microsecs)); 20773737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 20783737Shx147065 } 20793737Shx147065 20803737Shx147065 static int 20813737Shx147065 pcwl_reset_backend(pcwl_maci_t *pcwl_p) 20823737Shx147065 { 20833737Shx147065 uint16_t ret = 0; 20843737Shx147065 20853737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_INI, 0)) { 20863737Shx147065 return ((int)ret); 20873737Shx147065 } 20883737Shx147065 20893737Shx147065 pcwl_delay(pcwl_p, 100000); /* wait .1 sec */ 20903737Shx147065 20913737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_INI, 0)) { 20923737Shx147065 return ((int)ret); 20933737Shx147065 } 20943737Shx147065 pcwl_delay(pcwl_p, 100000); /* wait .1 sec */ 20953737Shx147065 20963737Shx147065 PCWL_DISABLE_INTR(pcwl_p); 20973737Shx147065 return (PCWL_SUCCESS); 20983737Shx147065 } 20993737Shx147065 21003737Shx147065 21013737Shx147065 /* 21023737Shx147065 * get card capability (WEP, default channel), setup broadcast, mac addresses 21033737Shx147065 */ 21043737Shx147065 static int 21053737Shx147065 pcwl_get_cap(pcwl_maci_t *pcwl_p) 21063737Shx147065 { 21073737Shx147065 uint16_t stat, ch_no; 21083737Shx147065 uint16_t buf[ETHERADDRL >> 1]; 21093737Shx147065 21103737Shx147065 bzero(buf, ETHERADDRL); 21113737Shx147065 if (stat = pcwl_get_ltv(pcwl_p, 2, WL_RID_OWN_CHNL, &ch_no)) { 21123737Shx147065 cmn_err(CE_CONT, "pcwl get_cap: get def channel failed" 21133737Shx147065 " %x\n", stat); 21143737Shx147065 return ((int)stat); 21153737Shx147065 } 21163737Shx147065 if (stat = pcwl_get_ltv(pcwl_p, 2, WL_RID_WEP_AVAIL, 21173737Shx147065 &pcwl_p->pcwl_has_wep)) { 21183737Shx147065 cmn_err(CE_CONT, "pcwl get_cap: get WEP capability failed" 21193737Shx147065 " %x\n", stat); 21203737Shx147065 return ((int)stat); 21213737Shx147065 } 21223737Shx147065 if (stat = pcwl_get_ltv(pcwl_p, ETHERADDRL, WL_RID_MAC_NODE, buf)) { 21233737Shx147065 cmn_err(CE_CONT, "pcwl get_cap: get macaddr failed" 21243737Shx147065 " %x\n", stat); 21253737Shx147065 return ((int)stat); 21263737Shx147065 } 21273737Shx147065 21283737Shx147065 /* 21293737Shx147065 * don't assume m_xxx members are 16-bit aligned 21303737Shx147065 */ 21313737Shx147065 PCWL_SWAP16(buf, ETHERADDRL); 21323737Shx147065 ether_copy(buf, pcwl_p->pcwl_mac_addr); 21333737Shx147065 return (PCWL_SUCCESS); 21343737Shx147065 } 21353737Shx147065 21363737Shx147065 static int 21373737Shx147065 pcwl_init_nicmem(pcwl_maci_t *pcwl_p) 21383737Shx147065 { 21393737Shx147065 uint16_t ret, i; 21403737Shx147065 uint16_t rc; 21413737Shx147065 21423737Shx147065 for (i = 0; i < WL_XMT_BUF_NUM; i++) { 21433737Shx147065 ret = pcwl_alloc_nicmem(pcwl_p, PCWL_NICMEM_SZ, &rc); 21443737Shx147065 if (ret) { 21453737Shx147065 cmn_err(CE_WARN, 21463737Shx147065 "pcwl: alloc NIC Tx buf failed %x\n", ret); 21473737Shx147065 return (PCWL_FAIL); 21483737Shx147065 } 21493737Shx147065 pcwl_p->pcwl_txring.wl_tx_fids[i] = rc; 21503737Shx147065 pcwl_p->pcwl_txring.wl_tx_ring[i] = 0; 21513737Shx147065 PCWLDBG((CE_NOTE, "pcwl: alloc_nicmem_id[%d]=%x\n", i, rc)); 21523737Shx147065 } 21533737Shx147065 pcwl_p->pcwl_txring.wl_tx_prod = pcwl_p->pcwl_txring.wl_tx_cons = 0; 21543737Shx147065 21553737Shx147065 ret = pcwl_alloc_nicmem(pcwl_p, PCWL_NICMEM_SZ, &pcwl_p->pcwl_mgmt_id); 21563737Shx147065 if (ret) { 21573737Shx147065 cmn_err(CE_WARN, "pcwl: alloc NIC Mgmt buf failed %x\n", ret); 21583737Shx147065 return (PCWL_FAIL); 21593737Shx147065 } 21603737Shx147065 PCWLDBG((CE_NOTE, "pcwl: alloc_nicmem mgmt_id=%x\n", 21613737Shx147065 pcwl_p->pcwl_mgmt_id)); 21623737Shx147065 return (PCWL_SUCCESS); 21633737Shx147065 } 21643737Shx147065 21653737Shx147065 static int 21663737Shx147065 pcwl_loaddef_rf(pcwl_maci_t *pcwl_p) 21673737Shx147065 { 21683737Shx147065 pcwl_p->pcwl_rf.rf_max_datalen = WL_DEFAULT_DATALEN; 21693737Shx147065 pcwl_p->pcwl_rf.rf_create_ibss = WL_DEFAULT_CREATE_IBSS; 21703737Shx147065 pcwl_p->pcwl_rf.rf_porttype = WL_BSS_BSS; 21713737Shx147065 pcwl_p->pcwl_rf.rf_rts_thresh = WL_DEFAULT_RTS_THRESH; 21723737Shx147065 pcwl_p->pcwl_rf.rf_tx_rate = WL_TX_RATE_FIX_11M(pcwl_p); 21733737Shx147065 pcwl_p->pcwl_rf.rf_pm_enabled = WL_DEFAULT_PM_ENABLED; 21743737Shx147065 pcwl_p->pcwl_rf.rf_own_chnl = WL_DEFAULT_CHAN; 21753737Shx147065 (void) strcpy(pcwl_p->pcwl_rf.rf_own_ssid, ""); 21763737Shx147065 (void) strcpy(pcwl_p->pcwl_rf.rf_desired_ssid, ""); 21773737Shx147065 (void) strcpy(pcwl_p->pcwl_rf.rf_nodename, ""); 21783737Shx147065 pcwl_p->pcwl_rf.rf_encryption = WL_NOENCRYPTION; 21793737Shx147065 pcwl_p->pcwl_rf.rf_authtype = WL_OPENSYSTEM; 21803737Shx147065 pcwl_p->pcwl_rf.rf_tx_crypt_key = WL_DEFAULT_TX_CRYPT_KEY; 21813737Shx147065 bzero((pcwl_p->pcwl_rf.rf_ckeys), sizeof (rf_ckey_t) * 4); 21823737Shx147065 21833737Shx147065 pcwl_p->pcwl_rf.rf_promiscuous = 0; 21843737Shx147065 21853737Shx147065 return (pcwl_config_rf(pcwl_p)); 21863737Shx147065 } 21873737Shx147065 21883737Shx147065 static int 21893737Shx147065 pcwl_config_rf(pcwl_maci_t *pcwl_p) 21903737Shx147065 { 21913737Shx147065 pcwl_rf_t *rf_p = &pcwl_p->pcwl_rf; 21923737Shx147065 uint16_t create_ibss, porttype; 21933737Shx147065 21943737Shx147065 /* 21953737Shx147065 * Lucent card: 21963737Shx147065 * 0 Join ESS or IBSS; 1 Join ESS or join/create IBSS 21973737Shx147065 * PrismII card: 21983737Shx147065 * 3 Join ESS or IBSS(do not create IBSS); 21993737Shx147065 * 1 Join ESS or join/create IBSS 22003737Shx147065 */ 22013737Shx147065 create_ibss = rf_p->rf_create_ibss; 22023737Shx147065 if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) { 22033737Shx147065 if (rf_p->rf_create_ibss == 0) 22043737Shx147065 create_ibss = 3; 22053737Shx147065 } 22063737Shx147065 /* 22073737Shx147065 * Lucent card: 22083737Shx147065 * 1 BSS; 3 pseudo IBSS(only for test,not the 802.11 IBSS) 22093737Shx147065 * so porttype register should always be set to 1 22103737Shx147065 * PrismII card: 22113737Shx147065 * 0 IBSS; 1 BSS; 2 WDS; 3 pseudo IBSS; 6 hostAP 22123737Shx147065 */ 22133737Shx147065 switch (pcwl_p->pcwl_chip_type) { 22143737Shx147065 case PCWL_CHIP_PRISMII: 22153737Shx147065 if (rf_p->rf_porttype == WL_BSS_BSS) 22163737Shx147065 porttype = 1; 22173737Shx147065 else if (rf_p->rf_porttype == WL_BSS_IBSS) 22183737Shx147065 porttype = 0; 22193737Shx147065 else 22203737Shx147065 porttype = 0; 22213737Shx147065 break; 22223737Shx147065 case PCWL_CHIP_LUCENT: 22233737Shx147065 default: 22243737Shx147065 porttype = 1; 22253737Shx147065 } 22263737Shx147065 22273737Shx147065 22283737Shx147065 FIL_LTV(pcwl_p, PCWL_MCBUF_LEN, WL_RID_MCAST, 0); 22293737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_PROMISC, 0); 22303737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_TICK_TIME, 0); 22313737Shx147065 22323737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_MAX_DATALEN, rf_p->rf_max_datalen); 22333737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_CREATE_IBSS, create_ibss); 22343737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_PORTTYPE, porttype); 22353737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_RTS_THRESH, rf_p->rf_rts_thresh); 22363737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_TX_RATE, rf_p->rf_tx_rate); 22373737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_SYSTEM_SCALE, rf_p->rf_system_scale); 22383737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_PM_ENABLED, rf_p->rf_pm_enabled); 22393737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_MAX_SLEEP, rf_p->rf_max_sleep); 22403737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_OWN_CHNL, rf_p->rf_own_chnl); 22413737Shx147065 22423737Shx147065 PUT_STR(pcwl_p, WL_RID_OWN_SSID, rf_p->rf_own_ssid); 22433737Shx147065 PUT_STR(pcwl_p, WL_RID_DESIRED_SSID, rf_p->rf_desired_ssid); 22443737Shx147065 PUT_STR(pcwl_p, WL_RID_NODENAME, rf_p->rf_nodename); 22453737Shx147065 22463737Shx147065 if (!pcwl_p->pcwl_has_wep) 22473737Shx147065 goto done; 22483737Shx147065 22493737Shx147065 switch (pcwl_p->pcwl_chip_type) { 22503737Shx147065 case PCWL_CHIP_PRISMII: { 22513737Shx147065 int i; 22523737Shx147065 22533737Shx147065 for (i = 0; i < 4; i++) { 22543737Shx147065 int k_len = strlen((char *)rf_p->rf_ckeys[i].ckey_dat); 22553737Shx147065 if (k_len == 0) 22563737Shx147065 continue; 22573737Shx147065 k_len = k_len > 5 ? 14 : 6; 22583737Shx147065 PUT_LTV(pcwl_p, k_len, WL_RID_CRYPT_KEY0_P2 + i, 22593737Shx147065 (uint16_t *)&rf_p->rf_ckeys[i].ckey_dat); 22603737Shx147065 } 22613737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_TX_CRYPT_KEY_P2, 22623737Shx147065 rf_p->rf_tx_crypt_key); 22633737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_AUTHTYPE_P2, 22643737Shx147065 rf_p->rf_authtype); 22653737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_ENCRYPTION_P2, 22663737Shx147065 rf_p->rf_encryption); 22673737Shx147065 if (pcwl_p->pcwl_rf.rf_promiscuous) 22683737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_PROMISC, 1); 22693737Shx147065 } 22703737Shx147065 break; 22713737Shx147065 case PCWL_CHIP_LUCENT: 22723737Shx147065 default: 22733737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_ENCRYPTION, 22743737Shx147065 rf_p->rf_encryption); 22753737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_AUTHTYPE_L, 22763737Shx147065 rf_p->rf_authtype); 22773737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_TX_CRYPT_KEY, 22783737Shx147065 rf_p->rf_tx_crypt_key); 22793737Shx147065 PUT_LTV(pcwl_p, sizeof (rf_p->rf_ckeys), 22803737Shx147065 WL_RID_DEFLT_CRYPT_KEYS, 22813737Shx147065 (uint16_t *)rf_p->rf_ckeys); 22823737Shx147065 break; 22833737Shx147065 } 22843737Shx147065 done: 22853737Shx147065 return (PCWL_SUCCESS); 22863737Shx147065 } 22873737Shx147065 22883737Shx147065 static void 22893737Shx147065 pcwl_start_locked(pcwl_maci_t *pcwl_p) 22903737Shx147065 { 22913737Shx147065 pcwl_p->pcwl_flag |= PCWL_CARD_INTREN; 22923737Shx147065 PCWL_ENABLE_INTR(pcwl_p); 22933737Shx147065 } 22943737Shx147065 22953737Shx147065 static void 22963737Shx147065 pcwl_stop_locked(pcwl_maci_t *pcwl_p) 22973737Shx147065 { 22983737Shx147065 PCWL_DISABLE_INTR(pcwl_p); 22993737Shx147065 pcwl_p->pcwl_flag &= (~PCWL_CARD_INTREN); 23003737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX|WL_EV_RX|WL_EV_TX_EXC| 23013737Shx147065 WL_EV_ALLOC|WL_EV_INFO|WL_EV_INFO_DROP); 23023737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX|WL_EV_RX|WL_EV_TX_EXC| 23033737Shx147065 WL_EV_ALLOC| WL_EV_INFO|WL_EV_INFO_DROP); 23043737Shx147065 } 23053737Shx147065 23063737Shx147065 /*ARGSUSED*/ 23073737Shx147065 static int 23083737Shx147065 pcwl_saddr_locked(pcwl_maci_t *pcwl_p) 23093737Shx147065 { 23103737Shx147065 int ret; 23113737Shx147065 uint16_t buf[ETHERADDRL >> 1]; 23123737Shx147065 23133737Shx147065 ether_copy(pcwl_p->pcwl_mac_addr, buf); 23143737Shx147065 PCWL_SWAP16(buf, ETHERADDRL); 23153737Shx147065 ret = pcwl_put_ltv(pcwl_p, ETHERADDRL, WL_RID_MAC_NODE, buf); 23163737Shx147065 if (ret) { 23173737Shx147065 cmn_err(CE_WARN, "pcwl set_mac_addr: failed %x\n", ret); 23183737Shx147065 return (PCWL_FAIL); 23193737Shx147065 } 23203737Shx147065 return (PCWL_SUCCESS); 23213737Shx147065 } 23223737Shx147065 23233737Shx147065 static void 23243737Shx147065 pcwl_chip_type(pcwl_maci_t *pcwl_p) 23253737Shx147065 { 23263737Shx147065 pcwl_ltv_ver_t ver; 23273737Shx147065 pcwl_ltv_fwver_t f; 23283737Shx147065 23293737Shx147065 bzero(&ver, sizeof (ver)); 23303737Shx147065 (void) pcwl_get_ltv(pcwl_p, sizeof (ver), 23313737Shx147065 WL_RID_CARD_ID, (uint16_t *)&ver); 23323737Shx147065 PCWLDBG((CE_NOTE, "card id:%04x-%04x-%04x-%04x\n", 23333737Shx147065 ver.wl_compid, ver.wl_variant, ver.wl_major, ver.wl_minor)); 23343737Shx147065 if ((ver.wl_compid & 0xf000) != 0x8000) 23353737Shx147065 return; /* lucent */ 23363737Shx147065 23373737Shx147065 pcwl_p->pcwl_chip_type = PCWL_CHIP_PRISMII; 23383737Shx147065 (void) pcwl_get_ltv(pcwl_p, sizeof (ver), WL_RID_COMP_IDENT, 23393737Shx147065 (uint16_t *)&ver); 23403737Shx147065 PCWLDBG((CE_NOTE, "PRISM-II ver:%04x-%04x-%04x-%04x\n", 23413737Shx147065 ver.wl_compid, ver.wl_variant, ver.wl_major, ver.wl_minor)); 23423737Shx147065 23433737Shx147065 bzero(&f, sizeof (f)); 23443737Shx147065 (void) pcwl_get_ltv(pcwl_p, sizeof (f), WL_RID_FWVER, (uint16_t *)&f); 23453737Shx147065 PCWL_SWAP16((uint16_t *)&f, sizeof (f)); 23463737Shx147065 PCWLDBG((CE_NOTE, "Firmware Pri:%s 2,3:%s\n", 23473737Shx147065 (char *)f.pri, (char *)f.st)); 23483737Shx147065 } 23493737Shx147065 23503737Shx147065 /* 23518410SWang.Lin@Sun.COM * Brussels support 23528410SWang.Lin@Sun.COM */ 23538410SWang.Lin@Sun.COM /* 23548410SWang.Lin@Sun.COM * MAC_PROP_WL_ESSID 23558410SWang.Lin@Sun.COM */ 23568410SWang.Lin@Sun.COM static int 23578410SWang.Lin@Sun.COM pcwl_set_essid(pcwl_maci_t *pcwl_p, const void *wldp_buf) 23588410SWang.Lin@Sun.COM { 23598410SWang.Lin@Sun.COM char *value; 23608410SWang.Lin@Sun.COM pcwl_rf_t *rf_p; 23618410SWang.Lin@Sun.COM wl_essid_t *iw_essid = (wl_essid_t *)wldp_buf; 23628410SWang.Lin@Sun.COM 23638410SWang.Lin@Sun.COM rf_p = &pcwl_p->pcwl_rf; 23648410SWang.Lin@Sun.COM 23658410SWang.Lin@Sun.COM value = iw_essid->wl_essid_essid; 23668410SWang.Lin@Sun.COM (void) strncpy(rf_p->rf_desired_ssid, value, 23678410SWang.Lin@Sun.COM MIN(32, strlen(value))); 23688410SWang.Lin@Sun.COM rf_p->rf_desired_ssid[strlen(value)] = '\0'; 23698410SWang.Lin@Sun.COM (void) strncpy(rf_p->rf_own_ssid, value, 23708410SWang.Lin@Sun.COM MIN(32, strlen(value))); 23718410SWang.Lin@Sun.COM rf_p->rf_own_ssid[strlen(value)] = '\0'; 23728410SWang.Lin@Sun.COM 23738410SWang.Lin@Sun.COM PCWLDBG((CE_CONT, "pcwl: set: desired essid=%s\n", 23748410SWang.Lin@Sun.COM rf_p->rf_desired_ssid)); 23758410SWang.Lin@Sun.COM 23768410SWang.Lin@Sun.COM return (ENETRESET); 23778410SWang.Lin@Sun.COM 23788410SWang.Lin@Sun.COM } 23798410SWang.Lin@Sun.COM 23808410SWang.Lin@Sun.COM static int 23818410SWang.Lin@Sun.COM pcwl_get_essid(pcwl_maci_t *pcwl_p, void *wldp_buf) 23828410SWang.Lin@Sun.COM { 23838410SWang.Lin@Sun.COM char ssid[36]; 23848410SWang.Lin@Sun.COM uint16_t ret; 23858410SWang.Lin@Sun.COM uint16_t val; 23868410SWang.Lin@Sun.COM int len; 23878410SWang.Lin@Sun.COM int err = 0; 23888410SWang.Lin@Sun.COM wl_essid_t ow_essid; 23898410SWang.Lin@Sun.COM pcwl_rf_t *rf_p; 23908410SWang.Lin@Sun.COM 23918410SWang.Lin@Sun.COM rf_p = &pcwl_p->pcwl_rf; 23928410SWang.Lin@Sun.COM bzero(&ow_essid, sizeof (wl_essid_t)); 23938410SWang.Lin@Sun.COM bzero(ssid, sizeof (ssid)); 23948410SWang.Lin@Sun.COM 23958410SWang.Lin@Sun.COM ret = pcwl_get_ltv(pcwl_p, 2, WL_RID_PORTSTATUS, &val); 23968410SWang.Lin@Sun.COM if (ret) { 23978410SWang.Lin@Sun.COM err = EIO; 23988410SWang.Lin@Sun.COM return (err); 23998410SWang.Lin@Sun.COM } 24008410SWang.Lin@Sun.COM PCWLDBG((CE_NOTE, "PortStatus = %d\n", val)); 24018410SWang.Lin@Sun.COM 24028410SWang.Lin@Sun.COM switch (val) { 24038410SWang.Lin@Sun.COM case WL_PORT_DISABLED: 24048410SWang.Lin@Sun.COM case WL_PORT_INITIAL: 24058410SWang.Lin@Sun.COM len = mi_strlen(rf_p->rf_desired_ssid); 24068410SWang.Lin@Sun.COM ow_essid.wl_essid_length = len; 24078410SWang.Lin@Sun.COM bcopy(rf_p->rf_desired_ssid, ow_essid.wl_essid_essid, 24088410SWang.Lin@Sun.COM len); 24098410SWang.Lin@Sun.COM break; 24108410SWang.Lin@Sun.COM case WL_PORT_TO_IBSS: 24118410SWang.Lin@Sun.COM case WL_PORT_TO_BSS: 24128410SWang.Lin@Sun.COM case WL_PORT_OOR: 24138410SWang.Lin@Sun.COM (void) pcwl_get_ltv((pcwl_p), 34, WL_RID_SSID, 24148410SWang.Lin@Sun.COM (uint16_t *)ssid); 24158410SWang.Lin@Sun.COM PCWL_SWAP16((uint16_t *)(ssid+2), *(uint16_t *)ssid); 24168410SWang.Lin@Sun.COM ssid[*(uint16_t *)ssid + 2] = '\0'; 24178410SWang.Lin@Sun.COM len = mi_strlen(ssid+2); 24188410SWang.Lin@Sun.COM ow_essid.wl_essid_length = len; 24198410SWang.Lin@Sun.COM bcopy(ssid + 2, ow_essid.wl_essid_essid, len); 24208410SWang.Lin@Sun.COM break; 24218410SWang.Lin@Sun.COM default: 24228410SWang.Lin@Sun.COM err = EINVAL; 24238410SWang.Lin@Sun.COM break; 24248410SWang.Lin@Sun.COM } 24258410SWang.Lin@Sun.COM 24268410SWang.Lin@Sun.COM bcopy(&ow_essid, wldp_buf, sizeof (wl_essid_t)); 24278410SWang.Lin@Sun.COM 24288410SWang.Lin@Sun.COM return (err); 24298410SWang.Lin@Sun.COM } 24308410SWang.Lin@Sun.COM 24318410SWang.Lin@Sun.COM /* 24328410SWang.Lin@Sun.COM * MAC_PROP_WL_BSSID 24338410SWang.Lin@Sun.COM */ 24348410SWang.Lin@Sun.COM static int 24358410SWang.Lin@Sun.COM pcwl_get_bssid(pcwl_maci_t *pcwl_p, void *wldp_buf) 24368410SWang.Lin@Sun.COM { 24378410SWang.Lin@Sun.COM uint16_t ret; 24388410SWang.Lin@Sun.COM uint16_t retval; 24398410SWang.Lin@Sun.COM uint8_t bssid[6]; 24408410SWang.Lin@Sun.COM int err = 0; 24418410SWang.Lin@Sun.COM 24428410SWang.Lin@Sun.COM if (ret = pcwl_get_ltv(pcwl_p, 2, WL_RID_PORTSTATUS, &retval)) { 24438410SWang.Lin@Sun.COM err = EIO; 24448410SWang.Lin@Sun.COM return (err); 24458410SWang.Lin@Sun.COM } 24468410SWang.Lin@Sun.COM 24478410SWang.Lin@Sun.COM PCWLDBG((CE_NOTE, "PortStatus = %d\n", ret)); 24488410SWang.Lin@Sun.COM 24498410SWang.Lin@Sun.COM if (retval == WL_PORT_DISABLED || retval == WL_PORT_INITIAL) { 24508410SWang.Lin@Sun.COM bzero(wldp_buf, sizeof (wl_bssid_t)); 24518410SWang.Lin@Sun.COM } else if (retval == WL_PORT_TO_IBSS || 24528410SWang.Lin@Sun.COM retval == WL_PORT_TO_BSS || retval == WL_PORT_OOR) { 24538410SWang.Lin@Sun.COM (void) pcwl_get_ltv(pcwl_p, 6, 24548410SWang.Lin@Sun.COM WL_RID_BSSID, (uint16_t *)bssid); 24558410SWang.Lin@Sun.COM PCWL_SWAP16((uint16_t *)bssid, 6); 24568410SWang.Lin@Sun.COM bcopy(bssid, wldp_buf, sizeof (wl_bssid_t)); 24578410SWang.Lin@Sun.COM } 24588410SWang.Lin@Sun.COM 24598410SWang.Lin@Sun.COM PCWLDBG((CE_CONT, "pcwl_get_bssid: bssid=%x %x %x %x %x %x\n", 24608410SWang.Lin@Sun.COM bssid[0], bssid[1], bssid[2], 24618410SWang.Lin@Sun.COM bssid[3], bssid[4], bssid[5])); 24628410SWang.Lin@Sun.COM 24638410SWang.Lin@Sun.COM return (err); 24648410SWang.Lin@Sun.COM } 24658410SWang.Lin@Sun.COM 24668410SWang.Lin@Sun.COM /* 24678410SWang.Lin@Sun.COM * MAC_PROP_WL_LINKSTATUS 24688410SWang.Lin@Sun.COM */ 24698410SWang.Lin@Sun.COM static int 24708410SWang.Lin@Sun.COM pcwl_get_linkstatus(pcwl_maci_t *pcwl_p, void *wldp_buf) 24718410SWang.Lin@Sun.COM { 24728410SWang.Lin@Sun.COM uint16_t ret; 24738410SWang.Lin@Sun.COM uint16_t retval; 24748410SWang.Lin@Sun.COM int err = 0; 24758410SWang.Lin@Sun.COM 24768410SWang.Lin@Sun.COM ret = pcwl_get_ltv(pcwl_p, 2, WL_RID_PORTSTATUS, &retval); 24778410SWang.Lin@Sun.COM if (ret) { 24788410SWang.Lin@Sun.COM err = EIO; 24798410SWang.Lin@Sun.COM PCWLDBG((CE_WARN, "cfg_linkstatus_get_error\n")); 24808410SWang.Lin@Sun.COM return (err); 24818410SWang.Lin@Sun.COM } 24828410SWang.Lin@Sun.COM PCWLDBG((CE_NOTE, "PortStatus = %d\n", retval)); 24838410SWang.Lin@Sun.COM 24848410SWang.Lin@Sun.COM switch (retval) { 24858410SWang.Lin@Sun.COM case WL_PORT_DISABLED: 24868410SWang.Lin@Sun.COM case WL_PORT_INITIAL: 24878410SWang.Lin@Sun.COM *(wl_linkstatus_t *)wldp_buf = WL_NOTCONNECTED; 24888410SWang.Lin@Sun.COM break; 24898410SWang.Lin@Sun.COM case WL_PORT_TO_IBSS: 24908410SWang.Lin@Sun.COM case WL_PORT_TO_BSS: 24918410SWang.Lin@Sun.COM case WL_PORT_OOR: 24928410SWang.Lin@Sun.COM *(wl_linkstatus_t *)wldp_buf = WL_CONNECTED; 24938410SWang.Lin@Sun.COM break; 24948410SWang.Lin@Sun.COM default: 24958410SWang.Lin@Sun.COM err = EINVAL; 24968410SWang.Lin@Sun.COM break; 24978410SWang.Lin@Sun.COM } 24988410SWang.Lin@Sun.COM 24998410SWang.Lin@Sun.COM return (err); 25008410SWang.Lin@Sun.COM } 25018410SWang.Lin@Sun.COM 25028410SWang.Lin@Sun.COM /* 25038410SWang.Lin@Sun.COM * MAC_PROP_WL_BSSTYP 25048410SWang.Lin@Sun.COM */ 25058410SWang.Lin@Sun.COM static int 25068410SWang.Lin@Sun.COM pcwl_set_bsstype(pcwl_maci_t *pcwl_p, const void *wldp_buf) 25078410SWang.Lin@Sun.COM { 25088410SWang.Lin@Sun.COM uint16_t ret; 25098410SWang.Lin@Sun.COM pcwl_rf_t *rf_p; 25108410SWang.Lin@Sun.COM int err = ENETRESET; 25118410SWang.Lin@Sun.COM 25128410SWang.Lin@Sun.COM rf_p = &pcwl_p->pcwl_rf; 25138410SWang.Lin@Sun.COM 25148410SWang.Lin@Sun.COM ret = (uint16_t)(*(wl_bss_type_t *)wldp_buf); 25158410SWang.Lin@Sun.COM if ((ret != WL_BSS_BSS) && 25168410SWang.Lin@Sun.COM (ret != WL_BSS_IBSS) && 25178410SWang.Lin@Sun.COM (ret != WL_BSS_ANY)) { 25188410SWang.Lin@Sun.COM err = ENOTSUP; 25198410SWang.Lin@Sun.COM return (err); 25208410SWang.Lin@Sun.COM } 25218410SWang.Lin@Sun.COM 25228410SWang.Lin@Sun.COM rf_p->rf_porttype = ret; 25238410SWang.Lin@Sun.COM 25248410SWang.Lin@Sun.COM return (err); 25258410SWang.Lin@Sun.COM } 25268410SWang.Lin@Sun.COM 25278410SWang.Lin@Sun.COM static void 25288410SWang.Lin@Sun.COM pcwl_get_bsstype(pcwl_maci_t *pcwl_p, void *wldp_buf) 25298410SWang.Lin@Sun.COM { 25308410SWang.Lin@Sun.COM pcwl_rf_t *rf_p; 25318410SWang.Lin@Sun.COM 25328410SWang.Lin@Sun.COM rf_p = &pcwl_p->pcwl_rf; 25338410SWang.Lin@Sun.COM 25348410SWang.Lin@Sun.COM *(wl_bss_type_t *)wldp_buf = rf_p->rf_porttype; 25358410SWang.Lin@Sun.COM 25368410SWang.Lin@Sun.COM PCWLDBG((CE_CONT, "pcwl_get_bsstype: porttype=%d\n", 25378410SWang.Lin@Sun.COM rf_p->rf_porttype)); 25388410SWang.Lin@Sun.COM } 25398410SWang.Lin@Sun.COM 25408410SWang.Lin@Sun.COM /* 25418410SWang.Lin@Sun.COM * MAC_PROP_WL_PHY_CONFIG 25428410SWang.Lin@Sun.COM */ 25438410SWang.Lin@Sun.COM static int 25448410SWang.Lin@Sun.COM pcwl_set_phy(pcwl_maci_t *pcwl_p, const void *wldp_buf) 25458410SWang.Lin@Sun.COM { 25468410SWang.Lin@Sun.COM uint16_t ret; 25478410SWang.Lin@Sun.COM pcwl_rf_t *rf_p; 25488410SWang.Lin@Sun.COM int err = ENETRESET; 25498410SWang.Lin@Sun.COM wl_phy_conf_t *phy = (wl_phy_conf_t *)wldp_buf; 25508410SWang.Lin@Sun.COM 25518410SWang.Lin@Sun.COM rf_p = &pcwl_p->pcwl_rf; 25528410SWang.Lin@Sun.COM ret = (uint16_t)(phy->wl_phy_dsss_conf.wl_dsss_channel); 25538410SWang.Lin@Sun.COM if (ret < 1 || ret > 14) { 25548410SWang.Lin@Sun.COM err = ENOTSUP; 25558410SWang.Lin@Sun.COM return (err); 25568410SWang.Lin@Sun.COM } 25578410SWang.Lin@Sun.COM 25588410SWang.Lin@Sun.COM rf_p->rf_own_chnl = ret; 25598410SWang.Lin@Sun.COM 25608410SWang.Lin@Sun.COM PCWLDBG((CE_CONT, "pcwl: set channel=%d\n", rf_p->rf_own_chnl)); 25618410SWang.Lin@Sun.COM 25628410SWang.Lin@Sun.COM return (err); 25638410SWang.Lin@Sun.COM } 25648410SWang.Lin@Sun.COM 25658410SWang.Lin@Sun.COM static int 25668410SWang.Lin@Sun.COM pcwl_get_phy(pcwl_maci_t *pcwl_p, void *wldp_buf) 25678410SWang.Lin@Sun.COM { 25688410SWang.Lin@Sun.COM uint16_t retval; 25698410SWang.Lin@Sun.COM wl_dsss_t *dsss = (wl_dsss_t *)wldp_buf; 25708410SWang.Lin@Sun.COM int err = 0; 25718410SWang.Lin@Sun.COM 25728410SWang.Lin@Sun.COM if (pcwl_get_ltv(pcwl_p, 2, WL_RID_CURRENT_CHNL, &retval)) { 25738410SWang.Lin@Sun.COM err = EIO; 25748410SWang.Lin@Sun.COM return (err); 25758410SWang.Lin@Sun.COM } 25768410SWang.Lin@Sun.COM 25778410SWang.Lin@Sun.COM dsss->wl_dsss_channel = retval; 25788410SWang.Lin@Sun.COM PCWLDBG((CE_CONT, "pcwl_get_phy: channel=%d\n", retval)); 25798410SWang.Lin@Sun.COM dsss->wl_dsss_subtype = WL_DSSS; 25808410SWang.Lin@Sun.COM 25818410SWang.Lin@Sun.COM return (err); 25828410SWang.Lin@Sun.COM } 25838410SWang.Lin@Sun.COM 25848410SWang.Lin@Sun.COM /* 25858410SWang.Lin@Sun.COM * MAC_PROP_WL_DESIRED_RATESa 25868410SWang.Lin@Sun.COM */ 25878410SWang.Lin@Sun.COM static int 25888410SWang.Lin@Sun.COM pcwl_set_desrates(pcwl_maci_t *pcwl_p, const void *wldp_buf) 25898410SWang.Lin@Sun.COM { 25908410SWang.Lin@Sun.COM int err = ENETRESET; 25918410SWang.Lin@Sun.COM char rates[4]; 25928410SWang.Lin@Sun.COM char maxrate; 25938410SWang.Lin@Sun.COM uint16_t i; 25948410SWang.Lin@Sun.COM pcwl_rf_t *rf_p; 25958410SWang.Lin@Sun.COM wl_rates_t *iw_rates = (wl_rates_t *)wldp_buf; 25968410SWang.Lin@Sun.COM 25978410SWang.Lin@Sun.COM rf_p = &pcwl_p->pcwl_rf; 25988410SWang.Lin@Sun.COM 25998410SWang.Lin@Sun.COM bzero(rates, sizeof (rates)); 26008410SWang.Lin@Sun.COM 26018410SWang.Lin@Sun.COM for (i = 0; i < 4; i++) { 26028410SWang.Lin@Sun.COM rates[i] = iw_rates->wl_rates_rates[i]; 26038410SWang.Lin@Sun.COM PCWLDBG((CE_CONT, "pcwl: set tx_rate[%d]=%d\n", i, rates[i])); 26048410SWang.Lin@Sun.COM } 26058410SWang.Lin@Sun.COM PCWLDBG((CE_CONT, "pcwl: set rate_num=%d\n", iw_rates->wl_rates_num)); 26068410SWang.Lin@Sun.COM 26078410SWang.Lin@Sun.COM switch (iw_rates->wl_rates_num) { 26088410SWang.Lin@Sun.COM case 1: 26098410SWang.Lin@Sun.COM switch (rates[0]) { 26108410SWang.Lin@Sun.COM case WL_RATE_1M: 26118410SWang.Lin@Sun.COM rf_p->rf_tx_rate = WL_TX_RATE_FIX_1M(pcwl_p); 26128410SWang.Lin@Sun.COM break; 26138410SWang.Lin@Sun.COM case WL_RATE_2M: 26148410SWang.Lin@Sun.COM rf_p->rf_tx_rate = WL_TX_RATE_FIX_2M(pcwl_p); 26158410SWang.Lin@Sun.COM break; 26168410SWang.Lin@Sun.COM case WL_RATE_11M: 26178410SWang.Lin@Sun.COM rf_p->rf_tx_rate = WL_TX_RATE_FIX_11M(pcwl_p); 26188410SWang.Lin@Sun.COM break; 26198410SWang.Lin@Sun.COM case WL_RATE_5_5M: 26208410SWang.Lin@Sun.COM rf_p->rf_tx_rate = WL_TX_RATE_FIX_5M(pcwl_p); 26218410SWang.Lin@Sun.COM break; 26228410SWang.Lin@Sun.COM default: 26238410SWang.Lin@Sun.COM err = EINVAL; 26248410SWang.Lin@Sun.COM break; 26258410SWang.Lin@Sun.COM } 26268410SWang.Lin@Sun.COM break; 26278410SWang.Lin@Sun.COM case 2: 26288410SWang.Lin@Sun.COM maxrate = (rates[0] > rates[1] ? rates[0] : rates[1]); 26298410SWang.Lin@Sun.COM switch (maxrate) { 26308410SWang.Lin@Sun.COM case WL_RATE_2M: 26318410SWang.Lin@Sun.COM rf_p->rf_tx_rate = WL_TX_RATE_AUTO_L(pcwl_p); 26328410SWang.Lin@Sun.COM break; 26338410SWang.Lin@Sun.COM case WL_RATE_11M: 26348410SWang.Lin@Sun.COM rf_p->rf_tx_rate = WL_TX_RATE_AUTO_H(pcwl_p); 26358410SWang.Lin@Sun.COM break; 26368410SWang.Lin@Sun.COM case WL_RATE_5_5M: 26378410SWang.Lin@Sun.COM rf_p->rf_tx_rate = WL_TX_RATE_AUTO_M(pcwl_p); 26388410SWang.Lin@Sun.COM break; 26398410SWang.Lin@Sun.COM default: 26408410SWang.Lin@Sun.COM err = EINVAL; 26418410SWang.Lin@Sun.COM break; 26428410SWang.Lin@Sun.COM } 26438410SWang.Lin@Sun.COM break; 26448410SWang.Lin@Sun.COM case 3: 26458410SWang.Lin@Sun.COM maxrate = (rates[0] > rates[1] ? rates[0] : rates[1]); 26468410SWang.Lin@Sun.COM maxrate = (rates[2] > maxrate ? rates[2] : maxrate); 26478410SWang.Lin@Sun.COM switch (maxrate) { 26488410SWang.Lin@Sun.COM case WL_RATE_11M: 26498410SWang.Lin@Sun.COM rf_p->rf_tx_rate = WL_TX_RATE_AUTO_H(pcwl_p); 26508410SWang.Lin@Sun.COM break; 26518410SWang.Lin@Sun.COM case WL_RATE_5_5M: 26528410SWang.Lin@Sun.COM rf_p->rf_tx_rate = WL_TX_RATE_AUTO_M(pcwl_p); 26538410SWang.Lin@Sun.COM break; 26548410SWang.Lin@Sun.COM default: 26558410SWang.Lin@Sun.COM err = EINVAL; 26568410SWang.Lin@Sun.COM break; 26578410SWang.Lin@Sun.COM } 26588410SWang.Lin@Sun.COM break; 26598410SWang.Lin@Sun.COM case 4: 26608410SWang.Lin@Sun.COM rf_p->rf_tx_rate = WL_TX_RATE_AUTO_H(pcwl_p); 26618410SWang.Lin@Sun.COM break; 26628410SWang.Lin@Sun.COM default: 26638410SWang.Lin@Sun.COM err = ENOTSUP; 26648410SWang.Lin@Sun.COM break; 26658410SWang.Lin@Sun.COM } 26668410SWang.Lin@Sun.COM PCWLDBG((CE_CONT, "pcwl: set tx_rate=%d\n", rf_p->rf_tx_rate)); 26678410SWang.Lin@Sun.COM 26688410SWang.Lin@Sun.COM return (err); 26698410SWang.Lin@Sun.COM } 26708410SWang.Lin@Sun.COM 26718410SWang.Lin@Sun.COM static int 26728410SWang.Lin@Sun.COM pcwl_get_desrates(pcwl_maci_t *pcwl_p, void *wldp_buf) 26738410SWang.Lin@Sun.COM { 26748410SWang.Lin@Sun.COM uint16_t rate; 26758410SWang.Lin@Sun.COM int err = 0; 26768410SWang.Lin@Sun.COM 26778410SWang.Lin@Sun.COM if (pcwl_get_ltv(pcwl_p, 2, WL_RID_TX_RATE, &rate)) { 26788410SWang.Lin@Sun.COM err = EIO; 26798410SWang.Lin@Sun.COM return (err); 26808410SWang.Lin@Sun.COM } 26818410SWang.Lin@Sun.COM 26828410SWang.Lin@Sun.COM if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) { 26838410SWang.Lin@Sun.COM ((wl_rates_t *)wldp_buf)->wl_rates_num = 1; 26848410SWang.Lin@Sun.COM switch (rate) { 26858410SWang.Lin@Sun.COM case WL_SPEED_1Mbps_P2: 26868410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] = 26878410SWang.Lin@Sun.COM WL_RATE_1M; 26888410SWang.Lin@Sun.COM break; 26898410SWang.Lin@Sun.COM case WL_SPEED_2Mbps_P2: 26908410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] = 26918410SWang.Lin@Sun.COM WL_RATE_2M; 26928410SWang.Lin@Sun.COM break; 26938410SWang.Lin@Sun.COM case WL_SPEED_55Mbps_P2: 26948410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] = 26958410SWang.Lin@Sun.COM WL_RATE_5_5M; 26968410SWang.Lin@Sun.COM break; 26978410SWang.Lin@Sun.COM case WL_SPEED_11Mbps_P2: 26988410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] = 26998410SWang.Lin@Sun.COM WL_RATE_11M; 27008410SWang.Lin@Sun.COM break; 27018410SWang.Lin@Sun.COM default: 27028410SWang.Lin@Sun.COM err = EINVAL; 27038410SWang.Lin@Sun.COM break; 27048410SWang.Lin@Sun.COM } 27058410SWang.Lin@Sun.COM } else { 27068410SWang.Lin@Sun.COM switch (rate) { 27078410SWang.Lin@Sun.COM case WL_L_TX_RATE_FIX_1M: 27088410SWang.Lin@Sun.COM ((wl_rates_t *)wldp_buf)->wl_rates_num = 1; 27098410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] = 27108410SWang.Lin@Sun.COM WL_RATE_1M; 27118410SWang.Lin@Sun.COM break; 27128410SWang.Lin@Sun.COM case WL_L_TX_RATE_FIX_2M: 27138410SWang.Lin@Sun.COM ((wl_rates_t *)wldp_buf)->wl_rates_num = 1; 27148410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] = 27158410SWang.Lin@Sun.COM WL_RATE_2M; 27168410SWang.Lin@Sun.COM break; 27178410SWang.Lin@Sun.COM case WL_L_TX_RATE_AUTO_H: 27188410SWang.Lin@Sun.COM ((wl_rates_t *)wldp_buf)->wl_rates_num = 4; 27198410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] = 27208410SWang.Lin@Sun.COM WL_RATE_1M; 27218410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[1] = 27228410SWang.Lin@Sun.COM WL_RATE_2M; 27238410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[2] = 27248410SWang.Lin@Sun.COM WL_RATE_5_5M; 27258410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[3] = 27268410SWang.Lin@Sun.COM WL_RATE_11M; 27278410SWang.Lin@Sun.COM break; 27288410SWang.Lin@Sun.COM case WL_L_TX_RATE_FIX_5M: 27298410SWang.Lin@Sun.COM ((wl_rates_t *)wldp_buf)->wl_rates_num = 1; 27308410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] = 27318410SWang.Lin@Sun.COM WL_RATE_5_5M; 27328410SWang.Lin@Sun.COM break; 27338410SWang.Lin@Sun.COM case WL_L_TX_RATE_FIX_11M: 27348410SWang.Lin@Sun.COM ((wl_rates_t *)wldp_buf)->wl_rates_num = 1; 27358410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] = 27368410SWang.Lin@Sun.COM WL_RATE_11M; 27378410SWang.Lin@Sun.COM break; 27388410SWang.Lin@Sun.COM case WL_L_TX_RATE_AUTO_L: 27398410SWang.Lin@Sun.COM ((wl_rates_t *)wldp_buf)->wl_rates_num = 2; 27408410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] = 27418410SWang.Lin@Sun.COM WL_RATE_1M; 27428410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[1] = 27438410SWang.Lin@Sun.COM WL_RATE_2M; 27448410SWang.Lin@Sun.COM break; 27458410SWang.Lin@Sun.COM case WL_L_TX_RATE_AUTO_M: 27468410SWang.Lin@Sun.COM ((wl_rates_t *)wldp_buf)->wl_rates_num = 3; 27478410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] = 27488410SWang.Lin@Sun.COM WL_RATE_1M; 27498410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[1] = 27508410SWang.Lin@Sun.COM WL_RATE_2M; 27518410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[2] = 27528410SWang.Lin@Sun.COM WL_RATE_5_5M; 27538410SWang.Lin@Sun.COM break; 27548410SWang.Lin@Sun.COM default: 27558410SWang.Lin@Sun.COM err = EINVAL; 27568410SWang.Lin@Sun.COM break; 27578410SWang.Lin@Sun.COM } 27588410SWang.Lin@Sun.COM } 27598410SWang.Lin@Sun.COM PCWLDBG((CE_CONT, "pcwl: get rate=%d\n", rate)); 27608410SWang.Lin@Sun.COM 27618410SWang.Lin@Sun.COM return (err); 27628410SWang.Lin@Sun.COM } 27638410SWang.Lin@Sun.COM 27648410SWang.Lin@Sun.COM /* 27658410SWang.Lin@Sun.COM * MAC_PROP_WL_SUP_RATE 27668410SWang.Lin@Sun.COM */ 27678410SWang.Lin@Sun.COM static void 27688410SWang.Lin@Sun.COM pcwl_get_suprates(void *wldp_buf) 27698410SWang.Lin@Sun.COM { 27708410SWang.Lin@Sun.COM wl_rates_t *wl_rates = (wl_rates_t *)wldp_buf; 27718410SWang.Lin@Sun.COM 27728410SWang.Lin@Sun.COM wl_rates->wl_rates_num = 4; 27738410SWang.Lin@Sun.COM wl_rates->wl_rates_rates[0] = WL_RATE_1M; 27748410SWang.Lin@Sun.COM wl_rates->wl_rates_rates[1] = WL_RATE_2M; 27758410SWang.Lin@Sun.COM wl_rates->wl_rates_rates[2] = WL_RATE_5_5M; 27768410SWang.Lin@Sun.COM wl_rates->wl_rates_rates[3] = WL_RATE_11M; 27778410SWang.Lin@Sun.COM } 27788410SWang.Lin@Sun.COM 27798410SWang.Lin@Sun.COM /* 27808410SWang.Lin@Sun.COM * MAC_PROP_WL_POWER_MODE 27818410SWang.Lin@Sun.COM */ 27828410SWang.Lin@Sun.COM static int 27838410SWang.Lin@Sun.COM pcwl_set_powermode(pcwl_maci_t *pcwl_p, const void *wldp_buf) 27848410SWang.Lin@Sun.COM { 27858410SWang.Lin@Sun.COM uint16_t ret; 27868410SWang.Lin@Sun.COM pcwl_rf_t *rf_p; 27878410SWang.Lin@Sun.COM int err = 0; 27888410SWang.Lin@Sun.COM 27898410SWang.Lin@Sun.COM rf_p = &pcwl_p->pcwl_rf; 27908410SWang.Lin@Sun.COM 27918410SWang.Lin@Sun.COM ret = (uint16_t)(((wl_ps_mode_t *)wldp_buf)->wl_ps_mode); 27928410SWang.Lin@Sun.COM if (ret != WL_PM_AM && ret != WL_PM_MPS && ret != WL_PM_FAST) { 27938410SWang.Lin@Sun.COM err = ENOTSUP; 27948410SWang.Lin@Sun.COM return (err); 27958410SWang.Lin@Sun.COM } 27968410SWang.Lin@Sun.COM 27978410SWang.Lin@Sun.COM rf_p->rf_pm_enabled = ret; 27988410SWang.Lin@Sun.COM 27998410SWang.Lin@Sun.COM return (err); 28008410SWang.Lin@Sun.COM 28018410SWang.Lin@Sun.COM } 28028410SWang.Lin@Sun.COM 28038410SWang.Lin@Sun.COM static void 28048410SWang.Lin@Sun.COM pcwl_get_powermode(pcwl_maci_t *pcwl_p, void *wldp_buf) 28058410SWang.Lin@Sun.COM { 28068410SWang.Lin@Sun.COM pcwl_rf_t *rf_p; 28078410SWang.Lin@Sun.COM 28088410SWang.Lin@Sun.COM rf_p = &pcwl_p->pcwl_rf; 28098410SWang.Lin@Sun.COM ((wl_ps_mode_t *)wldp_buf)->wl_ps_mode = rf_p->rf_pm_enabled; 28108410SWang.Lin@Sun.COM } 28118410SWang.Lin@Sun.COM 28128410SWang.Lin@Sun.COM /* 28138410SWang.Lin@Sun.COM * MAC_PROP_AUTH_MODE 28148410SWang.Lin@Sun.COM */ 28158410SWang.Lin@Sun.COM static int 28168410SWang.Lin@Sun.COM pcwl_set_authmode(pcwl_maci_t *pcwl_p, const void *wldp_buf) 28178410SWang.Lin@Sun.COM { 28188410SWang.Lin@Sun.COM uint16_t ret; 28198410SWang.Lin@Sun.COM pcwl_rf_t *rf_p; 28208410SWang.Lin@Sun.COM int err = ENETRESET; 28218410SWang.Lin@Sun.COM 28228410SWang.Lin@Sun.COM rf_p = &pcwl_p->pcwl_rf; 28238410SWang.Lin@Sun.COM 28248410SWang.Lin@Sun.COM ret = (uint16_t)(*(wl_authmode_t *)wldp_buf); 28258410SWang.Lin@Sun.COM if (ret != WL_OPENSYSTEM && ret != WL_SHAREDKEY) { 28268410SWang.Lin@Sun.COM err = ENOTSUP; 28278410SWang.Lin@Sun.COM return (err); 28288410SWang.Lin@Sun.COM } 28298410SWang.Lin@Sun.COM 28308410SWang.Lin@Sun.COM rf_p->rf_authtype = ret; 28318410SWang.Lin@Sun.COM 28328410SWang.Lin@Sun.COM return (err); 28338410SWang.Lin@Sun.COM } 28348410SWang.Lin@Sun.COM 28358410SWang.Lin@Sun.COM static void 28368410SWang.Lin@Sun.COM pcwl_get_authmode(pcwl_maci_t *pcwl_p, void *wldp_buf) 28378410SWang.Lin@Sun.COM { 28388410SWang.Lin@Sun.COM pcwl_rf_t *rf_p; 28398410SWang.Lin@Sun.COM 28408410SWang.Lin@Sun.COM rf_p = &pcwl_p->pcwl_rf; 28418410SWang.Lin@Sun.COM *(wl_authmode_t *)wldp_buf = rf_p->rf_authtype; 28428410SWang.Lin@Sun.COM } 28438410SWang.Lin@Sun.COM 28448410SWang.Lin@Sun.COM /* 28458410SWang.Lin@Sun.COM * MAC_PROP_WL_ENCRYPTION 28468410SWang.Lin@Sun.COM */ 28478410SWang.Lin@Sun.COM static int 28488410SWang.Lin@Sun.COM pcwl_set_encrypt(pcwl_maci_t *pcwl_p, const void *wldp_buf) 28498410SWang.Lin@Sun.COM { 28508410SWang.Lin@Sun.COM uint16_t ret; 28518410SWang.Lin@Sun.COM pcwl_rf_t *rf_p; 28528410SWang.Lin@Sun.COM int err = ENETRESET; 28538410SWang.Lin@Sun.COM 28548410SWang.Lin@Sun.COM rf_p = &pcwl_p->pcwl_rf; 28558410SWang.Lin@Sun.COM 28568410SWang.Lin@Sun.COM ret = (uint16_t)(*(wl_encryption_t *)wldp_buf); 28578410SWang.Lin@Sun.COM PCWLDBG((CE_NOTE, "pcwl_set_encrypt: %d\n", ret)); 28588410SWang.Lin@Sun.COM if (ret != WL_NOENCRYPTION && ret != WL_ENC_WEP) { 28598410SWang.Lin@Sun.COM err = ENOTSUP; 28608410SWang.Lin@Sun.COM return (err); 28618410SWang.Lin@Sun.COM } 28628410SWang.Lin@Sun.COM 28638410SWang.Lin@Sun.COM rf_p->rf_encryption = ret; 28648410SWang.Lin@Sun.COM 28658410SWang.Lin@Sun.COM return (err); 28668410SWang.Lin@Sun.COM } 28678410SWang.Lin@Sun.COM 28688410SWang.Lin@Sun.COM static void 28698410SWang.Lin@Sun.COM pcwl_get_encrypt(pcwl_maci_t *pcwl_p, void *wldp_buf) 28708410SWang.Lin@Sun.COM { 28718410SWang.Lin@Sun.COM pcwl_rf_t *rf_p; 28728410SWang.Lin@Sun.COM 28738410SWang.Lin@Sun.COM rf_p = &pcwl_p->pcwl_rf; 28748410SWang.Lin@Sun.COM *(wl_encryption_t *)wldp_buf = rf_p->rf_encryption; 28758410SWang.Lin@Sun.COM } 28768410SWang.Lin@Sun.COM 28778410SWang.Lin@Sun.COM /* 28788410SWang.Lin@Sun.COM * MAC_PROP_WL_CREATE_IBSS 28798410SWang.Lin@Sun.COM */ 28808410SWang.Lin@Sun.COM static int 28818410SWang.Lin@Sun.COM pcwl_set_ibss(pcwl_maci_t *pcwl_p, const void *wldp_buf) 28828410SWang.Lin@Sun.COM { 28838410SWang.Lin@Sun.COM uint16_t ret; 28848410SWang.Lin@Sun.COM pcwl_rf_t *rf_p; 28858410SWang.Lin@Sun.COM int err = ENETRESET; 28868410SWang.Lin@Sun.COM 28878410SWang.Lin@Sun.COM rf_p = &pcwl_p->pcwl_rf; 28888410SWang.Lin@Sun.COM 28898410SWang.Lin@Sun.COM ret = (uint16_t)(*(wl_create_ibss_t *)wldp_buf); 28908410SWang.Lin@Sun.COM if (ret != 0 && ret != 1) { 28918410SWang.Lin@Sun.COM err = ENOTSUP; 28928410SWang.Lin@Sun.COM return (err); 28938410SWang.Lin@Sun.COM } 28948410SWang.Lin@Sun.COM 28958410SWang.Lin@Sun.COM rf_p->rf_create_ibss = ret; 28968410SWang.Lin@Sun.COM 28978410SWang.Lin@Sun.COM return (err); 28988410SWang.Lin@Sun.COM } 28998410SWang.Lin@Sun.COM 29008410SWang.Lin@Sun.COM static void 29018410SWang.Lin@Sun.COM pcwl_get_ibss(pcwl_maci_t *pcwl_p, void *wldp_buf) 29028410SWang.Lin@Sun.COM { 29038410SWang.Lin@Sun.COM pcwl_rf_t *rf_p; 29048410SWang.Lin@Sun.COM 29058410SWang.Lin@Sun.COM rf_p = &pcwl_p->pcwl_rf; 29068410SWang.Lin@Sun.COM *(wl_create_ibss_t *)wldp_buf = rf_p->rf_create_ibss; 29078410SWang.Lin@Sun.COM } 29088410SWang.Lin@Sun.COM 29098410SWang.Lin@Sun.COM /* 29108410SWang.Lin@Sun.COM * MAC_PROP_WL_RSSI 29118410SWang.Lin@Sun.COM */ 29128410SWang.Lin@Sun.COM static void 29138410SWang.Lin@Sun.COM pcwl_get_param_rssi(pcwl_maci_t *pcwl_p, void *wldp_buf) 29148410SWang.Lin@Sun.COM { 29158410SWang.Lin@Sun.COM 29168410SWang.Lin@Sun.COM if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) { 29178410SWang.Lin@Sun.COM *(wl_rssi_t *)wldp_buf = 29188410SWang.Lin@Sun.COM min((pcwl_p->pcwl_rssi * 15 / 85 + 1), 15); 29198410SWang.Lin@Sun.COM } else { 29208410SWang.Lin@Sun.COM /* 29218410SWang.Lin@Sun.COM * According to the description of the 29228410SWang.Lin@Sun.COM * datasheet(Lucent card), the signal level 29238410SWang.Lin@Sun.COM * value is between 27 -- 154. 29248410SWang.Lin@Sun.COM * we reflect these value to 1-15 as rssi. 29258410SWang.Lin@Sun.COM */ 29268410SWang.Lin@Sun.COM if (pcwl_p->pcwl_rssi <= 27) 29278410SWang.Lin@Sun.COM *(wl_rssi_t *)wldp_buf = 1; 29288410SWang.Lin@Sun.COM else if (pcwl_p->pcwl_rssi > 154) 29298410SWang.Lin@Sun.COM *(wl_rssi_t *)wldp_buf = 15; 29308410SWang.Lin@Sun.COM else 29318410SWang.Lin@Sun.COM *(wl_rssi_t *)wldp_buf = 29328410SWang.Lin@Sun.COM min(15, ((pcwl_p->pcwl_rssi - 27) * 15 / 127)); 29338410SWang.Lin@Sun.COM } 29348410SWang.Lin@Sun.COM } 29358410SWang.Lin@Sun.COM 29368410SWang.Lin@Sun.COM /* 29378410SWang.Lin@Sun.COM * MAC_PROP_WL_KEY_TAB 29388410SWang.Lin@Sun.COM */ 29398410SWang.Lin@Sun.COM static int 29408410SWang.Lin@Sun.COM pcwl_set_wepkey(pcwl_maci_t *pcwl_p, const void *wldp_buf) 29418410SWang.Lin@Sun.COM { 29428410SWang.Lin@Sun.COM uint16_t i; 29438410SWang.Lin@Sun.COM pcwl_rf_t *rf_p; 29448410SWang.Lin@Sun.COM wl_wep_key_t *p_wepkey_tab; 29458410SWang.Lin@Sun.COM 29468410SWang.Lin@Sun.COM rf_p = &pcwl_p->pcwl_rf; 29478410SWang.Lin@Sun.COM bzero((rf_p->rf_ckeys), sizeof (rf_ckey_t) * MAX_NWEPKEYS); 29488410SWang.Lin@Sun.COM 29498410SWang.Lin@Sun.COM p_wepkey_tab = (wl_wep_key_t *)wldp_buf; 29508410SWang.Lin@Sun.COM for (i = 0; i < MAX_NWEPKEYS; i++) { 29518410SWang.Lin@Sun.COM if (p_wepkey_tab[i].wl_wep_operation == WL_ADD) { 29528410SWang.Lin@Sun.COM rf_p->rf_ckeys[i].ckey_len = 29538410SWang.Lin@Sun.COM p_wepkey_tab[i].wl_wep_length; 29548410SWang.Lin@Sun.COM bcopy(p_wepkey_tab[i].wl_wep_key, 29558410SWang.Lin@Sun.COM rf_p->rf_ckeys[i].ckey_dat, 29568410SWang.Lin@Sun.COM p_wepkey_tab[i].wl_wep_length); 29578410SWang.Lin@Sun.COM PCWL_SWAP16((uint16_t *) 29588410SWang.Lin@Sun.COM &rf_p->rf_ckeys[i].ckey_dat, 29598410SWang.Lin@Sun.COM rf_p->rf_ckeys[i].ckey_len + 1); 29608410SWang.Lin@Sun.COM PCWLDBG((CE_CONT, "%s, %d\n", 29618410SWang.Lin@Sun.COM rf_p->rf_ckeys[i].ckey_dat, i)); 29628410SWang.Lin@Sun.COM } 29638410SWang.Lin@Sun.COM PCWLDBG((CE_CONT, "pcwl: rf_ckeys[%d]=%s\n", i, 29648410SWang.Lin@Sun.COM (char *)(rf_p->rf_ckeys[i].ckey_dat))); 29658410SWang.Lin@Sun.COM } 29668410SWang.Lin@Sun.COM 29678410SWang.Lin@Sun.COM return (ENETRESET); 29688410SWang.Lin@Sun.COM } 29698410SWang.Lin@Sun.COM 29708410SWang.Lin@Sun.COM /* 29718410SWang.Lin@Sun.COM * MAC_PROP_WL_RADIO 29728410SWang.Lin@Sun.COM */ 29738410SWang.Lin@Sun.COM static void 29748410SWang.Lin@Sun.COM pcwl_get_radio(void *wldp_buf) 29758410SWang.Lin@Sun.COM { 29768410SWang.Lin@Sun.COM wl_radio_t *radio = (wl_radio_t *)wldp_buf; 29778410SWang.Lin@Sun.COM 29788410SWang.Lin@Sun.COM *radio = B_TRUE; 29798410SWang.Lin@Sun.COM } 29808410SWang.Lin@Sun.COM 29818410SWang.Lin@Sun.COM /* 29828410SWang.Lin@Sun.COM * MAC_PROP_WL_ESSLIST 29838410SWang.Lin@Sun.COM */ 29848410SWang.Lin@Sun.COM static void 29858410SWang.Lin@Sun.COM pcwl_get_esslist(pcwl_maci_t *pcwl_p, void *wldp_buf) 29868410SWang.Lin@Sun.COM { 29878410SWang.Lin@Sun.COM uint16_t i; 29888410SWang.Lin@Sun.COM wl_ess_conf_t *p_ess_conf; 29898410SWang.Lin@Sun.COM wl_scan_list_t *scan_item; 29908410SWang.Lin@Sun.COM 29918410SWang.Lin@Sun.COM mutex_enter(&pcwl_p->pcwl_scanlist_lock); 29928410SWang.Lin@Sun.COM 29938410SWang.Lin@Sun.COM ((wl_ess_list_t *)wldp_buf)->wl_ess_list_num = 29948410SWang.Lin@Sun.COM pcwl_p->pcwl_scan_num; 29958410SWang.Lin@Sun.COM 29968410SWang.Lin@Sun.COM scan_item = list_head(&pcwl_p->pcwl_scan_list); 29978410SWang.Lin@Sun.COM 29988410SWang.Lin@Sun.COM for (i = 0; i < pcwl_p->pcwl_scan_num; i++) { 29998410SWang.Lin@Sun.COM if (!scan_item) 30008410SWang.Lin@Sun.COM break; 30018410SWang.Lin@Sun.COM 30028410SWang.Lin@Sun.COM p_ess_conf = (wl_ess_conf_t *)((char *)wldp_buf + 30038410SWang.Lin@Sun.COM offsetof(wl_ess_list_t, wl_ess_list_ess) + 30048410SWang.Lin@Sun.COM i * sizeof (wl_ess_conf_t)); 30058410SWang.Lin@Sun.COM bcopy(scan_item->wl_val.wl_srt_ssid, 30068410SWang.Lin@Sun.COM p_ess_conf->wl_ess_conf_essid.wl_essid_essid, 30078410SWang.Lin@Sun.COM mi_strlen(scan_item->wl_val.wl_srt_ssid)); 30088410SWang.Lin@Sun.COM bcopy(scan_item->wl_val.wl_srt_bssid, 30098410SWang.Lin@Sun.COM p_ess_conf->wl_ess_conf_bssid, 6); 30108410SWang.Lin@Sun.COM (p_ess_conf->wl_phy_conf).wl_phy_dsss_conf.wl_dsss_subtype 30118410SWang.Lin@Sun.COM = WL_DSSS; 30128410SWang.Lin@Sun.COM p_ess_conf->wl_ess_conf_wepenabled = 30138410SWang.Lin@Sun.COM (scan_item->wl_val.wl_srt_cap & 0x10 ? 30148410SWang.Lin@Sun.COM WL_ENC_WEP : WL_NOENCRYPTION); 30158410SWang.Lin@Sun.COM p_ess_conf->wl_ess_conf_bsstype = 30168410SWang.Lin@Sun.COM (scan_item->wl_val.wl_srt_cap & 0x1 ? 30178410SWang.Lin@Sun.COM WL_BSS_BSS : WL_BSS_IBSS); 30188410SWang.Lin@Sun.COM p_ess_conf->wl_phy_conf.wl_phy_dsss_conf.wl_dsss_channel = 30198410SWang.Lin@Sun.COM scan_item->wl_val.wl_srt_chid; 30208410SWang.Lin@Sun.COM if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) { 30218410SWang.Lin@Sun.COM p_ess_conf->wl_ess_conf_sl = 30228410SWang.Lin@Sun.COM min(scan_item->wl_val.wl_srt_sl * 15 / 85 + 1, 30238410SWang.Lin@Sun.COM 15); 30248410SWang.Lin@Sun.COM } else { 30258410SWang.Lin@Sun.COM if (scan_item->wl_val.wl_srt_sl <= 27) 30268410SWang.Lin@Sun.COM p_ess_conf->wl_ess_conf_sl = 1; 30278410SWang.Lin@Sun.COM else if (scan_item->wl_val.wl_srt_sl > 154) 30288410SWang.Lin@Sun.COM p_ess_conf->wl_ess_conf_sl = 15; 30298410SWang.Lin@Sun.COM else 30308410SWang.Lin@Sun.COM p_ess_conf->wl_ess_conf_sl = min(15, 30318410SWang.Lin@Sun.COM ((scan_item->wl_val.wl_srt_sl - 27) 30328410SWang.Lin@Sun.COM * 15 / 127)); 30338410SWang.Lin@Sun.COM } 30348410SWang.Lin@Sun.COM 30358410SWang.Lin@Sun.COM p_ess_conf->wl_supported_rates[0] = WL_RATE_1M; 30368410SWang.Lin@Sun.COM p_ess_conf->wl_supported_rates[0] = WL_RATE_2M; 30378410SWang.Lin@Sun.COM p_ess_conf->wl_supported_rates[0] = WL_RATE_5_5M; 30388410SWang.Lin@Sun.COM p_ess_conf->wl_supported_rates[0] = WL_RATE_11M; 30398410SWang.Lin@Sun.COM 30408410SWang.Lin@Sun.COM scan_item = list_next(&pcwl_p->pcwl_scan_list, scan_item); 30418410SWang.Lin@Sun.COM } 30428410SWang.Lin@Sun.COM 30438410SWang.Lin@Sun.COM mutex_exit(&pcwl_p->pcwl_scanlist_lock); 30448410SWang.Lin@Sun.COM } 30458410SWang.Lin@Sun.COM 30468410SWang.Lin@Sun.COM 30478410SWang.Lin@Sun.COM /* 30483737Shx147065 * for wificonfig and dladm ioctl 30493737Shx147065 */ 30503737Shx147065 30513737Shx147065 static int 30523737Shx147065 pcwl_cfg_essid(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd) 30533737Shx147065 { 30548410SWang.Lin@Sun.COM char ssid[36]; 30558410SWang.Lin@Sun.COM uint16_t i; 30568410SWang.Lin@Sun.COM uint16_t val; 30578410SWang.Lin@Sun.COM pcwl_rf_t *rf_p; 30588410SWang.Lin@Sun.COM wldp_t *infp; 30598410SWang.Lin@Sun.COM wldp_t *outfp; 30608410SWang.Lin@Sun.COM char *buf; 30618410SWang.Lin@Sun.COM int iret; 30628410SWang.Lin@Sun.COM int err = 0; 30633737Shx147065 30643737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 30653737Shx147065 if (buf == NULL) { 30663737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n", 30673737Shx147065 MAX_BUF_LEN)); 30683737Shx147065 return (ENOMEM); 30693737Shx147065 } 30703737Shx147065 outfp = (wldp_t *)buf; 30713737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 30723737Shx147065 infp = (wldp_t *)mp->b_rptr; 30733737Shx147065 rf_p = &pcwl_p->pcwl_rf; 30743737Shx147065 30758410SWang.Lin@Sun.COM 30763737Shx147065 bzero(ssid, sizeof (ssid)); 30773737Shx147065 if (cmd == WLAN_GET_PARAM) { 30788410SWang.Lin@Sun.COM err = pcwl_get_essid(pcwl_p, outfp->wldp_buf); 30798410SWang.Lin@Sun.COM if (err == EIO) { 30803737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 30813737Shx147065 outfp->wldp_result = WL_HW_ERROR; 30823737Shx147065 goto done; 30833737Shx147065 } 30848410SWang.Lin@Sun.COM (void) pcwl_get_ltv(pcwl_p, 2, WL_RID_PORTSTATUS, &val); 30853737Shx147065 if (val == WL_PORT_DISABLED || val == WL_PORT_INITIAL) { 30863737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 30873737Shx147065 offsetof(wl_essid_t, wl_essid_essid) + 30883737Shx147065 mi_strlen(rf_p->rf_desired_ssid); 30893737Shx147065 } else if (val == WL_PORT_TO_IBSS || 30903737Shx147065 val == WL_PORT_TO_BSS || 30913737Shx147065 val == WL_PORT_OOR) { 30923737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 30933737Shx147065 offsetof(wl_essid_t, wl_essid_essid) + 30943737Shx147065 mi_strlen(ssid+2); 30953737Shx147065 } else { 30963737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 30973737Shx147065 } 30983737Shx147065 outfp->wldp_result = WL_SUCCESS; 30993737Shx147065 PCWLDBG((CE_CONT, "outfp->length=%d\n", outfp->wldp_length)); 31003737Shx147065 PCWLDBG((CE_CONT, "pcwl: get desired essid=%s\n", 31013737Shx147065 rf_p->rf_desired_ssid)); 31023737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 31038410SWang.Lin@Sun.COM (void) pcwl_set_essid(pcwl_p, infp->wldp_buf); 31043737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 31053737Shx147065 outfp->wldp_result = WL_SUCCESS; 31063737Shx147065 } else { 31073737Shx147065 kmem_free(buf, MAX_BUF_LEN); 31083737Shx147065 return (EINVAL); 31093737Shx147065 } 31103737Shx147065 done: 31113737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 31123737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 31133737Shx147065 iret = (int)(outfp->wldp_result); 31143737Shx147065 kmem_free(buf, MAX_BUF_LEN); 31153737Shx147065 return (iret); 31163737Shx147065 } 31173737Shx147065 31183737Shx147065 static int 31193737Shx147065 pcwl_cfg_bssid(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd) 31203737Shx147065 { 31218410SWang.Lin@Sun.COM uint16_t i; 31228410SWang.Lin@Sun.COM int iret; 31238410SWang.Lin@Sun.COM wldp_t *outfp; 31248410SWang.Lin@Sun.COM char *buf; 31258410SWang.Lin@Sun.COM int err = 0; 31263737Shx147065 31273737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 31283737Shx147065 if (buf == NULL) { 31293737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n", 31303737Shx147065 MAX_BUF_LEN)); 31313737Shx147065 return (ENOMEM); 31323737Shx147065 } 31333737Shx147065 outfp = (wldp_t *)buf; 31343737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 31353737Shx147065 31363737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_bssid_t); 31373737Shx147065 if (cmd == WLAN_GET_PARAM) { 31388410SWang.Lin@Sun.COM err = pcwl_get_bssid(pcwl_p, outfp->wldp_buf); 31398410SWang.Lin@Sun.COM if (err == EIO) { 31403737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 31413737Shx147065 outfp->wldp_result = WL_HW_ERROR; 31423737Shx147065 goto done; 31433737Shx147065 } 31443737Shx147065 outfp->wldp_result = WL_SUCCESS; 31453737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 31463737Shx147065 outfp->wldp_result = WL_READONLY; 31473737Shx147065 } else { 31483737Shx147065 kmem_free(buf, MAX_BUF_LEN); 31493737Shx147065 return (EINVAL); 31503737Shx147065 } 31513737Shx147065 done: 31523737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 31533737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 31543737Shx147065 iret = (int)(outfp->wldp_result); 31553737Shx147065 kmem_free(buf, MAX_BUF_LEN); 31563737Shx147065 return (iret); 31573737Shx147065 } 31583737Shx147065 31593737Shx147065 /*ARGSUSED*/ 31603737Shx147065 static int 31613737Shx147065 pcwl_cmd_scan(pcwl_maci_t *pcwl_p) 31623737Shx147065 { 31633737Shx147065 uint16_t vall[18], ret = WL_SUCCESS; 31643737Shx147065 pcwl_rf_t *rf_p; 31653737Shx147065 uint32_t enable, i; 31663737Shx147065 size_t len; 31673737Shx147065 31683737Shx147065 rf_p = &pcwl_p->pcwl_rf; 31693737Shx147065 31703737Shx147065 /* 31713737Shx147065 * The logic of this funtion is really tricky. 31723737Shx147065 * Firstly, the chip can only scan in BSS mode, so necessary 31733737Shx147065 * backup and restore is required before and after the scan 31743737Shx147065 * command. 31753737Shx147065 * Secondly, for Lucent chip, Alrealy associated with an AP 31763737Shx147065 * can only scan the APes on the fixed channel, so we must 31773737Shx147065 * set the desired_ssid as "" before scan and restore after. 31783737Shx147065 * Thirdly, scan cmd is effective only when the card is enabled 31793737Shx147065 * and any 'set' operation(such as set bsstype, ssid)must disable 31803737Shx147065 * the card first and then enable the card after the 'set' 31813737Shx147065 */ 31823737Shx147065 enable = pcwl_p->pcwl_flag & PCWL_ENABLED; 31833737Shx147065 len = strlen(rf_p->rf_desired_ssid); 31843737Shx147065 31853737Shx147065 if (pcwl_p->pcwl_rf.rf_porttype != WL_BSS_BSS) { 31863737Shx147065 if ((enable) && 31873737Shx147065 (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0))) { 31883737Shx147065 ret = (int)WL_HW_ERROR; 31893737Shx147065 goto done; 31903737Shx147065 } 31913737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_PORTTYPE, WL_BSS_BSS); 31923737Shx147065 } 31933737Shx147065 31943737Shx147065 if ((pcwl_p->pcwl_chip_type == PCWL_CHIP_LUCENT) && (len != 0)) { 31953737Shx147065 if ((enable) && 31963737Shx147065 (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0))) { 31973737Shx147065 ret = (int)WL_HW_ERROR; 31983737Shx147065 goto done; 31993737Shx147065 } 32003737Shx147065 PUT_STR(pcwl_p, WL_RID_DESIRED_SSID, ""); 32013737Shx147065 } 32023737Shx147065 32033737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) { 32043737Shx147065 ret = (int)WL_HW_ERROR; 32053737Shx147065 goto done; 32063737Shx147065 } 32073737Shx147065 pcwl_delay(pcwl_p, 1000000); 32083737Shx147065 32093737Shx147065 switch (pcwl_p->pcwl_chip_type) { 32103737Shx147065 case PCWL_CHIP_PRISMII: 32113737Shx147065 bzero(vall, sizeof (vall)); 32123737Shx147065 vall[0] = 0x3fff; /* channel mask */ 32133737Shx147065 vall[1] = 0x1; /* tx rate */ 32143737Shx147065 for (i = 0; i < WL_MAX_SCAN_TIMES; i++) { 32153737Shx147065 PUT_LTV(pcwl_p, sizeof (vall), 32163737Shx147065 WL_RID_HSCAN_REQUEST, vall); 32173737Shx147065 pcwl_delay(pcwl_p, 1000000); 32183737Shx147065 if (pcwl_p->pcwl_scan_num >= WL_SCAN_AGAIN_THRESHOLD) 32193737Shx147065 break; 32203737Shx147065 } 32213737Shx147065 PCWLDBG((CE_NOTE, "PRISM chip\n")); 32223737Shx147065 break; 32233737Shx147065 32243737Shx147065 case PCWL_CHIP_LUCENT: 32253737Shx147065 PCWLDBG((CE_NOTE, "LUCENT chip\n")); 32263737Shx147065 default: 32273737Shx147065 for (i = 0; i < WL_MAX_SCAN_TIMES; i++) { 32283737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_INQUIRE, 32293737Shx147065 WL_INFO_SCAN_RESULTS)) { 32303737Shx147065 ret = (int)WL_HW_ERROR; 32313737Shx147065 goto done; 32323737Shx147065 } 32333737Shx147065 pcwl_delay(pcwl_p, 500000); 32343737Shx147065 if (pcwl_p->pcwl_scan_num >= WL_SCAN_AGAIN_THRESHOLD) 32353737Shx147065 break; 32363737Shx147065 } 32373737Shx147065 break; 32383737Shx147065 } 32393737Shx147065 if ((pcwl_p->pcwl_rf.rf_porttype != WL_BSS_BSS) || 32403737Shx147065 ((pcwl_p->pcwl_chip_type == PCWL_CHIP_LUCENT) && (len != 0))) { 32413737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) { 32423737Shx147065 ret = (int)WL_HW_ERROR; 32433737Shx147065 goto done; 32443737Shx147065 } 32453737Shx147065 if (ret = pcwl_config_rf(pcwl_p)) { 32463737Shx147065 ret = (int)WL_HW_ERROR; 32473737Shx147065 goto done; 32483737Shx147065 } 32493737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) { 32503737Shx147065 ret = (int)WL_HW_ERROR; 32513737Shx147065 goto done; 32523737Shx147065 } 32533737Shx147065 32543737Shx147065 pcwl_delay(pcwl_p, 1000000); 32553737Shx147065 } 32563737Shx147065 32573737Shx147065 if ((!enable) && (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0))) { 32583737Shx147065 ret = (int)WL_HW_ERROR; 32593737Shx147065 } 32603737Shx147065 done: 32613737Shx147065 if (ret) 32624196Syx209050 cmn_err(CE_WARN, "pcwl: scan failed due to hardware error"); 32633737Shx147065 return (ret); 32643737Shx147065 32653737Shx147065 } 32663737Shx147065 32673737Shx147065 /*ARGSUSED*/ 32683737Shx147065 static int 32693737Shx147065 pcwl_cfg_scan(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd) 32703737Shx147065 { 32718410SWang.Lin@Sun.COM wldp_t *outfp; 32728410SWang.Lin@Sun.COM char *buf; 32738410SWang.Lin@Sun.COM uint16_t i; 32743737Shx147065 32753737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 32763737Shx147065 if (buf == NULL) { 32773737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n", 32783737Shx147065 MAX_BUF_LEN)); 32793737Shx147065 return (ENOMEM); 32803737Shx147065 } 32813737Shx147065 outfp = (wldp_t *)buf; 32823737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 32833737Shx147065 32848410SWang.Lin@Sun.COM pcwl_get_esslist(pcwl_p, outfp->wldp_buf); 32858410SWang.Lin@Sun.COM 32863737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 32873737Shx147065 offsetof(wl_ess_list_t, wl_ess_list_ess) + 32883737Shx147065 pcwl_p->pcwl_scan_num * sizeof (wl_ess_conf_t); 32893737Shx147065 outfp->wldp_result = WL_SUCCESS; 32903737Shx147065 32913737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 32923737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 32933737Shx147065 kmem_free(buf, MAX_BUF_LEN); 32943737Shx147065 return (WL_SUCCESS); 32958410SWang.Lin@Sun.COM 32963737Shx147065 } 32973737Shx147065 32983737Shx147065 /*ARGSUSED*/ 32993737Shx147065 static int 33003737Shx147065 pcwl_cfg_linkstatus(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd) 33013737Shx147065 { 33028410SWang.Lin@Sun.COM wldp_t *outfp; 33038410SWang.Lin@Sun.COM char *buf; 33048410SWang.Lin@Sun.COM uint16_t i, val; 33058410SWang.Lin@Sun.COM int iret; 33068410SWang.Lin@Sun.COM int err = 0; 33073737Shx147065 33083737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 33093737Shx147065 if (buf == NULL) { 33103737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n", 33113737Shx147065 MAX_BUF_LEN)); 33123737Shx147065 return (ENOMEM); 33133737Shx147065 } 33143737Shx147065 outfp = (wldp_t *)buf; 33153737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 33163737Shx147065 33178410SWang.Lin@Sun.COM err = pcwl_get_linkstatus(pcwl_p, outfp->wldp_buf); 33188410SWang.Lin@Sun.COM if (err == EIO) { 33193737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 33203737Shx147065 outfp->wldp_result = WL_HW_ERROR; 33213737Shx147065 goto done; 33223737Shx147065 } 33238410SWang.Lin@Sun.COM 33248410SWang.Lin@Sun.COM (void) pcwl_get_ltv(pcwl_p, 2, WL_RID_PORTSTATUS, &val); 33253737Shx147065 if (val == WL_PORT_DISABLED || val == WL_PORT_INITIAL) { 33263737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 33273737Shx147065 sizeof (wl_linkstatus_t); 33283737Shx147065 } else if (val == WL_PORT_TO_IBSS || 33298410SWang.Lin@Sun.COM val == WL_PORT_TO_BSS || 33308410SWang.Lin@Sun.COM val == WL_PORT_OOR) { 33313737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 33323737Shx147065 sizeof (wl_linkstatus_t); 33333737Shx147065 } else { 33343737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 33353737Shx147065 } 33368410SWang.Lin@Sun.COM 33373737Shx147065 outfp->wldp_result = WL_SUCCESS; 33383737Shx147065 done: 33393737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 33403737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 33413737Shx147065 iret = (int)(outfp->wldp_result); 33423737Shx147065 kmem_free(buf, MAX_BUF_LEN); 33433737Shx147065 return (iret); 33443737Shx147065 } 33453737Shx147065 33463737Shx147065 static int 33473737Shx147065 pcwl_cfg_bsstype(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd) 33483737Shx147065 { 33498410SWang.Lin@Sun.COM uint16_t i; 33508410SWang.Lin@Sun.COM wldp_t *infp; 33518410SWang.Lin@Sun.COM wldp_t *outfp; 33528410SWang.Lin@Sun.COM char *buf; 33538410SWang.Lin@Sun.COM int iret; 33548410SWang.Lin@Sun.COM int err = 0; 33553737Shx147065 33563737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 33573737Shx147065 if (buf == NULL) { 33583737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n", 33593737Shx147065 MAX_BUF_LEN)); 33603737Shx147065 return (ENOMEM); 33613737Shx147065 } 33623737Shx147065 outfp = (wldp_t *)buf; 33633737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 33643737Shx147065 infp = (wldp_t *)mp->b_rptr; 33653737Shx147065 33663737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_bss_type_t); 33673737Shx147065 if (cmd == WLAN_GET_PARAM) { 33688410SWang.Lin@Sun.COM pcwl_get_bsstype(pcwl_p, outfp->wldp_buf); 33693737Shx147065 outfp->wldp_result = WL_SUCCESS; 33703737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 33718410SWang.Lin@Sun.COM err = pcwl_set_bsstype(pcwl_p, infp->wldp_buf); 33728410SWang.Lin@Sun.COM if (err == ENOTSUP) { 33733737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 33743737Shx147065 outfp->wldp_result = WL_NOTSUPPORTED; 33753737Shx147065 goto done; 33763737Shx147065 } 33773737Shx147065 outfp->wldp_result = WL_SUCCESS; 33783737Shx147065 } else { 33793737Shx147065 kmem_free(buf, MAX_BUF_LEN); 33803737Shx147065 return (EINVAL); 33813737Shx147065 } 33823737Shx147065 done: 33833737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 33843737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 33853737Shx147065 iret = (int)(outfp->wldp_result); 33863737Shx147065 kmem_free(buf, MAX_BUF_LEN); 33873737Shx147065 return (iret); 33883737Shx147065 } 33893737Shx147065 33903737Shx147065 static int 33913737Shx147065 pcwl_cfg_phy(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd) 33923737Shx147065 { 33938410SWang.Lin@Sun.COM uint16_t i; 33948410SWang.Lin@Sun.COM wldp_t *infp; 33958410SWang.Lin@Sun.COM wldp_t *outfp; 33968410SWang.Lin@Sun.COM char *buf; 33978410SWang.Lin@Sun.COM int iret; 33988410SWang.Lin@Sun.COM int err = 0; 33993737Shx147065 34003737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 34013737Shx147065 if (buf == NULL) { 34023737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n", 34033737Shx147065 MAX_BUF_LEN)); 34043737Shx147065 return (ENOMEM); 34053737Shx147065 } 34063737Shx147065 outfp = (wldp_t *)buf; 34073737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 34083737Shx147065 infp = (wldp_t *)mp->b_rptr; 34093737Shx147065 34103737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_dsss_t); 34113737Shx147065 if (cmd == WLAN_GET_PARAM) { 34128410SWang.Lin@Sun.COM err = pcwl_get_phy(pcwl_p, outfp->wldp_buf); 34138410SWang.Lin@Sun.COM if (err == EIO) { 34143737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 34153737Shx147065 outfp->wldp_result = WL_HW_ERROR; 34163737Shx147065 goto done; 34173737Shx147065 } 34183737Shx147065 outfp->wldp_result = WL_SUCCESS; 34193737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 34208410SWang.Lin@Sun.COM err = pcwl_set_phy(pcwl_p, infp->wldp_buf); 34218410SWang.Lin@Sun.COM if (err == ENOTSUP) { 34223737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 34233737Shx147065 outfp->wldp_result = WL_NOTSUPPORTED; 34243737Shx147065 goto done; 34253737Shx147065 } 34263737Shx147065 outfp->wldp_result = WL_SUCCESS; 34273737Shx147065 } else { 34283737Shx147065 kmem_free(buf, MAX_BUF_LEN); 34293737Shx147065 return (EINVAL); 34303737Shx147065 } 34313737Shx147065 done: 34323737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 34333737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 34343737Shx147065 iret = (int)(outfp->wldp_result); 34353737Shx147065 kmem_free(buf, MAX_BUF_LEN); 34363737Shx147065 return (iret); 34373737Shx147065 34383737Shx147065 } 34393737Shx147065 34403737Shx147065 static int 34413737Shx147065 pcwl_cfg_desiredrates(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd) 34423737Shx147065 { 34438410SWang.Lin@Sun.COM uint16_t rate; 34448410SWang.Lin@Sun.COM uint16_t i; 34458410SWang.Lin@Sun.COM wldp_t *infp; 34468410SWang.Lin@Sun.COM wldp_t *outfp; 34478410SWang.Lin@Sun.COM char *buf; 34488410SWang.Lin@Sun.COM int iret; 34498410SWang.Lin@Sun.COM int err = 0; 34503737Shx147065 34513737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 34523737Shx147065 if (buf == NULL) { 34533737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n", 34543737Shx147065 MAX_BUF_LEN)); 34553737Shx147065 return (ENOMEM); 34563737Shx147065 } 34573737Shx147065 outfp = (wldp_t *)buf; 34583737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 34593737Shx147065 infp = (wldp_t *)mp->b_rptr; 34603737Shx147065 34613737Shx147065 if (cmd == WLAN_GET_PARAM) { 34628410SWang.Lin@Sun.COM err = pcwl_get_desrates(pcwl_p, outfp->wldp_buf); 34638410SWang.Lin@Sun.COM if (err == EIO || err == EINVAL) { 34643737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 34658410SWang.Lin@Sun.COM outfp->wldp_result = WL_NOTSUPPORTED; 34663737Shx147065 goto done; 34673737Shx147065 } 34683737Shx147065 if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) { 34693737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 34703737Shx147065 offsetof(wl_rates_t, wl_rates_rates) + 34713737Shx147065 1 * sizeof (char); 34723737Shx147065 } else { 34738410SWang.Lin@Sun.COM (void) pcwl_get_ltv(pcwl_p, 2, WL_RID_TX_RATE, &rate); 34743737Shx147065 switch (rate) { 34753737Shx147065 case WL_L_TX_RATE_FIX_1M: 34763737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 34773737Shx147065 offsetof(wl_rates_t, wl_rates_rates) + 34783737Shx147065 1 * sizeof (char); 34793737Shx147065 break; 34803737Shx147065 case WL_L_TX_RATE_FIX_2M: 34813737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 34823737Shx147065 offsetof(wl_rates_t, wl_rates_rates) + 34833737Shx147065 1 * sizeof (char); 34843737Shx147065 break; 34853737Shx147065 case WL_L_TX_RATE_AUTO_H: 34863737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 34873737Shx147065 offsetof(wl_rates_t, wl_rates_rates) + 34883737Shx147065 4 * sizeof (char); 34893737Shx147065 break; 34903737Shx147065 case WL_L_TX_RATE_FIX_5M: 34913737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 34923737Shx147065 offsetof(wl_rates_t, wl_rates_rates) + 34933737Shx147065 1 * sizeof (char); 34943737Shx147065 break; 34953737Shx147065 case WL_L_TX_RATE_FIX_11M: 34963737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 34973737Shx147065 offsetof(wl_rates_t, wl_rates_rates) + 34983737Shx147065 1 * sizeof (char); 34993737Shx147065 break; 35003737Shx147065 case WL_L_TX_RATE_AUTO_L: 35013737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 35023737Shx147065 offsetof(wl_rates_t, wl_rates_rates) + 35033737Shx147065 2 * sizeof (char); 35043737Shx147065 break; 35053737Shx147065 case WL_L_TX_RATE_AUTO_M: 35063737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 35073737Shx147065 offsetof(wl_rates_t, wl_rates_rates) + 35083737Shx147065 3 * sizeof (char); 35093737Shx147065 break; 35103737Shx147065 default: 35118410SWang.Lin@Sun.COM break; 35123737Shx147065 } 35133737Shx147065 } 35146062Shx147065 outfp->wldp_result = WL_SUCCESS; 35153737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 35168410SWang.Lin@Sun.COM err = pcwl_set_desrates(pcwl_p, infp->wldp_buf); 35178410SWang.Lin@Sun.COM if (err == EINVAL) { 35188410SWang.Lin@Sun.COM outfp->wldp_length = WIFI_BUF_OFFSET; 35198410SWang.Lin@Sun.COM outfp->wldp_result = WL_NOTSUPPORTED; 35208410SWang.Lin@Sun.COM goto done; 35213737Shx147065 } 35228410SWang.Lin@Sun.COM if (err == ENOTSUP) { 35233737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 35243737Shx147065 outfp->wldp_result = WL_LACK_FEATURE; 35253737Shx147065 goto done; 35263737Shx147065 } 35278410SWang.Lin@Sun.COM 35283737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 35293737Shx147065 outfp->wldp_result = WL_SUCCESS; 35303737Shx147065 } else { 35313737Shx147065 kmem_free(buf, MAX_BUF_LEN); 35323737Shx147065 return (EINVAL); 35333737Shx147065 } 35343737Shx147065 done: 35353737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 35363737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 35373737Shx147065 iret = (int)(outfp->wldp_result); 35383737Shx147065 kmem_free(buf, MAX_BUF_LEN); 35393737Shx147065 return (iret); 35403737Shx147065 } 35413737Shx147065 35423737Shx147065 /*ARGSUSED*/ 35433737Shx147065 static int 35443737Shx147065 pcwl_cfg_supportrates(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd) 35453737Shx147065 { 35463737Shx147065 uint16_t i; 35473737Shx147065 wldp_t *outfp; 35483737Shx147065 char *buf; 35493737Shx147065 35503737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 35513737Shx147065 if (buf == NULL) { 35523737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n", 35533737Shx147065 MAX_BUF_LEN)); 35543737Shx147065 return (ENOMEM); 35553737Shx147065 } 35563737Shx147065 outfp = (wldp_t *)buf; 35573737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 35583737Shx147065 35593737Shx147065 if (cmd == WLAN_GET_PARAM) { 35608410SWang.Lin@Sun.COM pcwl_get_suprates(outfp->wldp_buf); 35613737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 35623737Shx147065 offsetof(wl_rates_t, wl_rates_rates) + 35633737Shx147065 4 * sizeof (char); 35643737Shx147065 outfp->wldp_result = WL_SUCCESS; 35653737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 35663737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 35673737Shx147065 kmem_free(buf, MAX_BUF_LEN); 35683737Shx147065 return (WL_SUCCESS); 35693737Shx147065 } else { 35703737Shx147065 kmem_free(buf, MAX_BUF_LEN); 35713737Shx147065 return (EINVAL); 35723737Shx147065 } 35733737Shx147065 } 35743737Shx147065 35753737Shx147065 static int 35763737Shx147065 pcwl_cfg_powermode(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd) 35773737Shx147065 { 35788410SWang.Lin@Sun.COM uint16_t i; 35798410SWang.Lin@Sun.COM wldp_t *infp; 35808410SWang.Lin@Sun.COM wldp_t *outfp; 35818410SWang.Lin@Sun.COM char *buf; 35828410SWang.Lin@Sun.COM int iret; 35838410SWang.Lin@Sun.COM int err = 0; 35843737Shx147065 35853737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 35863737Shx147065 if (buf == NULL) { 35873737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n", 35883737Shx147065 MAX_BUF_LEN)); 35893737Shx147065 return (ENOMEM); 35903737Shx147065 } 35913737Shx147065 outfp = (wldp_t *)buf; 35923737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 35933737Shx147065 infp = (wldp_t *)mp->b_rptr; 35943737Shx147065 35953737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_ps_mode_t); 35963737Shx147065 if (cmd == WLAN_GET_PARAM) { 35978410SWang.Lin@Sun.COM pcwl_get_powermode(pcwl_p, outfp->wldp_buf); 35983737Shx147065 outfp->wldp_result = WL_SUCCESS; 35993737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 36008410SWang.Lin@Sun.COM err = pcwl_set_powermode(pcwl_p, infp->wldp_buf); 36018410SWang.Lin@Sun.COM if (err == ENOTSUP) { 36023737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 36033737Shx147065 outfp->wldp_result = WL_NOTSUPPORTED; 36043737Shx147065 goto done; 36053737Shx147065 } 36063737Shx147065 outfp->wldp_result = WL_SUCCESS; 36073737Shx147065 } else { 36083737Shx147065 kmem_free(buf, MAX_BUF_LEN); 36093737Shx147065 return (EINVAL); 36103737Shx147065 } 36113737Shx147065 done: 36123737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 36133737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 36143737Shx147065 iret = (int)(outfp->wldp_result); 36153737Shx147065 kmem_free(buf, MAX_BUF_LEN); 36163737Shx147065 return (iret); 36173737Shx147065 36183737Shx147065 } 36193737Shx147065 36203737Shx147065 static int 36213737Shx147065 pcwl_cfg_authmode(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd) 36223737Shx147065 { 36238410SWang.Lin@Sun.COM uint16_t i; 36248410SWang.Lin@Sun.COM wldp_t *infp; 36258410SWang.Lin@Sun.COM wldp_t *outfp; 36268410SWang.Lin@Sun.COM char *buf; 36278410SWang.Lin@Sun.COM int iret; 36288410SWang.Lin@Sun.COM int err = 0; 36293737Shx147065 36303737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 36313737Shx147065 if (buf == NULL) { 36323737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n", 36333737Shx147065 MAX_BUF_LEN)); 36343737Shx147065 return (ENOMEM); 36353737Shx147065 } 36363737Shx147065 outfp = (wldp_t *)buf; 36373737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 36383737Shx147065 infp = (wldp_t *)mp->b_rptr; 36393737Shx147065 36403737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_authmode_t); 36413737Shx147065 if (cmd == WLAN_GET_PARAM) { 36428410SWang.Lin@Sun.COM pcwl_get_authmode(pcwl_p, outfp->wldp_buf); 36433737Shx147065 outfp->wldp_result = WL_SUCCESS; 36443737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 36458410SWang.Lin@Sun.COM err = pcwl_set_authmode(pcwl_p, infp->wldp_buf); 36468410SWang.Lin@Sun.COM if (err == ENOTSUP) { 36473737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 36483737Shx147065 outfp->wldp_result = WL_NOTSUPPORTED; 36493737Shx147065 goto done; 36503737Shx147065 } 36513737Shx147065 outfp->wldp_result = WL_SUCCESS; 36523737Shx147065 } else { 36533737Shx147065 kmem_free(buf, MAX_BUF_LEN); 36543737Shx147065 return (EINVAL); 36553737Shx147065 } 36563737Shx147065 done: 36573737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 36583737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 36593737Shx147065 iret = (int)(outfp->wldp_result); 36603737Shx147065 kmem_free(buf, MAX_BUF_LEN); 36613737Shx147065 return (iret); 36623737Shx147065 } 36633737Shx147065 36643737Shx147065 static int 36653737Shx147065 pcwl_cfg_encryption(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd) 36663737Shx147065 { 36678410SWang.Lin@Sun.COM uint16_t i; 36688410SWang.Lin@Sun.COM wldp_t *infp; 36698410SWang.Lin@Sun.COM wldp_t *outfp; 36708410SWang.Lin@Sun.COM char *buf; 36718410SWang.Lin@Sun.COM int iret; 36728410SWang.Lin@Sun.COM int err = 0; 36733737Shx147065 36743737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 36753737Shx147065 if (buf == NULL) { 36763737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n", 36773737Shx147065 MAX_BUF_LEN)); 36783737Shx147065 return (ENOMEM); 36793737Shx147065 } 36803737Shx147065 outfp = (wldp_t *)buf; 36813737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 36823737Shx147065 infp = (wldp_t *)mp->b_rptr; 36833737Shx147065 36843737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_encryption_t); 36853737Shx147065 if (cmd == WLAN_GET_PARAM) { 36868410SWang.Lin@Sun.COM pcwl_get_encrypt(pcwl_p, outfp->wldp_buf); 36873737Shx147065 outfp->wldp_result = WL_SUCCESS; 36883737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 36898410SWang.Lin@Sun.COM err = pcwl_set_encrypt(pcwl_p, infp->wldp_buf); 36908410SWang.Lin@Sun.COM if (err == ENOTSUP) { 36913737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 36923737Shx147065 outfp->wldp_result = WL_NOTSUPPORTED; 36933737Shx147065 goto done; 36943737Shx147065 } 36953737Shx147065 outfp->wldp_result = WL_SUCCESS; 36963737Shx147065 } else { 36973737Shx147065 kmem_free(buf, MAX_BUF_LEN); 36983737Shx147065 return (EINVAL); 36993737Shx147065 } 37003737Shx147065 done: 37013737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 37023737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 37033737Shx147065 iret = (int)(outfp->wldp_result); 37043737Shx147065 kmem_free(buf, MAX_BUF_LEN); 37053737Shx147065 return (iret); 37063737Shx147065 } 37073737Shx147065 37083737Shx147065 static int 37093737Shx147065 pcwl_cfg_wepkeyid(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd) 37103737Shx147065 { 37113737Shx147065 uint16_t i, ret; 37123737Shx147065 pcwl_rf_t *rf_p; 37133737Shx147065 wldp_t *infp; 37143737Shx147065 wldp_t *outfp; 37153737Shx147065 char *buf; 37163737Shx147065 int iret; 37173737Shx147065 37183737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 37193737Shx147065 if (buf == NULL) { 37203737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n", 37213737Shx147065 MAX_BUF_LEN)); 37223737Shx147065 return (ENOMEM); 37233737Shx147065 } 37243737Shx147065 outfp = (wldp_t *)buf; 37253737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 37263737Shx147065 infp = (wldp_t *)mp->b_rptr; 37273737Shx147065 rf_p = &pcwl_p->pcwl_rf; 37283737Shx147065 37293737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_wep_key_id_t); 37303737Shx147065 if (cmd == WLAN_GET_PARAM) { 37313737Shx147065 *(wl_wep_key_id_t *)(outfp->wldp_buf) = rf_p->rf_tx_crypt_key; 37323737Shx147065 outfp->wldp_result = WL_SUCCESS; 37333737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 37343737Shx147065 ret = (uint16_t)(*(wl_wep_key_id_t *)(infp->wldp_buf)); 37353737Shx147065 if (ret >= MAX_NWEPKEYS) { 37363737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 37373737Shx147065 outfp->wldp_result = WL_NOTSUPPORTED; 37383737Shx147065 goto done; 37393737Shx147065 } 37403737Shx147065 rf_p->rf_tx_crypt_key = ret; 37413737Shx147065 outfp->wldp_result = WL_SUCCESS; 37423737Shx147065 } else { 37433737Shx147065 kmem_free(buf, MAX_BUF_LEN); 37443737Shx147065 return (EINVAL); 37453737Shx147065 } 37463737Shx147065 done: 37473737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 37483737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 37493737Shx147065 iret = (int)(outfp->wldp_result); 37503737Shx147065 kmem_free(buf, MAX_BUF_LEN); 37513737Shx147065 return (iret); 37523737Shx147065 } 37533737Shx147065 37543737Shx147065 static int 37553737Shx147065 pcwl_cfg_createibss(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd) 37563737Shx147065 { 37578410SWang.Lin@Sun.COM uint16_t i; 37588410SWang.Lin@Sun.COM wldp_t *infp; 37598410SWang.Lin@Sun.COM wldp_t *outfp; 37608410SWang.Lin@Sun.COM char *buf; 37618410SWang.Lin@Sun.COM int iret; 37628410SWang.Lin@Sun.COM int err = 0; 37633737Shx147065 37643737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 37653737Shx147065 if (buf == NULL) { 37663737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n", 37673737Shx147065 MAX_BUF_LEN)); 37683737Shx147065 return (ENOMEM); 37693737Shx147065 } 37703737Shx147065 outfp = (wldp_t *)buf; 37713737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 37723737Shx147065 infp = (wldp_t *)mp->b_rptr; 37733737Shx147065 37743737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_create_ibss_t); 37753737Shx147065 if (cmd == WLAN_GET_PARAM) { 37768410SWang.Lin@Sun.COM pcwl_get_ibss(pcwl_p, outfp->wldp_buf); 37773737Shx147065 outfp->wldp_result = WL_SUCCESS; 37783737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 37798410SWang.Lin@Sun.COM err = pcwl_set_ibss(pcwl_p, infp->wldp_buf); 37808410SWang.Lin@Sun.COM if (err == ENOTSUP) { 37813737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 37823737Shx147065 outfp->wldp_result = WL_NOTSUPPORTED; 37833737Shx147065 goto done; 37843737Shx147065 } 37853737Shx147065 outfp->wldp_result = WL_SUCCESS; 37863737Shx147065 } else { 37873737Shx147065 kmem_free(buf, MAX_BUF_LEN); 37883737Shx147065 return (EINVAL); 37893737Shx147065 } 37903737Shx147065 done: 37913737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 37923737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 37933737Shx147065 iret = (int)(outfp->wldp_result); 37943737Shx147065 kmem_free(buf, MAX_BUF_LEN); 37953737Shx147065 return (iret); 37963737Shx147065 } 37973737Shx147065 37983737Shx147065 static int 37993737Shx147065 pcwl_cfg_rssi(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd) 38003737Shx147065 { 38013737Shx147065 uint16_t i; 38023737Shx147065 int iret; 38033737Shx147065 wldp_t *outfp; 38043737Shx147065 char *buf; 38053737Shx147065 38063737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 38073737Shx147065 if (buf == NULL) { 38083737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n", 38093737Shx147065 MAX_BUF_LEN)); 38103737Shx147065 return (ENOMEM); 38113737Shx147065 } 38123737Shx147065 outfp = (wldp_t *)buf; 38133737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 38143737Shx147065 38153737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_rssi_t); 38163737Shx147065 38173737Shx147065 if (cmd == WLAN_GET_PARAM) { 38188410SWang.Lin@Sun.COM pcwl_get_param_rssi(pcwl_p, outfp->wldp_buf); 38193737Shx147065 outfp->wldp_result = WL_SUCCESS; 38203737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 38213737Shx147065 outfp->wldp_result = WL_READONLY; 38223737Shx147065 } else { 38233737Shx147065 kmem_free(buf, MAX_BUF_LEN); 38243737Shx147065 return (EINVAL); 38253737Shx147065 } 38263737Shx147065 done: 38273737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 38283737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 38293737Shx147065 iret = (int)(outfp->wldp_result); 38303737Shx147065 kmem_free(buf, MAX_BUF_LEN); 38313737Shx147065 return (iret); 38323737Shx147065 } 38333737Shx147065 38343737Shx147065 /*ARGSUSED*/ 38353737Shx147065 static int 38363737Shx147065 pcwl_cfg_radio(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd) 38373737Shx147065 { 38383737Shx147065 uint16_t i; 38393737Shx147065 int iret; 38403737Shx147065 wldp_t *outfp; 38413737Shx147065 char *buf; 38423737Shx147065 38433737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 38443737Shx147065 if (buf == NULL) { 38453737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n", 38463737Shx147065 MAX_BUF_LEN)); 38473737Shx147065 return (ENOMEM); 38483737Shx147065 } 38493737Shx147065 outfp = (wldp_t *)buf; 38503737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 38513737Shx147065 38523737Shx147065 if (cmd == WLAN_GET_PARAM) { 38533737Shx147065 *(wl_radio_t *)(outfp->wldp_buf) = B_TRUE; 38543737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_radio_t); 38553737Shx147065 outfp->wldp_result = WL_SUCCESS; 38563737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 38573737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 38583737Shx147065 outfp->wldp_result = WL_LACK_FEATURE; 38593737Shx147065 } else { 38603737Shx147065 kmem_free(buf, MAX_BUF_LEN); 38613737Shx147065 return (EINVAL); 38623737Shx147065 } 38633737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 38643737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 38653737Shx147065 iret = (int)(outfp->wldp_result); 38663737Shx147065 kmem_free(buf, MAX_BUF_LEN); 38673737Shx147065 return (iret); 38683737Shx147065 } 38693737Shx147065 38703737Shx147065 static int 38713737Shx147065 pcwl_cfg_wepkey(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd) 38723737Shx147065 { 38738410SWang.Lin@Sun.COM uint16_t i; 38748410SWang.Lin@Sun.COM wldp_t *infp; 38758410SWang.Lin@Sun.COM wldp_t *outfp; 38768410SWang.Lin@Sun.COM char *buf; 38778410SWang.Lin@Sun.COM int iret; 38783737Shx147065 38793737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 38803737Shx147065 if (buf == NULL) { 38813737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n", 38823737Shx147065 MAX_BUF_LEN)); 38833737Shx147065 return (ENOMEM); 38843737Shx147065 } 38853737Shx147065 outfp = (wldp_t *)buf; 38863737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 38873737Shx147065 infp = (wldp_t *)mp->b_rptr; 38883737Shx147065 38893737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_wep_key_tab_t); 38903737Shx147065 if (cmd == WLAN_GET_PARAM) { 38913737Shx147065 outfp->wldp_result = WL_WRITEONLY; 38923737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 38938410SWang.Lin@Sun.COM (void) pcwl_set_wepkey(pcwl_p, infp->wldp_buf); 38943737Shx147065 outfp->wldp_result = WL_SUCCESS; 38953737Shx147065 } else { 38963737Shx147065 kmem_free(buf, MAX_BUF_LEN); 38973737Shx147065 return (EINVAL); 38983737Shx147065 } 38993737Shx147065 done: 39003737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 39013737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 39023737Shx147065 iret = (int)(outfp->wldp_result); 39033737Shx147065 kmem_free(buf, MAX_BUF_LEN); 39043737Shx147065 return (iret); 39053737Shx147065 } 39063737Shx147065 39073737Shx147065 static void 39083737Shx147065 pcwl_connect_timeout(void *arg) 39093737Shx147065 { 39103737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg; 39113737Shx147065 uint16_t ret = 0; 39123737Shx147065 39133737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 39143737Shx147065 PCWL_DISABLE_INTR(pcwl_p); 39153737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) { 39163737Shx147065 goto done; 39173737Shx147065 } 39183737Shx147065 if (ret = pcwl_config_rf(pcwl_p)) { 39193737Shx147065 goto done; 39203737Shx147065 } 39213737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) { 39223737Shx147065 goto done; 39233737Shx147065 } 39243737Shx147065 PCWL_ENABLE_INTR(pcwl_p); 39253737Shx147065 done: 39263737Shx147065 if (ret) 39274196Syx209050 cmn_err(CE_WARN, "pcwl: connect failed due to hardware error"); 39283737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 39293737Shx147065 pcwl_p->pcwl_connect_timeout_id = 0; 39303737Shx147065 } 39313737Shx147065 39323737Shx147065 static int 39333737Shx147065 pcwl_getset(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd) 39343737Shx147065 { 39353737Shx147065 int ret = WL_SUCCESS; 39363737Shx147065 int connect = 0; 39373737Shx147065 39383737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 39393737Shx147065 if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) { 39403737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 39413737Shx147065 return (PCWL_FAIL); 39423737Shx147065 } 39433737Shx147065 switch (((wldp_t *)mp->b_rptr)->wldp_id) { 39443737Shx147065 case WL_ESSID: 39453737Shx147065 ret = pcwl_cfg_essid(mp, pcwl_p, cmd); 39463737Shx147065 connect = 1; 39473737Shx147065 PCWLDBG((CE_NOTE, "cfg_essid\n")); 39483737Shx147065 break; 39493737Shx147065 case WL_BSSID: 39503737Shx147065 ret = pcwl_cfg_bssid(mp, pcwl_p, cmd); 39513737Shx147065 connect = 1; 39523737Shx147065 PCWLDBG((CE_NOTE, "cfg_bssid\n")); 39533737Shx147065 break; 39543737Shx147065 case WL_ESS_LIST: 39553737Shx147065 ret = pcwl_cfg_scan(mp, pcwl_p, cmd); 39563737Shx147065 PCWLDBG((CE_NOTE, "cfg_scan\n")); 39573737Shx147065 break; 39583737Shx147065 case WL_LINKSTATUS: 39593737Shx147065 ret = pcwl_cfg_linkstatus(mp, pcwl_p, cmd); 39603737Shx147065 PCWLDBG((CE_NOTE, "cfg_linkstatus\n")); 39613737Shx147065 break; 39623737Shx147065 case WL_BSS_TYPE: 39633737Shx147065 ret = pcwl_cfg_bsstype(mp, pcwl_p, cmd); 39643737Shx147065 connect = 1; 39653737Shx147065 PCWLDBG((CE_NOTE, "cfg_bsstype\n")); 39663737Shx147065 break; 39673737Shx147065 case WL_PHY_CONFIG: 39683737Shx147065 ret = pcwl_cfg_phy(mp, pcwl_p, cmd); 39693737Shx147065 connect = 1; 39703737Shx147065 PCWLDBG((CE_NOTE, "cfg_phy\n")); 39713737Shx147065 break; 39723737Shx147065 case WL_DESIRED_RATES: 39733737Shx147065 ret = pcwl_cfg_desiredrates(mp, pcwl_p, cmd); 39743737Shx147065 connect = 1; 39753737Shx147065 PCWLDBG((CE_NOTE, "cfg_disred-rates\n")); 39763737Shx147065 break; 39773737Shx147065 case WL_SUPPORTED_RATES: 39783737Shx147065 ret = pcwl_cfg_supportrates(mp, pcwl_p, cmd); 39793737Shx147065 PCWLDBG((CE_NOTE, "cfg_supported-rates\n")); 39803737Shx147065 break; 39813737Shx147065 case WL_POWER_MODE: 39823737Shx147065 ret = pcwl_cfg_powermode(mp, pcwl_p, cmd); 39833737Shx147065 PCWLDBG((CE_NOTE, "cfg_powermode\n")); 39843737Shx147065 break; 39853737Shx147065 case WL_AUTH_MODE: 39863737Shx147065 ret = pcwl_cfg_authmode(mp, pcwl_p, cmd); 39873737Shx147065 connect = 1; 39883737Shx147065 PCWLDBG((CE_NOTE, "cfg_authmode\n")); 39893737Shx147065 break; 39903737Shx147065 case WL_ENCRYPTION: 39913737Shx147065 ret = pcwl_cfg_encryption(mp, pcwl_p, cmd); 39923737Shx147065 connect = 1; 39933737Shx147065 PCWLDBG((CE_NOTE, "cfg_encryption\n")); 39943737Shx147065 break; 39953737Shx147065 case WL_WEP_KEY_ID: 39963737Shx147065 ret = pcwl_cfg_wepkeyid(mp, pcwl_p, cmd); 39973737Shx147065 connect = 1; 39983737Shx147065 PCWLDBG((CE_NOTE, "cfg_wepkeyid\n")); 39993737Shx147065 break; 40003737Shx147065 case WL_CREATE_IBSS: 40013737Shx147065 ret = pcwl_cfg_createibss(mp, pcwl_p, cmd); 40023737Shx147065 connect = 1; 40033737Shx147065 PCWLDBG((CE_NOTE, "cfg_create-ibss\n")); 40043737Shx147065 break; 40053737Shx147065 case WL_RSSI: 40063737Shx147065 ret = pcwl_cfg_rssi(mp, pcwl_p, cmd); 40073737Shx147065 PCWLDBG((CE_NOTE, "cfg_rssi\n")); 40083737Shx147065 break; 40093737Shx147065 case WL_RADIO: 40103737Shx147065 ret = pcwl_cfg_radio(mp, pcwl_p, cmd); 40113737Shx147065 PCWLDBG((CE_NOTE, "cfg_radio\n")); 40123737Shx147065 break; 40133737Shx147065 case WL_WEP_KEY_TAB: 40143737Shx147065 ret = pcwl_cfg_wepkey(mp, pcwl_p, cmd); 40153737Shx147065 connect = 1; 40163737Shx147065 PCWLDBG((CE_NOTE, "cfg_wepkey\n")); 40173737Shx147065 break; 40183737Shx147065 case WL_SCAN: 40193737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 40203737Shx147065 if (pcwl_p->pcwl_connect_timeout_id != 0) { 40213737Shx147065 (void) untimeout(pcwl_p->pcwl_connect_timeout_id); 40223737Shx147065 pcwl_p->pcwl_connect_timeout_id = 0; 40233737Shx147065 } 40243737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 40253737Shx147065 ret = pcwl_cmd_scan(pcwl_p); 40263737Shx147065 break; 40273737Shx147065 case WL_LOAD_DEFAULTS: 40283737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 40293737Shx147065 if (pcwl_p->pcwl_connect_timeout_id != 0) { 40303737Shx147065 (void) untimeout(pcwl_p->pcwl_connect_timeout_id); 40313737Shx147065 pcwl_p->pcwl_connect_timeout_id = 0; 40323737Shx147065 } 40333737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 40343737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) { 40353737Shx147065 ret = (int)WL_HW_ERROR; 40363737Shx147065 break; 40373737Shx147065 } 40383737Shx147065 if (ret = pcwl_loaddef_rf(pcwl_p)) { 40393737Shx147065 ret = (int)WL_HW_ERROR; 40403737Shx147065 PCWLDBG((CE_WARN, "cfg_loaddef_err\n")); 40413737Shx147065 break; 40423737Shx147065 } 40433737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) { 40443737Shx147065 ret = (int)WL_HW_ERROR; 40453737Shx147065 break; 40463737Shx147065 } 40473737Shx147065 pcwl_delay(pcwl_p, 1000000); 40483737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) { 40493737Shx147065 ret = (int)WL_HW_ERROR; 40503737Shx147065 break; 40513737Shx147065 } 40523737Shx147065 PCWLDBG((CE_NOTE, "loaddef\n")); 40533737Shx147065 break; 40543737Shx147065 case WL_DISASSOCIATE: 40553737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 40563737Shx147065 if (pcwl_p->pcwl_connect_timeout_id != 0) { 40573737Shx147065 (void) untimeout(pcwl_p->pcwl_connect_timeout_id); 40583737Shx147065 pcwl_p->pcwl_connect_timeout_id = 0; 40593737Shx147065 } 40603737Shx147065 40613737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 40623737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) { 40633737Shx147065 ret = (int)WL_HW_ERROR; 40643737Shx147065 break; 40653737Shx147065 } 40663737Shx147065 /* 40673737Shx147065 * A workaround here: If the card is in ad-hoc mode, the 40683737Shx147065 * following scan will not work correctly, so any 40693737Shx147065 * 'dladm connect-wifi' which need a scan first will not 40703737Shx147065 * succeed. software reset the card here as a workround. 40713737Shx147065 */ 40723737Shx147065 if ((pcwl_p->pcwl_rf.rf_porttype == WL_BSS_IBSS) && 40733737Shx147065 (pcwl_p->pcwl_chip_type == PCWL_CHIP_LUCENT)) { 40743737Shx147065 if (ret = pcwl_reset_backend(pcwl_p)) { 40753737Shx147065 ret = (int)WL_HW_ERROR; 40763737Shx147065 break; 40773737Shx147065 } 40783737Shx147065 if (ret = pcwl_init_nicmem(pcwl_p)) { 40793737Shx147065 ret = (int)WL_HW_ERROR; 40803737Shx147065 break; 40813737Shx147065 } 40823737Shx147065 pcwl_start_locked(pcwl_p); 40833737Shx147065 } 40843737Shx147065 if (ret = pcwl_loaddef_rf(pcwl_p)) { 40853737Shx147065 ret = (int)WL_HW_ERROR; 40863737Shx147065 PCWLDBG((CE_WARN, "cfg_loaddef_err\n")); 40873737Shx147065 break; 40883737Shx147065 } 40893737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) { 40903737Shx147065 ret = (int)WL_HW_ERROR; 40913737Shx147065 break; 40923737Shx147065 } 40933737Shx147065 pcwl_delay(pcwl_p, 1000000); 40943737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) { 40953737Shx147065 ret = (int)WL_HW_ERROR; 40963737Shx147065 break; 40973737Shx147065 } 40983737Shx147065 PCWLDBG((CE_NOTE, "disassociate\n")); 40993737Shx147065 break; 41003737Shx147065 case WL_REASSOCIATE: 41013737Shx147065 case WL_ASSOCIAT: 41023737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 41033737Shx147065 if (pcwl_p->pcwl_connect_timeout_id != 0) { 41043737Shx147065 (void) untimeout(pcwl_p->pcwl_connect_timeout_id); 41053737Shx147065 pcwl_p->pcwl_connect_timeout_id = 0; 41063737Shx147065 } 41073737Shx147065 mutex_enter(&pcwl_p->pcwl_glock); 41083737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) { 41093737Shx147065 ret = (int)WL_HW_ERROR; 41103737Shx147065 break; 41113737Shx147065 } 41123737Shx147065 if (ret = pcwl_config_rf(pcwl_p)) { 41133737Shx147065 ret = (int)WL_HW_ERROR; 41143737Shx147065 break; 41153737Shx147065 } 41163737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) { 41173737Shx147065 ret = (int)WL_HW_ERROR; 41183737Shx147065 break; 41193737Shx147065 } 41203737Shx147065 PCWLDBG((CE_NOTE, "associate")); 41213737Shx147065 break; 41223737Shx147065 default: 41233737Shx147065 break; 41243737Shx147065 } 41253737Shx147065 mutex_exit(&pcwl_p->pcwl_glock); 41263737Shx147065 if ((cmd == WLAN_SET_PARAM) && (connect)) { 41273737Shx147065 (void) pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0); 41283737Shx147065 if (pcwl_p->pcwl_connect_timeout_id != 0) { 41293737Shx147065 (void) untimeout(pcwl_p->pcwl_connect_timeout_id); 41303737Shx147065 pcwl_p->pcwl_connect_timeout_id = 0; 41313737Shx147065 } 41323737Shx147065 pcwl_p->pcwl_connect_timeout_id = timeout(pcwl_connect_timeout, 41333737Shx147065 pcwl_p, 2 * drv_usectohz(1000000)); 41343737Shx147065 } 41353737Shx147065 return (ret); 41363737Shx147065 } 41373737Shx147065 41383737Shx147065 static void 41393737Shx147065 pcwl_wlan_ioctl(pcwl_maci_t *pcwl_p, queue_t *wq, mblk_t *mp, uint32_t cmd) 41403737Shx147065 { 41413737Shx147065 41423737Shx147065 struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 41433737Shx147065 wldp_t *infp; 41443737Shx147065 uint32_t len, ret; 41453737Shx147065 mblk_t *mp1; 41463737Shx147065 41473737Shx147065 /* 41483737Shx147065 * sanity check 41493737Shx147065 */ 41503737Shx147065 if (iocp->ioc_count == 0 || !(mp1 = mp->b_cont)) { 41513737Shx147065 miocnak(wq, mp, 0, EINVAL); 41523737Shx147065 return; 41533737Shx147065 } 41543737Shx147065 41553737Shx147065 /* 41563737Shx147065 * assuming single data block 41573737Shx147065 */ 41583737Shx147065 if (mp1->b_cont) { 41593737Shx147065 freemsg(mp1->b_cont); 41603737Shx147065 mp1->b_cont = NULL; 41613737Shx147065 } 41623737Shx147065 41633737Shx147065 /* 41643737Shx147065 * we will overwrite everything 41653737Shx147065 */ 41663737Shx147065 mp1->b_wptr = mp1->b_rptr; 41673737Shx147065 41683737Shx147065 infp = (wldp_t *)mp1->b_rptr; 41693737Shx147065 PCWLDBG((CE_NOTE, "pcwl: wldp->length=0x%x\n", infp->wldp_length)); 41703737Shx147065 PCWLDBG((CE_NOTE, "pcwl: wldp->type =:%s\n", 41713737Shx147065 infp->wldp_type == NET_802_11 ? "NET_802_11" : "Unknown")); 41723737Shx147065 PCWLDBG((CE_NOTE, "pcwl: wldp->id=0x%x\n", infp->wldp_id)); 41733737Shx147065 PCWLDBG((CE_NOTE, "pcwl: wldp->result=0x%x\n", infp->wldp_result)); 41743737Shx147065 41753737Shx147065 ret = pcwl_getset(mp1, pcwl_p, cmd); 41763737Shx147065 len = msgdsize(mp1); 41773737Shx147065 PCWLDBG((CE_CONT, "pcwl: ioctl message length = %d\n", len)); 41783737Shx147065 miocack(wq, mp, len, ret); 41793737Shx147065 41803737Shx147065 } 41813737Shx147065 41823737Shx147065 41833737Shx147065 static void 41843737Shx147065 pcwl_ioctl(void *arg, queue_t *wq, mblk_t *mp) 41853737Shx147065 { 41863737Shx147065 struct iocblk *iocp; 41873737Shx147065 uint32_t cmd, ret; 41883737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg; 41893737Shx147065 boolean_t need_privilege = B_TRUE; 41903737Shx147065 41913737Shx147065 /* 41923737Shx147065 * Validate the command before bothering with the mutexen ... 41933737Shx147065 */ 41943737Shx147065 iocp = (struct iocblk *)mp->b_rptr; 41953737Shx147065 iocp->ioc_error = 0; 41963737Shx147065 cmd = iocp->ioc_cmd; 41973737Shx147065 switch (cmd) { 41983737Shx147065 default: 41993737Shx147065 PCWLDBG((CE_CONT, "pcwl_ioctl: unknown cmd 0x%x", cmd)); 42003737Shx147065 miocnak(wq, mp, 0, EINVAL); 42013737Shx147065 return; 42023737Shx147065 case WLAN_GET_PARAM: 42037408SSebastien.Roy@Sun.COM need_privilege = B_FALSE; 42043737Shx147065 break; 42053737Shx147065 case WLAN_SET_PARAM: 42063737Shx147065 case WLAN_COMMAND: 42073737Shx147065 break; 42083737Shx147065 } 42097408SSebastien.Roy@Sun.COM 42107408SSebastien.Roy@Sun.COM if (need_privilege && (ret = secpolicy_dl_config(iocp->ioc_cr)) != 0) 42117408SSebastien.Roy@Sun.COM miocnak(wq, mp, 0, ret); 42127408SSebastien.Roy@Sun.COM else 42137408SSebastien.Roy@Sun.COM pcwl_wlan_ioctl(pcwl_p, wq, mp, cmd); 42143737Shx147065 } 42158410SWang.Lin@Sun.COM 42168410SWang.Lin@Sun.COM /* 42178410SWang.Lin@Sun.COM * brussels 42188410SWang.Lin@Sun.COM */ 42198410SWang.Lin@Sun.COM /* ARGSUSED */ 42208410SWang.Lin@Sun.COM static int 42218410SWang.Lin@Sun.COM pcwl_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num, 42228410SWang.Lin@Sun.COM uint_t wldp_length, const void *wldp_buf) 42238410SWang.Lin@Sun.COM { 42248410SWang.Lin@Sun.COM int err = 0; 42258410SWang.Lin@Sun.COM pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg; 42268410SWang.Lin@Sun.COM 42278410SWang.Lin@Sun.COM mutex_enter(&pcwl_p->pcwl_glock); 42288410SWang.Lin@Sun.COM if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) { 42298410SWang.Lin@Sun.COM mutex_exit(&pcwl_p->pcwl_glock); 42308410SWang.Lin@Sun.COM err = EINVAL; 42318410SWang.Lin@Sun.COM return (err); 42328410SWang.Lin@Sun.COM } 42338410SWang.Lin@Sun.COM 42348410SWang.Lin@Sun.COM switch (wldp_pr_num) { 42358410SWang.Lin@Sun.COM /* mac_prop_id */ 42368410SWang.Lin@Sun.COM case MAC_PROP_WL_ESSID: 42378410SWang.Lin@Sun.COM err = pcwl_set_essid(pcwl_p, wldp_buf); 42388410SWang.Lin@Sun.COM break; 42398410SWang.Lin@Sun.COM case MAC_PROP_WL_PHY_CONFIG: 42408410SWang.Lin@Sun.COM err = pcwl_set_phy(pcwl_p, wldp_buf); 42418410SWang.Lin@Sun.COM break; 42428410SWang.Lin@Sun.COM case MAC_PROP_WL_KEY_TAB: 42438410SWang.Lin@Sun.COM err = pcwl_set_wepkey(pcwl_p, wldp_buf); 42448410SWang.Lin@Sun.COM break; 42458410SWang.Lin@Sun.COM case MAC_PROP_WL_AUTH_MODE: 42468410SWang.Lin@Sun.COM err = pcwl_set_authmode(pcwl_p, wldp_buf); 42478410SWang.Lin@Sun.COM break; 42488410SWang.Lin@Sun.COM case MAC_PROP_WL_ENCRYPTION: 42498410SWang.Lin@Sun.COM err = pcwl_set_encrypt(pcwl_p, wldp_buf); 42508410SWang.Lin@Sun.COM break; 42518410SWang.Lin@Sun.COM case MAC_PROP_WL_BSSTYPE: 42528410SWang.Lin@Sun.COM err = pcwl_set_bsstype(pcwl_p, wldp_buf); 42538410SWang.Lin@Sun.COM break; 42548410SWang.Lin@Sun.COM case MAC_PROP_WL_DESIRED_RATES: 42558410SWang.Lin@Sun.COM err = pcwl_set_desrates(pcwl_p, wldp_buf); 42568410SWang.Lin@Sun.COM break; 42578410SWang.Lin@Sun.COM case MAC_PROP_WL_POWER_MODE: 42588410SWang.Lin@Sun.COM err = pcwl_set_powermode(pcwl_p, wldp_buf); 42598410SWang.Lin@Sun.COM break; 42608410SWang.Lin@Sun.COM case MAC_PROP_WL_CREATE_IBSS: 42618410SWang.Lin@Sun.COM err = pcwl_set_ibss(pcwl_p, wldp_buf); 42628410SWang.Lin@Sun.COM break; 42638410SWang.Lin@Sun.COM case MAC_PROP_WL_BSSID: 42648410SWang.Lin@Sun.COM case MAC_PROP_WL_RADIO: 42658410SWang.Lin@Sun.COM case MAC_PROP_WL_WPA: 42668410SWang.Lin@Sun.COM case MAC_PROP_WL_KEY: 42678410SWang.Lin@Sun.COM case MAC_PROP_WL_DELKEY: 42688410SWang.Lin@Sun.COM case MAC_PROP_WL_SETOPTIE: 42698410SWang.Lin@Sun.COM case MAC_PROP_WL_MLME: 42708410SWang.Lin@Sun.COM case MAC_PROP_WL_LINKSTATUS: 42718410SWang.Lin@Sun.COM case MAC_PROP_WL_ESS_LIST: 42728410SWang.Lin@Sun.COM case MAC_PROP_WL_SUPPORTED_RATES: 42738410SWang.Lin@Sun.COM case MAC_PROP_WL_RSSI: 42748410SWang.Lin@Sun.COM case MAC_PROP_WL_CAPABILITY: 42758410SWang.Lin@Sun.COM case MAC_PROP_WL_SCANRESULTS: 42768410SWang.Lin@Sun.COM cmn_err(CE_WARN, "pcwl_setprop:" 42778410SWang.Lin@Sun.COM "opmode not support\n"); 42788410SWang.Lin@Sun.COM err = ENOTSUP; 42798410SWang.Lin@Sun.COM break; 42808410SWang.Lin@Sun.COM default: 42818410SWang.Lin@Sun.COM cmn_err(CE_WARN, "pcwl_setprop:" 42828410SWang.Lin@Sun.COM "opmode err\n"); 42838410SWang.Lin@Sun.COM err = EINVAL; 42848410SWang.Lin@Sun.COM break; 42858410SWang.Lin@Sun.COM } 42868410SWang.Lin@Sun.COM 42878410SWang.Lin@Sun.COM mutex_exit(&pcwl_p->pcwl_glock); 42888410SWang.Lin@Sun.COM 42898410SWang.Lin@Sun.COM if (err == ENETRESET) { 42908410SWang.Lin@Sun.COM (void) pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0); 42918410SWang.Lin@Sun.COM if (pcwl_p->pcwl_connect_timeout_id != 0) { 42928410SWang.Lin@Sun.COM (void) untimeout(pcwl_p->pcwl_connect_timeout_id); 42938410SWang.Lin@Sun.COM pcwl_p->pcwl_connect_timeout_id = 0; 42948410SWang.Lin@Sun.COM } 42958410SWang.Lin@Sun.COM pcwl_p->pcwl_connect_timeout_id = timeout(pcwl_connect_timeout, 42968410SWang.Lin@Sun.COM pcwl_p, 2 * drv_usectohz(1000000)); 42978410SWang.Lin@Sun.COM 42988410SWang.Lin@Sun.COM err = 0; 42998410SWang.Lin@Sun.COM } 43008410SWang.Lin@Sun.COM 43018410SWang.Lin@Sun.COM return (err); 43028410SWang.Lin@Sun.COM } /* ARGSUSED */ 43038410SWang.Lin@Sun.COM 43048410SWang.Lin@Sun.COM /* ARGSUSED */ 43058410SWang.Lin@Sun.COM static int 43068410SWang.Lin@Sun.COM pcwl_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num, 43078410SWang.Lin@Sun.COM uint_t pr_flags, uint_t wldp_length, void *wldp_buf, uint_t *perm) 43088410SWang.Lin@Sun.COM { 43098410SWang.Lin@Sun.COM int err = 0; 43108410SWang.Lin@Sun.COM 43118410SWang.Lin@Sun.COM pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg; 43128410SWang.Lin@Sun.COM 43138410SWang.Lin@Sun.COM if (wldp_length == 0) { 43148410SWang.Lin@Sun.COM err = EINVAL; 43158410SWang.Lin@Sun.COM return (err); 43168410SWang.Lin@Sun.COM } 43178410SWang.Lin@Sun.COM bzero(wldp_buf, wldp_length); 43188410SWang.Lin@Sun.COM 43198410SWang.Lin@Sun.COM mutex_enter(&pcwl_p->pcwl_glock); 43208410SWang.Lin@Sun.COM if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) { 43218410SWang.Lin@Sun.COM mutex_exit(&pcwl_p->pcwl_glock); 43228410SWang.Lin@Sun.COM err = EINVAL; 43238410SWang.Lin@Sun.COM return (err); 43248410SWang.Lin@Sun.COM } 43258410SWang.Lin@Sun.COM 43268410SWang.Lin@Sun.COM *perm = MAC_PROP_PERM_RW; 43278410SWang.Lin@Sun.COM 43288410SWang.Lin@Sun.COM switch (wldp_pr_num) { 43298410SWang.Lin@Sun.COM /* mac_prop_id */ 43308410SWang.Lin@Sun.COM case MAC_PROP_WL_ESSID: 43318410SWang.Lin@Sun.COM err = pcwl_get_essid(pcwl_p, wldp_buf); 43328410SWang.Lin@Sun.COM break; 43338410SWang.Lin@Sun.COM case MAC_PROP_WL_BSSID: 43348410SWang.Lin@Sun.COM err = pcwl_get_bssid(pcwl_p, wldp_buf); 43358410SWang.Lin@Sun.COM break; 43368410SWang.Lin@Sun.COM case MAC_PROP_WL_PHY_CONFIG: 43378410SWang.Lin@Sun.COM err = pcwl_get_phy(pcwl_p, wldp_buf); 43388410SWang.Lin@Sun.COM break; 43398410SWang.Lin@Sun.COM case MAC_PROP_WL_AUTH_MODE: 43408410SWang.Lin@Sun.COM pcwl_get_authmode(pcwl_p, wldp_buf); 43418410SWang.Lin@Sun.COM break; 43428410SWang.Lin@Sun.COM case MAC_PROP_WL_ENCRYPTION: 43438410SWang.Lin@Sun.COM pcwl_get_encrypt(pcwl_p, wldp_buf); 43448410SWang.Lin@Sun.COM break; 43458410SWang.Lin@Sun.COM case MAC_PROP_WL_BSSTYPE: 43468410SWang.Lin@Sun.COM pcwl_get_bsstype(pcwl_p, wldp_buf); 43478410SWang.Lin@Sun.COM break; 43488410SWang.Lin@Sun.COM case MAC_PROP_WL_LINKSTATUS: 43498410SWang.Lin@Sun.COM *perm = MAC_PROP_PERM_READ; 43508410SWang.Lin@Sun.COM err = pcwl_get_linkstatus(pcwl_p, wldp_buf); 43518410SWang.Lin@Sun.COM break; 43528410SWang.Lin@Sun.COM case MAC_PROP_WL_ESS_LIST: 43538410SWang.Lin@Sun.COM *perm = MAC_PROP_PERM_READ; 43548410SWang.Lin@Sun.COM pcwl_get_esslist(pcwl_p, wldp_buf); 43558410SWang.Lin@Sun.COM break; 43568410SWang.Lin@Sun.COM case MAC_PROP_WL_SUPPORTED_RATES: 43578410SWang.Lin@Sun.COM *perm = MAC_PROP_PERM_READ; 43588410SWang.Lin@Sun.COM pcwl_get_suprates(wldp_buf); 43598410SWang.Lin@Sun.COM break; 43608410SWang.Lin@Sun.COM case MAC_PROP_WL_RSSI: 43618410SWang.Lin@Sun.COM *perm = MAC_PROP_PERM_READ; 43628410SWang.Lin@Sun.COM pcwl_get_param_rssi(pcwl_p, wldp_buf); 43638410SWang.Lin@Sun.COM break; 43648410SWang.Lin@Sun.COM case MAC_PROP_WL_RADIO: 43658410SWang.Lin@Sun.COM pcwl_get_radio(wldp_buf); 43668410SWang.Lin@Sun.COM break; 43678410SWang.Lin@Sun.COM case MAC_PROP_WL_POWER_MODE: 43688410SWang.Lin@Sun.COM pcwl_get_powermode(pcwl_p, wldp_buf); 43698410SWang.Lin@Sun.COM break; 43708410SWang.Lin@Sun.COM case MAC_PROP_WL_CREATE_IBSS: 43718410SWang.Lin@Sun.COM pcwl_get_ibss(pcwl_p, wldp_buf); 43728410SWang.Lin@Sun.COM break; 43738410SWang.Lin@Sun.COM case MAC_PROP_WL_DESIRED_RATES: 43748410SWang.Lin@Sun.COM err = pcwl_get_desrates(pcwl_p, wldp_buf); 43758410SWang.Lin@Sun.COM break; 43768410SWang.Lin@Sun.COM case MAC_PROP_WL_CAPABILITY: 43778410SWang.Lin@Sun.COM case MAC_PROP_WL_WPA: 43788410SWang.Lin@Sun.COM case MAC_PROP_WL_SCANRESULTS: 43798410SWang.Lin@Sun.COM case MAC_PROP_WL_KEY_TAB: 43808410SWang.Lin@Sun.COM case MAC_PROP_WL_KEY: 43818410SWang.Lin@Sun.COM case MAC_PROP_WL_DELKEY: 43828410SWang.Lin@Sun.COM case MAC_PROP_WL_SETOPTIE: 43838410SWang.Lin@Sun.COM case MAC_PROP_WL_MLME: 43848410SWang.Lin@Sun.COM cmn_err(CE_WARN, "pcwl_getprop:" 43858410SWang.Lin@Sun.COM "opmode not support\n"); 43868410SWang.Lin@Sun.COM err = ENOTSUP; 43878410SWang.Lin@Sun.COM break; 43888410SWang.Lin@Sun.COM default: 43898410SWang.Lin@Sun.COM cmn_err(CE_WARN, "pcwl_getprop:" 43908410SWang.Lin@Sun.COM "opmode err\n"); 43918410SWang.Lin@Sun.COM err = EINVAL; 43928410SWang.Lin@Sun.COM break; 43938410SWang.Lin@Sun.COM } 43948410SWang.Lin@Sun.COM 43958410SWang.Lin@Sun.COM mutex_exit(&pcwl_p->pcwl_glock); 43968410SWang.Lin@Sun.COM 43978410SWang.Lin@Sun.COM return (err); 43988410SWang.Lin@Sun.COM } 4399*8801SQuaker.Fang@Sun.COM 4400*8801SQuaker.Fang@Sun.COM /* 4401*8801SQuaker.Fang@Sun.COM * quiesce(9E) entry point. 4402*8801SQuaker.Fang@Sun.COM * 4403*8801SQuaker.Fang@Sun.COM * This function is called when the system is single-threaded at high 4404*8801SQuaker.Fang@Sun.COM * PIL with preemption disabled. Therefore, this function must not be 4405*8801SQuaker.Fang@Sun.COM * blocked. 4406*8801SQuaker.Fang@Sun.COM * 4407*8801SQuaker.Fang@Sun.COM * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure. 4408*8801SQuaker.Fang@Sun.COM * DDI_FAILURE indicates an error condition and should almost never happen. 4409*8801SQuaker.Fang@Sun.COM */ 4410*8801SQuaker.Fang@Sun.COM #ifndef __sparc 4411*8801SQuaker.Fang@Sun.COM static int 4412*8801SQuaker.Fang@Sun.COM pcwl_quiesce(dev_info_t *dip) 4413*8801SQuaker.Fang@Sun.COM { 4414*8801SQuaker.Fang@Sun.COM pcwl_maci_t *pcwl_p; 4415*8801SQuaker.Fang@Sun.COM 4416*8801SQuaker.Fang@Sun.COM pcwl_p = ddi_get_soft_state(pcwl_soft_state_p, ddi_get_instance(dip)); 4417*8801SQuaker.Fang@Sun.COM if (pcwl_p == NULL) 4418*8801SQuaker.Fang@Sun.COM return (DDI_FAILURE); 4419*8801SQuaker.Fang@Sun.COM 4420*8801SQuaker.Fang@Sun.COM if (pcwl_p->pcwl_flag & PCWL_CARD_READY) 4421*8801SQuaker.Fang@Sun.COM pcwl_stop_locked(pcwl_p); 4422*8801SQuaker.Fang@Sun.COM 4423*8801SQuaker.Fang@Sun.COM return (DDI_SUCCESS); 4424*8801SQuaker.Fang@Sun.COM } 4425*8801SQuaker.Fang@Sun.COM #endif 4426