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 "pcan.h"
573737Shx147065 #include <sys/mac_wifi.h>
583737Shx147065 #include <inet/wifi_ioctl.h>
593737Shx147065
603737Shx147065 #ifdef DEBUG
613737Shx147065 #define PCAN_DBG_BASIC 0x1
623737Shx147065 #define PCAN_DBG_INFO 0x2
633737Shx147065 #define PCAN_DBG_SEND 0x4
643737Shx147065 #define PCAN_DBG_RCV 0x8
653737Shx147065 #define PCAN_DBG_LINKINFO 0x10
663737Shx147065 #define PCAN_DBG_FW_VERSION 0x20
673737Shx147065 #define PCAN_DBG_CMD 0x40
683737Shx147065 uint32_t pcan_debug = 0;
693737Shx147065 #define PCANDBG(x) \
703737Shx147065 if (pcan_debug & PCAN_DBG_BASIC) cmn_err x
713737Shx147065 #else
723737Shx147065 #define PCANDBG(x)
733737Shx147065 #endif
743737Shx147065
753737Shx147065 static ddi_device_acc_attr_t accattr = {
763737Shx147065 DDI_DEVICE_ATTR_V0,
773737Shx147065 DDI_STRUCTURE_LE_ACC,
783737Shx147065 DDI_STRICTORDER_ACC,
793737Shx147065 };
803737Shx147065
813737Shx147065 static ddi_dma_attr_t control_cmd_dma_attr = {
823737Shx147065 DMA_ATTR_V0, /* version of this structure */
833737Shx147065 0, /* lowest usable address */
843737Shx147065 0xffffffffffffffffull, /* highest usable address */
853737Shx147065 0xffffffffull, /* maximum DMAable byte count */
863737Shx147065 4, /* alignment in bytes */
873737Shx147065 0xfff, /* burst sizes (any) */
883737Shx147065 1, /* minimum transfer */
893737Shx147065 0xffffull, /* maximum transfer */
903737Shx147065 0xffffffffffffffffull, /* maximum segment length */
913737Shx147065 1, /* maximum number of segments */
923737Shx147065 1, /* granularity */
933737Shx147065 0, /* flags (reserved) */
943737Shx147065 };
953737Shx147065
963737Shx147065 void *pcan_soft_state_p = NULL;
973737Shx147065 static int pcan_device_type;
983737Shx147065
998410SWang.Lin@Sun.COM /*
1008410SWang.Lin@Sun.COM * brussels
1018410SWang.Lin@Sun.COM */
1028410SWang.Lin@Sun.COM static int pcan_m_setprop(void *arg, const char *pr_name,
1038410SWang.Lin@Sun.COM mac_prop_id_t wldp_pr_num, uint_t wldp_length,
1048410SWang.Lin@Sun.COM const void *wldp_buf);
1058410SWang.Lin@Sun.COM static int pcan_m_getprop(void *arg, const char *pr_name,
106*11878SVenu.Iyer@Sun.COM mac_prop_id_t wldp_pr_num, uint_t wldp_length, void *wldp_buf);
107*11878SVenu.Iyer@Sun.COM static void pcan_m_propinfo(void *arg, const char *pr_name,
108*11878SVenu.Iyer@Sun.COM mac_prop_id_t wldp_pr_num, mac_prop_info_handle_t mph);
1098410SWang.Lin@Sun.COM
1103737Shx147065 mac_callbacks_t pcan_m_callbacks = {
111*11878SVenu.Iyer@Sun.COM MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
1123737Shx147065 pcan_gstat,
1133737Shx147065 pcan_start,
1143737Shx147065 pcan_stop,
1153737Shx147065 pcan_prom,
1163737Shx147065 pcan_sdmulti,
1173737Shx147065 pcan_saddr,
1183737Shx147065 pcan_tx,
119*11878SVenu.Iyer@Sun.COM NULL,
1208410SWang.Lin@Sun.COM pcan_ioctl,
1218410SWang.Lin@Sun.COM NULL,
1228410SWang.Lin@Sun.COM NULL,
1238410SWang.Lin@Sun.COM NULL,
1248410SWang.Lin@Sun.COM pcan_m_setprop,
125*11878SVenu.Iyer@Sun.COM pcan_m_getprop,
126*11878SVenu.Iyer@Sun.COM pcan_m_propinfo
1273737Shx147065 };
1283737Shx147065
1293737Shx147065 static char *pcan_name_str = "pcan";
1303737Shx147065
1318801SQuaker.Fang@Sun.COM #ifdef __sparc
1328801SQuaker.Fang@Sun.COM #define pcan_quiesce ddi_quiesce_not_supported
1338801SQuaker.Fang@Sun.COM #else
1348801SQuaker.Fang@Sun.COM static int pcan_quiesce(dev_info_t *);
1358801SQuaker.Fang@Sun.COM #endif
1368801SQuaker.Fang@Sun.COM
1373737Shx147065 DDI_DEFINE_STREAM_OPS(pcan_dev_ops, nulldev, pcan_probe, pcan_attach,
1388801SQuaker.Fang@Sun.COM pcan_detach, nodev, NULL, D_MP, NULL, pcan_quiesce);
1393737Shx147065
1403737Shx147065 extern struct mod_ops mod_driverops;
1413737Shx147065 static struct modldrv modldrv = {
1423737Shx147065 &mod_driverops,
1433737Shx147065 "Cisco-Aironet 802.11b driver",
1443737Shx147065 &pcan_dev_ops
1453737Shx147065 };
1463737Shx147065
1473737Shx147065 static struct modlinkage modlinkage = {
1483737Shx147065 MODREV_1, (void *)&modldrv, NULL
1493737Shx147065 };
1503737Shx147065
1513737Shx147065 int
_init(void)1523737Shx147065 _init(void)
1533737Shx147065 {
1543737Shx147065 int stat;
1553737Shx147065
1563737Shx147065 /* Allocate soft state */
1573737Shx147065 if ((stat = ddi_soft_state_init(&pcan_soft_state_p,
1583737Shx147065 sizeof (pcan_maci_t), 2)) != DDI_SUCCESS)
1593737Shx147065 return (stat);
1603737Shx147065
1613737Shx147065 mac_init_ops(&pcan_dev_ops, "pcan");
1623737Shx147065 stat = mod_install(&modlinkage);
1633737Shx147065 if (stat != 0) {
1643737Shx147065 mac_fini_ops(&pcan_dev_ops);
1653737Shx147065 ddi_soft_state_fini(&pcan_soft_state_p);
1663737Shx147065 }
1673737Shx147065
1683737Shx147065 return (stat);
1693737Shx147065 }
1703737Shx147065
1713737Shx147065 int
_fini(void)1723737Shx147065 _fini(void)
1733737Shx147065 {
1743737Shx147065 int stat;
1753737Shx147065
1763737Shx147065 stat = mod_remove(&modlinkage);
1773737Shx147065 if (stat != DDI_SUCCESS)
1783737Shx147065 return (stat);
1793737Shx147065 mac_fini_ops(&pcan_dev_ops);
1803737Shx147065 ddi_soft_state_fini(&pcan_soft_state_p);
1813737Shx147065 return (stat);
1823737Shx147065 }
1833737Shx147065
1843737Shx147065 int
_info(struct modinfo * modinfop)1853737Shx147065 _info(struct modinfo *modinfop)
1863737Shx147065 {
1873737Shx147065 return (mod_info(&modlinkage, modinfop));
1883737Shx147065 }
1893737Shx147065
1903737Shx147065 static int
pcan_probe(dev_info_t * dip)1913737Shx147065 pcan_probe(dev_info_t *dip)
1923737Shx147065 {
1933737Shx147065 int len, ret;
1943737Shx147065 char *buf;
1953737Shx147065 dev_info_t *pdip = ddi_get_parent(dip);
1963737Shx147065
1973737Shx147065 PCANDBG((CE_NOTE, "pcan probe: parent dip=0x%p-%s(%d)\n", (void *)pdip,
1983737Shx147065 ddi_driver_name(pdip), ddi_get_instance(pdip)));
1993737Shx147065
2003737Shx147065 ret = ddi_getlongprop(DDI_DEV_T_ANY, pdip, 0, "device_type",
2013737Shx147065 (caddr_t)&buf, &len);
2023737Shx147065 if (ret != DDI_SUCCESS)
2033737Shx147065 return (DDI_PROBE_FAILURE);
2043737Shx147065
2053737Shx147065 PCANDBG((CE_NOTE, "pcan probe: device_type %s\n", buf));
2063737Shx147065 if ((strcmp(buf, "pccard") == 0) || (strcmp(buf, "pcmcia") == 0)) {
2073737Shx147065 pcan_device_type = PCAN_DEVICE_PCCARD;
2083737Shx147065 #ifdef DEBUG
2093737Shx147065 if (pcan_debug & PCAN_DBG_FW_VERSION) {
2103737Shx147065 cmn_err(CE_NOTE, "Cisco 802.11 pccard\n");
2113737Shx147065 }
2123737Shx147065 #endif
2133737Shx147065 ret = DDI_PROBE_SUCCESS;
2143737Shx147065 } else if (strcmp(buf, "pci") == 0) {
2153737Shx147065 pcan_device_type = PCAN_DEVICE_PCI;
2163737Shx147065 #ifdef DEBUG
2173737Shx147065 if (pcan_debug & PCAN_DBG_FW_VERSION) {
2183737Shx147065 cmn_err(CE_NOTE, "Cisco 802.11 minipci card\n");
2193737Shx147065 }
2203737Shx147065 #endif
2213737Shx147065 ret = DDI_PROBE_SUCCESS;
2223737Shx147065 } else {
2233737Shx147065 cmn_err(CE_NOTE, "pcan probe: unsupported card\n");
2243737Shx147065 ret = DDI_PROBE_FAILURE;
2253737Shx147065 }
2263737Shx147065
2273737Shx147065 kmem_free(buf, len);
2283737Shx147065 return (ret);
2293737Shx147065 }
2303737Shx147065
2313737Shx147065 static int
pcan_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)2323737Shx147065 pcan_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2333737Shx147065 {
2343737Shx147065 int ret;
2353737Shx147065 int instance;
2363737Shx147065 uint16_t stat;
2373737Shx147065 uint32_t err;
2383737Shx147065 pcan_maci_t *pcan_p;
2393737Shx147065 wifi_data_t wd = { 0 };
2403737Shx147065 mac_register_t *macp;
2413737Shx147065 modify_config_t cfgmod;
2423737Shx147065 char strbuf[256];
2433737Shx147065
2443737Shx147065 PCANDBG((CE_NOTE, "dip=0x%p cmd=%x\n", (void *)dip, cmd));
2453737Shx147065 if (cmd != DDI_ATTACH)
2463737Shx147065 goto attach_fail1;
2473737Shx147065
2483737Shx147065 /*
2493737Shx147065 * Since this driver is porting from freebsd, so just like
2503737Shx147065 * the original driver, the minipci card doesn't work on amd64
2513737Shx147065 * machine.
2523737Shx147065 * For sparc, since no pci card is available for the test, so this
2533737Shx147065 * version doesn't support sparc. If there is card available and
2543737Shx147065 * requirement, future version will try to support sparc.
2553737Shx147065 * This driver works well for minipci card on 32bit x86
2563737Shx147065 * machine, so keep the code to just support minipci card on 32bit
2573737Shx147065 * mode.
2583737Shx147065 */
2593737Shx147065 #if defined(sparc) || defined(__sparc)
2603737Shx147065 if (pcan_device_type == PCAN_DEVICE_PCI) {
2613737Shx147065 cmn_err(CE_NOTE, "pcan attach: this driver does not support "
2623737Shx147065 "PCI/MiniPCI card on Sparc\n");
2633737Shx147065 goto attach_fail1;
2643737Shx147065 }
2653737Shx147065 #endif /* sparc */
2663737Shx147065 #if defined(__amd64)
2673737Shx147065 if (pcan_device_type == PCAN_DEVICE_PCI) {
2683737Shx147065 cmn_err(CE_NOTE, "pcan attach: this driver does not support "
2693737Shx147065 "PCI/MiniPCI card on amd64\n");
2703737Shx147065 goto attach_fail1;
2713737Shx147065 }
2723737Shx147065 #endif /* amd64 */
2733737Shx147065
2743737Shx147065 /* Allocate soft state associated with this instance. */
2753737Shx147065 if (ddi_soft_state_zalloc(pcan_soft_state_p,
2763737Shx147065 ddi_get_instance(dip)) != DDI_SUCCESS) {
2773737Shx147065 cmn_err(CE_CONT, "pcan attach: alloc softstate failed\n");
2783737Shx147065 goto attach_fail1;
2793737Shx147065 }
2803737Shx147065 pcan_p = (pcan_maci_t *)ddi_get_soft_state(pcan_soft_state_p,
2813737Shx147065 ddi_get_instance(dip));
2823737Shx147065
2833737Shx147065 pcan_p->pcan_device_type = pcan_device_type;
2843737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
2853737Shx147065 if (ddi_regs_map_setup(dip, 0,
2863737Shx147065 (caddr_t *)&pcan_p->pcan_cfg_base, 0, 0,
2873737Shx147065 &accattr, &pcan_p->pcan_cfg_handle) != DDI_SUCCESS)
2883737Shx147065 goto attach_fail2;
2893737Shx147065
2903737Shx147065 stat = ddi_get16(pcan_p->pcan_cfg_handle,
2913737Shx147065 (uint16_t *)(pcan_p->pcan_cfg_base + PCI_CONF_COMM));
2923737Shx147065 stat |= (PCI_COMM_IO | PCI_COMM_MAE);
2933737Shx147065 ddi_put16(pcan_p->pcan_cfg_handle,
2943737Shx147065 (uint16_t *)(pcan_p->pcan_cfg_base + PCI_CONF_COMM), stat);
2953737Shx147065
2963737Shx147065 ddi_regs_map_free(&pcan_p->pcan_cfg_handle);
2973737Shx147065 if (ddi_regs_map_setup(dip, 1, (caddr_t *)&pcan_p->pcan_bar0,
2983737Shx147065 0, 0, &accattr, &pcan_p->pcan_handle0) != DDI_SUCCESS)
2993737Shx147065 goto attach_fail3;
3003737Shx147065 if (ddi_regs_map_setup(dip, 2, (caddr_t *)&pcan_p->pcan_bar1,
3013737Shx147065 0, 0, &accattr, &pcan_p->pcan_handle1) != DDI_SUCCESS)
3023737Shx147065 goto attach_fail3;
3033737Shx147065 if (ddi_regs_map_setup(dip, 3, (caddr_t *)&pcan_p->pcan_bar2,
3043737Shx147065 0, 0, &accattr, &pcan_p->pcan_handle2) != DDI_SUCCESS)
3053737Shx147065 goto attach_fail3;
3063737Shx147065 }
3073737Shx147065
3083737Shx147065 pcan_p->pcan_dip = dip;
3093737Shx147065 pcan_p->pcan_flag = 0;
3103737Shx147065 pcan_p->glds_nocarrier = 0;
3113737Shx147065 pcan_p->glds_noxmtbuf = 0;
3123737Shx147065 pcan_p->glds_norcvbuf = 0;
3133737Shx147065 pcan_p->pcan_socket = ddi_getprop(DDI_DEV_T_NONE, dip,
3144343Sgd78059 DDI_PROP_DONTPASS, "socket", -1);
3153737Shx147065
3163737Shx147065 pcan_p->pcan_reschedule_need = B_FALSE;
3173737Shx147065 pcan_p->pcan_info_softint_pending = 0;
3183737Shx147065 pcan_p->pcan_reset_delay = ddi_getprop(DDI_DEV_T_ANY, dip,
3193737Shx147065 DDI_PROP_DONTPASS, "reset-delay", 5000);
3203737Shx147065
3213737Shx147065 if (ddi_get_iblock_cookie(dip,
3223737Shx147065 0, &pcan_p->pcan_ib_cookie) != DDI_SUCCESS) {
3233737Shx147065 cmn_err(CE_WARN, "pcan attach: get_iblk_cookie failed\n");
3243737Shx147065 goto attach_fail3;
3253737Shx147065 }
3263737Shx147065
3273737Shx147065 mutex_init(&pcan_p->pcan_glock, NULL,
3283737Shx147065 MUTEX_DRIVER, pcan_p->pcan_ib_cookie);
3293737Shx147065 mutex_init(&pcan_p->pcan_scanlist_lock, NULL,
3303737Shx147065 MUTEX_DRIVER, pcan_p->pcan_ib_cookie);
3313737Shx147065 mutex_init(&pcan_p->pcan_txring.an_tx_lock, NULL,
3323737Shx147065 MUTEX_DRIVER, pcan_p->pcan_ib_cookie);
3333737Shx147065
3343737Shx147065 if (ret = ddi_add_softintr(dip, DDI_SOFTINT_LOW,
3353737Shx147065 &pcan_p->pcan_info_softint_id, &pcan_p->pcan_ib_cookie, NULL,
3363737Shx147065 pcan_info_softint, (caddr_t)pcan_p)) {
3373737Shx147065 cmn_err(CE_WARN, "pcan attach: add info_softintr failed\n");
3383737Shx147065 goto attach_fail3a;
3393737Shx147065 }
3403737Shx147065
3413737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
3423737Shx147065 if (ret = ddi_add_intr(dip, 0, NULL, NULL,
3433737Shx147065 pcan_intr, (caddr_t)pcan_p)) {
3443737Shx147065 cmn_err(CE_WARN, "pcan attach: add intr failed\n");
3453737Shx147065 goto attach_fail4;
3463737Shx147065 }
3473737Shx147065 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
3483737Shx147065 if (ret = pcan_register_cs(dip, pcan_p)) {
3493737Shx147065 PCANDBG((CE_NOTE, "pcan attach: register_cs failed"
3503737Shx147065 " %x\n", ret));
3513737Shx147065 goto attach_fail4;
3523737Shx147065 }
3533737Shx147065 } else {
3543737Shx147065 cmn_err(CE_WARN, "pcan attach: unsupported device type\n");
3553737Shx147065 goto attach_fail4;
3563737Shx147065 }
3573737Shx147065
3583737Shx147065 mutex_enter(&pcan_p->pcan_glock);
3593737Shx147065 pcan_reset_backend(pcan_p, pcan_p->pcan_reset_delay);
3603737Shx147065 /* leaves IF down, intr disabled */
3613737Shx147065
3623737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
3633737Shx147065 if (ret = pcan_init_dma(dip, pcan_p)) {
3643737Shx147065 cmn_err(CE_WARN, "pcan init_dma: failed\n");
3653737Shx147065 mutex_exit(&pcan_p->pcan_glock);
3663737Shx147065 goto attach_fail5;
3673737Shx147065 }
3683737Shx147065 }
3693737Shx147065 if (ret = pcan_get_cap(pcan_p)) { /* sets macaddr for gld_register */
3703737Shx147065 cmn_err(CE_WARN, "pcan attach: get_cap failed %x\n", ret);
3713737Shx147065 mutex_exit(&pcan_p->pcan_glock);
3723737Shx147065 goto attach_fail6;
3733737Shx147065 }
3743737Shx147065
3753737Shx147065 mutex_exit(&pcan_p->pcan_glock);
3763737Shx147065 /*
3773737Shx147065 * Provide initial settings for the WiFi plugin; whenever this
3783737Shx147065 * information changes, we need to call mac_pdata_update()
3793737Shx147065 */
3803737Shx147065 wd.wd_secalloc = WIFI_SEC_NONE;
3813737Shx147065 wd.wd_opmode = IEEE80211_M_STA;
3823737Shx147065
3833737Shx147065 macp = mac_alloc(MAC_VERSION);
3843737Shx147065 if (macp == NULL) {
3853737Shx147065 PCANDBG((CE_NOTE, "pcan attach: "
3863737Shx147065 "MAC version mismatch\n"));
3873737Shx147065 goto attach_fail6;
3883737Shx147065 }
3893737Shx147065
3903737Shx147065 macp->m_type_ident = MAC_PLUGIN_IDENT_WIFI;
3913737Shx147065 macp->m_driver = pcan_p;
3923737Shx147065 macp->m_dip = dip;
3933737Shx147065 macp->m_src_addr = pcan_p->pcan_mac_addr;
3943737Shx147065 macp->m_callbacks = &pcan_m_callbacks;
3953737Shx147065 macp->m_min_sdu = 0;
3963737Shx147065 macp->m_max_sdu = IEEE80211_MTU;
3973737Shx147065 macp->m_pdata = &wd;
3983737Shx147065 macp->m_pdata_size = sizeof (wd);
3993737Shx147065
4003737Shx147065 err = mac_register(macp, &pcan_p->pcan_mh);
4013737Shx147065 mac_free(macp);
4023737Shx147065 if (err != 0) {
4033737Shx147065 PCANDBG((CE_NOTE, "pcan attach: "
4043737Shx147065 "mac_register err\n"));
4053737Shx147065 goto attach_fail6;
4063737Shx147065 }
4073737Shx147065
4083737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
4093737Shx147065 /* turn on CS interrupt */
4103737Shx147065 cfgmod.Attributes = CONF_ENABLE_IRQ_STEERING |
4113737Shx147065 CONF_IRQ_CHANGE_VALID;
4123737Shx147065 cfgmod.Vpp1 = 50;
4133737Shx147065 cfgmod.Vpp2 = 50;
4143737Shx147065 (void) csx_ModifyConfiguration(pcan_p->pcan_chdl, &cfgmod);
4153737Shx147065
4163737Shx147065 mutex_enter(&pcan_p->pcan_glock);
4173737Shx147065 if (ret = pcan_init_nicmem(pcan_p)) {
4183737Shx147065 cmn_err(CE_WARN, "pcan attach: init_nicmem failed %x\n",
4193737Shx147065 ret);
4203737Shx147065 mutex_exit(&pcan_p->pcan_glock);
4213737Shx147065 goto attach_fail7;
4223737Shx147065 }
4233737Shx147065 mutex_exit(&pcan_p->pcan_glock);
4243737Shx147065 }
4253737Shx147065 (void) ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
4263737Shx147065 "bad-rids", (caddr_t)&pcan_p->pcan_badrids,
4273737Shx147065 &pcan_p->pcan_badrids_len);
4283737Shx147065
4293737Shx147065 pcan_p->an_config.an_rxmode = AN_NORMAL_RXMODE;
4303737Shx147065 ether_copy(pcan_p->pcan_mac_addr, pcan_p->an_config.an_macaddr);
4313737Shx147065 mutex_enter(&pcan_p->pcan_glock);
4323737Shx147065 list_create(&pcan_p->an_scan_list, sizeof (an_scan_list_t),
4333737Shx147065 offsetof(an_scan_list_t, an_scan_node));
4343737Shx147065 pcan_p->an_scan_num = 0;
4353737Shx147065 mutex_exit(&pcan_p->pcan_glock);
4363737Shx147065 pcan_p->an_scanlist_timeout_id = timeout(pcan_scanlist_timeout,
4373737Shx147065 pcan_p, drv_usectohz(1000000));
4383737Shx147065
4393737Shx147065 instance = ddi_get_instance(dip);
4403737Shx147065 (void) snprintf(strbuf, sizeof (strbuf), "pcan%d", instance);
4413737Shx147065 if (ddi_create_minor_node(dip, strbuf, S_IFCHR,
4423737Shx147065 instance + 1, DDI_NT_NET_WIFI, 0) != DDI_SUCCESS) {
4433737Shx147065 goto attach_fail8;
4443737Shx147065 }
4453737Shx147065 mutex_enter(&pcan_p->pcan_glock);
4463737Shx147065 PCAN_DISABLE_INTR_CLEAR(pcan_p);
4473737Shx147065 (void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0);
4483737Shx147065 pcan_p->pcan_flag |= PCAN_ATTACHED;
4493737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
4503737Shx147065 pcan_p->pcan_flag |= PCAN_CARD_READY;
4513737Shx147065 }
4523737Shx147065 mutex_exit(&pcan_p->pcan_glock);
4533737Shx147065 return (DDI_SUCCESS);
4543737Shx147065 attach_fail8:
4553737Shx147065 if (pcan_p->an_scanlist_timeout_id != 0) {
4563737Shx147065 (void) untimeout(pcan_p->an_scanlist_timeout_id);
4573737Shx147065 pcan_p->an_scanlist_timeout_id = 0;
4583737Shx147065 }
4593737Shx147065 list_destroy(&pcan_p->an_scan_list);
4603737Shx147065 attach_fail7:
4613737Shx147065 (void) mac_unregister(pcan_p->pcan_mh);
4623737Shx147065 attach_fail6:
4633737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI)
4643737Shx147065 pcan_free_dma(pcan_p);
4653737Shx147065 attach_fail5:
4663737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
4673737Shx147065 ddi_remove_intr(dip, 0, pcan_p->pcan_ib_cookie);
4683737Shx147065 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
4693737Shx147065 pcan_unregister_cs(pcan_p);
4703737Shx147065 }
4713737Shx147065 attach_fail4:
4723737Shx147065 if (pcan_p->pcan_info_softint_id)
4733737Shx147065 ddi_remove_softintr(pcan_p->pcan_info_softint_id);
4743737Shx147065 attach_fail3a:
4753737Shx147065 pcan_destroy_locks(pcan_p);
4763737Shx147065 attach_fail3:
4773737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
4783737Shx147065 if (pcan_p->pcan_handle0)
4793737Shx147065 ddi_regs_map_free(&pcan_p->pcan_handle0);
4803737Shx147065 if (pcan_p->pcan_handle1)
4813737Shx147065 ddi_regs_map_free(&pcan_p->pcan_handle1);
4823737Shx147065 if (pcan_p->pcan_handle2)
4833737Shx147065 ddi_regs_map_free(&pcan_p->pcan_handle2);
4843737Shx147065 }
4853737Shx147065 attach_fail2:
4863737Shx147065 ddi_soft_state_free(pcan_soft_state_p, ddi_get_instance(dip));
4873737Shx147065 attach_fail1:
4883737Shx147065 return (DDI_FAILURE);
4893737Shx147065 }
4903737Shx147065
4913737Shx147065 static int
pcan_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)4923737Shx147065 pcan_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
4933737Shx147065 {
4943737Shx147065 pcan_maci_t *pcan_p;
4953737Shx147065 an_scan_list_t *scan_item0;
4963737Shx147065 int ret;
4973737Shx147065 pcan_p = ddi_get_soft_state(pcan_soft_state_p, ddi_get_instance(dip));
4983737Shx147065
4993737Shx147065 if (cmd != DDI_DETACH)
5003737Shx147065 return (DDI_FAILURE);
5013737Shx147065 if (!(pcan_p->pcan_flag & PCAN_ATTACHED))
5023737Shx147065 return (DDI_FAILURE);
5037507SXinghua.Wen@Sun.COM
5047507SXinghua.Wen@Sun.COM ret = mac_disable(pcan_p->pcan_mh);
5057507SXinghua.Wen@Sun.COM if (ret != 0)
5067507SXinghua.Wen@Sun.COM return (DDI_FAILURE);
5077507SXinghua.Wen@Sun.COM
5083737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
5093737Shx147065 mutex_enter(&pcan_p->pcan_glock);
5103737Shx147065 pcan_stop_locked(pcan_p);
5113737Shx147065 PCAN_DISABLE_INTR(pcan_p);
5123737Shx147065 mutex_exit(&pcan_p->pcan_glock);
5133737Shx147065 }
5143737Shx147065 if (pcan_p->an_scanlist_timeout_id != 0) {
5153737Shx147065 (void) untimeout(pcan_p->an_scanlist_timeout_id);
5163737Shx147065 pcan_p->an_scanlist_timeout_id = 0;
5173737Shx147065 }
5183737Shx147065 if (pcan_p->pcan_connect_timeout_id != 0) {
5193737Shx147065 (void) untimeout(pcan_p->pcan_connect_timeout_id);
5203737Shx147065 pcan_p->pcan_connect_timeout_id = 0;
5213737Shx147065 }
5223737Shx147065 mutex_enter(&pcan_p->pcan_scanlist_lock);
5233737Shx147065 scan_item0 = list_head(&pcan_p->an_scan_list);
5243737Shx147065 while (scan_item0) {
5253737Shx147065 pcan_delete_scan_item(pcan_p, scan_item0);
5263737Shx147065 scan_item0 = list_head(&pcan_p->an_scan_list);
5273737Shx147065 }
5283737Shx147065 list_destroy(&pcan_p->an_scan_list);
5293737Shx147065 mutex_exit(&pcan_p->pcan_scanlist_lock);
5303737Shx147065
5317507SXinghua.Wen@Sun.COM (void) mac_unregister(pcan_p->pcan_mh);
5323737Shx147065
5333737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
53411101SMikore.Li@Sun.COM mutex_enter(&pcan_p->pcan_glock);
5353737Shx147065 ddi_remove_intr(dip, 0, pcan_p->pcan_ib_cookie);
5363737Shx147065 pcan_free_dma(pcan_p);
5373737Shx147065 if (pcan_p->pcan_handle0)
5383737Shx147065 ddi_regs_map_free(&pcan_p->pcan_handle0);
5393737Shx147065 if (pcan_p->pcan_handle1)
5403737Shx147065 ddi_regs_map_free(&pcan_p->pcan_handle1);
5413737Shx147065 if (pcan_p->pcan_handle2)
5423737Shx147065 ddi_regs_map_free(&pcan_p->pcan_handle2);
54311101SMikore.Li@Sun.COM mutex_exit(&pcan_p->pcan_glock);
5443737Shx147065 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
5453737Shx147065 pcan_unregister_cs(pcan_p);
5463737Shx147065 } else {
5473737Shx147065 cmn_err(CE_WARN, "pcan detach: unsupported device type\n");
5483737Shx147065 }
5493737Shx147065 pcan_destroy_locks(pcan_p);
5503737Shx147065 if (pcan_p->pcan_info_softint_id)
5513737Shx147065 ddi_remove_softintr(pcan_p->pcan_info_softint_id);
5523737Shx147065
5533737Shx147065 if (pcan_p->pcan_badrids_len)
5543737Shx147065 kmem_free(pcan_p->pcan_badrids, pcan_p->pcan_badrids_len);
5553737Shx147065
5563737Shx147065 ddi_soft_state_free(pcan_soft_state_p, ddi_get_instance(dip));
5573737Shx147065 ddi_remove_minor_node(dip, NULL);
5583737Shx147065
5593737Shx147065 return (DDI_SUCCESS);
5603737Shx147065 }
5613737Shx147065
5623737Shx147065 /*
5633737Shx147065 * card services and event handlers
5643737Shx147065 */
5653737Shx147065
5663737Shx147065 static int
pcan_register_cs(dev_info_t * dip,pcan_maci_t * pcan_p)5673737Shx147065 pcan_register_cs(dev_info_t *dip, pcan_maci_t *pcan_p)
5683737Shx147065 {
5693737Shx147065 int ret;
5703737Shx147065 client_reg_t cr;
5713737Shx147065 client_handle_t chdl; /* uint encoding of socket, function, client */
5723737Shx147065 get_status_t card_status;
5733737Shx147065 request_socket_mask_t sock_req;
5743737Shx147065
5753737Shx147065 bzero(&cr, sizeof (cr));
5763737Shx147065 cr.Attributes = INFO_IO_CLIENT|INFO_CARD_EXCL|INFO_CARD_SHARE;
5773737Shx147065 cr.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
5783737Shx147065 CS_EVENT_REGISTRATION_COMPLETE | CS_EVENT_CARD_REMOVAL_LOWP |
5793737Shx147065 CS_EVENT_CARD_READY | CS_EVENT_PM_RESUME | CS_EVENT_PM_SUSPEND |
5803737Shx147065 CS_EVENT_CLIENT_INFO;
5813737Shx147065 cr.event_callback_args.client_data = pcan_p;
5823737Shx147065 cr.Version = CS_VERSION;
5833737Shx147065 cr.event_handler = (csfunction_t *)pcan_ev_hdlr;
5843737Shx147065 cr.dip = dip;
5853737Shx147065 (void) strcpy(cr.driver_name, pcan_name_str);
5863737Shx147065 if (ret = csx_RegisterClient(&chdl, &cr)) {
5873737Shx147065 cmn_err(CE_WARN, "pcan: RegisterClient failed %x", ret);
5883737Shx147065 goto regcs_ret;
5893737Shx147065 }
5903737Shx147065
5913737Shx147065 pcan_p->pcan_chdl = chdl;
5923737Shx147065
5933737Shx147065 bzero(&card_status, sizeof (card_status));
5943737Shx147065 (void) csx_GetStatus(chdl, &card_status);
5953737Shx147065 PCANDBG((CE_NOTE, "pcan: getstat Sock=%x CState=%x SState=%x rState=%x",
5963737Shx147065 card_status.Socket, card_status.CardState,
5973737Shx147065 card_status.SocketState, card_status.raw_CardState));
5983737Shx147065 if (!(card_status.CardState & CS_STATUS_CARD_INSERTED)) {
5993737Shx147065 /* card is not present, why are we attaching ? */
6003737Shx147065 ret = CS_NO_CARD;
6013737Shx147065 goto unreg;
6023737Shx147065 }
6033737Shx147065 cv_init(&pcan_p->pcan_cscv, NULL, CV_DRIVER, NULL);
6043737Shx147065 mutex_init(&pcan_p->pcan_cslock, NULL, MUTEX_DRIVER, *cr.iblk_cookie);
6053737Shx147065 mutex_enter(&pcan_p->pcan_cslock);
6063737Shx147065 if (ret = csx_MapLogSocket(chdl, &pcan_p->pcan_log_sock)) {
6073737Shx147065 cmn_err(CE_WARN, "pcan: MapLogSocket failed %x", ret);
6083737Shx147065 goto fail;
6093737Shx147065 }
6103737Shx147065 PCANDBG((CE_NOTE, "pcan: logsock: LogSock=%x PhyAdapter=%x PhySock=%x",
6113737Shx147065 pcan_p->pcan_log_sock.LogSocket,
6123737Shx147065 pcan_p->pcan_log_sock.PhyAdapter,
6133737Shx147065 pcan_p->pcan_log_sock.PhySocket));
6143737Shx147065
6153737Shx147065 /* turn on initialization events */
6163737Shx147065 sock_req.Socket = 0;
6173737Shx147065 sock_req.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
6183737Shx147065 CS_EVENT_REGISTRATION_COMPLETE;
6193737Shx147065 if (ret = csx_RequestSocketMask(chdl, &sock_req)) {
6203737Shx147065 cmn_err(CE_WARN, "pcan: RequestSocketMask failed %x\n", ret);
6213737Shx147065 goto fail;
6223737Shx147065 }
6233737Shx147065
6243737Shx147065 /* wait for and process card insertion events */
6253737Shx147065 while (!(pcan_p->pcan_flag & PCAN_CARD_READY))
6263737Shx147065 cv_wait(&pcan_p->pcan_cscv, &pcan_p->pcan_cslock);
6273737Shx147065 mutex_exit(&pcan_p->pcan_cslock);
6283737Shx147065
6293737Shx147065 pcan_p->pcan_flag |= PCAN_CS_REGISTERED;
6303737Shx147065 return (CS_SUCCESS);
6313737Shx147065 fail:
6323737Shx147065 mutex_destroy(&pcan_p->pcan_cslock);
6333737Shx147065 cv_destroy(&pcan_p->pcan_cscv);
6343737Shx147065 unreg:
6353737Shx147065 (void) csx_DeregisterClient(chdl);
6363737Shx147065 regcs_ret:
6373737Shx147065 pcan_p->pcan_flag &= ~PCAN_CS_REGISTERED;
6383737Shx147065 return (ret);
6393737Shx147065 }
6403737Shx147065
6413737Shx147065 static void
pcan_unregister_cs(pcan_maci_t * pcan_p)6423737Shx147065 pcan_unregister_cs(pcan_maci_t *pcan_p)
6433737Shx147065 {
6443737Shx147065 int ret;
6453737Shx147065 release_socket_mask_t mask;
6463737Shx147065 mask.Socket = pcan_p->pcan_socket;
6473737Shx147065
6483737Shx147065 /*
6493737Shx147065 * The card service not registered means register_cs function
6503737Shx147065 * doesnot return TRUE. Then all the lelated resource has been
6513737Shx147065 * released in register_cs.
6523737Shx147065 */
6533737Shx147065 if (!(pcan_p->pcan_flag | PCAN_CS_REGISTERED))
6543737Shx147065 return;
6553737Shx147065 (void) csx_ReleaseSocketMask(pcan_p->pcan_chdl, &mask);
6563737Shx147065
6573737Shx147065 if (pcan_p->pcan_flag & PCAN_CARD_READY) {
6583737Shx147065 pcan_card_remove(pcan_p);
6593737Shx147065 }
6603737Shx147065 mutex_destroy(&pcan_p->pcan_cslock);
6613737Shx147065 cv_destroy(&pcan_p->pcan_cscv);
6623737Shx147065 if (ret = csx_DeregisterClient(pcan_p->pcan_chdl))
6633737Shx147065 cmn_err(CE_WARN, "pcan: deregister failed %x\n", ret);
6643737Shx147065 }
6653737Shx147065 static void
pcan_destroy_locks(pcan_maci_t * pcan_p)6663737Shx147065 pcan_destroy_locks(pcan_maci_t *pcan_p)
6673737Shx147065 {
6683737Shx147065 mutex_destroy(&pcan_p->pcan_txring.an_tx_lock);
6693737Shx147065 mutex_destroy(&pcan_p->pcan_scanlist_lock);
6703737Shx147065 mutex_destroy(&pcan_p->pcan_glock);
6713737Shx147065 }
6723737Shx147065
6733737Shx147065 static int
pcan_ev_hdlr(event_t event,int priority,event_callback_args_t * arg)6743737Shx147065 pcan_ev_hdlr(event_t event, int priority, event_callback_args_t *arg)
6753737Shx147065 {
6763737Shx147065 int ret = CS_SUCCESS;
6773737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg->client_data;
6783737Shx147065 client_info_t *ci_p = (client_info_t *)&arg->client_info;
6793737Shx147065
6803737Shx147065 mutex_enter(&pcan_p->pcan_cslock);
6813737Shx147065 switch (event) {
6823737Shx147065 case CS_EVENT_CARD_INSERTION:
6833737Shx147065 ret = pcan_card_insert(pcan_p);
6843737Shx147065 cv_broadcast(&pcan_p->pcan_cscv);
6853737Shx147065 break;
6863737Shx147065 case CS_EVENT_REGISTRATION_COMPLETE:
6873737Shx147065 cv_broadcast(&pcan_p->pcan_cscv);
6883737Shx147065 break;
6893737Shx147065 case CS_EVENT_CARD_REMOVAL:
6903737Shx147065 if (priority & CS_EVENT_PRI_HIGH)
6913737Shx147065 break;
6923737Shx147065 pcan_card_remove(pcan_p);
6933737Shx147065 cv_broadcast(&pcan_p->pcan_cscv);
6943737Shx147065 break;
6953737Shx147065 case CS_EVENT_CLIENT_INFO:
6963737Shx147065 if (GET_CLIENT_INFO_SUBSVC(ci_p->Attributes) !=
6973737Shx147065 CS_CLIENT_INFO_SUBSVC_CS)
6983737Shx147065 break;
6993737Shx147065
7003737Shx147065 ci_p->Revision = 0x0101;
7013737Shx147065 ci_p->CSLevel = CS_VERSION;
7023737Shx147065 ci_p->RevDate = CS_CLIENT_INFO_MAKE_DATE(9, 12, 14);
7033737Shx147065 (void) strcpy(ci_p->ClientName, PCAN_IDENT_STRING);
7043737Shx147065 (void) strcpy(ci_p->VendorName, CS_SUN_VENDOR_DESCRIPTION);
7053737Shx147065 ci_p->Attributes |= CS_CLIENT_INFO_VALID;
7063737Shx147065 break;
70711101SMikore.Li@Sun.COM case CS_EVENT_PM_SUSPEND:
70811101SMikore.Li@Sun.COM pcan_do_suspend(pcan_p);
70911101SMikore.Li@Sun.COM break;
7103737Shx147065 default:
7113737Shx147065 ret = CS_UNSUPPORTED_EVENT;
7123737Shx147065 break;
7133737Shx147065 }
7143737Shx147065 mutex_exit(&pcan_p->pcan_cslock);
7153737Shx147065 return (ret);
7163737Shx147065 }
7173737Shx147065
7183737Shx147065 static int
pcan_card_insert(pcan_maci_t * pcan_p)7193737Shx147065 pcan_card_insert(pcan_maci_t *pcan_p)
7203737Shx147065 {
7213737Shx147065 int ret, hi, lo;
7223737Shx147065 tuple_t tuple;
7233737Shx147065 cisparse_t cisparse;
7243737Shx147065 io_req_t io;
7253737Shx147065 irq_req_t irq;
7263737Shx147065 config_req_t cfg;
7273737Shx147065 cistpl_config_t config;
7283737Shx147065 cistpl_cftable_entry_t *tbl_p;
7293737Shx147065 register client_handle_t chdl = pcan_p->pcan_chdl;
73011101SMikore.Li@Sun.COM modify_config_t cfgmod;
7313737Shx147065
7323737Shx147065 bzero(&tuple, sizeof (tuple));
7333737Shx147065 tuple.DesiredTuple = CISTPL_MANFID;
7343737Shx147065 if (ret = csx_GetFirstTuple(chdl, &tuple)) {
7353737Shx147065 cmn_err(CE_WARN, "pcan: get manufacture id failed %x\n", ret);
7363737Shx147065 goto insert_ret;
7373737Shx147065 }
7383737Shx147065 bzero(&cisparse, sizeof (cisparse));
7393737Shx147065 if (ret = csx_Parse_CISTPL_MANFID(chdl, &tuple, &cisparse.manfid)) {
7403737Shx147065 cmn_err(CE_WARN, "pcan: parse manufacture id failed %x\n", ret);
7413737Shx147065 goto insert_ret;
7423737Shx147065 }
7433737Shx147065 /* verify manufacture ID */
7443737Shx147065 PCANDBG((CE_NOTE, "pcan: manufacturer_id=%x card=%x\n",
7453737Shx147065 cisparse.manfid.manf, cisparse.manfid.card));
7463737Shx147065
7473737Shx147065 bzero(&tuple, sizeof (tuple));
7483737Shx147065 tuple.DesiredTuple = CISTPL_FUNCID;
7493737Shx147065 if (ret = csx_GetFirstTuple(chdl, &tuple)) {
7503737Shx147065 cmn_err(CE_WARN, "pcan: get function id failed %x\n", ret);
7513737Shx147065 goto insert_ret;
7523737Shx147065 }
7533737Shx147065 bzero(&cisparse, sizeof (cisparse));
7543737Shx147065 if (ret = csx_Parse_CISTPL_FUNCID(chdl, &tuple, &cisparse.funcid)) {
7553737Shx147065 cmn_err(CE_WARN, "pcan: parse function id failed %x\n", ret);
7563737Shx147065 goto insert_ret;
7573737Shx147065 }
7583737Shx147065 /* verify function ID */
7593737Shx147065 PCANDBG((CE_NOTE, "funcid=%x\n", cisparse.funcid.function));
7603737Shx147065
7613737Shx147065 bzero(&tuple, sizeof (tuple));
7623737Shx147065 tuple.DesiredTuple = CISTPL_CONFIG;
7633737Shx147065 if (ret = csx_GetFirstTuple(chdl, &tuple)) {
7643737Shx147065 cmn_err(CE_WARN, "pcan: get config failed %x\n", ret);
7653737Shx147065 goto insert_ret;
7663737Shx147065 }
7673737Shx147065 bzero(&config, sizeof (config));
7683737Shx147065 if (ret = csx_Parse_CISTPL_CONFIG(chdl, &tuple, &config)) {
7693737Shx147065 cmn_err(CE_WARN, "pcan: parse config failed %x\n", ret);
7703737Shx147065 goto insert_ret;
7713737Shx147065 }
7723737Shx147065 PCANDBG((CE_NOTE,
7733737Shx147065 "pcan: config present=%x nr=%x hr=%x regs[0]=%x base=%x last=%x\n",
7743737Shx147065 config.present, config.nr, config.hr, config.regs[0],
7753737Shx147065 config.base, config.last));
7763737Shx147065
7773737Shx147065 hi = 0;
7783737Shx147065 lo = (int)-1; /* really big number */
7793737Shx147065 tbl_p = &cisparse.cftable;
7803737Shx147065 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
7813737Shx147065 for (tbl_p->index = 0; tbl_p->index <= config.hr; ) {
7823737Shx147065 PCANDBG((CE_NOTE, "pcan: tuple idx=%x:\n", tbl_p->index));
7833737Shx147065 if (ret = csx_GetNextTuple(chdl, &tuple)) {
7843737Shx147065 cmn_err(CE_WARN, "pcan: get cftable failed %x\n", ret);
7853737Shx147065 break;
7863737Shx147065 }
7873737Shx147065 bzero((caddr_t)&cisparse, sizeof (cisparse));
7883737Shx147065 if (ret = csx_Parse_CISTPL_CFTABLE_ENTRY(chdl, &tuple, tbl_p)) {
7893737Shx147065 cmn_err(CE_WARN, "pcan: parse cftable failed%x\n", ret);
7903737Shx147065 break;
7913737Shx147065 }
7923737Shx147065 if (tbl_p->flags & CISTPL_CFTABLE_TPCE_FS_PWR &&
7934343Sgd78059 tbl_p->pd.flags & CISTPL_CFTABLE_TPCE_FS_PWR_VCC) {
7943737Shx147065 if (tbl_p->pd.pd_vcc.avgI > hi) {
7953737Shx147065 hi = tbl_p->pd.pd_vcc.avgI;
7963737Shx147065 pcan_p->pcan_config_hi = tbl_p->index;
7973737Shx147065 }
7983737Shx147065 if (tbl_p->pd.pd_vcc.avgI < lo) {
7993737Shx147065 lo = tbl_p->pd.pd_vcc.avgI;
8003737Shx147065 pcan_p->pcan_config = tbl_p->index;
8013737Shx147065 }
8023737Shx147065 }
8033737Shx147065 if (tbl_p->flags & CISTPL_CFTABLE_TPCE_DEFAULT) {
8043737Shx147065 if (tbl_p->pd.flags & CISTPL_CFTABLE_TPCE_FS_PWR_VCC)
8053737Shx147065 pcan_p->pcan_vcc = tbl_p->pd.pd_vcc.nomV;
8063737Shx147065 if (tbl_p->flags & CISTPL_CFTABLE_TPCE_FS_IO)
8073737Shx147065 pcan_p->pcan_iodecode = tbl_p->io.addr_lines;
8083737Shx147065 }
8093737Shx147065 }
8103737Shx147065 PCANDBG((CE_NOTE, "pcan: cfg_hi=%x cfg=%x vcc=%x iodecode=%x\n",
8113737Shx147065 pcan_p->pcan_config_hi, pcan_p->pcan_config,
8123737Shx147065 pcan_p->pcan_vcc, pcan_p->pcan_iodecode));
8133737Shx147065
8143737Shx147065 bzero(&io, sizeof (io));
8153737Shx147065 io.BasePort1.base = 0;
8163737Shx147065 io.NumPorts1 = 1 << pcan_p->pcan_iodecode;
8173737Shx147065 io.Attributes1 = IO_DATA_PATH_WIDTH_16;
8183737Shx147065 io.IOAddrLines = pcan_p->pcan_iodecode;
8193737Shx147065 if (ret = csx_RequestIO(chdl, &io)) {
8203737Shx147065 cmn_err(CE_WARN, "pcan: RequestIO failed %x\n", ret);
8213737Shx147065 goto insert_ret;
8223737Shx147065 }
8233737Shx147065 pcan_p->pcan_port = io.BasePort1.handle;
8243737Shx147065
8253737Shx147065 if (ret = ddi_add_softintr(DIP(pcan_p), DDI_SOFTINT_HIGH,
8263737Shx147065 &pcan_p->pcan_softint_id, &pcan_p->pcan_ib_cookie, NULL,
8273737Shx147065 pcan_intr, (caddr_t)pcan_p)) {
8283737Shx147065 cmn_err(CE_NOTE, "pcan: Add softintr failed\n");
8293737Shx147065 goto insert_ret;
8303737Shx147065 }
8313737Shx147065 irq.Attributes = IRQ_TYPE_EXCLUSIVE;
8323737Shx147065 irq.irq_handler = ddi_intr_hilevel(DIP(pcan_p), 0) ?
8333737Shx147065 (csfunction_t *)pcan_intr_hi : (csfunction_t *)pcan_intr;
8343737Shx147065 irq.irq_handler_arg = pcan_p;
8353737Shx147065 if (ret = csx_RequestIRQ(chdl, &irq)) {
8363737Shx147065 cmn_err(CE_WARN, "pcan: RequestIRQ failed %x\n", ret);
8373737Shx147065 goto un_io;
8383737Shx147065 }
8393737Shx147065
8403737Shx147065 bzero(&cfg, sizeof (cfg));
8413737Shx147065 cfg.Attributes = 0; /* not ready for CONF_ENABLE_IRQ_STEERING yet */
8423737Shx147065 cfg.Vcc = 50; /* pcan_vcc == 0 */
8433737Shx147065 cfg.Vpp1 = 50;
8443737Shx147065 cfg.Vpp2 = 50;
8453737Shx147065 cfg.IntType = SOCKET_INTERFACE_MEMORY_AND_IO;
8463737Shx147065 cfg.ConfigBase = config.base;
8473737Shx147065 cfg.ConfigIndex = pcan_p->pcan_config;
8483737Shx147065 cfg.Status = CCSR_IO_IS_8; /* no use */
8493737Shx147065 cfg.Present = config.present;
8503737Shx147065 pcan_p->pcan_flag |= PCAN_CARD_READY;
8513737Shx147065 if (ret = csx_RequestConfiguration(chdl, &cfg)) {
8523737Shx147065 cmn_err(CE_WARN, "pcan: RequestConfiguration failed %x\n", ret);
8533737Shx147065 goto un_irq;
8543737Shx147065 }
85511101SMikore.Li@Sun.COM
85611101SMikore.Li@Sun.COM if (pcan_p->pcan_flag & PCAN_SUSPENDED) {
85711101SMikore.Li@Sun.COM mutex_enter(&pcan_p->pcan_glock);
85811101SMikore.Li@Sun.COM pcan_reset_backend(pcan_p, pcan_p->pcan_reset_delay);
85911101SMikore.Li@Sun.COM /* turn on CS interrupt */
86011101SMikore.Li@Sun.COM cfgmod.Attributes = CONF_ENABLE_IRQ_STEERING |
86111101SMikore.Li@Sun.COM CONF_IRQ_CHANGE_VALID;
86211101SMikore.Li@Sun.COM cfgmod.Vpp1 = 50;
86311101SMikore.Li@Sun.COM cfgmod.Vpp2 = 50;
86411101SMikore.Li@Sun.COM (void) csx_ModifyConfiguration(pcan_p->pcan_chdl, &cfgmod);
86511101SMikore.Li@Sun.COM
86611101SMikore.Li@Sun.COM if (ret = pcan_init_nicmem(pcan_p)) {
86711101SMikore.Li@Sun.COM cmn_err(CE_WARN, "pcan insert: init_nicmem failed %x\n",
86811101SMikore.Li@Sun.COM ret);
86911101SMikore.Li@Sun.COM }
87011101SMikore.Li@Sun.COM PCAN_DISABLE_INTR_CLEAR(pcan_p);
87111101SMikore.Li@Sun.COM ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0);
87211101SMikore.Li@Sun.COM PCANDBG((CE_NOTE, "pcan insert set cmd ret =%x\n", ret));
87311101SMikore.Li@Sun.COM pcan_p->pcan_flag &= ~PCAN_SUSPENDED;
87411101SMikore.Li@Sun.COM mutex_exit(&pcan_p->pcan_glock);
87511101SMikore.Li@Sun.COM }
87611101SMikore.Li@Sun.COM
87711101SMikore.Li@Sun.COM if (pcan_p->pcan_flag & PCAN_PLUMBED) {
87811121SMikore.Li@Sun.COM (void) pcan_start(pcan_p);
87911101SMikore.Li@Sun.COM pcan_p->pcan_flag &= ~PCAN_PLUMBED;
88011101SMikore.Li@Sun.COM PCANDBG((CE_NOTE, "pcan insert: active interrupt\n"));
88111101SMikore.Li@Sun.COM }
8823737Shx147065 return (CS_SUCCESS);
8833737Shx147065 un_irq:
8843737Shx147065 (void) csx_ReleaseIRQ(chdl, &irq);
8853737Shx147065 un_io:
8863737Shx147065 ddi_remove_softintr(pcan_p->pcan_softint_id);
8873737Shx147065
8883737Shx147065 (void) csx_ReleaseIO(chdl, &io);
8893737Shx147065 pcan_p->pcan_port = 0;
8903737Shx147065 insert_ret:
8913737Shx147065 pcan_p->pcan_flag &= ~PCAN_CARD_READY;
8923737Shx147065 return (ret);
8933737Shx147065 }
8943737Shx147065
8953737Shx147065 /*
8963737Shx147065 * assume card is already removed, don't touch the hardware
8973737Shx147065 */
8983737Shx147065 static void
pcan_do_suspend(pcan_maci_t * pcan_p)89911101SMikore.Li@Sun.COM pcan_do_suspend(pcan_maci_t *pcan_p)
90011101SMikore.Li@Sun.COM {
90111101SMikore.Li@Sun.COM int ret;
90211101SMikore.Li@Sun.COM if (pcan_p->pcan_flag & PCAN_CARD_LINKUP) {
90311101SMikore.Li@Sun.COM if (pcan_p->pcan_connect_timeout_id != 0) {
90411101SMikore.Li@Sun.COM (void) untimeout(pcan_p->pcan_connect_timeout_id);
90511101SMikore.Li@Sun.COM pcan_p->pcan_connect_timeout_id = 0;
90611101SMikore.Li@Sun.COM }
90711101SMikore.Li@Sun.COM mutex_enter(&pcan_p->pcan_glock);
90811101SMikore.Li@Sun.COM pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
90911101SMikore.Li@Sun.COM if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0))
91011101SMikore.Li@Sun.COM PCANDBG((CE_NOTE, "pcan: disable failed, ret %d\n",
91111101SMikore.Li@Sun.COM ret));
91211101SMikore.Li@Sun.COM if (ret = pcan_loaddef(pcan_p))
91311101SMikore.Li@Sun.COM PCANDBG((CE_NOTE, "pcan: loaddef failed, ret %d\n",
91411101SMikore.Li@Sun.COM ret));
91511101SMikore.Li@Sun.COM mac_link_update(GLD3(pcan_p), LINK_STATE_DOWN);
91611101SMikore.Li@Sun.COM mutex_exit(&pcan_p->pcan_glock);
91711101SMikore.Li@Sun.COM }
91811101SMikore.Li@Sun.COM pcan_p->pcan_flag |= PCAN_SUSPENDED;
91911101SMikore.Li@Sun.COM }
92011101SMikore.Li@Sun.COM
92111101SMikore.Li@Sun.COM
92211101SMikore.Li@Sun.COM /*
92311101SMikore.Li@Sun.COM * assume card is already removed, don't touch the hardware
92411101SMikore.Li@Sun.COM */
92511101SMikore.Li@Sun.COM static void
pcan_card_remove(pcan_maci_t * pcan_p)9263737Shx147065 pcan_card_remove(pcan_maci_t *pcan_p)
9273737Shx147065 {
9283737Shx147065 int ret;
9293737Shx147065 io_req_t io;
9303737Shx147065 irq_req_t irq;
9313737Shx147065
9323737Shx147065 if (!(pcan_p->pcan_flag & PCAN_CARD_READY))
9333737Shx147065 return;
93411101SMikore.Li@Sun.COM if (pcan_p->pcan_connect_timeout_id != 0) {
93511101SMikore.Li@Sun.COM (void) untimeout(pcan_p->pcan_connect_timeout_id);
93611101SMikore.Li@Sun.COM pcan_p->pcan_connect_timeout_id = 0;
93711101SMikore.Li@Sun.COM }
93811101SMikore.Li@Sun.COM
93911101SMikore.Li@Sun.COM if (pcan_p->pcan_flag & PCAN_CARD_LINKUP) {
94011101SMikore.Li@Sun.COM pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
94111101SMikore.Li@Sun.COM mac_link_update(GLD3(pcan_p), LINK_STATE_DOWN);
94211101SMikore.Li@Sun.COM }
94311101SMikore.Li@Sun.COM mutex_enter(&pcan_p->pcan_glock);
94411101SMikore.Li@Sun.COM if (pcan_p->pcan_flag & PCAN_CARD_INTREN) {
94511101SMikore.Li@Sun.COM pcan_stop_locked(pcan_p);
94611101SMikore.Li@Sun.COM pcan_p->pcan_flag |= PCAN_PLUMBED;
94711101SMikore.Li@Sun.COM }
94811101SMikore.Li@Sun.COM pcan_p->pcan_flag &= ~PCAN_CARD_READY;
94911101SMikore.Li@Sun.COM mutex_exit(&pcan_p->pcan_glock);
95011101SMikore.Li@Sun.COM
9513737Shx147065 if (ret = csx_ReleaseConfiguration(pcan_p->pcan_chdl, NULL))
9523737Shx147065 cmn_err(CE_WARN, "pcan: ReleaseConfiguration failed %x\n", ret);
9533737Shx147065
9543737Shx147065 bzero(&irq, sizeof (irq));
9553737Shx147065 if (ret = csx_ReleaseIRQ(pcan_p->pcan_chdl, &irq))
9563737Shx147065 cmn_err(CE_WARN, "pcan: ReleaseIRQ failed %x\n", ret);
9573737Shx147065
9583737Shx147065 ddi_remove_softintr(pcan_p->pcan_softint_id);
95911101SMikore.Li@Sun.COM pcan_p->pcan_softint_id = 0;
9603737Shx147065
9613737Shx147065 bzero(&io, sizeof (io));
9623737Shx147065 io.BasePort1.handle = pcan_p->pcan_port;
9633737Shx147065 io.NumPorts1 = 16;
9643737Shx147065 if (ret = csx_ReleaseIO(pcan_p->pcan_chdl, &io))
9653737Shx147065 cmn_err(CE_WARN, "pcan: Release IO failed %x\n", ret);
9663737Shx147065
9673737Shx147065 pcan_p->pcan_port = 0;
96811101SMikore.Li@Sun.COM PCANDBG((CE_NOTE, "pcan: removed\n"));
9693737Shx147065 }
9703737Shx147065
9713737Shx147065 /*
9723737Shx147065 * gld operation interface routines
9733737Shx147065 */
9743737Shx147065 static int
pcan_start(void * arg)9753737Shx147065 pcan_start(void *arg)
9763737Shx147065 {
9773737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
9783737Shx147065
9793737Shx147065 mutex_enter(&pcan_p->pcan_glock);
9803737Shx147065 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
9813737Shx147065 mutex_exit(&pcan_p->pcan_glock);
9823737Shx147065 return (PCAN_FAIL);
9833737Shx147065 }
9843737Shx147065 (void) pcan_loaddef(pcan_p);
9853737Shx147065 pcan_start_locked(pcan_p);
9863737Shx147065 mutex_exit(&pcan_p->pcan_glock);
9873737Shx147065 return (PCAN_SUCCESS);
9883737Shx147065 }
9893737Shx147065
9903737Shx147065 static void
pcan_stop(void * arg)9913737Shx147065 pcan_stop(void *arg)
9923737Shx147065 {
9933737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
9943737Shx147065
9953737Shx147065 mutex_enter(&pcan_p->pcan_glock);
9963737Shx147065 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
9973737Shx147065 mutex_exit(&pcan_p->pcan_glock);
9983737Shx147065 return;
9993737Shx147065 }
10003737Shx147065 pcan_stop_locked(pcan_p);
10013737Shx147065 mutex_exit(&pcan_p->pcan_glock);
10023737Shx147065 if (pcan_p->pcan_connect_timeout_id != 0) {
10033737Shx147065 (void) untimeout(pcan_p->pcan_connect_timeout_id);
10043737Shx147065 pcan_p->pcan_connect_timeout_id = 0;
10053737Shx147065 }
10063737Shx147065 }
10073737Shx147065
10083737Shx147065 /*
10093737Shx147065 * mac address can only be set in 'disable' state and
10103737Shx147065 * be effective after 'enable' state.
10113737Shx147065 */
10123737Shx147065 static int
pcan_saddr(void * arg,const uint8_t * macaddr)10133737Shx147065 pcan_saddr(void *arg, const uint8_t *macaddr)
10143737Shx147065 {
10153737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
10163737Shx147065 int ret = PCAN_SUCCESS;
10173737Shx147065 ether_copy(macaddr, pcan_p->pcan_mac_addr);
10183737Shx147065
10193737Shx147065 mutex_enter(&pcan_p->pcan_glock);
10203737Shx147065 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
10213737Shx147065 ret = PCAN_FAIL;
10223737Shx147065 goto done;
10233737Shx147065 }
10243737Shx147065 ether_copy(pcan_p->pcan_mac_addr, pcan_p->an_config.an_macaddr);
10253737Shx147065 if (pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) {
10263737Shx147065 cmn_err(CE_WARN, "pcan set mac addr: failed\n");
10273737Shx147065 ret = PCAN_FAIL;
10283737Shx147065 goto done;
10293737Shx147065 }
10303737Shx147065 if (pcan_config_mac(pcan_p)) {
10313737Shx147065 cmn_err(CE_WARN, "pcan set mac addr: config_mac failed\n");
10323737Shx147065 ret = PCAN_FAIL;
10333737Shx147065 goto done;
10343737Shx147065 }
10353737Shx147065 if (pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0)) {
10363737Shx147065 cmn_err(CE_WARN, "pcan set mac addr: failed\n");
10373737Shx147065 ret = PCAN_FAIL;
10383737Shx147065 }
10393737Shx147065 done:
10403737Shx147065 mutex_exit(&pcan_p->pcan_glock);
10413737Shx147065 return (ret);
10423737Shx147065 }
10433737Shx147065
10443737Shx147065 /*
10453737Shx147065 * send a packet out for pccard
10463737Shx147065 */
10473737Shx147065 static int
pcan_send(pcan_maci_t * pcan_p,mblk_t * mblk_p)10483737Shx147065 pcan_send(pcan_maci_t *pcan_p, mblk_t *mblk_p)
10493737Shx147065 {
10503737Shx147065 char *buf, *buf_p;
10513737Shx147065 an_txfrm_t *frm_p;
10523737Shx147065 #ifdef PCAN_SEND_DEBUG
10533737Shx147065 struct an_ltv_status radio_status;
10543737Shx147065 #endif /* PCAN_SEND_DEBUG */
105511101SMikore.Li@Sun.COM uint16_t pkt_len, xmt_id, ring_idx, r = 0;
10563737Shx147065 struct ieee80211_frame *wh;
10573737Shx147065 int i = 0;
10583737Shx147065
10593737Shx147065 mutex_enter(&pcan_p->pcan_glock);
10603737Shx147065 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
10613737Shx147065 mutex_exit(&pcan_p->pcan_glock);
10623737Shx147065 freemsg(mblk_p);
10633737Shx147065 return (PCAN_SUCCESS); /* drop packet */
10643737Shx147065 }
10653737Shx147065 if (!(pcan_p->pcan_flag & PCAN_CARD_LINKUP)) { /* link down */
10663737Shx147065 PCANDBG((CE_NOTE, "pcan: link down, dropped\n"));
10673737Shx147065 pcan_p->glds_nocarrier++;
10683737Shx147065 mutex_exit(&pcan_p->pcan_glock);
10693737Shx147065 freemsg(mblk_p);
10703737Shx147065 return (PCAN_SUCCESS); /* drop packet */
10713737Shx147065 }
10723737Shx147065 mutex_exit(&pcan_p->pcan_glock);
10733737Shx147065 if (pullupmsg(mblk_p, -1) == 0) {
10743737Shx147065 cmn_err(CE_NOTE, "pcan send: pullupmsg failed\n");
10753737Shx147065 freemsg(mblk_p);
10763737Shx147065 return (PCAN_SUCCESS); /* drop packet */
10773737Shx147065 }
10783737Shx147065 wh = (struct ieee80211_frame *)mblk_p->b_rptr;
10793737Shx147065
10803737Shx147065 mutex_enter(&pcan_p->pcan_txring.an_tx_lock);
10813737Shx147065 ring_idx = pcan_p->pcan_txring.an_tx_prod;
10823737Shx147065 pcan_p->pcan_txring.an_tx_prod = (ring_idx + 1) & AN_TX_RING_MASK;
10833737Shx147065
10843737Shx147065 /* check whether there is a xmt buffer available */
10853737Shx147065 while ((i < AN_TX_RING_CNT) &&
10863737Shx147065 (pcan_p->pcan_txring.an_tx_ring[ring_idx])) {
10873737Shx147065 ring_idx = pcan_p->pcan_txring.an_tx_prod;
10883737Shx147065 pcan_p->pcan_txring.an_tx_prod =
10893737Shx147065 (ring_idx + 1) & AN_TX_RING_MASK;
10903737Shx147065 i++;
10913737Shx147065 }
10923737Shx147065
10933737Shx147065 if (i == AN_TX_RING_CNT) {
10943737Shx147065 mutex_exit(&pcan_p->pcan_txring.an_tx_lock);
10953737Shx147065 PCANDBG((CE_NOTE, "pcan: ring full, retrying\n"));
10963737Shx147065 mutex_enter(&pcan_p->pcan_glock);
10973737Shx147065 pcan_p->pcan_reschedule_need = B_TRUE;
10983737Shx147065 mutex_exit(&pcan_p->pcan_glock);
10993737Shx147065 pcan_p->glds_noxmtbuf++;
11003737Shx147065 return (PCAN_FAIL);
11013737Shx147065 }
11023737Shx147065 xmt_id = pcan_p->pcan_txring.an_tx_fids[ring_idx];
11033737Shx147065 pcan_p->pcan_txring.an_tx_ring[ring_idx] = xmt_id;
11043737Shx147065 mutex_exit(&pcan_p->pcan_txring.an_tx_lock);
11053737Shx147065
11063737Shx147065 buf = kmem_zalloc(PCAN_NICMEM_SZ, KM_SLEEP); /* too big for stack */
11073737Shx147065 buf_p = (ulong_t)buf & 1 ? buf + 1 : buf; /* 16-bit round up */
11083737Shx147065 frm_p = (an_txfrm_t *)buf_p;
11093737Shx147065
11103737Shx147065 #ifdef DEBUG
11113737Shx147065 if (pcan_debug & PCAN_DBG_SEND) {
11123737Shx147065 cmn_err(CE_NOTE, "pcan send: packet from plugin");
11137249Sff224033 for (i = 0; i < MBLKL(mblk_p); i++)
11143737Shx147065 cmn_err(CE_NOTE, "%x: %x\n", i,
11153737Shx147065 *((unsigned char *)mblk_p->b_rptr + i));
11163737Shx147065 }
11173737Shx147065 #endif
11183737Shx147065 pkt_len = msgdsize(mblk_p);
11193737Shx147065 if (pkt_len > PCAN_NICMEM_SZ - sizeof (an_txfrm_t)) {
11203737Shx147065 cmn_err(CE_WARN, "pcan send: mblk is too long");
11213737Shx147065 kmem_free(buf, PCAN_NICMEM_SZ);
11223737Shx147065 freemsg(mblk_p);
11233737Shx147065 return (PCAN_SUCCESS); /* drop packet */
11243737Shx147065 }
11253737Shx147065 if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) !=
11263737Shx147065 IEEE80211_FC1_DIR_TODS) {
11273737Shx147065 kmem_free(buf, PCAN_NICMEM_SZ);
11283737Shx147065 freemsg(mblk_p);
11293737Shx147065 return (PCAN_SUCCESS); /* drop packet */
11303737Shx147065 }
11313737Shx147065
11323737Shx147065 /* initialize xmt frame header, payload_len must be stored in LE */
11333737Shx147065 bzero(frm_p, sizeof (an_txfrm_t) + 2);
11343737Shx147065 frm_p->an_tx_ctl = AN_TXCTL_8023;
11353737Shx147065
11363737Shx147065 /*
11373737Shx147065 * mblk sent down from plugin includes station mode 802.11 frame and
11383737Shx147065 * llc, so we here need to remove them and add an ethernet header.
11393737Shx147065 */
11403737Shx147065 pkt_len = pkt_len - (sizeof (*wh) + sizeof (struct ieee80211_llc))
11413737Shx147065 + 2;
11423737Shx147065 bcopy(wh->i_addr3, buf_p + 0x38, ETHERADDRL); /* dst macaddr */
11433737Shx147065 bcopy(wh->i_addr2, buf_p + 0x3e, ETHERADDRL); /* src macaddr */
11443737Shx147065 *((uint16_t *)(buf_p + 0x36)) = pkt_len;
11453737Shx147065 bcopy(mblk_p->b_rptr + sizeof (*wh) + sizeof (struct ieee80211_llc)
11463737Shx147065 - 2, buf_p + 0x44, pkt_len);
11473737Shx147065
11483737Shx147065 if (pkt_len & 1) { /* round up to 16-bit boundary and pad 0 */
11493737Shx147065 buf_p[pkt_len + 0x44] = 0;
11503737Shx147065 pkt_len++;
11513737Shx147065 }
11523737Shx147065 ASSERT(pkt_len <= PCAN_NICMEM_SZ);
11533737Shx147065 #ifdef DEBUG
11543737Shx147065 if (pcan_debug & PCAN_DBG_SEND) {
11553737Shx147065 cmn_err(CE_NOTE, "pcan send: packet to hardware--pkt_len=%x",
11563737Shx147065 pkt_len);
11573737Shx147065 for (i = 0; i < pkt_len + 4; i++)
11583737Shx147065 cmn_err(CE_NOTE, "%x: %x\n", i,
11593737Shx147065 *((unsigned char *)buf_p + 0x36 + i));
11603737Shx147065 }
11613737Shx147065 #endif
11623737Shx147065 mutex_enter(&pcan_p->pcan_glock);
11633737Shx147065 (void) WRCH1(pcan_p, xmt_id, 0, (uint16_t *)buf_p, 0x38); /* frm */
11643737Shx147065 (void) WRPKT(pcan_p, xmt_id, 0x38, (uint16_t *)(buf_p + 0x38),
11654343Sgd78059 pkt_len + 12);
116611101SMikore.Li@Sun.COM r = pcan_set_cmd(pcan_p, AN_CMD_TX, xmt_id);
11673737Shx147065 mutex_exit(&pcan_p->pcan_glock);
11683737Shx147065
11693737Shx147065 PCANDBG((CE_NOTE, "pcan: pkt_len=0x44+%x=%x xmt=%x ret=%x\n",
11703737Shx147065 pkt_len, 0x44 + pkt_len, xmt_id, ring_idx));
11713737Shx147065 kmem_free(buf, PCAN_NICMEM_SZ);
11723737Shx147065 #ifdef PCAN_SEND_DEBUG
11733737Shx147065 if (pkt_len = pcan_status_ltv(PCAN_READ_LTV, pcan_p, &radio_status)) {
11743737Shx147065 PCANDBG((CE_NOTE, "pcan: bad radio status %x\n", pkt_len));
11753737Shx147065 } else {
11763737Shx147065 PCANDBG((CE_NOTE, "pcan: radio status:\n"));
11773737Shx147065 }
11783737Shx147065 #endif /* PCAN_SEND_DEBUG */
117911101SMikore.Li@Sun.COM if (r)
11803737Shx147065 return (PCAN_FAIL);
11813737Shx147065 else {
11823737Shx147065 freemsg(mblk_p);
11833737Shx147065 return (PCAN_SUCCESS);
11843737Shx147065 }
11853737Shx147065 }
11863737Shx147065
11873737Shx147065 /*
11883737Shx147065 * send a packet out for PCI/MiniPCI card
11893737Shx147065 */
11903737Shx147065 static int
pcian_send(pcan_maci_t * pcan_p,mblk_t * mblk_p)11913737Shx147065 pcian_send(pcan_maci_t *pcan_p, mblk_t *mblk_p)
11923737Shx147065 {
11933737Shx147065 char *buf;
11943737Shx147065 uint16_t pkt_len = msgdsize(mblk_p), ring_idx;
11953737Shx147065 uint32_t i;
11963737Shx147065 struct ieee80211_frame *wh;
11973737Shx147065 struct an_card_tx_desc an_tx_desc;
11983737Shx147065
11993737Shx147065 ring_idx = pcan_p->pcan_txring.an_tx_prod;
12003737Shx147065
12013737Shx147065 mutex_enter(&pcan_p->pcan_glock);
12023737Shx147065 if (!(pcan_p->pcan_flag & PCAN_CARD_LINKUP)) { /* link down */
12033737Shx147065 mutex_exit(&pcan_p->pcan_glock);
12043737Shx147065 pcan_p->glds_nocarrier++;
12053737Shx147065 freemsg(mblk_p);
12063737Shx147065 return (PCAN_SUCCESS); /* drop packet */
12073737Shx147065 }
12083737Shx147065 mutex_exit(&pcan_p->pcan_glock);
12093737Shx147065 if (pullupmsg(mblk_p, -1) == 0) {
12103737Shx147065 cmn_err(CE_NOTE, "pcan(pci) send: pullupmsg failed\n");
12113737Shx147065 freemsg(mblk_p);
12123737Shx147065 return (PCAN_SUCCESS); /* drop packet */
12133737Shx147065 }
12143737Shx147065 wh = (struct ieee80211_frame *)mblk_p->b_rptr;
12153737Shx147065
12163737Shx147065 mutex_enter(&pcan_p->pcan_txring.an_tx_lock);
12173737Shx147065 if ((pcan_p->pcan_flag & PCAN_CARD_SEND) &&
12183737Shx147065 (ring_idx == pcan_p->pcan_txring.an_tx_cons)) {
12193737Shx147065 pcan_p->glds_noxmtbuf++;
12203737Shx147065 pcan_p->pcan_reschedule_need = B_TRUE;
12213737Shx147065 mutex_exit(&pcan_p->pcan_txring.an_tx_lock);
12223737Shx147065 return (PCAN_FAIL);
12233737Shx147065 }
12243737Shx147065 mutex_exit(&pcan_p->pcan_txring.an_tx_lock);
12253737Shx147065
12263737Shx147065 #ifdef DEBUG
12273737Shx147065 if (pcan_debug & PCAN_DBG_SEND) {
12283737Shx147065 cmn_err(CE_NOTE, "pcan(pci) send: packet from plugin");
12297249Sff224033 for (i = 0; i < MBLKL(mblk_p); i++)
12303737Shx147065 cmn_err(CE_NOTE, "%x: %x\n", i,
12313737Shx147065 *((unsigned char *)mblk_p->b_rptr + i));
12323737Shx147065 }
12333737Shx147065 #endif
12343737Shx147065 mutex_enter(&pcan_p->pcan_glock);
12353737Shx147065
12363737Shx147065 buf = pcan_p->pcan_tx[ring_idx].dma_virtaddr;
12373737Shx147065 bzero(buf, AN_TX_BUFFER_SIZE);
12383737Shx147065
12393737Shx147065 /*
12403737Shx147065 * mblk sent down from plugin includes station mode 802.11 frame and
12413737Shx147065 * llc, so we here need to remove them and add an ethernet header.
12423737Shx147065 */
12433737Shx147065 *((uint16_t *)(buf + 8)) = htons(AN_TXCTL_8023);
12443737Shx147065 pkt_len = pkt_len - (sizeof (*wh) + sizeof (struct ieee80211_llc))
12453737Shx147065 + 2;
12463737Shx147065 bcopy(wh->i_addr3, buf + 0x38, ETHERADDRL); /* dst macaddr */
12473737Shx147065 bcopy(wh->i_addr2, buf + 0x3e, ETHERADDRL); /* src macaddr */
12483737Shx147065 *((uint16_t *)(buf + 0x36)) = pkt_len;
12493737Shx147065 bcopy(mblk_p->b_rptr + sizeof (*wh) + sizeof (struct ieee80211_llc)
12503737Shx147065 - 2, buf + 0x44, pkt_len);
12513737Shx147065
12523737Shx147065 #ifdef DEBUG
12533737Shx147065 if (pcan_debug & PCAN_DBG_SEND) {
12543737Shx147065 cmn_err(CE_NOTE, "pcan(pci) send: packet to hardware "
12553737Shx147065 "pkt_len=%x", pkt_len);
12563737Shx147065 for (i = 0; i < pkt_len + 14; i++)
12573737Shx147065 cmn_err(CE_NOTE, "%x: %x\n", i,
12583737Shx147065 *((unsigned char *)buf + 0x36 + i));
12593737Shx147065 }
12603737Shx147065 #endif
12613737Shx147065 bzero(&an_tx_desc, sizeof (an_tx_desc));
12623737Shx147065 an_tx_desc.an_offset = 0;
12633737Shx147065 an_tx_desc.an_eoc = (ring_idx == (AN_MAX_TX_DESC-1) ? 1 : 0);
12643737Shx147065 an_tx_desc.an_valid = 1;
12653737Shx147065 an_tx_desc.an_len = 0x44 + pkt_len;
12663737Shx147065 an_tx_desc.an_phys = pcan_p->pcan_tx[ring_idx].dma_physaddr;
12673737Shx147065 for (i = 0; i < sizeof (an_tx_desc) / 4; i++) {
12683737Shx147065 PCAN_AUX_PUT32(pcan_p, AN_TX_DESC_OFFSET +
12693737Shx147065 (ring_idx * sizeof (an_tx_desc)) + (i * 4),
12703737Shx147065 ((uint32_t *)&an_tx_desc)[i]);
12713737Shx147065 }
12723737Shx147065
12733737Shx147065 mutex_enter(&pcan_p->pcan_txring.an_tx_lock);
12743737Shx147065 pcan_p->pcan_txring.an_tx_prod = (ring_idx + 1) % AN_MAX_TX_DESC;
12753737Shx147065 pcan_p->pcan_flag |= PCAN_CARD_SEND;
12763737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_ALLOC);
12773737Shx147065 mutex_exit(&pcan_p->pcan_txring.an_tx_lock);
12783737Shx147065
12793737Shx147065 freemsg(mblk_p);
12803737Shx147065 mutex_exit(&pcan_p->pcan_glock);
12813737Shx147065 return (PCAN_SUCCESS);
12823737Shx147065 }
12833737Shx147065
12843737Shx147065 static mblk_t *
pcan_tx(void * arg,mblk_t * mp)12853737Shx147065 pcan_tx(void *arg, mblk_t *mp)
12863737Shx147065 {
12873737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
12883737Shx147065 mblk_t *next;
12893737Shx147065 int ret = 0;
12903737Shx147065
12913737Shx147065 ASSERT(mp != NULL);
12923737Shx147065 mutex_enter(&pcan_p->pcan_glock);
12933737Shx147065 if ((pcan_p->pcan_flag & (PCAN_CARD_LINKUP | PCAN_CARD_READY)) !=
12943737Shx147065 (PCAN_CARD_LINKUP | PCAN_CARD_READY)) {
12953737Shx147065 mutex_exit(&pcan_p->pcan_glock);
129611101SMikore.Li@Sun.COM freemsgchain(mp);
129711101SMikore.Li@Sun.COM return (NULL);
12983737Shx147065 }
12993737Shx147065 mutex_exit(&pcan_p->pcan_glock);
13003737Shx147065 while (mp != NULL) {
13013737Shx147065 next = mp->b_next;
13023737Shx147065 mp->b_next = NULL;
13033737Shx147065
13043737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
13053737Shx147065 ret = pcian_send(pcan_p, mp);
13063737Shx147065 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
13073737Shx147065 ret = pcan_send(pcan_p, mp);
13083737Shx147065 }
13093737Shx147065 if (ret) {
13103737Shx147065 mp->b_next = next;
13113737Shx147065 break;
13123737Shx147065 }
13133737Shx147065 mp = next;
13143737Shx147065 }
13153737Shx147065 return (mp);
13163737Shx147065 }
13173737Shx147065
13183737Shx147065 /*
13193737Shx147065 * this driver is porting from freebsd, the code in freebsd
13203737Shx147065 * doesn't show how to set promiscous mode.
13213737Shx147065 */
13223737Shx147065 /*ARGSUSED*/
13233737Shx147065 static int
pcan_prom(void * arg,boolean_t on)13243737Shx147065 pcan_prom(void *arg, boolean_t on)
13253737Shx147065 {
13263737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
13273737Shx147065 int ret = PCAN_SUCCESS;
13283737Shx147065
13293737Shx147065 mutex_enter(&pcan_p->pcan_glock);
13303737Shx147065 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
13313737Shx147065 ret = PCAN_FAIL;
13323737Shx147065 }
13333737Shx147065 mutex_exit(&pcan_p->pcan_glock);
13343737Shx147065 return (ret);
13353737Shx147065 }
13363737Shx147065
13373737Shx147065 /*ARGSUSED*/
13383737Shx147065 static int
pcan_gstat(void * arg,uint_t statitem,uint64_t * val)13393737Shx147065 pcan_gstat(void *arg, uint_t statitem, uint64_t *val)
13403737Shx147065 {
13413737Shx147065 uint16_t i;
13423737Shx147065 int ret = PCAN_SUCCESS;
13433737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
13443737Shx147065 uint64_t *cntr_p = pcan_p->pcan_cntrs_s;
13453737Shx147065
13463737Shx147065 PCANDBG((CE_NOTE, "pcan: gstat called\n"));
13473737Shx147065
13483737Shx147065 mutex_enter(&pcan_p->pcan_glock);
13493737Shx147065 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
13503737Shx147065 ret = PCAN_FAIL;
13513737Shx147065 goto done;
13523737Shx147065 }
13533737Shx147065 if (pcan_get_ltv(pcan_p, sizeof (pcan_p->an_stats),
13544343Sgd78059 AN_RID_16BITS_DELTACLR, (uint16_t *)&pcan_p->an_stats)) {
13553737Shx147065 cmn_err(CE_WARN, "pcan kstat: get ltv(32 delta statistics)"
13563737Shx147065 " failed \n");
13573737Shx147065 ret = PCAN_FAIL;
13583737Shx147065 goto done;
13593737Shx147065 }
13603737Shx147065 for (i = 0; i < ANC_STAT_CNT; i++) {
13613737Shx147065 cntr_p[i] += *((uint16_t *)&pcan_p->an_stats + 1 + i);
13623737Shx147065 }
13633737Shx147065 if (pcan_status_ltv(PCAN_READ_LTV, pcan_p, &pcan_p->an_status)) {
13643737Shx147065 cmn_err(CE_WARN, "pcan kstat: read status failed \n");
13653737Shx147065 ret = PCAN_FAIL;
13663737Shx147065 goto done;
13673737Shx147065 }
13683737Shx147065
13693737Shx147065 switch (statitem) {
13703737Shx147065 case MAC_STAT_IFSPEED:
13713737Shx147065 *val = 500000 * pcan_p->an_status.an_cur_tx_rate;
13723737Shx147065 break;
13733737Shx147065 case MAC_STAT_NOXMTBUF:
13743737Shx147065 *val = pcan_p->glds_noxmtbuf;
13753737Shx147065 break;
13763737Shx147065 case MAC_STAT_NORCVBUF:
13773737Shx147065 *val = pcan_p->glds_norcvbuf;
13783737Shx147065 break;
13793737Shx147065 case MAC_STAT_IERRORS:
13803737Shx147065 *val = cntr_p[ANC_RX_OVERRUNS] +
13813737Shx147065 cntr_p[ANC_RX_PLCP_CSUM_ERRS] +
13823737Shx147065 cntr_p[ANC_RX_PLCP_FORMAT_ERRS] +
13833737Shx147065 cntr_p[ANC_RX_PLCP_LEN_ERRS] +
13843737Shx147065 cntr_p[ANC_RX_MAC_CRC_ERRS] +
13853737Shx147065 cntr_p[ANC_RX_WEP_ERRS];
13863737Shx147065 break;
13873737Shx147065 case MAC_STAT_OERRORS:
13883737Shx147065 *val = cntr_p[ANC_TX_HOST_FAILED];
13893737Shx147065 break;
13903737Shx147065 case MAC_STAT_RBYTES:
13913737Shx147065 *val = cntr_p[ANC_HOST_RX_BYTES];
13923737Shx147065 break;
13933737Shx147065 case MAC_STAT_IPACKETS:
13943737Shx147065 *val = cntr_p[ANC_RX_HOST_UCASTS];
13953737Shx147065 break;
13963737Shx147065 case MAC_STAT_OBYTES:
13973737Shx147065 *val = cntr_p[ANC_HOST_TX_BYTES];
13983737Shx147065 break;
13993737Shx147065 case MAC_STAT_OPACKETS:
14003737Shx147065 *val = cntr_p[ANC_TX_HOST_UCASTS];
14013737Shx147065 break;
14023737Shx147065 case WIFI_STAT_TX_FAILED:
14033737Shx147065 *val = cntr_p[ANC_TX_HOST_FAILED];
14043737Shx147065 break;
14053737Shx147065 case WIFI_STAT_TX_RETRANS:
14063737Shx147065 *val = cntr_p[ANC_HOST_RETRIES];
14073737Shx147065 break;
14083737Shx147065 case WIFI_STAT_FCS_ERRORS:
14093737Shx147065 *val = cntr_p[ANC_RX_MAC_CRC_ERRS];
14103737Shx147065 break;
14113737Shx147065 case WIFI_STAT_WEP_ERRORS:
14123737Shx147065 *val = cntr_p[ANC_RX_WEP_ERRS];
14133737Shx147065 break;
14143737Shx147065 case WIFI_STAT_MCAST_TX:
14153737Shx147065 *val = cntr_p[ANC_TX_HOST_MCASTS];
14163737Shx147065 break;
14173737Shx147065 case WIFI_STAT_MCAST_RX:
14183737Shx147065 *val = cntr_p[ANC_RX_HOST_MCASTS];
14193737Shx147065 break;
14203737Shx147065 case WIFI_STAT_TX_FRAGS:
14213737Shx147065 case WIFI_STAT_RX_FRAGS:
14223737Shx147065 *val = 0;
14233737Shx147065 break;
14243737Shx147065 case WIFI_STAT_RTS_SUCCESS:
14253737Shx147065 *val = cntr_p[ANC_TX_RTS_OK];
14263737Shx147065 break;
14273737Shx147065 case WIFI_STAT_RTS_FAILURE:
14283737Shx147065 *val = cntr_p[ANC_NO_CTS];
14293737Shx147065 break;
14303737Shx147065 case WIFI_STAT_ACK_FAILURE:
14313737Shx147065 *val = cntr_p[ANC_NO_ACK];
14323737Shx147065 break;
14333737Shx147065 case WIFI_STAT_RX_DUPS:
14343737Shx147065 *val = cntr_p[ANC_RX_DUPS];
14353737Shx147065 break;
14363737Shx147065 default:
14373737Shx147065 ret = ENOTSUP;
14383737Shx147065 }
14393737Shx147065
14403737Shx147065
14413737Shx147065 done:
14423737Shx147065 mutex_exit(&pcan_p->pcan_glock);
14433737Shx147065 return (ret);
14443737Shx147065 }
14453737Shx147065
14463737Shx147065 /*
14473737Shx147065 * this driver is porting from freebsd, the code in freebsd
14483737Shx147065 * doesn't show how to set multi address.
14493737Shx147065 */
14503737Shx147065 /*ARGSUSED*/
14513737Shx147065 static int
pcan_sdmulti(void * arg,boolean_t add,const uint8_t * eth_p)14523737Shx147065 pcan_sdmulti(void *arg, boolean_t add, const uint8_t *eth_p)
14533737Shx147065 {
14543737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
14553737Shx147065
14563737Shx147065 mutex_enter(&pcan_p->pcan_glock);
14573737Shx147065 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
14583737Shx147065 mutex_exit(&pcan_p->pcan_glock);
14593737Shx147065 return (PCAN_FAIL);
14603737Shx147065 }
14613737Shx147065 mutex_exit(&pcan_p->pcan_glock);
14623737Shx147065 return (PCAN_SUCCESS);
14633737Shx147065 }
14643737Shx147065
14653737Shx147065 static uint_t
pcan_info_softint(caddr_t arg)14663737Shx147065 pcan_info_softint(caddr_t arg)
14673737Shx147065 {
14683737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
14693737Shx147065 wifi_data_t wd = { 0 };
14703737Shx147065 uint16_t link;
14713737Shx147065 uint32_t link_up;
14723737Shx147065
14733737Shx147065 mutex_enter(&pcan_p->pcan_glock);
14743737Shx147065 if (pcan_p->pcan_info_softint_pending != 1) {
14753737Shx147065 mutex_exit(&pcan_p->pcan_glock);
14763737Shx147065 return (DDI_INTR_UNCLAIMED);
14773737Shx147065 }
14783737Shx147065
14793737Shx147065 PCAN_READ(pcan_p, AN_LINKSTAT(pcan_p), link);
14803737Shx147065 link_up = pcan_p->pcan_flag & PCAN_CARD_LINKUP;
14813737Shx147065 if ((link == AN_LINKSTAT_ASSOCIATED) && !link_up) {
14823737Shx147065 pcan_p->pcan_flag |= PCAN_CARD_LINKUP;
14833737Shx147065 mutex_exit(&pcan_p->pcan_glock);
14843737Shx147065 if (pcan_p->pcan_connect_timeout_id != 0) {
14853737Shx147065 (void) untimeout(pcan_p->pcan_connect_timeout_id);
14863737Shx147065 pcan_p->pcan_connect_timeout_id = 0;
14873737Shx147065 }
14883737Shx147065 mac_link_update(GLD3(pcan_p), LINK_STATE_UP);
14893737Shx147065 mutex_enter(&pcan_p->pcan_glock);
14903737Shx147065 (void) pcan_status_ltv(PCAN_READ_LTV, pcan_p,
14913737Shx147065 &pcan_p->an_status);
14923737Shx147065 bcopy(pcan_p->an_status.an_cur_bssid, wd.wd_bssid, 6);
14933737Shx147065 wd.wd_secalloc = WIFI_SEC_NONE;
14943737Shx147065 wd.wd_opmode = IEEE80211_M_STA;
14953737Shx147065 (void) mac_pdata_update(pcan_p->pcan_mh, &wd,
14963737Shx147065 sizeof (wd));
14973737Shx147065 #ifdef DEBUG
14983737Shx147065 if (pcan_debug & PCAN_DBG_LINKINFO) {
14993737Shx147065 cmn_err(CE_NOTE, "pcan: link Up, chan=%d, "
15003737Shx147065 "ssid=\"%s\""
15013737Shx147065 " (%02x:%02x:%02x:%02x:%02x:%02x)\n",
15023737Shx147065 pcan_p->an_status.an_channel_set,
15033737Shx147065 pcan_p->an_status.an_ssid,
15043737Shx147065 pcan_p->an_status.an_cur_bssid[0],
15053737Shx147065 pcan_p->an_status.an_cur_bssid[1],
15063737Shx147065 pcan_p->an_status.an_cur_bssid[2],
15073737Shx147065 pcan_p->an_status.an_cur_bssid[3],
15083737Shx147065 pcan_p->an_status.an_cur_bssid[4],
15093737Shx147065 pcan_p->an_status.an_cur_bssid[5]);
15103737Shx147065 }
15113737Shx147065 #endif
15123737Shx147065 }
15133737Shx147065 if ((link != AN_LINKSTAT_ASSOCIATED) && link_up) {
15143737Shx147065 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
15153737Shx147065 #ifdef DEBUG
15163737Shx147065 if (pcan_debug & PCAN_DBG_LINKINFO) {
15173737Shx147065 cmn_err(CE_NOTE, "pcan: link Down 0x%x\n", link);
15183737Shx147065 }
15193737Shx147065 #endif
15203737Shx147065 if (link != AN_LINKSTAT_SYNCLOST_HOSTREQ) {
15213737Shx147065 pcan_p->pcan_connect_timeout_id =
15223737Shx147065 timeout(pcan_connect_timeout,
15233737Shx147065 pcan_p, drv_usectohz(1000));
15243737Shx147065 }
15253737Shx147065 mutex_exit(&pcan_p->pcan_glock);
15263737Shx147065 mac_link_update(GLD3(pcan_p), LINK_STATE_DOWN);
15273737Shx147065 mutex_enter(&pcan_p->pcan_glock);
15283737Shx147065 }
15293737Shx147065
15303737Shx147065 pcan_p->pcan_info_softint_pending = 0;
15313737Shx147065 mutex_exit(&pcan_p->pcan_glock);
15323737Shx147065 return (DDI_INTR_CLAIMED);
15333737Shx147065 }
15343737Shx147065
15353737Shx147065 static uint_t
pcan_intr(caddr_t arg)15363737Shx147065 pcan_intr(caddr_t arg)
15373737Shx147065 {
15383737Shx147065 uint16_t stat;
15393737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
15403737Shx147065
15413737Shx147065 mutex_enter(&pcan_p->pcan_glock);
15423737Shx147065 if ((pcan_p->pcan_flag & (PCAN_CARD_READY | PCAN_CARD_INTREN)) !=
15433737Shx147065 (PCAN_CARD_READY | PCAN_CARD_INTREN)) {
15443737Shx147065 mutex_exit(&pcan_p->pcan_glock);
15453737Shx147065 return (DDI_INTR_UNCLAIMED);
15463737Shx147065 }
15473737Shx147065 PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat);
15483737Shx147065
15493737Shx147065 if (!(stat & AN_INTRS(pcan_p)) || stat == AN_EV_ALL) {
15503737Shx147065 mutex_exit(&pcan_p->pcan_glock);
15513737Shx147065 return (DDI_INTR_UNCLAIMED);
15523737Shx147065 }
15533737Shx147065
15543737Shx147065 PCAN_DISABLE_INTR(pcan_p);
15553737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), ~AN_INTRS(pcan_p));
15563737Shx147065
15573737Shx147065 PCANDBG((CE_NOTE, "pcan intr: stat=%x pcan_flags=%x\n", stat,
15584343Sgd78059 pcan_p->pcan_flag));
15593737Shx147065
15603737Shx147065 if (stat & AN_EV_AWAKE) {
15613737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_AWAKE);
15623737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_AWAKE);
15633737Shx147065 }
15643737Shx147065 if (stat & AN_EV_LINKSTAT) {
15653737Shx147065 pcan_p->pcan_info_softint_pending = 1;
15663737Shx147065 ddi_trigger_softintr(pcan_p->pcan_info_softint_id);
15673737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_LINKSTAT);
15683737Shx147065 }
15693737Shx147065 if (stat & AN_EV_RX) {
15703737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
15713737Shx147065 pcian_rcv(pcan_p);
15723737Shx147065 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
15733737Shx147065 pcan_rcv(pcan_p);
15743737Shx147065 }
15753737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_RX);
15763737Shx147065 }
15773737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
15783737Shx147065 if (stat & AN_EV_TX_CPY) {
15793737Shx147065 (void) pcan_txdone(pcan_p, stat & AN_EV_TX_CPY);
15803737Shx147065 if (pcan_p->pcan_reschedule_need == B_TRUE) {
15813737Shx147065 mac_tx_update(GLD3(pcan_p));
15823737Shx147065 pcan_p->pcan_reschedule_need = B_FALSE;
15833737Shx147065 }
15843737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_TX_CPY);
15853737Shx147065 }
15863737Shx147065 }
15873737Shx147065 if (stat & AN_EV_TX) {
15883737Shx147065 if (pcan_txdone(pcan_p, stat & AN_EV_TX) == 0) {
15893737Shx147065 if (pcan_p->pcan_reschedule_need == B_TRUE) {
15903737Shx147065 mac_tx_update(GLD3(pcan_p));
15913737Shx147065 pcan_p->pcan_reschedule_need = B_FALSE;
15923737Shx147065 }
15933737Shx147065 }
15943737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_TX);
15953737Shx147065 }
15963737Shx147065 if (stat & AN_EV_TX_EXC) {
15973737Shx147065 if (pcan_txdone(pcan_p, stat & AN_EV_TX_EXC) == 0) {
15983737Shx147065 if (pcan_p->pcan_reschedule_need == B_TRUE) {
15993737Shx147065 mutex_exit(&pcan_p->pcan_glock);
16003737Shx147065 mac_tx_update(GLD3(pcan_p));
16013737Shx147065 mutex_enter(&pcan_p->pcan_glock);
16023737Shx147065 pcan_p->pcan_reschedule_need = B_FALSE;
16033737Shx147065 }
16043737Shx147065 }
16053737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_TX_EXC);
16063737Shx147065 }
16073737Shx147065 if (stat & AN_EV_ALLOC) {
16083737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_ALLOC);
16093737Shx147065 PCANDBG((CE_NOTE, "pcan intr: nicmem alloc done\n"));
16103737Shx147065 }
16113737Shx147065 if (stat & AN_EV_MIC) {
16123737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_MIC);
16133737Shx147065 }
16143737Shx147065 PCAN_ENABLE_INTR(pcan_p);
16153737Shx147065 mutex_exit(&pcan_p->pcan_glock);
16163737Shx147065 return (DDI_INTR_CLAIMED);
16173737Shx147065 }
16183737Shx147065
16193737Shx147065 static uint_t
pcan_intr_hi(caddr_t arg)16203737Shx147065 pcan_intr_hi(caddr_t arg)
16213737Shx147065 {
16223737Shx147065 uint16_t stat;
16233737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
16243737Shx147065
16253737Shx147065 mutex_enter(&pcan_p->pcan_glock);
16263737Shx147065 if ((pcan_p->pcan_flag & (PCAN_CARD_READY | PCAN_CARD_INTREN)) !=
16273737Shx147065 (PCAN_CARD_READY | PCAN_CARD_INTREN)) {
16283737Shx147065 mutex_exit(&pcan_p->pcan_glock);
16293737Shx147065 return (DDI_INTR_UNCLAIMED);
16303737Shx147065 }
16313737Shx147065 PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat);
16323737Shx147065 PCANDBG((CE_NOTE, "pcan intr(hi): stat=%x pcan_flags=%x\n", stat,
16333737Shx147065 pcan_p->pcan_flag));
16343737Shx147065
16353737Shx147065 if (!(stat & AN_INTRS(pcan_p)) || stat == AN_EV_ALL) {
16363737Shx147065 mutex_exit(&pcan_p->pcan_glock);
16373737Shx147065 return (DDI_INTR_UNCLAIMED);
16383737Shx147065 }
16393737Shx147065 /* disable interrupt without ack */
16403737Shx147065 PCAN_WRITE(pcan_p, AN_INT_EN(pcan_p), 0);
16413737Shx147065 mutex_exit(&pcan_p->pcan_glock);
16423737Shx147065 ddi_trigger_softintr(pcan_p->pcan_softint_id);
16433737Shx147065 return (DDI_INTR_CLAIMED);
16443737Shx147065 }
16453737Shx147065
16463737Shx147065 /*
16473737Shx147065 * retrieve data from pccard
16483737Shx147065 */
16493737Shx147065 static void
pcan_rcv(pcan_maci_t * pcan_p)16503737Shx147065 pcan_rcv(pcan_maci_t *pcan_p)
16513737Shx147065 {
16523737Shx147065 uint16_t id, off, ret, data_len, pkt_stat, frm_ctl;
16533737Shx147065 an_rxfrm_t frm;
16543737Shx147065 struct ieee80211_llc *llc;
16553737Shx147065
16563737Shx147065 mblk_t *mp = allocb(PCAN_NICMEM_SZ, BPRI_MED);
16573737Shx147065 if (!mp) {
16583737Shx147065 cmn_err(CE_WARN, "pcan: failed to alloc rcv buf");
16593737Shx147065 pcan_p->glds_norcvbuf++;
16603737Shx147065 return;
16613737Shx147065 }
16623737Shx147065 ASSERT(mp->b_rptr == mp->b_wptr);
16633737Shx147065
16643737Shx147065 PCAN_READ(pcan_p, AN_RX_FID, id);
16653737Shx147065 if (id == AN_INVALID_FID) {
16663737Shx147065 PCANDBG((CE_NOTE, "pcan rcv: can't get rx_fid\n"));
16673737Shx147065 pcan_p->glds_norcvbuf++;
16683737Shx147065 ret = PCAN_FAIL;
16693737Shx147065 goto done;
16703737Shx147065 }
16713737Shx147065 if (ret = RDCH0(pcan_p, id, 0, (uint16_t *)&frm, sizeof (frm))) {
16723737Shx147065 PCANDBG((CE_NOTE, "pcan rcv: read frm err %x\n", ret));
16733737Shx147065 goto done;
16743737Shx147065 }
16753737Shx147065 off = sizeof (frm);
16763737Shx147065 if (frm.an_rx_status) {
16773737Shx147065 PCANDBG((CE_NOTE, "pcan rcv: err stat %x\n", frm.an_rx_status));
16783737Shx147065 ret = frm.an_rx_status;
16793737Shx147065 goto done;
16803737Shx147065 }
16813737Shx147065 PCANDBG((CE_NOTE, "pcan rcv: payload_len=%x gap_len=%x\n",
16823737Shx147065 frm.an_rx_payload_len, frm.an_gaplen));
16833737Shx147065 if (frm.an_rx_payload_len > PCAN_NICMEM_SZ ||
16843737Shx147065 frm.an_gaplen > AN_RXGAP_MAX) {
16853737Shx147065 PCANDBG((CE_NOTE, "pcan rcv: bad len\n"));
16863737Shx147065 ret = PCAN_FAIL;
16873737Shx147065 goto done;
16883737Shx147065 }
16893737Shx147065 if (ret = RDCH0(pcan_p, id, off, &pkt_stat, sizeof (pkt_stat))) {
16903737Shx147065 PCANDBG((CE_NOTE, "pcan rcv: pkt status err %x\n", ret));
16913737Shx147065 ret = PCAN_FAIL;
16923737Shx147065 goto done;
16933737Shx147065 }
16943737Shx147065 off += sizeof (pkt_stat);
16953737Shx147065 if (ret = RDCH0(pcan_p, id, off, &data_len, sizeof (data_len))) {
16963737Shx147065 PCANDBG((CE_NOTE, "pcan rcv: payload len err %x\n", ret));
16973737Shx147065 ret = PCAN_FAIL;
16983737Shx147065 goto done;
16993737Shx147065 }
17003737Shx147065 off += sizeof (data_len);
17013737Shx147065 off += ETHERADDRL << 1;
17023737Shx147065 PCANDBG((CE_NOTE, "pcan rcv: pkt_stat=%x payload_len=%x+c off=%x\n",
17034343Sgd78059 pkt_stat, data_len, off));
17043737Shx147065
17053737Shx147065 #ifdef DEBUG
17063737Shx147065 if (pcan_debug & PCAN_DBG_RCV) {
17073737Shx147065 int i;
17083737Shx147065 cmn_err(CE_NOTE, "pcan rcv: frm header\n");
17093737Shx147065 for (i = 0; i < sizeof (frm); i++)
17103737Shx147065 cmn_err(CE_NOTE, "%x: %x\n", i,
17113737Shx147065 *((uint8_t *)&frm + i));
17123737Shx147065 }
17133737Shx147065 #endif
17143737Shx147065 /*
17153737Shx147065 * this driver deal with WEP by itself. so plugin always thinks no wep.
17163737Shx147065 */
17173737Shx147065 frm.an_frame_ctl &= ~(IEEE80211_FC1_WEP << 8);
17183737Shx147065 frm_ctl = frm.an_frame_ctl;
17193737Shx147065 PCAN_SWAP16((uint16_t *)&frm.an_frame_ctl,
17203737Shx147065 sizeof (struct ieee80211_frame));
17213737Shx147065 /*
17223737Shx147065 * discard those frames which are not from the AP we connect or
17233737Shx147065 * without 'ap->sta' direction
17243737Shx147065 */
17253737Shx147065 if (((pcan_p->an_config.an_opmode == AN_OPMODE_INFR_STATION)) &&
17263737Shx147065 ((((frm_ctl >> 8) & IEEE80211_FC1_DIR_MASK) !=
17273737Shx147065 IEEE80211_FC1_DIR_FROMDS) ||
17283737Shx147065 bcmp(pcan_p->an_status.an_cur_bssid, frm.an_addr2, 6) != 0)) {
17293737Shx147065 ret = PCAN_FAIL;
17303737Shx147065 goto done;
17313737Shx147065 }
17323737Shx147065 bcopy(&frm.an_frame_ctl, mp->b_wptr,
17333737Shx147065 sizeof (struct ieee80211_frame));
17343737Shx147065 mp->b_wptr += sizeof (struct ieee80211_frame);
17353737Shx147065
17363737Shx147065 /* the plugin need a llc here */
17373737Shx147065 llc = (struct ieee80211_llc *)mp->b_wptr;
17383737Shx147065 llc->illc_dsap = llc->illc_ssap = AN_SNAP_K1;
17393737Shx147065 llc->illc_control = AN_SNAP_CONTROL;
17403737Shx147065 bzero(llc->illc_oc, sizeof (llc->illc_oc));
17413737Shx147065 mp->b_wptr += AN_SNAPHDR_LEN;
17423737Shx147065
17433737Shx147065 /* read in the rest of data */
17443737Shx147065 data_len += data_len & 1; /* adjust to word boundary */
17453737Shx147065 if (data_len > MBLKSIZE(mp)) {
17463737Shx147065 cmn_err(CE_NOTE, "pcan rcv: data over length%x\n", data_len);
17473737Shx147065 ret = PCAN_FAIL;
17483737Shx147065 goto done;
17493737Shx147065 }
17503737Shx147065
17513737Shx147065 if (ret = RDPKT(pcan_p, id, off, (uint16_t *)mp->b_wptr, data_len)) {
17523737Shx147065 PCANDBG((CE_NOTE, "pcan rcv: err read data %x\n", ret));
17533737Shx147065 }
17543737Shx147065 done:
17553737Shx147065 if (ret) {
17563737Shx147065 PCANDBG((CE_NOTE, "pcan rcv: rd data %x\n", ret));
17573737Shx147065 freemsg(mp);
17583737Shx147065 return;
17593737Shx147065 }
17603737Shx147065 mp->b_wptr += data_len;
17613737Shx147065 #ifdef DEBUG
17623737Shx147065 if (pcan_debug & PCAN_DBG_RCV) {
17633737Shx147065 int i;
17643737Shx147065 cmn_err(CE_NOTE, "pcan rcv: len=0x%x\n", data_len);
17653737Shx147065 for (i = 0; i < data_len + sizeof (frm); i++)
17663737Shx147065 cmn_err(CE_NOTE, "%x: %x\n", i,
17673737Shx147065 *((uint8_t *)mp->b_rptr + i));
17683737Shx147065 }
17693737Shx147065 #endif
17703737Shx147065 mutex_exit(&pcan_p->pcan_glock);
17713737Shx147065 mac_rx(GLD3(pcan_p), NULL, mp);
17723737Shx147065 mutex_enter(&pcan_p->pcan_glock);
17733737Shx147065 }
17743737Shx147065
17753737Shx147065 /*
17763737Shx147065 * retrieve data from mini-pci card
17773737Shx147065 */
17783737Shx147065 static void
pcian_rcv(pcan_maci_t * pcan_p)17793737Shx147065 pcian_rcv(pcan_maci_t *pcan_p)
17803737Shx147065 {
17813737Shx147065 struct an_card_rx_desc an_rx_desc;
17823737Shx147065 char *buf;
17833737Shx147065 uint16_t ret = 0, data_len;
17843737Shx147065 int i, j;
17853737Shx147065 struct ieee80211_frame *frm;
17863737Shx147065 struct ieee80211_llc *llc;
17873737Shx147065
17883737Shx147065 mblk_t *mp = allocb(AN_RX_BUFFER_SIZE, BPRI_MED);
17893737Shx147065 if (!mp) {
17903737Shx147065 cmn_err(CE_WARN, "pcan(pci): failed to alloc rcv buf");
17913737Shx147065 pcan_p->glds_norcvbuf++;
17923737Shx147065 return;
17933737Shx147065 }
17943737Shx147065 ASSERT(mp->b_rptr == mp->b_wptr);
17953737Shx147065
17963737Shx147065 for (i = 0; i < sizeof (an_rx_desc) / 4; i++)
17973737Shx147065 PCAN_AUX_GET32(pcan_p, AN_RX_DESC_OFFSET + (i * 4),
17983737Shx147065 ((uint32_t *)&an_rx_desc)[i]);
17993737Shx147065 if (an_rx_desc.an_done && !an_rx_desc.an_valid) {
18003737Shx147065 buf = pcan_p->pcan_rx[0].dma_virtaddr;
18013737Shx147065 data_len = an_rx_desc.an_len;
18023737Shx147065 #ifdef DEBUG
18033737Shx147065 if (pcan_debug & PCAN_DBG_RCV) {
18043737Shx147065 cmn_err(CE_NOTE, "pcan(pci) rcv: data_len=%x",
18053737Shx147065 data_len);
18063737Shx147065 for (j = 0; j < data_len + 14; j++)
18073737Shx147065 cmn_err(CE_NOTE, "pcan_rcv %d: %x", j,
18083737Shx147065 *((uint8_t *)buf + j));
18093737Shx147065 }
18103737Shx147065 #endif
18113737Shx147065 if (data_len > MBLKSIZE(mp)) {
18123737Shx147065 cmn_err(CE_NOTE, "pcan(pci) rcv: data over length%x\n",
18133737Shx147065 data_len);
18143737Shx147065 ret = PCAN_FAIL;
18153737Shx147065 goto done;
18163737Shx147065 }
18173737Shx147065 /*
18183737Shx147065 * minipci card receive an ethernet frame, so assembly a 802.11
18193737Shx147065 * frame here manually.
18203737Shx147065 */
18213737Shx147065 frm = (struct ieee80211_frame *)mp->b_wptr;
18223737Shx147065 bzero(frm, sizeof (*frm));
18233737Shx147065 frm->i_fc[0] |= IEEE80211_FC0_TYPE_DATA;
18243737Shx147065 frm->i_fc[1] |= IEEE80211_FC1_DIR_FROMDS;
18253737Shx147065 bcopy(pcan_p->an_status.an_cur_bssid, frm->i_addr2, 6);
18263737Shx147065 bcopy(buf, frm->i_addr1, 6);
18273737Shx147065 bcopy(buf + 6, frm->i_addr3, 6);
18283737Shx147065 mp->b_wptr += sizeof (struct ieee80211_frame);
18293737Shx147065
18303737Shx147065 llc = (struct ieee80211_llc *)mp->b_wptr;
18313737Shx147065 llc->illc_dsap = llc->illc_ssap = AN_SNAP_K1;
18323737Shx147065 llc->illc_control = AN_SNAP_CONTROL;
18333737Shx147065 bzero(llc->illc_oc, sizeof (llc->illc_oc));
18343737Shx147065 mp->b_wptr += AN_SNAPHDR_LEN;
18353737Shx147065
18363737Shx147065 bcopy(buf + 12, mp->b_wptr, data_len);
18373737Shx147065 mp->b_wptr += data_len;
18383737Shx147065 #ifdef DEBUG
18393737Shx147065 if (pcan_debug & PCAN_DBG_RCV) {
18403737Shx147065 int i;
18413737Shx147065 cmn_err(CE_NOTE, "pcan(pci) rcv: len=0x%x\n", data_len);
18423737Shx147065 for (i = 0; i < data_len + sizeof (*frm)
18433737Shx147065 + sizeof (*llc); i++)
18443737Shx147065 cmn_err(CE_NOTE, "%x: %x\n", i,
18453737Shx147065 *((uint8_t *)mp->b_rptr + i));
18463737Shx147065 }
18473737Shx147065 #endif
18483737Shx147065 mutex_exit(&pcan_p->pcan_glock);
18493737Shx147065 mac_rx(GLD3(pcan_p), NULL, mp);
18503737Shx147065 mutex_enter(&pcan_p->pcan_glock);
18513737Shx147065 }
18523737Shx147065 done:
18533737Shx147065 bzero(&an_rx_desc, sizeof (an_rx_desc));
18543737Shx147065 an_rx_desc.an_valid = 1;
18553737Shx147065 an_rx_desc.an_len = AN_RX_BUFFER_SIZE;
18563737Shx147065 an_rx_desc.an_done = 0;
18573737Shx147065 an_rx_desc.an_phys = pcan_p->pcan_rx[0].dma_physaddr;
18583737Shx147065
18593737Shx147065 for (i = 0; i < sizeof (an_rx_desc) / 4; i++)
18603737Shx147065 PCAN_AUX_PUT32(pcan_p, AN_RX_DESC_OFFSET + (i * 4),
18613737Shx147065 ((uint32_t *)&an_rx_desc)[i]);
18623737Shx147065 if (ret) {
18633737Shx147065 freemsg(mp);
18643737Shx147065 }
18653737Shx147065 }
18663737Shx147065
18673737Shx147065 /*ARGSUSED*/
18683737Shx147065 static uint32_t
pcan_txdone(pcan_maci_t * pcan_p,uint16_t err)18693737Shx147065 pcan_txdone(pcan_maci_t *pcan_p, uint16_t err)
18703737Shx147065 {
18713737Shx147065 uint16_t fid, i, ring_idx;
18723737Shx147065 uint32_t ret = 0;
18733737Shx147065
18743737Shx147065 PCAN_READ(pcan_p, AN_TX_CMP_FID(pcan_p), fid);
18753737Shx147065 mutex_enter(&pcan_p->pcan_txring.an_tx_lock);
18763737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
18773737Shx147065 if (pcan_p->pcan_flag & PCAN_CARD_SEND) {
18783737Shx147065 ring_idx = pcan_p->pcan_txring.an_tx_cons;
18793737Shx147065 pcan_p->pcan_txring.an_tx_cons =
18803737Shx147065 (ring_idx + 1) % AN_MAX_TX_DESC;
18813737Shx147065 if (pcan_p->pcan_txring.an_tx_prod ==
18823737Shx147065 pcan_p->pcan_txring.an_tx_cons) {
18833737Shx147065 pcan_p->pcan_flag &= ~PCAN_CARD_SEND;
18843737Shx147065 }
18853737Shx147065 }
18863737Shx147065 ret = 0;
18873737Shx147065 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
18883737Shx147065 for (i = 0; i < AN_TX_RING_CNT; i++) {
18893737Shx147065 if (fid == pcan_p->pcan_txring.an_tx_ring[i]) {
18903737Shx147065 pcan_p->pcan_txring.an_tx_ring[i] = 0;
18913737Shx147065 break;
18923737Shx147065 }
18933737Shx147065 }
18943737Shx147065 pcan_p->pcan_txring.an_tx_cons =
18953737Shx147065 (pcan_p->pcan_txring.an_tx_cons + 1) & AN_TX_RING_MASK;
18963737Shx147065 ret = (i == AN_TX_RING_CNT ? 1 : 0);
18973737Shx147065 }
18983737Shx147065 mutex_exit(&pcan_p->pcan_txring.an_tx_lock);
18993737Shx147065 return (ret);
19003737Shx147065 }
19013737Shx147065
19023737Shx147065 /*
19033737Shx147065 * delay in which the mutex is not hold.
19043737Shx147065 * assuming the mutex has already been hold.
19053737Shx147065 */
19063737Shx147065 static void
pcan_delay(pcan_maci_t * pcan_p,clock_t microsecs)19073737Shx147065 pcan_delay(pcan_maci_t *pcan_p, clock_t microsecs)
19083737Shx147065 {
19093737Shx147065 ASSERT(mutex_owned(&pcan_p->pcan_glock));
19103737Shx147065
19113737Shx147065 mutex_exit(&pcan_p->pcan_glock);
19123737Shx147065 delay(drv_usectohz(microsecs));
19133737Shx147065 mutex_enter(&pcan_p->pcan_glock);
19143737Shx147065 }
19153737Shx147065
19163737Shx147065 static void
pcan_reset_backend(pcan_maci_t * pcan_p,int timeout)19173737Shx147065 pcan_reset_backend(pcan_maci_t *pcan_p, int timeout)
19183737Shx147065 {
19193737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
19203737Shx147065 (void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0);
19213737Shx147065 PCAN_DISABLE_INTR_CLEAR(pcan_p);
19223737Shx147065 (void) pcan_set_cmd(pcan_p, AN_CMD_FW_RESTART, 0);
19233737Shx147065 (void) pcan_set_cmd(pcan_p, AN_CMD_NOOP2, 0);
19243737Shx147065 (void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0);
19253737Shx147065 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
19263737Shx147065 (void) pcan_set_cmd0(pcan_p, AN_CMD_DISABLE, 0, 0, 0);
19273737Shx147065 (void) pcan_set_cmd0(pcan_p, AN_CMD_NOOP2, 0, 0, 0);
19283737Shx147065 PCAN_WRITE(pcan_p, AN_COMMAND(pcan_p), AN_CMD_FW_RESTART);
19293737Shx147065 pcan_delay(pcan_p, timeout); /* wait for firmware restart */
19303737Shx147065
19313737Shx147065 (void) pcan_set_cmd(pcan_p, AN_CMD_NOOP, 0);
19323737Shx147065 (void) pcan_set_cmd0(pcan_p, AN_CMD_DISABLE, 0, 0, 0);
19333737Shx147065
19343737Shx147065 PCAN_DISABLE_INTR_CLEAR(pcan_p);
19353737Shx147065 }
19363737Shx147065 }
19373737Shx147065
19383737Shx147065 /*
19393737Shx147065 * set command without the need of ACK.
19403737Shx147065 */
19413737Shx147065 static uint16_t
pcan_set_cmd0(pcan_maci_t * pcan_p,uint16_t cmd,uint16_t p0,uint16_t p1,uint16_t p2)19423737Shx147065 pcan_set_cmd0(pcan_maci_t *pcan_p, uint16_t cmd, uint16_t p0,
19433737Shx147065 uint16_t p1, uint16_t p2)
19443737Shx147065 {
19453737Shx147065 int i;
19463737Shx147065 uint16_t stat, r0, r1, r2;
19473737Shx147065
19483737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
19493737Shx147065 for (i = 0; i < AN_TIMEOUT; i++) {
19503737Shx147065 PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat);
19513737Shx147065 if (!(stat & AN_CMD_BUSY))
19523737Shx147065 break;
19533737Shx147065 }
19543737Shx147065 if (i == AN_TIMEOUT) {
19553737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p),
19563737Shx147065 AN_EV_CLR_STUCK_BUSY);
19573737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
19583737Shx147065 drv_usecwait(10);
19593737Shx147065 }
19603737Shx147065 PCAN_WRITE(pcan_p, AN_PARAM0(pcan_p), p0);
19613737Shx147065 PCAN_WRITE(pcan_p, AN_PARAM1(pcan_p), p1);
19623737Shx147065 PCAN_WRITE(pcan_p, AN_PARAM2(pcan_p), p2);
19633737Shx147065 }
19643737Shx147065 PCAN_WRITE(pcan_p, AN_COMMAND(pcan_p), cmd);
19653737Shx147065 for (i = 0; i < AN_TIMEOUT; i++) {
19663737Shx147065 PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat);
19673737Shx147065 if (stat & AN_EV_CMD)
19683737Shx147065 break;
19693737Shx147065 }
19703737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
19713737Shx147065 PCAN_READ(pcan_p, AN_RESP0(pcan_p), r0);
19723737Shx147065 PCAN_READ(pcan_p, AN_RESP1(pcan_p), r1);
19733737Shx147065 PCAN_READ(pcan_p, AN_RESP2(pcan_p), r2);
19743737Shx147065 PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat);
19753737Shx147065 if (stat & AN_CMD_BUSY)
19763737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p),
19773737Shx147065 AN_EV_CLR_STUCK_BUSY);
19783737Shx147065 PCANDBG((CE_NOTE, "pcan set_cmd0: "
19793737Shx147065 "stat=%x, r0=%x, r1=%x, r2=%x\n",
19803737Shx147065 stat, r0, r1, r2));
19813737Shx147065 }
19823737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
19833737Shx147065 return (i == AN_TIMEOUT ? PCAN_TIMEDOUT_ACCESS : PCAN_SUCCESS);
19843737Shx147065 }
19853737Shx147065
19863737Shx147065 static uint16_t
pcan_set_cmd(pcan_maci_t * pcan_p,uint16_t cmd,uint16_t param)19873737Shx147065 pcan_set_cmd(pcan_maci_t *pcan_p, uint16_t cmd, uint16_t param)
19883737Shx147065 {
19893737Shx147065 int i;
19903737Shx147065 uint16_t stat, r0, r1, r2;
19913737Shx147065 uint16_t ret;
19923737Shx147065
19933737Shx147065 if (((cmd == AN_CMD_ENABLE) &&
19943737Shx147065 ((pcan_p->pcan_flag & PCAN_ENABLED) != 0)) ||
19953737Shx147065 ((cmd == AN_CMD_DISABLE) &&
19963737Shx147065 ((pcan_p->pcan_flag & PCAN_ENABLED) == 0)))
19973737Shx147065 return (PCAN_SUCCESS);
19983737Shx147065 for (i = 0; i < AN_TIMEOUT; i++) {
19993737Shx147065 PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat);
20003737Shx147065 if (!(stat & AN_CMD_BUSY)) {
20013737Shx147065 break;
20023737Shx147065 }
20033737Shx147065 }
20043737Shx147065 if (i == AN_TIMEOUT) {
20053737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CLR_STUCK_BUSY);
20063737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
20073737Shx147065 drv_usecwait(10);
20083737Shx147065 }
20093737Shx147065
20103737Shx147065 PCAN_WRITE(pcan_p, AN_PARAM0(pcan_p), param);
20113737Shx147065 PCAN_WRITE(pcan_p, AN_PARAM1(pcan_p), 0);
20123737Shx147065 PCAN_WRITE(pcan_p, AN_PARAM2(pcan_p), 0);
20133737Shx147065 PCAN_WRITE(pcan_p, AN_COMMAND(pcan_p), cmd);
20143737Shx147065
20153737Shx147065 for (i = 0; i < AN_TIMEOUT; i++) {
20163737Shx147065 PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat);
20173737Shx147065 if (stat & AN_EV_CMD) {
20183737Shx147065 break;
20193737Shx147065 }
20203737Shx147065 PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat);
20213737Shx147065 if (stat == cmd)
20223737Shx147065 PCAN_WRITE(pcan_p, AN_COMMAND(pcan_p), cmd);
20233737Shx147065 }
20243737Shx147065 if (i == AN_TIMEOUT) {
20253737Shx147065 if (cmd == AN_CMD_FW_RESTART) {
20263737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
20273737Shx147065 return (PCAN_SUCCESS);
20283737Shx147065 }
20293737Shx147065 #ifdef DEBUG
20303737Shx147065 if (pcan_debug & PCAN_DBG_CMD) {
20313737Shx147065 cmn_err(CE_WARN, "pcan set_cmd: %x timeout stat=%x\n",
20323737Shx147065 cmd, stat);
20333737Shx147065 }
20343737Shx147065 #endif
20353737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
20363737Shx147065 return (PCAN_TIMEDOUT_CMD);
20373737Shx147065 }
20383737Shx147065
20393737Shx147065 for (i = 0; i < AN_TIMEOUT; i++) {
20403737Shx147065 PCAN_READ(pcan_p, AN_STATUS(pcan_p), stat);
20413737Shx147065 PCAN_READ(pcan_p, AN_RESP0(pcan_p), r0);
20423737Shx147065 PCAN_READ(pcan_p, AN_RESP1(pcan_p), r1);
20433737Shx147065 PCAN_READ(pcan_p, AN_RESP2(pcan_p), r2);
20443737Shx147065 if ((stat & AN_STAT_CMD_CODE) == (cmd & AN_STAT_CMD_CODE))
20453737Shx147065 break;
20463737Shx147065 }
20473737Shx147065 if (cmd == AN_CMD_FW_RESTART) {
20483737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
20493737Shx147065 return (PCAN_SUCCESS);
20503737Shx147065 }
20513737Shx147065 if (i == AN_TIMEOUT) {
20523737Shx147065 #ifdef DEBUG
20533737Shx147065 if (pcan_debug & PCAN_DBG_CMD) {
20543737Shx147065 cmn_err(CE_WARN, "pcan set_cmd<%x,%x>: timeout "
20553737Shx147065 "%x,%x,%x,%x\n", cmd, param, stat, r0, r1, r2);
20563737Shx147065 }
20573737Shx147065 #endif
20583737Shx147065 ret = PCAN_TIMEDOUT_ACCESS;
20593737Shx147065 } else {
20603737Shx147065 if (stat & AN_STAT_CMD_RESULT) {
20613737Shx147065 #ifdef DEBUG
20623737Shx147065 if (pcan_debug & PCAN_DBG_CMD) {
20633737Shx147065 cmn_err(CE_WARN, "pcan set_cmd<%x,%x>: failed "
20643737Shx147065 "%x,%x,%x,%x\n",
20653737Shx147065 cmd, param, stat, r0, r1, r2);
20663737Shx147065 }
20673737Shx147065 #endif
20683737Shx147065 ret = PCAN_TIMEDOUT_ACCESS;
20693737Shx147065 } else {
20703737Shx147065 ret = PCAN_SUCCESS;
20713737Shx147065 }
20723737Shx147065 }
20733737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
20743737Shx147065 PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat);
20753737Shx147065 if (stat & AN_CMD_BUSY)
20763737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CLR_STUCK_BUSY);
20773737Shx147065 if (ret == PCAN_SUCCESS) {
20783737Shx147065 if (cmd == AN_CMD_ENABLE)
20793737Shx147065 pcan_p->pcan_flag |= PCAN_ENABLED;
20803737Shx147065 if (cmd == AN_CMD_DISABLE)
20813737Shx147065 pcan_p->pcan_flag &= (~PCAN_ENABLED);
20823737Shx147065 }
20833737Shx147065 return (ret);
20843737Shx147065 }
20853737Shx147065
20863737Shx147065 static uint16_t
pcan_set_ch(pcan_maci_t * pcan_p,uint16_t type,uint16_t off,uint16_t channel)20873737Shx147065 pcan_set_ch(pcan_maci_t *pcan_p, uint16_t type, uint16_t off, uint16_t channel)
20883737Shx147065 {
20893737Shx147065 int i;
20903737Shx147065 uint16_t stat, select, offset;
20913737Shx147065
20923737Shx147065 if (channel) {
20933737Shx147065 select = AN_SEL1;
20943737Shx147065 offset = AN_OFF1;
20953737Shx147065 } else {
20963737Shx147065 select = AN_SEL0;
20973737Shx147065 offset = AN_OFF0;
20983737Shx147065 }
20993737Shx147065 PCAN_WRITE(pcan_p, select, type);
21003737Shx147065 PCAN_WRITE(pcan_p, offset, off);
21013737Shx147065 for (i = 0; i < AN_TIMEOUT; i++) {
21023737Shx147065 PCAN_READ(pcan_p, offset, stat);
21033737Shx147065 if (!(stat & (AN_OFF_BUSY|AN_OFF_ERR)))
21043737Shx147065 break;
21053737Shx147065 }
21063737Shx147065 if (stat & (AN_OFF_BUSY|AN_OFF_ERR)) { /* time out */
21073737Shx147065 PCANDBG((CE_WARN, "pcan: set_ch%d %x %x TO %x\n",
21083737Shx147065 channel, type, off, stat));
21093737Shx147065 return (PCAN_TIMEDOUT_TARGET);
21103737Shx147065 }
21113737Shx147065 return (PCAN_SUCCESS);
21123737Shx147065 }
21133737Shx147065
21143737Shx147065 static uint16_t
pcan_get_ltv(pcan_maci_t * pcan_p,uint16_t len,uint16_t type,uint16_t * val_p)21153737Shx147065 pcan_get_ltv(pcan_maci_t *pcan_p, uint16_t len, uint16_t type, uint16_t *val_p)
21163737Shx147065 {
21173737Shx147065 uint16_t stat;
21183737Shx147065
21193737Shx147065 PCANDBG((CE_NOTE, "pcan: get_ltv(%p,%x,%x,%p)\n",
21204343Sgd78059 (void *)pcan_p, len, type, (void *)val_p));
21213737Shx147065 ASSERT(!(len & 1));
21223737Shx147065
21233737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
21243737Shx147065 uint32_t i;
21253737Shx147065 struct an_card_rid_desc an_rid_desc;
21263737Shx147065 struct an_ltv_gen *an_ltv;
21273737Shx147065 if (!pcan_p->pcan_cmd.dma_virtaddr)
21283737Shx147065 return (EIO);
21293737Shx147065 an_rid_desc.an_valid = 1;
21303737Shx147065 an_rid_desc.an_len = AN_RID_BUFFER_SIZE;
21313737Shx147065 an_rid_desc.an_rid = 0;
21323737Shx147065 an_rid_desc.an_phys = pcan_p->pcan_cmd.dma_physaddr;
21333737Shx147065 bzero(pcan_p->pcan_cmd.dma_virtaddr, AN_RID_BUFFER_SIZE);
21343737Shx147065
21353737Shx147065 for (i = 0; i < sizeof (an_rid_desc) / 4; i++)
21363737Shx147065 PCAN_AUX_PUT32(pcan_p, AN_HOST_DESC_OFFSET + i * 4,
21373737Shx147065 ((uint32_t *)&an_rid_desc)[i]);
21383737Shx147065
21393737Shx147065 if (pcan_set_cmd0(pcan_p, AN_CMD_ACCESS |
21403737Shx147065 AN_ACCESS_READ, type, 0, 0)) {
21413737Shx147065 cmn_err(CE_WARN, "pcan get_ltv: set cmd error");
21423737Shx147065 return (EIO);
21433737Shx147065 }
21443737Shx147065
21453737Shx147065 an_ltv = (struct an_ltv_gen *)pcan_p->pcan_cmd.dma_virtaddr;
21463737Shx147065 #ifdef DEBUG
21473737Shx147065 if (pcan_debug & PCAN_DBG_INFO) {
21483737Shx147065 cmn_err(CE_NOTE, "pcan get_ltv: type=%x,"
21493737Shx147065 "expected len=%d," "actual len=%d",
21503737Shx147065 type, len, an_ltv->an_len);
21513737Shx147065 for (i = 0; i < an_ltv->an_len; i++)
21523737Shx147065 cmn_err(CE_NOTE, "%d: %x", i,
21533737Shx147065 *(((uint8_t *)an_ltv) + i));
21543737Shx147065 }
21553737Shx147065 #endif
21563737Shx147065 if (an_ltv->an_len != len) {
21573737Shx147065 PCANDBG((CE_WARN, "pcan get_ltv: rid=%x expected len=%d"
21583737Shx147065 "actual: len=%d", type,
21593737Shx147065 len, an_ltv->an_len));
21603737Shx147065 /* return (EIO); */
21613737Shx147065 }
21623737Shx147065 bcopy(an_ltv, val_p, len);
21633737Shx147065 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
21643737Shx147065 len >>= 1; /* convert bytes to 16-bit words */
21653737Shx147065
21663737Shx147065 /* 1. select read mode */
21673737Shx147065 if (stat = pcan_set_cmd(pcan_p, AN_CMD_ACCESS |
21683737Shx147065 AN_ACCESS_READ, type))
21693737Shx147065 return (stat);
21703737Shx147065
21713737Shx147065 /* 2. select Buffer Access Path (channel) 1 for PIO */
21723737Shx147065 if (stat = pcan_set_ch(pcan_p, type, 0, 1))
21733737Shx147065 return (stat);
21743737Shx147065
21753737Shx147065 /* 3. read length */
21763737Shx147065 PCAN_READ(pcan_p, AN_DATA1, stat);
21773737Shx147065 *val_p++ = stat;
21783737Shx147065 if (stat != (len << 1)) {
21793737Shx147065 PCANDBG((CE_NOTE, "pcan get_ltv[%x]:expect %x,"
21803737Shx147065 "got %x\n", type, (len + 1) << 1, stat));
21813737Shx147065 stat = (stat >> 1) - 1;
21823737Shx147065 len = MIN(stat, len);
21833737Shx147065 }
21843737Shx147065 /* 4. read value */
21853737Shx147065 for (stat = 0; stat < len - 1; stat++, val_p++) {
21863737Shx147065 PCAN_READ_P(pcan_p, AN_DATA1, val_p, 1);
21873737Shx147065 }
21883737Shx147065 }
21893737Shx147065 return (PCAN_SUCCESS);
21903737Shx147065 }
21913737Shx147065
21923737Shx147065 static uint16_t
pcan_put_ltv(pcan_maci_t * pcan_p,uint16_t len,uint16_t type,uint16_t * val_p)21933737Shx147065 pcan_put_ltv(pcan_maci_t *pcan_p, uint16_t len, uint16_t type, uint16_t *val_p)
21943737Shx147065 {
21953737Shx147065 uint16_t stat;
21963737Shx147065 int i;
21973737Shx147065
21983737Shx147065 ASSERT(!(len & 1));
21993737Shx147065
22003737Shx147065 if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
22013737Shx147065 struct an_card_rid_desc an_rid_desc;
22023737Shx147065
22033737Shx147065 for (i = 0; i < AN_TIMEOUT; i++) {
22043737Shx147065 PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat);
22053737Shx147065 if (!(stat & AN_CMD_BUSY)) {
22063737Shx147065 break;
22073737Shx147065 }
22083737Shx147065 }
22093737Shx147065 if (i == AN_TIMEOUT) {
22103737Shx147065 cmn_err(CE_WARN, "pcan put_ltv: busy");
22113737Shx147065 }
22123737Shx147065
22133737Shx147065 an_rid_desc.an_valid = 1;
22143737Shx147065 an_rid_desc.an_len = len;
22153737Shx147065 an_rid_desc.an_rid = type;
22163737Shx147065 an_rid_desc.an_phys = pcan_p->pcan_cmd.dma_physaddr;
22173737Shx147065
22183737Shx147065 bcopy(val_p, pcan_p->pcan_cmd.dma_virtaddr,
22193737Shx147065 an_rid_desc.an_len);
22203737Shx147065
22213737Shx147065 for (i = 0; i < sizeof (an_rid_desc) / 4; i++)
22223737Shx147065 PCAN_AUX_PUT32(pcan_p, AN_HOST_DESC_OFFSET + i * 4,
22233737Shx147065 ((uint32_t *)&an_rid_desc)[i]);
22243737Shx147065 pcan_delay(pcan_p, 100000);
22253737Shx147065 stat = pcan_set_cmd0(pcan_p, AN_CMD_ACCESS |
22263737Shx147065 AN_ACCESS_WRITE, type, 0, 0);
22273737Shx147065 pcan_delay(pcan_p, 100000);
22283737Shx147065 return (stat);
22293737Shx147065 } else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
22303737Shx147065 /* 0. select read mode first */
22313737Shx147065 if (stat = pcan_set_cmd(pcan_p, AN_CMD_ACCESS |
22323737Shx147065 AN_ACCESS_READ, type))
22333737Shx147065 return (stat);
22343737Shx147065
22353737Shx147065 /* 1. select Buffer Access Path (channel) 1 for PIO */
22363737Shx147065 if (stat = pcan_set_ch(pcan_p, type, 0, 1))
22373737Shx147065 return (stat);
22383737Shx147065
22393737Shx147065 /* 2. write length */
22403737Shx147065 len >>= 1; /* convert bytes to 16-bit words */
22413737Shx147065 stat = len;
22423737Shx147065 PCAN_WRITE(pcan_p, AN_DATA1, stat);
22433737Shx147065
22443737Shx147065 /* 3. write value */
22453737Shx147065 val_p++;
22463737Shx147065 for (stat = 0; stat < len-1; stat++, val_p++) {
22473737Shx147065 PCAN_WRITE_P(pcan_p, AN_DATA1, val_p, 1);
22483737Shx147065 }
22493737Shx147065
22503737Shx147065 /* 4. select write mode */
22513737Shx147065 return (pcan_set_cmd(pcan_p, AN_CMD_ACCESS |
22523737Shx147065 AN_ACCESS_WRITE, type));
22533737Shx147065 }
22543737Shx147065 return (PCAN_FAIL);
22553737Shx147065 }
22563737Shx147065
22573737Shx147065 /*ARGSUSED*/
22583737Shx147065 static uint16_t
pcan_rdch0(pcan_maci_t * pcan_p,uint16_t type,uint16_t off,uint16_t * buf_p,int len,int order)22593737Shx147065 pcan_rdch0(pcan_maci_t *pcan_p, uint16_t type, uint16_t off, uint16_t *buf_p,
22603737Shx147065 int len, int order)
22613737Shx147065 {
22623737Shx147065 ASSERT(!(len & 1));
22633737Shx147065
22643737Shx147065 if (pcan_set_ch(pcan_p, type, off, 0) != PCAN_SUCCESS)
22653737Shx147065 return (PCAN_FAIL);
22663737Shx147065 len >>= 1;
22673737Shx147065 for (off = 0; off < len; off++, buf_p++) {
22683737Shx147065 PCAN_READ_P(pcan_p, AN_DATA0, buf_p, order);
22693737Shx147065 }
22703737Shx147065 return (PCAN_SUCCESS);
22713737Shx147065 }
22723737Shx147065
22733737Shx147065 /*ARGSUSED*/
22743737Shx147065 static uint16_t
pcan_wrch1(pcan_maci_t * pcan_p,uint16_t type,uint16_t off,uint16_t * buf_p,int len,int order)22753737Shx147065 pcan_wrch1(pcan_maci_t *pcan_p, uint16_t type, uint16_t off, uint16_t *buf_p,
22763737Shx147065 int len, int order)
22773737Shx147065 {
22783737Shx147065 ASSERT(!(len & 1));
22793737Shx147065
22803737Shx147065 if (pcan_set_ch(pcan_p, type, off, 1) != PCAN_SUCCESS)
22813737Shx147065 return (PCAN_FAIL);
22823737Shx147065 len >>= 1;
22833737Shx147065 for (off = 0; off < len; off++, buf_p++) {
22843737Shx147065 PCAN_WRITE_P(pcan_p, AN_DATA1, buf_p, order);
22853737Shx147065 }
22863737Shx147065 return (PCAN_SUCCESS);
22873737Shx147065 }
22883737Shx147065
22893737Shx147065 static uint16_t
pcan_status_ltv(int rw,pcan_maci_t * pcan_p,struct an_ltv_status * status_p)22903737Shx147065 pcan_status_ltv(int rw, pcan_maci_t *pcan_p, struct an_ltv_status *status_p)
22913737Shx147065 {
22923737Shx147065 uint16_t ret, len;
22933737Shx147065
22943737Shx147065 if (rw != PCAN_READ_LTV) {
22953737Shx147065 cmn_err(CE_WARN, "pcan status_ltv: unsupported op %x", rw);
22963737Shx147065 return (PCAN_FAIL);
22973737Shx147065 }
22983737Shx147065 if (ret = pcan_get_ltv(pcan_p, sizeof (*status_p), AN_RID_STATUS,
22993737Shx147065 (uint16_t *)status_p))
23003737Shx147065 return (ret);
23013737Shx147065
23023737Shx147065 PCAN_SWAP16_BUF(status_p->an_macaddr);
23033737Shx147065 PCAN_SWAP16_BUF(status_p->an_ssid);
23043737Shx147065 len = min(status_p->an_ssidlen, 31);
23053737Shx147065 status_p->an_ssid[len] = '\0';
23063737Shx147065 PCAN_SWAP16_BUF(status_p->an_ap_name);
23073737Shx147065 PCAN_SWAP16_BUF(status_p->an_cur_bssid);
23083737Shx147065 PCAN_SWAP16_BUF(status_p->an_prev_bssid1);
23093737Shx147065 PCAN_SWAP16_BUF(status_p->an_prev_bssid2);
23103737Shx147065 PCAN_SWAP16_BUF(status_p->an_prev_bssid3);
23113737Shx147065 PCAN_SWAP16_BUF(status_p->an_ap_ip_address);
23123737Shx147065 PCAN_SWAP16_BUF(status_p->an_carrier);
23133737Shx147065 return (PCAN_SUCCESS);
23143737Shx147065 }
23153737Shx147065
23163737Shx147065 static uint16_t
pcan_cfg_ltv(int rw,pcan_maci_t * pcan_p,struct an_ltv_genconfig * cfg_p)23173737Shx147065 pcan_cfg_ltv(int rw, pcan_maci_t *pcan_p, struct an_ltv_genconfig *cfg_p)
23183737Shx147065 {
23193737Shx147065 uint16_t ret;
23203737Shx147065 uint16_t rid = cfg_p == &pcan_p->an_config ?
23213737Shx147065 AN_RID_GENCONFIG : AN_RID_ACTUALCFG;
23223737Shx147065
23233737Shx147065 if (rw == PCAN_READ_LTV) {
23243737Shx147065 if (ret = pcan_get_ltv(pcan_p, sizeof (*cfg_p), rid,
23253737Shx147065 (uint16_t *)cfg_p))
23263737Shx147065 return (ret);
23273737Shx147065 goto done;
23283737Shx147065 }
23293737Shx147065 PCAN_SWAP16_BUF(cfg_p->an_macaddr);
23303737Shx147065 PCAN_SWAP16_BUF(cfg_p->an_rates);
23313737Shx147065 if (ret = pcan_put_ltv(pcan_p, sizeof (*cfg_p),
23323737Shx147065 rid, (uint16_t *)cfg_p))
23333737Shx147065 return (ret);
23343737Shx147065 done:
23353737Shx147065 PCAN_SWAP16_BUF(cfg_p->an_macaddr);
23363737Shx147065 PCAN_SWAP16_BUF(cfg_p->an_rates);
23373737Shx147065 return (ret);
23383737Shx147065 }
23393737Shx147065
23403737Shx147065 static uint16_t
pcan_cap_ltv(int rw,pcan_maci_t * pcan_p)23413737Shx147065 pcan_cap_ltv(int rw, pcan_maci_t *pcan_p)
23423737Shx147065 {
23433737Shx147065 uint16_t ret;
23443737Shx147065
23453737Shx147065 if (rw != PCAN_READ_LTV) {
23463737Shx147065 cmn_err(CE_WARN, "pcan cap_ltv: unsupported op %x", rw);
23473737Shx147065 return (PCAN_FAIL);
23483737Shx147065 }
23493737Shx147065 if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_caps),
23504343Sgd78059 AN_RID_CAPABILITIES, (uint16_t *)&pcan_p->an_caps))
23513737Shx147065 return (ret);
23523737Shx147065
23533737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_caps.an_oui);
23543737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_caps.an_manufname);
23553737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_caps.an_prodname);
23563737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_caps.an_prodvers);
23573737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_caps.an_oemaddr);
23583737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_caps.an_aironetaddr);
23593737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_caps.an_callid);
23603737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_caps.an_supported_rates);
23613737Shx147065 return (PCAN_SUCCESS);
23623737Shx147065 }
23633737Shx147065
23643737Shx147065 static uint16_t
pcan_ssid_ltv(int rw,pcan_maci_t * pcan_p)23653737Shx147065 pcan_ssid_ltv(int rw, pcan_maci_t *pcan_p)
23663737Shx147065 {
23673737Shx147065 uint16_t ret;
23683737Shx147065
23693737Shx147065 if (rw == PCAN_READ_LTV) {
23703737Shx147065 if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_ssidlist),
23713737Shx147065 AN_RID_SSIDLIST, (uint16_t *)&pcan_p->an_ssidlist))
23723737Shx147065 return (ret);
23733737Shx147065 goto done;
23743737Shx147065 }
23753737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid1);
23763737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid2);
23773737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid3);
23783737Shx147065 if (ret = pcan_put_ltv(pcan_p, sizeof (struct an_ltv_ssidlist),
23793737Shx147065 AN_RID_SSIDLIST, (uint16_t *)&pcan_p->an_ssidlist))
23803737Shx147065 return (ret);
23813737Shx147065 done:
23823737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid1);
23833737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid2);
23843737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid3);
23853737Shx147065 return (ret);
23863737Shx147065 }
23873737Shx147065
23883737Shx147065 static uint16_t
pcan_aplist_ltv(int rw,pcan_maci_t * pcan_p)23893737Shx147065 pcan_aplist_ltv(int rw, pcan_maci_t *pcan_p)
23903737Shx147065 {
23913737Shx147065 uint16_t ret;
23923737Shx147065
23933737Shx147065 if (rw == PCAN_READ_LTV) {
23943737Shx147065 if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_aplist),
23953737Shx147065 AN_RID_APLIST, (uint16_t *)&pcan_p->an_aplist))
23963737Shx147065 return (ret);
23973737Shx147065 goto done;
23983737Shx147065 }
23993737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap1);
24003737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap2);
24013737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap3);
24023737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap4);
24033737Shx147065 if (ret = pcan_put_ltv(pcan_p, sizeof (struct an_ltv_aplist),
24043737Shx147065 AN_RID_APLIST, (uint16_t *)&pcan_p->an_aplist))
24053737Shx147065 return (ret);
24063737Shx147065 done:
24073737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap1);
24083737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap2);
24093737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap3);
24103737Shx147065 PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap4);
24113737Shx147065 return (ret);
24123737Shx147065 }
24133737Shx147065
24143737Shx147065 static uint16_t
pcan_scanresult_ltv(int rw,pcan_maci_t * pcan_p,uint16_t type,struct an_ltv_scanresult * scanresult_p)24153737Shx147065 pcan_scanresult_ltv(int rw, pcan_maci_t *pcan_p, uint16_t type,
24163737Shx147065 struct an_ltv_scanresult *scanresult_p)
24173737Shx147065 {
24183737Shx147065 uint16_t ret, len;
24193737Shx147065 if (rw != PCAN_READ_LTV) {
24203737Shx147065 cmn_err(CE_WARN, "pcan scan_ltv: readonly rid %x\n", type);
24213737Shx147065 return (PCAN_FAIL);
24223737Shx147065 }
24233737Shx147065 if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_scanresult),
24243737Shx147065 type, (uint16_t *)scanresult_p))
24253737Shx147065 return (ret);
24263737Shx147065 PCAN_SWAP16_BUF(scanresult_p->an_bssid);
24273737Shx147065 PCAN_SWAP16_BUF(scanresult_p->an_ssid);
24283737Shx147065 len = min(scanresult_p->an_ssidlen, 31);
24293737Shx147065 scanresult_p->an_ssid[len] = '\0';
24303737Shx147065 PCAN_SWAP16_BUF(scanresult_p->an_rates);
24313737Shx147065 return (PCAN_SUCCESS);
24323737Shx147065 }
24333737Shx147065
24343737Shx147065 static uint16_t
pcan_one_wepkey(int rw,pcan_maci_t * pcan_p,struct an_ltv_wepkey * wkp,uint16_t rid)24353737Shx147065 pcan_one_wepkey(int rw, pcan_maci_t *pcan_p, struct an_ltv_wepkey *wkp,
24363737Shx147065 uint16_t rid)
24373737Shx147065 {
24383737Shx147065 uint16_t ret;
24393737Shx147065
24403737Shx147065 if (rw == PCAN_READ_LTV) {
24413737Shx147065 if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_wepkey),
24423737Shx147065 rid, (uint16_t *)wkp)) {
24433737Shx147065 return (ret);
24443737Shx147065 }
24453737Shx147065 goto done;
24463737Shx147065 }
24473737Shx147065 PCAN_SWAP16_BUF(wkp->an_macaddr);
24483737Shx147065 PCAN_SWAP16_BUF(wkp->an_key);
24493737Shx147065 if (ret = pcan_put_ltv(pcan_p, sizeof (struct an_ltv_wepkey),
24503737Shx147065 rid, (uint16_t *)wkp))
24513737Shx147065 return (ret);
24523737Shx147065 done:
24533737Shx147065 PCAN_SWAP16_BUF(wkp->an_macaddr);
24543737Shx147065 PCAN_SWAP16_BUF(wkp->an_key);
24553737Shx147065 return (ret);
24563737Shx147065 }
24573737Shx147065
24583737Shx147065 static uint16_t
pcan_wepkey_ltv(int rw,pcan_maci_t * pcan_p)24593737Shx147065 pcan_wepkey_ltv(int rw, pcan_maci_t *pcan_p)
24603737Shx147065 {
24613737Shx147065 uint16_t ret, i;
24623737Shx147065 struct an_ltv_wepkey wk;
24633737Shx147065
24643737Shx147065 if (rw == PCAN_READ_LTV) {
24653737Shx147065 uint16_t rid = AN_RID_WEPKEY2;
24663737Shx147065
24673737Shx147065 if (ret = pcan_one_wepkey(rw, pcan_p, &wk, rid))
24683737Shx147065 return (ret);
24693737Shx147065 for (i = 0; i < 5; i++) {
24703737Shx147065 if (wk.an_index < 4)
24713737Shx147065 pcan_p->an_wepkey[wk.an_index] = wk;
24723737Shx147065 else if (wk.an_index == 0xffff)
24733737Shx147065 pcan_p->an_cur_wepkey = wk.an_macaddr[0];
24743737Shx147065 rid = AN_RID_WEPKEY;
24753737Shx147065 }
24763737Shx147065 return (PCAN_SUCCESS);
24773737Shx147065 }
24783737Shx147065 for (i = 0; i < MAX_NWEPKEYS; i++) {
24793737Shx147065 if (pcan_p->an_wepkey[i].an_index == i) {
24803737Shx147065 if (ret = pcan_one_wepkey(rw, pcan_p,
24813737Shx147065 &pcan_p->an_wepkey[i], AN_RID_WEPKEY2))
24823737Shx147065 return (ret);
24833737Shx147065 }
24843737Shx147065 }
24853737Shx147065 /* Now set the default key */
24863737Shx147065 (void) memset(&wk, 0, sizeof (wk));
24873737Shx147065 wk.an_index = 0xffff;
24883737Shx147065 wk.an_macaddr[0] = pcan_p->an_cur_wepkey;
24893737Shx147065 ret = pcan_one_wepkey(rw, pcan_p, &wk, AN_RID_WEPKEY2);
24903737Shx147065 return (ret);
24913737Shx147065 }
24923737Shx147065
24933737Shx147065 static uint16_t
pcan_alloc_nicmem(pcan_maci_t * pcan_p,uint16_t len,uint16_t * id_p)24943737Shx147065 pcan_alloc_nicmem(pcan_maci_t *pcan_p, uint16_t len, uint16_t *id_p)
24953737Shx147065 {
24963737Shx147065 int i;
24973737Shx147065 uint16_t stat;
24983737Shx147065
24993737Shx147065 len = ((len + 1) >> 1) << 1; /* round up to 16-bit boundary */
25003737Shx147065
25013737Shx147065 if (stat = pcan_set_cmd(pcan_p, AN_CMD_ALLOC_MEM, len))
25023737Shx147065 return (stat);
25033737Shx147065 for (i = 0; !(stat & AN_EV_ALLOC) && (i < AN_TIMEOUT); i++) {
25043737Shx147065 PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat);
25053737Shx147065 }
25063737Shx147065 if (!(stat & AN_EV_ALLOC))
25073737Shx147065 return (PCAN_TIMEDOUT_ALLOC);
25083737Shx147065 PCAN_READ(pcan_p, AN_ALLOC_FID, stat);
25093737Shx147065 PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_ALLOC);
25103737Shx147065 *id_p = stat;
25113737Shx147065
25123737Shx147065 /* zero fill the allocated NIC mem - sort of pcan_fill_ch0 */
25133737Shx147065 (void) pcan_set_ch(pcan_p, stat, 0, 0);
25143737Shx147065 for (len >>= 1, stat = 0; stat < len; stat++) {
25153737Shx147065 PCAN_WRITE(pcan_p, AN_DATA0, 0);
25163737Shx147065 }
25173737Shx147065 return (PCAN_SUCCESS);
25183737Shx147065 }
25193737Shx147065
25203737Shx147065 static void
pcan_stop_rx_dma(pcan_maci_t * pcan_p)25213737Shx147065 pcan_stop_rx_dma(pcan_maci_t *pcan_p)
25223737Shx147065 {
25233737Shx147065 int i, j;
25243737Shx147065 struct an_card_rx_desc an_rx_desc;
25253737Shx147065
25263737Shx147065 for (i = 0; i < AN_MAX_RX_DESC; i++) {
25273737Shx147065 bzero(&an_rx_desc, sizeof (an_rx_desc));
25283737Shx147065 an_rx_desc.an_valid = 0;
25293737Shx147065 an_rx_desc.an_len = AN_RX_BUFFER_SIZE;
25303737Shx147065 an_rx_desc.an_done = 1;
25313737Shx147065 an_rx_desc.an_phys = pcan_p->pcan_rx[i].dma_physaddr;
25323737Shx147065 for (j = 0; j < sizeof (an_rx_desc) / 4; j++)
25333737Shx147065 PCAN_AUX_PUT32(pcan_p, AN_RX_DESC_OFFSET
25343737Shx147065 + (i * sizeof (an_rx_desc))
25353737Shx147065 + (j * 4), ((uint32_t *)&an_rx_desc)[j]);
25363737Shx147065 }
25373737Shx147065 }
25383737Shx147065
25393737Shx147065 static int
pcan_init_dma_desc(pcan_maci_t * pcan_p)25403737Shx147065 pcan_init_dma_desc(pcan_maci_t *pcan_p)
25413737Shx147065 {
25423737Shx147065 int i, j;
25433737Shx147065 struct an_card_rid_desc an_rid_desc;
25443737Shx147065 struct an_card_rx_desc an_rx_desc;
25453737Shx147065 struct an_card_tx_desc an_tx_desc;
25463737Shx147065
25473737Shx147065 /* Allocate DMA for rx */
25483737Shx147065 if (pcan_set_cmd0(pcan_p, AN_CMD_ALLOC_DESC,
25493737Shx147065 AN_DESCRIPTOR_RX, AN_RX_DESC_OFFSET,
25503737Shx147065 AN_MAX_RX_DESC) != PCAN_SUCCESS) {
25513737Shx147065 cmn_err(CE_WARN, "pcan init_dma: fail to alloc rx descriptor");
25523737Shx147065 goto error;
25533737Shx147065 }
25543737Shx147065 for (i = 0; i < AN_MAX_RX_DESC; i++) {
25553737Shx147065 bzero(&an_rx_desc, sizeof (an_rx_desc));
25563737Shx147065 an_rx_desc.an_valid = 1;
25573737Shx147065 an_rx_desc.an_len = AN_RX_BUFFER_SIZE;
25583737Shx147065 an_rx_desc.an_done = 0;
25593737Shx147065 an_rx_desc.an_phys = pcan_p->pcan_rx[i].dma_physaddr;
25603737Shx147065 for (j = 0; j < sizeof (an_rx_desc) / 4; j++)
25613737Shx147065 PCAN_AUX_PUT32(pcan_p, AN_RX_DESC_OFFSET
25623737Shx147065 + (i * sizeof (an_rx_desc))
25633737Shx147065 + (j * 4), ((uint32_t *)&an_rx_desc)[j]);
25643737Shx147065 }
25653737Shx147065
25663737Shx147065
25673737Shx147065 /* Allocate DMA for tx */
25683737Shx147065 if (pcan_set_cmd0(pcan_p, AN_CMD_ALLOC_DESC,
25693737Shx147065 AN_DESCRIPTOR_TX, AN_TX_DESC_OFFSET,
25703737Shx147065 AN_MAX_TX_DESC) != PCAN_SUCCESS) {
25713737Shx147065 cmn_err(CE_WARN, "pcan init_dma: fail to alloc tx descriptor");
25723737Shx147065 goto error;
25733737Shx147065 }
25743737Shx147065
25753737Shx147065 for (i = 0; i < AN_MAX_TX_DESC; i++) {
25763737Shx147065 an_tx_desc.an_offset = 0;
25773737Shx147065 an_tx_desc.an_eoc = 0;
25783737Shx147065 an_tx_desc.an_valid = 0;
25793737Shx147065 an_tx_desc.an_len = 0;
25803737Shx147065 an_tx_desc.an_phys = pcan_p->pcan_tx[i].dma_physaddr;
25813737Shx147065
25823737Shx147065 for (j = 0; j < sizeof (an_tx_desc) / 4; j++)
25833737Shx147065 PCAN_AUX_PUT32(pcan_p, AN_TX_DESC_OFFSET
25843737Shx147065 + (i * sizeof (an_tx_desc))
25853737Shx147065 + (j * 4), ((uint32_t *)&an_tx_desc)[j]);
25863737Shx147065 }
25873737Shx147065
25883737Shx147065 /* Allocate DMA for rid */
25893737Shx147065 if (pcan_set_cmd0(pcan_p, AN_CMD_ALLOC_DESC,
25903737Shx147065 AN_DESCRIPTOR_HOSTRW, AN_HOST_DESC_OFFSET, 1) != PCAN_SUCCESS) {
25913737Shx147065 cmn_err(CE_WARN, "pcan init_dma: fail to alloc rid descriptor");
25923737Shx147065 goto error;
25933737Shx147065 }
25943737Shx147065 bzero(&an_rid_desc, sizeof (an_rid_desc));
25953737Shx147065 an_rid_desc.an_valid = 1;
25963737Shx147065 an_rid_desc.an_len = AN_RID_BUFFER_SIZE;
25973737Shx147065 an_rid_desc.an_rid = 0;
25983737Shx147065 an_rid_desc.an_phys = pcan_p->pcan_cmd.dma_physaddr;
25993737Shx147065
26003737Shx147065 for (i = 0; i < sizeof (an_rid_desc) / 4; i++)
26013737Shx147065 PCAN_AUX_PUT32(pcan_p, AN_HOST_DESC_OFFSET + i * 4,
26023737Shx147065 ((uint32_t *)&an_rid_desc)[i]);
26033737Shx147065
26043737Shx147065 pcan_p->pcan_txring.an_tx_prod = 0;
26053737Shx147065 pcan_p->pcan_txring.an_tx_cons = 0;
26063737Shx147065 pcan_p->pcan_flag &= ~PCAN_CARD_SEND;
26073737Shx147065 return (PCAN_SUCCESS);
26083737Shx147065 error:
26093737Shx147065 return (PCAN_FAIL);
26103737Shx147065 }
26113737Shx147065
26123737Shx147065 static int
pcan_init_dma(dev_info_t * dip,pcan_maci_t * pcan_p)26133737Shx147065 pcan_init_dma(dev_info_t *dip, pcan_maci_t *pcan_p)
26143737Shx147065 {
26153737Shx147065 int i, ret = PCAN_FAIL;
26163737Shx147065 ddi_dma_cookie_t dma_cookie;
26173737Shx147065 size_t len;
26183737Shx147065
26193737Shx147065 /* Allocate DMA for rx */
26203737Shx147065 for (i = 0; i < AN_MAX_RX_DESC; i++) {
26213737Shx147065 if (ddi_dma_alloc_handle(dip, &control_cmd_dma_attr,
26223737Shx147065 DDI_DMA_SLEEP, 0,
26233737Shx147065 &pcan_p->pcan_rx[i].dma_handle) != DDI_SUCCESS)
26243737Shx147065 goto error;
26253737Shx147065
26263737Shx147065 if (ddi_dma_mem_alloc(pcan_p->pcan_rx[i].dma_handle,
26273737Shx147065 AN_RX_BUFFER_SIZE, &accattr,
26283737Shx147065 DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0,
26293737Shx147065 (caddr_t *)&pcan_p->pcan_rx[i].dma_virtaddr, &len,
26303737Shx147065 &pcan_p->pcan_rx[i].dma_acc_handle) != DDI_SUCCESS) {
26313737Shx147065 goto error;
26323737Shx147065 }
26333737Shx147065 if (ddi_dma_addr_bind_handle(
26343737Shx147065 pcan_p->pcan_rx[i].dma_handle,
26353737Shx147065 NULL, (caddr_t)pcan_p->pcan_rx[i].dma_virtaddr,
26363737Shx147065 len, DDI_DMA_READ |
26373737Shx147065 DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0, &dma_cookie,
26383737Shx147065 &pcan_p->pcan_rx[i].ncookies) != DDI_DMA_MAPPED) {
26393737Shx147065 goto error;
26403737Shx147065 }
26413737Shx147065 ASSERT(pcan_p->pcan_rx[i].ncookies == 1);
26423737Shx147065 pcan_p->pcan_rx[i].dma_physaddr = dma_cookie.dmac_address;
26433737Shx147065 }
26443737Shx147065
26453737Shx147065 /* Allocate DMA for tx */
26463737Shx147065 for (i = 0; i < AN_MAX_TX_DESC; i++) {
26473737Shx147065 if (ddi_dma_alloc_handle(dip, &control_cmd_dma_attr,
26483737Shx147065 DDI_DMA_SLEEP, 0,
26493737Shx147065 &pcan_p->pcan_tx[i].dma_handle) != DDI_SUCCESS)
26503737Shx147065 goto error;
26513737Shx147065
26523737Shx147065 if (ddi_dma_mem_alloc(pcan_p->pcan_tx[i].dma_handle,
26533737Shx147065 AN_TX_BUFFER_SIZE, &accattr,
26543737Shx147065 DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0,
26553737Shx147065 (caddr_t *)&pcan_p->pcan_tx[i].dma_virtaddr, &len,
26563737Shx147065 &pcan_p->pcan_tx[i].dma_acc_handle) != DDI_SUCCESS) {
26573737Shx147065 goto error;
26583737Shx147065 }
26593737Shx147065 if (ddi_dma_addr_bind_handle(
26603737Shx147065 pcan_p->pcan_tx[i].dma_handle,
26613737Shx147065 NULL, (caddr_t)pcan_p->pcan_tx[i].dma_virtaddr,
26623737Shx147065 len, DDI_DMA_WRITE |
26633737Shx147065 DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0, &dma_cookie,
26643737Shx147065 &pcan_p->pcan_tx[i].ncookies) != DDI_DMA_MAPPED) {
26653737Shx147065 goto error;
26663737Shx147065 }
26673737Shx147065 ASSERT(pcan_p->pcan_tx[i].ncookies == 1);
26683737Shx147065 pcan_p->pcan_tx[i].dma_physaddr = dma_cookie.dmac_address;
26693737Shx147065 }
26703737Shx147065
26713737Shx147065 /* Allocate DMA for rid */
26723737Shx147065 if (ddi_dma_alloc_handle(dip, &control_cmd_dma_attr,
26733737Shx147065 DDI_DMA_SLEEP, 0,
26743737Shx147065 &pcan_p->pcan_cmd.dma_handle) != DDI_SUCCESS)
26753737Shx147065 goto error;
26763737Shx147065
26773737Shx147065 if (ddi_dma_mem_alloc(pcan_p->pcan_cmd.dma_handle,
26783737Shx147065 AN_RID_BUFFER_SIZE, &accattr,
26793737Shx147065 DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0,
26803737Shx147065 (caddr_t *)&pcan_p->pcan_cmd.dma_virtaddr, &len,
26813737Shx147065 &pcan_p->pcan_cmd.dma_acc_handle) != DDI_SUCCESS) {
26823737Shx147065 goto error;
26833737Shx147065 }
26843737Shx147065 if (ddi_dma_addr_bind_handle(
26853737Shx147065 pcan_p->pcan_cmd.dma_handle,
26863737Shx147065 NULL, (caddr_t)pcan_p->pcan_cmd.dma_virtaddr,
26873737Shx147065 len, DDI_DMA_RDWR |
26883737Shx147065 DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0, &dma_cookie,
26893737Shx147065 &pcan_p->pcan_cmd.ncookies) != DDI_DMA_MAPPED) {
26903737Shx147065 goto error;
26913737Shx147065 }
26923737Shx147065 ASSERT(pcan_p->pcan_cmd.ncookies == 1);
26933737Shx147065 pcan_p->pcan_cmd.dma_physaddr = dma_cookie.dmac_address;
26943737Shx147065
26953737Shx147065 if (ret = pcan_init_dma_desc(pcan_p)) {
26963737Shx147065 cmn_err(CE_WARN, "pcan init_dma_desc: failed\n");
26973737Shx147065 goto error;
26983737Shx147065 }
26993737Shx147065
27003737Shx147065 return (PCAN_SUCCESS);
27013737Shx147065 error:
27023737Shx147065 pcan_free_dma(pcan_p);
27033737Shx147065 return (ret);
27043737Shx147065 }
27053737Shx147065
27063737Shx147065 static void
pcan_free_dma(pcan_maci_t * pcan_p)27073737Shx147065 pcan_free_dma(pcan_maci_t *pcan_p)
27083737Shx147065 {
27093737Shx147065 int i;
27103737Shx147065
27113737Shx147065 /* free RX dma */
27123737Shx147065 pcan_stop_rx_dma(pcan_p);
27133737Shx147065 for (i = 0; i < AN_MAX_RX_DESC; i++) {
27143737Shx147065 if (pcan_p->pcan_rx[i].dma_handle != NULL) {
27153737Shx147065 if (pcan_p->pcan_rx[i].ncookies) {
27163737Shx147065 (void) ddi_dma_unbind_handle(
27173737Shx147065 pcan_p->pcan_rx[i].dma_handle);
27183737Shx147065 pcan_p->pcan_rx[i].ncookies = 0;
27193737Shx147065 }
27203737Shx147065 ddi_dma_free_handle(
27213737Shx147065 &pcan_p->pcan_rx[i].dma_handle);
27223737Shx147065 pcan_p->pcan_rx[i].dma_handle = NULL;
27233737Shx147065 }
27243737Shx147065 if (pcan_p->pcan_rx[i].dma_acc_handle != NULL) {
27253737Shx147065 ddi_dma_mem_free(
27263737Shx147065 &pcan_p->pcan_rx[i].dma_acc_handle);
27273737Shx147065 pcan_p->pcan_rx[i].dma_acc_handle = NULL;
27283737Shx147065 }
27293737Shx147065 }
27303737Shx147065
27313737Shx147065 /* free TX dma */
27323737Shx147065 for (i = 0; i < AN_MAX_TX_DESC; i++) {
27333737Shx147065 if (pcan_p->pcan_tx[i].dma_handle != NULL) {
27343737Shx147065 if (pcan_p->pcan_tx[i].ncookies) {
27353737Shx147065 (void) ddi_dma_unbind_handle(
27363737Shx147065 pcan_p->pcan_tx[i].dma_handle);
27373737Shx147065 pcan_p->pcan_tx[i].ncookies = 0;
27383737Shx147065 }
27393737Shx147065 ddi_dma_free_handle(
27403737Shx147065 &pcan_p->pcan_tx[i].dma_handle);
27413737Shx147065 pcan_p->pcan_tx[i].dma_handle = NULL;
27423737Shx147065 }
27433737Shx147065 if (pcan_p->pcan_tx[i].dma_acc_handle != NULL) {
27443737Shx147065 ddi_dma_mem_free(
27453737Shx147065 &pcan_p->pcan_tx[i].dma_acc_handle);
27463737Shx147065 pcan_p->pcan_tx[i].dma_acc_handle = NULL;
27473737Shx147065 }
27483737Shx147065 }
27493737Shx147065
27503737Shx147065 /* free cmd dma */
27513737Shx147065 if (pcan_p->pcan_cmd.dma_handle != NULL) {
27523737Shx147065 if (pcan_p->pcan_cmd.ncookies) {
27533737Shx147065 (void) ddi_dma_unbind_handle(
27543737Shx147065 pcan_p->pcan_cmd.dma_handle);
27553737Shx147065 pcan_p->pcan_cmd.ncookies = 0;
27563737Shx147065 }
27573737Shx147065 ddi_dma_free_handle(
27583737Shx147065 &pcan_p->pcan_cmd.dma_handle);
27593737Shx147065 pcan_p->pcan_cmd.dma_handle = NULL;
27603737Shx147065 }
27613737Shx147065 if (pcan_p->pcan_cmd.dma_acc_handle != NULL) {
27623737Shx147065 ddi_dma_mem_free(
27633737Shx147065 &pcan_p->pcan_cmd.dma_acc_handle);
27643737Shx147065 pcan_p->pcan_cmd.dma_acc_handle = NULL;
27653737Shx147065 }
27663737Shx147065 }
27673737Shx147065
27683737Shx147065 /*
27693737Shx147065 * get card capability (WEP, default channel), setup broadcast, mac addresses
27703737Shx147065 */
27713737Shx147065 static uint32_t
pcan_get_cap(pcan_maci_t * pcan_p)27723737Shx147065 pcan_get_cap(pcan_maci_t *pcan_p)
27733737Shx147065 {
27743737Shx147065 uint16_t stat;
27753737Shx147065
27763737Shx147065 if (stat = pcan_cfg_ltv(PCAN_READ_LTV, pcan_p, &pcan_p->an_config)) {
27773737Shx147065 PCANDBG((CE_NOTE, "pcan get_cap: read cfg fail %x", stat));
27783737Shx147065 return ((uint32_t)AN_RID_GENCONFIG << 16 | stat);
27793737Shx147065 }
27803737Shx147065
27813737Shx147065 if (stat = pcan_cap_ltv(PCAN_READ_LTV, pcan_p)) {
27823737Shx147065 PCANDBG((CE_NOTE, "pcan get_cap: read cap fail %x", stat));
27833737Shx147065 return ((uint32_t)AN_RID_CAPABILITIES << 16 | stat);
27843737Shx147065 }
27853737Shx147065 #ifdef DEBUG
27863737Shx147065 if (pcan_debug & PCAN_DBG_FW_VERSION) {
27873737Shx147065 cmn_err(CE_NOTE, "the version of the firmware in the wifi card "
27883737Shx147065 "'%s %s %s' is %s\n",
27893737Shx147065 pcan_p->an_caps.an_manufname,
27903737Shx147065 pcan_p->an_caps.an_prodname,
27913737Shx147065 pcan_p->pcan_device_type == PCAN_DEVICE_PCI ?
27923737Shx147065 "minipci" : "pccard",
27933737Shx147065 pcan_p->an_caps.an_prodvers);
27943737Shx147065 }
27953737Shx147065 #endif
27963737Shx147065
27973737Shx147065 if (stat = pcan_ssid_ltv(PCAN_READ_LTV, pcan_p)) {
27983737Shx147065 PCANDBG((CE_NOTE, "pcan get_cap: read ssid fail %x", stat));
27993737Shx147065 return ((uint32_t)AN_RID_SSIDLIST << 16 | stat);
28003737Shx147065 }
28013737Shx147065
28023737Shx147065 if (stat = pcan_aplist_ltv(PCAN_READ_LTV, pcan_p)) {
28033737Shx147065 PCANDBG((CE_NOTE, "pcan get_cap: read aplist fail %x", stat));
28043737Shx147065 return ((uint32_t)AN_RID_APLIST << 16 | stat);
28053737Shx147065 }
28063737Shx147065 if (stat = pcan_wepkey_ltv(PCAN_READ_LTV, pcan_p)) {
28073737Shx147065 PCANDBG((CE_NOTE, "pcan get_cap: read wepkey fail %x", stat));
28083737Shx147065 return ((uint32_t)AN_RID_WEPKEY2 << 16 | stat);
28093737Shx147065 }
28103737Shx147065 ether_copy(pcan_p->an_caps.an_oemaddr, pcan_p->pcan_mac_addr);
28113737Shx147065 return (PCAN_SUCCESS);
28123737Shx147065 }
28133737Shx147065
28143737Shx147065 static int
pcan_config_mac(pcan_maci_t * pcan_p)28153737Shx147065 pcan_config_mac(pcan_maci_t *pcan_p)
28163737Shx147065 {
28173737Shx147065 uint16_t stat;
28183737Shx147065
28193737Shx147065 if (stat = pcan_ssid_ltv(PCAN_WRITE_LTV, pcan_p)) {
28203737Shx147065 PCANDBG((CE_NOTE, "pcan config_mac: write SSID failed%x\n",
28213737Shx147065 stat));
28223737Shx147065 return ((int)stat);
28233737Shx147065 }
28243737Shx147065
28253737Shx147065 if (stat = pcan_aplist_ltv(PCAN_WRITE_LTV, pcan_p)) {
28263737Shx147065 PCANDBG((CE_NOTE, "pcan config_mac: write APlist failed%x\n",
28273737Shx147065 stat));
28283737Shx147065 return ((int)stat);
28293737Shx147065 }
28303737Shx147065 if (stat = pcan_wepkey_ltv(PCAN_WRITE_LTV, pcan_p)) {
28313737Shx147065 PCANDBG((CE_NOTE, "pcan config_mac: write wepkey failed%x\n",
28323737Shx147065 stat));
28333737Shx147065 return ((int)stat);
28343737Shx147065 }
28353737Shx147065 if (pcan_p->pcan_usewep)
28363737Shx147065 pcan_p->an_config.an_authtype |=
28373737Shx147065 AN_AUTHTYPE_ENABLEWEP | AN_AUTHTYPE_ALLOW_UNENCRYPTED;
28383737Shx147065 PCANDBG((CE_NOTE, "pcan config_mac: usewep=%x authtype=%x opmode=%x\n",
28393737Shx147065 pcan_p->pcan_usewep, pcan_p->an_config.an_authtype,
28403737Shx147065 pcan_p->an_config.an_opmode));
28413737Shx147065
28423737Shx147065 pcan_p->an_config.an_assoc_timeout = 5000; /* stop assoc seq in 5 sec */
28433737Shx147065 if (stat = pcan_cfg_ltv(PCAN_WRITE_LTV, pcan_p, &pcan_p->an_config)) {
28443737Shx147065 PCANDBG((CE_NOTE, "pcan config_mac: write cfg failed %x\n",
28453737Shx147065 stat));
28463737Shx147065 return ((int)stat);
28473737Shx147065 }
28483737Shx147065
28493737Shx147065 if (stat = pcan_cfg_ltv(PCAN_READ_LTV, pcan_p,
28503737Shx147065 &pcan_p->an_actual_config)) {
28513737Shx147065 PCANDBG((CE_NOTE, "pcan config_mac: read cfg failed%x\n",
28523737Shx147065 stat));
28533737Shx147065 return ((int)stat);
28543737Shx147065 }
28553737Shx147065 PCANDBG((CE_NOTE, "pcan config_mac: optionmask=%x authtype=%x\n", 0,
28563737Shx147065 pcan_p->an_actual_config.an_authtype));
28573737Shx147065
28583737Shx147065 if (stat = pcan_status_ltv(PCAN_READ_LTV, pcan_p, &pcan_p->an_status)) {
28593737Shx147065 PCANDBG((CE_NOTE, "pcan config_mac: read status failed %x\n",
28603737Shx147065 stat));
28613737Shx147065 return ((int)stat);
28623737Shx147065 }
28633737Shx147065 return (PCAN_SUCCESS);
28643737Shx147065 }
28653737Shx147065
28663737Shx147065 static int
pcan_loaddef(pcan_maci_t * pcan_p)28673737Shx147065 pcan_loaddef(pcan_maci_t *pcan_p)
28683737Shx147065 {
28693737Shx147065 int i;
28703737Shx147065
28713737Shx147065 pcan_p->an_ssidlist.an_ssid1_len = 0;
28723737Shx147065 bzero(pcan_p->an_ssidlist.an_ssid1,
28734343Sgd78059 sizeof (pcan_p->an_ssidlist.an_ssid1));
28743737Shx147065 for (i = 0; i < MAX_NWEPKEYS; i++) {
28753737Shx147065 pcan_p->an_wepkey[i].an_index = 0xffff;
28763737Shx147065 bzero(pcan_p->an_wepkey[i].an_key,
28773737Shx147065 sizeof (pcan_p->an_wepkey[i].an_key));
28783737Shx147065 pcan_p->an_wepkey[i].an_keylen = 0;
28793737Shx147065 bzero(pcan_p->an_wepkey[i].an_macaddr,
28803737Shx147065 sizeof (pcan_p->an_wepkey[i].an_macaddr));
28813737Shx147065 pcan_p->an_wepkey[i].an_macaddr[0] = 1;
28823737Shx147065 }
28833737Shx147065 pcan_p->an_cur_wepkey = 0;
28843737Shx147065
28853737Shx147065 pcan_p->pcan_usewep = 0;
28863737Shx147065 pcan_p->an_config.an_opmode = AN_OPMODE_INFR_STATION;
28873737Shx147065 pcan_p->an_config.an_authtype = AN_AUTHTYPE_OPEN;
28883737Shx147065 pcan_p->an_config.an_stationary = 1;
28893737Shx147065 pcan_p->an_config.an_max_beacon_lost_time = 0xffff;
28903737Shx147065 i = pcan_config_mac(pcan_p);
28913737Shx147065
28923737Shx147065 return (i);
28933737Shx147065 }
28943737Shx147065
28953737Shx147065 static int
pcan_init_nicmem(pcan_maci_t * pcan_p)28963737Shx147065 pcan_init_nicmem(pcan_maci_t *pcan_p)
28973737Shx147065 {
28983737Shx147065 int i;
28993737Shx147065 uint16_t ret;
29003737Shx147065 pcan_txring_t *ring_p = &pcan_p->pcan_txring;
29013737Shx147065
29023737Shx147065 for (i = 0; i < AN_TX_RING_CNT; i++) {
29033737Shx147065 uint16_t rc;
29043737Shx147065 ret = pcan_alloc_nicmem(pcan_p, PCAN_NICMEM_SZ, &rc);
29053737Shx147065 if (ret) {
29063737Shx147065 cmn_err(CE_WARN, "pcan alloc NIC Tx buf[%x]: failed "
29073737Shx147065 "%x\n", i, ret);
29083737Shx147065 return (DDI_FAILURE);
29093737Shx147065 }
29103737Shx147065 ring_p->an_tx_fids[i] = rc;
29113737Shx147065 ring_p->an_tx_ring[i] = 0;
29123737Shx147065 PCANDBG((CE_NOTE, "pcan: NIC tx_id[%x]=%x\n", i, rc));
29133737Shx147065 }
29143737Shx147065 ring_p->an_tx_prod = ring_p->an_tx_cons = 0;
29153737Shx147065 return (PCAN_SUCCESS);
29163737Shx147065 }
29173737Shx147065
29183737Shx147065
29193737Shx147065
29203737Shx147065 static void
pcan_start_locked(pcan_maci_t * pcan_p)29213737Shx147065 pcan_start_locked(pcan_maci_t *pcan_p)
29223737Shx147065 {
29233737Shx147065 pcan_p->pcan_flag |= PCAN_CARD_INTREN;
29243737Shx147065 PCAN_ENABLE_INTR(pcan_p);
29253737Shx147065 }
29263737Shx147065
29273737Shx147065 static void
pcan_stop_locked(pcan_maci_t * pcan_p)29283737Shx147065 pcan_stop_locked(pcan_maci_t *pcan_p)
29293737Shx147065 {
29303737Shx147065 PCAN_DISABLE_INTR_CLEAR(pcan_p);
29313737Shx147065 pcan_p->pcan_flag &= ~PCAN_CARD_INTREN;
29323737Shx147065 }
29333737Shx147065
29343737Shx147065 /*
29353737Shx147065 * for scan result
29363737Shx147065 */
29373737Shx147065 static int
pcan_add_scan_item(pcan_maci_t * pcan_p,struct an_ltv_scanresult s)29383737Shx147065 pcan_add_scan_item(pcan_maci_t *pcan_p, struct an_ltv_scanresult s)
29393737Shx147065 {
29403737Shx147065 an_scan_list_t *scan_item;
29413737Shx147065
29423737Shx147065 scan_item = kmem_zalloc(sizeof (an_scan_list_t), KM_SLEEP);
29433737Shx147065 if (scan_item == NULL) {
29443737Shx147065 cmn_err(CE_WARN, "pcan add_scan_item: zalloc failed\n");
29453737Shx147065 return (PCAN_FAIL);
29463737Shx147065 }
29473737Shx147065 scan_item->an_val = s;
29483737Shx147065 scan_item->an_timeout = AN_SCAN_TIMEOUT_MAX;
29493737Shx147065 list_insert_tail(&pcan_p->an_scan_list, scan_item);
29503737Shx147065 pcan_p->an_scan_num++;
29513737Shx147065 return (PCAN_SUCCESS);
29523737Shx147065 }
29533737Shx147065
29543737Shx147065 static void
pcan_delete_scan_item(pcan_maci_t * pcan_p,an_scan_list_t * s)29553737Shx147065 pcan_delete_scan_item(pcan_maci_t *pcan_p, an_scan_list_t *s)
29563737Shx147065 {
29573737Shx147065 list_remove(&pcan_p->an_scan_list, s);
29583737Shx147065 kmem_free(s, sizeof (*s));
29593737Shx147065 pcan_p->an_scan_num--;
29603737Shx147065 }
29613737Shx147065
29623737Shx147065 static void
pcan_scanlist_timeout(void * arg)29633737Shx147065 pcan_scanlist_timeout(void *arg)
29643737Shx147065 {
29653737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
29663737Shx147065 an_scan_list_t *scan_item0, *scan_item1;
29673737Shx147065
29683737Shx147065 mutex_enter(&pcan_p->pcan_scanlist_lock);
29693737Shx147065 scan_item0 = list_head(&pcan_p->an_scan_list);
29703737Shx147065 for (; scan_item0; ) {
29713737Shx147065 PCANDBG((CE_NOTE, "pcan scanlist: ssid = %s\n",
29723737Shx147065 scan_item0->an_val.an_ssid));
29733737Shx147065 PCANDBG((CE_NOTE, "pcan scanlist: timeout left: %ds",
29743737Shx147065 scan_item0->an_timeout));
29753737Shx147065 scan_item1 = list_next(&pcan_p->an_scan_list, scan_item0);
29763737Shx147065 if (scan_item0->an_timeout == 0) {
29773737Shx147065 pcan_delete_scan_item(pcan_p, scan_item0);
29783737Shx147065 } else {
29793737Shx147065 scan_item0->an_timeout--;
29803737Shx147065 }
29813737Shx147065 scan_item0 = scan_item1;
29823737Shx147065 }
29833737Shx147065 mutex_exit(&pcan_p->pcan_scanlist_lock);
29843737Shx147065 pcan_p->an_scanlist_timeout_id = timeout(pcan_scanlist_timeout,
29853737Shx147065 pcan_p, drv_usectohz(1000000));
29863737Shx147065 }
29873737Shx147065
29888410SWang.Lin@Sun.COM /*
29898410SWang.Lin@Sun.COM * Brussels support
29908410SWang.Lin@Sun.COM */
29918410SWang.Lin@Sun.COM /*
29928410SWang.Lin@Sun.COM * MAC_PROP_WL_ESSID
29938410SWang.Lin@Sun.COM */
29948410SWang.Lin@Sun.COM static int
pcan_set_essid(pcan_maci_t * pcan_p,const void * wldp_buf)29958410SWang.Lin@Sun.COM pcan_set_essid(pcan_maci_t *pcan_p, const void *wldp_buf)
29968410SWang.Lin@Sun.COM {
29978410SWang.Lin@Sun.COM char *value;
29988410SWang.Lin@Sun.COM struct an_ltv_ssidlist *ssidlist_p;
29998410SWang.Lin@Sun.COM wl_essid_t *iw_essid = (wl_essid_t *)wldp_buf;
30008410SWang.Lin@Sun.COM
30018410SWang.Lin@Sun.COM ssidlist_p = &pcan_p->an_ssidlist;
30028410SWang.Lin@Sun.COM bzero(ssidlist_p, sizeof (*ssidlist_p));
30038410SWang.Lin@Sun.COM value = iw_essid->wl_essid_essid;
30048410SWang.Lin@Sun.COM (void) strncpy(ssidlist_p->an_ssid1, value,
30058410SWang.Lin@Sun.COM MIN(32, strlen(value)));
30068410SWang.Lin@Sun.COM ssidlist_p->an_ssid1_len = strlen(value);
30078410SWang.Lin@Sun.COM
30088410SWang.Lin@Sun.COM return (ENETRESET);
30098410SWang.Lin@Sun.COM }
30108410SWang.Lin@Sun.COM
30118410SWang.Lin@Sun.COM static int
pcan_get_essid(pcan_maci_t * pcan_p,void * wldp_buf)30128410SWang.Lin@Sun.COM pcan_get_essid(pcan_maci_t *pcan_p, void *wldp_buf)
30138410SWang.Lin@Sun.COM {
30148410SWang.Lin@Sun.COM int err = 0;
30158410SWang.Lin@Sun.COM struct an_ltv_status *status_p;
30168410SWang.Lin@Sun.COM wl_essid_t *ow_essid = (wl_essid_t *)wldp_buf;
30178410SWang.Lin@Sun.COM
30188410SWang.Lin@Sun.COM status_p = &pcan_p->an_status;
30198410SWang.Lin@Sun.COM
30208410SWang.Lin@Sun.COM if (pcan_status_ltv(PCAN_READ_LTV, pcan_p, status_p)) {
30218410SWang.Lin@Sun.COM err = EIO;
30228410SWang.Lin@Sun.COM return (err);
30238410SWang.Lin@Sun.COM }
30248410SWang.Lin@Sun.COM ow_essid->wl_essid_length = status_p->an_ssidlen;
30258410SWang.Lin@Sun.COM bcopy(status_p->an_ssid, ow_essid->wl_essid_essid,
30268410SWang.Lin@Sun.COM status_p->an_ssidlen);
30278410SWang.Lin@Sun.COM
30288410SWang.Lin@Sun.COM return (err);
30298410SWang.Lin@Sun.COM }
30308410SWang.Lin@Sun.COM
30318410SWang.Lin@Sun.COM /*
30328410SWang.Lin@Sun.COM * MAC_PROP_WL_BSSID
30338410SWang.Lin@Sun.COM */
30348410SWang.Lin@Sun.COM static int
pcan_set_bssid(pcan_maci_t * pcan_p,const void * wldp_buf)30358410SWang.Lin@Sun.COM pcan_set_bssid(pcan_maci_t *pcan_p, const void *wldp_buf)
30368410SWang.Lin@Sun.COM {
30378410SWang.Lin@Sun.COM wl_bssid_t *value;
30388410SWang.Lin@Sun.COM struct an_ltv_aplist *aplist_p;
30398410SWang.Lin@Sun.COM
30408410SWang.Lin@Sun.COM aplist_p = &pcan_p->an_aplist;
30418410SWang.Lin@Sun.COM
30428410SWang.Lin@Sun.COM value = (wl_bssid_t *)wldp_buf;
30438410SWang.Lin@Sun.COM (void) strncpy((char *)aplist_p->an_ap1, (char *)value, 6);
30448410SWang.Lin@Sun.COM
30458410SWang.Lin@Sun.COM return (ENETRESET);
30468410SWang.Lin@Sun.COM }
30478410SWang.Lin@Sun.COM
30488410SWang.Lin@Sun.COM static int
pcan_get_bssid(pcan_maci_t * pcan_p,void * wldp_buf)30498410SWang.Lin@Sun.COM pcan_get_bssid(pcan_maci_t *pcan_p, void *wldp_buf)
30508410SWang.Lin@Sun.COM {
30518410SWang.Lin@Sun.COM int err = 0;
30528410SWang.Lin@Sun.COM struct an_ltv_status *status_p;
30538410SWang.Lin@Sun.COM
30548410SWang.Lin@Sun.COM status_p = &pcan_p->an_status;
30558410SWang.Lin@Sun.COM
30568410SWang.Lin@Sun.COM if (pcan_status_ltv(PCAN_READ_LTV, pcan_p, status_p)) {
30578410SWang.Lin@Sun.COM err = EIO;
30588410SWang.Lin@Sun.COM return (err);
30598410SWang.Lin@Sun.COM }
30608410SWang.Lin@Sun.COM
30618410SWang.Lin@Sun.COM bcopy(status_p->an_cur_bssid, wldp_buf, sizeof (wl_bssid_t));
30628410SWang.Lin@Sun.COM PCANDBG((CE_CONT,
30638410SWang.Lin@Sun.COM "pcan: cfg_bssid: bssid=%x %x %x %x %x %x\n",
30648410SWang.Lin@Sun.COM status_p->an_cur_bssid[0],
30658410SWang.Lin@Sun.COM status_p->an_cur_bssid[1],
30668410SWang.Lin@Sun.COM status_p->an_cur_bssid[2],
30678410SWang.Lin@Sun.COM status_p->an_cur_bssid[3],
30688410SWang.Lin@Sun.COM status_p->an_cur_bssid[4],
30698410SWang.Lin@Sun.COM status_p->an_cur_bssid[5]));
30708410SWang.Lin@Sun.COM
30718410SWang.Lin@Sun.COM return (err);
30728410SWang.Lin@Sun.COM }
30738410SWang.Lin@Sun.COM
30748410SWang.Lin@Sun.COM /*
30758410SWang.Lin@Sun.COM * MAC_PROP_WL_LINKSTATUS
30768410SWang.Lin@Sun.COM */
30778410SWang.Lin@Sun.COM static void
pcan_get_linkstatus(pcan_maci_t * pcan_p,void * wldp_buf)30788410SWang.Lin@Sun.COM pcan_get_linkstatus(pcan_maci_t *pcan_p, void *wldp_buf)
30798410SWang.Lin@Sun.COM {
30808410SWang.Lin@Sun.COM if (pcan_p->pcan_flag & PCAN_CARD_LINKUP)
30818410SWang.Lin@Sun.COM *(wl_linkstatus_t *)wldp_buf = WL_CONNECTED;
30828410SWang.Lin@Sun.COM else
30838410SWang.Lin@Sun.COM *(wl_linkstatus_t *)wldp_buf = WL_NOTCONNECTED;
30848410SWang.Lin@Sun.COM
30858410SWang.Lin@Sun.COM }
30868410SWang.Lin@Sun.COM
30878410SWang.Lin@Sun.COM /*
30888410SWang.Lin@Sun.COM * MAC_PROP_WL_BSSTYP
30898410SWang.Lin@Sun.COM */
30908410SWang.Lin@Sun.COM static int
pcan_set_bsstype(pcan_maci_t * pcan_p,const void * wldp_buf)30918410SWang.Lin@Sun.COM pcan_set_bsstype(pcan_maci_t *pcan_p, const void *wldp_buf)
30928410SWang.Lin@Sun.COM {
30938410SWang.Lin@Sun.COM struct an_ltv_genconfig *cfg_p;
30948410SWang.Lin@Sun.COM
30958410SWang.Lin@Sun.COM cfg_p = &pcan_p->an_config;
30968410SWang.Lin@Sun.COM
30978410SWang.Lin@Sun.COM if (*(wl_bss_type_t *)wldp_buf == WL_BSS_BSS)
30988410SWang.Lin@Sun.COM cfg_p->an_opmode = AN_OPMODE_INFR_STATION;
30998410SWang.Lin@Sun.COM if (*(wl_bss_type_t *)wldp_buf == WL_BSS_IBSS)
31008410SWang.Lin@Sun.COM cfg_p->an_opmode = AN_OPMODE_IBSS_ADHOC;
31018410SWang.Lin@Sun.COM if (*(wl_bss_type_t *)wldp_buf == WL_BSS_ANY)
31028410SWang.Lin@Sun.COM cfg_p->an_opmode = AN_OPMODE_INFR_STATION;
31038410SWang.Lin@Sun.COM cfg_p->an_assoc_timeout = 5000;
31048410SWang.Lin@Sun.COM
31058410SWang.Lin@Sun.COM return (ENETRESET);
31068410SWang.Lin@Sun.COM }
31078410SWang.Lin@Sun.COM
31088410SWang.Lin@Sun.COM static void
pcan_get_bsstype(pcan_maci_t * pcan_p,void * wldp_buf)31098410SWang.Lin@Sun.COM pcan_get_bsstype(pcan_maci_t *pcan_p, void *wldp_buf)
31108410SWang.Lin@Sun.COM {
31118410SWang.Lin@Sun.COM struct an_ltv_genconfig *cfg_p;
31128410SWang.Lin@Sun.COM
31138410SWang.Lin@Sun.COM cfg_p = &pcan_p->an_config;
31148410SWang.Lin@Sun.COM
31158410SWang.Lin@Sun.COM if (cfg_p->an_opmode == AN_OPMODE_INFR_STATION) {
31168410SWang.Lin@Sun.COM *(wl_bss_type_t *)wldp_buf = WL_BSS_BSS;
31178410SWang.Lin@Sun.COM } else if (cfg_p->an_opmode == AN_OPMODE_IBSS_ADHOC) {
31188410SWang.Lin@Sun.COM *(wl_bss_type_t *)wldp_buf = WL_BSS_IBSS;
31198410SWang.Lin@Sun.COM }
31208410SWang.Lin@Sun.COM }
31218410SWang.Lin@Sun.COM
31228410SWang.Lin@Sun.COM /*
31238410SWang.Lin@Sun.COM * MAC_PROP_WL_PHY_CONFIG
31248410SWang.Lin@Sun.COM */
31258410SWang.Lin@Sun.COM static int
pcan_set_phy(pcan_maci_t * pcan_p,const void * wldp_buf)31268410SWang.Lin@Sun.COM pcan_set_phy(pcan_maci_t *pcan_p, const void *wldp_buf)
31278410SWang.Lin@Sun.COM {
31288410SWang.Lin@Sun.COM uint16_t ret;
31298410SWang.Lin@Sun.COM int err = ENETRESET;
31308410SWang.Lin@Sun.COM wl_phy_conf_t *phy = (wl_phy_conf_t *)wldp_buf;
31318410SWang.Lin@Sun.COM struct an_ltv_genconfig *cfg_p;
31328410SWang.Lin@Sun.COM
31338410SWang.Lin@Sun.COM cfg_p = &pcan_p->an_config;
31348410SWang.Lin@Sun.COM
31358410SWang.Lin@Sun.COM ret = (uint16_t)(phy->wl_phy_dsss_conf.wl_dsss_channel);
31368410SWang.Lin@Sun.COM if (ret < 1 || ret > 14) {
31378410SWang.Lin@Sun.COM err = ENOTSUP;
31388410SWang.Lin@Sun.COM return (err);
31398410SWang.Lin@Sun.COM }
31408410SWang.Lin@Sun.COM cfg_p->an_ds_channel = ret;
31418410SWang.Lin@Sun.COM cfg_p->an_assoc_timeout = 5000;
31428410SWang.Lin@Sun.COM
31438410SWang.Lin@Sun.COM return (err);
31448410SWang.Lin@Sun.COM }
31458410SWang.Lin@Sun.COM
31468410SWang.Lin@Sun.COM static int
pcan_get_phy(pcan_maci_t * pcan_p,void * wldp_buf)31478410SWang.Lin@Sun.COM pcan_get_phy(pcan_maci_t *pcan_p, void *wldp_buf)
31488410SWang.Lin@Sun.COM {
31498410SWang.Lin@Sun.COM int err = 0;
31508410SWang.Lin@Sun.COM struct an_ltv_status *status_p;
31518410SWang.Lin@Sun.COM wl_dsss_t *dsss = (wl_dsss_t *)wldp_buf;
31528410SWang.Lin@Sun.COM
31538410SWang.Lin@Sun.COM status_p = &pcan_p->an_status;
31548410SWang.Lin@Sun.COM
31558410SWang.Lin@Sun.COM if (pcan_status_ltv(PCAN_READ_LTV, pcan_p, status_p)) {
31568410SWang.Lin@Sun.COM err = EIO;
31578410SWang.Lin@Sun.COM return (err);
31588410SWang.Lin@Sun.COM }
31598410SWang.Lin@Sun.COM
31608410SWang.Lin@Sun.COM dsss->wl_dsss_channel = status_p->an_channel_set;
31618410SWang.Lin@Sun.COM dsss->wl_dsss_subtype = WL_DSSS;
31628410SWang.Lin@Sun.COM
31638410SWang.Lin@Sun.COM return (err);
31648410SWang.Lin@Sun.COM }
31658410SWang.Lin@Sun.COM
31668410SWang.Lin@Sun.COM /*
31678410SWang.Lin@Sun.COM * MAC_PROP_WL_DESIRED_RATESa
31688410SWang.Lin@Sun.COM */
31698410SWang.Lin@Sun.COM static int
pcan_set_desrates(pcan_maci_t * pcan_p,const void * wldp_buf)31708410SWang.Lin@Sun.COM pcan_set_desrates(pcan_maci_t *pcan_p, const void *wldp_buf)
31718410SWang.Lin@Sun.COM {
31728410SWang.Lin@Sun.COM uint16_t i;
31738410SWang.Lin@Sun.COM struct an_ltv_genconfig *cfg_p;
31748410SWang.Lin@Sun.COM
31758410SWang.Lin@Sun.COM cfg_p = &pcan_p->an_config;
31768410SWang.Lin@Sun.COM
31778410SWang.Lin@Sun.COM bzero(cfg_p->an_rates, sizeof (cfg_p->an_rates));
31788410SWang.Lin@Sun.COM for (i = 0; i < ((wl_rates_t *)wldp_buf)->wl_rates_num; i++) {
31798410SWang.Lin@Sun.COM cfg_p->an_rates[i] =
31808410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[i];
31818410SWang.Lin@Sun.COM }
31828410SWang.Lin@Sun.COM cfg_p->an_assoc_timeout = 5000;
31838410SWang.Lin@Sun.COM
31848410SWang.Lin@Sun.COM return (ENETRESET);
31858410SWang.Lin@Sun.COM }
31868410SWang.Lin@Sun.COM
31878410SWang.Lin@Sun.COM static int
pcan_get_desrates(pcan_maci_t * pcan_p,void * wldp_buf)31888410SWang.Lin@Sun.COM pcan_get_desrates(pcan_maci_t *pcan_p, void *wldp_buf)
31898410SWang.Lin@Sun.COM {
31908410SWang.Lin@Sun.COM uint16_t i;
31918410SWang.Lin@Sun.COM uint8_t rates = 0;
31928410SWang.Lin@Sun.COM int err = 0;
31938410SWang.Lin@Sun.COM struct an_ltv_genconfig *actcfg_p;
31948410SWang.Lin@Sun.COM
31958410SWang.Lin@Sun.COM actcfg_p = &pcan_p->an_actual_config;
31968410SWang.Lin@Sun.COM
31978410SWang.Lin@Sun.COM if (pcan_cfg_ltv(PCAN_READ_LTV, pcan_p, actcfg_p)) {
31988410SWang.Lin@Sun.COM err = EIO;
31998410SWang.Lin@Sun.COM return (err);
32008410SWang.Lin@Sun.COM }
32018410SWang.Lin@Sun.COM
32028410SWang.Lin@Sun.COM for (i = 0; i < sizeof (actcfg_p->an_rates); i++) {
32038410SWang.Lin@Sun.COM if (actcfg_p->an_rates[i] == 0)
32048410SWang.Lin@Sun.COM break;
32058410SWang.Lin@Sun.COM rates = MAX(rates, actcfg_p->an_rates[i]);
32068410SWang.Lin@Sun.COM }
32078410SWang.Lin@Sun.COM (((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] = rates;
32088410SWang.Lin@Sun.COM ((wl_rates_t *)wldp_buf)->wl_rates_num = 1;
32098410SWang.Lin@Sun.COM
32108410SWang.Lin@Sun.COM return (err);
32118410SWang.Lin@Sun.COM }
32128410SWang.Lin@Sun.COM
32138410SWang.Lin@Sun.COM /*
32148410SWang.Lin@Sun.COM * MAC_PROP_WL_SUP_RATE
32158410SWang.Lin@Sun.COM */
32168410SWang.Lin@Sun.COM static void
pcan_get_suprates(void * wldp_buf)32178410SWang.Lin@Sun.COM pcan_get_suprates(void *wldp_buf)
32188410SWang.Lin@Sun.COM {
32198410SWang.Lin@Sun.COM wl_rates_t *wl_rates = (wl_rates_t *)wldp_buf;
32208410SWang.Lin@Sun.COM
32218410SWang.Lin@Sun.COM wl_rates->wl_rates_num = 4;
32228410SWang.Lin@Sun.COM wl_rates->wl_rates_rates[0] = WL_RATE_1M;
32238410SWang.Lin@Sun.COM wl_rates->wl_rates_rates[1] = WL_RATE_2M;
32248410SWang.Lin@Sun.COM wl_rates->wl_rates_rates[2] = WL_RATE_5_5M;
32258410SWang.Lin@Sun.COM wl_rates->wl_rates_rates[3] = WL_RATE_11M;
32268410SWang.Lin@Sun.COM }
32278410SWang.Lin@Sun.COM
32288410SWang.Lin@Sun.COM /*
32298410SWang.Lin@Sun.COM * MAC_PROP_WL_POWER_MODE
32308410SWang.Lin@Sun.COM */
32318410SWang.Lin@Sun.COM static int
pcan_get_powermode(pcan_maci_t * pcan_p,void * wldp_buf)32328410SWang.Lin@Sun.COM pcan_get_powermode(pcan_maci_t *pcan_p, void *wldp_buf)
32338410SWang.Lin@Sun.COM {
32348410SWang.Lin@Sun.COM int err = 0;
32358410SWang.Lin@Sun.COM wl_ps_mode_t *powermode = (wl_ps_mode_t *)wldp_buf;
32368410SWang.Lin@Sun.COM struct an_ltv_genconfig *actcfg_p;
32378410SWang.Lin@Sun.COM
32388410SWang.Lin@Sun.COM actcfg_p = &pcan_p->an_actual_config;
32398410SWang.Lin@Sun.COM if (pcan_cfg_ltv(PCAN_READ_LTV, pcan_p, actcfg_p)) {
32408410SWang.Lin@Sun.COM err = EIO;
32418410SWang.Lin@Sun.COM return (err);
32428410SWang.Lin@Sun.COM }
32438410SWang.Lin@Sun.COM powermode->wl_ps_mode = actcfg_p->an_psave_mode;
32448410SWang.Lin@Sun.COM
32458410SWang.Lin@Sun.COM return (err);
32468410SWang.Lin@Sun.COM }
32478410SWang.Lin@Sun.COM
32488410SWang.Lin@Sun.COM /*
32498410SWang.Lin@Sun.COM * MAC_PROP_AUTH_MODE
32508410SWang.Lin@Sun.COM */
32518410SWang.Lin@Sun.COM static int
pcan_set_authmode(pcan_maci_t * pcan_p,const void * wldp_buf)32528410SWang.Lin@Sun.COM pcan_set_authmode(pcan_maci_t *pcan_p, const void *wldp_buf)
32538410SWang.Lin@Sun.COM {
32548410SWang.Lin@Sun.COM struct an_ltv_genconfig *cfg_p;
32558410SWang.Lin@Sun.COM int err = ENETRESET;
32568410SWang.Lin@Sun.COM
32578410SWang.Lin@Sun.COM cfg_p = &pcan_p->an_config;
32588410SWang.Lin@Sun.COM if (*(wl_authmode_t *)wldp_buf == WL_OPENSYSTEM) {
32598410SWang.Lin@Sun.COM cfg_p->an_authtype |= AN_AUTHTYPE_OPEN;
32608410SWang.Lin@Sun.COM cfg_p->an_assoc_timeout = 5000;
32618410SWang.Lin@Sun.COM } else {
32628410SWang.Lin@Sun.COM err = EINVAL;
32638410SWang.Lin@Sun.COM }
32648410SWang.Lin@Sun.COM
32658410SWang.Lin@Sun.COM return (err);
32668410SWang.Lin@Sun.COM }
32678410SWang.Lin@Sun.COM
32688410SWang.Lin@Sun.COM static void
pcan_get_authmode(pcan_maci_t * pcan_p,void * wldp_buf)32698410SWang.Lin@Sun.COM pcan_get_authmode(pcan_maci_t *pcan_p, void *wldp_buf)
32708410SWang.Lin@Sun.COM {
32718410SWang.Lin@Sun.COM struct an_ltv_genconfig *cfg_p;
32728410SWang.Lin@Sun.COM
32738410SWang.Lin@Sun.COM cfg_p = &pcan_p->an_config;
32748410SWang.Lin@Sun.COM if (cfg_p->an_authtype & AN_AUTHTYPE_SHAREDKEY) {
32758410SWang.Lin@Sun.COM *(wl_bss_type_t *)wldp_buf = WL_SHAREDKEY;
32768410SWang.Lin@Sun.COM } else {
32778410SWang.Lin@Sun.COM *(wl_bss_type_t *)wldp_buf = WL_OPENSYSTEM;
32788410SWang.Lin@Sun.COM }
32798410SWang.Lin@Sun.COM }
32808410SWang.Lin@Sun.COM
32818410SWang.Lin@Sun.COM /*
32828410SWang.Lin@Sun.COM * MAC_PROP_WL_ENCRYPTION
32838410SWang.Lin@Sun.COM */
32848410SWang.Lin@Sun.COM static int
pcan_set_encrypt(pcan_maci_t * pcan_p,const void * wldp_buf)32858410SWang.Lin@Sun.COM pcan_set_encrypt(pcan_maci_t *pcan_p, const void *wldp_buf)
32868410SWang.Lin@Sun.COM {
32878410SWang.Lin@Sun.COM struct an_ltv_genconfig *cfg_p;
32888410SWang.Lin@Sun.COM
32898410SWang.Lin@Sun.COM cfg_p = &pcan_p->an_config;
32908410SWang.Lin@Sun.COM if (*(wl_encryption_t *)wldp_buf == WL_ENC_WEP) {
32918410SWang.Lin@Sun.COM cfg_p->an_authtype |= (AN_AUTHTYPE_ENABLEWEP |
32928410SWang.Lin@Sun.COM AN_AUTHTYPE_ALLOW_UNENCRYPTED);
32938410SWang.Lin@Sun.COM pcan_p->pcan_usewep = 1;
32948410SWang.Lin@Sun.COM }
32958410SWang.Lin@Sun.COM if (*(wl_authmode_t *)wldp_buf == WL_NOENCRYPTION) {
32968410SWang.Lin@Sun.COM cfg_p->an_authtype &= (~(AN_AUTHTYPE_ENABLEWEP |
32978410SWang.Lin@Sun.COM AN_AUTHTYPE_ALLOW_UNENCRYPTED));
32988410SWang.Lin@Sun.COM pcan_p->pcan_usewep = 0;
32998410SWang.Lin@Sun.COM }
33008410SWang.Lin@Sun.COM cfg_p->an_assoc_timeout = 5000;
33018410SWang.Lin@Sun.COM
33028410SWang.Lin@Sun.COM return (ENETRESET);
33038410SWang.Lin@Sun.COM }
33048410SWang.Lin@Sun.COM
33058410SWang.Lin@Sun.COM static void
pcan_get_encrypt(pcan_maci_t * pcan_p,void * wldp_buf)33068410SWang.Lin@Sun.COM pcan_get_encrypt(pcan_maci_t *pcan_p, void *wldp_buf)
33078410SWang.Lin@Sun.COM {
33088410SWang.Lin@Sun.COM struct an_ltv_genconfig *cfg_p;
33098410SWang.Lin@Sun.COM
33108410SWang.Lin@Sun.COM cfg_p = &pcan_p->an_config;
33118410SWang.Lin@Sun.COM if (cfg_p->an_authtype & AN_AUTHTYPE_ENABLEWEP) {
33128410SWang.Lin@Sun.COM *(wl_bss_type_t *)wldp_buf = WL_ENC_WEP;
33138410SWang.Lin@Sun.COM } else {
33148410SWang.Lin@Sun.COM *(wl_bss_type_t *)wldp_buf = WL_NOENCRYPTION;
33158410SWang.Lin@Sun.COM }
33168410SWang.Lin@Sun.COM }
33178410SWang.Lin@Sun.COM
33188410SWang.Lin@Sun.COM /*
33198410SWang.Lin@Sun.COM * MAC_PROP_WL_KEY_TAB
33208410SWang.Lin@Sun.COM */
33218410SWang.Lin@Sun.COM static int
pcan_set_wepkey(pcan_maci_t * pcan_p,const void * wldp_buf)33228410SWang.Lin@Sun.COM pcan_set_wepkey(pcan_maci_t *pcan_p, const void *wldp_buf)
33238410SWang.Lin@Sun.COM {
33248410SWang.Lin@Sun.COM uint16_t i;
33258410SWang.Lin@Sun.COM wl_wep_key_t *p_wepkey_tab;
33268410SWang.Lin@Sun.COM struct an_ltv_wepkey *wepkey_p;
33278410SWang.Lin@Sun.COM
33288410SWang.Lin@Sun.COM p_wepkey_tab = (wl_wep_key_t *)wldp_buf;
33298410SWang.Lin@Sun.COM for (i = 0; i < MAX_NWEPKEYS; i++) {
33308410SWang.Lin@Sun.COM if (p_wepkey_tab[i].wl_wep_operation == WL_ADD) {
33318410SWang.Lin@Sun.COM wepkey_p = &pcan_p->an_wepkey[i];
33328410SWang.Lin@Sun.COM bzero(wepkey_p, sizeof (*wepkey_p));
33338410SWang.Lin@Sun.COM wepkey_p->an_keylen =
33348410SWang.Lin@Sun.COM p_wepkey_tab[i].wl_wep_length;
33358410SWang.Lin@Sun.COM bcopy(p_wepkey_tab[i].wl_wep_key,
33368410SWang.Lin@Sun.COM wepkey_p->an_key,
33378410SWang.Lin@Sun.COM p_wepkey_tab[i].wl_wep_length);
33388410SWang.Lin@Sun.COM wepkey_p->an_index = i;
33398410SWang.Lin@Sun.COM wepkey_p->an_macaddr[0] = 1;
33408410SWang.Lin@Sun.COM }
33418410SWang.Lin@Sun.COM }
33428410SWang.Lin@Sun.COM
33438410SWang.Lin@Sun.COM return (ENETRESET);
33448410SWang.Lin@Sun.COM }
33458410SWang.Lin@Sun.COM
33468410SWang.Lin@Sun.COM /*
33478410SWang.Lin@Sun.COM * MAC_PROP_WL_RSSI
33488410SWang.Lin@Sun.COM */
33498410SWang.Lin@Sun.COM static int
pcan_get_rssi(pcan_maci_t * pcan_p,void * wldp_buf)33508410SWang.Lin@Sun.COM pcan_get_rssi(pcan_maci_t *pcan_p, void *wldp_buf)
33518410SWang.Lin@Sun.COM {
33528410SWang.Lin@Sun.COM uint16_t val;
33538410SWang.Lin@Sun.COM int err = 0;
33548410SWang.Lin@Sun.COM wl_rssi_t *rssi = (wl_rssi_t *)wldp_buf;
33558410SWang.Lin@Sun.COM struct an_ltv_status *status_p;
33568410SWang.Lin@Sun.COM
33578410SWang.Lin@Sun.COM status_p = &pcan_p->an_status;
33588410SWang.Lin@Sun.COM
33598410SWang.Lin@Sun.COM if (val = pcan_status_ltv(PCAN_READ_LTV, pcan_p, status_p)) {
33608410SWang.Lin@Sun.COM err = EIO;
33618410SWang.Lin@Sun.COM return (err);
33628410SWang.Lin@Sun.COM }
33638410SWang.Lin@Sun.COM val = status_p->an_cur_signal_quality;
33648410SWang.Lin@Sun.COM PCANDBG((CE_NOTE, "pcan cfg_rssi: sl=%x", val));
33658410SWang.Lin@Sun.COM /*
33668410SWang.Lin@Sun.COM * we reflect the value to 1-15 as rssi
33678410SWang.Lin@Sun.COM */
33688410SWang.Lin@Sun.COM *rssi = 15 - ((val & 0xff) * 15 / 128 + 1);
33698410SWang.Lin@Sun.COM
33708410SWang.Lin@Sun.COM return (err);
33718410SWang.Lin@Sun.COM }
33728410SWang.Lin@Sun.COM
33738410SWang.Lin@Sun.COM /*
33748410SWang.Lin@Sun.COM * MAC_PROP_WL_RADIO
33758410SWang.Lin@Sun.COM */
33768410SWang.Lin@Sun.COM static void
pcan_get_radio(void * wldp_buf)33778410SWang.Lin@Sun.COM pcan_get_radio(void *wldp_buf)
33788410SWang.Lin@Sun.COM {
33798410SWang.Lin@Sun.COM wl_radio_t *radio = (wl_radio_t *)wldp_buf;
33808410SWang.Lin@Sun.COM
33818410SWang.Lin@Sun.COM *radio = B_TRUE;
33828410SWang.Lin@Sun.COM }
33838410SWang.Lin@Sun.COM
33848410SWang.Lin@Sun.COM /*
33858410SWang.Lin@Sun.COM * MAC_PROP_WL_ESSLIST
33868410SWang.Lin@Sun.COM */
33878410SWang.Lin@Sun.COM static void
pcan_get_esslist(pcan_maci_t * pcan_p,void * wldp_buf)33888410SWang.Lin@Sun.COM pcan_get_esslist(pcan_maci_t *pcan_p, void *wldp_buf)
33898410SWang.Lin@Sun.COM {
33908410SWang.Lin@Sun.COM uint16_t i;
33918410SWang.Lin@Sun.COM wl_ess_conf_t *p_ess_conf;
33928410SWang.Lin@Sun.COM an_scan_list_t *scan_item;
33938410SWang.Lin@Sun.COM
33948410SWang.Lin@Sun.COM mutex_enter(&pcan_p->pcan_scanlist_lock);
33958410SWang.Lin@Sun.COM
33968410SWang.Lin@Sun.COM ((wl_ess_list_t *)wldp_buf)->wl_ess_list_num =
33978410SWang.Lin@Sun.COM pcan_p->an_scan_num;
33988410SWang.Lin@Sun.COM scan_item = list_head(&pcan_p->an_scan_list);
33998410SWang.Lin@Sun.COM for (i = 0; i < pcan_p->an_scan_num; i++) {
34008410SWang.Lin@Sun.COM if (!scan_item)
34018410SWang.Lin@Sun.COM break;
34028410SWang.Lin@Sun.COM p_ess_conf = (wl_ess_conf_t *)((char *)wldp_buf +
34038410SWang.Lin@Sun.COM offsetof(wl_ess_list_t, wl_ess_list_ess) +
34048410SWang.Lin@Sun.COM i * sizeof (wl_ess_conf_t));
34058410SWang.Lin@Sun.COM bcopy(scan_item->an_val.an_ssid,
34068410SWang.Lin@Sun.COM p_ess_conf->wl_ess_conf_essid.wl_essid_essid,
34078410SWang.Lin@Sun.COM mi_strlen(scan_item->an_val.an_ssid));
34088410SWang.Lin@Sun.COM bcopy(scan_item->an_val.an_bssid,
34098410SWang.Lin@Sun.COM p_ess_conf->wl_ess_conf_bssid, 6);
34108410SWang.Lin@Sun.COM (p_ess_conf->wl_phy_conf).wl_phy_dsss_conf.wl_dsss_subtype
34118410SWang.Lin@Sun.COM = WL_DSSS;
34128410SWang.Lin@Sun.COM p_ess_conf->wl_ess_conf_wepenabled =
34138410SWang.Lin@Sun.COM (scan_item->an_val.an_cap & 0x10 ?
34148410SWang.Lin@Sun.COM WL_ENC_WEP : WL_NOENCRYPTION);
34158410SWang.Lin@Sun.COM p_ess_conf->wl_ess_conf_bsstype =
34168410SWang.Lin@Sun.COM (scan_item->an_val.an_cap & 0x1 ?
34178410SWang.Lin@Sun.COM WL_BSS_BSS : WL_BSS_IBSS);
34188410SWang.Lin@Sun.COM p_ess_conf->wl_phy_conf.wl_phy_dsss_conf.wl_dsss_channel =
34198410SWang.Lin@Sun.COM scan_item->an_val.an_dschannel;
34208410SWang.Lin@Sun.COM p_ess_conf->wl_ess_conf_sl = 15 -
34218410SWang.Lin@Sun.COM ((scan_item->an_val.an_rssi & 0xff) * 15 / 128);
34228410SWang.Lin@Sun.COM p_ess_conf->wl_supported_rates[0] = WL_RATE_1M;
34238410SWang.Lin@Sun.COM p_ess_conf->wl_supported_rates[1] = WL_RATE_2M;
34248410SWang.Lin@Sun.COM p_ess_conf->wl_supported_rates[2] = WL_RATE_5_5M;
34258410SWang.Lin@Sun.COM p_ess_conf->wl_supported_rates[3] = WL_RATE_11M;
34268410SWang.Lin@Sun.COM scan_item = list_next(&pcan_p->an_scan_list, scan_item);
34278410SWang.Lin@Sun.COM }
34288410SWang.Lin@Sun.COM
34298410SWang.Lin@Sun.COM mutex_exit(&pcan_p->pcan_scanlist_lock);
34308410SWang.Lin@Sun.COM }
34313737Shx147065
34323737Shx147065 /*
34333737Shx147065 * for wificonfig and dlamd ioctl
34343737Shx147065 */
34353737Shx147065 static int
pcan_cfg_essid(mblk_t * mp,pcan_maci_t * pcan_p,uint32_t cmd)34363737Shx147065 pcan_cfg_essid(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
34373737Shx147065 {
34388410SWang.Lin@Sun.COM uint16_t i;
34398410SWang.Lin@Sun.COM wldp_t *infp;
34408410SWang.Lin@Sun.COM wldp_t *outfp;
34418410SWang.Lin@Sun.COM char *buf;
34428410SWang.Lin@Sun.COM int iret;
34438410SWang.Lin@Sun.COM int err = 0;
34443737Shx147065
34453737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
34463737Shx147065 if (buf == NULL) {
34473737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_essid: failed to alloc "
34483737Shx147065 "memory(%d)\n", MAX_BUF_LEN));
34493737Shx147065 return (ENOMEM);
34503737Shx147065 }
34513737Shx147065 outfp = (wldp_t *)buf;
34523737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
34533737Shx147065 infp = (wldp_t *)mp->b_rptr;
34543737Shx147065
34553737Shx147065 if (cmd == WLAN_GET_PARAM) {
34568410SWang.Lin@Sun.COM err = pcan_get_essid(pcan_p, outfp->wldp_buf);
34578410SWang.Lin@Sun.COM if (err == EIO) {
34583737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET;
34593737Shx147065 outfp->wldp_result = WL_HW_ERROR;
34603737Shx147065 goto done;
34613737Shx147065 }
34623737Shx147065 outfp->wldp_result = WL_SUCCESS;
34633737Shx147065 } else if (cmd == WLAN_SET_PARAM) {
34648410SWang.Lin@Sun.COM (void) pcan_set_essid(pcan_p, infp->wldp_buf);
34653737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET;
34663737Shx147065 outfp->wldp_result = WL_SUCCESS;
34673737Shx147065 } else {
34683737Shx147065 kmem_free(buf, MAX_BUF_LEN);
34693737Shx147065 return (EINVAL);
34703737Shx147065 }
34718410SWang.Lin@Sun.COM
34723737Shx147065 done:
34733737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) {
34743737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]);
34753737Shx147065 }
34763737Shx147065 iret = (int)(outfp->wldp_result);
34773737Shx147065 kmem_free(buf, MAX_BUF_LEN);
34783737Shx147065 return (iret);
34793737Shx147065 }
34803737Shx147065
34813737Shx147065 static int
pcan_cfg_bssid(mblk_t * mp,pcan_maci_t * pcan_p,uint32_t cmd)34823737Shx147065 pcan_cfg_bssid(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
34833737Shx147065 {
34848410SWang.Lin@Sun.COM uint16_t i;
34858410SWang.Lin@Sun.COM wldp_t *infp;
34868410SWang.Lin@Sun.COM wldp_t *outfp;
34878410SWang.Lin@Sun.COM char *buf;
34888410SWang.Lin@Sun.COM int iret;
34898410SWang.Lin@Sun.COM int err = 0;
34903737Shx147065
34913737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
34923737Shx147065 if (buf == NULL) {
34933737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_bssid: failed to alloc "
34943737Shx147065 "memory(%d)\n", MAX_BUF_LEN));
34953737Shx147065 return (ENOMEM);
34963737Shx147065 }
34973737Shx147065 outfp = (wldp_t *)buf;
34983737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
34993737Shx147065 infp = (wldp_t *)mp->b_rptr;
35003737Shx147065
35013737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_bssid_t);
35023737Shx147065
35033737Shx147065 if (cmd == WLAN_GET_PARAM) {
35048410SWang.Lin@Sun.COM err = pcan_get_bssid(pcan_p, outfp->wldp_buf);
35058410SWang.Lin@Sun.COM if (err == EIO) {
35063737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET;
35073737Shx147065 outfp->wldp_result = WL_HW_ERROR;
35083737Shx147065 goto done;
35093737Shx147065 }
35103737Shx147065 outfp->wldp_result = WL_SUCCESS;
35113737Shx147065 } else if (cmd == WLAN_SET_PARAM) {
35128410SWang.Lin@Sun.COM (void) pcan_set_bssid(pcan_p, infp->wldp_buf);
35133737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET;
35143737Shx147065 outfp->wldp_result = WL_SUCCESS;
35153737Shx147065 } else {
35163737Shx147065 kmem_free(buf, MAX_BUF_LEN);
35173737Shx147065 return (EINVAL);
35183737Shx147065 }
35198410SWang.Lin@Sun.COM
35203737Shx147065 done:
35213737Shx147065 for (i = 0; i < (outfp->wldp_length); i++) {
35223737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]);
35233737Shx147065 }
35243737Shx147065 iret = (int)(outfp->wldp_result);
35253737Shx147065 kmem_free(buf, MAX_BUF_LEN);
35263737Shx147065 return (iret);
35273737Shx147065 }
35283737Shx147065
35293737Shx147065 /*ARGSUSED*/
35303737Shx147065 static int
pcan_cmd_scan(pcan_maci_t * pcan_p)35313737Shx147065 pcan_cmd_scan(pcan_maci_t *pcan_p)
35323737Shx147065 {
35333737Shx147065 uint16_t i = 0, j, ret = WL_SUCCESS;
35343737Shx147065 uint8_t bssid_t[6];
35353737Shx147065 uint32_t check_num, enable;
35363737Shx147065 an_scan_list_t *scan_item0;
35373737Shx147065
35383737Shx147065 enable = pcan_p->pcan_flag & PCAN_ENABLED;
35393737Shx147065 if ((!enable) &&
35403737Shx147065 (ret = pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0))) {
35413737Shx147065 ret = (int)WL_HW_ERROR;
35423737Shx147065 goto exit;
35433737Shx147065 }
35443737Shx147065 if (ret = pcan_set_cmd(pcan_p, AN_CMD_SCAN, 0)) {
35453737Shx147065 ret = (int)WL_HW_ERROR;
35463737Shx147065 goto exit;
35473737Shx147065 }
35483737Shx147065
35493737Shx147065 pcan_delay(pcan_p, 500000);
35503737Shx147065 ret = pcan_scanresult_ltv(PCAN_READ_LTV,
35513737Shx147065 pcan_p, AN_RID_ESSIDLIST_FIRST, &pcan_p->an_scanresult[i]);
35523737Shx147065 if ((ret) || pcan_p->an_scanresult[i].an_index == 0xffff) {
35533737Shx147065 goto done;
35543737Shx147065 }
35553737Shx147065 do
35563737Shx147065 {
35573737Shx147065 i++;
35583737Shx147065 ret = pcan_scanresult_ltv(PCAN_READ_LTV,
35593737Shx147065 pcan_p, AN_RID_ESSIDLIST_NEXT, &pcan_p->an_scanresult[i]);
35603737Shx147065 } while ((!ret) && (i < 32) &&
35613737Shx147065 (pcan_p->an_scanresult[i].an_index != 0xffff));
35623737Shx147065 done:
35633737Shx147065 if ((!enable) &&
35643737Shx147065 (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0))) {
35653737Shx147065 ret = (int)WL_HW_ERROR;
35663737Shx147065 goto exit;
35673737Shx147065 }
35683737Shx147065 /* record the scan result for future use */
35693737Shx147065 bzero(bssid_t, sizeof (bssid_t));
35703737Shx147065 for (j = 0; j < i; j++) {
35713737Shx147065 /*
35723737Shx147065 * sometimes, those empty items are recorded by hardware,
35733737Shx147065 * this is wrong, just ignore those items here.
35743737Shx147065 */
35753737Shx147065 if (bcmp(pcan_p->an_scanresult[j].an_bssid,
35763737Shx147065 bssid_t, 6) == 0) {
35773737Shx147065 continue;
35783737Shx147065 }
35793737Shx147065 /*
35803737Shx147065 * save/update the scan item in scanlist
35813737Shx147065 */
35823737Shx147065 mutex_enter(&pcan_p->pcan_scanlist_lock);
35833737Shx147065 check_num = 0;
35843737Shx147065 scan_item0 = list_head(&pcan_p->an_scan_list);
35853737Shx147065 if (scan_item0 == NULL) {
35863737Shx147065 if (pcan_add_scan_item(pcan_p,
35873737Shx147065 pcan_p->an_scanresult[j]) != 0) {
35883737Shx147065 mutex_exit(&pcan_p->pcan_scanlist_lock);
35893737Shx147065 return (WL_SUCCESS);
35903737Shx147065 }
35913737Shx147065 }
35923737Shx147065 for (; scan_item0; ) {
35933737Shx147065 if (bcmp(pcan_p->an_scanresult[j].an_bssid,
35943737Shx147065 scan_item0->an_val.an_bssid, 6) == 0) {
35953737Shx147065 scan_item0->an_val = pcan_p->an_scanresult[j];
35963737Shx147065 scan_item0->an_timeout = AN_SCAN_TIMEOUT_MAX;
35973737Shx147065 break;
35983737Shx147065 } else {
35993737Shx147065 check_num++;
36003737Shx147065 }
36013737Shx147065 scan_item0 = list_next(&pcan_p->an_scan_list,
36023737Shx147065 scan_item0);
36033737Shx147065 }
36043737Shx147065 if (check_num == pcan_p->an_scan_num) {
36053737Shx147065 if (pcan_add_scan_item(pcan_p,
36063737Shx147065 pcan_p->an_scanresult[j]) != 0) {
36073737Shx147065 mutex_exit(&pcan_p->pcan_scanlist_lock);
36083737Shx147065 return (WL_SUCCESS);
36093737Shx147065 }
36103737Shx147065 }
36113737Shx147065 mutex_exit(&pcan_p->pcan_scanlist_lock);
36123737Shx147065 }
36133737Shx147065 exit:
36143737Shx147065 if (ret)
36154343Sgd78059 cmn_err(CE_WARN, "pcan: scan failed due to hardware error");
36163737Shx147065 return (ret);
36173737Shx147065 }
36183737Shx147065
36193737Shx147065 /*ARGSUSED*/
36203737Shx147065 static int
pcan_cfg_scan(mblk_t * mp,pcan_maci_t * pcan_p,uint32_t cmd)36213737Shx147065 pcan_cfg_scan(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
36223737Shx147065 {
36238410SWang.Lin@Sun.COM wldp_t *outfp;
36248410SWang.Lin@Sun.COM char *buf;
36258410SWang.Lin@Sun.COM uint16_t i;
36263737Shx147065
36273737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
36283737Shx147065 if (buf == NULL) {
36293737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_scanlist: failed to alloc "
36303737Shx147065 "memory(%d)\n", MAX_BUF_LEN));
36313737Shx147065 return (ENOMEM);
36323737Shx147065 }
36333737Shx147065 outfp = (wldp_t *)buf;
36343737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
36353737Shx147065
36368410SWang.Lin@Sun.COM pcan_get_esslist(pcan_p, outfp->wldp_buf);
36378410SWang.Lin@Sun.COM
36383737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET +
36393737Shx147065 offsetof(wl_ess_list_t, wl_ess_list_ess) +
36403737Shx147065 pcan_p->an_scan_num * sizeof (wl_ess_conf_t);
36413737Shx147065 outfp->wldp_result = WL_SUCCESS;
36423737Shx147065 for (i = 0; i < (outfp->wldp_length); i++)
36433737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]);
36443737Shx147065 kmem_free(buf, MAX_BUF_LEN);
36453737Shx147065 return (WL_SUCCESS);
36463737Shx147065 }
36473737Shx147065
36483737Shx147065 /*ARGSUSED*/
36493737Shx147065 static int
pcan_cfg_linkstatus(mblk_t * mp,pcan_maci_t * pcan_p,uint32_t cmd)36503737Shx147065 pcan_cfg_linkstatus(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
36513737Shx147065 {
36523737Shx147065 wldp_t *outfp;
36533737Shx147065 char *buf;
36543737Shx147065 uint16_t i;
36553737Shx147065
36563737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
36573737Shx147065 if (buf == NULL) {
36583737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_linkstatus: failed to alloc "
36593737Shx147065 "memory(%d)\n", MAX_BUF_LEN));
36603737Shx147065 return (ENOMEM);
36613737Shx147065 }
36623737Shx147065 outfp = (wldp_t *)buf;
36633737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
36643737Shx147065
36658410SWang.Lin@Sun.COM pcan_get_linkstatus(pcan_p, outfp->wldp_buf);
36668410SWang.Lin@Sun.COM
36678410SWang.Lin@Sun.COM outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_linkstatus_t);
36683737Shx147065 outfp->wldp_result = WL_SUCCESS;
36693737Shx147065 for (i = 0; i < (outfp->wldp_length); i++)
36703737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]);
36713737Shx147065 kmem_free(buf, MAX_BUF_LEN);
36723737Shx147065 return (WL_SUCCESS);
36733737Shx147065 }
36743737Shx147065
36753737Shx147065 static int
pcan_cfg_bsstype(mblk_t * mp,pcan_maci_t * pcan_p,uint32_t cmd)36763737Shx147065 pcan_cfg_bsstype(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
36773737Shx147065 {
36783737Shx147065 uint16_t i;
36793737Shx147065 wldp_t *infp;
36803737Shx147065 wldp_t *outfp;
36813737Shx147065 char *buf;
36823737Shx147065 int iret;
36833737Shx147065
36843737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
36853737Shx147065 if (buf == NULL) {
36863737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_bsstype: failed to alloc "
36873737Shx147065 "memory(%d)\n", 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_bss_type_t);
36953737Shx147065
36963737Shx147065 if (cmd == WLAN_GET_PARAM) {
36978410SWang.Lin@Sun.COM pcan_get_bsstype(pcan_p, outfp->wldp_buf);
36983737Shx147065 outfp->wldp_result = WL_SUCCESS;
36993737Shx147065 } else if (cmd == WLAN_SET_PARAM) {
37008410SWang.Lin@Sun.COM (void) pcan_set_bsstype(pcan_p, infp->wldp_buf);
37013737Shx147065 outfp->wldp_result = WL_SUCCESS;
37023737Shx147065 } else {
37033737Shx147065 kmem_free(buf, MAX_BUF_LEN);
37043737Shx147065 return (EINVAL);
37053737Shx147065 }
37063737Shx147065
37073737Shx147065 for (i = 0; i < (outfp->wldp_length); i++)
37083737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]);
37093737Shx147065 iret = (int)(outfp->wldp_result);
37103737Shx147065 kmem_free(buf, MAX_BUF_LEN);
37113737Shx147065 return (iret);
37123737Shx147065 }
37133737Shx147065
37143737Shx147065 static int
pcan_cfg_phy(mblk_t * mp,pcan_maci_t * pcan_p,uint32_t cmd)37153737Shx147065 pcan_cfg_phy(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
37163737Shx147065 {
37178410SWang.Lin@Sun.COM uint16_t i;
37188410SWang.Lin@Sun.COM wldp_t *infp;
37198410SWang.Lin@Sun.COM wldp_t *outfp;
37208410SWang.Lin@Sun.COM char *buf;
37218410SWang.Lin@Sun.COM int iret;
37228410SWang.Lin@Sun.COM int err = 0;
37233737Shx147065
37243737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
37253737Shx147065 if (buf == NULL) {
37263737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_phy: failed to alloc "
37273737Shx147065 "memory(%d)\n", MAX_BUF_LEN));
37283737Shx147065 return (ENOMEM);
37293737Shx147065 }
37303737Shx147065 outfp = (wldp_t *)buf;
37313737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
37323737Shx147065 infp = (wldp_t *)mp->b_rptr;
37333737Shx147065
37343737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_dsss_t);
37358410SWang.Lin@Sun.COM
37363737Shx147065 if (cmd == WLAN_GET_PARAM) {
37378410SWang.Lin@Sun.COM err = pcan_get_phy(pcan_p, outfp->wldp_buf);
37388410SWang.Lin@Sun.COM if (err == EIO) {
37393737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET;
37403737Shx147065 outfp->wldp_result = WL_HW_ERROR;
37413737Shx147065 goto done;
37423737Shx147065 }
37433737Shx147065 outfp->wldp_result = WL_SUCCESS;
37443737Shx147065 } else if (cmd == WLAN_SET_PARAM) {
37458410SWang.Lin@Sun.COM err = pcan_set_phy(pcan_p, infp->wldp_buf);
37468410SWang.Lin@Sun.COM if (err == ENOTSUP) {
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 }
37558410SWang.Lin@Sun.COM
37563737Shx147065 done:
37573737Shx147065 for (i = 0; i < (outfp->wldp_length); i++)
37583737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]);
37593737Shx147065 iret = (int)(outfp->wldp_result);
37603737Shx147065 kmem_free(buf, MAX_BUF_LEN);
37613737Shx147065 return (iret);
37623737Shx147065
37633737Shx147065 }
37643737Shx147065
37653737Shx147065 /*ARGSUSED*/
37663737Shx147065 static int
pcan_cfg_desiredrates(mblk_t * mp,pcan_maci_t * pcan_p,uint32_t cmd)37673737Shx147065 pcan_cfg_desiredrates(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
37683737Shx147065 {
37698410SWang.Lin@Sun.COM uint16_t i;
37708410SWang.Lin@Sun.COM wldp_t *infp;
37718410SWang.Lin@Sun.COM wldp_t *outfp;
37728410SWang.Lin@Sun.COM char *buf;
37738410SWang.Lin@Sun.COM int iret;
37748410SWang.Lin@Sun.COM int err = 0;
37758410SWang.Lin@Sun.COM
37763737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
37773737Shx147065 if (buf == NULL) {
37783737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_rates: failed to alloc "
37793737Shx147065 "memory(%d)\n", MAX_BUF_LEN));
37803737Shx147065 return (ENOMEM);
37813737Shx147065 }
37823737Shx147065 outfp = (wldp_t *)buf;
37833737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
37843737Shx147065 infp = (wldp_t *)mp->b_rptr;
37853737Shx147065
37863737Shx147065 if (cmd == WLAN_GET_PARAM) {
37878410SWang.Lin@Sun.COM err = pcan_get_desrates(pcan_p, outfp->wldp_buf);
37888410SWang.Lin@Sun.COM if (err == EIO) {
37893737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET;
37903737Shx147065 outfp->wldp_result = WL_HW_ERROR;
37913737Shx147065 goto done;
37923737Shx147065 }
37933737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET +
37943737Shx147065 offsetof(wl_rates_t, wl_rates_rates) + sizeof (char);
37953737Shx147065 outfp->wldp_result = WL_SUCCESS;
37963737Shx147065 } else if (cmd == WLAN_SET_PARAM) {
37978410SWang.Lin@Sun.COM (void) pcan_set_desrates(pcan_p, infp->wldp_buf);
37983737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET;
37993737Shx147065 outfp->wldp_result = WL_SUCCESS;
38003737Shx147065 } else {
38013737Shx147065 kmem_free(buf, MAX_BUF_LEN);
38023737Shx147065 return (EINVAL);
38033737Shx147065 }
38048410SWang.Lin@Sun.COM
38053737Shx147065 done:
38063737Shx147065 for (i = 0; i < (outfp->wldp_length); i++)
38073737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]);
38083737Shx147065 iret = (int)(outfp->wldp_result);
38093737Shx147065 kmem_free(buf, MAX_BUF_LEN);
38103737Shx147065 return (iret);
38113737Shx147065 }
38123737Shx147065
38133737Shx147065 /*ARGSUSED*/
38143737Shx147065 static int
pcan_cfg_supportrates(mblk_t * mp,pcan_maci_t * pcan_p,uint32_t cmd)38153737Shx147065 pcan_cfg_supportrates(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
38163737Shx147065 {
38173737Shx147065 uint16_t i;
38183737Shx147065 int iret;
38193737Shx147065 wldp_t *outfp;
38203737Shx147065 char *buf;
38213737Shx147065
38223737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
38233737Shx147065 if (buf == NULL) {
38243737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_supportedrates: failed to alloc "
38253737Shx147065 "memory(%d)\n", MAX_BUF_LEN));
38263737Shx147065 return (ENOMEM);
38273737Shx147065 }
38283737Shx147065 outfp = (wldp_t *)buf;
38293737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
38303737Shx147065
38313737Shx147065 if (cmd == WLAN_GET_PARAM) {
38328410SWang.Lin@Sun.COM pcan_get_suprates(outfp->wldp_buf);
38333737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET +
38343737Shx147065 offsetof(wl_rates_t, wl_rates_rates) +
38353737Shx147065 4 * sizeof (char);
38363737Shx147065 outfp->wldp_result = WL_SUCCESS;
38373737Shx147065 } else {
38383737Shx147065 kmem_free(buf, MAX_BUF_LEN);
38393737Shx147065 return (EINVAL);
38403737Shx147065 }
38418410SWang.Lin@Sun.COM
38423737Shx147065 done:
38433737Shx147065 for (i = 0; i < (outfp->wldp_length); i++)
38443737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]);
38453737Shx147065 iret = (int)(outfp->wldp_result);
38463737Shx147065 kmem_free(buf, MAX_BUF_LEN);
38473737Shx147065 return (iret);
38483737Shx147065 }
38493737Shx147065
38503737Shx147065 /*ARGSUSED*/
38513737Shx147065 static int
pcan_cfg_powermode(mblk_t * mp,pcan_maci_t * pcan_p,uint32_t cmd)38523737Shx147065 pcan_cfg_powermode(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
38533737Shx147065 {
38548410SWang.Lin@Sun.COM uint16_t i;
38558410SWang.Lin@Sun.COM wldp_t *outfp;
38568410SWang.Lin@Sun.COM char *buf;
38578410SWang.Lin@Sun.COM int iret;
38588410SWang.Lin@Sun.COM int err = 0;
38593737Shx147065
38603737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
38613737Shx147065 if (buf == NULL) {
38623737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_powermode: failed to alloc "
38633737Shx147065 "memory(%d)\n", MAX_BUF_LEN));
38643737Shx147065 return (ENOMEM);
38653737Shx147065 }
38663737Shx147065 outfp = (wldp_t *)buf;
38673737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
38683737Shx147065
38693737Shx147065 if (cmd == WLAN_GET_PARAM) {
38708410SWang.Lin@Sun.COM err = pcan_get_powermode(pcan_p, outfp->wldp_buf);
38718410SWang.Lin@Sun.COM if (err == EIO) {
38723737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET;
38733737Shx147065 outfp->wldp_result = WL_HW_ERROR;
38743737Shx147065 goto done;
38753737Shx147065 }
38763737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET +
38773737Shx147065 sizeof (wl_ps_mode_t);
38783737Shx147065 outfp->wldp_result = WL_SUCCESS;
38793737Shx147065 } else if (cmd == WLAN_SET_PARAM) {
38803737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET;
38813737Shx147065 outfp->wldp_result = WL_LACK_FEATURE;
38823737Shx147065 } else {
38833737Shx147065 kmem_free(buf, MAX_BUF_LEN);
38843737Shx147065 return (EINVAL);
38853737Shx147065 }
38868410SWang.Lin@Sun.COM
38873737Shx147065 done:
38883737Shx147065 for (i = 0; i < (outfp->wldp_length); i++)
38893737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]);
38903737Shx147065 iret = (int)(outfp->wldp_result);
38913737Shx147065 kmem_free(buf, MAX_BUF_LEN);
38923737Shx147065 return (iret);
38933737Shx147065
38943737Shx147065 }
38953737Shx147065
38963737Shx147065 static int
pcan_cfg_authmode(mblk_t * mp,pcan_maci_t * pcan_p,uint32_t cmd)38973737Shx147065 pcan_cfg_authmode(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
38983737Shx147065 {
38993737Shx147065 uint16_t i;
39003737Shx147065 wldp_t *outfp;
39013737Shx147065 char *buf;
39023737Shx147065 int iret;
39038410SWang.Lin@Sun.COM int err = 0;
39043737Shx147065 struct an_ltv_genconfig *actcfg_p;
39053737Shx147065
39063737Shx147065 actcfg_p = &pcan_p->an_actual_config;
39073737Shx147065
39083737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
39093737Shx147065 if (buf == NULL) {
39103737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_autymode: failed to alloc "
39113737Shx147065 "memory(%d)\n", MAX_BUF_LEN));
39123737Shx147065 return (ENOMEM);
39133737Shx147065 }
39143737Shx147065 outfp = (wldp_t *)buf;
39153737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
39163737Shx147065
39173737Shx147065 if (cmd == WLAN_GET_PARAM) {
39188410SWang.Lin@Sun.COM pcan_get_authmode(pcan_p, outfp->wldp_buf);
39193737Shx147065 outfp->wldp_result = WL_SUCCESS;
39203737Shx147065 } else if (cmd == WLAN_SET_PARAM) {
39218410SWang.Lin@Sun.COM err = pcan_set_authmode(pcan_p, outfp->wldp_buf);
39228410SWang.Lin@Sun.COM if (err == EINVAL) {
39238410SWang.Lin@Sun.COM outfp->wldp_length = WIFI_BUF_OFFSET;
39248410SWang.Lin@Sun.COM outfp->wldp_result = WL_LACK_FEATURE;
39258410SWang.Lin@Sun.COM } else {
39263737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET;
39273737Shx147065 outfp->wldp_result = WL_SUCCESS;
39283737Shx147065 }
39293737Shx147065 } else {
39303737Shx147065 kmem_free(buf, MAX_BUF_LEN);
39313737Shx147065 return (EINVAL);
39323737Shx147065 }
39333737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_authmode: actual.authmode=%x",
39343737Shx147065 actcfg_p->an_authtype));
39353737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_authmode: actual.home_product=%x",
39363737Shx147065 actcfg_p->an_rsvd6[2]));
39378410SWang.Lin@Sun.COM
39383737Shx147065 for (i = 0; i < (outfp->wldp_length); i++)
39393737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]);
39403737Shx147065 iret = (int)(outfp->wldp_result);
39413737Shx147065 kmem_free(buf, MAX_BUF_LEN);
39423737Shx147065 return (iret);
39433737Shx147065 }
39443737Shx147065
39453737Shx147065 static int
pcan_cfg_encryption(mblk_t * mp,pcan_maci_t * pcan_p,uint32_t cmd)39463737Shx147065 pcan_cfg_encryption(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
39473737Shx147065 {
39483737Shx147065 uint16_t i;
39493737Shx147065 wldp_t *outfp;
39503737Shx147065 char *buf;
39513737Shx147065 int iret;
39523737Shx147065
39533737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
39543737Shx147065 if (buf == NULL) {
39553737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_encryption: failed to alloc "
39563737Shx147065 "memory(%d)\n", MAX_BUF_LEN));
39573737Shx147065 return (ENOMEM);
39583737Shx147065 }
39593737Shx147065 outfp = (wldp_t *)buf;
39603737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
39613737Shx147065
39623737Shx147065 if (cmd == WLAN_GET_PARAM) {
39638410SWang.Lin@Sun.COM pcan_get_encrypt(pcan_p, outfp->wldp_buf);
39643737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_encryption_t);
39653737Shx147065 outfp->wldp_result = WL_SUCCESS;
39663737Shx147065 } else if (cmd == WLAN_SET_PARAM) {
39678410SWang.Lin@Sun.COM (void) pcan_set_encrypt(pcan_p, outfp->wldp_buf);
39683737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET;
39693737Shx147065 outfp->wldp_result = WL_SUCCESS;
39703737Shx147065 } else {
39713737Shx147065 kmem_free(buf, MAX_BUF_LEN);
39723737Shx147065 return (EINVAL);
39733737Shx147065 }
39748410SWang.Lin@Sun.COM
39753737Shx147065 for (i = 0; i < (outfp->wldp_length); i++)
39763737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]);
39773737Shx147065 iret = (int)(outfp->wldp_result);
39783737Shx147065 kmem_free(buf, MAX_BUF_LEN);
39793737Shx147065 return (iret);
39803737Shx147065 }
39813737Shx147065
39823737Shx147065 static int
pcan_cfg_wepkeyid(mblk_t * mp,pcan_maci_t * pcan_p,uint32_t cmd)39833737Shx147065 pcan_cfg_wepkeyid(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
39843737Shx147065 {
39853737Shx147065 uint16_t i, ret;
39863737Shx147065 wldp_t *infp;
39873737Shx147065 wldp_t *outfp;
39883737Shx147065 char *buf;
39893737Shx147065 int iret;
39903737Shx147065 struct an_ltv_wepkey wepkey;
39913737Shx147065
39923737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
39933737Shx147065 if (buf == NULL) {
39943737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_wepkeyid: failed to alloc "
39953737Shx147065 "memory(%d)\n", MAX_BUF_LEN));
39963737Shx147065 return (ENOMEM);
39973737Shx147065 }
39983737Shx147065 outfp = (wldp_t *)buf;
39993737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
40003737Shx147065 infp = (wldp_t *)mp->b_rptr;
40013737Shx147065
40023737Shx147065 if (cmd == WLAN_GET_PARAM) {
40033737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_wep_key_id_t);
40043737Shx147065 outfp->wldp_result = WL_SUCCESS;
40053737Shx147065 *(wl_wep_key_id_t *)(outfp->wldp_buf) = pcan_p->an_cur_wepkey;
40063737Shx147065 } else if (cmd == WLAN_SET_PARAM) {
40073737Shx147065 ret = (uint16_t)(*(wl_wep_key_id_t *)(infp->wldp_buf));
40083737Shx147065 if (ret > 3) {
40093737Shx147065 kmem_free(buf, MAX_BUF_LEN);
40103737Shx147065 return (EINVAL);
40113737Shx147065 }
40123737Shx147065 wepkey.an_index = 0xffff;
40133737Shx147065 wepkey.an_macaddr[0] = ret & 0xff;
40143737Shx147065 pcan_p->an_cur_wepkey = ret;
40153737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET;
40163737Shx147065 outfp->wldp_result = WL_SUCCESS;
40173737Shx147065 } else {
40183737Shx147065 kmem_free(buf, MAX_BUF_LEN);
40193737Shx147065 return (EINVAL);
40203737Shx147065 }
40213737Shx147065 for (i = 0; i < (outfp->wldp_length); i++)
40223737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]);
40233737Shx147065 iret = (int)(outfp->wldp_result);
40243737Shx147065 kmem_free(buf, MAX_BUF_LEN);
40253737Shx147065 return (iret);
40263737Shx147065 }
40273737Shx147065
40283737Shx147065 /*ARGSUSED*/
40293737Shx147065 static int
pcan_cfg_createibss(mblk_t * mp,pcan_maci_t * pcan_p,uint32_t cmd)40303737Shx147065 pcan_cfg_createibss(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
40313737Shx147065 {
40323737Shx147065 uint16_t i;
40333737Shx147065 wldp_t *outfp;
40343737Shx147065 char *buf;
40353737Shx147065 int iret;
40363737Shx147065
40373737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
40383737Shx147065 if (buf == NULL) {
40393737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_createibss: failed to alloc "
40403737Shx147065 "memory(%d)\n", MAX_BUF_LEN));
40413737Shx147065 return (ENOMEM);
40423737Shx147065 }
40433737Shx147065 outfp = (wldp_t *)buf;
40443737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
40453737Shx147065
40463737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_create_ibss_t);
40473737Shx147065 outfp->wldp_result = WL_LACK_FEATURE;
40483737Shx147065 for (i = 0; i < (outfp->wldp_length); i++)
40493737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]);
40503737Shx147065 iret = (int)(outfp->wldp_result);
40513737Shx147065 kmem_free(buf, MAX_BUF_LEN);
40523737Shx147065 return (iret);
40533737Shx147065 }
40543737Shx147065
40553737Shx147065 static int
pcan_cfg_rssi(mblk_t * mp,pcan_maci_t * pcan_p,uint32_t cmd)40563737Shx147065 pcan_cfg_rssi(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
40573737Shx147065 {
40588410SWang.Lin@Sun.COM uint16_t i;
40598410SWang.Lin@Sun.COM int iret;
40608410SWang.Lin@Sun.COM wldp_t *outfp;
40618410SWang.Lin@Sun.COM char *buf;
40628410SWang.Lin@Sun.COM int err = 0;
40633737Shx147065
40643737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
40653737Shx147065 if (buf == NULL) {
40663737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_rssi: failed to alloc "
40673737Shx147065 "memory(%d)\n", MAX_BUF_LEN));
40683737Shx147065 return (ENOMEM);
40693737Shx147065 }
40703737Shx147065 outfp = (wldp_t *)buf;
40713737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
40723737Shx147065
40733737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_rssi_t);
40743737Shx147065
40753737Shx147065 if (cmd == WLAN_GET_PARAM) {
40768410SWang.Lin@Sun.COM err = pcan_get_rssi(pcan_p, outfp->wldp_buf);
40778410SWang.Lin@Sun.COM if (err == EIO) {
40783737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET;
40793737Shx147065 outfp->wldp_result = WL_HW_ERROR;
40803737Shx147065 goto done;
40813737Shx147065 }
40823737Shx147065 outfp->wldp_result = WL_SUCCESS;
40833737Shx147065 } else if (cmd == WLAN_SET_PARAM) {
40843737Shx147065 outfp->wldp_result = WL_READONLY;
40853737Shx147065 } else {
40863737Shx147065 kmem_free(buf, MAX_BUF_LEN);
40873737Shx147065 return (EINVAL);
40883737Shx147065 }
40898410SWang.Lin@Sun.COM
40903737Shx147065 done:
40913737Shx147065 for (i = 0; i < (outfp->wldp_length); i++)
40923737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]);
40933737Shx147065 iret = (int)(outfp->wldp_result);
40943737Shx147065 kmem_free(buf, MAX_BUF_LEN);
40953737Shx147065 return (iret);
40963737Shx147065 }
40973737Shx147065
40983737Shx147065 /*ARGSUSED*/
40993737Shx147065 static int
pcan_cfg_radio(mblk_t * mp,pcan_maci_t * pcan_p,uint32_t cmd)41003737Shx147065 pcan_cfg_radio(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
41013737Shx147065 {
41023737Shx147065 uint16_t i;
41033737Shx147065 int iret;
41043737Shx147065 wldp_t *outfp;
41053737Shx147065 char *buf;
41063737Shx147065
41073737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
41083737Shx147065 if (buf == NULL) {
41093737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_radio: failed to alloc "
41103737Shx147065 "memory(%d)\n", MAX_BUF_LEN));
41113737Shx147065 return (ENOMEM);
41123737Shx147065 }
41133737Shx147065 outfp = (wldp_t *)buf;
41143737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
41153737Shx147065
41163737Shx147065 if (cmd == WLAN_GET_PARAM) {
41173737Shx147065 *(wl_radio_t *)(outfp->wldp_buf) = B_TRUE;
41183737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_radio_t);
41193737Shx147065 outfp->wldp_result = WL_SUCCESS;
41203737Shx147065 } else if (cmd == WLAN_SET_PARAM) {
41213737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET;
41223737Shx147065 outfp->wldp_result = WL_LACK_FEATURE;
41233737Shx147065 } else {
41243737Shx147065 kmem_free(buf, MAX_BUF_LEN);
41253737Shx147065 return (EINVAL);
41263737Shx147065 }
41273737Shx147065
41283737Shx147065 for (i = 0; i < (outfp->wldp_length); i++)
41293737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]);
41303737Shx147065 iret = (int)(outfp->wldp_result);
41313737Shx147065 kmem_free(buf, MAX_BUF_LEN);
41323737Shx147065 return (iret);
41333737Shx147065 }
41343737Shx147065
41353737Shx147065 static int
pcan_cfg_wepkey(mblk_t * mp,pcan_maci_t * pcan_p,uint32_t cmd)41363737Shx147065 pcan_cfg_wepkey(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
41373737Shx147065 {
41383737Shx147065 uint16_t i;
41393737Shx147065 wldp_t *outfp;
41403737Shx147065 char *buf;
41413737Shx147065 int iret;
41423737Shx147065 wldp_t *infp;
41433737Shx147065
41443737Shx147065 buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
41453737Shx147065 if (buf == NULL) {
41463737Shx147065 PCANDBG((CE_NOTE, "pcan cfg_wep: failed to alloc "
41473737Shx147065 "memory(%d)\n", MAX_BUF_LEN));
41483737Shx147065 return (ENOMEM);
41493737Shx147065 }
41503737Shx147065 outfp = (wldp_t *)buf;
41513737Shx147065 bcopy(mp->b_rptr, buf, sizeof (wldp_t));
41523737Shx147065 infp = (wldp_t *)mp->b_rptr;
41533737Shx147065
41543737Shx147065 if (cmd == WLAN_GET_PARAM) {
41553737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET +
41563737Shx147065 sizeof (wl_wep_key_tab_t);
41573737Shx147065 outfp->wldp_result = WL_WRITEONLY;
41583737Shx147065 } else if (cmd == WLAN_SET_PARAM) {
41598410SWang.Lin@Sun.COM (void) pcan_set_wepkey(pcan_p, infp->wldp_buf);
41603737Shx147065 outfp->wldp_length = WIFI_BUF_OFFSET;
41613737Shx147065 outfp->wldp_result = WL_SUCCESS;
41623737Shx147065 } else {
41633737Shx147065 kmem_free(buf, MAX_BUF_LEN);
41643737Shx147065 return (EINVAL);
41653737Shx147065 }
41663737Shx147065
41673737Shx147065 for (i = 0; i < (outfp->wldp_length); i++)
41683737Shx147065 (void) mi_mpprintf_putc((char *)mp, buf[i]);
41693737Shx147065 iret = (int)(outfp->wldp_result);
41703737Shx147065 kmem_free(buf, MAX_BUF_LEN);
41713737Shx147065 return (iret);
41723737Shx147065 }
41733737Shx147065
41743737Shx147065 static void
pcan_connect_timeout(void * arg)41753737Shx147065 pcan_connect_timeout(void *arg)
41763737Shx147065 {
41773737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
41783737Shx147065 uint16_t ret;
41793737Shx147065
41803737Shx147065 mutex_enter(&pcan_p->pcan_glock);
41813737Shx147065 if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0))
41823737Shx147065 goto done;
41833737Shx147065 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
41843737Shx147065 if (ret = pcan_config_mac(pcan_p))
41853737Shx147065 goto done;
41863737Shx147065 ret = pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0);
41873737Shx147065 done:
41883737Shx147065 if (ret)
41894343Sgd78059 cmn_err(CE_WARN, "pcan: connect failed due to hardware error");
41903737Shx147065 mutex_exit(&pcan_p->pcan_glock);
41913737Shx147065 pcan_p->pcan_connect_timeout_id = 0;
41923737Shx147065 }
41933737Shx147065
41943737Shx147065 static int
pcan_getset(mblk_t * mp,pcan_maci_t * pcan_p,uint32_t cmd)41953737Shx147065 pcan_getset(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
41963737Shx147065 {
41973737Shx147065 int ret = WL_SUCCESS;
41983737Shx147065 int connect = 0;
41993737Shx147065
42003737Shx147065 mutex_enter(&pcan_p->pcan_glock);
42013737Shx147065 if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
42023737Shx147065 mutex_exit(&pcan_p->pcan_glock);
42033737Shx147065 return (PCAN_FAIL);
42043737Shx147065 }
42053737Shx147065
42063737Shx147065 switch (((wldp_t *)mp->b_rptr)->wldp_id) {
42073737Shx147065 case WL_ESSID:
42083737Shx147065 ret = pcan_cfg_essid(mp, pcan_p, cmd);
42093737Shx147065 connect = 1;
42103737Shx147065 PCANDBG((CE_NOTE, "cfg_essid\n"));
42113737Shx147065 break;
42123737Shx147065 case WL_BSSID:
42133737Shx147065 ret = pcan_cfg_bssid(mp, pcan_p, cmd);
42143737Shx147065 connect = 1;
42153737Shx147065 PCANDBG((CE_NOTE, "cfg_bssid\n"));
42163737Shx147065 break;
42173737Shx147065 case WL_ESS_LIST:
42183737Shx147065 ret = pcan_cfg_scan(mp, pcan_p, cmd);
42193737Shx147065 PCANDBG((CE_NOTE, "cfg_scan\n"));
42203737Shx147065 break;
42213737Shx147065 case WL_LINKSTATUS:
42223737Shx147065 ret = pcan_cfg_linkstatus(mp, pcan_p, cmd);
42233737Shx147065 PCANDBG((CE_NOTE, "cfg_linkstatus\n"));
42243737Shx147065 break;
42253737Shx147065 case WL_BSS_TYPE:
42263737Shx147065 ret = pcan_cfg_bsstype(mp, pcan_p, cmd);
42273737Shx147065 connect = 1;
42283737Shx147065 PCANDBG((CE_NOTE, "cfg_bsstype\n"));
42293737Shx147065 break;
42303737Shx147065 case WL_PHY_CONFIG:
42313737Shx147065 ret = pcan_cfg_phy(mp, pcan_p, cmd);
42323737Shx147065 connect = 1;
42333737Shx147065 PCANDBG((CE_NOTE, "cfg_phy\n"));
42343737Shx147065 break;
42353737Shx147065 case WL_DESIRED_RATES:
42363737Shx147065 ret = pcan_cfg_desiredrates(mp, pcan_p, cmd);
42373737Shx147065 connect = 1;
42383737Shx147065 PCANDBG((CE_NOTE, "cfg_disred-rates\n"));
42393737Shx147065 break;
42403737Shx147065 case WL_SUPPORTED_RATES:
42413737Shx147065 ret = pcan_cfg_supportrates(mp, pcan_p, cmd);
42423737Shx147065 PCANDBG((CE_NOTE, "cfg_supported-rates\n"));
42433737Shx147065 break;
42443737Shx147065 case WL_POWER_MODE:
42453737Shx147065 ret = pcan_cfg_powermode(mp, pcan_p, cmd);
42463737Shx147065 PCANDBG((CE_NOTE, "cfg_powermode\n"));
42473737Shx147065 break;
42483737Shx147065 case WL_AUTH_MODE:
42493737Shx147065 ret = pcan_cfg_authmode(mp, pcan_p, cmd);
42503737Shx147065 connect = 1;
42513737Shx147065 PCANDBG((CE_NOTE, "cfg_authmode\n"));
42523737Shx147065 break;
42533737Shx147065 case WL_ENCRYPTION:
42543737Shx147065 ret = pcan_cfg_encryption(mp, pcan_p, cmd);
42553737Shx147065 connect = 1;
42563737Shx147065 PCANDBG((CE_NOTE, "cfg_encryption\n"));
42573737Shx147065 break;
42583737Shx147065 case WL_WEP_KEY_ID:
42593737Shx147065 ret = pcan_cfg_wepkeyid(mp, pcan_p, cmd);
42603737Shx147065 connect = 1;
42613737Shx147065 PCANDBG((CE_NOTE, "cfg_wepkeyid\n"));
42623737Shx147065 break;
42633737Shx147065 case WL_CREATE_IBSS:
42643737Shx147065 ret = pcan_cfg_createibss(mp, pcan_p, cmd);
42653737Shx147065 connect = 1;
42663737Shx147065 PCANDBG((CE_NOTE, "cfg_create-ibss\n"));
42673737Shx147065 break;
42683737Shx147065 case WL_RSSI:
42693737Shx147065 ret = pcan_cfg_rssi(mp, pcan_p, cmd);
42703737Shx147065 PCANDBG((CE_NOTE, "cfg_rssi\n"));
42713737Shx147065 break;
42723737Shx147065 case WL_RADIO:
42733737Shx147065 ret = pcan_cfg_radio(mp, pcan_p, cmd);
42743737Shx147065 PCANDBG((CE_NOTE, "cfg_radio\n"));
42753737Shx147065 break;
42763737Shx147065 case WL_WEP_KEY_TAB:
42773737Shx147065 ret = pcan_cfg_wepkey(mp, pcan_p, cmd);
42783737Shx147065 connect = 1;
42793737Shx147065 PCANDBG((CE_NOTE, "cfg_wepkey\n"));
42803737Shx147065 break;
42813737Shx147065 case WL_SCAN:
42823737Shx147065 mutex_exit(&pcan_p->pcan_glock);
42833737Shx147065 if (pcan_p->pcan_connect_timeout_id != 0) {
42843737Shx147065 (void) untimeout(pcan_p->pcan_connect_timeout_id);
42853737Shx147065 pcan_p->pcan_connect_timeout_id = 0;
42863737Shx147065 }
42873737Shx147065 mutex_enter(&pcan_p->pcan_glock);
428811101SMikore.Li@Sun.COM if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
428911101SMikore.Li@Sun.COM mutex_exit(&pcan_p->pcan_glock);
429011101SMikore.Li@Sun.COM return (PCAN_FAIL);
429111101SMikore.Li@Sun.COM }
42923737Shx147065 ret = pcan_cmd_scan(pcan_p);
42933737Shx147065 /*
42943737Shx147065 * a trick here.
42953737Shx147065 * since the scan doesn't return too many items due to hardware
42963737Shx147065 * reason, so the current scan result is an accumulation of
42973737Shx147065 * several scans. For the first time or after many of the items
42983737Shx147065 * aged, we scan again if too few items now in the scan table.
42993737Shx147065 */
43003737Shx147065 if (pcan_p->an_scan_num < AN_SCAN_AGAIN_THRESHOLD)
43013737Shx147065 ret = pcan_cmd_scan(pcan_p);
43023737Shx147065 break;
43033737Shx147065 case WL_LOAD_DEFAULTS:
43043737Shx147065 if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) {
43053737Shx147065 ret = (int)WL_HW_ERROR;
43063737Shx147065 break;
43073737Shx147065 }
43083737Shx147065 if (ret = pcan_loaddef(pcan_p)) {
43093737Shx147065 ret = (int)WL_HW_ERROR;
43103737Shx147065 break;
43113737Shx147065 }
43123737Shx147065 if (ret = pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0)) {
43133737Shx147065 ret = (int)WL_HW_ERROR;
43143737Shx147065 break;
43153737Shx147065 }
43163737Shx147065 PCANDBG((CE_NOTE, "loaddef\n"));
43173737Shx147065 break;
43183737Shx147065 case WL_DISASSOCIATE:
43193737Shx147065 mutex_exit(&pcan_p->pcan_glock);
43203737Shx147065 if (pcan_p->pcan_connect_timeout_id != 0) {
43213737Shx147065 (void) untimeout(pcan_p->pcan_connect_timeout_id);
43223737Shx147065 pcan_p->pcan_connect_timeout_id = 0;
43233737Shx147065 }
43243737Shx147065 mutex_enter(&pcan_p->pcan_glock);
432511101SMikore.Li@Sun.COM if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
432611101SMikore.Li@Sun.COM mutex_exit(&pcan_p->pcan_glock);
432711101SMikore.Li@Sun.COM return (PCAN_FAIL);
432811101SMikore.Li@Sun.COM }
43293737Shx147065 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
43303737Shx147065 if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) {
43313737Shx147065 ret = (int)WL_HW_ERROR;
43323737Shx147065 break;
43333737Shx147065 }
43343737Shx147065 if (ret = pcan_loaddef(pcan_p)) {
43353737Shx147065 ret = (int)WL_HW_ERROR;
43363737Shx147065 break;
43373737Shx147065 }
43383737Shx147065 PCANDBG((CE_NOTE, "disassociate\n"));
43393737Shx147065 break;
43403737Shx147065 case WL_REASSOCIATE:
43413737Shx147065 case WL_ASSOCIAT:
43423737Shx147065 mutex_exit(&pcan_p->pcan_glock);
43433737Shx147065 if (pcan_p->pcan_connect_timeout_id != 0) {
43443737Shx147065 (void) untimeout(pcan_p->pcan_connect_timeout_id);
43453737Shx147065 pcan_p->pcan_connect_timeout_id = 0;
43463737Shx147065 }
43473737Shx147065 mutex_enter(&pcan_p->pcan_glock);
434811101SMikore.Li@Sun.COM if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
434911101SMikore.Li@Sun.COM mutex_exit(&pcan_p->pcan_glock);
435011101SMikore.Li@Sun.COM return (PCAN_FAIL);
435111101SMikore.Li@Sun.COM }
43523737Shx147065 if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) {
43533737Shx147065 ret = (int)WL_HW_ERROR;
43543737Shx147065 break;
43553737Shx147065 }
43563737Shx147065 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
43573737Shx147065 if (ret = pcan_config_mac(pcan_p)) {
43583737Shx147065 ret = (int)WL_HW_ERROR;
43593737Shx147065 break;
43603737Shx147065 }
43613737Shx147065 if (ret = pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0)) {
43623737Shx147065 ret = (int)WL_HW_ERROR;
43633737Shx147065 break;
43643737Shx147065 }
43653737Shx147065 PCANDBG((CE_NOTE, "associate"));
43663737Shx147065 break;
43673737Shx147065
43683737Shx147065 default:
43693737Shx147065 break;
43703737Shx147065 }
43713737Shx147065 mutex_exit(&pcan_p->pcan_glock);
43723737Shx147065 if ((cmd == WLAN_SET_PARAM) && (ret == WL_SUCCESS) && (connect)) {
43733737Shx147065 pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
43743737Shx147065 (void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0);
43753737Shx147065 if (pcan_p->pcan_connect_timeout_id != 0) {
43763737Shx147065 (void) untimeout(pcan_p->pcan_connect_timeout_id);
43773737Shx147065 pcan_p->pcan_connect_timeout_id = 0;
43783737Shx147065 }
43793737Shx147065 pcan_p->pcan_connect_timeout_id = timeout(pcan_connect_timeout,
43803737Shx147065 pcan_p, drv_usectohz(1000000));
43813737Shx147065 }
43823737Shx147065 return (ret);
43833737Shx147065 }
43843737Shx147065
43853737Shx147065 static void
pcan_wlan_ioctl(pcan_maci_t * pcan_p,queue_t * wq,mblk_t * mp,uint32_t cmd)43863737Shx147065 pcan_wlan_ioctl(pcan_maci_t *pcan_p, queue_t *wq, mblk_t *mp, uint32_t cmd)
43873737Shx147065 {
43883737Shx147065
43893737Shx147065 struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
43903737Shx147065 uint32_t len, ret;
43913737Shx147065 mblk_t *mp1;
43923737Shx147065
43933737Shx147065 /* sanity check */
43943737Shx147065 if (iocp->ioc_count == 0 || !(mp1 = mp->b_cont)) {
43953737Shx147065 miocnak(wq, mp, 0, EINVAL);
43963737Shx147065 return;
43973737Shx147065 }
43983737Shx147065
43993737Shx147065 /* assuming single data block */
44003737Shx147065 if (mp1->b_cont) {
44013737Shx147065 freemsg(mp1->b_cont);
44023737Shx147065 mp1->b_cont = NULL;
44033737Shx147065 }
44043737Shx147065
44053737Shx147065 /* we will overwrite everything */
44063737Shx147065 mp1->b_wptr = mp1->b_rptr;
44073737Shx147065
44083737Shx147065 ret = pcan_getset(mp1, pcan_p, cmd);
44093737Shx147065 len = msgdsize(mp1);
44103737Shx147065 miocack(wq, mp, len, ret);
44113737Shx147065 }
44123737Shx147065
44133737Shx147065 static void
pcan_ioctl(void * arg,queue_t * wq,mblk_t * mp)44143737Shx147065 pcan_ioctl(void *arg, queue_t *wq, mblk_t *mp)
44153737Shx147065 {
44163737Shx147065 struct iocblk *iocp;
44173737Shx147065 uint32_t cmd, ret;
44183737Shx147065 pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
44193737Shx147065 boolean_t need_privilege = B_TRUE;
44203737Shx147065
44213737Shx147065 iocp = (struct iocblk *)mp->b_rptr;
44223737Shx147065 iocp->ioc_error = 0;
44233737Shx147065 cmd = iocp->ioc_cmd;
44243737Shx147065 switch (cmd) {
44253737Shx147065 default:
44263737Shx147065 miocnak(wq, mp, 0, EINVAL);
44273737Shx147065 return;
44283737Shx147065 case WLAN_GET_PARAM:
44293737Shx147065 need_privilege = B_FALSE;
44303737Shx147065 break;
44313737Shx147065 case WLAN_SET_PARAM:
44323737Shx147065 case WLAN_COMMAND:
44333737Shx147065 break;
44343737Shx147065 }
44353737Shx147065
44367408SSebastien.Roy@Sun.COM if (need_privilege && (ret = secpolicy_dl_config(iocp->ioc_cr)) != 0)
44377408SSebastien.Roy@Sun.COM miocnak(wq, mp, 0, ret);
44387408SSebastien.Roy@Sun.COM else
44397408SSebastien.Roy@Sun.COM pcan_wlan_ioctl(pcan_p, wq, mp, cmd);
44403737Shx147065 }
44418410SWang.Lin@Sun.COM /*
44428410SWang.Lin@Sun.COM * brussels
44438410SWang.Lin@Sun.COM */
44448410SWang.Lin@Sun.COM /* ARGSUSED */
44458410SWang.Lin@Sun.COM static int
pcan_m_setprop(void * arg,const char * pr_name,mac_prop_id_t wldp_pr_num,uint_t wldp_length,const void * wldp_buf)44468410SWang.Lin@Sun.COM pcan_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
44478410SWang.Lin@Sun.COM uint_t wldp_length, const void *wldp_buf)
44488410SWang.Lin@Sun.COM {
44498410SWang.Lin@Sun.COM int err = 0;
44508410SWang.Lin@Sun.COM pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
44518410SWang.Lin@Sun.COM
44528410SWang.Lin@Sun.COM mutex_enter(&pcan_p->pcan_glock);
44538410SWang.Lin@Sun.COM if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
44548410SWang.Lin@Sun.COM mutex_exit(&pcan_p->pcan_glock);
44558410SWang.Lin@Sun.COM err = EINVAL;
44568410SWang.Lin@Sun.COM return (err);
44578410SWang.Lin@Sun.COM }
44588410SWang.Lin@Sun.COM
44598410SWang.Lin@Sun.COM switch (wldp_pr_num) {
44608410SWang.Lin@Sun.COM /* mac_prop_id */
44618410SWang.Lin@Sun.COM case MAC_PROP_WL_ESSID:
44628410SWang.Lin@Sun.COM err = pcan_set_essid(pcan_p, wldp_buf);
44638410SWang.Lin@Sun.COM break;
44648410SWang.Lin@Sun.COM case MAC_PROP_WL_BSSID:
44658410SWang.Lin@Sun.COM err = pcan_set_bssid(pcan_p, wldp_buf);
44668410SWang.Lin@Sun.COM break;
44678410SWang.Lin@Sun.COM case MAC_PROP_WL_PHY_CONFIG:
44688410SWang.Lin@Sun.COM err = pcan_set_phy(pcan_p, wldp_buf);
44698410SWang.Lin@Sun.COM break;
44708410SWang.Lin@Sun.COM case MAC_PROP_WL_KEY_TAB:
44718410SWang.Lin@Sun.COM err = pcan_set_wepkey(pcan_p, wldp_buf);
44728410SWang.Lin@Sun.COM break;
44738410SWang.Lin@Sun.COM case MAC_PROP_WL_AUTH_MODE:
44748410SWang.Lin@Sun.COM err = pcan_set_authmode(pcan_p, wldp_buf);
44758410SWang.Lin@Sun.COM break;
44768410SWang.Lin@Sun.COM case MAC_PROP_WL_ENCRYPTION:
44778410SWang.Lin@Sun.COM err = pcan_set_encrypt(pcan_p, wldp_buf);
44788410SWang.Lin@Sun.COM break;
44798410SWang.Lin@Sun.COM case MAC_PROP_WL_BSSTYPE:
44808410SWang.Lin@Sun.COM err = pcan_set_bsstype(pcan_p, wldp_buf);
44818410SWang.Lin@Sun.COM break;
44828410SWang.Lin@Sun.COM case MAC_PROP_WL_DESIRED_RATES:
44838410SWang.Lin@Sun.COM err = pcan_set_desrates(pcan_p, wldp_buf);
44848410SWang.Lin@Sun.COM break;
44858410SWang.Lin@Sun.COM case MAC_PROP_WL_POWER_MODE:
44868410SWang.Lin@Sun.COM case MAC_PROP_WL_CREATE_IBSS:
44878410SWang.Lin@Sun.COM case MAC_PROP_WL_RADIO:
44888410SWang.Lin@Sun.COM case MAC_PROP_WL_WPA:
44898410SWang.Lin@Sun.COM case MAC_PROP_WL_KEY:
44908410SWang.Lin@Sun.COM case MAC_PROP_WL_DELKEY:
44918410SWang.Lin@Sun.COM case MAC_PROP_WL_SETOPTIE:
44928410SWang.Lin@Sun.COM case MAC_PROP_WL_MLME:
44938410SWang.Lin@Sun.COM case MAC_PROP_WL_LINKSTATUS:
44948410SWang.Lin@Sun.COM case MAC_PROP_WL_ESS_LIST:
44958410SWang.Lin@Sun.COM case MAC_PROP_WL_SUPPORTED_RATES:
44968410SWang.Lin@Sun.COM case MAC_PROP_WL_RSSI:
44978410SWang.Lin@Sun.COM case MAC_PROP_WL_CAPABILITY:
44988410SWang.Lin@Sun.COM case MAC_PROP_WL_SCANRESULTS:
44998410SWang.Lin@Sun.COM cmn_err(CE_WARN, "pcan_setprop:"
45008410SWang.Lin@Sun.COM "opmode not support\n");
45018410SWang.Lin@Sun.COM err = ENOTSUP;
45028410SWang.Lin@Sun.COM break;
45038410SWang.Lin@Sun.COM default:
45048410SWang.Lin@Sun.COM cmn_err(CE_WARN, "pcan_setprop:"
45058410SWang.Lin@Sun.COM "opmode err\n");
45068410SWang.Lin@Sun.COM err = EINVAL;
45078410SWang.Lin@Sun.COM break;
45088410SWang.Lin@Sun.COM }
45098410SWang.Lin@Sun.COM
45108410SWang.Lin@Sun.COM mutex_exit(&pcan_p->pcan_glock);
45118410SWang.Lin@Sun.COM
45128410SWang.Lin@Sun.COM if (err == ENETRESET) {
45138410SWang.Lin@Sun.COM pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
45148410SWang.Lin@Sun.COM (void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0);
45158410SWang.Lin@Sun.COM if (pcan_p->pcan_connect_timeout_id != 0) {
45168410SWang.Lin@Sun.COM (void) untimeout(pcan_p->pcan_connect_timeout_id);
45178410SWang.Lin@Sun.COM pcan_p->pcan_connect_timeout_id = 0;
45188410SWang.Lin@Sun.COM }
45198410SWang.Lin@Sun.COM pcan_p->pcan_connect_timeout_id = timeout(pcan_connect_timeout,
45208410SWang.Lin@Sun.COM pcan_p, drv_usectohz(1000000));
45218410SWang.Lin@Sun.COM
45228410SWang.Lin@Sun.COM err = 0;
45238410SWang.Lin@Sun.COM }
45248410SWang.Lin@Sun.COM
45258410SWang.Lin@Sun.COM return (err);
45268410SWang.Lin@Sun.COM } /* ARGSUSED */
45278410SWang.Lin@Sun.COM
45288410SWang.Lin@Sun.COM /* ARGSUSED */
45298410SWang.Lin@Sun.COM static int
pcan_m_getprop(void * arg,const char * pr_name,mac_prop_id_t wldp_pr_num,uint_t wldp_length,void * wldp_buf)45308410SWang.Lin@Sun.COM pcan_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
4531*11878SVenu.Iyer@Sun.COM uint_t wldp_length, void *wldp_buf)
45328410SWang.Lin@Sun.COM {
45338410SWang.Lin@Sun.COM int err = 0;
45348410SWang.Lin@Sun.COM pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
45358410SWang.Lin@Sun.COM
45368410SWang.Lin@Sun.COM mutex_enter(&pcan_p->pcan_glock);
45378410SWang.Lin@Sun.COM if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
45388410SWang.Lin@Sun.COM mutex_exit(&pcan_p->pcan_glock);
45398410SWang.Lin@Sun.COM err = EINVAL;
45408410SWang.Lin@Sun.COM return (err);
45418410SWang.Lin@Sun.COM }
45428410SWang.Lin@Sun.COM
45438410SWang.Lin@Sun.COM switch (wldp_pr_num) {
45448410SWang.Lin@Sun.COM /* mac_prop_id */
45458410SWang.Lin@Sun.COM case MAC_PROP_WL_ESSID:
45468410SWang.Lin@Sun.COM err = pcan_get_essid(pcan_p, wldp_buf);
45478410SWang.Lin@Sun.COM break;
45488410SWang.Lin@Sun.COM case MAC_PROP_WL_BSSID:
45498410SWang.Lin@Sun.COM err = pcan_get_bssid(pcan_p, wldp_buf);
45508410SWang.Lin@Sun.COM break;
45518410SWang.Lin@Sun.COM case MAC_PROP_WL_PHY_CONFIG:
45528410SWang.Lin@Sun.COM err = pcan_get_phy(pcan_p, wldp_buf);
45538410SWang.Lin@Sun.COM break;
45548410SWang.Lin@Sun.COM case MAC_PROP_WL_AUTH_MODE:
45558410SWang.Lin@Sun.COM pcan_get_authmode(pcan_p, wldp_buf);
45568410SWang.Lin@Sun.COM break;
45578410SWang.Lin@Sun.COM case MAC_PROP_WL_ENCRYPTION:
45588410SWang.Lin@Sun.COM pcan_get_encrypt(pcan_p, wldp_buf);
45598410SWang.Lin@Sun.COM break;
45608410SWang.Lin@Sun.COM case MAC_PROP_WL_BSSTYPE:
45618410SWang.Lin@Sun.COM pcan_get_bsstype(pcan_p, wldp_buf);
45628410SWang.Lin@Sun.COM break;
45638410SWang.Lin@Sun.COM case MAC_PROP_WL_LINKSTATUS:
45648410SWang.Lin@Sun.COM pcan_get_linkstatus(pcan_p, wldp_buf);
45658410SWang.Lin@Sun.COM break;
45668410SWang.Lin@Sun.COM case MAC_PROP_WL_ESS_LIST:
45678410SWang.Lin@Sun.COM pcan_get_esslist(pcan_p, wldp_buf);
45688410SWang.Lin@Sun.COM break;
45698410SWang.Lin@Sun.COM case MAC_PROP_WL_SUPPORTED_RATES:
45708410SWang.Lin@Sun.COM pcan_get_suprates(wldp_buf);
45718410SWang.Lin@Sun.COM break;
45728410SWang.Lin@Sun.COM case MAC_PROP_WL_RSSI:
45738410SWang.Lin@Sun.COM err = pcan_get_rssi(pcan_p, wldp_buf);
45748410SWang.Lin@Sun.COM break;
45758410SWang.Lin@Sun.COM case MAC_PROP_WL_RADIO:
45768410SWang.Lin@Sun.COM pcan_get_radio(wldp_buf);
45778410SWang.Lin@Sun.COM break;
45788410SWang.Lin@Sun.COM case MAC_PROP_WL_POWER_MODE:
45798410SWang.Lin@Sun.COM err = pcan_get_powermode(pcan_p, wldp_buf);
45808410SWang.Lin@Sun.COM break;
45818410SWang.Lin@Sun.COM case MAC_PROP_WL_DESIRED_RATES:
45828410SWang.Lin@Sun.COM err = pcan_get_desrates(pcan_p, wldp_buf);
45838410SWang.Lin@Sun.COM break;
45848410SWang.Lin@Sun.COM case MAC_PROP_WL_CREATE_IBSS:
45858410SWang.Lin@Sun.COM case MAC_PROP_WL_CAPABILITY:
45868410SWang.Lin@Sun.COM case MAC_PROP_WL_WPA:
45878410SWang.Lin@Sun.COM case MAC_PROP_WL_SCANRESULTS:
45888410SWang.Lin@Sun.COM case MAC_PROP_WL_KEY_TAB:
45898410SWang.Lin@Sun.COM case MAC_PROP_WL_KEY:
45908410SWang.Lin@Sun.COM case MAC_PROP_WL_DELKEY:
45918410SWang.Lin@Sun.COM case MAC_PROP_WL_SETOPTIE:
45928410SWang.Lin@Sun.COM case MAC_PROP_WL_MLME:
45938410SWang.Lin@Sun.COM cmn_err(CE_WARN, "pcan_getprop:"
459411101SMikore.Li@Sun.COM "opmode not support %x\n", wldp_pr_num);
45958410SWang.Lin@Sun.COM err = ENOTSUP;
45968410SWang.Lin@Sun.COM break;
45978410SWang.Lin@Sun.COM default:
45988410SWang.Lin@Sun.COM cmn_err(CE_WARN, "pcan_getprop:"
45998410SWang.Lin@Sun.COM "opmode err\n");
46008410SWang.Lin@Sun.COM err = EINVAL;
46018410SWang.Lin@Sun.COM break;
46028410SWang.Lin@Sun.COM }
46038410SWang.Lin@Sun.COM
46048410SWang.Lin@Sun.COM mutex_exit(&pcan_p->pcan_glock);
46058410SWang.Lin@Sun.COM
46068410SWang.Lin@Sun.COM return (err);
46078410SWang.Lin@Sun.COM }
46088801SQuaker.Fang@Sun.COM
4609*11878SVenu.Iyer@Sun.COM static void
pcan_m_propinfo(void * arg,const char * pr_name,mac_prop_id_t wldp_pr_num,mac_prop_info_handle_t mph)4610*11878SVenu.Iyer@Sun.COM pcan_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
4611*11878SVenu.Iyer@Sun.COM mac_prop_info_handle_t mph)
4612*11878SVenu.Iyer@Sun.COM {
4613*11878SVenu.Iyer@Sun.COM _NOTE(ARGUNUSED(arg, pr_name));
4614*11878SVenu.Iyer@Sun.COM
4615*11878SVenu.Iyer@Sun.COM switch (wldp_pr_num) {
4616*11878SVenu.Iyer@Sun.COM case MAC_PROP_WL_BSSTYPE:
4617*11878SVenu.Iyer@Sun.COM case MAC_PROP_WL_ESS_LIST:
4618*11878SVenu.Iyer@Sun.COM case MAC_PROP_WL_SUPPORTED_RATES:
4619*11878SVenu.Iyer@Sun.COM case MAC_PROP_WL_RSSI:
4620*11878SVenu.Iyer@Sun.COM mac_prop_info_set_perm(mph, MAC_PROP_PERM_READ);
4621*11878SVenu.Iyer@Sun.COM break;
4622*11878SVenu.Iyer@Sun.COM }
4623*11878SVenu.Iyer@Sun.COM }
4624*11878SVenu.Iyer@Sun.COM
4625*11878SVenu.Iyer@Sun.COM
46268801SQuaker.Fang@Sun.COM /*
46278801SQuaker.Fang@Sun.COM * quiesce(9E) entry point.
46288801SQuaker.Fang@Sun.COM *
46298801SQuaker.Fang@Sun.COM * This function is called when the system is single-threaded at high
46308801SQuaker.Fang@Sun.COM * PIL with preemption disabled. Therefore, this function must not be
46318801SQuaker.Fang@Sun.COM * blocked.
46328801SQuaker.Fang@Sun.COM *
46338801SQuaker.Fang@Sun.COM * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
46348801SQuaker.Fang@Sun.COM * DDI_FAILURE indicates an error condition and should almost never happen.
46358801SQuaker.Fang@Sun.COM */
46368801SQuaker.Fang@Sun.COM #ifndef __sparc
46378801SQuaker.Fang@Sun.COM static int
pcan_quiesce(dev_info_t * dip)46388801SQuaker.Fang@Sun.COM pcan_quiesce(dev_info_t *dip)
46398801SQuaker.Fang@Sun.COM {
46408801SQuaker.Fang@Sun.COM pcan_maci_t *pcan_p;
46418801SQuaker.Fang@Sun.COM
46428801SQuaker.Fang@Sun.COM pcan_p = ddi_get_soft_state(pcan_soft_state_p, ddi_get_instance(dip));
46438801SQuaker.Fang@Sun.COM if (pcan_p == NULL)
46448801SQuaker.Fang@Sun.COM return (DDI_FAILURE);
46458801SQuaker.Fang@Sun.COM
46468801SQuaker.Fang@Sun.COM if (pcan_p->pcan_flag & PCAN_CARD_READY)
46478801SQuaker.Fang@Sun.COM pcan_stop_locked(pcan_p);
46488801SQuaker.Fang@Sun.COM
46498801SQuaker.Fang@Sun.COM return (DDI_SUCCESS);
46508801SQuaker.Fang@Sun.COM }
46518801SQuaker.Fang@Sun.COM #endif
4652