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