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