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