13737Shx147065 /* 27249Sff224033 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 33737Shx147065 * Use is subject to license terms. 43737Shx147065 */ 53737Shx147065 63737Shx147065 /* 73737Shx147065 * Copyright (c) 1997, 1998, 1999 83737Shx147065 * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 93737Shx147065 * 103737Shx147065 * Redistribution and use in source and binary forms, with or without 113737Shx147065 * modification, are permitted provided that the following conditions 123737Shx147065 * are met: 133737Shx147065 * 1. Redistributions of source code must retain the above copyright 143737Shx147065 * notice, this list of conditions and the following disclaimer. 153737Shx147065 * 2. Redistributions in binary form must reproduce the above copyright 163737Shx147065 * notice, this list of conditions and the following disclaimer in the 173737Shx147065 * documentation and/or other materials provided with the distribution. 183737Shx147065 * 3. All advertising materials mentioning features or use of this software 193737Shx147065 * must display the following acknowledgement: 203737Shx147065 * This product includes software developed by Bill Paul. 213737Shx147065 * 4. Neither the name of the author nor the names of any co-contributors 223737Shx147065 * may be used to endorse or promote products derived from this software 233737Shx147065 * without specific prior written permission. 243737Shx147065 * 253737Shx147065 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 263737Shx147065 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 273737Shx147065 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 283737Shx147065 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 293737Shx147065 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 303737Shx147065 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 313737Shx147065 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 323737Shx147065 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 333737Shx147065 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 343737Shx147065 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 353737Shx147065 * THE POSSIBILITY OF SUCH DAMAGE. 363737Shx147065 */ 373737Shx147065 383737Shx147065 #include <sys/conf.h> 393737Shx147065 #include <sys/ddi.h> 403737Shx147065 #include <sys/sunddi.h> 413737Shx147065 #include <sys/dlpi.h> 423737Shx147065 #include <sys/ethernet.h> 433737Shx147065 #include <sys/strsun.h> 443737Shx147065 #include <sys/stat.h> 453737Shx147065 #include <sys/byteorder.h> 463737Shx147065 #include <sys/pccard.h> 473737Shx147065 #include <sys/pci.h> 483737Shx147065 #include <sys/policy.h> 493737Shx147065 #include <sys/mac.h> 503737Shx147065 #include <sys/stream.h> 513737Shx147065 #include <inet/common.h> 523737Shx147065 #include <inet/nd.h> 533737Shx147065 #include <inet/mi.h> 543737Shx147065 553737Shx147065 #include "pcan.h" 563737Shx147065 #include <sys/mac_wifi.h> 573737Shx147065 #include <inet/wifi_ioctl.h> 583737Shx147065 593737Shx147065 #ifdef DEBUG 603737Shx147065 #define PCAN_DBG_BASIC 0x1 613737Shx147065 #define PCAN_DBG_INFO 0x2 623737Shx147065 #define PCAN_DBG_SEND 0x4 633737Shx147065 #define PCAN_DBG_RCV 0x8 643737Shx147065 #define PCAN_DBG_LINKINFO 0x10 653737Shx147065 #define PCAN_DBG_FW_VERSION 0x20 663737Shx147065 #define PCAN_DBG_CMD 0x40 673737Shx147065 uint32_t pcan_debug = 0; 683737Shx147065 #define PCANDBG(x) \ 693737Shx147065 if (pcan_debug & PCAN_DBG_BASIC) cmn_err x 703737Shx147065 #else 713737Shx147065 #define PCANDBG(x) 723737Shx147065 #endif 733737Shx147065 743737Shx147065 static ddi_device_acc_attr_t accattr = { 753737Shx147065 DDI_DEVICE_ATTR_V0, 763737Shx147065 DDI_STRUCTURE_LE_ACC, 773737Shx147065 DDI_STRICTORDER_ACC, 783737Shx147065 }; 793737Shx147065 803737Shx147065 static ddi_dma_attr_t control_cmd_dma_attr = { 813737Shx147065 DMA_ATTR_V0, /* version of this structure */ 823737Shx147065 0, /* lowest usable address */ 833737Shx147065 0xffffffffffffffffull, /* highest usable address */ 843737Shx147065 0xffffffffull, /* maximum DMAable byte count */ 853737Shx147065 4, /* alignment in bytes */ 863737Shx147065 0xfff, /* burst sizes (any) */ 873737Shx147065 1, /* minimum transfer */ 883737Shx147065 0xffffull, /* maximum transfer */ 893737Shx147065 0xffffffffffffffffull, /* maximum segment length */ 903737Shx147065 1, /* maximum number of segments */ 913737Shx147065 1, /* granularity */ 923737Shx147065 0, /* flags (reserved) */ 933737Shx147065 }; 943737Shx147065 953737Shx147065 void *pcan_soft_state_p = NULL; 963737Shx147065 static int pcan_device_type; 973737Shx147065 983737Shx147065 mac_callbacks_t pcan_m_callbacks = { 993737Shx147065 MC_IOCTL, 1003737Shx147065 pcan_gstat, 1013737Shx147065 pcan_start, 1023737Shx147065 pcan_stop, 1033737Shx147065 pcan_prom, 1043737Shx147065 pcan_sdmulti, 1053737Shx147065 pcan_saddr, 1063737Shx147065 pcan_tx, 1073737Shx147065 NULL, 1083737Shx147065 pcan_ioctl 1093737Shx147065 }; 1103737Shx147065 1113737Shx147065 static char *pcan_name_str = "pcan"; 1123737Shx147065 1133737Shx147065 DDI_DEFINE_STREAM_OPS(pcan_dev_ops, nulldev, pcan_probe, pcan_attach, 1143737Shx147065 1153737Shx147065 pcan_detach, nodev, NULL, D_MP, NULL); 1163737Shx147065 1173737Shx147065 extern struct mod_ops mod_driverops; 1183737Shx147065 static struct modldrv modldrv = { 1193737Shx147065 &mod_driverops, 1203737Shx147065 "Cisco-Aironet 802.11b driver", 1213737Shx147065 &pcan_dev_ops 1223737Shx147065 }; 1233737Shx147065 1243737Shx147065 static struct modlinkage modlinkage = { 1253737Shx147065 MODREV_1, (void *)&modldrv, NULL 1263737Shx147065 }; 1273737Shx147065 1283737Shx147065 int 1293737Shx147065 _init(void) 1303737Shx147065 { 1313737Shx147065 int stat; 1323737Shx147065 1333737Shx147065 /* Allocate soft state */ 1343737Shx147065 if ((stat = ddi_soft_state_init(&pcan_soft_state_p, 1353737Shx147065 sizeof (pcan_maci_t), 2)) != DDI_SUCCESS) 1363737Shx147065 return (stat); 1373737Shx147065 1383737Shx147065 mac_init_ops(&pcan_dev_ops, "pcan"); 1393737Shx147065 stat = mod_install(&modlinkage); 1403737Shx147065 if (stat != 0) { 1413737Shx147065 mac_fini_ops(&pcan_dev_ops); 1423737Shx147065 ddi_soft_state_fini(&pcan_soft_state_p); 1433737Shx147065 } 1443737Shx147065 1453737Shx147065 return (stat); 1463737Shx147065 } 1473737Shx147065 1483737Shx147065 int 1493737Shx147065 _fini(void) 1503737Shx147065 { 1513737Shx147065 int stat; 1523737Shx147065 1533737Shx147065 stat = mod_remove(&modlinkage); 1543737Shx147065 if (stat != DDI_SUCCESS) 1553737Shx147065 return (stat); 1563737Shx147065 mac_fini_ops(&pcan_dev_ops); 1573737Shx147065 ddi_soft_state_fini(&pcan_soft_state_p); 1583737Shx147065 return (stat); 1593737Shx147065 } 1603737Shx147065 1613737Shx147065 int 1623737Shx147065 _info(struct modinfo *modinfop) 1633737Shx147065 { 1643737Shx147065 return (mod_info(&modlinkage, modinfop)); 1653737Shx147065 } 1663737Shx147065 1673737Shx147065 static int 1683737Shx147065 pcan_probe(dev_info_t *dip) 1693737Shx147065 { 1703737Shx147065 int len, ret; 1713737Shx147065 char *buf; 1723737Shx147065 dev_info_t *pdip = ddi_get_parent(dip); 1733737Shx147065 1743737Shx147065 PCANDBG((CE_NOTE, "pcan probe: parent dip=0x%p-%s(%d)\n", (void *)pdip, 1753737Shx147065 ddi_driver_name(pdip), ddi_get_instance(pdip))); 1763737Shx147065 1773737Shx147065 ret = ddi_getlongprop(DDI_DEV_T_ANY, pdip, 0, "device_type", 1783737Shx147065 (caddr_t)&buf, &len); 1793737Shx147065 if (ret != DDI_SUCCESS) 1803737Shx147065 return (DDI_PROBE_FAILURE); 1813737Shx147065 1823737Shx147065 PCANDBG((CE_NOTE, "pcan probe: device_type %s\n", buf)); 1833737Shx147065 if ((strcmp(buf, "pccard") == 0) || (strcmp(buf, "pcmcia") == 0)) { 1843737Shx147065 pcan_device_type = PCAN_DEVICE_PCCARD; 1853737Shx147065 #ifdef DEBUG 1863737Shx147065 if (pcan_debug & PCAN_DBG_FW_VERSION) { 1873737Shx147065 cmn_err(CE_NOTE, "Cisco 802.11 pccard\n"); 1883737Shx147065 } 1893737Shx147065 #endif 1903737Shx147065 ret = DDI_PROBE_SUCCESS; 1913737Shx147065 } else if (strcmp(buf, "pci") == 0) { 1923737Shx147065 pcan_device_type = PCAN_DEVICE_PCI; 1933737Shx147065 #ifdef DEBUG 1943737Shx147065 if (pcan_debug & PCAN_DBG_FW_VERSION) { 1953737Shx147065 cmn_err(CE_NOTE, "Cisco 802.11 minipci card\n"); 1963737Shx147065 } 1973737Shx147065 #endif 1983737Shx147065 ret = DDI_PROBE_SUCCESS; 1993737Shx147065 } else { 2003737Shx147065 cmn_err(CE_NOTE, "pcan probe: unsupported card\n"); 2013737Shx147065 ret = DDI_PROBE_FAILURE; 2023737Shx147065 } 2033737Shx147065 2043737Shx147065 kmem_free(buf, len); 2053737Shx147065 return (ret); 2063737Shx147065 } 2073737Shx147065 2083737Shx147065 static int 2093737Shx147065 pcan_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2103737Shx147065 { 2113737Shx147065 int ret; 2123737Shx147065 int instance; 2133737Shx147065 uint16_t stat; 2143737Shx147065 uint32_t err; 2153737Shx147065 pcan_maci_t *pcan_p; 2163737Shx147065 wifi_data_t wd = { 0 }; 2173737Shx147065 mac_register_t *macp; 2183737Shx147065 modify_config_t cfgmod; 2193737Shx147065 char strbuf[256]; 2203737Shx147065 2213737Shx147065 PCANDBG((CE_NOTE, "dip=0x%p cmd=%x\n", (void *)dip, cmd)); 2223737Shx147065 if (cmd != DDI_ATTACH) 2233737Shx147065 goto attach_fail1; 2243737Shx147065 2253737Shx147065 /* 2263737Shx147065 * Since this driver is porting from freebsd, so just like 2273737Shx147065 * the original driver, the minipci card doesn't work on amd64 2283737Shx147065 * machine. 2293737Shx147065 * For sparc, since no pci card is available for the test, so this 2303737Shx147065 * version doesn't support sparc. If there is card available and 2313737Shx147065 * requirement, future version will try to support sparc. 2323737Shx147065 * This driver works well for minipci card on 32bit x86 2333737Shx147065 * machine, so keep the code to just support minipci card on 32bit 2343737Shx147065 * mode. 2353737Shx147065 */ 2363737Shx147065 #if defined(sparc) || defined(__sparc) 2373737Shx147065 if (pcan_device_type == PCAN_DEVICE_PCI) { 2383737Shx147065 cmn_err(CE_NOTE, "pcan attach: this driver does not support " 2393737Shx147065 "PCI/MiniPCI card on Sparc\n"); 2403737Shx147065 goto attach_fail1; 2413737Shx147065 } 2423737Shx147065 #endif /* sparc */ 2433737Shx147065 #if defined(__amd64) 2443737Shx147065 if (pcan_device_type == PCAN_DEVICE_PCI) { 2453737Shx147065 cmn_err(CE_NOTE, "pcan attach: this driver does not support " 2463737Shx147065 "PCI/MiniPCI card on amd64\n"); 2473737Shx147065 goto attach_fail1; 2483737Shx147065 } 2493737Shx147065 #endif /* amd64 */ 2503737Shx147065 2513737Shx147065 /* Allocate soft state associated with this instance. */ 2523737Shx147065 if (ddi_soft_state_zalloc(pcan_soft_state_p, 2533737Shx147065 ddi_get_instance(dip)) != DDI_SUCCESS) { 2543737Shx147065 cmn_err(CE_CONT, "pcan attach: alloc softstate failed\n"); 2553737Shx147065 goto attach_fail1; 2563737Shx147065 } 2573737Shx147065 pcan_p = (pcan_maci_t *)ddi_get_soft_state(pcan_soft_state_p, 2583737Shx147065 ddi_get_instance(dip)); 2593737Shx147065 2603737Shx147065 pcan_p->pcan_device_type = pcan_device_type; 2613737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 2623737Shx147065 if (ddi_regs_map_setup(dip, 0, 2633737Shx147065 (caddr_t *)&pcan_p->pcan_cfg_base, 0, 0, 2643737Shx147065 &accattr, &pcan_p->pcan_cfg_handle) != DDI_SUCCESS) 2653737Shx147065 goto attach_fail2; 2663737Shx147065 2673737Shx147065 stat = ddi_get16(pcan_p->pcan_cfg_handle, 2683737Shx147065 (uint16_t *)(pcan_p->pcan_cfg_base + PCI_CONF_COMM)); 2693737Shx147065 stat |= (PCI_COMM_IO | PCI_COMM_MAE); 2703737Shx147065 ddi_put16(pcan_p->pcan_cfg_handle, 2713737Shx147065 (uint16_t *)(pcan_p->pcan_cfg_base + PCI_CONF_COMM), stat); 2723737Shx147065 2733737Shx147065 ddi_regs_map_free(&pcan_p->pcan_cfg_handle); 2743737Shx147065 if (ddi_regs_map_setup(dip, 1, (caddr_t *)&pcan_p->pcan_bar0, 2753737Shx147065 0, 0, &accattr, &pcan_p->pcan_handle0) != DDI_SUCCESS) 2763737Shx147065 goto attach_fail3; 2773737Shx147065 if (ddi_regs_map_setup(dip, 2, (caddr_t *)&pcan_p->pcan_bar1, 2783737Shx147065 0, 0, &accattr, &pcan_p->pcan_handle1) != DDI_SUCCESS) 2793737Shx147065 goto attach_fail3; 2803737Shx147065 if (ddi_regs_map_setup(dip, 3, (caddr_t *)&pcan_p->pcan_bar2, 2813737Shx147065 0, 0, &accattr, &pcan_p->pcan_handle2) != DDI_SUCCESS) 2823737Shx147065 goto attach_fail3; 2833737Shx147065 } 2843737Shx147065 2853737Shx147065 pcan_p->pcan_dip = dip; 2863737Shx147065 pcan_p->pcan_flag = 0; 2873737Shx147065 pcan_p->glds_nocarrier = 0; 2883737Shx147065 pcan_p->glds_noxmtbuf = 0; 2893737Shx147065 pcan_p->glds_norcvbuf = 0; 2903737Shx147065 pcan_p->pcan_socket = ddi_getprop(DDI_DEV_T_NONE, dip, 2914343Sgd78059 DDI_PROP_DONTPASS, "socket", -1); 2923737Shx147065 2933737Shx147065 pcan_p->pcan_reschedule_need = B_FALSE; 2943737Shx147065 pcan_p->pcan_info_softint_pending = 0; 2953737Shx147065 pcan_p->pcan_reset_delay = ddi_getprop(DDI_DEV_T_ANY, dip, 2963737Shx147065 DDI_PROP_DONTPASS, "reset-delay", 5000); 2973737Shx147065 2983737Shx147065 if (ddi_get_iblock_cookie(dip, 2993737Shx147065 0, &pcan_p->pcan_ib_cookie) != DDI_SUCCESS) { 3003737Shx147065 cmn_err(CE_WARN, "pcan attach: get_iblk_cookie failed\n"); 3013737Shx147065 goto attach_fail3; 3023737Shx147065 } 3033737Shx147065 3043737Shx147065 mutex_init(&pcan_p->pcan_glock, NULL, 3053737Shx147065 MUTEX_DRIVER, pcan_p->pcan_ib_cookie); 3063737Shx147065 mutex_init(&pcan_p->pcan_scanlist_lock, NULL, 3073737Shx147065 MUTEX_DRIVER, pcan_p->pcan_ib_cookie); 3083737Shx147065 mutex_init(&pcan_p->pcan_txring.an_tx_lock, NULL, 3093737Shx147065 MUTEX_DRIVER, pcan_p->pcan_ib_cookie); 3103737Shx147065 3113737Shx147065 if (ret = ddi_add_softintr(dip, DDI_SOFTINT_LOW, 3123737Shx147065 &pcan_p->pcan_info_softint_id, &pcan_p->pcan_ib_cookie, NULL, 3133737Shx147065 pcan_info_softint, (caddr_t)pcan_p)) { 3143737Shx147065 cmn_err(CE_WARN, "pcan attach: add info_softintr failed\n"); 3153737Shx147065 goto attach_fail3a; 3163737Shx147065 } 3173737Shx147065 3183737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 3193737Shx147065 if (ret = ddi_add_intr(dip, 0, NULL, NULL, 3203737Shx147065 pcan_intr, (caddr_t)pcan_p)) { 3213737Shx147065 cmn_err(CE_WARN, "pcan attach: add intr failed\n"); 3223737Shx147065 goto attach_fail4; 3233737Shx147065 } 3243737Shx147065 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) { 3253737Shx147065 if (ret = pcan_register_cs(dip, pcan_p)) { 3263737Shx147065 PCANDBG((CE_NOTE, "pcan attach: register_cs failed" 3273737Shx147065 " %x\n", ret)); 3283737Shx147065 goto attach_fail4; 3293737Shx147065 } 3303737Shx147065 } else { 3313737Shx147065 cmn_err(CE_WARN, "pcan attach: unsupported device type\n"); 3323737Shx147065 goto attach_fail4; 3333737Shx147065 } 3343737Shx147065 3353737Shx147065 mutex_enter(&pcan_p->pcan_glock); 3363737Shx147065 pcan_reset_backend(pcan_p, pcan_p->pcan_reset_delay); 3373737Shx147065 /* leaves IF down, intr disabled */ 3383737Shx147065 3393737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 3403737Shx147065 if (ret = pcan_init_dma(dip, pcan_p)) { 3413737Shx147065 cmn_err(CE_WARN, "pcan init_dma: failed\n"); 3423737Shx147065 mutex_exit(&pcan_p->pcan_glock); 3433737Shx147065 goto attach_fail5; 3443737Shx147065 } 3453737Shx147065 } 3463737Shx147065 if (ret = pcan_get_cap(pcan_p)) { /* sets macaddr for gld_register */ 3473737Shx147065 cmn_err(CE_WARN, "pcan attach: get_cap failed %x\n", ret); 3483737Shx147065 mutex_exit(&pcan_p->pcan_glock); 3493737Shx147065 goto attach_fail6; 3503737Shx147065 } 3513737Shx147065 3523737Shx147065 mutex_exit(&pcan_p->pcan_glock); 3533737Shx147065 /* 3543737Shx147065 * Provide initial settings for the WiFi plugin; whenever this 3553737Shx147065 * information changes, we need to call mac_pdata_update() 3563737Shx147065 */ 3573737Shx147065 wd.wd_secalloc = WIFI_SEC_NONE; 3583737Shx147065 wd.wd_opmode = IEEE80211_M_STA; 3593737Shx147065 3603737Shx147065 macp = mac_alloc(MAC_VERSION); 3613737Shx147065 if (macp == NULL) { 3623737Shx147065 PCANDBG((CE_NOTE, "pcan attach: " 3633737Shx147065 "MAC version mismatch\n")); 3643737Shx147065 goto attach_fail6; 3653737Shx147065 } 3663737Shx147065 3673737Shx147065 macp->m_type_ident = MAC_PLUGIN_IDENT_WIFI; 3683737Shx147065 macp->m_driver = pcan_p; 3693737Shx147065 macp->m_dip = dip; 3703737Shx147065 macp->m_src_addr = pcan_p->pcan_mac_addr; 3713737Shx147065 macp->m_callbacks = &pcan_m_callbacks; 3723737Shx147065 macp->m_min_sdu = 0; 3733737Shx147065 macp->m_max_sdu = IEEE80211_MTU; 3743737Shx147065 macp->m_pdata = &wd; 3753737Shx147065 macp->m_pdata_size = sizeof (wd); 3763737Shx147065 3773737Shx147065 err = mac_register(macp, &pcan_p->pcan_mh); 3783737Shx147065 mac_free(macp); 3793737Shx147065 if (err != 0) { 3803737Shx147065 PCANDBG((CE_NOTE, "pcan attach: " 3813737Shx147065 "mac_register err\n")); 3823737Shx147065 goto attach_fail6; 3833737Shx147065 } 3843737Shx147065 3853737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) { 3863737Shx147065 /* turn on CS interrupt */ 3873737Shx147065 cfgmod.Attributes = CONF_ENABLE_IRQ_STEERING | 3883737Shx147065 CONF_IRQ_CHANGE_VALID; 3893737Shx147065 cfgmod.Vpp1 = 50; 3903737Shx147065 cfgmod.Vpp2 = 50; 3913737Shx147065 (void) csx_ModifyConfiguration(pcan_p->pcan_chdl, &cfgmod); 3923737Shx147065 3933737Shx147065 mutex_enter(&pcan_p->pcan_glock); 3943737Shx147065 if (ret = pcan_init_nicmem(pcan_p)) { 3953737Shx147065 cmn_err(CE_WARN, "pcan attach: init_nicmem failed %x\n", 3963737Shx147065 ret); 3973737Shx147065 mutex_exit(&pcan_p->pcan_glock); 3983737Shx147065 goto attach_fail7; 3993737Shx147065 } 4003737Shx147065 mutex_exit(&pcan_p->pcan_glock); 4013737Shx147065 } 4023737Shx147065 (void) ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 4033737Shx147065 "bad-rids", (caddr_t)&pcan_p->pcan_badrids, 4043737Shx147065 &pcan_p->pcan_badrids_len); 4053737Shx147065 4063737Shx147065 pcan_p->an_config.an_rxmode = AN_NORMAL_RXMODE; 4073737Shx147065 ether_copy(pcan_p->pcan_mac_addr, pcan_p->an_config.an_macaddr); 4083737Shx147065 mutex_enter(&pcan_p->pcan_glock); 4093737Shx147065 list_create(&pcan_p->an_scan_list, sizeof (an_scan_list_t), 4103737Shx147065 offsetof(an_scan_list_t, an_scan_node)); 4113737Shx147065 pcan_p->an_scan_num = 0; 4123737Shx147065 mutex_exit(&pcan_p->pcan_glock); 4133737Shx147065 pcan_p->an_scanlist_timeout_id = timeout(pcan_scanlist_timeout, 4143737Shx147065 pcan_p, drv_usectohz(1000000)); 4153737Shx147065 4163737Shx147065 instance = ddi_get_instance(dip); 4173737Shx147065 (void) snprintf(strbuf, sizeof (strbuf), "pcan%d", instance); 4183737Shx147065 if (ddi_create_minor_node(dip, strbuf, S_IFCHR, 4193737Shx147065 instance + 1, DDI_NT_NET_WIFI, 0) != DDI_SUCCESS) { 4203737Shx147065 goto attach_fail8; 4213737Shx147065 } 4223737Shx147065 mutex_enter(&pcan_p->pcan_glock); 4233737Shx147065 PCAN_DISABLE_INTR_CLEAR(pcan_p); 4243737Shx147065 (void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0); 4253737Shx147065 pcan_p->pcan_flag |= PCAN_ATTACHED; 4263737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 4273737Shx147065 pcan_p->pcan_flag |= PCAN_CARD_READY; 4283737Shx147065 } 4293737Shx147065 mutex_exit(&pcan_p->pcan_glock); 4303737Shx147065 return (DDI_SUCCESS); 4313737Shx147065 attach_fail8: 4323737Shx147065 if (pcan_p->an_scanlist_timeout_id != 0) { 4333737Shx147065 (void) untimeout(pcan_p->an_scanlist_timeout_id); 4343737Shx147065 pcan_p->an_scanlist_timeout_id = 0; 4353737Shx147065 } 4363737Shx147065 list_destroy(&pcan_p->an_scan_list); 4373737Shx147065 attach_fail7: 4383737Shx147065 (void) mac_unregister(pcan_p->pcan_mh); 4393737Shx147065 attach_fail6: 4403737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) 4413737Shx147065 pcan_free_dma(pcan_p); 4423737Shx147065 attach_fail5: 4433737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 4443737Shx147065 ddi_remove_intr(dip, 0, pcan_p->pcan_ib_cookie); 4453737Shx147065 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) { 4463737Shx147065 pcan_unregister_cs(pcan_p); 4473737Shx147065 } 4483737Shx147065 attach_fail4: 4493737Shx147065 if (pcan_p->pcan_info_softint_id) 4503737Shx147065 ddi_remove_softintr(pcan_p->pcan_info_softint_id); 4513737Shx147065 attach_fail3a: 4523737Shx147065 pcan_destroy_locks(pcan_p); 4533737Shx147065 attach_fail3: 4543737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 4553737Shx147065 if (pcan_p->pcan_handle0) 4563737Shx147065 ddi_regs_map_free(&pcan_p->pcan_handle0); 4573737Shx147065 if (pcan_p->pcan_handle1) 4583737Shx147065 ddi_regs_map_free(&pcan_p->pcan_handle1); 4593737Shx147065 if (pcan_p->pcan_handle2) 4603737Shx147065 ddi_regs_map_free(&pcan_p->pcan_handle2); 4613737Shx147065 } 4623737Shx147065 attach_fail2: 4633737Shx147065 ddi_soft_state_free(pcan_soft_state_p, ddi_get_instance(dip)); 4643737Shx147065 attach_fail1: 4653737Shx147065 return (DDI_FAILURE); 4663737Shx147065 } 4673737Shx147065 4683737Shx147065 static int 4693737Shx147065 pcan_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 4703737Shx147065 { 4713737Shx147065 pcan_maci_t *pcan_p; 4723737Shx147065 an_scan_list_t *scan_item0; 4733737Shx147065 int ret; 4743737Shx147065 pcan_p = ddi_get_soft_state(pcan_soft_state_p, ddi_get_instance(dip)); 4753737Shx147065 4763737Shx147065 if (cmd != DDI_DETACH) 4773737Shx147065 return (DDI_FAILURE); 4783737Shx147065 if (!(pcan_p->pcan_flag & PCAN_ATTACHED)) 4793737Shx147065 return (DDI_FAILURE); 4803737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 4813737Shx147065 mutex_enter(&pcan_p->pcan_glock); 4823737Shx147065 pcan_stop_locked(pcan_p); 4833737Shx147065 PCAN_DISABLE_INTR(pcan_p); 4843737Shx147065 mutex_exit(&pcan_p->pcan_glock); 4853737Shx147065 } 4863737Shx147065 if (pcan_p->an_scanlist_timeout_id != 0) { 4873737Shx147065 (void) untimeout(pcan_p->an_scanlist_timeout_id); 4883737Shx147065 pcan_p->an_scanlist_timeout_id = 0; 4893737Shx147065 } 4903737Shx147065 if (pcan_p->pcan_connect_timeout_id != 0) { 4913737Shx147065 (void) untimeout(pcan_p->pcan_connect_timeout_id); 4923737Shx147065 pcan_p->pcan_connect_timeout_id = 0; 4933737Shx147065 } 4943737Shx147065 mutex_enter(&pcan_p->pcan_scanlist_lock); 4953737Shx147065 scan_item0 = list_head(&pcan_p->an_scan_list); 4963737Shx147065 while (scan_item0) { 4973737Shx147065 pcan_delete_scan_item(pcan_p, scan_item0); 4983737Shx147065 scan_item0 = list_head(&pcan_p->an_scan_list); 4993737Shx147065 } 5003737Shx147065 list_destroy(&pcan_p->an_scan_list); 5013737Shx147065 mutex_exit(&pcan_p->pcan_scanlist_lock); 5023737Shx147065 5033737Shx147065 ret = mac_unregister(pcan_p->pcan_mh); 5043737Shx147065 if (ret != 0) 5053737Shx147065 return (DDI_FAILURE); 5063737Shx147065 5073737Shx147065 mutex_enter(&pcan_p->pcan_glock); 5083737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 5093737Shx147065 ddi_remove_intr(dip, 0, pcan_p->pcan_ib_cookie); 5103737Shx147065 pcan_free_dma(pcan_p); 5113737Shx147065 if (pcan_p->pcan_handle0) 5123737Shx147065 ddi_regs_map_free(&pcan_p->pcan_handle0); 5133737Shx147065 if (pcan_p->pcan_handle1) 5143737Shx147065 ddi_regs_map_free(&pcan_p->pcan_handle1); 5153737Shx147065 if (pcan_p->pcan_handle2) 5163737Shx147065 ddi_regs_map_free(&pcan_p->pcan_handle2); 5173737Shx147065 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) { 5183737Shx147065 pcan_unregister_cs(pcan_p); 5193737Shx147065 } else { 5203737Shx147065 cmn_err(CE_WARN, "pcan detach: unsupported device type\n"); 5213737Shx147065 } 5223737Shx147065 mutex_exit(&pcan_p->pcan_glock); 5233737Shx147065 pcan_destroy_locks(pcan_p); 5243737Shx147065 if (pcan_p->pcan_info_softint_id) 5253737Shx147065 ddi_remove_softintr(pcan_p->pcan_info_softint_id); 5263737Shx147065 5273737Shx147065 if (pcan_p->pcan_badrids_len) 5283737Shx147065 kmem_free(pcan_p->pcan_badrids, pcan_p->pcan_badrids_len); 5293737Shx147065 5303737Shx147065 ddi_soft_state_free(pcan_soft_state_p, ddi_get_instance(dip)); 5313737Shx147065 ddi_remove_minor_node(dip, NULL); 5323737Shx147065 5333737Shx147065 return (DDI_SUCCESS); 5343737Shx147065 } 5353737Shx147065 5363737Shx147065 /* 5373737Shx147065 * card services and event handlers 5383737Shx147065 */ 5393737Shx147065 5403737Shx147065 static int 5413737Shx147065 pcan_register_cs(dev_info_t *dip, pcan_maci_t *pcan_p) 5423737Shx147065 { 5433737Shx147065 int ret; 5443737Shx147065 client_reg_t cr; 5453737Shx147065 client_handle_t chdl; /* uint encoding of socket, function, client */ 5463737Shx147065 get_status_t card_status; 5473737Shx147065 request_socket_mask_t sock_req; 5483737Shx147065 5493737Shx147065 bzero(&cr, sizeof (cr)); 5503737Shx147065 cr.Attributes = INFO_IO_CLIENT|INFO_CARD_EXCL|INFO_CARD_SHARE; 5513737Shx147065 cr.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | 5523737Shx147065 CS_EVENT_REGISTRATION_COMPLETE | CS_EVENT_CARD_REMOVAL_LOWP | 5533737Shx147065 CS_EVENT_CARD_READY | CS_EVENT_PM_RESUME | CS_EVENT_PM_SUSPEND | 5543737Shx147065 CS_EVENT_CLIENT_INFO; 5553737Shx147065 cr.event_callback_args.client_data = pcan_p; 5563737Shx147065 cr.Version = CS_VERSION; 5573737Shx147065 cr.event_handler = (csfunction_t *)pcan_ev_hdlr; 5583737Shx147065 cr.dip = dip; 5593737Shx147065 (void) strcpy(cr.driver_name, pcan_name_str); 5603737Shx147065 if (ret = csx_RegisterClient(&chdl, &cr)) { 5613737Shx147065 cmn_err(CE_WARN, "pcan: RegisterClient failed %x", ret); 5623737Shx147065 goto regcs_ret; 5633737Shx147065 } 5643737Shx147065 5653737Shx147065 pcan_p->pcan_chdl = chdl; 5663737Shx147065 5673737Shx147065 bzero(&card_status, sizeof (card_status)); 5683737Shx147065 (void) csx_GetStatus(chdl, &card_status); 5693737Shx147065 PCANDBG((CE_NOTE, "pcan: getstat Sock=%x CState=%x SState=%x rState=%x", 5703737Shx147065 card_status.Socket, card_status.CardState, 5713737Shx147065 card_status.SocketState, card_status.raw_CardState)); 5723737Shx147065 if (!(card_status.CardState & CS_STATUS_CARD_INSERTED)) { 5733737Shx147065 /* card is not present, why are we attaching ? */ 5743737Shx147065 ret = CS_NO_CARD; 5753737Shx147065 goto unreg; 5763737Shx147065 } 5773737Shx147065 cv_init(&pcan_p->pcan_cscv, NULL, CV_DRIVER, NULL); 5783737Shx147065 mutex_init(&pcan_p->pcan_cslock, NULL, MUTEX_DRIVER, *cr.iblk_cookie); 5793737Shx147065 mutex_enter(&pcan_p->pcan_cslock); 5803737Shx147065 if (ret = csx_MapLogSocket(chdl, &pcan_p->pcan_log_sock)) { 5813737Shx147065 cmn_err(CE_WARN, "pcan: MapLogSocket failed %x", ret); 5823737Shx147065 goto fail; 5833737Shx147065 } 5843737Shx147065 PCANDBG((CE_NOTE, "pcan: logsock: LogSock=%x PhyAdapter=%x PhySock=%x", 5853737Shx147065 pcan_p->pcan_log_sock.LogSocket, 5863737Shx147065 pcan_p->pcan_log_sock.PhyAdapter, 5873737Shx147065 pcan_p->pcan_log_sock.PhySocket)); 5883737Shx147065 5893737Shx147065 /* turn on initialization events */ 5903737Shx147065 sock_req.Socket = 0; 5913737Shx147065 sock_req.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | 5923737Shx147065 CS_EVENT_REGISTRATION_COMPLETE; 5933737Shx147065 if (ret = csx_RequestSocketMask(chdl, &sock_req)) { 5943737Shx147065 cmn_err(CE_WARN, "pcan: RequestSocketMask failed %x\n", ret); 5953737Shx147065 goto fail; 5963737Shx147065 } 5973737Shx147065 5983737Shx147065 /* wait for and process card insertion events */ 5993737Shx147065 while (!(pcan_p->pcan_flag & PCAN_CARD_READY)) 6003737Shx147065 cv_wait(&pcan_p->pcan_cscv, &pcan_p->pcan_cslock); 6013737Shx147065 mutex_exit(&pcan_p->pcan_cslock); 6023737Shx147065 6033737Shx147065 pcan_p->pcan_flag |= PCAN_CS_REGISTERED; 6043737Shx147065 return (CS_SUCCESS); 6053737Shx147065 fail: 6063737Shx147065 mutex_destroy(&pcan_p->pcan_cslock); 6073737Shx147065 cv_destroy(&pcan_p->pcan_cscv); 6083737Shx147065 unreg: 6093737Shx147065 (void) csx_DeregisterClient(chdl); 6103737Shx147065 regcs_ret: 6113737Shx147065 pcan_p->pcan_flag &= ~PCAN_CS_REGISTERED; 6123737Shx147065 return (ret); 6133737Shx147065 } 6143737Shx147065 6153737Shx147065 static void 6163737Shx147065 pcan_unregister_cs(pcan_maci_t *pcan_p) 6173737Shx147065 { 6183737Shx147065 int ret; 6193737Shx147065 release_socket_mask_t mask; 6203737Shx147065 mask.Socket = pcan_p->pcan_socket; 6213737Shx147065 6223737Shx147065 /* 6233737Shx147065 * The card service not registered means register_cs function 6243737Shx147065 * doesnot return TRUE. Then all the lelated resource has been 6253737Shx147065 * released in register_cs. 6263737Shx147065 */ 6273737Shx147065 if (!(pcan_p->pcan_flag | PCAN_CS_REGISTERED)) 6283737Shx147065 return; 6293737Shx147065 (void) csx_ReleaseSocketMask(pcan_p->pcan_chdl, &mask); 6303737Shx147065 6313737Shx147065 if (pcan_p->pcan_flag & PCAN_CARD_READY) { 6323737Shx147065 pcan_card_remove(pcan_p); 6333737Shx147065 pcan_p->pcan_flag &= ~PCAN_CARD_READY; 6343737Shx147065 } 6353737Shx147065 mutex_destroy(&pcan_p->pcan_cslock); 6363737Shx147065 cv_destroy(&pcan_p->pcan_cscv); 6373737Shx147065 if (ret = csx_DeregisterClient(pcan_p->pcan_chdl)) 6383737Shx147065 cmn_err(CE_WARN, "pcan: deregister failed %x\n", ret); 6393737Shx147065 } 6403737Shx147065 static void 6413737Shx147065 pcan_destroy_locks(pcan_maci_t *pcan_p) 6423737Shx147065 { 6433737Shx147065 mutex_destroy(&pcan_p->pcan_txring.an_tx_lock); 6443737Shx147065 mutex_destroy(&pcan_p->pcan_scanlist_lock); 6453737Shx147065 mutex_destroy(&pcan_p->pcan_glock); 6463737Shx147065 } 6473737Shx147065 6483737Shx147065 static int 6493737Shx147065 pcan_ev_hdlr(event_t event, int priority, event_callback_args_t *arg) 6503737Shx147065 { 6513737Shx147065 int ret = CS_SUCCESS; 6523737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg->client_data; 6533737Shx147065 client_info_t *ci_p = (client_info_t *)&arg->client_info; 6543737Shx147065 6553737Shx147065 mutex_enter(&pcan_p->pcan_cslock); 6563737Shx147065 switch (event) { 6573737Shx147065 case CS_EVENT_CARD_INSERTION: 6583737Shx147065 ret = pcan_card_insert(pcan_p); 6593737Shx147065 cv_broadcast(&pcan_p->pcan_cscv); 6603737Shx147065 break; 6613737Shx147065 case CS_EVENT_REGISTRATION_COMPLETE: 6623737Shx147065 cv_broadcast(&pcan_p->pcan_cscv); 6633737Shx147065 break; 6643737Shx147065 case CS_EVENT_CARD_REMOVAL: 6653737Shx147065 if (priority & CS_EVENT_PRI_HIGH) 6663737Shx147065 break; 6673737Shx147065 pcan_card_remove(pcan_p); 6683737Shx147065 cv_broadcast(&pcan_p->pcan_cscv); 6693737Shx147065 break; 6703737Shx147065 case CS_EVENT_CLIENT_INFO: 6713737Shx147065 if (GET_CLIENT_INFO_SUBSVC(ci_p->Attributes) != 6723737Shx147065 CS_CLIENT_INFO_SUBSVC_CS) 6733737Shx147065 break; 6743737Shx147065 6753737Shx147065 ci_p->Revision = 0x0101; 6763737Shx147065 ci_p->CSLevel = CS_VERSION; 6773737Shx147065 ci_p->RevDate = CS_CLIENT_INFO_MAKE_DATE(9, 12, 14); 6783737Shx147065 (void) strcpy(ci_p->ClientName, PCAN_IDENT_STRING); 6793737Shx147065 (void) strcpy(ci_p->VendorName, CS_SUN_VENDOR_DESCRIPTION); 6803737Shx147065 ci_p->Attributes |= CS_CLIENT_INFO_VALID; 6813737Shx147065 break; 6823737Shx147065 default: 6833737Shx147065 ret = CS_UNSUPPORTED_EVENT; 6843737Shx147065 break; 6853737Shx147065 } 6863737Shx147065 mutex_exit(&pcan_p->pcan_cslock); 6873737Shx147065 return (ret); 6883737Shx147065 } 6893737Shx147065 6903737Shx147065 static int 6913737Shx147065 pcan_card_insert(pcan_maci_t *pcan_p) 6923737Shx147065 { 6933737Shx147065 int ret, hi, lo; 6943737Shx147065 tuple_t tuple; 6953737Shx147065 cisparse_t cisparse; 6963737Shx147065 io_req_t io; 6973737Shx147065 irq_req_t irq; 6983737Shx147065 config_req_t cfg; 6993737Shx147065 cistpl_config_t config; 7003737Shx147065 cistpl_cftable_entry_t *tbl_p; 7013737Shx147065 register client_handle_t chdl = pcan_p->pcan_chdl; 7023737Shx147065 7033737Shx147065 bzero(&tuple, sizeof (tuple)); 7043737Shx147065 tuple.DesiredTuple = CISTPL_MANFID; 7053737Shx147065 if (ret = csx_GetFirstTuple(chdl, &tuple)) { 7063737Shx147065 cmn_err(CE_WARN, "pcan: get manufacture id failed %x\n", ret); 7073737Shx147065 goto insert_ret; 7083737Shx147065 } 7093737Shx147065 bzero(&cisparse, sizeof (cisparse)); 7103737Shx147065 if (ret = csx_Parse_CISTPL_MANFID(chdl, &tuple, &cisparse.manfid)) { 7113737Shx147065 cmn_err(CE_WARN, "pcan: parse manufacture id failed %x\n", ret); 7123737Shx147065 goto insert_ret; 7133737Shx147065 } 7143737Shx147065 /* verify manufacture ID */ 7153737Shx147065 PCANDBG((CE_NOTE, "pcan: manufacturer_id=%x card=%x\n", 7163737Shx147065 cisparse.manfid.manf, cisparse.manfid.card)); 7173737Shx147065 7183737Shx147065 bzero(&tuple, sizeof (tuple)); 7193737Shx147065 tuple.DesiredTuple = CISTPL_FUNCID; 7203737Shx147065 if (ret = csx_GetFirstTuple(chdl, &tuple)) { 7213737Shx147065 cmn_err(CE_WARN, "pcan: get function id failed %x\n", ret); 7223737Shx147065 goto insert_ret; 7233737Shx147065 } 7243737Shx147065 bzero(&cisparse, sizeof (cisparse)); 7253737Shx147065 if (ret = csx_Parse_CISTPL_FUNCID(chdl, &tuple, &cisparse.funcid)) { 7263737Shx147065 cmn_err(CE_WARN, "pcan: parse function id failed %x\n", ret); 7273737Shx147065 goto insert_ret; 7283737Shx147065 } 7293737Shx147065 /* verify function ID */ 7303737Shx147065 PCANDBG((CE_NOTE, "funcid=%x\n", cisparse.funcid.function)); 7313737Shx147065 7323737Shx147065 bzero(&tuple, sizeof (tuple)); 7333737Shx147065 tuple.DesiredTuple = CISTPL_CONFIG; 7343737Shx147065 if (ret = csx_GetFirstTuple(chdl, &tuple)) { 7353737Shx147065 cmn_err(CE_WARN, "pcan: get config failed %x\n", ret); 7363737Shx147065 goto insert_ret; 7373737Shx147065 } 7383737Shx147065 bzero(&config, sizeof (config)); 7393737Shx147065 if (ret = csx_Parse_CISTPL_CONFIG(chdl, &tuple, &config)) { 7403737Shx147065 cmn_err(CE_WARN, "pcan: parse config failed %x\n", ret); 7413737Shx147065 goto insert_ret; 7423737Shx147065 } 7433737Shx147065 PCANDBG((CE_NOTE, 7443737Shx147065 "pcan: config present=%x nr=%x hr=%x regs[0]=%x base=%x last=%x\n", 7453737Shx147065 config.present, config.nr, config.hr, config.regs[0], 7463737Shx147065 config.base, config.last)); 7473737Shx147065 7483737Shx147065 hi = 0; 7493737Shx147065 lo = (int)-1; /* really big number */ 7503737Shx147065 tbl_p = &cisparse.cftable; 7513737Shx147065 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; 7523737Shx147065 for (tbl_p->index = 0; tbl_p->index <= config.hr; ) { 7533737Shx147065 PCANDBG((CE_NOTE, "pcan: tuple idx=%x:\n", tbl_p->index)); 7543737Shx147065 if (ret = csx_GetNextTuple(chdl, &tuple)) { 7553737Shx147065 cmn_err(CE_WARN, "pcan: get cftable failed %x\n", ret); 7563737Shx147065 break; 7573737Shx147065 } 7583737Shx147065 bzero((caddr_t)&cisparse, sizeof (cisparse)); 7593737Shx147065 if (ret = csx_Parse_CISTPL_CFTABLE_ENTRY(chdl, &tuple, tbl_p)) { 7603737Shx147065 cmn_err(CE_WARN, "pcan: parse cftable failed%x\n", ret); 7613737Shx147065 break; 7623737Shx147065 } 7633737Shx147065 if (tbl_p->flags & CISTPL_CFTABLE_TPCE_FS_PWR && 7644343Sgd78059 tbl_p->pd.flags & CISTPL_CFTABLE_TPCE_FS_PWR_VCC) { 7653737Shx147065 if (tbl_p->pd.pd_vcc.avgI > hi) { 7663737Shx147065 hi = tbl_p->pd.pd_vcc.avgI; 7673737Shx147065 pcan_p->pcan_config_hi = tbl_p->index; 7683737Shx147065 } 7693737Shx147065 if (tbl_p->pd.pd_vcc.avgI < lo) { 7703737Shx147065 lo = tbl_p->pd.pd_vcc.avgI; 7713737Shx147065 pcan_p->pcan_config = tbl_p->index; 7723737Shx147065 } 7733737Shx147065 } 7743737Shx147065 if (tbl_p->flags & CISTPL_CFTABLE_TPCE_DEFAULT) { 7753737Shx147065 if (tbl_p->pd.flags & CISTPL_CFTABLE_TPCE_FS_PWR_VCC) 7763737Shx147065 pcan_p->pcan_vcc = tbl_p->pd.pd_vcc.nomV; 7773737Shx147065 if (tbl_p->flags & CISTPL_CFTABLE_TPCE_FS_IO) 7783737Shx147065 pcan_p->pcan_iodecode = tbl_p->io.addr_lines; 7793737Shx147065 } 7803737Shx147065 } 7813737Shx147065 PCANDBG((CE_NOTE, "pcan: cfg_hi=%x cfg=%x vcc=%x iodecode=%x\n", 7823737Shx147065 pcan_p->pcan_config_hi, pcan_p->pcan_config, 7833737Shx147065 pcan_p->pcan_vcc, pcan_p->pcan_iodecode)); 7843737Shx147065 7853737Shx147065 bzero(&io, sizeof (io)); 7863737Shx147065 io.BasePort1.base = 0; 7873737Shx147065 io.NumPorts1 = 1 << pcan_p->pcan_iodecode; 7883737Shx147065 io.Attributes1 = IO_DATA_PATH_WIDTH_16; 7893737Shx147065 io.IOAddrLines = pcan_p->pcan_iodecode; 7903737Shx147065 if (ret = csx_RequestIO(chdl, &io)) { 7913737Shx147065 cmn_err(CE_WARN, "pcan: RequestIO failed %x\n", ret); 7923737Shx147065 goto insert_ret; 7933737Shx147065 } 7943737Shx147065 pcan_p->pcan_port = io.BasePort1.handle; 7953737Shx147065 7963737Shx147065 if (ret = ddi_add_softintr(DIP(pcan_p), DDI_SOFTINT_HIGH, 7973737Shx147065 &pcan_p->pcan_softint_id, &pcan_p->pcan_ib_cookie, NULL, 7983737Shx147065 pcan_intr, (caddr_t)pcan_p)) { 7993737Shx147065 cmn_err(CE_NOTE, "pcan: Add softintr failed\n"); 8003737Shx147065 goto insert_ret; 8013737Shx147065 } 8023737Shx147065 irq.Attributes = IRQ_TYPE_EXCLUSIVE; 8033737Shx147065 irq.irq_handler = ddi_intr_hilevel(DIP(pcan_p), 0) ? 8043737Shx147065 (csfunction_t *)pcan_intr_hi : (csfunction_t *)pcan_intr; 8053737Shx147065 irq.irq_handler_arg = pcan_p; 8063737Shx147065 if (ret = csx_RequestIRQ(chdl, &irq)) { 8073737Shx147065 cmn_err(CE_WARN, "pcan: RequestIRQ failed %x\n", ret); 8083737Shx147065 goto un_io; 8093737Shx147065 } 8103737Shx147065 8113737Shx147065 bzero(&cfg, sizeof (cfg)); 8123737Shx147065 cfg.Attributes = 0; /* not ready for CONF_ENABLE_IRQ_STEERING yet */ 8133737Shx147065 cfg.Vcc = 50; /* pcan_vcc == 0 */ 8143737Shx147065 cfg.Vpp1 = 50; 8153737Shx147065 cfg.Vpp2 = 50; 8163737Shx147065 cfg.IntType = SOCKET_INTERFACE_MEMORY_AND_IO; 8173737Shx147065 cfg.ConfigBase = config.base; 8183737Shx147065 cfg.ConfigIndex = pcan_p->pcan_config; 8193737Shx147065 cfg.Status = CCSR_IO_IS_8; /* no use */ 8203737Shx147065 cfg.Present = config.present; 8213737Shx147065 pcan_p->pcan_flag |= PCAN_CARD_READY; 8223737Shx147065 if (ret = csx_RequestConfiguration(chdl, &cfg)) { 8233737Shx147065 cmn_err(CE_WARN, "pcan: RequestConfiguration failed %x\n", ret); 8243737Shx147065 goto un_irq; 8253737Shx147065 } 8263737Shx147065 return (CS_SUCCESS); 8273737Shx147065 un_irq: 8283737Shx147065 (void) csx_ReleaseIRQ(chdl, &irq); 8293737Shx147065 un_io: 8303737Shx147065 ddi_remove_softintr(pcan_p->pcan_softint_id); 8313737Shx147065 8323737Shx147065 (void) csx_ReleaseIO(chdl, &io); 8333737Shx147065 pcan_p->pcan_port = 0; 8343737Shx147065 insert_ret: 8353737Shx147065 pcan_p->pcan_flag &= ~PCAN_CARD_READY; 8363737Shx147065 return (ret); 8373737Shx147065 } 8383737Shx147065 8393737Shx147065 /* 8403737Shx147065 * assume card is already removed, don't touch the hardware 8413737Shx147065 */ 8423737Shx147065 static void 8433737Shx147065 pcan_card_remove(pcan_maci_t *pcan_p) 8443737Shx147065 { 8453737Shx147065 int ret; 8463737Shx147065 io_req_t io; 8473737Shx147065 irq_req_t irq; 8483737Shx147065 8493737Shx147065 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) 8503737Shx147065 return; 8513737Shx147065 if (ret = csx_ReleaseConfiguration(pcan_p->pcan_chdl, NULL)) 8523737Shx147065 cmn_err(CE_WARN, "pcan: ReleaseConfiguration failed %x\n", ret); 8533737Shx147065 8543737Shx147065 bzero(&irq, sizeof (irq)); 8553737Shx147065 if (ret = csx_ReleaseIRQ(pcan_p->pcan_chdl, &irq)) 8563737Shx147065 cmn_err(CE_WARN, "pcan: ReleaseIRQ failed %x\n", ret); 8573737Shx147065 8583737Shx147065 ddi_remove_softintr(pcan_p->pcan_softint_id); 8593737Shx147065 8603737Shx147065 bzero(&io, sizeof (io)); 8613737Shx147065 io.BasePort1.handle = pcan_p->pcan_port; 8623737Shx147065 io.NumPorts1 = 16; 8633737Shx147065 if (ret = csx_ReleaseIO(pcan_p->pcan_chdl, &io)) 8643737Shx147065 cmn_err(CE_WARN, "pcan: Release IO failed %x\n", ret); 8653737Shx147065 8663737Shx147065 pcan_p->pcan_port = 0; 8673737Shx147065 pcan_p->pcan_flag &= ~PCAN_CARD_READY; 8683737Shx147065 } 8693737Shx147065 8703737Shx147065 /* 8713737Shx147065 * gld operation interface routines 8723737Shx147065 */ 8733737Shx147065 static int 8743737Shx147065 pcan_start(void *arg) 8753737Shx147065 { 8763737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 8773737Shx147065 8783737Shx147065 mutex_enter(&pcan_p->pcan_glock); 8793737Shx147065 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) { 8803737Shx147065 mutex_exit(&pcan_p->pcan_glock); 8813737Shx147065 return (PCAN_FAIL); 8823737Shx147065 } 8833737Shx147065 (void) pcan_loaddef(pcan_p); 8843737Shx147065 pcan_start_locked(pcan_p); 8853737Shx147065 mutex_exit(&pcan_p->pcan_glock); 8863737Shx147065 return (PCAN_SUCCESS); 8873737Shx147065 } 8883737Shx147065 8893737Shx147065 static void 8903737Shx147065 pcan_stop(void *arg) 8913737Shx147065 { 8923737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 8933737Shx147065 8943737Shx147065 mutex_enter(&pcan_p->pcan_glock); 8953737Shx147065 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) { 8963737Shx147065 mutex_exit(&pcan_p->pcan_glock); 8973737Shx147065 return; 8983737Shx147065 } 8993737Shx147065 pcan_stop_locked(pcan_p); 9003737Shx147065 mutex_exit(&pcan_p->pcan_glock); 9013737Shx147065 if (pcan_p->pcan_connect_timeout_id != 0) { 9023737Shx147065 (void) untimeout(pcan_p->pcan_connect_timeout_id); 9033737Shx147065 pcan_p->pcan_connect_timeout_id = 0; 9043737Shx147065 } 9053737Shx147065 } 9063737Shx147065 9073737Shx147065 /* 9083737Shx147065 * mac address can only be set in 'disable' state and 9093737Shx147065 * be effective after 'enable' state. 9103737Shx147065 */ 9113737Shx147065 static int 9123737Shx147065 pcan_saddr(void *arg, const uint8_t *macaddr) 9133737Shx147065 { 9143737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 9153737Shx147065 int ret = PCAN_SUCCESS; 9163737Shx147065 ether_copy(macaddr, pcan_p->pcan_mac_addr); 9173737Shx147065 9183737Shx147065 mutex_enter(&pcan_p->pcan_glock); 9193737Shx147065 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) { 9203737Shx147065 ret = PCAN_FAIL; 9213737Shx147065 goto done; 9223737Shx147065 } 9233737Shx147065 ether_copy(pcan_p->pcan_mac_addr, pcan_p->an_config.an_macaddr); 9243737Shx147065 if (pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) { 9253737Shx147065 cmn_err(CE_WARN, "pcan set mac addr: failed\n"); 9263737Shx147065 ret = PCAN_FAIL; 9273737Shx147065 goto done; 9283737Shx147065 } 9293737Shx147065 if (pcan_config_mac(pcan_p)) { 9303737Shx147065 cmn_err(CE_WARN, "pcan set mac addr: config_mac failed\n"); 9313737Shx147065 ret = PCAN_FAIL; 9323737Shx147065 goto done; 9333737Shx147065 } 9343737Shx147065 if (pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0)) { 9353737Shx147065 cmn_err(CE_WARN, "pcan set mac addr: failed\n"); 9363737Shx147065 ret = PCAN_FAIL; 9373737Shx147065 } 9383737Shx147065 done: 9393737Shx147065 mutex_exit(&pcan_p->pcan_glock); 9403737Shx147065 return (ret); 9413737Shx147065 } 9423737Shx147065 9433737Shx147065 /* 9443737Shx147065 * send a packet out for pccard 9453737Shx147065 */ 9463737Shx147065 static int 9473737Shx147065 pcan_send(pcan_maci_t *pcan_p, mblk_t *mblk_p) 9483737Shx147065 { 9493737Shx147065 char *buf, *buf_p; 9503737Shx147065 an_txfrm_t *frm_p; 9513737Shx147065 #ifdef PCAN_SEND_DEBUG 9523737Shx147065 struct an_ltv_status radio_status; 9533737Shx147065 #endif /* PCAN_SEND_DEBUG */ 9543737Shx147065 uint16_t pkt_len, xmt_id, ring_idx; 9553737Shx147065 struct ieee80211_frame *wh; 9563737Shx147065 int i = 0; 9573737Shx147065 9583737Shx147065 mutex_enter(&pcan_p->pcan_glock); 9593737Shx147065 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) { 9603737Shx147065 mutex_exit(&pcan_p->pcan_glock); 9613737Shx147065 freemsg(mblk_p); 9623737Shx147065 return (PCAN_SUCCESS); /* drop packet */ 9633737Shx147065 } 9643737Shx147065 if (!(pcan_p->pcan_flag & PCAN_CARD_LINKUP)) { /* link down */ 9653737Shx147065 PCANDBG((CE_NOTE, "pcan: link down, dropped\n")); 9663737Shx147065 pcan_p->glds_nocarrier++; 9673737Shx147065 mutex_exit(&pcan_p->pcan_glock); 9683737Shx147065 freemsg(mblk_p); 9693737Shx147065 return (PCAN_SUCCESS); /* drop packet */ 9703737Shx147065 } 9713737Shx147065 mutex_exit(&pcan_p->pcan_glock); 9723737Shx147065 if (pullupmsg(mblk_p, -1) == 0) { 9733737Shx147065 cmn_err(CE_NOTE, "pcan send: pullupmsg failed\n"); 9743737Shx147065 freemsg(mblk_p); 9753737Shx147065 return (PCAN_SUCCESS); /* drop packet */ 9763737Shx147065 } 9773737Shx147065 wh = (struct ieee80211_frame *)mblk_p->b_rptr; 9783737Shx147065 9793737Shx147065 mutex_enter(&pcan_p->pcan_txring.an_tx_lock); 9803737Shx147065 ring_idx = pcan_p->pcan_txring.an_tx_prod; 9813737Shx147065 pcan_p->pcan_txring.an_tx_prod = (ring_idx + 1) & AN_TX_RING_MASK; 9823737Shx147065 9833737Shx147065 /* check whether there is a xmt buffer available */ 9843737Shx147065 while ((i < AN_TX_RING_CNT) && 9853737Shx147065 (pcan_p->pcan_txring.an_tx_ring[ring_idx])) { 9863737Shx147065 ring_idx = pcan_p->pcan_txring.an_tx_prod; 9873737Shx147065 pcan_p->pcan_txring.an_tx_prod = 9883737Shx147065 (ring_idx + 1) & AN_TX_RING_MASK; 9893737Shx147065 i++; 9903737Shx147065 } 9913737Shx147065 9923737Shx147065 if (i == AN_TX_RING_CNT) { 9933737Shx147065 mutex_exit(&pcan_p->pcan_txring.an_tx_lock); 9943737Shx147065 PCANDBG((CE_NOTE, "pcan: ring full, retrying\n")); 9953737Shx147065 mutex_enter(&pcan_p->pcan_glock); 9963737Shx147065 pcan_p->pcan_reschedule_need = B_TRUE; 9973737Shx147065 mutex_exit(&pcan_p->pcan_glock); 9983737Shx147065 pcan_p->glds_noxmtbuf++; 9993737Shx147065 return (PCAN_FAIL); 10003737Shx147065 } 10013737Shx147065 xmt_id = pcan_p->pcan_txring.an_tx_fids[ring_idx]; 10023737Shx147065 pcan_p->pcan_txring.an_tx_ring[ring_idx] = xmt_id; 10033737Shx147065 mutex_exit(&pcan_p->pcan_txring.an_tx_lock); 10043737Shx147065 10053737Shx147065 buf = kmem_zalloc(PCAN_NICMEM_SZ, KM_SLEEP); /* too big for stack */ 10063737Shx147065 buf_p = (ulong_t)buf & 1 ? buf + 1 : buf; /* 16-bit round up */ 10073737Shx147065 frm_p = (an_txfrm_t *)buf_p; 10083737Shx147065 10093737Shx147065 #ifdef DEBUG 10103737Shx147065 if (pcan_debug & PCAN_DBG_SEND) { 10113737Shx147065 cmn_err(CE_NOTE, "pcan send: packet from plugin"); 10127249Sff224033 for (i = 0; i < MBLKL(mblk_p); i++) 10133737Shx147065 cmn_err(CE_NOTE, "%x: %x\n", i, 10143737Shx147065 *((unsigned char *)mblk_p->b_rptr + i)); 10153737Shx147065 } 10163737Shx147065 #endif 10173737Shx147065 pkt_len = msgdsize(mblk_p); 10183737Shx147065 if (pkt_len > PCAN_NICMEM_SZ - sizeof (an_txfrm_t)) { 10193737Shx147065 cmn_err(CE_WARN, "pcan send: mblk is too long"); 10203737Shx147065 kmem_free(buf, PCAN_NICMEM_SZ); 10213737Shx147065 freemsg(mblk_p); 10223737Shx147065 return (PCAN_SUCCESS); /* drop packet */ 10233737Shx147065 } 10243737Shx147065 if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) != 10253737Shx147065 IEEE80211_FC1_DIR_TODS) { 10263737Shx147065 kmem_free(buf, PCAN_NICMEM_SZ); 10273737Shx147065 freemsg(mblk_p); 10283737Shx147065 return (PCAN_SUCCESS); /* drop packet */ 10293737Shx147065 } 10303737Shx147065 10313737Shx147065 /* initialize xmt frame header, payload_len must be stored in LE */ 10323737Shx147065 bzero(frm_p, sizeof (an_txfrm_t) + 2); 10333737Shx147065 frm_p->an_tx_ctl = AN_TXCTL_8023; 10343737Shx147065 10353737Shx147065 /* 10363737Shx147065 * mblk sent down from plugin includes station mode 802.11 frame and 10373737Shx147065 * llc, so we here need to remove them and add an ethernet header. 10383737Shx147065 */ 10393737Shx147065 pkt_len = pkt_len - (sizeof (*wh) + sizeof (struct ieee80211_llc)) 10403737Shx147065 + 2; 10413737Shx147065 bcopy(wh->i_addr3, buf_p + 0x38, ETHERADDRL); /* dst macaddr */ 10423737Shx147065 bcopy(wh->i_addr2, buf_p + 0x3e, ETHERADDRL); /* src macaddr */ 10433737Shx147065 *((uint16_t *)(buf_p + 0x36)) = pkt_len; 10443737Shx147065 bcopy(mblk_p->b_rptr + sizeof (*wh) + sizeof (struct ieee80211_llc) 10453737Shx147065 - 2, buf_p + 0x44, pkt_len); 10463737Shx147065 10473737Shx147065 if (pkt_len & 1) { /* round up to 16-bit boundary and pad 0 */ 10483737Shx147065 buf_p[pkt_len + 0x44] = 0; 10493737Shx147065 pkt_len++; 10503737Shx147065 } 10513737Shx147065 ASSERT(pkt_len <= PCAN_NICMEM_SZ); 10523737Shx147065 #ifdef DEBUG 10533737Shx147065 if (pcan_debug & PCAN_DBG_SEND) { 10543737Shx147065 cmn_err(CE_NOTE, "pcan send: packet to hardware--pkt_len=%x", 10553737Shx147065 pkt_len); 10563737Shx147065 for (i = 0; i < pkt_len + 4; i++) 10573737Shx147065 cmn_err(CE_NOTE, "%x: %x\n", i, 10583737Shx147065 *((unsigned char *)buf_p + 0x36 + i)); 10593737Shx147065 } 10603737Shx147065 #endif 10613737Shx147065 mutex_enter(&pcan_p->pcan_glock); 10623737Shx147065 (void) WRCH1(pcan_p, xmt_id, 0, (uint16_t *)buf_p, 0x38); /* frm */ 10633737Shx147065 (void) WRPKT(pcan_p, xmt_id, 0x38, (uint16_t *)(buf_p + 0x38), 10644343Sgd78059 pkt_len + 12); 10653737Shx147065 ring_idx = pcan_set_cmd(pcan_p, AN_CMD_TX, xmt_id); 10663737Shx147065 mutex_exit(&pcan_p->pcan_glock); 10673737Shx147065 10683737Shx147065 PCANDBG((CE_NOTE, "pcan: pkt_len=0x44+%x=%x xmt=%x ret=%x\n", 10693737Shx147065 pkt_len, 0x44 + pkt_len, xmt_id, ring_idx)); 10703737Shx147065 kmem_free(buf, PCAN_NICMEM_SZ); 10713737Shx147065 #ifdef PCAN_SEND_DEBUG 10723737Shx147065 if (pkt_len = pcan_status_ltv(PCAN_READ_LTV, pcan_p, &radio_status)) { 10733737Shx147065 PCANDBG((CE_NOTE, "pcan: bad radio status %x\n", pkt_len)); 10743737Shx147065 } else { 10753737Shx147065 PCANDBG((CE_NOTE, "pcan: radio status:\n")); 10763737Shx147065 } 10773737Shx147065 #endif /* PCAN_SEND_DEBUG */ 10783737Shx147065 if (ring_idx) 10793737Shx147065 return (PCAN_FAIL); 10803737Shx147065 else { 10813737Shx147065 freemsg(mblk_p); 10823737Shx147065 return (PCAN_SUCCESS); 10833737Shx147065 } 10843737Shx147065 } 10853737Shx147065 10863737Shx147065 /* 10873737Shx147065 * send a packet out for PCI/MiniPCI card 10883737Shx147065 */ 10893737Shx147065 static int 10903737Shx147065 pcian_send(pcan_maci_t *pcan_p, mblk_t *mblk_p) 10913737Shx147065 { 10923737Shx147065 char *buf; 10933737Shx147065 uint16_t pkt_len = msgdsize(mblk_p), ring_idx; 10943737Shx147065 uint32_t i; 10953737Shx147065 struct ieee80211_frame *wh; 10963737Shx147065 struct an_card_tx_desc an_tx_desc; 10973737Shx147065 10983737Shx147065 ring_idx = pcan_p->pcan_txring.an_tx_prod; 10993737Shx147065 11003737Shx147065 mutex_enter(&pcan_p->pcan_glock); 11013737Shx147065 if (!(pcan_p->pcan_flag & PCAN_CARD_LINKUP)) { /* link down */ 11023737Shx147065 mutex_exit(&pcan_p->pcan_glock); 11033737Shx147065 pcan_p->glds_nocarrier++; 11043737Shx147065 freemsg(mblk_p); 11053737Shx147065 return (PCAN_SUCCESS); /* drop packet */ 11063737Shx147065 } 11073737Shx147065 mutex_exit(&pcan_p->pcan_glock); 11083737Shx147065 if (pullupmsg(mblk_p, -1) == 0) { 11093737Shx147065 cmn_err(CE_NOTE, "pcan(pci) send: pullupmsg failed\n"); 11103737Shx147065 freemsg(mblk_p); 11113737Shx147065 return (PCAN_SUCCESS); /* drop packet */ 11123737Shx147065 } 11133737Shx147065 wh = (struct ieee80211_frame *)mblk_p->b_rptr; 11143737Shx147065 11153737Shx147065 mutex_enter(&pcan_p->pcan_txring.an_tx_lock); 11163737Shx147065 if ((pcan_p->pcan_flag & PCAN_CARD_SEND) && 11173737Shx147065 (ring_idx == pcan_p->pcan_txring.an_tx_cons)) { 11183737Shx147065 pcan_p->glds_noxmtbuf++; 11193737Shx147065 pcan_p->pcan_reschedule_need = B_TRUE; 11203737Shx147065 mutex_exit(&pcan_p->pcan_txring.an_tx_lock); 11213737Shx147065 return (PCAN_FAIL); 11223737Shx147065 } 11233737Shx147065 mutex_exit(&pcan_p->pcan_txring.an_tx_lock); 11243737Shx147065 11253737Shx147065 #ifdef DEBUG 11263737Shx147065 if (pcan_debug & PCAN_DBG_SEND) { 11273737Shx147065 cmn_err(CE_NOTE, "pcan(pci) send: packet from plugin"); 11287249Sff224033 for (i = 0; i < MBLKL(mblk_p); i++) 11293737Shx147065 cmn_err(CE_NOTE, "%x: %x\n", i, 11303737Shx147065 *((unsigned char *)mblk_p->b_rptr + i)); 11313737Shx147065 } 11323737Shx147065 #endif 11333737Shx147065 mutex_enter(&pcan_p->pcan_glock); 11343737Shx147065 11353737Shx147065 buf = pcan_p->pcan_tx[ring_idx].dma_virtaddr; 11363737Shx147065 bzero(buf, AN_TX_BUFFER_SIZE); 11373737Shx147065 11383737Shx147065 /* 11393737Shx147065 * mblk sent down from plugin includes station mode 802.11 frame and 11403737Shx147065 * llc, so we here need to remove them and add an ethernet header. 11413737Shx147065 */ 11423737Shx147065 *((uint16_t *)(buf + 8)) = htons(AN_TXCTL_8023); 11433737Shx147065 pkt_len = pkt_len - (sizeof (*wh) + sizeof (struct ieee80211_llc)) 11443737Shx147065 + 2; 11453737Shx147065 bcopy(wh->i_addr3, buf + 0x38, ETHERADDRL); /* dst macaddr */ 11463737Shx147065 bcopy(wh->i_addr2, buf + 0x3e, ETHERADDRL); /* src macaddr */ 11473737Shx147065 *((uint16_t *)(buf + 0x36)) = pkt_len; 11483737Shx147065 bcopy(mblk_p->b_rptr + sizeof (*wh) + sizeof (struct ieee80211_llc) 11493737Shx147065 - 2, buf + 0x44, pkt_len); 11503737Shx147065 11513737Shx147065 #ifdef DEBUG 11523737Shx147065 if (pcan_debug & PCAN_DBG_SEND) { 11533737Shx147065 cmn_err(CE_NOTE, "pcan(pci) send: packet to hardware " 11543737Shx147065 "pkt_len=%x", pkt_len); 11553737Shx147065 for (i = 0; i < pkt_len + 14; i++) 11563737Shx147065 cmn_err(CE_NOTE, "%x: %x\n", i, 11573737Shx147065 *((unsigned char *)buf + 0x36 + i)); 11583737Shx147065 } 11593737Shx147065 #endif 11603737Shx147065 bzero(&an_tx_desc, sizeof (an_tx_desc)); 11613737Shx147065 an_tx_desc.an_offset = 0; 11623737Shx147065 an_tx_desc.an_eoc = (ring_idx == (AN_MAX_TX_DESC-1) ? 1 : 0); 11633737Shx147065 an_tx_desc.an_valid = 1; 11643737Shx147065 an_tx_desc.an_len = 0x44 + pkt_len; 11653737Shx147065 an_tx_desc.an_phys = pcan_p->pcan_tx[ring_idx].dma_physaddr; 11663737Shx147065 for (i = 0; i < sizeof (an_tx_desc) / 4; i++) { 11673737Shx147065 PCAN_AUX_PUT32(pcan_p, AN_TX_DESC_OFFSET + 11683737Shx147065 (ring_idx * sizeof (an_tx_desc)) + (i * 4), 11693737Shx147065 ((uint32_t *)&an_tx_desc)[i]); 11703737Shx147065 } 11713737Shx147065 11723737Shx147065 mutex_enter(&pcan_p->pcan_txring.an_tx_lock); 11733737Shx147065 pcan_p->pcan_txring.an_tx_prod = (ring_idx + 1) % AN_MAX_TX_DESC; 11743737Shx147065 pcan_p->pcan_flag |= PCAN_CARD_SEND; 11753737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_ALLOC); 11763737Shx147065 mutex_exit(&pcan_p->pcan_txring.an_tx_lock); 11773737Shx147065 11783737Shx147065 freemsg(mblk_p); 11793737Shx147065 mutex_exit(&pcan_p->pcan_glock); 11803737Shx147065 return (PCAN_SUCCESS); 11813737Shx147065 } 11823737Shx147065 11833737Shx147065 static mblk_t * 11843737Shx147065 pcan_tx(void *arg, mblk_t *mp) 11853737Shx147065 { 11863737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 11873737Shx147065 mblk_t *next; 11883737Shx147065 int ret = 0; 11893737Shx147065 11903737Shx147065 ASSERT(mp != NULL); 11913737Shx147065 mutex_enter(&pcan_p->pcan_glock); 11923737Shx147065 if ((pcan_p->pcan_flag & (PCAN_CARD_LINKUP | PCAN_CARD_READY)) != 11933737Shx147065 (PCAN_CARD_LINKUP | PCAN_CARD_READY)) { 11943737Shx147065 mutex_exit(&pcan_p->pcan_glock); 11953737Shx147065 return (mp); 11963737Shx147065 } 11973737Shx147065 mutex_exit(&pcan_p->pcan_glock); 11983737Shx147065 while (mp != NULL) { 11993737Shx147065 next = mp->b_next; 12003737Shx147065 mp->b_next = NULL; 12013737Shx147065 12023737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 12033737Shx147065 ret = pcian_send(pcan_p, mp); 12043737Shx147065 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) { 12053737Shx147065 ret = pcan_send(pcan_p, mp); 12063737Shx147065 } 12073737Shx147065 if (ret) { 12083737Shx147065 mp->b_next = next; 12093737Shx147065 break; 12103737Shx147065 } 12113737Shx147065 mp = next; 12123737Shx147065 } 12133737Shx147065 return (mp); 12143737Shx147065 } 12153737Shx147065 12163737Shx147065 /* 12173737Shx147065 * this driver is porting from freebsd, the code in freebsd 12183737Shx147065 * doesn't show how to set promiscous mode. 12193737Shx147065 */ 12203737Shx147065 /*ARGSUSED*/ 12213737Shx147065 static int 12223737Shx147065 pcan_prom(void *arg, boolean_t on) 12233737Shx147065 { 12243737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 12253737Shx147065 int ret = PCAN_SUCCESS; 12263737Shx147065 12273737Shx147065 mutex_enter(&pcan_p->pcan_glock); 12283737Shx147065 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) { 12293737Shx147065 ret = PCAN_FAIL; 12303737Shx147065 } 12313737Shx147065 mutex_exit(&pcan_p->pcan_glock); 12323737Shx147065 return (ret); 12333737Shx147065 } 12343737Shx147065 12353737Shx147065 /*ARGSUSED*/ 12363737Shx147065 static int 12373737Shx147065 pcan_gstat(void *arg, uint_t statitem, uint64_t *val) 12383737Shx147065 { 12393737Shx147065 uint16_t i; 12403737Shx147065 int ret = PCAN_SUCCESS; 12413737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 12423737Shx147065 uint64_t *cntr_p = pcan_p->pcan_cntrs_s; 12433737Shx147065 12443737Shx147065 PCANDBG((CE_NOTE, "pcan: gstat called\n")); 12453737Shx147065 12463737Shx147065 mutex_enter(&pcan_p->pcan_glock); 12473737Shx147065 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) { 12483737Shx147065 ret = PCAN_FAIL; 12493737Shx147065 goto done; 12503737Shx147065 } 12513737Shx147065 if (pcan_get_ltv(pcan_p, sizeof (pcan_p->an_stats), 12524343Sgd78059 AN_RID_16BITS_DELTACLR, (uint16_t *)&pcan_p->an_stats)) { 12533737Shx147065 cmn_err(CE_WARN, "pcan kstat: get ltv(32 delta statistics)" 12543737Shx147065 " failed \n"); 12553737Shx147065 ret = PCAN_FAIL; 12563737Shx147065 goto done; 12573737Shx147065 } 12583737Shx147065 for (i = 0; i < ANC_STAT_CNT; i++) { 12593737Shx147065 cntr_p[i] += *((uint16_t *)&pcan_p->an_stats + 1 + i); 12603737Shx147065 } 12613737Shx147065 if (pcan_status_ltv(PCAN_READ_LTV, pcan_p, &pcan_p->an_status)) { 12623737Shx147065 cmn_err(CE_WARN, "pcan kstat: read status failed \n"); 12633737Shx147065 ret = PCAN_FAIL; 12643737Shx147065 goto done; 12653737Shx147065 } 12663737Shx147065 12673737Shx147065 switch (statitem) { 12683737Shx147065 case MAC_STAT_IFSPEED: 12693737Shx147065 *val = 500000 * pcan_p->an_status.an_cur_tx_rate; 12703737Shx147065 break; 12713737Shx147065 case MAC_STAT_NOXMTBUF: 12723737Shx147065 *val = pcan_p->glds_noxmtbuf; 12733737Shx147065 break; 12743737Shx147065 case MAC_STAT_NORCVBUF: 12753737Shx147065 *val = pcan_p->glds_norcvbuf; 12763737Shx147065 break; 12773737Shx147065 case MAC_STAT_IERRORS: 12783737Shx147065 *val = cntr_p[ANC_RX_OVERRUNS] + 12793737Shx147065 cntr_p[ANC_RX_PLCP_CSUM_ERRS] + 12803737Shx147065 cntr_p[ANC_RX_PLCP_FORMAT_ERRS] + 12813737Shx147065 cntr_p[ANC_RX_PLCP_LEN_ERRS] + 12823737Shx147065 cntr_p[ANC_RX_MAC_CRC_ERRS] + 12833737Shx147065 cntr_p[ANC_RX_WEP_ERRS]; 12843737Shx147065 break; 12853737Shx147065 case MAC_STAT_OERRORS: 12863737Shx147065 *val = cntr_p[ANC_TX_HOST_FAILED]; 12873737Shx147065 break; 12883737Shx147065 case MAC_STAT_RBYTES: 12893737Shx147065 *val = cntr_p[ANC_HOST_RX_BYTES]; 12903737Shx147065 break; 12913737Shx147065 case MAC_STAT_IPACKETS: 12923737Shx147065 *val = cntr_p[ANC_RX_HOST_UCASTS]; 12933737Shx147065 break; 12943737Shx147065 case MAC_STAT_OBYTES: 12953737Shx147065 *val = cntr_p[ANC_HOST_TX_BYTES]; 12963737Shx147065 break; 12973737Shx147065 case MAC_STAT_OPACKETS: 12983737Shx147065 *val = cntr_p[ANC_TX_HOST_UCASTS]; 12993737Shx147065 break; 13003737Shx147065 case WIFI_STAT_TX_FAILED: 13013737Shx147065 *val = cntr_p[ANC_TX_HOST_FAILED]; 13023737Shx147065 break; 13033737Shx147065 case WIFI_STAT_TX_RETRANS: 13043737Shx147065 *val = cntr_p[ANC_HOST_RETRIES]; 13053737Shx147065 break; 13063737Shx147065 case WIFI_STAT_FCS_ERRORS: 13073737Shx147065 *val = cntr_p[ANC_RX_MAC_CRC_ERRS]; 13083737Shx147065 break; 13093737Shx147065 case WIFI_STAT_WEP_ERRORS: 13103737Shx147065 *val = cntr_p[ANC_RX_WEP_ERRS]; 13113737Shx147065 break; 13123737Shx147065 case WIFI_STAT_MCAST_TX: 13133737Shx147065 *val = cntr_p[ANC_TX_HOST_MCASTS]; 13143737Shx147065 break; 13153737Shx147065 case WIFI_STAT_MCAST_RX: 13163737Shx147065 *val = cntr_p[ANC_RX_HOST_MCASTS]; 13173737Shx147065 break; 13183737Shx147065 case WIFI_STAT_TX_FRAGS: 13193737Shx147065 case WIFI_STAT_RX_FRAGS: 13203737Shx147065 *val = 0; 13213737Shx147065 break; 13223737Shx147065 case WIFI_STAT_RTS_SUCCESS: 13233737Shx147065 *val = cntr_p[ANC_TX_RTS_OK]; 13243737Shx147065 break; 13253737Shx147065 case WIFI_STAT_RTS_FAILURE: 13263737Shx147065 *val = cntr_p[ANC_NO_CTS]; 13273737Shx147065 break; 13283737Shx147065 case WIFI_STAT_ACK_FAILURE: 13293737Shx147065 *val = cntr_p[ANC_NO_ACK]; 13303737Shx147065 break; 13313737Shx147065 case WIFI_STAT_RX_DUPS: 13323737Shx147065 *val = cntr_p[ANC_RX_DUPS]; 13333737Shx147065 break; 13343737Shx147065 default: 13353737Shx147065 ret = ENOTSUP; 13363737Shx147065 } 13373737Shx147065 13383737Shx147065 13393737Shx147065 done: 13403737Shx147065 mutex_exit(&pcan_p->pcan_glock); 13413737Shx147065 return (ret); 13423737Shx147065 } 13433737Shx147065 13443737Shx147065 /* 13453737Shx147065 * this driver is porting from freebsd, the code in freebsd 13463737Shx147065 * doesn't show how to set multi address. 13473737Shx147065 */ 13483737Shx147065 /*ARGSUSED*/ 13493737Shx147065 static int 13503737Shx147065 pcan_sdmulti(void *arg, boolean_t add, const uint8_t *eth_p) 13513737Shx147065 { 13523737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 13533737Shx147065 13543737Shx147065 mutex_enter(&pcan_p->pcan_glock); 13553737Shx147065 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) { 13563737Shx147065 mutex_exit(&pcan_p->pcan_glock); 13573737Shx147065 return (PCAN_FAIL); 13583737Shx147065 } 13593737Shx147065 mutex_exit(&pcan_p->pcan_glock); 13603737Shx147065 return (PCAN_SUCCESS); 13613737Shx147065 } 13623737Shx147065 13633737Shx147065 static uint_t 13643737Shx147065 pcan_info_softint(caddr_t arg) 13653737Shx147065 { 13663737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 13673737Shx147065 wifi_data_t wd = { 0 }; 13683737Shx147065 uint16_t link; 13693737Shx147065 uint32_t link_up; 13703737Shx147065 13713737Shx147065 mutex_enter(&pcan_p->pcan_glock); 13723737Shx147065 if (pcan_p->pcan_info_softint_pending != 1) { 13733737Shx147065 mutex_exit(&pcan_p->pcan_glock); 13743737Shx147065 return (DDI_INTR_UNCLAIMED); 13753737Shx147065 } 13763737Shx147065 13773737Shx147065 PCAN_READ(pcan_p, AN_LINKSTAT(pcan_p), link); 13783737Shx147065 link_up = pcan_p->pcan_flag & PCAN_CARD_LINKUP; 13793737Shx147065 if ((link == AN_LINKSTAT_ASSOCIATED) && !link_up) { 13803737Shx147065 pcan_p->pcan_flag |= PCAN_CARD_LINKUP; 13813737Shx147065 mutex_exit(&pcan_p->pcan_glock); 13823737Shx147065 if (pcan_p->pcan_connect_timeout_id != 0) { 13833737Shx147065 (void) untimeout(pcan_p->pcan_connect_timeout_id); 13843737Shx147065 pcan_p->pcan_connect_timeout_id = 0; 13853737Shx147065 } 13863737Shx147065 mac_link_update(GLD3(pcan_p), LINK_STATE_UP); 13873737Shx147065 mutex_enter(&pcan_p->pcan_glock); 13883737Shx147065 (void) pcan_status_ltv(PCAN_READ_LTV, pcan_p, 13893737Shx147065 &pcan_p->an_status); 13903737Shx147065 bcopy(pcan_p->an_status.an_cur_bssid, wd.wd_bssid, 6); 13913737Shx147065 wd.wd_secalloc = WIFI_SEC_NONE; 13923737Shx147065 wd.wd_opmode = IEEE80211_M_STA; 13933737Shx147065 (void) mac_pdata_update(pcan_p->pcan_mh, &wd, 13943737Shx147065 sizeof (wd)); 13953737Shx147065 #ifdef DEBUG 13963737Shx147065 if (pcan_debug & PCAN_DBG_LINKINFO) { 13973737Shx147065 cmn_err(CE_NOTE, "pcan: link Up, chan=%d, " 13983737Shx147065 "ssid=\"%s\"" 13993737Shx147065 " (%02x:%02x:%02x:%02x:%02x:%02x)\n", 14003737Shx147065 pcan_p->an_status.an_channel_set, 14013737Shx147065 pcan_p->an_status.an_ssid, 14023737Shx147065 pcan_p->an_status.an_cur_bssid[0], 14033737Shx147065 pcan_p->an_status.an_cur_bssid[1], 14043737Shx147065 pcan_p->an_status.an_cur_bssid[2], 14053737Shx147065 pcan_p->an_status.an_cur_bssid[3], 14063737Shx147065 pcan_p->an_status.an_cur_bssid[4], 14073737Shx147065 pcan_p->an_status.an_cur_bssid[5]); 14083737Shx147065 } 14093737Shx147065 #endif 14103737Shx147065 } 14113737Shx147065 if ((link != AN_LINKSTAT_ASSOCIATED) && link_up) { 14123737Shx147065 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP; 14133737Shx147065 #ifdef DEBUG 14143737Shx147065 if (pcan_debug & PCAN_DBG_LINKINFO) { 14153737Shx147065 cmn_err(CE_NOTE, "pcan: link Down 0x%x\n", link); 14163737Shx147065 } 14173737Shx147065 #endif 14183737Shx147065 if (link != AN_LINKSTAT_SYNCLOST_HOSTREQ) { 14193737Shx147065 pcan_p->pcan_connect_timeout_id = 14203737Shx147065 timeout(pcan_connect_timeout, 14213737Shx147065 pcan_p, drv_usectohz(1000)); 14223737Shx147065 } 14233737Shx147065 mutex_exit(&pcan_p->pcan_glock); 14243737Shx147065 mac_link_update(GLD3(pcan_p), LINK_STATE_DOWN); 14253737Shx147065 mutex_enter(&pcan_p->pcan_glock); 14263737Shx147065 } 14273737Shx147065 14283737Shx147065 pcan_p->pcan_info_softint_pending = 0; 14293737Shx147065 mutex_exit(&pcan_p->pcan_glock); 14303737Shx147065 return (DDI_INTR_CLAIMED); 14313737Shx147065 } 14323737Shx147065 14333737Shx147065 static uint_t 14343737Shx147065 pcan_intr(caddr_t arg) 14353737Shx147065 { 14363737Shx147065 uint16_t stat; 14373737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 14383737Shx147065 14393737Shx147065 mutex_enter(&pcan_p->pcan_glock); 14403737Shx147065 if ((pcan_p->pcan_flag & (PCAN_CARD_READY | PCAN_CARD_INTREN)) != 14413737Shx147065 (PCAN_CARD_READY | PCAN_CARD_INTREN)) { 14423737Shx147065 mutex_exit(&pcan_p->pcan_glock); 14433737Shx147065 return (DDI_INTR_UNCLAIMED); 14443737Shx147065 } 14453737Shx147065 PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat); 14463737Shx147065 14473737Shx147065 if (!(stat & AN_INTRS(pcan_p)) || stat == AN_EV_ALL) { 14483737Shx147065 mutex_exit(&pcan_p->pcan_glock); 14493737Shx147065 return (DDI_INTR_UNCLAIMED); 14503737Shx147065 } 14513737Shx147065 14523737Shx147065 PCAN_DISABLE_INTR(pcan_p); 14533737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), ~AN_INTRS(pcan_p)); 14543737Shx147065 14553737Shx147065 PCANDBG((CE_NOTE, "pcan intr: stat=%x pcan_flags=%x\n", stat, 14564343Sgd78059 pcan_p->pcan_flag)); 14573737Shx147065 14583737Shx147065 if (stat & AN_EV_AWAKE) { 14593737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_AWAKE); 14603737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_AWAKE); 14613737Shx147065 } 14623737Shx147065 if (stat & AN_EV_LINKSTAT) { 14633737Shx147065 pcan_p->pcan_info_softint_pending = 1; 14643737Shx147065 ddi_trigger_softintr(pcan_p->pcan_info_softint_id); 14653737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_LINKSTAT); 14663737Shx147065 } 14673737Shx147065 if (stat & AN_EV_RX) { 14683737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 14693737Shx147065 pcian_rcv(pcan_p); 14703737Shx147065 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) { 14713737Shx147065 pcan_rcv(pcan_p); 14723737Shx147065 } 14733737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_RX); 14743737Shx147065 } 14753737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 14763737Shx147065 if (stat & AN_EV_TX_CPY) { 14773737Shx147065 (void) pcan_txdone(pcan_p, stat & AN_EV_TX_CPY); 14783737Shx147065 if (pcan_p->pcan_reschedule_need == B_TRUE) { 14793737Shx147065 mac_tx_update(GLD3(pcan_p)); 14803737Shx147065 pcan_p->pcan_reschedule_need = B_FALSE; 14813737Shx147065 } 14823737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_TX_CPY); 14833737Shx147065 } 14843737Shx147065 } 14853737Shx147065 if (stat & AN_EV_TX) { 14863737Shx147065 if (pcan_txdone(pcan_p, stat & AN_EV_TX) == 0) { 14873737Shx147065 if (pcan_p->pcan_reschedule_need == B_TRUE) { 14883737Shx147065 mac_tx_update(GLD3(pcan_p)); 14893737Shx147065 pcan_p->pcan_reschedule_need = B_FALSE; 14903737Shx147065 } 14913737Shx147065 } 14923737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_TX); 14933737Shx147065 } 14943737Shx147065 if (stat & AN_EV_TX_EXC) { 14953737Shx147065 if (pcan_txdone(pcan_p, stat & AN_EV_TX_EXC) == 0) { 14963737Shx147065 if (pcan_p->pcan_reschedule_need == B_TRUE) { 14973737Shx147065 mutex_exit(&pcan_p->pcan_glock); 14983737Shx147065 mac_tx_update(GLD3(pcan_p)); 14993737Shx147065 mutex_enter(&pcan_p->pcan_glock); 15003737Shx147065 pcan_p->pcan_reschedule_need = B_FALSE; 15013737Shx147065 } 15023737Shx147065 } 15033737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_TX_EXC); 15043737Shx147065 } 15053737Shx147065 if (stat & AN_EV_ALLOC) { 15063737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_ALLOC); 15073737Shx147065 PCANDBG((CE_NOTE, "pcan intr: nicmem alloc done\n")); 15083737Shx147065 } 15093737Shx147065 if (stat & AN_EV_MIC) { 15103737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_MIC); 15113737Shx147065 } 15123737Shx147065 PCAN_ENABLE_INTR(pcan_p); 15133737Shx147065 mutex_exit(&pcan_p->pcan_glock); 15143737Shx147065 return (DDI_INTR_CLAIMED); 15153737Shx147065 } 15163737Shx147065 15173737Shx147065 static uint_t 15183737Shx147065 pcan_intr_hi(caddr_t arg) 15193737Shx147065 { 15203737Shx147065 uint16_t stat; 15213737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 15223737Shx147065 15233737Shx147065 mutex_enter(&pcan_p->pcan_glock); 15243737Shx147065 if ((pcan_p->pcan_flag & (PCAN_CARD_READY | PCAN_CARD_INTREN)) != 15253737Shx147065 (PCAN_CARD_READY | PCAN_CARD_INTREN)) { 15263737Shx147065 mutex_exit(&pcan_p->pcan_glock); 15273737Shx147065 return (DDI_INTR_UNCLAIMED); 15283737Shx147065 } 15293737Shx147065 PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat); 15303737Shx147065 PCANDBG((CE_NOTE, "pcan intr(hi): stat=%x pcan_flags=%x\n", stat, 15313737Shx147065 pcan_p->pcan_flag)); 15323737Shx147065 15333737Shx147065 if (!(stat & AN_INTRS(pcan_p)) || stat == AN_EV_ALL) { 15343737Shx147065 mutex_exit(&pcan_p->pcan_glock); 15353737Shx147065 return (DDI_INTR_UNCLAIMED); 15363737Shx147065 } 15373737Shx147065 /* disable interrupt without ack */ 15383737Shx147065 PCAN_WRITE(pcan_p, AN_INT_EN(pcan_p), 0); 15393737Shx147065 mutex_exit(&pcan_p->pcan_glock); 15403737Shx147065 ddi_trigger_softintr(pcan_p->pcan_softint_id); 15413737Shx147065 return (DDI_INTR_CLAIMED); 15423737Shx147065 } 15433737Shx147065 15443737Shx147065 /* 15453737Shx147065 * retrieve data from pccard 15463737Shx147065 */ 15473737Shx147065 static void 15483737Shx147065 pcan_rcv(pcan_maci_t *pcan_p) 15493737Shx147065 { 15503737Shx147065 uint16_t id, off, ret, data_len, pkt_stat, frm_ctl; 15513737Shx147065 an_rxfrm_t frm; 15523737Shx147065 struct ieee80211_llc *llc; 15533737Shx147065 15543737Shx147065 mblk_t *mp = allocb(PCAN_NICMEM_SZ, BPRI_MED); 15553737Shx147065 if (!mp) { 15563737Shx147065 cmn_err(CE_WARN, "pcan: failed to alloc rcv buf"); 15573737Shx147065 pcan_p->glds_norcvbuf++; 15583737Shx147065 return; 15593737Shx147065 } 15603737Shx147065 ASSERT(mp->b_rptr == mp->b_wptr); 15613737Shx147065 15623737Shx147065 PCAN_READ(pcan_p, AN_RX_FID, id); 15633737Shx147065 if (id == AN_INVALID_FID) { 15643737Shx147065 PCANDBG((CE_NOTE, "pcan rcv: can't get rx_fid\n")); 15653737Shx147065 pcan_p->glds_norcvbuf++; 15663737Shx147065 ret = PCAN_FAIL; 15673737Shx147065 goto done; 15683737Shx147065 } 15693737Shx147065 if (ret = RDCH0(pcan_p, id, 0, (uint16_t *)&frm, sizeof (frm))) { 15703737Shx147065 PCANDBG((CE_NOTE, "pcan rcv: read frm err %x\n", ret)); 15713737Shx147065 goto done; 15723737Shx147065 } 15733737Shx147065 off = sizeof (frm); 15743737Shx147065 if (frm.an_rx_status) { 15753737Shx147065 PCANDBG((CE_NOTE, "pcan rcv: err stat %x\n", frm.an_rx_status)); 15763737Shx147065 ret = frm.an_rx_status; 15773737Shx147065 goto done; 15783737Shx147065 } 15793737Shx147065 PCANDBG((CE_NOTE, "pcan rcv: payload_len=%x gap_len=%x\n", 15803737Shx147065 frm.an_rx_payload_len, frm.an_gaplen)); 15813737Shx147065 if (frm.an_rx_payload_len > PCAN_NICMEM_SZ || 15823737Shx147065 frm.an_gaplen > AN_RXGAP_MAX) { 15833737Shx147065 PCANDBG((CE_NOTE, "pcan rcv: bad len\n")); 15843737Shx147065 ret = PCAN_FAIL; 15853737Shx147065 goto done; 15863737Shx147065 } 15873737Shx147065 if (ret = RDCH0(pcan_p, id, off, &pkt_stat, sizeof (pkt_stat))) { 15883737Shx147065 PCANDBG((CE_NOTE, "pcan rcv: pkt status err %x\n", ret)); 15893737Shx147065 ret = PCAN_FAIL; 15903737Shx147065 goto done; 15913737Shx147065 } 15923737Shx147065 off += sizeof (pkt_stat); 15933737Shx147065 if (ret = RDCH0(pcan_p, id, off, &data_len, sizeof (data_len))) { 15943737Shx147065 PCANDBG((CE_NOTE, "pcan rcv: payload len err %x\n", ret)); 15953737Shx147065 ret = PCAN_FAIL; 15963737Shx147065 goto done; 15973737Shx147065 } 15983737Shx147065 off += sizeof (data_len); 15993737Shx147065 off += ETHERADDRL << 1; 16003737Shx147065 PCANDBG((CE_NOTE, "pcan rcv: pkt_stat=%x payload_len=%x+c off=%x\n", 16014343Sgd78059 pkt_stat, data_len, off)); 16023737Shx147065 16033737Shx147065 #ifdef DEBUG 16043737Shx147065 if (pcan_debug & PCAN_DBG_RCV) { 16053737Shx147065 int i; 16063737Shx147065 cmn_err(CE_NOTE, "pcan rcv: frm header\n"); 16073737Shx147065 for (i = 0; i < sizeof (frm); i++) 16083737Shx147065 cmn_err(CE_NOTE, "%x: %x\n", i, 16093737Shx147065 *((uint8_t *)&frm + i)); 16103737Shx147065 } 16113737Shx147065 #endif 16123737Shx147065 /* 16133737Shx147065 * this driver deal with WEP by itself. so plugin always thinks no wep. 16143737Shx147065 */ 16153737Shx147065 frm.an_frame_ctl &= ~(IEEE80211_FC1_WEP << 8); 16163737Shx147065 frm_ctl = frm.an_frame_ctl; 16173737Shx147065 PCAN_SWAP16((uint16_t *)&frm.an_frame_ctl, 16183737Shx147065 sizeof (struct ieee80211_frame)); 16193737Shx147065 /* 16203737Shx147065 * discard those frames which are not from the AP we connect or 16213737Shx147065 * without 'ap->sta' direction 16223737Shx147065 */ 16233737Shx147065 if (((pcan_p->an_config.an_opmode == AN_OPMODE_INFR_STATION)) && 16243737Shx147065 ((((frm_ctl >> 8) & IEEE80211_FC1_DIR_MASK) != 16253737Shx147065 IEEE80211_FC1_DIR_FROMDS) || 16263737Shx147065 bcmp(pcan_p->an_status.an_cur_bssid, frm.an_addr2, 6) != 0)) { 16273737Shx147065 ret = PCAN_FAIL; 16283737Shx147065 goto done; 16293737Shx147065 } 16303737Shx147065 bcopy(&frm.an_frame_ctl, mp->b_wptr, 16313737Shx147065 sizeof (struct ieee80211_frame)); 16323737Shx147065 mp->b_wptr += sizeof (struct ieee80211_frame); 16333737Shx147065 16343737Shx147065 /* the plugin need a llc here */ 16353737Shx147065 llc = (struct ieee80211_llc *)mp->b_wptr; 16363737Shx147065 llc->illc_dsap = llc->illc_ssap = AN_SNAP_K1; 16373737Shx147065 llc->illc_control = AN_SNAP_CONTROL; 16383737Shx147065 bzero(llc->illc_oc, sizeof (llc->illc_oc)); 16393737Shx147065 mp->b_wptr += AN_SNAPHDR_LEN; 16403737Shx147065 16413737Shx147065 /* read in the rest of data */ 16423737Shx147065 data_len += data_len & 1; /* adjust to word boundary */ 16433737Shx147065 if (data_len > MBLKSIZE(mp)) { 16443737Shx147065 cmn_err(CE_NOTE, "pcan rcv: data over length%x\n", data_len); 16453737Shx147065 ret = PCAN_FAIL; 16463737Shx147065 goto done; 16473737Shx147065 } 16483737Shx147065 16493737Shx147065 if (ret = RDPKT(pcan_p, id, off, (uint16_t *)mp->b_wptr, data_len)) { 16503737Shx147065 PCANDBG((CE_NOTE, "pcan rcv: err read data %x\n", ret)); 16513737Shx147065 } 16523737Shx147065 done: 16533737Shx147065 if (ret) { 16543737Shx147065 PCANDBG((CE_NOTE, "pcan rcv: rd data %x\n", ret)); 16553737Shx147065 freemsg(mp); 16563737Shx147065 return; 16573737Shx147065 } 16583737Shx147065 mp->b_wptr += data_len; 16593737Shx147065 #ifdef DEBUG 16603737Shx147065 if (pcan_debug & PCAN_DBG_RCV) { 16613737Shx147065 int i; 16623737Shx147065 cmn_err(CE_NOTE, "pcan rcv: len=0x%x\n", data_len); 16633737Shx147065 for (i = 0; i < data_len + sizeof (frm); i++) 16643737Shx147065 cmn_err(CE_NOTE, "%x: %x\n", i, 16653737Shx147065 *((uint8_t *)mp->b_rptr + i)); 16663737Shx147065 } 16673737Shx147065 #endif 16683737Shx147065 mutex_exit(&pcan_p->pcan_glock); 16693737Shx147065 mac_rx(GLD3(pcan_p), NULL, mp); 16703737Shx147065 mutex_enter(&pcan_p->pcan_glock); 16713737Shx147065 } 16723737Shx147065 16733737Shx147065 /* 16743737Shx147065 * retrieve data from mini-pci card 16753737Shx147065 */ 16763737Shx147065 static void 16773737Shx147065 pcian_rcv(pcan_maci_t *pcan_p) 16783737Shx147065 { 16793737Shx147065 struct an_card_rx_desc an_rx_desc; 16803737Shx147065 char *buf; 16813737Shx147065 uint16_t ret = 0, data_len; 16823737Shx147065 int i, j; 16833737Shx147065 struct ieee80211_frame *frm; 16843737Shx147065 struct ieee80211_llc *llc; 16853737Shx147065 16863737Shx147065 mblk_t *mp = allocb(AN_RX_BUFFER_SIZE, BPRI_MED); 16873737Shx147065 if (!mp) { 16883737Shx147065 cmn_err(CE_WARN, "pcan(pci): failed to alloc rcv buf"); 16893737Shx147065 pcan_p->glds_norcvbuf++; 16903737Shx147065 return; 16913737Shx147065 } 16923737Shx147065 ASSERT(mp->b_rptr == mp->b_wptr); 16933737Shx147065 16943737Shx147065 for (i = 0; i < sizeof (an_rx_desc) / 4; i++) 16953737Shx147065 PCAN_AUX_GET32(pcan_p, AN_RX_DESC_OFFSET + (i * 4), 16963737Shx147065 ((uint32_t *)&an_rx_desc)[i]); 16973737Shx147065 if (an_rx_desc.an_done && !an_rx_desc.an_valid) { 16983737Shx147065 buf = pcan_p->pcan_rx[0].dma_virtaddr; 16993737Shx147065 data_len = an_rx_desc.an_len; 17003737Shx147065 #ifdef DEBUG 17013737Shx147065 if (pcan_debug & PCAN_DBG_RCV) { 17023737Shx147065 cmn_err(CE_NOTE, "pcan(pci) rcv: data_len=%x", 17033737Shx147065 data_len); 17043737Shx147065 for (j = 0; j < data_len + 14; j++) 17053737Shx147065 cmn_err(CE_NOTE, "pcan_rcv %d: %x", j, 17063737Shx147065 *((uint8_t *)buf + j)); 17073737Shx147065 } 17083737Shx147065 #endif 17093737Shx147065 if (data_len > MBLKSIZE(mp)) { 17103737Shx147065 cmn_err(CE_NOTE, "pcan(pci) rcv: data over length%x\n", 17113737Shx147065 data_len); 17123737Shx147065 ret = PCAN_FAIL; 17133737Shx147065 goto done; 17143737Shx147065 } 17153737Shx147065 /* 17163737Shx147065 * minipci card receive an ethernet frame, so assembly a 802.11 17173737Shx147065 * frame here manually. 17183737Shx147065 */ 17193737Shx147065 frm = (struct ieee80211_frame *)mp->b_wptr; 17203737Shx147065 bzero(frm, sizeof (*frm)); 17213737Shx147065 frm->i_fc[0] |= IEEE80211_FC0_TYPE_DATA; 17223737Shx147065 frm->i_fc[1] |= IEEE80211_FC1_DIR_FROMDS; 17233737Shx147065 bcopy(pcan_p->an_status.an_cur_bssid, frm->i_addr2, 6); 17243737Shx147065 bcopy(buf, frm->i_addr1, 6); 17253737Shx147065 bcopy(buf + 6, frm->i_addr3, 6); 17263737Shx147065 mp->b_wptr += sizeof (struct ieee80211_frame); 17273737Shx147065 17283737Shx147065 llc = (struct ieee80211_llc *)mp->b_wptr; 17293737Shx147065 llc->illc_dsap = llc->illc_ssap = AN_SNAP_K1; 17303737Shx147065 llc->illc_control = AN_SNAP_CONTROL; 17313737Shx147065 bzero(llc->illc_oc, sizeof (llc->illc_oc)); 17323737Shx147065 mp->b_wptr += AN_SNAPHDR_LEN; 17333737Shx147065 17343737Shx147065 bcopy(buf + 12, mp->b_wptr, data_len); 17353737Shx147065 mp->b_wptr += data_len; 17363737Shx147065 #ifdef DEBUG 17373737Shx147065 if (pcan_debug & PCAN_DBG_RCV) { 17383737Shx147065 int i; 17393737Shx147065 cmn_err(CE_NOTE, "pcan(pci) rcv: len=0x%x\n", data_len); 17403737Shx147065 for (i = 0; i < data_len + sizeof (*frm) 17413737Shx147065 + sizeof (*llc); i++) 17423737Shx147065 cmn_err(CE_NOTE, "%x: %x\n", i, 17433737Shx147065 *((uint8_t *)mp->b_rptr + i)); 17443737Shx147065 } 17453737Shx147065 #endif 17463737Shx147065 mutex_exit(&pcan_p->pcan_glock); 17473737Shx147065 mac_rx(GLD3(pcan_p), NULL, mp); 17483737Shx147065 mutex_enter(&pcan_p->pcan_glock); 17493737Shx147065 } 17503737Shx147065 done: 17513737Shx147065 bzero(&an_rx_desc, sizeof (an_rx_desc)); 17523737Shx147065 an_rx_desc.an_valid = 1; 17533737Shx147065 an_rx_desc.an_len = AN_RX_BUFFER_SIZE; 17543737Shx147065 an_rx_desc.an_done = 0; 17553737Shx147065 an_rx_desc.an_phys = pcan_p->pcan_rx[0].dma_physaddr; 17563737Shx147065 17573737Shx147065 for (i = 0; i < sizeof (an_rx_desc) / 4; i++) 17583737Shx147065 PCAN_AUX_PUT32(pcan_p, AN_RX_DESC_OFFSET + (i * 4), 17593737Shx147065 ((uint32_t *)&an_rx_desc)[i]); 17603737Shx147065 if (ret) { 17613737Shx147065 freemsg(mp); 17623737Shx147065 } 17633737Shx147065 } 17643737Shx147065 17653737Shx147065 /*ARGSUSED*/ 17663737Shx147065 static uint32_t 17673737Shx147065 pcan_txdone(pcan_maci_t *pcan_p, uint16_t err) 17683737Shx147065 { 17693737Shx147065 uint16_t fid, i, ring_idx; 17703737Shx147065 uint32_t ret = 0; 17713737Shx147065 17723737Shx147065 PCAN_READ(pcan_p, AN_TX_CMP_FID(pcan_p), fid); 17733737Shx147065 mutex_enter(&pcan_p->pcan_txring.an_tx_lock); 17743737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 17753737Shx147065 if (pcan_p->pcan_flag & PCAN_CARD_SEND) { 17763737Shx147065 ring_idx = pcan_p->pcan_txring.an_tx_cons; 17773737Shx147065 pcan_p->pcan_txring.an_tx_cons = 17783737Shx147065 (ring_idx + 1) % AN_MAX_TX_DESC; 17793737Shx147065 if (pcan_p->pcan_txring.an_tx_prod == 17803737Shx147065 pcan_p->pcan_txring.an_tx_cons) { 17813737Shx147065 pcan_p->pcan_flag &= ~PCAN_CARD_SEND; 17823737Shx147065 } 17833737Shx147065 } 17843737Shx147065 ret = 0; 17853737Shx147065 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) { 17863737Shx147065 for (i = 0; i < AN_TX_RING_CNT; i++) { 17873737Shx147065 if (fid == pcan_p->pcan_txring.an_tx_ring[i]) { 17883737Shx147065 pcan_p->pcan_txring.an_tx_ring[i] = 0; 17893737Shx147065 break; 17903737Shx147065 } 17913737Shx147065 } 17923737Shx147065 pcan_p->pcan_txring.an_tx_cons = 17933737Shx147065 (pcan_p->pcan_txring.an_tx_cons + 1) & AN_TX_RING_MASK; 17943737Shx147065 ret = (i == AN_TX_RING_CNT ? 1 : 0); 17953737Shx147065 } 17963737Shx147065 mutex_exit(&pcan_p->pcan_txring.an_tx_lock); 17973737Shx147065 return (ret); 17983737Shx147065 } 17993737Shx147065 18003737Shx147065 /* 18013737Shx147065 * delay in which the mutex is not hold. 18023737Shx147065 * assuming the mutex has already been hold. 18033737Shx147065 */ 18043737Shx147065 static void 18053737Shx147065 pcan_delay(pcan_maci_t *pcan_p, clock_t microsecs) 18063737Shx147065 { 18073737Shx147065 ASSERT(mutex_owned(&pcan_p->pcan_glock)); 18083737Shx147065 18093737Shx147065 mutex_exit(&pcan_p->pcan_glock); 18103737Shx147065 delay(drv_usectohz(microsecs)); 18113737Shx147065 mutex_enter(&pcan_p->pcan_glock); 18123737Shx147065 } 18133737Shx147065 18143737Shx147065 static void 18153737Shx147065 pcan_reset_backend(pcan_maci_t *pcan_p, int timeout) 18163737Shx147065 { 18173737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 18183737Shx147065 (void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0); 18193737Shx147065 PCAN_DISABLE_INTR_CLEAR(pcan_p); 18203737Shx147065 (void) pcan_set_cmd(pcan_p, AN_CMD_FW_RESTART, 0); 18213737Shx147065 (void) pcan_set_cmd(pcan_p, AN_CMD_NOOP2, 0); 18223737Shx147065 (void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0); 18233737Shx147065 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) { 18243737Shx147065 (void) pcan_set_cmd0(pcan_p, AN_CMD_DISABLE, 0, 0, 0); 18253737Shx147065 (void) pcan_set_cmd0(pcan_p, AN_CMD_NOOP2, 0, 0, 0); 18263737Shx147065 PCAN_WRITE(pcan_p, AN_COMMAND(pcan_p), AN_CMD_FW_RESTART); 18273737Shx147065 pcan_delay(pcan_p, timeout); /* wait for firmware restart */ 18283737Shx147065 18293737Shx147065 (void) pcan_set_cmd(pcan_p, AN_CMD_NOOP, 0); 18303737Shx147065 (void) pcan_set_cmd0(pcan_p, AN_CMD_DISABLE, 0, 0, 0); 18313737Shx147065 18323737Shx147065 PCAN_DISABLE_INTR_CLEAR(pcan_p); 18333737Shx147065 } 18343737Shx147065 } 18353737Shx147065 18363737Shx147065 /* 18373737Shx147065 * set command without the need of ACK. 18383737Shx147065 */ 18393737Shx147065 static uint16_t 18403737Shx147065 pcan_set_cmd0(pcan_maci_t *pcan_p, uint16_t cmd, uint16_t p0, 18413737Shx147065 uint16_t p1, uint16_t p2) 18423737Shx147065 { 18433737Shx147065 int i; 18443737Shx147065 uint16_t stat, r0, r1, r2; 18453737Shx147065 18463737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 18473737Shx147065 for (i = 0; i < AN_TIMEOUT; i++) { 18483737Shx147065 PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat); 18493737Shx147065 if (!(stat & AN_CMD_BUSY)) 18503737Shx147065 break; 18513737Shx147065 } 18523737Shx147065 if (i == AN_TIMEOUT) { 18533737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), 18543737Shx147065 AN_EV_CLR_STUCK_BUSY); 18553737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD); 18563737Shx147065 drv_usecwait(10); 18573737Shx147065 } 18583737Shx147065 PCAN_WRITE(pcan_p, AN_PARAM0(pcan_p), p0); 18593737Shx147065 PCAN_WRITE(pcan_p, AN_PARAM1(pcan_p), p1); 18603737Shx147065 PCAN_WRITE(pcan_p, AN_PARAM2(pcan_p), p2); 18613737Shx147065 } 18623737Shx147065 PCAN_WRITE(pcan_p, AN_COMMAND(pcan_p), cmd); 18633737Shx147065 for (i = 0; i < AN_TIMEOUT; i++) { 18643737Shx147065 PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat); 18653737Shx147065 if (stat & AN_EV_CMD) 18663737Shx147065 break; 18673737Shx147065 } 18683737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 18693737Shx147065 PCAN_READ(pcan_p, AN_RESP0(pcan_p), r0); 18703737Shx147065 PCAN_READ(pcan_p, AN_RESP1(pcan_p), r1); 18713737Shx147065 PCAN_READ(pcan_p, AN_RESP2(pcan_p), r2); 18723737Shx147065 PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat); 18733737Shx147065 if (stat & AN_CMD_BUSY) 18743737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), 18753737Shx147065 AN_EV_CLR_STUCK_BUSY); 18763737Shx147065 PCANDBG((CE_NOTE, "pcan set_cmd0: " 18773737Shx147065 "stat=%x, r0=%x, r1=%x, r2=%x\n", 18783737Shx147065 stat, r0, r1, r2)); 18793737Shx147065 } 18803737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD); 18813737Shx147065 return (i == AN_TIMEOUT ? PCAN_TIMEDOUT_ACCESS : PCAN_SUCCESS); 18823737Shx147065 } 18833737Shx147065 18843737Shx147065 static uint16_t 18853737Shx147065 pcan_set_cmd(pcan_maci_t *pcan_p, uint16_t cmd, uint16_t param) 18863737Shx147065 { 18873737Shx147065 int i; 18883737Shx147065 uint16_t stat, r0, r1, r2; 18893737Shx147065 uint16_t ret; 18903737Shx147065 18913737Shx147065 if (((cmd == AN_CMD_ENABLE) && 18923737Shx147065 ((pcan_p->pcan_flag & PCAN_ENABLED) != 0)) || 18933737Shx147065 ((cmd == AN_CMD_DISABLE) && 18943737Shx147065 ((pcan_p->pcan_flag & PCAN_ENABLED) == 0))) 18953737Shx147065 return (PCAN_SUCCESS); 18963737Shx147065 for (i = 0; i < AN_TIMEOUT; i++) { 18973737Shx147065 PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat); 18983737Shx147065 if (!(stat & AN_CMD_BUSY)) { 18993737Shx147065 break; 19003737Shx147065 } 19013737Shx147065 } 19023737Shx147065 if (i == AN_TIMEOUT) { 19033737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CLR_STUCK_BUSY); 19043737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD); 19053737Shx147065 drv_usecwait(10); 19063737Shx147065 } 19073737Shx147065 19083737Shx147065 PCAN_WRITE(pcan_p, AN_PARAM0(pcan_p), param); 19093737Shx147065 PCAN_WRITE(pcan_p, AN_PARAM1(pcan_p), 0); 19103737Shx147065 PCAN_WRITE(pcan_p, AN_PARAM2(pcan_p), 0); 19113737Shx147065 PCAN_WRITE(pcan_p, AN_COMMAND(pcan_p), cmd); 19123737Shx147065 19133737Shx147065 for (i = 0; i < AN_TIMEOUT; i++) { 19143737Shx147065 PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat); 19153737Shx147065 if (stat & AN_EV_CMD) { 19163737Shx147065 break; 19173737Shx147065 } 19183737Shx147065 PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat); 19193737Shx147065 if (stat == cmd) 19203737Shx147065 PCAN_WRITE(pcan_p, AN_COMMAND(pcan_p), cmd); 19213737Shx147065 } 19223737Shx147065 if (i == AN_TIMEOUT) { 19233737Shx147065 if (cmd == AN_CMD_FW_RESTART) { 19243737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD); 19253737Shx147065 return (PCAN_SUCCESS); 19263737Shx147065 } 19273737Shx147065 #ifdef DEBUG 19283737Shx147065 if (pcan_debug & PCAN_DBG_CMD) { 19293737Shx147065 cmn_err(CE_WARN, "pcan set_cmd: %x timeout stat=%x\n", 19303737Shx147065 cmd, stat); 19313737Shx147065 } 19323737Shx147065 #endif 19333737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD); 19343737Shx147065 return (PCAN_TIMEDOUT_CMD); 19353737Shx147065 } 19363737Shx147065 19373737Shx147065 for (i = 0; i < AN_TIMEOUT; i++) { 19383737Shx147065 PCAN_READ(pcan_p, AN_STATUS(pcan_p), stat); 19393737Shx147065 PCAN_READ(pcan_p, AN_RESP0(pcan_p), r0); 19403737Shx147065 PCAN_READ(pcan_p, AN_RESP1(pcan_p), r1); 19413737Shx147065 PCAN_READ(pcan_p, AN_RESP2(pcan_p), r2); 19423737Shx147065 if ((stat & AN_STAT_CMD_CODE) == (cmd & AN_STAT_CMD_CODE)) 19433737Shx147065 break; 19443737Shx147065 } 19453737Shx147065 if (cmd == AN_CMD_FW_RESTART) { 19463737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD); 19473737Shx147065 return (PCAN_SUCCESS); 19483737Shx147065 } 19493737Shx147065 if (i == AN_TIMEOUT) { 19503737Shx147065 #ifdef DEBUG 19513737Shx147065 if (pcan_debug & PCAN_DBG_CMD) { 19523737Shx147065 cmn_err(CE_WARN, "pcan set_cmd<%x,%x>: timeout " 19533737Shx147065 "%x,%x,%x,%x\n", cmd, param, stat, r0, r1, r2); 19543737Shx147065 } 19553737Shx147065 #endif 19563737Shx147065 ret = PCAN_TIMEDOUT_ACCESS; 19573737Shx147065 } else { 19583737Shx147065 if (stat & AN_STAT_CMD_RESULT) { 19593737Shx147065 #ifdef DEBUG 19603737Shx147065 if (pcan_debug & PCAN_DBG_CMD) { 19613737Shx147065 cmn_err(CE_WARN, "pcan set_cmd<%x,%x>: failed " 19623737Shx147065 "%x,%x,%x,%x\n", 19633737Shx147065 cmd, param, stat, r0, r1, r2); 19643737Shx147065 } 19653737Shx147065 #endif 19663737Shx147065 ret = PCAN_TIMEDOUT_ACCESS; 19673737Shx147065 } else { 19683737Shx147065 ret = PCAN_SUCCESS; 19693737Shx147065 } 19703737Shx147065 } 19713737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD); 19723737Shx147065 PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat); 19733737Shx147065 if (stat & AN_CMD_BUSY) 19743737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CLR_STUCK_BUSY); 19753737Shx147065 if (ret == PCAN_SUCCESS) { 19763737Shx147065 if (cmd == AN_CMD_ENABLE) 19773737Shx147065 pcan_p->pcan_flag |= PCAN_ENABLED; 19783737Shx147065 if (cmd == AN_CMD_DISABLE) 19793737Shx147065 pcan_p->pcan_flag &= (~PCAN_ENABLED); 19803737Shx147065 } 19813737Shx147065 return (ret); 19823737Shx147065 } 19833737Shx147065 19843737Shx147065 static uint16_t 19853737Shx147065 pcan_set_ch(pcan_maci_t *pcan_p, uint16_t type, uint16_t off, uint16_t channel) 19863737Shx147065 { 19873737Shx147065 int i; 19883737Shx147065 uint16_t stat, select, offset; 19893737Shx147065 19903737Shx147065 if (channel) { 19913737Shx147065 select = AN_SEL1; 19923737Shx147065 offset = AN_OFF1; 19933737Shx147065 } else { 19943737Shx147065 select = AN_SEL0; 19953737Shx147065 offset = AN_OFF0; 19963737Shx147065 } 19973737Shx147065 PCAN_WRITE(pcan_p, select, type); 19983737Shx147065 PCAN_WRITE(pcan_p, offset, off); 19993737Shx147065 for (i = 0; i < AN_TIMEOUT; i++) { 20003737Shx147065 PCAN_READ(pcan_p, offset, stat); 20013737Shx147065 if (!(stat & (AN_OFF_BUSY|AN_OFF_ERR))) 20023737Shx147065 break; 20033737Shx147065 } 20043737Shx147065 if (stat & (AN_OFF_BUSY|AN_OFF_ERR)) { /* time out */ 20053737Shx147065 PCANDBG((CE_WARN, "pcan: set_ch%d %x %x TO %x\n", 20063737Shx147065 channel, type, off, stat)); 20073737Shx147065 return (PCAN_TIMEDOUT_TARGET); 20083737Shx147065 } 20093737Shx147065 return (PCAN_SUCCESS); 20103737Shx147065 } 20113737Shx147065 20123737Shx147065 static uint16_t 20133737Shx147065 pcan_get_ltv(pcan_maci_t *pcan_p, uint16_t len, uint16_t type, uint16_t *val_p) 20143737Shx147065 { 20153737Shx147065 uint16_t stat; 20163737Shx147065 20173737Shx147065 PCANDBG((CE_NOTE, "pcan: get_ltv(%p,%x,%x,%p)\n", 20184343Sgd78059 (void *)pcan_p, len, type, (void *)val_p)); 20193737Shx147065 ASSERT(!(len & 1)); 20203737Shx147065 20213737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 20223737Shx147065 uint32_t i; 20233737Shx147065 struct an_card_rid_desc an_rid_desc; 20243737Shx147065 struct an_ltv_gen *an_ltv; 20253737Shx147065 if (!pcan_p->pcan_cmd.dma_virtaddr) 20263737Shx147065 return (EIO); 20273737Shx147065 an_rid_desc.an_valid = 1; 20283737Shx147065 an_rid_desc.an_len = AN_RID_BUFFER_SIZE; 20293737Shx147065 an_rid_desc.an_rid = 0; 20303737Shx147065 an_rid_desc.an_phys = pcan_p->pcan_cmd.dma_physaddr; 20313737Shx147065 bzero(pcan_p->pcan_cmd.dma_virtaddr, AN_RID_BUFFER_SIZE); 20323737Shx147065 20333737Shx147065 for (i = 0; i < sizeof (an_rid_desc) / 4; i++) 20343737Shx147065 PCAN_AUX_PUT32(pcan_p, AN_HOST_DESC_OFFSET + i * 4, 20353737Shx147065 ((uint32_t *)&an_rid_desc)[i]); 20363737Shx147065 20373737Shx147065 if (pcan_set_cmd0(pcan_p, AN_CMD_ACCESS | 20383737Shx147065 AN_ACCESS_READ, type, 0, 0)) { 20393737Shx147065 cmn_err(CE_WARN, "pcan get_ltv: set cmd error"); 20403737Shx147065 return (EIO); 20413737Shx147065 } 20423737Shx147065 20433737Shx147065 an_ltv = (struct an_ltv_gen *)pcan_p->pcan_cmd.dma_virtaddr; 20443737Shx147065 #ifdef DEBUG 20453737Shx147065 if (pcan_debug & PCAN_DBG_INFO) { 20463737Shx147065 cmn_err(CE_NOTE, "pcan get_ltv: type=%x," 20473737Shx147065 "expected len=%d," "actual len=%d", 20483737Shx147065 type, len, an_ltv->an_len); 20493737Shx147065 for (i = 0; i < an_ltv->an_len; i++) 20503737Shx147065 cmn_err(CE_NOTE, "%d: %x", i, 20513737Shx147065 *(((uint8_t *)an_ltv) + i)); 20523737Shx147065 } 20533737Shx147065 #endif 20543737Shx147065 if (an_ltv->an_len != len) { 20553737Shx147065 PCANDBG((CE_WARN, "pcan get_ltv: rid=%x expected len=%d" 20563737Shx147065 "actual: len=%d", type, 20573737Shx147065 len, an_ltv->an_len)); 20583737Shx147065 /* return (EIO); */ 20593737Shx147065 } 20603737Shx147065 bcopy(an_ltv, val_p, len); 20613737Shx147065 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) { 20623737Shx147065 len >>= 1; /* convert bytes to 16-bit words */ 20633737Shx147065 20643737Shx147065 /* 1. select read mode */ 20653737Shx147065 if (stat = pcan_set_cmd(pcan_p, AN_CMD_ACCESS | 20663737Shx147065 AN_ACCESS_READ, type)) 20673737Shx147065 return (stat); 20683737Shx147065 20693737Shx147065 /* 2. select Buffer Access Path (channel) 1 for PIO */ 20703737Shx147065 if (stat = pcan_set_ch(pcan_p, type, 0, 1)) 20713737Shx147065 return (stat); 20723737Shx147065 20733737Shx147065 /* 3. read length */ 20743737Shx147065 PCAN_READ(pcan_p, AN_DATA1, stat); 20753737Shx147065 *val_p++ = stat; 20763737Shx147065 if (stat != (len << 1)) { 20773737Shx147065 PCANDBG((CE_NOTE, "pcan get_ltv[%x]:expect %x," 20783737Shx147065 "got %x\n", type, (len + 1) << 1, stat)); 20793737Shx147065 stat = (stat >> 1) - 1; 20803737Shx147065 len = MIN(stat, len); 20813737Shx147065 } 20823737Shx147065 /* 4. read value */ 20833737Shx147065 for (stat = 0; stat < len - 1; stat++, val_p++) { 20843737Shx147065 PCAN_READ_P(pcan_p, AN_DATA1, val_p, 1); 20853737Shx147065 } 20863737Shx147065 } 20873737Shx147065 return (PCAN_SUCCESS); 20883737Shx147065 } 20893737Shx147065 20903737Shx147065 static uint16_t 20913737Shx147065 pcan_put_ltv(pcan_maci_t *pcan_p, uint16_t len, uint16_t type, uint16_t *val_p) 20923737Shx147065 { 20933737Shx147065 uint16_t stat; 20943737Shx147065 int i; 20953737Shx147065 20963737Shx147065 ASSERT(!(len & 1)); 20973737Shx147065 20983737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 20993737Shx147065 struct an_card_rid_desc an_rid_desc; 21003737Shx147065 21013737Shx147065 for (i = 0; i < AN_TIMEOUT; i++) { 21023737Shx147065 PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat); 21033737Shx147065 if (!(stat & AN_CMD_BUSY)) { 21043737Shx147065 break; 21053737Shx147065 } 21063737Shx147065 } 21073737Shx147065 if (i == AN_TIMEOUT) { 21083737Shx147065 cmn_err(CE_WARN, "pcan put_ltv: busy"); 21093737Shx147065 } 21103737Shx147065 21113737Shx147065 an_rid_desc.an_valid = 1; 21123737Shx147065 an_rid_desc.an_len = len; 21133737Shx147065 an_rid_desc.an_rid = type; 21143737Shx147065 an_rid_desc.an_phys = pcan_p->pcan_cmd.dma_physaddr; 21153737Shx147065 21163737Shx147065 bcopy(val_p, pcan_p->pcan_cmd.dma_virtaddr, 21173737Shx147065 an_rid_desc.an_len); 21183737Shx147065 21193737Shx147065 for (i = 0; i < sizeof (an_rid_desc) / 4; i++) 21203737Shx147065 PCAN_AUX_PUT32(pcan_p, AN_HOST_DESC_OFFSET + i * 4, 21213737Shx147065 ((uint32_t *)&an_rid_desc)[i]); 21223737Shx147065 pcan_delay(pcan_p, 100000); 21233737Shx147065 stat = pcan_set_cmd0(pcan_p, AN_CMD_ACCESS | 21243737Shx147065 AN_ACCESS_WRITE, type, 0, 0); 21253737Shx147065 pcan_delay(pcan_p, 100000); 21263737Shx147065 return (stat); 21273737Shx147065 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) { 21283737Shx147065 /* 0. select read mode first */ 21293737Shx147065 if (stat = pcan_set_cmd(pcan_p, AN_CMD_ACCESS | 21303737Shx147065 AN_ACCESS_READ, type)) 21313737Shx147065 return (stat); 21323737Shx147065 21333737Shx147065 /* 1. select Buffer Access Path (channel) 1 for PIO */ 21343737Shx147065 if (stat = pcan_set_ch(pcan_p, type, 0, 1)) 21353737Shx147065 return (stat); 21363737Shx147065 21373737Shx147065 /* 2. write length */ 21383737Shx147065 len >>= 1; /* convert bytes to 16-bit words */ 21393737Shx147065 stat = len; 21403737Shx147065 PCAN_WRITE(pcan_p, AN_DATA1, stat); 21413737Shx147065 21423737Shx147065 /* 3. write value */ 21433737Shx147065 val_p++; 21443737Shx147065 for (stat = 0; stat < len-1; stat++, val_p++) { 21453737Shx147065 PCAN_WRITE_P(pcan_p, AN_DATA1, val_p, 1); 21463737Shx147065 } 21473737Shx147065 21483737Shx147065 /* 4. select write mode */ 21493737Shx147065 return (pcan_set_cmd(pcan_p, AN_CMD_ACCESS | 21503737Shx147065 AN_ACCESS_WRITE, type)); 21513737Shx147065 } 21523737Shx147065 return (PCAN_FAIL); 21533737Shx147065 } 21543737Shx147065 21553737Shx147065 /*ARGSUSED*/ 21563737Shx147065 static uint16_t 21573737Shx147065 pcan_rdch0(pcan_maci_t *pcan_p, uint16_t type, uint16_t off, uint16_t *buf_p, 21583737Shx147065 int len, int order) 21593737Shx147065 { 21603737Shx147065 ASSERT(!(len & 1)); 21613737Shx147065 21623737Shx147065 if (pcan_set_ch(pcan_p, type, off, 0) != PCAN_SUCCESS) 21633737Shx147065 return (PCAN_FAIL); 21643737Shx147065 len >>= 1; 21653737Shx147065 for (off = 0; off < len; off++, buf_p++) { 21663737Shx147065 PCAN_READ_P(pcan_p, AN_DATA0, buf_p, order); 21673737Shx147065 } 21683737Shx147065 return (PCAN_SUCCESS); 21693737Shx147065 } 21703737Shx147065 21713737Shx147065 /*ARGSUSED*/ 21723737Shx147065 static uint16_t 21733737Shx147065 pcan_wrch1(pcan_maci_t *pcan_p, uint16_t type, uint16_t off, uint16_t *buf_p, 21743737Shx147065 int len, int order) 21753737Shx147065 { 21763737Shx147065 ASSERT(!(len & 1)); 21773737Shx147065 21783737Shx147065 if (pcan_set_ch(pcan_p, type, off, 1) != PCAN_SUCCESS) 21793737Shx147065 return (PCAN_FAIL); 21803737Shx147065 len >>= 1; 21813737Shx147065 for (off = 0; off < len; off++, buf_p++) { 21823737Shx147065 PCAN_WRITE_P(pcan_p, AN_DATA1, buf_p, order); 21833737Shx147065 } 21843737Shx147065 return (PCAN_SUCCESS); 21853737Shx147065 } 21863737Shx147065 21873737Shx147065 static uint16_t 21883737Shx147065 pcan_status_ltv(int rw, pcan_maci_t *pcan_p, struct an_ltv_status *status_p) 21893737Shx147065 { 21903737Shx147065 uint16_t ret, len; 21913737Shx147065 21923737Shx147065 if (rw != PCAN_READ_LTV) { 21933737Shx147065 cmn_err(CE_WARN, "pcan status_ltv: unsupported op %x", rw); 21943737Shx147065 return (PCAN_FAIL); 21953737Shx147065 } 21963737Shx147065 if (ret = pcan_get_ltv(pcan_p, sizeof (*status_p), AN_RID_STATUS, 21973737Shx147065 (uint16_t *)status_p)) 21983737Shx147065 return (ret); 21993737Shx147065 22003737Shx147065 PCAN_SWAP16_BUF(status_p->an_macaddr); 22013737Shx147065 PCAN_SWAP16_BUF(status_p->an_ssid); 22023737Shx147065 len = min(status_p->an_ssidlen, 31); 22033737Shx147065 status_p->an_ssid[len] = '\0'; 22043737Shx147065 PCAN_SWAP16_BUF(status_p->an_ap_name); 22053737Shx147065 PCAN_SWAP16_BUF(status_p->an_cur_bssid); 22063737Shx147065 PCAN_SWAP16_BUF(status_p->an_prev_bssid1); 22073737Shx147065 PCAN_SWAP16_BUF(status_p->an_prev_bssid2); 22083737Shx147065 PCAN_SWAP16_BUF(status_p->an_prev_bssid3); 22093737Shx147065 PCAN_SWAP16_BUF(status_p->an_ap_ip_address); 22103737Shx147065 PCAN_SWAP16_BUF(status_p->an_carrier); 22113737Shx147065 return (PCAN_SUCCESS); 22123737Shx147065 } 22133737Shx147065 22143737Shx147065 static uint16_t 22153737Shx147065 pcan_cfg_ltv(int rw, pcan_maci_t *pcan_p, struct an_ltv_genconfig *cfg_p) 22163737Shx147065 { 22173737Shx147065 uint16_t ret; 22183737Shx147065 uint16_t rid = cfg_p == &pcan_p->an_config ? 22193737Shx147065 AN_RID_GENCONFIG : AN_RID_ACTUALCFG; 22203737Shx147065 22213737Shx147065 if (rw == PCAN_READ_LTV) { 22223737Shx147065 if (ret = pcan_get_ltv(pcan_p, sizeof (*cfg_p), rid, 22233737Shx147065 (uint16_t *)cfg_p)) 22243737Shx147065 return (ret); 22253737Shx147065 goto done; 22263737Shx147065 } 22273737Shx147065 PCAN_SWAP16_BUF(cfg_p->an_macaddr); 22283737Shx147065 PCAN_SWAP16_BUF(cfg_p->an_rates); 22293737Shx147065 if (ret = pcan_put_ltv(pcan_p, sizeof (*cfg_p), 22303737Shx147065 rid, (uint16_t *)cfg_p)) 22313737Shx147065 return (ret); 22323737Shx147065 done: 22333737Shx147065 PCAN_SWAP16_BUF(cfg_p->an_macaddr); 22343737Shx147065 PCAN_SWAP16_BUF(cfg_p->an_rates); 22353737Shx147065 return (ret); 22363737Shx147065 } 22373737Shx147065 22383737Shx147065 static uint16_t 22393737Shx147065 pcan_cap_ltv(int rw, pcan_maci_t *pcan_p) 22403737Shx147065 { 22413737Shx147065 uint16_t ret; 22423737Shx147065 22433737Shx147065 if (rw != PCAN_READ_LTV) { 22443737Shx147065 cmn_err(CE_WARN, "pcan cap_ltv: unsupported op %x", rw); 22453737Shx147065 return (PCAN_FAIL); 22463737Shx147065 } 22473737Shx147065 if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_caps), 22484343Sgd78059 AN_RID_CAPABILITIES, (uint16_t *)&pcan_p->an_caps)) 22493737Shx147065 return (ret); 22503737Shx147065 22513737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_caps.an_oui); 22523737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_caps.an_manufname); 22533737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_caps.an_prodname); 22543737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_caps.an_prodvers); 22553737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_caps.an_oemaddr); 22563737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_caps.an_aironetaddr); 22573737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_caps.an_callid); 22583737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_caps.an_supported_rates); 22593737Shx147065 return (PCAN_SUCCESS); 22603737Shx147065 } 22613737Shx147065 22623737Shx147065 static uint16_t 22633737Shx147065 pcan_ssid_ltv(int rw, pcan_maci_t *pcan_p) 22643737Shx147065 { 22653737Shx147065 uint16_t ret; 22663737Shx147065 22673737Shx147065 if (rw == PCAN_READ_LTV) { 22683737Shx147065 if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_ssidlist), 22693737Shx147065 AN_RID_SSIDLIST, (uint16_t *)&pcan_p->an_ssidlist)) 22703737Shx147065 return (ret); 22713737Shx147065 goto done; 22723737Shx147065 } 22733737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid1); 22743737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid2); 22753737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid3); 22763737Shx147065 if (ret = pcan_put_ltv(pcan_p, sizeof (struct an_ltv_ssidlist), 22773737Shx147065 AN_RID_SSIDLIST, (uint16_t *)&pcan_p->an_ssidlist)) 22783737Shx147065 return (ret); 22793737Shx147065 done: 22803737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid1); 22813737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid2); 22823737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid3); 22833737Shx147065 return (ret); 22843737Shx147065 } 22853737Shx147065 22863737Shx147065 static uint16_t 22873737Shx147065 pcan_aplist_ltv(int rw, pcan_maci_t *pcan_p) 22883737Shx147065 { 22893737Shx147065 uint16_t ret; 22903737Shx147065 22913737Shx147065 if (rw == PCAN_READ_LTV) { 22923737Shx147065 if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_aplist), 22933737Shx147065 AN_RID_APLIST, (uint16_t *)&pcan_p->an_aplist)) 22943737Shx147065 return (ret); 22953737Shx147065 goto done; 22963737Shx147065 } 22973737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap1); 22983737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap2); 22993737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap3); 23003737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap4); 23013737Shx147065 if (ret = pcan_put_ltv(pcan_p, sizeof (struct an_ltv_aplist), 23023737Shx147065 AN_RID_APLIST, (uint16_t *)&pcan_p->an_aplist)) 23033737Shx147065 return (ret); 23043737Shx147065 done: 23053737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap1); 23063737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap2); 23073737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap3); 23083737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap4); 23093737Shx147065 return (ret); 23103737Shx147065 } 23113737Shx147065 23123737Shx147065 static uint16_t 23133737Shx147065 pcan_scanresult_ltv(int rw, pcan_maci_t *pcan_p, uint16_t type, 23143737Shx147065 struct an_ltv_scanresult *scanresult_p) 23153737Shx147065 { 23163737Shx147065 uint16_t ret, len; 23173737Shx147065 23183737Shx147065 if (rw != PCAN_READ_LTV) { 23193737Shx147065 cmn_err(CE_WARN, "pcan scan_ltv: readonly rid %x\n", type); 23203737Shx147065 return (PCAN_FAIL); 23213737Shx147065 } 23223737Shx147065 if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_scanresult), 23233737Shx147065 type, (uint16_t *)scanresult_p)) 23243737Shx147065 return (ret); 23253737Shx147065 PCAN_SWAP16_BUF(scanresult_p->an_bssid); 23263737Shx147065 PCAN_SWAP16_BUF(scanresult_p->an_ssid); 23273737Shx147065 len = min(scanresult_p->an_ssidlen, 31); 23283737Shx147065 scanresult_p->an_ssid[len] = '\0'; 23293737Shx147065 PCAN_SWAP16_BUF(scanresult_p->an_rates); 23303737Shx147065 return (PCAN_SUCCESS); 23313737Shx147065 } 23323737Shx147065 23333737Shx147065 static uint16_t 23343737Shx147065 pcan_one_wepkey(int rw, pcan_maci_t *pcan_p, struct an_ltv_wepkey *wkp, 23353737Shx147065 uint16_t rid) 23363737Shx147065 { 23373737Shx147065 uint16_t ret; 23383737Shx147065 23393737Shx147065 if (rw == PCAN_READ_LTV) { 23403737Shx147065 if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_wepkey), 23413737Shx147065 rid, (uint16_t *)wkp)) { 23423737Shx147065 return (ret); 23433737Shx147065 } 23443737Shx147065 goto done; 23453737Shx147065 } 23463737Shx147065 PCAN_SWAP16_BUF(wkp->an_macaddr); 23473737Shx147065 PCAN_SWAP16_BUF(wkp->an_key); 23483737Shx147065 if (ret = pcan_put_ltv(pcan_p, sizeof (struct an_ltv_wepkey), 23493737Shx147065 rid, (uint16_t *)wkp)) 23503737Shx147065 return (ret); 23513737Shx147065 done: 23523737Shx147065 PCAN_SWAP16_BUF(wkp->an_macaddr); 23533737Shx147065 PCAN_SWAP16_BUF(wkp->an_key); 23543737Shx147065 return (ret); 23553737Shx147065 } 23563737Shx147065 23573737Shx147065 static uint16_t 23583737Shx147065 pcan_wepkey_ltv(int rw, pcan_maci_t *pcan_p) 23593737Shx147065 { 23603737Shx147065 uint16_t ret, i; 23613737Shx147065 struct an_ltv_wepkey wk; 23623737Shx147065 23633737Shx147065 if (rw == PCAN_READ_LTV) { 23643737Shx147065 uint16_t rid = AN_RID_WEPKEY2; 23653737Shx147065 23663737Shx147065 if (ret = pcan_one_wepkey(rw, pcan_p, &wk, rid)) 23673737Shx147065 return (ret); 23683737Shx147065 for (i = 0; i < 5; i++) { 23693737Shx147065 if (wk.an_index < 4) 23703737Shx147065 pcan_p->an_wepkey[wk.an_index] = wk; 23713737Shx147065 else if (wk.an_index == 0xffff) 23723737Shx147065 pcan_p->an_cur_wepkey = wk.an_macaddr[0]; 23733737Shx147065 rid = AN_RID_WEPKEY; 23743737Shx147065 } 23753737Shx147065 return (PCAN_SUCCESS); 23763737Shx147065 } 23773737Shx147065 for (i = 0; i < MAX_NWEPKEYS; i++) { 23783737Shx147065 if (pcan_p->an_wepkey[i].an_index == i) { 23793737Shx147065 if (ret = pcan_one_wepkey(rw, pcan_p, 23803737Shx147065 &pcan_p->an_wepkey[i], AN_RID_WEPKEY2)) 23813737Shx147065 return (ret); 23823737Shx147065 } 23833737Shx147065 } 23843737Shx147065 /* Now set the default key */ 23853737Shx147065 (void) memset(&wk, 0, sizeof (wk)); 23863737Shx147065 wk.an_index = 0xffff; 23873737Shx147065 wk.an_macaddr[0] = pcan_p->an_cur_wepkey; 23883737Shx147065 ret = pcan_one_wepkey(rw, pcan_p, &wk, AN_RID_WEPKEY2); 23893737Shx147065 return (ret); 23903737Shx147065 } 23913737Shx147065 23923737Shx147065 static uint16_t 23933737Shx147065 pcan_alloc_nicmem(pcan_maci_t *pcan_p, uint16_t len, uint16_t *id_p) 23943737Shx147065 { 23953737Shx147065 int i; 23963737Shx147065 uint16_t stat; 23973737Shx147065 23983737Shx147065 len = ((len + 1) >> 1) << 1; /* round up to 16-bit boundary */ 23993737Shx147065 24003737Shx147065 if (stat = pcan_set_cmd(pcan_p, AN_CMD_ALLOC_MEM, len)) 24013737Shx147065 return (stat); 24023737Shx147065 for (i = 0; !(stat & AN_EV_ALLOC) && (i < AN_TIMEOUT); i++) { 24033737Shx147065 PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat); 24043737Shx147065 } 24053737Shx147065 if (!(stat & AN_EV_ALLOC)) 24063737Shx147065 return (PCAN_TIMEDOUT_ALLOC); 24073737Shx147065 PCAN_READ(pcan_p, AN_ALLOC_FID, stat); 24083737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_ALLOC); 24093737Shx147065 *id_p = stat; 24103737Shx147065 24113737Shx147065 /* zero fill the allocated NIC mem - sort of pcan_fill_ch0 */ 24123737Shx147065 (void) pcan_set_ch(pcan_p, stat, 0, 0); 24133737Shx147065 for (len >>= 1, stat = 0; stat < len; stat++) { 24143737Shx147065 PCAN_WRITE(pcan_p, AN_DATA0, 0); 24153737Shx147065 } 24163737Shx147065 return (PCAN_SUCCESS); 24173737Shx147065 } 24183737Shx147065 24193737Shx147065 static void 24203737Shx147065 pcan_stop_rx_dma(pcan_maci_t *pcan_p) 24213737Shx147065 { 24223737Shx147065 int i, j; 24233737Shx147065 struct an_card_rx_desc an_rx_desc; 24243737Shx147065 24253737Shx147065 for (i = 0; i < AN_MAX_RX_DESC; i++) { 24263737Shx147065 bzero(&an_rx_desc, sizeof (an_rx_desc)); 24273737Shx147065 an_rx_desc.an_valid = 0; 24283737Shx147065 an_rx_desc.an_len = AN_RX_BUFFER_SIZE; 24293737Shx147065 an_rx_desc.an_done = 1; 24303737Shx147065 an_rx_desc.an_phys = pcan_p->pcan_rx[i].dma_physaddr; 24313737Shx147065 for (j = 0; j < sizeof (an_rx_desc) / 4; j++) 24323737Shx147065 PCAN_AUX_PUT32(pcan_p, AN_RX_DESC_OFFSET 24333737Shx147065 + (i * sizeof (an_rx_desc)) 24343737Shx147065 + (j * 4), ((uint32_t *)&an_rx_desc)[j]); 24353737Shx147065 } 24363737Shx147065 } 24373737Shx147065 24383737Shx147065 static int 24393737Shx147065 pcan_init_dma_desc(pcan_maci_t *pcan_p) 24403737Shx147065 { 24413737Shx147065 int i, j; 24423737Shx147065 struct an_card_rid_desc an_rid_desc; 24433737Shx147065 struct an_card_rx_desc an_rx_desc; 24443737Shx147065 struct an_card_tx_desc an_tx_desc; 24453737Shx147065 24463737Shx147065 /* Allocate DMA for rx */ 24473737Shx147065 if (pcan_set_cmd0(pcan_p, AN_CMD_ALLOC_DESC, 24483737Shx147065 AN_DESCRIPTOR_RX, AN_RX_DESC_OFFSET, 24493737Shx147065 AN_MAX_RX_DESC) != PCAN_SUCCESS) { 24503737Shx147065 cmn_err(CE_WARN, "pcan init_dma: fail to alloc rx descriptor"); 24513737Shx147065 goto error; 24523737Shx147065 } 24533737Shx147065 for (i = 0; i < AN_MAX_RX_DESC; i++) { 24543737Shx147065 bzero(&an_rx_desc, sizeof (an_rx_desc)); 24553737Shx147065 an_rx_desc.an_valid = 1; 24563737Shx147065 an_rx_desc.an_len = AN_RX_BUFFER_SIZE; 24573737Shx147065 an_rx_desc.an_done = 0; 24583737Shx147065 an_rx_desc.an_phys = pcan_p->pcan_rx[i].dma_physaddr; 24593737Shx147065 for (j = 0; j < sizeof (an_rx_desc) / 4; j++) 24603737Shx147065 PCAN_AUX_PUT32(pcan_p, AN_RX_DESC_OFFSET 24613737Shx147065 + (i * sizeof (an_rx_desc)) 24623737Shx147065 + (j * 4), ((uint32_t *)&an_rx_desc)[j]); 24633737Shx147065 } 24643737Shx147065 24653737Shx147065 24663737Shx147065 /* Allocate DMA for tx */ 24673737Shx147065 if (pcan_set_cmd0(pcan_p, AN_CMD_ALLOC_DESC, 24683737Shx147065 AN_DESCRIPTOR_TX, AN_TX_DESC_OFFSET, 24693737Shx147065 AN_MAX_TX_DESC) != PCAN_SUCCESS) { 24703737Shx147065 cmn_err(CE_WARN, "pcan init_dma: fail to alloc tx descriptor"); 24713737Shx147065 goto error; 24723737Shx147065 } 24733737Shx147065 24743737Shx147065 for (i = 0; i < AN_MAX_TX_DESC; i++) { 24753737Shx147065 an_tx_desc.an_offset = 0; 24763737Shx147065 an_tx_desc.an_eoc = 0; 24773737Shx147065 an_tx_desc.an_valid = 0; 24783737Shx147065 an_tx_desc.an_len = 0; 24793737Shx147065 an_tx_desc.an_phys = pcan_p->pcan_tx[i].dma_physaddr; 24803737Shx147065 24813737Shx147065 for (j = 0; j < sizeof (an_tx_desc) / 4; j++) 24823737Shx147065 PCAN_AUX_PUT32(pcan_p, AN_TX_DESC_OFFSET 24833737Shx147065 + (i * sizeof (an_tx_desc)) 24843737Shx147065 + (j * 4), ((uint32_t *)&an_tx_desc)[j]); 24853737Shx147065 } 24863737Shx147065 24873737Shx147065 /* Allocate DMA for rid */ 24883737Shx147065 if (pcan_set_cmd0(pcan_p, AN_CMD_ALLOC_DESC, 24893737Shx147065 AN_DESCRIPTOR_HOSTRW, AN_HOST_DESC_OFFSET, 1) != PCAN_SUCCESS) { 24903737Shx147065 cmn_err(CE_WARN, "pcan init_dma: fail to alloc rid descriptor"); 24913737Shx147065 goto error; 24923737Shx147065 } 24933737Shx147065 bzero(&an_rid_desc, sizeof (an_rid_desc)); 24943737Shx147065 an_rid_desc.an_valid = 1; 24953737Shx147065 an_rid_desc.an_len = AN_RID_BUFFER_SIZE; 24963737Shx147065 an_rid_desc.an_rid = 0; 24973737Shx147065 an_rid_desc.an_phys = pcan_p->pcan_cmd.dma_physaddr; 24983737Shx147065 24993737Shx147065 for (i = 0; i < sizeof (an_rid_desc) / 4; i++) 25003737Shx147065 PCAN_AUX_PUT32(pcan_p, AN_HOST_DESC_OFFSET + i * 4, 25013737Shx147065 ((uint32_t *)&an_rid_desc)[i]); 25023737Shx147065 25033737Shx147065 pcan_p->pcan_txring.an_tx_prod = 0; 25043737Shx147065 pcan_p->pcan_txring.an_tx_cons = 0; 25053737Shx147065 pcan_p->pcan_flag &= ~PCAN_CARD_SEND; 25063737Shx147065 return (PCAN_SUCCESS); 25073737Shx147065 error: 25083737Shx147065 return (PCAN_FAIL); 25093737Shx147065 } 25103737Shx147065 25113737Shx147065 static int 25123737Shx147065 pcan_init_dma(dev_info_t *dip, pcan_maci_t *pcan_p) 25133737Shx147065 { 25143737Shx147065 int i, ret = PCAN_FAIL; 25153737Shx147065 ddi_dma_cookie_t dma_cookie; 25163737Shx147065 size_t len; 25173737Shx147065 25183737Shx147065 /* Allocate DMA for rx */ 25193737Shx147065 for (i = 0; i < AN_MAX_RX_DESC; i++) { 25203737Shx147065 if (ddi_dma_alloc_handle(dip, &control_cmd_dma_attr, 25213737Shx147065 DDI_DMA_SLEEP, 0, 25223737Shx147065 &pcan_p->pcan_rx[i].dma_handle) != DDI_SUCCESS) 25233737Shx147065 goto error; 25243737Shx147065 25253737Shx147065 if (ddi_dma_mem_alloc(pcan_p->pcan_rx[i].dma_handle, 25263737Shx147065 AN_RX_BUFFER_SIZE, &accattr, 25273737Shx147065 DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0, 25283737Shx147065 (caddr_t *)&pcan_p->pcan_rx[i].dma_virtaddr, &len, 25293737Shx147065 &pcan_p->pcan_rx[i].dma_acc_handle) != DDI_SUCCESS) { 25303737Shx147065 goto error; 25313737Shx147065 } 25323737Shx147065 if (ddi_dma_addr_bind_handle( 25333737Shx147065 pcan_p->pcan_rx[i].dma_handle, 25343737Shx147065 NULL, (caddr_t)pcan_p->pcan_rx[i].dma_virtaddr, 25353737Shx147065 len, DDI_DMA_READ | 25363737Shx147065 DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0, &dma_cookie, 25373737Shx147065 &pcan_p->pcan_rx[i].ncookies) != DDI_DMA_MAPPED) { 25383737Shx147065 goto error; 25393737Shx147065 } 25403737Shx147065 ASSERT(pcan_p->pcan_rx[i].ncookies == 1); 25413737Shx147065 pcan_p->pcan_rx[i].dma_physaddr = dma_cookie.dmac_address; 25423737Shx147065 } 25433737Shx147065 25443737Shx147065 /* Allocate DMA for tx */ 25453737Shx147065 for (i = 0; i < AN_MAX_TX_DESC; i++) { 25463737Shx147065 if (ddi_dma_alloc_handle(dip, &control_cmd_dma_attr, 25473737Shx147065 DDI_DMA_SLEEP, 0, 25483737Shx147065 &pcan_p->pcan_tx[i].dma_handle) != DDI_SUCCESS) 25493737Shx147065 goto error; 25503737Shx147065 25513737Shx147065 if (ddi_dma_mem_alloc(pcan_p->pcan_tx[i].dma_handle, 25523737Shx147065 AN_TX_BUFFER_SIZE, &accattr, 25533737Shx147065 DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0, 25543737Shx147065 (caddr_t *)&pcan_p->pcan_tx[i].dma_virtaddr, &len, 25553737Shx147065 &pcan_p->pcan_tx[i].dma_acc_handle) != DDI_SUCCESS) { 25563737Shx147065 goto error; 25573737Shx147065 } 25583737Shx147065 if (ddi_dma_addr_bind_handle( 25593737Shx147065 pcan_p->pcan_tx[i].dma_handle, 25603737Shx147065 NULL, (caddr_t)pcan_p->pcan_tx[i].dma_virtaddr, 25613737Shx147065 len, DDI_DMA_WRITE | 25623737Shx147065 DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0, &dma_cookie, 25633737Shx147065 &pcan_p->pcan_tx[i].ncookies) != DDI_DMA_MAPPED) { 25643737Shx147065 goto error; 25653737Shx147065 } 25663737Shx147065 ASSERT(pcan_p->pcan_tx[i].ncookies == 1); 25673737Shx147065 pcan_p->pcan_tx[i].dma_physaddr = dma_cookie.dmac_address; 25683737Shx147065 } 25693737Shx147065 25703737Shx147065 /* Allocate DMA for rid */ 25713737Shx147065 if (ddi_dma_alloc_handle(dip, &control_cmd_dma_attr, 25723737Shx147065 DDI_DMA_SLEEP, 0, 25733737Shx147065 &pcan_p->pcan_cmd.dma_handle) != DDI_SUCCESS) 25743737Shx147065 goto error; 25753737Shx147065 25763737Shx147065 if (ddi_dma_mem_alloc(pcan_p->pcan_cmd.dma_handle, 25773737Shx147065 AN_RID_BUFFER_SIZE, &accattr, 25783737Shx147065 DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0, 25793737Shx147065 (caddr_t *)&pcan_p->pcan_cmd.dma_virtaddr, &len, 25803737Shx147065 &pcan_p->pcan_cmd.dma_acc_handle) != DDI_SUCCESS) { 25813737Shx147065 goto error; 25823737Shx147065 } 25833737Shx147065 if (ddi_dma_addr_bind_handle( 25843737Shx147065 pcan_p->pcan_cmd.dma_handle, 25853737Shx147065 NULL, (caddr_t)pcan_p->pcan_cmd.dma_virtaddr, 25863737Shx147065 len, DDI_DMA_RDWR | 25873737Shx147065 DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0, &dma_cookie, 25883737Shx147065 &pcan_p->pcan_cmd.ncookies) != DDI_DMA_MAPPED) { 25893737Shx147065 goto error; 25903737Shx147065 } 25913737Shx147065 ASSERT(pcan_p->pcan_cmd.ncookies == 1); 25923737Shx147065 pcan_p->pcan_cmd.dma_physaddr = dma_cookie.dmac_address; 25933737Shx147065 25943737Shx147065 if (ret = pcan_init_dma_desc(pcan_p)) { 25953737Shx147065 cmn_err(CE_WARN, "pcan init_dma_desc: failed\n"); 25963737Shx147065 goto error; 25973737Shx147065 } 25983737Shx147065 25993737Shx147065 return (PCAN_SUCCESS); 26003737Shx147065 error: 26013737Shx147065 pcan_free_dma(pcan_p); 26023737Shx147065 return (ret); 26033737Shx147065 } 26043737Shx147065 26053737Shx147065 static void 26063737Shx147065 pcan_free_dma(pcan_maci_t *pcan_p) 26073737Shx147065 { 26083737Shx147065 int i; 26093737Shx147065 26103737Shx147065 /* free RX dma */ 26113737Shx147065 pcan_stop_rx_dma(pcan_p); 26123737Shx147065 for (i = 0; i < AN_MAX_RX_DESC; i++) { 26133737Shx147065 if (pcan_p->pcan_rx[i].dma_handle != NULL) { 26143737Shx147065 if (pcan_p->pcan_rx[i].ncookies) { 26153737Shx147065 (void) ddi_dma_unbind_handle( 26163737Shx147065 pcan_p->pcan_rx[i].dma_handle); 26173737Shx147065 pcan_p->pcan_rx[i].ncookies = 0; 26183737Shx147065 } 26193737Shx147065 ddi_dma_free_handle( 26203737Shx147065 &pcan_p->pcan_rx[i].dma_handle); 26213737Shx147065 pcan_p->pcan_rx[i].dma_handle = NULL; 26223737Shx147065 } 26233737Shx147065 if (pcan_p->pcan_rx[i].dma_acc_handle != NULL) { 26243737Shx147065 ddi_dma_mem_free( 26253737Shx147065 &pcan_p->pcan_rx[i].dma_acc_handle); 26263737Shx147065 pcan_p->pcan_rx[i].dma_acc_handle = NULL; 26273737Shx147065 } 26283737Shx147065 } 26293737Shx147065 26303737Shx147065 /* free TX dma */ 26313737Shx147065 for (i = 0; i < AN_MAX_TX_DESC; i++) { 26323737Shx147065 if (pcan_p->pcan_tx[i].dma_handle != NULL) { 26333737Shx147065 if (pcan_p->pcan_tx[i].ncookies) { 26343737Shx147065 (void) ddi_dma_unbind_handle( 26353737Shx147065 pcan_p->pcan_tx[i].dma_handle); 26363737Shx147065 pcan_p->pcan_tx[i].ncookies = 0; 26373737Shx147065 } 26383737Shx147065 ddi_dma_free_handle( 26393737Shx147065 &pcan_p->pcan_tx[i].dma_handle); 26403737Shx147065 pcan_p->pcan_tx[i].dma_handle = NULL; 26413737Shx147065 } 26423737Shx147065 if (pcan_p->pcan_tx[i].dma_acc_handle != NULL) { 26433737Shx147065 ddi_dma_mem_free( 26443737Shx147065 &pcan_p->pcan_tx[i].dma_acc_handle); 26453737Shx147065 pcan_p->pcan_tx[i].dma_acc_handle = NULL; 26463737Shx147065 } 26473737Shx147065 } 26483737Shx147065 26493737Shx147065 /* free cmd dma */ 26503737Shx147065 if (pcan_p->pcan_cmd.dma_handle != NULL) { 26513737Shx147065 if (pcan_p->pcan_cmd.ncookies) { 26523737Shx147065 (void) ddi_dma_unbind_handle( 26533737Shx147065 pcan_p->pcan_cmd.dma_handle); 26543737Shx147065 pcan_p->pcan_cmd.ncookies = 0; 26553737Shx147065 } 26563737Shx147065 ddi_dma_free_handle( 26573737Shx147065 &pcan_p->pcan_cmd.dma_handle); 26583737Shx147065 pcan_p->pcan_cmd.dma_handle = NULL; 26593737Shx147065 } 26603737Shx147065 if (pcan_p->pcan_cmd.dma_acc_handle != NULL) { 26613737Shx147065 ddi_dma_mem_free( 26623737Shx147065 &pcan_p->pcan_cmd.dma_acc_handle); 26633737Shx147065 pcan_p->pcan_cmd.dma_acc_handle = NULL; 26643737Shx147065 } 26653737Shx147065 } 26663737Shx147065 26673737Shx147065 /* 26683737Shx147065 * get card capability (WEP, default channel), setup broadcast, mac addresses 26693737Shx147065 */ 26703737Shx147065 static uint32_t 26713737Shx147065 pcan_get_cap(pcan_maci_t *pcan_p) 26723737Shx147065 { 26733737Shx147065 uint16_t stat; 26743737Shx147065 26753737Shx147065 if (stat = pcan_cfg_ltv(PCAN_READ_LTV, pcan_p, &pcan_p->an_config)) { 26763737Shx147065 PCANDBG((CE_NOTE, "pcan get_cap: read cfg fail %x", stat)); 26773737Shx147065 return ((uint32_t)AN_RID_GENCONFIG << 16 | stat); 26783737Shx147065 } 26793737Shx147065 26803737Shx147065 if (stat = pcan_cap_ltv(PCAN_READ_LTV, pcan_p)) { 26813737Shx147065 PCANDBG((CE_NOTE, "pcan get_cap: read cap fail %x", stat)); 26823737Shx147065 return ((uint32_t)AN_RID_CAPABILITIES << 16 | stat); 26833737Shx147065 } 26843737Shx147065 #ifdef DEBUG 26853737Shx147065 if (pcan_debug & PCAN_DBG_FW_VERSION) { 26863737Shx147065 cmn_err(CE_NOTE, "the version of the firmware in the wifi card " 26873737Shx147065 "'%s %s %s' is %s\n", 26883737Shx147065 pcan_p->an_caps.an_manufname, 26893737Shx147065 pcan_p->an_caps.an_prodname, 26903737Shx147065 pcan_p->pcan_device_type == PCAN_DEVICE_PCI ? 26913737Shx147065 "minipci" : "pccard", 26923737Shx147065 pcan_p->an_caps.an_prodvers); 26933737Shx147065 } 26943737Shx147065 #endif 26953737Shx147065 26963737Shx147065 if (stat = pcan_ssid_ltv(PCAN_READ_LTV, pcan_p)) { 26973737Shx147065 PCANDBG((CE_NOTE, "pcan get_cap: read ssid fail %x", stat)); 26983737Shx147065 return ((uint32_t)AN_RID_SSIDLIST << 16 | stat); 26993737Shx147065 } 27003737Shx147065 27013737Shx147065 if (stat = pcan_aplist_ltv(PCAN_READ_LTV, pcan_p)) { 27023737Shx147065 PCANDBG((CE_NOTE, "pcan get_cap: read aplist fail %x", stat)); 27033737Shx147065 return ((uint32_t)AN_RID_APLIST << 16 | stat); 27043737Shx147065 } 27053737Shx147065 if (stat = pcan_wepkey_ltv(PCAN_READ_LTV, pcan_p)) { 27063737Shx147065 PCANDBG((CE_NOTE, "pcan get_cap: read wepkey fail %x", stat)); 27073737Shx147065 return ((uint32_t)AN_RID_WEPKEY2 << 16 | stat); 27083737Shx147065 } 27093737Shx147065 ether_copy(pcan_p->an_caps.an_oemaddr, pcan_p->pcan_mac_addr); 27103737Shx147065 return (PCAN_SUCCESS); 27113737Shx147065 } 27123737Shx147065 27133737Shx147065 static int 27143737Shx147065 pcan_config_mac(pcan_maci_t *pcan_p) 27153737Shx147065 { 27163737Shx147065 uint16_t stat; 27173737Shx147065 27183737Shx147065 if (stat = pcan_ssid_ltv(PCAN_WRITE_LTV, pcan_p)) { 27193737Shx147065 PCANDBG((CE_NOTE, "pcan config_mac: write SSID failed%x\n", 27203737Shx147065 stat)); 27213737Shx147065 return ((int)stat); 27223737Shx147065 } 27233737Shx147065 27243737Shx147065 if (stat = pcan_aplist_ltv(PCAN_WRITE_LTV, pcan_p)) { 27253737Shx147065 PCANDBG((CE_NOTE, "pcan config_mac: write APlist failed%x\n", 27263737Shx147065 stat)); 27273737Shx147065 return ((int)stat); 27283737Shx147065 } 27293737Shx147065 if (stat = pcan_wepkey_ltv(PCAN_WRITE_LTV, pcan_p)) { 27303737Shx147065 PCANDBG((CE_NOTE, "pcan config_mac: write wepkey failed%x\n", 27313737Shx147065 stat)); 27323737Shx147065 return ((int)stat); 27333737Shx147065 } 27343737Shx147065 if (pcan_p->pcan_usewep) 27353737Shx147065 pcan_p->an_config.an_authtype |= 27363737Shx147065 AN_AUTHTYPE_ENABLEWEP | AN_AUTHTYPE_ALLOW_UNENCRYPTED; 27373737Shx147065 PCANDBG((CE_NOTE, "pcan config_mac: usewep=%x authtype=%x opmode=%x\n", 27383737Shx147065 pcan_p->pcan_usewep, pcan_p->an_config.an_authtype, 27393737Shx147065 pcan_p->an_config.an_opmode)); 27403737Shx147065 27413737Shx147065 pcan_p->an_config.an_assoc_timeout = 5000; /* stop assoc seq in 5 sec */ 27423737Shx147065 if (stat = pcan_cfg_ltv(PCAN_WRITE_LTV, pcan_p, &pcan_p->an_config)) { 27433737Shx147065 PCANDBG((CE_NOTE, "pcan config_mac: write cfg failed %x\n", 27443737Shx147065 stat)); 27453737Shx147065 return ((int)stat); 27463737Shx147065 } 27473737Shx147065 27483737Shx147065 if (stat = pcan_cfg_ltv(PCAN_READ_LTV, pcan_p, 27493737Shx147065 &pcan_p->an_actual_config)) { 27503737Shx147065 PCANDBG((CE_NOTE, "pcan config_mac: read cfg failed%x\n", 27513737Shx147065 stat)); 27523737Shx147065 return ((int)stat); 27533737Shx147065 } 27543737Shx147065 PCANDBG((CE_NOTE, "pcan config_mac: optionmask=%x authtype=%x\n", 0, 27553737Shx147065 pcan_p->an_actual_config.an_authtype)); 27563737Shx147065 27573737Shx147065 if (stat = pcan_status_ltv(PCAN_READ_LTV, pcan_p, &pcan_p->an_status)) { 27583737Shx147065 PCANDBG((CE_NOTE, "pcan config_mac: read status failed %x\n", 27593737Shx147065 stat)); 27603737Shx147065 return ((int)stat); 27613737Shx147065 } 27623737Shx147065 return (PCAN_SUCCESS); 27633737Shx147065 } 27643737Shx147065 27653737Shx147065 static int 27663737Shx147065 pcan_loaddef(pcan_maci_t *pcan_p) 27673737Shx147065 { 27683737Shx147065 int i; 27693737Shx147065 27703737Shx147065 pcan_p->an_ssidlist.an_ssid1_len = 0; 27713737Shx147065 bzero(pcan_p->an_ssidlist.an_ssid1, 27724343Sgd78059 sizeof (pcan_p->an_ssidlist.an_ssid1)); 27733737Shx147065 for (i = 0; i < MAX_NWEPKEYS; i++) { 27743737Shx147065 pcan_p->an_wepkey[i].an_index = 0xffff; 27753737Shx147065 bzero(pcan_p->an_wepkey[i].an_key, 27763737Shx147065 sizeof (pcan_p->an_wepkey[i].an_key)); 27773737Shx147065 pcan_p->an_wepkey[i].an_keylen = 0; 27783737Shx147065 bzero(pcan_p->an_wepkey[i].an_macaddr, 27793737Shx147065 sizeof (pcan_p->an_wepkey[i].an_macaddr)); 27803737Shx147065 pcan_p->an_wepkey[i].an_macaddr[0] = 1; 27813737Shx147065 } 27823737Shx147065 pcan_p->an_cur_wepkey = 0; 27833737Shx147065 27843737Shx147065 pcan_p->pcan_usewep = 0; 27853737Shx147065 pcan_p->an_config.an_opmode = AN_OPMODE_INFR_STATION; 27863737Shx147065 pcan_p->an_config.an_authtype = AN_AUTHTYPE_OPEN; 27873737Shx147065 pcan_p->an_config.an_stationary = 1; 27883737Shx147065 pcan_p->an_config.an_max_beacon_lost_time = 0xffff; 27893737Shx147065 i = pcan_config_mac(pcan_p); 27903737Shx147065 27913737Shx147065 return (i); 27923737Shx147065 } 27933737Shx147065 27943737Shx147065 static int 27953737Shx147065 pcan_init_nicmem(pcan_maci_t *pcan_p) 27963737Shx147065 { 27973737Shx147065 int i; 27983737Shx147065 uint16_t ret; 27993737Shx147065 pcan_txring_t *ring_p = &pcan_p->pcan_txring; 28003737Shx147065 28013737Shx147065 for (i = 0; i < AN_TX_RING_CNT; i++) { 28023737Shx147065 uint16_t rc; 28033737Shx147065 ret = pcan_alloc_nicmem(pcan_p, PCAN_NICMEM_SZ, &rc); 28043737Shx147065 if (ret) { 28053737Shx147065 cmn_err(CE_WARN, "pcan alloc NIC Tx buf[%x]: failed " 28063737Shx147065 "%x\n", i, ret); 28073737Shx147065 return (DDI_FAILURE); 28083737Shx147065 } 28093737Shx147065 ring_p->an_tx_fids[i] = rc; 28103737Shx147065 ring_p->an_tx_ring[i] = 0; 28113737Shx147065 PCANDBG((CE_NOTE, "pcan: NIC tx_id[%x]=%x\n", i, rc)); 28123737Shx147065 } 28133737Shx147065 ring_p->an_tx_prod = ring_p->an_tx_cons = 0; 28143737Shx147065 return (PCAN_SUCCESS); 28153737Shx147065 } 28163737Shx147065 28173737Shx147065 28183737Shx147065 28193737Shx147065 static void 28203737Shx147065 pcan_start_locked(pcan_maci_t *pcan_p) 28213737Shx147065 { 28223737Shx147065 pcan_p->pcan_flag |= PCAN_CARD_INTREN; 28233737Shx147065 PCAN_ENABLE_INTR(pcan_p); 28243737Shx147065 } 28253737Shx147065 28263737Shx147065 static void 28273737Shx147065 pcan_stop_locked(pcan_maci_t *pcan_p) 28283737Shx147065 { 28293737Shx147065 PCAN_DISABLE_INTR_CLEAR(pcan_p); 28303737Shx147065 pcan_p->pcan_flag &= ~PCAN_CARD_INTREN; 28313737Shx147065 } 28323737Shx147065 28333737Shx147065 /* 28343737Shx147065 * for scan result 28353737Shx147065 */ 28363737Shx147065 static int 28373737Shx147065 pcan_add_scan_item(pcan_maci_t *pcan_p, struct an_ltv_scanresult s) 28383737Shx147065 { 28393737Shx147065 an_scan_list_t *scan_item; 28403737Shx147065 28413737Shx147065 scan_item = kmem_zalloc(sizeof (an_scan_list_t), KM_SLEEP); 28423737Shx147065 if (scan_item == NULL) { 28433737Shx147065 cmn_err(CE_WARN, "pcan add_scan_item: zalloc failed\n"); 28443737Shx147065 return (PCAN_FAIL); 28453737Shx147065 } 28463737Shx147065 scan_item->an_val = s; 28473737Shx147065 scan_item->an_timeout = AN_SCAN_TIMEOUT_MAX; 28483737Shx147065 list_insert_tail(&pcan_p->an_scan_list, scan_item); 28493737Shx147065 pcan_p->an_scan_num++; 28503737Shx147065 return (PCAN_SUCCESS); 28513737Shx147065 } 28523737Shx147065 28533737Shx147065 static void 28543737Shx147065 pcan_delete_scan_item(pcan_maci_t *pcan_p, an_scan_list_t *s) 28553737Shx147065 { 28563737Shx147065 list_remove(&pcan_p->an_scan_list, s); 28573737Shx147065 kmem_free(s, sizeof (*s)); 28583737Shx147065 pcan_p->an_scan_num--; 28593737Shx147065 } 28603737Shx147065 28613737Shx147065 static void 28623737Shx147065 pcan_scanlist_timeout(void *arg) 28633737Shx147065 { 28643737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 28653737Shx147065 an_scan_list_t *scan_item0, *scan_item1; 28663737Shx147065 28673737Shx147065 mutex_enter(&pcan_p->pcan_scanlist_lock); 28683737Shx147065 scan_item0 = list_head(&pcan_p->an_scan_list); 28693737Shx147065 for (; scan_item0; ) { 28703737Shx147065 PCANDBG((CE_NOTE, "pcan scanlist: ssid = %s\n", 28713737Shx147065 scan_item0->an_val.an_ssid)); 28723737Shx147065 PCANDBG((CE_NOTE, "pcan scanlist: timeout left: %ds", 28733737Shx147065 scan_item0->an_timeout)); 28743737Shx147065 scan_item1 = list_next(&pcan_p->an_scan_list, scan_item0); 28753737Shx147065 if (scan_item0->an_timeout == 0) { 28763737Shx147065 pcan_delete_scan_item(pcan_p, scan_item0); 28773737Shx147065 } else { 28783737Shx147065 scan_item0->an_timeout--; 28793737Shx147065 } 28803737Shx147065 scan_item0 = scan_item1; 28813737Shx147065 } 28823737Shx147065 mutex_exit(&pcan_p->pcan_scanlist_lock); 28833737Shx147065 pcan_p->an_scanlist_timeout_id = timeout(pcan_scanlist_timeout, 28843737Shx147065 pcan_p, drv_usectohz(1000000)); 28853737Shx147065 } 28863737Shx147065 28873737Shx147065 28883737Shx147065 /* 28893737Shx147065 * for wificonfig and dlamd ioctl 28903737Shx147065 */ 28913737Shx147065 static int 28923737Shx147065 pcan_cfg_essid(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 28933737Shx147065 { 28943737Shx147065 uint16_t i; 28953737Shx147065 char *value; 28963737Shx147065 wldp_t *infp; 28973737Shx147065 wldp_t *outfp; 28983737Shx147065 char *buf; 28993737Shx147065 int iret; 29003737Shx147065 struct an_ltv_status *status_p; 29013737Shx147065 struct an_ltv_ssidlist *ssidlist_p; 29023737Shx147065 29033737Shx147065 status_p = &pcan_p->an_status; 29043737Shx147065 ssidlist_p = &pcan_p->an_ssidlist; 29053737Shx147065 29063737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 29073737Shx147065 if (buf == NULL) { 29083737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_essid: failed to alloc " 29093737Shx147065 "memory(%d)\n", MAX_BUF_LEN)); 29103737Shx147065 return (ENOMEM); 29113737Shx147065 } 29123737Shx147065 outfp = (wldp_t *)buf; 29133737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 29143737Shx147065 infp = (wldp_t *)mp->b_rptr; 29153737Shx147065 29163737Shx147065 if (cmd == WLAN_GET_PARAM) { 29173737Shx147065 if (pcan_status_ltv(PCAN_READ_LTV, pcan_p, status_p)) { 29183737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 29193737Shx147065 outfp->wldp_result = WL_HW_ERROR; 29203737Shx147065 goto done; 29213737Shx147065 } 29223737Shx147065 29233737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 29243737Shx147065 offsetof(wl_essid_t, wl_essid_essid) + 29253737Shx147065 status_p->an_ssidlen; 29263737Shx147065 ((wl_essid_t *)(outfp->wldp_buf))->wl_essid_length = 29273737Shx147065 status_p->an_ssidlen; 29283737Shx147065 bcopy(status_p->an_ssid, buf + WIFI_BUF_OFFSET + 29293737Shx147065 offsetof(wl_essid_t, wl_essid_essid), 29303737Shx147065 status_p->an_ssidlen); 29313737Shx147065 outfp->wldp_result = WL_SUCCESS; 29323737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 29333737Shx147065 bzero(ssidlist_p, sizeof (*ssidlist_p)); 29343737Shx147065 value = ((wl_essid_t *)(infp->wldp_buf))->wl_essid_essid; 29353737Shx147065 (void) strncpy(ssidlist_p->an_ssid1, value, 29363737Shx147065 MIN(32, strlen(value))); 29373737Shx147065 ssidlist_p->an_ssid1_len = strlen(value); 29383737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 29393737Shx147065 outfp->wldp_result = WL_SUCCESS; 29403737Shx147065 } else { 29413737Shx147065 kmem_free(buf, MAX_BUF_LEN); 29423737Shx147065 return (EINVAL); 29433737Shx147065 } 29443737Shx147065 done: 29453737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) { 29463737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 29473737Shx147065 } 29483737Shx147065 iret = (int)(outfp->wldp_result); 29493737Shx147065 kmem_free(buf, MAX_BUF_LEN); 29503737Shx147065 return (iret); 29513737Shx147065 } 29523737Shx147065 29533737Shx147065 static int 29543737Shx147065 pcan_cfg_bssid(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 29553737Shx147065 { 29563737Shx147065 uint16_t i; 29573737Shx147065 wldp_t *infp; 29583737Shx147065 wldp_t *outfp; 29593737Shx147065 char *buf; 29603737Shx147065 wl_bssid_t *value; 29613737Shx147065 int iret; 29623737Shx147065 struct an_ltv_status *status_p; 29633737Shx147065 struct an_ltv_aplist *aplist_p; 29643737Shx147065 29653737Shx147065 status_p = &pcan_p->an_status; 29663737Shx147065 aplist_p = &pcan_p->an_aplist; 29673737Shx147065 29683737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 29693737Shx147065 if (buf == NULL) { 29703737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_bssid: failed to alloc " 29713737Shx147065 "memory(%d)\n", MAX_BUF_LEN)); 29723737Shx147065 return (ENOMEM); 29733737Shx147065 } 29743737Shx147065 outfp = (wldp_t *)buf; 29753737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 29763737Shx147065 infp = (wldp_t *)mp->b_rptr; 29773737Shx147065 29783737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_bssid_t); 29793737Shx147065 29803737Shx147065 if (cmd == WLAN_GET_PARAM) { 29813737Shx147065 if (pcan_status_ltv(PCAN_READ_LTV, pcan_p, status_p)) { 29823737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 29833737Shx147065 outfp->wldp_result = WL_HW_ERROR; 29843737Shx147065 goto done; 29853737Shx147065 } 29863737Shx147065 29873737Shx147065 bcopy(status_p->an_cur_bssid, buf + WIFI_BUF_OFFSET, 29883737Shx147065 sizeof (wl_bssid_t)); 29893737Shx147065 outfp->wldp_result = WL_SUCCESS; 29903737Shx147065 PCANDBG((CE_CONT, 29913737Shx147065 "pcan: cfg_bssid: bssid=%x %x %x %x %x %x\n", 29923737Shx147065 status_p->an_cur_bssid[0], 29933737Shx147065 status_p->an_cur_bssid[1], 29943737Shx147065 status_p->an_cur_bssid[2], 29953737Shx147065 status_p->an_cur_bssid[3], 29963737Shx147065 status_p->an_cur_bssid[4], 29973737Shx147065 status_p->an_cur_bssid[5])); 29983737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 29993737Shx147065 value = (wl_bssid_t *)(infp->wldp_buf); 30003737Shx147065 (void) strncpy((char *)aplist_p->an_ap1, (char *)value, 6); 30013737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 30023737Shx147065 outfp->wldp_result = WL_SUCCESS; 30033737Shx147065 } else { 30043737Shx147065 kmem_free(buf, MAX_BUF_LEN); 30053737Shx147065 return (EINVAL); 30063737Shx147065 } 30073737Shx147065 done: 30083737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) { 30093737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 30103737Shx147065 } 30113737Shx147065 iret = (int)(outfp->wldp_result); 30123737Shx147065 kmem_free(buf, MAX_BUF_LEN); 30133737Shx147065 return (iret); 30143737Shx147065 } 30153737Shx147065 30163737Shx147065 /*ARGSUSED*/ 30173737Shx147065 static int 30183737Shx147065 pcan_cmd_scan(pcan_maci_t *pcan_p) 30193737Shx147065 { 30203737Shx147065 uint16_t i = 0, j, ret = WL_SUCCESS; 30213737Shx147065 uint8_t bssid_t[6]; 30223737Shx147065 uint32_t check_num, enable; 30233737Shx147065 an_scan_list_t *scan_item0; 30243737Shx147065 30253737Shx147065 enable = pcan_p->pcan_flag & PCAN_ENABLED; 30263737Shx147065 if ((!enable) && 30273737Shx147065 (ret = pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0))) { 30283737Shx147065 ret = (int)WL_HW_ERROR; 30293737Shx147065 goto exit; 30303737Shx147065 } 30313737Shx147065 if (ret = pcan_set_cmd(pcan_p, AN_CMD_SCAN, 0)) { 30323737Shx147065 ret = (int)WL_HW_ERROR; 30333737Shx147065 goto exit; 30343737Shx147065 } 30353737Shx147065 30363737Shx147065 pcan_delay(pcan_p, 500000); 30373737Shx147065 ret = pcan_scanresult_ltv(PCAN_READ_LTV, 30383737Shx147065 pcan_p, AN_RID_ESSIDLIST_FIRST, &pcan_p->an_scanresult[i]); 30393737Shx147065 if ((ret) || pcan_p->an_scanresult[i].an_index == 0xffff) { 30403737Shx147065 goto done; 30413737Shx147065 } 30423737Shx147065 do 30433737Shx147065 { 30443737Shx147065 i++; 30453737Shx147065 ret = pcan_scanresult_ltv(PCAN_READ_LTV, 30463737Shx147065 pcan_p, AN_RID_ESSIDLIST_NEXT, &pcan_p->an_scanresult[i]); 30473737Shx147065 } while ((!ret) && (i < 32) && 30483737Shx147065 (pcan_p->an_scanresult[i].an_index != 0xffff)); 30493737Shx147065 done: 30503737Shx147065 if ((!enable) && 30513737Shx147065 (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0))) { 30523737Shx147065 ret = (int)WL_HW_ERROR; 30533737Shx147065 goto exit; 30543737Shx147065 } 30553737Shx147065 /* record the scan result for future use */ 30563737Shx147065 bzero(bssid_t, sizeof (bssid_t)); 30573737Shx147065 for (j = 0; j < i; j++) { 30583737Shx147065 /* 30593737Shx147065 * sometimes, those empty items are recorded by hardware, 30603737Shx147065 * this is wrong, just ignore those items here. 30613737Shx147065 */ 30623737Shx147065 if (bcmp(pcan_p->an_scanresult[j].an_bssid, 30633737Shx147065 bssid_t, 6) == 0) { 30643737Shx147065 continue; 30653737Shx147065 } 30663737Shx147065 /* 30673737Shx147065 * save/update the scan item in scanlist 30683737Shx147065 */ 30693737Shx147065 mutex_enter(&pcan_p->pcan_scanlist_lock); 30703737Shx147065 check_num = 0; 30713737Shx147065 scan_item0 = list_head(&pcan_p->an_scan_list); 30723737Shx147065 if (scan_item0 == NULL) { 30733737Shx147065 if (pcan_add_scan_item(pcan_p, 30743737Shx147065 pcan_p->an_scanresult[j]) != 0) { 30753737Shx147065 mutex_exit(&pcan_p->pcan_scanlist_lock); 30763737Shx147065 return (WL_SUCCESS); 30773737Shx147065 } 30783737Shx147065 } 30793737Shx147065 for (; scan_item0; ) { 30803737Shx147065 if (bcmp(pcan_p->an_scanresult[j].an_bssid, 30813737Shx147065 scan_item0->an_val.an_bssid, 6) == 0) { 30823737Shx147065 scan_item0->an_val = pcan_p->an_scanresult[j]; 30833737Shx147065 scan_item0->an_timeout = AN_SCAN_TIMEOUT_MAX; 30843737Shx147065 break; 30853737Shx147065 } else { 30863737Shx147065 check_num++; 30873737Shx147065 } 30883737Shx147065 scan_item0 = list_next(&pcan_p->an_scan_list, 30893737Shx147065 scan_item0); 30903737Shx147065 } 30913737Shx147065 if (check_num == pcan_p->an_scan_num) { 30923737Shx147065 if (pcan_add_scan_item(pcan_p, 30933737Shx147065 pcan_p->an_scanresult[j]) != 0) { 30943737Shx147065 mutex_exit(&pcan_p->pcan_scanlist_lock); 30953737Shx147065 return (WL_SUCCESS); 30963737Shx147065 } 30973737Shx147065 } 30983737Shx147065 mutex_exit(&pcan_p->pcan_scanlist_lock); 30993737Shx147065 } 31003737Shx147065 exit: 31013737Shx147065 if (ret) 31024343Sgd78059 cmn_err(CE_WARN, "pcan: scan failed due to hardware error"); 31033737Shx147065 return (ret); 31043737Shx147065 } 31053737Shx147065 31063737Shx147065 /*ARGSUSED*/ 31073737Shx147065 static int 31083737Shx147065 pcan_cfg_scan(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 31093737Shx147065 { 31103737Shx147065 wl_ess_conf_t *p_ess_conf; 31113737Shx147065 wldp_t *outfp; 31123737Shx147065 char *buf; 31133737Shx147065 uint16_t i; 31143737Shx147065 an_scan_list_t *scan_item; 31153737Shx147065 31163737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 31173737Shx147065 if (buf == NULL) { 31183737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_scanlist: failed to alloc " 31193737Shx147065 "memory(%d)\n", MAX_BUF_LEN)); 31203737Shx147065 return (ENOMEM); 31213737Shx147065 } 31223737Shx147065 outfp = (wldp_t *)buf; 31233737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 31243737Shx147065 31253737Shx147065 mutex_enter(&pcan_p->pcan_scanlist_lock); 31263737Shx147065 ((wl_ess_list_t *)(outfp->wldp_buf))->wl_ess_list_num = 31273737Shx147065 pcan_p->an_scan_num; 31283737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 31293737Shx147065 offsetof(wl_ess_list_t, wl_ess_list_ess) + 31303737Shx147065 pcan_p->an_scan_num * sizeof (wl_ess_conf_t); 31313737Shx147065 31323737Shx147065 scan_item = list_head(&pcan_p->an_scan_list); 31333737Shx147065 for (i = 0; i < pcan_p->an_scan_num; i++) { 31343737Shx147065 if (!scan_item) 31353737Shx147065 goto done; 31363737Shx147065 31373737Shx147065 p_ess_conf = (wl_ess_conf_t *)(buf + WIFI_BUF_OFFSET + 31383737Shx147065 offsetof(wl_ess_list_t, wl_ess_list_ess) + 31393737Shx147065 i * sizeof (wl_ess_conf_t)); 31403737Shx147065 bcopy(scan_item->an_val.an_ssid, 31413737Shx147065 p_ess_conf->wl_ess_conf_essid.wl_essid_essid, 31423737Shx147065 mi_strlen(scan_item->an_val.an_ssid)); 31433737Shx147065 bcopy(scan_item->an_val.an_bssid, 31443737Shx147065 p_ess_conf->wl_ess_conf_bssid, 6); 31453737Shx147065 (p_ess_conf->wl_phy_conf).wl_phy_dsss_conf.wl_dsss_subtype 31463737Shx147065 = WL_DSSS; 31473737Shx147065 p_ess_conf->wl_ess_conf_wepenabled = 31483737Shx147065 (scan_item->an_val.an_cap & 0x10 ? 31493737Shx147065 WL_ENC_WEP : WL_NOENCRYPTION); 31503737Shx147065 p_ess_conf->wl_ess_conf_bsstype = 31513737Shx147065 (scan_item->an_val.an_cap & 0x1 ? 31523737Shx147065 WL_BSS_BSS : WL_BSS_IBSS); 31533737Shx147065 p_ess_conf->wl_phy_conf.wl_phy_dsss_conf.wl_dsss_channel = 31543737Shx147065 scan_item->an_val.an_dschannel; 31553737Shx147065 p_ess_conf->wl_ess_conf_sl = 15 - 31563737Shx147065 ((scan_item->an_val.an_rssi & 0xff) * 15 / 128); 31573737Shx147065 p_ess_conf->wl_supported_rates[0] = WL_RATE_1M; 31583737Shx147065 p_ess_conf->wl_supported_rates[1] = WL_RATE_2M; 31593737Shx147065 p_ess_conf->wl_supported_rates[2] = WL_RATE_5_5M; 31603737Shx147065 p_ess_conf->wl_supported_rates[3] = WL_RATE_11M; 31613737Shx147065 scan_item = list_next(&pcan_p->an_scan_list, scan_item); 31623737Shx147065 } 31633737Shx147065 done: 31643737Shx147065 mutex_exit(&pcan_p->pcan_scanlist_lock); 31653737Shx147065 outfp->wldp_result = WL_SUCCESS; 31663737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 31673737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 31683737Shx147065 kmem_free(buf, MAX_BUF_LEN); 31693737Shx147065 return (WL_SUCCESS); 31703737Shx147065 } 31713737Shx147065 31723737Shx147065 /*ARGSUSED*/ 31733737Shx147065 static int 31743737Shx147065 pcan_cfg_linkstatus(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 31753737Shx147065 { 31763737Shx147065 wldp_t *outfp; 31773737Shx147065 char *buf; 31783737Shx147065 uint16_t i; 31793737Shx147065 31803737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 31813737Shx147065 if (buf == NULL) { 31823737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_linkstatus: failed to alloc " 31833737Shx147065 "memory(%d)\n", MAX_BUF_LEN)); 31843737Shx147065 return (ENOMEM); 31853737Shx147065 } 31863737Shx147065 outfp = (wldp_t *)buf; 31873737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 31883737Shx147065 31893737Shx147065 if (pcan_p->pcan_flag & PCAN_CARD_LINKUP) 31903737Shx147065 *(wl_linkstatus_t *)(outfp->wldp_buf) = WL_CONNECTED; 31913737Shx147065 else 31923737Shx147065 *(wl_linkstatus_t *)(outfp->wldp_buf) = WL_NOTCONNECTED; 31933737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_encryption_t); 31943737Shx147065 outfp->wldp_result = WL_SUCCESS; 31953737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 31963737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 31973737Shx147065 kmem_free(buf, MAX_BUF_LEN); 31983737Shx147065 return (WL_SUCCESS); 31993737Shx147065 } 32003737Shx147065 32013737Shx147065 static int 32023737Shx147065 pcan_cfg_bsstype(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 32033737Shx147065 { 32043737Shx147065 uint16_t i; 32053737Shx147065 wldp_t *infp; 32063737Shx147065 wldp_t *outfp; 32073737Shx147065 char *buf; 32083737Shx147065 int iret; 32093737Shx147065 struct an_ltv_genconfig *cfg_p; 32103737Shx147065 32113737Shx147065 cfg_p = &pcan_p->an_config; 32123737Shx147065 32133737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 32143737Shx147065 if (buf == NULL) { 32153737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_bsstype: failed to alloc " 32163737Shx147065 "memory(%d)\n", MAX_BUF_LEN)); 32173737Shx147065 return (ENOMEM); 32183737Shx147065 } 32193737Shx147065 outfp = (wldp_t *)buf; 32203737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 32213737Shx147065 infp = (wldp_t *)mp->b_rptr; 32223737Shx147065 32233737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_bss_type_t); 32243737Shx147065 32253737Shx147065 if (cmd == WLAN_GET_PARAM) { 32263737Shx147065 if (cfg_p->an_opmode == AN_OPMODE_INFR_STATION) { 32273737Shx147065 *(wl_bss_type_t *)(outfp->wldp_buf) = WL_BSS_BSS; 32283737Shx147065 } else if (cfg_p->an_opmode == AN_OPMODE_IBSS_ADHOC) { 32293737Shx147065 *(wl_bss_type_t *)(outfp->wldp_buf) = WL_BSS_IBSS; 32303737Shx147065 } 32313737Shx147065 outfp->wldp_result = WL_SUCCESS; 32323737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 32333737Shx147065 if (*(wl_bss_type_t *)(infp->wldp_buf) == WL_BSS_BSS) 32343737Shx147065 cfg_p->an_opmode = AN_OPMODE_INFR_STATION; 32353737Shx147065 if (*(wl_bss_type_t *)(infp->wldp_buf) == WL_BSS_IBSS) 32363737Shx147065 cfg_p->an_opmode = AN_OPMODE_IBSS_ADHOC; 32373737Shx147065 if (*(wl_bss_type_t *)(infp->wldp_buf) == WL_BSS_ANY) 32383737Shx147065 cfg_p->an_opmode = AN_OPMODE_INFR_STATION; 32393737Shx147065 cfg_p->an_assoc_timeout = 5000; 32403737Shx147065 outfp->wldp_result = WL_SUCCESS; 32413737Shx147065 } else { 32423737Shx147065 kmem_free(buf, MAX_BUF_LEN); 32433737Shx147065 return (EINVAL); 32443737Shx147065 } 32453737Shx147065 32463737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 32473737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 32483737Shx147065 iret = (int)(outfp->wldp_result); 32493737Shx147065 kmem_free(buf, MAX_BUF_LEN); 32503737Shx147065 return (iret); 32513737Shx147065 } 32523737Shx147065 32533737Shx147065 static int 32543737Shx147065 pcan_cfg_phy(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 32553737Shx147065 { 32563737Shx147065 uint16_t ret, i; 32573737Shx147065 wldp_t *infp; 32583737Shx147065 wldp_t *outfp; 32593737Shx147065 char *buf; 32603737Shx147065 int iret; 32613737Shx147065 struct an_ltv_genconfig *cfg_p; 32623737Shx147065 struct an_ltv_status *status_p; 32633737Shx147065 32643737Shx147065 cfg_p = &pcan_p->an_config; 32653737Shx147065 status_p = &pcan_p->an_status; 32663737Shx147065 32673737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 32683737Shx147065 if (buf == NULL) { 32693737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_phy: failed to alloc " 32703737Shx147065 "memory(%d)\n", MAX_BUF_LEN)); 32713737Shx147065 return (ENOMEM); 32723737Shx147065 } 32733737Shx147065 outfp = (wldp_t *)buf; 32743737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 32753737Shx147065 infp = (wldp_t *)mp->b_rptr; 32763737Shx147065 32773737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_dsss_t); 32783737Shx147065 if (cmd == WLAN_GET_PARAM) { 32793737Shx147065 if (ret = pcan_status_ltv(PCAN_READ_LTV, pcan_p, status_p)) { 32803737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 32813737Shx147065 outfp->wldp_result = WL_HW_ERROR; 32823737Shx147065 goto done; 32833737Shx147065 } 32843737Shx147065 ((wl_dsss_t *)(outfp->wldp_buf))->wl_dsss_channel = 32853737Shx147065 status_p->an_channel_set; 32863737Shx147065 ((wl_dsss_t *)(outfp->wldp_buf))->wl_dsss_subtype = WL_DSSS; 32873737Shx147065 outfp->wldp_result = WL_SUCCESS; 32883737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 32893737Shx147065 ret = (uint16_t) 32903737Shx147065 (((wl_phy_conf_t *)(infp->wldp_buf)) 32913737Shx147065 ->wl_phy_dsss_conf.wl_dsss_channel); 32923737Shx147065 if (ret < 1 || ret > 14) { 32933737Shx147065 outfp->wldp_result = WL_NOTSUPPORTED; 32943737Shx147065 goto done; 32953737Shx147065 } 32963737Shx147065 cfg_p->an_ds_channel = ret; 32973737Shx147065 cfg_p->an_assoc_timeout = 5000; 32983737Shx147065 outfp->wldp_result = WL_SUCCESS; 32993737Shx147065 } else { 33003737Shx147065 kmem_free(buf, MAX_BUF_LEN); 33013737Shx147065 return (EINVAL); 33023737Shx147065 } 33033737Shx147065 done: 33043737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 33053737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 33063737Shx147065 iret = (int)(outfp->wldp_result); 33073737Shx147065 kmem_free(buf, MAX_BUF_LEN); 33083737Shx147065 return (iret); 33093737Shx147065 33103737Shx147065 } 33113737Shx147065 33123737Shx147065 /*ARGSUSED*/ 33133737Shx147065 static int 33143737Shx147065 pcan_cfg_desiredrates(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 33153737Shx147065 { 33163737Shx147065 uint16_t i; 33173737Shx147065 uint8_t rates = 0; 33183737Shx147065 wldp_t *infp; 33193737Shx147065 wldp_t *outfp; 33203737Shx147065 char *buf; 33213737Shx147065 int iret; 33223737Shx147065 struct an_ltv_genconfig *cfg_p; 33233737Shx147065 struct an_ltv_genconfig *actcfg_p; 33243737Shx147065 33253737Shx147065 cfg_p = &pcan_p->an_config; 33263737Shx147065 actcfg_p = &pcan_p->an_actual_config; 33273737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 33283737Shx147065 if (buf == NULL) { 33293737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_rates: failed to alloc " 33303737Shx147065 "memory(%d)\n", MAX_BUF_LEN)); 33313737Shx147065 return (ENOMEM); 33323737Shx147065 } 33333737Shx147065 outfp = (wldp_t *)buf; 33343737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 33353737Shx147065 infp = (wldp_t *)mp->b_rptr; 33363737Shx147065 33373737Shx147065 if (cmd == WLAN_GET_PARAM) { 33383737Shx147065 if (pcan_cfg_ltv(PCAN_READ_LTV, pcan_p, actcfg_p)) { 33393737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 33403737Shx147065 outfp->wldp_result = WL_HW_ERROR; 33413737Shx147065 goto done; 33423737Shx147065 } 33433737Shx147065 for (i = 0; i < sizeof (actcfg_p->an_rates); i++) { 33443737Shx147065 if (actcfg_p->an_rates[i] == 0) 33453737Shx147065 break; 33463737Shx147065 rates = MAX(rates, actcfg_p->an_rates[i]); 33473737Shx147065 } 33483737Shx147065 (((wl_rates_t *)(outfp->wldp_buf))->wl_rates_rates)[0] 33493737Shx147065 = rates; 33503737Shx147065 ((wl_rates_t *)(outfp->wldp_buf))->wl_rates_num = 1; 33513737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 33523737Shx147065 offsetof(wl_rates_t, wl_rates_rates) + sizeof (char); 33533737Shx147065 outfp->wldp_result = WL_SUCCESS; 33543737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 33553737Shx147065 bzero(cfg_p->an_rates, sizeof (cfg_p->an_rates)); 33563737Shx147065 for (i = 0; i < ((wl_rates_t *)(infp->wldp_buf))->wl_rates_num; 33573737Shx147065 i++) { 33583737Shx147065 cfg_p->an_rates[i] = (((wl_rates_t *) 33593737Shx147065 (infp->wldp_buf))->wl_rates_rates)[i]; 33603737Shx147065 } 33613737Shx147065 cfg_p->an_assoc_timeout = 5000; 33623737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 33633737Shx147065 outfp->wldp_result = WL_SUCCESS; 33643737Shx147065 } else { 33653737Shx147065 kmem_free(buf, MAX_BUF_LEN); 33663737Shx147065 return (EINVAL); 33673737Shx147065 } 33683737Shx147065 done: 33693737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 33703737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 33713737Shx147065 iret = (int)(outfp->wldp_result); 33723737Shx147065 kmem_free(buf, MAX_BUF_LEN); 33733737Shx147065 return (iret); 33743737Shx147065 } 33753737Shx147065 33763737Shx147065 /*ARGSUSED*/ 33773737Shx147065 static int 33783737Shx147065 pcan_cfg_supportrates(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 33793737Shx147065 { 33803737Shx147065 uint16_t i; 33813737Shx147065 int iret; 33823737Shx147065 wldp_t *outfp; 33833737Shx147065 char *buf; 33843737Shx147065 33853737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 33863737Shx147065 if (buf == NULL) { 33873737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_supportedrates: failed to alloc " 33883737Shx147065 "memory(%d)\n", MAX_BUF_LEN)); 33893737Shx147065 return (ENOMEM); 33903737Shx147065 } 33913737Shx147065 outfp = (wldp_t *)buf; 33923737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 33933737Shx147065 33943737Shx147065 if (cmd == WLAN_GET_PARAM) { 33953737Shx147065 ((wl_rates_t *)(outfp->wldp_buf))->wl_rates_num = 4; 33963737Shx147065 (((wl_rates_t *)(outfp->wldp_buf))->wl_rates_rates)[0] 33973737Shx147065 = WL_RATE_1M; 33983737Shx147065 (((wl_rates_t *)(outfp->wldp_buf))->wl_rates_rates)[1] 33993737Shx147065 = WL_RATE_2M; 34003737Shx147065 (((wl_rates_t *)(outfp->wldp_buf))->wl_rates_rates)[2] 34013737Shx147065 = WL_RATE_5_5M; 34023737Shx147065 (((wl_rates_t *)(outfp->wldp_buf))->wl_rates_rates)[3] 34033737Shx147065 = WL_RATE_11M; 34043737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 34053737Shx147065 offsetof(wl_rates_t, wl_rates_rates) + 34063737Shx147065 4 * sizeof (char); 34073737Shx147065 outfp->wldp_result = WL_SUCCESS; 34083737Shx147065 } else { 34093737Shx147065 kmem_free(buf, MAX_BUF_LEN); 34103737Shx147065 return (EINVAL); 34113737Shx147065 } 34123737Shx147065 done: 34133737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 34143737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 34153737Shx147065 iret = (int)(outfp->wldp_result); 34163737Shx147065 kmem_free(buf, MAX_BUF_LEN); 34173737Shx147065 return (iret); 34183737Shx147065 } 34193737Shx147065 34203737Shx147065 /*ARGSUSED*/ 34213737Shx147065 static int 34223737Shx147065 pcan_cfg_powermode(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 34233737Shx147065 { 34243737Shx147065 uint16_t i; 34253737Shx147065 wldp_t *outfp; 34263737Shx147065 char *buf; 34273737Shx147065 int iret; 34283737Shx147065 struct an_ltv_genconfig *actcfg_p; 34293737Shx147065 34303737Shx147065 actcfg_p = &pcan_p->an_actual_config; 34313737Shx147065 34323737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 34333737Shx147065 if (buf == NULL) { 34343737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_powermode: failed to alloc " 34353737Shx147065 "memory(%d)\n", MAX_BUF_LEN)); 34363737Shx147065 return (ENOMEM); 34373737Shx147065 } 34383737Shx147065 outfp = (wldp_t *)buf; 34393737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 34403737Shx147065 34413737Shx147065 if (cmd == WLAN_GET_PARAM) { 34423737Shx147065 if (pcan_cfg_ltv(PCAN_READ_LTV, pcan_p, actcfg_p)) { 34433737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 34443737Shx147065 outfp->wldp_result = WL_HW_ERROR; 34453737Shx147065 goto done; 34463737Shx147065 } 34473737Shx147065 ((wl_ps_mode_t *)(outfp->wldp_buf))->wl_ps_mode = 34483737Shx147065 actcfg_p->an_psave_mode; 34493737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 34503737Shx147065 sizeof (wl_ps_mode_t); 34513737Shx147065 outfp->wldp_result = WL_SUCCESS; 34523737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 34533737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 34543737Shx147065 outfp->wldp_result = WL_LACK_FEATURE; 34553737Shx147065 } else { 34563737Shx147065 kmem_free(buf, MAX_BUF_LEN); 34573737Shx147065 return (EINVAL); 34583737Shx147065 } 34593737Shx147065 done: 34603737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 34613737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 34623737Shx147065 iret = (int)(outfp->wldp_result); 34633737Shx147065 kmem_free(buf, MAX_BUF_LEN); 34643737Shx147065 return (iret); 34653737Shx147065 34663737Shx147065 } 34673737Shx147065 34683737Shx147065 static int 34693737Shx147065 pcan_cfg_authmode(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 34703737Shx147065 { 34713737Shx147065 uint16_t i; 34723737Shx147065 wldp_t *outfp; 34733737Shx147065 char *buf; 34743737Shx147065 int iret; 34753737Shx147065 struct an_ltv_genconfig *cfg_p; 34763737Shx147065 struct an_ltv_genconfig *actcfg_p; 34773737Shx147065 34783737Shx147065 cfg_p = &pcan_p->an_config; 34793737Shx147065 actcfg_p = &pcan_p->an_actual_config; 34803737Shx147065 34813737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 34823737Shx147065 if (buf == NULL) { 34833737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_autymode: failed to alloc " 34843737Shx147065 "memory(%d)\n", MAX_BUF_LEN)); 34853737Shx147065 return (ENOMEM); 34863737Shx147065 } 34873737Shx147065 outfp = (wldp_t *)buf; 34883737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 34893737Shx147065 34903737Shx147065 if (cmd == WLAN_GET_PARAM) { 34913737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_authmode_t); 34923737Shx147065 if (cfg_p->an_authtype & AN_AUTHTYPE_SHAREDKEY) { 34933737Shx147065 *(wl_bss_type_t *)(outfp->wldp_buf) = WL_SHAREDKEY; 34943737Shx147065 } else { 34953737Shx147065 *(wl_bss_type_t *)(outfp->wldp_buf) = WL_OPENSYSTEM; 34963737Shx147065 } 34973737Shx147065 outfp->wldp_result = WL_SUCCESS; 34983737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 34993737Shx147065 if (*(wl_authmode_t *)(outfp->wldp_buf) == WL_OPENSYSTEM) { 35003737Shx147065 cfg_p->an_authtype |= AN_AUTHTYPE_OPEN; 35013737Shx147065 cfg_p->an_assoc_timeout = 5000; 35023737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 35033737Shx147065 outfp->wldp_result = WL_SUCCESS; 35043737Shx147065 } else { 35053737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 35063737Shx147065 outfp->wldp_result = WL_LACK_FEATURE; 35073737Shx147065 } 35083737Shx147065 } else { 35093737Shx147065 kmem_free(buf, MAX_BUF_LEN); 35103737Shx147065 return (EINVAL); 35113737Shx147065 } 35123737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_authmode: actual.authmode=%x", 35133737Shx147065 actcfg_p->an_authtype)); 35143737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_authmode: actual.home_product=%x", 35153737Shx147065 actcfg_p->an_rsvd6[2])); 35163737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 35173737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 35183737Shx147065 iret = (int)(outfp->wldp_result); 35193737Shx147065 kmem_free(buf, MAX_BUF_LEN); 35203737Shx147065 return (iret); 35213737Shx147065 } 35223737Shx147065 35233737Shx147065 static int 35243737Shx147065 pcan_cfg_encryption(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 35253737Shx147065 { 35263737Shx147065 uint16_t i; 35273737Shx147065 wldp_t *outfp; 35283737Shx147065 char *buf; 35293737Shx147065 int iret; 35303737Shx147065 struct an_ltv_genconfig *cfg_p; 35313737Shx147065 35323737Shx147065 cfg_p = &pcan_p->an_config; 35333737Shx147065 35343737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 35353737Shx147065 if (buf == NULL) { 35363737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_encryption: failed to alloc " 35373737Shx147065 "memory(%d)\n", MAX_BUF_LEN)); 35383737Shx147065 return (ENOMEM); 35393737Shx147065 } 35403737Shx147065 outfp = (wldp_t *)buf; 35413737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 35423737Shx147065 35433737Shx147065 if (cmd == WLAN_GET_PARAM) { 35443737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_encryption_t); 35453737Shx147065 if (cfg_p->an_authtype & AN_AUTHTYPE_ENABLEWEP) { 35463737Shx147065 *(wl_bss_type_t *)(outfp->wldp_buf) = WL_ENC_WEP; 35473737Shx147065 } else { 35483737Shx147065 *(wl_bss_type_t *)(outfp->wldp_buf) = WL_NOENCRYPTION; 35493737Shx147065 } 35503737Shx147065 outfp->wldp_result = WL_SUCCESS; 35513737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 35523737Shx147065 if (*(wl_encryption_t *)(outfp->wldp_buf) == WL_ENC_WEP) { 35533737Shx147065 cfg_p->an_authtype |= (AN_AUTHTYPE_ENABLEWEP | 35543737Shx147065 AN_AUTHTYPE_ALLOW_UNENCRYPTED); 35553737Shx147065 pcan_p->pcan_usewep = 1; 35563737Shx147065 } 35573737Shx147065 if (*(wl_authmode_t *)(outfp->wldp_buf) == WL_NOENCRYPTION) { 35583737Shx147065 cfg_p->an_authtype &= (~(AN_AUTHTYPE_ENABLEWEP | 35593737Shx147065 AN_AUTHTYPE_ALLOW_UNENCRYPTED)); 35603737Shx147065 pcan_p->pcan_usewep = 0; 35613737Shx147065 } 35623737Shx147065 cfg_p->an_assoc_timeout = 5000; 35633737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 35643737Shx147065 outfp->wldp_result = WL_SUCCESS; 35653737Shx147065 } else { 35663737Shx147065 kmem_free(buf, MAX_BUF_LEN); 35673737Shx147065 return (EINVAL); 35683737Shx147065 } 35693737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 35703737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 35713737Shx147065 iret = (int)(outfp->wldp_result); 35723737Shx147065 kmem_free(buf, MAX_BUF_LEN); 35733737Shx147065 return (iret); 35743737Shx147065 } 35753737Shx147065 35763737Shx147065 static int 35773737Shx147065 pcan_cfg_wepkeyid(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 35783737Shx147065 { 35793737Shx147065 uint16_t i, ret; 35803737Shx147065 wldp_t *infp; 35813737Shx147065 wldp_t *outfp; 35823737Shx147065 char *buf; 35833737Shx147065 int iret; 35843737Shx147065 struct an_ltv_wepkey wepkey; 35853737Shx147065 35863737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 35873737Shx147065 if (buf == NULL) { 35883737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_wepkeyid: failed to alloc " 35893737Shx147065 "memory(%d)\n", MAX_BUF_LEN)); 35903737Shx147065 return (ENOMEM); 35913737Shx147065 } 35923737Shx147065 outfp = (wldp_t *)buf; 35933737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 35943737Shx147065 infp = (wldp_t *)mp->b_rptr; 35953737Shx147065 35963737Shx147065 if (cmd == WLAN_GET_PARAM) { 35973737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_wep_key_id_t); 35983737Shx147065 outfp->wldp_result = WL_SUCCESS; 35993737Shx147065 *(wl_wep_key_id_t *)(outfp->wldp_buf) = pcan_p->an_cur_wepkey; 36003737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 36013737Shx147065 ret = (uint16_t)(*(wl_wep_key_id_t *)(infp->wldp_buf)); 36023737Shx147065 if (ret > 3) { 36033737Shx147065 kmem_free(buf, MAX_BUF_LEN); 36043737Shx147065 return (EINVAL); 36053737Shx147065 } 36063737Shx147065 wepkey.an_index = 0xffff; 36073737Shx147065 wepkey.an_macaddr[0] = ret & 0xff; 36083737Shx147065 pcan_p->an_cur_wepkey = ret; 36093737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 36103737Shx147065 outfp->wldp_result = WL_SUCCESS; 36113737Shx147065 } else { 36123737Shx147065 kmem_free(buf, MAX_BUF_LEN); 36133737Shx147065 return (EINVAL); 36143737Shx147065 } 36153737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 36163737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 36173737Shx147065 iret = (int)(outfp->wldp_result); 36183737Shx147065 kmem_free(buf, MAX_BUF_LEN); 36193737Shx147065 return (iret); 36203737Shx147065 } 36213737Shx147065 36223737Shx147065 /*ARGSUSED*/ 36233737Shx147065 static int 36243737Shx147065 pcan_cfg_createibss(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 36253737Shx147065 { 36263737Shx147065 uint16_t i; 36273737Shx147065 wldp_t *outfp; 36283737Shx147065 char *buf; 36293737Shx147065 int iret; 36303737Shx147065 36313737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 36323737Shx147065 if (buf == NULL) { 36333737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_createibss: failed to alloc " 36343737Shx147065 "memory(%d)\n", MAX_BUF_LEN)); 36353737Shx147065 return (ENOMEM); 36363737Shx147065 } 36373737Shx147065 outfp = (wldp_t *)buf; 36383737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 36393737Shx147065 36403737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_create_ibss_t); 36413737Shx147065 outfp->wldp_result = WL_LACK_FEATURE; 36423737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 36433737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 36443737Shx147065 iret = (int)(outfp->wldp_result); 36453737Shx147065 kmem_free(buf, MAX_BUF_LEN); 36463737Shx147065 return (iret); 36473737Shx147065 } 36483737Shx147065 36493737Shx147065 static int 36503737Shx147065 pcan_cfg_rssi(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 36513737Shx147065 { 36523737Shx147065 uint16_t i, val; 36533737Shx147065 int iret; 36543737Shx147065 wldp_t *outfp; 36553737Shx147065 char *buf; 36563737Shx147065 struct an_ltv_status *status_p; 36573737Shx147065 status_p = &pcan_p->an_status; 36583737Shx147065 36593737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 36603737Shx147065 if (buf == NULL) { 36613737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_rssi: failed to alloc " 36623737Shx147065 "memory(%d)\n", MAX_BUF_LEN)); 36633737Shx147065 return (ENOMEM); 36643737Shx147065 } 36653737Shx147065 outfp = (wldp_t *)buf; 36663737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 36673737Shx147065 36683737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_rssi_t); 36693737Shx147065 36703737Shx147065 if (cmd == WLAN_GET_PARAM) { 36713737Shx147065 if (val = pcan_status_ltv(PCAN_READ_LTV, pcan_p, status_p)) { 36723737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 36733737Shx147065 outfp->wldp_result = WL_HW_ERROR; 36743737Shx147065 goto done; 36753737Shx147065 } 36763737Shx147065 val = status_p->an_cur_signal_quality; 36773737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_rssi: sl=%x", val)); 36783737Shx147065 /* 36793737Shx147065 * we reflect the value to 1-15 as rssi 36803737Shx147065 */ 36813737Shx147065 *(wl_rssi_t *)(outfp->wldp_buf) = 15 - 36823737Shx147065 ((val & 0xff) * 15 / 128 + 1); 36833737Shx147065 outfp->wldp_result = WL_SUCCESS; 36843737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 36853737Shx147065 outfp->wldp_result = WL_READONLY; 36863737Shx147065 } else { 36873737Shx147065 kmem_free(buf, MAX_BUF_LEN); 36883737Shx147065 return (EINVAL); 36893737Shx147065 } 36903737Shx147065 done: 36913737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 36923737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 36933737Shx147065 iret = (int)(outfp->wldp_result); 36943737Shx147065 kmem_free(buf, MAX_BUF_LEN); 36953737Shx147065 return (iret); 36963737Shx147065 } 36973737Shx147065 36983737Shx147065 /*ARGSUSED*/ 36993737Shx147065 static int 37003737Shx147065 pcan_cfg_radio(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 37013737Shx147065 { 37023737Shx147065 uint16_t i; 37033737Shx147065 int iret; 37043737Shx147065 wldp_t *outfp; 37053737Shx147065 char *buf; 37063737Shx147065 37073737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 37083737Shx147065 if (buf == NULL) { 37093737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_radio: failed to alloc " 37103737Shx147065 "memory(%d)\n", MAX_BUF_LEN)); 37113737Shx147065 return (ENOMEM); 37123737Shx147065 } 37133737Shx147065 outfp = (wldp_t *)buf; 37143737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 37153737Shx147065 37163737Shx147065 if (cmd == WLAN_GET_PARAM) { 37173737Shx147065 *(wl_radio_t *)(outfp->wldp_buf) = B_TRUE; 37183737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_radio_t); 37193737Shx147065 outfp->wldp_result = WL_SUCCESS; 37203737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 37213737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 37223737Shx147065 outfp->wldp_result = WL_LACK_FEATURE; 37233737Shx147065 } else { 37243737Shx147065 kmem_free(buf, MAX_BUF_LEN); 37253737Shx147065 return (EINVAL); 37263737Shx147065 } 37273737Shx147065 37283737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 37293737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 37303737Shx147065 iret = (int)(outfp->wldp_result); 37313737Shx147065 kmem_free(buf, MAX_BUF_LEN); 37323737Shx147065 return (iret); 37333737Shx147065 } 37343737Shx147065 37353737Shx147065 static int 37363737Shx147065 pcan_cfg_wepkey(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 37373737Shx147065 { 37383737Shx147065 uint16_t i; 37393737Shx147065 wl_wep_key_t *p_wepkey_tab; 37403737Shx147065 wldp_t *outfp; 37413737Shx147065 char *buf; 37423737Shx147065 int iret; 37433737Shx147065 wldp_t *infp; 37443737Shx147065 struct an_ltv_wepkey *wepkey_p; 37453737Shx147065 37463737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 37473737Shx147065 if (buf == NULL) { 37483737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_wep: failed to alloc " 37493737Shx147065 "memory(%d)\n", MAX_BUF_LEN)); 37503737Shx147065 return (ENOMEM); 37513737Shx147065 } 37523737Shx147065 outfp = (wldp_t *)buf; 37533737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 37543737Shx147065 infp = (wldp_t *)mp->b_rptr; 37553737Shx147065 37563737Shx147065 if (cmd == WLAN_GET_PARAM) { 37573737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 37583737Shx147065 sizeof (wl_wep_key_tab_t); 37593737Shx147065 outfp->wldp_result = WL_WRITEONLY; 37603737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 37613737Shx147065 p_wepkey_tab = (wl_wep_key_t *)(infp->wldp_buf); 37623737Shx147065 for (i = 0; i < MAX_NWEPKEYS; i++) { 37633737Shx147065 if (p_wepkey_tab[i].wl_wep_operation == WL_ADD) { 37643737Shx147065 wepkey_p = &pcan_p->an_wepkey[i]; 37653737Shx147065 bzero(wepkey_p, sizeof (*wepkey_p)); 37663737Shx147065 wepkey_p->an_keylen = 37674343Sgd78059 p_wepkey_tab[i].wl_wep_length; 37683737Shx147065 bcopy(p_wepkey_tab[i].wl_wep_key, 37694343Sgd78059 wepkey_p->an_key, 37704343Sgd78059 p_wepkey_tab[i].wl_wep_length); 37713737Shx147065 wepkey_p->an_index = i; 37723737Shx147065 wepkey_p->an_macaddr[0] = 1; 37733737Shx147065 } 37743737Shx147065 } 37753737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 37763737Shx147065 outfp->wldp_result = WL_SUCCESS; 37773737Shx147065 } else { 37783737Shx147065 kmem_free(buf, MAX_BUF_LEN); 37793737Shx147065 return (EINVAL); 37803737Shx147065 } 37813737Shx147065 37823737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 37833737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 37843737Shx147065 iret = (int)(outfp->wldp_result); 37853737Shx147065 kmem_free(buf, MAX_BUF_LEN); 37863737Shx147065 return (iret); 37873737Shx147065 } 37883737Shx147065 37893737Shx147065 static void 37903737Shx147065 pcan_connect_timeout(void *arg) 37913737Shx147065 { 37923737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 37933737Shx147065 uint16_t ret; 37943737Shx147065 37953737Shx147065 mutex_enter(&pcan_p->pcan_glock); 37963737Shx147065 if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) 37973737Shx147065 goto done; 37983737Shx147065 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP; 37993737Shx147065 if (ret = pcan_config_mac(pcan_p)) 38003737Shx147065 goto done; 38013737Shx147065 ret = pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0); 38023737Shx147065 done: 38033737Shx147065 if (ret) 38044343Sgd78059 cmn_err(CE_WARN, "pcan: connect failed due to hardware error"); 38053737Shx147065 mutex_exit(&pcan_p->pcan_glock); 38063737Shx147065 pcan_p->pcan_connect_timeout_id = 0; 38073737Shx147065 } 38083737Shx147065 38093737Shx147065 static int 38103737Shx147065 pcan_getset(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 38113737Shx147065 { 38123737Shx147065 int ret = WL_SUCCESS; 38133737Shx147065 int connect = 0; 38143737Shx147065 38153737Shx147065 mutex_enter(&pcan_p->pcan_glock); 38163737Shx147065 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) { 38173737Shx147065 mutex_exit(&pcan_p->pcan_glock); 38183737Shx147065 return (PCAN_FAIL); 38193737Shx147065 } 38203737Shx147065 38213737Shx147065 switch (((wldp_t *)mp->b_rptr)->wldp_id) { 38223737Shx147065 case WL_ESSID: 38233737Shx147065 ret = pcan_cfg_essid(mp, pcan_p, cmd); 38243737Shx147065 connect = 1; 38253737Shx147065 PCANDBG((CE_NOTE, "cfg_essid\n")); 38263737Shx147065 break; 38273737Shx147065 case WL_BSSID: 38283737Shx147065 ret = pcan_cfg_bssid(mp, pcan_p, cmd); 38293737Shx147065 connect = 1; 38303737Shx147065 PCANDBG((CE_NOTE, "cfg_bssid\n")); 38313737Shx147065 break; 38323737Shx147065 case WL_ESS_LIST: 38333737Shx147065 ret = pcan_cfg_scan(mp, pcan_p, cmd); 38343737Shx147065 PCANDBG((CE_NOTE, "cfg_scan\n")); 38353737Shx147065 break; 38363737Shx147065 case WL_LINKSTATUS: 38373737Shx147065 ret = pcan_cfg_linkstatus(mp, pcan_p, cmd); 38383737Shx147065 PCANDBG((CE_NOTE, "cfg_linkstatus\n")); 38393737Shx147065 break; 38403737Shx147065 case WL_BSS_TYPE: 38413737Shx147065 ret = pcan_cfg_bsstype(mp, pcan_p, cmd); 38423737Shx147065 connect = 1; 38433737Shx147065 PCANDBG((CE_NOTE, "cfg_bsstype\n")); 38443737Shx147065 break; 38453737Shx147065 case WL_PHY_CONFIG: 38463737Shx147065 ret = pcan_cfg_phy(mp, pcan_p, cmd); 38473737Shx147065 connect = 1; 38483737Shx147065 PCANDBG((CE_NOTE, "cfg_phy\n")); 38493737Shx147065 break; 38503737Shx147065 case WL_DESIRED_RATES: 38513737Shx147065 ret = pcan_cfg_desiredrates(mp, pcan_p, cmd); 38523737Shx147065 connect = 1; 38533737Shx147065 PCANDBG((CE_NOTE, "cfg_disred-rates\n")); 38543737Shx147065 break; 38553737Shx147065 case WL_SUPPORTED_RATES: 38563737Shx147065 ret = pcan_cfg_supportrates(mp, pcan_p, cmd); 38573737Shx147065 PCANDBG((CE_NOTE, "cfg_supported-rates\n")); 38583737Shx147065 break; 38593737Shx147065 case WL_POWER_MODE: 38603737Shx147065 ret = pcan_cfg_powermode(mp, pcan_p, cmd); 38613737Shx147065 PCANDBG((CE_NOTE, "cfg_powermode\n")); 38623737Shx147065 break; 38633737Shx147065 case WL_AUTH_MODE: 38643737Shx147065 ret = pcan_cfg_authmode(mp, pcan_p, cmd); 38653737Shx147065 connect = 1; 38663737Shx147065 PCANDBG((CE_NOTE, "cfg_authmode\n")); 38673737Shx147065 break; 38683737Shx147065 case WL_ENCRYPTION: 38693737Shx147065 ret = pcan_cfg_encryption(mp, pcan_p, cmd); 38703737Shx147065 connect = 1; 38713737Shx147065 PCANDBG((CE_NOTE, "cfg_encryption\n")); 38723737Shx147065 break; 38733737Shx147065 case WL_WEP_KEY_ID: 38743737Shx147065 ret = pcan_cfg_wepkeyid(mp, pcan_p, cmd); 38753737Shx147065 connect = 1; 38763737Shx147065 PCANDBG((CE_NOTE, "cfg_wepkeyid\n")); 38773737Shx147065 break; 38783737Shx147065 case WL_CREATE_IBSS: 38793737Shx147065 ret = pcan_cfg_createibss(mp, pcan_p, cmd); 38803737Shx147065 connect = 1; 38813737Shx147065 PCANDBG((CE_NOTE, "cfg_create-ibss\n")); 38823737Shx147065 break; 38833737Shx147065 case WL_RSSI: 38843737Shx147065 ret = pcan_cfg_rssi(mp, pcan_p, cmd); 38853737Shx147065 PCANDBG((CE_NOTE, "cfg_rssi\n")); 38863737Shx147065 break; 38873737Shx147065 case WL_RADIO: 38883737Shx147065 ret = pcan_cfg_radio(mp, pcan_p, cmd); 38893737Shx147065 PCANDBG((CE_NOTE, "cfg_radio\n")); 38903737Shx147065 break; 38913737Shx147065 case WL_WEP_KEY_TAB: 38923737Shx147065 ret = pcan_cfg_wepkey(mp, pcan_p, cmd); 38933737Shx147065 connect = 1; 38943737Shx147065 PCANDBG((CE_NOTE, "cfg_wepkey\n")); 38953737Shx147065 break; 38963737Shx147065 case WL_SCAN: 38973737Shx147065 mutex_exit(&pcan_p->pcan_glock); 38983737Shx147065 if (pcan_p->pcan_connect_timeout_id != 0) { 38993737Shx147065 (void) untimeout(pcan_p->pcan_connect_timeout_id); 39003737Shx147065 pcan_p->pcan_connect_timeout_id = 0; 39013737Shx147065 } 39023737Shx147065 mutex_enter(&pcan_p->pcan_glock); 39033737Shx147065 ret = pcan_cmd_scan(pcan_p); 39043737Shx147065 /* 39053737Shx147065 * a trick here. 39063737Shx147065 * since the scan doesn't return too many items due to hardware 39073737Shx147065 * reason, so the current scan result is an accumulation of 39083737Shx147065 * several scans. For the first time or after many of the items 39093737Shx147065 * aged, we scan again if too few items now in the scan table. 39103737Shx147065 */ 39113737Shx147065 if (pcan_p->an_scan_num < AN_SCAN_AGAIN_THRESHOLD) 39123737Shx147065 ret = pcan_cmd_scan(pcan_p); 39133737Shx147065 break; 39143737Shx147065 case WL_LOAD_DEFAULTS: 39153737Shx147065 if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) { 39163737Shx147065 ret = (int)WL_HW_ERROR; 39173737Shx147065 break; 39183737Shx147065 } 39193737Shx147065 if (ret = pcan_loaddef(pcan_p)) { 39203737Shx147065 ret = (int)WL_HW_ERROR; 39213737Shx147065 break; 39223737Shx147065 } 39233737Shx147065 if (ret = pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0)) { 39243737Shx147065 ret = (int)WL_HW_ERROR; 39253737Shx147065 break; 39263737Shx147065 } 39273737Shx147065 PCANDBG((CE_NOTE, "loaddef\n")); 39283737Shx147065 break; 39293737Shx147065 case WL_DISASSOCIATE: 39303737Shx147065 mutex_exit(&pcan_p->pcan_glock); 39313737Shx147065 if (pcan_p->pcan_connect_timeout_id != 0) { 39323737Shx147065 (void) untimeout(pcan_p->pcan_connect_timeout_id); 39333737Shx147065 pcan_p->pcan_connect_timeout_id = 0; 39343737Shx147065 } 39353737Shx147065 mutex_enter(&pcan_p->pcan_glock); 39363737Shx147065 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP; 39373737Shx147065 if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) { 39383737Shx147065 ret = (int)WL_HW_ERROR; 39393737Shx147065 break; 39403737Shx147065 } 39413737Shx147065 if (ret = pcan_loaddef(pcan_p)) { 39423737Shx147065 ret = (int)WL_HW_ERROR; 39433737Shx147065 break; 39443737Shx147065 } 39453737Shx147065 PCANDBG((CE_NOTE, "disassociate\n")); 39463737Shx147065 break; 39473737Shx147065 case WL_REASSOCIATE: 39483737Shx147065 case WL_ASSOCIAT: 39493737Shx147065 mutex_exit(&pcan_p->pcan_glock); 39503737Shx147065 if (pcan_p->pcan_connect_timeout_id != 0) { 39513737Shx147065 (void) untimeout(pcan_p->pcan_connect_timeout_id); 39523737Shx147065 pcan_p->pcan_connect_timeout_id = 0; 39533737Shx147065 } 39543737Shx147065 mutex_enter(&pcan_p->pcan_glock); 39553737Shx147065 if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) { 39563737Shx147065 ret = (int)WL_HW_ERROR; 39573737Shx147065 break; 39583737Shx147065 } 39593737Shx147065 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP; 39603737Shx147065 if (ret = pcan_config_mac(pcan_p)) { 39613737Shx147065 ret = (int)WL_HW_ERROR; 39623737Shx147065 break; 39633737Shx147065 } 39643737Shx147065 if (ret = pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0)) { 39653737Shx147065 ret = (int)WL_HW_ERROR; 39663737Shx147065 break; 39673737Shx147065 } 39683737Shx147065 PCANDBG((CE_NOTE, "associate")); 39693737Shx147065 break; 39703737Shx147065 39713737Shx147065 default: 39723737Shx147065 break; 39733737Shx147065 } 39743737Shx147065 mutex_exit(&pcan_p->pcan_glock); 39753737Shx147065 if ((cmd == WLAN_SET_PARAM) && (ret == WL_SUCCESS) && (connect)) { 39763737Shx147065 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP; 39773737Shx147065 (void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0); 39783737Shx147065 if (pcan_p->pcan_connect_timeout_id != 0) { 39793737Shx147065 (void) untimeout(pcan_p->pcan_connect_timeout_id); 39803737Shx147065 pcan_p->pcan_connect_timeout_id = 0; 39813737Shx147065 } 39823737Shx147065 pcan_p->pcan_connect_timeout_id = timeout(pcan_connect_timeout, 39833737Shx147065 pcan_p, drv_usectohz(1000000)); 39843737Shx147065 } 39853737Shx147065 return (ret); 39863737Shx147065 } 39873737Shx147065 39883737Shx147065 static void 39893737Shx147065 pcan_wlan_ioctl(pcan_maci_t *pcan_p, queue_t *wq, mblk_t *mp, uint32_t cmd) 39903737Shx147065 { 39913737Shx147065 39923737Shx147065 struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 39933737Shx147065 uint32_t len, ret; 39943737Shx147065 mblk_t *mp1; 39953737Shx147065 39963737Shx147065 /* sanity check */ 39973737Shx147065 if (iocp->ioc_count == 0 || !(mp1 = mp->b_cont)) { 39983737Shx147065 miocnak(wq, mp, 0, EINVAL); 39993737Shx147065 return; 40003737Shx147065 } 40013737Shx147065 40023737Shx147065 /* assuming single data block */ 40033737Shx147065 if (mp1->b_cont) { 40043737Shx147065 freemsg(mp1->b_cont); 40053737Shx147065 mp1->b_cont = NULL; 40063737Shx147065 } 40073737Shx147065 40083737Shx147065 /* we will overwrite everything */ 40093737Shx147065 mp1->b_wptr = mp1->b_rptr; 40103737Shx147065 40113737Shx147065 ret = pcan_getset(mp1, pcan_p, cmd); 40123737Shx147065 len = msgdsize(mp1); 40133737Shx147065 miocack(wq, mp, len, ret); 40143737Shx147065 } 40153737Shx147065 40163737Shx147065 static void 40173737Shx147065 pcan_ioctl(void *arg, queue_t *wq, mblk_t *mp) 40183737Shx147065 { 40193737Shx147065 struct iocblk *iocp; 40203737Shx147065 uint32_t cmd, ret; 40213737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 40223737Shx147065 boolean_t need_privilege = B_TRUE; 40233737Shx147065 40243737Shx147065 iocp = (struct iocblk *)mp->b_rptr; 40253737Shx147065 iocp->ioc_error = 0; 40263737Shx147065 cmd = iocp->ioc_cmd; 40273737Shx147065 switch (cmd) { 40283737Shx147065 default: 40293737Shx147065 miocnak(wq, mp, 0, EINVAL); 40303737Shx147065 return; 40313737Shx147065 case WLAN_GET_PARAM: 40323737Shx147065 need_privilege = B_FALSE; 40333737Shx147065 break; 40343737Shx147065 case WLAN_SET_PARAM: 40353737Shx147065 case WLAN_COMMAND: 40363737Shx147065 break; 40373737Shx147065 } 40383737Shx147065 4039*7408SSebastien.Roy@Sun.COM if (need_privilege && (ret = secpolicy_dl_config(iocp->ioc_cr)) != 0) 4040*7408SSebastien.Roy@Sun.COM miocnak(wq, mp, 0, ret); 4041*7408SSebastien.Roy@Sun.COM else 4042*7408SSebastien.Roy@Sun.COM pcan_wlan_ioctl(pcan_p, wq, mp, cmd); 40433737Shx147065 } 4044