13737Shx147065 /* 2*8801SQuaker.Fang@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 33737Shx147065 * Use is subject to license terms. 43737Shx147065 */ 53737Shx147065 63737Shx147065 /* 73737Shx147065 * Copyright (c) 1997, 1998, 1999 83737Shx147065 * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 93737Shx147065 * 103737Shx147065 * Redistribution and use in source and binary forms, with or without 113737Shx147065 * modification, are permitted provided that the following conditions 123737Shx147065 * are met: 133737Shx147065 * 1. Redistributions of source code must retain the above copyright 143737Shx147065 * notice, this list of conditions and the following disclaimer. 153737Shx147065 * 2. Redistributions in binary form must reproduce the above copyright 163737Shx147065 * notice, this list of conditions and the following disclaimer in the 173737Shx147065 * documentation and/or other materials provided with the distribution. 183737Shx147065 * 3. All advertising materials mentioning features or use of this software 193737Shx147065 * must display the following acknowledgement: 203737Shx147065 * This product includes software developed by Bill Paul. 213737Shx147065 * 4. Neither the name of the author nor the names of any co-contributors 223737Shx147065 * may be used to endorse or promote products derived from this software 233737Shx147065 * without specific prior written permission. 243737Shx147065 * 253737Shx147065 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 263737Shx147065 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 273737Shx147065 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 283737Shx147065 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 293737Shx147065 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 303737Shx147065 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 313737Shx147065 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 323737Shx147065 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 333737Shx147065 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 343737Shx147065 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 353737Shx147065 * THE POSSIBILITY OF SUCH DAMAGE. 363737Shx147065 */ 373737Shx147065 383737Shx147065 #include <sys/conf.h> 393737Shx147065 #include <sys/ddi.h> 403737Shx147065 #include <sys/sunddi.h> 413737Shx147065 #include <sys/dlpi.h> 423737Shx147065 #include <sys/ethernet.h> 433737Shx147065 #include <sys/strsun.h> 443737Shx147065 #include <sys/stat.h> 453737Shx147065 #include <sys/byteorder.h> 463737Shx147065 #include <sys/pccard.h> 473737Shx147065 #include <sys/pci.h> 483737Shx147065 #include <sys/policy.h> 498275SEric Cheng #include <sys/mac_provider.h> 503737Shx147065 #include <sys/stream.h> 513737Shx147065 #include <inet/common.h> 523737Shx147065 #include <inet/nd.h> 533737Shx147065 #include <inet/mi.h> 543737Shx147065 553737Shx147065 #include "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 988410SWang.Lin@Sun.COM /* 998410SWang.Lin@Sun.COM * brussels 1008410SWang.Lin@Sun.COM */ 1018410SWang.Lin@Sun.COM static int pcan_m_setprop(void *arg, const char *pr_name, 1028410SWang.Lin@Sun.COM mac_prop_id_t wldp_pr_num, uint_t wldp_length, 1038410SWang.Lin@Sun.COM const void *wldp_buf); 1048410SWang.Lin@Sun.COM static int pcan_m_getprop(void *arg, const char *pr_name, 1058410SWang.Lin@Sun.COM mac_prop_id_t wldp_pr_num, uint_t pr_flags, 1068410SWang.Lin@Sun.COM uint_t wldp_length, void *wldp_buf, uint_t *perm); 1078410SWang.Lin@Sun.COM 1083737Shx147065 mac_callbacks_t pcan_m_callbacks = { 1098410SWang.Lin@Sun.COM MC_IOCTL | MC_SETPROP | MC_GETPROP, 1103737Shx147065 pcan_gstat, 1113737Shx147065 pcan_start, 1123737Shx147065 pcan_stop, 1133737Shx147065 pcan_prom, 1143737Shx147065 pcan_sdmulti, 1153737Shx147065 pcan_saddr, 1163737Shx147065 pcan_tx, 1178410SWang.Lin@Sun.COM pcan_ioctl, 1188410SWang.Lin@Sun.COM NULL, 1198410SWang.Lin@Sun.COM NULL, 1208410SWang.Lin@Sun.COM NULL, 1218410SWang.Lin@Sun.COM pcan_m_setprop, 1228410SWang.Lin@Sun.COM pcan_m_getprop 1233737Shx147065 }; 1243737Shx147065 1253737Shx147065 static char *pcan_name_str = "pcan"; 1263737Shx147065 127*8801SQuaker.Fang@Sun.COM #ifdef __sparc 128*8801SQuaker.Fang@Sun.COM #define pcan_quiesce ddi_quiesce_not_supported 129*8801SQuaker.Fang@Sun.COM #else 130*8801SQuaker.Fang@Sun.COM static int pcan_quiesce(dev_info_t *); 131*8801SQuaker.Fang@Sun.COM #endif 132*8801SQuaker.Fang@Sun.COM 1333737Shx147065 DDI_DEFINE_STREAM_OPS(pcan_dev_ops, nulldev, pcan_probe, pcan_attach, 134*8801SQuaker.Fang@Sun.COM pcan_detach, nodev, NULL, D_MP, NULL, pcan_quiesce); 1353737Shx147065 1363737Shx147065 extern struct mod_ops mod_driverops; 1373737Shx147065 static struct modldrv modldrv = { 1383737Shx147065 &mod_driverops, 1393737Shx147065 "Cisco-Aironet 802.11b driver", 1403737Shx147065 &pcan_dev_ops 1413737Shx147065 }; 1423737Shx147065 1433737Shx147065 static struct modlinkage modlinkage = { 1443737Shx147065 MODREV_1, (void *)&modldrv, NULL 1453737Shx147065 }; 1463737Shx147065 1473737Shx147065 int 1483737Shx147065 _init(void) 1493737Shx147065 { 1503737Shx147065 int stat; 1513737Shx147065 1523737Shx147065 /* Allocate soft state */ 1533737Shx147065 if ((stat = ddi_soft_state_init(&pcan_soft_state_p, 1543737Shx147065 sizeof (pcan_maci_t), 2)) != DDI_SUCCESS) 1553737Shx147065 return (stat); 1563737Shx147065 1573737Shx147065 mac_init_ops(&pcan_dev_ops, "pcan"); 1583737Shx147065 stat = mod_install(&modlinkage); 1593737Shx147065 if (stat != 0) { 1603737Shx147065 mac_fini_ops(&pcan_dev_ops); 1613737Shx147065 ddi_soft_state_fini(&pcan_soft_state_p); 1623737Shx147065 } 1633737Shx147065 1643737Shx147065 return (stat); 1653737Shx147065 } 1663737Shx147065 1673737Shx147065 int 1683737Shx147065 _fini(void) 1693737Shx147065 { 1703737Shx147065 int stat; 1713737Shx147065 1723737Shx147065 stat = mod_remove(&modlinkage); 1733737Shx147065 if (stat != DDI_SUCCESS) 1743737Shx147065 return (stat); 1753737Shx147065 mac_fini_ops(&pcan_dev_ops); 1763737Shx147065 ddi_soft_state_fini(&pcan_soft_state_p); 1773737Shx147065 return (stat); 1783737Shx147065 } 1793737Shx147065 1803737Shx147065 int 1813737Shx147065 _info(struct modinfo *modinfop) 1823737Shx147065 { 1833737Shx147065 return (mod_info(&modlinkage, modinfop)); 1843737Shx147065 } 1853737Shx147065 1863737Shx147065 static int 1873737Shx147065 pcan_probe(dev_info_t *dip) 1883737Shx147065 { 1893737Shx147065 int len, ret; 1903737Shx147065 char *buf; 1913737Shx147065 dev_info_t *pdip = ddi_get_parent(dip); 1923737Shx147065 1933737Shx147065 PCANDBG((CE_NOTE, "pcan probe: parent dip=0x%p-%s(%d)\n", (void *)pdip, 1943737Shx147065 ddi_driver_name(pdip), ddi_get_instance(pdip))); 1953737Shx147065 1963737Shx147065 ret = ddi_getlongprop(DDI_DEV_T_ANY, pdip, 0, "device_type", 1973737Shx147065 (caddr_t)&buf, &len); 1983737Shx147065 if (ret != DDI_SUCCESS) 1993737Shx147065 return (DDI_PROBE_FAILURE); 2003737Shx147065 2013737Shx147065 PCANDBG((CE_NOTE, "pcan probe: device_type %s\n", buf)); 2023737Shx147065 if ((strcmp(buf, "pccard") == 0) || (strcmp(buf, "pcmcia") == 0)) { 2033737Shx147065 pcan_device_type = PCAN_DEVICE_PCCARD; 2043737Shx147065 #ifdef DEBUG 2053737Shx147065 if (pcan_debug & PCAN_DBG_FW_VERSION) { 2063737Shx147065 cmn_err(CE_NOTE, "Cisco 802.11 pccard\n"); 2073737Shx147065 } 2083737Shx147065 #endif 2093737Shx147065 ret = DDI_PROBE_SUCCESS; 2103737Shx147065 } else if (strcmp(buf, "pci") == 0) { 2113737Shx147065 pcan_device_type = PCAN_DEVICE_PCI; 2123737Shx147065 #ifdef DEBUG 2133737Shx147065 if (pcan_debug & PCAN_DBG_FW_VERSION) { 2143737Shx147065 cmn_err(CE_NOTE, "Cisco 802.11 minipci card\n"); 2153737Shx147065 } 2163737Shx147065 #endif 2173737Shx147065 ret = DDI_PROBE_SUCCESS; 2183737Shx147065 } else { 2193737Shx147065 cmn_err(CE_NOTE, "pcan probe: unsupported card\n"); 2203737Shx147065 ret = DDI_PROBE_FAILURE; 2213737Shx147065 } 2223737Shx147065 2233737Shx147065 kmem_free(buf, len); 2243737Shx147065 return (ret); 2253737Shx147065 } 2263737Shx147065 2273737Shx147065 static int 2283737Shx147065 pcan_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2293737Shx147065 { 2303737Shx147065 int ret; 2313737Shx147065 int instance; 2323737Shx147065 uint16_t stat; 2333737Shx147065 uint32_t err; 2343737Shx147065 pcan_maci_t *pcan_p; 2353737Shx147065 wifi_data_t wd = { 0 }; 2363737Shx147065 mac_register_t *macp; 2373737Shx147065 modify_config_t cfgmod; 2383737Shx147065 char strbuf[256]; 2393737Shx147065 2403737Shx147065 PCANDBG((CE_NOTE, "dip=0x%p cmd=%x\n", (void *)dip, cmd)); 2413737Shx147065 if (cmd != DDI_ATTACH) 2423737Shx147065 goto attach_fail1; 2433737Shx147065 2443737Shx147065 /* 2453737Shx147065 * Since this driver is porting from freebsd, so just like 2463737Shx147065 * the original driver, the minipci card doesn't work on amd64 2473737Shx147065 * machine. 2483737Shx147065 * For sparc, since no pci card is available for the test, so this 2493737Shx147065 * version doesn't support sparc. If there is card available and 2503737Shx147065 * requirement, future version will try to support sparc. 2513737Shx147065 * This driver works well for minipci card on 32bit x86 2523737Shx147065 * machine, so keep the code to just support minipci card on 32bit 2533737Shx147065 * mode. 2543737Shx147065 */ 2553737Shx147065 #if defined(sparc) || defined(__sparc) 2563737Shx147065 if (pcan_device_type == PCAN_DEVICE_PCI) { 2573737Shx147065 cmn_err(CE_NOTE, "pcan attach: this driver does not support " 2583737Shx147065 "PCI/MiniPCI card on Sparc\n"); 2593737Shx147065 goto attach_fail1; 2603737Shx147065 } 2613737Shx147065 #endif /* sparc */ 2623737Shx147065 #if defined(__amd64) 2633737Shx147065 if (pcan_device_type == PCAN_DEVICE_PCI) { 2643737Shx147065 cmn_err(CE_NOTE, "pcan attach: this driver does not support " 2653737Shx147065 "PCI/MiniPCI card on amd64\n"); 2663737Shx147065 goto attach_fail1; 2673737Shx147065 } 2683737Shx147065 #endif /* amd64 */ 2693737Shx147065 2703737Shx147065 /* Allocate soft state associated with this instance. */ 2713737Shx147065 if (ddi_soft_state_zalloc(pcan_soft_state_p, 2723737Shx147065 ddi_get_instance(dip)) != DDI_SUCCESS) { 2733737Shx147065 cmn_err(CE_CONT, "pcan attach: alloc softstate failed\n"); 2743737Shx147065 goto attach_fail1; 2753737Shx147065 } 2763737Shx147065 pcan_p = (pcan_maci_t *)ddi_get_soft_state(pcan_soft_state_p, 2773737Shx147065 ddi_get_instance(dip)); 2783737Shx147065 2793737Shx147065 pcan_p->pcan_device_type = pcan_device_type; 2803737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 2813737Shx147065 if (ddi_regs_map_setup(dip, 0, 2823737Shx147065 (caddr_t *)&pcan_p->pcan_cfg_base, 0, 0, 2833737Shx147065 &accattr, &pcan_p->pcan_cfg_handle) != DDI_SUCCESS) 2843737Shx147065 goto attach_fail2; 2853737Shx147065 2863737Shx147065 stat = ddi_get16(pcan_p->pcan_cfg_handle, 2873737Shx147065 (uint16_t *)(pcan_p->pcan_cfg_base + PCI_CONF_COMM)); 2883737Shx147065 stat |= (PCI_COMM_IO | PCI_COMM_MAE); 2893737Shx147065 ddi_put16(pcan_p->pcan_cfg_handle, 2903737Shx147065 (uint16_t *)(pcan_p->pcan_cfg_base + PCI_CONF_COMM), stat); 2913737Shx147065 2923737Shx147065 ddi_regs_map_free(&pcan_p->pcan_cfg_handle); 2933737Shx147065 if (ddi_regs_map_setup(dip, 1, (caddr_t *)&pcan_p->pcan_bar0, 2943737Shx147065 0, 0, &accattr, &pcan_p->pcan_handle0) != DDI_SUCCESS) 2953737Shx147065 goto attach_fail3; 2963737Shx147065 if (ddi_regs_map_setup(dip, 2, (caddr_t *)&pcan_p->pcan_bar1, 2973737Shx147065 0, 0, &accattr, &pcan_p->pcan_handle1) != DDI_SUCCESS) 2983737Shx147065 goto attach_fail3; 2993737Shx147065 if (ddi_regs_map_setup(dip, 3, (caddr_t *)&pcan_p->pcan_bar2, 3003737Shx147065 0, 0, &accattr, &pcan_p->pcan_handle2) != DDI_SUCCESS) 3013737Shx147065 goto attach_fail3; 3023737Shx147065 } 3033737Shx147065 3043737Shx147065 pcan_p->pcan_dip = dip; 3053737Shx147065 pcan_p->pcan_flag = 0; 3063737Shx147065 pcan_p->glds_nocarrier = 0; 3073737Shx147065 pcan_p->glds_noxmtbuf = 0; 3083737Shx147065 pcan_p->glds_norcvbuf = 0; 3093737Shx147065 pcan_p->pcan_socket = ddi_getprop(DDI_DEV_T_NONE, dip, 3104343Sgd78059 DDI_PROP_DONTPASS, "socket", -1); 3113737Shx147065 3123737Shx147065 pcan_p->pcan_reschedule_need = B_FALSE; 3133737Shx147065 pcan_p->pcan_info_softint_pending = 0; 3143737Shx147065 pcan_p->pcan_reset_delay = ddi_getprop(DDI_DEV_T_ANY, dip, 3153737Shx147065 DDI_PROP_DONTPASS, "reset-delay", 5000); 3163737Shx147065 3173737Shx147065 if (ddi_get_iblock_cookie(dip, 3183737Shx147065 0, &pcan_p->pcan_ib_cookie) != DDI_SUCCESS) { 3193737Shx147065 cmn_err(CE_WARN, "pcan attach: get_iblk_cookie failed\n"); 3203737Shx147065 goto attach_fail3; 3213737Shx147065 } 3223737Shx147065 3233737Shx147065 mutex_init(&pcan_p->pcan_glock, NULL, 3243737Shx147065 MUTEX_DRIVER, pcan_p->pcan_ib_cookie); 3253737Shx147065 mutex_init(&pcan_p->pcan_scanlist_lock, NULL, 3263737Shx147065 MUTEX_DRIVER, pcan_p->pcan_ib_cookie); 3273737Shx147065 mutex_init(&pcan_p->pcan_txring.an_tx_lock, NULL, 3283737Shx147065 MUTEX_DRIVER, pcan_p->pcan_ib_cookie); 3293737Shx147065 3303737Shx147065 if (ret = ddi_add_softintr(dip, DDI_SOFTINT_LOW, 3313737Shx147065 &pcan_p->pcan_info_softint_id, &pcan_p->pcan_ib_cookie, NULL, 3323737Shx147065 pcan_info_softint, (caddr_t)pcan_p)) { 3333737Shx147065 cmn_err(CE_WARN, "pcan attach: add info_softintr failed\n"); 3343737Shx147065 goto attach_fail3a; 3353737Shx147065 } 3363737Shx147065 3373737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 3383737Shx147065 if (ret = ddi_add_intr(dip, 0, NULL, NULL, 3393737Shx147065 pcan_intr, (caddr_t)pcan_p)) { 3403737Shx147065 cmn_err(CE_WARN, "pcan attach: add intr failed\n"); 3413737Shx147065 goto attach_fail4; 3423737Shx147065 } 3433737Shx147065 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) { 3443737Shx147065 if (ret = pcan_register_cs(dip, pcan_p)) { 3453737Shx147065 PCANDBG((CE_NOTE, "pcan attach: register_cs failed" 3463737Shx147065 " %x\n", ret)); 3473737Shx147065 goto attach_fail4; 3483737Shx147065 } 3493737Shx147065 } else { 3503737Shx147065 cmn_err(CE_WARN, "pcan attach: unsupported device type\n"); 3513737Shx147065 goto attach_fail4; 3523737Shx147065 } 3533737Shx147065 3543737Shx147065 mutex_enter(&pcan_p->pcan_glock); 3553737Shx147065 pcan_reset_backend(pcan_p, pcan_p->pcan_reset_delay); 3563737Shx147065 /* leaves IF down, intr disabled */ 3573737Shx147065 3583737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 3593737Shx147065 if (ret = pcan_init_dma(dip, pcan_p)) { 3603737Shx147065 cmn_err(CE_WARN, "pcan init_dma: failed\n"); 3613737Shx147065 mutex_exit(&pcan_p->pcan_glock); 3623737Shx147065 goto attach_fail5; 3633737Shx147065 } 3643737Shx147065 } 3653737Shx147065 if (ret = pcan_get_cap(pcan_p)) { /* sets macaddr for gld_register */ 3663737Shx147065 cmn_err(CE_WARN, "pcan attach: get_cap failed %x\n", ret); 3673737Shx147065 mutex_exit(&pcan_p->pcan_glock); 3683737Shx147065 goto attach_fail6; 3693737Shx147065 } 3703737Shx147065 3713737Shx147065 mutex_exit(&pcan_p->pcan_glock); 3723737Shx147065 /* 3733737Shx147065 * Provide initial settings for the WiFi plugin; whenever this 3743737Shx147065 * information changes, we need to call mac_pdata_update() 3753737Shx147065 */ 3763737Shx147065 wd.wd_secalloc = WIFI_SEC_NONE; 3773737Shx147065 wd.wd_opmode = IEEE80211_M_STA; 3783737Shx147065 3793737Shx147065 macp = mac_alloc(MAC_VERSION); 3803737Shx147065 if (macp == NULL) { 3813737Shx147065 PCANDBG((CE_NOTE, "pcan attach: " 3823737Shx147065 "MAC version mismatch\n")); 3833737Shx147065 goto attach_fail6; 3843737Shx147065 } 3853737Shx147065 3863737Shx147065 macp->m_type_ident = MAC_PLUGIN_IDENT_WIFI; 3873737Shx147065 macp->m_driver = pcan_p; 3883737Shx147065 macp->m_dip = dip; 3893737Shx147065 macp->m_src_addr = pcan_p->pcan_mac_addr; 3903737Shx147065 macp->m_callbacks = &pcan_m_callbacks; 3913737Shx147065 macp->m_min_sdu = 0; 3923737Shx147065 macp->m_max_sdu = IEEE80211_MTU; 3933737Shx147065 macp->m_pdata = &wd; 3943737Shx147065 macp->m_pdata_size = sizeof (wd); 3953737Shx147065 3963737Shx147065 err = mac_register(macp, &pcan_p->pcan_mh); 3973737Shx147065 mac_free(macp); 3983737Shx147065 if (err != 0) { 3993737Shx147065 PCANDBG((CE_NOTE, "pcan attach: " 4003737Shx147065 "mac_register err\n")); 4013737Shx147065 goto attach_fail6; 4023737Shx147065 } 4033737Shx147065 4043737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) { 4053737Shx147065 /* turn on CS interrupt */ 4063737Shx147065 cfgmod.Attributes = CONF_ENABLE_IRQ_STEERING | 4073737Shx147065 CONF_IRQ_CHANGE_VALID; 4083737Shx147065 cfgmod.Vpp1 = 50; 4093737Shx147065 cfgmod.Vpp2 = 50; 4103737Shx147065 (void) csx_ModifyConfiguration(pcan_p->pcan_chdl, &cfgmod); 4113737Shx147065 4123737Shx147065 mutex_enter(&pcan_p->pcan_glock); 4133737Shx147065 if (ret = pcan_init_nicmem(pcan_p)) { 4143737Shx147065 cmn_err(CE_WARN, "pcan attach: init_nicmem failed %x\n", 4153737Shx147065 ret); 4163737Shx147065 mutex_exit(&pcan_p->pcan_glock); 4173737Shx147065 goto attach_fail7; 4183737Shx147065 } 4193737Shx147065 mutex_exit(&pcan_p->pcan_glock); 4203737Shx147065 } 4213737Shx147065 (void) ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 4223737Shx147065 "bad-rids", (caddr_t)&pcan_p->pcan_badrids, 4233737Shx147065 &pcan_p->pcan_badrids_len); 4243737Shx147065 4253737Shx147065 pcan_p->an_config.an_rxmode = AN_NORMAL_RXMODE; 4263737Shx147065 ether_copy(pcan_p->pcan_mac_addr, pcan_p->an_config.an_macaddr); 4273737Shx147065 mutex_enter(&pcan_p->pcan_glock); 4283737Shx147065 list_create(&pcan_p->an_scan_list, sizeof (an_scan_list_t), 4293737Shx147065 offsetof(an_scan_list_t, an_scan_node)); 4303737Shx147065 pcan_p->an_scan_num = 0; 4313737Shx147065 mutex_exit(&pcan_p->pcan_glock); 4323737Shx147065 pcan_p->an_scanlist_timeout_id = timeout(pcan_scanlist_timeout, 4333737Shx147065 pcan_p, drv_usectohz(1000000)); 4343737Shx147065 4353737Shx147065 instance = ddi_get_instance(dip); 4363737Shx147065 (void) snprintf(strbuf, sizeof (strbuf), "pcan%d", instance); 4373737Shx147065 if (ddi_create_minor_node(dip, strbuf, S_IFCHR, 4383737Shx147065 instance + 1, DDI_NT_NET_WIFI, 0) != DDI_SUCCESS) { 4393737Shx147065 goto attach_fail8; 4403737Shx147065 } 4413737Shx147065 mutex_enter(&pcan_p->pcan_glock); 4423737Shx147065 PCAN_DISABLE_INTR_CLEAR(pcan_p); 4433737Shx147065 (void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0); 4443737Shx147065 pcan_p->pcan_flag |= PCAN_ATTACHED; 4453737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 4463737Shx147065 pcan_p->pcan_flag |= PCAN_CARD_READY; 4473737Shx147065 } 4483737Shx147065 mutex_exit(&pcan_p->pcan_glock); 4493737Shx147065 return (DDI_SUCCESS); 4503737Shx147065 attach_fail8: 4513737Shx147065 if (pcan_p->an_scanlist_timeout_id != 0) { 4523737Shx147065 (void) untimeout(pcan_p->an_scanlist_timeout_id); 4533737Shx147065 pcan_p->an_scanlist_timeout_id = 0; 4543737Shx147065 } 4553737Shx147065 list_destroy(&pcan_p->an_scan_list); 4563737Shx147065 attach_fail7: 4573737Shx147065 (void) mac_unregister(pcan_p->pcan_mh); 4583737Shx147065 attach_fail6: 4593737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) 4603737Shx147065 pcan_free_dma(pcan_p); 4613737Shx147065 attach_fail5: 4623737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 4633737Shx147065 ddi_remove_intr(dip, 0, pcan_p->pcan_ib_cookie); 4643737Shx147065 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) { 4653737Shx147065 pcan_unregister_cs(pcan_p); 4663737Shx147065 } 4673737Shx147065 attach_fail4: 4683737Shx147065 if (pcan_p->pcan_info_softint_id) 4693737Shx147065 ddi_remove_softintr(pcan_p->pcan_info_softint_id); 4703737Shx147065 attach_fail3a: 4713737Shx147065 pcan_destroy_locks(pcan_p); 4723737Shx147065 attach_fail3: 4733737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 4743737Shx147065 if (pcan_p->pcan_handle0) 4753737Shx147065 ddi_regs_map_free(&pcan_p->pcan_handle0); 4763737Shx147065 if (pcan_p->pcan_handle1) 4773737Shx147065 ddi_regs_map_free(&pcan_p->pcan_handle1); 4783737Shx147065 if (pcan_p->pcan_handle2) 4793737Shx147065 ddi_regs_map_free(&pcan_p->pcan_handle2); 4803737Shx147065 } 4813737Shx147065 attach_fail2: 4823737Shx147065 ddi_soft_state_free(pcan_soft_state_p, ddi_get_instance(dip)); 4833737Shx147065 attach_fail1: 4843737Shx147065 return (DDI_FAILURE); 4853737Shx147065 } 4863737Shx147065 4873737Shx147065 static int 4883737Shx147065 pcan_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 4893737Shx147065 { 4903737Shx147065 pcan_maci_t *pcan_p; 4913737Shx147065 an_scan_list_t *scan_item0; 4923737Shx147065 int ret; 4933737Shx147065 pcan_p = ddi_get_soft_state(pcan_soft_state_p, ddi_get_instance(dip)); 4943737Shx147065 4953737Shx147065 if (cmd != DDI_DETACH) 4963737Shx147065 return (DDI_FAILURE); 4973737Shx147065 if (!(pcan_p->pcan_flag & PCAN_ATTACHED)) 4983737Shx147065 return (DDI_FAILURE); 4997507SXinghua.Wen@Sun.COM 5007507SXinghua.Wen@Sun.COM ret = mac_disable(pcan_p->pcan_mh); 5017507SXinghua.Wen@Sun.COM if (ret != 0) 5027507SXinghua.Wen@Sun.COM return (DDI_FAILURE); 5037507SXinghua.Wen@Sun.COM 5043737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 5053737Shx147065 mutex_enter(&pcan_p->pcan_glock); 5063737Shx147065 pcan_stop_locked(pcan_p); 5073737Shx147065 PCAN_DISABLE_INTR(pcan_p); 5083737Shx147065 mutex_exit(&pcan_p->pcan_glock); 5093737Shx147065 } 5103737Shx147065 if (pcan_p->an_scanlist_timeout_id != 0) { 5113737Shx147065 (void) untimeout(pcan_p->an_scanlist_timeout_id); 5123737Shx147065 pcan_p->an_scanlist_timeout_id = 0; 5133737Shx147065 } 5143737Shx147065 if (pcan_p->pcan_connect_timeout_id != 0) { 5153737Shx147065 (void) untimeout(pcan_p->pcan_connect_timeout_id); 5163737Shx147065 pcan_p->pcan_connect_timeout_id = 0; 5173737Shx147065 } 5183737Shx147065 mutex_enter(&pcan_p->pcan_scanlist_lock); 5193737Shx147065 scan_item0 = list_head(&pcan_p->an_scan_list); 5203737Shx147065 while (scan_item0) { 5213737Shx147065 pcan_delete_scan_item(pcan_p, scan_item0); 5223737Shx147065 scan_item0 = list_head(&pcan_p->an_scan_list); 5233737Shx147065 } 5243737Shx147065 list_destroy(&pcan_p->an_scan_list); 5253737Shx147065 mutex_exit(&pcan_p->pcan_scanlist_lock); 5263737Shx147065 5277507SXinghua.Wen@Sun.COM (void) mac_unregister(pcan_p->pcan_mh); 5283737Shx147065 5293737Shx147065 mutex_enter(&pcan_p->pcan_glock); 5303737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 5313737Shx147065 ddi_remove_intr(dip, 0, pcan_p->pcan_ib_cookie); 5323737Shx147065 pcan_free_dma(pcan_p); 5333737Shx147065 if (pcan_p->pcan_handle0) 5343737Shx147065 ddi_regs_map_free(&pcan_p->pcan_handle0); 5353737Shx147065 if (pcan_p->pcan_handle1) 5363737Shx147065 ddi_regs_map_free(&pcan_p->pcan_handle1); 5373737Shx147065 if (pcan_p->pcan_handle2) 5383737Shx147065 ddi_regs_map_free(&pcan_p->pcan_handle2); 5393737Shx147065 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) { 5403737Shx147065 pcan_unregister_cs(pcan_p); 5413737Shx147065 } else { 5423737Shx147065 cmn_err(CE_WARN, "pcan detach: unsupported device type\n"); 5433737Shx147065 } 5443737Shx147065 mutex_exit(&pcan_p->pcan_glock); 5453737Shx147065 pcan_destroy_locks(pcan_p); 5463737Shx147065 if (pcan_p->pcan_info_softint_id) 5473737Shx147065 ddi_remove_softintr(pcan_p->pcan_info_softint_id); 5483737Shx147065 5493737Shx147065 if (pcan_p->pcan_badrids_len) 5503737Shx147065 kmem_free(pcan_p->pcan_badrids, pcan_p->pcan_badrids_len); 5513737Shx147065 5523737Shx147065 ddi_soft_state_free(pcan_soft_state_p, ddi_get_instance(dip)); 5533737Shx147065 ddi_remove_minor_node(dip, NULL); 5543737Shx147065 5553737Shx147065 return (DDI_SUCCESS); 5563737Shx147065 } 5573737Shx147065 5583737Shx147065 /* 5593737Shx147065 * card services and event handlers 5603737Shx147065 */ 5613737Shx147065 5623737Shx147065 static int 5633737Shx147065 pcan_register_cs(dev_info_t *dip, pcan_maci_t *pcan_p) 5643737Shx147065 { 5653737Shx147065 int ret; 5663737Shx147065 client_reg_t cr; 5673737Shx147065 client_handle_t chdl; /* uint encoding of socket, function, client */ 5683737Shx147065 get_status_t card_status; 5693737Shx147065 request_socket_mask_t sock_req; 5703737Shx147065 5713737Shx147065 bzero(&cr, sizeof (cr)); 5723737Shx147065 cr.Attributes = INFO_IO_CLIENT|INFO_CARD_EXCL|INFO_CARD_SHARE; 5733737Shx147065 cr.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | 5743737Shx147065 CS_EVENT_REGISTRATION_COMPLETE | CS_EVENT_CARD_REMOVAL_LOWP | 5753737Shx147065 CS_EVENT_CARD_READY | CS_EVENT_PM_RESUME | CS_EVENT_PM_SUSPEND | 5763737Shx147065 CS_EVENT_CLIENT_INFO; 5773737Shx147065 cr.event_callback_args.client_data = pcan_p; 5783737Shx147065 cr.Version = CS_VERSION; 5793737Shx147065 cr.event_handler = (csfunction_t *)pcan_ev_hdlr; 5803737Shx147065 cr.dip = dip; 5813737Shx147065 (void) strcpy(cr.driver_name, pcan_name_str); 5823737Shx147065 if (ret = csx_RegisterClient(&chdl, &cr)) { 5833737Shx147065 cmn_err(CE_WARN, "pcan: RegisterClient failed %x", ret); 5843737Shx147065 goto regcs_ret; 5853737Shx147065 } 5863737Shx147065 5873737Shx147065 pcan_p->pcan_chdl = chdl; 5883737Shx147065 5893737Shx147065 bzero(&card_status, sizeof (card_status)); 5903737Shx147065 (void) csx_GetStatus(chdl, &card_status); 5913737Shx147065 PCANDBG((CE_NOTE, "pcan: getstat Sock=%x CState=%x SState=%x rState=%x", 5923737Shx147065 card_status.Socket, card_status.CardState, 5933737Shx147065 card_status.SocketState, card_status.raw_CardState)); 5943737Shx147065 if (!(card_status.CardState & CS_STATUS_CARD_INSERTED)) { 5953737Shx147065 /* card is not present, why are we attaching ? */ 5963737Shx147065 ret = CS_NO_CARD; 5973737Shx147065 goto unreg; 5983737Shx147065 } 5993737Shx147065 cv_init(&pcan_p->pcan_cscv, NULL, CV_DRIVER, NULL); 6003737Shx147065 mutex_init(&pcan_p->pcan_cslock, NULL, MUTEX_DRIVER, *cr.iblk_cookie); 6013737Shx147065 mutex_enter(&pcan_p->pcan_cslock); 6023737Shx147065 if (ret = csx_MapLogSocket(chdl, &pcan_p->pcan_log_sock)) { 6033737Shx147065 cmn_err(CE_WARN, "pcan: MapLogSocket failed %x", ret); 6043737Shx147065 goto fail; 6053737Shx147065 } 6063737Shx147065 PCANDBG((CE_NOTE, "pcan: logsock: LogSock=%x PhyAdapter=%x PhySock=%x", 6073737Shx147065 pcan_p->pcan_log_sock.LogSocket, 6083737Shx147065 pcan_p->pcan_log_sock.PhyAdapter, 6093737Shx147065 pcan_p->pcan_log_sock.PhySocket)); 6103737Shx147065 6113737Shx147065 /* turn on initialization events */ 6123737Shx147065 sock_req.Socket = 0; 6133737Shx147065 sock_req.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | 6143737Shx147065 CS_EVENT_REGISTRATION_COMPLETE; 6153737Shx147065 if (ret = csx_RequestSocketMask(chdl, &sock_req)) { 6163737Shx147065 cmn_err(CE_WARN, "pcan: RequestSocketMask failed %x\n", ret); 6173737Shx147065 goto fail; 6183737Shx147065 } 6193737Shx147065 6203737Shx147065 /* wait for and process card insertion events */ 6213737Shx147065 while (!(pcan_p->pcan_flag & PCAN_CARD_READY)) 6223737Shx147065 cv_wait(&pcan_p->pcan_cscv, &pcan_p->pcan_cslock); 6233737Shx147065 mutex_exit(&pcan_p->pcan_cslock); 6243737Shx147065 6253737Shx147065 pcan_p->pcan_flag |= PCAN_CS_REGISTERED; 6263737Shx147065 return (CS_SUCCESS); 6273737Shx147065 fail: 6283737Shx147065 mutex_destroy(&pcan_p->pcan_cslock); 6293737Shx147065 cv_destroy(&pcan_p->pcan_cscv); 6303737Shx147065 unreg: 6313737Shx147065 (void) csx_DeregisterClient(chdl); 6323737Shx147065 regcs_ret: 6333737Shx147065 pcan_p->pcan_flag &= ~PCAN_CS_REGISTERED; 6343737Shx147065 return (ret); 6353737Shx147065 } 6363737Shx147065 6373737Shx147065 static void 6383737Shx147065 pcan_unregister_cs(pcan_maci_t *pcan_p) 6393737Shx147065 { 6403737Shx147065 int ret; 6413737Shx147065 release_socket_mask_t mask; 6423737Shx147065 mask.Socket = pcan_p->pcan_socket; 6433737Shx147065 6443737Shx147065 /* 6453737Shx147065 * The card service not registered means register_cs function 6463737Shx147065 * doesnot return TRUE. Then all the lelated resource has been 6473737Shx147065 * released in register_cs. 6483737Shx147065 */ 6493737Shx147065 if (!(pcan_p->pcan_flag | PCAN_CS_REGISTERED)) 6503737Shx147065 return; 6513737Shx147065 (void) csx_ReleaseSocketMask(pcan_p->pcan_chdl, &mask); 6523737Shx147065 6533737Shx147065 if (pcan_p->pcan_flag & PCAN_CARD_READY) { 6543737Shx147065 pcan_card_remove(pcan_p); 6553737Shx147065 pcan_p->pcan_flag &= ~PCAN_CARD_READY; 6563737Shx147065 } 6573737Shx147065 mutex_destroy(&pcan_p->pcan_cslock); 6583737Shx147065 cv_destroy(&pcan_p->pcan_cscv); 6593737Shx147065 if (ret = csx_DeregisterClient(pcan_p->pcan_chdl)) 6603737Shx147065 cmn_err(CE_WARN, "pcan: deregister failed %x\n", ret); 6613737Shx147065 } 6623737Shx147065 static void 6633737Shx147065 pcan_destroy_locks(pcan_maci_t *pcan_p) 6643737Shx147065 { 6653737Shx147065 mutex_destroy(&pcan_p->pcan_txring.an_tx_lock); 6663737Shx147065 mutex_destroy(&pcan_p->pcan_scanlist_lock); 6673737Shx147065 mutex_destroy(&pcan_p->pcan_glock); 6683737Shx147065 } 6693737Shx147065 6703737Shx147065 static int 6713737Shx147065 pcan_ev_hdlr(event_t event, int priority, event_callback_args_t *arg) 6723737Shx147065 { 6733737Shx147065 int ret = CS_SUCCESS; 6743737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg->client_data; 6753737Shx147065 client_info_t *ci_p = (client_info_t *)&arg->client_info; 6763737Shx147065 6773737Shx147065 mutex_enter(&pcan_p->pcan_cslock); 6783737Shx147065 switch (event) { 6793737Shx147065 case CS_EVENT_CARD_INSERTION: 6803737Shx147065 ret = pcan_card_insert(pcan_p); 6813737Shx147065 cv_broadcast(&pcan_p->pcan_cscv); 6823737Shx147065 break; 6833737Shx147065 case CS_EVENT_REGISTRATION_COMPLETE: 6843737Shx147065 cv_broadcast(&pcan_p->pcan_cscv); 6853737Shx147065 break; 6863737Shx147065 case CS_EVENT_CARD_REMOVAL: 6873737Shx147065 if (priority & CS_EVENT_PRI_HIGH) 6883737Shx147065 break; 6893737Shx147065 pcan_card_remove(pcan_p); 6903737Shx147065 cv_broadcast(&pcan_p->pcan_cscv); 6913737Shx147065 break; 6923737Shx147065 case CS_EVENT_CLIENT_INFO: 6933737Shx147065 if (GET_CLIENT_INFO_SUBSVC(ci_p->Attributes) != 6943737Shx147065 CS_CLIENT_INFO_SUBSVC_CS) 6953737Shx147065 break; 6963737Shx147065 6973737Shx147065 ci_p->Revision = 0x0101; 6983737Shx147065 ci_p->CSLevel = CS_VERSION; 6993737Shx147065 ci_p->RevDate = CS_CLIENT_INFO_MAKE_DATE(9, 12, 14); 7003737Shx147065 (void) strcpy(ci_p->ClientName, PCAN_IDENT_STRING); 7013737Shx147065 (void) strcpy(ci_p->VendorName, CS_SUN_VENDOR_DESCRIPTION); 7023737Shx147065 ci_p->Attributes |= CS_CLIENT_INFO_VALID; 7033737Shx147065 break; 7043737Shx147065 default: 7053737Shx147065 ret = CS_UNSUPPORTED_EVENT; 7063737Shx147065 break; 7073737Shx147065 } 7083737Shx147065 mutex_exit(&pcan_p->pcan_cslock); 7093737Shx147065 return (ret); 7103737Shx147065 } 7113737Shx147065 7123737Shx147065 static int 7133737Shx147065 pcan_card_insert(pcan_maci_t *pcan_p) 7143737Shx147065 { 7153737Shx147065 int ret, hi, lo; 7163737Shx147065 tuple_t tuple; 7173737Shx147065 cisparse_t cisparse; 7183737Shx147065 io_req_t io; 7193737Shx147065 irq_req_t irq; 7203737Shx147065 config_req_t cfg; 7213737Shx147065 cistpl_config_t config; 7223737Shx147065 cistpl_cftable_entry_t *tbl_p; 7233737Shx147065 register client_handle_t chdl = pcan_p->pcan_chdl; 7243737Shx147065 7253737Shx147065 bzero(&tuple, sizeof (tuple)); 7263737Shx147065 tuple.DesiredTuple = CISTPL_MANFID; 7273737Shx147065 if (ret = csx_GetFirstTuple(chdl, &tuple)) { 7283737Shx147065 cmn_err(CE_WARN, "pcan: get manufacture id failed %x\n", ret); 7293737Shx147065 goto insert_ret; 7303737Shx147065 } 7313737Shx147065 bzero(&cisparse, sizeof (cisparse)); 7323737Shx147065 if (ret = csx_Parse_CISTPL_MANFID(chdl, &tuple, &cisparse.manfid)) { 7333737Shx147065 cmn_err(CE_WARN, "pcan: parse manufacture id failed %x\n", ret); 7343737Shx147065 goto insert_ret; 7353737Shx147065 } 7363737Shx147065 /* verify manufacture ID */ 7373737Shx147065 PCANDBG((CE_NOTE, "pcan: manufacturer_id=%x card=%x\n", 7383737Shx147065 cisparse.manfid.manf, cisparse.manfid.card)); 7393737Shx147065 7403737Shx147065 bzero(&tuple, sizeof (tuple)); 7413737Shx147065 tuple.DesiredTuple = CISTPL_FUNCID; 7423737Shx147065 if (ret = csx_GetFirstTuple(chdl, &tuple)) { 7433737Shx147065 cmn_err(CE_WARN, "pcan: get function id failed %x\n", ret); 7443737Shx147065 goto insert_ret; 7453737Shx147065 } 7463737Shx147065 bzero(&cisparse, sizeof (cisparse)); 7473737Shx147065 if (ret = csx_Parse_CISTPL_FUNCID(chdl, &tuple, &cisparse.funcid)) { 7483737Shx147065 cmn_err(CE_WARN, "pcan: parse function id failed %x\n", ret); 7493737Shx147065 goto insert_ret; 7503737Shx147065 } 7513737Shx147065 /* verify function ID */ 7523737Shx147065 PCANDBG((CE_NOTE, "funcid=%x\n", cisparse.funcid.function)); 7533737Shx147065 7543737Shx147065 bzero(&tuple, sizeof (tuple)); 7553737Shx147065 tuple.DesiredTuple = CISTPL_CONFIG; 7563737Shx147065 if (ret = csx_GetFirstTuple(chdl, &tuple)) { 7573737Shx147065 cmn_err(CE_WARN, "pcan: get config failed %x\n", ret); 7583737Shx147065 goto insert_ret; 7593737Shx147065 } 7603737Shx147065 bzero(&config, sizeof (config)); 7613737Shx147065 if (ret = csx_Parse_CISTPL_CONFIG(chdl, &tuple, &config)) { 7623737Shx147065 cmn_err(CE_WARN, "pcan: parse config failed %x\n", ret); 7633737Shx147065 goto insert_ret; 7643737Shx147065 } 7653737Shx147065 PCANDBG((CE_NOTE, 7663737Shx147065 "pcan: config present=%x nr=%x hr=%x regs[0]=%x base=%x last=%x\n", 7673737Shx147065 config.present, config.nr, config.hr, config.regs[0], 7683737Shx147065 config.base, config.last)); 7693737Shx147065 7703737Shx147065 hi = 0; 7713737Shx147065 lo = (int)-1; /* really big number */ 7723737Shx147065 tbl_p = &cisparse.cftable; 7733737Shx147065 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; 7743737Shx147065 for (tbl_p->index = 0; tbl_p->index <= config.hr; ) { 7753737Shx147065 PCANDBG((CE_NOTE, "pcan: tuple idx=%x:\n", tbl_p->index)); 7763737Shx147065 if (ret = csx_GetNextTuple(chdl, &tuple)) { 7773737Shx147065 cmn_err(CE_WARN, "pcan: get cftable failed %x\n", ret); 7783737Shx147065 break; 7793737Shx147065 } 7803737Shx147065 bzero((caddr_t)&cisparse, sizeof (cisparse)); 7813737Shx147065 if (ret = csx_Parse_CISTPL_CFTABLE_ENTRY(chdl, &tuple, tbl_p)) { 7823737Shx147065 cmn_err(CE_WARN, "pcan: parse cftable failed%x\n", ret); 7833737Shx147065 break; 7843737Shx147065 } 7853737Shx147065 if (tbl_p->flags & CISTPL_CFTABLE_TPCE_FS_PWR && 7864343Sgd78059 tbl_p->pd.flags & CISTPL_CFTABLE_TPCE_FS_PWR_VCC) { 7873737Shx147065 if (tbl_p->pd.pd_vcc.avgI > hi) { 7883737Shx147065 hi = tbl_p->pd.pd_vcc.avgI; 7893737Shx147065 pcan_p->pcan_config_hi = tbl_p->index; 7903737Shx147065 } 7913737Shx147065 if (tbl_p->pd.pd_vcc.avgI < lo) { 7923737Shx147065 lo = tbl_p->pd.pd_vcc.avgI; 7933737Shx147065 pcan_p->pcan_config = tbl_p->index; 7943737Shx147065 } 7953737Shx147065 } 7963737Shx147065 if (tbl_p->flags & CISTPL_CFTABLE_TPCE_DEFAULT) { 7973737Shx147065 if (tbl_p->pd.flags & CISTPL_CFTABLE_TPCE_FS_PWR_VCC) 7983737Shx147065 pcan_p->pcan_vcc = tbl_p->pd.pd_vcc.nomV; 7993737Shx147065 if (tbl_p->flags & CISTPL_CFTABLE_TPCE_FS_IO) 8003737Shx147065 pcan_p->pcan_iodecode = tbl_p->io.addr_lines; 8013737Shx147065 } 8023737Shx147065 } 8033737Shx147065 PCANDBG((CE_NOTE, "pcan: cfg_hi=%x cfg=%x vcc=%x iodecode=%x\n", 8043737Shx147065 pcan_p->pcan_config_hi, pcan_p->pcan_config, 8053737Shx147065 pcan_p->pcan_vcc, pcan_p->pcan_iodecode)); 8063737Shx147065 8073737Shx147065 bzero(&io, sizeof (io)); 8083737Shx147065 io.BasePort1.base = 0; 8093737Shx147065 io.NumPorts1 = 1 << pcan_p->pcan_iodecode; 8103737Shx147065 io.Attributes1 = IO_DATA_PATH_WIDTH_16; 8113737Shx147065 io.IOAddrLines = pcan_p->pcan_iodecode; 8123737Shx147065 if (ret = csx_RequestIO(chdl, &io)) { 8133737Shx147065 cmn_err(CE_WARN, "pcan: RequestIO failed %x\n", ret); 8143737Shx147065 goto insert_ret; 8153737Shx147065 } 8163737Shx147065 pcan_p->pcan_port = io.BasePort1.handle; 8173737Shx147065 8183737Shx147065 if (ret = ddi_add_softintr(DIP(pcan_p), DDI_SOFTINT_HIGH, 8193737Shx147065 &pcan_p->pcan_softint_id, &pcan_p->pcan_ib_cookie, NULL, 8203737Shx147065 pcan_intr, (caddr_t)pcan_p)) { 8213737Shx147065 cmn_err(CE_NOTE, "pcan: Add softintr failed\n"); 8223737Shx147065 goto insert_ret; 8233737Shx147065 } 8243737Shx147065 irq.Attributes = IRQ_TYPE_EXCLUSIVE; 8253737Shx147065 irq.irq_handler = ddi_intr_hilevel(DIP(pcan_p), 0) ? 8263737Shx147065 (csfunction_t *)pcan_intr_hi : (csfunction_t *)pcan_intr; 8273737Shx147065 irq.irq_handler_arg = pcan_p; 8283737Shx147065 if (ret = csx_RequestIRQ(chdl, &irq)) { 8293737Shx147065 cmn_err(CE_WARN, "pcan: RequestIRQ failed %x\n", ret); 8303737Shx147065 goto un_io; 8313737Shx147065 } 8323737Shx147065 8333737Shx147065 bzero(&cfg, sizeof (cfg)); 8343737Shx147065 cfg.Attributes = 0; /* not ready for CONF_ENABLE_IRQ_STEERING yet */ 8353737Shx147065 cfg.Vcc = 50; /* pcan_vcc == 0 */ 8363737Shx147065 cfg.Vpp1 = 50; 8373737Shx147065 cfg.Vpp2 = 50; 8383737Shx147065 cfg.IntType = SOCKET_INTERFACE_MEMORY_AND_IO; 8393737Shx147065 cfg.ConfigBase = config.base; 8403737Shx147065 cfg.ConfigIndex = pcan_p->pcan_config; 8413737Shx147065 cfg.Status = CCSR_IO_IS_8; /* no use */ 8423737Shx147065 cfg.Present = config.present; 8433737Shx147065 pcan_p->pcan_flag |= PCAN_CARD_READY; 8443737Shx147065 if (ret = csx_RequestConfiguration(chdl, &cfg)) { 8453737Shx147065 cmn_err(CE_WARN, "pcan: RequestConfiguration failed %x\n", ret); 8463737Shx147065 goto un_irq; 8473737Shx147065 } 8483737Shx147065 return (CS_SUCCESS); 8493737Shx147065 un_irq: 8503737Shx147065 (void) csx_ReleaseIRQ(chdl, &irq); 8513737Shx147065 un_io: 8523737Shx147065 ddi_remove_softintr(pcan_p->pcan_softint_id); 8533737Shx147065 8543737Shx147065 (void) csx_ReleaseIO(chdl, &io); 8553737Shx147065 pcan_p->pcan_port = 0; 8563737Shx147065 insert_ret: 8573737Shx147065 pcan_p->pcan_flag &= ~PCAN_CARD_READY; 8583737Shx147065 return (ret); 8593737Shx147065 } 8603737Shx147065 8613737Shx147065 /* 8623737Shx147065 * assume card is already removed, don't touch the hardware 8633737Shx147065 */ 8643737Shx147065 static void 8653737Shx147065 pcan_card_remove(pcan_maci_t *pcan_p) 8663737Shx147065 { 8673737Shx147065 int ret; 8683737Shx147065 io_req_t io; 8693737Shx147065 irq_req_t irq; 8703737Shx147065 8713737Shx147065 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) 8723737Shx147065 return; 8733737Shx147065 if (ret = csx_ReleaseConfiguration(pcan_p->pcan_chdl, NULL)) 8743737Shx147065 cmn_err(CE_WARN, "pcan: ReleaseConfiguration failed %x\n", ret); 8753737Shx147065 8763737Shx147065 bzero(&irq, sizeof (irq)); 8773737Shx147065 if (ret = csx_ReleaseIRQ(pcan_p->pcan_chdl, &irq)) 8783737Shx147065 cmn_err(CE_WARN, "pcan: ReleaseIRQ failed %x\n", ret); 8793737Shx147065 8803737Shx147065 ddi_remove_softintr(pcan_p->pcan_softint_id); 8813737Shx147065 8823737Shx147065 bzero(&io, sizeof (io)); 8833737Shx147065 io.BasePort1.handle = pcan_p->pcan_port; 8843737Shx147065 io.NumPorts1 = 16; 8853737Shx147065 if (ret = csx_ReleaseIO(pcan_p->pcan_chdl, &io)) 8863737Shx147065 cmn_err(CE_WARN, "pcan: Release IO failed %x\n", ret); 8873737Shx147065 8883737Shx147065 pcan_p->pcan_port = 0; 8893737Shx147065 pcan_p->pcan_flag &= ~PCAN_CARD_READY; 8903737Shx147065 } 8913737Shx147065 8923737Shx147065 /* 8933737Shx147065 * gld operation interface routines 8943737Shx147065 */ 8953737Shx147065 static int 8963737Shx147065 pcan_start(void *arg) 8973737Shx147065 { 8983737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 8993737Shx147065 9003737Shx147065 mutex_enter(&pcan_p->pcan_glock); 9013737Shx147065 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) { 9023737Shx147065 mutex_exit(&pcan_p->pcan_glock); 9033737Shx147065 return (PCAN_FAIL); 9043737Shx147065 } 9053737Shx147065 (void) pcan_loaddef(pcan_p); 9063737Shx147065 pcan_start_locked(pcan_p); 9073737Shx147065 mutex_exit(&pcan_p->pcan_glock); 9083737Shx147065 return (PCAN_SUCCESS); 9093737Shx147065 } 9103737Shx147065 9113737Shx147065 static void 9123737Shx147065 pcan_stop(void *arg) 9133737Shx147065 { 9143737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 9153737Shx147065 9163737Shx147065 mutex_enter(&pcan_p->pcan_glock); 9173737Shx147065 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) { 9183737Shx147065 mutex_exit(&pcan_p->pcan_glock); 9193737Shx147065 return; 9203737Shx147065 } 9213737Shx147065 pcan_stop_locked(pcan_p); 9223737Shx147065 mutex_exit(&pcan_p->pcan_glock); 9233737Shx147065 if (pcan_p->pcan_connect_timeout_id != 0) { 9243737Shx147065 (void) untimeout(pcan_p->pcan_connect_timeout_id); 9253737Shx147065 pcan_p->pcan_connect_timeout_id = 0; 9263737Shx147065 } 9273737Shx147065 } 9283737Shx147065 9293737Shx147065 /* 9303737Shx147065 * mac address can only be set in 'disable' state and 9313737Shx147065 * be effective after 'enable' state. 9323737Shx147065 */ 9333737Shx147065 static int 9343737Shx147065 pcan_saddr(void *arg, const uint8_t *macaddr) 9353737Shx147065 { 9363737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 9373737Shx147065 int ret = PCAN_SUCCESS; 9383737Shx147065 ether_copy(macaddr, pcan_p->pcan_mac_addr); 9393737Shx147065 9403737Shx147065 mutex_enter(&pcan_p->pcan_glock); 9413737Shx147065 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) { 9423737Shx147065 ret = PCAN_FAIL; 9433737Shx147065 goto done; 9443737Shx147065 } 9453737Shx147065 ether_copy(pcan_p->pcan_mac_addr, pcan_p->an_config.an_macaddr); 9463737Shx147065 if (pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) { 9473737Shx147065 cmn_err(CE_WARN, "pcan set mac addr: failed\n"); 9483737Shx147065 ret = PCAN_FAIL; 9493737Shx147065 goto done; 9503737Shx147065 } 9513737Shx147065 if (pcan_config_mac(pcan_p)) { 9523737Shx147065 cmn_err(CE_WARN, "pcan set mac addr: config_mac failed\n"); 9533737Shx147065 ret = PCAN_FAIL; 9543737Shx147065 goto done; 9553737Shx147065 } 9563737Shx147065 if (pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0)) { 9573737Shx147065 cmn_err(CE_WARN, "pcan set mac addr: failed\n"); 9583737Shx147065 ret = PCAN_FAIL; 9593737Shx147065 } 9603737Shx147065 done: 9613737Shx147065 mutex_exit(&pcan_p->pcan_glock); 9623737Shx147065 return (ret); 9633737Shx147065 } 9643737Shx147065 9653737Shx147065 /* 9663737Shx147065 * send a packet out for pccard 9673737Shx147065 */ 9683737Shx147065 static int 9693737Shx147065 pcan_send(pcan_maci_t *pcan_p, mblk_t *mblk_p) 9703737Shx147065 { 9713737Shx147065 char *buf, *buf_p; 9723737Shx147065 an_txfrm_t *frm_p; 9733737Shx147065 #ifdef PCAN_SEND_DEBUG 9743737Shx147065 struct an_ltv_status radio_status; 9753737Shx147065 #endif /* PCAN_SEND_DEBUG */ 9763737Shx147065 uint16_t pkt_len, xmt_id, ring_idx; 9773737Shx147065 struct ieee80211_frame *wh; 9783737Shx147065 int i = 0; 9793737Shx147065 9803737Shx147065 mutex_enter(&pcan_p->pcan_glock); 9813737Shx147065 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) { 9823737Shx147065 mutex_exit(&pcan_p->pcan_glock); 9833737Shx147065 freemsg(mblk_p); 9843737Shx147065 return (PCAN_SUCCESS); /* drop packet */ 9853737Shx147065 } 9863737Shx147065 if (!(pcan_p->pcan_flag & PCAN_CARD_LINKUP)) { /* link down */ 9873737Shx147065 PCANDBG((CE_NOTE, "pcan: link down, dropped\n")); 9883737Shx147065 pcan_p->glds_nocarrier++; 9893737Shx147065 mutex_exit(&pcan_p->pcan_glock); 9903737Shx147065 freemsg(mblk_p); 9913737Shx147065 return (PCAN_SUCCESS); /* drop packet */ 9923737Shx147065 } 9933737Shx147065 mutex_exit(&pcan_p->pcan_glock); 9943737Shx147065 if (pullupmsg(mblk_p, -1) == 0) { 9953737Shx147065 cmn_err(CE_NOTE, "pcan send: pullupmsg failed\n"); 9963737Shx147065 freemsg(mblk_p); 9973737Shx147065 return (PCAN_SUCCESS); /* drop packet */ 9983737Shx147065 } 9993737Shx147065 wh = (struct ieee80211_frame *)mblk_p->b_rptr; 10003737Shx147065 10013737Shx147065 mutex_enter(&pcan_p->pcan_txring.an_tx_lock); 10023737Shx147065 ring_idx = pcan_p->pcan_txring.an_tx_prod; 10033737Shx147065 pcan_p->pcan_txring.an_tx_prod = (ring_idx + 1) & AN_TX_RING_MASK; 10043737Shx147065 10053737Shx147065 /* check whether there is a xmt buffer available */ 10063737Shx147065 while ((i < AN_TX_RING_CNT) && 10073737Shx147065 (pcan_p->pcan_txring.an_tx_ring[ring_idx])) { 10083737Shx147065 ring_idx = pcan_p->pcan_txring.an_tx_prod; 10093737Shx147065 pcan_p->pcan_txring.an_tx_prod = 10103737Shx147065 (ring_idx + 1) & AN_TX_RING_MASK; 10113737Shx147065 i++; 10123737Shx147065 } 10133737Shx147065 10143737Shx147065 if (i == AN_TX_RING_CNT) { 10153737Shx147065 mutex_exit(&pcan_p->pcan_txring.an_tx_lock); 10163737Shx147065 PCANDBG((CE_NOTE, "pcan: ring full, retrying\n")); 10173737Shx147065 mutex_enter(&pcan_p->pcan_glock); 10183737Shx147065 pcan_p->pcan_reschedule_need = B_TRUE; 10193737Shx147065 mutex_exit(&pcan_p->pcan_glock); 10203737Shx147065 pcan_p->glds_noxmtbuf++; 10213737Shx147065 return (PCAN_FAIL); 10223737Shx147065 } 10233737Shx147065 xmt_id = pcan_p->pcan_txring.an_tx_fids[ring_idx]; 10243737Shx147065 pcan_p->pcan_txring.an_tx_ring[ring_idx] = xmt_id; 10253737Shx147065 mutex_exit(&pcan_p->pcan_txring.an_tx_lock); 10263737Shx147065 10273737Shx147065 buf = kmem_zalloc(PCAN_NICMEM_SZ, KM_SLEEP); /* too big for stack */ 10283737Shx147065 buf_p = (ulong_t)buf & 1 ? buf + 1 : buf; /* 16-bit round up */ 10293737Shx147065 frm_p = (an_txfrm_t *)buf_p; 10303737Shx147065 10313737Shx147065 #ifdef DEBUG 10323737Shx147065 if (pcan_debug & PCAN_DBG_SEND) { 10333737Shx147065 cmn_err(CE_NOTE, "pcan send: packet from plugin"); 10347249Sff224033 for (i = 0; i < MBLKL(mblk_p); i++) 10353737Shx147065 cmn_err(CE_NOTE, "%x: %x\n", i, 10363737Shx147065 *((unsigned char *)mblk_p->b_rptr + i)); 10373737Shx147065 } 10383737Shx147065 #endif 10393737Shx147065 pkt_len = msgdsize(mblk_p); 10403737Shx147065 if (pkt_len > PCAN_NICMEM_SZ - sizeof (an_txfrm_t)) { 10413737Shx147065 cmn_err(CE_WARN, "pcan send: mblk is too long"); 10423737Shx147065 kmem_free(buf, PCAN_NICMEM_SZ); 10433737Shx147065 freemsg(mblk_p); 10443737Shx147065 return (PCAN_SUCCESS); /* drop packet */ 10453737Shx147065 } 10463737Shx147065 if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) != 10473737Shx147065 IEEE80211_FC1_DIR_TODS) { 10483737Shx147065 kmem_free(buf, PCAN_NICMEM_SZ); 10493737Shx147065 freemsg(mblk_p); 10503737Shx147065 return (PCAN_SUCCESS); /* drop packet */ 10513737Shx147065 } 10523737Shx147065 10533737Shx147065 /* initialize xmt frame header, payload_len must be stored in LE */ 10543737Shx147065 bzero(frm_p, sizeof (an_txfrm_t) + 2); 10553737Shx147065 frm_p->an_tx_ctl = AN_TXCTL_8023; 10563737Shx147065 10573737Shx147065 /* 10583737Shx147065 * mblk sent down from plugin includes station mode 802.11 frame and 10593737Shx147065 * llc, so we here need to remove them and add an ethernet header. 10603737Shx147065 */ 10613737Shx147065 pkt_len = pkt_len - (sizeof (*wh) + sizeof (struct ieee80211_llc)) 10623737Shx147065 + 2; 10633737Shx147065 bcopy(wh->i_addr3, buf_p + 0x38, ETHERADDRL); /* dst macaddr */ 10643737Shx147065 bcopy(wh->i_addr2, buf_p + 0x3e, ETHERADDRL); /* src macaddr */ 10653737Shx147065 *((uint16_t *)(buf_p + 0x36)) = pkt_len; 10663737Shx147065 bcopy(mblk_p->b_rptr + sizeof (*wh) + sizeof (struct ieee80211_llc) 10673737Shx147065 - 2, buf_p + 0x44, pkt_len); 10683737Shx147065 10693737Shx147065 if (pkt_len & 1) { /* round up to 16-bit boundary and pad 0 */ 10703737Shx147065 buf_p[pkt_len + 0x44] = 0; 10713737Shx147065 pkt_len++; 10723737Shx147065 } 10733737Shx147065 ASSERT(pkt_len <= PCAN_NICMEM_SZ); 10743737Shx147065 #ifdef DEBUG 10753737Shx147065 if (pcan_debug & PCAN_DBG_SEND) { 10763737Shx147065 cmn_err(CE_NOTE, "pcan send: packet to hardware--pkt_len=%x", 10773737Shx147065 pkt_len); 10783737Shx147065 for (i = 0; i < pkt_len + 4; i++) 10793737Shx147065 cmn_err(CE_NOTE, "%x: %x\n", i, 10803737Shx147065 *((unsigned char *)buf_p + 0x36 + i)); 10813737Shx147065 } 10823737Shx147065 #endif 10833737Shx147065 mutex_enter(&pcan_p->pcan_glock); 10843737Shx147065 (void) WRCH1(pcan_p, xmt_id, 0, (uint16_t *)buf_p, 0x38); /* frm */ 10853737Shx147065 (void) WRPKT(pcan_p, xmt_id, 0x38, (uint16_t *)(buf_p + 0x38), 10864343Sgd78059 pkt_len + 12); 10873737Shx147065 ring_idx = pcan_set_cmd(pcan_p, AN_CMD_TX, xmt_id); 10883737Shx147065 mutex_exit(&pcan_p->pcan_glock); 10893737Shx147065 10903737Shx147065 PCANDBG((CE_NOTE, "pcan: pkt_len=0x44+%x=%x xmt=%x ret=%x\n", 10913737Shx147065 pkt_len, 0x44 + pkt_len, xmt_id, ring_idx)); 10923737Shx147065 kmem_free(buf, PCAN_NICMEM_SZ); 10933737Shx147065 #ifdef PCAN_SEND_DEBUG 10943737Shx147065 if (pkt_len = pcan_status_ltv(PCAN_READ_LTV, pcan_p, &radio_status)) { 10953737Shx147065 PCANDBG((CE_NOTE, "pcan: bad radio status %x\n", pkt_len)); 10963737Shx147065 } else { 10973737Shx147065 PCANDBG((CE_NOTE, "pcan: radio status:\n")); 10983737Shx147065 } 10993737Shx147065 #endif /* PCAN_SEND_DEBUG */ 11003737Shx147065 if (ring_idx) 11013737Shx147065 return (PCAN_FAIL); 11023737Shx147065 else { 11033737Shx147065 freemsg(mblk_p); 11043737Shx147065 return (PCAN_SUCCESS); 11053737Shx147065 } 11063737Shx147065 } 11073737Shx147065 11083737Shx147065 /* 11093737Shx147065 * send a packet out for PCI/MiniPCI card 11103737Shx147065 */ 11113737Shx147065 static int 11123737Shx147065 pcian_send(pcan_maci_t *pcan_p, mblk_t *mblk_p) 11133737Shx147065 { 11143737Shx147065 char *buf; 11153737Shx147065 uint16_t pkt_len = msgdsize(mblk_p), ring_idx; 11163737Shx147065 uint32_t i; 11173737Shx147065 struct ieee80211_frame *wh; 11183737Shx147065 struct an_card_tx_desc an_tx_desc; 11193737Shx147065 11203737Shx147065 ring_idx = pcan_p->pcan_txring.an_tx_prod; 11213737Shx147065 11223737Shx147065 mutex_enter(&pcan_p->pcan_glock); 11233737Shx147065 if (!(pcan_p->pcan_flag & PCAN_CARD_LINKUP)) { /* link down */ 11243737Shx147065 mutex_exit(&pcan_p->pcan_glock); 11253737Shx147065 pcan_p->glds_nocarrier++; 11263737Shx147065 freemsg(mblk_p); 11273737Shx147065 return (PCAN_SUCCESS); /* drop packet */ 11283737Shx147065 } 11293737Shx147065 mutex_exit(&pcan_p->pcan_glock); 11303737Shx147065 if (pullupmsg(mblk_p, -1) == 0) { 11313737Shx147065 cmn_err(CE_NOTE, "pcan(pci) send: pullupmsg failed\n"); 11323737Shx147065 freemsg(mblk_p); 11333737Shx147065 return (PCAN_SUCCESS); /* drop packet */ 11343737Shx147065 } 11353737Shx147065 wh = (struct ieee80211_frame *)mblk_p->b_rptr; 11363737Shx147065 11373737Shx147065 mutex_enter(&pcan_p->pcan_txring.an_tx_lock); 11383737Shx147065 if ((pcan_p->pcan_flag & PCAN_CARD_SEND) && 11393737Shx147065 (ring_idx == pcan_p->pcan_txring.an_tx_cons)) { 11403737Shx147065 pcan_p->glds_noxmtbuf++; 11413737Shx147065 pcan_p->pcan_reschedule_need = B_TRUE; 11423737Shx147065 mutex_exit(&pcan_p->pcan_txring.an_tx_lock); 11433737Shx147065 return (PCAN_FAIL); 11443737Shx147065 } 11453737Shx147065 mutex_exit(&pcan_p->pcan_txring.an_tx_lock); 11463737Shx147065 11473737Shx147065 #ifdef DEBUG 11483737Shx147065 if (pcan_debug & PCAN_DBG_SEND) { 11493737Shx147065 cmn_err(CE_NOTE, "pcan(pci) send: packet from plugin"); 11507249Sff224033 for (i = 0; i < MBLKL(mblk_p); i++) 11513737Shx147065 cmn_err(CE_NOTE, "%x: %x\n", i, 11523737Shx147065 *((unsigned char *)mblk_p->b_rptr + i)); 11533737Shx147065 } 11543737Shx147065 #endif 11553737Shx147065 mutex_enter(&pcan_p->pcan_glock); 11563737Shx147065 11573737Shx147065 buf = pcan_p->pcan_tx[ring_idx].dma_virtaddr; 11583737Shx147065 bzero(buf, AN_TX_BUFFER_SIZE); 11593737Shx147065 11603737Shx147065 /* 11613737Shx147065 * mblk sent down from plugin includes station mode 802.11 frame and 11623737Shx147065 * llc, so we here need to remove them and add an ethernet header. 11633737Shx147065 */ 11643737Shx147065 *((uint16_t *)(buf + 8)) = htons(AN_TXCTL_8023); 11653737Shx147065 pkt_len = pkt_len - (sizeof (*wh) + sizeof (struct ieee80211_llc)) 11663737Shx147065 + 2; 11673737Shx147065 bcopy(wh->i_addr3, buf + 0x38, ETHERADDRL); /* dst macaddr */ 11683737Shx147065 bcopy(wh->i_addr2, buf + 0x3e, ETHERADDRL); /* src macaddr */ 11693737Shx147065 *((uint16_t *)(buf + 0x36)) = pkt_len; 11703737Shx147065 bcopy(mblk_p->b_rptr + sizeof (*wh) + sizeof (struct ieee80211_llc) 11713737Shx147065 - 2, buf + 0x44, pkt_len); 11723737Shx147065 11733737Shx147065 #ifdef DEBUG 11743737Shx147065 if (pcan_debug & PCAN_DBG_SEND) { 11753737Shx147065 cmn_err(CE_NOTE, "pcan(pci) send: packet to hardware " 11763737Shx147065 "pkt_len=%x", pkt_len); 11773737Shx147065 for (i = 0; i < pkt_len + 14; i++) 11783737Shx147065 cmn_err(CE_NOTE, "%x: %x\n", i, 11793737Shx147065 *((unsigned char *)buf + 0x36 + i)); 11803737Shx147065 } 11813737Shx147065 #endif 11823737Shx147065 bzero(&an_tx_desc, sizeof (an_tx_desc)); 11833737Shx147065 an_tx_desc.an_offset = 0; 11843737Shx147065 an_tx_desc.an_eoc = (ring_idx == (AN_MAX_TX_DESC-1) ? 1 : 0); 11853737Shx147065 an_tx_desc.an_valid = 1; 11863737Shx147065 an_tx_desc.an_len = 0x44 + pkt_len; 11873737Shx147065 an_tx_desc.an_phys = pcan_p->pcan_tx[ring_idx].dma_physaddr; 11883737Shx147065 for (i = 0; i < sizeof (an_tx_desc) / 4; i++) { 11893737Shx147065 PCAN_AUX_PUT32(pcan_p, AN_TX_DESC_OFFSET + 11903737Shx147065 (ring_idx * sizeof (an_tx_desc)) + (i * 4), 11913737Shx147065 ((uint32_t *)&an_tx_desc)[i]); 11923737Shx147065 } 11933737Shx147065 11943737Shx147065 mutex_enter(&pcan_p->pcan_txring.an_tx_lock); 11953737Shx147065 pcan_p->pcan_txring.an_tx_prod = (ring_idx + 1) % AN_MAX_TX_DESC; 11963737Shx147065 pcan_p->pcan_flag |= PCAN_CARD_SEND; 11973737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_ALLOC); 11983737Shx147065 mutex_exit(&pcan_p->pcan_txring.an_tx_lock); 11993737Shx147065 12003737Shx147065 freemsg(mblk_p); 12013737Shx147065 mutex_exit(&pcan_p->pcan_glock); 12023737Shx147065 return (PCAN_SUCCESS); 12033737Shx147065 } 12043737Shx147065 12053737Shx147065 static mblk_t * 12063737Shx147065 pcan_tx(void *arg, mblk_t *mp) 12073737Shx147065 { 12083737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 12093737Shx147065 mblk_t *next; 12103737Shx147065 int ret = 0; 12113737Shx147065 12123737Shx147065 ASSERT(mp != NULL); 12133737Shx147065 mutex_enter(&pcan_p->pcan_glock); 12143737Shx147065 if ((pcan_p->pcan_flag & (PCAN_CARD_LINKUP | PCAN_CARD_READY)) != 12153737Shx147065 (PCAN_CARD_LINKUP | PCAN_CARD_READY)) { 12163737Shx147065 mutex_exit(&pcan_p->pcan_glock); 12173737Shx147065 return (mp); 12183737Shx147065 } 12193737Shx147065 mutex_exit(&pcan_p->pcan_glock); 12203737Shx147065 while (mp != NULL) { 12213737Shx147065 next = mp->b_next; 12223737Shx147065 mp->b_next = NULL; 12233737Shx147065 12243737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 12253737Shx147065 ret = pcian_send(pcan_p, mp); 12263737Shx147065 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) { 12273737Shx147065 ret = pcan_send(pcan_p, mp); 12283737Shx147065 } 12293737Shx147065 if (ret) { 12303737Shx147065 mp->b_next = next; 12313737Shx147065 break; 12323737Shx147065 } 12333737Shx147065 mp = next; 12343737Shx147065 } 12353737Shx147065 return (mp); 12363737Shx147065 } 12373737Shx147065 12383737Shx147065 /* 12393737Shx147065 * this driver is porting from freebsd, the code in freebsd 12403737Shx147065 * doesn't show how to set promiscous mode. 12413737Shx147065 */ 12423737Shx147065 /*ARGSUSED*/ 12433737Shx147065 static int 12443737Shx147065 pcan_prom(void *arg, boolean_t on) 12453737Shx147065 { 12463737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 12473737Shx147065 int ret = PCAN_SUCCESS; 12483737Shx147065 12493737Shx147065 mutex_enter(&pcan_p->pcan_glock); 12503737Shx147065 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) { 12513737Shx147065 ret = PCAN_FAIL; 12523737Shx147065 } 12533737Shx147065 mutex_exit(&pcan_p->pcan_glock); 12543737Shx147065 return (ret); 12553737Shx147065 } 12563737Shx147065 12573737Shx147065 /*ARGSUSED*/ 12583737Shx147065 static int 12593737Shx147065 pcan_gstat(void *arg, uint_t statitem, uint64_t *val) 12603737Shx147065 { 12613737Shx147065 uint16_t i; 12623737Shx147065 int ret = PCAN_SUCCESS; 12633737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 12643737Shx147065 uint64_t *cntr_p = pcan_p->pcan_cntrs_s; 12653737Shx147065 12663737Shx147065 PCANDBG((CE_NOTE, "pcan: gstat called\n")); 12673737Shx147065 12683737Shx147065 mutex_enter(&pcan_p->pcan_glock); 12693737Shx147065 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) { 12703737Shx147065 ret = PCAN_FAIL; 12713737Shx147065 goto done; 12723737Shx147065 } 12733737Shx147065 if (pcan_get_ltv(pcan_p, sizeof (pcan_p->an_stats), 12744343Sgd78059 AN_RID_16BITS_DELTACLR, (uint16_t *)&pcan_p->an_stats)) { 12753737Shx147065 cmn_err(CE_WARN, "pcan kstat: get ltv(32 delta statistics)" 12763737Shx147065 " failed \n"); 12773737Shx147065 ret = PCAN_FAIL; 12783737Shx147065 goto done; 12793737Shx147065 } 12803737Shx147065 for (i = 0; i < ANC_STAT_CNT; i++) { 12813737Shx147065 cntr_p[i] += *((uint16_t *)&pcan_p->an_stats + 1 + i); 12823737Shx147065 } 12833737Shx147065 if (pcan_status_ltv(PCAN_READ_LTV, pcan_p, &pcan_p->an_status)) { 12843737Shx147065 cmn_err(CE_WARN, "pcan kstat: read status failed \n"); 12853737Shx147065 ret = PCAN_FAIL; 12863737Shx147065 goto done; 12873737Shx147065 } 12883737Shx147065 12893737Shx147065 switch (statitem) { 12903737Shx147065 case MAC_STAT_IFSPEED: 12913737Shx147065 *val = 500000 * pcan_p->an_status.an_cur_tx_rate; 12923737Shx147065 break; 12933737Shx147065 case MAC_STAT_NOXMTBUF: 12943737Shx147065 *val = pcan_p->glds_noxmtbuf; 12953737Shx147065 break; 12963737Shx147065 case MAC_STAT_NORCVBUF: 12973737Shx147065 *val = pcan_p->glds_norcvbuf; 12983737Shx147065 break; 12993737Shx147065 case MAC_STAT_IERRORS: 13003737Shx147065 *val = cntr_p[ANC_RX_OVERRUNS] + 13013737Shx147065 cntr_p[ANC_RX_PLCP_CSUM_ERRS] + 13023737Shx147065 cntr_p[ANC_RX_PLCP_FORMAT_ERRS] + 13033737Shx147065 cntr_p[ANC_RX_PLCP_LEN_ERRS] + 13043737Shx147065 cntr_p[ANC_RX_MAC_CRC_ERRS] + 13053737Shx147065 cntr_p[ANC_RX_WEP_ERRS]; 13063737Shx147065 break; 13073737Shx147065 case MAC_STAT_OERRORS: 13083737Shx147065 *val = cntr_p[ANC_TX_HOST_FAILED]; 13093737Shx147065 break; 13103737Shx147065 case MAC_STAT_RBYTES: 13113737Shx147065 *val = cntr_p[ANC_HOST_RX_BYTES]; 13123737Shx147065 break; 13133737Shx147065 case MAC_STAT_IPACKETS: 13143737Shx147065 *val = cntr_p[ANC_RX_HOST_UCASTS]; 13153737Shx147065 break; 13163737Shx147065 case MAC_STAT_OBYTES: 13173737Shx147065 *val = cntr_p[ANC_HOST_TX_BYTES]; 13183737Shx147065 break; 13193737Shx147065 case MAC_STAT_OPACKETS: 13203737Shx147065 *val = cntr_p[ANC_TX_HOST_UCASTS]; 13213737Shx147065 break; 13223737Shx147065 case WIFI_STAT_TX_FAILED: 13233737Shx147065 *val = cntr_p[ANC_TX_HOST_FAILED]; 13243737Shx147065 break; 13253737Shx147065 case WIFI_STAT_TX_RETRANS: 13263737Shx147065 *val = cntr_p[ANC_HOST_RETRIES]; 13273737Shx147065 break; 13283737Shx147065 case WIFI_STAT_FCS_ERRORS: 13293737Shx147065 *val = cntr_p[ANC_RX_MAC_CRC_ERRS]; 13303737Shx147065 break; 13313737Shx147065 case WIFI_STAT_WEP_ERRORS: 13323737Shx147065 *val = cntr_p[ANC_RX_WEP_ERRS]; 13333737Shx147065 break; 13343737Shx147065 case WIFI_STAT_MCAST_TX: 13353737Shx147065 *val = cntr_p[ANC_TX_HOST_MCASTS]; 13363737Shx147065 break; 13373737Shx147065 case WIFI_STAT_MCAST_RX: 13383737Shx147065 *val = cntr_p[ANC_RX_HOST_MCASTS]; 13393737Shx147065 break; 13403737Shx147065 case WIFI_STAT_TX_FRAGS: 13413737Shx147065 case WIFI_STAT_RX_FRAGS: 13423737Shx147065 *val = 0; 13433737Shx147065 break; 13443737Shx147065 case WIFI_STAT_RTS_SUCCESS: 13453737Shx147065 *val = cntr_p[ANC_TX_RTS_OK]; 13463737Shx147065 break; 13473737Shx147065 case WIFI_STAT_RTS_FAILURE: 13483737Shx147065 *val = cntr_p[ANC_NO_CTS]; 13493737Shx147065 break; 13503737Shx147065 case WIFI_STAT_ACK_FAILURE: 13513737Shx147065 *val = cntr_p[ANC_NO_ACK]; 13523737Shx147065 break; 13533737Shx147065 case WIFI_STAT_RX_DUPS: 13543737Shx147065 *val = cntr_p[ANC_RX_DUPS]; 13553737Shx147065 break; 13563737Shx147065 default: 13573737Shx147065 ret = ENOTSUP; 13583737Shx147065 } 13593737Shx147065 13603737Shx147065 13613737Shx147065 done: 13623737Shx147065 mutex_exit(&pcan_p->pcan_glock); 13633737Shx147065 return (ret); 13643737Shx147065 } 13653737Shx147065 13663737Shx147065 /* 13673737Shx147065 * this driver is porting from freebsd, the code in freebsd 13683737Shx147065 * doesn't show how to set multi address. 13693737Shx147065 */ 13703737Shx147065 /*ARGSUSED*/ 13713737Shx147065 static int 13723737Shx147065 pcan_sdmulti(void *arg, boolean_t add, const uint8_t *eth_p) 13733737Shx147065 { 13743737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 13753737Shx147065 13763737Shx147065 mutex_enter(&pcan_p->pcan_glock); 13773737Shx147065 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) { 13783737Shx147065 mutex_exit(&pcan_p->pcan_glock); 13793737Shx147065 return (PCAN_FAIL); 13803737Shx147065 } 13813737Shx147065 mutex_exit(&pcan_p->pcan_glock); 13823737Shx147065 return (PCAN_SUCCESS); 13833737Shx147065 } 13843737Shx147065 13853737Shx147065 static uint_t 13863737Shx147065 pcan_info_softint(caddr_t arg) 13873737Shx147065 { 13883737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 13893737Shx147065 wifi_data_t wd = { 0 }; 13903737Shx147065 uint16_t link; 13913737Shx147065 uint32_t link_up; 13923737Shx147065 13933737Shx147065 mutex_enter(&pcan_p->pcan_glock); 13943737Shx147065 if (pcan_p->pcan_info_softint_pending != 1) { 13953737Shx147065 mutex_exit(&pcan_p->pcan_glock); 13963737Shx147065 return (DDI_INTR_UNCLAIMED); 13973737Shx147065 } 13983737Shx147065 13993737Shx147065 PCAN_READ(pcan_p, AN_LINKSTAT(pcan_p), link); 14003737Shx147065 link_up = pcan_p->pcan_flag & PCAN_CARD_LINKUP; 14013737Shx147065 if ((link == AN_LINKSTAT_ASSOCIATED) && !link_up) { 14023737Shx147065 pcan_p->pcan_flag |= PCAN_CARD_LINKUP; 14033737Shx147065 mutex_exit(&pcan_p->pcan_glock); 14043737Shx147065 if (pcan_p->pcan_connect_timeout_id != 0) { 14053737Shx147065 (void) untimeout(pcan_p->pcan_connect_timeout_id); 14063737Shx147065 pcan_p->pcan_connect_timeout_id = 0; 14073737Shx147065 } 14083737Shx147065 mac_link_update(GLD3(pcan_p), LINK_STATE_UP); 14093737Shx147065 mutex_enter(&pcan_p->pcan_glock); 14103737Shx147065 (void) pcan_status_ltv(PCAN_READ_LTV, pcan_p, 14113737Shx147065 &pcan_p->an_status); 14123737Shx147065 bcopy(pcan_p->an_status.an_cur_bssid, wd.wd_bssid, 6); 14133737Shx147065 wd.wd_secalloc = WIFI_SEC_NONE; 14143737Shx147065 wd.wd_opmode = IEEE80211_M_STA; 14153737Shx147065 (void) mac_pdata_update(pcan_p->pcan_mh, &wd, 14163737Shx147065 sizeof (wd)); 14173737Shx147065 #ifdef DEBUG 14183737Shx147065 if (pcan_debug & PCAN_DBG_LINKINFO) { 14193737Shx147065 cmn_err(CE_NOTE, "pcan: link Up, chan=%d, " 14203737Shx147065 "ssid=\"%s\"" 14213737Shx147065 " (%02x:%02x:%02x:%02x:%02x:%02x)\n", 14223737Shx147065 pcan_p->an_status.an_channel_set, 14233737Shx147065 pcan_p->an_status.an_ssid, 14243737Shx147065 pcan_p->an_status.an_cur_bssid[0], 14253737Shx147065 pcan_p->an_status.an_cur_bssid[1], 14263737Shx147065 pcan_p->an_status.an_cur_bssid[2], 14273737Shx147065 pcan_p->an_status.an_cur_bssid[3], 14283737Shx147065 pcan_p->an_status.an_cur_bssid[4], 14293737Shx147065 pcan_p->an_status.an_cur_bssid[5]); 14303737Shx147065 } 14313737Shx147065 #endif 14323737Shx147065 } 14333737Shx147065 if ((link != AN_LINKSTAT_ASSOCIATED) && link_up) { 14343737Shx147065 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP; 14353737Shx147065 #ifdef DEBUG 14363737Shx147065 if (pcan_debug & PCAN_DBG_LINKINFO) { 14373737Shx147065 cmn_err(CE_NOTE, "pcan: link Down 0x%x\n", link); 14383737Shx147065 } 14393737Shx147065 #endif 14403737Shx147065 if (link != AN_LINKSTAT_SYNCLOST_HOSTREQ) { 14413737Shx147065 pcan_p->pcan_connect_timeout_id = 14423737Shx147065 timeout(pcan_connect_timeout, 14433737Shx147065 pcan_p, drv_usectohz(1000)); 14443737Shx147065 } 14453737Shx147065 mutex_exit(&pcan_p->pcan_glock); 14463737Shx147065 mac_link_update(GLD3(pcan_p), LINK_STATE_DOWN); 14473737Shx147065 mutex_enter(&pcan_p->pcan_glock); 14483737Shx147065 } 14493737Shx147065 14503737Shx147065 pcan_p->pcan_info_softint_pending = 0; 14513737Shx147065 mutex_exit(&pcan_p->pcan_glock); 14523737Shx147065 return (DDI_INTR_CLAIMED); 14533737Shx147065 } 14543737Shx147065 14553737Shx147065 static uint_t 14563737Shx147065 pcan_intr(caddr_t arg) 14573737Shx147065 { 14583737Shx147065 uint16_t stat; 14593737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 14603737Shx147065 14613737Shx147065 mutex_enter(&pcan_p->pcan_glock); 14623737Shx147065 if ((pcan_p->pcan_flag & (PCAN_CARD_READY | PCAN_CARD_INTREN)) != 14633737Shx147065 (PCAN_CARD_READY | PCAN_CARD_INTREN)) { 14643737Shx147065 mutex_exit(&pcan_p->pcan_glock); 14653737Shx147065 return (DDI_INTR_UNCLAIMED); 14663737Shx147065 } 14673737Shx147065 PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat); 14683737Shx147065 14693737Shx147065 if (!(stat & AN_INTRS(pcan_p)) || stat == AN_EV_ALL) { 14703737Shx147065 mutex_exit(&pcan_p->pcan_glock); 14713737Shx147065 return (DDI_INTR_UNCLAIMED); 14723737Shx147065 } 14733737Shx147065 14743737Shx147065 PCAN_DISABLE_INTR(pcan_p); 14753737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), ~AN_INTRS(pcan_p)); 14763737Shx147065 14773737Shx147065 PCANDBG((CE_NOTE, "pcan intr: stat=%x pcan_flags=%x\n", stat, 14784343Sgd78059 pcan_p->pcan_flag)); 14793737Shx147065 14803737Shx147065 if (stat & AN_EV_AWAKE) { 14813737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_AWAKE); 14823737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_AWAKE); 14833737Shx147065 } 14843737Shx147065 if (stat & AN_EV_LINKSTAT) { 14853737Shx147065 pcan_p->pcan_info_softint_pending = 1; 14863737Shx147065 ddi_trigger_softintr(pcan_p->pcan_info_softint_id); 14873737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_LINKSTAT); 14883737Shx147065 } 14893737Shx147065 if (stat & AN_EV_RX) { 14903737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 14913737Shx147065 pcian_rcv(pcan_p); 14923737Shx147065 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) { 14933737Shx147065 pcan_rcv(pcan_p); 14943737Shx147065 } 14953737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_RX); 14963737Shx147065 } 14973737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 14983737Shx147065 if (stat & AN_EV_TX_CPY) { 14993737Shx147065 (void) pcan_txdone(pcan_p, stat & AN_EV_TX_CPY); 15003737Shx147065 if (pcan_p->pcan_reschedule_need == B_TRUE) { 15013737Shx147065 mac_tx_update(GLD3(pcan_p)); 15023737Shx147065 pcan_p->pcan_reschedule_need = B_FALSE; 15033737Shx147065 } 15043737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_TX_CPY); 15053737Shx147065 } 15063737Shx147065 } 15073737Shx147065 if (stat & AN_EV_TX) { 15083737Shx147065 if (pcan_txdone(pcan_p, stat & AN_EV_TX) == 0) { 15093737Shx147065 if (pcan_p->pcan_reschedule_need == B_TRUE) { 15103737Shx147065 mac_tx_update(GLD3(pcan_p)); 15113737Shx147065 pcan_p->pcan_reschedule_need = B_FALSE; 15123737Shx147065 } 15133737Shx147065 } 15143737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_TX); 15153737Shx147065 } 15163737Shx147065 if (stat & AN_EV_TX_EXC) { 15173737Shx147065 if (pcan_txdone(pcan_p, stat & AN_EV_TX_EXC) == 0) { 15183737Shx147065 if (pcan_p->pcan_reschedule_need == B_TRUE) { 15193737Shx147065 mutex_exit(&pcan_p->pcan_glock); 15203737Shx147065 mac_tx_update(GLD3(pcan_p)); 15213737Shx147065 mutex_enter(&pcan_p->pcan_glock); 15223737Shx147065 pcan_p->pcan_reschedule_need = B_FALSE; 15233737Shx147065 } 15243737Shx147065 } 15253737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_TX_EXC); 15263737Shx147065 } 15273737Shx147065 if (stat & AN_EV_ALLOC) { 15283737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_ALLOC); 15293737Shx147065 PCANDBG((CE_NOTE, "pcan intr: nicmem alloc done\n")); 15303737Shx147065 } 15313737Shx147065 if (stat & AN_EV_MIC) { 15323737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_MIC); 15333737Shx147065 } 15343737Shx147065 PCAN_ENABLE_INTR(pcan_p); 15353737Shx147065 mutex_exit(&pcan_p->pcan_glock); 15363737Shx147065 return (DDI_INTR_CLAIMED); 15373737Shx147065 } 15383737Shx147065 15393737Shx147065 static uint_t 15403737Shx147065 pcan_intr_hi(caddr_t arg) 15413737Shx147065 { 15423737Shx147065 uint16_t stat; 15433737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 15443737Shx147065 15453737Shx147065 mutex_enter(&pcan_p->pcan_glock); 15463737Shx147065 if ((pcan_p->pcan_flag & (PCAN_CARD_READY | PCAN_CARD_INTREN)) != 15473737Shx147065 (PCAN_CARD_READY | PCAN_CARD_INTREN)) { 15483737Shx147065 mutex_exit(&pcan_p->pcan_glock); 15493737Shx147065 return (DDI_INTR_UNCLAIMED); 15503737Shx147065 } 15513737Shx147065 PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat); 15523737Shx147065 PCANDBG((CE_NOTE, "pcan intr(hi): stat=%x pcan_flags=%x\n", stat, 15533737Shx147065 pcan_p->pcan_flag)); 15543737Shx147065 15553737Shx147065 if (!(stat & AN_INTRS(pcan_p)) || stat == AN_EV_ALL) { 15563737Shx147065 mutex_exit(&pcan_p->pcan_glock); 15573737Shx147065 return (DDI_INTR_UNCLAIMED); 15583737Shx147065 } 15593737Shx147065 /* disable interrupt without ack */ 15603737Shx147065 PCAN_WRITE(pcan_p, AN_INT_EN(pcan_p), 0); 15613737Shx147065 mutex_exit(&pcan_p->pcan_glock); 15623737Shx147065 ddi_trigger_softintr(pcan_p->pcan_softint_id); 15633737Shx147065 return (DDI_INTR_CLAIMED); 15643737Shx147065 } 15653737Shx147065 15663737Shx147065 /* 15673737Shx147065 * retrieve data from pccard 15683737Shx147065 */ 15693737Shx147065 static void 15703737Shx147065 pcan_rcv(pcan_maci_t *pcan_p) 15713737Shx147065 { 15723737Shx147065 uint16_t id, off, ret, data_len, pkt_stat, frm_ctl; 15733737Shx147065 an_rxfrm_t frm; 15743737Shx147065 struct ieee80211_llc *llc; 15753737Shx147065 15763737Shx147065 mblk_t *mp = allocb(PCAN_NICMEM_SZ, BPRI_MED); 15773737Shx147065 if (!mp) { 15783737Shx147065 cmn_err(CE_WARN, "pcan: failed to alloc rcv buf"); 15793737Shx147065 pcan_p->glds_norcvbuf++; 15803737Shx147065 return; 15813737Shx147065 } 15823737Shx147065 ASSERT(mp->b_rptr == mp->b_wptr); 15833737Shx147065 15843737Shx147065 PCAN_READ(pcan_p, AN_RX_FID, id); 15853737Shx147065 if (id == AN_INVALID_FID) { 15863737Shx147065 PCANDBG((CE_NOTE, "pcan rcv: can't get rx_fid\n")); 15873737Shx147065 pcan_p->glds_norcvbuf++; 15883737Shx147065 ret = PCAN_FAIL; 15893737Shx147065 goto done; 15903737Shx147065 } 15913737Shx147065 if (ret = RDCH0(pcan_p, id, 0, (uint16_t *)&frm, sizeof (frm))) { 15923737Shx147065 PCANDBG((CE_NOTE, "pcan rcv: read frm err %x\n", ret)); 15933737Shx147065 goto done; 15943737Shx147065 } 15953737Shx147065 off = sizeof (frm); 15963737Shx147065 if (frm.an_rx_status) { 15973737Shx147065 PCANDBG((CE_NOTE, "pcan rcv: err stat %x\n", frm.an_rx_status)); 15983737Shx147065 ret = frm.an_rx_status; 15993737Shx147065 goto done; 16003737Shx147065 } 16013737Shx147065 PCANDBG((CE_NOTE, "pcan rcv: payload_len=%x gap_len=%x\n", 16023737Shx147065 frm.an_rx_payload_len, frm.an_gaplen)); 16033737Shx147065 if (frm.an_rx_payload_len > PCAN_NICMEM_SZ || 16043737Shx147065 frm.an_gaplen > AN_RXGAP_MAX) { 16053737Shx147065 PCANDBG((CE_NOTE, "pcan rcv: bad len\n")); 16063737Shx147065 ret = PCAN_FAIL; 16073737Shx147065 goto done; 16083737Shx147065 } 16093737Shx147065 if (ret = RDCH0(pcan_p, id, off, &pkt_stat, sizeof (pkt_stat))) { 16103737Shx147065 PCANDBG((CE_NOTE, "pcan rcv: pkt status err %x\n", ret)); 16113737Shx147065 ret = PCAN_FAIL; 16123737Shx147065 goto done; 16133737Shx147065 } 16143737Shx147065 off += sizeof (pkt_stat); 16153737Shx147065 if (ret = RDCH0(pcan_p, id, off, &data_len, sizeof (data_len))) { 16163737Shx147065 PCANDBG((CE_NOTE, "pcan rcv: payload len err %x\n", ret)); 16173737Shx147065 ret = PCAN_FAIL; 16183737Shx147065 goto done; 16193737Shx147065 } 16203737Shx147065 off += sizeof (data_len); 16213737Shx147065 off += ETHERADDRL << 1; 16223737Shx147065 PCANDBG((CE_NOTE, "pcan rcv: pkt_stat=%x payload_len=%x+c off=%x\n", 16234343Sgd78059 pkt_stat, data_len, off)); 16243737Shx147065 16253737Shx147065 #ifdef DEBUG 16263737Shx147065 if (pcan_debug & PCAN_DBG_RCV) { 16273737Shx147065 int i; 16283737Shx147065 cmn_err(CE_NOTE, "pcan rcv: frm header\n"); 16293737Shx147065 for (i = 0; i < sizeof (frm); i++) 16303737Shx147065 cmn_err(CE_NOTE, "%x: %x\n", i, 16313737Shx147065 *((uint8_t *)&frm + i)); 16323737Shx147065 } 16333737Shx147065 #endif 16343737Shx147065 /* 16353737Shx147065 * this driver deal with WEP by itself. so plugin always thinks no wep. 16363737Shx147065 */ 16373737Shx147065 frm.an_frame_ctl &= ~(IEEE80211_FC1_WEP << 8); 16383737Shx147065 frm_ctl = frm.an_frame_ctl; 16393737Shx147065 PCAN_SWAP16((uint16_t *)&frm.an_frame_ctl, 16403737Shx147065 sizeof (struct ieee80211_frame)); 16413737Shx147065 /* 16423737Shx147065 * discard those frames which are not from the AP we connect or 16433737Shx147065 * without 'ap->sta' direction 16443737Shx147065 */ 16453737Shx147065 if (((pcan_p->an_config.an_opmode == AN_OPMODE_INFR_STATION)) && 16463737Shx147065 ((((frm_ctl >> 8) & IEEE80211_FC1_DIR_MASK) != 16473737Shx147065 IEEE80211_FC1_DIR_FROMDS) || 16483737Shx147065 bcmp(pcan_p->an_status.an_cur_bssid, frm.an_addr2, 6) != 0)) { 16493737Shx147065 ret = PCAN_FAIL; 16503737Shx147065 goto done; 16513737Shx147065 } 16523737Shx147065 bcopy(&frm.an_frame_ctl, mp->b_wptr, 16533737Shx147065 sizeof (struct ieee80211_frame)); 16543737Shx147065 mp->b_wptr += sizeof (struct ieee80211_frame); 16553737Shx147065 16563737Shx147065 /* the plugin need a llc here */ 16573737Shx147065 llc = (struct ieee80211_llc *)mp->b_wptr; 16583737Shx147065 llc->illc_dsap = llc->illc_ssap = AN_SNAP_K1; 16593737Shx147065 llc->illc_control = AN_SNAP_CONTROL; 16603737Shx147065 bzero(llc->illc_oc, sizeof (llc->illc_oc)); 16613737Shx147065 mp->b_wptr += AN_SNAPHDR_LEN; 16623737Shx147065 16633737Shx147065 /* read in the rest of data */ 16643737Shx147065 data_len += data_len & 1; /* adjust to word boundary */ 16653737Shx147065 if (data_len > MBLKSIZE(mp)) { 16663737Shx147065 cmn_err(CE_NOTE, "pcan rcv: data over length%x\n", data_len); 16673737Shx147065 ret = PCAN_FAIL; 16683737Shx147065 goto done; 16693737Shx147065 } 16703737Shx147065 16713737Shx147065 if (ret = RDPKT(pcan_p, id, off, (uint16_t *)mp->b_wptr, data_len)) { 16723737Shx147065 PCANDBG((CE_NOTE, "pcan rcv: err read data %x\n", ret)); 16733737Shx147065 } 16743737Shx147065 done: 16753737Shx147065 if (ret) { 16763737Shx147065 PCANDBG((CE_NOTE, "pcan rcv: rd data %x\n", ret)); 16773737Shx147065 freemsg(mp); 16783737Shx147065 return; 16793737Shx147065 } 16803737Shx147065 mp->b_wptr += data_len; 16813737Shx147065 #ifdef DEBUG 16823737Shx147065 if (pcan_debug & PCAN_DBG_RCV) { 16833737Shx147065 int i; 16843737Shx147065 cmn_err(CE_NOTE, "pcan rcv: len=0x%x\n", data_len); 16853737Shx147065 for (i = 0; i < data_len + sizeof (frm); i++) 16863737Shx147065 cmn_err(CE_NOTE, "%x: %x\n", i, 16873737Shx147065 *((uint8_t *)mp->b_rptr + i)); 16883737Shx147065 } 16893737Shx147065 #endif 16903737Shx147065 mutex_exit(&pcan_p->pcan_glock); 16913737Shx147065 mac_rx(GLD3(pcan_p), NULL, mp); 16923737Shx147065 mutex_enter(&pcan_p->pcan_glock); 16933737Shx147065 } 16943737Shx147065 16953737Shx147065 /* 16963737Shx147065 * retrieve data from mini-pci card 16973737Shx147065 */ 16983737Shx147065 static void 16993737Shx147065 pcian_rcv(pcan_maci_t *pcan_p) 17003737Shx147065 { 17013737Shx147065 struct an_card_rx_desc an_rx_desc; 17023737Shx147065 char *buf; 17033737Shx147065 uint16_t ret = 0, data_len; 17043737Shx147065 int i, j; 17053737Shx147065 struct ieee80211_frame *frm; 17063737Shx147065 struct ieee80211_llc *llc; 17073737Shx147065 17083737Shx147065 mblk_t *mp = allocb(AN_RX_BUFFER_SIZE, BPRI_MED); 17093737Shx147065 if (!mp) { 17103737Shx147065 cmn_err(CE_WARN, "pcan(pci): failed to alloc rcv buf"); 17113737Shx147065 pcan_p->glds_norcvbuf++; 17123737Shx147065 return; 17133737Shx147065 } 17143737Shx147065 ASSERT(mp->b_rptr == mp->b_wptr); 17153737Shx147065 17163737Shx147065 for (i = 0; i < sizeof (an_rx_desc) / 4; i++) 17173737Shx147065 PCAN_AUX_GET32(pcan_p, AN_RX_DESC_OFFSET + (i * 4), 17183737Shx147065 ((uint32_t *)&an_rx_desc)[i]); 17193737Shx147065 if (an_rx_desc.an_done && !an_rx_desc.an_valid) { 17203737Shx147065 buf = pcan_p->pcan_rx[0].dma_virtaddr; 17213737Shx147065 data_len = an_rx_desc.an_len; 17223737Shx147065 #ifdef DEBUG 17233737Shx147065 if (pcan_debug & PCAN_DBG_RCV) { 17243737Shx147065 cmn_err(CE_NOTE, "pcan(pci) rcv: data_len=%x", 17253737Shx147065 data_len); 17263737Shx147065 for (j = 0; j < data_len + 14; j++) 17273737Shx147065 cmn_err(CE_NOTE, "pcan_rcv %d: %x", j, 17283737Shx147065 *((uint8_t *)buf + j)); 17293737Shx147065 } 17303737Shx147065 #endif 17313737Shx147065 if (data_len > MBLKSIZE(mp)) { 17323737Shx147065 cmn_err(CE_NOTE, "pcan(pci) rcv: data over length%x\n", 17333737Shx147065 data_len); 17343737Shx147065 ret = PCAN_FAIL; 17353737Shx147065 goto done; 17363737Shx147065 } 17373737Shx147065 /* 17383737Shx147065 * minipci card receive an ethernet frame, so assembly a 802.11 17393737Shx147065 * frame here manually. 17403737Shx147065 */ 17413737Shx147065 frm = (struct ieee80211_frame *)mp->b_wptr; 17423737Shx147065 bzero(frm, sizeof (*frm)); 17433737Shx147065 frm->i_fc[0] |= IEEE80211_FC0_TYPE_DATA; 17443737Shx147065 frm->i_fc[1] |= IEEE80211_FC1_DIR_FROMDS; 17453737Shx147065 bcopy(pcan_p->an_status.an_cur_bssid, frm->i_addr2, 6); 17463737Shx147065 bcopy(buf, frm->i_addr1, 6); 17473737Shx147065 bcopy(buf + 6, frm->i_addr3, 6); 17483737Shx147065 mp->b_wptr += sizeof (struct ieee80211_frame); 17493737Shx147065 17503737Shx147065 llc = (struct ieee80211_llc *)mp->b_wptr; 17513737Shx147065 llc->illc_dsap = llc->illc_ssap = AN_SNAP_K1; 17523737Shx147065 llc->illc_control = AN_SNAP_CONTROL; 17533737Shx147065 bzero(llc->illc_oc, sizeof (llc->illc_oc)); 17543737Shx147065 mp->b_wptr += AN_SNAPHDR_LEN; 17553737Shx147065 17563737Shx147065 bcopy(buf + 12, mp->b_wptr, data_len); 17573737Shx147065 mp->b_wptr += data_len; 17583737Shx147065 #ifdef DEBUG 17593737Shx147065 if (pcan_debug & PCAN_DBG_RCV) { 17603737Shx147065 int i; 17613737Shx147065 cmn_err(CE_NOTE, "pcan(pci) rcv: len=0x%x\n", data_len); 17623737Shx147065 for (i = 0; i < data_len + sizeof (*frm) 17633737Shx147065 + sizeof (*llc); i++) 17643737Shx147065 cmn_err(CE_NOTE, "%x: %x\n", i, 17653737Shx147065 *((uint8_t *)mp->b_rptr + i)); 17663737Shx147065 } 17673737Shx147065 #endif 17683737Shx147065 mutex_exit(&pcan_p->pcan_glock); 17693737Shx147065 mac_rx(GLD3(pcan_p), NULL, mp); 17703737Shx147065 mutex_enter(&pcan_p->pcan_glock); 17713737Shx147065 } 17723737Shx147065 done: 17733737Shx147065 bzero(&an_rx_desc, sizeof (an_rx_desc)); 17743737Shx147065 an_rx_desc.an_valid = 1; 17753737Shx147065 an_rx_desc.an_len = AN_RX_BUFFER_SIZE; 17763737Shx147065 an_rx_desc.an_done = 0; 17773737Shx147065 an_rx_desc.an_phys = pcan_p->pcan_rx[0].dma_physaddr; 17783737Shx147065 17793737Shx147065 for (i = 0; i < sizeof (an_rx_desc) / 4; i++) 17803737Shx147065 PCAN_AUX_PUT32(pcan_p, AN_RX_DESC_OFFSET + (i * 4), 17813737Shx147065 ((uint32_t *)&an_rx_desc)[i]); 17823737Shx147065 if (ret) { 17833737Shx147065 freemsg(mp); 17843737Shx147065 } 17853737Shx147065 } 17863737Shx147065 17873737Shx147065 /*ARGSUSED*/ 17883737Shx147065 static uint32_t 17893737Shx147065 pcan_txdone(pcan_maci_t *pcan_p, uint16_t err) 17903737Shx147065 { 17913737Shx147065 uint16_t fid, i, ring_idx; 17923737Shx147065 uint32_t ret = 0; 17933737Shx147065 17943737Shx147065 PCAN_READ(pcan_p, AN_TX_CMP_FID(pcan_p), fid); 17953737Shx147065 mutex_enter(&pcan_p->pcan_txring.an_tx_lock); 17963737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 17973737Shx147065 if (pcan_p->pcan_flag & PCAN_CARD_SEND) { 17983737Shx147065 ring_idx = pcan_p->pcan_txring.an_tx_cons; 17993737Shx147065 pcan_p->pcan_txring.an_tx_cons = 18003737Shx147065 (ring_idx + 1) % AN_MAX_TX_DESC; 18013737Shx147065 if (pcan_p->pcan_txring.an_tx_prod == 18023737Shx147065 pcan_p->pcan_txring.an_tx_cons) { 18033737Shx147065 pcan_p->pcan_flag &= ~PCAN_CARD_SEND; 18043737Shx147065 } 18053737Shx147065 } 18063737Shx147065 ret = 0; 18073737Shx147065 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) { 18083737Shx147065 for (i = 0; i < AN_TX_RING_CNT; i++) { 18093737Shx147065 if (fid == pcan_p->pcan_txring.an_tx_ring[i]) { 18103737Shx147065 pcan_p->pcan_txring.an_tx_ring[i] = 0; 18113737Shx147065 break; 18123737Shx147065 } 18133737Shx147065 } 18143737Shx147065 pcan_p->pcan_txring.an_tx_cons = 18153737Shx147065 (pcan_p->pcan_txring.an_tx_cons + 1) & AN_TX_RING_MASK; 18163737Shx147065 ret = (i == AN_TX_RING_CNT ? 1 : 0); 18173737Shx147065 } 18183737Shx147065 mutex_exit(&pcan_p->pcan_txring.an_tx_lock); 18193737Shx147065 return (ret); 18203737Shx147065 } 18213737Shx147065 18223737Shx147065 /* 18233737Shx147065 * delay in which the mutex is not hold. 18243737Shx147065 * assuming the mutex has already been hold. 18253737Shx147065 */ 18263737Shx147065 static void 18273737Shx147065 pcan_delay(pcan_maci_t *pcan_p, clock_t microsecs) 18283737Shx147065 { 18293737Shx147065 ASSERT(mutex_owned(&pcan_p->pcan_glock)); 18303737Shx147065 18313737Shx147065 mutex_exit(&pcan_p->pcan_glock); 18323737Shx147065 delay(drv_usectohz(microsecs)); 18333737Shx147065 mutex_enter(&pcan_p->pcan_glock); 18343737Shx147065 } 18353737Shx147065 18363737Shx147065 static void 18373737Shx147065 pcan_reset_backend(pcan_maci_t *pcan_p, int timeout) 18383737Shx147065 { 18393737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 18403737Shx147065 (void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0); 18413737Shx147065 PCAN_DISABLE_INTR_CLEAR(pcan_p); 18423737Shx147065 (void) pcan_set_cmd(pcan_p, AN_CMD_FW_RESTART, 0); 18433737Shx147065 (void) pcan_set_cmd(pcan_p, AN_CMD_NOOP2, 0); 18443737Shx147065 (void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0); 18453737Shx147065 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) { 18463737Shx147065 (void) pcan_set_cmd0(pcan_p, AN_CMD_DISABLE, 0, 0, 0); 18473737Shx147065 (void) pcan_set_cmd0(pcan_p, AN_CMD_NOOP2, 0, 0, 0); 18483737Shx147065 PCAN_WRITE(pcan_p, AN_COMMAND(pcan_p), AN_CMD_FW_RESTART); 18493737Shx147065 pcan_delay(pcan_p, timeout); /* wait for firmware restart */ 18503737Shx147065 18513737Shx147065 (void) pcan_set_cmd(pcan_p, AN_CMD_NOOP, 0); 18523737Shx147065 (void) pcan_set_cmd0(pcan_p, AN_CMD_DISABLE, 0, 0, 0); 18533737Shx147065 18543737Shx147065 PCAN_DISABLE_INTR_CLEAR(pcan_p); 18553737Shx147065 } 18563737Shx147065 } 18573737Shx147065 18583737Shx147065 /* 18593737Shx147065 * set command without the need of ACK. 18603737Shx147065 */ 18613737Shx147065 static uint16_t 18623737Shx147065 pcan_set_cmd0(pcan_maci_t *pcan_p, uint16_t cmd, uint16_t p0, 18633737Shx147065 uint16_t p1, uint16_t p2) 18643737Shx147065 { 18653737Shx147065 int i; 18663737Shx147065 uint16_t stat, r0, r1, r2; 18673737Shx147065 18683737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 18693737Shx147065 for (i = 0; i < AN_TIMEOUT; i++) { 18703737Shx147065 PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat); 18713737Shx147065 if (!(stat & AN_CMD_BUSY)) 18723737Shx147065 break; 18733737Shx147065 } 18743737Shx147065 if (i == AN_TIMEOUT) { 18753737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), 18763737Shx147065 AN_EV_CLR_STUCK_BUSY); 18773737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD); 18783737Shx147065 drv_usecwait(10); 18793737Shx147065 } 18803737Shx147065 PCAN_WRITE(pcan_p, AN_PARAM0(pcan_p), p0); 18813737Shx147065 PCAN_WRITE(pcan_p, AN_PARAM1(pcan_p), p1); 18823737Shx147065 PCAN_WRITE(pcan_p, AN_PARAM2(pcan_p), p2); 18833737Shx147065 } 18843737Shx147065 PCAN_WRITE(pcan_p, AN_COMMAND(pcan_p), cmd); 18853737Shx147065 for (i = 0; i < AN_TIMEOUT; i++) { 18863737Shx147065 PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat); 18873737Shx147065 if (stat & AN_EV_CMD) 18883737Shx147065 break; 18893737Shx147065 } 18903737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 18913737Shx147065 PCAN_READ(pcan_p, AN_RESP0(pcan_p), r0); 18923737Shx147065 PCAN_READ(pcan_p, AN_RESP1(pcan_p), r1); 18933737Shx147065 PCAN_READ(pcan_p, AN_RESP2(pcan_p), r2); 18943737Shx147065 PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat); 18953737Shx147065 if (stat & AN_CMD_BUSY) 18963737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), 18973737Shx147065 AN_EV_CLR_STUCK_BUSY); 18983737Shx147065 PCANDBG((CE_NOTE, "pcan set_cmd0: " 18993737Shx147065 "stat=%x, r0=%x, r1=%x, r2=%x\n", 19003737Shx147065 stat, r0, r1, r2)); 19013737Shx147065 } 19023737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD); 19033737Shx147065 return (i == AN_TIMEOUT ? PCAN_TIMEDOUT_ACCESS : PCAN_SUCCESS); 19043737Shx147065 } 19053737Shx147065 19063737Shx147065 static uint16_t 19073737Shx147065 pcan_set_cmd(pcan_maci_t *pcan_p, uint16_t cmd, uint16_t param) 19083737Shx147065 { 19093737Shx147065 int i; 19103737Shx147065 uint16_t stat, r0, r1, r2; 19113737Shx147065 uint16_t ret; 19123737Shx147065 19133737Shx147065 if (((cmd == AN_CMD_ENABLE) && 19143737Shx147065 ((pcan_p->pcan_flag & PCAN_ENABLED) != 0)) || 19153737Shx147065 ((cmd == AN_CMD_DISABLE) && 19163737Shx147065 ((pcan_p->pcan_flag & PCAN_ENABLED) == 0))) 19173737Shx147065 return (PCAN_SUCCESS); 19183737Shx147065 for (i = 0; i < AN_TIMEOUT; i++) { 19193737Shx147065 PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat); 19203737Shx147065 if (!(stat & AN_CMD_BUSY)) { 19213737Shx147065 break; 19223737Shx147065 } 19233737Shx147065 } 19243737Shx147065 if (i == AN_TIMEOUT) { 19253737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CLR_STUCK_BUSY); 19263737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD); 19273737Shx147065 drv_usecwait(10); 19283737Shx147065 } 19293737Shx147065 19303737Shx147065 PCAN_WRITE(pcan_p, AN_PARAM0(pcan_p), param); 19313737Shx147065 PCAN_WRITE(pcan_p, AN_PARAM1(pcan_p), 0); 19323737Shx147065 PCAN_WRITE(pcan_p, AN_PARAM2(pcan_p), 0); 19333737Shx147065 PCAN_WRITE(pcan_p, AN_COMMAND(pcan_p), cmd); 19343737Shx147065 19353737Shx147065 for (i = 0; i < AN_TIMEOUT; i++) { 19363737Shx147065 PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat); 19373737Shx147065 if (stat & AN_EV_CMD) { 19383737Shx147065 break; 19393737Shx147065 } 19403737Shx147065 PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat); 19413737Shx147065 if (stat == cmd) 19423737Shx147065 PCAN_WRITE(pcan_p, AN_COMMAND(pcan_p), cmd); 19433737Shx147065 } 19443737Shx147065 if (i == AN_TIMEOUT) { 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 #ifdef DEBUG 19503737Shx147065 if (pcan_debug & PCAN_DBG_CMD) { 19513737Shx147065 cmn_err(CE_WARN, "pcan set_cmd: %x timeout stat=%x\n", 19523737Shx147065 cmd, stat); 19533737Shx147065 } 19543737Shx147065 #endif 19553737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD); 19563737Shx147065 return (PCAN_TIMEDOUT_CMD); 19573737Shx147065 } 19583737Shx147065 19593737Shx147065 for (i = 0; i < AN_TIMEOUT; i++) { 19603737Shx147065 PCAN_READ(pcan_p, AN_STATUS(pcan_p), stat); 19613737Shx147065 PCAN_READ(pcan_p, AN_RESP0(pcan_p), r0); 19623737Shx147065 PCAN_READ(pcan_p, AN_RESP1(pcan_p), r1); 19633737Shx147065 PCAN_READ(pcan_p, AN_RESP2(pcan_p), r2); 19643737Shx147065 if ((stat & AN_STAT_CMD_CODE) == (cmd & AN_STAT_CMD_CODE)) 19653737Shx147065 break; 19663737Shx147065 } 19673737Shx147065 if (cmd == AN_CMD_FW_RESTART) { 19683737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD); 19693737Shx147065 return (PCAN_SUCCESS); 19703737Shx147065 } 19713737Shx147065 if (i == AN_TIMEOUT) { 19723737Shx147065 #ifdef DEBUG 19733737Shx147065 if (pcan_debug & PCAN_DBG_CMD) { 19743737Shx147065 cmn_err(CE_WARN, "pcan set_cmd<%x,%x>: timeout " 19753737Shx147065 "%x,%x,%x,%x\n", cmd, param, stat, r0, r1, r2); 19763737Shx147065 } 19773737Shx147065 #endif 19783737Shx147065 ret = PCAN_TIMEDOUT_ACCESS; 19793737Shx147065 } else { 19803737Shx147065 if (stat & AN_STAT_CMD_RESULT) { 19813737Shx147065 #ifdef DEBUG 19823737Shx147065 if (pcan_debug & PCAN_DBG_CMD) { 19833737Shx147065 cmn_err(CE_WARN, "pcan set_cmd<%x,%x>: failed " 19843737Shx147065 "%x,%x,%x,%x\n", 19853737Shx147065 cmd, param, stat, r0, r1, r2); 19863737Shx147065 } 19873737Shx147065 #endif 19883737Shx147065 ret = PCAN_TIMEDOUT_ACCESS; 19893737Shx147065 } else { 19903737Shx147065 ret = PCAN_SUCCESS; 19913737Shx147065 } 19923737Shx147065 } 19933737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD); 19943737Shx147065 PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat); 19953737Shx147065 if (stat & AN_CMD_BUSY) 19963737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CLR_STUCK_BUSY); 19973737Shx147065 if (ret == PCAN_SUCCESS) { 19983737Shx147065 if (cmd == AN_CMD_ENABLE) 19993737Shx147065 pcan_p->pcan_flag |= PCAN_ENABLED; 20003737Shx147065 if (cmd == AN_CMD_DISABLE) 20013737Shx147065 pcan_p->pcan_flag &= (~PCAN_ENABLED); 20023737Shx147065 } 20033737Shx147065 return (ret); 20043737Shx147065 } 20053737Shx147065 20063737Shx147065 static uint16_t 20073737Shx147065 pcan_set_ch(pcan_maci_t *pcan_p, uint16_t type, uint16_t off, uint16_t channel) 20083737Shx147065 { 20093737Shx147065 int i; 20103737Shx147065 uint16_t stat, select, offset; 20113737Shx147065 20123737Shx147065 if (channel) { 20133737Shx147065 select = AN_SEL1; 20143737Shx147065 offset = AN_OFF1; 20153737Shx147065 } else { 20163737Shx147065 select = AN_SEL0; 20173737Shx147065 offset = AN_OFF0; 20183737Shx147065 } 20193737Shx147065 PCAN_WRITE(pcan_p, select, type); 20203737Shx147065 PCAN_WRITE(pcan_p, offset, off); 20213737Shx147065 for (i = 0; i < AN_TIMEOUT; i++) { 20223737Shx147065 PCAN_READ(pcan_p, offset, stat); 20233737Shx147065 if (!(stat & (AN_OFF_BUSY|AN_OFF_ERR))) 20243737Shx147065 break; 20253737Shx147065 } 20263737Shx147065 if (stat & (AN_OFF_BUSY|AN_OFF_ERR)) { /* time out */ 20273737Shx147065 PCANDBG((CE_WARN, "pcan: set_ch%d %x %x TO %x\n", 20283737Shx147065 channel, type, off, stat)); 20293737Shx147065 return (PCAN_TIMEDOUT_TARGET); 20303737Shx147065 } 20313737Shx147065 return (PCAN_SUCCESS); 20323737Shx147065 } 20333737Shx147065 20343737Shx147065 static uint16_t 20353737Shx147065 pcan_get_ltv(pcan_maci_t *pcan_p, uint16_t len, uint16_t type, uint16_t *val_p) 20363737Shx147065 { 20373737Shx147065 uint16_t stat; 20383737Shx147065 20393737Shx147065 PCANDBG((CE_NOTE, "pcan: get_ltv(%p,%x,%x,%p)\n", 20404343Sgd78059 (void *)pcan_p, len, type, (void *)val_p)); 20413737Shx147065 ASSERT(!(len & 1)); 20423737Shx147065 20433737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 20443737Shx147065 uint32_t i; 20453737Shx147065 struct an_card_rid_desc an_rid_desc; 20463737Shx147065 struct an_ltv_gen *an_ltv; 20473737Shx147065 if (!pcan_p->pcan_cmd.dma_virtaddr) 20483737Shx147065 return (EIO); 20493737Shx147065 an_rid_desc.an_valid = 1; 20503737Shx147065 an_rid_desc.an_len = AN_RID_BUFFER_SIZE; 20513737Shx147065 an_rid_desc.an_rid = 0; 20523737Shx147065 an_rid_desc.an_phys = pcan_p->pcan_cmd.dma_physaddr; 20533737Shx147065 bzero(pcan_p->pcan_cmd.dma_virtaddr, AN_RID_BUFFER_SIZE); 20543737Shx147065 20553737Shx147065 for (i = 0; i < sizeof (an_rid_desc) / 4; i++) 20563737Shx147065 PCAN_AUX_PUT32(pcan_p, AN_HOST_DESC_OFFSET + i * 4, 20573737Shx147065 ((uint32_t *)&an_rid_desc)[i]); 20583737Shx147065 20593737Shx147065 if (pcan_set_cmd0(pcan_p, AN_CMD_ACCESS | 20603737Shx147065 AN_ACCESS_READ, type, 0, 0)) { 20613737Shx147065 cmn_err(CE_WARN, "pcan get_ltv: set cmd error"); 20623737Shx147065 return (EIO); 20633737Shx147065 } 20643737Shx147065 20653737Shx147065 an_ltv = (struct an_ltv_gen *)pcan_p->pcan_cmd.dma_virtaddr; 20663737Shx147065 #ifdef DEBUG 20673737Shx147065 if (pcan_debug & PCAN_DBG_INFO) { 20683737Shx147065 cmn_err(CE_NOTE, "pcan get_ltv: type=%x," 20693737Shx147065 "expected len=%d," "actual len=%d", 20703737Shx147065 type, len, an_ltv->an_len); 20713737Shx147065 for (i = 0; i < an_ltv->an_len; i++) 20723737Shx147065 cmn_err(CE_NOTE, "%d: %x", i, 20733737Shx147065 *(((uint8_t *)an_ltv) + i)); 20743737Shx147065 } 20753737Shx147065 #endif 20763737Shx147065 if (an_ltv->an_len != len) { 20773737Shx147065 PCANDBG((CE_WARN, "pcan get_ltv: rid=%x expected len=%d" 20783737Shx147065 "actual: len=%d", type, 20793737Shx147065 len, an_ltv->an_len)); 20803737Shx147065 /* return (EIO); */ 20813737Shx147065 } 20823737Shx147065 bcopy(an_ltv, val_p, len); 20833737Shx147065 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) { 20843737Shx147065 len >>= 1; /* convert bytes to 16-bit words */ 20853737Shx147065 20863737Shx147065 /* 1. select read mode */ 20873737Shx147065 if (stat = pcan_set_cmd(pcan_p, AN_CMD_ACCESS | 20883737Shx147065 AN_ACCESS_READ, type)) 20893737Shx147065 return (stat); 20903737Shx147065 20913737Shx147065 /* 2. select Buffer Access Path (channel) 1 for PIO */ 20923737Shx147065 if (stat = pcan_set_ch(pcan_p, type, 0, 1)) 20933737Shx147065 return (stat); 20943737Shx147065 20953737Shx147065 /* 3. read length */ 20963737Shx147065 PCAN_READ(pcan_p, AN_DATA1, stat); 20973737Shx147065 *val_p++ = stat; 20983737Shx147065 if (stat != (len << 1)) { 20993737Shx147065 PCANDBG((CE_NOTE, "pcan get_ltv[%x]:expect %x," 21003737Shx147065 "got %x\n", type, (len + 1) << 1, stat)); 21013737Shx147065 stat = (stat >> 1) - 1; 21023737Shx147065 len = MIN(stat, len); 21033737Shx147065 } 21043737Shx147065 /* 4. read value */ 21053737Shx147065 for (stat = 0; stat < len - 1; stat++, val_p++) { 21063737Shx147065 PCAN_READ_P(pcan_p, AN_DATA1, val_p, 1); 21073737Shx147065 } 21083737Shx147065 } 21093737Shx147065 return (PCAN_SUCCESS); 21103737Shx147065 } 21113737Shx147065 21123737Shx147065 static uint16_t 21133737Shx147065 pcan_put_ltv(pcan_maci_t *pcan_p, uint16_t len, uint16_t type, uint16_t *val_p) 21143737Shx147065 { 21153737Shx147065 uint16_t stat; 21163737Shx147065 int i; 21173737Shx147065 21183737Shx147065 ASSERT(!(len & 1)); 21193737Shx147065 21203737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) { 21213737Shx147065 struct an_card_rid_desc an_rid_desc; 21223737Shx147065 21233737Shx147065 for (i = 0; i < AN_TIMEOUT; i++) { 21243737Shx147065 PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat); 21253737Shx147065 if (!(stat & AN_CMD_BUSY)) { 21263737Shx147065 break; 21273737Shx147065 } 21283737Shx147065 } 21293737Shx147065 if (i == AN_TIMEOUT) { 21303737Shx147065 cmn_err(CE_WARN, "pcan put_ltv: busy"); 21313737Shx147065 } 21323737Shx147065 21333737Shx147065 an_rid_desc.an_valid = 1; 21343737Shx147065 an_rid_desc.an_len = len; 21353737Shx147065 an_rid_desc.an_rid = type; 21363737Shx147065 an_rid_desc.an_phys = pcan_p->pcan_cmd.dma_physaddr; 21373737Shx147065 21383737Shx147065 bcopy(val_p, pcan_p->pcan_cmd.dma_virtaddr, 21393737Shx147065 an_rid_desc.an_len); 21403737Shx147065 21413737Shx147065 for (i = 0; i < sizeof (an_rid_desc) / 4; i++) 21423737Shx147065 PCAN_AUX_PUT32(pcan_p, AN_HOST_DESC_OFFSET + i * 4, 21433737Shx147065 ((uint32_t *)&an_rid_desc)[i]); 21443737Shx147065 pcan_delay(pcan_p, 100000); 21453737Shx147065 stat = pcan_set_cmd0(pcan_p, AN_CMD_ACCESS | 21463737Shx147065 AN_ACCESS_WRITE, type, 0, 0); 21473737Shx147065 pcan_delay(pcan_p, 100000); 21483737Shx147065 return (stat); 21493737Shx147065 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) { 21503737Shx147065 /* 0. select read mode first */ 21513737Shx147065 if (stat = pcan_set_cmd(pcan_p, AN_CMD_ACCESS | 21523737Shx147065 AN_ACCESS_READ, type)) 21533737Shx147065 return (stat); 21543737Shx147065 21553737Shx147065 /* 1. select Buffer Access Path (channel) 1 for PIO */ 21563737Shx147065 if (stat = pcan_set_ch(pcan_p, type, 0, 1)) 21573737Shx147065 return (stat); 21583737Shx147065 21593737Shx147065 /* 2. write length */ 21603737Shx147065 len >>= 1; /* convert bytes to 16-bit words */ 21613737Shx147065 stat = len; 21623737Shx147065 PCAN_WRITE(pcan_p, AN_DATA1, stat); 21633737Shx147065 21643737Shx147065 /* 3. write value */ 21653737Shx147065 val_p++; 21663737Shx147065 for (stat = 0; stat < len-1; stat++, val_p++) { 21673737Shx147065 PCAN_WRITE_P(pcan_p, AN_DATA1, val_p, 1); 21683737Shx147065 } 21693737Shx147065 21703737Shx147065 /* 4. select write mode */ 21713737Shx147065 return (pcan_set_cmd(pcan_p, AN_CMD_ACCESS | 21723737Shx147065 AN_ACCESS_WRITE, type)); 21733737Shx147065 } 21743737Shx147065 return (PCAN_FAIL); 21753737Shx147065 } 21763737Shx147065 21773737Shx147065 /*ARGSUSED*/ 21783737Shx147065 static uint16_t 21793737Shx147065 pcan_rdch0(pcan_maci_t *pcan_p, uint16_t type, uint16_t off, uint16_t *buf_p, 21803737Shx147065 int len, int order) 21813737Shx147065 { 21823737Shx147065 ASSERT(!(len & 1)); 21833737Shx147065 21843737Shx147065 if (pcan_set_ch(pcan_p, type, off, 0) != PCAN_SUCCESS) 21853737Shx147065 return (PCAN_FAIL); 21863737Shx147065 len >>= 1; 21873737Shx147065 for (off = 0; off < len; off++, buf_p++) { 21883737Shx147065 PCAN_READ_P(pcan_p, AN_DATA0, buf_p, order); 21893737Shx147065 } 21903737Shx147065 return (PCAN_SUCCESS); 21913737Shx147065 } 21923737Shx147065 21933737Shx147065 /*ARGSUSED*/ 21943737Shx147065 static uint16_t 21953737Shx147065 pcan_wrch1(pcan_maci_t *pcan_p, uint16_t type, uint16_t off, uint16_t *buf_p, 21963737Shx147065 int len, int order) 21973737Shx147065 { 21983737Shx147065 ASSERT(!(len & 1)); 21993737Shx147065 22003737Shx147065 if (pcan_set_ch(pcan_p, type, off, 1) != PCAN_SUCCESS) 22013737Shx147065 return (PCAN_FAIL); 22023737Shx147065 len >>= 1; 22033737Shx147065 for (off = 0; off < len; off++, buf_p++) { 22043737Shx147065 PCAN_WRITE_P(pcan_p, AN_DATA1, buf_p, order); 22053737Shx147065 } 22063737Shx147065 return (PCAN_SUCCESS); 22073737Shx147065 } 22083737Shx147065 22093737Shx147065 static uint16_t 22103737Shx147065 pcan_status_ltv(int rw, pcan_maci_t *pcan_p, struct an_ltv_status *status_p) 22113737Shx147065 { 22123737Shx147065 uint16_t ret, len; 22133737Shx147065 22143737Shx147065 if (rw != PCAN_READ_LTV) { 22153737Shx147065 cmn_err(CE_WARN, "pcan status_ltv: unsupported op %x", rw); 22163737Shx147065 return (PCAN_FAIL); 22173737Shx147065 } 22183737Shx147065 if (ret = pcan_get_ltv(pcan_p, sizeof (*status_p), AN_RID_STATUS, 22193737Shx147065 (uint16_t *)status_p)) 22203737Shx147065 return (ret); 22213737Shx147065 22223737Shx147065 PCAN_SWAP16_BUF(status_p->an_macaddr); 22233737Shx147065 PCAN_SWAP16_BUF(status_p->an_ssid); 22243737Shx147065 len = min(status_p->an_ssidlen, 31); 22253737Shx147065 status_p->an_ssid[len] = '\0'; 22263737Shx147065 PCAN_SWAP16_BUF(status_p->an_ap_name); 22273737Shx147065 PCAN_SWAP16_BUF(status_p->an_cur_bssid); 22283737Shx147065 PCAN_SWAP16_BUF(status_p->an_prev_bssid1); 22293737Shx147065 PCAN_SWAP16_BUF(status_p->an_prev_bssid2); 22303737Shx147065 PCAN_SWAP16_BUF(status_p->an_prev_bssid3); 22313737Shx147065 PCAN_SWAP16_BUF(status_p->an_ap_ip_address); 22323737Shx147065 PCAN_SWAP16_BUF(status_p->an_carrier); 22333737Shx147065 return (PCAN_SUCCESS); 22343737Shx147065 } 22353737Shx147065 22363737Shx147065 static uint16_t 22373737Shx147065 pcan_cfg_ltv(int rw, pcan_maci_t *pcan_p, struct an_ltv_genconfig *cfg_p) 22383737Shx147065 { 22393737Shx147065 uint16_t ret; 22403737Shx147065 uint16_t rid = cfg_p == &pcan_p->an_config ? 22413737Shx147065 AN_RID_GENCONFIG : AN_RID_ACTUALCFG; 22423737Shx147065 22433737Shx147065 if (rw == PCAN_READ_LTV) { 22443737Shx147065 if (ret = pcan_get_ltv(pcan_p, sizeof (*cfg_p), rid, 22453737Shx147065 (uint16_t *)cfg_p)) 22463737Shx147065 return (ret); 22473737Shx147065 goto done; 22483737Shx147065 } 22493737Shx147065 PCAN_SWAP16_BUF(cfg_p->an_macaddr); 22503737Shx147065 PCAN_SWAP16_BUF(cfg_p->an_rates); 22513737Shx147065 if (ret = pcan_put_ltv(pcan_p, sizeof (*cfg_p), 22523737Shx147065 rid, (uint16_t *)cfg_p)) 22533737Shx147065 return (ret); 22543737Shx147065 done: 22553737Shx147065 PCAN_SWAP16_BUF(cfg_p->an_macaddr); 22563737Shx147065 PCAN_SWAP16_BUF(cfg_p->an_rates); 22573737Shx147065 return (ret); 22583737Shx147065 } 22593737Shx147065 22603737Shx147065 static uint16_t 22613737Shx147065 pcan_cap_ltv(int rw, pcan_maci_t *pcan_p) 22623737Shx147065 { 22633737Shx147065 uint16_t ret; 22643737Shx147065 22653737Shx147065 if (rw != PCAN_READ_LTV) { 22663737Shx147065 cmn_err(CE_WARN, "pcan cap_ltv: unsupported op %x", rw); 22673737Shx147065 return (PCAN_FAIL); 22683737Shx147065 } 22693737Shx147065 if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_caps), 22704343Sgd78059 AN_RID_CAPABILITIES, (uint16_t *)&pcan_p->an_caps)) 22713737Shx147065 return (ret); 22723737Shx147065 22733737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_caps.an_oui); 22743737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_caps.an_manufname); 22753737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_caps.an_prodname); 22763737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_caps.an_prodvers); 22773737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_caps.an_oemaddr); 22783737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_caps.an_aironetaddr); 22793737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_caps.an_callid); 22803737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_caps.an_supported_rates); 22813737Shx147065 return (PCAN_SUCCESS); 22823737Shx147065 } 22833737Shx147065 22843737Shx147065 static uint16_t 22853737Shx147065 pcan_ssid_ltv(int rw, pcan_maci_t *pcan_p) 22863737Shx147065 { 22873737Shx147065 uint16_t ret; 22883737Shx147065 22893737Shx147065 if (rw == PCAN_READ_LTV) { 22903737Shx147065 if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_ssidlist), 22913737Shx147065 AN_RID_SSIDLIST, (uint16_t *)&pcan_p->an_ssidlist)) 22923737Shx147065 return (ret); 22933737Shx147065 goto done; 22943737Shx147065 } 22953737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid1); 22963737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid2); 22973737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid3); 22983737Shx147065 if (ret = pcan_put_ltv(pcan_p, sizeof (struct an_ltv_ssidlist), 22993737Shx147065 AN_RID_SSIDLIST, (uint16_t *)&pcan_p->an_ssidlist)) 23003737Shx147065 return (ret); 23013737Shx147065 done: 23023737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid1); 23033737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid2); 23043737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid3); 23053737Shx147065 return (ret); 23063737Shx147065 } 23073737Shx147065 23083737Shx147065 static uint16_t 23093737Shx147065 pcan_aplist_ltv(int rw, pcan_maci_t *pcan_p) 23103737Shx147065 { 23113737Shx147065 uint16_t ret; 23123737Shx147065 23133737Shx147065 if (rw == PCAN_READ_LTV) { 23143737Shx147065 if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_aplist), 23153737Shx147065 AN_RID_APLIST, (uint16_t *)&pcan_p->an_aplist)) 23163737Shx147065 return (ret); 23173737Shx147065 goto done; 23183737Shx147065 } 23193737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap1); 23203737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap2); 23213737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap3); 23223737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap4); 23233737Shx147065 if (ret = pcan_put_ltv(pcan_p, sizeof (struct an_ltv_aplist), 23243737Shx147065 AN_RID_APLIST, (uint16_t *)&pcan_p->an_aplist)) 23253737Shx147065 return (ret); 23263737Shx147065 done: 23273737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap1); 23283737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap2); 23293737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap3); 23303737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap4); 23313737Shx147065 return (ret); 23323737Shx147065 } 23333737Shx147065 23343737Shx147065 static uint16_t 23353737Shx147065 pcan_scanresult_ltv(int rw, pcan_maci_t *pcan_p, uint16_t type, 23363737Shx147065 struct an_ltv_scanresult *scanresult_p) 23373737Shx147065 { 23383737Shx147065 uint16_t ret, len; 23393737Shx147065 23403737Shx147065 if (rw != PCAN_READ_LTV) { 23413737Shx147065 cmn_err(CE_WARN, "pcan scan_ltv: readonly rid %x\n", type); 23423737Shx147065 return (PCAN_FAIL); 23433737Shx147065 } 23443737Shx147065 if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_scanresult), 23453737Shx147065 type, (uint16_t *)scanresult_p)) 23463737Shx147065 return (ret); 23473737Shx147065 PCAN_SWAP16_BUF(scanresult_p->an_bssid); 23483737Shx147065 PCAN_SWAP16_BUF(scanresult_p->an_ssid); 23493737Shx147065 len = min(scanresult_p->an_ssidlen, 31); 23503737Shx147065 scanresult_p->an_ssid[len] = '\0'; 23513737Shx147065 PCAN_SWAP16_BUF(scanresult_p->an_rates); 23523737Shx147065 return (PCAN_SUCCESS); 23533737Shx147065 } 23543737Shx147065 23553737Shx147065 static uint16_t 23563737Shx147065 pcan_one_wepkey(int rw, pcan_maci_t *pcan_p, struct an_ltv_wepkey *wkp, 23573737Shx147065 uint16_t rid) 23583737Shx147065 { 23593737Shx147065 uint16_t ret; 23603737Shx147065 23613737Shx147065 if (rw == PCAN_READ_LTV) { 23623737Shx147065 if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_wepkey), 23633737Shx147065 rid, (uint16_t *)wkp)) { 23643737Shx147065 return (ret); 23653737Shx147065 } 23663737Shx147065 goto done; 23673737Shx147065 } 23683737Shx147065 PCAN_SWAP16_BUF(wkp->an_macaddr); 23693737Shx147065 PCAN_SWAP16_BUF(wkp->an_key); 23703737Shx147065 if (ret = pcan_put_ltv(pcan_p, sizeof (struct an_ltv_wepkey), 23713737Shx147065 rid, (uint16_t *)wkp)) 23723737Shx147065 return (ret); 23733737Shx147065 done: 23743737Shx147065 PCAN_SWAP16_BUF(wkp->an_macaddr); 23753737Shx147065 PCAN_SWAP16_BUF(wkp->an_key); 23763737Shx147065 return (ret); 23773737Shx147065 } 23783737Shx147065 23793737Shx147065 static uint16_t 23803737Shx147065 pcan_wepkey_ltv(int rw, pcan_maci_t *pcan_p) 23813737Shx147065 { 23823737Shx147065 uint16_t ret, i; 23833737Shx147065 struct an_ltv_wepkey wk; 23843737Shx147065 23853737Shx147065 if (rw == PCAN_READ_LTV) { 23863737Shx147065 uint16_t rid = AN_RID_WEPKEY2; 23873737Shx147065 23883737Shx147065 if (ret = pcan_one_wepkey(rw, pcan_p, &wk, rid)) 23893737Shx147065 return (ret); 23903737Shx147065 for (i = 0; i < 5; i++) { 23913737Shx147065 if (wk.an_index < 4) 23923737Shx147065 pcan_p->an_wepkey[wk.an_index] = wk; 23933737Shx147065 else if (wk.an_index == 0xffff) 23943737Shx147065 pcan_p->an_cur_wepkey = wk.an_macaddr[0]; 23953737Shx147065 rid = AN_RID_WEPKEY; 23963737Shx147065 } 23973737Shx147065 return (PCAN_SUCCESS); 23983737Shx147065 } 23993737Shx147065 for (i = 0; i < MAX_NWEPKEYS; i++) { 24003737Shx147065 if (pcan_p->an_wepkey[i].an_index == i) { 24013737Shx147065 if (ret = pcan_one_wepkey(rw, pcan_p, 24023737Shx147065 &pcan_p->an_wepkey[i], AN_RID_WEPKEY2)) 24033737Shx147065 return (ret); 24043737Shx147065 } 24053737Shx147065 } 24063737Shx147065 /* Now set the default key */ 24073737Shx147065 (void) memset(&wk, 0, sizeof (wk)); 24083737Shx147065 wk.an_index = 0xffff; 24093737Shx147065 wk.an_macaddr[0] = pcan_p->an_cur_wepkey; 24103737Shx147065 ret = pcan_one_wepkey(rw, pcan_p, &wk, AN_RID_WEPKEY2); 24113737Shx147065 return (ret); 24123737Shx147065 } 24133737Shx147065 24143737Shx147065 static uint16_t 24153737Shx147065 pcan_alloc_nicmem(pcan_maci_t *pcan_p, uint16_t len, uint16_t *id_p) 24163737Shx147065 { 24173737Shx147065 int i; 24183737Shx147065 uint16_t stat; 24193737Shx147065 24203737Shx147065 len = ((len + 1) >> 1) << 1; /* round up to 16-bit boundary */ 24213737Shx147065 24223737Shx147065 if (stat = pcan_set_cmd(pcan_p, AN_CMD_ALLOC_MEM, len)) 24233737Shx147065 return (stat); 24243737Shx147065 for (i = 0; !(stat & AN_EV_ALLOC) && (i < AN_TIMEOUT); i++) { 24253737Shx147065 PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat); 24263737Shx147065 } 24273737Shx147065 if (!(stat & AN_EV_ALLOC)) 24283737Shx147065 return (PCAN_TIMEDOUT_ALLOC); 24293737Shx147065 PCAN_READ(pcan_p, AN_ALLOC_FID, stat); 24303737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_ALLOC); 24313737Shx147065 *id_p = stat; 24323737Shx147065 24333737Shx147065 /* zero fill the allocated NIC mem - sort of pcan_fill_ch0 */ 24343737Shx147065 (void) pcan_set_ch(pcan_p, stat, 0, 0); 24353737Shx147065 for (len >>= 1, stat = 0; stat < len; stat++) { 24363737Shx147065 PCAN_WRITE(pcan_p, AN_DATA0, 0); 24373737Shx147065 } 24383737Shx147065 return (PCAN_SUCCESS); 24393737Shx147065 } 24403737Shx147065 24413737Shx147065 static void 24423737Shx147065 pcan_stop_rx_dma(pcan_maci_t *pcan_p) 24433737Shx147065 { 24443737Shx147065 int i, j; 24453737Shx147065 struct an_card_rx_desc an_rx_desc; 24463737Shx147065 24473737Shx147065 for (i = 0; i < AN_MAX_RX_DESC; i++) { 24483737Shx147065 bzero(&an_rx_desc, sizeof (an_rx_desc)); 24493737Shx147065 an_rx_desc.an_valid = 0; 24503737Shx147065 an_rx_desc.an_len = AN_RX_BUFFER_SIZE; 24513737Shx147065 an_rx_desc.an_done = 1; 24523737Shx147065 an_rx_desc.an_phys = pcan_p->pcan_rx[i].dma_physaddr; 24533737Shx147065 for (j = 0; j < sizeof (an_rx_desc) / 4; j++) 24543737Shx147065 PCAN_AUX_PUT32(pcan_p, AN_RX_DESC_OFFSET 24553737Shx147065 + (i * sizeof (an_rx_desc)) 24563737Shx147065 + (j * 4), ((uint32_t *)&an_rx_desc)[j]); 24573737Shx147065 } 24583737Shx147065 } 24593737Shx147065 24603737Shx147065 static int 24613737Shx147065 pcan_init_dma_desc(pcan_maci_t *pcan_p) 24623737Shx147065 { 24633737Shx147065 int i, j; 24643737Shx147065 struct an_card_rid_desc an_rid_desc; 24653737Shx147065 struct an_card_rx_desc an_rx_desc; 24663737Shx147065 struct an_card_tx_desc an_tx_desc; 24673737Shx147065 24683737Shx147065 /* Allocate DMA for rx */ 24693737Shx147065 if (pcan_set_cmd0(pcan_p, AN_CMD_ALLOC_DESC, 24703737Shx147065 AN_DESCRIPTOR_RX, AN_RX_DESC_OFFSET, 24713737Shx147065 AN_MAX_RX_DESC) != PCAN_SUCCESS) { 24723737Shx147065 cmn_err(CE_WARN, "pcan init_dma: fail to alloc rx descriptor"); 24733737Shx147065 goto error; 24743737Shx147065 } 24753737Shx147065 for (i = 0; i < AN_MAX_RX_DESC; i++) { 24763737Shx147065 bzero(&an_rx_desc, sizeof (an_rx_desc)); 24773737Shx147065 an_rx_desc.an_valid = 1; 24783737Shx147065 an_rx_desc.an_len = AN_RX_BUFFER_SIZE; 24793737Shx147065 an_rx_desc.an_done = 0; 24803737Shx147065 an_rx_desc.an_phys = pcan_p->pcan_rx[i].dma_physaddr; 24813737Shx147065 for (j = 0; j < sizeof (an_rx_desc) / 4; j++) 24823737Shx147065 PCAN_AUX_PUT32(pcan_p, AN_RX_DESC_OFFSET 24833737Shx147065 + (i * sizeof (an_rx_desc)) 24843737Shx147065 + (j * 4), ((uint32_t *)&an_rx_desc)[j]); 24853737Shx147065 } 24863737Shx147065 24873737Shx147065 24883737Shx147065 /* Allocate DMA for tx */ 24893737Shx147065 if (pcan_set_cmd0(pcan_p, AN_CMD_ALLOC_DESC, 24903737Shx147065 AN_DESCRIPTOR_TX, AN_TX_DESC_OFFSET, 24913737Shx147065 AN_MAX_TX_DESC) != PCAN_SUCCESS) { 24923737Shx147065 cmn_err(CE_WARN, "pcan init_dma: fail to alloc tx descriptor"); 24933737Shx147065 goto error; 24943737Shx147065 } 24953737Shx147065 24963737Shx147065 for (i = 0; i < AN_MAX_TX_DESC; i++) { 24973737Shx147065 an_tx_desc.an_offset = 0; 24983737Shx147065 an_tx_desc.an_eoc = 0; 24993737Shx147065 an_tx_desc.an_valid = 0; 25003737Shx147065 an_tx_desc.an_len = 0; 25013737Shx147065 an_tx_desc.an_phys = pcan_p->pcan_tx[i].dma_physaddr; 25023737Shx147065 25033737Shx147065 for (j = 0; j < sizeof (an_tx_desc) / 4; j++) 25043737Shx147065 PCAN_AUX_PUT32(pcan_p, AN_TX_DESC_OFFSET 25053737Shx147065 + (i * sizeof (an_tx_desc)) 25063737Shx147065 + (j * 4), ((uint32_t *)&an_tx_desc)[j]); 25073737Shx147065 } 25083737Shx147065 25093737Shx147065 /* Allocate DMA for rid */ 25103737Shx147065 if (pcan_set_cmd0(pcan_p, AN_CMD_ALLOC_DESC, 25113737Shx147065 AN_DESCRIPTOR_HOSTRW, AN_HOST_DESC_OFFSET, 1) != PCAN_SUCCESS) { 25123737Shx147065 cmn_err(CE_WARN, "pcan init_dma: fail to alloc rid descriptor"); 25133737Shx147065 goto error; 25143737Shx147065 } 25153737Shx147065 bzero(&an_rid_desc, sizeof (an_rid_desc)); 25163737Shx147065 an_rid_desc.an_valid = 1; 25173737Shx147065 an_rid_desc.an_len = AN_RID_BUFFER_SIZE; 25183737Shx147065 an_rid_desc.an_rid = 0; 25193737Shx147065 an_rid_desc.an_phys = pcan_p->pcan_cmd.dma_physaddr; 25203737Shx147065 25213737Shx147065 for (i = 0; i < sizeof (an_rid_desc) / 4; i++) 25223737Shx147065 PCAN_AUX_PUT32(pcan_p, AN_HOST_DESC_OFFSET + i * 4, 25233737Shx147065 ((uint32_t *)&an_rid_desc)[i]); 25243737Shx147065 25253737Shx147065 pcan_p->pcan_txring.an_tx_prod = 0; 25263737Shx147065 pcan_p->pcan_txring.an_tx_cons = 0; 25273737Shx147065 pcan_p->pcan_flag &= ~PCAN_CARD_SEND; 25283737Shx147065 return (PCAN_SUCCESS); 25293737Shx147065 error: 25303737Shx147065 return (PCAN_FAIL); 25313737Shx147065 } 25323737Shx147065 25333737Shx147065 static int 25343737Shx147065 pcan_init_dma(dev_info_t *dip, pcan_maci_t *pcan_p) 25353737Shx147065 { 25363737Shx147065 int i, ret = PCAN_FAIL; 25373737Shx147065 ddi_dma_cookie_t dma_cookie; 25383737Shx147065 size_t len; 25393737Shx147065 25403737Shx147065 /* Allocate DMA for rx */ 25413737Shx147065 for (i = 0; i < AN_MAX_RX_DESC; i++) { 25423737Shx147065 if (ddi_dma_alloc_handle(dip, &control_cmd_dma_attr, 25433737Shx147065 DDI_DMA_SLEEP, 0, 25443737Shx147065 &pcan_p->pcan_rx[i].dma_handle) != DDI_SUCCESS) 25453737Shx147065 goto error; 25463737Shx147065 25473737Shx147065 if (ddi_dma_mem_alloc(pcan_p->pcan_rx[i].dma_handle, 25483737Shx147065 AN_RX_BUFFER_SIZE, &accattr, 25493737Shx147065 DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0, 25503737Shx147065 (caddr_t *)&pcan_p->pcan_rx[i].dma_virtaddr, &len, 25513737Shx147065 &pcan_p->pcan_rx[i].dma_acc_handle) != DDI_SUCCESS) { 25523737Shx147065 goto error; 25533737Shx147065 } 25543737Shx147065 if (ddi_dma_addr_bind_handle( 25553737Shx147065 pcan_p->pcan_rx[i].dma_handle, 25563737Shx147065 NULL, (caddr_t)pcan_p->pcan_rx[i].dma_virtaddr, 25573737Shx147065 len, DDI_DMA_READ | 25583737Shx147065 DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0, &dma_cookie, 25593737Shx147065 &pcan_p->pcan_rx[i].ncookies) != DDI_DMA_MAPPED) { 25603737Shx147065 goto error; 25613737Shx147065 } 25623737Shx147065 ASSERT(pcan_p->pcan_rx[i].ncookies == 1); 25633737Shx147065 pcan_p->pcan_rx[i].dma_physaddr = dma_cookie.dmac_address; 25643737Shx147065 } 25653737Shx147065 25663737Shx147065 /* Allocate DMA for tx */ 25673737Shx147065 for (i = 0; i < AN_MAX_TX_DESC; i++) { 25683737Shx147065 if (ddi_dma_alloc_handle(dip, &control_cmd_dma_attr, 25693737Shx147065 DDI_DMA_SLEEP, 0, 25703737Shx147065 &pcan_p->pcan_tx[i].dma_handle) != DDI_SUCCESS) 25713737Shx147065 goto error; 25723737Shx147065 25733737Shx147065 if (ddi_dma_mem_alloc(pcan_p->pcan_tx[i].dma_handle, 25743737Shx147065 AN_TX_BUFFER_SIZE, &accattr, 25753737Shx147065 DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0, 25763737Shx147065 (caddr_t *)&pcan_p->pcan_tx[i].dma_virtaddr, &len, 25773737Shx147065 &pcan_p->pcan_tx[i].dma_acc_handle) != DDI_SUCCESS) { 25783737Shx147065 goto error; 25793737Shx147065 } 25803737Shx147065 if (ddi_dma_addr_bind_handle( 25813737Shx147065 pcan_p->pcan_tx[i].dma_handle, 25823737Shx147065 NULL, (caddr_t)pcan_p->pcan_tx[i].dma_virtaddr, 25833737Shx147065 len, DDI_DMA_WRITE | 25843737Shx147065 DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0, &dma_cookie, 25853737Shx147065 &pcan_p->pcan_tx[i].ncookies) != DDI_DMA_MAPPED) { 25863737Shx147065 goto error; 25873737Shx147065 } 25883737Shx147065 ASSERT(pcan_p->pcan_tx[i].ncookies == 1); 25893737Shx147065 pcan_p->pcan_tx[i].dma_physaddr = dma_cookie.dmac_address; 25903737Shx147065 } 25913737Shx147065 25923737Shx147065 /* Allocate DMA for rid */ 25933737Shx147065 if (ddi_dma_alloc_handle(dip, &control_cmd_dma_attr, 25943737Shx147065 DDI_DMA_SLEEP, 0, 25953737Shx147065 &pcan_p->pcan_cmd.dma_handle) != DDI_SUCCESS) 25963737Shx147065 goto error; 25973737Shx147065 25983737Shx147065 if (ddi_dma_mem_alloc(pcan_p->pcan_cmd.dma_handle, 25993737Shx147065 AN_RID_BUFFER_SIZE, &accattr, 26003737Shx147065 DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0, 26013737Shx147065 (caddr_t *)&pcan_p->pcan_cmd.dma_virtaddr, &len, 26023737Shx147065 &pcan_p->pcan_cmd.dma_acc_handle) != DDI_SUCCESS) { 26033737Shx147065 goto error; 26043737Shx147065 } 26053737Shx147065 if (ddi_dma_addr_bind_handle( 26063737Shx147065 pcan_p->pcan_cmd.dma_handle, 26073737Shx147065 NULL, (caddr_t)pcan_p->pcan_cmd.dma_virtaddr, 26083737Shx147065 len, DDI_DMA_RDWR | 26093737Shx147065 DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0, &dma_cookie, 26103737Shx147065 &pcan_p->pcan_cmd.ncookies) != DDI_DMA_MAPPED) { 26113737Shx147065 goto error; 26123737Shx147065 } 26133737Shx147065 ASSERT(pcan_p->pcan_cmd.ncookies == 1); 26143737Shx147065 pcan_p->pcan_cmd.dma_physaddr = dma_cookie.dmac_address; 26153737Shx147065 26163737Shx147065 if (ret = pcan_init_dma_desc(pcan_p)) { 26173737Shx147065 cmn_err(CE_WARN, "pcan init_dma_desc: failed\n"); 26183737Shx147065 goto error; 26193737Shx147065 } 26203737Shx147065 26213737Shx147065 return (PCAN_SUCCESS); 26223737Shx147065 error: 26233737Shx147065 pcan_free_dma(pcan_p); 26243737Shx147065 return (ret); 26253737Shx147065 } 26263737Shx147065 26273737Shx147065 static void 26283737Shx147065 pcan_free_dma(pcan_maci_t *pcan_p) 26293737Shx147065 { 26303737Shx147065 int i; 26313737Shx147065 26323737Shx147065 /* free RX dma */ 26333737Shx147065 pcan_stop_rx_dma(pcan_p); 26343737Shx147065 for (i = 0; i < AN_MAX_RX_DESC; i++) { 26353737Shx147065 if (pcan_p->pcan_rx[i].dma_handle != NULL) { 26363737Shx147065 if (pcan_p->pcan_rx[i].ncookies) { 26373737Shx147065 (void) ddi_dma_unbind_handle( 26383737Shx147065 pcan_p->pcan_rx[i].dma_handle); 26393737Shx147065 pcan_p->pcan_rx[i].ncookies = 0; 26403737Shx147065 } 26413737Shx147065 ddi_dma_free_handle( 26423737Shx147065 &pcan_p->pcan_rx[i].dma_handle); 26433737Shx147065 pcan_p->pcan_rx[i].dma_handle = NULL; 26443737Shx147065 } 26453737Shx147065 if (pcan_p->pcan_rx[i].dma_acc_handle != NULL) { 26463737Shx147065 ddi_dma_mem_free( 26473737Shx147065 &pcan_p->pcan_rx[i].dma_acc_handle); 26483737Shx147065 pcan_p->pcan_rx[i].dma_acc_handle = NULL; 26493737Shx147065 } 26503737Shx147065 } 26513737Shx147065 26523737Shx147065 /* free TX dma */ 26533737Shx147065 for (i = 0; i < AN_MAX_TX_DESC; i++) { 26543737Shx147065 if (pcan_p->pcan_tx[i].dma_handle != NULL) { 26553737Shx147065 if (pcan_p->pcan_tx[i].ncookies) { 26563737Shx147065 (void) ddi_dma_unbind_handle( 26573737Shx147065 pcan_p->pcan_tx[i].dma_handle); 26583737Shx147065 pcan_p->pcan_tx[i].ncookies = 0; 26593737Shx147065 } 26603737Shx147065 ddi_dma_free_handle( 26613737Shx147065 &pcan_p->pcan_tx[i].dma_handle); 26623737Shx147065 pcan_p->pcan_tx[i].dma_handle = NULL; 26633737Shx147065 } 26643737Shx147065 if (pcan_p->pcan_tx[i].dma_acc_handle != NULL) { 26653737Shx147065 ddi_dma_mem_free( 26663737Shx147065 &pcan_p->pcan_tx[i].dma_acc_handle); 26673737Shx147065 pcan_p->pcan_tx[i].dma_acc_handle = NULL; 26683737Shx147065 } 26693737Shx147065 } 26703737Shx147065 26713737Shx147065 /* free cmd dma */ 26723737Shx147065 if (pcan_p->pcan_cmd.dma_handle != NULL) { 26733737Shx147065 if (pcan_p->pcan_cmd.ncookies) { 26743737Shx147065 (void) ddi_dma_unbind_handle( 26753737Shx147065 pcan_p->pcan_cmd.dma_handle); 26763737Shx147065 pcan_p->pcan_cmd.ncookies = 0; 26773737Shx147065 } 26783737Shx147065 ddi_dma_free_handle( 26793737Shx147065 &pcan_p->pcan_cmd.dma_handle); 26803737Shx147065 pcan_p->pcan_cmd.dma_handle = NULL; 26813737Shx147065 } 26823737Shx147065 if (pcan_p->pcan_cmd.dma_acc_handle != NULL) { 26833737Shx147065 ddi_dma_mem_free( 26843737Shx147065 &pcan_p->pcan_cmd.dma_acc_handle); 26853737Shx147065 pcan_p->pcan_cmd.dma_acc_handle = NULL; 26863737Shx147065 } 26873737Shx147065 } 26883737Shx147065 26893737Shx147065 /* 26903737Shx147065 * get card capability (WEP, default channel), setup broadcast, mac addresses 26913737Shx147065 */ 26923737Shx147065 static uint32_t 26933737Shx147065 pcan_get_cap(pcan_maci_t *pcan_p) 26943737Shx147065 { 26953737Shx147065 uint16_t stat; 26963737Shx147065 26973737Shx147065 if (stat = pcan_cfg_ltv(PCAN_READ_LTV, pcan_p, &pcan_p->an_config)) { 26983737Shx147065 PCANDBG((CE_NOTE, "pcan get_cap: read cfg fail %x", stat)); 26993737Shx147065 return ((uint32_t)AN_RID_GENCONFIG << 16 | stat); 27003737Shx147065 } 27013737Shx147065 27023737Shx147065 if (stat = pcan_cap_ltv(PCAN_READ_LTV, pcan_p)) { 27033737Shx147065 PCANDBG((CE_NOTE, "pcan get_cap: read cap fail %x", stat)); 27043737Shx147065 return ((uint32_t)AN_RID_CAPABILITIES << 16 | stat); 27053737Shx147065 } 27063737Shx147065 #ifdef DEBUG 27073737Shx147065 if (pcan_debug & PCAN_DBG_FW_VERSION) { 27083737Shx147065 cmn_err(CE_NOTE, "the version of the firmware in the wifi card " 27093737Shx147065 "'%s %s %s' is %s\n", 27103737Shx147065 pcan_p->an_caps.an_manufname, 27113737Shx147065 pcan_p->an_caps.an_prodname, 27123737Shx147065 pcan_p->pcan_device_type == PCAN_DEVICE_PCI ? 27133737Shx147065 "minipci" : "pccard", 27143737Shx147065 pcan_p->an_caps.an_prodvers); 27153737Shx147065 } 27163737Shx147065 #endif 27173737Shx147065 27183737Shx147065 if (stat = pcan_ssid_ltv(PCAN_READ_LTV, pcan_p)) { 27193737Shx147065 PCANDBG((CE_NOTE, "pcan get_cap: read ssid fail %x", stat)); 27203737Shx147065 return ((uint32_t)AN_RID_SSIDLIST << 16 | stat); 27213737Shx147065 } 27223737Shx147065 27233737Shx147065 if (stat = pcan_aplist_ltv(PCAN_READ_LTV, pcan_p)) { 27243737Shx147065 PCANDBG((CE_NOTE, "pcan get_cap: read aplist fail %x", stat)); 27253737Shx147065 return ((uint32_t)AN_RID_APLIST << 16 | stat); 27263737Shx147065 } 27273737Shx147065 if (stat = pcan_wepkey_ltv(PCAN_READ_LTV, pcan_p)) { 27283737Shx147065 PCANDBG((CE_NOTE, "pcan get_cap: read wepkey fail %x", stat)); 27293737Shx147065 return ((uint32_t)AN_RID_WEPKEY2 << 16 | stat); 27303737Shx147065 } 27313737Shx147065 ether_copy(pcan_p->an_caps.an_oemaddr, pcan_p->pcan_mac_addr); 27323737Shx147065 return (PCAN_SUCCESS); 27333737Shx147065 } 27343737Shx147065 27353737Shx147065 static int 27363737Shx147065 pcan_config_mac(pcan_maci_t *pcan_p) 27373737Shx147065 { 27383737Shx147065 uint16_t stat; 27393737Shx147065 27403737Shx147065 if (stat = pcan_ssid_ltv(PCAN_WRITE_LTV, pcan_p)) { 27413737Shx147065 PCANDBG((CE_NOTE, "pcan config_mac: write SSID failed%x\n", 27423737Shx147065 stat)); 27433737Shx147065 return ((int)stat); 27443737Shx147065 } 27453737Shx147065 27463737Shx147065 if (stat = pcan_aplist_ltv(PCAN_WRITE_LTV, pcan_p)) { 27473737Shx147065 PCANDBG((CE_NOTE, "pcan config_mac: write APlist failed%x\n", 27483737Shx147065 stat)); 27493737Shx147065 return ((int)stat); 27503737Shx147065 } 27513737Shx147065 if (stat = pcan_wepkey_ltv(PCAN_WRITE_LTV, pcan_p)) { 27523737Shx147065 PCANDBG((CE_NOTE, "pcan config_mac: write wepkey failed%x\n", 27533737Shx147065 stat)); 27543737Shx147065 return ((int)stat); 27553737Shx147065 } 27563737Shx147065 if (pcan_p->pcan_usewep) 27573737Shx147065 pcan_p->an_config.an_authtype |= 27583737Shx147065 AN_AUTHTYPE_ENABLEWEP | AN_AUTHTYPE_ALLOW_UNENCRYPTED; 27593737Shx147065 PCANDBG((CE_NOTE, "pcan config_mac: usewep=%x authtype=%x opmode=%x\n", 27603737Shx147065 pcan_p->pcan_usewep, pcan_p->an_config.an_authtype, 27613737Shx147065 pcan_p->an_config.an_opmode)); 27623737Shx147065 27633737Shx147065 pcan_p->an_config.an_assoc_timeout = 5000; /* stop assoc seq in 5 sec */ 27643737Shx147065 if (stat = pcan_cfg_ltv(PCAN_WRITE_LTV, pcan_p, &pcan_p->an_config)) { 27653737Shx147065 PCANDBG((CE_NOTE, "pcan config_mac: write cfg failed %x\n", 27663737Shx147065 stat)); 27673737Shx147065 return ((int)stat); 27683737Shx147065 } 27693737Shx147065 27703737Shx147065 if (stat = pcan_cfg_ltv(PCAN_READ_LTV, pcan_p, 27713737Shx147065 &pcan_p->an_actual_config)) { 27723737Shx147065 PCANDBG((CE_NOTE, "pcan config_mac: read cfg failed%x\n", 27733737Shx147065 stat)); 27743737Shx147065 return ((int)stat); 27753737Shx147065 } 27763737Shx147065 PCANDBG((CE_NOTE, "pcan config_mac: optionmask=%x authtype=%x\n", 0, 27773737Shx147065 pcan_p->an_actual_config.an_authtype)); 27783737Shx147065 27793737Shx147065 if (stat = pcan_status_ltv(PCAN_READ_LTV, pcan_p, &pcan_p->an_status)) { 27803737Shx147065 PCANDBG((CE_NOTE, "pcan config_mac: read status failed %x\n", 27813737Shx147065 stat)); 27823737Shx147065 return ((int)stat); 27833737Shx147065 } 27843737Shx147065 return (PCAN_SUCCESS); 27853737Shx147065 } 27863737Shx147065 27873737Shx147065 static int 27883737Shx147065 pcan_loaddef(pcan_maci_t *pcan_p) 27893737Shx147065 { 27903737Shx147065 int i; 27913737Shx147065 27923737Shx147065 pcan_p->an_ssidlist.an_ssid1_len = 0; 27933737Shx147065 bzero(pcan_p->an_ssidlist.an_ssid1, 27944343Sgd78059 sizeof (pcan_p->an_ssidlist.an_ssid1)); 27953737Shx147065 for (i = 0; i < MAX_NWEPKEYS; i++) { 27963737Shx147065 pcan_p->an_wepkey[i].an_index = 0xffff; 27973737Shx147065 bzero(pcan_p->an_wepkey[i].an_key, 27983737Shx147065 sizeof (pcan_p->an_wepkey[i].an_key)); 27993737Shx147065 pcan_p->an_wepkey[i].an_keylen = 0; 28003737Shx147065 bzero(pcan_p->an_wepkey[i].an_macaddr, 28013737Shx147065 sizeof (pcan_p->an_wepkey[i].an_macaddr)); 28023737Shx147065 pcan_p->an_wepkey[i].an_macaddr[0] = 1; 28033737Shx147065 } 28043737Shx147065 pcan_p->an_cur_wepkey = 0; 28053737Shx147065 28063737Shx147065 pcan_p->pcan_usewep = 0; 28073737Shx147065 pcan_p->an_config.an_opmode = AN_OPMODE_INFR_STATION; 28083737Shx147065 pcan_p->an_config.an_authtype = AN_AUTHTYPE_OPEN; 28093737Shx147065 pcan_p->an_config.an_stationary = 1; 28103737Shx147065 pcan_p->an_config.an_max_beacon_lost_time = 0xffff; 28113737Shx147065 i = pcan_config_mac(pcan_p); 28123737Shx147065 28133737Shx147065 return (i); 28143737Shx147065 } 28153737Shx147065 28163737Shx147065 static int 28173737Shx147065 pcan_init_nicmem(pcan_maci_t *pcan_p) 28183737Shx147065 { 28193737Shx147065 int i; 28203737Shx147065 uint16_t ret; 28213737Shx147065 pcan_txring_t *ring_p = &pcan_p->pcan_txring; 28223737Shx147065 28233737Shx147065 for (i = 0; i < AN_TX_RING_CNT; i++) { 28243737Shx147065 uint16_t rc; 28253737Shx147065 ret = pcan_alloc_nicmem(pcan_p, PCAN_NICMEM_SZ, &rc); 28263737Shx147065 if (ret) { 28273737Shx147065 cmn_err(CE_WARN, "pcan alloc NIC Tx buf[%x]: failed " 28283737Shx147065 "%x\n", i, ret); 28293737Shx147065 return (DDI_FAILURE); 28303737Shx147065 } 28313737Shx147065 ring_p->an_tx_fids[i] = rc; 28323737Shx147065 ring_p->an_tx_ring[i] = 0; 28333737Shx147065 PCANDBG((CE_NOTE, "pcan: NIC tx_id[%x]=%x\n", i, rc)); 28343737Shx147065 } 28353737Shx147065 ring_p->an_tx_prod = ring_p->an_tx_cons = 0; 28363737Shx147065 return (PCAN_SUCCESS); 28373737Shx147065 } 28383737Shx147065 28393737Shx147065 28403737Shx147065 28413737Shx147065 static void 28423737Shx147065 pcan_start_locked(pcan_maci_t *pcan_p) 28433737Shx147065 { 28443737Shx147065 pcan_p->pcan_flag |= PCAN_CARD_INTREN; 28453737Shx147065 PCAN_ENABLE_INTR(pcan_p); 28463737Shx147065 } 28473737Shx147065 28483737Shx147065 static void 28493737Shx147065 pcan_stop_locked(pcan_maci_t *pcan_p) 28503737Shx147065 { 28513737Shx147065 PCAN_DISABLE_INTR_CLEAR(pcan_p); 28523737Shx147065 pcan_p->pcan_flag &= ~PCAN_CARD_INTREN; 28533737Shx147065 } 28543737Shx147065 28553737Shx147065 /* 28563737Shx147065 * for scan result 28573737Shx147065 */ 28583737Shx147065 static int 28593737Shx147065 pcan_add_scan_item(pcan_maci_t *pcan_p, struct an_ltv_scanresult s) 28603737Shx147065 { 28613737Shx147065 an_scan_list_t *scan_item; 28623737Shx147065 28633737Shx147065 scan_item = kmem_zalloc(sizeof (an_scan_list_t), KM_SLEEP); 28643737Shx147065 if (scan_item == NULL) { 28653737Shx147065 cmn_err(CE_WARN, "pcan add_scan_item: zalloc failed\n"); 28663737Shx147065 return (PCAN_FAIL); 28673737Shx147065 } 28683737Shx147065 scan_item->an_val = s; 28693737Shx147065 scan_item->an_timeout = AN_SCAN_TIMEOUT_MAX; 28703737Shx147065 list_insert_tail(&pcan_p->an_scan_list, scan_item); 28713737Shx147065 pcan_p->an_scan_num++; 28723737Shx147065 return (PCAN_SUCCESS); 28733737Shx147065 } 28743737Shx147065 28753737Shx147065 static void 28763737Shx147065 pcan_delete_scan_item(pcan_maci_t *pcan_p, an_scan_list_t *s) 28773737Shx147065 { 28783737Shx147065 list_remove(&pcan_p->an_scan_list, s); 28793737Shx147065 kmem_free(s, sizeof (*s)); 28803737Shx147065 pcan_p->an_scan_num--; 28813737Shx147065 } 28823737Shx147065 28833737Shx147065 static void 28843737Shx147065 pcan_scanlist_timeout(void *arg) 28853737Shx147065 { 28863737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 28873737Shx147065 an_scan_list_t *scan_item0, *scan_item1; 28883737Shx147065 28893737Shx147065 mutex_enter(&pcan_p->pcan_scanlist_lock); 28903737Shx147065 scan_item0 = list_head(&pcan_p->an_scan_list); 28913737Shx147065 for (; scan_item0; ) { 28923737Shx147065 PCANDBG((CE_NOTE, "pcan scanlist: ssid = %s\n", 28933737Shx147065 scan_item0->an_val.an_ssid)); 28943737Shx147065 PCANDBG((CE_NOTE, "pcan scanlist: timeout left: %ds", 28953737Shx147065 scan_item0->an_timeout)); 28963737Shx147065 scan_item1 = list_next(&pcan_p->an_scan_list, scan_item0); 28973737Shx147065 if (scan_item0->an_timeout == 0) { 28983737Shx147065 pcan_delete_scan_item(pcan_p, scan_item0); 28993737Shx147065 } else { 29003737Shx147065 scan_item0->an_timeout--; 29013737Shx147065 } 29023737Shx147065 scan_item0 = scan_item1; 29033737Shx147065 } 29043737Shx147065 mutex_exit(&pcan_p->pcan_scanlist_lock); 29053737Shx147065 pcan_p->an_scanlist_timeout_id = timeout(pcan_scanlist_timeout, 29063737Shx147065 pcan_p, drv_usectohz(1000000)); 29073737Shx147065 } 29083737Shx147065 29098410SWang.Lin@Sun.COM /* 29108410SWang.Lin@Sun.COM * Brussels support 29118410SWang.Lin@Sun.COM */ 29128410SWang.Lin@Sun.COM /* 29138410SWang.Lin@Sun.COM * MAC_PROP_WL_ESSID 29148410SWang.Lin@Sun.COM */ 29158410SWang.Lin@Sun.COM static int 29168410SWang.Lin@Sun.COM pcan_set_essid(pcan_maci_t *pcan_p, const void *wldp_buf) 29178410SWang.Lin@Sun.COM { 29188410SWang.Lin@Sun.COM char *value; 29198410SWang.Lin@Sun.COM struct an_ltv_ssidlist *ssidlist_p; 29208410SWang.Lin@Sun.COM wl_essid_t *iw_essid = (wl_essid_t *)wldp_buf; 29218410SWang.Lin@Sun.COM 29228410SWang.Lin@Sun.COM ssidlist_p = &pcan_p->an_ssidlist; 29238410SWang.Lin@Sun.COM bzero(ssidlist_p, sizeof (*ssidlist_p)); 29248410SWang.Lin@Sun.COM value = iw_essid->wl_essid_essid; 29258410SWang.Lin@Sun.COM (void) strncpy(ssidlist_p->an_ssid1, value, 29268410SWang.Lin@Sun.COM MIN(32, strlen(value))); 29278410SWang.Lin@Sun.COM ssidlist_p->an_ssid1_len = strlen(value); 29288410SWang.Lin@Sun.COM 29298410SWang.Lin@Sun.COM return (ENETRESET); 29308410SWang.Lin@Sun.COM } 29318410SWang.Lin@Sun.COM 29328410SWang.Lin@Sun.COM static int 29338410SWang.Lin@Sun.COM pcan_get_essid(pcan_maci_t *pcan_p, void *wldp_buf) 29348410SWang.Lin@Sun.COM { 29358410SWang.Lin@Sun.COM int err = 0; 29368410SWang.Lin@Sun.COM struct an_ltv_status *status_p; 29378410SWang.Lin@Sun.COM wl_essid_t *ow_essid = (wl_essid_t *)wldp_buf; 29388410SWang.Lin@Sun.COM 29398410SWang.Lin@Sun.COM status_p = &pcan_p->an_status; 29408410SWang.Lin@Sun.COM 29418410SWang.Lin@Sun.COM if (pcan_status_ltv(PCAN_READ_LTV, pcan_p, status_p)) { 29428410SWang.Lin@Sun.COM err = EIO; 29438410SWang.Lin@Sun.COM return (err); 29448410SWang.Lin@Sun.COM } 29458410SWang.Lin@Sun.COM ow_essid->wl_essid_length = status_p->an_ssidlen; 29468410SWang.Lin@Sun.COM bcopy(status_p->an_ssid, ow_essid->wl_essid_essid, 29478410SWang.Lin@Sun.COM status_p->an_ssidlen); 29488410SWang.Lin@Sun.COM 29498410SWang.Lin@Sun.COM return (err); 29508410SWang.Lin@Sun.COM } 29518410SWang.Lin@Sun.COM 29528410SWang.Lin@Sun.COM /* 29538410SWang.Lin@Sun.COM * MAC_PROP_WL_BSSID 29548410SWang.Lin@Sun.COM */ 29558410SWang.Lin@Sun.COM static int 29568410SWang.Lin@Sun.COM pcan_set_bssid(pcan_maci_t *pcan_p, const void *wldp_buf) 29578410SWang.Lin@Sun.COM { 29588410SWang.Lin@Sun.COM wl_bssid_t *value; 29598410SWang.Lin@Sun.COM struct an_ltv_aplist *aplist_p; 29608410SWang.Lin@Sun.COM 29618410SWang.Lin@Sun.COM aplist_p = &pcan_p->an_aplist; 29628410SWang.Lin@Sun.COM 29638410SWang.Lin@Sun.COM value = (wl_bssid_t *)wldp_buf; 29648410SWang.Lin@Sun.COM (void) strncpy((char *)aplist_p->an_ap1, (char *)value, 6); 29658410SWang.Lin@Sun.COM 29668410SWang.Lin@Sun.COM return (ENETRESET); 29678410SWang.Lin@Sun.COM } 29688410SWang.Lin@Sun.COM 29698410SWang.Lin@Sun.COM static int 29708410SWang.Lin@Sun.COM pcan_get_bssid(pcan_maci_t *pcan_p, void *wldp_buf) 29718410SWang.Lin@Sun.COM { 29728410SWang.Lin@Sun.COM int err = 0; 29738410SWang.Lin@Sun.COM struct an_ltv_status *status_p; 29748410SWang.Lin@Sun.COM 29758410SWang.Lin@Sun.COM status_p = &pcan_p->an_status; 29768410SWang.Lin@Sun.COM 29778410SWang.Lin@Sun.COM if (pcan_status_ltv(PCAN_READ_LTV, pcan_p, status_p)) { 29788410SWang.Lin@Sun.COM err = EIO; 29798410SWang.Lin@Sun.COM return (err); 29808410SWang.Lin@Sun.COM } 29818410SWang.Lin@Sun.COM 29828410SWang.Lin@Sun.COM bcopy(status_p->an_cur_bssid, wldp_buf, sizeof (wl_bssid_t)); 29838410SWang.Lin@Sun.COM PCANDBG((CE_CONT, 29848410SWang.Lin@Sun.COM "pcan: cfg_bssid: bssid=%x %x %x %x %x %x\n", 29858410SWang.Lin@Sun.COM status_p->an_cur_bssid[0], 29868410SWang.Lin@Sun.COM status_p->an_cur_bssid[1], 29878410SWang.Lin@Sun.COM status_p->an_cur_bssid[2], 29888410SWang.Lin@Sun.COM status_p->an_cur_bssid[3], 29898410SWang.Lin@Sun.COM status_p->an_cur_bssid[4], 29908410SWang.Lin@Sun.COM status_p->an_cur_bssid[5])); 29918410SWang.Lin@Sun.COM 29928410SWang.Lin@Sun.COM return (err); 29938410SWang.Lin@Sun.COM } 29948410SWang.Lin@Sun.COM 29958410SWang.Lin@Sun.COM /* 29968410SWang.Lin@Sun.COM * MAC_PROP_WL_LINKSTATUS 29978410SWang.Lin@Sun.COM */ 29988410SWang.Lin@Sun.COM static void 29998410SWang.Lin@Sun.COM pcan_get_linkstatus(pcan_maci_t *pcan_p, void *wldp_buf) 30008410SWang.Lin@Sun.COM { 30018410SWang.Lin@Sun.COM if (pcan_p->pcan_flag & PCAN_CARD_LINKUP) 30028410SWang.Lin@Sun.COM *(wl_linkstatus_t *)wldp_buf = WL_CONNECTED; 30038410SWang.Lin@Sun.COM else 30048410SWang.Lin@Sun.COM *(wl_linkstatus_t *)wldp_buf = WL_NOTCONNECTED; 30058410SWang.Lin@Sun.COM 30068410SWang.Lin@Sun.COM } 30078410SWang.Lin@Sun.COM 30088410SWang.Lin@Sun.COM /* 30098410SWang.Lin@Sun.COM * MAC_PROP_WL_BSSTYP 30108410SWang.Lin@Sun.COM */ 30118410SWang.Lin@Sun.COM static int 30128410SWang.Lin@Sun.COM pcan_set_bsstype(pcan_maci_t *pcan_p, const void *wldp_buf) 30138410SWang.Lin@Sun.COM { 30148410SWang.Lin@Sun.COM struct an_ltv_genconfig *cfg_p; 30158410SWang.Lin@Sun.COM 30168410SWang.Lin@Sun.COM cfg_p = &pcan_p->an_config; 30178410SWang.Lin@Sun.COM 30188410SWang.Lin@Sun.COM if (*(wl_bss_type_t *)wldp_buf == WL_BSS_BSS) 30198410SWang.Lin@Sun.COM cfg_p->an_opmode = AN_OPMODE_INFR_STATION; 30208410SWang.Lin@Sun.COM if (*(wl_bss_type_t *)wldp_buf == WL_BSS_IBSS) 30218410SWang.Lin@Sun.COM cfg_p->an_opmode = AN_OPMODE_IBSS_ADHOC; 30228410SWang.Lin@Sun.COM if (*(wl_bss_type_t *)wldp_buf == WL_BSS_ANY) 30238410SWang.Lin@Sun.COM cfg_p->an_opmode = AN_OPMODE_INFR_STATION; 30248410SWang.Lin@Sun.COM cfg_p->an_assoc_timeout = 5000; 30258410SWang.Lin@Sun.COM 30268410SWang.Lin@Sun.COM return (ENETRESET); 30278410SWang.Lin@Sun.COM } 30288410SWang.Lin@Sun.COM 30298410SWang.Lin@Sun.COM static void 30308410SWang.Lin@Sun.COM pcan_get_bsstype(pcan_maci_t *pcan_p, void *wldp_buf) 30318410SWang.Lin@Sun.COM { 30328410SWang.Lin@Sun.COM struct an_ltv_genconfig *cfg_p; 30338410SWang.Lin@Sun.COM 30348410SWang.Lin@Sun.COM cfg_p = &pcan_p->an_config; 30358410SWang.Lin@Sun.COM 30368410SWang.Lin@Sun.COM if (cfg_p->an_opmode == AN_OPMODE_INFR_STATION) { 30378410SWang.Lin@Sun.COM *(wl_bss_type_t *)wldp_buf = WL_BSS_BSS; 30388410SWang.Lin@Sun.COM } else if (cfg_p->an_opmode == AN_OPMODE_IBSS_ADHOC) { 30398410SWang.Lin@Sun.COM *(wl_bss_type_t *)wldp_buf = WL_BSS_IBSS; 30408410SWang.Lin@Sun.COM } 30418410SWang.Lin@Sun.COM } 30428410SWang.Lin@Sun.COM 30438410SWang.Lin@Sun.COM /* 30448410SWang.Lin@Sun.COM * MAC_PROP_WL_PHY_CONFIG 30458410SWang.Lin@Sun.COM */ 30468410SWang.Lin@Sun.COM static int 30478410SWang.Lin@Sun.COM pcan_set_phy(pcan_maci_t *pcan_p, const void *wldp_buf) 30488410SWang.Lin@Sun.COM { 30498410SWang.Lin@Sun.COM uint16_t ret; 30508410SWang.Lin@Sun.COM int err = ENETRESET; 30518410SWang.Lin@Sun.COM wl_phy_conf_t *phy = (wl_phy_conf_t *)wldp_buf; 30528410SWang.Lin@Sun.COM struct an_ltv_genconfig *cfg_p; 30538410SWang.Lin@Sun.COM 30548410SWang.Lin@Sun.COM cfg_p = &pcan_p->an_config; 30558410SWang.Lin@Sun.COM 30568410SWang.Lin@Sun.COM ret = (uint16_t)(phy->wl_phy_dsss_conf.wl_dsss_channel); 30578410SWang.Lin@Sun.COM if (ret < 1 || ret > 14) { 30588410SWang.Lin@Sun.COM err = ENOTSUP; 30598410SWang.Lin@Sun.COM return (err); 30608410SWang.Lin@Sun.COM } 30618410SWang.Lin@Sun.COM cfg_p->an_ds_channel = ret; 30628410SWang.Lin@Sun.COM cfg_p->an_assoc_timeout = 5000; 30638410SWang.Lin@Sun.COM 30648410SWang.Lin@Sun.COM return (err); 30658410SWang.Lin@Sun.COM } 30668410SWang.Lin@Sun.COM 30678410SWang.Lin@Sun.COM static int 30688410SWang.Lin@Sun.COM pcan_get_phy(pcan_maci_t *pcan_p, void *wldp_buf) 30698410SWang.Lin@Sun.COM { 30708410SWang.Lin@Sun.COM int err = 0; 30718410SWang.Lin@Sun.COM struct an_ltv_status *status_p; 30728410SWang.Lin@Sun.COM wl_dsss_t *dsss = (wl_dsss_t *)wldp_buf; 30738410SWang.Lin@Sun.COM 30748410SWang.Lin@Sun.COM status_p = &pcan_p->an_status; 30758410SWang.Lin@Sun.COM 30768410SWang.Lin@Sun.COM if (pcan_status_ltv(PCAN_READ_LTV, pcan_p, status_p)) { 30778410SWang.Lin@Sun.COM err = EIO; 30788410SWang.Lin@Sun.COM return (err); 30798410SWang.Lin@Sun.COM } 30808410SWang.Lin@Sun.COM 30818410SWang.Lin@Sun.COM dsss->wl_dsss_channel = status_p->an_channel_set; 30828410SWang.Lin@Sun.COM dsss->wl_dsss_subtype = WL_DSSS; 30838410SWang.Lin@Sun.COM 30848410SWang.Lin@Sun.COM return (err); 30858410SWang.Lin@Sun.COM } 30868410SWang.Lin@Sun.COM 30878410SWang.Lin@Sun.COM /* 30888410SWang.Lin@Sun.COM * MAC_PROP_WL_DESIRED_RATESa 30898410SWang.Lin@Sun.COM */ 30908410SWang.Lin@Sun.COM static int 30918410SWang.Lin@Sun.COM pcan_set_desrates(pcan_maci_t *pcan_p, const void *wldp_buf) 30928410SWang.Lin@Sun.COM { 30938410SWang.Lin@Sun.COM uint16_t i; 30948410SWang.Lin@Sun.COM struct an_ltv_genconfig *cfg_p; 30958410SWang.Lin@Sun.COM 30968410SWang.Lin@Sun.COM cfg_p = &pcan_p->an_config; 30978410SWang.Lin@Sun.COM 30988410SWang.Lin@Sun.COM bzero(cfg_p->an_rates, sizeof (cfg_p->an_rates)); 30998410SWang.Lin@Sun.COM for (i = 0; i < ((wl_rates_t *)wldp_buf)->wl_rates_num; i++) { 31008410SWang.Lin@Sun.COM cfg_p->an_rates[i] = 31018410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[i]; 31028410SWang.Lin@Sun.COM } 31038410SWang.Lin@Sun.COM cfg_p->an_assoc_timeout = 5000; 31048410SWang.Lin@Sun.COM 31058410SWang.Lin@Sun.COM return (ENETRESET); 31068410SWang.Lin@Sun.COM } 31078410SWang.Lin@Sun.COM 31088410SWang.Lin@Sun.COM static int 31098410SWang.Lin@Sun.COM pcan_get_desrates(pcan_maci_t *pcan_p, void *wldp_buf) 31108410SWang.Lin@Sun.COM { 31118410SWang.Lin@Sun.COM uint16_t i; 31128410SWang.Lin@Sun.COM uint8_t rates = 0; 31138410SWang.Lin@Sun.COM int err = 0; 31148410SWang.Lin@Sun.COM struct an_ltv_genconfig *actcfg_p; 31158410SWang.Lin@Sun.COM 31168410SWang.Lin@Sun.COM actcfg_p = &pcan_p->an_actual_config; 31178410SWang.Lin@Sun.COM 31188410SWang.Lin@Sun.COM if (pcan_cfg_ltv(PCAN_READ_LTV, pcan_p, actcfg_p)) { 31198410SWang.Lin@Sun.COM err = EIO; 31208410SWang.Lin@Sun.COM return (err); 31218410SWang.Lin@Sun.COM } 31228410SWang.Lin@Sun.COM 31238410SWang.Lin@Sun.COM for (i = 0; i < sizeof (actcfg_p->an_rates); i++) { 31248410SWang.Lin@Sun.COM if (actcfg_p->an_rates[i] == 0) 31258410SWang.Lin@Sun.COM break; 31268410SWang.Lin@Sun.COM rates = MAX(rates, actcfg_p->an_rates[i]); 31278410SWang.Lin@Sun.COM } 31288410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] = rates; 31298410SWang.Lin@Sun.COM ((wl_rates_t *)wldp_buf)->wl_rates_num = 1; 31308410SWang.Lin@Sun.COM 31318410SWang.Lin@Sun.COM return (err); 31328410SWang.Lin@Sun.COM } 31338410SWang.Lin@Sun.COM 31348410SWang.Lin@Sun.COM /* 31358410SWang.Lin@Sun.COM * MAC_PROP_WL_SUP_RATE 31368410SWang.Lin@Sun.COM */ 31378410SWang.Lin@Sun.COM static void 31388410SWang.Lin@Sun.COM pcan_get_suprates(void *wldp_buf) 31398410SWang.Lin@Sun.COM { 31408410SWang.Lin@Sun.COM wl_rates_t *wl_rates = (wl_rates_t *)wldp_buf; 31418410SWang.Lin@Sun.COM 31428410SWang.Lin@Sun.COM wl_rates->wl_rates_num = 4; 31438410SWang.Lin@Sun.COM wl_rates->wl_rates_rates[0] = WL_RATE_1M; 31448410SWang.Lin@Sun.COM wl_rates->wl_rates_rates[1] = WL_RATE_2M; 31458410SWang.Lin@Sun.COM wl_rates->wl_rates_rates[2] = WL_RATE_5_5M; 31468410SWang.Lin@Sun.COM wl_rates->wl_rates_rates[3] = WL_RATE_11M; 31478410SWang.Lin@Sun.COM } 31488410SWang.Lin@Sun.COM 31498410SWang.Lin@Sun.COM /* 31508410SWang.Lin@Sun.COM * MAC_PROP_WL_POWER_MODE 31518410SWang.Lin@Sun.COM */ 31528410SWang.Lin@Sun.COM static int 31538410SWang.Lin@Sun.COM pcan_get_powermode(pcan_maci_t *pcan_p, void *wldp_buf) 31548410SWang.Lin@Sun.COM { 31558410SWang.Lin@Sun.COM int err = 0; 31568410SWang.Lin@Sun.COM wl_ps_mode_t *powermode = (wl_ps_mode_t *)wldp_buf; 31578410SWang.Lin@Sun.COM struct an_ltv_genconfig *actcfg_p; 31588410SWang.Lin@Sun.COM 31598410SWang.Lin@Sun.COM actcfg_p = &pcan_p->an_actual_config; 31608410SWang.Lin@Sun.COM if (pcan_cfg_ltv(PCAN_READ_LTV, pcan_p, actcfg_p)) { 31618410SWang.Lin@Sun.COM err = EIO; 31628410SWang.Lin@Sun.COM return (err); 31638410SWang.Lin@Sun.COM } 31648410SWang.Lin@Sun.COM powermode->wl_ps_mode = actcfg_p->an_psave_mode; 31658410SWang.Lin@Sun.COM 31668410SWang.Lin@Sun.COM return (err); 31678410SWang.Lin@Sun.COM } 31688410SWang.Lin@Sun.COM 31698410SWang.Lin@Sun.COM /* 31708410SWang.Lin@Sun.COM * MAC_PROP_AUTH_MODE 31718410SWang.Lin@Sun.COM */ 31728410SWang.Lin@Sun.COM static int 31738410SWang.Lin@Sun.COM pcan_set_authmode(pcan_maci_t *pcan_p, const void *wldp_buf) 31748410SWang.Lin@Sun.COM { 31758410SWang.Lin@Sun.COM struct an_ltv_genconfig *cfg_p; 31768410SWang.Lin@Sun.COM int err = ENETRESET; 31778410SWang.Lin@Sun.COM 31788410SWang.Lin@Sun.COM cfg_p = &pcan_p->an_config; 31798410SWang.Lin@Sun.COM if (*(wl_authmode_t *)wldp_buf == WL_OPENSYSTEM) { 31808410SWang.Lin@Sun.COM cfg_p->an_authtype |= AN_AUTHTYPE_OPEN; 31818410SWang.Lin@Sun.COM cfg_p->an_assoc_timeout = 5000; 31828410SWang.Lin@Sun.COM } else { 31838410SWang.Lin@Sun.COM err = EINVAL; 31848410SWang.Lin@Sun.COM } 31858410SWang.Lin@Sun.COM 31868410SWang.Lin@Sun.COM return (err); 31878410SWang.Lin@Sun.COM } 31888410SWang.Lin@Sun.COM 31898410SWang.Lin@Sun.COM static void 31908410SWang.Lin@Sun.COM pcan_get_authmode(pcan_maci_t *pcan_p, void *wldp_buf) 31918410SWang.Lin@Sun.COM { 31928410SWang.Lin@Sun.COM struct an_ltv_genconfig *cfg_p; 31938410SWang.Lin@Sun.COM 31948410SWang.Lin@Sun.COM cfg_p = &pcan_p->an_config; 31958410SWang.Lin@Sun.COM if (cfg_p->an_authtype & AN_AUTHTYPE_SHAREDKEY) { 31968410SWang.Lin@Sun.COM *(wl_bss_type_t *)wldp_buf = WL_SHAREDKEY; 31978410SWang.Lin@Sun.COM } else { 31988410SWang.Lin@Sun.COM *(wl_bss_type_t *)wldp_buf = WL_OPENSYSTEM; 31998410SWang.Lin@Sun.COM } 32008410SWang.Lin@Sun.COM } 32018410SWang.Lin@Sun.COM 32028410SWang.Lin@Sun.COM /* 32038410SWang.Lin@Sun.COM * MAC_PROP_WL_ENCRYPTION 32048410SWang.Lin@Sun.COM */ 32058410SWang.Lin@Sun.COM static int 32068410SWang.Lin@Sun.COM pcan_set_encrypt(pcan_maci_t *pcan_p, const void *wldp_buf) 32078410SWang.Lin@Sun.COM { 32088410SWang.Lin@Sun.COM struct an_ltv_genconfig *cfg_p; 32098410SWang.Lin@Sun.COM 32108410SWang.Lin@Sun.COM cfg_p = &pcan_p->an_config; 32118410SWang.Lin@Sun.COM if (*(wl_encryption_t *)wldp_buf == WL_ENC_WEP) { 32128410SWang.Lin@Sun.COM cfg_p->an_authtype |= (AN_AUTHTYPE_ENABLEWEP | 32138410SWang.Lin@Sun.COM AN_AUTHTYPE_ALLOW_UNENCRYPTED); 32148410SWang.Lin@Sun.COM pcan_p->pcan_usewep = 1; 32158410SWang.Lin@Sun.COM } 32168410SWang.Lin@Sun.COM if (*(wl_authmode_t *)wldp_buf == WL_NOENCRYPTION) { 32178410SWang.Lin@Sun.COM cfg_p->an_authtype &= (~(AN_AUTHTYPE_ENABLEWEP | 32188410SWang.Lin@Sun.COM AN_AUTHTYPE_ALLOW_UNENCRYPTED)); 32198410SWang.Lin@Sun.COM pcan_p->pcan_usewep = 0; 32208410SWang.Lin@Sun.COM } 32218410SWang.Lin@Sun.COM cfg_p->an_assoc_timeout = 5000; 32228410SWang.Lin@Sun.COM 32238410SWang.Lin@Sun.COM return (ENETRESET); 32248410SWang.Lin@Sun.COM } 32258410SWang.Lin@Sun.COM 32268410SWang.Lin@Sun.COM static void 32278410SWang.Lin@Sun.COM pcan_get_encrypt(pcan_maci_t *pcan_p, void *wldp_buf) 32288410SWang.Lin@Sun.COM { 32298410SWang.Lin@Sun.COM struct an_ltv_genconfig *cfg_p; 32308410SWang.Lin@Sun.COM 32318410SWang.Lin@Sun.COM cfg_p = &pcan_p->an_config; 32328410SWang.Lin@Sun.COM if (cfg_p->an_authtype & AN_AUTHTYPE_ENABLEWEP) { 32338410SWang.Lin@Sun.COM *(wl_bss_type_t *)wldp_buf = WL_ENC_WEP; 32348410SWang.Lin@Sun.COM } else { 32358410SWang.Lin@Sun.COM *(wl_bss_type_t *)wldp_buf = WL_NOENCRYPTION; 32368410SWang.Lin@Sun.COM } 32378410SWang.Lin@Sun.COM } 32388410SWang.Lin@Sun.COM 32398410SWang.Lin@Sun.COM /* 32408410SWang.Lin@Sun.COM * MAC_PROP_WL_KEY_TAB 32418410SWang.Lin@Sun.COM */ 32428410SWang.Lin@Sun.COM static int 32438410SWang.Lin@Sun.COM pcan_set_wepkey(pcan_maci_t *pcan_p, const void *wldp_buf) 32448410SWang.Lin@Sun.COM { 32458410SWang.Lin@Sun.COM uint16_t i; 32468410SWang.Lin@Sun.COM wl_wep_key_t *p_wepkey_tab; 32478410SWang.Lin@Sun.COM struct an_ltv_wepkey *wepkey_p; 32488410SWang.Lin@Sun.COM 32498410SWang.Lin@Sun.COM p_wepkey_tab = (wl_wep_key_t *)wldp_buf; 32508410SWang.Lin@Sun.COM for (i = 0; i < MAX_NWEPKEYS; i++) { 32518410SWang.Lin@Sun.COM if (p_wepkey_tab[i].wl_wep_operation == WL_ADD) { 32528410SWang.Lin@Sun.COM wepkey_p = &pcan_p->an_wepkey[i]; 32538410SWang.Lin@Sun.COM bzero(wepkey_p, sizeof (*wepkey_p)); 32548410SWang.Lin@Sun.COM wepkey_p->an_keylen = 32558410SWang.Lin@Sun.COM p_wepkey_tab[i].wl_wep_length; 32568410SWang.Lin@Sun.COM bcopy(p_wepkey_tab[i].wl_wep_key, 32578410SWang.Lin@Sun.COM wepkey_p->an_key, 32588410SWang.Lin@Sun.COM p_wepkey_tab[i].wl_wep_length); 32598410SWang.Lin@Sun.COM wepkey_p->an_index = i; 32608410SWang.Lin@Sun.COM wepkey_p->an_macaddr[0] = 1; 32618410SWang.Lin@Sun.COM } 32628410SWang.Lin@Sun.COM } 32638410SWang.Lin@Sun.COM 32648410SWang.Lin@Sun.COM return (ENETRESET); 32658410SWang.Lin@Sun.COM } 32668410SWang.Lin@Sun.COM 32678410SWang.Lin@Sun.COM /* 32688410SWang.Lin@Sun.COM * MAC_PROP_WL_RSSI 32698410SWang.Lin@Sun.COM */ 32708410SWang.Lin@Sun.COM static int 32718410SWang.Lin@Sun.COM pcan_get_rssi(pcan_maci_t *pcan_p, void *wldp_buf) 32728410SWang.Lin@Sun.COM { 32738410SWang.Lin@Sun.COM uint16_t val; 32748410SWang.Lin@Sun.COM int err = 0; 32758410SWang.Lin@Sun.COM wl_rssi_t *rssi = (wl_rssi_t *)wldp_buf; 32768410SWang.Lin@Sun.COM struct an_ltv_status *status_p; 32778410SWang.Lin@Sun.COM 32788410SWang.Lin@Sun.COM status_p = &pcan_p->an_status; 32798410SWang.Lin@Sun.COM 32808410SWang.Lin@Sun.COM if (val = pcan_status_ltv(PCAN_READ_LTV, pcan_p, status_p)) { 32818410SWang.Lin@Sun.COM err = EIO; 32828410SWang.Lin@Sun.COM return (err); 32838410SWang.Lin@Sun.COM } 32848410SWang.Lin@Sun.COM val = status_p->an_cur_signal_quality; 32858410SWang.Lin@Sun.COM PCANDBG((CE_NOTE, "pcan cfg_rssi: sl=%x", val)); 32868410SWang.Lin@Sun.COM /* 32878410SWang.Lin@Sun.COM * we reflect the value to 1-15 as rssi 32888410SWang.Lin@Sun.COM */ 32898410SWang.Lin@Sun.COM *rssi = 15 - ((val & 0xff) * 15 / 128 + 1); 32908410SWang.Lin@Sun.COM 32918410SWang.Lin@Sun.COM return (err); 32928410SWang.Lin@Sun.COM } 32938410SWang.Lin@Sun.COM 32948410SWang.Lin@Sun.COM /* 32958410SWang.Lin@Sun.COM * MAC_PROP_WL_RADIO 32968410SWang.Lin@Sun.COM */ 32978410SWang.Lin@Sun.COM static void 32988410SWang.Lin@Sun.COM pcan_get_radio(void *wldp_buf) 32998410SWang.Lin@Sun.COM { 33008410SWang.Lin@Sun.COM wl_radio_t *radio = (wl_radio_t *)wldp_buf; 33018410SWang.Lin@Sun.COM 33028410SWang.Lin@Sun.COM *radio = B_TRUE; 33038410SWang.Lin@Sun.COM } 33048410SWang.Lin@Sun.COM 33058410SWang.Lin@Sun.COM /* 33068410SWang.Lin@Sun.COM * MAC_PROP_WL_ESSLIST 33078410SWang.Lin@Sun.COM */ 33088410SWang.Lin@Sun.COM static void 33098410SWang.Lin@Sun.COM pcan_get_esslist(pcan_maci_t *pcan_p, void *wldp_buf) 33108410SWang.Lin@Sun.COM { 33118410SWang.Lin@Sun.COM uint16_t i; 33128410SWang.Lin@Sun.COM wl_ess_conf_t *p_ess_conf; 33138410SWang.Lin@Sun.COM an_scan_list_t *scan_item; 33148410SWang.Lin@Sun.COM 33158410SWang.Lin@Sun.COM mutex_enter(&pcan_p->pcan_scanlist_lock); 33168410SWang.Lin@Sun.COM 33178410SWang.Lin@Sun.COM ((wl_ess_list_t *)wldp_buf)->wl_ess_list_num = 33188410SWang.Lin@Sun.COM pcan_p->an_scan_num; 33198410SWang.Lin@Sun.COM scan_item = list_head(&pcan_p->an_scan_list); 33208410SWang.Lin@Sun.COM for (i = 0; i < pcan_p->an_scan_num; i++) { 33218410SWang.Lin@Sun.COM if (!scan_item) 33228410SWang.Lin@Sun.COM break; 33238410SWang.Lin@Sun.COM p_ess_conf = (wl_ess_conf_t *)((char *)wldp_buf + 33248410SWang.Lin@Sun.COM offsetof(wl_ess_list_t, wl_ess_list_ess) + 33258410SWang.Lin@Sun.COM i * sizeof (wl_ess_conf_t)); 33268410SWang.Lin@Sun.COM bcopy(scan_item->an_val.an_ssid, 33278410SWang.Lin@Sun.COM p_ess_conf->wl_ess_conf_essid.wl_essid_essid, 33288410SWang.Lin@Sun.COM mi_strlen(scan_item->an_val.an_ssid)); 33298410SWang.Lin@Sun.COM bcopy(scan_item->an_val.an_bssid, 33308410SWang.Lin@Sun.COM p_ess_conf->wl_ess_conf_bssid, 6); 33318410SWang.Lin@Sun.COM (p_ess_conf->wl_phy_conf).wl_phy_dsss_conf.wl_dsss_subtype 33328410SWang.Lin@Sun.COM = WL_DSSS; 33338410SWang.Lin@Sun.COM p_ess_conf->wl_ess_conf_wepenabled = 33348410SWang.Lin@Sun.COM (scan_item->an_val.an_cap & 0x10 ? 33358410SWang.Lin@Sun.COM WL_ENC_WEP : WL_NOENCRYPTION); 33368410SWang.Lin@Sun.COM p_ess_conf->wl_ess_conf_bsstype = 33378410SWang.Lin@Sun.COM (scan_item->an_val.an_cap & 0x1 ? 33388410SWang.Lin@Sun.COM WL_BSS_BSS : WL_BSS_IBSS); 33398410SWang.Lin@Sun.COM p_ess_conf->wl_phy_conf.wl_phy_dsss_conf.wl_dsss_channel = 33408410SWang.Lin@Sun.COM scan_item->an_val.an_dschannel; 33418410SWang.Lin@Sun.COM p_ess_conf->wl_ess_conf_sl = 15 - 33428410SWang.Lin@Sun.COM ((scan_item->an_val.an_rssi & 0xff) * 15 / 128); 33438410SWang.Lin@Sun.COM p_ess_conf->wl_supported_rates[0] = WL_RATE_1M; 33448410SWang.Lin@Sun.COM p_ess_conf->wl_supported_rates[1] = WL_RATE_2M; 33458410SWang.Lin@Sun.COM p_ess_conf->wl_supported_rates[2] = WL_RATE_5_5M; 33468410SWang.Lin@Sun.COM p_ess_conf->wl_supported_rates[3] = WL_RATE_11M; 33478410SWang.Lin@Sun.COM scan_item = list_next(&pcan_p->an_scan_list, scan_item); 33488410SWang.Lin@Sun.COM } 33498410SWang.Lin@Sun.COM 33508410SWang.Lin@Sun.COM mutex_exit(&pcan_p->pcan_scanlist_lock); 33518410SWang.Lin@Sun.COM } 33523737Shx147065 33533737Shx147065 /* 33543737Shx147065 * for wificonfig and dlamd ioctl 33553737Shx147065 */ 33563737Shx147065 static int 33573737Shx147065 pcan_cfg_essid(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 33583737Shx147065 { 33598410SWang.Lin@Sun.COM uint16_t i; 33608410SWang.Lin@Sun.COM wldp_t *infp; 33618410SWang.Lin@Sun.COM wldp_t *outfp; 33628410SWang.Lin@Sun.COM char *buf; 33638410SWang.Lin@Sun.COM int iret; 33648410SWang.Lin@Sun.COM int err = 0; 33653737Shx147065 33663737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 33673737Shx147065 if (buf == NULL) { 33683737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_essid: failed to alloc " 33693737Shx147065 "memory(%d)\n", MAX_BUF_LEN)); 33703737Shx147065 return (ENOMEM); 33713737Shx147065 } 33723737Shx147065 outfp = (wldp_t *)buf; 33733737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 33743737Shx147065 infp = (wldp_t *)mp->b_rptr; 33753737Shx147065 33763737Shx147065 if (cmd == WLAN_GET_PARAM) { 33778410SWang.Lin@Sun.COM err = pcan_get_essid(pcan_p, outfp->wldp_buf); 33788410SWang.Lin@Sun.COM if (err == EIO) { 33793737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 33803737Shx147065 outfp->wldp_result = WL_HW_ERROR; 33813737Shx147065 goto done; 33823737Shx147065 } 33833737Shx147065 outfp->wldp_result = WL_SUCCESS; 33843737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 33858410SWang.Lin@Sun.COM (void) pcan_set_essid(pcan_p, infp->wldp_buf); 33863737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 33873737Shx147065 outfp->wldp_result = WL_SUCCESS; 33883737Shx147065 } else { 33893737Shx147065 kmem_free(buf, MAX_BUF_LEN); 33903737Shx147065 return (EINVAL); 33913737Shx147065 } 33928410SWang.Lin@Sun.COM 33933737Shx147065 done: 33943737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) { 33953737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 33963737Shx147065 } 33973737Shx147065 iret = (int)(outfp->wldp_result); 33983737Shx147065 kmem_free(buf, MAX_BUF_LEN); 33993737Shx147065 return (iret); 34003737Shx147065 } 34013737Shx147065 34023737Shx147065 static int 34033737Shx147065 pcan_cfg_bssid(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 34043737Shx147065 { 34058410SWang.Lin@Sun.COM uint16_t i; 34068410SWang.Lin@Sun.COM wldp_t *infp; 34078410SWang.Lin@Sun.COM wldp_t *outfp; 34088410SWang.Lin@Sun.COM char *buf; 34098410SWang.Lin@Sun.COM int iret; 34108410SWang.Lin@Sun.COM int err = 0; 34113737Shx147065 34123737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 34133737Shx147065 if (buf == NULL) { 34143737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_bssid: failed to alloc " 34153737Shx147065 "memory(%d)\n", MAX_BUF_LEN)); 34163737Shx147065 return (ENOMEM); 34173737Shx147065 } 34183737Shx147065 outfp = (wldp_t *)buf; 34193737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 34203737Shx147065 infp = (wldp_t *)mp->b_rptr; 34213737Shx147065 34223737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_bssid_t); 34233737Shx147065 34243737Shx147065 if (cmd == WLAN_GET_PARAM) { 34258410SWang.Lin@Sun.COM err = pcan_get_bssid(pcan_p, outfp->wldp_buf); 34268410SWang.Lin@Sun.COM if (err == EIO) { 34273737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 34283737Shx147065 outfp->wldp_result = WL_HW_ERROR; 34293737Shx147065 goto done; 34303737Shx147065 } 34313737Shx147065 outfp->wldp_result = WL_SUCCESS; 34323737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 34338410SWang.Lin@Sun.COM (void) pcan_set_bssid(pcan_p, infp->wldp_buf); 34343737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 34353737Shx147065 outfp->wldp_result = WL_SUCCESS; 34363737Shx147065 } else { 34373737Shx147065 kmem_free(buf, MAX_BUF_LEN); 34383737Shx147065 return (EINVAL); 34393737Shx147065 } 34408410SWang.Lin@Sun.COM 34413737Shx147065 done: 34423737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) { 34433737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 34443737Shx147065 } 34453737Shx147065 iret = (int)(outfp->wldp_result); 34463737Shx147065 kmem_free(buf, MAX_BUF_LEN); 34473737Shx147065 return (iret); 34483737Shx147065 } 34493737Shx147065 34503737Shx147065 /*ARGSUSED*/ 34513737Shx147065 static int 34523737Shx147065 pcan_cmd_scan(pcan_maci_t *pcan_p) 34533737Shx147065 { 34543737Shx147065 uint16_t i = 0, j, ret = WL_SUCCESS; 34553737Shx147065 uint8_t bssid_t[6]; 34563737Shx147065 uint32_t check_num, enable; 34573737Shx147065 an_scan_list_t *scan_item0; 34583737Shx147065 34593737Shx147065 enable = pcan_p->pcan_flag & PCAN_ENABLED; 34603737Shx147065 if ((!enable) && 34613737Shx147065 (ret = pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0))) { 34623737Shx147065 ret = (int)WL_HW_ERROR; 34633737Shx147065 goto exit; 34643737Shx147065 } 34653737Shx147065 if (ret = pcan_set_cmd(pcan_p, AN_CMD_SCAN, 0)) { 34663737Shx147065 ret = (int)WL_HW_ERROR; 34673737Shx147065 goto exit; 34683737Shx147065 } 34693737Shx147065 34703737Shx147065 pcan_delay(pcan_p, 500000); 34713737Shx147065 ret = pcan_scanresult_ltv(PCAN_READ_LTV, 34723737Shx147065 pcan_p, AN_RID_ESSIDLIST_FIRST, &pcan_p->an_scanresult[i]); 34733737Shx147065 if ((ret) || pcan_p->an_scanresult[i].an_index == 0xffff) { 34743737Shx147065 goto done; 34753737Shx147065 } 34763737Shx147065 do 34773737Shx147065 { 34783737Shx147065 i++; 34793737Shx147065 ret = pcan_scanresult_ltv(PCAN_READ_LTV, 34803737Shx147065 pcan_p, AN_RID_ESSIDLIST_NEXT, &pcan_p->an_scanresult[i]); 34813737Shx147065 } while ((!ret) && (i < 32) && 34823737Shx147065 (pcan_p->an_scanresult[i].an_index != 0xffff)); 34833737Shx147065 done: 34843737Shx147065 if ((!enable) && 34853737Shx147065 (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0))) { 34863737Shx147065 ret = (int)WL_HW_ERROR; 34873737Shx147065 goto exit; 34883737Shx147065 } 34893737Shx147065 /* record the scan result for future use */ 34903737Shx147065 bzero(bssid_t, sizeof (bssid_t)); 34913737Shx147065 for (j = 0; j < i; j++) { 34923737Shx147065 /* 34933737Shx147065 * sometimes, those empty items are recorded by hardware, 34943737Shx147065 * this is wrong, just ignore those items here. 34953737Shx147065 */ 34963737Shx147065 if (bcmp(pcan_p->an_scanresult[j].an_bssid, 34973737Shx147065 bssid_t, 6) == 0) { 34983737Shx147065 continue; 34993737Shx147065 } 35003737Shx147065 /* 35013737Shx147065 * save/update the scan item in scanlist 35023737Shx147065 */ 35033737Shx147065 mutex_enter(&pcan_p->pcan_scanlist_lock); 35043737Shx147065 check_num = 0; 35053737Shx147065 scan_item0 = list_head(&pcan_p->an_scan_list); 35063737Shx147065 if (scan_item0 == NULL) { 35073737Shx147065 if (pcan_add_scan_item(pcan_p, 35083737Shx147065 pcan_p->an_scanresult[j]) != 0) { 35093737Shx147065 mutex_exit(&pcan_p->pcan_scanlist_lock); 35103737Shx147065 return (WL_SUCCESS); 35113737Shx147065 } 35123737Shx147065 } 35133737Shx147065 for (; scan_item0; ) { 35143737Shx147065 if (bcmp(pcan_p->an_scanresult[j].an_bssid, 35153737Shx147065 scan_item0->an_val.an_bssid, 6) == 0) { 35163737Shx147065 scan_item0->an_val = pcan_p->an_scanresult[j]; 35173737Shx147065 scan_item0->an_timeout = AN_SCAN_TIMEOUT_MAX; 35183737Shx147065 break; 35193737Shx147065 } else { 35203737Shx147065 check_num++; 35213737Shx147065 } 35223737Shx147065 scan_item0 = list_next(&pcan_p->an_scan_list, 35233737Shx147065 scan_item0); 35243737Shx147065 } 35253737Shx147065 if (check_num == pcan_p->an_scan_num) { 35263737Shx147065 if (pcan_add_scan_item(pcan_p, 35273737Shx147065 pcan_p->an_scanresult[j]) != 0) { 35283737Shx147065 mutex_exit(&pcan_p->pcan_scanlist_lock); 35293737Shx147065 return (WL_SUCCESS); 35303737Shx147065 } 35313737Shx147065 } 35323737Shx147065 mutex_exit(&pcan_p->pcan_scanlist_lock); 35333737Shx147065 } 35343737Shx147065 exit: 35353737Shx147065 if (ret) 35364343Sgd78059 cmn_err(CE_WARN, "pcan: scan failed due to hardware error"); 35373737Shx147065 return (ret); 35383737Shx147065 } 35393737Shx147065 35403737Shx147065 /*ARGSUSED*/ 35413737Shx147065 static int 35423737Shx147065 pcan_cfg_scan(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 35433737Shx147065 { 35448410SWang.Lin@Sun.COM wldp_t *outfp; 35458410SWang.Lin@Sun.COM char *buf; 35468410SWang.Lin@Sun.COM uint16_t i; 35473737Shx147065 35483737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 35493737Shx147065 if (buf == NULL) { 35503737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_scanlist: failed to alloc " 35513737Shx147065 "memory(%d)\n", MAX_BUF_LEN)); 35523737Shx147065 return (ENOMEM); 35533737Shx147065 } 35543737Shx147065 outfp = (wldp_t *)buf; 35553737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 35563737Shx147065 35578410SWang.Lin@Sun.COM pcan_get_esslist(pcan_p, outfp->wldp_buf); 35588410SWang.Lin@Sun.COM 35593737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 35603737Shx147065 offsetof(wl_ess_list_t, wl_ess_list_ess) + 35613737Shx147065 pcan_p->an_scan_num * sizeof (wl_ess_conf_t); 35623737Shx147065 outfp->wldp_result = WL_SUCCESS; 35633737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 35643737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 35653737Shx147065 kmem_free(buf, MAX_BUF_LEN); 35663737Shx147065 return (WL_SUCCESS); 35673737Shx147065 } 35683737Shx147065 35693737Shx147065 /*ARGSUSED*/ 35703737Shx147065 static int 35713737Shx147065 pcan_cfg_linkstatus(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 35723737Shx147065 { 35733737Shx147065 wldp_t *outfp; 35743737Shx147065 char *buf; 35753737Shx147065 uint16_t i; 35763737Shx147065 35773737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 35783737Shx147065 if (buf == NULL) { 35793737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_linkstatus: failed to alloc " 35803737Shx147065 "memory(%d)\n", MAX_BUF_LEN)); 35813737Shx147065 return (ENOMEM); 35823737Shx147065 } 35833737Shx147065 outfp = (wldp_t *)buf; 35843737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 35853737Shx147065 35868410SWang.Lin@Sun.COM pcan_get_linkstatus(pcan_p, outfp->wldp_buf); 35878410SWang.Lin@Sun.COM 35888410SWang.Lin@Sun.COM outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_linkstatus_t); 35893737Shx147065 outfp->wldp_result = WL_SUCCESS; 35903737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 35913737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 35923737Shx147065 kmem_free(buf, MAX_BUF_LEN); 35933737Shx147065 return (WL_SUCCESS); 35943737Shx147065 } 35953737Shx147065 35963737Shx147065 static int 35973737Shx147065 pcan_cfg_bsstype(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 35983737Shx147065 { 35993737Shx147065 uint16_t i; 36003737Shx147065 wldp_t *infp; 36013737Shx147065 wldp_t *outfp; 36023737Shx147065 char *buf; 36033737Shx147065 int iret; 36043737Shx147065 36053737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 36063737Shx147065 if (buf == NULL) { 36073737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_bsstype: failed to alloc " 36083737Shx147065 "memory(%d)\n", MAX_BUF_LEN)); 36093737Shx147065 return (ENOMEM); 36103737Shx147065 } 36113737Shx147065 outfp = (wldp_t *)buf; 36123737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 36133737Shx147065 infp = (wldp_t *)mp->b_rptr; 36143737Shx147065 36153737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_bss_type_t); 36163737Shx147065 36173737Shx147065 if (cmd == WLAN_GET_PARAM) { 36188410SWang.Lin@Sun.COM pcan_get_bsstype(pcan_p, outfp->wldp_buf); 36193737Shx147065 outfp->wldp_result = WL_SUCCESS; 36203737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 36218410SWang.Lin@Sun.COM (void) pcan_set_bsstype(pcan_p, infp->wldp_buf); 36223737Shx147065 outfp->wldp_result = WL_SUCCESS; 36233737Shx147065 } else { 36243737Shx147065 kmem_free(buf, MAX_BUF_LEN); 36253737Shx147065 return (EINVAL); 36263737Shx147065 } 36273737Shx147065 36283737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 36293737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 36303737Shx147065 iret = (int)(outfp->wldp_result); 36313737Shx147065 kmem_free(buf, MAX_BUF_LEN); 36323737Shx147065 return (iret); 36333737Shx147065 } 36343737Shx147065 36353737Shx147065 static int 36363737Shx147065 pcan_cfg_phy(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 36373737Shx147065 { 36388410SWang.Lin@Sun.COM uint16_t i; 36398410SWang.Lin@Sun.COM wldp_t *infp; 36408410SWang.Lin@Sun.COM wldp_t *outfp; 36418410SWang.Lin@Sun.COM char *buf; 36428410SWang.Lin@Sun.COM int iret; 36438410SWang.Lin@Sun.COM int err = 0; 36443737Shx147065 36453737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 36463737Shx147065 if (buf == NULL) { 36473737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_phy: failed to alloc " 36483737Shx147065 "memory(%d)\n", MAX_BUF_LEN)); 36493737Shx147065 return (ENOMEM); 36503737Shx147065 } 36513737Shx147065 outfp = (wldp_t *)buf; 36523737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 36533737Shx147065 infp = (wldp_t *)mp->b_rptr; 36543737Shx147065 36553737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_dsss_t); 36568410SWang.Lin@Sun.COM 36573737Shx147065 if (cmd == WLAN_GET_PARAM) { 36588410SWang.Lin@Sun.COM err = pcan_get_phy(pcan_p, outfp->wldp_buf); 36598410SWang.Lin@Sun.COM if (err == EIO) { 36603737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 36613737Shx147065 outfp->wldp_result = WL_HW_ERROR; 36623737Shx147065 goto done; 36633737Shx147065 } 36643737Shx147065 outfp->wldp_result = WL_SUCCESS; 36653737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 36668410SWang.Lin@Sun.COM err = pcan_set_phy(pcan_p, infp->wldp_buf); 36678410SWang.Lin@Sun.COM if (err == ENOTSUP) { 36683737Shx147065 outfp->wldp_result = WL_NOTSUPPORTED; 36693737Shx147065 goto done; 36703737Shx147065 } 36713737Shx147065 outfp->wldp_result = WL_SUCCESS; 36723737Shx147065 } else { 36733737Shx147065 kmem_free(buf, MAX_BUF_LEN); 36743737Shx147065 return (EINVAL); 36753737Shx147065 } 36768410SWang.Lin@Sun.COM 36773737Shx147065 done: 36783737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 36793737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 36803737Shx147065 iret = (int)(outfp->wldp_result); 36813737Shx147065 kmem_free(buf, MAX_BUF_LEN); 36823737Shx147065 return (iret); 36833737Shx147065 36843737Shx147065 } 36853737Shx147065 36863737Shx147065 /*ARGSUSED*/ 36873737Shx147065 static int 36883737Shx147065 pcan_cfg_desiredrates(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 36893737Shx147065 { 36908410SWang.Lin@Sun.COM uint16_t i; 36918410SWang.Lin@Sun.COM wldp_t *infp; 36928410SWang.Lin@Sun.COM wldp_t *outfp; 36938410SWang.Lin@Sun.COM char *buf; 36948410SWang.Lin@Sun.COM int iret; 36958410SWang.Lin@Sun.COM int err = 0; 36968410SWang.Lin@Sun.COM 36973737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 36983737Shx147065 if (buf == NULL) { 36993737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_rates: failed to alloc " 37003737Shx147065 "memory(%d)\n", MAX_BUF_LEN)); 37013737Shx147065 return (ENOMEM); 37023737Shx147065 } 37033737Shx147065 outfp = (wldp_t *)buf; 37043737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 37053737Shx147065 infp = (wldp_t *)mp->b_rptr; 37063737Shx147065 37073737Shx147065 if (cmd == WLAN_GET_PARAM) { 37088410SWang.Lin@Sun.COM err = pcan_get_desrates(pcan_p, outfp->wldp_buf); 37098410SWang.Lin@Sun.COM if (err == EIO) { 37103737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 37113737Shx147065 outfp->wldp_result = WL_HW_ERROR; 37123737Shx147065 goto done; 37133737Shx147065 } 37143737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 37153737Shx147065 offsetof(wl_rates_t, wl_rates_rates) + sizeof (char); 37163737Shx147065 outfp->wldp_result = WL_SUCCESS; 37173737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 37188410SWang.Lin@Sun.COM (void) pcan_set_desrates(pcan_p, infp->wldp_buf); 37193737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 37203737Shx147065 outfp->wldp_result = WL_SUCCESS; 37213737Shx147065 } else { 37223737Shx147065 kmem_free(buf, MAX_BUF_LEN); 37233737Shx147065 return (EINVAL); 37243737Shx147065 } 37258410SWang.Lin@Sun.COM 37263737Shx147065 done: 37273737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 37283737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 37293737Shx147065 iret = (int)(outfp->wldp_result); 37303737Shx147065 kmem_free(buf, MAX_BUF_LEN); 37313737Shx147065 return (iret); 37323737Shx147065 } 37333737Shx147065 37343737Shx147065 /*ARGSUSED*/ 37353737Shx147065 static int 37363737Shx147065 pcan_cfg_supportrates(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 37373737Shx147065 { 37383737Shx147065 uint16_t i; 37393737Shx147065 int iret; 37403737Shx147065 wldp_t *outfp; 37413737Shx147065 char *buf; 37423737Shx147065 37433737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 37443737Shx147065 if (buf == NULL) { 37453737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_supportedrates: failed to alloc " 37463737Shx147065 "memory(%d)\n", MAX_BUF_LEN)); 37473737Shx147065 return (ENOMEM); 37483737Shx147065 } 37493737Shx147065 outfp = (wldp_t *)buf; 37503737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 37513737Shx147065 37523737Shx147065 if (cmd == WLAN_GET_PARAM) { 37538410SWang.Lin@Sun.COM pcan_get_suprates(outfp->wldp_buf); 37543737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 37553737Shx147065 offsetof(wl_rates_t, wl_rates_rates) + 37563737Shx147065 4 * sizeof (char); 37573737Shx147065 outfp->wldp_result = WL_SUCCESS; 37583737Shx147065 } else { 37593737Shx147065 kmem_free(buf, MAX_BUF_LEN); 37603737Shx147065 return (EINVAL); 37613737Shx147065 } 37628410SWang.Lin@Sun.COM 37633737Shx147065 done: 37643737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 37653737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 37663737Shx147065 iret = (int)(outfp->wldp_result); 37673737Shx147065 kmem_free(buf, MAX_BUF_LEN); 37683737Shx147065 return (iret); 37693737Shx147065 } 37703737Shx147065 37713737Shx147065 /*ARGSUSED*/ 37723737Shx147065 static int 37733737Shx147065 pcan_cfg_powermode(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 37743737Shx147065 { 37758410SWang.Lin@Sun.COM uint16_t i; 37768410SWang.Lin@Sun.COM wldp_t *outfp; 37778410SWang.Lin@Sun.COM char *buf; 37788410SWang.Lin@Sun.COM int iret; 37798410SWang.Lin@Sun.COM int err = 0; 37803737Shx147065 37813737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 37823737Shx147065 if (buf == NULL) { 37833737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_powermode: failed to alloc " 37843737Shx147065 "memory(%d)\n", MAX_BUF_LEN)); 37853737Shx147065 return (ENOMEM); 37863737Shx147065 } 37873737Shx147065 outfp = (wldp_t *)buf; 37883737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 37893737Shx147065 37903737Shx147065 if (cmd == WLAN_GET_PARAM) { 37918410SWang.Lin@Sun.COM err = pcan_get_powermode(pcan_p, outfp->wldp_buf); 37928410SWang.Lin@Sun.COM if (err == EIO) { 37933737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 37943737Shx147065 outfp->wldp_result = WL_HW_ERROR; 37953737Shx147065 goto done; 37963737Shx147065 } 37973737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 37983737Shx147065 sizeof (wl_ps_mode_t); 37993737Shx147065 outfp->wldp_result = WL_SUCCESS; 38003737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 38013737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 38023737Shx147065 outfp->wldp_result = WL_LACK_FEATURE; 38033737Shx147065 } else { 38043737Shx147065 kmem_free(buf, MAX_BUF_LEN); 38053737Shx147065 return (EINVAL); 38063737Shx147065 } 38078410SWang.Lin@Sun.COM 38083737Shx147065 done: 38093737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 38103737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 38113737Shx147065 iret = (int)(outfp->wldp_result); 38123737Shx147065 kmem_free(buf, MAX_BUF_LEN); 38133737Shx147065 return (iret); 38143737Shx147065 38153737Shx147065 } 38163737Shx147065 38173737Shx147065 static int 38183737Shx147065 pcan_cfg_authmode(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 38193737Shx147065 { 38203737Shx147065 uint16_t i; 38213737Shx147065 wldp_t *outfp; 38223737Shx147065 char *buf; 38233737Shx147065 int iret; 38248410SWang.Lin@Sun.COM int err = 0; 38253737Shx147065 struct an_ltv_genconfig *actcfg_p; 38263737Shx147065 38273737Shx147065 actcfg_p = &pcan_p->an_actual_config; 38283737Shx147065 38293737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 38303737Shx147065 if (buf == NULL) { 38313737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_autymode: failed to alloc " 38323737Shx147065 "memory(%d)\n", MAX_BUF_LEN)); 38333737Shx147065 return (ENOMEM); 38343737Shx147065 } 38353737Shx147065 outfp = (wldp_t *)buf; 38363737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 38373737Shx147065 38383737Shx147065 if (cmd == WLAN_GET_PARAM) { 38398410SWang.Lin@Sun.COM pcan_get_authmode(pcan_p, outfp->wldp_buf); 38403737Shx147065 outfp->wldp_result = WL_SUCCESS; 38413737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 38428410SWang.Lin@Sun.COM err = pcan_set_authmode(pcan_p, outfp->wldp_buf); 38438410SWang.Lin@Sun.COM if (err == EINVAL) { 38448410SWang.Lin@Sun.COM outfp->wldp_length = WIFI_BUF_OFFSET; 38458410SWang.Lin@Sun.COM outfp->wldp_result = WL_LACK_FEATURE; 38468410SWang.Lin@Sun.COM } else { 38473737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 38483737Shx147065 outfp->wldp_result = WL_SUCCESS; 38493737Shx147065 } 38503737Shx147065 } else { 38513737Shx147065 kmem_free(buf, MAX_BUF_LEN); 38523737Shx147065 return (EINVAL); 38533737Shx147065 } 38543737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_authmode: actual.authmode=%x", 38553737Shx147065 actcfg_p->an_authtype)); 38563737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_authmode: actual.home_product=%x", 38573737Shx147065 actcfg_p->an_rsvd6[2])); 38588410SWang.Lin@Sun.COM 38593737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 38603737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 38613737Shx147065 iret = (int)(outfp->wldp_result); 38623737Shx147065 kmem_free(buf, MAX_BUF_LEN); 38633737Shx147065 return (iret); 38643737Shx147065 } 38653737Shx147065 38663737Shx147065 static int 38673737Shx147065 pcan_cfg_encryption(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 38683737Shx147065 { 38693737Shx147065 uint16_t i; 38703737Shx147065 wldp_t *outfp; 38713737Shx147065 char *buf; 38723737Shx147065 int iret; 38733737Shx147065 38743737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 38753737Shx147065 if (buf == NULL) { 38763737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_encryption: failed to alloc " 38773737Shx147065 "memory(%d)\n", MAX_BUF_LEN)); 38783737Shx147065 return (ENOMEM); 38793737Shx147065 } 38803737Shx147065 outfp = (wldp_t *)buf; 38813737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 38823737Shx147065 38833737Shx147065 if (cmd == WLAN_GET_PARAM) { 38848410SWang.Lin@Sun.COM pcan_get_encrypt(pcan_p, outfp->wldp_buf); 38853737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_encryption_t); 38863737Shx147065 outfp->wldp_result = WL_SUCCESS; 38873737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 38888410SWang.Lin@Sun.COM (void) pcan_set_encrypt(pcan_p, outfp->wldp_buf); 38893737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 38903737Shx147065 outfp->wldp_result = WL_SUCCESS; 38913737Shx147065 } else { 38923737Shx147065 kmem_free(buf, MAX_BUF_LEN); 38933737Shx147065 return (EINVAL); 38943737Shx147065 } 38958410SWang.Lin@Sun.COM 38963737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 38973737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 38983737Shx147065 iret = (int)(outfp->wldp_result); 38993737Shx147065 kmem_free(buf, MAX_BUF_LEN); 39003737Shx147065 return (iret); 39013737Shx147065 } 39023737Shx147065 39033737Shx147065 static int 39043737Shx147065 pcan_cfg_wepkeyid(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 39053737Shx147065 { 39063737Shx147065 uint16_t i, ret; 39073737Shx147065 wldp_t *infp; 39083737Shx147065 wldp_t *outfp; 39093737Shx147065 char *buf; 39103737Shx147065 int iret; 39113737Shx147065 struct an_ltv_wepkey wepkey; 39123737Shx147065 39133737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 39143737Shx147065 if (buf == NULL) { 39153737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_wepkeyid: failed to alloc " 39163737Shx147065 "memory(%d)\n", MAX_BUF_LEN)); 39173737Shx147065 return (ENOMEM); 39183737Shx147065 } 39193737Shx147065 outfp = (wldp_t *)buf; 39203737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 39213737Shx147065 infp = (wldp_t *)mp->b_rptr; 39223737Shx147065 39233737Shx147065 if (cmd == WLAN_GET_PARAM) { 39243737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_wep_key_id_t); 39253737Shx147065 outfp->wldp_result = WL_SUCCESS; 39263737Shx147065 *(wl_wep_key_id_t *)(outfp->wldp_buf) = pcan_p->an_cur_wepkey; 39273737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 39283737Shx147065 ret = (uint16_t)(*(wl_wep_key_id_t *)(infp->wldp_buf)); 39293737Shx147065 if (ret > 3) { 39303737Shx147065 kmem_free(buf, MAX_BUF_LEN); 39313737Shx147065 return (EINVAL); 39323737Shx147065 } 39333737Shx147065 wepkey.an_index = 0xffff; 39343737Shx147065 wepkey.an_macaddr[0] = ret & 0xff; 39353737Shx147065 pcan_p->an_cur_wepkey = ret; 39363737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 39373737Shx147065 outfp->wldp_result = WL_SUCCESS; 39383737Shx147065 } else { 39393737Shx147065 kmem_free(buf, MAX_BUF_LEN); 39403737Shx147065 return (EINVAL); 39413737Shx147065 } 39423737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 39433737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 39443737Shx147065 iret = (int)(outfp->wldp_result); 39453737Shx147065 kmem_free(buf, MAX_BUF_LEN); 39463737Shx147065 return (iret); 39473737Shx147065 } 39483737Shx147065 39493737Shx147065 /*ARGSUSED*/ 39503737Shx147065 static int 39513737Shx147065 pcan_cfg_createibss(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 39523737Shx147065 { 39533737Shx147065 uint16_t i; 39543737Shx147065 wldp_t *outfp; 39553737Shx147065 char *buf; 39563737Shx147065 int iret; 39573737Shx147065 39583737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 39593737Shx147065 if (buf == NULL) { 39603737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_createibss: failed to alloc " 39613737Shx147065 "memory(%d)\n", MAX_BUF_LEN)); 39623737Shx147065 return (ENOMEM); 39633737Shx147065 } 39643737Shx147065 outfp = (wldp_t *)buf; 39653737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 39663737Shx147065 39673737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_create_ibss_t); 39683737Shx147065 outfp->wldp_result = WL_LACK_FEATURE; 39693737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 39703737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 39713737Shx147065 iret = (int)(outfp->wldp_result); 39723737Shx147065 kmem_free(buf, MAX_BUF_LEN); 39733737Shx147065 return (iret); 39743737Shx147065 } 39753737Shx147065 39763737Shx147065 static int 39773737Shx147065 pcan_cfg_rssi(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 39783737Shx147065 { 39798410SWang.Lin@Sun.COM uint16_t i; 39808410SWang.Lin@Sun.COM int iret; 39818410SWang.Lin@Sun.COM wldp_t *outfp; 39828410SWang.Lin@Sun.COM char *buf; 39838410SWang.Lin@Sun.COM int err = 0; 39843737Shx147065 39853737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 39863737Shx147065 if (buf == NULL) { 39873737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_rssi: failed to alloc " 39883737Shx147065 "memory(%d)\n", MAX_BUF_LEN)); 39893737Shx147065 return (ENOMEM); 39903737Shx147065 } 39913737Shx147065 outfp = (wldp_t *)buf; 39923737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 39933737Shx147065 39943737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_rssi_t); 39953737Shx147065 39963737Shx147065 if (cmd == WLAN_GET_PARAM) { 39978410SWang.Lin@Sun.COM err = pcan_get_rssi(pcan_p, outfp->wldp_buf); 39988410SWang.Lin@Sun.COM if (err == EIO) { 39993737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 40003737Shx147065 outfp->wldp_result = WL_HW_ERROR; 40013737Shx147065 goto done; 40023737Shx147065 } 40033737Shx147065 outfp->wldp_result = WL_SUCCESS; 40043737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 40053737Shx147065 outfp->wldp_result = WL_READONLY; 40063737Shx147065 } else { 40073737Shx147065 kmem_free(buf, MAX_BUF_LEN); 40083737Shx147065 return (EINVAL); 40093737Shx147065 } 40108410SWang.Lin@Sun.COM 40113737Shx147065 done: 40123737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 40133737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 40143737Shx147065 iret = (int)(outfp->wldp_result); 40153737Shx147065 kmem_free(buf, MAX_BUF_LEN); 40163737Shx147065 return (iret); 40173737Shx147065 } 40183737Shx147065 40193737Shx147065 /*ARGSUSED*/ 40203737Shx147065 static int 40213737Shx147065 pcan_cfg_radio(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 40223737Shx147065 { 40233737Shx147065 uint16_t i; 40243737Shx147065 int iret; 40253737Shx147065 wldp_t *outfp; 40263737Shx147065 char *buf; 40273737Shx147065 40283737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 40293737Shx147065 if (buf == NULL) { 40303737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_radio: failed to alloc " 40313737Shx147065 "memory(%d)\n", MAX_BUF_LEN)); 40323737Shx147065 return (ENOMEM); 40333737Shx147065 } 40343737Shx147065 outfp = (wldp_t *)buf; 40353737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 40363737Shx147065 40373737Shx147065 if (cmd == WLAN_GET_PARAM) { 40383737Shx147065 *(wl_radio_t *)(outfp->wldp_buf) = B_TRUE; 40393737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_radio_t); 40403737Shx147065 outfp->wldp_result = WL_SUCCESS; 40413737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 40423737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 40433737Shx147065 outfp->wldp_result = WL_LACK_FEATURE; 40443737Shx147065 } else { 40453737Shx147065 kmem_free(buf, MAX_BUF_LEN); 40463737Shx147065 return (EINVAL); 40473737Shx147065 } 40483737Shx147065 40493737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 40503737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 40513737Shx147065 iret = (int)(outfp->wldp_result); 40523737Shx147065 kmem_free(buf, MAX_BUF_LEN); 40533737Shx147065 return (iret); 40543737Shx147065 } 40553737Shx147065 40563737Shx147065 static int 40573737Shx147065 pcan_cfg_wepkey(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 40583737Shx147065 { 40593737Shx147065 uint16_t i; 40603737Shx147065 wldp_t *outfp; 40613737Shx147065 char *buf; 40623737Shx147065 int iret; 40633737Shx147065 wldp_t *infp; 40643737Shx147065 40653737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP); 40663737Shx147065 if (buf == NULL) { 40673737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_wep: failed to alloc " 40683737Shx147065 "memory(%d)\n", MAX_BUF_LEN)); 40693737Shx147065 return (ENOMEM); 40703737Shx147065 } 40713737Shx147065 outfp = (wldp_t *)buf; 40723737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t)); 40733737Shx147065 infp = (wldp_t *)mp->b_rptr; 40743737Shx147065 40753737Shx147065 if (cmd == WLAN_GET_PARAM) { 40763737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + 40773737Shx147065 sizeof (wl_wep_key_tab_t); 40783737Shx147065 outfp->wldp_result = WL_WRITEONLY; 40793737Shx147065 } else if (cmd == WLAN_SET_PARAM) { 40808410SWang.Lin@Sun.COM (void) pcan_set_wepkey(pcan_p, infp->wldp_buf); 40813737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET; 40823737Shx147065 outfp->wldp_result = WL_SUCCESS; 40833737Shx147065 } else { 40843737Shx147065 kmem_free(buf, MAX_BUF_LEN); 40853737Shx147065 return (EINVAL); 40863737Shx147065 } 40873737Shx147065 40883737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) 40893737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]); 40903737Shx147065 iret = (int)(outfp->wldp_result); 40913737Shx147065 kmem_free(buf, MAX_BUF_LEN); 40923737Shx147065 return (iret); 40933737Shx147065 } 40943737Shx147065 40953737Shx147065 static void 40963737Shx147065 pcan_connect_timeout(void *arg) 40973737Shx147065 { 40983737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 40993737Shx147065 uint16_t ret; 41003737Shx147065 41013737Shx147065 mutex_enter(&pcan_p->pcan_glock); 41023737Shx147065 if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) 41033737Shx147065 goto done; 41043737Shx147065 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP; 41053737Shx147065 if (ret = pcan_config_mac(pcan_p)) 41063737Shx147065 goto done; 41073737Shx147065 ret = pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0); 41083737Shx147065 done: 41093737Shx147065 if (ret) 41104343Sgd78059 cmn_err(CE_WARN, "pcan: connect failed due to hardware error"); 41113737Shx147065 mutex_exit(&pcan_p->pcan_glock); 41123737Shx147065 pcan_p->pcan_connect_timeout_id = 0; 41133737Shx147065 } 41143737Shx147065 41153737Shx147065 static int 41163737Shx147065 pcan_getset(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd) 41173737Shx147065 { 41183737Shx147065 int ret = WL_SUCCESS; 41193737Shx147065 int connect = 0; 41203737Shx147065 41213737Shx147065 mutex_enter(&pcan_p->pcan_glock); 41223737Shx147065 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) { 41233737Shx147065 mutex_exit(&pcan_p->pcan_glock); 41243737Shx147065 return (PCAN_FAIL); 41253737Shx147065 } 41263737Shx147065 41273737Shx147065 switch (((wldp_t *)mp->b_rptr)->wldp_id) { 41283737Shx147065 case WL_ESSID: 41293737Shx147065 ret = pcan_cfg_essid(mp, pcan_p, cmd); 41303737Shx147065 connect = 1; 41313737Shx147065 PCANDBG((CE_NOTE, "cfg_essid\n")); 41323737Shx147065 break; 41333737Shx147065 case WL_BSSID: 41343737Shx147065 ret = pcan_cfg_bssid(mp, pcan_p, cmd); 41353737Shx147065 connect = 1; 41363737Shx147065 PCANDBG((CE_NOTE, "cfg_bssid\n")); 41373737Shx147065 break; 41383737Shx147065 case WL_ESS_LIST: 41393737Shx147065 ret = pcan_cfg_scan(mp, pcan_p, cmd); 41403737Shx147065 PCANDBG((CE_NOTE, "cfg_scan\n")); 41413737Shx147065 break; 41423737Shx147065 case WL_LINKSTATUS: 41433737Shx147065 ret = pcan_cfg_linkstatus(mp, pcan_p, cmd); 41443737Shx147065 PCANDBG((CE_NOTE, "cfg_linkstatus\n")); 41453737Shx147065 break; 41463737Shx147065 case WL_BSS_TYPE: 41473737Shx147065 ret = pcan_cfg_bsstype(mp, pcan_p, cmd); 41483737Shx147065 connect = 1; 41493737Shx147065 PCANDBG((CE_NOTE, "cfg_bsstype\n")); 41503737Shx147065 break; 41513737Shx147065 case WL_PHY_CONFIG: 41523737Shx147065 ret = pcan_cfg_phy(mp, pcan_p, cmd); 41533737Shx147065 connect = 1; 41543737Shx147065 PCANDBG((CE_NOTE, "cfg_phy\n")); 41553737Shx147065 break; 41563737Shx147065 case WL_DESIRED_RATES: 41573737Shx147065 ret = pcan_cfg_desiredrates(mp, pcan_p, cmd); 41583737Shx147065 connect = 1; 41593737Shx147065 PCANDBG((CE_NOTE, "cfg_disred-rates\n")); 41603737Shx147065 break; 41613737Shx147065 case WL_SUPPORTED_RATES: 41623737Shx147065 ret = pcan_cfg_supportrates(mp, pcan_p, cmd); 41633737Shx147065 PCANDBG((CE_NOTE, "cfg_supported-rates\n")); 41643737Shx147065 break; 41653737Shx147065 case WL_POWER_MODE: 41663737Shx147065 ret = pcan_cfg_powermode(mp, pcan_p, cmd); 41673737Shx147065 PCANDBG((CE_NOTE, "cfg_powermode\n")); 41683737Shx147065 break; 41693737Shx147065 case WL_AUTH_MODE: 41703737Shx147065 ret = pcan_cfg_authmode(mp, pcan_p, cmd); 41713737Shx147065 connect = 1; 41723737Shx147065 PCANDBG((CE_NOTE, "cfg_authmode\n")); 41733737Shx147065 break; 41743737Shx147065 case WL_ENCRYPTION: 41753737Shx147065 ret = pcan_cfg_encryption(mp, pcan_p, cmd); 41763737Shx147065 connect = 1; 41773737Shx147065 PCANDBG((CE_NOTE, "cfg_encryption\n")); 41783737Shx147065 break; 41793737Shx147065 case WL_WEP_KEY_ID: 41803737Shx147065 ret = pcan_cfg_wepkeyid(mp, pcan_p, cmd); 41813737Shx147065 connect = 1; 41823737Shx147065 PCANDBG((CE_NOTE, "cfg_wepkeyid\n")); 41833737Shx147065 break; 41843737Shx147065 case WL_CREATE_IBSS: 41853737Shx147065 ret = pcan_cfg_createibss(mp, pcan_p, cmd); 41863737Shx147065 connect = 1; 41873737Shx147065 PCANDBG((CE_NOTE, "cfg_create-ibss\n")); 41883737Shx147065 break; 41893737Shx147065 case WL_RSSI: 41903737Shx147065 ret = pcan_cfg_rssi(mp, pcan_p, cmd); 41913737Shx147065 PCANDBG((CE_NOTE, "cfg_rssi\n")); 41923737Shx147065 break; 41933737Shx147065 case WL_RADIO: 41943737Shx147065 ret = pcan_cfg_radio(mp, pcan_p, cmd); 41953737Shx147065 PCANDBG((CE_NOTE, "cfg_radio\n")); 41963737Shx147065 break; 41973737Shx147065 case WL_WEP_KEY_TAB: 41983737Shx147065 ret = pcan_cfg_wepkey(mp, pcan_p, cmd); 41993737Shx147065 connect = 1; 42003737Shx147065 PCANDBG((CE_NOTE, "cfg_wepkey\n")); 42013737Shx147065 break; 42023737Shx147065 case WL_SCAN: 42033737Shx147065 mutex_exit(&pcan_p->pcan_glock); 42043737Shx147065 if (pcan_p->pcan_connect_timeout_id != 0) { 42053737Shx147065 (void) untimeout(pcan_p->pcan_connect_timeout_id); 42063737Shx147065 pcan_p->pcan_connect_timeout_id = 0; 42073737Shx147065 } 42083737Shx147065 mutex_enter(&pcan_p->pcan_glock); 42093737Shx147065 ret = pcan_cmd_scan(pcan_p); 42103737Shx147065 /* 42113737Shx147065 * a trick here. 42123737Shx147065 * since the scan doesn't return too many items due to hardware 42133737Shx147065 * reason, so the current scan result is an accumulation of 42143737Shx147065 * several scans. For the first time or after many of the items 42153737Shx147065 * aged, we scan again if too few items now in the scan table. 42163737Shx147065 */ 42173737Shx147065 if (pcan_p->an_scan_num < AN_SCAN_AGAIN_THRESHOLD) 42183737Shx147065 ret = pcan_cmd_scan(pcan_p); 42193737Shx147065 break; 42203737Shx147065 case WL_LOAD_DEFAULTS: 42213737Shx147065 if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) { 42223737Shx147065 ret = (int)WL_HW_ERROR; 42233737Shx147065 break; 42243737Shx147065 } 42253737Shx147065 if (ret = pcan_loaddef(pcan_p)) { 42263737Shx147065 ret = (int)WL_HW_ERROR; 42273737Shx147065 break; 42283737Shx147065 } 42293737Shx147065 if (ret = pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0)) { 42303737Shx147065 ret = (int)WL_HW_ERROR; 42313737Shx147065 break; 42323737Shx147065 } 42333737Shx147065 PCANDBG((CE_NOTE, "loaddef\n")); 42343737Shx147065 break; 42353737Shx147065 case WL_DISASSOCIATE: 42363737Shx147065 mutex_exit(&pcan_p->pcan_glock); 42373737Shx147065 if (pcan_p->pcan_connect_timeout_id != 0) { 42383737Shx147065 (void) untimeout(pcan_p->pcan_connect_timeout_id); 42393737Shx147065 pcan_p->pcan_connect_timeout_id = 0; 42403737Shx147065 } 42413737Shx147065 mutex_enter(&pcan_p->pcan_glock); 42423737Shx147065 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP; 42433737Shx147065 if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) { 42443737Shx147065 ret = (int)WL_HW_ERROR; 42453737Shx147065 break; 42463737Shx147065 } 42473737Shx147065 if (ret = pcan_loaddef(pcan_p)) { 42483737Shx147065 ret = (int)WL_HW_ERROR; 42493737Shx147065 break; 42503737Shx147065 } 42513737Shx147065 PCANDBG((CE_NOTE, "disassociate\n")); 42523737Shx147065 break; 42533737Shx147065 case WL_REASSOCIATE: 42543737Shx147065 case WL_ASSOCIAT: 42553737Shx147065 mutex_exit(&pcan_p->pcan_glock); 42563737Shx147065 if (pcan_p->pcan_connect_timeout_id != 0) { 42573737Shx147065 (void) untimeout(pcan_p->pcan_connect_timeout_id); 42583737Shx147065 pcan_p->pcan_connect_timeout_id = 0; 42593737Shx147065 } 42603737Shx147065 mutex_enter(&pcan_p->pcan_glock); 42613737Shx147065 if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) { 42623737Shx147065 ret = (int)WL_HW_ERROR; 42633737Shx147065 break; 42643737Shx147065 } 42653737Shx147065 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP; 42663737Shx147065 if (ret = pcan_config_mac(pcan_p)) { 42673737Shx147065 ret = (int)WL_HW_ERROR; 42683737Shx147065 break; 42693737Shx147065 } 42703737Shx147065 if (ret = pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0)) { 42713737Shx147065 ret = (int)WL_HW_ERROR; 42723737Shx147065 break; 42733737Shx147065 } 42743737Shx147065 PCANDBG((CE_NOTE, "associate")); 42753737Shx147065 break; 42763737Shx147065 42773737Shx147065 default: 42783737Shx147065 break; 42793737Shx147065 } 42803737Shx147065 mutex_exit(&pcan_p->pcan_glock); 42813737Shx147065 if ((cmd == WLAN_SET_PARAM) && (ret == WL_SUCCESS) && (connect)) { 42823737Shx147065 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP; 42833737Shx147065 (void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0); 42843737Shx147065 if (pcan_p->pcan_connect_timeout_id != 0) { 42853737Shx147065 (void) untimeout(pcan_p->pcan_connect_timeout_id); 42863737Shx147065 pcan_p->pcan_connect_timeout_id = 0; 42873737Shx147065 } 42883737Shx147065 pcan_p->pcan_connect_timeout_id = timeout(pcan_connect_timeout, 42893737Shx147065 pcan_p, drv_usectohz(1000000)); 42903737Shx147065 } 42913737Shx147065 return (ret); 42923737Shx147065 } 42933737Shx147065 42943737Shx147065 static void 42953737Shx147065 pcan_wlan_ioctl(pcan_maci_t *pcan_p, queue_t *wq, mblk_t *mp, uint32_t cmd) 42963737Shx147065 { 42973737Shx147065 42983737Shx147065 struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 42993737Shx147065 uint32_t len, ret; 43003737Shx147065 mblk_t *mp1; 43013737Shx147065 43023737Shx147065 /* sanity check */ 43033737Shx147065 if (iocp->ioc_count == 0 || !(mp1 = mp->b_cont)) { 43043737Shx147065 miocnak(wq, mp, 0, EINVAL); 43053737Shx147065 return; 43063737Shx147065 } 43073737Shx147065 43083737Shx147065 /* assuming single data block */ 43093737Shx147065 if (mp1->b_cont) { 43103737Shx147065 freemsg(mp1->b_cont); 43113737Shx147065 mp1->b_cont = NULL; 43123737Shx147065 } 43133737Shx147065 43143737Shx147065 /* we will overwrite everything */ 43153737Shx147065 mp1->b_wptr = mp1->b_rptr; 43163737Shx147065 43173737Shx147065 ret = pcan_getset(mp1, pcan_p, cmd); 43183737Shx147065 len = msgdsize(mp1); 43193737Shx147065 miocack(wq, mp, len, ret); 43203737Shx147065 } 43213737Shx147065 43223737Shx147065 static void 43233737Shx147065 pcan_ioctl(void *arg, queue_t *wq, mblk_t *mp) 43243737Shx147065 { 43253737Shx147065 struct iocblk *iocp; 43263737Shx147065 uint32_t cmd, ret; 43273737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 43283737Shx147065 boolean_t need_privilege = B_TRUE; 43293737Shx147065 43303737Shx147065 iocp = (struct iocblk *)mp->b_rptr; 43313737Shx147065 iocp->ioc_error = 0; 43323737Shx147065 cmd = iocp->ioc_cmd; 43333737Shx147065 switch (cmd) { 43343737Shx147065 default: 43353737Shx147065 miocnak(wq, mp, 0, EINVAL); 43363737Shx147065 return; 43373737Shx147065 case WLAN_GET_PARAM: 43383737Shx147065 need_privilege = B_FALSE; 43393737Shx147065 break; 43403737Shx147065 case WLAN_SET_PARAM: 43413737Shx147065 case WLAN_COMMAND: 43423737Shx147065 break; 43433737Shx147065 } 43443737Shx147065 43457408SSebastien.Roy@Sun.COM if (need_privilege && (ret = secpolicy_dl_config(iocp->ioc_cr)) != 0) 43467408SSebastien.Roy@Sun.COM miocnak(wq, mp, 0, ret); 43477408SSebastien.Roy@Sun.COM else 43487408SSebastien.Roy@Sun.COM pcan_wlan_ioctl(pcan_p, wq, mp, cmd); 43493737Shx147065 } 43508410SWang.Lin@Sun.COM /* 43518410SWang.Lin@Sun.COM * brussels 43528410SWang.Lin@Sun.COM */ 43538410SWang.Lin@Sun.COM /* ARGSUSED */ 43548410SWang.Lin@Sun.COM static int 43558410SWang.Lin@Sun.COM pcan_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num, 43568410SWang.Lin@Sun.COM uint_t wldp_length, const void *wldp_buf) 43578410SWang.Lin@Sun.COM { 43588410SWang.Lin@Sun.COM int err = 0; 43598410SWang.Lin@Sun.COM pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 43608410SWang.Lin@Sun.COM 43618410SWang.Lin@Sun.COM mutex_enter(&pcan_p->pcan_glock); 43628410SWang.Lin@Sun.COM if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) { 43638410SWang.Lin@Sun.COM mutex_exit(&pcan_p->pcan_glock); 43648410SWang.Lin@Sun.COM err = EINVAL; 43658410SWang.Lin@Sun.COM return (err); 43668410SWang.Lin@Sun.COM } 43678410SWang.Lin@Sun.COM 43688410SWang.Lin@Sun.COM switch (wldp_pr_num) { 43698410SWang.Lin@Sun.COM /* mac_prop_id */ 43708410SWang.Lin@Sun.COM case MAC_PROP_WL_ESSID: 43718410SWang.Lin@Sun.COM err = pcan_set_essid(pcan_p, wldp_buf); 43728410SWang.Lin@Sun.COM break; 43738410SWang.Lin@Sun.COM case MAC_PROP_WL_BSSID: 43748410SWang.Lin@Sun.COM err = pcan_set_bssid(pcan_p, wldp_buf); 43758410SWang.Lin@Sun.COM break; 43768410SWang.Lin@Sun.COM case MAC_PROP_WL_PHY_CONFIG: 43778410SWang.Lin@Sun.COM err = pcan_set_phy(pcan_p, wldp_buf); 43788410SWang.Lin@Sun.COM break; 43798410SWang.Lin@Sun.COM case MAC_PROP_WL_KEY_TAB: 43808410SWang.Lin@Sun.COM err = pcan_set_wepkey(pcan_p, wldp_buf); 43818410SWang.Lin@Sun.COM break; 43828410SWang.Lin@Sun.COM case MAC_PROP_WL_AUTH_MODE: 43838410SWang.Lin@Sun.COM err = pcan_set_authmode(pcan_p, wldp_buf); 43848410SWang.Lin@Sun.COM break; 43858410SWang.Lin@Sun.COM case MAC_PROP_WL_ENCRYPTION: 43868410SWang.Lin@Sun.COM err = pcan_set_encrypt(pcan_p, wldp_buf); 43878410SWang.Lin@Sun.COM break; 43888410SWang.Lin@Sun.COM case MAC_PROP_WL_BSSTYPE: 43898410SWang.Lin@Sun.COM err = pcan_set_bsstype(pcan_p, wldp_buf); 43908410SWang.Lin@Sun.COM break; 43918410SWang.Lin@Sun.COM case MAC_PROP_WL_DESIRED_RATES: 43928410SWang.Lin@Sun.COM err = pcan_set_desrates(pcan_p, wldp_buf); 43938410SWang.Lin@Sun.COM break; 43948410SWang.Lin@Sun.COM case MAC_PROP_WL_POWER_MODE: 43958410SWang.Lin@Sun.COM case MAC_PROP_WL_CREATE_IBSS: 43968410SWang.Lin@Sun.COM case MAC_PROP_WL_RADIO: 43978410SWang.Lin@Sun.COM case MAC_PROP_WL_WPA: 43988410SWang.Lin@Sun.COM case MAC_PROP_WL_KEY: 43998410SWang.Lin@Sun.COM case MAC_PROP_WL_DELKEY: 44008410SWang.Lin@Sun.COM case MAC_PROP_WL_SETOPTIE: 44018410SWang.Lin@Sun.COM case MAC_PROP_WL_MLME: 44028410SWang.Lin@Sun.COM case MAC_PROP_WL_LINKSTATUS: 44038410SWang.Lin@Sun.COM case MAC_PROP_WL_ESS_LIST: 44048410SWang.Lin@Sun.COM case MAC_PROP_WL_SUPPORTED_RATES: 44058410SWang.Lin@Sun.COM case MAC_PROP_WL_RSSI: 44068410SWang.Lin@Sun.COM case MAC_PROP_WL_CAPABILITY: 44078410SWang.Lin@Sun.COM case MAC_PROP_WL_SCANRESULTS: 44088410SWang.Lin@Sun.COM cmn_err(CE_WARN, "pcan_setprop:" 44098410SWang.Lin@Sun.COM "opmode not support\n"); 44108410SWang.Lin@Sun.COM err = ENOTSUP; 44118410SWang.Lin@Sun.COM break; 44128410SWang.Lin@Sun.COM default: 44138410SWang.Lin@Sun.COM cmn_err(CE_WARN, "pcan_setprop:" 44148410SWang.Lin@Sun.COM "opmode err\n"); 44158410SWang.Lin@Sun.COM err = EINVAL; 44168410SWang.Lin@Sun.COM break; 44178410SWang.Lin@Sun.COM } 44188410SWang.Lin@Sun.COM 44198410SWang.Lin@Sun.COM mutex_exit(&pcan_p->pcan_glock); 44208410SWang.Lin@Sun.COM 44218410SWang.Lin@Sun.COM if (err == ENETRESET) { 44228410SWang.Lin@Sun.COM pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP; 44238410SWang.Lin@Sun.COM (void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0); 44248410SWang.Lin@Sun.COM if (pcan_p->pcan_connect_timeout_id != 0) { 44258410SWang.Lin@Sun.COM (void) untimeout(pcan_p->pcan_connect_timeout_id); 44268410SWang.Lin@Sun.COM pcan_p->pcan_connect_timeout_id = 0; 44278410SWang.Lin@Sun.COM } 44288410SWang.Lin@Sun.COM pcan_p->pcan_connect_timeout_id = timeout(pcan_connect_timeout, 44298410SWang.Lin@Sun.COM pcan_p, drv_usectohz(1000000)); 44308410SWang.Lin@Sun.COM 44318410SWang.Lin@Sun.COM err = 0; 44328410SWang.Lin@Sun.COM } 44338410SWang.Lin@Sun.COM 44348410SWang.Lin@Sun.COM return (err); 44358410SWang.Lin@Sun.COM } /* ARGSUSED */ 44368410SWang.Lin@Sun.COM 44378410SWang.Lin@Sun.COM /* ARGSUSED */ 44388410SWang.Lin@Sun.COM static int 44398410SWang.Lin@Sun.COM pcan_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num, 44408410SWang.Lin@Sun.COM uint_t pr_flags, uint_t wldp_length, void *wldp_buf, uint_t *perm) 44418410SWang.Lin@Sun.COM { 44428410SWang.Lin@Sun.COM int err = 0; 44438410SWang.Lin@Sun.COM pcan_maci_t *pcan_p = (pcan_maci_t *)arg; 44448410SWang.Lin@Sun.COM 44458410SWang.Lin@Sun.COM mutex_enter(&pcan_p->pcan_glock); 44468410SWang.Lin@Sun.COM if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) { 44478410SWang.Lin@Sun.COM mutex_exit(&pcan_p->pcan_glock); 44488410SWang.Lin@Sun.COM err = EINVAL; 44498410SWang.Lin@Sun.COM return (err); 44508410SWang.Lin@Sun.COM } 44518410SWang.Lin@Sun.COM bzero(wldp_buf, wldp_length); 44528410SWang.Lin@Sun.COM 44538410SWang.Lin@Sun.COM *perm = MAC_PROP_PERM_RW; 44548410SWang.Lin@Sun.COM 44558410SWang.Lin@Sun.COM switch (wldp_pr_num) { 44568410SWang.Lin@Sun.COM /* mac_prop_id */ 44578410SWang.Lin@Sun.COM case MAC_PROP_WL_ESSID: 44588410SWang.Lin@Sun.COM err = pcan_get_essid(pcan_p, wldp_buf); 44598410SWang.Lin@Sun.COM break; 44608410SWang.Lin@Sun.COM case MAC_PROP_WL_BSSID: 44618410SWang.Lin@Sun.COM err = pcan_get_bssid(pcan_p, wldp_buf); 44628410SWang.Lin@Sun.COM break; 44638410SWang.Lin@Sun.COM case MAC_PROP_WL_PHY_CONFIG: 44648410SWang.Lin@Sun.COM err = pcan_get_phy(pcan_p, wldp_buf); 44658410SWang.Lin@Sun.COM break; 44668410SWang.Lin@Sun.COM case MAC_PROP_WL_AUTH_MODE: 44678410SWang.Lin@Sun.COM pcan_get_authmode(pcan_p, wldp_buf); 44688410SWang.Lin@Sun.COM break; 44698410SWang.Lin@Sun.COM case MAC_PROP_WL_ENCRYPTION: 44708410SWang.Lin@Sun.COM pcan_get_encrypt(pcan_p, wldp_buf); 44718410SWang.Lin@Sun.COM break; 44728410SWang.Lin@Sun.COM case MAC_PROP_WL_BSSTYPE: 44738410SWang.Lin@Sun.COM *perm = MAC_PROP_PERM_READ; 44748410SWang.Lin@Sun.COM pcan_get_bsstype(pcan_p, wldp_buf); 44758410SWang.Lin@Sun.COM break; 44768410SWang.Lin@Sun.COM case MAC_PROP_WL_LINKSTATUS: 44778410SWang.Lin@Sun.COM pcan_get_linkstatus(pcan_p, wldp_buf); 44788410SWang.Lin@Sun.COM break; 44798410SWang.Lin@Sun.COM case MAC_PROP_WL_ESS_LIST: 44808410SWang.Lin@Sun.COM *perm = MAC_PROP_PERM_READ; 44818410SWang.Lin@Sun.COM pcan_get_esslist(pcan_p, wldp_buf); 44828410SWang.Lin@Sun.COM break; 44838410SWang.Lin@Sun.COM case MAC_PROP_WL_SUPPORTED_RATES: 44848410SWang.Lin@Sun.COM *perm = MAC_PROP_PERM_READ; 44858410SWang.Lin@Sun.COM pcan_get_suprates(wldp_buf); 44868410SWang.Lin@Sun.COM break; 44878410SWang.Lin@Sun.COM case MAC_PROP_WL_RSSI: 44888410SWang.Lin@Sun.COM *perm = MAC_PROP_PERM_READ; 44898410SWang.Lin@Sun.COM err = pcan_get_rssi(pcan_p, wldp_buf); 44908410SWang.Lin@Sun.COM break; 44918410SWang.Lin@Sun.COM case MAC_PROP_WL_RADIO: 44928410SWang.Lin@Sun.COM pcan_get_radio(wldp_buf); 44938410SWang.Lin@Sun.COM break; 44948410SWang.Lin@Sun.COM case MAC_PROP_WL_POWER_MODE: 44958410SWang.Lin@Sun.COM err = pcan_get_powermode(pcan_p, wldp_buf); 44968410SWang.Lin@Sun.COM break; 44978410SWang.Lin@Sun.COM case MAC_PROP_WL_DESIRED_RATES: 44988410SWang.Lin@Sun.COM err = pcan_get_desrates(pcan_p, wldp_buf); 44998410SWang.Lin@Sun.COM break; 45008410SWang.Lin@Sun.COM case MAC_PROP_WL_CREATE_IBSS: 45018410SWang.Lin@Sun.COM case MAC_PROP_WL_CAPABILITY: 45028410SWang.Lin@Sun.COM case MAC_PROP_WL_WPA: 45038410SWang.Lin@Sun.COM case MAC_PROP_WL_SCANRESULTS: 45048410SWang.Lin@Sun.COM case MAC_PROP_WL_KEY_TAB: 45058410SWang.Lin@Sun.COM case MAC_PROP_WL_KEY: 45068410SWang.Lin@Sun.COM case MAC_PROP_WL_DELKEY: 45078410SWang.Lin@Sun.COM case MAC_PROP_WL_SETOPTIE: 45088410SWang.Lin@Sun.COM case MAC_PROP_WL_MLME: 45098410SWang.Lin@Sun.COM cmn_err(CE_WARN, "pcan_getprop:" 45108410SWang.Lin@Sun.COM "opmode not support\n"); 45118410SWang.Lin@Sun.COM err = ENOTSUP; 45128410SWang.Lin@Sun.COM break; 45138410SWang.Lin@Sun.COM default: 45148410SWang.Lin@Sun.COM cmn_err(CE_WARN, "pcan_getprop:" 45158410SWang.Lin@Sun.COM "opmode err\n"); 45168410SWang.Lin@Sun.COM err = EINVAL; 45178410SWang.Lin@Sun.COM break; 45188410SWang.Lin@Sun.COM } 45198410SWang.Lin@Sun.COM 45208410SWang.Lin@Sun.COM mutex_exit(&pcan_p->pcan_glock); 45218410SWang.Lin@Sun.COM 45228410SWang.Lin@Sun.COM return (err); 45238410SWang.Lin@Sun.COM } 4524*8801SQuaker.Fang@Sun.COM 4525*8801SQuaker.Fang@Sun.COM /* 4526*8801SQuaker.Fang@Sun.COM * quiesce(9E) entry point. 4527*8801SQuaker.Fang@Sun.COM * 4528*8801SQuaker.Fang@Sun.COM * This function is called when the system is single-threaded at high 4529*8801SQuaker.Fang@Sun.COM * PIL with preemption disabled. Therefore, this function must not be 4530*8801SQuaker.Fang@Sun.COM * blocked. 4531*8801SQuaker.Fang@Sun.COM * 4532*8801SQuaker.Fang@Sun.COM * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure. 4533*8801SQuaker.Fang@Sun.COM * DDI_FAILURE indicates an error condition and should almost never happen. 4534*8801SQuaker.Fang@Sun.COM */ 4535*8801SQuaker.Fang@Sun.COM #ifndef __sparc 4536*8801SQuaker.Fang@Sun.COM static int 4537*8801SQuaker.Fang@Sun.COM pcan_quiesce(dev_info_t *dip) 4538*8801SQuaker.Fang@Sun.COM { 4539*8801SQuaker.Fang@Sun.COM pcan_maci_t *pcan_p; 4540*8801SQuaker.Fang@Sun.COM 4541*8801SQuaker.Fang@Sun.COM pcan_p = ddi_get_soft_state(pcan_soft_state_p, ddi_get_instance(dip)); 4542*8801SQuaker.Fang@Sun.COM if (pcan_p == NULL) 4543*8801SQuaker.Fang@Sun.COM return (DDI_FAILURE); 4544*8801SQuaker.Fang@Sun.COM 4545*8801SQuaker.Fang@Sun.COM if (pcan_p->pcan_flag & PCAN_CARD_READY) 4546*8801SQuaker.Fang@Sun.COM pcan_stop_locked(pcan_p); 4547*8801SQuaker.Fang@Sun.COM 4548*8801SQuaker.Fang@Sun.COM return (DDI_SUCCESS); 4549*8801SQuaker.Fang@Sun.COM } 4550*8801SQuaker.Fang@Sun.COM #endif 4551