13737Shx147065 /*
2*11878SVenu.Iyer@Sun.COM * Copyright 2010 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>
4311101SMikore.Li@Sun.COM #include <sys/strsubr.h>
443737Shx147065 #include <sys/strsun.h>
453737Shx147065 #include <sys/stat.h>
463737Shx147065 #include <sys/byteorder.h>
473737Shx147065 #include <sys/pccard.h>
483737Shx147065 #include <sys/pci.h>
493737Shx147065 #include <sys/policy.h>
508275SEric Cheng #include <sys/mac_provider.h>
513737Shx147065 #include <sys/stream.h>
523737Shx147065 #include <inet/common.h>
533737Shx147065 #include <inet/nd.h>
543737Shx147065 #include <inet/mi.h>
553737Shx147065
563737Shx147065 #include "pcwl.h"
573737Shx147065 #include <sys/mac_wifi.h>
583737Shx147065 #include <inet/wifi_ioctl.h>
593737Shx147065
603737Shx147065 #ifdef DEBUG
613737Shx147065 #define PCWL_DBG_BASIC 0x1
623737Shx147065 #define PCWL_DBG_INFO 0x2
633737Shx147065 #define PCWL_DBG_SEND 0x4
643737Shx147065 #define PCWL_DBG_RCV 0x8
653737Shx147065 #define PCWL_DBG_LINKINFO 0x10
663737Shx147065 uint32_t pcwl_debug = 0;
673737Shx147065 #define PCWLDBG(x) \
683737Shx147065 if (pcwl_debug & PCWL_DBG_BASIC) cmn_err x
693737Shx147065 #else
703737Shx147065 #define PCWLDBG(x)
713737Shx147065 #endif
723737Shx147065
733737Shx147065 /* for pci card */
743737Shx147065 static ddi_device_acc_attr_t accattr = {
753737Shx147065 DDI_DEVICE_ATTR_V0,
763737Shx147065 DDI_NEVERSWAP_ACC,
773737Shx147065 DDI_STRICTORDER_ACC,
783737Shx147065 DDI_DEFAULT_ACC
793737Shx147065 };
803737Shx147065
813737Shx147065 void *pcwl_soft_state_p = NULL;
823737Shx147065 static int pcwl_device_type;
833737Shx147065
848410SWang.Lin@Sun.COM static int pcwl_m_setprop(void *arg, const char *pr_name,
858410SWang.Lin@Sun.COM mac_prop_id_t wldp_pr_num, uint_t wldp_length,
868410SWang.Lin@Sun.COM const void *wldp_buf);
878410SWang.Lin@Sun.COM static int pcwl_m_getprop(void *arg, const char *pr_name,
88*11878SVenu.Iyer@Sun.COM mac_prop_id_t wldp_pr_num, uint_t wldp_length, void *wldp_buf);
89*11878SVenu.Iyer@Sun.COM static void pcwl_m_propinfo(void *arg, const char *pr_name,
90*11878SVenu.Iyer@Sun.COM mac_prop_id_t wlpd_pr_num, mac_prop_info_handle_t mph);
9111101SMikore.Li@Sun.COM static void
9211101SMikore.Li@Sun.COM pcwl_delay(pcwl_maci_t *, clock_t);
938410SWang.Lin@Sun.COM
943737Shx147065 mac_callbacks_t pcwl_m_callbacks = {
95*11878SVenu.Iyer@Sun.COM MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
963737Shx147065 pcwl_gstat,
973737Shx147065 pcwl_start,
983737Shx147065 pcwl_stop,
993737Shx147065 pcwl_prom,
1003737Shx147065 pcwl_sdmulti,
1013737Shx147065 pcwl_saddr,
1023737Shx147065 pcwl_tx,
103*11878SVenu.Iyer@Sun.COM NULL,
1048410SWang.Lin@Sun.COM pcwl_ioctl,
1058410SWang.Lin@Sun.COM NULL,
1068410SWang.Lin@Sun.COM NULL,
1078410SWang.Lin@Sun.COM NULL,
1088410SWang.Lin@Sun.COM pcwl_m_setprop,
109*11878SVenu.Iyer@Sun.COM pcwl_m_getprop,
110*11878SVenu.Iyer@Sun.COM pcwl_m_propinfo
1113737Shx147065 };
1123737Shx147065
1133737Shx147065 static char *pcwl_name_str = "pcwl";
1143737Shx147065
1158801SQuaker.Fang@Sun.COM #ifdef __sparc
1168801SQuaker.Fang@Sun.COM #define pcwl_quiesce ddi_quiesce_not_supported
1178801SQuaker.Fang@Sun.COM #else
1188801SQuaker.Fang@Sun.COM static int pcwl_quiesce(dev_info_t *);
1198801SQuaker.Fang@Sun.COM #endif
1208801SQuaker.Fang@Sun.COM
1213737Shx147065 DDI_DEFINE_STREAM_OPS(pcwl_dev_ops, nulldev, pcwl_probe, pcwl_attach,
1228801SQuaker.Fang@Sun.COM pcwl_detach, nodev, NULL, D_MP, NULL, pcwl_quiesce);
1233737Shx147065
1243737Shx147065 extern struct mod_ops mod_driverops;
1253737Shx147065 static struct modldrv modldrv = {
1263737Shx147065 &mod_driverops,
1273737Shx147065 "Lucent/PRISM-II 802.11b driver",
1283737Shx147065 &pcwl_dev_ops
1293737Shx147065 };
1303737Shx147065
1313737Shx147065 static struct modlinkage modlinkage = {
1323737Shx147065 MODREV_1, (void *)&modldrv, NULL
1333737Shx147065 };
1343737Shx147065
1353737Shx147065 int
_init(void)1363737Shx147065 _init(void)
1373737Shx147065 {
1383737Shx147065 int stat;
1393737Shx147065
1403737Shx147065 /* Allocate soft state */
1413737Shx147065 if ((stat = ddi_soft_state_init(&pcwl_soft_state_p,
1423737Shx147065 sizeof (pcwl_maci_t), N_PCWL)) != DDI_SUCCESS)
1433737Shx147065 return (stat);
1443737Shx147065
1453737Shx147065 mac_init_ops(&pcwl_dev_ops, "pcwl");
1463737Shx147065 wl_frame_default.wl_dat[0] = htons(WL_SNAP_WORD0);
1473737Shx147065 wl_frame_default.wl_dat[1] = htons(WL_SNAP_WORD1);
1483737Shx147065 stat = mod_install(&modlinkage);
1493737Shx147065 if (stat != DDI_SUCCESS) {
1503737Shx147065 mac_fini_ops(&pcwl_dev_ops);
1513737Shx147065 ddi_soft_state_fini(&pcwl_soft_state_p);
1523737Shx147065 }
1533737Shx147065 return (stat);
1543737Shx147065 }
1553737Shx147065
1563737Shx147065 int
_fini(void)1573737Shx147065 _fini(void)
1583737Shx147065 {
1593737Shx147065 int stat;
1603737Shx147065
1613737Shx147065 if ((stat = mod_remove(&modlinkage)) != DDI_SUCCESS)
1623737Shx147065 return (stat);
1633737Shx147065 mac_fini_ops(&pcwl_dev_ops);
1643737Shx147065 ddi_soft_state_fini(&pcwl_soft_state_p);
1653737Shx147065
1663737Shx147065 return (stat);
1673737Shx147065 }
1683737Shx147065
1693737Shx147065 int
_info(struct modinfo * modinfop)1703737Shx147065 _info(struct modinfo *modinfop)
1713737Shx147065 {
1723737Shx147065 return (mod_info(&modlinkage, modinfop));
1733737Shx147065 }
1743737Shx147065
1753737Shx147065 static int
pcwl_probe(dev_info_t * dip)1763737Shx147065 pcwl_probe(dev_info_t *dip)
1773737Shx147065 {
1783737Shx147065 int len, ret;
1793737Shx147065 char *buf;
1803737Shx147065 dev_info_t *pdip = ddi_get_parent(dip);
1813737Shx147065
1823737Shx147065 ret = ddi_getlongprop(DDI_DEV_T_ANY, pdip, 0, "device_type",
1833737Shx147065 (caddr_t)&buf, &len);
1843737Shx147065 if (ret != DDI_SUCCESS)
1853737Shx147065 return (DDI_PROBE_FAILURE);
1863737Shx147065
1873737Shx147065 PCWLDBG((CE_NOTE, "pcwl probe: device_type %s\n", buf));
1883737Shx147065 if ((strcmp(buf, "pccard") == 0) || (strcmp(buf, "pcmcia") == 0)) {
1893737Shx147065 pcwl_device_type = PCWL_DEVICE_PCCARD;
1903737Shx147065 ret = DDI_PROBE_SUCCESS;
1913737Shx147065 } else if (strcmp(buf, "pci") == 0) {
1923737Shx147065 pcwl_device_type = PCWL_DEVICE_PCI;
1933737Shx147065 ret = DDI_PROBE_SUCCESS;
1943737Shx147065 } else {
1953737Shx147065 ret = DDI_PROBE_FAILURE;
1963737Shx147065 }
1973737Shx147065 kmem_free(buf, len);
1983737Shx147065 return (ret);
1993737Shx147065 }
2003737Shx147065
2013737Shx147065 static int
pcwl_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)2023737Shx147065 pcwl_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2033737Shx147065 {
2043737Shx147065 int ret, i;
2053737Shx147065 int instance;
2063737Shx147065 uint16_t stat;
2073737Shx147065 uint32_t err;
2083737Shx147065 pcwl_maci_t *pcwl_p;
2093737Shx147065 wifi_data_t wd = { 0 };
2103737Shx147065 mac_register_t *macp;
2113737Shx147065 modify_config_t cfgmod;
2123737Shx147065 char strbuf[256];
2133737Shx147065
2143737Shx147065 PCWLDBG((CE_NOTE, "pcwl attach: dip=0x%p cmd=%x\n", (void *)dip, cmd));
2153737Shx147065 if (cmd != DDI_ATTACH)
2163737Shx147065 goto attach_fail1;
2173737Shx147065 /*
2183737Shx147065 * Allocate soft state associated with this instance.
2193737Shx147065 */
2203737Shx147065 if (ddi_soft_state_zalloc(pcwl_soft_state_p,
2213737Shx147065 ddi_get_instance(dip)) != DDI_SUCCESS) {
2223737Shx147065 cmn_err(CE_CONT, "pcwl attach: alloc softstate failed\n");
2233737Shx147065 goto attach_fail1;
2243737Shx147065 }
2253737Shx147065 pcwl_p = (pcwl_maci_t *)ddi_get_soft_state(pcwl_soft_state_p,
2263737Shx147065 ddi_get_instance(dip));
2273737Shx147065 pcwl_p->pcwl_device_type = pcwl_device_type;
2283737Shx147065 if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) {
2293737Shx147065 if (ddi_regs_map_setup(dip, 0,
2303737Shx147065 (caddr_t *)&pcwl_p->pcwl_cfg_base, 0, 0,
2313737Shx147065 &accattr, &pcwl_p->pcwl_cfg_handle) != DDI_SUCCESS) {
2323737Shx147065 cmn_err(CE_WARN, "pcwl(pci) attach: pci_regs_map_setup"
2333737Shx147065 " failed\n");
2343737Shx147065 goto attach_fail2;
2353737Shx147065 }
2363737Shx147065
2373737Shx147065 stat = ddi_get16(pcwl_p->pcwl_cfg_handle,
2383737Shx147065 (uint16_t *)(pcwl_p->pcwl_cfg_base + PCI_CONF_COMM));
2393737Shx147065 stat |= (PCI_COMM_IO | PCI_COMM_MAE);
2403737Shx147065 ddi_put16(pcwl_p->pcwl_cfg_handle,
2413737Shx147065 (uint16_t *)(pcwl_p->pcwl_cfg_base + PCI_CONF_COMM), stat);
2423737Shx147065 stat = ddi_get16(pcwl_p->pcwl_cfg_handle,
2433737Shx147065 (uint16_t *)(pcwl_p->pcwl_cfg_base + PCI_CONF_COMM));
2443737Shx147065 if ((stat & (PCI_COMM_IO | PCI_COMM_MAE)) !=
2453737Shx147065 (PCI_COMM_IO | PCI_COMM_MAE)) {
2463737Shx147065 cmn_err(CE_WARN, "pcwl(pci) attach: pci command"
2473737Shx147065 " reg enable failed\n");
2483737Shx147065 goto attach_fail2a;
2493737Shx147065 }
2503737Shx147065
2513737Shx147065
2523737Shx147065 if (ddi_regs_map_setup(dip, 1, (caddr_t *)&pcwl_p->pcwl_bar,
2533737Shx147065 0, 0, &accattr, (ddi_acc_handle_t *)&pcwl_p->pcwl_handle)
2543737Shx147065 != DDI_SUCCESS) {
2553737Shx147065 cmn_err(CE_WARN, "pcwl(pci) attach: pci_regs_map_setup"
2563737Shx147065 " failed\n");
2573737Shx147065 goto attach_fail2a;
2583737Shx147065 }
2593737Shx147065 PCWLDBG((CE_NOTE, "pcwl(pci): regs_map_setup,bar=%p\n",
2603737Shx147065 (void *)pcwl_p->pcwl_bar));
2613737Shx147065
2623737Shx147065 /*
2633737Shx147065 * tricky! copy from freebsd code.
2643737Shx147065 */
2653737Shx147065 PCWL_WRITE(pcwl_p, 0x26, 0x80);
2663737Shx147065 drv_usecwait(500000);
2673737Shx147065 PCWL_WRITE(pcwl_p, 0x26, 0x0);
2683737Shx147065 drv_usecwait(500000);
2693737Shx147065
2703737Shx147065 for (i = 0; i < WL_TIMEOUT; i++) {
2713737Shx147065 PCWL_READ(pcwl_p, 0x0, stat);
2723737Shx147065 if (stat & WL_CMD_BUSY)
2733737Shx147065 drv_usecwait(10);
2743737Shx147065 else
2753737Shx147065 break;
2763737Shx147065 }
2773737Shx147065 if (i == WL_TIMEOUT) {
2783737Shx147065 cmn_err(CE_WARN, "pcwl(pci) attach: hardware init"
2793737Shx147065 " failed\n");
2803737Shx147065 goto attach_fail3;
2813737Shx147065 }
2823737Shx147065
2833737Shx147065 /*
2843737Shx147065 * magic number verification.
2853737Shx147065 * tricky! copy from freebsd code.
2863737Shx147065 */
2873737Shx147065 PCWL_WRITE(pcwl_p, 0x28, 0x4a2d);
2883737Shx147065 PCWL_READ(pcwl_p, 0x28, stat);
2893737Shx147065 PCWLDBG((CE_NOTE, "pcwl(pci):magic number = %x\n", stat));
2903737Shx147065 if (stat != 0x4a2d) {
2913737Shx147065 cmn_err(CE_WARN, "pcwl(pci) attach: magic verify"
2923737Shx147065 " failed\n");
2933737Shx147065 goto attach_fail3;
2943737Shx147065 }
2953737Shx147065 }
2963737Shx147065 pcwl_p->pcwl_dip = dip;
2973737Shx147065 pcwl_p->pcwl_flag = 0;
2983737Shx147065 pcwl_p->pcwl_socket = ddi_getprop(DDI_DEV_T_NONE, dip,
2993737Shx147065 DDI_PROP_DONTPASS, "socket", -1);
3003737Shx147065 pcwl_p->pcwl_reschedule_need = B_FALSE;
3013737Shx147065
3023737Shx147065 if (ddi_get_iblock_cookie(dip,
3033737Shx147065 0, &pcwl_p->pcwl_ib_cookie) != DDI_SUCCESS) {
3043737Shx147065 cmn_err(CE_WARN, "pcwl attach: get_iblk_cookie failed\n");
3053737Shx147065 goto attach_fail3;
3063737Shx147065 }
3073737Shx147065
3083737Shx147065 mutex_init(&pcwl_p->pcwl_glock, NULL, MUTEX_DRIVER,
3093737Shx147065 pcwl_p->pcwl_ib_cookie);
3103737Shx147065 mutex_init(&pcwl_p->pcwl_scanlist_lock, NULL, MUTEX_DRIVER,
3113737Shx147065 pcwl_p->pcwl_ib_cookie);
3123737Shx147065 mutex_init(&pcwl_p->pcwl_txring.wl_tx_lock, NULL, MUTEX_DRIVER,
3133737Shx147065 pcwl_p->pcwl_ib_cookie);
3143737Shx147065
3153737Shx147065 if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) {
3163737Shx147065 if (ret = ddi_add_intr(dip, 0, NULL, NULL,
3173737Shx147065 pcwl_intr, (caddr_t)pcwl_p)) {
3183737Shx147065 cmn_err(CE_NOTE, "pcwl(pci) attach: add intr failed\n");
3193737Shx147065 goto attach_fail3a;
3203737Shx147065 }
3213737Shx147065 } else if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCCARD) {
3223737Shx147065 if (ret = pcwl_register_cs(dip, pcwl_p)) {
3233737Shx147065 cmn_err(CE_WARN, "pcwl attach(pccard): "
3243737Shx147065 "register_cs err %x\n", ret);
3253737Shx147065 goto attach_fail3a;
3263737Shx147065 }
3273737Shx147065 } else {
3283737Shx147065 cmn_err(CE_WARN, "pcwl attach: unsupported device type\n");
3293737Shx147065 goto attach_fail3a;
3303737Shx147065 }
3313737Shx147065 mutex_enter(&pcwl_p->pcwl_glock);
3323737Shx147065 if (ret = pcwl_reset_backend(pcwl_p)) {
3333737Shx147065 cmn_err(CE_WARN, "pcwl attach: reset_backend failed %x\n", ret);
3343737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
3353737Shx147065 goto attach_fail4;
3363737Shx147065 }
3373737Shx147065 if (ret = pcwl_get_cap(pcwl_p)) { /* sets macaddr for mac_register */
3383737Shx147065 cmn_err(CE_WARN, "pcwl attach: get_cap failed %x\n", ret);
3393737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
3403737Shx147065 goto attach_fail4;
3413737Shx147065 }
3423737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
3433737Shx147065 /*
3443737Shx147065 * Provide initial settings for the WiFi plugin; whenever this
3453737Shx147065 * information changes, we need to call mac_pdata_update()
3463737Shx147065 */
3473737Shx147065 wd.wd_secalloc = WIFI_SEC_NONE;
3483737Shx147065 wd.wd_opmode = IEEE80211_M_STA;
3493737Shx147065
3503737Shx147065 macp = mac_alloc(MAC_VERSION);
3513737Shx147065 if (macp == NULL) {
3523737Shx147065 PCWLDBG((CE_NOTE, "pcwl attach: "
3533737Shx147065 "MAC version mismatch\n"));
3543737Shx147065 goto attach_fail4;
3553737Shx147065 }
3563737Shx147065
3573737Shx147065 macp->m_type_ident = MAC_PLUGIN_IDENT_WIFI;
3583737Shx147065 macp->m_driver = pcwl_p;
3593737Shx147065 macp->m_dip = dip;
3603737Shx147065 macp->m_src_addr = pcwl_p->pcwl_mac_addr;
3613737Shx147065 macp->m_callbacks = &pcwl_m_callbacks;
3623737Shx147065 macp->m_min_sdu = 0;
3633737Shx147065 macp->m_max_sdu = IEEE80211_MTU;
3643737Shx147065 macp->m_pdata = &wd;
3653737Shx147065 macp->m_pdata_size = sizeof (wd);
3663737Shx147065
3673737Shx147065 err = mac_register(macp, &pcwl_p->pcwl_mh);
3683737Shx147065 mac_free(macp);
3693737Shx147065 if (err != 0) {
3703737Shx147065 PCWLDBG((CE_NOTE, "pcwl attach: "
3713737Shx147065 "mac_register err\n"));
3723737Shx147065 goto attach_fail4;
3733737Shx147065 }
3743737Shx147065
3753737Shx147065 mutex_enter(&pcwl_p->pcwl_glock);
3763737Shx147065 if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCCARD) {
3773737Shx147065 /*
3783737Shx147065 * turn on CS interrupt
3793737Shx147065 */
3803737Shx147065 cfgmod.Attributes = CONF_ENABLE_IRQ_STEERING |
3813737Shx147065 CONF_IRQ_CHANGE_VALID;
3823737Shx147065 cfgmod.Vpp1 = 0;
3833737Shx147065 cfgmod.Vpp2 = 0;
3843737Shx147065 (void) csx_ModifyConfiguration(pcwl_p->pcwl_chdl, &cfgmod);
3853737Shx147065
3863737Shx147065 }
3873737Shx147065 if (ret = pcwl_init_nicmem(pcwl_p)) {
3883737Shx147065 cmn_err(CE_WARN, "pcwl(pccard) attach: pcwl_init_nicmem"
3893737Shx147065 " failed %x\n", ret);
3903737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
3913737Shx147065 goto attach_fail5;
3923737Shx147065 }
3933737Shx147065 pcwl_chip_type(pcwl_p);
3943737Shx147065 if (ret = pcwl_loaddef_rf(pcwl_p)) {
3953737Shx147065 cmn_err(CE_WARN, "pcwl attach: config_rf failed%x\n", ret);
3963737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
3973737Shx147065 goto attach_fail5;
3983737Shx147065 }
3993737Shx147065 (void) pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0);
4003737Shx147065 pcwl_stop_locked(pcwl_p); /* leaves interface down */
4013737Shx147065 list_create(&pcwl_p->pcwl_scan_list, sizeof (wl_scan_list_t),
4023737Shx147065 offsetof(wl_scan_list_t, wl_scan_node));
4033737Shx147065 pcwl_p->pcwl_scan_num = 0;
4043737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
4053737Shx147065 pcwl_p->pcwl_scanlist_timeout_id = timeout(pcwl_scanlist_timeout,
4063737Shx147065 pcwl_p, drv_usectohz(1000000));
4073737Shx147065 instance = ddi_get_instance(dip);
4083737Shx147065 (void) snprintf(strbuf, sizeof (strbuf), "pcwl%d", instance);
4093737Shx147065 if (ddi_create_minor_node(dip, strbuf, S_IFCHR,
4103737Shx147065 instance + 1, DDI_NT_NET_WIFI, 0) != DDI_SUCCESS) {
4113737Shx147065 goto attach_fail6;
4123737Shx147065 }
4133737Shx147065 pcwl_p->pcwl_flag |= PCWL_ATTACHED;
4143737Shx147065 if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) {
4153737Shx147065 pcwl_p->pcwl_flag |= PCWL_CARD_READY;
4163737Shx147065 }
4173737Shx147065 return (DDI_SUCCESS);
4183737Shx147065 attach_fail6:
4193737Shx147065 if (pcwl_p->pcwl_scanlist_timeout_id != 0) {
4203737Shx147065 (void) untimeout(pcwl_p->pcwl_scanlist_timeout_id);
4213737Shx147065 pcwl_p->pcwl_scanlist_timeout_id = 0;
4223737Shx147065 }
4233737Shx147065 list_destroy(&pcwl_p->pcwl_scan_list);
4243737Shx147065 attach_fail5:
4253737Shx147065 (void) mac_unregister(pcwl_p->pcwl_mh);
4263737Shx147065 attach_fail4:
4273737Shx147065 if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) {
4283737Shx147065 ddi_remove_intr(dip, 0, pcwl_p->pcwl_ib_cookie);
4293737Shx147065 } else if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCCARD) {
4303737Shx147065 pcwl_unregister_cs(pcwl_p);
4313737Shx147065 }
4323737Shx147065 attach_fail3a:
4333737Shx147065 pcwl_destroy_locks(pcwl_p);
4343737Shx147065 attach_fail3:
4353737Shx147065 if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI)
4363737Shx147065 ddi_regs_map_free(&pcwl_p->pcwl_handle);
4373737Shx147065 attach_fail2a:
4383737Shx147065 if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI)
4393737Shx147065 ddi_regs_map_free(&pcwl_p->pcwl_cfg_handle);
4403737Shx147065 attach_fail2:
4413737Shx147065 ddi_soft_state_free(pcwl_soft_state_p, ddi_get_instance(dip));
4423737Shx147065 attach_fail1:
4433737Shx147065 return (DDI_FAILURE);
4443737Shx147065 }
4453737Shx147065
4463737Shx147065 static int
pcwl_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)4473737Shx147065 pcwl_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
4483737Shx147065 {
4493737Shx147065 pcwl_maci_t *pcwl_p;
4503737Shx147065 wl_scan_list_t *scan_item0;
4513737Shx147065 int ret;
4523737Shx147065 pcwl_p = ddi_get_soft_state(pcwl_soft_state_p, ddi_get_instance(dip));
4533737Shx147065
4543737Shx147065 PCWLDBG((CE_NOTE, "pcwl detach: dip=0x%p cmd=%x\n", (void *)dip, cmd));
4553737Shx147065 if (cmd != DDI_DETACH)
4563737Shx147065 return (DDI_FAILURE);
4573737Shx147065 if (!(pcwl_p->pcwl_flag & PCWL_ATTACHED))
4583737Shx147065 return (DDI_FAILURE);
4593737Shx147065
4607507SXinghua.Wen@Sun.COM ret = mac_disable(pcwl_p->pcwl_mh);
4617507SXinghua.Wen@Sun.COM if (ret != 0)
4627507SXinghua.Wen@Sun.COM return (DDI_FAILURE);
4637507SXinghua.Wen@Sun.COM
4643737Shx147065 if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) {
4653737Shx147065 mutex_enter(&pcwl_p->pcwl_glock);
4663737Shx147065 (void) pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0);
4673737Shx147065 PCWL_DISABLE_INTR(pcwl_p);
4683737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
4693737Shx147065 }
4703737Shx147065 if (pcwl_p->pcwl_scanlist_timeout_id != 0) {
4713737Shx147065 (void) untimeout(pcwl_p->pcwl_scanlist_timeout_id);
4723737Shx147065 pcwl_p->pcwl_scanlist_timeout_id = 0;
4733737Shx147065 }
4743737Shx147065 if (pcwl_p->pcwl_connect_timeout_id != 0) {
4753737Shx147065 (void) untimeout(pcwl_p->pcwl_connect_timeout_id);
4763737Shx147065 pcwl_p->pcwl_connect_timeout_id = 0;
4773737Shx147065 }
4783737Shx147065 mutex_enter(&pcwl_p->pcwl_scanlist_lock);
4793737Shx147065 scan_item0 = list_head(&pcwl_p->pcwl_scan_list);
4803737Shx147065 while (scan_item0) {
4813737Shx147065 pcwl_delete_scan_item(pcwl_p, scan_item0);
4823737Shx147065 scan_item0 = list_head(&pcwl_p->pcwl_scan_list);
4833737Shx147065 }
4843737Shx147065 list_destroy(&pcwl_p->pcwl_scan_list);
4853737Shx147065 mutex_exit(&pcwl_p->pcwl_scanlist_lock);
4867507SXinghua.Wen@Sun.COM (void) mac_unregister(pcwl_p->pcwl_mh);
4873737Shx147065
4883737Shx147065 if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) {
48911101SMikore.Li@Sun.COM mutex_enter(&pcwl_p->pcwl_glock);
4903737Shx147065 ddi_remove_intr(dip, 0, pcwl_p->pcwl_ib_cookie);
4913737Shx147065 ddi_regs_map_free(&pcwl_p->pcwl_handle);
4923737Shx147065 ddi_regs_map_free(&pcwl_p->pcwl_cfg_handle);
49311101SMikore.Li@Sun.COM mutex_exit(&pcwl_p->pcwl_glock);
4943737Shx147065 } else if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCCARD) {
4953737Shx147065 pcwl_unregister_cs(pcwl_p);
4963737Shx147065 }
4973737Shx147065 pcwl_destroy_locks(pcwl_p);
4983737Shx147065 ddi_remove_minor_node(dip, NULL);
4993737Shx147065 ddi_soft_state_free(pcwl_soft_state_p, ddi_get_instance(dip));
5003737Shx147065 return (DDI_SUCCESS);
5013737Shx147065 }
5023737Shx147065
5033737Shx147065 /*
5043737Shx147065 * card services and event handlers
5053737Shx147065 */
5063737Shx147065 static int
pcwl_register_cs(dev_info_t * dip,pcwl_maci_t * pcwl_p)5073737Shx147065 pcwl_register_cs(dev_info_t *dip, pcwl_maci_t *pcwl_p)
5083737Shx147065 {
5093737Shx147065 int ret;
5103737Shx147065 client_reg_t cr;
5113737Shx147065 client_handle_t chdl; /* uint encoding of socket, function, client */
5123737Shx147065 get_status_t card_status;
5133737Shx147065 request_socket_mask_t sock_req;
5143737Shx147065
5153737Shx147065 bzero(&cr, sizeof (cr));
5163737Shx147065 cr.Attributes = INFO_IO_CLIENT|INFO_CARD_EXCL|INFO_CARD_SHARE;
5173737Shx147065 cr.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
5183737Shx147065 CS_EVENT_REGISTRATION_COMPLETE | CS_EVENT_CARD_REMOVAL_LOWP |
5193737Shx147065 CS_EVENT_CARD_READY | CS_EVENT_PM_RESUME |
5203737Shx147065 CS_EVENT_PM_SUSPEND | CS_EVENT_CLIENT_INFO;
5213737Shx147065 cr.event_callback_args.client_data = pcwl_p;
5223737Shx147065 cr.Version = CS_VERSION;
5233737Shx147065 cr.event_handler = (csfunction_t *)pcwl_ev_hdlr;
5243737Shx147065 cr.dip = dip;
5253737Shx147065 (void) strcpy(cr.driver_name, pcwl_name_str);
5263737Shx147065 if (ret = csx_RegisterClient(&chdl, &cr)) {
5273737Shx147065 cmn_err(CE_WARN, "pcwl: RegisterClient failed %x\n", ret);
5283737Shx147065 goto regcs_ret;
5293737Shx147065 }
5303737Shx147065 pcwl_p->pcwl_chdl = chdl;
5313737Shx147065
5323737Shx147065 bzero(&card_status, sizeof (card_status));
5333737Shx147065 (void) csx_GetStatus(chdl, &card_status);
5343737Shx147065 PCWLDBG((CE_NOTE,
5353737Shx147065 "pcwl: register_cs: Sock=%x CState=%x SState=%x rState=%x\n",
5363737Shx147065 card_status.Socket, card_status.CardState,
5373737Shx147065 card_status.SocketState, card_status.raw_CardState));
5383737Shx147065 if (!(card_status.CardState & CS_STATUS_CARD_INSERTED)) {
5393737Shx147065 /* card is not present, why are we attaching ? */
5403737Shx147065 ret = CS_NO_CARD;
5413737Shx147065 goto regcs_unreg;
5423737Shx147065 }
5433737Shx147065 cv_init(&pcwl_p->pcwl_cscv, NULL, CV_DRIVER, NULL);
5443737Shx147065 mutex_init(&pcwl_p->pcwl_cslock, NULL, MUTEX_DRIVER, *cr.iblk_cookie);
5453737Shx147065 mutex_enter(&pcwl_p->pcwl_cslock);
5463737Shx147065 if (ret = csx_MapLogSocket(chdl, &pcwl_p->pcwl_log_sock)) {
5473737Shx147065 cmn_err(CE_WARN, "pcwl: MapLogSocket failed %x\n", ret);
5483737Shx147065 goto regcs_fail;
5493737Shx147065 }
5503737Shx147065 PCWLDBG((CE_NOTE,
5513737Shx147065 "pcwl: register_cs: LogSock=%x PhyAdapter=%x PhySock=%x\n",
5523737Shx147065 pcwl_p->pcwl_log_sock.LogSocket,
5533737Shx147065 pcwl_p->pcwl_log_sock.PhyAdapter,
5543737Shx147065 pcwl_p->pcwl_log_sock.PhySocket));
5553737Shx147065 /* turn on initialization events */
5563737Shx147065 sock_req.Socket = 0;
5573737Shx147065 sock_req.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
5583737Shx147065 CS_EVENT_REGISTRATION_COMPLETE;
5593737Shx147065 if (ret = csx_RequestSocketMask(chdl, &sock_req)) {
5603737Shx147065 cmn_err(CE_WARN, "pcwl: RequestSocketMask failed %x\n", ret);
5613737Shx147065 goto regcs_fail;
5623737Shx147065 }
5633737Shx147065 /* wait for and process card insertion events */
5643737Shx147065 while (!(pcwl_p->pcwl_flag & PCWL_CARD_READY))
5653737Shx147065 cv_wait(&pcwl_p->pcwl_cscv, &pcwl_p->pcwl_cslock);
5663737Shx147065 mutex_exit(&pcwl_p->pcwl_cslock);
5673737Shx147065
5683737Shx147065 pcwl_p->pcwl_flag |= PCWL_CS_REGISTERED;
5693737Shx147065 return (PCWL_SUCCESS);
5703737Shx147065 regcs_fail:
5713737Shx147065 mutex_destroy(&pcwl_p->pcwl_cslock);
5723737Shx147065 cv_destroy(&pcwl_p->pcwl_cscv);
5733737Shx147065 regcs_unreg:
5743737Shx147065 (void) csx_DeregisterClient(chdl);
5753737Shx147065 regcs_ret:
5763737Shx147065 pcwl_p->pcwl_flag &= ~PCWL_CS_REGISTERED;
5773737Shx147065 return (ret);
5783737Shx147065 }
5793737Shx147065
5803737Shx147065 static void
pcwl_unregister_cs(pcwl_maci_t * pcwl_p)5813737Shx147065 pcwl_unregister_cs(pcwl_maci_t *pcwl_p)
5823737Shx147065 {
5833737Shx147065 int ret;
5843737Shx147065 release_socket_mask_t mask;
5853737Shx147065 mask.Socket = pcwl_p->pcwl_socket;
5863737Shx147065
5873737Shx147065 /*
5883737Shx147065 * The card service not registered means register_cs function
5893737Shx147065 * doesnot return TRUE. Then all the lelated resource has been
5903737Shx147065 * released in register_cs.
5913737Shx147065 */
5923737Shx147065 if (!(pcwl_p->pcwl_flag | PCWL_CS_REGISTERED))
5933737Shx147065 return;
5943737Shx147065
5953737Shx147065 if (ret = csx_ReleaseSocketMask(pcwl_p->pcwl_chdl, &mask))
5963737Shx147065 cmn_err(CE_WARN, "pcwl: ReleaseSocket mask failed %x\n", ret);
5973737Shx147065
5983737Shx147065 if (pcwl_p->pcwl_flag & PCWL_CARD_READY) {
5993737Shx147065 pcwl_card_remove(pcwl_p);
6003737Shx147065 pcwl_p->pcwl_flag &= ~PCWL_CARD_READY;
6013737Shx147065 }
6023737Shx147065 mutex_destroy(&pcwl_p->pcwl_cslock);
6033737Shx147065 cv_destroy(&pcwl_p->pcwl_cscv);
6043737Shx147065 if (ret = csx_DeregisterClient(pcwl_p->pcwl_chdl))
6053737Shx147065 cmn_err(CE_WARN, "pcwl: Deregister failed %x\n", ret);
6063737Shx147065 }
6073737Shx147065
6083737Shx147065 static void
pcwl_destroy_locks(pcwl_maci_t * pcwl_p)6093737Shx147065 pcwl_destroy_locks(pcwl_maci_t *pcwl_p)
6103737Shx147065 {
6113737Shx147065 mutex_destroy(&pcwl_p->pcwl_txring.wl_tx_lock);
6123737Shx147065 mutex_destroy(&pcwl_p->pcwl_scanlist_lock);
6133737Shx147065 mutex_destroy(&pcwl_p->pcwl_glock);
6143737Shx147065 }
6153737Shx147065
61611101SMikore.Li@Sun.COM static void
61711101SMikore.Li@Sun.COM pcwl_do_suspend(pcwl_maci_t *pcwl_p);
61811101SMikore.Li@Sun.COM
6193737Shx147065 static int
pcwl_ev_hdlr(event_t event,int priority,event_callback_args_t * arg)6203737Shx147065 pcwl_ev_hdlr(event_t event, int priority, event_callback_args_t *arg)
6213737Shx147065 {
6223737Shx147065 int ret = CS_SUCCESS;
6233737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg->client_data;
6243737Shx147065 client_info_t *ci_p = (client_info_t *)&arg->client_info;
6253737Shx147065
6263737Shx147065 mutex_enter(&pcwl_p->pcwl_cslock);
6273737Shx147065 switch (event) {
6283737Shx147065 case CS_EVENT_CARD_INSERTION:
6293737Shx147065 ret = pcwl_card_insert(pcwl_p);
6303737Shx147065 cv_broadcast(&pcwl_p->pcwl_cscv);
6313737Shx147065 break;
6323737Shx147065 case CS_EVENT_REGISTRATION_COMPLETE:
6333737Shx147065 cv_broadcast(&pcwl_p->pcwl_cscv);
6343737Shx147065 break;
6353737Shx147065 case CS_EVENT_CARD_REMOVAL:
6363737Shx147065 if (priority & CS_EVENT_PRI_HIGH)
6373737Shx147065 break;
6383737Shx147065 pcwl_card_remove(pcwl_p);
6393737Shx147065 cv_broadcast(&pcwl_p->pcwl_cscv);
6403737Shx147065 break;
6413737Shx147065 case CS_EVENT_CLIENT_INFO:
6423737Shx147065 if (GET_CLIENT_INFO_SUBSVC(ci_p->Attributes) !=
6433737Shx147065 CS_CLIENT_INFO_SUBSVC_CS)
6443737Shx147065 break;
6453737Shx147065
6463737Shx147065 ci_p->Revision = 0x0101;
6473737Shx147065 ci_p->CSLevel = CS_VERSION;
6483737Shx147065 ci_p->RevDate = CS_CLIENT_INFO_MAKE_DATE(9, 12, 14);
6493737Shx147065 (void) strcpy(ci_p->ClientName, PCWL_IDENT_STRING);
6503737Shx147065 (void) strcpy(ci_p->VendorName, CS_SUN_VENDOR_DESCRIPTION);
6513737Shx147065 ci_p->Attributes |= CS_CLIENT_INFO_VALID;
6523737Shx147065 break;
65311101SMikore.Li@Sun.COM case CS_EVENT_PM_SUSPEND:
65411101SMikore.Li@Sun.COM pcwl_do_suspend(pcwl_p);
65511101SMikore.Li@Sun.COM break;
6563737Shx147065 default:
6573737Shx147065 ret = CS_UNSUPPORTED_EVENT;
6583737Shx147065 break;
6593737Shx147065 }
6603737Shx147065 mutex_exit(&pcwl_p->pcwl_cslock);
6613737Shx147065 return (ret);
6623737Shx147065 }
6633737Shx147065
66411101SMikore.Li@Sun.COM /*
66511101SMikore.Li@Sun.COM * assume card is already removed, don't touch the hardware
66611101SMikore.Li@Sun.COM */
66711101SMikore.Li@Sun.COM static void
pcwl_do_suspend(pcwl_maci_t * pcwl_p)66811101SMikore.Li@Sun.COM pcwl_do_suspend(pcwl_maci_t *pcwl_p)
66911101SMikore.Li@Sun.COM {
67011101SMikore.Li@Sun.COM int ret;
67111101SMikore.Li@Sun.COM
67211101SMikore.Li@Sun.COM if (pcwl_p->pcwl_flag & PCWL_CARD_LINKUP) {
67311101SMikore.Li@Sun.COM if (pcwl_p->pcwl_connect_timeout_id != 0) {
67411101SMikore.Li@Sun.COM (void) untimeout(pcwl_p->pcwl_connect_timeout_id);
67511101SMikore.Li@Sun.COM pcwl_p->pcwl_connect_timeout_id = 0;
67611101SMikore.Li@Sun.COM }
67711101SMikore.Li@Sun.COM mutex_enter(&pcwl_p->pcwl_glock);
67811101SMikore.Li@Sun.COM pcwl_p->pcwl_flag &= ~PCWL_CARD_LINKUP;
67911101SMikore.Li@Sun.COM (void) pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0);
68011101SMikore.Li@Sun.COM /*
68111101SMikore.Li@Sun.COM * A workaround here: If the card is in ad-hoc mode, the
68211101SMikore.Li@Sun.COM * following scan will not work correctly, so any
68311101SMikore.Li@Sun.COM * 'dladm connect-wifi' which need a scan first will not
68411101SMikore.Li@Sun.COM * succeed. software reset the card here as a workround.
68511101SMikore.Li@Sun.COM */
68611101SMikore.Li@Sun.COM if ((pcwl_p->pcwl_rf.rf_porttype == WL_BSS_IBSS) &&
68711101SMikore.Li@Sun.COM (pcwl_p->pcwl_chip_type == PCWL_CHIP_LUCENT)) {
68811101SMikore.Li@Sun.COM (void) pcwl_reset_backend(pcwl_p);
68911101SMikore.Li@Sun.COM (void) pcwl_init_nicmem(pcwl_p);
69011101SMikore.Li@Sun.COM pcwl_start_locked(pcwl_p);
69111101SMikore.Li@Sun.COM }
69211101SMikore.Li@Sun.COM if (ret = pcwl_loaddef_rf(pcwl_p)) {
69311101SMikore.Li@Sun.COM PCWLDBG((CE_WARN, "cfg_loaddef_err %d\n", ret));
69411101SMikore.Li@Sun.COM }
69511101SMikore.Li@Sun.COM if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) {
69611101SMikore.Li@Sun.COM PCWLDBG((CE_WARN, "set enable cmd err\n"));
69711101SMikore.Li@Sun.COM }
69811101SMikore.Li@Sun.COM pcwl_delay(pcwl_p, 1000000);
69911101SMikore.Li@Sun.COM if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
70011101SMikore.Li@Sun.COM PCWLDBG((CE_WARN, "set disable cmd err\n"));
70111101SMikore.Li@Sun.COM }
70211101SMikore.Li@Sun.COM mac_link_update(GLD3(pcwl_p), LINK_STATE_DOWN);
70311101SMikore.Li@Sun.COM mutex_exit(&pcwl_p->pcwl_glock);
70411101SMikore.Li@Sun.COM }
70511101SMikore.Li@Sun.COM pcwl_p->pcwl_flag |= PCWL_CARD_SUSPEND;
70611101SMikore.Li@Sun.COM PCWLDBG((CE_WARN, "pcwl: do suspend\n"));
70711101SMikore.Li@Sun.COM }
70811101SMikore.Li@Sun.COM
70911101SMikore.Li@Sun.COM
7103737Shx147065 static int
pcwl_card_insert(pcwl_maci_t * pcwl_p)7113737Shx147065 pcwl_card_insert(pcwl_maci_t *pcwl_p)
7123737Shx147065 {
7133737Shx147065 int ret, hi, lo;
7143737Shx147065 tuple_t tuple;
7153737Shx147065 cisparse_t cisparse;
7163737Shx147065 io_req_t io;
7173737Shx147065 irq_req_t irq;
7183737Shx147065 config_req_t cfg;
7193737Shx147065 cistpl_config_t config;
7203737Shx147065 cistpl_cftable_entry_t *tbl_p;
7213737Shx147065 register client_handle_t chdl = pcwl_p->pcwl_chdl;
72211101SMikore.Li@Sun.COM modify_config_t cfgmod;
7233737Shx147065
7243737Shx147065 bzero(&tuple, sizeof (tuple));
7253737Shx147065 tuple.DesiredTuple = CISTPL_MANFID;
7263737Shx147065 if (ret = csx_GetFirstTuple(chdl, &tuple)) {
7273737Shx147065 cmn_err(CE_WARN, "pcwl: get manufacture id failed %x\n", ret);
7283737Shx147065 goto insert_ret;
7293737Shx147065 }
7303737Shx147065 bzero(&cisparse, sizeof (cisparse));
7313737Shx147065 if (ret = csx_Parse_CISTPL_MANFID(chdl, &tuple, &cisparse.manfid)) {
7323737Shx147065 cmn_err(CE_WARN, "pcwl: parse manufacture id failed %x\n", ret);
7333737Shx147065 goto insert_ret;
7343737Shx147065 }
7353737Shx147065
7363737Shx147065 /*
7373737Shx147065 * verify manufacture ID
7383737Shx147065 */
7393737Shx147065 PCWLDBG((CE_NOTE, "pcwl insert: manufacturer_id=%x card=%x\n",
7403737Shx147065 cisparse.manfid.manf, cisparse.manfid.card));
7413737Shx147065 bzero(&tuple, sizeof (tuple));
7423737Shx147065 tuple.DesiredTuple = CISTPL_FUNCID;
7433737Shx147065 if (ret = csx_GetFirstTuple(chdl, &tuple)) {
7443737Shx147065 cmn_err(CE_WARN, "pcwl: get function id failed %x\n", ret);
7453737Shx147065 goto insert_ret;
7463737Shx147065 }
7473737Shx147065 bzero(&cisparse, sizeof (cisparse));
7483737Shx147065 if (ret = csx_Parse_CISTPL_FUNCID(chdl, &tuple, &cisparse.funcid)) {
7493737Shx147065 cmn_err(CE_WARN, "pcwl: parse function id failed %x\n", ret);
7503737Shx147065 goto insert_ret;
7513737Shx147065 }
7523737Shx147065
7533737Shx147065 /*
7543737Shx147065 * verify function ID
7553737Shx147065 */
7563737Shx147065 PCWLDBG((CE_NOTE, "insert:fun_id=%x\n", cisparse.funcid.function));
7573737Shx147065 bzero(&tuple, sizeof (tuple));
7583737Shx147065 tuple.DesiredTuple = CISTPL_CONFIG;
7593737Shx147065 if (ret = csx_GetFirstTuple(chdl, &tuple)) {
7603737Shx147065 cmn_err(CE_WARN, "pcwl: get config failed %x\n", ret);
7613737Shx147065 goto insert_ret;
7623737Shx147065 }
7633737Shx147065 bzero(&config, sizeof (config));
7643737Shx147065 if (ret = csx_Parse_CISTPL_CONFIG(chdl, &tuple, &config)) {
7653737Shx147065 cmn_err(CE_WARN, "pcwl: parse config failed %x\n", ret);
7663737Shx147065 goto insert_ret;
7673737Shx147065 }
7683737Shx147065 PCWLDBG((CE_NOTE,
7693737Shx147065 "pcwl: config present=%x nr=%x hr=%x regs[0]=%x base=%x last=%x\n",
7703737Shx147065 config.present, config.nr, config.hr, config.regs[0],
7713737Shx147065 config.base, config.last));
7723737Shx147065 hi = 0;
7733737Shx147065 lo = (int)-1; /* really big number */
7743737Shx147065 tbl_p = &cisparse.cftable;
7753737Shx147065 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
7763737Shx147065 for (tbl_p->index = 0; tbl_p->index <= config.hr; ) {
7773737Shx147065 PCWLDBG((CE_NOTE, "pcwl insert:tuple idx=%x:\n", tbl_p->index));
7783737Shx147065 if (ret = csx_GetNextTuple(chdl, &tuple)) {
7793737Shx147065 cmn_err(CE_WARN, "pcwl: get cftable failed %x\n",
7803737Shx147065 ret);
7813737Shx147065 break;
7823737Shx147065 }
7833737Shx147065 bzero((caddr_t)&cisparse, sizeof (cisparse));
7843737Shx147065 if (ret = csx_Parse_CISTPL_CFTABLE_ENTRY(chdl, &tuple, tbl_p)) {
7853737Shx147065 cmn_err(CE_WARN, "pcwl: parse cftable failed %x\n",
7863737Shx147065 ret);
7873737Shx147065 break;
7883737Shx147065 }
7893737Shx147065 if (tbl_p->flags & CISTPL_CFTABLE_TPCE_FS_PWR &&
7906062Shx147065 tbl_p->pd.flags & CISTPL_CFTABLE_TPCE_FS_PWR_VCC) {
7913737Shx147065 if (tbl_p->pd.pd_vcc.avgI > hi) {
7923737Shx147065 hi = tbl_p->pd.pd_vcc.avgI;
7933737Shx147065 pcwl_p->pcwl_config_hi = tbl_p->index;
7943737Shx147065 }
7953737Shx147065 if (tbl_p->pd.pd_vcc.avgI < lo) {
7963737Shx147065 lo = tbl_p->pd.pd_vcc.avgI;
7973737Shx147065 pcwl_p->pcwl_config = tbl_p->index;
7983737Shx147065 }
7993737Shx147065 }
8003737Shx147065 if (tbl_p->flags & CISTPL_CFTABLE_TPCE_DEFAULT) {
8013737Shx147065 if (tbl_p->pd.flags & CISTPL_CFTABLE_TPCE_FS_PWR_VCC)
8023737Shx147065 pcwl_p->pcwl_vcc = tbl_p->pd.pd_vcc.nomV;
8033737Shx147065 if (tbl_p->flags & CISTPL_CFTABLE_TPCE_FS_IO)
8043737Shx147065 pcwl_p->pcwl_iodecode = tbl_p->io.addr_lines;
8053737Shx147065 }
8063737Shx147065 }
8073737Shx147065 PCWLDBG((CE_NOTE, "pcwl: insert:cfg_hi=%x cfg=%x vcc=%x iodecode=%x\n",
8083737Shx147065 pcwl_p->pcwl_config_hi, pcwl_p->pcwl_config,
8093737Shx147065 pcwl_p->pcwl_vcc, pcwl_p->pcwl_iodecode));
8103737Shx147065 bzero(&io, sizeof (io));
8113737Shx147065 io.BasePort1.base = 0;
8123737Shx147065 io.NumPorts1 = 1 << pcwl_p->pcwl_iodecode;
8133737Shx147065 io.Attributes1 = IO_DATA_PATH_WIDTH_16;
8143737Shx147065 io.IOAddrLines = pcwl_p->pcwl_iodecode;
8153737Shx147065 if (ret = csx_RequestIO(chdl, &io)) {
8163737Shx147065 cmn_err(CE_WARN, "pcwl: RequestIO failed %x\n", ret);
8173737Shx147065 goto insert_ret;
8183737Shx147065 }
8193737Shx147065 pcwl_p->pcwl_port = io.BasePort1.handle;
8203737Shx147065 if (ret = ddi_add_softintr(DIP(pcwl_p), DDI_SOFTINT_HIGH,
8213737Shx147065 &pcwl_p->pcwl_softint_id, &pcwl_p->pcwl_ib_cookie, NULL,
8223737Shx147065 pcwl_intr, (caddr_t)pcwl_p)) {
8233737Shx147065 cmn_err(CE_NOTE, "pcwl(pccard): add softintr failed\n");
8243737Shx147065 goto insert_ret;
8253737Shx147065 }
8263737Shx147065 irq.Attributes = IRQ_TYPE_EXCLUSIVE;
8273737Shx147065 irq.irq_handler = ddi_intr_hilevel(DIP(pcwl_p), 0) ?
8283737Shx147065 (csfunction_t *)pcwl_intr_hi : (csfunction_t *)pcwl_intr;
8293737Shx147065 irq.irq_handler_arg = pcwl_p;
8303737Shx147065 if (ret = csx_RequestIRQ(pcwl_p->pcwl_chdl, &irq)) {
8313737Shx147065 cmn_err(CE_WARN, "pcwl: RequestIRQ failed %x\n", ret);
8323737Shx147065 goto un_io;
8333737Shx147065 }
8343737Shx147065 bzero(&cfg, sizeof (cfg));
8353737Shx147065 cfg.Attributes = 0; /* not ready for CONF_ENABLE_IRQ_STEERING yet */
8363737Shx147065 cfg.Vcc = 50;
8373737Shx147065 cfg.IntType = SOCKET_INTERFACE_MEMORY_AND_IO;
8383737Shx147065 cfg.ConfigBase = config.base;
8393737Shx147065 cfg.ConfigIndex = pcwl_p->pcwl_config;
8403737Shx147065 cfg.Status = CCSR_IO_IS_8;
8413737Shx147065 cfg.Present = config.present;
8423737Shx147065 pcwl_p->pcwl_flag |= PCWL_CARD_READY;
8433737Shx147065 if (ret = csx_RequestConfiguration(chdl, &cfg)) {
8443737Shx147065 cmn_err(CE_WARN, "pcwl: RequestConfiguration failed %x\n", ret);
8453737Shx147065 goto un_irq;
8463737Shx147065 }
84711101SMikore.Li@Sun.COM
84811101SMikore.Li@Sun.COM if (pcwl_p->pcwl_flag & PCWL_CARD_SUSPEND) {
84911101SMikore.Li@Sun.COM mutex_enter(&pcwl_p->pcwl_glock);
85011121SMikore.Li@Sun.COM (void) pcwl_reset_backend(pcwl_p);
85111101SMikore.Li@Sun.COM /* turn on CS interrupt */
85211101SMikore.Li@Sun.COM cfgmod.Attributes = CONF_ENABLE_IRQ_STEERING |
85311101SMikore.Li@Sun.COM CONF_IRQ_CHANGE_VALID;
85411101SMikore.Li@Sun.COM cfgmod.Vpp1 = 50;
85511101SMikore.Li@Sun.COM cfgmod.Vpp2 = 50;
85611101SMikore.Li@Sun.COM (void) csx_ModifyConfiguration(pcwl_p->pcwl_chdl, &cfgmod);
85711101SMikore.Li@Sun.COM
85811101SMikore.Li@Sun.COM (void) pcwl_init_nicmem(pcwl_p);
85911101SMikore.Li@Sun.COM pcwl_chip_type(pcwl_p);
86011101SMikore.Li@Sun.COM (void) pcwl_loaddef_rf(pcwl_p);
86111101SMikore.Li@Sun.COM (void) pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0);
86211101SMikore.Li@Sun.COM pcwl_stop_locked(pcwl_p); /* leaves interface down */
86311101SMikore.Li@Sun.COM pcwl_p->pcwl_flag &= ~PCWL_CARD_SUSPEND;
86411101SMikore.Li@Sun.COM mutex_exit(&pcwl_p->pcwl_glock);
86511101SMikore.Li@Sun.COM }
86611101SMikore.Li@Sun.COM if (pcwl_p->pcwl_flag & PCWL_CARD_PLUMBED) {
86711121SMikore.Li@Sun.COM (void) pcwl_start(pcwl_p);
86811101SMikore.Li@Sun.COM pcwl_p->pcwl_flag &= ~PCWL_CARD_PLUMBED;
86911101SMikore.Li@Sun.COM }
8703737Shx147065 return (CS_SUCCESS);
8713737Shx147065 un_irq:
8723737Shx147065 (void) csx_ReleaseIRQ(chdl, &irq);
8733737Shx147065 un_io:
8743737Shx147065 ddi_remove_softintr(pcwl_p->pcwl_softint_id);
8753737Shx147065 (void) csx_ReleaseIO(chdl, &io);
8763737Shx147065 pcwl_p->pcwl_port = 0;
8773737Shx147065 insert_ret:
8783737Shx147065 pcwl_p->pcwl_flag &= ~PCWL_CARD_READY;
8793737Shx147065 return (ret);
8803737Shx147065
8813737Shx147065 }
8823737Shx147065
8833737Shx147065 /*
8843737Shx147065 * assume card is already removed, don't touch the hardware
8853737Shx147065 */
8863737Shx147065 static void
pcwl_card_remove(pcwl_maci_t * pcwl_p)8873737Shx147065 pcwl_card_remove(pcwl_maci_t *pcwl_p)
8883737Shx147065 {
8893737Shx147065 int ret;
8903737Shx147065 io_req_t io;
8913737Shx147065 irq_req_t irq;
8923737Shx147065
8933737Shx147065 /*
8943737Shx147065 * The card not ready means Insert function doesnot return TRUE.
8953737Shx147065 * then the IO and IRQ has been released in Insert
8963737Shx147065 */
8973737Shx147065 if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY))
8983737Shx147065 return;
89911101SMikore.Li@Sun.COM
90011101SMikore.Li@Sun.COM if (pcwl_p->pcwl_connect_timeout_id != 0) {
90111101SMikore.Li@Sun.COM (void) untimeout(pcwl_p->pcwl_connect_timeout_id);
90211101SMikore.Li@Sun.COM pcwl_p->pcwl_connect_timeout_id = 0;
90311101SMikore.Li@Sun.COM }
90411101SMikore.Li@Sun.COM
90511101SMikore.Li@Sun.COM if (pcwl_p->pcwl_flag & PCWL_CARD_LINKUP) {
90611101SMikore.Li@Sun.COM pcwl_p->pcwl_flag &= ~PCWL_CARD_LINKUP;
90711101SMikore.Li@Sun.COM mac_link_update(GLD3(pcwl_p), LINK_STATE_DOWN);
90811101SMikore.Li@Sun.COM }
90911101SMikore.Li@Sun.COM mutex_enter(&pcwl_p->pcwl_glock);
91011101SMikore.Li@Sun.COM if (pcwl_p->pcwl_flag & PCWL_CARD_INTREN) {
91111101SMikore.Li@Sun.COM pcwl_stop_locked(pcwl_p);
91211101SMikore.Li@Sun.COM pcwl_p->pcwl_flag |= PCWL_CARD_PLUMBED;
91311101SMikore.Li@Sun.COM }
91411101SMikore.Li@Sun.COM pcwl_p->pcwl_flag &= ~PCWL_CARD_READY;
91511101SMikore.Li@Sun.COM mutex_exit(&pcwl_p->pcwl_glock);
9163737Shx147065 if (ret = csx_ReleaseConfiguration(pcwl_p->pcwl_chdl, NULL))
9173737Shx147065 cmn_err(CE_WARN, "pcwl: ReleaseConfiguration failed %x\n", ret);
9183737Shx147065
9193737Shx147065 bzero(&irq, sizeof (irq));
9203737Shx147065 if (ret = csx_ReleaseIRQ(pcwl_p->pcwl_chdl, &irq))
9213737Shx147065 cmn_err(CE_WARN, "pcwl: ReleaseIRQ failed %x\n", ret);
9223737Shx147065
9233737Shx147065 ddi_remove_softintr(pcwl_p->pcwl_softint_id);
9243737Shx147065
9253737Shx147065 bzero(&io, sizeof (io));
9263737Shx147065 io.BasePort1.handle = pcwl_p->pcwl_port;
9273737Shx147065 io.NumPorts1 = 16;
9283737Shx147065 if (ret = csx_ReleaseIO(pcwl_p->pcwl_chdl, &io))
9293737Shx147065 cmn_err(CE_WARN, "pcwl: ReleaseIO failed %x\n", ret);
9303737Shx147065
9313737Shx147065 pcwl_p->pcwl_port = 0;
9323737Shx147065 }
9333737Shx147065
9343737Shx147065 /*
9353737Shx147065 * mac operation interface routines
9363737Shx147065 */
9373737Shx147065 static int
pcwl_start(void * arg)9383737Shx147065 pcwl_start(void *arg)
9393737Shx147065 {
9403737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
9413737Shx147065
9423737Shx147065 mutex_enter(&pcwl_p->pcwl_glock);
9433737Shx147065 if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
9443737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
9453737Shx147065 return (PCWL_FAIL);
9463737Shx147065 }
9473737Shx147065 pcwl_start_locked(pcwl_p);
9483737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
9493737Shx147065 return (PCWL_SUCCESS);
9503737Shx147065 }
9513737Shx147065
9523737Shx147065 static void
pcwl_stop(void * arg)9533737Shx147065 pcwl_stop(void *arg)
9543737Shx147065 {
9553737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
9563737Shx147065
9573737Shx147065 PCWLDBG((CE_NOTE, "pcwl_stop called\n"));
9583737Shx147065 mutex_enter(&pcwl_p->pcwl_glock);
9593737Shx147065 if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
9603737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
9613737Shx147065 return;
9623737Shx147065 }
9633737Shx147065
9643737Shx147065 pcwl_stop_locked(pcwl_p);
9653737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
9663737Shx147065 if (pcwl_p->pcwl_connect_timeout_id != 0) {
9673737Shx147065 (void) untimeout(pcwl_p->pcwl_connect_timeout_id);
9683737Shx147065 pcwl_p->pcwl_connect_timeout_id = 0;
9693737Shx147065 }
9703737Shx147065 }
9713737Shx147065
9723737Shx147065 static int
pcwl_saddr(void * arg,const uint8_t * macaddr)9733737Shx147065 pcwl_saddr(void *arg, const uint8_t *macaddr)
9743737Shx147065 {
9753737Shx147065 int ret = PCWL_SUCCESS;
9763737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
9773737Shx147065
9783737Shx147065 mutex_enter(&pcwl_p->pcwl_glock);
9793737Shx147065 if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
9803737Shx147065 ret = PCWL_FAIL;
9813737Shx147065 goto done;
9823737Shx147065 }
9833737Shx147065 ether_copy(macaddr, pcwl_p->pcwl_mac_addr);
9843737Shx147065 if (pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
9853737Shx147065 ret = PCWL_FAIL;
9863737Shx147065 goto done;
9873737Shx147065 }
9883737Shx147065 if (pcwl_saddr_locked(pcwl_p)) {
9893737Shx147065 ret = PCWL_FAIL;
9903737Shx147065 goto done;
9913737Shx147065 }
9923737Shx147065 if (pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) {
9933737Shx147065 ret = PCWL_FAIL;
9943737Shx147065 }
9953737Shx147065 done:
9963737Shx147065 if (ret)
9973737Shx147065 cmn_err(CE_WARN, "pcwl set_mac_addr: failed\n");
9983737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
9993737Shx147065 return (ret);
10003737Shx147065 }
10013737Shx147065
10023737Shx147065 static int
pcwl_send(pcwl_maci_t * pcwl_p,mblk_t * mblk_p)10033737Shx147065 pcwl_send(pcwl_maci_t *pcwl_p, mblk_t *mblk_p)
10043737Shx147065 {
10053737Shx147065 int i = 0;
10063737Shx147065 char *buf, *buf_p;
10073737Shx147065 wl_frame_t *frm_p;
10083737Shx147065 uint16_t pkt_len, ret;
10093737Shx147065 uint16_t xmt_id, ring_idx;
10103737Shx147065 struct ieee80211_frame *wh;
10113737Shx147065 struct ieee80211_llc *llc;
10123737Shx147065
10133737Shx147065 mutex_enter(&pcwl_p->pcwl_glock);
10143737Shx147065 if ((pcwl_p->pcwl_flag & (PCWL_CARD_READY | PCWL_CARD_LINKUP)) !=
10153737Shx147065 (PCWL_CARD_READY | PCWL_CARD_LINKUP)) {
10163737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
10173737Shx147065 freemsg(mblk_p);
10183737Shx147065 return (PCWL_SUCCESS); /* drop packet */
10193737Shx147065 }
10203737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
10213737Shx147065
10223737Shx147065 if (pullupmsg(mblk_p, -1) == 0) {
10233737Shx147065 freemsg(mblk_p);
10243737Shx147065 return (PCWL_SUCCESS); /* drop packet */
10253737Shx147065 }
10263737Shx147065 wh = (struct ieee80211_frame *)mblk_p->b_rptr;
10273737Shx147065 llc = (struct ieee80211_llc *)&wh[1];
10283737Shx147065
10293737Shx147065 mutex_enter(&pcwl_p->pcwl_txring.wl_tx_lock);
10303737Shx147065 ring_idx = pcwl_p->pcwl_txring.wl_tx_prod;
10313737Shx147065 pcwl_p->pcwl_txring.wl_tx_prod = (ring_idx + 1) & (WL_XMT_BUF_NUM - 1);
10323737Shx147065
10333737Shx147065 /*
10343737Shx147065 * check whether there is a xmt buffer available
10353737Shx147065 */
10363737Shx147065 while ((i < WL_XMT_BUF_NUM) &&
10373737Shx147065 (pcwl_p->pcwl_txring.wl_tx_ring[ring_idx])) {
10383737Shx147065 ring_idx = pcwl_p->pcwl_txring.wl_tx_prod;
10393737Shx147065 pcwl_p->pcwl_txring.wl_tx_prod =
10403737Shx147065 (ring_idx + 1) & (WL_XMT_BUF_NUM - 1);
10413737Shx147065 i++;
10423737Shx147065 }
10433737Shx147065 if (i == WL_XMT_BUF_NUM) {
10443737Shx147065 mutex_exit(&pcwl_p->pcwl_txring.wl_tx_lock);
10453737Shx147065 mutex_enter(&pcwl_p->pcwl_glock);
10463737Shx147065 pcwl_p->pcwl_reschedule_need = B_TRUE;
10473737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
10483737Shx147065 pcwl_p->pcwl_noxmtbuf++;
10493737Shx147065 return (PCWL_FAIL);
10503737Shx147065 }
10513737Shx147065 xmt_id = pcwl_p->pcwl_txring.wl_tx_fids[ring_idx];
10523737Shx147065 pcwl_p->pcwl_txring.wl_tx_ring[ring_idx] = xmt_id;
10533737Shx147065 mutex_exit(&pcwl_p->pcwl_txring.wl_tx_lock);
10543737Shx147065
10553737Shx147065 buf = kmem_zalloc(PCWL_NICMEM_SZ, KM_SLEEP);
10563737Shx147065 buf_p = (ulong_t)buf & 1 ? buf + 1 : buf;
10573737Shx147065 frm_p = (wl_frame_t *)buf_p;
10583737Shx147065 #ifdef DEBUG
10593737Shx147065 if (pcwl_debug & PCWL_DBG_SEND) {
10603737Shx147065 cmn_err(CE_NOTE, "pcwl send: packet");
10616990Sgd78059 for (i = 0; i < MBLKL(mblk_p); i++)
10623737Shx147065 cmn_err(CE_NOTE, "%x: %x\n", i,
10633737Shx147065 *((unsigned char *)mblk_p->b_rptr + i));
10643737Shx147065 }
10653737Shx147065 #endif
10663737Shx147065 pkt_len = msgdsize(mblk_p);
10673737Shx147065 if (pkt_len > (PCWL_NICMEM_SZ - sizeof (wl_frame_t))) {
10683737Shx147065 cmn_err(CE_WARN, "pcwl: send mblk is too long");
10693737Shx147065 kmem_free(buf, PCWL_NICMEM_SZ);
10703737Shx147065 freemsg(mblk_p);
10713737Shx147065 return (PCWL_SUCCESS); /* drop packet */
10723737Shx147065 }
10733737Shx147065 if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) !=
10743737Shx147065 IEEE80211_FC1_DIR_TODS) {
10753737Shx147065 kmem_free(buf, PCWL_NICMEM_SZ);
10763737Shx147065 freemsg(mblk_p);
10773737Shx147065 return (PCWL_SUCCESS); /* drop packet */
10783737Shx147065 }
10793737Shx147065 bzero(frm_p, WL_802_11_HDRLEN);
10803737Shx147065
10813737Shx147065 frm_p->wl_tx_ctl = WL_TXCNTL_SET;
10823737Shx147065 bcopy(wh->i_addr3, frm_p->wl_dst_addr, ETHERADDRL); /* dst macaddr */
10833737Shx147065 bcopy(wh->i_addr2, frm_p->wl_src_addr, ETHERADDRL); /* src macaddr */
10843737Shx147065 frm_p->wl_len = htons(pkt_len - sizeof (*wh));
10853737Shx147065 bcopy(llc, &frm_p->wl_dat[0], pkt_len - sizeof (*wh));
10863737Shx147065 pkt_len = pkt_len - (sizeof (*wh) + sizeof (*llc)) +
10873737Shx147065 WL_802_11_HDRLEN;
10883737Shx147065 PCWLDBG((CE_NOTE, "send: DIX frmsz=%x pkt_len=%x\n",
10893737Shx147065 WL_802_11_HDRLEN, pkt_len));
10903737Shx147065
10913737Shx147065 if (pkt_len & 1) /* round up to 16-bit boundary and pad 0 */
10923737Shx147065 buf_p[pkt_len++] = 0;
10933737Shx147065
10943737Shx147065 ASSERT(pkt_len <= PCWL_NICMEM_SZ);
10953737Shx147065 #ifdef DEBUG
10963737Shx147065 if (pcwl_debug & PCWL_DBG_SEND) {
10973737Shx147065 cmn_err(CE_NOTE, "pkt_len = %x\n", pkt_len);
10983737Shx147065 for (i = 0; i < pkt_len; i++)
10993737Shx147065 cmn_err(CE_NOTE, "%x: %x\n", i,
11003737Shx147065 *((unsigned char *)buf + i));
11013737Shx147065 }
11023737Shx147065 #endif
11033737Shx147065 mutex_enter(&pcwl_p->pcwl_glock);
11043737Shx147065 ret = (WRCH1(pcwl_p, xmt_id, 0, (uint16_t *)buf_p, 0x2e) ||
11053737Shx147065 WRPKT(pcwl_p, xmt_id, 0x2e, (uint16_t *)(buf_p + 0x2e),
11063737Shx147065 pkt_len - 0x2e));
11073737Shx147065 if (ret) {
11083737Shx147065 goto done;
11093737Shx147065 }
11103737Shx147065 PCWLDBG((CE_NOTE, "send: xmt_id=%x send=%x\n", xmt_id, pkt_len));
11113737Shx147065 (void) pcwl_set_cmd(pcwl_p, WL_CMD_TX | WL_RECLAIM, xmt_id);
11123737Shx147065
11133737Shx147065 done:
11143737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
11153737Shx147065 kmem_free(buf, PCWL_NICMEM_SZ);
11163737Shx147065 freemsg(mblk_p);
11173737Shx147065 return (PCWL_SUCCESS);
11183737Shx147065 }
11193737Shx147065
11203737Shx147065 static mblk_t *
pcwl_tx(void * arg,mblk_t * mp)11213737Shx147065 pcwl_tx(void *arg, mblk_t *mp)
11223737Shx147065 {
11233737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
11243737Shx147065 mblk_t *next;
11253737Shx147065
11263737Shx147065 ASSERT(mp != NULL);
11273737Shx147065 mutex_enter(&pcwl_p->pcwl_glock);
11283737Shx147065 if ((pcwl_p->pcwl_flag & (PCWL_CARD_LINKUP | PCWL_CARD_READY)) !=
11293737Shx147065 (PCWL_CARD_LINKUP | PCWL_CARD_READY)) {
11303737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
113111101SMikore.Li@Sun.COM freemsgchain(mp);
113211101SMikore.Li@Sun.COM return (NULL);
11333737Shx147065 }
11343737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
11353737Shx147065 while (mp != NULL) {
11363737Shx147065 next = mp->b_next;
11373737Shx147065 mp->b_next = NULL;
11383737Shx147065
11393737Shx147065 if (pcwl_send(pcwl_p, mp)) {
11403737Shx147065 mp->b_next = next;
11413737Shx147065 break;
11423737Shx147065 }
11433737Shx147065 mp = next;
11443737Shx147065 }
11453737Shx147065 return (mp);
11463737Shx147065 }
11473737Shx147065
11483737Shx147065 static int
pcwl_prom(void * arg,boolean_t on)11493737Shx147065 pcwl_prom(void *arg, boolean_t on)
11503737Shx147065 {
11513737Shx147065 int ret = PCWL_SUCCESS;
11523737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
11533737Shx147065
11543737Shx147065 mutex_enter(&pcwl_p->pcwl_glock);
11553737Shx147065 if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
11563737Shx147065 ret = PCWL_FAIL;
11573737Shx147065 goto done;
11583737Shx147065 }
11593737Shx147065
11603737Shx147065 PCWLDBG((CE_NOTE, "pcwl_prom called %x\n", on));
11613737Shx147065
11623737Shx147065 if (on)
11633737Shx147065 pcwl_p->pcwl_rf.rf_promiscuous = 1;
11643737Shx147065 else
11653737Shx147065 pcwl_p->pcwl_rf.rf_promiscuous = 0;
11663737Shx147065 if (ret = pcwl_fil_ltv(pcwl_p, 2, WL_RID_PROMISC,
11673737Shx147065 pcwl_p->pcwl_rf.rf_promiscuous)) {
11683737Shx147065 ret = PCWL_FAIL;
11693737Shx147065 }
11703737Shx147065 done:
11713737Shx147065 if (ret)
11723737Shx147065 cmn_err(CE_WARN, "pcwl promisc: failed\n");
11733737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
11743737Shx147065 return (ret);
11753737Shx147065 }
11763737Shx147065
11773737Shx147065 static int
pcwl_gstat(void * arg,uint_t statitem,uint64_t * val)11783737Shx147065 pcwl_gstat(void *arg, uint_t statitem, uint64_t *val)
11793737Shx147065 {
11803737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
11813737Shx147065 int ret = PCWL_SUCCESS;
11823737Shx147065 uint64_t *cntr_p = pcwl_p->pcwl_cntrs_s;
11833737Shx147065 uint16_t rate = 0;
11843737Shx147065 uint64_t speed;
11853737Shx147065
11863737Shx147065 PCWLDBG((CE_NOTE, "pcwl_gstat called\n"));
11873737Shx147065 mutex_enter(&pcwl_p->pcwl_glock);
11883737Shx147065 if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
11893737Shx147065 ret = PCWL_FAIL;
11903737Shx147065 goto done;
11913737Shx147065 }
11923737Shx147065
11933737Shx147065 if (pcwl_get_ltv(pcwl_p, 2, WL_RID_CUR_TX_RATE, &rate)) {
11943737Shx147065 cmn_err(CE_WARN, "pcwl kstat: get speed failed\n");
11953737Shx147065 ret = PCWL_FAIL;
11963737Shx147065 goto done;
11973737Shx147065 }
11983737Shx147065 switch (pcwl_p->pcwl_chip_type) {
11993737Shx147065 case PCWL_CHIP_PRISMII:
12003737Shx147065 switch (rate) {
12013737Shx147065 case WL_SPEED_1Mbps_P2: rate = 2; break;
12023737Shx147065 case WL_SPEED_2Mbps_P2: rate = 4; break;
12033737Shx147065 case WL_SPEED_55Mbps_P2: rate = 11; break;
12043737Shx147065 case WL_SPEED_11Mbps_P2: rate = 22; break;
12053737Shx147065 default: rate = 0; break;
12063737Shx147065 }
12073737Shx147065 speed = rate * 500000;
12083737Shx147065 break;
12093737Shx147065 case PCWL_CHIP_LUCENT:
12103737Shx147065 default:
12113737Shx147065 speed = rate * 1000000;
12123737Shx147065 if (rate == 6)
12133737Shx147065 speed = 5500000;
12143737Shx147065 break;
12153737Shx147065 }
12163737Shx147065
12173737Shx147065 switch (statitem) {
12183737Shx147065 case MAC_STAT_IFSPEED:
12193737Shx147065 *val = speed;
12203737Shx147065 break;
12213737Shx147065 case MAC_STAT_NOXMTBUF:
12223737Shx147065 *val = pcwl_p->pcwl_noxmtbuf;
12233737Shx147065 break;
12243737Shx147065 case MAC_STAT_NORCVBUF:
12253737Shx147065 *val = cntr_p[WLC_RX_DISCARDS_NOBUF];
12263737Shx147065 break;
12273737Shx147065 case MAC_STAT_IERRORS:
12283737Shx147065 *val = 0;
12293737Shx147065 break;
12303737Shx147065 case MAC_STAT_OERRORS:
12313737Shx147065 *val = cntr_p[WLC_TX_DISCARDS] +
12323737Shx147065 cntr_p[WLC_TX_DISCARDS_WRONG_SA];
12333737Shx147065 break;
12343737Shx147065 case MAC_STAT_RBYTES:
12353737Shx147065 *val = cntr_p[WLC_RX_UNICAST_OCTETS];
12363737Shx147065 break;
12373737Shx147065 case MAC_STAT_IPACKETS:
12383737Shx147065 *val = cntr_p[WLC_RX_UNICAST_FRAMES];
12393737Shx147065 break;
12403737Shx147065 case MAC_STAT_OBYTES:
12413737Shx147065 *val = cntr_p[WLC_TX_UNICAST_OCTETS];
12423737Shx147065 break;
12433737Shx147065 case MAC_STAT_OPACKETS:
12443737Shx147065 *val = cntr_p[WLC_TX_UNICAST_FRAMES];
12453737Shx147065 break;
12463737Shx147065 case WIFI_STAT_TX_FAILED:
12473737Shx147065 *val = cntr_p[WLC_TX_RETRY_LIMIT] +
12483737Shx147065 cntr_p[WLC_TX_DEFERRED_XMITS];
12493737Shx147065 break;
12503737Shx147065 case WIFI_STAT_TX_RETRANS:
12513737Shx147065 *val = cntr_p[WLC_TX_SINGLE_RETRIES] +
12523737Shx147065 cntr_p[WLC_TX_MULTI_RETRIES];
12533737Shx147065 break;
12543737Shx147065 case WIFI_STAT_FCS_ERRORS:
12553737Shx147065 *val = cntr_p[WLC_RX_FCS_ERRORS];
12563737Shx147065 break;
12573737Shx147065 case WIFI_STAT_WEP_ERRORS:
12583737Shx147065 *val = cntr_p[WLC_RX_WEP_CANT_DECRYPT];
12593737Shx147065 break;
12603737Shx147065 case WIFI_STAT_MCAST_TX:
12613737Shx147065 *val = cntr_p[WLC_TX_MULTICAST_FRAMES];
12623737Shx147065 break;
12633737Shx147065 case WIFI_STAT_MCAST_RX:
12643737Shx147065 *val = cntr_p[WLC_RX_MULTICAST_FRAMES];
12653737Shx147065 break;
12663737Shx147065 case WIFI_STAT_TX_FRAGS:
12673737Shx147065 *val = cntr_p[WLC_TX_FRAGMENTS];
12683737Shx147065 break;
12693737Shx147065 case WIFI_STAT_RX_FRAGS:
12703737Shx147065 *val = cntr_p[WLC_RX_FRAGMENTS] +
12713737Shx147065 cntr_p[WLC_RX_MSG_IN_MSG_FRAGS] +
12723737Shx147065 cntr_p[WLC_RX_MSG_IN_BAD_MSG_FRAGS];
12733737Shx147065 break;
12743737Shx147065 case WIFI_STAT_RTS_SUCCESS:
12753737Shx147065 case WIFI_STAT_RTS_FAILURE:
12763737Shx147065 case WIFI_STAT_ACK_FAILURE:
12773737Shx147065 case WIFI_STAT_RX_DUPS:
12783737Shx147065 *val = 0;
12793737Shx147065 break;
12803737Shx147065 default:
12813737Shx147065 ret = ENOTSUP;
12823737Shx147065 }
12833737Shx147065 done:
12843737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
12853737Shx147065 return (ret);
12863737Shx147065 }
12873737Shx147065
12883737Shx147065 static int
pcwl_sdmulti(void * arg,boolean_t add,const uint8_t * eth_p)12893737Shx147065 pcwl_sdmulti(void *arg, boolean_t add, const uint8_t *eth_p)
12903737Shx147065 {
12913737Shx147065 int ret = PCWL_SUCCESS;
12923737Shx147065 uint16_t i;
12933737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
12943737Shx147065 uint16_t *mc_p = pcwl_p->pcwl_mcast;
12953737Shx147065
12963737Shx147065 mutex_enter(&pcwl_p->pcwl_glock);
12973737Shx147065 if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
12983737Shx147065 ret = PCWL_FAIL;
12993737Shx147065 goto done;
13003737Shx147065 }
13013737Shx147065
13023737Shx147065 if (add) { /* enable multicast on eth_p, search for available entries */
13033737Shx147065 for (i = 0; i < 16; i++, mc_p += (ETHERADDRL >> 1)) {
13043737Shx147065 if (!ether_cmp(eth_p, mc_p))
13053737Shx147065 break;
13063737Shx147065 }
13073737Shx147065 if (i < 16) /* already part of the filter */
13083737Shx147065 goto done;
13093737Shx147065 mc_p = pcwl_p->pcwl_mcast; /* reset mc_p for 2nd scan */
13103737Shx147065 for (i = 0; i < 16; i++, mc_p += (ETHERADDRL >> 1)) {
13113737Shx147065 PCWLDBG((CE_NOTE, "smulti: mc[%x]=%s\n", i,
13123737Shx147065 ether_sprintf((struct ether_addr *)mc_p)));
13133737Shx147065 if (mc_p[0] == 0 && mc_p[1] == 0 && mc_p[2] == 0)
13143737Shx147065 break;
13153737Shx147065 }
13163737Shx147065 if (i >= 16) /* can't find a vacant entry */
13173737Shx147065 goto done;
13183737Shx147065 ether_copy(eth_p, mc_p);
13193737Shx147065 } else { /* disable multicast, locate the entry and clear it */
13203737Shx147065 for (i = 0; i < 16; i++, mc_p += (ETHERADDRL >> 1)) {
13213737Shx147065 if (!ether_cmp(eth_p, mc_p))
13223737Shx147065 break;
13233737Shx147065 }
13243737Shx147065 if (i >= 16)
13253737Shx147065 goto done;
13263737Shx147065 mc_p[0] = 0;
13273737Shx147065 mc_p[1] = 0;
13283737Shx147065 mc_p[2] = 0;
13293737Shx147065 }
13303737Shx147065 /*
13313737Shx147065 * re-blow the entire 16 entries buffer
13323737Shx147065 */
13333737Shx147065 if (i = pcwl_put_ltv(pcwl_p, ETHERADDRL << 4, WL_RID_MCAST,
13343737Shx147065 pcwl_p->pcwl_mcast)) {
13353737Shx147065 ret = PCWL_FAIL;
13363737Shx147065 }
13373737Shx147065 done:
13383737Shx147065 if (ret)
13393737Shx147065 cmn_err(CE_WARN, "pcwl set multi addr: failed\n");
13403737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
13413737Shx147065 return (ret);
13423737Shx147065 }
13433737Shx147065
13443737Shx147065 static uint_t
pcwl_intr(caddr_t arg)13453737Shx147065 pcwl_intr(caddr_t arg)
13463737Shx147065 {
13473737Shx147065 uint16_t stat;
13483737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
13493737Shx147065
13503737Shx147065 mutex_enter(&pcwl_p->pcwl_glock);
13513737Shx147065 if ((pcwl_p->pcwl_flag & (PCWL_CARD_READY | PCWL_CARD_INTREN)) !=
13523737Shx147065 (PCWL_CARD_READY | PCWL_CARD_INTREN)) {
13533737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
13543737Shx147065 return (DDI_INTR_UNCLAIMED);
13553737Shx147065 }
13563737Shx147065 PCWL_READ(pcwl_p, WL_EVENT_STAT, stat);
13573737Shx147065 if (!(stat & WL_INTRS) || stat == WL_EV_ALL) {
13583737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
13593737Shx147065 return (DDI_INTR_UNCLAIMED);
13603737Shx147065 }
13613737Shx147065
13623737Shx147065 PCWL_WRITE(pcwl_p, WL_INT_EN, 0);
13633737Shx147065 if (stat & WL_EV_RX) {
13643737Shx147065 pcwl_rcv(pcwl_p);
13653737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_RX);
13663737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_RX);
13673737Shx147065 }
13683737Shx147065 if (stat & WL_EV_TX) {
13693737Shx147065 if (pcwl_txdone(pcwl_p) == PCWL_SUCCESS) {
13703737Shx147065 if (pcwl_p->pcwl_reschedule_need == B_TRUE) {
13713737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
13723737Shx147065 mac_tx_update(GLD3(pcwl_p));
13733737Shx147065 mutex_enter(&pcwl_p->pcwl_glock);
13743737Shx147065 pcwl_p->pcwl_reschedule_need = B_FALSE;
13753737Shx147065 }
13763737Shx147065 }
13773737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX);
13783737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX);
13793737Shx147065 }
13803737Shx147065 if (stat & WL_EV_ALLOC) {
13813737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_ALLOC | 0x1000);
13823737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, 0x1000);
13833737Shx147065 }
13843737Shx147065 if (stat & WL_EV_INFO) {
13853737Shx147065 pcwl_infodone(pcwl_p);
13863737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_INFO);
13873737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_INFO);
13883737Shx147065 }
13893737Shx147065 if (stat & WL_EV_TX_EXC) {
13903737Shx147065 if (pcwl_txdone(pcwl_p) == PCWL_SUCCESS) {
13913737Shx147065 if (pcwl_p->pcwl_reschedule_need == B_TRUE) {
13923737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
13933737Shx147065 mac_tx_update(GLD3(pcwl_p));
13943737Shx147065 mutex_enter(&pcwl_p->pcwl_glock);
13953737Shx147065 pcwl_p->pcwl_reschedule_need = B_FALSE;
13963737Shx147065 }
13973737Shx147065 }
13983737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX_EXC);
13993737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX_EXC);
14003737Shx147065 }
14013737Shx147065 if (stat & WL_EV_INFO_DROP) {
14023737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_INFO_DROP);
14033737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_INFO_DROP);
14043737Shx147065 }
14053737Shx147065 PCWL_ENABLE_INTR(pcwl_p);
14063737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
14073737Shx147065
14083737Shx147065 return (DDI_INTR_CLAIMED);
14093737Shx147065 }
14103737Shx147065
14113737Shx147065 static uint_t
pcwl_intr_hi(caddr_t arg)14123737Shx147065 pcwl_intr_hi(caddr_t arg)
14133737Shx147065 {
14143737Shx147065 uint16_t stat;
14153737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
14163737Shx147065
14173737Shx147065 mutex_enter(&pcwl_p->pcwl_glock);
14183737Shx147065 if ((pcwl_p->pcwl_flag & (PCWL_CARD_READY | PCWL_CARD_INTREN)) !=
14193737Shx147065 (PCWL_CARD_READY | PCWL_CARD_INTREN)) {
14203737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
14213737Shx147065 return (DDI_INTR_UNCLAIMED);
14223737Shx147065 }
14233737Shx147065 PCWL_READ(pcwl_p, WL_EVENT_STAT, stat);
14243737Shx147065 if (!(stat & WL_INTRS) || stat == WL_EV_ALL) {
14253737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
14263737Shx147065 return (DDI_INTR_UNCLAIMED);
14273737Shx147065 }
14283737Shx147065 PCWL_WRITE(pcwl_p, WL_INT_EN, 0); /* disable interrupt without ack */
14293737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
14303737Shx147065 ddi_trigger_softintr(pcwl_p->pcwl_softint_id);
14313737Shx147065 return (DDI_INTR_CLAIMED);
14323737Shx147065 }
14333737Shx147065
14343737Shx147065 /*
14353737Shx147065 * called at interrupt context to retrieve data from card
14363737Shx147065 */
14373737Shx147065 static void
pcwl_rcv(pcwl_maci_t * pcwl_p)14383737Shx147065 pcwl_rcv(pcwl_maci_t *pcwl_p)
14393737Shx147065 {
14403737Shx147065 uint16_t id, len, off, ret, frm_ctl;
14413737Shx147065 wl_frame_t frm;
14423737Shx147065 mblk_t *mp = allocb(PCWL_NICMEM_SZ, BPRI_MED);
14433737Shx147065 if (!mp)
14443737Shx147065 return;
14453737Shx147065 ASSERT(mp->b_rptr == mp->b_wptr);
14463737Shx147065
14473737Shx147065 PCWL_READ(pcwl_p, WL_RX_FID, id);
14483737Shx147065 PCWL_WRITE(pcwl_p, WL_RX_FID, 0);
14493737Shx147065 if (id == WL_INVALID_FID) {
14503737Shx147065 PCWLDBG((CE_NOTE, "pcwl rcv: get rx_fid failed\n"));
14513737Shx147065 ret = PCWL_FAIL;
14523737Shx147065 goto done;
14533737Shx147065 }
14543737Shx147065 if (ret = RDCH0(pcwl_p, id, 0, (uint16_t *)&frm, sizeof (frm))) {
14553737Shx147065 PCWLDBG((CE_NOTE, "pcwl rcv: read frm failed %x\n", ret));
14563737Shx147065 goto done;
14573737Shx147065 }
14583737Shx147065 if (frm.wl_status & WL_STAT_ERRSTAT) {
14593737Shx147065 PCWLDBG((CE_NOTE, "pcwl rcv: errstat %x\n", frm.wl_status));
14603737Shx147065 ret = frm.wl_status;
14613737Shx147065 goto done;
14623737Shx147065 }
14633737Shx147065 PCWLDBG((CE_NOTE, "pcwl rcv: frame type %x\n", frm.wl_status));
14643737Shx147065 #ifdef DEBUG
14653737Shx147065 if (pcwl_debug & PCWL_DBG_RCV) {
14663737Shx147065 int i;
14673737Shx147065 cmn_err(CE_NOTE, "pcwl rcv: frm header\n");
14683737Shx147065 for (i = 0; i < WL_802_11_HDRLEN; i++)
14693737Shx147065 cmn_err(CE_NOTE, "%x: %x\n", i,
14703737Shx147065 *((uint8_t *)&frm + i));
14713737Shx147065 }
14723737Shx147065 #endif
14733737Shx147065 len = frm.wl_dat_len;
14743737Shx147065 /*
14753737Shx147065 * this driver deal with WEP by itself. so plugin always thinks no wep.
14763737Shx147065 */
14773737Shx147065 frm.wl_frame_ctl &= ~(IEEE80211_FC1_WEP << 8);
14783737Shx147065 frm_ctl = frm.wl_frame_ctl;
14793737Shx147065 switch (frm.wl_status) {
14803737Shx147065 case WL_STAT_1042:
14813737Shx147065 case WL_STAT_TUNNEL:
14823737Shx147065 case WL_STAT_WMP_MSG:
14833737Shx147065 PCWL_SWAP16((uint16_t *)&frm.wl_frame_ctl,
14843737Shx147065 sizeof (struct ieee80211_frame));
14853737Shx147065 /*
14863737Shx147065 * discard those frames which are not from the AP we connect or
14873737Shx147065 * without 'ap->sta' direction
14883737Shx147065 */
14893737Shx147065 if ((pcwl_p->pcwl_rf.rf_porttype == WL_BSS_BSS) &&
14903737Shx147065 ((((frm_ctl >> 8) & IEEE80211_FC1_DIR_MASK) !=
14913737Shx147065 IEEE80211_FC1_DIR_FROMDS) ||
14923737Shx147065 bcmp(pcwl_p->pcwl_bssid, frm.wl_addr2, 6) != 0)) {
14933737Shx147065 ret = PCWL_FAIL;
14943737Shx147065 goto done;
14953737Shx147065 }
14963737Shx147065
14973737Shx147065 bcopy(&frm.wl_frame_ctl, mp->b_wptr,
14983737Shx147065 sizeof (struct ieee80211_frame));
14993737Shx147065 mp->b_wptr += sizeof (struct ieee80211_frame);
15003737Shx147065
15013737Shx147065 PCWL_SWAP16((uint16_t *)&frm.wl_dat[0],
15023737Shx147065 sizeof (struct ieee80211_llc));
15033737Shx147065 bcopy(&frm.wl_dat[0], mp->b_wptr,
15043737Shx147065 sizeof (struct ieee80211_llc));
15053737Shx147065 mp->b_wptr += sizeof (struct ieee80211_llc);
15063737Shx147065
15073737Shx147065 len -= (2 + WL_SNAPHDR_LEN);
15083737Shx147065 off = WL_802_11_HDRLEN;
15093737Shx147065 break;
15103737Shx147065 default:
15113737Shx147065 PCWLDBG((CE_NOTE, "pcwl rcv: incorrect pkt\n"));
15123737Shx147065 break;
15133737Shx147065 }
15143737Shx147065 if (len > MBLKSIZE(mp)) {
15153737Shx147065 PCWLDBG((CE_NOTE, "pcwl rcv: oversz pkt %x\n", len));
15163737Shx147065 ret = PCWL_FAIL;
15173737Shx147065 goto done;
15183737Shx147065 }
15193737Shx147065 if (len & 1)
15203737Shx147065 len++;
15213737Shx147065 ret = RDPKT(pcwl_p, id, off, (uint16_t *)mp->b_wptr, len);
15223737Shx147065 done:
15233737Shx147065 if (ret) {
15243737Shx147065 PCWLDBG((CE_NOTE, "pcwl rcv: rd data %x\n", ret));
15253737Shx147065 freemsg(mp);
15263737Shx147065 return;
15273737Shx147065 }
15283737Shx147065 mp->b_wptr = mp->b_wptr + len;
15293737Shx147065 #ifdef DEBUG
15303737Shx147065 if (pcwl_debug & PCWL_DBG_RCV) {
15313737Shx147065 int i;
15323737Shx147065 cmn_err(CE_NOTE, "pcwl rcv: len=0x%x\n", len);
15333737Shx147065 for (i = 0; i < len+14; i++)
15343737Shx147065 cmn_err(CE_NOTE, "%x: %x\n", i,
15353737Shx147065 *((uint8_t *)mp->b_rptr + i));
15363737Shx147065 }
15373737Shx147065 #endif
15383737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
15393737Shx147065 mac_rx(GLD3(pcwl_p), NULL, mp);
15403737Shx147065 mutex_enter(&pcwl_p->pcwl_glock);
15413737Shx147065 }
15423737Shx147065
15433737Shx147065 static uint32_t
pcwl_txdone(pcwl_maci_t * pcwl_p)15443737Shx147065 pcwl_txdone(pcwl_maci_t *pcwl_p)
15453737Shx147065 {
15463737Shx147065 uint16_t fid, i;
15473737Shx147065 PCWL_READ(pcwl_p, WL_ALLOC_FID, fid);
15483737Shx147065 PCWL_WRITE(pcwl_p, WL_ALLOC_FID, 0);
15493737Shx147065
15503737Shx147065 mutex_enter(&pcwl_p->pcwl_txring.wl_tx_lock);
15513737Shx147065 for (i = 0; i < WL_XMT_BUF_NUM; i++) {
15523737Shx147065 if (fid == pcwl_p->pcwl_txring.wl_tx_ring[i]) {
15533737Shx147065 pcwl_p->pcwl_txring.wl_tx_ring[i] = 0;
15543737Shx147065 break;
15553737Shx147065 }
15563737Shx147065 }
15573737Shx147065 pcwl_p->pcwl_txring.wl_tx_cons =
15583737Shx147065 (pcwl_p->pcwl_txring.wl_tx_cons + 1) & (WL_XMT_BUF_NUM - 1);
15593737Shx147065 mutex_exit(&pcwl_p->pcwl_txring.wl_tx_lock);
15603737Shx147065 if (i == WL_XMT_BUF_NUM)
15613737Shx147065 return (PCWL_FAIL);
15623737Shx147065 return (PCWL_SUCCESS);
15633737Shx147065
15643737Shx147065 }
15653737Shx147065
15663737Shx147065 static void
pcwl_infodone(pcwl_maci_t * pcwl_p)15673737Shx147065 pcwl_infodone(pcwl_maci_t *pcwl_p)
15683737Shx147065 {
15693737Shx147065 uint16_t id, ret, i;
15703737Shx147065 uint16_t linkStatus[2];
15713737Shx147065 uint16_t linkStat;
15723737Shx147065 wifi_data_t wd = { 0 };
15733737Shx147065
15743737Shx147065 PCWL_READ(pcwl_p, WL_INFO_FID, id);
15753737Shx147065 if (id == WL_INVALID_FID) {
15763737Shx147065 cmn_err(CE_WARN, "pcwl infodone: read info_fid failed\n");
15773737Shx147065 return;
15783737Shx147065 }
15793737Shx147065 if (ret = RDCH0(pcwl_p, id, 0, linkStatus, sizeof (linkStatus))) {
15803737Shx147065 PCWLDBG((CE_WARN, "pcwl infodone read infoFrm failed %x\n",
15813737Shx147065 ret));
15823737Shx147065 return;
15833737Shx147065 }
15843737Shx147065 PCWLDBG((CE_NOTE, "pcwl infodone: Frame length= %x, Frame Type = %x\n",
15853737Shx147065 linkStatus[0], linkStatus[1]));
15863737Shx147065
15873737Shx147065 switch (linkStatus[1]) {
15883737Shx147065 case WL_INFO_LINK_STAT:
15893737Shx147065 (void) RDCH0(pcwl_p, id, sizeof (linkStatus), &linkStat,
15903737Shx147065 sizeof (linkStat));
15913737Shx147065 PCWLDBG((CE_NOTE, "pcwl infodone: link status=%x\n", linkStat));
15923737Shx147065 if (!(pcwl_p->pcwl_flag & PCWL_CARD_LINKUP) &&
15933737Shx147065 linkStat == WL_LINK_CONNECT) {
15943737Shx147065 #ifdef DEBUG
15953737Shx147065 if (pcwl_debug & PCWL_DBG_LINKINFO)
15963737Shx147065 cmn_err(CE_NOTE, "pcwl: Link up \n");
15973737Shx147065 #endif
15983737Shx147065 pcwl_p->pcwl_flag |= PCWL_CARD_LINKUP;
15993737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
16003737Shx147065 if (pcwl_p->pcwl_connect_timeout_id != 0) {
16013737Shx147065 (void) untimeout(pcwl_p->
16023737Shx147065 pcwl_connect_timeout_id);
16033737Shx147065 pcwl_p->pcwl_connect_timeout_id = 0;
16043737Shx147065 }
16053737Shx147065 mutex_enter(&pcwl_p->pcwl_glock);
16063737Shx147065 mac_link_update(GLD3(pcwl_p), LINK_STATE_UP);
16073737Shx147065 (void) pcwl_get_ltv(pcwl_p, 6,
16083737Shx147065 WL_RID_BSSID, (uint16_t *)pcwl_p->pcwl_bssid);
16093737Shx147065 PCWL_SWAP16((uint16_t *)pcwl_p->pcwl_bssid, 6);
16103737Shx147065 pcwl_get_rssi(pcwl_p);
16113737Shx147065 bcopy(pcwl_p->pcwl_bssid, wd.wd_bssid, 6);
16123737Shx147065 wd.wd_secalloc = WIFI_SEC_NONE;
16133737Shx147065 wd.wd_opmode = IEEE80211_M_STA;
16143737Shx147065 (void) mac_pdata_update(pcwl_p->pcwl_mh, &wd,
16153737Shx147065 sizeof (wd));
16163737Shx147065 }
16173737Shx147065 if ((pcwl_p->pcwl_flag & PCWL_CARD_LINKUP) &&
16183737Shx147065 ((linkStat == WL_LINK_DISCONNECT) ||
16193737Shx147065 (linkStat == WL_LINK_AP_OOR))) {
16203737Shx147065 #ifdef DEBUG
16213737Shx147065 if (pcwl_debug & PCWL_DBG_LINKINFO)
16223737Shx147065 cmn_err(CE_NOTE, "pcwl: Link down \n");
16233737Shx147065 #endif
16243737Shx147065 PCWLDBG((CE_NOTE, "pcwl infodone: link status = %d\n",
16253737Shx147065 linkStat));
16263737Shx147065 pcwl_p->pcwl_flag &= ~PCWL_CARD_LINKUP;
16273737Shx147065 if (linkStat == WL_LINK_AP_OOR)
16283737Shx147065 pcwl_p->pcwl_connect_timeout_id =
16293737Shx147065 timeout(pcwl_connect_timeout,
16303737Shx147065 pcwl_p, drv_usectohz(1000));
16313737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
16323737Shx147065 mac_link_update(GLD3(pcwl_p), LINK_STATE_DOWN);
16333737Shx147065 mutex_enter(&pcwl_p->pcwl_glock);
16343737Shx147065 }
16353737Shx147065 break;
16363737Shx147065 case WL_INFO_SCAN_RESULTS:
16373737Shx147065 case WL_INFO_HSCAN_RESULTS:
16383737Shx147065 pcwl_ssid_scan(pcwl_p, id, linkStatus[0], linkStatus[1]);
16393737Shx147065 break;
16403737Shx147065 case WL_INFO_COUNTERS:
16413737Shx147065 linkStatus[0]--;
16423737Shx147065 if (linkStatus[0] > WLC_STAT_CNT) {
16433737Shx147065 linkStatus[0] = MIN(linkStatus[0], WLC_STAT_CNT);
16443737Shx147065 }
16453737Shx147065 (void) RDCH0(pcwl_p, id, sizeof (linkStatus),
16463737Shx147065 pcwl_p->pcwl_cntrs_t, linkStatus[0]<<1);
16473737Shx147065 /*
16483737Shx147065 * accumulate all the statistics items for kstat use.
16493737Shx147065 */
16503737Shx147065 for (i = 0; i < WLC_STAT_CNT; i++)
16513737Shx147065 pcwl_p->pcwl_cntrs_s[i] += pcwl_p->pcwl_cntrs_t[i];
16523737Shx147065 break;
16533737Shx147065 default:
16543737Shx147065 break;
16553737Shx147065 }
16563737Shx147065 }
16573737Shx147065
16583737Shx147065 static uint16_t
pcwl_set_cmd(pcwl_maci_t * pcwl_p,uint16_t cmd,uint16_t param)16593737Shx147065 pcwl_set_cmd(pcwl_maci_t *pcwl_p, uint16_t cmd, uint16_t param)
16603737Shx147065 {
16613737Shx147065 int i;
16623737Shx147065 uint16_t stat;
16633737Shx147065
16643737Shx147065 if (((cmd == WL_CMD_ENABLE) &&
16653737Shx147065 ((pcwl_p->pcwl_flag & PCWL_ENABLED) != 0)) ||
16663737Shx147065 ((cmd == WL_CMD_DISABLE) &&
16673737Shx147065 ((pcwl_p->pcwl_flag & PCWL_ENABLED) == 0)))
16683737Shx147065 return (PCWL_SUCCESS);
16693737Shx147065
16703737Shx147065 for (i = 0; i < WL_TIMEOUT; i++) {
16713737Shx147065 PCWL_READ(pcwl_p, WL_COMMAND, stat);
16723737Shx147065 if (stat & WL_CMD_BUSY) {
16733737Shx147065 drv_usecwait(1);
16743737Shx147065 } else {
16753737Shx147065 break;
16763737Shx147065 }
16773737Shx147065 }
16783737Shx147065 if (i == WL_TIMEOUT) {
16793737Shx147065 cmn_err(CE_WARN, "pcwl: setcmd %x, %x timeout %x due to "
16803737Shx147065 "busy bit\n", cmd, param, stat);
16813737Shx147065 return (PCWL_TIMEDOUT_CMD);
16823737Shx147065 }
16833737Shx147065
16843737Shx147065 PCWL_WRITE(pcwl_p, WL_PARAM0, param);
16853737Shx147065 PCWL_WRITE(pcwl_p, WL_PARAM1, 0);
16863737Shx147065 PCWL_WRITE(pcwl_p, WL_PARAM2, 0);
16873737Shx147065 PCWL_WRITE(pcwl_p, WL_COMMAND, cmd);
16883737Shx147065 if (cmd == WL_CMD_INI)
16893737Shx147065 drv_usecwait(100000); /* wait .1 sec */
16903737Shx147065
16913737Shx147065 for (i = 0; i < WL_TIMEOUT; i++) {
16923737Shx147065 PCWL_READ(pcwl_p, WL_EVENT_STAT, stat);
16933737Shx147065 if (!(stat & WL_EV_CMD)) {
16943737Shx147065 drv_usecwait(1);
16953737Shx147065 } else {
16963737Shx147065 break;
16973737Shx147065 }
16983737Shx147065 }
16993737Shx147065 if (i == WL_TIMEOUT) {
17003737Shx147065 cmn_err(CE_WARN, "pcwl: setcmd %x,%x timeout %x\n",
17013737Shx147065 cmd, param, stat);
17023737Shx147065 if (stat & (WL_EV_ALLOC | WL_EV_RX))
17033737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, stat);
17043737Shx147065 return (PCWL_TIMEDOUT_CMD);
17053737Shx147065 }
17063737Shx147065 PCWL_READ(pcwl_p, WL_STATUS, stat);
17073737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_CMD);
17083737Shx147065 if (stat & WL_STAT_CMD_RESULT) { /* err in feedback status */
17093737Shx147065 cmn_err(CE_WARN, "pcwl: set_cmd %x,%x failed %x\n",
17103737Shx147065 cmd, param, stat);
17113737Shx147065 return (PCWL_FAILURE_CMD);
17123737Shx147065 }
17133737Shx147065 if (cmd == WL_CMD_ENABLE)
17143737Shx147065 pcwl_p->pcwl_flag |= PCWL_ENABLED;
17153737Shx147065 if (cmd == WL_CMD_DISABLE)
17163737Shx147065 pcwl_p->pcwl_flag &= (~PCWL_ENABLED);
17173737Shx147065 return (PCWL_SUCCESS);
17183737Shx147065 }
17193737Shx147065
17203737Shx147065 static uint16_t
pcwl_set_ch(pcwl_maci_t * pcwl_p,uint16_t type,uint16_t off,uint16_t channel)17213737Shx147065 pcwl_set_ch(pcwl_maci_t *pcwl_p, uint16_t type, uint16_t off, uint16_t channel)
17223737Shx147065 {
17233737Shx147065 int i;
17243737Shx147065 uint16_t stat, select, offset;
17253737Shx147065
17263737Shx147065 if (channel) {
17273737Shx147065 select = WL_SEL1;
17283737Shx147065 offset = WL_OFF1;
17293737Shx147065 } else {
17303737Shx147065 select = WL_SEL0;
17313737Shx147065 offset = WL_OFF0;
17323737Shx147065 }
17333737Shx147065 PCWL_WRITE(pcwl_p, select, type);
17343737Shx147065 PCWL_WRITE(pcwl_p, offset, off);
17353737Shx147065 for (stat = 0, i = 0; i < WL_TIMEOUT; i++) {
17363737Shx147065 PCWL_READ(pcwl_p, offset, stat);
17373737Shx147065 if (!(stat & (WL_OFF_BUSY|WL_OFF_ERR)))
17383737Shx147065 break;
17393737Shx147065 else {
17403737Shx147065 drv_usecwait(1);
17413737Shx147065 }
17423737Shx147065 }
17433737Shx147065 if (i == WL_TIMEOUT) {
17443737Shx147065 cmn_err(CE_WARN, "set_ch%d %x,%x failed %x\n",
17453737Shx147065 channel, type, off, stat);
17463737Shx147065 return (PCWL_TIMEDOUT_TARGET);
17473737Shx147065 }
17483737Shx147065 return (PCWL_SUCCESS);
17493737Shx147065 }
17503737Shx147065
17513737Shx147065 static uint16_t
pcwl_get_ltv(pcwl_maci_t * pcwl_p,uint16_t len,uint16_t type,uint16_t * val_p)17523737Shx147065 pcwl_get_ltv(pcwl_maci_t *pcwl_p, uint16_t len, uint16_t type, uint16_t *val_p)
17533737Shx147065 {
17543737Shx147065 uint16_t stat;
17553737Shx147065
17563737Shx147065 ASSERT(!(len & 1));
17573737Shx147065 len >>= 1; /* convert bytes to 16-bit words */
17583737Shx147065
17593737Shx147065 /*
17603737Shx147065 * 1. select read mode
17613737Shx147065 */
17623737Shx147065 if (stat = pcwl_set_cmd(pcwl_p, WL_CMD_ACCESS | WL_ACCESS_READ, type))
17633737Shx147065 return (stat);
17643737Shx147065
17653737Shx147065 /*
17663737Shx147065 * 2. select Buffer Access Path (channel) 1 for PIO
17673737Shx147065 */
17683737Shx147065 if (stat = pcwl_set_ch(pcwl_p, type, 0, 1))
17693737Shx147065 return (stat);
17703737Shx147065
17713737Shx147065 /*
17723737Shx147065 * 3. read length
17733737Shx147065 */
17743737Shx147065 PCWL_READ(pcwl_p, WL_DATA1, stat);
17753737Shx147065 if (stat != (len + 1)) {
17763737Shx147065 PCWLDBG((CE_NOTE, "get_ltv 0x%x expected 0x%x+1, got 0x%x\n",
17773737Shx147065 type, (len + 1) << 1, stat));
17783737Shx147065 stat = (stat >> 1) - 1;
17793737Shx147065 len = MIN(stat, len);
17803737Shx147065 }
17813737Shx147065
17823737Shx147065 /*
17833737Shx147065 * 4. read type
17843737Shx147065 */
17853737Shx147065 PCWL_READ(pcwl_p, WL_DATA1, stat);
17863737Shx147065 if (stat != type)
17873737Shx147065 return (PCWL_BADTYPE);
17883737Shx147065
17893737Shx147065 /*
17903737Shx147065 * 5. read value
17913737Shx147065 */
17923737Shx147065 for (stat = 0; stat < len; stat++, val_p++) {
17933737Shx147065 PCWL_READ_P(pcwl_p, WL_DATA1, val_p, 1);
17943737Shx147065 }
17953737Shx147065 return (PCWL_SUCCESS);
17963737Shx147065 }
17973737Shx147065
17983737Shx147065 static uint16_t
pcwl_fil_ltv(pcwl_maci_t * pcwl_p,uint16_t len,uint16_t type,uint16_t val)17993737Shx147065 pcwl_fil_ltv(pcwl_maci_t *pcwl_p, uint16_t len, uint16_t type, uint16_t val)
18003737Shx147065 {
18013737Shx147065 uint16_t stat;
18023737Shx147065
18033737Shx147065 ASSERT(!(len & 1));
18043737Shx147065
18053737Shx147065 /*
18063737Shx147065 * 1. select Buffer Access Path (channel) 1 for PIO
18073737Shx147065 */
18083737Shx147065 if (stat = pcwl_set_ch(pcwl_p, type, 0, 1))
18093737Shx147065 return (stat);
18103737Shx147065
18113737Shx147065 /*
18123737Shx147065 * 2. write length
18133737Shx147065 */
18143737Shx147065 len >>= 1; /* convert bytes to 16-bit words */
18153737Shx147065 stat = len + 1; /* 1 extra word */
18163737Shx147065 PCWL_WRITE(pcwl_p, WL_DATA1, stat);
18173737Shx147065
18183737Shx147065 /*
18193737Shx147065 * 3. write type
18203737Shx147065 */
18213737Shx147065 PCWL_WRITE(pcwl_p, WL_DATA1, type);
18223737Shx147065
18233737Shx147065 /*
18243737Shx147065 * 4. fill value
18253737Shx147065 */
18263737Shx147065 for (stat = 0; stat < len; stat++) {
18273737Shx147065 PCWL_WRITE(pcwl_p, WL_DATA1, val);
18283737Shx147065 }
18293737Shx147065
18303737Shx147065 /*
18313737Shx147065 * 5. select write mode
18323737Shx147065 */
18333737Shx147065 return (pcwl_set_cmd(pcwl_p, WL_CMD_ACCESS|WL_ACCESS_WRITE, type));
18343737Shx147065 }
18353737Shx147065
18363737Shx147065 static uint16_t
pcwl_put_ltv(pcwl_maci_t * pcwl_p,uint16_t len,uint16_t type,uint16_t * val_p)18373737Shx147065 pcwl_put_ltv(pcwl_maci_t *pcwl_p, uint16_t len, uint16_t type, uint16_t *val_p)
18383737Shx147065 {
18393737Shx147065 uint16_t stat;
18403737Shx147065
18413737Shx147065 ASSERT(!(len & 1));
18423737Shx147065
18433737Shx147065 /*
18443737Shx147065 * 1. select Buffer Access Path (channel) 1 for PIO
18453737Shx147065 */
18463737Shx147065 if (stat = pcwl_set_ch(pcwl_p, type, 0, 1))
18473737Shx147065 return (stat);
18483737Shx147065
18493737Shx147065 /*
18503737Shx147065 * 2. write length
18513737Shx147065 */
18523737Shx147065 len >>= 1; /* convert bytes to 16-bit words */
18533737Shx147065 stat = len + 1; /* 1 extra word */
18543737Shx147065 PCWL_WRITE(pcwl_p, WL_DATA1, stat);
18553737Shx147065
18563737Shx147065 /*
18573737Shx147065 * 3. write type
18583737Shx147065 */
18593737Shx147065 PCWL_WRITE(pcwl_p, WL_DATA1, type);
18603737Shx147065
18613737Shx147065 /*
18623737Shx147065 * 4. write value
18633737Shx147065 */
18643737Shx147065 for (stat = 0; stat < len; stat++, val_p++) {
18653737Shx147065 PCWL_WRITE_P(pcwl_p, WL_DATA1, val_p, 1);
18663737Shx147065 }
18673737Shx147065
18683737Shx147065 /*
18693737Shx147065 * 5. select write mode
18703737Shx147065 */
18713737Shx147065 return (pcwl_set_cmd(pcwl_p, WL_CMD_ACCESS|WL_ACCESS_WRITE, type));
18723737Shx147065 }
18733737Shx147065
18743737Shx147065 #define PCWL_COMPSTR_LEN 34
18753737Shx147065 static uint16_t
pcwl_put_str(pcwl_maci_t * pcwl_p,uint16_t type,char * str_p)18763737Shx147065 pcwl_put_str(pcwl_maci_t *pcwl_p, uint16_t type, char *str_p)
18773737Shx147065 {
18783737Shx147065 uint16_t buf[PCWL_COMPSTR_LEN / 2];
18793737Shx147065 uint8_t str_len = strlen(str_p);
18803737Shx147065
18813737Shx147065 bzero(buf, PCWL_COMPSTR_LEN);
18823737Shx147065 buf[0] = str_len;
18833737Shx147065 bcopy(str_p, (caddr_t)(buf + 1), str_len);
18843737Shx147065 PCWLDBG((CE_NOTE, "put_str: buf[0]=%x buf=%s\n",
18853737Shx147065 buf[0], (caddr_t)(buf + 1)));
18863737Shx147065 PCWL_SWAP16(buf + 1, PCWL_COMPSTR_LEN - 2);
18873737Shx147065 return (pcwl_put_ltv(pcwl_p, PCWL_COMPSTR_LEN, type, buf));
18883737Shx147065 }
18893737Shx147065
18903737Shx147065 /*ARGSUSED*/
18913737Shx147065 static uint16_t
pcwl_rdch0(pcwl_maci_t * pcwl_p,uint16_t type,uint16_t off,uint16_t * buf_p,int len,int order)18923737Shx147065 pcwl_rdch0(pcwl_maci_t *pcwl_p, uint16_t type, uint16_t off, uint16_t *buf_p,
18933737Shx147065 int len, int order)
18943737Shx147065 {
18953737Shx147065 uint16_t o;
18963737Shx147065 ASSERT(!(len & 1));
18973737Shx147065 /*
18983737Shx147065 * It seems that for PrismII chip, frequently overlap use of path0
18993737Shx147065 * and path1 may hang the hardware. So for PrismII chip, just use
19003737Shx147065 * path1. Test proves this workaround is OK.
19013737Shx147065 */
19023737Shx147065 if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) {
19033737Shx147065 if (type = pcwl_set_ch(pcwl_p, type, off, 1))
19043737Shx147065 return (type);
19053737Shx147065 o = WL_DATA1;
19063737Shx147065 } else {
19073737Shx147065 if (type = pcwl_set_ch(pcwl_p, type, off, 0))
19083737Shx147065 return (type);
19093737Shx147065 o = WL_DATA0;
19103737Shx147065 }
19113737Shx147065 len >>= 1;
19123737Shx147065 for (off = 0; off < len; off++, buf_p++) {
19133737Shx147065 PCWL_READ_P(pcwl_p, o, buf_p, order);
19143737Shx147065 }
19153737Shx147065 return (PCWL_SUCCESS);
19163737Shx147065 }
19173737Shx147065
19183737Shx147065 /*ARGSUSED*/
19193737Shx147065 static uint16_t
pcwl_wrch1(pcwl_maci_t * pcwl_p,uint16_t type,uint16_t off,uint16_t * buf_p,int len,int order)19203737Shx147065 pcwl_wrch1(pcwl_maci_t *pcwl_p, uint16_t type, uint16_t off, uint16_t *buf_p,
19213737Shx147065 int len, int order)
19223737Shx147065 {
19233737Shx147065 ASSERT(!(len & 1));
19243737Shx147065 if (type = pcwl_set_ch(pcwl_p, type, off, 1))
19253737Shx147065 return (type);
19263737Shx147065 len >>= 1;
19273737Shx147065 for (off = 0; off < len; off++, buf_p++) {
19283737Shx147065 PCWL_WRITE_P(pcwl_p, WL_DATA1, buf_p, order);
19293737Shx147065 }
19303737Shx147065 return (PCWL_SUCCESS);
19313737Shx147065 }
19323737Shx147065
19333737Shx147065 static uint16_t
pcwl_alloc_nicmem(pcwl_maci_t * pcwl_p,uint16_t len,uint16_t * id_p)19343737Shx147065 pcwl_alloc_nicmem(pcwl_maci_t *pcwl_p, uint16_t len, uint16_t *id_p)
19353737Shx147065 {
19363737Shx147065 int i;
19373737Shx147065 uint16_t stat;
19383737Shx147065
19393737Shx147065 len = ((len + 1) >> 1) << 1; /* round up to 16-bit boundary */
19403737Shx147065
19413737Shx147065 if (stat = pcwl_set_cmd(pcwl_p, WL_CMD_ALLOC_MEM, len))
19423737Shx147065 return (stat);
19433737Shx147065 for (stat = 0, i = 0; i < WL_TIMEOUT; i++) {
19443737Shx147065 PCWL_READ(pcwl_p, WL_EVENT_STAT, stat);
19453737Shx147065 if (stat & WL_EV_ALLOC)
19463737Shx147065 break;
19473737Shx147065 else
19483737Shx147065 drv_usecwait(1);
19493737Shx147065 }
19503737Shx147065 if (i == WL_TIMEOUT)
19513737Shx147065 return (PCWL_TIMEDOUT_ALLOC);
19523737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_ALLOC);
19533737Shx147065 PCWL_READ(pcwl_p, WL_ALLOC_FID, stat);
19543737Shx147065 *id_p = stat;
19553737Shx147065
19563737Shx147065 /*
19573737Shx147065 * zero fill the allocated NIC mem - sort of pcwl_fill_ch
19583737Shx147065 */
19593737Shx147065 (void) pcwl_set_ch(pcwl_p, stat, 0, 1);
19603737Shx147065
19613737Shx147065 for (len >>= 1, stat = 0; stat < len; stat++) {
19623737Shx147065 PCWL_WRITE(pcwl_p, WL_DATA1, 0);
19633737Shx147065 }
19643737Shx147065 return (PCWL_SUCCESS);
19653737Shx147065 }
19663737Shx147065
19673737Shx147065 static int
pcwl_add_scan_item(pcwl_maci_t * pcwl_p,wl_scan_result_t s)19683737Shx147065 pcwl_add_scan_item(pcwl_maci_t *pcwl_p, wl_scan_result_t s)
19693737Shx147065 {
19703737Shx147065 wl_scan_list_t *scan_item;
19713737Shx147065
19723737Shx147065 scan_item = kmem_zalloc(sizeof (wl_scan_list_t), KM_SLEEP);
19733737Shx147065 if (scan_item == NULL) {
19743737Shx147065 cmn_err(CE_WARN, "pcwl add_scan_item: zalloc failed\n");
19753737Shx147065 return (PCWL_FAIL);
19763737Shx147065 }
19773737Shx147065 scan_item->wl_val = s;
19783737Shx147065 scan_item->wl_timeout = WL_SCAN_TIMEOUT_MAX;
19793737Shx147065 list_insert_tail(&pcwl_p->pcwl_scan_list, scan_item);
19803737Shx147065 pcwl_p->pcwl_scan_num++;
19813737Shx147065 return (PCWL_SUCCESS);
19823737Shx147065 }
19833737Shx147065
19843737Shx147065 static void
pcwl_delete_scan_item(pcwl_maci_t * pcwl_p,wl_scan_list_t * s)19853737Shx147065 pcwl_delete_scan_item(pcwl_maci_t *pcwl_p, wl_scan_list_t *s)
19863737Shx147065 {
19873737Shx147065 list_remove(&pcwl_p->pcwl_scan_list, s);
19883737Shx147065 kmem_free(s, sizeof (*s));
19893737Shx147065 pcwl_p->pcwl_scan_num--;
19903737Shx147065 }
19913737Shx147065
19923737Shx147065 static void
pcwl_scanlist_timeout(void * arg)19933737Shx147065 pcwl_scanlist_timeout(void *arg)
19943737Shx147065 {
19953737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
19963737Shx147065 wl_scan_list_t *scan_item0, *scan_item1;
19973737Shx147065
19983737Shx147065 mutex_enter(&pcwl_p->pcwl_scanlist_lock);
19993737Shx147065 scan_item0 = list_head(&pcwl_p->pcwl_scan_list);
20003737Shx147065 for (; scan_item0; ) {
20013737Shx147065 PCWLDBG((CE_NOTE, "ssid = %s\n",
20023737Shx147065 scan_item0->wl_val.wl_srt_ssid));
20033737Shx147065 PCWLDBG((CE_NOTE, "timeout left: %ds",
20043737Shx147065 scan_item0->wl_timeout));
20053737Shx147065 scan_item1 = list_next(&pcwl_p->pcwl_scan_list, scan_item0);
20063737Shx147065 if (scan_item0->wl_timeout == 0) {
20073737Shx147065 pcwl_delete_scan_item(pcwl_p, scan_item0);
20083737Shx147065 } else {
20093737Shx147065 scan_item0->wl_timeout--;
20103737Shx147065 }
20113737Shx147065 scan_item0 = scan_item1;
20123737Shx147065 }
20133737Shx147065 mutex_exit(&pcwl_p->pcwl_scanlist_lock);
20143737Shx147065 pcwl_p->pcwl_scanlist_timeout_id = timeout(pcwl_scanlist_timeout,
20153737Shx147065 pcwl_p, drv_usectohz(1000000));
20163737Shx147065 }
20173737Shx147065
20183737Shx147065 static void
pcwl_get_rssi(pcwl_maci_t * pcwl_p)20193737Shx147065 pcwl_get_rssi(pcwl_maci_t *pcwl_p)
20203737Shx147065 {
20213737Shx147065 wl_scan_list_t *scan_item0;
20223737Shx147065 uint16_t cq[3];
20233737Shx147065
20243737Shx147065 bzero(cq, sizeof (cq));
20253737Shx147065 mutex_enter(&pcwl_p->pcwl_scanlist_lock);
20263737Shx147065 scan_item0 = list_head(&pcwl_p->pcwl_scan_list);
20273737Shx147065 for (; scan_item0; ) {
20283737Shx147065 if (bcmp(scan_item0->wl_val.wl_srt_bssid,
20293737Shx147065 pcwl_p->pcwl_bssid, 6) == 0) {
20303737Shx147065 pcwl_p->pcwl_rssi = scan_item0->wl_val.wl_srt_sl;
20313737Shx147065 }
20323737Shx147065 scan_item0 = list_next(&pcwl_p->pcwl_scan_list, scan_item0);
20333737Shx147065 }
20343737Shx147065 mutex_exit(&pcwl_p->pcwl_scanlist_lock);
20353737Shx147065 if (!pcwl_p->pcwl_rssi) {
20363737Shx147065 (void) pcwl_get_ltv(pcwl_p, 6, WL_RID_COMMQUAL, cq);
20373737Shx147065 pcwl_p->pcwl_rssi = cq[1];
20383737Shx147065 }
20393737Shx147065 }
20403737Shx147065
20413737Shx147065 /*
20423737Shx147065 * Note:
20433737Shx147065 * PrismII chipset has 2 extra space for the reason why scan is initiated
20443737Shx147065 */
20453737Shx147065 static void
pcwl_ssid_scan(pcwl_maci_t * pcwl_p,uint16_t fid,uint16_t flen,uint16_t stype)20463737Shx147065 pcwl_ssid_scan(pcwl_maci_t *pcwl_p, uint16_t fid, uint16_t flen, uint16_t stype)
20473737Shx147065 {
20483737Shx147065 uint16_t stat;
20493737Shx147065 uint16_t ssidNum, i;
20503737Shx147065 uint16_t off, szbuf;
20513737Shx147065 uint16_t tmp[2];
20523737Shx147065 wl_scan_list_t *scan_item0;
20533737Shx147065 uint32_t check_num;
20543737Shx147065 uint8_t bssid_t[6];
20553737Shx147065
20563737Shx147065 wl_scan_result_t sctbl;
20573737Shx147065
20583737Shx147065 off = sizeof (uint16_t) * 2;
20593737Shx147065 switch (pcwl_p->pcwl_chip_type) {
20603737Shx147065 case PCWL_CHIP_PRISMII:
20613737Shx147065 (void) RDCH0(pcwl_p, fid, off, tmp, 4);
20623737Shx147065 off += 4;
20633737Shx147065 szbuf = (stype == WL_INFO_SCAN_RESULTS ? 31 : 32);
20643737Shx147065 PCWLDBG((CE_NOTE, "pcwl ssid_scan: PRISM chip\n"));
20653737Shx147065 break;
20663737Shx147065 case PCWL_CHIP_LUCENT:
20673737Shx147065 PCWLDBG((CE_NOTE, "pcwl ssid_scan LUCENT chip\n"));
20683737Shx147065 default:
20693737Shx147065 szbuf = 25;
20703737Shx147065 }
20713737Shx147065
20723737Shx147065 flen = flen + 1 - (off >> 1);
20733737Shx147065 ssidNum = flen/szbuf;
20743737Shx147065 ssidNum = min(WL_SRT_MAX_NUM, ssidNum);
20753737Shx147065
20763737Shx147065 PCWLDBG((CE_NOTE, "pcwl: ssid_scan frame length = %d\n", flen));
20773737Shx147065
20783737Shx147065 PCWLDBG((CE_NOTE, "pcwl ssid_scan: %d ssid(s) available", ssidNum));
20793737Shx147065
20803737Shx147065 bzero(bssid_t, sizeof (bssid_t));
20813737Shx147065 for (i = 0; i < ssidNum; i++) {
20823737Shx147065 (void) RDCH0(pcwl_p, fid, off, (uint16_t *)&sctbl, 2*szbuf);
20833737Shx147065
20843737Shx147065 #ifdef DEBUG
20853737Shx147065 if (pcwl_debug & PCWL_DBG_INFO) {
20863737Shx147065 int j;
20873737Shx147065 for (j = 0; j < sizeof (sctbl); j++)
20883737Shx147065 cmn_err(CE_NOTE, "%d: %x\n", j,
20893737Shx147065 *((uint8_t *)&sctbl + j));
20903737Shx147065 }
20913737Shx147065 #endif
20923737Shx147065
20933737Shx147065 off += (szbuf << 1);
20943737Shx147065 stat = min(sctbl.wl_srt_ssidlen, 31);
20953737Shx147065 PCWL_SWAP16((uint16_t *)(sctbl.wl_srt_bssid), 6);
20963737Shx147065 PCWL_SWAP16((uint16_t *)(sctbl.wl_srt_ssid), stat);
20973737Shx147065 sctbl.wl_srt_ssid[stat] = '\0';
20983737Shx147065 sctbl.wl_srt_sl &= 0x7f;
20993737Shx147065
21003737Shx147065 /*
21013737Shx147065 * sometimes, those empty items are recorded by hardware,
21023737Shx147065 * this is wrong, just ignore those items here.
21033737Shx147065 */
21043737Shx147065 if (bcmp(sctbl.wl_srt_bssid,
21053737Shx147065 bssid_t, 6) == 0) {
21063737Shx147065 continue;
21073737Shx147065 }
21083737Shx147065 if (bcmp(sctbl.wl_srt_bssid,
21093737Shx147065 pcwl_p->pcwl_bssid, 6) == 0) {
21103737Shx147065 pcwl_p->pcwl_rssi = sctbl.wl_srt_sl;
21113737Shx147065 }
21123737Shx147065 /*
21133737Shx147065 * save/update the scan item in scanlist
21143737Shx147065 */
21153737Shx147065 mutex_enter(&pcwl_p->pcwl_scanlist_lock);
21163737Shx147065 check_num = 0;
21173737Shx147065 scan_item0 = list_head(&pcwl_p->pcwl_scan_list);
21183737Shx147065 if (scan_item0 == NULL) {
21193737Shx147065 if (pcwl_add_scan_item(pcwl_p, sctbl)
21203737Shx147065 != 0) {
21213737Shx147065 mutex_exit(&pcwl_p->pcwl_scanlist_lock);
21223737Shx147065 return;
21233737Shx147065 }
21243737Shx147065 }
21253737Shx147065 for (; scan_item0; ) {
21263737Shx147065 if (bcmp(sctbl.wl_srt_bssid,
21273737Shx147065 scan_item0->wl_val.wl_srt_bssid, 6) == 0) {
21283737Shx147065 scan_item0->wl_val = sctbl;
21293737Shx147065 scan_item0->wl_timeout = WL_SCAN_TIMEOUT_MAX;
21303737Shx147065 break;
21313737Shx147065 } else {
21323737Shx147065 check_num++;
21333737Shx147065 }
21343737Shx147065 scan_item0 = list_next(&pcwl_p->pcwl_scan_list,
21353737Shx147065 scan_item0);
21363737Shx147065 }
21373737Shx147065 if (check_num == pcwl_p->pcwl_scan_num) {
21383737Shx147065 if (pcwl_add_scan_item(pcwl_p, sctbl)
21393737Shx147065 != 0) {
21403737Shx147065 mutex_exit(&pcwl_p->pcwl_scanlist_lock);
21413737Shx147065 return;
21423737Shx147065 }
21433737Shx147065 }
21443737Shx147065 mutex_exit(&pcwl_p->pcwl_scanlist_lock);
21453737Shx147065 PCWLDBG((CE_NOTE, "pcwl ssid_scan: ssid%d = %s\n", i+1,
21463737Shx147065 sctbl.wl_srt_ssid));
21473737Shx147065 PCWLDBG((CE_NOTE, "pcwl ssid_scan: channel = %d\n",
21483737Shx147065 sctbl.wl_srt_chid));
21493737Shx147065 PCWLDBG((CE_NOTE, "pcwl ssid_scan: signal level= %d\n",
21503737Shx147065 sctbl.wl_srt_sl));
21513737Shx147065 PCWLDBG((CE_NOTE, "pcwl ssid_scan: noise level = %d\n",
21523737Shx147065 sctbl.wl_srt_anl));
21533737Shx147065 PCWLDBG((CE_NOTE, "pcwl ssid_scan: bssid%d ="
21543737Shx147065 " %x %x %x %x %x %x\n\n", i+1,
21553737Shx147065 sctbl.wl_srt_bssid[0],
21563737Shx147065 sctbl.wl_srt_bssid[1],
21573737Shx147065 sctbl.wl_srt_bssid[2],
21583737Shx147065 sctbl.wl_srt_bssid[3],
21593737Shx147065 sctbl.wl_srt_bssid[4],
21603737Shx147065 sctbl.wl_srt_bssid[5]));
21613737Shx147065 }
21623737Shx147065
21633737Shx147065 }
21643737Shx147065
21653737Shx147065 /*
21663737Shx147065 * delay in which the mutex is not hold.
21673737Shx147065 * assuming the mutex has already been hold.
21683737Shx147065 */
21693737Shx147065 static void
pcwl_delay(pcwl_maci_t * pcwl_p,clock_t microsecs)21703737Shx147065 pcwl_delay(pcwl_maci_t *pcwl_p, clock_t microsecs)
21713737Shx147065 {
21723737Shx147065 ASSERT(mutex_owned(&pcwl_p->pcwl_glock));
21733737Shx147065
21743737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
21753737Shx147065 delay(drv_usectohz(microsecs));
21763737Shx147065 mutex_enter(&pcwl_p->pcwl_glock);
21773737Shx147065 }
21783737Shx147065
21793737Shx147065 static int
pcwl_reset_backend(pcwl_maci_t * pcwl_p)21803737Shx147065 pcwl_reset_backend(pcwl_maci_t *pcwl_p)
21813737Shx147065 {
21823737Shx147065 uint16_t ret = 0;
21833737Shx147065
21843737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_INI, 0)) {
21853737Shx147065 return ((int)ret);
21863737Shx147065 }
21873737Shx147065
21883737Shx147065 pcwl_delay(pcwl_p, 100000); /* wait .1 sec */
21893737Shx147065
21903737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_INI, 0)) {
21913737Shx147065 return ((int)ret);
21923737Shx147065 }
21933737Shx147065 pcwl_delay(pcwl_p, 100000); /* wait .1 sec */
21943737Shx147065
21953737Shx147065 PCWL_DISABLE_INTR(pcwl_p);
21963737Shx147065 return (PCWL_SUCCESS);
21973737Shx147065 }
21983737Shx147065
21993737Shx147065
22003737Shx147065 /*
22013737Shx147065 * get card capability (WEP, default channel), setup broadcast, mac addresses
22023737Shx147065 */
22033737Shx147065 static int
pcwl_get_cap(pcwl_maci_t * pcwl_p)22043737Shx147065 pcwl_get_cap(pcwl_maci_t *pcwl_p)
22053737Shx147065 {
22063737Shx147065 uint16_t stat, ch_no;
22073737Shx147065 uint16_t buf[ETHERADDRL >> 1];
22083737Shx147065
22093737Shx147065 bzero(buf, ETHERADDRL);
22103737Shx147065 if (stat = pcwl_get_ltv(pcwl_p, 2, WL_RID_OWN_CHNL, &ch_no)) {
22113737Shx147065 cmn_err(CE_CONT, "pcwl get_cap: get def channel failed"
22123737Shx147065 " %x\n", stat);
22133737Shx147065 return ((int)stat);
22143737Shx147065 }
22153737Shx147065 if (stat = pcwl_get_ltv(pcwl_p, 2, WL_RID_WEP_AVAIL,
22163737Shx147065 &pcwl_p->pcwl_has_wep)) {
22173737Shx147065 cmn_err(CE_CONT, "pcwl get_cap: get WEP capability failed"
22183737Shx147065 " %x\n", stat);
22193737Shx147065 return ((int)stat);
22203737Shx147065 }
22213737Shx147065 if (stat = pcwl_get_ltv(pcwl_p, ETHERADDRL, WL_RID_MAC_NODE, buf)) {
22223737Shx147065 cmn_err(CE_CONT, "pcwl get_cap: get macaddr failed"
22233737Shx147065 " %x\n", stat);
22243737Shx147065 return ((int)stat);
22253737Shx147065 }
22263737Shx147065
22273737Shx147065 /*
22283737Shx147065 * don't assume m_xxx members are 16-bit aligned
22293737Shx147065 */
22303737Shx147065 PCWL_SWAP16(buf, ETHERADDRL);
22313737Shx147065 ether_copy(buf, pcwl_p->pcwl_mac_addr);
22323737Shx147065 return (PCWL_SUCCESS);
22333737Shx147065 }
22343737Shx147065
22353737Shx147065 static int
pcwl_init_nicmem(pcwl_maci_t * pcwl_p)22363737Shx147065 pcwl_init_nicmem(pcwl_maci_t *pcwl_p)
22373737Shx147065 {
22383737Shx147065 uint16_t ret, i;
22393737Shx147065 uint16_t rc;
22403737Shx147065
22413737Shx147065 for (i = 0; i < WL_XMT_BUF_NUM; i++) {
22423737Shx147065 ret = pcwl_alloc_nicmem(pcwl_p, PCWL_NICMEM_SZ, &rc);
22433737Shx147065 if (ret) {
22443737Shx147065 cmn_err(CE_WARN,
22453737Shx147065 "pcwl: alloc NIC Tx buf failed %x\n", ret);
22463737Shx147065 return (PCWL_FAIL);
22473737Shx147065 }
22483737Shx147065 pcwl_p->pcwl_txring.wl_tx_fids[i] = rc;
22493737Shx147065 pcwl_p->pcwl_txring.wl_tx_ring[i] = 0;
22503737Shx147065 PCWLDBG((CE_NOTE, "pcwl: alloc_nicmem_id[%d]=%x\n", i, rc));
22513737Shx147065 }
22523737Shx147065 pcwl_p->pcwl_txring.wl_tx_prod = pcwl_p->pcwl_txring.wl_tx_cons = 0;
22533737Shx147065
22543737Shx147065 ret = pcwl_alloc_nicmem(pcwl_p, PCWL_NICMEM_SZ, &pcwl_p->pcwl_mgmt_id);
22553737Shx147065 if (ret) {
22563737Shx147065 cmn_err(CE_WARN, "pcwl: alloc NIC Mgmt buf failed %x\n", ret);
22573737Shx147065 return (PCWL_FAIL);
22583737Shx147065 }
22593737Shx147065 PCWLDBG((CE_NOTE, "pcwl: alloc_nicmem mgmt_id=%x\n",
22603737Shx147065 pcwl_p->pcwl_mgmt_id));
22613737Shx147065 return (PCWL_SUCCESS);
22623737Shx147065 }
22633737Shx147065
22643737Shx147065 static int
pcwl_loaddef_rf(pcwl_maci_t * pcwl_p)22653737Shx147065 pcwl_loaddef_rf(pcwl_maci_t *pcwl_p)
22663737Shx147065 {
22673737Shx147065 pcwl_p->pcwl_rf.rf_max_datalen = WL_DEFAULT_DATALEN;
22683737Shx147065 pcwl_p->pcwl_rf.rf_create_ibss = WL_DEFAULT_CREATE_IBSS;
22693737Shx147065 pcwl_p->pcwl_rf.rf_porttype = WL_BSS_BSS;
22703737Shx147065 pcwl_p->pcwl_rf.rf_rts_thresh = WL_DEFAULT_RTS_THRESH;
22713737Shx147065 pcwl_p->pcwl_rf.rf_tx_rate = WL_TX_RATE_FIX_11M(pcwl_p);
22723737Shx147065 pcwl_p->pcwl_rf.rf_pm_enabled = WL_DEFAULT_PM_ENABLED;
22733737Shx147065 pcwl_p->pcwl_rf.rf_own_chnl = WL_DEFAULT_CHAN;
22743737Shx147065 (void) strcpy(pcwl_p->pcwl_rf.rf_own_ssid, "");
22753737Shx147065 (void) strcpy(pcwl_p->pcwl_rf.rf_desired_ssid, "");
22763737Shx147065 (void) strcpy(pcwl_p->pcwl_rf.rf_nodename, "");
22773737Shx147065 pcwl_p->pcwl_rf.rf_encryption = WL_NOENCRYPTION;
22783737Shx147065 pcwl_p->pcwl_rf.rf_authtype = WL_OPENSYSTEM;
22793737Shx147065 pcwl_p->pcwl_rf.rf_tx_crypt_key = WL_DEFAULT_TX_CRYPT_KEY;
22803737Shx147065 bzero((pcwl_p->pcwl_rf.rf_ckeys), sizeof (rf_ckey_t) * 4);
22813737Shx147065
22823737Shx147065 pcwl_p->pcwl_rf.rf_promiscuous = 0;
22833737Shx147065
22843737Shx147065 return (pcwl_config_rf(pcwl_p));
22853737Shx147065 }
22863737Shx147065
22873737Shx147065 static int
pcwl_config_rf(pcwl_maci_t * pcwl_p)22883737Shx147065 pcwl_config_rf(pcwl_maci_t *pcwl_p)
22893737Shx147065 {
22903737Shx147065 pcwl_rf_t *rf_p = &pcwl_p->pcwl_rf;
22913737Shx147065 uint16_t create_ibss, porttype;
22923737Shx147065
22933737Shx147065 /*
22943737Shx147065 * Lucent card:
22953737Shx147065 * 0 Join ESS or IBSS; 1 Join ESS or join/create IBSS
22963737Shx147065 * PrismII card:
22973737Shx147065 * 3 Join ESS or IBSS(do not create IBSS);
22983737Shx147065 * 1 Join ESS or join/create IBSS
22993737Shx147065 */
23003737Shx147065 create_ibss = rf_p->rf_create_ibss;
23013737Shx147065 if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) {
23023737Shx147065 if (rf_p->rf_create_ibss == 0)
23033737Shx147065 create_ibss = 3;
23043737Shx147065 }
23053737Shx147065 /*
23063737Shx147065 * Lucent card:
23073737Shx147065 * 1 BSS; 3 pseudo IBSS(only for test,not the 802.11 IBSS)
23083737Shx147065 * so porttype register should always be set to 1
23093737Shx147065 * PrismII card:
23103737Shx147065 * 0 IBSS; 1 BSS; 2 WDS; 3 pseudo IBSS; 6 hostAP
23113737Shx147065 */
23123737Shx147065 switch (pcwl_p->pcwl_chip_type) {
23133737Shx147065 case PCWL_CHIP_PRISMII:
23143737Shx147065 if (rf_p->rf_porttype == WL_BSS_BSS)
23153737Shx147065 porttype = 1;
23163737Shx147065 else if (rf_p->rf_porttype == WL_BSS_IBSS)
23173737Shx147065 porttype = 0;
23183737Shx147065 else
23193737Shx147065 porttype = 0;
23203737Shx147065 break;
23213737Shx147065 case PCWL_CHIP_LUCENT:
23223737Shx147065 default:
23233737Shx147065 porttype = 1;
23243737Shx147065 }
23253737Shx147065
23263737Shx147065
23273737Shx147065 FIL_LTV(pcwl_p, PCWL_MCBUF_LEN, WL_RID_MCAST, 0);
23283737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_PROMISC, 0);
23293737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_TICK_TIME, 0);
23303737Shx147065
23313737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_MAX_DATALEN, rf_p->rf_max_datalen);
23323737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_CREATE_IBSS, create_ibss);
23333737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_PORTTYPE, porttype);
23343737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_RTS_THRESH, rf_p->rf_rts_thresh);
23353737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_TX_RATE, rf_p->rf_tx_rate);
23363737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_SYSTEM_SCALE, rf_p->rf_system_scale);
23373737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_PM_ENABLED, rf_p->rf_pm_enabled);
23383737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_MAX_SLEEP, rf_p->rf_max_sleep);
23393737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_OWN_CHNL, rf_p->rf_own_chnl);
23403737Shx147065
23413737Shx147065 PUT_STR(pcwl_p, WL_RID_OWN_SSID, rf_p->rf_own_ssid);
23423737Shx147065 PUT_STR(pcwl_p, WL_RID_DESIRED_SSID, rf_p->rf_desired_ssid);
23433737Shx147065 PUT_STR(pcwl_p, WL_RID_NODENAME, rf_p->rf_nodename);
23443737Shx147065
23453737Shx147065 if (!pcwl_p->pcwl_has_wep)
23463737Shx147065 goto done;
23473737Shx147065
23483737Shx147065 switch (pcwl_p->pcwl_chip_type) {
23493737Shx147065 case PCWL_CHIP_PRISMII: {
23503737Shx147065 int i;
23513737Shx147065
23523737Shx147065 for (i = 0; i < 4; i++) {
23533737Shx147065 int k_len = strlen((char *)rf_p->rf_ckeys[i].ckey_dat);
23543737Shx147065 if (k_len == 0)
23553737Shx147065 continue;
23563737Shx147065 k_len = k_len > 5 ? 14 : 6;
23573737Shx147065 PUT_LTV(pcwl_p, k_len, WL_RID_CRYPT_KEY0_P2 + i,
23583737Shx147065 (uint16_t *)&rf_p->rf_ckeys[i].ckey_dat);
23593737Shx147065 }
23603737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_TX_CRYPT_KEY_P2,
23613737Shx147065 rf_p->rf_tx_crypt_key);
23623737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_AUTHTYPE_P2,
23633737Shx147065 rf_p->rf_authtype);
23643737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_ENCRYPTION_P2,
23653737Shx147065 rf_p->rf_encryption);
23663737Shx147065 if (pcwl_p->pcwl_rf.rf_promiscuous)
23673737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_PROMISC, 1);
23683737Shx147065 }
23693737Shx147065 break;
23703737Shx147065 case PCWL_CHIP_LUCENT:
23713737Shx147065 default:
23723737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_ENCRYPTION,
23733737Shx147065 rf_p->rf_encryption);
23743737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_AUTHTYPE_L,
23753737Shx147065 rf_p->rf_authtype);
23763737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_TX_CRYPT_KEY,
23773737Shx147065 rf_p->rf_tx_crypt_key);
23783737Shx147065 PUT_LTV(pcwl_p, sizeof (rf_p->rf_ckeys),
23793737Shx147065 WL_RID_DEFLT_CRYPT_KEYS,
23803737Shx147065 (uint16_t *)rf_p->rf_ckeys);
23813737Shx147065 break;
23823737Shx147065 }
23833737Shx147065 done:
23843737Shx147065 return (PCWL_SUCCESS);
23853737Shx147065 }
23863737Shx147065
23873737Shx147065 static void
pcwl_start_locked(pcwl_maci_t * pcwl_p)23883737Shx147065 pcwl_start_locked(pcwl_maci_t *pcwl_p)
23893737Shx147065 {
23903737Shx147065 pcwl_p->pcwl_flag |= PCWL_CARD_INTREN;
23913737Shx147065 PCWL_ENABLE_INTR(pcwl_p);
23923737Shx147065 }
23933737Shx147065
23943737Shx147065 static void
pcwl_stop_locked(pcwl_maci_t * pcwl_p)23953737Shx147065 pcwl_stop_locked(pcwl_maci_t *pcwl_p)
23963737Shx147065 {
23973737Shx147065 PCWL_DISABLE_INTR(pcwl_p);
23983737Shx147065 pcwl_p->pcwl_flag &= (~PCWL_CARD_INTREN);
23993737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX|WL_EV_RX|WL_EV_TX_EXC|
24003737Shx147065 WL_EV_ALLOC|WL_EV_INFO|WL_EV_INFO_DROP);
24013737Shx147065 PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX|WL_EV_RX|WL_EV_TX_EXC|
24023737Shx147065 WL_EV_ALLOC| WL_EV_INFO|WL_EV_INFO_DROP);
24033737Shx147065 }
24043737Shx147065
24053737Shx147065 /*ARGSUSED*/
24063737Shx147065 static int
pcwl_saddr_locked(pcwl_maci_t * pcwl_p)24073737Shx147065 pcwl_saddr_locked(pcwl_maci_t *pcwl_p)
24083737Shx147065 {
24093737Shx147065 int ret;
24103737Shx147065 uint16_t buf[ETHERADDRL >> 1];
24113737Shx147065
24123737Shx147065 ether_copy(pcwl_p->pcwl_mac_addr, buf);
24133737Shx147065 PCWL_SWAP16(buf, ETHERADDRL);
24143737Shx147065 ret = pcwl_put_ltv(pcwl_p, ETHERADDRL, WL_RID_MAC_NODE, buf);
24153737Shx147065 if (ret) {
24163737Shx147065 cmn_err(CE_WARN, "pcwl set_mac_addr: failed %x\n", ret);
24173737Shx147065 return (PCWL_FAIL);
24183737Shx147065 }
24193737Shx147065 return (PCWL_SUCCESS);
24203737Shx147065 }
24213737Shx147065
24223737Shx147065 static void
pcwl_chip_type(pcwl_maci_t * pcwl_p)24233737Shx147065 pcwl_chip_type(pcwl_maci_t *pcwl_p)
24243737Shx147065 {
24253737Shx147065 pcwl_ltv_ver_t ver;
24263737Shx147065 pcwl_ltv_fwver_t f;
24273737Shx147065
24283737Shx147065 bzero(&ver, sizeof (ver));
24293737Shx147065 (void) pcwl_get_ltv(pcwl_p, sizeof (ver),
24303737Shx147065 WL_RID_CARD_ID, (uint16_t *)&ver);
24313737Shx147065 PCWLDBG((CE_NOTE, "card id:%04x-%04x-%04x-%04x\n",
24323737Shx147065 ver.wl_compid, ver.wl_variant, ver.wl_major, ver.wl_minor));
24333737Shx147065 if ((ver.wl_compid & 0xf000) != 0x8000)
24343737Shx147065 return; /* lucent */
24353737Shx147065
24363737Shx147065 pcwl_p->pcwl_chip_type = PCWL_CHIP_PRISMII;
24373737Shx147065 (void) pcwl_get_ltv(pcwl_p, sizeof (ver), WL_RID_COMP_IDENT,
24383737Shx147065 (uint16_t *)&ver);
24393737Shx147065 PCWLDBG((CE_NOTE, "PRISM-II ver:%04x-%04x-%04x-%04x\n",
24403737Shx147065 ver.wl_compid, ver.wl_variant, ver.wl_major, ver.wl_minor));
24413737Shx147065
24423737Shx147065 bzero(&f, sizeof (f));
24433737Shx147065 (void) pcwl_get_ltv(pcwl_p, sizeof (f), WL_RID_FWVER, (uint16_t *)&f);
24443737Shx147065 PCWL_SWAP16((uint16_t *)&f, sizeof (f));
24453737Shx147065 PCWLDBG((CE_NOTE, "Firmware Pri:%s 2,3:%s\n",
24463737Shx147065 (char *)f.pri, (char *)f.st));
24473737Shx147065 }
24483737Shx147065
24493737Shx147065 /*
24508410SWang.Lin@Sun.COM * Brussels support
24518410SWang.Lin@Sun.COM */
24528410SWang.Lin@Sun.COM /*
24538410SWang.Lin@Sun.COM * MAC_PROP_WL_ESSID
24548410SWang.Lin@Sun.COM */
24558410SWang.Lin@Sun.COM static int
pcwl_set_essid(pcwl_maci_t * pcwl_p,const void * wldp_buf)24568410SWang.Lin@Sun.COM pcwl_set_essid(pcwl_maci_t *pcwl_p, const void *wldp_buf)
24578410SWang.Lin@Sun.COM {
24588410SWang.Lin@Sun.COM char *value;
24598410SWang.Lin@Sun.COM pcwl_rf_t *rf_p;
24608410SWang.Lin@Sun.COM wl_essid_t *iw_essid = (wl_essid_t *)wldp_buf;
24618410SWang.Lin@Sun.COM
24628410SWang.Lin@Sun.COM rf_p = &pcwl_p->pcwl_rf;
24638410SWang.Lin@Sun.COM
24648410SWang.Lin@Sun.COM value = iw_essid->wl_essid_essid;
24658410SWang.Lin@Sun.COM (void) strncpy(rf_p->rf_desired_ssid, value,
24668410SWang.Lin@Sun.COM MIN(32, strlen(value)));
24678410SWang.Lin@Sun.COM rf_p->rf_desired_ssid[strlen(value)] = '\0';
24688410SWang.Lin@Sun.COM (void) strncpy(rf_p->rf_own_ssid, value,
24698410SWang.Lin@Sun.COM MIN(32, strlen(value)));
24708410SWang.Lin@Sun.COM rf_p->rf_own_ssid[strlen(value)] = '\0';
24718410SWang.Lin@Sun.COM
24728410SWang.Lin@Sun.COM PCWLDBG((CE_CONT, "pcwl: set: desired essid=%s\n",
24738410SWang.Lin@Sun.COM rf_p->rf_desired_ssid));
24748410SWang.Lin@Sun.COM
24758410SWang.Lin@Sun.COM return (ENETRESET);
24768410SWang.Lin@Sun.COM
24778410SWang.Lin@Sun.COM }
24788410SWang.Lin@Sun.COM
24798410SWang.Lin@Sun.COM static int
pcwl_get_essid(pcwl_maci_t * pcwl_p,void * wldp_buf)24808410SWang.Lin@Sun.COM pcwl_get_essid(pcwl_maci_t *pcwl_p, void *wldp_buf)
24818410SWang.Lin@Sun.COM {
24828410SWang.Lin@Sun.COM char ssid[36];
24838410SWang.Lin@Sun.COM uint16_t ret;
24848410SWang.Lin@Sun.COM uint16_t val;
24858410SWang.Lin@Sun.COM int len;
24868410SWang.Lin@Sun.COM int err = 0;
24878410SWang.Lin@Sun.COM wl_essid_t ow_essid;
24888410SWang.Lin@Sun.COM pcwl_rf_t *rf_p;
24898410SWang.Lin@Sun.COM
24908410SWang.Lin@Sun.COM rf_p = &pcwl_p->pcwl_rf;
24918410SWang.Lin@Sun.COM bzero(&ow_essid, sizeof (wl_essid_t));
24928410SWang.Lin@Sun.COM bzero(ssid, sizeof (ssid));
24938410SWang.Lin@Sun.COM
24948410SWang.Lin@Sun.COM ret = pcwl_get_ltv(pcwl_p, 2, WL_RID_PORTSTATUS, &val);
24958410SWang.Lin@Sun.COM if (ret) {
24968410SWang.Lin@Sun.COM err = EIO;
24978410SWang.Lin@Sun.COM return (err);
24988410SWang.Lin@Sun.COM }
24998410SWang.Lin@Sun.COM PCWLDBG((CE_NOTE, "PortStatus = %d\n", val));
25008410SWang.Lin@Sun.COM
25018410SWang.Lin@Sun.COM switch (val) {
25028410SWang.Lin@Sun.COM case WL_PORT_DISABLED:
25038410SWang.Lin@Sun.COM case WL_PORT_INITIAL:
25048410SWang.Lin@Sun.COM len = mi_strlen(rf_p->rf_desired_ssid);
25058410SWang.Lin@Sun.COM ow_essid.wl_essid_length = len;
25068410SWang.Lin@Sun.COM bcopy(rf_p->rf_desired_ssid, ow_essid.wl_essid_essid,
25078410SWang.Lin@Sun.COM len);
25088410SWang.Lin@Sun.COM break;
25098410SWang.Lin@Sun.COM case WL_PORT_TO_IBSS:
25108410SWang.Lin@Sun.COM case WL_PORT_TO_BSS:
25118410SWang.Lin@Sun.COM case WL_PORT_OOR:
25128410SWang.Lin@Sun.COM (void) pcwl_get_ltv((pcwl_p), 34, WL_RID_SSID,
25138410SWang.Lin@Sun.COM (uint16_t *)ssid);
25148410SWang.Lin@Sun.COM PCWL_SWAP16((uint16_t *)(ssid+2), *(uint16_t *)ssid);
25158410SWang.Lin@Sun.COM ssid[*(uint16_t *)ssid + 2] = '\0';
25168410SWang.Lin@Sun.COM len = mi_strlen(ssid+2);
25178410SWang.Lin@Sun.COM ow_essid.wl_essid_length = len;
25188410SWang.Lin@Sun.COM bcopy(ssid + 2, ow_essid.wl_essid_essid, len);
25198410SWang.Lin@Sun.COM break;
25208410SWang.Lin@Sun.COM default:
25218410SWang.Lin@Sun.COM err = EINVAL;
25228410SWang.Lin@Sun.COM break;
25238410SWang.Lin@Sun.COM }
25248410SWang.Lin@Sun.COM
25258410SWang.Lin@Sun.COM bcopy(&ow_essid, wldp_buf, sizeof (wl_essid_t));
25268410SWang.Lin@Sun.COM
25278410SWang.Lin@Sun.COM return (err);
25288410SWang.Lin@Sun.COM }
25298410SWang.Lin@Sun.COM
25308410SWang.Lin@Sun.COM /*
25318410SWang.Lin@Sun.COM * MAC_PROP_WL_BSSID
25328410SWang.Lin@Sun.COM */
25338410SWang.Lin@Sun.COM static int
pcwl_get_bssid(pcwl_maci_t * pcwl_p,void * wldp_buf)25348410SWang.Lin@Sun.COM pcwl_get_bssid(pcwl_maci_t *pcwl_p, void *wldp_buf)
25358410SWang.Lin@Sun.COM {
25368410SWang.Lin@Sun.COM uint16_t ret;
25378410SWang.Lin@Sun.COM uint16_t retval;
25388410SWang.Lin@Sun.COM uint8_t bssid[6];
25398410SWang.Lin@Sun.COM int err = 0;
25408410SWang.Lin@Sun.COM
25418410SWang.Lin@Sun.COM if (ret = pcwl_get_ltv(pcwl_p, 2, WL_RID_PORTSTATUS, &retval)) {
25428410SWang.Lin@Sun.COM err = EIO;
25438410SWang.Lin@Sun.COM return (err);
25448410SWang.Lin@Sun.COM }
25458410SWang.Lin@Sun.COM
25468410SWang.Lin@Sun.COM PCWLDBG((CE_NOTE, "PortStatus = %d\n", ret));
25478410SWang.Lin@Sun.COM
25488410SWang.Lin@Sun.COM if (retval == WL_PORT_DISABLED || retval == WL_PORT_INITIAL) {
25498410SWang.Lin@Sun.COM bzero(wldp_buf, sizeof (wl_bssid_t));
25508410SWang.Lin@Sun.COM } else if (retval == WL_PORT_TO_IBSS ||
25518410SWang.Lin@Sun.COM retval == WL_PORT_TO_BSS || retval == WL_PORT_OOR) {
25528410SWang.Lin@Sun.COM (void) pcwl_get_ltv(pcwl_p, 6,
25538410SWang.Lin@Sun.COM WL_RID_BSSID, (uint16_t *)bssid);
25548410SWang.Lin@Sun.COM PCWL_SWAP16((uint16_t *)bssid, 6);
25558410SWang.Lin@Sun.COM bcopy(bssid, wldp_buf, sizeof (wl_bssid_t));
25568410SWang.Lin@Sun.COM }
25578410SWang.Lin@Sun.COM
25588410SWang.Lin@Sun.COM PCWLDBG((CE_CONT, "pcwl_get_bssid: bssid=%x %x %x %x %x %x\n",
25598410SWang.Lin@Sun.COM bssid[0], bssid[1], bssid[2],
25608410SWang.Lin@Sun.COM bssid[3], bssid[4], bssid[5]));
25618410SWang.Lin@Sun.COM
25628410SWang.Lin@Sun.COM return (err);
25638410SWang.Lin@Sun.COM }
25648410SWang.Lin@Sun.COM
25658410SWang.Lin@Sun.COM /*
25668410SWang.Lin@Sun.COM * MAC_PROP_WL_LINKSTATUS
25678410SWang.Lin@Sun.COM */
25688410SWang.Lin@Sun.COM static int
pcwl_get_linkstatus(pcwl_maci_t * pcwl_p,void * wldp_buf)25698410SWang.Lin@Sun.COM pcwl_get_linkstatus(pcwl_maci_t *pcwl_p, void *wldp_buf)
25708410SWang.Lin@Sun.COM {
25718410SWang.Lin@Sun.COM uint16_t ret;
25728410SWang.Lin@Sun.COM uint16_t retval;
25738410SWang.Lin@Sun.COM int err = 0;
25748410SWang.Lin@Sun.COM
25758410SWang.Lin@Sun.COM ret = pcwl_get_ltv(pcwl_p, 2, WL_RID_PORTSTATUS, &retval);
25768410SWang.Lin@Sun.COM if (ret) {
25778410SWang.Lin@Sun.COM err = EIO;
25788410SWang.Lin@Sun.COM PCWLDBG((CE_WARN, "cfg_linkstatus_get_error\n"));
25798410SWang.Lin@Sun.COM return (err);
25808410SWang.Lin@Sun.COM }
25818410SWang.Lin@Sun.COM PCWLDBG((CE_NOTE, "PortStatus = %d\n", retval));
25828410SWang.Lin@Sun.COM
25838410SWang.Lin@Sun.COM switch (retval) {
25848410SWang.Lin@Sun.COM case WL_PORT_DISABLED:
25858410SWang.Lin@Sun.COM case WL_PORT_INITIAL:
25868410SWang.Lin@Sun.COM *(wl_linkstatus_t *)wldp_buf = WL_NOTCONNECTED;
25878410SWang.Lin@Sun.COM break;
25888410SWang.Lin@Sun.COM case WL_PORT_TO_IBSS:
25898410SWang.Lin@Sun.COM case WL_PORT_TO_BSS:
25908410SWang.Lin@Sun.COM case WL_PORT_OOR:
25918410SWang.Lin@Sun.COM *(wl_linkstatus_t *)wldp_buf = WL_CONNECTED;
25928410SWang.Lin@Sun.COM break;
25938410SWang.Lin@Sun.COM default:
25948410SWang.Lin@Sun.COM err = EINVAL;
25958410SWang.Lin@Sun.COM break;
25968410SWang.Lin@Sun.COM }
25978410SWang.Lin@Sun.COM
25988410SWang.Lin@Sun.COM return (err);
25998410SWang.Lin@Sun.COM }
26008410SWang.Lin@Sun.COM
26018410SWang.Lin@Sun.COM /*
26028410SWang.Lin@Sun.COM * MAC_PROP_WL_BSSTYP
26038410SWang.Lin@Sun.COM */
26048410SWang.Lin@Sun.COM static int
pcwl_set_bsstype(pcwl_maci_t * pcwl_p,const void * wldp_buf)26058410SWang.Lin@Sun.COM pcwl_set_bsstype(pcwl_maci_t *pcwl_p, const void *wldp_buf)
26068410SWang.Lin@Sun.COM {
26078410SWang.Lin@Sun.COM uint16_t ret;
26088410SWang.Lin@Sun.COM pcwl_rf_t *rf_p;
26098410SWang.Lin@Sun.COM int err = ENETRESET;
26108410SWang.Lin@Sun.COM
26118410SWang.Lin@Sun.COM rf_p = &pcwl_p->pcwl_rf;
26128410SWang.Lin@Sun.COM
26138410SWang.Lin@Sun.COM ret = (uint16_t)(*(wl_bss_type_t *)wldp_buf);
26148410SWang.Lin@Sun.COM if ((ret != WL_BSS_BSS) &&
26158410SWang.Lin@Sun.COM (ret != WL_BSS_IBSS) &&
26168410SWang.Lin@Sun.COM (ret != WL_BSS_ANY)) {
26178410SWang.Lin@Sun.COM err = ENOTSUP;
26188410SWang.Lin@Sun.COM return (err);
26198410SWang.Lin@Sun.COM }
26208410SWang.Lin@Sun.COM
26218410SWang.Lin@Sun.COM rf_p->rf_porttype = ret;
26228410SWang.Lin@Sun.COM
26238410SWang.Lin@Sun.COM return (err);
26248410SWang.Lin@Sun.COM }
26258410SWang.Lin@Sun.COM
26268410SWang.Lin@Sun.COM static void
pcwl_get_bsstype(pcwl_maci_t * pcwl_p,void * wldp_buf)26278410SWang.Lin@Sun.COM pcwl_get_bsstype(pcwl_maci_t *pcwl_p, void *wldp_buf)
26288410SWang.Lin@Sun.COM {
26298410SWang.Lin@Sun.COM pcwl_rf_t *rf_p;
26308410SWang.Lin@Sun.COM
26318410SWang.Lin@Sun.COM rf_p = &pcwl_p->pcwl_rf;
26328410SWang.Lin@Sun.COM
26338410SWang.Lin@Sun.COM *(wl_bss_type_t *)wldp_buf = rf_p->rf_porttype;
26348410SWang.Lin@Sun.COM
26358410SWang.Lin@Sun.COM PCWLDBG((CE_CONT, "pcwl_get_bsstype: porttype=%d\n",
26368410SWang.Lin@Sun.COM rf_p->rf_porttype));
26378410SWang.Lin@Sun.COM }
26388410SWang.Lin@Sun.COM
26398410SWang.Lin@Sun.COM /*
26408410SWang.Lin@Sun.COM * MAC_PROP_WL_PHY_CONFIG
26418410SWang.Lin@Sun.COM */
26428410SWang.Lin@Sun.COM static int
pcwl_set_phy(pcwl_maci_t * pcwl_p,const void * wldp_buf)26438410SWang.Lin@Sun.COM pcwl_set_phy(pcwl_maci_t *pcwl_p, const void *wldp_buf)
26448410SWang.Lin@Sun.COM {
26458410SWang.Lin@Sun.COM uint16_t ret;
26468410SWang.Lin@Sun.COM pcwl_rf_t *rf_p;
26478410SWang.Lin@Sun.COM int err = ENETRESET;
26488410SWang.Lin@Sun.COM wl_phy_conf_t *phy = (wl_phy_conf_t *)wldp_buf;
26498410SWang.Lin@Sun.COM
26508410SWang.Lin@Sun.COM rf_p = &pcwl_p->pcwl_rf;
26518410SWang.Lin@Sun.COM ret = (uint16_t)(phy->wl_phy_dsss_conf.wl_dsss_channel);
26528410SWang.Lin@Sun.COM if (ret < 1 || ret > 14) {
26538410SWang.Lin@Sun.COM err = ENOTSUP;
26548410SWang.Lin@Sun.COM return (err);
26558410SWang.Lin@Sun.COM }
26568410SWang.Lin@Sun.COM
26578410SWang.Lin@Sun.COM rf_p->rf_own_chnl = ret;
26588410SWang.Lin@Sun.COM
26598410SWang.Lin@Sun.COM PCWLDBG((CE_CONT, "pcwl: set channel=%d\n", rf_p->rf_own_chnl));
26608410SWang.Lin@Sun.COM
26618410SWang.Lin@Sun.COM return (err);
26628410SWang.Lin@Sun.COM }
26638410SWang.Lin@Sun.COM
26648410SWang.Lin@Sun.COM static int
pcwl_get_phy(pcwl_maci_t * pcwl_p,void * wldp_buf)26658410SWang.Lin@Sun.COM pcwl_get_phy(pcwl_maci_t *pcwl_p, void *wldp_buf)
26668410SWang.Lin@Sun.COM {
26678410SWang.Lin@Sun.COM uint16_t retval;
26688410SWang.Lin@Sun.COM wl_dsss_t *dsss = (wl_dsss_t *)wldp_buf;
26698410SWang.Lin@Sun.COM int err = 0;
26708410SWang.Lin@Sun.COM
26718410SWang.Lin@Sun.COM if (pcwl_get_ltv(pcwl_p, 2, WL_RID_CURRENT_CHNL, &retval)) {
26728410SWang.Lin@Sun.COM err = EIO;
26738410SWang.Lin@Sun.COM return (err);
26748410SWang.Lin@Sun.COM }
26758410SWang.Lin@Sun.COM
26768410SWang.Lin@Sun.COM dsss->wl_dsss_channel = retval;
26778410SWang.Lin@Sun.COM PCWLDBG((CE_CONT, "pcwl_get_phy: channel=%d\n", retval));
26788410SWang.Lin@Sun.COM dsss->wl_dsss_subtype = WL_DSSS;
26798410SWang.Lin@Sun.COM
26808410SWang.Lin@Sun.COM return (err);
26818410SWang.Lin@Sun.COM }
26828410SWang.Lin@Sun.COM
26838410SWang.Lin@Sun.COM /*
26848410SWang.Lin@Sun.COM * MAC_PROP_WL_DESIRED_RATESa
26858410SWang.Lin@Sun.COM */
26868410SWang.Lin@Sun.COM static int
pcwl_set_desrates(pcwl_maci_t * pcwl_p,const void * wldp_buf)26878410SWang.Lin@Sun.COM pcwl_set_desrates(pcwl_maci_t *pcwl_p, const void *wldp_buf)
26888410SWang.Lin@Sun.COM {
26898410SWang.Lin@Sun.COM int err = ENETRESET;
26908410SWang.Lin@Sun.COM char rates[4];
26918410SWang.Lin@Sun.COM char maxrate;
26928410SWang.Lin@Sun.COM uint16_t i;
26938410SWang.Lin@Sun.COM pcwl_rf_t *rf_p;
26948410SWang.Lin@Sun.COM wl_rates_t *iw_rates = (wl_rates_t *)wldp_buf;
26958410SWang.Lin@Sun.COM
26968410SWang.Lin@Sun.COM rf_p = &pcwl_p->pcwl_rf;
26978410SWang.Lin@Sun.COM
26988410SWang.Lin@Sun.COM bzero(rates, sizeof (rates));
26998410SWang.Lin@Sun.COM
27008410SWang.Lin@Sun.COM for (i = 0; i < 4; i++) {
27018410SWang.Lin@Sun.COM rates[i] = iw_rates->wl_rates_rates[i];
27028410SWang.Lin@Sun.COM PCWLDBG((CE_CONT, "pcwl: set tx_rate[%d]=%d\n", i, rates[i]));
27038410SWang.Lin@Sun.COM }
27048410SWang.Lin@Sun.COM PCWLDBG((CE_CONT, "pcwl: set rate_num=%d\n", iw_rates->wl_rates_num));
27058410SWang.Lin@Sun.COM
27068410SWang.Lin@Sun.COM switch (iw_rates->wl_rates_num) {
27078410SWang.Lin@Sun.COM case 1:
27088410SWang.Lin@Sun.COM switch (rates[0]) {
27098410SWang.Lin@Sun.COM case WL_RATE_1M:
27108410SWang.Lin@Sun.COM rf_p->rf_tx_rate = WL_TX_RATE_FIX_1M(pcwl_p);
27118410SWang.Lin@Sun.COM break;
27128410SWang.Lin@Sun.COM case WL_RATE_2M:
27138410SWang.Lin@Sun.COM rf_p->rf_tx_rate = WL_TX_RATE_FIX_2M(pcwl_p);
27148410SWang.Lin@Sun.COM break;
27158410SWang.Lin@Sun.COM case WL_RATE_11M:
27168410SWang.Lin@Sun.COM rf_p->rf_tx_rate = WL_TX_RATE_FIX_11M(pcwl_p);
27178410SWang.Lin@Sun.COM break;
27188410SWang.Lin@Sun.COM case WL_RATE_5_5M:
27198410SWang.Lin@Sun.COM rf_p->rf_tx_rate = WL_TX_RATE_FIX_5M(pcwl_p);
27208410SWang.Lin@Sun.COM break;
27218410SWang.Lin@Sun.COM default:
27228410SWang.Lin@Sun.COM err = EINVAL;
27238410SWang.Lin@Sun.COM break;
27248410SWang.Lin@Sun.COM }
27258410SWang.Lin@Sun.COM break;
27268410SWang.Lin@Sun.COM case 2:
27278410SWang.Lin@Sun.COM maxrate = (rates[0] > rates[1] ? rates[0] : rates[1]);
27288410SWang.Lin@Sun.COM switch (maxrate) {
27298410SWang.Lin@Sun.COM case WL_RATE_2M:
27308410SWang.Lin@Sun.COM rf_p->rf_tx_rate = WL_TX_RATE_AUTO_L(pcwl_p);
27318410SWang.Lin@Sun.COM break;
27328410SWang.Lin@Sun.COM case WL_RATE_11M:
27338410SWang.Lin@Sun.COM rf_p->rf_tx_rate = WL_TX_RATE_AUTO_H(pcwl_p);
27348410SWang.Lin@Sun.COM break;
27358410SWang.Lin@Sun.COM case WL_RATE_5_5M:
27368410SWang.Lin@Sun.COM rf_p->rf_tx_rate = WL_TX_RATE_AUTO_M(pcwl_p);
27378410SWang.Lin@Sun.COM break;
27388410SWang.Lin@Sun.COM default:
27398410SWang.Lin@Sun.COM err = EINVAL;
27408410SWang.Lin@Sun.COM break;
27418410SWang.Lin@Sun.COM }
27428410SWang.Lin@Sun.COM break;
27438410SWang.Lin@Sun.COM case 3:
27448410SWang.Lin@Sun.COM maxrate = (rates[0] > rates[1] ? rates[0] : rates[1]);
27458410SWang.Lin@Sun.COM maxrate = (rates[2] > maxrate ? rates[2] : maxrate);
27468410SWang.Lin@Sun.COM switch (maxrate) {
27478410SWang.Lin@Sun.COM case WL_RATE_11M:
27488410SWang.Lin@Sun.COM rf_p->rf_tx_rate = WL_TX_RATE_AUTO_H(pcwl_p);
27498410SWang.Lin@Sun.COM break;
27508410SWang.Lin@Sun.COM case WL_RATE_5_5M:
27518410SWang.Lin@Sun.COM rf_p->rf_tx_rate = WL_TX_RATE_AUTO_M(pcwl_p);
27528410SWang.Lin@Sun.COM break;
27538410SWang.Lin@Sun.COM default:
27548410SWang.Lin@Sun.COM err = EINVAL;
27558410SWang.Lin@Sun.COM break;
27568410SWang.Lin@Sun.COM }
27578410SWang.Lin@Sun.COM break;
27588410SWang.Lin@Sun.COM case 4:
27598410SWang.Lin@Sun.COM rf_p->rf_tx_rate = WL_TX_RATE_AUTO_H(pcwl_p);
27608410SWang.Lin@Sun.COM break;
27618410SWang.Lin@Sun.COM default:
27628410SWang.Lin@Sun.COM err = ENOTSUP;
27638410SWang.Lin@Sun.COM break;
27648410SWang.Lin@Sun.COM }
27658410SWang.Lin@Sun.COM PCWLDBG((CE_CONT, "pcwl: set tx_rate=%d\n", rf_p->rf_tx_rate));
27668410SWang.Lin@Sun.COM
27678410SWang.Lin@Sun.COM return (err);
27688410SWang.Lin@Sun.COM }
27698410SWang.Lin@Sun.COM
27708410SWang.Lin@Sun.COM static int
pcwl_get_desrates(pcwl_maci_t * pcwl_p,void * wldp_buf)27718410SWang.Lin@Sun.COM pcwl_get_desrates(pcwl_maci_t *pcwl_p, void *wldp_buf)
27728410SWang.Lin@Sun.COM {
27738410SWang.Lin@Sun.COM uint16_t rate;
27748410SWang.Lin@Sun.COM int err = 0;
27758410SWang.Lin@Sun.COM
27768410SWang.Lin@Sun.COM if (pcwl_get_ltv(pcwl_p, 2, WL_RID_TX_RATE, &rate)) {
27778410SWang.Lin@Sun.COM err = EIO;
27788410SWang.Lin@Sun.COM return (err);
27798410SWang.Lin@Sun.COM }
27808410SWang.Lin@Sun.COM
27818410SWang.Lin@Sun.COM if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) {
27828410SWang.Lin@Sun.COM ((wl_rates_t *)wldp_buf)->wl_rates_num = 1;
27838410SWang.Lin@Sun.COM switch (rate) {
27848410SWang.Lin@Sun.COM case WL_SPEED_1Mbps_P2:
27858410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
27868410SWang.Lin@Sun.COM WL_RATE_1M;
27878410SWang.Lin@Sun.COM break;
27888410SWang.Lin@Sun.COM case WL_SPEED_2Mbps_P2:
27898410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
27908410SWang.Lin@Sun.COM WL_RATE_2M;
27918410SWang.Lin@Sun.COM break;
27928410SWang.Lin@Sun.COM case WL_SPEED_55Mbps_P2:
27938410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
27948410SWang.Lin@Sun.COM WL_RATE_5_5M;
27958410SWang.Lin@Sun.COM break;
27968410SWang.Lin@Sun.COM case WL_SPEED_11Mbps_P2:
27978410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
27988410SWang.Lin@Sun.COM WL_RATE_11M;
27998410SWang.Lin@Sun.COM break;
28008410SWang.Lin@Sun.COM default:
28018410SWang.Lin@Sun.COM err = EINVAL;
28028410SWang.Lin@Sun.COM break;
28038410SWang.Lin@Sun.COM }
28048410SWang.Lin@Sun.COM } else {
28058410SWang.Lin@Sun.COM switch (rate) {
28068410SWang.Lin@Sun.COM case WL_L_TX_RATE_FIX_1M:
28078410SWang.Lin@Sun.COM ((wl_rates_t *)wldp_buf)->wl_rates_num = 1;
28088410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
28098410SWang.Lin@Sun.COM WL_RATE_1M;
28108410SWang.Lin@Sun.COM break;
28118410SWang.Lin@Sun.COM case WL_L_TX_RATE_FIX_2M:
28128410SWang.Lin@Sun.COM ((wl_rates_t *)wldp_buf)->wl_rates_num = 1;
28138410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
28148410SWang.Lin@Sun.COM WL_RATE_2M;
28158410SWang.Lin@Sun.COM break;
28168410SWang.Lin@Sun.COM case WL_L_TX_RATE_AUTO_H:
28178410SWang.Lin@Sun.COM ((wl_rates_t *)wldp_buf)->wl_rates_num = 4;
28188410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
28198410SWang.Lin@Sun.COM WL_RATE_1M;
28208410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[1] =
28218410SWang.Lin@Sun.COM WL_RATE_2M;
28228410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[2] =
28238410SWang.Lin@Sun.COM WL_RATE_5_5M;
28248410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[3] =
28258410SWang.Lin@Sun.COM WL_RATE_11M;
28268410SWang.Lin@Sun.COM break;
28278410SWang.Lin@Sun.COM case WL_L_TX_RATE_FIX_5M:
28288410SWang.Lin@Sun.COM ((wl_rates_t *)wldp_buf)->wl_rates_num = 1;
28298410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
28308410SWang.Lin@Sun.COM WL_RATE_5_5M;
28318410SWang.Lin@Sun.COM break;
28328410SWang.Lin@Sun.COM case WL_L_TX_RATE_FIX_11M:
28338410SWang.Lin@Sun.COM ((wl_rates_t *)wldp_buf)->wl_rates_num = 1;
28348410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
28358410SWang.Lin@Sun.COM WL_RATE_11M;
28368410SWang.Lin@Sun.COM break;
28378410SWang.Lin@Sun.COM case WL_L_TX_RATE_AUTO_L:
28388410SWang.Lin@Sun.COM ((wl_rates_t *)wldp_buf)->wl_rates_num = 2;
28398410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
28408410SWang.Lin@Sun.COM WL_RATE_1M;
28418410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[1] =
28428410SWang.Lin@Sun.COM WL_RATE_2M;
28438410SWang.Lin@Sun.COM break;
28448410SWang.Lin@Sun.COM case WL_L_TX_RATE_AUTO_M:
28458410SWang.Lin@Sun.COM ((wl_rates_t *)wldp_buf)->wl_rates_num = 3;
28468410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
28478410SWang.Lin@Sun.COM WL_RATE_1M;
28488410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[1] =
28498410SWang.Lin@Sun.COM WL_RATE_2M;
28508410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[2] =
28518410SWang.Lin@Sun.COM WL_RATE_5_5M;
28528410SWang.Lin@Sun.COM break;
28538410SWang.Lin@Sun.COM default:
28548410SWang.Lin@Sun.COM err = EINVAL;
28558410SWang.Lin@Sun.COM break;
28568410SWang.Lin@Sun.COM }
28578410SWang.Lin@Sun.COM }
28588410SWang.Lin@Sun.COM PCWLDBG((CE_CONT, "pcwl: get rate=%d\n", rate));
28598410SWang.Lin@Sun.COM
28608410SWang.Lin@Sun.COM return (err);
28618410SWang.Lin@Sun.COM }
28628410SWang.Lin@Sun.COM
28638410SWang.Lin@Sun.COM /*
28648410SWang.Lin@Sun.COM * MAC_PROP_WL_SUP_RATE
28658410SWang.Lin@Sun.COM */
28668410SWang.Lin@Sun.COM static void
pcwl_get_suprates(void * wldp_buf)28678410SWang.Lin@Sun.COM pcwl_get_suprates(void *wldp_buf)
28688410SWang.Lin@Sun.COM {
28698410SWang.Lin@Sun.COM wl_rates_t *wl_rates = (wl_rates_t *)wldp_buf;
28708410SWang.Lin@Sun.COM
28718410SWang.Lin@Sun.COM wl_rates->wl_rates_num = 4;
28728410SWang.Lin@Sun.COM wl_rates->wl_rates_rates[0] = WL_RATE_1M;
28738410SWang.Lin@Sun.COM wl_rates->wl_rates_rates[1] = WL_RATE_2M;
28748410SWang.Lin@Sun.COM wl_rates->wl_rates_rates[2] = WL_RATE_5_5M;
28758410SWang.Lin@Sun.COM wl_rates->wl_rates_rates[3] = WL_RATE_11M;
28768410SWang.Lin@Sun.COM }
28778410SWang.Lin@Sun.COM
28788410SWang.Lin@Sun.COM /*
28798410SWang.Lin@Sun.COM * MAC_PROP_WL_POWER_MODE
28808410SWang.Lin@Sun.COM */
28818410SWang.Lin@Sun.COM static int
pcwl_set_powermode(pcwl_maci_t * pcwl_p,const void * wldp_buf)28828410SWang.Lin@Sun.COM pcwl_set_powermode(pcwl_maci_t *pcwl_p, const void *wldp_buf)
28838410SWang.Lin@Sun.COM {
28848410SWang.Lin@Sun.COM uint16_t ret;
28858410SWang.Lin@Sun.COM pcwl_rf_t *rf_p;
28868410SWang.Lin@Sun.COM int err = 0;
28878410SWang.Lin@Sun.COM
28888410SWang.Lin@Sun.COM rf_p = &pcwl_p->pcwl_rf;
28898410SWang.Lin@Sun.COM
28908410SWang.Lin@Sun.COM ret = (uint16_t)(((wl_ps_mode_t *)wldp_buf)->wl_ps_mode);
28918410SWang.Lin@Sun.COM if (ret != WL_PM_AM && ret != WL_PM_MPS && ret != WL_PM_FAST) {
28928410SWang.Lin@Sun.COM err = ENOTSUP;
28938410SWang.Lin@Sun.COM return (err);
28948410SWang.Lin@Sun.COM }
28958410SWang.Lin@Sun.COM
28968410SWang.Lin@Sun.COM rf_p->rf_pm_enabled = ret;
28978410SWang.Lin@Sun.COM
28988410SWang.Lin@Sun.COM return (err);
28998410SWang.Lin@Sun.COM
29008410SWang.Lin@Sun.COM }
29018410SWang.Lin@Sun.COM
29028410SWang.Lin@Sun.COM static void
pcwl_get_powermode(pcwl_maci_t * pcwl_p,void * wldp_buf)29038410SWang.Lin@Sun.COM pcwl_get_powermode(pcwl_maci_t *pcwl_p, void *wldp_buf)
29048410SWang.Lin@Sun.COM {
29058410SWang.Lin@Sun.COM pcwl_rf_t *rf_p;
29068410SWang.Lin@Sun.COM
29078410SWang.Lin@Sun.COM rf_p = &pcwl_p->pcwl_rf;
29088410SWang.Lin@Sun.COM ((wl_ps_mode_t *)wldp_buf)->wl_ps_mode = rf_p->rf_pm_enabled;
29098410SWang.Lin@Sun.COM }
29108410SWang.Lin@Sun.COM
29118410SWang.Lin@Sun.COM /*
29128410SWang.Lin@Sun.COM * MAC_PROP_AUTH_MODE
29138410SWang.Lin@Sun.COM */
29148410SWang.Lin@Sun.COM static int
pcwl_set_authmode(pcwl_maci_t * pcwl_p,const void * wldp_buf)29158410SWang.Lin@Sun.COM pcwl_set_authmode(pcwl_maci_t *pcwl_p, const void *wldp_buf)
29168410SWang.Lin@Sun.COM {
29178410SWang.Lin@Sun.COM uint16_t ret;
29188410SWang.Lin@Sun.COM pcwl_rf_t *rf_p;
29198410SWang.Lin@Sun.COM int err = ENETRESET;
29208410SWang.Lin@Sun.COM
29218410SWang.Lin@Sun.COM rf_p = &pcwl_p->pcwl_rf;
29228410SWang.Lin@Sun.COM
29238410SWang.Lin@Sun.COM ret = (uint16_t)(*(wl_authmode_t *)wldp_buf);
29248410SWang.Lin@Sun.COM if (ret != WL_OPENSYSTEM && ret != WL_SHAREDKEY) {
29258410SWang.Lin@Sun.COM err = ENOTSUP;
29268410SWang.Lin@Sun.COM return (err);
29278410SWang.Lin@Sun.COM }
29288410SWang.Lin@Sun.COM
29298410SWang.Lin@Sun.COM rf_p->rf_authtype = ret;
29308410SWang.Lin@Sun.COM
29318410SWang.Lin@Sun.COM return (err);
29328410SWang.Lin@Sun.COM }
29338410SWang.Lin@Sun.COM
29348410SWang.Lin@Sun.COM static void
pcwl_get_authmode(pcwl_maci_t * pcwl_p,void * wldp_buf)29358410SWang.Lin@Sun.COM pcwl_get_authmode(pcwl_maci_t *pcwl_p, void *wldp_buf)
29368410SWang.Lin@Sun.COM {
29378410SWang.Lin@Sun.COM pcwl_rf_t *rf_p;
29388410SWang.Lin@Sun.COM
29398410SWang.Lin@Sun.COM rf_p = &pcwl_p->pcwl_rf;
29408410SWang.Lin@Sun.COM *(wl_authmode_t *)wldp_buf = rf_p->rf_authtype;
29418410SWang.Lin@Sun.COM }
29428410SWang.Lin@Sun.COM
29438410SWang.Lin@Sun.COM /*
29448410SWang.Lin@Sun.COM * MAC_PROP_WL_ENCRYPTION
29458410SWang.Lin@Sun.COM */
29468410SWang.Lin@Sun.COM static int
pcwl_set_encrypt(pcwl_maci_t * pcwl_p,const void * wldp_buf)29478410SWang.Lin@Sun.COM pcwl_set_encrypt(pcwl_maci_t *pcwl_p, const void *wldp_buf)
29488410SWang.Lin@Sun.COM {
29498410SWang.Lin@Sun.COM uint16_t ret;
29508410SWang.Lin@Sun.COM pcwl_rf_t *rf_p;
29518410SWang.Lin@Sun.COM int err = ENETRESET;
29528410SWang.Lin@Sun.COM
29538410SWang.Lin@Sun.COM rf_p = &pcwl_p->pcwl_rf;
29548410SWang.Lin@Sun.COM
29558410SWang.Lin@Sun.COM ret = (uint16_t)(*(wl_encryption_t *)wldp_buf);
29568410SWang.Lin@Sun.COM PCWLDBG((CE_NOTE, "pcwl_set_encrypt: %d\n", ret));
29578410SWang.Lin@Sun.COM if (ret != WL_NOENCRYPTION && ret != WL_ENC_WEP) {
29588410SWang.Lin@Sun.COM err = ENOTSUP;
29598410SWang.Lin@Sun.COM return (err);
29608410SWang.Lin@Sun.COM }
29618410SWang.Lin@Sun.COM
29628410SWang.Lin@Sun.COM rf_p->rf_encryption = ret;
29638410SWang.Lin@Sun.COM
29648410SWang.Lin@Sun.COM return (err);
29658410SWang.Lin@Sun.COM }
29668410SWang.Lin@Sun.COM
29678410SWang.Lin@Sun.COM static void
pcwl_get_encrypt(pcwl_maci_t * pcwl_p,void * wldp_buf)29688410SWang.Lin@Sun.COM pcwl_get_encrypt(pcwl_maci_t *pcwl_p, void *wldp_buf)
29698410SWang.Lin@Sun.COM {
29708410SWang.Lin@Sun.COM pcwl_rf_t *rf_p;
29718410SWang.Lin@Sun.COM
29728410SWang.Lin@Sun.COM rf_p = &pcwl_p->pcwl_rf;
29738410SWang.Lin@Sun.COM *(wl_encryption_t *)wldp_buf = rf_p->rf_encryption;
29748410SWang.Lin@Sun.COM }
29758410SWang.Lin@Sun.COM
29768410SWang.Lin@Sun.COM /*
29778410SWang.Lin@Sun.COM * MAC_PROP_WL_CREATE_IBSS
29788410SWang.Lin@Sun.COM */
29798410SWang.Lin@Sun.COM static int
pcwl_set_ibss(pcwl_maci_t * pcwl_p,const void * wldp_buf)29808410SWang.Lin@Sun.COM pcwl_set_ibss(pcwl_maci_t *pcwl_p, const void *wldp_buf)
29818410SWang.Lin@Sun.COM {
29828410SWang.Lin@Sun.COM uint16_t ret;
29838410SWang.Lin@Sun.COM pcwl_rf_t *rf_p;
29848410SWang.Lin@Sun.COM int err = ENETRESET;
29858410SWang.Lin@Sun.COM
29868410SWang.Lin@Sun.COM rf_p = &pcwl_p->pcwl_rf;
29878410SWang.Lin@Sun.COM
29888410SWang.Lin@Sun.COM ret = (uint16_t)(*(wl_create_ibss_t *)wldp_buf);
29898410SWang.Lin@Sun.COM if (ret != 0 && ret != 1) {
29908410SWang.Lin@Sun.COM err = ENOTSUP;
29918410SWang.Lin@Sun.COM return (err);
29928410SWang.Lin@Sun.COM }
29938410SWang.Lin@Sun.COM
29948410SWang.Lin@Sun.COM rf_p->rf_create_ibss = ret;
29958410SWang.Lin@Sun.COM
29968410SWang.Lin@Sun.COM return (err);
29978410SWang.Lin@Sun.COM }
29988410SWang.Lin@Sun.COM
29998410SWang.Lin@Sun.COM static void
pcwl_get_ibss(pcwl_maci_t * pcwl_p,void * wldp_buf)30008410SWang.Lin@Sun.COM pcwl_get_ibss(pcwl_maci_t *pcwl_p, void *wldp_buf)
30018410SWang.Lin@Sun.COM {
30028410SWang.Lin@Sun.COM pcwl_rf_t *rf_p;
30038410SWang.Lin@Sun.COM
30048410SWang.Lin@Sun.COM rf_p = &pcwl_p->pcwl_rf;
30058410SWang.Lin@Sun.COM *(wl_create_ibss_t *)wldp_buf = rf_p->rf_create_ibss;
30068410SWang.Lin@Sun.COM }
30078410SWang.Lin@Sun.COM
30088410SWang.Lin@Sun.COM /*
30098410SWang.Lin@Sun.COM * MAC_PROP_WL_RSSI
30108410SWang.Lin@Sun.COM */
30118410SWang.Lin@Sun.COM static void
pcwl_get_param_rssi(pcwl_maci_t * pcwl_p,void * wldp_buf)30128410SWang.Lin@Sun.COM pcwl_get_param_rssi(pcwl_maci_t *pcwl_p, void *wldp_buf)
30138410SWang.Lin@Sun.COM {
30148410SWang.Lin@Sun.COM
30158410SWang.Lin@Sun.COM if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) {
30168410SWang.Lin@Sun.COM *(wl_rssi_t *)wldp_buf =
30178410SWang.Lin@Sun.COM min((pcwl_p->pcwl_rssi * 15 / 85 + 1), 15);
30188410SWang.Lin@Sun.COM } else {
30198410SWang.Lin@Sun.COM /*
30208410SWang.Lin@Sun.COM * According to the description of the
30218410SWang.Lin@Sun.COM * datasheet(Lucent card), the signal level
30228410SWang.Lin@Sun.COM * value is between 27 -- 154.
30238410SWang.Lin@Sun.COM * we reflect these value to 1-15 as rssi.
30248410SWang.Lin@Sun.COM */
30258410SWang.Lin@Sun.COM if (pcwl_p->pcwl_rssi <= 27)
30268410SWang.Lin@Sun.COM *(wl_rssi_t *)wldp_buf = 1;
30278410SWang.Lin@Sun.COM else if (pcwl_p->pcwl_rssi > 154)
30288410SWang.Lin@Sun.COM *(wl_rssi_t *)wldp_buf = 15;
30298410SWang.Lin@Sun.COM else
30308410SWang.Lin@Sun.COM *(wl_rssi_t *)wldp_buf =
30318410SWang.Lin@Sun.COM min(15, ((pcwl_p->pcwl_rssi - 27) * 15 / 127));
30328410SWang.Lin@Sun.COM }
30338410SWang.Lin@Sun.COM }
30348410SWang.Lin@Sun.COM
30358410SWang.Lin@Sun.COM /*
30368410SWang.Lin@Sun.COM * MAC_PROP_WL_KEY_TAB
30378410SWang.Lin@Sun.COM */
30388410SWang.Lin@Sun.COM static int
pcwl_set_wepkey(pcwl_maci_t * pcwl_p,const void * wldp_buf)30398410SWang.Lin@Sun.COM pcwl_set_wepkey(pcwl_maci_t *pcwl_p, const void *wldp_buf)
30408410SWang.Lin@Sun.COM {
30418410SWang.Lin@Sun.COM uint16_t i;
30428410SWang.Lin@Sun.COM pcwl_rf_t *rf_p;
30438410SWang.Lin@Sun.COM wl_wep_key_t *p_wepkey_tab;
30448410SWang.Lin@Sun.COM
30458410SWang.Lin@Sun.COM rf_p = &pcwl_p->pcwl_rf;
30468410SWang.Lin@Sun.COM bzero((rf_p->rf_ckeys), sizeof (rf_ckey_t) * MAX_NWEPKEYS);
30478410SWang.Lin@Sun.COM
30488410SWang.Lin@Sun.COM p_wepkey_tab = (wl_wep_key_t *)wldp_buf;
30498410SWang.Lin@Sun.COM for (i = 0; i < MAX_NWEPKEYS; i++) {
30508410SWang.Lin@Sun.COM if (p_wepkey_tab[i].wl_wep_operation == WL_ADD) {
30518410SWang.Lin@Sun.COM rf_p->rf_ckeys[i].ckey_len =
30528410SWang.Lin@Sun.COM p_wepkey_tab[i].wl_wep_length;
30538410SWang.Lin@Sun.COM bcopy(p_wepkey_tab[i].wl_wep_key,
30548410SWang.Lin@Sun.COM rf_p->rf_ckeys[i].ckey_dat,
30558410SWang.Lin@Sun.COM p_wepkey_tab[i].wl_wep_length);
30568410SWang.Lin@Sun.COM PCWL_SWAP16((uint16_t *)
30578410SWang.Lin@Sun.COM &rf_p->rf_ckeys[i].ckey_dat,
30588410SWang.Lin@Sun.COM rf_p->rf_ckeys[i].ckey_len + 1);
30598410SWang.Lin@Sun.COM PCWLDBG((CE_CONT, "%s, %d\n",
30608410SWang.Lin@Sun.COM rf_p->rf_ckeys[i].ckey_dat, i));
30618410SWang.Lin@Sun.COM }
30628410SWang.Lin@Sun.COM PCWLDBG((CE_CONT, "pcwl: rf_ckeys[%d]=%s\n", i,
30638410SWang.Lin@Sun.COM (char *)(rf_p->rf_ckeys[i].ckey_dat)));
30648410SWang.Lin@Sun.COM }
30658410SWang.Lin@Sun.COM
30668410SWang.Lin@Sun.COM return (ENETRESET);
30678410SWang.Lin@Sun.COM }
30688410SWang.Lin@Sun.COM
30698410SWang.Lin@Sun.COM /*
30708410SWang.Lin@Sun.COM * MAC_PROP_WL_RADIO
30718410SWang.Lin@Sun.COM */
30728410SWang.Lin@Sun.COM static void
pcwl_get_radio(void * wldp_buf)30738410SWang.Lin@Sun.COM pcwl_get_radio(void *wldp_buf)
30748410SWang.Lin@Sun.COM {
30758410SWang.Lin@Sun.COM wl_radio_t *radio = (wl_radio_t *)wldp_buf;
30768410SWang.Lin@Sun.COM
30778410SWang.Lin@Sun.COM *radio = B_TRUE;
30788410SWang.Lin@Sun.COM }
30798410SWang.Lin@Sun.COM
30808410SWang.Lin@Sun.COM /*
30818410SWang.Lin@Sun.COM * MAC_PROP_WL_ESSLIST
30828410SWang.Lin@Sun.COM */
30838410SWang.Lin@Sun.COM static void
pcwl_get_esslist(pcwl_maci_t * pcwl_p,void * wldp_buf)30848410SWang.Lin@Sun.COM pcwl_get_esslist(pcwl_maci_t *pcwl_p, void *wldp_buf)
30858410SWang.Lin@Sun.COM {
30868410SWang.Lin@Sun.COM uint16_t i;
30878410SWang.Lin@Sun.COM wl_ess_conf_t *p_ess_conf;
30888410SWang.Lin@Sun.COM wl_scan_list_t *scan_item;
30898410SWang.Lin@Sun.COM
30908410SWang.Lin@Sun.COM mutex_enter(&pcwl_p->pcwl_scanlist_lock);
30918410SWang.Lin@Sun.COM
30928410SWang.Lin@Sun.COM ((wl_ess_list_t *)wldp_buf)->wl_ess_list_num =
30938410SWang.Lin@Sun.COM pcwl_p->pcwl_scan_num;
30948410SWang.Lin@Sun.COM
30958410SWang.Lin@Sun.COM scan_item = list_head(&pcwl_p->pcwl_scan_list);
30968410SWang.Lin@Sun.COM
30978410SWang.Lin@Sun.COM for (i = 0; i < pcwl_p->pcwl_scan_num; i++) {
30988410SWang.Lin@Sun.COM if (!scan_item)
30998410SWang.Lin@Sun.COM break;
31008410SWang.Lin@Sun.COM
31018410SWang.Lin@Sun.COM p_ess_conf = (wl_ess_conf_t *)((char *)wldp_buf +
31028410SWang.Lin@Sun.COM offsetof(wl_ess_list_t, wl_ess_list_ess) +
31038410SWang.Lin@Sun.COM i * sizeof (wl_ess_conf_t));
31048410SWang.Lin@Sun.COM bcopy(scan_item->wl_val.wl_srt_ssid,
31058410SWang.Lin@Sun.COM p_ess_conf->wl_ess_conf_essid.wl_essid_essid,
31068410SWang.Lin@Sun.COM mi_strlen(scan_item->wl_val.wl_srt_ssid));
31078410SWang.Lin@Sun.COM bcopy(scan_item->wl_val.wl_srt_bssid,
31088410SWang.Lin@Sun.COM p_ess_conf->wl_ess_conf_bssid, 6);
31098410SWang.Lin@Sun.COM (p_ess_conf->wl_phy_conf).wl_phy_dsss_conf.wl_dsss_subtype
31108410SWang.Lin@Sun.COM = WL_DSSS;
31118410SWang.Lin@Sun.COM p_ess_conf->wl_ess_conf_wepenabled =
31128410SWang.Lin@Sun.COM (scan_item->wl_val.wl_srt_cap & 0x10 ?
31138410SWang.Lin@Sun.COM WL_ENC_WEP : WL_NOENCRYPTION);
31148410SWang.Lin@Sun.COM p_ess_conf->wl_ess_conf_bsstype =
31158410SWang.Lin@Sun.COM (scan_item->wl_val.wl_srt_cap & 0x1 ?
31168410SWang.Lin@Sun.COM WL_BSS_BSS : WL_BSS_IBSS);
31178410SWang.Lin@Sun.COM p_ess_conf->wl_phy_conf.wl_phy_dsss_conf.wl_dsss_channel =
31188410SWang.Lin@Sun.COM scan_item->wl_val.wl_srt_chid;
31198410SWang.Lin@Sun.COM if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) {
31208410SWang.Lin@Sun.COM p_ess_conf->wl_ess_conf_sl =
31218410SWang.Lin@Sun.COM min(scan_item->wl_val.wl_srt_sl * 15 / 85 + 1,
31228410SWang.Lin@Sun.COM 15);
31238410SWang.Lin@Sun.COM } else {
31248410SWang.Lin@Sun.COM if (scan_item->wl_val.wl_srt_sl <= 27)
31258410SWang.Lin@Sun.COM p_ess_conf->wl_ess_conf_sl = 1;
31268410SWang.Lin@Sun.COM else if (scan_item->wl_val.wl_srt_sl > 154)
31278410SWang.Lin@Sun.COM p_ess_conf->wl_ess_conf_sl = 15;
31288410SWang.Lin@Sun.COM else
31298410SWang.Lin@Sun.COM p_ess_conf->wl_ess_conf_sl = min(15,
31308410SWang.Lin@Sun.COM ((scan_item->wl_val.wl_srt_sl - 27)
31318410SWang.Lin@Sun.COM * 15 / 127));
31328410SWang.Lin@Sun.COM }
31338410SWang.Lin@Sun.COM
31348410SWang.Lin@Sun.COM p_ess_conf->wl_supported_rates[0] = WL_RATE_1M;
31358410SWang.Lin@Sun.COM p_ess_conf->wl_supported_rates[0] = WL_RATE_2M;
31368410SWang.Lin@Sun.COM p_ess_conf->wl_supported_rates[0] = WL_RATE_5_5M;
31378410SWang.Lin@Sun.COM p_ess_conf->wl_supported_rates[0] = WL_RATE_11M;
31388410SWang.Lin@Sun.COM
31398410SWang.Lin@Sun.COM scan_item = list_next(&pcwl_p->pcwl_scan_list, scan_item);
31408410SWang.Lin@Sun.COM }
31418410SWang.Lin@Sun.COM
31428410SWang.Lin@Sun.COM mutex_exit(&pcwl_p->pcwl_scanlist_lock);
31438410SWang.Lin@Sun.COM }
31448410SWang.Lin@Sun.COM
31458410SWang.Lin@Sun.COM
31468410SWang.Lin@Sun.COM /*
31473737Shx147065 * for wificonfig and dladm ioctl
31483737Shx147065 */
31493737Shx147065
31503737Shx147065 static int
pcwl_cfg_essid(mblk_t * mp,pcwl_maci_t * pcwl_p,uint32_t cmd)31513737Shx147065 pcwl_cfg_essid(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
31523737Shx147065 {
31538410SWang.Lin@Sun.COM char ssid[36];
31548410SWang.Lin@Sun.COM uint16_t i;
31558410SWang.Lin@Sun.COM uint16_t val;
31568410SWang.Lin@Sun.COM pcwl_rf_t *rf_p;
31578410SWang.Lin@Sun.COM wldp_t *infp;
31588410SWang.Lin@Sun.COM wldp_t *outfp;
31598410SWang.Lin@Sun.COM char *buf;
31608410SWang.Lin@Sun.COM int iret;
31618410SWang.Lin@Sun.COM int err = 0;
31623737Shx147065
31633737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
31643737Shx147065 if (buf == NULL) {
31653737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
31663737Shx147065 MAX_BUF_LEN));
31673737Shx147065 return (ENOMEM);
31683737Shx147065 }
31693737Shx147065 outfp = (wldp_t *)buf;
31703737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
31713737Shx147065 infp = (wldp_t *)mp->b_rptr;
31723737Shx147065 rf_p = &pcwl_p->pcwl_rf;
31733737Shx147065
31748410SWang.Lin@Sun.COM
31753737Shx147065 bzero(ssid, sizeof (ssid));
31763737Shx147065 if (cmd == WLAN_GET_PARAM) {
31778410SWang.Lin@Sun.COM err = pcwl_get_essid(pcwl_p, outfp->wldp_buf);
31788410SWang.Lin@Sun.COM if (err == EIO) {
31793737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET;
31803737Shx147065 outfp->wldp_result = WL_HW_ERROR;
31813737Shx147065 goto done;
31823737Shx147065 }
31838410SWang.Lin@Sun.COM (void) pcwl_get_ltv(pcwl_p, 2, WL_RID_PORTSTATUS, &val);
31843737Shx147065 if (val == WL_PORT_DISABLED || val == WL_PORT_INITIAL) {
31853737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET +
31863737Shx147065 offsetof(wl_essid_t, wl_essid_essid) +
31873737Shx147065 mi_strlen(rf_p->rf_desired_ssid);
31883737Shx147065 } else if (val == WL_PORT_TO_IBSS ||
31893737Shx147065 val == WL_PORT_TO_BSS ||
31903737Shx147065 val == WL_PORT_OOR) {
31913737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET +
31923737Shx147065 offsetof(wl_essid_t, wl_essid_essid) +
31933737Shx147065 mi_strlen(ssid+2);
31943737Shx147065 } else {
31953737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET;
31963737Shx147065 }
31973737Shx147065 outfp->wldp_result = WL_SUCCESS;
31983737Shx147065 PCWLDBG((CE_CONT, "outfp->length=%d\n", outfp->wldp_length));
31993737Shx147065 PCWLDBG((CE_CONT, "pcwl: get desired essid=%s\n",
32003737Shx147065 rf_p->rf_desired_ssid));
32013737Shx147065 } else if (cmd == WLAN_SET_PARAM) {
32028410SWang.Lin@Sun.COM (void) pcwl_set_essid(pcwl_p, infp->wldp_buf);
32033737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET;
32043737Shx147065 outfp->wldp_result = WL_SUCCESS;
32053737Shx147065 } else {
32063737Shx147065 kmem_free(buf, MAX_BUF_LEN);
32073737Shx147065 return (EINVAL);
32083737Shx147065 }
32093737Shx147065 done:
32103737Shx147065 for (i = 0; i < (outfp->wldp_length); i++)
32113737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]);
32123737Shx147065 iret = (int)(outfp->wldp_result);
32133737Shx147065 kmem_free(buf, MAX_BUF_LEN);
32143737Shx147065 return (iret);
32153737Shx147065 }
32163737Shx147065
32173737Shx147065 static int
pcwl_cfg_bssid(mblk_t * mp,pcwl_maci_t * pcwl_p,uint32_t cmd)32183737Shx147065 pcwl_cfg_bssid(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
32193737Shx147065 {
32208410SWang.Lin@Sun.COM uint16_t i;
32218410SWang.Lin@Sun.COM int iret;
32228410SWang.Lin@Sun.COM wldp_t *outfp;
32238410SWang.Lin@Sun.COM char *buf;
32248410SWang.Lin@Sun.COM int err = 0;
32253737Shx147065
32263737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
32273737Shx147065 if (buf == NULL) {
32283737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
32293737Shx147065 MAX_BUF_LEN));
32303737Shx147065 return (ENOMEM);
32313737Shx147065 }
32323737Shx147065 outfp = (wldp_t *)buf;
32333737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
32343737Shx147065
32353737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_bssid_t);
32363737Shx147065 if (cmd == WLAN_GET_PARAM) {
32378410SWang.Lin@Sun.COM err = pcwl_get_bssid(pcwl_p, outfp->wldp_buf);
32388410SWang.Lin@Sun.COM if (err == EIO) {
32393737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET;
32403737Shx147065 outfp->wldp_result = WL_HW_ERROR;
32413737Shx147065 goto done;
32423737Shx147065 }
32433737Shx147065 outfp->wldp_result = WL_SUCCESS;
32443737Shx147065 } else if (cmd == WLAN_SET_PARAM) {
32453737Shx147065 outfp->wldp_result = WL_READONLY;
32463737Shx147065 } else {
32473737Shx147065 kmem_free(buf, MAX_BUF_LEN);
32483737Shx147065 return (EINVAL);
32493737Shx147065 }
32503737Shx147065 done:
32513737Shx147065 for (i = 0; i < (outfp->wldp_length); i++)
32523737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]);
32533737Shx147065 iret = (int)(outfp->wldp_result);
32543737Shx147065 kmem_free(buf, MAX_BUF_LEN);
32553737Shx147065 return (iret);
32563737Shx147065 }
32573737Shx147065
32583737Shx147065 /*ARGSUSED*/
32593737Shx147065 static int
pcwl_cmd_scan(pcwl_maci_t * pcwl_p)32603737Shx147065 pcwl_cmd_scan(pcwl_maci_t *pcwl_p)
32613737Shx147065 {
32623737Shx147065 uint16_t vall[18], ret = WL_SUCCESS;
32633737Shx147065 pcwl_rf_t *rf_p;
32643737Shx147065 uint32_t enable, i;
32653737Shx147065 size_t len;
32663737Shx147065
32673737Shx147065 rf_p = &pcwl_p->pcwl_rf;
32683737Shx147065
32693737Shx147065 /*
32703737Shx147065 * The logic of this funtion is really tricky.
32713737Shx147065 * Firstly, the chip can only scan in BSS mode, so necessary
32723737Shx147065 * backup and restore is required before and after the scan
32733737Shx147065 * command.
32743737Shx147065 * Secondly, for Lucent chip, Alrealy associated with an AP
32753737Shx147065 * can only scan the APes on the fixed channel, so we must
32763737Shx147065 * set the desired_ssid as "" before scan and restore after.
32773737Shx147065 * Thirdly, scan cmd is effective only when the card is enabled
32783737Shx147065 * and any 'set' operation(such as set bsstype, ssid)must disable
32793737Shx147065 * the card first and then enable the card after the 'set'
32803737Shx147065 */
32813737Shx147065 enable = pcwl_p->pcwl_flag & PCWL_ENABLED;
32823737Shx147065 len = strlen(rf_p->rf_desired_ssid);
32833737Shx147065
32843737Shx147065 if (pcwl_p->pcwl_rf.rf_porttype != WL_BSS_BSS) {
32853737Shx147065 if ((enable) &&
32863737Shx147065 (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0))) {
32873737Shx147065 ret = (int)WL_HW_ERROR;
32883737Shx147065 goto done;
32893737Shx147065 }
32903737Shx147065 FIL_LTV(pcwl_p, 2, WL_RID_PORTTYPE, WL_BSS_BSS);
32913737Shx147065 }
32923737Shx147065
32933737Shx147065 if ((pcwl_p->pcwl_chip_type == PCWL_CHIP_LUCENT) && (len != 0)) {
32943737Shx147065 if ((enable) &&
32953737Shx147065 (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0))) {
32963737Shx147065 ret = (int)WL_HW_ERROR;
32973737Shx147065 goto done;
32983737Shx147065 }
32993737Shx147065 PUT_STR(pcwl_p, WL_RID_DESIRED_SSID, "");
33003737Shx147065 }
33013737Shx147065
33023737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) {
33033737Shx147065 ret = (int)WL_HW_ERROR;
33043737Shx147065 goto done;
33053737Shx147065 }
33063737Shx147065 pcwl_delay(pcwl_p, 1000000);
33073737Shx147065
33083737Shx147065 switch (pcwl_p->pcwl_chip_type) {
33093737Shx147065 case PCWL_CHIP_PRISMII:
33103737Shx147065 bzero(vall, sizeof (vall));
33113737Shx147065 vall[0] = 0x3fff; /* channel mask */
33123737Shx147065 vall[1] = 0x1; /* tx rate */
33133737Shx147065 for (i = 0; i < WL_MAX_SCAN_TIMES; i++) {
33143737Shx147065 PUT_LTV(pcwl_p, sizeof (vall),
33153737Shx147065 WL_RID_HSCAN_REQUEST, vall);
33163737Shx147065 pcwl_delay(pcwl_p, 1000000);
33173737Shx147065 if (pcwl_p->pcwl_scan_num >= WL_SCAN_AGAIN_THRESHOLD)
33183737Shx147065 break;
33193737Shx147065 }
33203737Shx147065 PCWLDBG((CE_NOTE, "PRISM chip\n"));
33213737Shx147065 break;
33223737Shx147065
33233737Shx147065 case PCWL_CHIP_LUCENT:
33243737Shx147065 PCWLDBG((CE_NOTE, "LUCENT chip\n"));
33253737Shx147065 default:
33263737Shx147065 for (i = 0; i < WL_MAX_SCAN_TIMES; i++) {
33273737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_INQUIRE,
33283737Shx147065 WL_INFO_SCAN_RESULTS)) {
33293737Shx147065 ret = (int)WL_HW_ERROR;
33303737Shx147065 goto done;
33313737Shx147065 }
33323737Shx147065 pcwl_delay(pcwl_p, 500000);
33333737Shx147065 if (pcwl_p->pcwl_scan_num >= WL_SCAN_AGAIN_THRESHOLD)
33343737Shx147065 break;
33353737Shx147065 }
33363737Shx147065 break;
33373737Shx147065 }
33383737Shx147065 if ((pcwl_p->pcwl_rf.rf_porttype != WL_BSS_BSS) ||
33393737Shx147065 ((pcwl_p->pcwl_chip_type == PCWL_CHIP_LUCENT) && (len != 0))) {
33403737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
33413737Shx147065 ret = (int)WL_HW_ERROR;
33423737Shx147065 goto done;
33433737Shx147065 }
33443737Shx147065 if (ret = pcwl_config_rf(pcwl_p)) {
33453737Shx147065 ret = (int)WL_HW_ERROR;
33463737Shx147065 goto done;
33473737Shx147065 }
33483737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) {
33493737Shx147065 ret = (int)WL_HW_ERROR;
33503737Shx147065 goto done;
33513737Shx147065 }
33523737Shx147065
33533737Shx147065 pcwl_delay(pcwl_p, 1000000);
33543737Shx147065 }
33553737Shx147065
33563737Shx147065 if ((!enable) && (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0))) {
33573737Shx147065 ret = (int)WL_HW_ERROR;
33583737Shx147065 }
33593737Shx147065 done:
33603737Shx147065 if (ret)
33614196Syx209050 cmn_err(CE_WARN, "pcwl: scan failed due to hardware error");
33623737Shx147065 return (ret);
33633737Shx147065
33643737Shx147065 }
33653737Shx147065
33663737Shx147065 /*ARGSUSED*/
33673737Shx147065 static int
pcwl_cfg_scan(mblk_t * mp,pcwl_maci_t * pcwl_p,uint32_t cmd)33683737Shx147065 pcwl_cfg_scan(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
33693737Shx147065 {
33708410SWang.Lin@Sun.COM wldp_t *outfp;
33718410SWang.Lin@Sun.COM char *buf;
33728410SWang.Lin@Sun.COM uint16_t i;
33733737Shx147065
33743737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
33753737Shx147065 if (buf == NULL) {
33763737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
33773737Shx147065 MAX_BUF_LEN));
33783737Shx147065 return (ENOMEM);
33793737Shx147065 }
33803737Shx147065 outfp = (wldp_t *)buf;
33813737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
33823737Shx147065
33838410SWang.Lin@Sun.COM pcwl_get_esslist(pcwl_p, outfp->wldp_buf);
33848410SWang.Lin@Sun.COM
33853737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET +
33863737Shx147065 offsetof(wl_ess_list_t, wl_ess_list_ess) +
33873737Shx147065 pcwl_p->pcwl_scan_num * sizeof (wl_ess_conf_t);
33883737Shx147065 outfp->wldp_result = WL_SUCCESS;
33893737Shx147065
33903737Shx147065 for (i = 0; i < (outfp->wldp_length); i++)
33913737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]);
33923737Shx147065 kmem_free(buf, MAX_BUF_LEN);
33933737Shx147065 return (WL_SUCCESS);
33948410SWang.Lin@Sun.COM
33953737Shx147065 }
33963737Shx147065
33973737Shx147065 /*ARGSUSED*/
33983737Shx147065 static int
pcwl_cfg_linkstatus(mblk_t * mp,pcwl_maci_t * pcwl_p,uint32_t cmd)33993737Shx147065 pcwl_cfg_linkstatus(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
34003737Shx147065 {
34018410SWang.Lin@Sun.COM wldp_t *outfp;
34028410SWang.Lin@Sun.COM char *buf;
34038410SWang.Lin@Sun.COM uint16_t i, val;
34048410SWang.Lin@Sun.COM int iret;
34058410SWang.Lin@Sun.COM int err = 0;
34063737Shx147065
34073737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
34083737Shx147065 if (buf == NULL) {
34093737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
34103737Shx147065 MAX_BUF_LEN));
34113737Shx147065 return (ENOMEM);
34123737Shx147065 }
34133737Shx147065 outfp = (wldp_t *)buf;
34143737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
34153737Shx147065
34168410SWang.Lin@Sun.COM err = pcwl_get_linkstatus(pcwl_p, outfp->wldp_buf);
34178410SWang.Lin@Sun.COM if (err == EIO) {
34183737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET;
34193737Shx147065 outfp->wldp_result = WL_HW_ERROR;
34203737Shx147065 goto done;
34213737Shx147065 }
34228410SWang.Lin@Sun.COM
34238410SWang.Lin@Sun.COM (void) pcwl_get_ltv(pcwl_p, 2, WL_RID_PORTSTATUS, &val);
34243737Shx147065 if (val == WL_PORT_DISABLED || val == WL_PORT_INITIAL) {
34253737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET +
34263737Shx147065 sizeof (wl_linkstatus_t);
34273737Shx147065 } else if (val == WL_PORT_TO_IBSS ||
34288410SWang.Lin@Sun.COM val == WL_PORT_TO_BSS ||
34298410SWang.Lin@Sun.COM val == WL_PORT_OOR) {
34303737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET +
34313737Shx147065 sizeof (wl_linkstatus_t);
34323737Shx147065 } else {
34333737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET;
34343737Shx147065 }
34358410SWang.Lin@Sun.COM
34363737Shx147065 outfp->wldp_result = WL_SUCCESS;
34373737Shx147065 done:
34383737Shx147065 for (i = 0; i < (outfp->wldp_length); i++)
34393737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]);
34403737Shx147065 iret = (int)(outfp->wldp_result);
34413737Shx147065 kmem_free(buf, MAX_BUF_LEN);
34423737Shx147065 return (iret);
34433737Shx147065 }
34443737Shx147065
34453737Shx147065 static int
pcwl_cfg_bsstype(mblk_t * mp,pcwl_maci_t * pcwl_p,uint32_t cmd)34463737Shx147065 pcwl_cfg_bsstype(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
34473737Shx147065 {
34488410SWang.Lin@Sun.COM uint16_t i;
34498410SWang.Lin@Sun.COM wldp_t *infp;
34508410SWang.Lin@Sun.COM wldp_t *outfp;
34518410SWang.Lin@Sun.COM char *buf;
34528410SWang.Lin@Sun.COM int iret;
34538410SWang.Lin@Sun.COM int err = 0;
34543737Shx147065
34553737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
34563737Shx147065 if (buf == NULL) {
34573737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
34583737Shx147065 MAX_BUF_LEN));
34593737Shx147065 return (ENOMEM);
34603737Shx147065 }
34613737Shx147065 outfp = (wldp_t *)buf;
34623737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
34633737Shx147065 infp = (wldp_t *)mp->b_rptr;
34643737Shx147065
34653737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_bss_type_t);
34663737Shx147065 if (cmd == WLAN_GET_PARAM) {
34678410SWang.Lin@Sun.COM pcwl_get_bsstype(pcwl_p, outfp->wldp_buf);
34683737Shx147065 outfp->wldp_result = WL_SUCCESS;
34693737Shx147065 } else if (cmd == WLAN_SET_PARAM) {
34708410SWang.Lin@Sun.COM err = pcwl_set_bsstype(pcwl_p, infp->wldp_buf);
34718410SWang.Lin@Sun.COM if (err == ENOTSUP) {
34723737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET;
34733737Shx147065 outfp->wldp_result = WL_NOTSUPPORTED;
34743737Shx147065 goto done;
34753737Shx147065 }
34763737Shx147065 outfp->wldp_result = WL_SUCCESS;
34773737Shx147065 } else {
34783737Shx147065 kmem_free(buf, MAX_BUF_LEN);
34793737Shx147065 return (EINVAL);
34803737Shx147065 }
34813737Shx147065 done:
34823737Shx147065 for (i = 0; i < (outfp->wldp_length); i++)
34833737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]);
34843737Shx147065 iret = (int)(outfp->wldp_result);
34853737Shx147065 kmem_free(buf, MAX_BUF_LEN);
34863737Shx147065 return (iret);
34873737Shx147065 }
34883737Shx147065
34893737Shx147065 static int
pcwl_cfg_phy(mblk_t * mp,pcwl_maci_t * pcwl_p,uint32_t cmd)34903737Shx147065 pcwl_cfg_phy(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
34913737Shx147065 {
34928410SWang.Lin@Sun.COM uint16_t i;
34938410SWang.Lin@Sun.COM wldp_t *infp;
34948410SWang.Lin@Sun.COM wldp_t *outfp;
34958410SWang.Lin@Sun.COM char *buf;
34968410SWang.Lin@Sun.COM int iret;
34978410SWang.Lin@Sun.COM int err = 0;
34983737Shx147065
34993737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
35003737Shx147065 if (buf == NULL) {
35013737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
35023737Shx147065 MAX_BUF_LEN));
35033737Shx147065 return (ENOMEM);
35043737Shx147065 }
35053737Shx147065 outfp = (wldp_t *)buf;
35063737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
35073737Shx147065 infp = (wldp_t *)mp->b_rptr;
35083737Shx147065
35093737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_dsss_t);
35103737Shx147065 if (cmd == WLAN_GET_PARAM) {
35118410SWang.Lin@Sun.COM err = pcwl_get_phy(pcwl_p, outfp->wldp_buf);
35128410SWang.Lin@Sun.COM if (err == EIO) {
35133737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET;
35143737Shx147065 outfp->wldp_result = WL_HW_ERROR;
35153737Shx147065 goto done;
35163737Shx147065 }
35173737Shx147065 outfp->wldp_result = WL_SUCCESS;
35183737Shx147065 } else if (cmd == WLAN_SET_PARAM) {
35198410SWang.Lin@Sun.COM err = pcwl_set_phy(pcwl_p, infp->wldp_buf);
35208410SWang.Lin@Sun.COM if (err == ENOTSUP) {
35213737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET;
35223737Shx147065 outfp->wldp_result = WL_NOTSUPPORTED;
35233737Shx147065 goto done;
35243737Shx147065 }
35253737Shx147065 outfp->wldp_result = WL_SUCCESS;
35263737Shx147065 } else {
35273737Shx147065 kmem_free(buf, MAX_BUF_LEN);
35283737Shx147065 return (EINVAL);
35293737Shx147065 }
35303737Shx147065 done:
35313737Shx147065 for (i = 0; i < (outfp->wldp_length); i++)
35323737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]);
35333737Shx147065 iret = (int)(outfp->wldp_result);
35343737Shx147065 kmem_free(buf, MAX_BUF_LEN);
35353737Shx147065 return (iret);
35363737Shx147065
35373737Shx147065 }
35383737Shx147065
35393737Shx147065 static int
pcwl_cfg_desiredrates(mblk_t * mp,pcwl_maci_t * pcwl_p,uint32_t cmd)35403737Shx147065 pcwl_cfg_desiredrates(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
35413737Shx147065 {
35428410SWang.Lin@Sun.COM uint16_t rate;
35438410SWang.Lin@Sun.COM uint16_t i;
35448410SWang.Lin@Sun.COM wldp_t *infp;
35458410SWang.Lin@Sun.COM wldp_t *outfp;
35468410SWang.Lin@Sun.COM char *buf;
35478410SWang.Lin@Sun.COM int iret;
35488410SWang.Lin@Sun.COM int err = 0;
35493737Shx147065
35503737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
35513737Shx147065 if (buf == NULL) {
35523737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
35533737Shx147065 MAX_BUF_LEN));
35543737Shx147065 return (ENOMEM);
35553737Shx147065 }
35563737Shx147065 outfp = (wldp_t *)buf;
35573737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
35583737Shx147065 infp = (wldp_t *)mp->b_rptr;
35593737Shx147065
35603737Shx147065 if (cmd == WLAN_GET_PARAM) {
35618410SWang.Lin@Sun.COM err = pcwl_get_desrates(pcwl_p, outfp->wldp_buf);
35628410SWang.Lin@Sun.COM if (err == EIO || err == EINVAL) {
35633737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET;
35648410SWang.Lin@Sun.COM outfp->wldp_result = WL_NOTSUPPORTED;
35653737Shx147065 goto done;
35663737Shx147065 }
35673737Shx147065 if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) {
35683737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET +
35693737Shx147065 offsetof(wl_rates_t, wl_rates_rates) +
35703737Shx147065 1 * sizeof (char);
35713737Shx147065 } else {
35728410SWang.Lin@Sun.COM (void) pcwl_get_ltv(pcwl_p, 2, WL_RID_TX_RATE, &rate);
35733737Shx147065 switch (rate) {
35743737Shx147065 case WL_L_TX_RATE_FIX_1M:
35753737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET +
35763737Shx147065 offsetof(wl_rates_t, wl_rates_rates) +
35773737Shx147065 1 * sizeof (char);
35783737Shx147065 break;
35793737Shx147065 case WL_L_TX_RATE_FIX_2M:
35803737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET +
35813737Shx147065 offsetof(wl_rates_t, wl_rates_rates) +
35823737Shx147065 1 * sizeof (char);
35833737Shx147065 break;
35843737Shx147065 case WL_L_TX_RATE_AUTO_H:
35853737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET +
35863737Shx147065 offsetof(wl_rates_t, wl_rates_rates) +
35873737Shx147065 4 * sizeof (char);
35883737Shx147065 break;
35893737Shx147065 case WL_L_TX_RATE_FIX_5M:
35903737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET +
35913737Shx147065 offsetof(wl_rates_t, wl_rates_rates) +
35923737Shx147065 1 * sizeof (char);
35933737Shx147065 break;
35943737Shx147065 case WL_L_TX_RATE_FIX_11M:
35953737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET +
35963737Shx147065 offsetof(wl_rates_t, wl_rates_rates) +
35973737Shx147065 1 * sizeof (char);
35983737Shx147065 break;
35993737Shx147065 case WL_L_TX_RATE_AUTO_L:
36003737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET +
36013737Shx147065 offsetof(wl_rates_t, wl_rates_rates) +
36023737Shx147065 2 * sizeof (char);
36033737Shx147065 break;
36043737Shx147065 case WL_L_TX_RATE_AUTO_M:
36053737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET +
36063737Shx147065 offsetof(wl_rates_t, wl_rates_rates) +
36073737Shx147065 3 * sizeof (char);
36083737Shx147065 break;
36093737Shx147065 default:
36108410SWang.Lin@Sun.COM break;
36113737Shx147065 }
36123737Shx147065 }
36136062Shx147065 outfp->wldp_result = WL_SUCCESS;
36143737Shx147065 } else if (cmd == WLAN_SET_PARAM) {
36158410SWang.Lin@Sun.COM err = pcwl_set_desrates(pcwl_p, infp->wldp_buf);
36168410SWang.Lin@Sun.COM if (err == EINVAL) {
36178410SWang.Lin@Sun.COM outfp->wldp_length = WIFI_BUF_OFFSET;
36188410SWang.Lin@Sun.COM outfp->wldp_result = WL_NOTSUPPORTED;
36198410SWang.Lin@Sun.COM goto done;
36203737Shx147065 }
36218410SWang.Lin@Sun.COM if (err == ENOTSUP) {
36223737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET;
36233737Shx147065 outfp->wldp_result = WL_LACK_FEATURE;
36243737Shx147065 goto done;
36253737Shx147065 }
36268410SWang.Lin@Sun.COM
36273737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET;
36283737Shx147065 outfp->wldp_result = WL_SUCCESS;
36293737Shx147065 } else {
36303737Shx147065 kmem_free(buf, MAX_BUF_LEN);
36313737Shx147065 return (EINVAL);
36323737Shx147065 }
36333737Shx147065 done:
36343737Shx147065 for (i = 0; i < (outfp->wldp_length); i++)
36353737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]);
36363737Shx147065 iret = (int)(outfp->wldp_result);
36373737Shx147065 kmem_free(buf, MAX_BUF_LEN);
36383737Shx147065 return (iret);
36393737Shx147065 }
36403737Shx147065
36413737Shx147065 /*ARGSUSED*/
36423737Shx147065 static int
pcwl_cfg_supportrates(mblk_t * mp,pcwl_maci_t * pcwl_p,uint32_t cmd)36433737Shx147065 pcwl_cfg_supportrates(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
36443737Shx147065 {
36453737Shx147065 uint16_t i;
36463737Shx147065 wldp_t *outfp;
36473737Shx147065 char *buf;
36483737Shx147065
36493737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
36503737Shx147065 if (buf == NULL) {
36513737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
36523737Shx147065 MAX_BUF_LEN));
36533737Shx147065 return (ENOMEM);
36543737Shx147065 }
36553737Shx147065 outfp = (wldp_t *)buf;
36563737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
36573737Shx147065
36583737Shx147065 if (cmd == WLAN_GET_PARAM) {
36598410SWang.Lin@Sun.COM pcwl_get_suprates(outfp->wldp_buf);
36603737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET +
36613737Shx147065 offsetof(wl_rates_t, wl_rates_rates) +
36623737Shx147065 4 * sizeof (char);
36633737Shx147065 outfp->wldp_result = WL_SUCCESS;
36643737Shx147065 for (i = 0; i < (outfp->wldp_length); i++)
36653737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]);
36663737Shx147065 kmem_free(buf, MAX_BUF_LEN);
36673737Shx147065 return (WL_SUCCESS);
36683737Shx147065 } else {
36693737Shx147065 kmem_free(buf, MAX_BUF_LEN);
36703737Shx147065 return (EINVAL);
36713737Shx147065 }
36723737Shx147065 }
36733737Shx147065
36743737Shx147065 static int
pcwl_cfg_powermode(mblk_t * mp,pcwl_maci_t * pcwl_p,uint32_t cmd)36753737Shx147065 pcwl_cfg_powermode(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
36763737Shx147065 {
36778410SWang.Lin@Sun.COM uint16_t i;
36788410SWang.Lin@Sun.COM wldp_t *infp;
36798410SWang.Lin@Sun.COM wldp_t *outfp;
36808410SWang.Lin@Sun.COM char *buf;
36818410SWang.Lin@Sun.COM int iret;
36828410SWang.Lin@Sun.COM int err = 0;
36833737Shx147065
36843737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
36853737Shx147065 if (buf == NULL) {
36863737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
36873737Shx147065 MAX_BUF_LEN));
36883737Shx147065 return (ENOMEM);
36893737Shx147065 }
36903737Shx147065 outfp = (wldp_t *)buf;
36913737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
36923737Shx147065 infp = (wldp_t *)mp->b_rptr;
36933737Shx147065
36943737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_ps_mode_t);
36953737Shx147065 if (cmd == WLAN_GET_PARAM) {
36968410SWang.Lin@Sun.COM pcwl_get_powermode(pcwl_p, outfp->wldp_buf);
36973737Shx147065 outfp->wldp_result = WL_SUCCESS;
36983737Shx147065 } else if (cmd == WLAN_SET_PARAM) {
36998410SWang.Lin@Sun.COM err = pcwl_set_powermode(pcwl_p, infp->wldp_buf);
37008410SWang.Lin@Sun.COM if (err == ENOTSUP) {
37013737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET;
37023737Shx147065 outfp->wldp_result = WL_NOTSUPPORTED;
37033737Shx147065 goto done;
37043737Shx147065 }
37053737Shx147065 outfp->wldp_result = WL_SUCCESS;
37063737Shx147065 } else {
37073737Shx147065 kmem_free(buf, MAX_BUF_LEN);
37083737Shx147065 return (EINVAL);
37093737Shx147065 }
37103737Shx147065 done:
37113737Shx147065 for (i = 0; i < (outfp->wldp_length); i++)
37123737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]);
37133737Shx147065 iret = (int)(outfp->wldp_result);
37143737Shx147065 kmem_free(buf, MAX_BUF_LEN);
37153737Shx147065 return (iret);
37163737Shx147065
37173737Shx147065 }
37183737Shx147065
37193737Shx147065 static int
pcwl_cfg_authmode(mblk_t * mp,pcwl_maci_t * pcwl_p,uint32_t cmd)37203737Shx147065 pcwl_cfg_authmode(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
37213737Shx147065 {
37228410SWang.Lin@Sun.COM uint16_t i;
37238410SWang.Lin@Sun.COM wldp_t *infp;
37248410SWang.Lin@Sun.COM wldp_t *outfp;
37258410SWang.Lin@Sun.COM char *buf;
37268410SWang.Lin@Sun.COM int iret;
37278410SWang.Lin@Sun.COM int err = 0;
37283737Shx147065
37293737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
37303737Shx147065 if (buf == NULL) {
37313737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
37323737Shx147065 MAX_BUF_LEN));
37333737Shx147065 return (ENOMEM);
37343737Shx147065 }
37353737Shx147065 outfp = (wldp_t *)buf;
37363737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
37373737Shx147065 infp = (wldp_t *)mp->b_rptr;
37383737Shx147065
37393737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_authmode_t);
37403737Shx147065 if (cmd == WLAN_GET_PARAM) {
37418410SWang.Lin@Sun.COM pcwl_get_authmode(pcwl_p, outfp->wldp_buf);
37423737Shx147065 outfp->wldp_result = WL_SUCCESS;
37433737Shx147065 } else if (cmd == WLAN_SET_PARAM) {
37448410SWang.Lin@Sun.COM err = pcwl_set_authmode(pcwl_p, infp->wldp_buf);
37458410SWang.Lin@Sun.COM if (err == ENOTSUP) {
37463737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET;
37473737Shx147065 outfp->wldp_result = WL_NOTSUPPORTED;
37483737Shx147065 goto done;
37493737Shx147065 }
37503737Shx147065 outfp->wldp_result = WL_SUCCESS;
37513737Shx147065 } else {
37523737Shx147065 kmem_free(buf, MAX_BUF_LEN);
37533737Shx147065 return (EINVAL);
37543737Shx147065 }
37553737Shx147065 done:
37563737Shx147065 for (i = 0; i < (outfp->wldp_length); i++)
37573737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]);
37583737Shx147065 iret = (int)(outfp->wldp_result);
37593737Shx147065 kmem_free(buf, MAX_BUF_LEN);
37603737Shx147065 return (iret);
37613737Shx147065 }
37623737Shx147065
37633737Shx147065 static int
pcwl_cfg_encryption(mblk_t * mp,pcwl_maci_t * pcwl_p,uint32_t cmd)37643737Shx147065 pcwl_cfg_encryption(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
37653737Shx147065 {
37668410SWang.Lin@Sun.COM uint16_t i;
37678410SWang.Lin@Sun.COM wldp_t *infp;
37688410SWang.Lin@Sun.COM wldp_t *outfp;
37698410SWang.Lin@Sun.COM char *buf;
37708410SWang.Lin@Sun.COM int iret;
37718410SWang.Lin@Sun.COM int err = 0;
37723737Shx147065
37733737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
37743737Shx147065 if (buf == NULL) {
37753737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
37763737Shx147065 MAX_BUF_LEN));
37773737Shx147065 return (ENOMEM);
37783737Shx147065 }
37793737Shx147065 outfp = (wldp_t *)buf;
37803737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
37813737Shx147065 infp = (wldp_t *)mp->b_rptr;
37823737Shx147065
37833737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_encryption_t);
37843737Shx147065 if (cmd == WLAN_GET_PARAM) {
37858410SWang.Lin@Sun.COM pcwl_get_encrypt(pcwl_p, outfp->wldp_buf);
37863737Shx147065 outfp->wldp_result = WL_SUCCESS;
37873737Shx147065 } else if (cmd == WLAN_SET_PARAM) {
37888410SWang.Lin@Sun.COM err = pcwl_set_encrypt(pcwl_p, infp->wldp_buf);
37898410SWang.Lin@Sun.COM if (err == ENOTSUP) {
37903737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET;
37913737Shx147065 outfp->wldp_result = WL_NOTSUPPORTED;
37923737Shx147065 goto done;
37933737Shx147065 }
37943737Shx147065 outfp->wldp_result = WL_SUCCESS;
37953737Shx147065 } else {
37963737Shx147065 kmem_free(buf, MAX_BUF_LEN);
37973737Shx147065 return (EINVAL);
37983737Shx147065 }
37993737Shx147065 done:
38003737Shx147065 for (i = 0; i < (outfp->wldp_length); i++)
38013737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]);
38023737Shx147065 iret = (int)(outfp->wldp_result);
38033737Shx147065 kmem_free(buf, MAX_BUF_LEN);
38043737Shx147065 return (iret);
38053737Shx147065 }
38063737Shx147065
38073737Shx147065 static int
pcwl_cfg_wepkeyid(mblk_t * mp,pcwl_maci_t * pcwl_p,uint32_t cmd)38083737Shx147065 pcwl_cfg_wepkeyid(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
38093737Shx147065 {
38103737Shx147065 uint16_t i, ret;
38113737Shx147065 pcwl_rf_t *rf_p;
38123737Shx147065 wldp_t *infp;
38133737Shx147065 wldp_t *outfp;
38143737Shx147065 char *buf;
38153737Shx147065 int iret;
38163737Shx147065
38173737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
38183737Shx147065 if (buf == NULL) {
38193737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
38203737Shx147065 MAX_BUF_LEN));
38213737Shx147065 return (ENOMEM);
38223737Shx147065 }
38233737Shx147065 outfp = (wldp_t *)buf;
38243737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
38253737Shx147065 infp = (wldp_t *)mp->b_rptr;
38263737Shx147065 rf_p = &pcwl_p->pcwl_rf;
38273737Shx147065
38283737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_wep_key_id_t);
38293737Shx147065 if (cmd == WLAN_GET_PARAM) {
38303737Shx147065 *(wl_wep_key_id_t *)(outfp->wldp_buf) = rf_p->rf_tx_crypt_key;
38313737Shx147065 outfp->wldp_result = WL_SUCCESS;
38323737Shx147065 } else if (cmd == WLAN_SET_PARAM) {
38333737Shx147065 ret = (uint16_t)(*(wl_wep_key_id_t *)(infp->wldp_buf));
38343737Shx147065 if (ret >= MAX_NWEPKEYS) {
38353737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET;
38363737Shx147065 outfp->wldp_result = WL_NOTSUPPORTED;
38373737Shx147065 goto done;
38383737Shx147065 }
38393737Shx147065 rf_p->rf_tx_crypt_key = ret;
38403737Shx147065 outfp->wldp_result = WL_SUCCESS;
38413737Shx147065 } else {
38423737Shx147065 kmem_free(buf, MAX_BUF_LEN);
38433737Shx147065 return (EINVAL);
38443737Shx147065 }
38453737Shx147065 done:
38463737Shx147065 for (i = 0; i < (outfp->wldp_length); i++)
38473737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]);
38483737Shx147065 iret = (int)(outfp->wldp_result);
38493737Shx147065 kmem_free(buf, MAX_BUF_LEN);
38503737Shx147065 return (iret);
38513737Shx147065 }
38523737Shx147065
38533737Shx147065 static int
pcwl_cfg_createibss(mblk_t * mp,pcwl_maci_t * pcwl_p,uint32_t cmd)38543737Shx147065 pcwl_cfg_createibss(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
38553737Shx147065 {
38568410SWang.Lin@Sun.COM uint16_t i;
38578410SWang.Lin@Sun.COM wldp_t *infp;
38588410SWang.Lin@Sun.COM wldp_t *outfp;
38598410SWang.Lin@Sun.COM char *buf;
38608410SWang.Lin@Sun.COM int iret;
38618410SWang.Lin@Sun.COM int err = 0;
38623737Shx147065
38633737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
38643737Shx147065 if (buf == NULL) {
38653737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
38663737Shx147065 MAX_BUF_LEN));
38673737Shx147065 return (ENOMEM);
38683737Shx147065 }
38693737Shx147065 outfp = (wldp_t *)buf;
38703737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
38713737Shx147065 infp = (wldp_t *)mp->b_rptr;
38723737Shx147065
38733737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_create_ibss_t);
38743737Shx147065 if (cmd == WLAN_GET_PARAM) {
38758410SWang.Lin@Sun.COM pcwl_get_ibss(pcwl_p, outfp->wldp_buf);
38763737Shx147065 outfp->wldp_result = WL_SUCCESS;
38773737Shx147065 } else if (cmd == WLAN_SET_PARAM) {
38788410SWang.Lin@Sun.COM err = pcwl_set_ibss(pcwl_p, infp->wldp_buf);
38798410SWang.Lin@Sun.COM if (err == ENOTSUP) {
38803737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET;
38813737Shx147065 outfp->wldp_result = WL_NOTSUPPORTED;
38823737Shx147065 goto done;
38833737Shx147065 }
38843737Shx147065 outfp->wldp_result = WL_SUCCESS;
38853737Shx147065 } else {
38863737Shx147065 kmem_free(buf, MAX_BUF_LEN);
38873737Shx147065 return (EINVAL);
38883737Shx147065 }
38893737Shx147065 done:
38903737Shx147065 for (i = 0; i < (outfp->wldp_length); i++)
38913737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]);
38923737Shx147065 iret = (int)(outfp->wldp_result);
38933737Shx147065 kmem_free(buf, MAX_BUF_LEN);
38943737Shx147065 return (iret);
38953737Shx147065 }
38963737Shx147065
38973737Shx147065 static int
pcwl_cfg_rssi(mblk_t * mp,pcwl_maci_t * pcwl_p,uint32_t cmd)38983737Shx147065 pcwl_cfg_rssi(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
38993737Shx147065 {
39003737Shx147065 uint16_t i;
39013737Shx147065 int iret;
39023737Shx147065 wldp_t *outfp;
39033737Shx147065 char *buf;
39043737Shx147065
39053737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
39063737Shx147065 if (buf == NULL) {
39073737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
39083737Shx147065 MAX_BUF_LEN));
39093737Shx147065 return (ENOMEM);
39103737Shx147065 }
39113737Shx147065 outfp = (wldp_t *)buf;
39123737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
39133737Shx147065
39143737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_rssi_t);
39153737Shx147065
39163737Shx147065 if (cmd == WLAN_GET_PARAM) {
39178410SWang.Lin@Sun.COM pcwl_get_param_rssi(pcwl_p, outfp->wldp_buf);
39183737Shx147065 outfp->wldp_result = WL_SUCCESS;
39193737Shx147065 } else if (cmd == WLAN_SET_PARAM) {
39203737Shx147065 outfp->wldp_result = WL_READONLY;
39213737Shx147065 } else {
39223737Shx147065 kmem_free(buf, MAX_BUF_LEN);
39233737Shx147065 return (EINVAL);
39243737Shx147065 }
39253737Shx147065 done:
39263737Shx147065 for (i = 0; i < (outfp->wldp_length); i++)
39273737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]);
39283737Shx147065 iret = (int)(outfp->wldp_result);
39293737Shx147065 kmem_free(buf, MAX_BUF_LEN);
39303737Shx147065 return (iret);
39313737Shx147065 }
39323737Shx147065
39333737Shx147065 /*ARGSUSED*/
39343737Shx147065 static int
pcwl_cfg_radio(mblk_t * mp,pcwl_maci_t * pcwl_p,uint32_t cmd)39353737Shx147065 pcwl_cfg_radio(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
39363737Shx147065 {
39373737Shx147065 uint16_t i;
39383737Shx147065 int iret;
39393737Shx147065 wldp_t *outfp;
39403737Shx147065 char *buf;
39413737Shx147065
39423737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
39433737Shx147065 if (buf == NULL) {
39443737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
39453737Shx147065 MAX_BUF_LEN));
39463737Shx147065 return (ENOMEM);
39473737Shx147065 }
39483737Shx147065 outfp = (wldp_t *)buf;
39493737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
39503737Shx147065
39513737Shx147065 if (cmd == WLAN_GET_PARAM) {
39523737Shx147065 *(wl_radio_t *)(outfp->wldp_buf) = B_TRUE;
39533737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_radio_t);
39543737Shx147065 outfp->wldp_result = WL_SUCCESS;
39553737Shx147065 } else if (cmd == WLAN_SET_PARAM) {
39563737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET;
39573737Shx147065 outfp->wldp_result = WL_LACK_FEATURE;
39583737Shx147065 } else {
39593737Shx147065 kmem_free(buf, MAX_BUF_LEN);
39603737Shx147065 return (EINVAL);
39613737Shx147065 }
39623737Shx147065 for (i = 0; i < (outfp->wldp_length); i++)
39633737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]);
39643737Shx147065 iret = (int)(outfp->wldp_result);
39653737Shx147065 kmem_free(buf, MAX_BUF_LEN);
39663737Shx147065 return (iret);
39673737Shx147065 }
39683737Shx147065
39693737Shx147065 static int
pcwl_cfg_wepkey(mblk_t * mp,pcwl_maci_t * pcwl_p,uint32_t cmd)39703737Shx147065 pcwl_cfg_wepkey(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
39713737Shx147065 {
39728410SWang.Lin@Sun.COM uint16_t i;
39738410SWang.Lin@Sun.COM wldp_t *infp;
39748410SWang.Lin@Sun.COM wldp_t *outfp;
39758410SWang.Lin@Sun.COM char *buf;
39768410SWang.Lin@Sun.COM int iret;
39773737Shx147065
39783737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
39793737Shx147065 if (buf == NULL) {
39803737Shx147065 PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
39813737Shx147065 MAX_BUF_LEN));
39823737Shx147065 return (ENOMEM);
39833737Shx147065 }
39843737Shx147065 outfp = (wldp_t *)buf;
39853737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
39863737Shx147065 infp = (wldp_t *)mp->b_rptr;
39873737Shx147065
39883737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_wep_key_tab_t);
39893737Shx147065 if (cmd == WLAN_GET_PARAM) {
39903737Shx147065 outfp->wldp_result = WL_WRITEONLY;
39913737Shx147065 } else if (cmd == WLAN_SET_PARAM) {
39928410SWang.Lin@Sun.COM (void) pcwl_set_wepkey(pcwl_p, infp->wldp_buf);
39933737Shx147065 outfp->wldp_result = WL_SUCCESS;
39943737Shx147065 } else {
39953737Shx147065 kmem_free(buf, MAX_BUF_LEN);
39963737Shx147065 return (EINVAL);
39973737Shx147065 }
39983737Shx147065 done:
39993737Shx147065 for (i = 0; i < (outfp->wldp_length); i++)
40003737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]);
40013737Shx147065 iret = (int)(outfp->wldp_result);
40023737Shx147065 kmem_free(buf, MAX_BUF_LEN);
40033737Shx147065 return (iret);
40043737Shx147065 }
40053737Shx147065
40063737Shx147065 static void
pcwl_connect_timeout(void * arg)40073737Shx147065 pcwl_connect_timeout(void *arg)
40083737Shx147065 {
40093737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
40103737Shx147065 uint16_t ret = 0;
40113737Shx147065
40123737Shx147065 mutex_enter(&pcwl_p->pcwl_glock);
40133737Shx147065 PCWL_DISABLE_INTR(pcwl_p);
40143737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
40153737Shx147065 goto done;
40163737Shx147065 }
40173737Shx147065 if (ret = pcwl_config_rf(pcwl_p)) {
40183737Shx147065 goto done;
40193737Shx147065 }
40203737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) {
40213737Shx147065 goto done;
40223737Shx147065 }
40233737Shx147065 PCWL_ENABLE_INTR(pcwl_p);
40243737Shx147065 done:
40253737Shx147065 if (ret)
40264196Syx209050 cmn_err(CE_WARN, "pcwl: connect failed due to hardware error");
40273737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
40283737Shx147065 pcwl_p->pcwl_connect_timeout_id = 0;
40293737Shx147065 }
40303737Shx147065
40313737Shx147065 static int
pcwl_getset(mblk_t * mp,pcwl_maci_t * pcwl_p,uint32_t cmd)40323737Shx147065 pcwl_getset(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
40333737Shx147065 {
40343737Shx147065 int ret = WL_SUCCESS;
40353737Shx147065 int connect = 0;
40363737Shx147065
40373737Shx147065 mutex_enter(&pcwl_p->pcwl_glock);
40383737Shx147065 if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
40393737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
40403737Shx147065 return (PCWL_FAIL);
40413737Shx147065 }
40423737Shx147065 switch (((wldp_t *)mp->b_rptr)->wldp_id) {
40433737Shx147065 case WL_ESSID:
40443737Shx147065 ret = pcwl_cfg_essid(mp, pcwl_p, cmd);
40453737Shx147065 connect = 1;
40463737Shx147065 PCWLDBG((CE_NOTE, "cfg_essid\n"));
40473737Shx147065 break;
40483737Shx147065 case WL_BSSID:
40493737Shx147065 ret = pcwl_cfg_bssid(mp, pcwl_p, cmd);
40503737Shx147065 connect = 1;
40513737Shx147065 PCWLDBG((CE_NOTE, "cfg_bssid\n"));
40523737Shx147065 break;
40533737Shx147065 case WL_ESS_LIST:
40543737Shx147065 ret = pcwl_cfg_scan(mp, pcwl_p, cmd);
40553737Shx147065 PCWLDBG((CE_NOTE, "cfg_scan\n"));
40563737Shx147065 break;
40573737Shx147065 case WL_LINKSTATUS:
40583737Shx147065 ret = pcwl_cfg_linkstatus(mp, pcwl_p, cmd);
40593737Shx147065 PCWLDBG((CE_NOTE, "cfg_linkstatus\n"));
40603737Shx147065 break;
40613737Shx147065 case WL_BSS_TYPE:
40623737Shx147065 ret = pcwl_cfg_bsstype(mp, pcwl_p, cmd);
40633737Shx147065 connect = 1;
40643737Shx147065 PCWLDBG((CE_NOTE, "cfg_bsstype\n"));
40653737Shx147065 break;
40663737Shx147065 case WL_PHY_CONFIG:
40673737Shx147065 ret = pcwl_cfg_phy(mp, pcwl_p, cmd);
40683737Shx147065 connect = 1;
40693737Shx147065 PCWLDBG((CE_NOTE, "cfg_phy\n"));
40703737Shx147065 break;
40713737Shx147065 case WL_DESIRED_RATES:
40723737Shx147065 ret = pcwl_cfg_desiredrates(mp, pcwl_p, cmd);
40733737Shx147065 connect = 1;
40743737Shx147065 PCWLDBG((CE_NOTE, "cfg_disred-rates\n"));
40753737Shx147065 break;
40763737Shx147065 case WL_SUPPORTED_RATES:
40773737Shx147065 ret = pcwl_cfg_supportrates(mp, pcwl_p, cmd);
40783737Shx147065 PCWLDBG((CE_NOTE, "cfg_supported-rates\n"));
40793737Shx147065 break;
40803737Shx147065 case WL_POWER_MODE:
40813737Shx147065 ret = pcwl_cfg_powermode(mp, pcwl_p, cmd);
40823737Shx147065 PCWLDBG((CE_NOTE, "cfg_powermode\n"));
40833737Shx147065 break;
40843737Shx147065 case WL_AUTH_MODE:
40853737Shx147065 ret = pcwl_cfg_authmode(mp, pcwl_p, cmd);
40863737Shx147065 connect = 1;
40873737Shx147065 PCWLDBG((CE_NOTE, "cfg_authmode\n"));
40883737Shx147065 break;
40893737Shx147065 case WL_ENCRYPTION:
40903737Shx147065 ret = pcwl_cfg_encryption(mp, pcwl_p, cmd);
40913737Shx147065 connect = 1;
40923737Shx147065 PCWLDBG((CE_NOTE, "cfg_encryption\n"));
40933737Shx147065 break;
40943737Shx147065 case WL_WEP_KEY_ID:
40953737Shx147065 ret = pcwl_cfg_wepkeyid(mp, pcwl_p, cmd);
40963737Shx147065 connect = 1;
40973737Shx147065 PCWLDBG((CE_NOTE, "cfg_wepkeyid\n"));
40983737Shx147065 break;
40993737Shx147065 case WL_CREATE_IBSS:
41003737Shx147065 ret = pcwl_cfg_createibss(mp, pcwl_p, cmd);
41013737Shx147065 connect = 1;
41023737Shx147065 PCWLDBG((CE_NOTE, "cfg_create-ibss\n"));
41033737Shx147065 break;
41043737Shx147065 case WL_RSSI:
41053737Shx147065 ret = pcwl_cfg_rssi(mp, pcwl_p, cmd);
41063737Shx147065 PCWLDBG((CE_NOTE, "cfg_rssi\n"));
41073737Shx147065 break;
41083737Shx147065 case WL_RADIO:
41093737Shx147065 ret = pcwl_cfg_radio(mp, pcwl_p, cmd);
41103737Shx147065 PCWLDBG((CE_NOTE, "cfg_radio\n"));
41113737Shx147065 break;
41123737Shx147065 case WL_WEP_KEY_TAB:
41133737Shx147065 ret = pcwl_cfg_wepkey(mp, pcwl_p, cmd);
41143737Shx147065 connect = 1;
41153737Shx147065 PCWLDBG((CE_NOTE, "cfg_wepkey\n"));
41163737Shx147065 break;
41173737Shx147065 case WL_SCAN:
41183737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
41193737Shx147065 if (pcwl_p->pcwl_connect_timeout_id != 0) {
41203737Shx147065 (void) untimeout(pcwl_p->pcwl_connect_timeout_id);
41213737Shx147065 pcwl_p->pcwl_connect_timeout_id = 0;
41223737Shx147065 }
41233737Shx147065 mutex_enter(&pcwl_p->pcwl_glock);
41243737Shx147065 ret = pcwl_cmd_scan(pcwl_p);
41253737Shx147065 break;
41263737Shx147065 case WL_LOAD_DEFAULTS:
41273737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
41283737Shx147065 if (pcwl_p->pcwl_connect_timeout_id != 0) {
41293737Shx147065 (void) untimeout(pcwl_p->pcwl_connect_timeout_id);
41303737Shx147065 pcwl_p->pcwl_connect_timeout_id = 0;
41313737Shx147065 }
41323737Shx147065 mutex_enter(&pcwl_p->pcwl_glock);
41333737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
41343737Shx147065 ret = (int)WL_HW_ERROR;
41353737Shx147065 break;
41363737Shx147065 }
41373737Shx147065 if (ret = pcwl_loaddef_rf(pcwl_p)) {
41383737Shx147065 ret = (int)WL_HW_ERROR;
41393737Shx147065 PCWLDBG((CE_WARN, "cfg_loaddef_err\n"));
41403737Shx147065 break;
41413737Shx147065 }
41423737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) {
41433737Shx147065 ret = (int)WL_HW_ERROR;
41443737Shx147065 break;
41453737Shx147065 }
41463737Shx147065 pcwl_delay(pcwl_p, 1000000);
41473737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
41483737Shx147065 ret = (int)WL_HW_ERROR;
41493737Shx147065 break;
41503737Shx147065 }
41513737Shx147065 PCWLDBG((CE_NOTE, "loaddef\n"));
41523737Shx147065 break;
41533737Shx147065 case WL_DISASSOCIATE:
41543737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
41553737Shx147065 if (pcwl_p->pcwl_connect_timeout_id != 0) {
41563737Shx147065 (void) untimeout(pcwl_p->pcwl_connect_timeout_id);
41573737Shx147065 pcwl_p->pcwl_connect_timeout_id = 0;
41583737Shx147065 }
41593737Shx147065
41603737Shx147065 mutex_enter(&pcwl_p->pcwl_glock);
41613737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
41623737Shx147065 ret = (int)WL_HW_ERROR;
41633737Shx147065 break;
41643737Shx147065 }
41653737Shx147065 /*
41663737Shx147065 * A workaround here: If the card is in ad-hoc mode, the
41673737Shx147065 * following scan will not work correctly, so any
41683737Shx147065 * 'dladm connect-wifi' which need a scan first will not
41693737Shx147065 * succeed. software reset the card here as a workround.
41703737Shx147065 */
41713737Shx147065 if ((pcwl_p->pcwl_rf.rf_porttype == WL_BSS_IBSS) &&
41723737Shx147065 (pcwl_p->pcwl_chip_type == PCWL_CHIP_LUCENT)) {
41733737Shx147065 if (ret = pcwl_reset_backend(pcwl_p)) {
41743737Shx147065 ret = (int)WL_HW_ERROR;
41753737Shx147065 break;
41763737Shx147065 }
41773737Shx147065 if (ret = pcwl_init_nicmem(pcwl_p)) {
41783737Shx147065 ret = (int)WL_HW_ERROR;
41793737Shx147065 break;
41803737Shx147065 }
41813737Shx147065 pcwl_start_locked(pcwl_p);
41823737Shx147065 }
41833737Shx147065 if (ret = pcwl_loaddef_rf(pcwl_p)) {
41843737Shx147065 ret = (int)WL_HW_ERROR;
41853737Shx147065 PCWLDBG((CE_WARN, "cfg_loaddef_err\n"));
41863737Shx147065 break;
41873737Shx147065 }
41883737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) {
41893737Shx147065 ret = (int)WL_HW_ERROR;
41903737Shx147065 break;
41913737Shx147065 }
41923737Shx147065 pcwl_delay(pcwl_p, 1000000);
41933737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
41943737Shx147065 ret = (int)WL_HW_ERROR;
41953737Shx147065 break;
41963737Shx147065 }
41973737Shx147065 PCWLDBG((CE_NOTE, "disassociate\n"));
41983737Shx147065 break;
41993737Shx147065 case WL_REASSOCIATE:
42003737Shx147065 case WL_ASSOCIAT:
42013737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
42023737Shx147065 if (pcwl_p->pcwl_connect_timeout_id != 0) {
42033737Shx147065 (void) untimeout(pcwl_p->pcwl_connect_timeout_id);
42043737Shx147065 pcwl_p->pcwl_connect_timeout_id = 0;
42053737Shx147065 }
42063737Shx147065 mutex_enter(&pcwl_p->pcwl_glock);
42073737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
42083737Shx147065 ret = (int)WL_HW_ERROR;
42093737Shx147065 break;
42103737Shx147065 }
42113737Shx147065 if (ret = pcwl_config_rf(pcwl_p)) {
42123737Shx147065 ret = (int)WL_HW_ERROR;
42133737Shx147065 break;
42143737Shx147065 }
42153737Shx147065 if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) {
42163737Shx147065 ret = (int)WL_HW_ERROR;
42173737Shx147065 break;
42183737Shx147065 }
42193737Shx147065 PCWLDBG((CE_NOTE, "associate"));
42203737Shx147065 break;
42213737Shx147065 default:
42223737Shx147065 break;
42233737Shx147065 }
42243737Shx147065 mutex_exit(&pcwl_p->pcwl_glock);
42253737Shx147065 if ((cmd == WLAN_SET_PARAM) && (connect)) {
42263737Shx147065 (void) pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0);
42273737Shx147065 if (pcwl_p->pcwl_connect_timeout_id != 0) {
42283737Shx147065 (void) untimeout(pcwl_p->pcwl_connect_timeout_id);
42293737Shx147065 pcwl_p->pcwl_connect_timeout_id = 0;
42303737Shx147065 }
42313737Shx147065 pcwl_p->pcwl_connect_timeout_id = timeout(pcwl_connect_timeout,
42323737Shx147065 pcwl_p, 2 * drv_usectohz(1000000));
42333737Shx147065 }
42343737Shx147065 return (ret);
42353737Shx147065 }
42363737Shx147065
42373737Shx147065 static void
pcwl_wlan_ioctl(pcwl_maci_t * pcwl_p,queue_t * wq,mblk_t * mp,uint32_t cmd)42383737Shx147065 pcwl_wlan_ioctl(pcwl_maci_t *pcwl_p, queue_t *wq, mblk_t *mp, uint32_t cmd)
42393737Shx147065 {
42403737Shx147065
42413737Shx147065 struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
42423737Shx147065 wldp_t *infp;
42433737Shx147065 uint32_t len, ret;
42443737Shx147065 mblk_t *mp1;
42453737Shx147065
42463737Shx147065 /*
42473737Shx147065 * sanity check
42483737Shx147065 */
42493737Shx147065 if (iocp->ioc_count == 0 || !(mp1 = mp->b_cont)) {
42503737Shx147065 miocnak(wq, mp, 0, EINVAL);
42513737Shx147065 return;
42523737Shx147065 }
42533737Shx147065
42543737Shx147065 /*
42553737Shx147065 * assuming single data block
42563737Shx147065 */
42573737Shx147065 if (mp1->b_cont) {
42583737Shx147065 freemsg(mp1->b_cont);
42593737Shx147065 mp1->b_cont = NULL;
42603737Shx147065 }
42613737Shx147065
42623737Shx147065 /*
42633737Shx147065 * we will overwrite everything
42643737Shx147065 */
42653737Shx147065 mp1->b_wptr = mp1->b_rptr;
42663737Shx147065
42673737Shx147065 infp = (wldp_t *)mp1->b_rptr;
42683737Shx147065 PCWLDBG((CE_NOTE, "pcwl: wldp->length=0x%x\n", infp->wldp_length));
42693737Shx147065 PCWLDBG((CE_NOTE, "pcwl: wldp->type =:%s\n",
42703737Shx147065 infp->wldp_type == NET_802_11 ? "NET_802_11" : "Unknown"));
42713737Shx147065 PCWLDBG((CE_NOTE, "pcwl: wldp->id=0x%x\n", infp->wldp_id));
42723737Shx147065 PCWLDBG((CE_NOTE, "pcwl: wldp->result=0x%x\n", infp->wldp_result));
42733737Shx147065
42743737Shx147065 ret = pcwl_getset(mp1, pcwl_p, cmd);
42753737Shx147065 len = msgdsize(mp1);
42763737Shx147065 PCWLDBG((CE_CONT, "pcwl: ioctl message length = %d\n", len));
42773737Shx147065 miocack(wq, mp, len, ret);
42783737Shx147065
42793737Shx147065 }
42803737Shx147065
42813737Shx147065
42823737Shx147065 static void
pcwl_ioctl(void * arg,queue_t * wq,mblk_t * mp)42833737Shx147065 pcwl_ioctl(void *arg, queue_t *wq, mblk_t *mp)
42843737Shx147065 {
42853737Shx147065 struct iocblk *iocp;
42863737Shx147065 uint32_t cmd, ret;
42873737Shx147065 pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
42883737Shx147065 boolean_t need_privilege = B_TRUE;
42893737Shx147065
42903737Shx147065 /*
42913737Shx147065 * Validate the command before bothering with the mutexen ...
42923737Shx147065 */
42933737Shx147065 iocp = (struct iocblk *)mp->b_rptr;
42943737Shx147065 iocp->ioc_error = 0;
42953737Shx147065 cmd = iocp->ioc_cmd;
42963737Shx147065 switch (cmd) {
42973737Shx147065 default:
42983737Shx147065 PCWLDBG((CE_CONT, "pcwl_ioctl: unknown cmd 0x%x", cmd));
42993737Shx147065 miocnak(wq, mp, 0, EINVAL);
43003737Shx147065 return;
43013737Shx147065 case WLAN_GET_PARAM:
43027408SSebastien.Roy@Sun.COM need_privilege = B_FALSE;
43033737Shx147065 break;
43043737Shx147065 case WLAN_SET_PARAM:
43053737Shx147065 case WLAN_COMMAND:
43063737Shx147065 break;
43073737Shx147065 }
43087408SSebastien.Roy@Sun.COM
43097408SSebastien.Roy@Sun.COM if (need_privilege && (ret = secpolicy_dl_config(iocp->ioc_cr)) != 0)
43107408SSebastien.Roy@Sun.COM miocnak(wq, mp, 0, ret);
43117408SSebastien.Roy@Sun.COM else
43127408SSebastien.Roy@Sun.COM pcwl_wlan_ioctl(pcwl_p, wq, mp, cmd);
43133737Shx147065 }
43148410SWang.Lin@Sun.COM
43158410SWang.Lin@Sun.COM /*
43168410SWang.Lin@Sun.COM * brussels
43178410SWang.Lin@Sun.COM */
43188410SWang.Lin@Sun.COM /* ARGSUSED */
43198410SWang.Lin@Sun.COM static int
pcwl_m_setprop(void * arg,const char * pr_name,mac_prop_id_t wldp_pr_num,uint_t wldp_length,const void * wldp_buf)43208410SWang.Lin@Sun.COM pcwl_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
43218410SWang.Lin@Sun.COM uint_t wldp_length, const void *wldp_buf)
43228410SWang.Lin@Sun.COM {
43238410SWang.Lin@Sun.COM int err = 0;
43248410SWang.Lin@Sun.COM pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
43258410SWang.Lin@Sun.COM
43268410SWang.Lin@Sun.COM mutex_enter(&pcwl_p->pcwl_glock);
43278410SWang.Lin@Sun.COM if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
43288410SWang.Lin@Sun.COM mutex_exit(&pcwl_p->pcwl_glock);
43298410SWang.Lin@Sun.COM err = EINVAL;
43308410SWang.Lin@Sun.COM return (err);
43318410SWang.Lin@Sun.COM }
43328410SWang.Lin@Sun.COM
43338410SWang.Lin@Sun.COM switch (wldp_pr_num) {
43348410SWang.Lin@Sun.COM /* mac_prop_id */
43358410SWang.Lin@Sun.COM case MAC_PROP_WL_ESSID:
43368410SWang.Lin@Sun.COM err = pcwl_set_essid(pcwl_p, wldp_buf);
43378410SWang.Lin@Sun.COM break;
43388410SWang.Lin@Sun.COM case MAC_PROP_WL_PHY_CONFIG:
43398410SWang.Lin@Sun.COM err = pcwl_set_phy(pcwl_p, wldp_buf);
43408410SWang.Lin@Sun.COM break;
43418410SWang.Lin@Sun.COM case MAC_PROP_WL_KEY_TAB:
43428410SWang.Lin@Sun.COM err = pcwl_set_wepkey(pcwl_p, wldp_buf);
43438410SWang.Lin@Sun.COM break;
43448410SWang.Lin@Sun.COM case MAC_PROP_WL_AUTH_MODE:
43458410SWang.Lin@Sun.COM err = pcwl_set_authmode(pcwl_p, wldp_buf);
43468410SWang.Lin@Sun.COM break;
43478410SWang.Lin@Sun.COM case MAC_PROP_WL_ENCRYPTION:
43488410SWang.Lin@Sun.COM err = pcwl_set_encrypt(pcwl_p, wldp_buf);
43498410SWang.Lin@Sun.COM break;
43508410SWang.Lin@Sun.COM case MAC_PROP_WL_BSSTYPE:
43518410SWang.Lin@Sun.COM err = pcwl_set_bsstype(pcwl_p, wldp_buf);
43528410SWang.Lin@Sun.COM break;
43538410SWang.Lin@Sun.COM case MAC_PROP_WL_DESIRED_RATES:
43548410SWang.Lin@Sun.COM err = pcwl_set_desrates(pcwl_p, wldp_buf);
43558410SWang.Lin@Sun.COM break;
43568410SWang.Lin@Sun.COM case MAC_PROP_WL_POWER_MODE:
43578410SWang.Lin@Sun.COM err = pcwl_set_powermode(pcwl_p, wldp_buf);
43588410SWang.Lin@Sun.COM break;
43598410SWang.Lin@Sun.COM case MAC_PROP_WL_CREATE_IBSS:
43608410SWang.Lin@Sun.COM err = pcwl_set_ibss(pcwl_p, wldp_buf);
43618410SWang.Lin@Sun.COM break;
43628410SWang.Lin@Sun.COM case MAC_PROP_WL_BSSID:
43638410SWang.Lin@Sun.COM case MAC_PROP_WL_RADIO:
43648410SWang.Lin@Sun.COM case MAC_PROP_WL_WPA:
43658410SWang.Lin@Sun.COM case MAC_PROP_WL_KEY:
43668410SWang.Lin@Sun.COM case MAC_PROP_WL_DELKEY:
43678410SWang.Lin@Sun.COM case MAC_PROP_WL_SETOPTIE:
43688410SWang.Lin@Sun.COM case MAC_PROP_WL_MLME:
43698410SWang.Lin@Sun.COM case MAC_PROP_WL_LINKSTATUS:
43708410SWang.Lin@Sun.COM case MAC_PROP_WL_ESS_LIST:
43718410SWang.Lin@Sun.COM case MAC_PROP_WL_SUPPORTED_RATES:
43728410SWang.Lin@Sun.COM case MAC_PROP_WL_RSSI:
43738410SWang.Lin@Sun.COM case MAC_PROP_WL_CAPABILITY:
43748410SWang.Lin@Sun.COM case MAC_PROP_WL_SCANRESULTS:
43758410SWang.Lin@Sun.COM cmn_err(CE_WARN, "pcwl_setprop:"
43768410SWang.Lin@Sun.COM "opmode not support\n");
43778410SWang.Lin@Sun.COM err = ENOTSUP;
43788410SWang.Lin@Sun.COM break;
43798410SWang.Lin@Sun.COM default:
43808410SWang.Lin@Sun.COM cmn_err(CE_WARN, "pcwl_setprop:"
43818410SWang.Lin@Sun.COM "opmode err\n");
43828410SWang.Lin@Sun.COM err = EINVAL;
43838410SWang.Lin@Sun.COM break;
43848410SWang.Lin@Sun.COM }
43858410SWang.Lin@Sun.COM
43868410SWang.Lin@Sun.COM mutex_exit(&pcwl_p->pcwl_glock);
43878410SWang.Lin@Sun.COM
43888410SWang.Lin@Sun.COM if (err == ENETRESET) {
43898410SWang.Lin@Sun.COM (void) pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0);
43908410SWang.Lin@Sun.COM if (pcwl_p->pcwl_connect_timeout_id != 0) {
43918410SWang.Lin@Sun.COM (void) untimeout(pcwl_p->pcwl_connect_timeout_id);
43928410SWang.Lin@Sun.COM pcwl_p->pcwl_connect_timeout_id = 0;
43938410SWang.Lin@Sun.COM }
43948410SWang.Lin@Sun.COM pcwl_p->pcwl_connect_timeout_id = timeout(pcwl_connect_timeout,
43958410SWang.Lin@Sun.COM pcwl_p, 2 * drv_usectohz(1000000));
43968410SWang.Lin@Sun.COM
43978410SWang.Lin@Sun.COM err = 0;
43988410SWang.Lin@Sun.COM }
43998410SWang.Lin@Sun.COM
44008410SWang.Lin@Sun.COM return (err);
44018410SWang.Lin@Sun.COM } /* ARGSUSED */
44028410SWang.Lin@Sun.COM
44038410SWang.Lin@Sun.COM /* ARGSUSED */
44048410SWang.Lin@Sun.COM static int
pcwl_m_getprop(void * arg,const char * pr_name,mac_prop_id_t wldp_pr_num,uint_t wldp_length,void * wldp_buf)44058410SWang.Lin@Sun.COM pcwl_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
4406*11878SVenu.Iyer@Sun.COM uint_t wldp_length, void *wldp_buf)
44078410SWang.Lin@Sun.COM {
44088410SWang.Lin@Sun.COM int err = 0;
44098410SWang.Lin@Sun.COM pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
44108410SWang.Lin@Sun.COM
44118410SWang.Lin@Sun.COM mutex_enter(&pcwl_p->pcwl_glock);
44128410SWang.Lin@Sun.COM if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
44138410SWang.Lin@Sun.COM mutex_exit(&pcwl_p->pcwl_glock);
44148410SWang.Lin@Sun.COM err = EINVAL;
44158410SWang.Lin@Sun.COM return (err);
44168410SWang.Lin@Sun.COM }
44178410SWang.Lin@Sun.COM
44188410SWang.Lin@Sun.COM switch (wldp_pr_num) {
44198410SWang.Lin@Sun.COM /* mac_prop_id */
44208410SWang.Lin@Sun.COM case MAC_PROP_WL_ESSID:
44218410SWang.Lin@Sun.COM err = pcwl_get_essid(pcwl_p, wldp_buf);
44228410SWang.Lin@Sun.COM break;
44238410SWang.Lin@Sun.COM case MAC_PROP_WL_BSSID:
44248410SWang.Lin@Sun.COM err = pcwl_get_bssid(pcwl_p, wldp_buf);
44258410SWang.Lin@Sun.COM break;
44268410SWang.Lin@Sun.COM case MAC_PROP_WL_PHY_CONFIG:
44278410SWang.Lin@Sun.COM err = pcwl_get_phy(pcwl_p, wldp_buf);
44288410SWang.Lin@Sun.COM break;
44298410SWang.Lin@Sun.COM case MAC_PROP_WL_AUTH_MODE:
44308410SWang.Lin@Sun.COM pcwl_get_authmode(pcwl_p, wldp_buf);
44318410SWang.Lin@Sun.COM break;
44328410SWang.Lin@Sun.COM case MAC_PROP_WL_ENCRYPTION:
44338410SWang.Lin@Sun.COM pcwl_get_encrypt(pcwl_p, wldp_buf);
44348410SWang.Lin@Sun.COM break;
44358410SWang.Lin@Sun.COM case MAC_PROP_WL_BSSTYPE:
44368410SWang.Lin@Sun.COM pcwl_get_bsstype(pcwl_p, wldp_buf);
44378410SWang.Lin@Sun.COM break;
44388410SWang.Lin@Sun.COM case MAC_PROP_WL_LINKSTATUS:
44398410SWang.Lin@Sun.COM err = pcwl_get_linkstatus(pcwl_p, wldp_buf);
44408410SWang.Lin@Sun.COM break;
44418410SWang.Lin@Sun.COM case MAC_PROP_WL_ESS_LIST:
44428410SWang.Lin@Sun.COM pcwl_get_esslist(pcwl_p, wldp_buf);
44438410SWang.Lin@Sun.COM break;
44448410SWang.Lin@Sun.COM case MAC_PROP_WL_SUPPORTED_RATES:
44458410SWang.Lin@Sun.COM pcwl_get_suprates(wldp_buf);
44468410SWang.Lin@Sun.COM break;
44478410SWang.Lin@Sun.COM case MAC_PROP_WL_RSSI:
44488410SWang.Lin@Sun.COM pcwl_get_param_rssi(pcwl_p, wldp_buf);
44498410SWang.Lin@Sun.COM break;
44508410SWang.Lin@Sun.COM case MAC_PROP_WL_RADIO:
44518410SWang.Lin@Sun.COM pcwl_get_radio(wldp_buf);
44528410SWang.Lin@Sun.COM break;
44538410SWang.Lin@Sun.COM case MAC_PROP_WL_POWER_MODE:
44548410SWang.Lin@Sun.COM pcwl_get_powermode(pcwl_p, wldp_buf);
44558410SWang.Lin@Sun.COM break;
44568410SWang.Lin@Sun.COM case MAC_PROP_WL_CREATE_IBSS:
44578410SWang.Lin@Sun.COM pcwl_get_ibss(pcwl_p, wldp_buf);
44588410SWang.Lin@Sun.COM break;
44598410SWang.Lin@Sun.COM case MAC_PROP_WL_DESIRED_RATES:
44608410SWang.Lin@Sun.COM err = pcwl_get_desrates(pcwl_p, wldp_buf);
44618410SWang.Lin@Sun.COM break;
44628410SWang.Lin@Sun.COM case MAC_PROP_WL_CAPABILITY:
44638410SWang.Lin@Sun.COM case MAC_PROP_WL_WPA:
44648410SWang.Lin@Sun.COM case MAC_PROP_WL_SCANRESULTS:
44658410SWang.Lin@Sun.COM case MAC_PROP_WL_KEY_TAB:
44668410SWang.Lin@Sun.COM case MAC_PROP_WL_KEY:
44678410SWang.Lin@Sun.COM case MAC_PROP_WL_DELKEY:
44688410SWang.Lin@Sun.COM case MAC_PROP_WL_SETOPTIE:
44698410SWang.Lin@Sun.COM case MAC_PROP_WL_MLME:
44708410SWang.Lin@Sun.COM cmn_err(CE_WARN, "pcwl_getprop:"
44718410SWang.Lin@Sun.COM "opmode not support\n");
44728410SWang.Lin@Sun.COM err = ENOTSUP;
44738410SWang.Lin@Sun.COM break;
44748410SWang.Lin@Sun.COM default:
44758410SWang.Lin@Sun.COM cmn_err(CE_WARN, "pcwl_getprop:"
44768410SWang.Lin@Sun.COM "opmode err\n");
44778410SWang.Lin@Sun.COM err = EINVAL;
44788410SWang.Lin@Sun.COM break;
44798410SWang.Lin@Sun.COM }
44808410SWang.Lin@Sun.COM
44818410SWang.Lin@Sun.COM mutex_exit(&pcwl_p->pcwl_glock);
44828410SWang.Lin@Sun.COM
44838410SWang.Lin@Sun.COM return (err);
44848410SWang.Lin@Sun.COM }
44858801SQuaker.Fang@Sun.COM
4486*11878SVenu.Iyer@Sun.COM
4487*11878SVenu.Iyer@Sun.COM static void
pcwl_m_propinfo(void * arg,const char * pr_name,mac_prop_id_t wlpd_pr_num,mac_prop_info_handle_t prh)4488*11878SVenu.Iyer@Sun.COM pcwl_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t wlpd_pr_num,
4489*11878SVenu.Iyer@Sun.COM mac_prop_info_handle_t prh)
4490*11878SVenu.Iyer@Sun.COM {
4491*11878SVenu.Iyer@Sun.COM _NOTE(ARGUNUSED(arg, pr_name));
4492*11878SVenu.Iyer@Sun.COM
4493*11878SVenu.Iyer@Sun.COM switch (wlpd_pr_num) {
4494*11878SVenu.Iyer@Sun.COM case MAC_PROP_WL_LINKSTATUS:
4495*11878SVenu.Iyer@Sun.COM case MAC_PROP_WL_ESS_LIST:
4496*11878SVenu.Iyer@Sun.COM case MAC_PROP_WL_SUPPORTED_RATES:
4497*11878SVenu.Iyer@Sun.COM case MAC_PROP_WL_RSSI:
4498*11878SVenu.Iyer@Sun.COM mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
4499*11878SVenu.Iyer@Sun.COM }
4500*11878SVenu.Iyer@Sun.COM }
4501*11878SVenu.Iyer@Sun.COM
4502*11878SVenu.Iyer@Sun.COM
45038801SQuaker.Fang@Sun.COM /*
45048801SQuaker.Fang@Sun.COM * quiesce(9E) entry point.
45058801SQuaker.Fang@Sun.COM *
45068801SQuaker.Fang@Sun.COM * This function is called when the system is single-threaded at high
45078801SQuaker.Fang@Sun.COM * PIL with preemption disabled. Therefore, this function must not be
45088801SQuaker.Fang@Sun.COM * blocked.
45098801SQuaker.Fang@Sun.COM *
45108801SQuaker.Fang@Sun.COM * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
45118801SQuaker.Fang@Sun.COM * DDI_FAILURE indicates an error condition and should almost never happen.
45128801SQuaker.Fang@Sun.COM */
45138801SQuaker.Fang@Sun.COM #ifndef __sparc
45148801SQuaker.Fang@Sun.COM static int
pcwl_quiesce(dev_info_t * dip)45158801SQuaker.Fang@Sun.COM pcwl_quiesce(dev_info_t *dip)
45168801SQuaker.Fang@Sun.COM {
45178801SQuaker.Fang@Sun.COM pcwl_maci_t *pcwl_p;
45188801SQuaker.Fang@Sun.COM
45198801SQuaker.Fang@Sun.COM pcwl_p = ddi_get_soft_state(pcwl_soft_state_p, ddi_get_instance(dip));
45208801SQuaker.Fang@Sun.COM if (pcwl_p == NULL)
45218801SQuaker.Fang@Sun.COM return (DDI_FAILURE);
45228801SQuaker.Fang@Sun.COM
45238801SQuaker.Fang@Sun.COM if (pcwl_p->pcwl_flag & PCWL_CARD_READY)
45248801SQuaker.Fang@Sun.COM pcwl_stop_locked(pcwl_p);
45258801SQuaker.Fang@Sun.COM
45268801SQuaker.Fang@Sun.COM return (DDI_SUCCESS);
45278801SQuaker.Fang@Sun.COM }
45288801SQuaker.Fang@Sun.COM #endif
4529