From 92983db9a2ed5116c103cd7dceabe3a703b26bef Mon Sep 17 00:00:00 2001 From: Igor Pecovnik Date: Mon, 29 Feb 2016 15:30:31 +0100 Subject: [PATCH] Fixed Banana PRO wireless driver in legacy kernel, module name AP6211, enabled I2S in Banana PRO legacy --- config/bananapipro.fex | 2 +- config/linux-sun7i-default.config | 5 + configuration.sh | 2 +- ...ch => 0030-ap6210_module-cubietruck.patch} | 0 .../0031-ap6211_module-bananapro.patch | 84915 ++++++++++++++++ 5 files changed, 84922 insertions(+), 2 deletions(-) rename patch/kernel/sun7i-default/{0030-ap6210_module.patch => 0030-ap6210_module-cubietruck.patch} (100%) create mode 100644 patch/kernel/sun7i-default/0031-ap6211_module-bananapro.patch diff --git a/config/bananapipro.fex b/config/bananapipro.fex index 71639825c..3bf50f461 100644 --- a/config/bananapipro.fex +++ b/config/bananapipro.fex @@ -942,7 +942,7 @@ bt_gpio = port:PI21<1> bt_rst = port:PB05<1> [i2s_para] -i2s_used = 0 +i2s_used = 1 i2s_channel = 2 i2s_mclk = port:PB05<2><1> i2s_bclk = port:PB06<2><1> diff --git a/config/linux-sun7i-default.config b/config/linux-sun7i-default.config index db5495b4e..1a4642384 100644 --- a/config/linux-sun7i-default.config +++ b/config/linux-sun7i-default.config @@ -1511,6 +1511,11 @@ CONFIG_AP6210_FW_PATH="/lib/firmware/ap6210/fw_bcmxxxx.bin" CONFIG_AP6210_NVRAM_PATH="/lib/firmware/ap6210/nvram_apxxxx.txt" CONFIG_AP6210_OOB=y # CONFIG_AP6210_SDIO_IRQ is not set +CONFIG_AP6211=m +CONFIG_AP6211_FW_PATH="/lib/firmware/ap6210/fw_bcmxxxx.bin" +CONFIG_AP6211_NVRAM_PATH="/lib/firmware/ap6210/nvram_ap6210.txt" +CONFIG_AP6211_OOB=y +# CONFIG_AP6211_SDIO_IRQ is not set CONFIG_BRCMUTIL=m CONFIG_BRCMFMAC=m CONFIG_BRCMFMAC_SDIO=y diff --git a/configuration.sh b/configuration.sh index 4f9ca8bd7..97380073d 100644 --- a/configuration.sh +++ b/configuration.sh @@ -179,7 +179,7 @@ case $BOARD in #build 6 LINUXFAMILY="sun7i" BOOTCONFIG="Bananapi_defconfig" - MODULES="hci_uart gpio_sunxi rfcomm hidp sunxi-ir bonding spi_sun7i 8021q a20_tp ap6210" + MODULES="hci_uart gpio_sunxi rfcomm hidp sunxi-ir bonding spi_sun7i 8021q a20_tp ap6211" MODULES_NEXT="brcmfmac bonding" DESKTOP_TARGET="trusty,%" ;; diff --git a/patch/kernel/sun7i-default/0030-ap6210_module.patch b/patch/kernel/sun7i-default/0030-ap6210_module-cubietruck.patch similarity index 100% rename from patch/kernel/sun7i-default/0030-ap6210_module.patch rename to patch/kernel/sun7i-default/0030-ap6210_module-cubietruck.patch diff --git a/patch/kernel/sun7i-default/0031-ap6211_module-bananapro.patch b/patch/kernel/sun7i-default/0031-ap6211_module-bananapro.patch new file mode 100644 index 000000000..7dd09ba3d --- /dev/null +++ b/patch/kernel/sun7i-default/0031-ap6211_module-bananapro.patch @@ -0,0 +1,84915 @@ +diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig +old mode 100644 +new mode 100755 +index a17fd93..6afeab3 +--- a/drivers/net/wireless/Kconfig ++++ b/drivers/net/wireless/Kconfig +@@ -278,7 +278,8 @@ source "drivers/net/wireless/ath/Kconfig" + source "drivers/net/wireless/b43/Kconfig" + source "drivers/net/wireless/b43legacy/Kconfig" + source "drivers/net/wireless/bcmdhd/Kconfig" + source "drivers/net/wireless/ap6210/Kconfig" ++source "drivers/net/wireless/ap6211/Kconfig" + source "drivers/net/wireless/brcm80211/Kconfig" + source "drivers/net/wireless/bcm4330/Kconfig" + source "drivers/net/wireless/hostap/Kconfig" +diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile +old mode 100644 +new mode 100755 +index 0db00ba..a970c43 +--- a/drivers/net/wireless/Makefile ++++ b/drivers/net/wireless/Makefile +@@ -65,7 +65,8 @@ obj-$(CONFIG_IWM) += iwmc3200wifi/ + obj-$(CONFIG_MWIFIEX) += mwifiex/ + + obj-$(CONFIG_BCMDHD) += bcmdhd/ + obj-$(CONFIG_AP6210) += ap6210/ ++obj-$(CONFIG_AP6211) += ap6211/ + + obj-$(CONFIG_BRCMFMAC) += brcm80211/ + obj-$(CONFIG_BRCMSMAC) += brcm80211/ +diff --git a/drivers/net/wireless/ap6211/Kconfig b/drivers/net/wireless/ap6211/Kconfig +new file mode 100755 +index 0000000..9756ac7 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/Kconfig +@@ -0,0 +1,45 @@ ++config AP6211 ++ tristate "AMPAK AP6211 wireless/bluetooth module support" ++ depends on MMC ++ default n ++ ---help--- ++ This module adds support for the wireless and bluetooth ++ module of the CubieTruck. ++ ++config AP6211_FW_PATH ++ depends on AP6211 ++ string "Firmware path" ++ default "/system/vendor/modules/fw_bcmxxxx.bin" ++ ---help--- ++ Path to the firmware file. ++ ++config AP6211_NVRAM_PATH ++ depends on AP6211 ++ string "NVRAM path" ++ default "/system/vendor/modules/nvram_apxxxx.txt" ++ ---help--- ++ Path to the calibration file. ++ ++config AP6211_WEXT ++ bool "Enable WEXT support" ++ depends on AP6211 && CFG80211 = n ++ select WIRELESS_EXT ++ select WEXT_PRIV ++ help ++ Enables WEXT support ++ ++choice ++ depends on AP6211 ++ prompt "Interrupt type" ++config AP6211_OOB ++ depends on AP6211 ++ bool "Out-of-Band Interrupt" ++ ---help--- ++ Interrupt through WL_HOST_WAKE. ++config AP6211_SDIO_IRQ ++ depends on AP6211 ++ bool "In-Band Interrupt" ++ default y ++ ---help--- ++ Interrupt through SDIO DAT[1] ++endchoice +diff --git a/drivers/net/wireless/ap6211/Makefile b/drivers/net/wireless/ap6211/Makefile +new file mode 100755 +index 0000000..59ef7c8 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/Makefile +@@ -0,0 +1,65 @@ ++# ap6211 ++DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DBCMDRIVER \ ++ -DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE \ ++ -DDHDTHREAD -DDHD_DEBUG -DSDTEST -DBDC -DTOE \ ++ -DDHD_BCMEVENTS -DSHOW_EVENTS -DPROP_TXSTATUS -DBCMDBG \ ++ -DMMC_SDIO_ABORT -DBCMSDIO -DBCMLXSDMMC -DBCMPLATFORM_BUS -DWLP2P \ ++ -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT \ ++ -DKEEP_ALIVE -DPKT_FILTER_SUPPORT \ ++ -DEMBEDDED_PLATFORM -DENABLE_INSMOD_NO_FW_LOAD -DPNO_SUPPORT \ ++ -DDHD_USE_IDLECOUNT -DSET_RANDOM_MAC_SOFTAP -DVSDB \ ++ -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST -DSDIO_CRC_ERROR_FIX \ ++ -DESCAN_RESULT_PATCH -DHT40_GO -DPASS_ARP_PACKET -DSUPPORT_PM2_ONLY \ ++ -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT -DAMPDU_HOSTREORDER \ ++ -DDISABLE_FW_ROAM_SUSPEND -DDISABLE_BUILTIN_ROAM \ ++ -DCUSTOM_SDIO_F2_BLKSIZE=128 -DWL_SDO -DWL_SUPPORT_BACKPORTED_KPATCHES\ ++ -Idrivers/net/wireless/ap6211 -Idrivers/net/wireless/ap6211/include ++ ++DHDOFILES = aiutils.o bcmsdh_sdmmc_linux.o dhd_linux.o siutils.o bcmutils.o \ ++ dhd_linux_sched.o dhd_sdio.o bcmwifi_channels.o bcmevent.o hndpmu.o \ ++ bcmsdh.o dhd_cdc.o bcmsdh_linux.o dhd_common.o linux_osl.o \ ++ bcmsdh_sdmmc.o dhd_custom_gpio.o sbutils.o wldev_common.o wl_android.o \ ++ ap6211_gpio_wifi.o ap6211_gpio_bt.o ++ ++obj-$(CONFIG_AP6211) += ap6211.o ++ap6211-objs += $(DHDOFILES) ++ ++DHDOFILES += dhd_gpio.o ++DHDCFLAGS += -DCUSTOMER_HW ++#DHDCFLAGS += -DBCMWAPI_WPI -DBCMWAPI_WAI ++ ++ifeq ($(CONFIG_AP6211_OOB),y) ++DHDCFLAGS += -DOOB_INTR_ONLY -DHW_OOB -DCUSTOMER_OOB ++else ++DHDCFLAGS += -DSDIO_ISR_THREAD ++endif ++ ++ifeq ($(CONFIG_AP6211_AG),y) ++ DHDCFLAGS += -DBAND_AG ++endif ++ ++ifneq ($(CONFIG_WIRELESS_EXT),) ++ap6211-objs += wl_iw.o ++DHDCFLAGS += -DSOFTAP -DWL_WIRELESS_EXT -DUSE_IW ++endif ++ifneq ($(CONFIG_CFG80211),) ++ap6211-objs += wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o dhd_cfg80211.o ++DHDCFLAGS += -DWL_CFG80211 -DWL_CFG80211_STA_EVENT ++DHDCFLAGS += -DCUSTOM_ROAM_TRIGGER_SETTING=-65 ++DHDCFLAGS += -DCUSTOM_ROAM_DELTA_SETTING=15 ++DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=28000 ++DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=7 ++#DHDCFLAGS += -fno-aggressive-loop-optimizations ++endif ++ifneq ($(CONFIG_DHD_USE_SCHED_SCAN),) ++DHDCFLAGS += -DWL_SCHED_SCAN ++endif ++EXTRA_CFLAGS = $(DHDCFLAGS) ++ifeq ($(CONFIG_AP6211),m) ++EXTRA_LDFLAGS += --strip-debug ++endif ++ ++# GPIO Power Management Modules ++ ++#obj-$(CONFIG_AP6211) += ap6211_gpio_wifi.o ++#obj-$(CONFIG_AP6211) += ap6211_gpio_bt.o +diff --git a/drivers/net/wireless/ap6211/aiutils.c b/drivers/net/wireless/ap6211/aiutils.c +new file mode 100755 +index 0000000..bc116d7 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/aiutils.c +@@ -0,0 +1,873 @@ ++/* ++ * Misc utility routines for accessing chip-specific features ++ * of the SiliconBackplane-based Broadcom chips. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: aiutils.c 347614 2012-07-27 10:24:51Z $ ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "siutils_priv.h" ++ ++#include ++ ++#define BCM47162_DMP() (0) ++#define BCM5357_DMP() (0) ++#define remap_coreid(sih, coreid) (coreid) ++#define remap_corerev(sih, corerev) (corerev) ++ ++/* EROM parsing */ ++ ++static uint32 ++get_erom_ent(si_t *sih, uint32 **eromptr, uint32 mask, uint32 match) ++{ ++ uint32 ent; ++ uint inv = 0, nom = 0; ++ ++ while (TRUE) { ++ ent = R_REG(si_osh(sih), *eromptr); ++ (*eromptr)++; ++ ++ if (mask == 0) ++ break; ++ ++ if ((ent & ER_VALID) == 0) { ++ inv++; ++ continue; ++ } ++ ++ if (ent == (ER_END | ER_VALID)) ++ break; ++ ++ if ((ent & mask) == match) ++ break; ++ ++ nom++; ++ } ++ ++ AP6211_DEBUG("%s: Returning ent 0x%08x\n", __FUNCTION__, ent); ++ if (inv + nom) { ++ AP6211_DEBUG(" after %d invalid and %d non-matching entries\n", inv, nom); ++ } ++ return ent; ++} ++ ++static uint32 ++get_asd(si_t *sih, uint32 **eromptr, uint sp, uint ad, uint st, uint32 *addrl, uint32 *addrh, ++ uint32 *sizel, uint32 *sizeh) ++{ ++ uint32 asd, sz, szd; ++ ++ asd = get_erom_ent(sih, eromptr, ER_VALID, ER_VALID); ++ if (((asd & ER_TAG1) != ER_ADD) || ++ (((asd & AD_SP_MASK) >> AD_SP_SHIFT) != sp) || ++ ((asd & AD_ST_MASK) != st)) { ++ /* This is not what we want, "push" it back */ ++ (*eromptr)--; ++ return 0; ++ } ++ *addrl = asd & AD_ADDR_MASK; ++ if (asd & AD_AG32) ++ *addrh = get_erom_ent(sih, eromptr, 0, 0); ++ else ++ *addrh = 0; ++ *sizeh = 0; ++ sz = asd & AD_SZ_MASK; ++ if (sz == AD_SZ_SZD) { ++ szd = get_erom_ent(sih, eromptr, 0, 0); ++ *sizel = szd & SD_SZ_MASK; ++ if (szd & SD_SG32) ++ *sizeh = get_erom_ent(sih, eromptr, 0, 0); ++ } else ++ *sizel = AD_SZ_BASE << (sz >> AD_SZ_SHIFT); ++ ++ AP6211_DEBUG(" SP %d, ad %d: st = %d, 0x%08x_0x%08x @ 0x%08x_0x%08x\n", ++ sp, ad, st, *sizeh, *sizel, *addrh, *addrl); ++ ++ return asd; ++} ++ ++static void ++ai_hwfixup(si_info_t *sii) ++{ ++} ++ ++ ++/* parse the enumeration rom to identify all cores */ ++void ++ai_scan(si_t *sih, void *regs, uint devid) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ chipcregs_t *cc = (chipcregs_t *)regs; ++ uint32 erombase, *eromptr, *eromlim; ++ ++ erombase = R_REG(sii->osh, &cc->eromptr); ++ ++ switch (BUSTYPE(sih->bustype)) { ++ case SI_BUS: ++ eromptr = (uint32 *)REG_MAP(erombase, SI_CORE_SIZE); ++ break; ++ ++ case PCI_BUS: ++ /* Set wrappers address */ ++ sii->curwrap = (void *)((uintptr)regs + SI_CORE_SIZE); ++ ++ /* Now point the window at the erom */ ++ OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, erombase); ++ eromptr = regs; ++ break; ++ ++ case SPI_BUS: ++ case SDIO_BUS: ++ eromptr = (uint32 *)(uintptr)erombase; ++ break; ++ ++ case PCMCIA_BUS: ++ default: ++ AP6211_ERR("Don't know how to do AXI enumertion on bus %d\n", sih->bustype); ++ ASSERT(0); ++ return; ++ } ++ eromlim = eromptr + (ER_REMAPCONTROL / sizeof(uint32)); ++ ++ AP6211_DEBUG("ai_scan: regs = 0x%p, erombase = 0x%08x, eromptr = 0x%p, eromlim = 0x%p\n", ++ regs, erombase, eromptr, eromlim); ++ while (eromptr < eromlim) { ++ uint32 cia, cib, cid, mfg, crev, nmw, nsw, nmp, nsp; ++ uint32 mpd, asd, addrl, addrh, sizel, sizeh; ++ uint i, j, idx; ++ bool br; ++ ++ br = FALSE; ++ ++ /* Grok a component */ ++ cia = get_erom_ent(sih, &eromptr, ER_TAG, ER_CI); ++ if (cia == (ER_END | ER_VALID)) { ++ AP6211_DEBUG("Found END of erom after %d cores\n", sii->numcores); ++ ai_hwfixup(sii); ++ return; ++ } ++ ++ cib = get_erom_ent(sih, &eromptr, 0, 0); ++ ++ if ((cib & ER_TAG) != ER_CI) { ++ AP6211_ERR("CIA not followed by CIB\n"); ++ goto error; ++ } ++ ++ cid = (cia & CIA_CID_MASK) >> CIA_CID_SHIFT; ++ mfg = (cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT; ++ crev = (cib & CIB_REV_MASK) >> CIB_REV_SHIFT; ++ nmw = (cib & CIB_NMW_MASK) >> CIB_NMW_SHIFT; ++ nsw = (cib & CIB_NSW_MASK) >> CIB_NSW_SHIFT; ++ nmp = (cib & CIB_NMP_MASK) >> CIB_NMP_SHIFT; ++ nsp = (cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT; ++ ++#ifdef BCMDBG_SI ++ AP6211_DEBUG("Found component 0x%04x/0x%04x rev %d at erom addr 0x%p, with nmw = %d, " ++ "nsw = %d, nmp = %d & nsp = %d\n", ++ mfg, cid, crev, eromptr - 1, nmw, nsw, nmp, nsp); ++#else ++ BCM_REFERENCE(crev); ++#endif ++ ++ if (((mfg == MFGID_ARM) && (cid == DEF_AI_COMP)) || (nsp == 0)) ++ continue; ++ if ((nmw + nsw == 0)) { ++ /* A component which is not a core */ ++ if (cid == OOB_ROUTER_CORE_ID) { ++ asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, ++ &addrl, &addrh, &sizel, &sizeh); ++ if (asd != 0) { ++ sii->oob_router = addrl; ++ } ++ } ++ if (cid != GMAC_COMMON_4706_CORE_ID) ++ continue; ++ } ++ ++ idx = sii->numcores; ++ ++ sii->cia[idx] = cia; ++ sii->cib[idx] = cib; ++ sii->coreid[idx] = remap_coreid(sih, cid); ++ ++ for (i = 0; i < nmp; i++) { ++ mpd = get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID); ++ if ((mpd & ER_TAG) != ER_MP) { ++ AP6211_ERR("Not enough MP entries for component 0x%x\n", cid); ++ goto error; ++ } ++ AP6211_DEBUG(" Master port %d, mp: %d id: %d\n", i, ++ (mpd & MPD_MP_MASK) >> MPD_MP_SHIFT, ++ (mpd & MPD_MUI_MASK) >> MPD_MUI_SHIFT); ++ } ++ ++ /* First Slave Address Descriptor should be port 0: ++ * the main register space for the core ++ */ ++ asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, &addrl, &addrh, &sizel, &sizeh); ++ if (asd == 0) { ++ do { ++ /* Try again to see if it is a bridge */ ++ asd = get_asd(sih, &eromptr, 0, 0, AD_ST_BRIDGE, &addrl, &addrh, ++ &sizel, &sizeh); ++ if (asd != 0) ++ br = TRUE; ++ else { ++ if (br == TRUE) { ++ break; ++ } ++ else if ((addrh != 0) || (sizeh != 0) || ++ (sizel != SI_CORE_SIZE)) { ++ AP6211_ERR("addrh = 0x%x\t sizeh = 0x%x\t size1 =" ++ "0x%x\n", addrh, sizeh, sizel); ++ AP6211_ERR("First Slave ASD for" ++ "core 0x%04x malformed " ++ "(0x%08x)\n", cid, asd); ++ goto error; ++ } ++ } ++ } while (1); ++ } ++ sii->coresba[idx] = addrl; ++ sii->coresba_size[idx] = sizel; ++ /* Get any more ASDs in port 0 */ ++ j = 1; ++ do { ++ asd = get_asd(sih, &eromptr, 0, j, AD_ST_SLAVE, &addrl, &addrh, ++ &sizel, &sizeh); ++ if ((asd != 0) && (j == 1) && (sizel == SI_CORE_SIZE)) { ++ sii->coresba2[idx] = addrl; ++ sii->coresba2_size[idx] = sizel; ++ } ++ j++; ++ } while (asd != 0); ++ ++ /* Go through the ASDs for other slave ports */ ++ for (i = 1; i < nsp; i++) { ++ j = 0; ++ do { ++ asd = get_asd(sih, &eromptr, i, j, AD_ST_SLAVE, &addrl, &addrh, ++ &sizel, &sizeh); ++ ++ if (asd == 0) ++ break; ++ j++; ++ } while (1); ++ if (j == 0) { ++ AP6211_ERR(" SP %d has no address descriptors\n", i); ++ goto error; ++ } ++ } ++ ++ /* Now get master wrappers */ ++ for (i = 0; i < nmw; i++) { ++ asd = get_asd(sih, &eromptr, i, 0, AD_ST_MWRAP, &addrl, &addrh, ++ &sizel, &sizeh); ++ if (asd == 0) { ++ AP6211_ERR("Missing descriptor for MW %d\n", i); ++ goto error; ++ } ++ if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) { ++ AP6211_ERR("Master wrapper %d is not 4KB\n", i); ++ goto error; ++ } ++ if (i == 0) ++ sii->wrapba[idx] = addrl; ++ } ++ ++ /* And finally slave wrappers */ ++ for (i = 0; i < nsw; i++) { ++ uint fwp = (nsp == 1) ? 0 : 1; ++ asd = get_asd(sih, &eromptr, fwp + i, 0, AD_ST_SWRAP, &addrl, &addrh, ++ &sizel, &sizeh); ++ if (asd == 0) { ++ AP6211_ERR("Missing descriptor for SW %d\n", i); ++ goto error; ++ } ++ if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) { ++ AP6211_ERR("Slave wrapper %d is not 4KB\n", i); ++ goto error; ++ } ++ if ((nmw == 0) && (i == 0)) ++ sii->wrapba[idx] = addrl; ++ } ++ ++ ++ /* Don't record bridges */ ++ if (br) ++ continue; ++ ++ /* Done with core */ ++ sii->numcores++; ++ } ++ ++ AP6211_ERR("Reached end of erom without finding END"); ++ ++error: ++ sii->numcores = 0; ++ return; ++} ++ ++/* This function changes the logical "focus" to the indicated core. ++ * Return the current core's virtual address. ++ */ ++void * ++ai_setcoreidx(si_t *sih, uint coreidx) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ uint32 addr, wrap; ++ void *regs; ++ ++ if (coreidx >= MIN(sii->numcores, SI_MAXCORES)) ++ return (NULL); ++ ++ addr = sii->coresba[coreidx]; ++ wrap = sii->wrapba[coreidx]; ++ ++ /* ++ * If the user has provided an interrupt mask enabled function, ++ * then assert interrupts are disabled before switching the core. ++ */ ++ ASSERT((sii->intrsenabled_fn == NULL) || !(*(sii)->intrsenabled_fn)((sii)->intr_arg)); ++ ++ switch (BUSTYPE(sih->bustype)) { ++ case SI_BUS: ++ /* map new one */ ++ if (!sii->regs[coreidx]) { ++ sii->regs[coreidx] = REG_MAP(addr, SI_CORE_SIZE); ++ ASSERT(GOODREGS(sii->regs[coreidx])); ++ } ++ sii->curmap = regs = sii->regs[coreidx]; ++ if (!sii->wrappers[coreidx]) { ++ sii->wrappers[coreidx] = REG_MAP(wrap, SI_CORE_SIZE); ++ ASSERT(GOODREGS(sii->wrappers[coreidx])); ++ } ++ sii->curwrap = sii->wrappers[coreidx]; ++ break; ++ ++ ++ case SPI_BUS: ++ case SDIO_BUS: ++ sii->curmap = regs = (void *)((uintptr)addr); ++ sii->curwrap = (void *)((uintptr)wrap); ++ break; ++ ++ case PCMCIA_BUS: ++ default: ++ ASSERT(0); ++ regs = NULL; ++ break; ++ } ++ ++ sii->curmap = regs; ++ sii->curidx = coreidx; ++ ++ return regs; ++} ++ ++void ++ai_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ chipcregs_t *cc = NULL; ++ uint32 erombase, *eromptr, *eromlim; ++ uint i, j, cidx; ++ uint32 cia, cib, nmp, nsp; ++ uint32 asd, addrl, addrh, sizel, sizeh; ++ ++ for (i = 0; i < sii->numcores; i++) { ++ if (sii->coreid[i] == CC_CORE_ID) { ++ cc = (chipcregs_t *)sii->regs[i]; ++ break; ++ } ++ } ++ if (cc == NULL) ++ goto error; ++ ++ erombase = R_REG(sii->osh, &cc->eromptr); ++ eromptr = (uint32 *)REG_MAP(erombase, SI_CORE_SIZE); ++ eromlim = eromptr + (ER_REMAPCONTROL / sizeof(uint32)); ++ ++ cidx = sii->curidx; ++ cia = sii->cia[cidx]; ++ cib = sii->cib[cidx]; ++ ++ nmp = (cib & CIB_NMP_MASK) >> CIB_NMP_SHIFT; ++ nsp = (cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT; ++ ++ /* scan for cores */ ++ while (eromptr < eromlim) { ++ if ((get_erom_ent(sih, &eromptr, ER_TAG, ER_CI) == cia) && ++ (get_erom_ent(sih, &eromptr, 0, 0) == cib)) { ++ break; ++ } ++ } ++ ++ /* skip master ports */ ++ for (i = 0; i < nmp; i++) ++ get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID); ++ ++ /* Skip ASDs in port 0 */ ++ asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, &addrl, &addrh, &sizel, &sizeh); ++ if (asd == 0) { ++ /* Try again to see if it is a bridge */ ++ asd = get_asd(sih, &eromptr, 0, 0, AD_ST_BRIDGE, &addrl, &addrh, ++ &sizel, &sizeh); ++ } ++ ++ j = 1; ++ do { ++ asd = get_asd(sih, &eromptr, 0, j, AD_ST_SLAVE, &addrl, &addrh, ++ &sizel, &sizeh); ++ j++; ++ } while (asd != 0); ++ ++ /* Go through the ASDs for other slave ports */ ++ for (i = 1; i < nsp; i++) { ++ j = 0; ++ do { ++ asd = get_asd(sih, &eromptr, i, j, AD_ST_SLAVE, &addrl, &addrh, ++ &sizel, &sizeh); ++ if (asd == 0) ++ break; ++ ++ if (!asidx--) { ++ *addr = addrl; ++ *size = sizel; ++ return; ++ } ++ j++; ++ } while (1); ++ ++ if (j == 0) { ++ AP6211_ERR(" SP %d has no address descriptors\n", i); ++ break; ++ } ++ } ++ ++error: ++ *size = 0; ++ return; ++} ++ ++/* Return the number of address spaces in current core */ ++int ++ai_numaddrspaces(si_t *sih) ++{ ++ return 2; ++} ++ ++/* Return the address of the nth address space in the current core */ ++uint32 ++ai_addrspace(si_t *sih, uint asidx) ++{ ++ si_info_t *sii; ++ uint cidx; ++ ++ sii = SI_INFO(sih); ++ cidx = sii->curidx; ++ ++ if (asidx == 0) ++ return sii->coresba[cidx]; ++ else if (asidx == 1) ++ return sii->coresba2[cidx]; ++ else { ++ AP6211_ERR("%s: Need to parse the erom again to find addr space %d\n", ++ __FUNCTION__, asidx); ++ return 0; ++ } ++} ++ ++/* Return the size of the nth address space in the current core */ ++uint32 ++ai_addrspacesize(si_t *sih, uint asidx) ++{ ++ si_info_t *sii; ++ uint cidx; ++ ++ sii = SI_INFO(sih); ++ cidx = sii->curidx; ++ ++ if (asidx == 0) ++ return sii->coresba_size[cidx]; ++ else if (asidx == 1) ++ return sii->coresba2_size[cidx]; ++ else { ++ AP6211_ERR("%s: Need to parse the erom again to find addr space %d\n", ++ __FUNCTION__, asidx); ++ return 0; ++ } ++} ++ ++uint ++ai_flag(si_t *sih) ++{ ++ si_info_t *sii; ++ aidmp_t *ai; ++ ++ sii = SI_INFO(sih); ++ if (BCM47162_DMP()) { ++ AP6211_ERR("%s: Attempting to read MIPS DMP registers on 47162a0", __FUNCTION__); ++ return sii->curidx; ++ } ++ if (BCM5357_DMP()) { ++ AP6211_ERR("%s: Attempting to read USB20H DMP registers on 5357b0\n", __FUNCTION__); ++ return sii->curidx; ++ } ++ ai = sii->curwrap; ++ ++ return (R_REG(sii->osh, &ai->oobselouta30) & 0x1f); ++} ++ ++void ++ai_setint(si_t *sih, int siflag) ++{ ++} ++ ++uint ++ai_wrap_reg(si_t *sih, uint32 offset, uint32 mask, uint32 val) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ uint32 *map = (uint32 *) sii->curwrap; ++ ++ if (mask || val) { ++ uint32 w = R_REG(sii->osh, map+(offset/4)); ++ w &= ~mask; ++ w |= val; ++ W_REG(sii->osh, map+(offset/4), val); ++ } ++ ++ return (R_REG(sii->osh, map+(offset/4))); ++} ++ ++uint ++ai_corevendor(si_t *sih) ++{ ++ si_info_t *sii; ++ uint32 cia; ++ ++ sii = SI_INFO(sih); ++ cia = sii->cia[sii->curidx]; ++ return ((cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT); ++} ++ ++uint ++ai_corerev(si_t *sih) ++{ ++ si_info_t *sii; ++ uint32 cib; ++ ++ sii = SI_INFO(sih); ++ cib = sii->cib[sii->curidx]; ++ return remap_corerev(sih, (cib & CIB_REV_MASK) >> CIB_REV_SHIFT); ++} ++ ++bool ++ai_iscoreup(si_t *sih) ++{ ++ si_info_t *sii; ++ aidmp_t *ai; ++ ++ sii = SI_INFO(sih); ++ ai = sii->curwrap; ++ ++ return (((R_REG(sii->osh, &ai->ioctrl) & (SICF_FGC | SICF_CLOCK_EN)) == SICF_CLOCK_EN) && ++ ((R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) == 0)); ++} ++ ++/* ++ * Switch to 'coreidx', issue a single arbitrary 32bit register mask&set operation, ++ * switch back to the original core, and return the new value. ++ * ++ * When using the silicon backplane, no fiddling with interrupts or core switches is needed. ++ * ++ * Also, when using pci/pcie, we can optimize away the core switching for pci registers ++ * and (on newer pci cores) chipcommon registers. ++ */ ++uint ++ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) ++{ ++ uint origidx = 0; ++ uint32 *r = NULL; ++ uint w; ++ uint intr_val = 0; ++ bool fast = FALSE; ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ ++ ASSERT(GOODIDX(coreidx)); ++ ASSERT(regoff < SI_CORE_SIZE); ++ ASSERT((val & ~mask) == 0); ++ ++ if (coreidx >= SI_MAXCORES) ++ return 0; ++ ++ if (BUSTYPE(sih->bustype) == SI_BUS) { ++ /* If internal bus, we can always get at everything */ ++ fast = TRUE; ++ /* map if does not exist */ ++ if (!sii->regs[coreidx]) { ++ sii->regs[coreidx] = REG_MAP(sii->coresba[coreidx], ++ SI_CORE_SIZE); ++ ASSERT(GOODREGS(sii->regs[coreidx])); ++ } ++ r = (uint32 *)((uchar *)sii->regs[coreidx] + regoff); ++ } else if (BUSTYPE(sih->bustype) == PCI_BUS) { ++ /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ ++ ++ if ((sii->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { ++ /* Chipc registers are mapped at 12KB */ ++ ++ fast = TRUE; ++ r = (uint32 *)((char *)sii->curmap + PCI_16KB0_CCREGS_OFFSET + regoff); ++ } else if (sii->pub.buscoreidx == coreidx) { ++ /* pci registers are at either in the last 2KB of an 8KB window ++ * or, in pcie and pci rev 13 at 8KB ++ */ ++ fast = TRUE; ++ if (SI_FAST(sii)) ++ r = (uint32 *)((char *)sii->curmap + ++ PCI_16KB0_PCIREGS_OFFSET + regoff); ++ else ++ r = (uint32 *)((char *)sii->curmap + ++ ((regoff >= SBCONFIGOFF) ? ++ PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) + ++ regoff); ++ } ++ } ++ ++ if (!fast) { ++ INTR_OFF(sii, intr_val); ++ ++ /* save current core index */ ++ origidx = si_coreidx(&sii->pub); ++ ++ /* switch core */ ++ r = (uint32*) ((uchar*) ai_setcoreidx(&sii->pub, coreidx) + regoff); ++ } ++ ASSERT(r != NULL); ++ ++ /* mask and set */ ++ if (mask || val) { ++ w = (R_REG(sii->osh, r) & ~mask) | val; ++ W_REG(sii->osh, r, w); ++ } ++ ++ /* readback */ ++ w = R_REG(sii->osh, r); ++ ++ if (!fast) { ++ /* restore core index */ ++ if (origidx != coreidx) ++ ai_setcoreidx(&sii->pub, origidx); ++ ++ INTR_RESTORE(sii, intr_val); ++ } ++ ++ return (w); ++} ++ ++void ++ai_core_disable(si_t *sih, uint32 bits) ++{ ++ si_info_t *sii; ++ volatile uint32 dummy; ++ uint32 status; ++ aidmp_t *ai; ++ ++ sii = SI_INFO(sih); ++ ++ ASSERT(GOODREGS(sii->curwrap)); ++ ai = sii->curwrap; ++ ++ /* if core is already in reset, just return */ ++ if (R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) ++ return; ++ ++ /* ensure there are no pending backplane operations */ ++ SPINWAIT(((status = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); ++ ++ /* if pending backplane ops still, try waiting longer */ ++ if (status != 0) { ++ /* 300usecs was sufficient to allow backplane ops to clear for big hammer */ ++ /* during driver load we may need more time */ ++ SPINWAIT(((status = R_REG(sii->osh, &ai->resetstatus)) != 0), 10000); ++ /* if still pending ops, continue on and try disable anyway */ ++ /* this is in big hammer path, so don't call wl_reinit in this case... */ ++ } ++ ++ W_REG(sii->osh, &ai->ioctrl, bits); ++ dummy = R_REG(sii->osh, &ai->ioctrl); ++ BCM_REFERENCE(dummy); ++ OSL_DELAY(10); ++ ++ W_REG(sii->osh, &ai->resetctrl, AIRC_RESET); ++ dummy = R_REG(sii->osh, &ai->resetctrl); ++ BCM_REFERENCE(dummy); ++ OSL_DELAY(1); ++} ++ ++/* reset and re-enable a core ++ * inputs: ++ * bits - core specific bits that are set during and after reset sequence ++ * resetbits - core specific bits that are set only during reset sequence ++ */ ++void ++ai_core_reset(si_t *sih, uint32 bits, uint32 resetbits) ++{ ++ si_info_t *sii; ++ aidmp_t *ai; ++ volatile uint32 dummy; ++ ++ sii = SI_INFO(sih); ++ ASSERT(GOODREGS(sii->curwrap)); ++ ai = sii->curwrap; ++ ++ /* ++ * Must do the disable sequence first to work for arbitrary current core state. ++ */ ++ ai_core_disable(sih, (bits | resetbits)); ++ ++ /* ++ * Now do the initialization sequence. ++ */ ++ W_REG(sii->osh, &ai->ioctrl, (bits | SICF_FGC | SICF_CLOCK_EN)); ++ dummy = R_REG(sii->osh, &ai->ioctrl); ++ BCM_REFERENCE(dummy); ++ ++ W_REG(sii->osh, &ai->resetctrl, 0); ++ dummy = R_REG(sii->osh, &ai->resetctrl); ++ BCM_REFERENCE(dummy); ++ OSL_DELAY(1); ++ ++ W_REG(sii->osh, &ai->ioctrl, (bits | SICF_CLOCK_EN)); ++ dummy = R_REG(sii->osh, &ai->ioctrl); ++ BCM_REFERENCE(dummy); ++ OSL_DELAY(1); ++} ++ ++void ++ai_core_cflags_wo(si_t *sih, uint32 mask, uint32 val) ++{ ++ si_info_t *sii; ++ aidmp_t *ai; ++ uint32 w; ++ ++ sii = SI_INFO(sih); ++ ++ if (BCM47162_DMP()) { ++ AP6211_ERR("%s: Accessing MIPS DMP register (ioctrl) on 47162a0", ++ __FUNCTION__); ++ return; ++ } ++ if (BCM5357_DMP()) { ++ AP6211_ERR("%s: Accessing USB20H DMP register (ioctrl) on 5357\n", ++ __FUNCTION__); ++ return; ++ } ++ ++ ASSERT(GOODREGS(sii->curwrap)); ++ ai = sii->curwrap; ++ ++ ASSERT((val & ~mask) == 0); ++ ++ if (mask || val) { ++ w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val); ++ W_REG(sii->osh, &ai->ioctrl, w); ++ } ++} ++ ++uint32 ++ai_core_cflags(si_t *sih, uint32 mask, uint32 val) ++{ ++ si_info_t *sii; ++ aidmp_t *ai; ++ uint32 w; ++ ++ sii = SI_INFO(sih); ++ if (BCM47162_DMP()) { ++ AP6211_ERR("%s: Accessing MIPS DMP register (ioctrl) on 47162a0", ++ __FUNCTION__); ++ return 0; ++ } ++ if (BCM5357_DMP()) { ++ AP6211_ERR("%s: Accessing USB20H DMP register (ioctrl) on 5357\n", ++ __FUNCTION__); ++ return 0; ++ } ++ ++ ASSERT(GOODREGS(sii->curwrap)); ++ ai = sii->curwrap; ++ ++ ASSERT((val & ~mask) == 0); ++ ++ if (mask || val) { ++ w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val); ++ W_REG(sii->osh, &ai->ioctrl, w); ++ } ++ ++ return R_REG(sii->osh, &ai->ioctrl); ++} ++ ++uint32 ++ai_core_sflags(si_t *sih, uint32 mask, uint32 val) ++{ ++ si_info_t *sii; ++ aidmp_t *ai; ++ uint32 w; ++ ++ sii = SI_INFO(sih); ++ if (BCM47162_DMP()) { ++ AP6211_ERR("%s: Accessing MIPS DMP register (iostatus) on 47162a0", ++ __FUNCTION__); ++ return 0; ++ } ++ if (BCM5357_DMP()) { ++ AP6211_ERR("%s: Accessing USB20H DMP register (iostatus) on 5357\n", ++ __FUNCTION__); ++ return 0; ++ } ++ ++ ASSERT(GOODREGS(sii->curwrap)); ++ ai = sii->curwrap; ++ ++ ASSERT((val & ~mask) == 0); ++ ASSERT((mask & ~SISF_CORE_BITS) == 0); ++ ++ if (mask || val) { ++ w = ((R_REG(sii->osh, &ai->iostatus) & ~mask) | val); ++ W_REG(sii->osh, &ai->iostatus, w); ++ } ++ ++ return R_REG(sii->osh, &ai->iostatus); ++} +diff --git a/drivers/net/wireless/ap6211/ap6211.h b/drivers/net/wireless/ap6211/ap6211.h +new file mode 100755 +index 0000000..90e7d8d +--- /dev/null ++++ b/drivers/net/wireless/ap6211/ap6211.h +@@ -0,0 +1,22 @@ ++#ifndef __AP6211_H__ ++#define __AP6211_H__ ++ ++#define AP6211_EMERG(...) pr_emerg("[ap6211] "__VA_ARGS__) ++#define AP6211_ALERT(...) pr_alert("[ap6211] "__VA_ARGS__) ++#define AP6211_CRIT(...) pr_crit("[ap6211] "__VA_ARGS__) ++#define AP6211_ERR(...) pr_err("[ap6211] "__VA_ARGS__) ++#define AP6211_WARN(...) pr_warn("[ap6211] "__VA_ARGS__) ++#define AP6211_NOTICE(...) pr_notice("[ap6211] "__VA_ARGS__) ++#define AP6211_INFO(...) pr_info("[ap6211] "__VA_ARGS__) ++#define AP6211_DEBUG(...) pr_debug("[ap6211] "__VA_ARGS__) ++#define AP6211_DUMP(...) pr_debug(__VA_ARGS__) ++#define AP6211_CONT(...) pr_cont(__VA_ARGS__) ++ ++extern int __init sw_rfkill_init(void); ++extern void __exit sw_rfkill_exit(void); ++ ++extern int __init ap6211_gpio_wifi_init(void); ++extern void __exit ap6211_gpio_wifi_exit(void); ++ ++ ++#endif /* __AP6211_H__ */ +diff --git a/drivers/net/wireless/ap6211/ap6211_gpio.h b/drivers/net/wireless/ap6211/ap6211_gpio.h +new file mode 100755 +index 0000000..96a3166 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/ap6211_gpio.h +@@ -0,0 +1,9 @@ ++#ifndef __AP6211_GPIO_H__ ++#define __AP6211_GPIO_H__ ++ ++extern int ap6211_gpio_wifi_get_mod_type(void); ++extern int ap6211_gpio_wifi_gpio_ctrl(char* name, int level); ++extern void ap6211_gpio_wifi_power(int on); ++extern char *ap6211_gpio_wifi_get_name(int module_sel); ++ ++#endif /* __AP6211_GPIO_H__ */ +diff --git a/drivers/net/wireless/ap6211/ap6211_gpio_bt.c b/drivers/net/wireless/ap6211/ap6211_gpio_bt.c +new file mode 100755 +index 0000000..4686615 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/ap6211_gpio_bt.c +@@ -0,0 +1,164 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if (defined CONFIG_MMC) ++#include "ap6211_gpio.h" ++#else ++static __inline int ap6211_gpio_wifi_get_mod_type(void) ++{ ++ AP6211_DEBUG("%s : not implemented!\n", __FUNCTION__ ); ++ return 0; ++} ++static __inline int ap6211_gpio_wifi_gpio_ctrl(char* name, int level) ++{ ++ AP6211_DEBUG("%s : not implemented!\n", __FUNCTION__ ); ++ return -1; ++} ++#endif ++ ++#include ++ ++static const char bt_name[] = "bcm40183"; ++static struct rfkill *sw_rfkill; ++static int bt_used; ++ ++static int rfkill_set_power(void *data, bool blocked) ++{ ++ unsigned int mod_sel = ap6211_gpio_wifi_get_mod_type(); ++ ++ AP6211_DEBUG("rfkill set power %s\n", ( blocked ? "blocked" : "unblocked" )); ++ ++ switch (mod_sel) ++ { ++ case 2: /* bcm40183 */ ++ if (!blocked) { ++ ap6211_gpio_wifi_gpio_ctrl("bcm40183_bt_regon", 1); ++ ap6211_gpio_wifi_gpio_ctrl("bcm40183_bt_rst", 1); ++ } else { ++ ap6211_gpio_wifi_gpio_ctrl("bcm40183_bt_rst", 0); ++ ap6211_gpio_wifi_gpio_ctrl("bcm40183_bt_regon", 0); ++ } ++ AP6211_ERR("Using %s configuration.\n", ap6211_gpio_wifi_get_name(mod_sel) ); ++ break; ++ case 3: /* realtek rtl8723as */ ++ if (!blocked) { ++ ap6211_gpio_wifi_gpio_ctrl("rtk_rtl8723as_bt_dis", 1); ++ } else { ++ ap6211_gpio_wifi_gpio_ctrl("rtk_rtl8723as_bt_dis", 0); ++ } ++ AP6211_ERR("Using %s configuration.\n", ap6211_gpio_wifi_get_name(mod_sel) ); ++ break; ++ case 7: /* ap6211 */ ++ case 8: /* ap6330 */ ++ if (!blocked) { ++ ap6211_gpio_wifi_gpio_ctrl("ap6xxx_bt_regon", 1); ++ } else { ++ ap6211_gpio_wifi_gpio_ctrl("ap6xxx_bt_regon", 0); ++ } ++ AP6211_ERR("Using %s configuration.\n", ap6211_gpio_wifi_get_name(mod_sel) ); ++ break; ++ case 10: /* realtek rtl8723au */ ++ if (!blocked) { ++ ap6211_gpio_wifi_gpio_ctrl("rtl8723au_bt", 1); ++ } else { ++ ap6211_gpio_wifi_gpio_ctrl("rtl8723au_bt", 0); ++ } ++ AP6211_ERR("Using %s configuration.\n", ap6211_gpio_wifi_get_name(mod_sel) ); ++ break; ++ default: ++ AP6211_ERR("no bluetooth module matched.\n" ); ++ } ++ ++ msleep(10); ++ return 0; ++} ++ ++static struct rfkill_ops sw_rfkill_ops = { ++ .set_block = rfkill_set_power, ++}; ++ ++static int sw_rfkill_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ ++ sw_rfkill = rfkill_alloc(bt_name, &pdev->dev, ++ RFKILL_TYPE_BLUETOOTH, &sw_rfkill_ops, NULL); ++ if (unlikely(!sw_rfkill)) { ++ AP6211_DEBUG("Unable to alocate rfkill structure.\n" ); ++ return -ENOMEM; ++ } ++ ++ ret = rfkill_register(sw_rfkill); ++ if (unlikely(ret)) { ++ AP6211_DEBUG("Unable to register rfkill structure.\n" ); ++ rfkill_destroy(sw_rfkill); ++ } ++ AP6211_DEBUG("rfkill structure registered successfully.\n" ); ++ return ret; ++} ++ ++static int sw_rfkill_remove(struct platform_device *pdev) ++{ ++ if (likely(sw_rfkill)) { ++ rfkill_unregister(sw_rfkill); ++ rfkill_destroy(sw_rfkill); ++ AP6211_DEBUG("rfkill structure removed successfully.\n" ); ++ } ++ ++ return 0; ++} ++ ++static struct platform_driver sw_rfkill_driver = { ++ .probe = sw_rfkill_probe, ++ .remove = sw_rfkill_remove, ++ .driver = { ++ .name = "sunxi-rfkill", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static struct platform_device sw_rfkill_dev = { ++ .name = "sunxi-rfkill", ++}; ++ ++int __init sw_rfkill_init(void) ++{ ++ if (SCRIPT_PARSER_OK != script_parser_fetch("bt_para", "bt_used", &bt_used, 1)) { ++ AP6211_DEBUG("parse bt_used failed in script.fex.\n" ); ++ return -1; ++ } ++ ++ if (!bt_used) { ++ AP6211_ERR("bluetooth is disable in script.fex.\n" ); ++ return 0; ++ } ++ ++ platform_device_register(&sw_rfkill_dev); ++ AP6211_ERR("platform device registered successfully.\n" ); ++ return platform_driver_register(&sw_rfkill_driver); ++} ++ ++void __exit sw_rfkill_exit(void) ++{ ++ if (!bt_used) { ++ AP6211_ERR("exit no bt used in configuration\n" ); ++ return ; ++ } ++ ++ platform_device_unregister(&sw_rfkill_dev); ++ platform_driver_unregister(&sw_rfkill_driver); ++} ++ ++/* ++module_init(sw_rfkill_init); ++module_exit(sw_rfkill_exit); ++ ++MODULE_DESCRIPTION("sunxi-rfkill driver"); ++MODULE_AUTHOR("Aaron.magic"); ++MODULE_LICENSE("GPL"); ++*/ ++ +diff --git a/drivers/net/wireless/ap6211/ap6211_gpio_wifi.c b/drivers/net/wireless/ap6211/ap6211_gpio_wifi.c +new file mode 100755 +index 0000000..916749d +--- /dev/null ++++ b/drivers/net/wireless/ap6211/ap6211_gpio_wifi.c +@@ -0,0 +1,463 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static char *wifi_para = "sdio_wifi_pro_para"; /*modify by lemaker team for ap6211*/ ++ ++struct ap6211_gpio_wifi_ops { ++ char* mod_name; ++ int wifi_used; ++ int sdio_id; ++ int usb_id; ++ int module_sel; ++ int (*gpio_ctrl)(char* name, int level); ++ void (*standby)(int in); ++ void (*power)(int mode, int *updown); ++ ++#ifdef CONFIG_PROC_FS ++ struct proc_dir_entry *proc_root; ++ struct proc_dir_entry *proc_power; ++#endif /* CONFIG_PROC_FS */ ++}; ++ ++static unsigned int ap6211_wl_regon = 0; ++static unsigned int ap6211_bt_regon = 0; ++static unsigned int ap6211_wl_vdd_en = 0; /*add by lemaker team for ap6211*/ ++ ++struct ap6211_gpio_wifi_ops ap6211_wifi_select_pm_ops; ++ ++char *ap6211_gpio_wifi_get_name(int module_sel) { ++ char* mod_name[] = { " ", ++ "bcm40181", /* 1 - BCM40181(BCM4330)*/ ++ "bcm40183", /* 2 - BCM40183(BCM4330)*/ ++ "rtl8723as", /* 3 - RTL8723AS(RF-SM02B) */ ++ "rtl8189es", /* 4 - RTL8189ES(SM89E00) */ ++ "rtl8192cu", /* 5 - RTL8192CU*/ ++ "rtl8188eu", /* 6 - RTL8188EU*/ ++ "ap6211", /* 7 - AP6211*/ ++ "ap6330", /* 8 - AP6330*/ ++ "ap6181", /* 9 - AP6181*/ ++ "rtl8723au", /* 10 - RTL8723AU */ ++ }; ++ ++ return(mod_name[module_sel]); ++} ++ ++EXPORT_SYMBOL(ap6211_gpio_wifi_get_name); ++ ++static int ap6211_gpio_ctrl(char* name, int level) ++{ ++ int i = 0; ++ int ret = 0; ++ int gpio = 0; ++ char * gpio_name[3] = {"ap6211_wl_regon", "ap6211_bt_regon", "ap6211_wl_vdd_en"}; /*modify by lemaker team for ap6211*/ ++ ++ for (i = 0; i < 3; i++) { ++ if (strcmp(name, gpio_name[i]) == 0) { ++ switch (i) ++ { ++ case 0: /*ap6211_wl_regon*/ ++ gpio = ap6211_wl_regon; ++ break; ++ case 1: /*ap6211_bt_regon*/ ++ gpio = ap6211_bt_regon; ++ break; ++ case 2: /*add by lemaker team for ap6211*/ ++ gpio = ap6211_wl_vdd_en; ++ break; ++ default: ++ AP6211_ERR("no matched gpio.\n" ); ++ } ++ break; ++ } ++ } ++ ++ ret = gpio_write_one_pin_value(gpio, level, name); ++ ++ if (ret) /*add by lemaker team for ap6211*/ ++ { ++ AP6211_INFO("Failed to set the gpio %s to %d\n", name, level); ++ return -1; ++ }else{ ++ AP6211_INFO("Succeed to set the gpio %s to %d\n", name, level); ++ } ++ ++ return 0; ++} ++ ++static int ap6211_gpio_read(char* name) ++{ ++ int i = 0; ++ int gpio = 0; ++ int val = 0; ++ char * gpio_name[3] = {"ap6211_wl_regon", "ap6211_bt_regon", "ap6211_wl_vdd_en"}; /*modify by lemaker team for ap6211*/ ++ ++ for (i = 0; i < 3; i++) { ++ if (strcmp(name, gpio_name[i]) == 0) { ++ switch (i) ++ { ++ case 0: /*ap6211_wl_regon*/ ++ gpio = ap6211_wl_regon; ++ break; ++ case 1: /*ap6211_bt_regon*/ ++ gpio = ap6211_bt_regon; ++ break; ++ case 2: /*add by lemaker team for ap6211*/ ++ gpio = ap6211_wl_vdd_en; ++ break; ++ default: ++ AP6211_ERR("no matched gpio.\n" ); ++ } ++ break; ++ } ++ } ++ ++ val = gpio_read_one_pin_value(gpio, name); ++ ++ return val; ++} ++ ++ ++void ap6211_power(int mode, int *updown) ++{ ++ if (mode) { ++ if (*updown) { ++ ap6211_gpio_ctrl("ap6211_wl_regon", 1); ++ mdelay(100); ++ } else { ++ ap6211_gpio_ctrl("ap6211_wl_regon", 0); ++ mdelay(100); ++ } ++ AP6211_DEBUG("sdio wifi power state: %s\n", *updown ? "on" : "off"); ++ } else { ++ *updown = ap6211_gpio_read("ap6211_wl_regon"); ++ } ++ ++ return; ++} ++/* remove by lemaker team for ap6211 ++static void ap6211_cfg_gpio_32k_clkout(int gpio_index) ++{ ++ int ret; ++ struct clk *clk_32k, *parent; ++ ++ parent = clk_get(NULL, CLK_SYS_LOSC); ++ clk_32k = clk_get(NULL, CLK_MOD_OUTA); ++ ret = clk_set_parent(clk_32k, parent); ++ ++ if(ret){ ++ AP6211_ERR("32k clk_set_parent fail.\n" ); ++ return; ++ } ++ ++ ret = clk_set_rate(clk_32k, 32768); ++ if(ret){ ++ AP6211_ERR("32k clk_set_rate fail.\n" ); ++ return; ++ } ++ ++ clk_enable(clk_32k); ++} ++*/ ++void ap6211_gpio_init(void) ++{ ++ struct ap6211_gpio_wifi_ops *ops = &ap6211_wifi_select_pm_ops; ++ /*int ap6211_lpo = 0;*/ ++ ++/* CT expected ap6211_lpo as a GPIO */ ++/* remove by lemaker team for ap6211 ++ ap6211_lpo = gpio_request_ex(wifi_para, "ap6xxx_lpo"); ++ if (!ap6211_lpo) { ++ AP6211_ERR("request lpo gpio failed.\n" ); ++ return; ++ } ++ ++ if(ap6211_lpo) { ++ AP6211_DEBUG("config 32k clock.\n" ); ++ ap6211_cfg_gpio_32k_clkout(ap6211_lpo); ++ } ++*/ ++ ap6211_wl_regon = gpio_request_ex(wifi_para, "ap6xxx_wl_regon"); ++ if (!ap6211_wl_regon) { ++ AP6211_ERR("request wl_regon gpio failed.\n" ); ++ return; ++ } ++ /* The comment must remove when we use the Bluetooth ++ ap6211_bt_regon = gpio_request_ex(wifi_para, "ap6xxx_bt_regon"); ++ if (!ap6211_bt_regon) { ++ AP6211_ERR("request ap6211_bt_regon gpio failed.\n" ); ++ return; ++ } ++ */ ++ ++ /*add by lemaker team for ap6211*/ ++ ap6211_wl_vdd_en = gpio_request_ex(wifi_para, "ap6xxx_wl_vdd_en"); ++ if (!ap6211_wl_vdd_en) { ++ AP6211_ERR("request wl_vdd_en gpio failed.\n" ); ++ return; ++ } ++ ops->gpio_ctrl = ap6211_gpio_ctrl; ++ ops->power = ap6211_power; ++ ++ ap6211_gpio_ctrl("ap6211_wl_vdd_en", 0); /*enable the vdd*/ ++ ++} ++ ++int ap6211_gpio_wifi_get_mod_type(void) ++{ ++ struct ap6211_gpio_wifi_ops *ops = &ap6211_wifi_select_pm_ops; ++ if (ops->wifi_used) ++ return ops->module_sel; ++ else { ++ AP6211_ERR("No wifi type selected, please check your config.\n" ); ++ return 0; ++ } ++} ++EXPORT_SYMBOL(ap6211_gpio_wifi_get_mod_type); ++ ++int ap6211_gpio_wifi_gpio_ctrl(char* name, int level) ++{ ++ struct ap6211_gpio_wifi_ops *ops = &ap6211_wifi_select_pm_ops; ++ if (ops->wifi_used && ops->gpio_ctrl) ++ return ops->gpio_ctrl(name, level); ++ else { ++ AP6211_ERR("No wifi type selected, please check your config.\n" ); ++ return -1; ++ } ++} ++EXPORT_SYMBOL(ap6211_gpio_wifi_gpio_ctrl); ++ ++void ap6211_gpio_wifi_power(int on) ++{ ++ struct ap6211_gpio_wifi_ops *ops = &ap6211_wifi_select_pm_ops; ++ int power = on; ++ ++ if (ops->wifi_used && ops->power) ++ return ops->power(1, &power); ++ else { ++ AP6211_ERR("No wifi type selected, please check your config.\n" ); ++ return; ++ } ++} ++EXPORT_SYMBOL(ap6211_gpio_wifi_power); ++ ++#ifdef CONFIG_PROC_FS ++static int ap6211_gpio_wifi_power_stat(char *page, char **start, off_t off, int count, int *eof, void *data) ++{ ++ struct ap6211_gpio_wifi_ops *ops = (struct ap6211_gpio_wifi_ops *)data; ++ char *p = page; ++ int power = 0; ++ ++ if (ops->power) ++ ops->power(0, &power); ++ ++ p += sprintf(p, "%s : power state %s\n", ops->mod_name, power ? "on" : "off"); ++ return p - page; ++} ++ ++static int ap6211_gpio_wifi_power_ctrl(struct file *file, const char __user *buffer, unsigned long count, void *data) ++{ ++ struct ap6211_gpio_wifi_ops *ops = (struct ap6211_gpio_wifi_ops *)data; ++ int power = simple_strtoul(buffer, NULL, 10); ++ ++ power = power ? 1 : 0; ++ if (ops->power) ++ ops->power(1, &power); ++ else ++ AP6211_ERR("No power control for %s\n", ops->mod_name); ++ return sizeof(power); ++} ++ ++static inline void awwifi_procfs_attach(void) ++{ ++ char proc_rootname[] = "driver/ap6211_gpio_wifi"; ++ char proc_powername[] = "power"; ++ ++ struct ap6211_gpio_wifi_ops *ops = &ap6211_wifi_select_pm_ops; ++ ++ ops->proc_root = proc_mkdir(proc_rootname, NULL); ++ if (IS_ERR(ops->proc_root)) ++ { ++ AP6211_ERR("failed to create procfs \"%s\".\n", proc_rootname ); ++ } ++ ++ ops->proc_power = create_proc_entry(proc_powername, 0644, ops->proc_root); ++ if (IS_ERR(ops->proc_power)) ++ { ++ AP6211_ERR("failed to create procfs \"%s\".\n", proc_powername); ++ } ++ ops->proc_power->data = ops; ++ ops->proc_power->read_proc = ap6211_gpio_wifi_power_stat; ++ ops->proc_power->write_proc = ap6211_gpio_wifi_power_ctrl; ++} ++ ++static inline void awwifi_procfs_remove(void) ++{ ++ struct ap6211_gpio_wifi_ops *ops = &ap6211_wifi_select_pm_ops; ++ char proc_rootname[] = "driver/ap6211_gpio_wifi"; ++ ++ remove_proc_entry("power", ops->proc_root); ++ remove_proc_entry(proc_rootname, NULL); ++} ++#else ++static inline void awwifi_procfs_attach(void) {} ++static inline void awwifi_procfs_remove(void) {} ++#endif ++ ++ ++ ++static int ap6211_gpio_wifi_get_res(void) ++{ ++ struct ap6211_gpio_wifi_ops *ops = &ap6211_wifi_select_pm_ops; ++ ++ /*add by lemaker team for AP6211*/ ++ if (SCRIPT_PARSER_OK != script_parser_fetch(wifi_para, "sdio_wifi_pro_used", &ops->wifi_used, 1)) { ++ AP6211_ERR("parse sdio_wifi_pro_used failed in script.fex.\n" ); ++ return -1; ++ } ++ if (!ops->wifi_used) { ++ AP6211_ERR("wifi pm disable in script.fex.\n" ); ++ return -1; ++ } ++ ++ /*add by lemaker team for AP6211*/ ++ if (SCRIPT_PARSER_OK != script_parser_fetch(wifi_para, "sdio_wifi_pro_sdc_id", &ops->sdio_id, 1)) { ++ AP6211_ERR("parse sdio_wifi_pro_sdc_id in script.fex failed.\n" ); ++ return -1; ++ } ++/* remove by lemaker team for AP6211 ++ if (SCRIPT_PARSER_OK != script_parser_fetch(wifi_para, "wifi_usbc_id", &ops->usb_id, 1)) { ++ AP6211_ERR("parse wifi_sdc_id in script.fex failed.\n" ); ++ return -1; ++ } ++*/ ++ /*add by lemaker team for AP6211*/ ++ if (SCRIPT_PARSER_OK != script_parser_fetch(wifi_para, "sdio_wifi_pro_mod_sel", &ops->module_sel, 1)) { ++ AP6211_ERR("parse sdio_wifi_pro_mod_sel in script.fex failed.\n" ); ++ return -1; ++ } ++ ++ ops->mod_name = ap6211_gpio_wifi_get_name(ops->module_sel); ++ ++ AP6211_ERR("select wifi %s\n", ops->mod_name); ++ ++ return 0; ++} ++ ++static int __devinit ap6211_gpio_wifi_probe(struct platform_device *pdev) ++{ ++ struct ap6211_gpio_wifi_ops *ops = &ap6211_wifi_select_pm_ops; ++ ++ switch (ops->module_sel) { ++ case 1: /* BCM40181 */ ++ case 2: /* BCM40183 */ ++ case 3: /* RTL8723AS */ ++ case 4: /* RTL8189ES */ ++ case 5: /* RTL8192CU */ ++ case 6: /* RTL8188EU */ ++ AP6211_ERR("Unsupported device.\n"); ++ break; ++ case 7: /* AP6211 */ ++ case 8: /* AP6330 */ ++ case 9: /* AP6181 */ ++ AP6211_ERR("Initializing %s.\n", ops->mod_name); ++ ap6211_gpio_init(); ++ break; ++ case 10: /* RTL8723AU */ ++ AP6211_ERR("Unsupported device.\n"); ++ break; ++ default: ++ AP6211_ERR("Unsupported device.\n"); ++ } ++ ++ awwifi_procfs_attach(); ++ AP6211_DEBUG("wifi gpio attached.\n" ); ++ return 0; ++} ++ ++static int __devexit ap6211_gpio_wifi_remove(struct platform_device *pdev) ++{ ++ awwifi_procfs_remove(); ++ AP6211_DEBUG("wifi gpio released.\n" ); ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int ap6211_gpio_wifi_suspend(struct device *dev) ++{ ++ struct ap6211_gpio_wifi_ops *ops = &ap6211_wifi_select_pm_ops; ++ ++ if (ops->standby) ++ ops->standby(1); ++ return 0; ++} ++ ++static int ap6211_gpio_wifi_resume(struct device *dev) ++{ ++ struct ap6211_gpio_wifi_ops *ops = &ap6211_wifi_select_pm_ops; ++ ++ if (ops->standby) ++ ops->standby(0); ++ return 0; ++} ++ ++static struct dev_pm_ops wifi_dev_pm_ops = { ++ .suspend = ap6211_gpio_wifi_suspend, ++ .resume = ap6211_gpio_wifi_resume, ++}; ++#endif ++ ++static struct platform_device ap6211_gpio_wifi_dev = { ++ .name = "ap6211_gpio_wifi", ++}; ++ ++static struct platform_driver ap6211_gpio_wifi_driver = { ++ .driver.name = "ap6211_gpio_wifi", ++ .driver.owner = THIS_MODULE, ++#ifdef CONFIG_PM ++ .driver.pm = &wifi_dev_pm_ops, ++#endif ++ .probe = ap6211_gpio_wifi_probe, ++ .remove = __devexit_p(ap6211_gpio_wifi_remove), ++}; ++ ++int __init ap6211_gpio_wifi_init(void) ++{ ++ struct ap6211_gpio_wifi_ops *ops = &ap6211_wifi_select_pm_ops; ++ ++ memset(ops, 0, sizeof(struct ap6211_gpio_wifi_ops)); ++ ap6211_gpio_wifi_get_res(); ++ if (!ops->wifi_used) ++ return 0; ++ ++ platform_device_register(&ap6211_gpio_wifi_dev); ++ return platform_driver_register(&ap6211_gpio_wifi_driver); ++} ++ ++void __exit ap6211_gpio_wifi_exit(void) ++{ ++ struct ap6211_gpio_wifi_ops *ops = &ap6211_wifi_select_pm_ops; ++ if (!ops->wifi_used) ++ return; ++ ++ platform_driver_unregister(&ap6211_gpio_wifi_driver); ++ memset(ops, 0, sizeof(struct ap6211_gpio_wifi_ops)); ++} ++ ++/* ++module_init(ap6211_gpio_wifi_init); ++module_exit(ap6211_gpio_wifi_exit); ++ ++MODULE_LICENSE("GPL"); ++*/ +diff --git a/drivers/net/wireless/ap6211/bcmevent.c b/drivers/net/wireless/ap6211/bcmevent.c +new file mode 100755 +index 0000000..16e2fca +--- /dev/null ++++ b/drivers/net/wireless/ap6211/bcmevent.c +@@ -0,0 +1,152 @@ ++/* ++ * bcmevent read-only data shared by kernel or app layers ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * $Id: bcmevent.c 370587 2012-11-22 09:32:38Z $ ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if WLC_E_LAST != 107 ++#error "You need to add an entry to bcmevent_names[] for the new event" ++#endif ++ ++const bcmevent_name_t bcmevent_names[] = { ++ { WLC_E_SET_SSID, "SET_SSID" }, ++ { WLC_E_JOIN, "JOIN" }, ++ { WLC_E_START, "START" }, ++ { WLC_E_AUTH, "AUTH" }, ++ { WLC_E_AUTH_IND, "AUTH_IND" }, ++ { WLC_E_DEAUTH, "DEAUTH" }, ++ { WLC_E_DEAUTH_IND, "DEAUTH_IND" }, ++ { WLC_E_ASSOC, "ASSOC" }, ++ { WLC_E_ASSOC_IND, "ASSOC_IND" }, ++ { WLC_E_REASSOC, "REASSOC" }, ++ { WLC_E_REASSOC_IND, "REASSOC_IND" }, ++ { WLC_E_DISASSOC, "DISASSOC" }, ++ { WLC_E_DISASSOC_IND, "DISASSOC_IND" }, ++ { WLC_E_QUIET_START, "START_QUIET" }, ++ { WLC_E_QUIET_END, "END_QUIET" }, ++ { WLC_E_BEACON_RX, "BEACON_RX" }, ++ { WLC_E_LINK, "LINK" }, ++ { WLC_E_MIC_ERROR, "MIC_ERROR" }, ++ { WLC_E_NDIS_LINK, "NDIS_LINK" }, ++ { WLC_E_ROAM, "ROAM" }, ++ { WLC_E_TXFAIL, "TXFAIL" }, ++ { WLC_E_PMKID_CACHE, "PMKID_CACHE" }, ++ { WLC_E_RETROGRADE_TSF, "RETROGRADE_TSF" }, ++ { WLC_E_PRUNE, "PRUNE" }, ++ { WLC_E_AUTOAUTH, "AUTOAUTH" }, ++ { WLC_E_EAPOL_MSG, "EAPOL_MSG" }, ++ { WLC_E_SCAN_COMPLETE, "SCAN_COMPLETE" }, ++ { WLC_E_ADDTS_IND, "ADDTS_IND" }, ++ { WLC_E_DELTS_IND, "DELTS_IND" }, ++ { WLC_E_BCNSENT_IND, "BCNSENT_IND" }, ++ { WLC_E_BCNRX_MSG, "BCNRX_MSG" }, ++ { WLC_E_BCNLOST_MSG, "BCNLOST_IND" }, ++ { WLC_E_ROAM_PREP, "ROAM_PREP" }, ++ { WLC_E_PFN_NET_FOUND, "PFNFOUND_IND" }, ++ { WLC_E_PFN_NET_LOST, "PFNLOST_IND" }, ++#if defined(IBSS_PEER_DISCOVERY_EVENT) ++ { WLC_E_IBSS_ASSOC, "IBSS_ASSOC" }, ++#endif /* defined(IBSS_PEER_DISCOVERY_EVENT) */ ++ { WLC_E_RADIO, "RADIO" }, ++ { WLC_E_PSM_WATCHDOG, "PSM_WATCHDOG" }, ++ { WLC_E_PROBREQ_MSG, "PROBE_REQ_MSG" }, ++ { WLC_E_SCAN_CONFIRM_IND, "SCAN_CONFIRM_IND" }, ++ { WLC_E_PSK_SUP, "PSK_SUP" }, ++ { WLC_E_COUNTRY_CODE_CHANGED, "CNTRYCODE_IND" }, ++ { WLC_E_EXCEEDED_MEDIUM_TIME, "EXCEEDED_MEDIUM_TIME" }, ++ { WLC_E_ICV_ERROR, "ICV_ERROR" }, ++ { WLC_E_UNICAST_DECODE_ERROR, "UNICAST_DECODE_ERROR" }, ++ { WLC_E_MULTICAST_DECODE_ERROR, "MULTICAST_DECODE_ERROR" }, ++ { WLC_E_TRACE, "TRACE" }, ++#ifdef WLBTAMP ++ { WLC_E_BTA_HCI_EVENT, "BTA_HCI_EVENT" }, ++#endif ++ { WLC_E_IF, "IF" }, ++#ifdef WLP2P ++ { WLC_E_P2P_DISC_LISTEN_COMPLETE, "WLC_E_P2P_DISC_LISTEN_COMPLETE" }, ++#endif ++ { WLC_E_RSSI, "RSSI" }, ++ { WLC_E_PFN_SCAN_COMPLETE, "SCAN_COMPLETE" }, ++ { WLC_E_EXTLOG_MSG, "EXTERNAL LOG MESSAGE" }, ++#ifdef WIFI_ACT_FRAME ++ { WLC_E_ACTION_FRAME, "ACTION_FRAME" }, ++ { WLC_E_ACTION_FRAME_RX, "ACTION_FRAME_RX" }, ++ { WLC_E_ACTION_FRAME_COMPLETE, "ACTION_FRAME_COMPLETE" }, ++#endif ++#ifdef BCMWAPI_WAI ++ { WLC_E_WAI_STA_EVENT, "WAI_STA_EVENT" }, ++ { WLC_E_WAI_MSG, "WAI_MSG" }, ++#endif /* BCMWAPI_WAI */ ++#if 0 && (NDISVER >= 0x0620) ++ { WLC_E_PRE_ASSOC_IND, "ASSOC_RECV" }, ++ { WLC_E_PRE_REASSOC_IND, "REASSOC_RECV" }, ++ { WLC_E_CHANNEL_ADOPTED, "CHANNEL_ADOPTED" }, ++ { WLC_E_AP_STARTED, "AP_STARTED" }, ++ { WLC_E_DFS_AP_STOP, "DFS_AP_STOP" }, ++ { WLC_E_DFS_AP_RESUME, "DFS_AP_RESUME" }, ++ { WLC_E_ASSOC_IND_NDIS, "ASSOC_IND_NDIS"}, ++ { WLC_E_REASSOC_IND_NDIS, "REASSOC_IND_NDIS"}, ++ { WLC_E_ACTION_FRAME_RX_NDIS, "WLC_E_ACTION_FRAME_RX_NDIS" }, ++ { WLC_E_AUTH_REQ, "WLC_E_AUTH_REQ" }, ++#endif ++ { WLC_E_ESCAN_RESULT, "WLC_E_ESCAN_RESULT" }, ++ { WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE, "WLC_E_AF_OFF_CHAN_COMPLETE" }, ++#ifdef WLP2P ++ { WLC_E_PROBRESP_MSG, "PROBE_RESP_MSG" }, ++ { WLC_E_P2P_PROBREQ_MSG, "P2P PROBE_REQ_MSG" }, ++#endif ++#ifdef PROP_TXSTATUS ++ { WLC_E_FIFO_CREDIT_MAP, "FIFO_CREDIT_MAP" }, ++#endif ++ { WLC_E_WAKE_EVENT, "WAKE_EVENT" }, ++ { WLC_E_DCS_REQUEST, "DCS_REQUEST" }, ++ { WLC_E_RM_COMPLETE, "RM_COMPLETE" }, ++#ifdef WLMEDIA_HTSF ++ { WLC_E_HTSFSYNC, "HTSF_SYNC_EVENT" }, ++#endif ++ { WLC_E_OVERLAY_REQ, "OVERLAY_REQ_EVENT" }, ++ { WLC_E_CSA_COMPLETE_IND, "WLC_E_CSA_COMPLETE_IND"}, ++ { WLC_E_EXCESS_PM_WAKE_EVENT, "EXCESS_PM_WAKE_EVENT" }, ++ { WLC_E_PFN_SCAN_NONE, "PFN_SCAN_NONE" }, ++ { WLC_E_PFN_SCAN_ALLGONE, "PFN_SCAN_ALLGONE" }, ++#ifdef SOFTAP ++ { WLC_E_GTK_PLUMBED, "GTK_PLUMBED" }, ++#endif ++ { WLC_E_ASSOC_REQ_IE, "ASSOC_REQ_IE" }, ++ { WLC_E_ASSOC_RESP_IE, "ASSOC_RESP_IE" }, ++ { WLC_E_ACTION_FRAME_RX_NDIS, "WLC_E_ACTION_FRAME_RX_NDIS" }, ++#ifdef WLTDLS ++ { WLC_E_TDLS_PEER_EVENT, "TDLS_PEER_EVENT" }, ++#endif /* WLTDLS */ ++ { WLC_E_SERVICE_FOUND, "SERVICE_FOUND" }, ++ { WLC_E_P2PO_ADD_DEVICE, "P2PO_DEV_FOUND" }, ++ { WLC_E_P2PO_DEL_DEVICE, "P2PO_DEV_LOST" }, ++}; ++ ++const int bcmevent_names_size = ARRAYSIZE(bcmevent_names); +diff --git a/drivers/net/wireless/ap6211/bcmsdh.c b/drivers/net/wireless/ap6211/bcmsdh.c +new file mode 100755 +index 0000000..ca59ff8 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/bcmsdh.c +@@ -0,0 +1,778 @@ ++/* ++ * BCMSDH interface glue ++ * implement bcmsdh API for SDIOH driver ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmsdh.c 373330 2012-12-07 04:46:17Z $ ++ */ ++ ++/** ++ * @file bcmsdh.c ++ */ ++ ++/* ****************** BCMSDH Interface Functions *************************** */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include /* BRCM API for SDIO clients (such as wl, dhd) */ ++#include /* common SDIO/controller interface */ ++#include /* SDIO device core hardware definitions. */ ++ ++#include /* SDIO Device and Protocol Specs */ ++ ++#include ++ ++#define SDIOH_API_ACCESS_RETRY_LIMIT 2 ++const uint bcmsdh_msglevel = BCMSDH_ERROR_VAL; ++ ++/** ++ * BCMSDH API context ++ */ ++struct bcmsdh_info ++{ ++ bool init_success; /* underlying driver successfully attached */ ++ void *sdioh; /* handler for sdioh */ ++ uint32 vendevid; /* Target Vendor and Device ID on SD bus */ ++ osl_t *osh; ++ bool regfail; /* Save status of last reg_read/reg_write call */ ++ uint32 sbwad; /* Save backplane window address */ ++}; ++/* local copy of bcm sd handler */ ++bcmsdh_info_t * l_bcmsdh = NULL; ++ ++#if defined(OOB_INTR_ONLY) && defined(HW_OOB) ++extern int ++sdioh_enable_hw_oob_intr(void *sdioh, bool enable); ++ ++void ++bcmsdh_enable_hw_oob_intr(bcmsdh_info_t *sdh, bool enable) ++{ ++ sdioh_enable_hw_oob_intr(sdh->sdioh, enable); ++} ++#endif ++ ++#if defined(HW_OOB) ++#include ++void ++bcmsdh_config_hw_oob_intr(bcmsdh_info_t *sdh, uint chip) ++{ ++ uint32 gpiocontrol, addr; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ if (CHIPID(chip) == BCM43362_CHIP_ID) { ++ addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, gpiocontrol); ++ gpiocontrol = bcmsdh_reg_read(sdh, addr, 4); ++ gpiocontrol |= 0x2; ++ bcmsdh_reg_write(sdh, addr, 4, gpiocontrol); ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, 0x10005, 0xf, NULL); ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, 0x10006, 0x0, NULL); ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, 0x10007, 0x2, NULL); ++ } ++} ++#endif ++ ++/* Attach BCMSDH layer to SDIO Host Controller Driver ++ * ++ * @param osh OSL Handle. ++ * @param cfghdl Configuration Handle. ++ * @param regsva Virtual address of controller registers. ++ * @param irq Interrupt number of SDIO controller. ++ * ++ * @return bcmsdh_info_t Handle to BCMSDH context. ++ */ ++bcmsdh_info_t * ++bcmsdh_attach(osl_t *osh, void *cfghdl, void **regsva, uint irq) ++{ ++ bcmsdh_info_t *bcmsdh; ++ ++ if ((bcmsdh = (bcmsdh_info_t *)MALLOC(osh, sizeof(bcmsdh_info_t))) == NULL) { ++ BCMSDH_ERROR(("bcmsdh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh))); ++ return NULL; ++ } ++ bzero((char *)bcmsdh, sizeof(bcmsdh_info_t)); ++ ++ /* save the handler locally */ ++ l_bcmsdh = bcmsdh; ++ ++ if (!(bcmsdh->sdioh = sdioh_attach(osh, cfghdl, irq))) { ++ bcmsdh_detach(osh, bcmsdh); ++ return NULL; ++ } ++ ++ bcmsdh->osh = osh; ++ bcmsdh->init_success = TRUE; ++ ++ *regsva = (uint32 *)SI_ENUM_BASE; ++ ++ /* Report the BAR, to fix if needed */ ++ bcmsdh->sbwad = SI_ENUM_BASE; ++ return bcmsdh; ++} ++ ++int ++bcmsdh_detach(osl_t *osh, void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ ++ if (bcmsdh != NULL) { ++ if (bcmsdh->sdioh) { ++ sdioh_detach(osh, bcmsdh->sdioh); ++ bcmsdh->sdioh = NULL; ++ } ++ MFREE(osh, bcmsdh, sizeof(bcmsdh_info_t)); ++ } ++ ++ l_bcmsdh = NULL; ++ return 0; ++} ++ ++int ++bcmsdh_iovar_op(void *sdh, const char *name, ++ void *params, int plen, void *arg, int len, bool set) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ return sdioh_iovar_op(bcmsdh->sdioh, name, params, plen, arg, len, set); ++} ++ ++bool ++bcmsdh_intr_query(void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ bool on; ++ ++ ASSERT(bcmsdh); ++ status = sdioh_interrupt_query(bcmsdh->sdioh, &on); ++ if (SDIOH_API_SUCCESS(status)) ++ return FALSE; ++ else ++ return on; ++} ++ ++int ++bcmsdh_intr_enable(void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ ASSERT(bcmsdh); ++ ++ status = sdioh_interrupt_set(bcmsdh->sdioh, TRUE); ++ return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); ++} ++ ++int ++bcmsdh_intr_disable(void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ ASSERT(bcmsdh); ++ ++ status = sdioh_interrupt_set(bcmsdh->sdioh, FALSE); ++ return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); ++} ++ ++int ++bcmsdh_intr_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ ASSERT(bcmsdh); ++ ++ status = sdioh_interrupt_register(bcmsdh->sdioh, fn, argh); ++ return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); ++} ++ ++int ++bcmsdh_intr_dereg(void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ ASSERT(bcmsdh); ++ ++ status = sdioh_interrupt_deregister(bcmsdh->sdioh); ++ return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); ++} ++ ++#if defined(DHD_DEBUG) ++bool ++bcmsdh_intr_pending(void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ ++ ASSERT(sdh); ++ return sdioh_interrupt_pending(bcmsdh->sdioh); ++} ++#endif ++ ++ ++int ++bcmsdh_devremove_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh) ++{ ++ ASSERT(sdh); ++ ++ /* don't support yet */ ++ return BCME_UNSUPPORTED; ++} ++ ++/** ++ * Read from SDIO Configuration Space ++ * @param sdh SDIO Host context. ++ * @param func_num Function number to read from. ++ * @param addr Address to read from. ++ * @param err Error return. ++ * @return value read from SDIO configuration space. ++ */ ++uint8 ++bcmsdh_cfg_read(void *sdh, uint fnc_num, uint32 addr, int *err) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++#ifdef SDIOH_API_ACCESS_RETRY_LIMIT ++ int32 retry = 0; ++#endif ++ uint8 data = 0; ++ ++ if (!bcmsdh) ++ bcmsdh = l_bcmsdh; ++ ++ ASSERT(bcmsdh->init_success); ++ ++#ifdef SDIOH_API_ACCESS_RETRY_LIMIT ++ do { ++ if (retry) /* wait for 1 ms till bus get settled down */ ++ OSL_DELAY(1000); ++#endif ++ status = sdioh_cfg_read(bcmsdh->sdioh, fnc_num, addr, (uint8 *)&data); ++#ifdef SDIOH_API_ACCESS_RETRY_LIMIT ++ } while (!SDIOH_API_SUCCESS(status) && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT)); ++#endif ++ if (err) ++ *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR); ++ ++ BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint8data = 0x%x\n", __FUNCTION__, ++ fnc_num, addr, data)); ++ ++ return data; ++} ++ ++void ++bcmsdh_cfg_write(void *sdh, uint fnc_num, uint32 addr, uint8 data, int *err) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++#ifdef SDIOH_API_ACCESS_RETRY_LIMIT ++ int32 retry = 0; ++#endif ++ ++ if (!bcmsdh) ++ bcmsdh = l_bcmsdh; ++ ++ ASSERT(bcmsdh->init_success); ++ ++#ifdef SDIOH_API_ACCESS_RETRY_LIMIT ++ do { ++ if (retry) /* wait for 1 ms till bus get settled down */ ++ OSL_DELAY(1000); ++#endif ++ status = sdioh_cfg_write(bcmsdh->sdioh, fnc_num, addr, (uint8 *)&data); ++#ifdef SDIOH_API_ACCESS_RETRY_LIMIT ++ } while (!SDIOH_API_SUCCESS(status) && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT)); ++#endif ++ if (err) ++ *err = SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR; ++ ++ BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint8data = 0x%x\n", __FUNCTION__, ++ fnc_num, addr, data)); ++} ++ ++uint32 ++bcmsdh_cfg_read_word(void *sdh, uint fnc_num, uint32 addr, int *err) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ uint32 data = 0; ++ ++ if (!bcmsdh) ++ bcmsdh = l_bcmsdh; ++ ++ ASSERT(bcmsdh->init_success); ++ ++ status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_READ, fnc_num, ++ addr, &data, 4); ++ ++ if (err) ++ *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR); ++ ++ BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint32data = 0x%x\n", __FUNCTION__, ++ fnc_num, addr, data)); ++ ++ return data; ++} ++ ++void ++bcmsdh_cfg_write_word(void *sdh, uint fnc_num, uint32 addr, uint32 data, int *err) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ ++ if (!bcmsdh) ++ bcmsdh = l_bcmsdh; ++ ++ ASSERT(bcmsdh->init_success); ++ ++ status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_WRITE, fnc_num, ++ addr, &data, 4); ++ ++ if (err) ++ *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR); ++ ++ BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint32data = 0x%x\n", __FUNCTION__, fnc_num, ++ addr, data)); ++} ++ ++ ++int ++bcmsdh_cis_read(void *sdh, uint func, uint8 *cis, uint length) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ ++ uint8 *tmp_buf, *tmp_ptr; ++ uint8 *ptr; ++ bool ascii = func & ~0xf; ++ func &= 0x7; ++ ++ if (!bcmsdh) ++ bcmsdh = l_bcmsdh; ++ ++ ASSERT(bcmsdh->init_success); ++ ASSERT(cis); ++ ASSERT(length <= SBSDIO_CIS_SIZE_LIMIT); ++ ++ status = sdioh_cis_read(bcmsdh->sdioh, func, cis, length); ++ ++ if (ascii) { ++ /* Move binary bits to tmp and format them into the provided buffer. */ ++ if ((tmp_buf = (uint8 *)MALLOC(bcmsdh->osh, length)) == NULL) { ++ BCMSDH_ERROR(("%s: out of memory\n", __FUNCTION__)); ++ return BCME_NOMEM; ++ } ++ bcopy(cis, tmp_buf, length); ++ for (tmp_ptr = tmp_buf, ptr = cis; ptr < (cis + length - 4); tmp_ptr++) { ++ ptr += snprintf((char*)ptr, (cis + length - ptr - 4), ++ "%.2x ", *tmp_ptr & 0xff); ++ if ((((tmp_ptr - tmp_buf) + 1) & 0xf) == 0) ++ ptr += snprintf((char *)ptr, (cis + length - ptr -4), "\n"); ++ } ++ MFREE(bcmsdh->osh, tmp_buf, length); ++ } ++ ++ return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); ++} ++ ++ ++int ++bcmsdhsdio_set_sbaddr_window(void *sdh, uint32 address, bool force_set) ++{ ++ int err = 0; ++ uint bar0 = address & ~SBSDIO_SB_OFT_ADDR_MASK; ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ ++ if (bar0 != bcmsdh->sbwad || force_set) { ++ bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, ++ (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err); ++ if (!err) ++ bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID, ++ (address >> 16) & SBSDIO_SBADDRMID_MASK, &err); ++ if (!err) ++ bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH, ++ (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err); ++ ++ if (!err) ++ bcmsdh->sbwad = bar0; ++ else ++ /* invalidate cached window var */ ++ bcmsdh->sbwad = 0; ++ ++ } ++ ++ return err; ++} ++ ++uint32 ++bcmsdh_reg_read(void *sdh, uint32 addr, uint size) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ uint32 word = 0; ++ ++ BCMSDH_INFO(("%s:fun = 1, addr = 0x%x, ", __FUNCTION__, addr)); ++ ++ if (!bcmsdh) ++ bcmsdh = l_bcmsdh; ++ ++ ASSERT(bcmsdh->init_success); ++ ++ if (bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE)) ++ return 0xFFFFFFFF; ++ ++ addr &= SBSDIO_SB_OFT_ADDR_MASK; ++ if (size == 4) ++ addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; ++ ++ status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, ++ SDIOH_READ, SDIO_FUNC_1, addr, &word, size); ++ ++ bcmsdh->regfail = !(SDIOH_API_SUCCESS(status)); ++ ++ BCMSDH_INFO(("uint32data = 0x%x\n", word)); ++ ++ /* if ok, return appropriately masked word */ ++ if (SDIOH_API_SUCCESS(status)) { ++ switch (size) { ++ case sizeof(uint8): ++ return (word & 0xff); ++ case sizeof(uint16): ++ return (word & 0xffff); ++ case sizeof(uint32): ++ return word; ++ default: ++ bcmsdh->regfail = TRUE; ++ ++ } ++ } ++ ++ /* otherwise, bad sdio access or invalid size */ ++ BCMSDH_ERROR(("%s: error reading addr 0x%04x size %d\n", __FUNCTION__, addr, size)); ++ return 0xFFFFFFFF; ++} ++ ++uint32 ++bcmsdh_reg_write(void *sdh, uint32 addr, uint size, uint32 data) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ int err = 0; ++ ++ BCMSDH_INFO(("%s:fun = 1, addr = 0x%x, uint%ddata = 0x%x\n", ++ __FUNCTION__, addr, size*8, data)); ++ ++ if (!bcmsdh) ++ bcmsdh = l_bcmsdh; ++ ++ ASSERT(bcmsdh->init_success); ++ ++ if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE))) ++ return err; ++ ++ addr &= SBSDIO_SB_OFT_ADDR_MASK; ++ if (size == 4) ++ addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; ++ status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_WRITE, SDIO_FUNC_1, ++ addr, &data, size); ++ bcmsdh->regfail = !(SDIOH_API_SUCCESS(status)); ++ ++ if (SDIOH_API_SUCCESS(status)) ++ return 0; ++ ++ BCMSDH_ERROR(("%s: error writing 0x%08x to addr 0x%04x size %d\n", ++ __FUNCTION__, data, addr, size)); ++ return 0xFFFFFFFF; ++} ++ ++bool ++bcmsdh_regfail(void *sdh) ++{ ++ return ((bcmsdh_info_t *)sdh)->regfail; ++} ++ ++int ++bcmsdh_recv_buf(void *sdh, uint32 addr, uint fn, uint flags, ++ uint8 *buf, uint nbytes, void *pkt, ++ bcmsdh_cmplt_fn_t complete_fn, void *handle) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ uint incr_fix; ++ uint width; ++ int err = 0; ++ ++ ASSERT(bcmsdh); ++ ASSERT(bcmsdh->init_success); ++ ++ BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n", ++ __FUNCTION__, fn, addr, nbytes)); ++ ++ /* Async not implemented yet */ ++ ASSERT(!(flags & SDIO_REQ_ASYNC)); ++ if (flags & SDIO_REQ_ASYNC) ++ return BCME_UNSUPPORTED; ++ ++ if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE))) ++ return err; ++ ++ addr &= SBSDIO_SB_OFT_ADDR_MASK; ++ ++ incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC; ++ width = (flags & SDIO_REQ_4BYTE) ? 4 : 2; ++ if (width == 4) ++ addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; ++ ++ status = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, incr_fix, ++ SDIOH_READ, fn, addr, width, nbytes, buf, pkt); ++ ++ return (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR); ++} ++ ++int ++bcmsdh_send_buf(void *sdh, uint32 addr, uint fn, uint flags, ++ uint8 *buf, uint nbytes, void *pkt, ++ bcmsdh_cmplt_fn_t complete_fn, void *handle) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ uint incr_fix; ++ uint width; ++ int err = 0; ++ ++ ASSERT(bcmsdh); ++ ASSERT(bcmsdh->init_success); ++ ++ BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n", ++ __FUNCTION__, fn, addr, nbytes)); ++ ++ /* Async not implemented yet */ ++ ASSERT(!(flags & SDIO_REQ_ASYNC)); ++ if (flags & SDIO_REQ_ASYNC) ++ return BCME_UNSUPPORTED; ++ ++ if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE))) ++ return err; ++ ++ addr &= SBSDIO_SB_OFT_ADDR_MASK; ++ ++ incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC; ++ width = (flags & SDIO_REQ_4BYTE) ? 4 : 2; ++ if (width == 4) ++ addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; ++ ++ status = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, incr_fix, ++ SDIOH_WRITE, fn, addr, width, nbytes, buf, pkt); ++ ++ return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); ++} ++ ++int ++bcmsdh_rwdata(void *sdh, uint rw, uint32 addr, uint8 *buf, uint nbytes) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ ++ ASSERT(bcmsdh); ++ ASSERT(bcmsdh->init_success); ++ ASSERT((addr & SBSDIO_SBWINDOW_MASK) == 0); ++ ++ addr &= SBSDIO_SB_OFT_ADDR_MASK; ++ addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; ++ ++ status = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, SDIOH_DATA_INC, ++ (rw ? SDIOH_WRITE : SDIOH_READ), SDIO_FUNC_1, ++ addr, 4, nbytes, buf, NULL); ++ ++ return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); ++} ++ ++int ++bcmsdh_abort(void *sdh, uint fn) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ ++ return sdioh_abort(bcmsdh->sdioh, fn); ++} ++ ++int ++bcmsdh_start(void *sdh, int stage) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ ++ return sdioh_start(bcmsdh->sdioh, stage); ++} ++ ++int ++bcmsdh_stop(void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ ++ return sdioh_stop(bcmsdh->sdioh); ++} ++ ++int ++bcmsdh_waitlockfree(void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ if (!bcmsdh) ++ bcmsdh = l_bcmsdh; ++ ++ return sdioh_waitlockfree(bcmsdh->sdioh); ++} ++ ++ ++int ++bcmsdh_query_device(void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ bcmsdh->vendevid = (VENDOR_BROADCOM << 16) | 0; ++ return (bcmsdh->vendevid); ++} ++ ++uint ++bcmsdh_query_iofnum(void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ ++ if (!bcmsdh) ++ bcmsdh = l_bcmsdh; ++ ++ return (sdioh_query_iofnum(bcmsdh->sdioh)); ++} ++ ++int ++bcmsdh_reset(bcmsdh_info_t *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ ++ return sdioh_sdio_reset(bcmsdh->sdioh); ++} ++ ++void *bcmsdh_get_sdioh(bcmsdh_info_t *sdh) ++{ ++ ASSERT(sdh); ++ return sdh->sdioh; ++} ++ ++/* Function to pass device-status bits to DHD. */ ++uint32 ++bcmsdh_get_dstatus(void *sdh) ++{ ++ return 0; ++} ++uint32 ++bcmsdh_cur_sbwad(void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ ++ if (!bcmsdh) ++ bcmsdh = l_bcmsdh; ++ ++ return (bcmsdh->sbwad); ++} ++ ++void ++bcmsdh_chipinfo(void *sdh, uint32 chip, uint32 chiprev) ++{ ++ return; ++} ++ ++ ++int ++bcmsdh_sleep(void *sdh, bool enab) ++{ ++#ifdef SDIOH_SLEEP_ENABLED ++ bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; ++ sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); ++ ++ return sdioh_sleep(sd, enab); ++#else ++ return BCME_UNSUPPORTED; ++#endif ++} ++ ++int ++bcmsdh_gpio_init(void *sdh) ++{ ++ bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; ++ sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); ++ ++ return sdioh_gpio_init(sd); ++} ++ ++bool ++bcmsdh_gpioin(void *sdh, uint32 gpio) ++{ ++ bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; ++ sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); ++ ++ return sdioh_gpioin(sd, gpio); ++} ++ ++int ++bcmsdh_gpioouten(void *sdh, uint32 gpio) ++{ ++ bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; ++ sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); ++ ++ return sdioh_gpioouten(sd, gpio); ++} ++ ++int ++bcmsdh_gpioout(void *sdh, uint32 gpio, bool enab) ++{ ++ bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; ++ sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); ++ ++ return sdioh_gpioout(sd, gpio, enab); ++} ++ ++#ifdef BCMSDIOH_TXGLOM ++void ++bcmsdh_glom_post(void *sdh, uint8 *frame, uint len) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ sdioh_glom_post(bcmsdh->sdioh, frame, len); ++} ++ ++void ++bcmsdh_glom_clear(void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ sdioh_glom_clear(bcmsdh->sdioh); ++} ++ ++uint ++bcmsdh_set_mode(void *sdh, uint mode) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ return (sdioh_set_mode(bcmsdh->sdioh, mode)); ++} ++ ++bool ++bcmsdh_glom_enabled(void) ++{ ++ return (sdioh_glom_enabled()); ++} ++#endif /* BCMSDIOH_TXGLOM */ +diff --git a/drivers/net/wireless/ap6211/bcmsdh_linux.c b/drivers/net/wireless/ap6211/bcmsdh_linux.c +new file mode 100755 +index 0000000..71bb3d9 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/bcmsdh_linux.c +@@ -0,0 +1,796 @@ ++/* ++ * SDIO access interface for drivers - linux specific (pci only) ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmsdh_linux.c 373359 2012-12-07 06:36:37Z $ ++ */ ++ ++/** ++ * @file bcmsdh_linux.c ++ */ ++ ++#define __UNDEF_NO_VERSION__ ++ ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if defined(OOB_INTR_ONLY) ++#include ++extern void dhdsdio_isr(void * args); ++#include ++#include ++#include ++#include ++#include ++#endif ++ ++#include ++ ++/** ++ * SDIO Host Controller info ++ */ ++typedef struct bcmsdh_hc bcmsdh_hc_t; ++ ++struct bcmsdh_hc { ++ bcmsdh_hc_t *next; ++#ifdef BCMPLATFORM_BUS ++ struct device *dev; /* platform device handle */ ++#else ++ struct pci_dev *dev; /* pci device handle */ ++#endif /* BCMPLATFORM_BUS */ ++ osl_t *osh; ++ void *regs; /* SDIO Host Controller address */ ++ bcmsdh_info_t *sdh; /* SDIO Host Controller handle */ ++ void *ch; ++ unsigned int oob_irq; ++ unsigned long oob_flags; /* OOB Host specifiction as edge and etc */ ++ bool oob_irq_registered; ++ bool oob_irq_enable_flag; ++#if defined(OOB_INTR_ONLY) ++ spinlock_t irq_lock; ++#endif ++}; ++static bcmsdh_hc_t *sdhcinfo = NULL; ++ ++/* driver info, initialized when bcmsdh_register is called */ ++static bcmsdh_driver_t drvinfo = {NULL, NULL}; ++ ++/** ++ * Checks to see if vendor and device IDs match a supported SDIO Host Controller. ++ */ ++bool ++bcmsdh_chipmatch(uint16 vendor, uint16 device) ++{ ++ /* Add other vendors and devices as required */ ++ ++#ifdef BCMSDIOH_STD ++ /* Check for Arasan host controller */ ++ if (vendor == VENDOR_SI_IMAGE) { ++ return (TRUE); ++ } ++ /* Check for BRCM 27XX Standard host controller */ ++ if (device == BCM27XX_SDIOH_ID && vendor == VENDOR_BROADCOM) { ++ return (TRUE); ++ } ++ /* Check for BRCM Standard host controller */ ++ if (device == SDIOH_FPGA_ID && vendor == VENDOR_BROADCOM) { ++ return (TRUE); ++ } ++ /* Check for TI PCIxx21 Standard host controller */ ++ if (device == PCIXX21_SDIOH_ID && vendor == VENDOR_TI) { ++ return (TRUE); ++ } ++ if (device == PCIXX21_SDIOH0_ID && vendor == VENDOR_TI) { ++ return (TRUE); ++ } ++ /* Ricoh R5C822 Standard SDIO Host */ ++ if (device == R5C822_SDIOH_ID && vendor == VENDOR_RICOH) { ++ return (TRUE); ++ } ++ /* JMicron Standard SDIO Host */ ++ if (device == JMICRON_SDIOH_ID && vendor == VENDOR_JMICRON) { ++ return (TRUE); ++ } ++ ++#endif /* BCMSDIOH_STD */ ++#ifdef BCMSDIOH_SPI ++ /* This is the PciSpiHost. */ ++ if (device == SPIH_FPGA_ID && vendor == VENDOR_BROADCOM) { ++ AP6211_ERR("Found PCI SPI Host Controller\n"); ++ return (TRUE); ++ } ++ ++#endif /* BCMSDIOH_SPI */ ++ ++ return (FALSE); ++} ++ ++#if defined(BCMPLATFORM_BUS) ++#if defined(BCMLXSDMMC) ++/* forward declarations */ ++int bcmsdh_probe(struct device *dev); ++int bcmsdh_remove(struct device *dev); ++ ++EXPORT_SYMBOL(bcmsdh_probe); ++EXPORT_SYMBOL(bcmsdh_remove); ++ ++#else ++/* forward declarations */ ++static int __devinit bcmsdh_probe(struct device *dev); ++static int __devexit bcmsdh_remove(struct device *dev); ++#endif ++ ++#if !defined(BCMLXSDMMC) ++static ++#endif ++int bcmsdh_probe(struct device *dev) ++{ ++ osl_t *osh = NULL; ++ bcmsdh_hc_t *sdhc = NULL; ++ ulong regs = 0; ++ bcmsdh_info_t *sdh = NULL; ++#if !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS) ++ struct platform_device *pdev; ++ struct resource *r; ++#endif ++ int irq = 0; ++ uint32 vendevid; ++ unsigned long irq_flags = 0; ++ ++#if !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS) ++ pdev = to_platform_device(dev); ++ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ irq = platform_get_irq(pdev, 0); ++ if (!r || irq == NO_IRQ) ++ return -ENXIO; ++#endif ++ ++#if defined(OOB_INTR_ONLY) ++#ifdef HW_OOB ++ irq_flags = ++ IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE; ++#else ++ irq_flags = IRQF_TRIGGER_FALLING; ++#endif /* HW_OOB */ ++ ++ /* Get customer specific OOB IRQ parametres: IRQ number as IRQ type */ ++ irq = dhd_customer_oob_irq_map(&irq_flags); ++#if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI) ++ /* Do not disable this IRQ during suspend */ ++ irq_flags |= IRQF_NO_SUSPEND; ++#endif /* defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI) */ ++ if (irq < 0) { ++ AP6211_ERR("%s: Host irq is not defined\n", __FUNCTION__); ++ return 1; ++ } ++#endif ++ /* allocate SDIO Host Controller state info */ ++ if (!(osh = osl_attach(dev, PCI_BUS, FALSE))) { ++ AP6211_ERR("%s: osl_attach failed\n", __FUNCTION__); ++ goto err; ++ } ++ if (!(sdhc = MALLOC(osh, sizeof(bcmsdh_hc_t)))) { ++ AP6211_ERR("%s: out of memory, allocated %d bytes\n", ++ __FUNCTION__, ++ MALLOCED(osh)); ++ goto err; ++ } ++ bzero(sdhc, sizeof(bcmsdh_hc_t)); ++ sdhc->osh = osh; ++ ++ sdhc->dev = (void *)dev; ++ ++#if defined(BCMLXSDMMC) ++ if (!(sdh = bcmsdh_attach(osh, (void *)0, ++ (void **)®s, irq))) { ++ AP6211_ERR("%s: bcmsdh_attach failed\n", __FUNCTION__); ++ goto err; ++ } ++#else ++ if (!(sdh = bcmsdh_attach(osh, (void *)r->start, ++ (void **)®s, irq))) { ++ AP6211_ERR("%s: bcmsdh_attach failed\n", __FUNCTION__); ++ goto err; ++ } ++#endif ++ sdhc->sdh = sdh; ++ sdhc->oob_irq = irq; ++ sdhc->oob_flags = irq_flags; ++ sdhc->oob_irq_registered = FALSE; /* to make sure.. */ ++ sdhc->oob_irq_enable_flag = FALSE; ++#if defined(OOB_INTR_ONLY) ++ spin_lock_init(&sdhc->irq_lock); ++#endif ++ ++ /* chain SDIO Host Controller info together */ ++ sdhc->next = sdhcinfo; ++ sdhcinfo = sdhc; ++ ++ /* Read the vendor/device ID from the CIS */ ++ vendevid = bcmsdh_query_device(sdh); ++ /* try to attach to the target device */ ++ if (!(sdhc->ch = drvinfo.attach((vendevid >> 16), ++ (vendevid & 0xFFFF), 0, 0, 0, 0, ++ (void *)regs, NULL, sdh))) { ++ AP6211_ERR("%s: device attach failed\n", __FUNCTION__); ++ goto err; ++ } ++ ++ return 0; ++ ++ /* error handling */ ++err: ++ if (sdhc) { ++ if (sdhc->sdh) ++ bcmsdh_detach(sdhc->osh, sdhc->sdh); ++ MFREE(osh, sdhc, sizeof(bcmsdh_hc_t)); ++ } ++ if (osh) ++ osl_detach(osh); ++ return -ENODEV; ++} ++ ++#if !defined(BCMLXSDMMC) ++static ++#endif ++int bcmsdh_remove(struct device *dev) ++{ ++ bcmsdh_hc_t *sdhc, *prev; ++ osl_t *osh; ++ ++ sdhc = sdhcinfo; ++ drvinfo.detach(sdhc->ch); ++ bcmsdh_detach(sdhc->osh, sdhc->sdh); ++ ++ /* find the SDIO Host Controller state for this pdev and take it out from the list */ ++ for (sdhc = sdhcinfo, prev = NULL; sdhc; sdhc = sdhc->next) { ++ if (sdhc->dev == (void *)dev) { ++ if (prev) ++ prev->next = sdhc->next; ++ else ++ sdhcinfo = NULL; ++ break; ++ } ++ prev = sdhc; ++ } ++ if (!sdhc) { ++ AP6211_ERR("%s: failed\n", __FUNCTION__); ++ return 0; ++ } ++ ++ /* release SDIO Host Controller info */ ++ osh = sdhc->osh; ++ MFREE(osh, sdhc, sizeof(bcmsdh_hc_t)); ++ osl_detach(osh); ++ ++#if !defined(BCMLXSDMMC) || defined(OOB_INTR_ONLY) ++ dev_set_drvdata(dev, NULL); ++#endif ++ ++ return 0; ++} ++ ++#else /* BCMPLATFORM_BUS */ ++ ++#if !defined(BCMLXSDMMC) ++/* forward declarations for PCI probe and remove functions. */ ++static int __devinit bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent); ++static void __devexit bcmsdh_pci_remove(struct pci_dev *pdev); ++ ++/** ++ * pci id table ++ */ ++static struct pci_device_id bcmsdh_pci_devid[] __devinitdata = { ++ { vendor: PCI_ANY_ID, ++ device: PCI_ANY_ID, ++ subvendor: PCI_ANY_ID, ++ subdevice: PCI_ANY_ID, ++ class: 0, ++ class_mask: 0, ++ driver_data: 0, ++ }, ++ { 0, } ++}; ++MODULE_DEVICE_TABLE(pci, bcmsdh_pci_devid); ++ ++/** ++ * SDIO Host Controller pci driver info ++ */ ++static struct pci_driver bcmsdh_pci_driver = { ++ node: {}, ++ name: "bcmsdh", ++ id_table: bcmsdh_pci_devid, ++ probe: bcmsdh_pci_probe, ++ remove: bcmsdh_pci_remove, ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) ++ save_state: NULL, ++#endif ++ suspend: NULL, ++ resume: NULL, ++ }; ++ ++ ++extern uint sd_pci_slot; /* Force detection to a particular PCI */ ++ /* slot only . Allows for having multiple */ ++ /* WL devices at once in a PC */ ++ /* Only one instance of dhd will be */ ++ /* usable at a time */ ++ /* Upper word is bus number, */ ++ /* lower word is slot number */ ++ /* Default value of 0xffffffff turns this */ ++ /* off */ ++module_param(sd_pci_slot, uint, 0); ++ ++ ++/** ++ * Detect supported SDIO Host Controller and attach if found. ++ * ++ * Determine if the device described by pdev is a supported SDIO Host ++ * Controller. If so, attach to it and attach to the target device. ++ */ ++static int __devinit ++bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ++{ ++ osl_t *osh = NULL; ++ bcmsdh_hc_t *sdhc = NULL; ++ ulong regs; ++ bcmsdh_info_t *sdh = NULL; ++ int rc; ++ ++ if (sd_pci_slot != 0xFFFFffff) { ++ if (pdev->bus->number != (sd_pci_slot>>16) || ++ PCI_SLOT(pdev->devfn) != (sd_pci_slot&0xffff)) { ++ AP6211_DEBUG("%s: %s: bus %X, slot %X, vend %X, dev %X\n", ++ __FUNCTION__, ++ bcmsdh_chipmatch(pdev->vendor, pdev->device) ++ ?"Found compatible SDIOHC" ++ :"Probing unknown device", ++ pdev->bus->number, PCI_SLOT(pdev->devfn), pdev->vendor, ++ pdev->device); ++ return -ENODEV; ++ } ++ AP6211_DEBUG("%s: %s: bus %X, slot %X, vendor %X, device %X (good PCI location)\n", ++ __FUNCTION__, ++ bcmsdh_chipmatch(pdev->vendor, pdev->device) ++ ?"Using compatible SDIOHC" ++ :"WARNING, forced use of unkown device", ++ pdev->bus->number, PCI_SLOT(pdev->devfn), pdev->vendor, pdev->device); ++ } ++ ++ if ((pdev->vendor == VENDOR_TI) && ((pdev->device == PCIXX21_FLASHMEDIA_ID) || ++ (pdev->device == PCIXX21_FLASHMEDIA0_ID))) { ++ uint32 config_reg; ++ ++ AP6211_ERR("%s: Disabling TI FlashMedia Controller.\n", __FUNCTION__); ++ if (!(osh = osl_attach(pdev, PCI_BUS, FALSE))) { ++ AP6211_ERR("%s: osl_attach failed\n", __FUNCTION__); ++ goto err; ++ } ++ ++ config_reg = OSL_PCI_READ_CONFIG(osh, 0x4c, 4); ++ ++ /* ++ * Set MMC_SD_DIS bit in FlashMedia Controller. ++ * Disbling the SD/MMC Controller in the FlashMedia Controller ++ * allows the Standard SD Host Controller to take over control ++ * of the SD Slot. ++ */ ++ config_reg |= 0x02; ++ OSL_PCI_WRITE_CONFIG(osh, 0x4c, 4, config_reg); ++ osl_detach(osh); ++ } ++ /* match this pci device with what we support */ ++ /* we can't solely rely on this to believe it is our SDIO Host Controller! */ ++ if (!bcmsdh_chipmatch(pdev->vendor, pdev->device)) { ++ return -ENODEV; ++ } ++ ++ /* this is a pci device we might support */ ++ AP6211_ERR("%s: Found possible SDIO Host Controller: bus %d slot %d func %d irq %d\n", ++ __FUNCTION__, ++ pdev->bus->number, PCI_SLOT(pdev->devfn), ++ PCI_FUNC(pdev->devfn), pdev->irq); ++ ++ /* use bcmsdh_query_device() to get the vendor ID of the target device so ++ * it will eventually appear in the Broadcom string on the console ++ */ ++ ++ /* allocate SDIO Host Controller state info */ ++ if (!(osh = osl_attach(pdev, PCI_BUS, FALSE))) { ++ AP6211_ERR("%s: osl_attach failed\n", __FUNCTION__); ++ goto err; ++ } ++ if (!(sdhc = MALLOC(osh, sizeof(bcmsdh_hc_t)))) { ++ AP6211_ERR("%s: out of memory, allocated %d bytes\n", ++ __FUNCTION__, ++ MALLOCED(osh)); ++ goto err; ++ } ++ bzero(sdhc, sizeof(bcmsdh_hc_t)); ++ sdhc->osh = osh; ++ ++ sdhc->dev = pdev; ++ ++ /* map to address where host can access */ ++ pci_set_master(pdev); ++ rc = pci_enable_device(pdev); ++ if (rc) { ++ AP6211_ERR("%s: Cannot enable PCI device\n", __FUNCTION__); ++ goto err; ++ } ++ if (!(sdh = bcmsdh_attach(osh, (void *)(uintptr)pci_resource_start(pdev, 0), ++ (void **)®s, pdev->irq))) { ++ AP6211_ERR("%s: bcmsdh_attach failed\n", __FUNCTION__); ++ goto err; ++ } ++ ++ sdhc->sdh = sdh; ++ ++ /* try to attach to the target device */ ++ if (!(sdhc->ch = drvinfo.attach(VENDOR_BROADCOM, /* pdev->vendor, */ ++ bcmsdh_query_device(sdh) & 0xFFFF, 0, 0, 0, 0, ++ (void *)regs, NULL, sdh))) { ++ AP6211_ERR("%s: device attach failed\n", __FUNCTION__); ++ goto err; ++ } ++ ++ /* chain SDIO Host Controller info together */ ++ sdhc->next = sdhcinfo; ++ sdhcinfo = sdhc; ++ ++ return 0; ++ ++ /* error handling */ ++err: ++ if (sdhc) { ++ if (sdhc->sdh) ++ bcmsdh_detach(sdhc->osh, sdhc->sdh); ++ MFREE(osh, sdhc, sizeof(bcmsdh_hc_t)); ++ } ++ if (osh) ++ osl_detach(osh); ++ return -ENODEV; ++} ++ ++ ++/** ++ * Detach from target devices and SDIO Host Controller ++ */ ++static void __devexit ++bcmsdh_pci_remove(struct pci_dev *pdev) ++{ ++ bcmsdh_hc_t *sdhc, *prev; ++ osl_t *osh; ++ ++ /* find the SDIO Host Controller state for this pdev and take it out from the list */ ++ for (sdhc = sdhcinfo, prev = NULL; sdhc; sdhc = sdhc->next) { ++ if (sdhc->dev == pdev) { ++ if (prev) ++ prev->next = sdhc->next; ++ else ++ sdhcinfo = NULL; ++ break; ++ } ++ prev = sdhc; ++ } ++ if (!sdhc) ++ return; ++ ++ drvinfo.detach(sdhc->ch); ++ ++ bcmsdh_detach(sdhc->osh, sdhc->sdh); ++ ++ /* release SDIO Host Controller info */ ++ osh = sdhc->osh; ++ MFREE(osh, sdhc, sizeof(bcmsdh_hc_t)); ++ osl_detach(osh); ++} ++#endif /* BCMLXSDMMC */ ++#endif /* BCMPLATFORM_BUS */ ++ ++extern int sdio_function_init(void); ++ ++extern int sdio_func_reg_notify(void* semaphore); ++extern void sdio_func_unreg_notify(void); ++ ++#if defined(BCMLXSDMMC) ++int bcmsdh_reg_sdio_notify(void* semaphore) ++{ ++ return sdio_func_reg_notify(semaphore); ++} ++ ++void bcmsdh_unreg_sdio_notify(void) ++{ ++ sdio_func_unreg_notify(); ++} ++#endif /* defined(BCMLXSDMMC) */ ++ ++int ++bcmsdh_register(bcmsdh_driver_t *driver) ++{ ++ int error = 0; ++ ++ drvinfo = *driver; ++ ++#if defined(BCMPLATFORM_BUS) ++ AP6211_ERR("Linux Kernel SDIO/MMC Driver\n"); ++ error = sdio_function_init(); ++ return error; ++#endif /* defined(BCMPLATFORM_BUS) */ ++ ++#if !defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC) ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) ++ if (!(error = pci_module_init(&bcmsdh_pci_driver))) ++ return 0; ++#else ++ if (!(error = pci_register_driver(&bcmsdh_pci_driver))) ++ return 0; ++#endif ++ ++ AP6211_ERR("%s: pci_module_init failed 0x%x\n", __FUNCTION__, error); ++#endif /* BCMPLATFORM_BUS */ ++ ++ return error; ++} ++ ++extern void sdio_function_cleanup(void); ++ ++void ++bcmsdh_unregister(void) ++{ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) ++ if (bcmsdh_pci_driver.node.next) ++#endif ++ ++#if defined(BCMLXSDMMC) ++ sdio_function_cleanup(); ++#endif /* BCMLXSDMMC */ ++ ++#if !defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC) ++ pci_unregister_driver(&bcmsdh_pci_driver); ++#endif /* BCMPLATFORM_BUS */ ++} ++ ++int bcmsdh_set_drvdata(void * dhdp) ++{ ++ AP6211_DEBUG("%s Enter \n", __FUNCTION__); ++ ++ dev_set_drvdata(sdhcinfo->dev, dhdp); ++ ++ return 0; ++} ++ ++#if defined(OOB_INTR_ONLY) ++#define CONFIG_ARCH_SUN6I_AP6211 1 ++ ++void bcmsdh_oob_intr_set(bool enable) ++{ ++ static bool curstate = 1; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&sdhcinfo->irq_lock, flags); ++ if (curstate != enable) { ++ if(enable) { ++ enable_irq(sdhcinfo->oob_irq); ++ } ++ else { ++ disable_irq_nosync(sdhcinfo->oob_irq); ++ } ++ curstate = enable; ++ } ++ ++ spin_unlock_irqrestore(&sdhcinfo->irq_lock, flags); ++} ++ ++static irqreturn_t wlan_oob_irq(int irq, void *dev_id) ++{ ++ dhd_pub_t *dhdp; ++ ++ dhdp = (dhd_pub_t *)dev_get_drvdata(sdhcinfo->dev); ++ ++ bcmsdh_oob_intr_set(0); ++ ++ if (dhdp == NULL) { ++ AP6211_ERR("Out of band GPIO interrupt fired way too early\n"); ++ return IRQ_HANDLED; ++ } ++ ++ dhdsdio_isr((void *)dhdp->bus); ++ ++ return IRQ_HANDLED; ++} ++ ++extern int wl_host_wake_irqno; ++irqreturn_t bcmdhd_gpio_irq_handler(int irq, void *dev) ++{ ++ wlan_oob_irq(0, NULL); ++ return IRQ_HANDLED; ++} ++ ++int bcmsdh_register_oob_intr(void * dhdp) ++{ ++ int error = 0; ++ int ret; ++ AP6211_DEBUG("%s Enter \n", __FUNCTION__); ++ ++ /* IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE; */ ++ dev_set_drvdata(sdhcinfo->dev, dhdp); ++ ++ if (!sdhcinfo->oob_irq_registered) { ++ AP6211_DEBUG("%s IRQ=%d Type=%X \n", __FUNCTION__, ++ (int)sdhcinfo->oob_irq, (int)sdhcinfo->oob_flags); ++ ++ ret = request_irq(wl_host_wake_irqno, bcmdhd_gpio_irq_handler, IRQF_DISABLED| IRQF_SHARED| IRQF_TRIGGER_HIGH, "bcmdhd_gpio_irq", (void *)&wl_host_wake_irqno); ++ if (ret) { ++ AP6211_ERR("request irq%d failed\n", wl_host_wake_irqno); ++ return -1; ++ } ++ ++#if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI) || defined(CONFIG_ARCH_SUN6I_AP6211) ++ if (device_may_wakeup(sdhcinfo->dev)) { ++#endif ++ error = enable_irq_wake(sdhcinfo->oob_irq); ++#if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI) || defined(CONFIG_ARCH_SUN6I_AP6211) ++ } ++#endif ++ if (error) ++ AP6211_ERR("%s enable_irq_wake error=%d \n", __FUNCTION__, error); ++ sdhcinfo->oob_irq_registered = TRUE; ++ sdhcinfo->oob_irq_enable_flag = TRUE; ++ } ++ ++ return 0; ++} ++ ++void bcmsdh_set_irq(int flag) ++{ ++ if (sdhcinfo->oob_irq_registered && sdhcinfo->oob_irq_enable_flag != flag) { ++ AP6211_ERR("%s Flag = %d\n", __FUNCTION__, flag); ++ sdhcinfo->oob_irq_enable_flag = flag; ++ if (flag) { ++ enable_irq(sdhcinfo->oob_irq); ++ ++#if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI) || defined(CONFIG_ARCH_SUN6I_AP6211) ++ if (device_may_wakeup(sdhcinfo->dev)) ++#endif ++ enable_irq_wake(sdhcinfo->oob_irq); ++ } else { ++#if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI) || defined(CONFIG_ARCH_SUN6I_AP6211) ++ if (device_may_wakeup(sdhcinfo->dev)) ++#endif ++ disable_irq_wake(sdhcinfo->oob_irq); ++ ++ ++ disable_irq(sdhcinfo->oob_irq); ++ } ++ } ++} ++ ++void bcmsdh_unregister_oob_intr(void) ++{ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ if (sdhcinfo->oob_irq_registered == TRUE) { ++ ++ if(0 != wl_host_wake_irqno) { ++ AP6211_DEBUG("free_irq %d\n", wl_host_wake_irqno); ++ free_irq(wl_host_wake_irqno, &wl_host_wake_irqno); ++ } ++ ++ sdhcinfo->oob_irq_registered = FALSE; ++ } ++} ++#endif ++ ++#if defined(BCMLXSDMMC) ++void *bcmsdh_get_drvdata(void) ++{ ++ if (!sdhcinfo) ++ return NULL; ++ return dev_get_drvdata(sdhcinfo->dev); ++} ++#endif ++ ++/* Module parameters specific to each host-controller driver */ ++ ++extern uint sd_msglevel; /* Debug message level */ ++module_param(sd_msglevel, uint, 0); ++ ++extern uint sd_power; /* 0 = SD Power OFF, 1 = SD Power ON. */ ++module_param(sd_power, uint, 0); ++ ++extern uint sd_clock; /* SD Clock Control, 0 = SD Clock OFF, 1 = SD Clock ON */ ++module_param(sd_clock, uint, 0); ++ ++extern uint sd_divisor; /* Divisor (-1 means external clock) */ ++module_param(sd_divisor, uint, 0); ++ ++extern uint sd_sdmode; /* Default is SD4, 0=SPI, 1=SD1, 2=SD4 */ ++module_param(sd_sdmode, uint, 0); ++ ++extern uint sd_hiok; /* Ok to use hi-speed mode */ ++module_param(sd_hiok, uint, 0); ++ ++extern uint sd_f2_blocksize; ++module_param(sd_f2_blocksize, int, 0); ++ ++#ifdef BCMSDIOH_STD ++extern int sd_uhsimode; ++module_param(sd_uhsimode, int, 0); ++#endif ++ ++#ifdef BCMSDIOH_TXGLOM ++extern uint sd_txglom; ++module_param(sd_txglom, uint, 0); ++#endif ++ ++#ifdef BCMSDH_MODULE ++EXPORT_SYMBOL(bcmsdh_attach); ++EXPORT_SYMBOL(bcmsdh_detach); ++EXPORT_SYMBOL(bcmsdh_intr_query); ++EXPORT_SYMBOL(bcmsdh_intr_enable); ++EXPORT_SYMBOL(bcmsdh_intr_disable); ++EXPORT_SYMBOL(bcmsdh_intr_reg); ++EXPORT_SYMBOL(bcmsdh_intr_dereg); ++ ++#if defined(DHD_DEBUG) ++EXPORT_SYMBOL(bcmsdh_intr_pending); ++#endif ++ ++EXPORT_SYMBOL(bcmsdh_devremove_reg); ++EXPORT_SYMBOL(bcmsdh_cfg_read); ++EXPORT_SYMBOL(bcmsdh_cfg_write); ++EXPORT_SYMBOL(bcmsdh_cis_read); ++EXPORT_SYMBOL(bcmsdh_reg_read); ++EXPORT_SYMBOL(bcmsdh_reg_write); ++EXPORT_SYMBOL(bcmsdh_regfail); ++EXPORT_SYMBOL(bcmsdh_send_buf); ++EXPORT_SYMBOL(bcmsdh_recv_buf); ++ ++EXPORT_SYMBOL(bcmsdh_rwdata); ++EXPORT_SYMBOL(bcmsdh_abort); ++EXPORT_SYMBOL(bcmsdh_query_device); ++EXPORT_SYMBOL(bcmsdh_query_iofnum); ++EXPORT_SYMBOL(bcmsdh_iovar_op); ++EXPORT_SYMBOL(bcmsdh_register); ++EXPORT_SYMBOL(bcmsdh_unregister); ++EXPORT_SYMBOL(bcmsdh_chipmatch); ++EXPORT_SYMBOL(bcmsdh_reset); ++EXPORT_SYMBOL(bcmsdh_waitlockfree); ++ ++EXPORT_SYMBOL(bcmsdh_get_dstatus); ++EXPORT_SYMBOL(bcmsdh_cfg_read_word); ++EXPORT_SYMBOL(bcmsdh_cfg_write_word); ++EXPORT_SYMBOL(bcmsdh_cur_sbwad); ++EXPORT_SYMBOL(bcmsdh_chipinfo); ++ ++#endif /* BCMSDH_MODULE */ +diff --git a/drivers/net/wireless/ap6211/bcmsdh_sdmmc.c b/drivers/net/wireless/ap6211/bcmsdh_sdmmc.c +new file mode 100755 +index 0000000..5f0d300 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/bcmsdh_sdmmc.c +@@ -0,0 +1,1532 @@ ++/* ++ * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmsdh_sdmmc.c 362913 2012-10-15 11:26:11Z $ ++ */ ++#include ++ ++#include ++#include ++#include ++#include ++#include /* SDIO Device and Protocol Specs */ ++#include /* Standard SDIO Host Controller Specification */ ++#include /* bcmsdh to/from specific controller APIs */ ++#include /* ioctl/iovars */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) ++#include ++extern volatile bool dhd_mmc_suspend; ++#endif ++#include "bcmsdh_sdmmc.h" ++ ++#include ++ ++#ifndef BCMSDH_MODULE ++extern int sdio_function_init(void); ++extern void sdio_function_cleanup(void); ++#endif /* BCMSDH_MODULE */ ++ ++#if !defined(OOB_INTR_ONLY) ++static void IRQHandler(struct sdio_func *func); ++static void IRQHandlerF2(struct sdio_func *func); ++#endif /* !defined(OOB_INTR_ONLY) */ ++static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr); ++extern int sdio_reset_comm(struct mmc_card *card); ++extern int sw_mci_check_r1_ready(struct mmc_host* mmc, unsigned ms); ++ ++extern PBCMSDH_SDMMC_INSTANCE gInstance; ++ ++#define DEFAULT_SDIO_F2_BLKSIZE 512 ++#ifndef CUSTOM_SDIO_F2_BLKSIZE ++#define CUSTOM_SDIO_F2_BLKSIZE DEFAULT_SDIO_F2_BLKSIZE ++#endif ++ ++uint sd_sdmode = SDIOH_MODE_SD4; /* Use SD4 mode by default */ ++uint sd_f2_blocksize = CUSTOM_SDIO_F2_BLKSIZE; ++uint sd_divisor = 2; /* Default 48MHz/2 = 24MHz */ ++ ++uint sd_power = 1; /* Default to SD Slot powered ON */ ++uint sd_clock = 1; /* Default to SD Clock turned ON */ ++uint sd_hiok = FALSE; /* Don't use hi-speed mode by default */ ++uint sd_msglevel = 0x01; ++uint sd_use_dma = TRUE; ++DHD_PM_RESUME_WAIT_INIT(sdioh_request_byte_wait); ++DHD_PM_RESUME_WAIT_INIT(sdioh_request_word_wait); ++DHD_PM_RESUME_WAIT_INIT(sdioh_request_packet_wait); ++DHD_PM_RESUME_WAIT_INIT(sdioh_request_buffer_wait); ++ ++#define DMA_ALIGN_MASK 0x03 ++#define MMC_SDIO_ABORT_RETRY_LIMIT 5 ++ ++int sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data); ++ ++static int ++sdioh_sdmmc_card_enablefuncs(sdioh_info_t *sd) ++{ ++ int err_ret; ++ uint32 fbraddr; ++ uint8 func; ++ ++ AP6211_DEBUG("%s\n", __FUNCTION__);; ++ ++ /* Get the Card's common CIS address */ ++ sd->com_cis_ptr = sdioh_sdmmc_get_cisaddr(sd, SDIOD_CCCR_CISPTR_0); ++ sd->func_cis_ptr[0] = sd->com_cis_ptr; ++ AP6211_DEBUG("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr); ++ ++ /* Get the Card's function CIS (for each function) */ ++ for (fbraddr = SDIOD_FBR_STARTADDR, func = 1; ++ func <= sd->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) { ++ sd->func_cis_ptr[func] = sdioh_sdmmc_get_cisaddr(sd, SDIOD_FBR_CISPTR_0 + fbraddr); ++ AP6211_DEBUG("%s: Function %d CIS Ptr = 0x%x\n", ++ __FUNCTION__, func, sd->func_cis_ptr[func]); ++ } ++ ++ sd->func_cis_ptr[0] = sd->com_cis_ptr; ++ AP6211_DEBUG("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr); ++ ++ /* Enable Function 1 */ ++ sdio_claim_host(gInstance->func[1]); ++ err_ret = sdio_enable_func(gInstance->func[1]); ++ sdio_release_host(gInstance->func[1]); ++ if (err_ret) { ++ AP6211_ERR("bcmsdh_sdmmc: Failed to enable F1 Err: 0x%08x", err_ret); ++ } ++ ++ return FALSE; ++} ++ ++/* ++ * Public entry points & extern's ++ */ ++extern sdioh_info_t * ++sdioh_attach(osl_t *osh, void *bar0, uint irq) ++{ ++ sdioh_info_t *sd; ++ int err_ret; ++ ++ AP6211_DEBUG("%s\n", __FUNCTION__); ++ ++ if (gInstance == NULL) { ++ AP6211_ERR("%s: SDIO Device not present\n", __FUNCTION__); ++ return NULL; ++ } ++ ++ if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) { ++ AP6211_ERR("sdioh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh)); ++ return NULL; ++ } ++ bzero((char *)sd, sizeof(sdioh_info_t)); ++ sd->osh = osh; ++ if (sdioh_sdmmc_osinit(sd) != 0) { ++ AP6211_ERR("%s:sdioh_sdmmc_osinit() failed\n", __FUNCTION__); ++ MFREE(sd->osh, sd, sizeof(sdioh_info_t)); ++ return NULL; ++ } ++ ++ sd->num_funcs = 2; ++ sd->sd_blockmode = TRUE; ++ sd->use_client_ints = TRUE; ++ sd->client_block_size[0] = 64; ++ sd->use_rxchain = FALSE; ++ ++ gInstance->sd = sd; ++ ++ /* Claim host controller */ ++ if (gInstance->func[1]) { ++ sdio_claim_host(gInstance->func[1]); ++ ++ sd->client_block_size[1] = 64; ++ err_ret = sdio_set_block_size(gInstance->func[1], 64); ++ if (err_ret) { ++ AP6211_ERR("bcmsdh_sdmmc: Failed to set F1 blocksize\n"); ++ } ++ ++ /* Release host controller F1 */ ++ sdio_release_host(gInstance->func[1]); ++ } else { ++ AP6211_ERR("%s:gInstance->func[1] is null\n", __FUNCTION__); ++ MFREE(sd->osh, sd, sizeof(sdioh_info_t)); ++ return NULL; ++ } ++ ++ if (gInstance->func[2]) { ++ /* Claim host controller F2 */ ++ sdio_claim_host(gInstance->func[2]); ++ ++ sd->client_block_size[2] = sd_f2_blocksize; ++ err_ret = sdio_set_block_size(gInstance->func[2], sd_f2_blocksize); ++ if (err_ret) { ++ AP6211_ERR("bcmsdh_sdmmc: Failed to set F2 blocksize to %d\n", ++ sd_f2_blocksize); ++ } ++ ++ /* Release host controller F2 */ ++ sdio_release_host(gInstance->func[2]); ++ } else { ++ AP6211_ERR("%s:gInstance->func[2] is null\n", __FUNCTION__); ++ MFREE(sd->osh, sd, sizeof(sdioh_info_t)); ++ return NULL; ++ } ++ ++ sdioh_sdmmc_card_enablefuncs(sd); ++ ++ AP6211_DEBUG("%s: Done\n", __FUNCTION__); ++ return sd; ++} ++ ++ ++extern SDIOH_API_RC ++sdioh_detach(osl_t *osh, sdioh_info_t *sd) ++{ ++ AP6211_DEBUG("%s\n", __FUNCTION__); ++ ++ if (sd) { ++ ++ /* Disable Function 2 */ ++ sdio_claim_host(gInstance->func[2]); ++ sdio_disable_func(gInstance->func[2]); ++ sdio_release_host(gInstance->func[2]); ++ ++ /* Disable Function 1 */ ++ if (gInstance->func[1]) { ++ sdio_claim_host(gInstance->func[1]); ++ sdio_disable_func(gInstance->func[1]); ++ sdio_release_host(gInstance->func[1]); ++ } ++ ++ gInstance->func[1] = NULL; ++ gInstance->func[2] = NULL; ++ ++ /* deregister irq */ ++ sdioh_sdmmc_osfree(sd); ++ ++ MFREE(sd->osh, sd, sizeof(sdioh_info_t)); ++ } ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++#if defined(OOB_INTR_ONLY) && defined(HW_OOB) ++ ++extern SDIOH_API_RC ++sdioh_enable_func_intr(void) ++{ ++ uint8 reg; ++ int err; ++ ++ if (gInstance->func[0]) { ++ sdio_claim_host(gInstance->func[0]); ++ ++ reg = sdio_readb(gInstance->func[0], SDIOD_CCCR_INTEN, &err); ++ if (err) { ++ AP6211_ERR("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err); ++ sdio_release_host(gInstance->func[0]); ++ return SDIOH_API_RC_FAIL; ++ } ++ ++ /* Enable F1 and F2 interrupts, set master enable */ ++ reg |= (INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN | INTR_CTL_MASTER_EN); ++ ++ sdio_writeb(gInstance->func[0], reg, SDIOD_CCCR_INTEN, &err); ++ sdio_release_host(gInstance->func[0]); ++ ++ if (err) { ++ AP6211_ERR("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err); ++ return SDIOH_API_RC_FAIL; ++ } ++ } ++ ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++extern SDIOH_API_RC ++sdioh_disable_func_intr(void) ++{ ++ uint8 reg; ++ int err; ++ ++ if (gInstance->func[0]) { ++ sdio_claim_host(gInstance->func[0]); ++ reg = sdio_readb(gInstance->func[0], SDIOD_CCCR_INTEN, &err); ++ if (err) { ++ AP6211_ERR("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err); ++ sdio_release_host(gInstance->func[0]); ++ return SDIOH_API_RC_FAIL; ++ } ++ ++ reg &= ~(INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN); ++ /* Disable master interrupt with the last function interrupt */ ++ if (!(reg & 0xFE)) ++ reg = 0; ++ sdio_writeb(gInstance->func[0], reg, SDIOD_CCCR_INTEN, &err); ++ ++ sdio_release_host(gInstance->func[0]); ++ if (err) { ++ AP6211_ERR("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err); ++ return SDIOH_API_RC_FAIL; ++ } ++ } ++ return SDIOH_API_RC_SUCCESS; ++} ++#endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */ ++ ++/* Configure callback to client when we recieve client interrupt */ ++extern SDIOH_API_RC ++sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh) ++{ ++ AP6211_DEBUG("%s: Entering\n", __FUNCTION__); ++ if (fn == NULL) { ++ AP6211_ERR("%s: interrupt handler is NULL, not registering\n", __FUNCTION__); ++ return SDIOH_API_RC_FAIL; ++ } ++#if !defined(OOB_INTR_ONLY) ++ sd->intr_handler = fn; ++ sd->intr_handler_arg = argh; ++ sd->intr_handler_valid = TRUE; ++ ++ /* register and unmask irq */ ++ if (gInstance->func[2]) { ++ sdio_claim_host(gInstance->func[2]); ++ sdio_claim_irq(gInstance->func[2], IRQHandlerF2); ++ sdio_release_host(gInstance->func[2]); ++ } ++ ++ if (gInstance->func[1]) { ++ sdio_claim_host(gInstance->func[1]); ++ sdio_claim_irq(gInstance->func[1], IRQHandler); ++ sdio_release_host(gInstance->func[1]); ++ } ++#elif defined(HW_OOB) ++ sdioh_enable_func_intr(); ++#endif /* !defined(OOB_INTR_ONLY) */ ++ ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++extern SDIOH_API_RC ++sdioh_interrupt_deregister(sdioh_info_t *sd) ++{ ++ AP6211_DEBUG("%s: Entering\n", __FUNCTION__); ++ ++#if !defined(OOB_INTR_ONLY) ++ if (gInstance->func[1]) { ++ /* register and unmask irq */ ++ sdio_claim_host(gInstance->func[1]); ++ sdio_release_irq(gInstance->func[1]); ++ sdio_release_host(gInstance->func[1]); ++ } ++ ++ if (gInstance->func[2]) { ++ /* Claim host controller F2 */ ++ sdio_claim_host(gInstance->func[2]); ++ sdio_release_irq(gInstance->func[2]); ++ /* Release host controller F2 */ ++ sdio_release_host(gInstance->func[2]); ++ } ++ ++ sd->intr_handler_valid = FALSE; ++ sd->intr_handler = NULL; ++ sd->intr_handler_arg = NULL; ++#elif defined(HW_OOB) ++ sdioh_disable_func_intr(); ++#endif /* !defined(OOB_INTR_ONLY) */ ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++extern SDIOH_API_RC ++sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff) ++{ ++ AP6211_DEBUG("%s: Entering\n", __FUNCTION__); ++ *onoff = sd->client_intr_enabled; ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++#if defined(DHD_DEBUG) ++extern bool ++sdioh_interrupt_pending(sdioh_info_t *sd) ++{ ++ return (0); ++} ++#endif ++ ++uint ++sdioh_query_iofnum(sdioh_info_t *sd) ++{ ++ return sd->num_funcs; ++} ++ ++/* IOVar table */ ++enum { ++ IOV_MSGLEVEL = 1, ++ IOV_BLOCKMODE, ++ IOV_BLOCKSIZE, ++ IOV_DMA, ++ IOV_USEINTS, ++ IOV_NUMINTS, ++ IOV_NUMLOCALINTS, ++ IOV_HOSTREG, ++ IOV_DEVREG, ++ IOV_DIVISOR, ++ IOV_SDMODE, ++ IOV_HISPEED, ++ IOV_HCIREGS, ++ IOV_POWER, ++ IOV_CLOCK, ++ IOV_RXCHAIN ++}; ++ ++const bcm_iovar_t sdioh_iovars[] = { ++ {"sd_msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 }, ++ {"sd_blockmode", IOV_BLOCKMODE, 0, IOVT_BOOL, 0 }, ++ {"sd_blocksize", IOV_BLOCKSIZE, 0, IOVT_UINT32, 0 }, /* ((fn << 16) | size) */ ++ {"sd_dma", IOV_DMA, 0, IOVT_BOOL, 0 }, ++ {"sd_ints", IOV_USEINTS, 0, IOVT_BOOL, 0 }, ++ {"sd_numints", IOV_NUMINTS, 0, IOVT_UINT32, 0 }, ++ {"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32, 0 }, ++ {"sd_hostreg", IOV_HOSTREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, ++ {"sd_devreg", IOV_DEVREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, ++ {"sd_divisor", IOV_DIVISOR, 0, IOVT_UINT32, 0 }, ++ {"sd_power", IOV_POWER, 0, IOVT_UINT32, 0 }, ++ {"sd_clock", IOV_CLOCK, 0, IOVT_UINT32, 0 }, ++ {"sd_mode", IOV_SDMODE, 0, IOVT_UINT32, 100}, ++ {"sd_highspeed", IOV_HISPEED, 0, IOVT_UINT32, 0 }, ++ {"sd_rxchain", IOV_RXCHAIN, 0, IOVT_BOOL, 0 }, ++ {NULL, 0, 0, 0, 0 } ++}; ++ ++int ++sdioh_iovar_op(sdioh_info_t *si, const char *name, ++ void *params, int plen, void *arg, int len, bool set) ++{ ++ const bcm_iovar_t *vi = NULL; ++ int bcmerror = 0; ++ int val_size; ++ int32 int_val = 0; ++ bool bool_val; ++ uint32 actionid; ++ ++ ASSERT(name); ++ ASSERT(len >= 0); ++ ++ /* Get must have return space; Set does not take qualifiers */ ++ ASSERT(set || (arg && len)); ++ ASSERT(!set || (!params && !plen)); ++ ++ AP6211_DEBUG("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name); ++ ++ if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) { ++ bcmerror = BCME_UNSUPPORTED; ++ goto exit; ++ } ++ ++ if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0) ++ goto exit; ++ ++ /* Set up params so get and set can share the convenience variables */ ++ if (params == NULL) { ++ params = arg; ++ plen = len; ++ } ++ ++ if (vi->type == IOVT_VOID) ++ val_size = 0; ++ else if (vi->type == IOVT_BUFFER) ++ val_size = len; ++ else ++ val_size = sizeof(int); ++ ++ if (plen >= (int)sizeof(int_val)) ++ bcopy(params, &int_val, sizeof(int_val)); ++ ++ bool_val = (int_val != 0) ? TRUE : FALSE; ++ BCM_REFERENCE(bool_val); ++ ++ actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); ++ switch (actionid) { ++ case IOV_GVAL(IOV_MSGLEVEL): ++ int_val = (int32)sd_msglevel; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_MSGLEVEL): ++ sd_msglevel = int_val; ++ break; ++ ++ case IOV_GVAL(IOV_BLOCKMODE): ++ int_val = (int32)si->sd_blockmode; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_BLOCKMODE): ++ si->sd_blockmode = (bool)int_val; ++ /* Haven't figured out how to make non-block mode with DMA */ ++ break; ++ ++ case IOV_GVAL(IOV_BLOCKSIZE): ++ if ((uint32)int_val > si->num_funcs) { ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ int_val = (int32)si->client_block_size[int_val]; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_BLOCKSIZE): ++ { ++ uint func = ((uint32)int_val >> 16); ++ uint blksize = (uint16)int_val; ++ uint maxsize; ++ ++ if (func > si->num_funcs) { ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ ++ switch (func) { ++ case 0: maxsize = 32; break; ++ case 1: maxsize = BLOCK_SIZE_4318; break; ++ case 2: maxsize = BLOCK_SIZE_4328; break; ++ default: maxsize = 0; ++ } ++ if (blksize > maxsize) { ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ if (!blksize) { ++ blksize = maxsize; ++ } ++ ++ /* Now set it */ ++ si->client_block_size[func] = blksize; ++ ++ break; ++ } ++ ++ case IOV_GVAL(IOV_RXCHAIN): ++ int_val = (int32)si->use_rxchain; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_GVAL(IOV_DMA): ++ int_val = (int32)si->sd_use_dma; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_DMA): ++ si->sd_use_dma = (bool)int_val; ++ break; ++ ++ case IOV_GVAL(IOV_USEINTS): ++ int_val = (int32)si->use_client_ints; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_USEINTS): ++ si->use_client_ints = (bool)int_val; ++ if (si->use_client_ints) ++ si->intmask |= CLIENT_INTR; ++ else ++ si->intmask &= ~CLIENT_INTR; ++ ++ break; ++ ++ case IOV_GVAL(IOV_DIVISOR): ++ int_val = (uint32)sd_divisor; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_DIVISOR): ++ sd_divisor = int_val; ++ break; ++ ++ case IOV_GVAL(IOV_POWER): ++ int_val = (uint32)sd_power; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_POWER): ++ sd_power = int_val; ++ break; ++ ++ case IOV_GVAL(IOV_CLOCK): ++ int_val = (uint32)sd_clock; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_CLOCK): ++ sd_clock = int_val; ++ break; ++ ++ case IOV_GVAL(IOV_SDMODE): ++ int_val = (uint32)sd_sdmode; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_SDMODE): ++ sd_sdmode = int_val; ++ break; ++ ++ case IOV_GVAL(IOV_HISPEED): ++ int_val = (uint32)sd_hiok; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_HISPEED): ++ sd_hiok = int_val; ++ break; ++ ++ case IOV_GVAL(IOV_NUMINTS): ++ int_val = (int32)si->intrcount; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_GVAL(IOV_NUMLOCALINTS): ++ int_val = (int32)0; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_GVAL(IOV_HOSTREG): ++ { ++ sdreg_t *sd_ptr = (sdreg_t *)params; ++ ++ if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) { ++ AP6211_ERR("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset); ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ ++ AP6211_DEBUG("%s: rreg%d at offset %d\n", __FUNCTION__, ++ (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32), ++ sd_ptr->offset); ++ if (sd_ptr->offset & 1) ++ int_val = 8; /* sdioh_sdmmc_rreg8(si, sd_ptr->offset); */ ++ else if (sd_ptr->offset & 2) ++ int_val = 16; /* sdioh_sdmmc_rreg16(si, sd_ptr->offset); */ ++ else ++ int_val = 32; /* sdioh_sdmmc_rreg(si, sd_ptr->offset); */ ++ ++ bcopy(&int_val, arg, sizeof(int_val)); ++ break; ++ } ++ ++ case IOV_SVAL(IOV_HOSTREG): ++ { ++ sdreg_t *sd_ptr = (sdreg_t *)params; ++ ++ if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) { ++ AP6211_ERR("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset); ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ ++ AP6211_DEBUG("%s: wreg%d value 0x%08x at offset %d\n", __FUNCTION__, sd_ptr->value, ++ (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32), ++ sd_ptr->offset); ++ break; ++ } ++ ++ case IOV_GVAL(IOV_DEVREG): ++ { ++ sdreg_t *sd_ptr = (sdreg_t *)params; ++ uint8 data = 0; ++ ++ if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) { ++ bcmerror = BCME_SDIO_ERROR; ++ break; ++ } ++ ++ int_val = (int)data; ++ bcopy(&int_val, arg, sizeof(int_val)); ++ break; ++ } ++ ++ case IOV_SVAL(IOV_DEVREG): ++ { ++ sdreg_t *sd_ptr = (sdreg_t *)params; ++ uint8 data = (uint8)sd_ptr->value; ++ ++ if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) { ++ bcmerror = BCME_SDIO_ERROR; ++ break; ++ } ++ break; ++ } ++ ++ default: ++ bcmerror = BCME_UNSUPPORTED; ++ break; ++ } ++exit: ++ ++ return bcmerror; ++} ++ ++#if defined(OOB_INTR_ONLY) && defined(HW_OOB) ++ ++SDIOH_API_RC ++sdioh_enable_hw_oob_intr(sdioh_info_t *sd, bool enable) ++{ ++ SDIOH_API_RC status; ++ uint8 data; ++ ++ if (enable) ++ data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE | SDIO_SEPINT_ACT_HI; ++ else ++ data = SDIO_SEPINT_ACT_HI; /* disable hw oob interrupt */ ++ ++ status = sdioh_request_byte(sd, SDIOH_WRITE, 0, SDIOD_CCCR_BRCM_SEPINT, &data); ++ return status; ++} ++#endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */ ++ ++extern SDIOH_API_RC ++sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) ++{ ++ SDIOH_API_RC status; ++ /* No lock needed since sdioh_request_byte does locking */ ++ status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data); ++ return status; ++} ++ ++extern SDIOH_API_RC ++sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) ++{ ++ /* No lock needed since sdioh_request_byte does locking */ ++ SDIOH_API_RC status; ++ status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data); ++ return status; ++} ++ ++static int ++sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr) ++{ ++ /* read 24 bits and return valid 17 bit addr */ ++ int i; ++ uint32 scratch, regdata; ++ uint8 *ptr = (uint8 *)&scratch; ++ for (i = 0; i < 3; i++) { ++ if ((sdioh_sdmmc_card_regread (sd, 0, regaddr, 1, ®data)) != SUCCESS) ++ AP6211_ERR("%s: Can't read!\n", __FUNCTION__); ++ ++ *ptr++ = (uint8) regdata; ++ regaddr++; ++ } ++ ++ /* Only the lower 17-bits are valid */ ++ scratch = ltoh32(scratch); ++ scratch &= 0x0001FFFF; ++ return (scratch); ++} ++ ++extern SDIOH_API_RC ++sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length) ++{ ++ uint32 count; ++ int offset; ++ uint32 foo; ++ uint8 *cis = cisd; ++ ++ AP6211_DEBUG("%s: Func = %d\n", __FUNCTION__, func); ++ ++ if (!sd->func_cis_ptr[func]) { ++ bzero(cis, length); ++ AP6211_ERR("%s: no func_cis_ptr[%d]\n", __FUNCTION__, func); ++ return SDIOH_API_RC_FAIL; ++ } ++ ++ AP6211_ERR("%s: func_cis_ptr[%d]=0x%04x\n", __FUNCTION__, func, sd->func_cis_ptr[func]); ++ ++ for (count = 0; count < length; count++) { ++ offset = sd->func_cis_ptr[func] + count; ++ if (sdioh_sdmmc_card_regread (sd, 0, offset, 1, &foo) < 0) { ++ AP6211_ERR("%s: regread failed: Can't read CIS\n", __FUNCTION__); ++ return SDIOH_API_RC_FAIL; ++ } ++ ++ *cis = (uint8)(foo & 0xff); ++ cis++; ++ } ++ ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++extern SDIOH_API_RC ++sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte) ++{ ++ int err_ret; ++#if defined(MMC_SDIO_ABORT) ++ int sdio_abort_retry = MMC_SDIO_ABORT_RETRY_LIMIT; ++#endif ++ int ret = 0; ++ ++ AP6211_DEBUG("%s: rw=%d, func=%d, addr=0x%05x\n", __FUNCTION__, rw, func, regaddr); ++ ++ DHD_PM_RESUME_WAIT(sdioh_request_byte_wait); ++ DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); ++ if(rw) { /* CMD52 Write */ ++ if (func == 0) { ++ /* Can only directly write to some F0 registers. Handle F2 enable ++ * as a special case. ++ */ ++ if (regaddr == SDIOD_CCCR_IOEN) { ++ if (gInstance->func[2]) { ++ sdio_claim_host(gInstance->func[2]); ++ if (*byte & SDIO_FUNC_ENABLE_2) { ++ /* Enable Function 2 */ ++ err_ret = sdio_enable_func(gInstance->func[2]); ++ if (err_ret) { ++ AP6211_ERR("bcmsdh_sdmmc: enable F2 failed:%d", ++ err_ret); ++ } ++ } else { ++ /* Disable Function 2 */ ++ err_ret = sdio_disable_func(gInstance->func[2]); ++ if (err_ret) { ++ AP6211_ERR("bcmsdh_sdmmc: Disab F2 failed:%d", ++ err_ret); ++ } ++ } ++ sdio_release_host(gInstance->func[2]); ++ } ++ } ++#if defined(MMC_SDIO_ABORT) ++ /* to allow abort command through F1 */ ++ else if (regaddr == SDIOD_CCCR_IOABORT) { ++ /* Because of SDIO3.0 host issue on Manta, ++ * sometimes the abort fails. ++ * Retrying again will fix this issue. ++ */ ++ while (sdio_abort_retry--) { ++ if (gInstance->func[func]) { ++ sdio_claim_host(gInstance->func[func]); ++ /* ++ * this sdio_f0_writeb() can be replaced with ++ * another api depending upon MMC driver change. ++ * As of this time, this is temporaray one ++ */ ++ sdio_writeb(gInstance->func[func], ++ *byte, regaddr, &err_ret); ++ sdio_release_host(gInstance->func[func]); ++ } ++ if (!err_ret) ++ break; ++ } ++ } ++#endif /* MMC_SDIO_ABORT */ ++ else if (regaddr < 0xF0) { ++ AP6211_ERR("bcmsdh_sdmmc: F0 Wr:0x%02x: write disallowed\n", regaddr); ++ } else { ++ /* Claim host controller, perform F0 write, and release */ ++ if (gInstance->func[func]) { ++ sdio_claim_host(gInstance->func[func]); ++ sdio_f0_writeb(gInstance->func[func], ++ *byte, regaddr, &err_ret); ++ sdio_release_host(gInstance->func[func]); ++ } ++ } ++ } else { ++ /* Claim host controller, perform Fn write, and release */ ++ if (gInstance->func[func]) { ++ sdio_claim_host(gInstance->func[func]); ++ sdio_writeb(gInstance->func[func], *byte, regaddr, &err_ret); ++ sdio_release_host(gInstance->func[func]); ++ } ++ } ++ } else { /* CMD52 Read */ ++ /* Claim host controller, perform Fn read, and release */ ++ if (gInstance->func[func]) { ++ sdio_claim_host(gInstance->func[func]); ++ if (func == 0) { ++ *byte = sdio_f0_readb(gInstance->func[func], regaddr, &err_ret); ++ } else { ++ *byte = sdio_readb(gInstance->func[func], regaddr, &err_ret); ++ } ++ sdio_release_host(gInstance->func[func]); ++ } ++ } ++ ++ //AW judge sdio read write timeout, 1s ++ ret = sw_mci_check_r1_ready(gInstance->func[func]->card->host, 1000); ++ if (ret != 0) ++ AP6211_DEBUG("%s data timeout.\n", __FUNCTION__); ++ ++ if (err_ret) { ++ AP6211_ERR("bcmsdh_sdmmc: Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n", ++ rw ? "Write" : "Read", func, regaddr, *byte, err_ret); ++ } ++ ++ return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); ++} ++ ++extern SDIOH_API_RC ++sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr, ++ uint32 *word, uint nbytes) ++{ ++ int err_ret = SDIOH_API_RC_FAIL; ++#if defined(MMC_SDIO_ABORT) ++ int sdio_abort_retry = MMC_SDIO_ABORT_RETRY_LIMIT; ++#endif ++ int ret = 0; ++ ++ if (func == 0) { ++ AP6211_ERR("%s: Only CMD52 allowed to F0.\n", __FUNCTION__); ++ return SDIOH_API_RC_FAIL; ++ } ++ ++ AP6211_DEBUG("%s: cmd_type=%d, rw=%d, func=%d, addr=0x%05x, nbytes=%d\n", ++ __FUNCTION__, cmd_type, rw, func, addr, nbytes); ++ ++ DHD_PM_RESUME_WAIT(sdioh_request_word_wait); ++ DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); ++ /* Claim host controller */ ++ sdio_claim_host(gInstance->func[func]); ++ ++ if(rw) { /* CMD53 Write */ ++ if (nbytes == 4) { ++ sdio_writel(gInstance->func[func], *word, addr, &err_ret); ++ } else if (nbytes == 2) { ++ sdio_writew(gInstance->func[func], (*word & 0xFFFF), addr, &err_ret); ++ } else { ++ AP6211_ERR("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes); ++ } ++ } else { /* CMD52 Read */ ++ if (nbytes == 4) { ++ *word = sdio_readl(gInstance->func[func], addr, &err_ret); ++ } else if (nbytes == 2) { ++ *word = sdio_readw(gInstance->func[func], addr, &err_ret) & 0xFFFF; ++ } else { ++ AP6211_ERR("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes); ++ } ++ } ++ ++ //AW judge sdio read write timeout, 1s ++ ret = sw_mci_check_r1_ready(gInstance->func[func]->card->host, 1000); ++ if (ret != 0) ++ AP6211_DEBUG("%s data timeout.\n", __FUNCTION__); ++ ++ /* Release host controller */ ++ sdio_release_host(gInstance->func[func]); ++ ++ if (err_ret) { ++#if defined(MMC_SDIO_ABORT) ++ /* Any error on CMD53 transaction should abort that function using function 0. */ ++ while (sdio_abort_retry--) { ++ if (gInstance->func[0]) { ++ sdio_claim_host(gInstance->func[0]); ++ /* ++ * this sdio_f0_writeb() can be replaced with another api ++ * depending upon MMC driver change. ++ * As of this time, this is temporaray one ++ */ ++ sdio_writeb(gInstance->func[0], ++ func, SDIOD_CCCR_IOABORT, &err_ret); ++ sdio_release_host(gInstance->func[0]); ++ } ++ if (!err_ret) ++ break; ++ } ++ if (err_ret) ++#endif /* MMC_SDIO_ABORT */ ++ { ++ AP6211_ERR("bcmsdh_sdmmc: Failed to %s word, Err: 0x%08x\n", ++ rw ? "Write" : "Read", err_ret); ++ } ++ } ++ ++ return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); ++} ++ ++static SDIOH_API_RC ++sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func, ++ uint addr, void *pkt) ++{ ++ bool fifo = (fix_inc == SDIOH_DATA_FIX); ++ uint32 SGCount = 0; ++ int err_ret = 0; ++ void *pnext, *pprev; ++ uint ttl_len, dma_len, lft_len, xfred_len, pkt_len; ++ uint blk_num; ++ int blk_size; ++ struct mmc_request mmc_req; ++ struct mmc_command mmc_cmd; ++ struct mmc_data mmc_dat; ++ int ret = 0; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ ASSERT(pkt); ++ DHD_PM_RESUME_WAIT(sdioh_request_packet_wait); ++ DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); ++ ++ ttl_len = xfred_len = 0; ++ /* at least 4 bytes alignment of skb buff is guaranteed */ ++ for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) ++ ttl_len += PKTLEN(sd->osh, pnext); ++ ++ blk_size = sd->client_block_size[func]; ++ if (!sd->use_rxchain || ttl_len <= blk_size) { ++ blk_num = 0; ++ dma_len = 0; ++ } else { ++ blk_num = ttl_len / blk_size; ++ dma_len = blk_num * blk_size; ++ } ++ lft_len = ttl_len - dma_len; ++ ++ AP6211_DEBUG("%s: %s %dB to func%d:%08x, %d blks with DMA, %dB leftover\n", ++ __FUNCTION__, write ? "W" : "R", ++ ttl_len, func, addr, blk_num, lft_len); ++ ++ if (0 != dma_len) { ++ memset(&mmc_req, 0, sizeof(struct mmc_request)); ++ memset(&mmc_cmd, 0, sizeof(struct mmc_command)); ++ memset(&mmc_dat, 0, sizeof(struct mmc_data)); ++ ++ /* Set up DMA descriptors */ ++ pprev = pkt; ++ for (pnext = pkt; ++ pnext && dma_len; ++ pnext = PKTNEXT(sd->osh, pnext)) { ++ pkt_len = PKTLEN(sd->osh, pnext); ++ ++ if (dma_len > pkt_len) ++ dma_len -= pkt_len; ++ else { ++ pkt_len = xfred_len = dma_len; ++ dma_len = 0; ++ pkt = pnext; ++ } ++ ++ sg_set_buf(&sd->sg_list[SGCount++], ++ (uint8*)PKTDATA(sd->osh, pnext), ++ pkt_len); ++ ++ if (SGCount >= SDIOH_SDMMC_MAX_SG_ENTRIES) { ++ AP6211_ERR("%s: sg list entries exceed limit\n", ++ __FUNCTION__); ++ return (SDIOH_API_RC_FAIL); ++ } ++ } ++ ++ mmc_dat.sg = sd->sg_list; ++ mmc_dat.sg_len = SGCount; ++ mmc_dat.blksz = blk_size; ++ mmc_dat.blocks = blk_num; ++ mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; ++ ++ mmc_cmd.opcode = 53; /* SD_IO_RW_EXTENDED */ ++ mmc_cmd.arg = write ? 1<<31 : 0; ++ mmc_cmd.arg |= (func & 0x7) << 28; ++ mmc_cmd.arg |= 1<<27; ++ mmc_cmd.arg |= fifo ? 0 : 1<<26; ++ mmc_cmd.arg |= (addr & 0x1FFFF) << 9; ++ mmc_cmd.arg |= blk_num & 0x1FF; ++ mmc_cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC; ++ ++ mmc_req.cmd = &mmc_cmd; ++ mmc_req.data = &mmc_dat; ++ ++ sdio_claim_host(gInstance->func[func]); ++ mmc_set_data_timeout(&mmc_dat, gInstance->func[func]->card); ++ mmc_wait_for_req(gInstance->func[func]->card->host, &mmc_req); ++ sdio_release_host(gInstance->func[func]); ++ ++ err_ret = mmc_cmd.error? mmc_cmd.error : mmc_dat.error; ++ if (0 != err_ret) { ++ AP6211_ERR("%s:CMD53 %s failed with code %d\n", ++ __FUNCTION__, ++ write ? "write" : "read", ++ err_ret); ++ AP6211_ERR("%s:Disabling rxchain and fire it with PIO\n", ++ __FUNCTION__); ++ sd->use_rxchain = FALSE; ++ pkt = pprev; ++ lft_len = ttl_len; ++ } else if (!fifo) { ++ addr = addr + ttl_len - lft_len - dma_len; ++ } ++ } ++ ++ /* PIO mode */ ++ if (0 != lft_len) { ++ /* Claim host controller */ ++ sdio_claim_host(gInstance->func[func]); ++ for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) { ++ uint8 *buf = (uint8*)PKTDATA(sd->osh, pnext) + ++ xfred_len; ++ pkt_len = PKTLEN(sd->osh, pnext); ++ if (0 != xfred_len) { ++ pkt_len -= xfred_len; ++ xfred_len = 0; ++ } ++ ++ /* Align Patch ++ * read or small packet(ex:BDC header) skip 32 byte align ++ * otherwise, padding DHD_SDALIGN for performance ++ */ ++ if (write == 0 || pkt_len < 32) ++ pkt_len = (pkt_len + 3) & 0xFFFFFFFC; ++ else if (pkt_len % blk_size) ++ pkt_len += blk_size - (pkt_len % blk_size); ++ ++#ifdef CONFIG_MMC_MSM7X00A ++ if ((pkt_len % 64) == 32) { ++ AP6211_DEBUG("%s: Rounding up TX packet +=32\n", __FUNCTION__); ++ pkt_len += 32; ++ } ++#endif /* CONFIG_MMC_MSM7X00A */ ++ ++ if ((write) && (!fifo)) ++ err_ret = sdio_memcpy_toio( ++ gInstance->func[func], ++ addr, buf, pkt_len); ++ else if (write) ++ err_ret = sdio_memcpy_toio( ++ gInstance->func[func], ++ addr, buf, pkt_len); ++ else if (fifo) ++ err_ret = sdio_readsb( ++ gInstance->func[func], ++ buf, addr, pkt_len); ++ else ++ err_ret = sdio_memcpy_fromio( ++ gInstance->func[func], ++ buf, addr, pkt_len); ++ ++ //AW judge sdio read write timeout, 1s ++ ret = sw_mci_check_r1_ready(gInstance->func[func]->card->host, 1000); ++ if (ret != 0) ++ AP6211_DEBUG("%s data timeout.\n", __FUNCTION__); ++ ++ if (err_ret) ++ AP6211_ERR("%s: %s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=%d\n", ++ __FUNCTION__, ++ (write) ? "TX" : "RX", ++ pnext, SGCount, addr, pkt_len, err_ret); ++ else ++ AP6211_DEBUG("%s: %s xfr'd %p[%d], addr=0x%05x, len=%d\n", ++ __FUNCTION__, ++ (write) ? "TX" : "RX", ++ pnext, SGCount, addr, pkt_len); ++ ++ if (!fifo) ++ addr += pkt_len; ++ SGCount ++; ++ } ++ sdio_release_host(gInstance->func[func]); ++ } ++ ++ AP6211_DEBUG("%s: Exit\n", __FUNCTION__); ++ return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); ++} ++ ++ ++/* ++ * This function takes a buffer or packet, and fixes everything up so that in the ++ * end, a DMA-able packet is created. ++ * ++ * A buffer does not have an associated packet pointer, and may or may not be aligned. ++ * A packet may consist of a single packet, or a packet chain. If it is a packet chain, ++ * then all the packets in the chain must be properly aligned. If the packet data is not ++ * aligned, then there may only be one packet, and in this case, it is copied to a new ++ * aligned packet. ++ * ++ */ ++extern SDIOH_API_RC ++sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, uint func, ++ uint addr, uint reg_width, uint buflen_u, uint8 *buffer, void *pkt) ++{ ++ SDIOH_API_RC Status; ++ void *mypkt = NULL; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ DHD_PM_RESUME_WAIT(sdioh_request_buffer_wait); ++ DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); ++ /* Case 1: we don't have a packet. */ ++ if (pkt == NULL) { ++ AP6211_DEBUG("%s: Creating new %s Packet, len=%d\n", ++ __FUNCTION__, write ? "TX" : "RX", buflen_u); ++#ifdef CONFIG_DHD_USE_STATIC_BUF ++ if (!(mypkt = PKTGET_STATIC(sd->osh, buflen_u, write ? TRUE : FALSE))) ++#else ++ if (!(mypkt = PKTGET(sd->osh, buflen_u, write ? TRUE : FALSE))) ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ { ++ AP6211_ERR("%s: PKTGET failed: len %d\n", ++ __FUNCTION__, buflen_u); ++ return SDIOH_API_RC_FAIL; ++ } ++ ++ /* For a write, copy the buffer data into the packet. */ ++ if (write) { ++ bcopy(buffer, PKTDATA(sd->osh, mypkt), buflen_u); ++ } ++ ++ Status = sdioh_request_packet(sd, fix_inc, write, func, addr, mypkt); ++ ++ /* For a read, copy the packet data back to the buffer. */ ++ if (!write) { ++ bcopy(PKTDATA(sd->osh, mypkt), buffer, buflen_u); ++ } ++#ifdef CONFIG_DHD_USE_STATIC_BUF ++ PKTFREE_STATIC(sd->osh, mypkt, write ? TRUE : FALSE); ++#else ++ PKTFREE(sd->osh, mypkt, write ? TRUE : FALSE); ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ } else if (((uint32)(PKTDATA(sd->osh, pkt)) & DMA_ALIGN_MASK) != 0) { ++ /* Case 2: We have a packet, but it is unaligned. */ ++ ++ /* In this case, we cannot have a chain. */ ++ ASSERT(PKTNEXT(sd->osh, pkt) == NULL); ++ ++ AP6211_DEBUG("%s: Creating aligned %s Packet, len=%d\n", ++ __FUNCTION__, write ? "TX" : "RX", PKTLEN(sd->osh, pkt)); ++#ifdef CONFIG_DHD_USE_STATIC_BUF ++ if (!(mypkt = PKTGET_STATIC(sd->osh, PKTLEN(sd->osh, pkt), write ? TRUE : FALSE))) ++#else ++ if (!(mypkt = PKTGET(sd->osh, PKTLEN(sd->osh, pkt), write ? TRUE : FALSE))) ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ { ++ AP6211_ERR("%s: PKTGET failed: len %d\n", ++ __FUNCTION__, PKTLEN(sd->osh, pkt)); ++ return SDIOH_API_RC_FAIL; ++ } ++ ++ /* For a write, copy the buffer data into the packet. */ ++ if (write) { ++ bcopy(PKTDATA(sd->osh, pkt), ++ PKTDATA(sd->osh, mypkt), ++ PKTLEN(sd->osh, pkt)); ++ } ++ ++ Status = sdioh_request_packet(sd, fix_inc, write, func, addr, mypkt); ++ ++ /* For a read, copy the packet data back to the buffer. */ ++ if (!write) { ++ bcopy(PKTDATA(sd->osh, mypkt), ++ PKTDATA(sd->osh, pkt), ++ PKTLEN(sd->osh, mypkt)); ++ } ++#ifdef CONFIG_DHD_USE_STATIC_BUF ++ PKTFREE_STATIC(sd->osh, mypkt, write ? TRUE : FALSE); ++#else ++ PKTFREE(sd->osh, mypkt, write ? TRUE : FALSE); ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ } else { /* case 3: We have a packet and it is aligned. */ ++ AP6211_DEBUG("%s: Aligned %s Packet, direct DMA\n", ++ __FUNCTION__, write ? "Tx" : "Rx"); ++ Status = sdioh_request_packet(sd, fix_inc, write, func, addr, pkt); ++ } ++ ++ return (Status); ++} ++ ++/* this function performs "abort" for both of host & device */ ++extern int ++sdioh_abort(sdioh_info_t *sd, uint func) ++{ ++#if defined(MMC_SDIO_ABORT) ++ char t_func = (char) func; ++#endif /* defined(MMC_SDIO_ABORT) */ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++#if defined(MMC_SDIO_ABORT) ++ /* issue abort cmd52 command through F1 */ ++ sdioh_request_byte(sd, SD_IO_OP_WRITE, SDIO_FUNC_0, SDIOD_CCCR_IOABORT, &t_func); ++#endif /* defined(MMC_SDIO_ABORT) */ ++ ++ AP6211_DEBUG("%s: Exit\n", __FUNCTION__); ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++/* Reset and re-initialize the device */ ++int sdioh_sdio_reset(sdioh_info_t *si) ++{ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ AP6211_DEBUG("%s: Exit\n", __FUNCTION__); ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++/* Disable device interrupt */ ++void ++sdioh_sdmmc_devintr_off(sdioh_info_t *sd) ++{ ++ AP6211_DEBUG("%s: %d\n", __FUNCTION__, sd->use_client_ints); ++ sd->intmask &= ~CLIENT_INTR; ++} ++ ++/* Enable device interrupt */ ++void ++sdioh_sdmmc_devintr_on(sdioh_info_t *sd) ++{ ++ AP6211_DEBUG("%s: %d\n", __FUNCTION__, sd->use_client_ints); ++ sd->intmask |= CLIENT_INTR; ++} ++ ++/* Read client card reg */ ++int ++sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data) ++{ ++ ++ if ((func == 0) || (regsize == 1)) { ++ uint8 temp = 0; ++ ++ sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp); ++ *data = temp; ++ *data &= 0xff; ++ AP6211_DEBUG("%s: byte read data=0x%02x\n", ++ __FUNCTION__, *data); ++ } else { ++ sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, data, regsize); ++ if (regsize == 2) ++ *data &= 0xffff; ++ ++ AP6211_DEBUG("%s: word read data=0x%08x\n", ++ __FUNCTION__, *data); ++ } ++ ++ return SUCCESS; ++} ++ ++#if !defined(OOB_INTR_ONLY) ++/* bcmsdh_sdmmc interrupt handler */ ++static void IRQHandler(struct sdio_func *func) ++{ ++ sdioh_info_t *sd; ++ ++ AP6211_DEBUG("bcmsdh_sdmmc: ***IRQHandler\n"); ++ sd = gInstance->sd; ++ ++ ASSERT(sd != NULL); ++ sdio_release_host(gInstance->func[0]); ++ ++ if (sd->use_client_ints) { ++ sd->intrcount++; ++ ASSERT(sd->intr_handler); ++ ASSERT(sd->intr_handler_arg); ++ (sd->intr_handler)(sd->intr_handler_arg); ++ } else { ++ AP6211_ERR("bcmsdh_sdmmc: ***IRQHandler\n"); ++ ++ AP6211_ERR("%s: Not ready for intr: enabled %d, handler %p\n", ++ __FUNCTION__, sd->client_intr_enabled, sd->intr_handler); ++ } ++ ++ sdio_claim_host(gInstance->func[0]); ++} ++ ++/* bcmsdh_sdmmc interrupt handler for F2 (dummy handler) */ ++static void IRQHandlerF2(struct sdio_func *func) ++{ ++ sdioh_info_t *sd; ++ ++ AP6211_DEBUG("bcmsdh_sdmmc: ***IRQHandlerF2\n"); ++ ++ sd = gInstance->sd; ++ ++ ASSERT(sd != NULL); ++ BCM_REFERENCE(sd); ++} ++#endif /* !defined(OOB_INTR_ONLY) */ ++ ++#ifdef NOTUSED ++/* Write client card reg */ ++static int ++sdioh_sdmmc_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data) ++{ ++ ++ if ((func == 0) || (regsize == 1)) { ++ uint8 temp; ++ ++ temp = data & 0xff; ++ sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp); ++ AP6211_DEBUG("%s: byte write data=0x%02x\n", ++ __FUNCTION__, data); ++ } else { ++ if (regsize == 2) ++ data &= 0xffff; ++ ++ sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, &data, regsize); ++ ++ AP6211_DEBUG("%s: word write data=0x%08x\n", ++ __FUNCTION__, data); ++ } ++ ++ return SUCCESS; ++} ++#endif /* NOTUSED */ ++ ++int ++sdioh_start(sdioh_info_t *si, int stage) ++{ ++ int ret; ++ sdioh_info_t *sd = gInstance->sd; ++ ++ if (!sd) return (0); ++ ++ /* Need to do this stages as we can't enable the interrupt till ++ downloading of the firmware is complete, other wise polling ++ sdio access will come in way ++ */ ++ if (gInstance->func[0]) { ++ if (stage == 0) { ++ /* Since the power to the chip is killed, we will have ++ re enumerate the device again. Set the block size ++ and enable the fucntion 1 for in preparation for ++ downloading the code ++ */ ++ /* sdio_reset_comm() - has been fixed in latest kernel/msm.git for Linux ++ 2.6.27. The implementation prior to that is buggy, and needs broadcom's ++ patch for it ++ */ ++ if ((ret = sdio_reset_comm(gInstance->func[0]->card))) { ++ AP6211_ERR("%s Failed, error = %d\n", __FUNCTION__, ret); ++ return ret; ++ } ++ else { ++ sd->num_funcs = 2; ++ sd->sd_blockmode = TRUE; ++ sd->use_client_ints = TRUE; ++ sd->client_block_size[0] = 64; ++ ++ if (gInstance->func[1]) { ++ /* Claim host controller */ ++ sdio_claim_host(gInstance->func[1]); ++ ++ sd->client_block_size[1] = 64; ++ if (sdio_set_block_size(gInstance->func[1], 64)) { ++ AP6211_ERR("bcmsdh_sdmmc: Failed to set F1 blocksize\n"); ++ } ++ ++ /* Release host controller F1 */ ++ sdio_release_host(gInstance->func[1]); ++ } ++ ++ if (gInstance->func[2]) { ++ /* Claim host controller F2 */ ++ sdio_claim_host(gInstance->func[2]); ++ ++ sd->client_block_size[2] = sd_f2_blocksize; ++ if (sdio_set_block_size(gInstance->func[2], ++ sd_f2_blocksize)) { ++ AP6211_ERR("bcmsdh_sdmmc: Failed to set F2 " ++ "blocksize to %d\n", sd_f2_blocksize); ++ } ++ ++ /* Release host controller F2 */ ++ sdio_release_host(gInstance->func[2]); ++ } ++ ++ sdioh_sdmmc_card_enablefuncs(sd); ++ } ++ } else { ++#if !defined(OOB_INTR_ONLY) ++ sdio_claim_host(gInstance->func[0]); ++ if (gInstance->func[2]) ++ sdio_claim_irq(gInstance->func[2], IRQHandlerF2); ++ if (gInstance->func[1]) ++ sdio_claim_irq(gInstance->func[1], IRQHandler); ++ sdio_release_host(gInstance->func[0]); ++#else /* defined(OOB_INTR_ONLY) */ ++#if defined(HW_OOB) ++ sdioh_enable_func_intr(); ++#endif ++ bcmsdh_oob_intr_set(TRUE); ++#endif /* !defined(OOB_INTR_ONLY) */ ++ } ++ } ++ else ++ AP6211_ERR("%s Failed\n", __FUNCTION__); ++ ++ return (0); ++} ++ ++int ++sdioh_stop(sdioh_info_t *si) ++{ ++ /* MSM7201A Android sdio stack has bug with interrupt ++ So internaly within SDIO stack they are polling ++ which cause issue when device is turned off. So ++ unregister interrupt with SDIO stack to stop the ++ polling ++ */ ++ if (gInstance->func[0]) { ++#if !defined(OOB_INTR_ONLY) ++ sdio_claim_host(gInstance->func[0]); ++ if (gInstance->func[1]) ++ sdio_release_irq(gInstance->func[1]); ++ if (gInstance->func[2]) ++ sdio_release_irq(gInstance->func[2]); ++ sdio_release_host(gInstance->func[0]); ++#else /* defined(OOB_INTR_ONLY) */ ++#if defined(HW_OOB) ++ sdioh_disable_func_intr(); ++#endif ++ bcmsdh_oob_intr_set(FALSE); ++#endif /* !defined(OOB_INTR_ONLY) */ ++ } ++ else ++ AP6211_ERR("%s Failed\n", __FUNCTION__); ++ return (0); ++} ++ ++int ++sdioh_waitlockfree(sdioh_info_t *sd) ++{ ++ return (1); ++} ++ ++ ++SDIOH_API_RC ++sdioh_gpioouten(sdioh_info_t *sd, uint32 gpio) ++{ ++ return SDIOH_API_RC_FAIL; ++} ++ ++SDIOH_API_RC ++sdioh_gpioout(sdioh_info_t *sd, uint32 gpio, bool enab) ++{ ++ return SDIOH_API_RC_FAIL; ++} ++ ++bool ++sdioh_gpioin(sdioh_info_t *sd, uint32 gpio) ++{ ++ return FALSE; ++} ++ ++SDIOH_API_RC ++sdioh_gpio_init(sdioh_info_t *sd) ++{ ++ return SDIOH_API_RC_FAIL; ++} +diff --git a/drivers/net/wireless/ap6211/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/ap6211/bcmsdh_sdmmc_linux.c +new file mode 100755 +index 0000000..98b5818 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/bcmsdh_sdmmc_linux.c +@@ -0,0 +1,427 @@ ++/* ++ * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmsdh_sdmmc_linux.c 363783 2012-10-19 06:27:14Z $ ++ */ ++ ++#include ++#include ++#include /* SDIO Device and Protocol Specs */ ++#include /* bcmsdh to/from specific controller APIs */ ++#include /* to get msglevel bit values */ ++ ++#include /* request_irq() */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++#if !defined(SDIO_VENDOR_ID_BROADCOM) ++#define SDIO_VENDOR_ID_BROADCOM 0x02d0 ++#endif /* !defined(SDIO_VENDOR_ID_BROADCOM) */ ++ ++#define SDIO_DEVICE_ID_BROADCOM_DEFAULT 0x0000 ++ ++#if !defined(SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) ++#define SDIO_DEVICE_ID_BROADCOM_4325_SDGWB 0x0492 /* BCM94325SDGWB */ ++#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) */ ++#if !defined(SDIO_DEVICE_ID_BROADCOM_4325) ++#define SDIO_DEVICE_ID_BROADCOM_4325 0x0493 ++#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325) */ ++#if !defined(SDIO_DEVICE_ID_BROADCOM_4329) ++#define SDIO_DEVICE_ID_BROADCOM_4329 0x4329 ++#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4329) */ ++#if !defined(SDIO_DEVICE_ID_BROADCOM_4319) ++#define SDIO_DEVICE_ID_BROADCOM_4319 0x4319 ++#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4319) */ ++#if !defined(SDIO_DEVICE_ID_BROADCOM_4330) ++#define SDIO_DEVICE_ID_BROADCOM_4330 0x4330 ++#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4330) */ ++#if !defined(SDIO_DEVICE_ID_BROADCOM_4334) ++#define SDIO_DEVICE_ID_BROADCOM_4334 0x4334 ++#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4334) */ ++#if !defined(SDIO_DEVICE_ID_BROADCOM_4324) ++#define SDIO_DEVICE_ID_BROADCOM_4324 0x4324 ++#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4324) */ ++#if !defined(SDIO_DEVICE_ID_BROADCOM_43239) ++#define SDIO_DEVICE_ID_BROADCOM_43239 43239 ++#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_43239) */ ++ ++ ++#include ++ ++#include ++ ++#ifdef WL_CFG80211 ++extern void wl_cfg80211_set_parent_dev(void *dev); ++#endif ++ ++extern void sdioh_sdmmc_devintr_off(sdioh_info_t *sd); ++extern void sdioh_sdmmc_devintr_on(sdioh_info_t *sd); ++extern int dhd_os_check_wakelock(void *dhdp); ++extern int dhd_os_check_if_up(void *dhdp); ++extern void *bcmsdh_get_drvdata(void); ++ ++int sdio_function_init(void); ++void sdio_function_cleanup(void); ++ ++#define DESCRIPTION "bcmsdh_sdmmc Driver" ++#define AUTHOR "Broadcom Corporation" ++ ++/* module param defaults */ ++static int clockoverride = 0; ++ ++module_param(clockoverride, int, 0644); ++MODULE_PARM_DESC(clockoverride, "SDIO card clock override"); ++ ++PBCMSDH_SDMMC_INSTANCE gInstance; ++ ++/* Maximum number of bcmsdh_sdmmc devices supported by driver */ ++#define BCMSDH_SDMMC_MAX_DEVICES 1 ++ ++extern int bcmsdh_probe(struct device *dev); ++extern int bcmsdh_remove(struct device *dev); ++extern volatile bool dhd_mmc_suspend; ++ ++static int bcmsdh_sdmmc_probe(struct sdio_func *func, ++ const struct sdio_device_id *id) ++{ ++ int ret = 0; ++ static struct sdio_func sdio_func_0; ++ ++ if (func) { ++ AP6211_DEBUG("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__); ++ AP6211_DEBUG("sdio_bcmsdh: func->class=%x\n", func->class); ++ AP6211_DEBUG("sdio_vendor: 0x%04x\n", func->vendor); ++ AP6211_DEBUG("sdio_device: 0x%04x\n", func->device); ++ AP6211_DEBUG("Function#: 0x%04x\n", func->num); ++ ++ if (func->num == 1) { ++ sdio_func_0.num = 0; ++ sdio_func_0.card = func->card; ++ gInstance->func[0] = &sdio_func_0; ++ if(func->device == 0x4) { /* 4318 */ ++ gInstance->func[2] = NULL; ++ AP6211_DEBUG("NIC found, calling bcmsdh_probe...\n"); ++ ret = bcmsdh_probe(&func->dev); ++ } ++ } ++ ++ gInstance->func[func->num] = func; ++ ++ if (func->num == 2) { ++ #ifdef WL_CFG80211 ++ wl_cfg80211_set_parent_dev(&func->dev); ++ #endif ++ AP6211_DEBUG("F2 found, calling bcmsdh_probe...\n"); ++ ret = bcmsdh_probe(&func->dev); ++ } ++ } else { ++ ret = -ENODEV; ++ } ++ ++ return ret; ++} ++ ++static void bcmsdh_sdmmc_remove(struct sdio_func *func) ++{ ++ if (func) { ++ AP6211_DEBUG("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__); ++ AP6211_DEBUG("sdio_bcmsdh: func->class=%x\n", func->class); ++ AP6211_DEBUG("sdio_vendor: 0x%04x\n", func->vendor); ++ AP6211_DEBUG("sdio_device: 0x%04x\n", func->device); ++ AP6211_DEBUG("Function#: 0x%04x\n", func->num); ++ ++ if (gInstance->func[2]) { ++ AP6211_DEBUG("F2 found, calling bcmsdh_remove...\n"); ++ bcmsdh_remove(&func->dev); ++ gInstance->func[2] = NULL; ++ } ++ if (func->num == 1) { ++ sdio_claim_host(func); ++ sdio_disable_func(func); ++ sdio_release_host(func); ++ gInstance->func[1] = NULL; ++ } ++ } ++} ++ ++/* devices we support, null terminated */ ++static const struct sdio_device_id bcmsdh_sdmmc_ids[] = { ++ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_DEFAULT) }, ++ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) }, ++ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325) }, ++ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329) }, ++ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4319) }, ++ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330) }, ++ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334) }, ++ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4324) }, ++ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43239) }, ++ { SDIO_DEVICE_CLASS(SDIO_CLASS_NONE) }, ++ { /* end: all zeroes */ }, ++}; ++ ++MODULE_DEVICE_TABLE(sdio, bcmsdh_sdmmc_ids); ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) ++static int bcmsdh_sdmmc_suspend(struct device *pdev) ++{ ++ struct sdio_func *func = dev_to_sdio_func(pdev); ++ mmc_pm_flag_t sdio_flags; ++ int ret; ++ ++ if (func->num != 2) ++ return 0; ++ ++ AP6211_DEBUG("%s Enter\n", __FUNCTION__); ++ ++ if (dhd_os_check_wakelock(bcmsdh_get_drvdata())) ++ return -EBUSY; ++ ++ sdio_flags = sdio_get_host_pm_caps(func); ++ ++ if (!(sdio_flags & MMC_PM_KEEP_POWER)) { ++ AP6211_ERR("%s: can't keep power while host is suspended\n", __FUNCTION__); ++ return -EINVAL; ++ } ++ ++ /* keep power while host suspended */ ++ ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); ++ if (ret) { ++ AP6211_ERR("%s: error while trying to keep power\n", __FUNCTION__); ++ return ret; ++ } ++ ++#if defined(OOB_INTR_ONLY) ++ bcmsdh_oob_intr_set(0); ++#endif /* defined(OOB_INTR_ONLY) */ ++ dhd_mmc_suspend = TRUE; ++ smp_mb(); ++ ++ return 0; ++} ++ ++static int bcmsdh_sdmmc_resume(struct device *pdev) ++{ ++#if defined(OOB_INTR_ONLY) ++ struct sdio_func *func = dev_to_sdio_func(pdev); ++#endif /* defined(OOB_INTR_ONLY) */ ++ AP6211_DEBUG("%s Enter\n", __FUNCTION__); ++ ++ dhd_mmc_suspend = FALSE; ++#if defined(OOB_INTR_ONLY) ++ if ((func->num == 2) && dhd_os_check_if_up(bcmsdh_get_drvdata())) ++ bcmsdh_oob_intr_set(1); ++#endif /* (OOB_INTR_ONLY) */ ++ smp_mb(); ++ return 0; ++} ++ ++static const struct dev_pm_ops bcmsdh_sdmmc_pm_ops = { ++ .suspend = bcmsdh_sdmmc_suspend, ++ .resume = bcmsdh_sdmmc_resume, ++}; ++#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) */ ++ ++#if defined(BCMLXSDMMC) ++static struct semaphore *notify_semaphore = NULL; ++ ++static int dummy_probe(struct sdio_func *func, ++ const struct sdio_device_id *id) ++{ ++ if (notify_semaphore) ++ up(notify_semaphore); ++ return 0; ++} ++ ++static void dummy_remove(struct sdio_func *func) ++{ ++} ++ ++static struct sdio_driver dummy_sdmmc_driver = { ++ .probe = dummy_probe, ++ .remove = dummy_remove, ++ .name = "dummy_sdmmc", ++ .id_table = bcmsdh_sdmmc_ids, ++ }; ++ ++int sdio_func_reg_notify(void* semaphore) ++{ ++ notify_semaphore = semaphore; ++ return sdio_register_driver(&dummy_sdmmc_driver); ++} ++ ++void sdio_func_unreg_notify(void) ++{ ++ sdio_unregister_driver(&dummy_sdmmc_driver); ++} ++ ++#endif /* defined(BCMLXSDMMC) */ ++ ++static struct sdio_driver bcmsdh_sdmmc_driver = { ++ .probe = bcmsdh_sdmmc_probe, ++ .remove = bcmsdh_sdmmc_remove, ++ .name = "bcmsdh_sdmmc", ++ .id_table = bcmsdh_sdmmc_ids, ++#if !defined(CONFIG_ARCH_RHEA) || !defined(CONFIG_ARCH_CAPRI) ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) ++ .drv = { ++ .pm = &bcmsdh_sdmmc_pm_ops, ++ }, ++#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) */ ++#endif /* !defined(CONFIG_ARCH_RHEA) || !defined(CONFIG_ARCH_CAPRI) */ ++ }; ++ ++struct sdos_info { ++ sdioh_info_t *sd; ++ spinlock_t lock; ++}; ++ ++ ++int ++sdioh_sdmmc_osinit(sdioh_info_t *sd) ++{ ++ struct sdos_info *sdos; ++ ++ if (!sd) ++ return BCME_BADARG; ++ ++ sdos = (struct sdos_info*)MALLOC(sd->osh, sizeof(struct sdos_info)); ++ sd->sdos_info = (void*)sdos; ++ if (sdos == NULL) ++ return BCME_NOMEM; ++ ++ sdos->sd = sd; ++ spin_lock_init(&sdos->lock); ++ return BCME_OK; ++} ++ ++void ++sdioh_sdmmc_osfree(sdioh_info_t *sd) ++{ ++ struct sdos_info *sdos; ++ ASSERT(sd && sd->sdos_info); ++ ++ sdos = (struct sdos_info *)sd->sdos_info; ++ MFREE(sd->osh, sdos, sizeof(struct sdos_info)); ++} ++ ++/* Interrupt enable/disable */ ++SDIOH_API_RC ++sdioh_interrupt_set(sdioh_info_t *sd, bool enable) ++{ ++ ulong flags; ++ struct sdos_info *sdos; ++ ++ if (!sd) ++ return BCME_BADARG; ++ ++ AP6211_DEBUG("%s: %s\n", __FUNCTION__, enable ? "Enabling" : "Disabling"); ++ ++ sdos = (struct sdos_info *)sd->sdos_info; ++ ASSERT(sdos); ++ ++#if !defined(OOB_INTR_ONLY) ++ if (enable && !(sd->intr_handler && sd->intr_handler_arg)) { ++ AP6211_ERR("%s: no handler registered, will not enable\n", __FUNCTION__); ++ return SDIOH_API_RC_FAIL; ++ } ++#endif /* !defined(OOB_INTR_ONLY) */ ++ ++ /* Ensure atomicity for enable/disable calls */ ++ spin_lock_irqsave(&sdos->lock, flags); ++ ++ sd->client_intr_enabled = enable; ++ if (enable) { ++ sdioh_sdmmc_devintr_on(sd); ++ } else { ++ sdioh_sdmmc_devintr_off(sd); ++ } ++ ++ spin_unlock_irqrestore(&sdos->lock, flags); ++ ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++ ++#ifdef BCMSDH_MODULE ++static int __init ++bcmsdh_module_init(void) ++{ ++ int error = 0; ++ error = sdio_function_init(); ++ return error; ++} ++ ++static void __exit ++bcmsdh_module_cleanup(void) ++{ ++ sdio_function_cleanup(); ++} ++ ++module_init(bcmsdh_module_init); ++module_exit(bcmsdh_module_cleanup); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_DESCRIPTION(DESCRIPTION); ++MODULE_AUTHOR(AUTHOR); ++ ++#endif /* BCMSDH_MODULE */ ++/* ++ * module init ++*/ ++int sdio_function_init(void) ++{ ++ int error = 0; ++ AP6211_DEBUG("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__); ++ ++ gInstance = kzalloc(sizeof(BCMSDH_SDMMC_INSTANCE), GFP_KERNEL); ++ if (!gInstance) ++ return -ENOMEM; ++ ++ error = sdio_register_driver(&bcmsdh_sdmmc_driver); ++ if (error && gInstance) { ++ kfree(gInstance); ++ gInstance = 0; ++ } ++ ++ return error; ++} ++ ++/* ++ * module cleanup ++*/ ++extern int bcmsdh_remove(struct device *dev); ++void sdio_function_cleanup(void) ++{ ++ AP6211_DEBUG("%s Enter\n", __FUNCTION__); ++ ++ ++ sdio_unregister_driver(&bcmsdh_sdmmc_driver); ++ ++ if (gInstance) ++ kfree(gInstance); ++} +diff --git a/drivers/net/wireless/ap6211/bcmutils.c b/drivers/net/wireless/ap6211/bcmutils.c +new file mode 100755 +index 0000000..631125a +--- /dev/null ++++ b/drivers/net/wireless/ap6211/bcmutils.c +@@ -0,0 +1,2095 @@ ++/* ++ * Driver O/S-independent utility routines ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * $Id: bcmutils.c 312855 2012-02-04 02:01:18Z $ ++ */ ++ ++#include ++#include ++#include ++#include ++#ifdef BCMDRIVER ++ ++#include ++#include ++ ++#else /* !BCMDRIVER */ ++ ++#include ++#include ++#include ++ ++#if defined(BCMEXTSUP) ++#include ++#endif ++ ++ ++#endif /* !BCMDRIVER */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++void *_bcmutils_dummy_fn = NULL; ++ ++#include ++ ++ ++#ifdef BCMDRIVER ++ ++ ++ ++/* copy a pkt buffer chain into a buffer */ ++uint ++pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf) ++{ ++ uint n, ret = 0; ++ ++ if (len < 0) ++ len = 4096; /* "infinite" */ ++ ++ /* skip 'offset' bytes */ ++ for (; p && offset; p = PKTNEXT(osh, p)) { ++ if (offset < (uint)PKTLEN(osh, p)) ++ break; ++ offset -= PKTLEN(osh, p); ++ } ++ ++ if (!p) ++ return 0; ++ ++ /* copy the data */ ++ for (; p && len; p = PKTNEXT(osh, p)) { ++ n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len); ++ bcopy(PKTDATA(osh, p) + offset, buf, n); ++ buf += n; ++ len -= n; ++ ret += n; ++ offset = 0; ++ } ++ ++ return ret; ++} ++ ++/* copy a buffer into a pkt buffer chain */ ++uint ++pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf) ++{ ++ uint n, ret = 0; ++ ++ /* skip 'offset' bytes */ ++ for (; p && offset; p = PKTNEXT(osh, p)) { ++ if (offset < (uint)PKTLEN(osh, p)) ++ break; ++ offset -= PKTLEN(osh, p); ++ } ++ ++ if (!p) ++ return 0; ++ ++ /* copy the data */ ++ for (; p && len; p = PKTNEXT(osh, p)) { ++ n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len); ++ bcopy(buf, PKTDATA(osh, p) + offset, n); ++ buf += n; ++ len -= n; ++ ret += n; ++ offset = 0; ++ } ++ ++ return ret; ++} ++ ++ ++ ++/* return total length of buffer chain */ ++uint BCMFASTPATH ++pkttotlen(osl_t *osh, void *p) ++{ ++ uint total; ++ int len; ++ ++ total = 0; ++ for (; p; p = PKTNEXT(osh, p)) { ++ len = PKTLEN(osh, p); ++ total += len; ++ } ++ ++ return (total); ++} ++ ++/* return the last buffer of chained pkt */ ++void * ++pktlast(osl_t *osh, void *p) ++{ ++ for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p)) ++ ; ++ ++ return (p); ++} ++ ++/* count segments of a chained packet */ ++uint BCMFASTPATH ++pktsegcnt(osl_t *osh, void *p) ++{ ++ uint cnt; ++ ++ for (cnt = 0; p; p = PKTNEXT(osh, p)) ++ cnt++; ++ ++ return cnt; ++} ++ ++ ++/* count segments of a chained packet */ ++uint BCMFASTPATH ++pktsegcnt_war(osl_t *osh, void *p) ++{ ++ uint cnt; ++ uint8 *pktdata; ++ uint len, remain, align64; ++ ++ for (cnt = 0; p; p = PKTNEXT(osh, p)) { ++ cnt++; ++ len = PKTLEN(osh, p); ++ if (len > 128) { ++ pktdata = (uint8 *)PKTDATA(osh, p); /* starting address of data */ ++ /* Check for page boundary straddle (2048B) */ ++ if (((uintptr)pktdata & ~0x7ff) != ((uintptr)(pktdata+len) & ~0x7ff)) ++ cnt++; ++ ++ align64 = (uint)((uintptr)pktdata & 0x3f); /* aligned to 64B */ ++ align64 = (64 - align64) & 0x3f; ++ len -= align64; /* bytes from aligned 64B to end */ ++ /* if aligned to 128B, check for MOD 128 between 1 to 4B */ ++ remain = len % 128; ++ if (remain > 0 && remain <= 4) ++ cnt++; /* add extra seg */ ++ } ++ } ++ ++ return cnt; ++} ++ ++uint8 * BCMFASTPATH ++pktoffset(osl_t *osh, void *p, uint offset) ++{ ++ uint total = pkttotlen(osh, p); ++ uint pkt_off = 0, len = 0; ++ uint8 *pdata = (uint8 *) PKTDATA(osh, p); ++ ++ if (offset > total) ++ return NULL; ++ ++ for (; p; p = PKTNEXT(osh, p)) { ++ pdata = (uint8 *) PKTDATA(osh, p); ++ pkt_off = offset - len; ++ len += PKTLEN(osh, p); ++ if (len > offset) ++ break; ++ } ++ return (uint8*) (pdata+pkt_off); ++} ++ ++/* ++ * osl multiple-precedence packet queue ++ * hi_prec is always >= the number of the highest non-empty precedence ++ */ ++void * BCMFASTPATH ++pktq_penq(struct pktq *pq, int prec, void *p) ++{ ++ struct pktq_prec *q; ++ ++ ASSERT(prec >= 0 && prec < pq->num_prec); ++ ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */ ++ ++ ASSERT(!pktq_full(pq)); ++ ASSERT(!pktq_pfull(pq, prec)); ++ ++ q = &pq->q[prec]; ++ ++ if (q->head) ++ PKTSETLINK(q->tail, p); ++ else ++ q->head = p; ++ ++ q->tail = p; ++ q->len++; ++ ++ pq->len++; ++ ++ if (pq->hi_prec < prec) ++ pq->hi_prec = (uint8)prec; ++ ++ return p; ++} ++ ++void * BCMFASTPATH ++pktq_penq_head(struct pktq *pq, int prec, void *p) ++{ ++ struct pktq_prec *q; ++ ++ ASSERT(prec >= 0 && prec < pq->num_prec); ++ ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */ ++ ++ ASSERT(!pktq_full(pq)); ++ ASSERT(!pktq_pfull(pq, prec)); ++ ++ q = &pq->q[prec]; ++ ++ if (q->head == NULL) ++ q->tail = p; ++ ++ PKTSETLINK(p, q->head); ++ q->head = p; ++ q->len++; ++ ++ pq->len++; ++ ++ if (pq->hi_prec < prec) ++ pq->hi_prec = (uint8)prec; ++ ++ return p; ++} ++ ++void * BCMFASTPATH ++pktq_pdeq(struct pktq *pq, int prec) ++{ ++ struct pktq_prec *q; ++ void *p; ++ ++ ASSERT(prec >= 0 && prec < pq->num_prec); ++ ++ q = &pq->q[prec]; ++ ++ if ((p = q->head) == NULL) ++ return NULL; ++ ++ if ((q->head = PKTLINK(p)) == NULL) ++ q->tail = NULL; ++ ++ q->len--; ++ ++ pq->len--; ++ ++ PKTSETLINK(p, NULL); ++ ++ return p; ++} ++ ++void * BCMFASTPATH ++pktq_pdeq_prev(struct pktq *pq, int prec, void *prev_p) ++{ ++ struct pktq_prec *q; ++ void *p; ++ ++ ASSERT(prec >= 0 && prec < pq->num_prec); ++ ++ q = &pq->q[prec]; ++ ++ if (prev_p == NULL) ++ return NULL; ++ ++ if ((p = PKTLINK(prev_p)) == NULL) ++ return NULL; ++ ++ q->len--; ++ ++ pq->len--; ++ ++ PKTSETLINK(prev_p, PKTLINK(p)); ++ PKTSETLINK(p, NULL); ++ ++ return p; ++} ++ ++void * BCMFASTPATH ++pktq_pdeq_tail(struct pktq *pq, int prec) ++{ ++ struct pktq_prec *q; ++ void *p, *prev; ++ ++ ASSERT(prec >= 0 && prec < pq->num_prec); ++ ++ q = &pq->q[prec]; ++ ++ if ((p = q->head) == NULL) ++ return NULL; ++ ++ for (prev = NULL; p != q->tail; p = PKTLINK(p)) ++ prev = p; ++ ++ if (prev) ++ PKTSETLINK(prev, NULL); ++ else ++ q->head = NULL; ++ ++ q->tail = prev; ++ q->len--; ++ ++ pq->len--; ++ ++ return p; ++} ++ ++void ++pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn, int arg) ++{ ++ struct pktq_prec *q; ++ void *p, *prev = NULL; ++ ++ q = &pq->q[prec]; ++ p = q->head; ++ while (p) { ++ if (fn == NULL || (*fn)(p, arg)) { ++ bool head = (p == q->head); ++ if (head) ++ q->head = PKTLINK(p); ++ else ++ PKTSETLINK(prev, PKTLINK(p)); ++ PKTSETLINK(p, NULL); ++ PKTFREE(osh, p, dir); ++ q->len--; ++ pq->len--; ++ p = (head ? q->head : PKTLINK(prev)); ++ } else { ++ prev = p; ++ p = PKTLINK(p); ++ } ++ } ++ ++ if (q->head == NULL) { ++ ASSERT(q->len == 0); ++ q->tail = NULL; ++ } ++} ++ ++bool BCMFASTPATH ++pktq_pdel(struct pktq *pq, void *pktbuf, int prec) ++{ ++ struct pktq_prec *q; ++ void *p; ++ ++ ASSERT(prec >= 0 && prec < pq->num_prec); ++ ++ if (!pktbuf) ++ return FALSE; ++ ++ q = &pq->q[prec]; ++ ++ if (q->head == pktbuf) { ++ if ((q->head = PKTLINK(pktbuf)) == NULL) ++ q->tail = NULL; ++ } else { ++ for (p = q->head; p && PKTLINK(p) != pktbuf; p = PKTLINK(p)) ++ ; ++ if (p == NULL) ++ return FALSE; ++ ++ PKTSETLINK(p, PKTLINK(pktbuf)); ++ if (q->tail == pktbuf) ++ q->tail = p; ++ } ++ ++ q->len--; ++ pq->len--; ++ PKTSETLINK(pktbuf, NULL); ++ return TRUE; ++} ++ ++void ++pktq_init(struct pktq *pq, int num_prec, int max_len) ++{ ++ int prec; ++ ++ ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC); ++ ++ /* pq is variable size; only zero out what's requested */ ++ bzero(pq, OFFSETOF(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec)); ++ ++ pq->num_prec = (uint16)num_prec; ++ ++ pq->max = (uint16)max_len; ++ ++ for (prec = 0; prec < num_prec; prec++) ++ pq->q[prec].max = pq->max; ++} ++ ++void ++pktq_set_max_plen(struct pktq *pq, int prec, int max_len) ++{ ++ ASSERT(prec >= 0 && prec < pq->num_prec); ++ ++ if (prec < pq->num_prec) ++ pq->q[prec].max = (uint16)max_len; ++} ++ ++void * BCMFASTPATH ++pktq_deq(struct pktq *pq, int *prec_out) ++{ ++ struct pktq_prec *q; ++ void *p; ++ int prec; ++ ++ if (pq->len == 0) ++ return NULL; ++ ++ while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) ++ pq->hi_prec--; ++ ++ q = &pq->q[prec]; ++ ++ if ((p = q->head) == NULL) ++ return NULL; ++ ++ if ((q->head = PKTLINK(p)) == NULL) ++ q->tail = NULL; ++ ++ q->len--; ++ ++ pq->len--; ++ ++ if (prec_out) ++ *prec_out = prec; ++ ++ PKTSETLINK(p, NULL); ++ ++ return p; ++} ++ ++void * BCMFASTPATH ++pktq_deq_tail(struct pktq *pq, int *prec_out) ++{ ++ struct pktq_prec *q; ++ void *p, *prev; ++ int prec; ++ ++ if (pq->len == 0) ++ return NULL; ++ ++ for (prec = 0; prec < pq->hi_prec; prec++) ++ if (pq->q[prec].head) ++ break; ++ ++ q = &pq->q[prec]; ++ ++ if ((p = q->head) == NULL) ++ return NULL; ++ ++ for (prev = NULL; p != q->tail; p = PKTLINK(p)) ++ prev = p; ++ ++ if (prev) ++ PKTSETLINK(prev, NULL); ++ else ++ q->head = NULL; ++ ++ q->tail = prev; ++ q->len--; ++ ++ pq->len--; ++ ++ if (prec_out) ++ *prec_out = prec; ++ ++ PKTSETLINK(p, NULL); ++ ++ return p; ++} ++ ++void * ++pktq_peek(struct pktq *pq, int *prec_out) ++{ ++ int prec; ++ ++ if (pq->len == 0) ++ return NULL; ++ ++ while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) ++ pq->hi_prec--; ++ ++ if (prec_out) ++ *prec_out = prec; ++ ++ return (pq->q[prec].head); ++} ++ ++void * ++pktq_peek_tail(struct pktq *pq, int *prec_out) ++{ ++ int prec; ++ ++ if (pq->len == 0) ++ return NULL; ++ ++ for (prec = 0; prec < pq->hi_prec; prec++) ++ if (pq->q[prec].head) ++ break; ++ ++ if (prec_out) ++ *prec_out = prec; ++ ++ return (pq->q[prec].tail); ++} ++ ++void ++pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg) ++{ ++ int prec; ++ ++ /* Optimize flush, if pktq len = 0, just return. ++ * pktq len of 0 means pktq's prec q's are all empty. ++ */ ++ if (pq->len == 0) { ++ return; ++ } ++ ++ for (prec = 0; prec < pq->num_prec; prec++) ++ pktq_pflush(osh, pq, prec, dir, fn, arg); ++ if (fn == NULL) ++ ASSERT(pq->len == 0); ++} ++ ++/* Return sum of lengths of a specific set of precedences */ ++int ++pktq_mlen(struct pktq *pq, uint prec_bmp) ++{ ++ int prec, len; ++ ++ len = 0; ++ ++ for (prec = 0; prec <= pq->hi_prec; prec++) ++ if (prec_bmp & (1 << prec)) ++ len += pq->q[prec].len; ++ ++ return len; ++} ++ ++/* Priority peek from a specific set of precedences */ ++void * BCMFASTPATH ++pktq_mpeek(struct pktq *pq, uint prec_bmp, int *prec_out) ++{ ++ struct pktq_prec *q; ++ void *p; ++ int prec; ++ ++ if (pq->len == 0) ++ { ++ return NULL; ++ } ++ while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) ++ pq->hi_prec--; ++ ++ while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL) ++ if (prec-- == 0) ++ return NULL; ++ ++ q = &pq->q[prec]; ++ ++ if ((p = q->head) == NULL) ++ return NULL; ++ ++ if (prec_out) ++ *prec_out = prec; ++ ++ return p; ++} ++/* Priority dequeue from a specific set of precedences */ ++void * BCMFASTPATH ++pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out) ++{ ++ struct pktq_prec *q; ++ void *p; ++ int prec; ++ ++ if (pq->len == 0) ++ return NULL; ++ ++ while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) ++ pq->hi_prec--; ++ ++ while ((pq->q[prec].head == NULL) || ((prec_bmp & (1 << prec)) == 0)) ++ if (prec-- == 0) ++ return NULL; ++ ++ q = &pq->q[prec]; ++ ++ if ((p = q->head) == NULL) ++ return NULL; ++ ++ if ((q->head = PKTLINK(p)) == NULL) ++ q->tail = NULL; ++ ++ q->len--; ++ ++ if (prec_out) ++ *prec_out = prec; ++ ++ pq->len--; ++ ++ PKTSETLINK(p, NULL); ++ ++ return p; ++} ++ ++#endif /* BCMDRIVER */ ++ ++const unsigned char bcm_ctype[] = { ++ ++ _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */ ++ _BCM_C, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C, ++ _BCM_C, /* 8-15 */ ++ _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */ ++ _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */ ++ _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */ ++ _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */ ++ _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */ ++ _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */ ++ _BCM_P, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, ++ _BCM_U|_BCM_X, _BCM_U, /* 64-71 */ ++ _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */ ++ _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */ ++ _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */ ++ _BCM_P, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, ++ _BCM_L|_BCM_X, _BCM_L, /* 96-103 */ ++ _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */ ++ _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */ ++ _BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */ ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */ ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */ ++ _BCM_S|_BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, ++ _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */ ++ _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, ++ _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */ ++ _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, ++ _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */ ++ _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U, _BCM_U, _BCM_U, ++ _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */ ++ _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, ++ _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */ ++ _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L, _BCM_L, _BCM_L, ++ _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */ ++}; ++ ++ulong ++bcm_strtoul(const char *cp, char **endp, uint base) ++{ ++ ulong result, last_result = 0, value; ++ bool minus; ++ ++ minus = FALSE; ++ ++ while (bcm_isspace(*cp)) ++ cp++; ++ ++ if (cp[0] == '+') ++ cp++; ++ else if (cp[0] == '-') { ++ minus = TRUE; ++ cp++; ++ } ++ ++ if (base == 0) { ++ if (cp[0] == '0') { ++ if ((cp[1] == 'x') || (cp[1] == 'X')) { ++ base = 16; ++ cp = &cp[2]; ++ } else { ++ base = 8; ++ cp = &cp[1]; ++ } ++ } else ++ base = 10; ++ } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) { ++ cp = &cp[2]; ++ } ++ ++ result = 0; ++ ++ while (bcm_isxdigit(*cp) && ++ (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) { ++ result = result*base + value; ++ /* Detected overflow */ ++ if (result < last_result && !minus) ++ return (ulong)-1; ++ last_result = result; ++ cp++; ++ } ++ ++ if (minus) ++ result = (ulong)(-(long)result); ++ ++ if (endp) ++ *endp = DISCARD_QUAL(cp, char); ++ ++ return (result); ++} ++ ++int ++bcm_atoi(const char *s) ++{ ++ return (int)bcm_strtoul(s, NULL, 10); ++} ++ ++/* return pointer to location of substring 'needle' in 'haystack' */ ++char * ++bcmstrstr(const char *haystack, const char *needle) ++{ ++ int len, nlen; ++ int i; ++ ++ if ((haystack == NULL) || (needle == NULL)) ++ return DISCARD_QUAL(haystack, char); ++ ++ nlen = strlen(needle); ++ len = strlen(haystack) - nlen + 1; ++ ++ for (i = 0; i < len; i++) ++ if (memcmp(needle, &haystack[i], nlen) == 0) ++ return DISCARD_QUAL(&haystack[i], char); ++ return (NULL); ++} ++ ++char * ++bcmstrcat(char *dest, const char *src) ++{ ++ char *p; ++ ++ p = dest + strlen(dest); ++ ++ while ((*p++ = *src++) != '\0') ++ ; ++ ++ return (dest); ++} ++ ++char * ++bcmstrncat(char *dest, const char *src, uint size) ++{ ++ char *endp; ++ char *p; ++ ++ p = dest + strlen(dest); ++ endp = p + size; ++ ++ while (p != endp && (*p++ = *src++) != '\0') ++ ; ++ ++ return (dest); ++} ++ ++ ++/**************************************************************************** ++* Function: bcmstrtok ++* ++* Purpose: ++* Tokenizes a string. This function is conceptually similiar to ANSI C strtok(), ++* but allows strToken() to be used by different strings or callers at the same ++* time. Each call modifies '*string' by substituting a NULL character for the ++* first delimiter that is encountered, and updates 'string' to point to the char ++* after the delimiter. Leading delimiters are skipped. ++* ++* Parameters: ++* string (mod) Ptr to string ptr, updated by token. ++* delimiters (in) Set of delimiter characters. ++* tokdelim (out) Character that delimits the returned token. (May ++* be set to NULL if token delimiter is not required). ++* ++* Returns: Pointer to the next token found. NULL when no more tokens are found. ++***************************************************************************** ++*/ ++char * ++bcmstrtok(char **string, const char *delimiters, char *tokdelim) ++{ ++ unsigned char *str; ++ unsigned long map[8]; ++ int count; ++ char *nextoken; ++ ++ if (tokdelim != NULL) { ++ /* Prime the token delimiter */ ++ *tokdelim = '\0'; ++ } ++ ++ /* Clear control map */ ++ for (count = 0; count < 8; count++) { ++ map[count] = 0; ++ } ++ ++ /* Set bits in delimiter table */ ++ do { ++ map[*delimiters >> 5] |= (1 << (*delimiters & 31)); ++ } ++ while (*delimiters++); ++ ++ str = (unsigned char*)*string; ++ ++ /* Find beginning of token (skip over leading delimiters). Note that ++ * there is no token iff this loop sets str to point to the terminal ++ * null (*str == '\0') ++ */ ++ while (((map[*str >> 5] & (1 << (*str & 31))) && *str) || (*str == ' ')) { ++ str++; ++ } ++ ++ nextoken = (char*)str; ++ ++ /* Find the end of the token. If it is not the end of the string, ++ * put a null there. ++ */ ++ for (; *str; str++) { ++ if (map[*str >> 5] & (1 << (*str & 31))) { ++ if (tokdelim != NULL) { ++ *tokdelim = *str; ++ } ++ ++ *str++ = '\0'; ++ break; ++ } ++ } ++ ++ *string = (char*)str; ++ ++ /* Determine if a token has been found. */ ++ if (nextoken == (char *) str) { ++ return NULL; ++ } ++ else { ++ return nextoken; ++ } ++} ++ ++ ++#define xToLower(C) \ ++ ((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C) ++ ++ ++/**************************************************************************** ++* Function: bcmstricmp ++* ++* Purpose: Compare to strings case insensitively. ++* ++* Parameters: s1 (in) First string to compare. ++* s2 (in) Second string to compare. ++* ++* Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if ++* t1 > t2, when ignoring case sensitivity. ++***************************************************************************** ++*/ ++int ++bcmstricmp(const char *s1, const char *s2) ++{ ++ char dc, sc; ++ ++ while (*s2 && *s1) { ++ dc = xToLower(*s1); ++ sc = xToLower(*s2); ++ if (dc < sc) return -1; ++ if (dc > sc) return 1; ++ s1++; ++ s2++; ++ } ++ ++ if (*s1 && !*s2) return 1; ++ if (!*s1 && *s2) return -1; ++ return 0; ++} ++ ++ ++/**************************************************************************** ++* Function: bcmstrnicmp ++* ++* Purpose: Compare to strings case insensitively, upto a max of 'cnt' ++* characters. ++* ++* Parameters: s1 (in) First string to compare. ++* s2 (in) Second string to compare. ++* cnt (in) Max characters to compare. ++* ++* Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if ++* t1 > t2, when ignoring case sensitivity. ++***************************************************************************** ++*/ ++int ++bcmstrnicmp(const char* s1, const char* s2, int cnt) ++{ ++ char dc, sc; ++ ++ while (*s2 && *s1 && cnt) { ++ dc = xToLower(*s1); ++ sc = xToLower(*s2); ++ if (dc < sc) return -1; ++ if (dc > sc) return 1; ++ s1++; ++ s2++; ++ cnt--; ++ } ++ ++ if (!cnt) return 0; ++ if (*s1 && !*s2) return 1; ++ if (!*s1 && *s2) return -1; ++ return 0; ++} ++ ++/* parse a xx:xx:xx:xx:xx:xx format ethernet address */ ++int ++bcm_ether_atoe(const char *p, struct ether_addr *ea) ++{ ++ int i = 0; ++ char *ep; ++ ++ for (;;) { ++ ea->octet[i++] = (char) bcm_strtoul(p, &ep, 16); ++ p = ep; ++ if (!*p++ || i == 6) ++ break; ++ } ++ ++ return (i == 6); ++} ++ ++ ++#if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER) ++/* registry routine buffer preparation utility functions: ++ * parameter order is like strncpy, but returns count ++ * of bytes copied. Minimum bytes copied is null char(1)/wchar(2) ++ */ ++ulong ++wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen) ++{ ++ ulong copyct = 1; ++ ushort i; ++ ++ if (abuflen == 0) ++ return 0; ++ ++ /* wbuflen is in bytes */ ++ wbuflen /= sizeof(ushort); ++ ++ for (i = 0; i < wbuflen; ++i) { ++ if (--abuflen == 0) ++ break; ++ *abuf++ = (char) *wbuf++; ++ ++copyct; ++ } ++ *abuf = '\0'; ++ ++ return copyct; ++} ++#endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */ ++ ++char * ++bcm_ether_ntoa(const struct ether_addr *ea, char *buf) ++{ ++ static const char hex[] = ++ { ++ '0', '1', '2', '3', '4', '5', '6', '7', ++ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' ++ }; ++ const uint8 *octet = ea->octet; ++ char *p = buf; ++ int i; ++ ++ for (i = 0; i < 6; i++, octet++) { ++ *p++ = hex[(*octet >> 4) & 0xf]; ++ *p++ = hex[*octet & 0xf]; ++ *p++ = ':'; ++ } ++ ++ *(p-1) = '\0'; ++ ++ return (buf); ++} ++ ++char * ++bcm_ip_ntoa(struct ipv4_addr *ia, char *buf) ++{ ++ snprintf(buf, 16, "%d.%d.%d.%d", ++ ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]); ++ return (buf); ++} ++ ++#ifdef BCMDRIVER ++ ++void ++bcm_mdelay(uint ms) ++{ ++ uint i; ++ ++ for (i = 0; i < ms; i++) { ++ OSL_DELAY(1000); ++ } ++} ++ ++ ++ ++ ++ ++#if defined(DHD_DEBUG) ++/* pretty hex print a pkt buffer chain */ ++void ++prpkt(const char *msg, osl_t *osh, void *p0) ++{ ++ void *p; ++ ++ if (msg && (msg[0] != '\0')) ++ AP6211_DEBUG("%s:\n", msg); ++ ++ for (p = p0; p; p = PKTNEXT(osh, p)) ++ prhex(NULL, PKTDATA(osh, p), PKTLEN(osh, p)); ++} ++#endif ++ ++/* Takes an Ethernet frame and sets out-of-bound PKTPRIO. ++ * Also updates the inplace vlan tag if requested. ++ * For debugging, it returns an indication of what it did. ++ */ ++uint BCMFASTPATH ++pktsetprio(void *pkt, bool update_vtag) ++{ ++ struct ether_header *eh; ++ struct ethervlan_header *evh; ++ uint8 *pktdata; ++ int priority = 0; ++ int rc = 0; ++ ++ pktdata = (uint8 *)PKTDATA(NULL, pkt); ++ ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16))); ++ ++ eh = (struct ether_header *) pktdata; ++ ++ if (ntoh16(eh->ether_type) == ETHER_TYPE_8021Q) { ++ uint16 vlan_tag; ++ int vlan_prio, dscp_prio = 0; ++ ++ evh = (struct ethervlan_header *)eh; ++ ++ vlan_tag = ntoh16(evh->vlan_tag); ++ vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK; ++ ++ if (ntoh16(evh->ether_type) == ETHER_TYPE_IP) { ++ uint8 *ip_body = pktdata + sizeof(struct ethervlan_header); ++ uint8 tos_tc = IP_TOS46(ip_body); ++ dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); ++ } ++ ++ /* DSCP priority gets precedence over 802.1P (vlan tag) */ ++ if (dscp_prio != 0) { ++ priority = dscp_prio; ++ rc |= PKTPRIO_VDSCP; ++ } else { ++ priority = vlan_prio; ++ rc |= PKTPRIO_VLAN; ++ } ++ /* ++ * If the DSCP priority is not the same as the VLAN priority, ++ * then overwrite the priority field in the vlan tag, with the ++ * DSCP priority value. This is required for Linux APs because ++ * the VLAN driver on Linux, overwrites the skb->priority field ++ * with the priority value in the vlan tag ++ */ ++ if (update_vtag && (priority != vlan_prio)) { ++ vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT); ++ vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT; ++ evh->vlan_tag = hton16(vlan_tag); ++ rc |= PKTPRIO_UPD; ++ } ++ } else if (ntoh16(eh->ether_type) == ETHER_TYPE_IP) { ++ uint8 *ip_body = pktdata + sizeof(struct ether_header); ++ uint8 tos_tc = IP_TOS46(ip_body); ++ priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); ++ rc |= PKTPRIO_DSCP; ++ } ++ ++ ASSERT(priority >= 0 && priority <= MAXPRIO); ++ PKTSETPRIO(pkt, priority); ++ return (rc | priority); ++} ++ ++ ++static char bcm_undeferrstr[32]; ++static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE; ++ ++/* Convert the error codes into related error strings */ ++const char * ++bcmerrorstr(int bcmerror) ++{ ++ /* check if someone added a bcmerror code but forgot to add errorstring */ ++ ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1)); ++ ++ if (bcmerror > 0 || bcmerror < BCME_LAST) { ++ snprintf(bcm_undeferrstr, sizeof(bcm_undeferrstr), "Undefined error %d", bcmerror); ++ return bcm_undeferrstr; ++ } ++ ++ ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN); ++ ++ return bcmerrorstrtable[-bcmerror]; ++} ++ ++ ++ ++/* iovar table lookup */ ++const bcm_iovar_t* ++bcm_iovar_lookup(const bcm_iovar_t *table, const char *name) ++{ ++ const bcm_iovar_t *vi; ++ const char *lookup_name; ++ ++ /* skip any ':' delimited option prefixes */ ++ lookup_name = strrchr(name, ':'); ++ if (lookup_name != NULL) ++ lookup_name++; ++ else ++ lookup_name = name; ++ ++ ASSERT(table != NULL); ++ ++ for (vi = table; vi->name; vi++) { ++ if (!strcmp(vi->name, lookup_name)) ++ return vi; ++ } ++ /* ran to end of table */ ++ ++ return NULL; /* var name not found */ ++} ++ ++int ++bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set) ++{ ++ int bcmerror = 0; ++ ++ /* length check on io buf */ ++ switch (vi->type) { ++ case IOVT_BOOL: ++ case IOVT_INT8: ++ case IOVT_INT16: ++ case IOVT_INT32: ++ case IOVT_UINT8: ++ case IOVT_UINT16: ++ case IOVT_UINT32: ++ /* all integers are int32 sized args at the ioctl interface */ ++ if (len < (int)sizeof(int)) { ++ bcmerror = BCME_BUFTOOSHORT; ++ } ++ break; ++ ++ case IOVT_BUFFER: ++ /* buffer must meet minimum length requirement */ ++ if (len < vi->minlen) { ++ bcmerror = BCME_BUFTOOSHORT; ++ } ++ break; ++ ++ case IOVT_VOID: ++ if (!set) { ++ /* Cannot return nil... */ ++ bcmerror = BCME_UNSUPPORTED; ++ } else if (len) { ++ /* Set is an action w/o parameters */ ++ bcmerror = BCME_BUFTOOLONG; ++ } ++ break; ++ ++ default: ++ /* unknown type for length check in iovar info */ ++ ASSERT(0); ++ bcmerror = BCME_UNSUPPORTED; ++ } ++ ++ return bcmerror; ++} ++ ++#endif /* BCMDRIVER */ ++ ++ ++/******************************************************************************* ++ * crc8 ++ * ++ * Computes a crc8 over the input data using the polynomial: ++ * ++ * x^8 + x^7 +x^6 + x^4 + x^2 + 1 ++ * ++ * The caller provides the initial value (either CRC8_INIT_VALUE ++ * or the previous returned value) to allow for processing of ++ * discontiguous blocks of data. When generating the CRC the ++ * caller is responsible for complementing the final return value ++ * and inserting it into the byte stream. When checking, a final ++ * return value of CRC8_GOOD_VALUE indicates a valid CRC. ++ * ++ * Reference: Dallas Semiconductor Application Note 27 ++ * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms", ++ * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd., ++ * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt ++ * ++ * **************************************************************************** ++ */ ++ ++static const uint8 crc8_table[256] = { ++ 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B, ++ 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21, ++ 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF, ++ 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5, ++ 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14, ++ 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E, ++ 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80, ++ 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA, ++ 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95, ++ 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF, ++ 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01, ++ 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B, ++ 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA, ++ 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0, ++ 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E, ++ 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34, ++ 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0, ++ 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A, ++ 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54, ++ 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E, ++ 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF, ++ 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5, ++ 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B, ++ 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61, ++ 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E, ++ 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74, ++ 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA, ++ 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0, ++ 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41, ++ 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B, ++ 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5, ++ 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F ++}; ++ ++#define CRC_INNER_LOOP(n, c, x) \ ++ (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff] ++ ++uint8 ++hndcrc8( ++ uint8 *pdata, /* pointer to array of data to process */ ++ uint nbytes, /* number of input data bytes to process */ ++ uint8 crc /* either CRC8_INIT_VALUE or previous return value */ ++) ++{ ++ /* hard code the crc loop instead of using CRC_INNER_LOOP macro ++ * to avoid the undefined and unnecessary (uint8 >> 8) operation. ++ */ ++ while (nbytes-- > 0) ++ crc = crc8_table[(crc ^ *pdata++) & 0xff]; ++ ++ return crc; ++} ++ ++/******************************************************************************* ++ * crc16 ++ * ++ * Computes a crc16 over the input data using the polynomial: ++ * ++ * x^16 + x^12 +x^5 + 1 ++ * ++ * The caller provides the initial value (either CRC16_INIT_VALUE ++ * or the previous returned value) to allow for processing of ++ * discontiguous blocks of data. When generating the CRC the ++ * caller is responsible for complementing the final return value ++ * and inserting it into the byte stream. When checking, a final ++ * return value of CRC16_GOOD_VALUE indicates a valid CRC. ++ * ++ * Reference: Dallas Semiconductor Application Note 27 ++ * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms", ++ * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd., ++ * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt ++ * ++ * **************************************************************************** ++ */ ++ ++static const uint16 crc16_table[256] = { ++ 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, ++ 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7, ++ 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E, ++ 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876, ++ 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD, ++ 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5, ++ 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C, ++ 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974, ++ 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB, ++ 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3, ++ 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A, ++ 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72, ++ 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9, ++ 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1, ++ 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738, ++ 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70, ++ 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7, ++ 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF, ++ 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036, ++ 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E, ++ 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5, ++ 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD, ++ 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134, ++ 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C, ++ 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3, ++ 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB, ++ 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232, ++ 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A, ++ 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1, ++ 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9, ++ 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330, ++ 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78 ++}; ++ ++uint16 ++hndcrc16( ++ uint8 *pdata, /* pointer to array of data to process */ ++ uint nbytes, /* number of input data bytes to process */ ++ uint16 crc /* either CRC16_INIT_VALUE or previous return value */ ++) ++{ ++ while (nbytes-- > 0) ++ CRC_INNER_LOOP(16, crc, *pdata++); ++ return crc; ++} ++ ++static const uint32 crc32_table[256] = { ++ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, ++ 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, ++ 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, ++ 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, ++ 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, ++ 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, ++ 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, ++ 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, ++ 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, ++ 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, ++ 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, ++ 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, ++ 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, ++ 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, ++ 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, ++ 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, ++ 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, ++ 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, ++ 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, ++ 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, ++ 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, ++ 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, ++ 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, ++ 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, ++ 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, ++ 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, ++ 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, ++ 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, ++ 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, ++ 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, ++ 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, ++ 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, ++ 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, ++ 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, ++ 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, ++ 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, ++ 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, ++ 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, ++ 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, ++ 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, ++ 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, ++ 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, ++ 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, ++ 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, ++ 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, ++ 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, ++ 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, ++ 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, ++ 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, ++ 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, ++ 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, ++ 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, ++ 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, ++ 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, ++ 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, ++ 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, ++ 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, ++ 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, ++ 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, ++ 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, ++ 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, ++ 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, ++ 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, ++ 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D ++}; ++ ++/* ++ * crc input is CRC32_INIT_VALUE for a fresh start, or previous return value if ++ * accumulating over multiple pieces. ++ */ ++uint32 ++hndcrc32(uint8 *pdata, uint nbytes, uint32 crc) ++{ ++ uint8 *pend; ++ pend = pdata + nbytes; ++ while (pdata < pend) ++ CRC_INNER_LOOP(32, crc, *pdata++); ++ ++ return crc; ++} ++ ++#ifdef notdef ++#define CLEN 1499 /* CRC Length */ ++#define CBUFSIZ (CLEN+4) ++#define CNBUFS 5 /* # of bufs */ ++ ++void ++testcrc32(void) ++{ ++ uint j, k, l; ++ uint8 *buf; ++ uint len[CNBUFS]; ++ uint32 crcr; ++ uint32 crc32tv[CNBUFS] = ++ {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110}; ++ ++ ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL); ++ ++ /* step through all possible alignments */ ++ for (l = 0; l <= 4; l++) { ++ for (j = 0; j < CNBUFS; j++) { ++ len[j] = CLEN; ++ for (k = 0; k < len[j]; k++) ++ *(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff; ++ } ++ ++ for (j = 0; j < CNBUFS; j++) { ++ crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE); ++ ASSERT(crcr == crc32tv[j]); ++ } ++ } ++ ++ MFREE(buf, CBUFSIZ*CNBUFS); ++ return; ++} ++#endif /* notdef */ ++ ++/* ++ * Advance from the current 1-byte tag/1-byte length/variable-length value ++ * triple, to the next, returning a pointer to the next. ++ * If the current or next TLV is invalid (does not fit in given buffer length), ++ * NULL is returned. ++ * *buflen is not modified if the TLV elt parameter is invalid, or is decremented ++ * by the TLV parameter's length if it is valid. ++ */ ++bcm_tlv_t * ++bcm_next_tlv(bcm_tlv_t *elt, int *buflen) ++{ ++ int len; ++ ++ /* validate current elt */ ++ if (!bcm_valid_tlv(elt, *buflen)) ++ return NULL; ++ ++ /* advance to next elt */ ++ len = elt->len; ++ elt = (bcm_tlv_t*)(elt->data + len); ++ *buflen -= (TLV_HDR_LEN + len); ++ ++ /* validate next elt */ ++ if (!bcm_valid_tlv(elt, *buflen)) ++ return NULL; ++ ++ return elt; ++} ++ ++/* ++ * Traverse a string of 1-byte tag/1-byte length/variable-length value ++ * triples, returning a pointer to the substring whose first element ++ * matches tag ++ */ ++bcm_tlv_t * ++bcm_parse_tlvs(void *buf, int buflen, uint key) ++{ ++ bcm_tlv_t *elt; ++ int totlen; ++ ++ elt = (bcm_tlv_t*)buf; ++ totlen = buflen; ++ ++ /* find tagged parameter */ ++ while (totlen >= TLV_HDR_LEN) { ++ int len = elt->len; ++ ++ /* validate remaining totlen */ ++ if ((elt->id == key) && ++ (totlen >= (len + TLV_HDR_LEN))) ++ return (elt); ++ ++ elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN)); ++ totlen -= (len + TLV_HDR_LEN); ++ } ++ ++ return NULL; ++} ++ ++/* ++ * Traverse a string of 1-byte tag/1-byte length/variable-length value ++ * triples, returning a pointer to the substring whose first element ++ * matches tag. Stop parsing when we see an element whose ID is greater ++ * than the target key. ++ */ ++bcm_tlv_t * ++bcm_parse_ordered_tlvs(void *buf, int buflen, uint key) ++{ ++ bcm_tlv_t *elt; ++ int totlen; ++ ++ elt = (bcm_tlv_t*)buf; ++ totlen = buflen; ++ ++ /* find tagged parameter */ ++ while (totlen >= TLV_HDR_LEN) { ++ uint id = elt->id; ++ int len = elt->len; ++ ++ /* Punt if we start seeing IDs > than target key */ ++ if (id > key) ++ return (NULL); ++ ++ /* validate remaining totlen */ ++ if ((id == key) && ++ (totlen >= (len + TLV_HDR_LEN))) ++ return (elt); ++ ++ elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN)); ++ totlen -= (len + TLV_HDR_LEN); ++ } ++ return NULL; ++} ++ ++#if defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \ ++ defined(DHD_DEBUG) ++int ++bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len) ++{ ++ int i; ++ char* p = buf; ++ char hexstr[16]; ++ int slen = 0, nlen = 0; ++ uint32 bit; ++ const char* name; ++ ++ if (len < 2 || !buf) ++ return 0; ++ ++ buf[0] = '\0'; ++ ++ for (i = 0; flags != 0; i++) { ++ bit = bd[i].bit; ++ name = bd[i].name; ++ if (bit == 0 && flags != 0) { ++ /* print any unnamed bits */ ++ snprintf(hexstr, 16, "0x%X", flags); ++ name = hexstr; ++ flags = 0; /* exit loop */ ++ } else if ((flags & bit) == 0) ++ continue; ++ flags &= ~bit; ++ nlen = strlen(name); ++ slen += nlen; ++ /* count btwn flag space */ ++ if (flags != 0) ++ slen += 1; ++ /* need NULL char as well */ ++ if (len <= slen) ++ break; ++ /* copy NULL char but don't count it */ ++ strncpy(p, name, nlen + 1); ++ p += nlen; ++ /* copy btwn flag space and NULL char */ ++ if (flags != 0) ++ p += snprintf(p, 2, " "); ++ } ++ ++ /* indicate the str was too short */ ++ if (flags != 0) { ++ if (len < 2) ++ p -= 2 - len; /* overwrite last char */ ++ p += snprintf(p, 2, ">"); ++ } ++ ++ return (int)(p - buf); ++} ++ ++/* print bytes formatted as hex to a string. return the resulting string length */ ++int ++bcm_format_hex(char *str, const void *bytes, int len) ++{ ++ int i; ++ char *p = str; ++ const uint8 *src = (const uint8*)bytes; ++ ++ for (i = 0; i < len; i++) { ++ p += snprintf(p, 3, "%02X", *src); ++ src++; ++ } ++ return (int)(p - str); ++} ++#endif ++ ++/* pretty hex print a contiguous buffer */ ++void ++prhex(const char *msg, uchar *buf, uint nbytes) ++{ ++ char line[128], *p; ++ int len = sizeof(line); ++ int nchar; ++ uint i; ++ ++ if (msg && (msg[0] != '\0')) ++ AP6211_DEBUG("%s:\n", msg); ++ ++ p = line; ++ for (i = 0; i < nbytes; i++) { ++ if (i % 16 == 0) { ++ nchar = snprintf(p, len, " %04d: ", i); /* line prefix */ ++ p += nchar; ++ len -= nchar; ++ } ++ if (len > 0) { ++ nchar = snprintf(p, len, "%02x ", buf[i]); ++ p += nchar; ++ len -= nchar; ++ } ++ ++ if (i % 16 == 15) { ++ AP6211_DEBUG("%s\n", line); /* flush line */ ++ p = line; ++ len = sizeof(line); ++ } ++ } ++ ++ /* flush last partial line */ ++ if (p != line) ++ AP6211_DUMP("%s\n", line); ++} ++ ++static const char *crypto_algo_names[] = { ++ "NONE", ++ "WEP1", ++ "TKIP", ++ "WEP128", ++ "AES_CCM", ++ "AES_OCB_MSDU", ++ "AES_OCB_MPDU", ++ "NALG" ++ "UNDEF", ++ "UNDEF", ++ "UNDEF", ++#ifdef BCMWAPI_WPI ++ "WAPI", ++#endif /* BCMWAPI_WPI */ ++ "UNDEF" ++}; ++ ++const char * ++bcm_crypto_algo_name(uint algo) ++{ ++ return (algo < ARRAYSIZE(crypto_algo_names)) ? crypto_algo_names[algo] : "ERR"; ++} ++ ++ ++char * ++bcm_chipname(uint chipid, char *buf, uint len) ++{ ++ const char *fmt; ++ ++ fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x"; ++ snprintf(buf, len, fmt, chipid); ++ return buf; ++} ++ ++/* Produce a human-readable string for boardrev */ ++char * ++bcm_brev_str(uint32 brev, char *buf) ++{ ++ if (brev < 0x100) ++ snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf); ++ else ++ snprintf(buf, 8, "%c%03x", ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff); ++ ++ return (buf); ++} ++ ++#define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */ ++ ++/* dump large strings to console */ ++void ++printbig(char *buf) ++{ ++ uint len, max_len; ++ char c; ++ ++ len = strlen(buf); ++ ++ max_len = BUFSIZE_TODUMP_ATONCE; ++ ++ while (len > max_len) { ++ c = buf[max_len]; ++ buf[max_len] = '\0'; ++ AP6211_DUMP("%s", buf); ++ buf[max_len] = c; ++ ++ buf += max_len; ++ len -= max_len; ++ } ++ /* print the remaining string */ ++ AP6211_DUMP("%s\n", buf); ++ return; ++} ++ ++/* routine to dump fields in a fileddesc structure */ ++uint ++bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1, struct fielddesc *fielddesc_array, ++ char *buf, uint32 bufsize) ++{ ++ uint filled_len; ++ int len; ++ struct fielddesc *cur_ptr; ++ ++ filled_len = 0; ++ cur_ptr = fielddesc_array; ++ ++ while (bufsize > 1) { ++ if (cur_ptr->nameandfmt == NULL) ++ break; ++ len = snprintf(buf, bufsize, cur_ptr->nameandfmt, ++ read_rtn(arg0, arg1, cur_ptr->offset)); ++ /* check for snprintf overflow or error */ ++ if (len < 0 || (uint32)len >= bufsize) ++ len = bufsize - 1; ++ buf += len; ++ bufsize -= len; ++ filled_len += len; ++ cur_ptr++; ++ } ++ return filled_len; ++} ++ ++uint ++bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen) ++{ ++ uint len; ++ ++ len = strlen(name) + 1; ++ ++ if ((len + datalen) > buflen) ++ return 0; ++ ++ strncpy(buf, name, buflen); ++ ++ /* append data onto the end of the name string */ ++ memcpy(&buf[len], data, datalen); ++ len += datalen; ++ ++ return len; ++} ++ ++/* Quarter dBm units to mW ++ * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153 ++ * Table is offset so the last entry is largest mW value that fits in ++ * a uint16. ++ */ ++ ++#define QDBM_OFFSET 153 /* Offset for first entry */ ++#define QDBM_TABLE_LEN 40 /* Table size */ ++ ++/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET. ++ * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2 ++ */ ++#define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */ ++ ++/* Largest mW value that will round down to the last table entry, ++ * QDBM_OFFSET + QDBM_TABLE_LEN-1. ++ * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2. ++ */ ++#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */ ++ ++static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = { ++/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */ ++/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000, ++/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849, ++/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119, ++/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811, ++/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096 ++}; ++ ++uint16 ++bcm_qdbm_to_mw(uint8 qdbm) ++{ ++ uint factor = 1; ++ int idx = qdbm - QDBM_OFFSET; ++ ++ if (idx >= QDBM_TABLE_LEN) { ++ /* clamp to max uint16 mW value */ ++ return 0xFFFF; ++ } ++ ++ /* scale the qdBm index up to the range of the table 0-40 ++ * where an offset of 40 qdBm equals a factor of 10 mW. ++ */ ++ while (idx < 0) { ++ idx += 40; ++ factor *= 10; ++ } ++ ++ /* return the mW value scaled down to the correct factor of 10, ++ * adding in factor/2 to get proper rounding. ++ */ ++ return ((nqdBm_to_mW_map[idx] + factor/2) / factor); ++} ++ ++uint8 ++bcm_mw_to_qdbm(uint16 mw) ++{ ++ uint8 qdbm; ++ int offset; ++ uint mw_uint = mw; ++ uint boundary; ++ ++ /* handle boundary case */ ++ if (mw_uint <= 1) ++ return 0; ++ ++ offset = QDBM_OFFSET; ++ ++ /* move mw into the range of the table */ ++ while (mw_uint < QDBM_TABLE_LOW_BOUND) { ++ mw_uint *= 10; ++ offset -= 40; ++ } ++ ++ for (qdbm = 0; qdbm < QDBM_TABLE_LEN-1; qdbm++) { ++ boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm+1] - ++ nqdBm_to_mW_map[qdbm])/2; ++ if (mw_uint < boundary) break; ++ } ++ ++ qdbm += (uint8)offset; ++ ++ return (qdbm); ++} ++ ++ ++uint ++bcm_bitcount(uint8 *bitmap, uint length) ++{ ++ uint bitcount = 0, i; ++ uint8 tmp; ++ for (i = 0; i < length; i++) { ++ tmp = bitmap[i]; ++ while (tmp) { ++ bitcount++; ++ tmp &= (tmp - 1); ++ } ++ } ++ return bitcount; ++} ++ ++#ifdef BCMDRIVER ++ ++/* Initialization of bcmstrbuf structure */ ++void ++bcm_binit(struct bcmstrbuf *b, char *buf, uint size) ++{ ++ b->origsize = b->size = size; ++ b->origbuf = b->buf = buf; ++} ++ ++/* Buffer sprintf wrapper to guard against buffer overflow */ ++int ++bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...) ++{ ++ va_list ap; ++ int r; ++ ++ va_start(ap, fmt); ++ ++ r = vsnprintf(b->buf, b->size, fmt, ap); ++ ++ /* Non Ansi C99 compliant returns -1, ++ * Ansi compliant return r >= b->size, ++ * bcmstdlib returns 0, handle all ++ */ ++ /* r == 0 is also the case when strlen(fmt) is zero. ++ * typically the case when "" is passed as argument. ++ */ ++ if ((r == -1) || (r >= (int)b->size)) { ++ b->size = 0; ++ } else { ++ b->size -= r; ++ b->buf += r; ++ } ++ ++ va_end(ap); ++ ++ return r; ++} ++ ++void ++bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, uint8 *buf, int len) ++{ ++ int i; ++ ++ if (msg != NULL && msg[0] != '\0') ++ bcm_bprintf(b, "%s", msg); ++ for (i = 0; i < len; i ++) ++ bcm_bprintf(b, "%02X", buf[i]); ++ if (newline) ++ bcm_bprintf(b, "\n"); ++} ++ ++void ++bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount) ++{ ++ int i; ++ ++ for (i = 0; i < num_bytes; i++) { ++ num[i] += amount; ++ if (num[i] >= amount) ++ break; ++ amount = 1; ++ } ++} ++ ++int ++bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes) ++{ ++ int i; ++ ++ for (i = nbytes - 1; i >= 0; i--) { ++ if (arg1[i] != arg2[i]) ++ return (arg1[i] - arg2[i]); ++ } ++ return 0; ++} ++ ++void ++bcm_print_bytes(const char *name, const uchar *data, int len) ++{ ++ int i; ++ int per_line = 0; ++ ++ AP6211_DEBUG("%s: %d \n", name ? name : "", len); ++ for (i = 0; i < len; i++) { ++ AP6211_DUMP("%02x ", *data++); ++ per_line++; ++ if (per_line == 16) { ++ per_line = 0; ++ AP6211_DUMP("\n"); ++ } ++ } ++ AP6211_DUMP("\n"); ++} ++#if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \ ++ defined(WLMSG_PRPKT) || defined(WLMSG_WSEC) ++#define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1) ++ ++int ++bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len) ++{ ++ uint i, c; ++ char *p = buf; ++ char *endp = buf + SSID_FMT_BUF_LEN; ++ ++ if (ssid_len > DOT11_MAX_SSID_LEN) ssid_len = DOT11_MAX_SSID_LEN; ++ ++ for (i = 0; i < ssid_len; i++) { ++ c = (uint)ssid[i]; ++ if (c == '\\') { ++ *p++ = '\\'; ++ *p++ = '\\'; ++ } else if (bcm_isprint((uchar)c)) { ++ *p++ = (char)c; ++ } else { ++ p += snprintf(p, (endp - p), "\\x%02X", c); ++ } ++ } ++ *p = '\0'; ++ ASSERT(p < endp); ++ ++ return (int)(p - buf); ++} ++#endif ++ ++#endif /* BCMDRIVER */ ++ ++/* ++ * ProcessVars:Takes a buffer of "=\n" lines read from a file and ending in a NUL. ++ * also accepts nvram files which are already in the format of =\0\=\0 ++ * Removes carriage returns, empty lines, comment lines, and converts newlines to NULs. ++ * Shortens buffer as needed and pads with NULs. End of buffer is marked by two NULs. ++*/ ++ ++unsigned int ++process_nvram_vars(char *varbuf, unsigned int len) ++{ ++ char *dp; ++ bool findNewline; ++ int column; ++ unsigned int buf_len, n; ++ unsigned int pad = 0; ++ ++ dp = varbuf; ++ ++ findNewline = FALSE; ++ column = 0; ++ ++ for (n = 0; n < len; n++) { ++ if (varbuf[n] == '\r') ++ continue; ++ if (findNewline && varbuf[n] != '\n') ++ continue; ++ findNewline = FALSE; ++ if (varbuf[n] == '#') { ++ findNewline = TRUE; ++ continue; ++ } ++ if (varbuf[n] == '\n') { ++ if (column == 0) ++ continue; ++ *dp++ = 0; ++ column = 0; ++ continue; ++ } ++ *dp++ = varbuf[n]; ++ column++; ++ } ++ buf_len = (unsigned int)(dp - varbuf); ++ if (buf_len % 4) { ++ pad = 4 - buf_len % 4; ++ if (pad && (buf_len + pad <= len)) { ++ buf_len += pad; ++ } ++ } ++ ++ while (dp < varbuf + n) ++ *dp++ = 0; ++ ++ return buf_len; ++} +diff --git a/drivers/net/wireless/ap6211/bcmwifi_channels.c b/drivers/net/wireless/ap6211/bcmwifi_channels.c +new file mode 100755 +index 0000000..6b5b0a3 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/bcmwifi_channels.c +@@ -0,0 +1,1179 @@ ++/* ++ * Misc utility routines used by kernel or app-level. ++ * Contents are wifi-specific, used by any kernel or app-level ++ * software that might want wifi things as it grows. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * $Id: bcmwifi_channels.c 309193 2012-01-19 00:03:57Z $ ++ */ ++ ++#include ++#include ++ ++#ifdef BCMDRIVER ++#include ++#include ++#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) ++#define tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c)) ++#else ++#include ++#include ++#include ++#ifndef ASSERT ++#define ASSERT(exp) ++#endif ++#endif /* BCMDRIVER */ ++ ++#ifdef _bcmwifi_c_ ++/* temporary for transitional compatibility */ ++#include ++#else ++#include ++#endif ++ ++#if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL)) ++#include /* For wl/exe/GNUmakefile.brcm_wlu and GNUmakefile.wlm_dll */ ++#endif ++ ++#ifndef D11AC_IOTYPES ++ ++/* Definitions for legacy Chanspec type */ ++ ++/* Chanspec ASCII representation: ++ * ++ * digit [AB] [N] [UL] ++ * ++ * : channel number of the 10MHz or 20MHz channel, ++ * or control sideband channel of 40MHz channel. ++ * : A for 5GHz, B for 2.4GHz ++ * : N for 10MHz, nothing for 20MHz or 40MHz ++ * (ctl-sideband spec implies 40MHz) ++ * : U for upper, L for lower ++ * ++ * may be omitted on input, and will be assumed to be ++ * 2.4GHz if channel number <= 14. ++ * ++ * Examples: ++ * 8 -> 2.4GHz channel 8, 20MHz ++ * 8b -> 2.4GHz channel 8, 20MHz ++ * 8l -> 2.4GHz channel 8, 40MHz, lower ctl sideband ++ * 8a -> 5GHz channel 8 (low 5 GHz band), 20MHz ++ * 36 -> 5GHz channel 36, 20MHz ++ * 36l -> 5GHz channel 36, 40MHz, lower ctl sideband ++ * 40u -> 5GHz channel 40, 40MHz, upper ctl sideband ++ * 180n -> channel 180, 10MHz ++ */ ++ ++ ++/* given a chanspec and a string buffer, format the chanspec as a ++ * string, and return the original pointer a. ++ * Min buffer length must be CHANSPEC_STR_LEN. ++ * On error return NULL ++ */ ++char * ++wf_chspec_ntoa(chanspec_t chspec, char *buf) ++{ ++ const char *band, *bw, *sb; ++ uint channel; ++ ++ band = ""; ++ bw = ""; ++ sb = ""; ++ channel = CHSPEC_CHANNEL(chspec); ++ /* check for non-default band spec */ ++ if ((CHSPEC_IS2G(chspec) && channel > CH_MAX_2G_CHANNEL) || ++ (CHSPEC_IS5G(chspec) && channel <= CH_MAX_2G_CHANNEL)) ++ band = (CHSPEC_IS2G(chspec)) ? "b" : "a"; ++ if (CHSPEC_IS40(chspec)) { ++ if (CHSPEC_SB_UPPER(chspec)) { ++ sb = "u"; ++ channel += CH_10MHZ_APART; ++ } else { ++ sb = "l"; ++ channel -= CH_10MHZ_APART; ++ } ++ } else if (CHSPEC_IS10(chspec)) { ++ bw = "n"; ++ } ++ ++ /* Outputs a max of 6 chars including '\0' */ ++ snprintf(buf, 6, "%d%s%s%s", channel, band, bw, sb); ++ return (buf); ++} ++ ++/* given a chanspec string, convert to a chanspec. ++ * On error return 0 ++ */ ++chanspec_t ++wf_chspec_aton(const char *a) ++{ ++ char *endp = NULL; ++ uint channel, band, bw, ctl_sb; ++ char c; ++ ++ channel = strtoul(a, &endp, 10); ++ ++ /* check for no digits parsed */ ++ if (endp == a) ++ return 0; ++ ++ if (channel > MAXCHANNEL) ++ return 0; ++ ++ band = ((channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G); ++ bw = WL_CHANSPEC_BW_20; ++ ctl_sb = WL_CHANSPEC_CTL_SB_NONE; ++ ++ a = endp; ++ ++ c = tolower(a[0]); ++ if (c == '\0') ++ goto done; ++ ++ /* parse the optional ['A' | 'B'] band spec */ ++ if (c == 'a' || c == 'b') { ++ band = (c == 'a') ? WL_CHANSPEC_BAND_5G : WL_CHANSPEC_BAND_2G; ++ a++; ++ c = tolower(a[0]); ++ if (c == '\0') ++ goto done; ++ } ++ ++ /* parse bandwidth 'N' (10MHz) or 40MHz ctl sideband ['L' | 'U'] */ ++ if (c == 'n') { ++ bw = WL_CHANSPEC_BW_10; ++ } else if (c == 'l') { ++ bw = WL_CHANSPEC_BW_40; ++ ctl_sb = WL_CHANSPEC_CTL_SB_LOWER; ++ /* adjust channel to center of 40MHz band */ ++ if (channel <= (MAXCHANNEL - CH_20MHZ_APART)) ++ channel += CH_10MHZ_APART; ++ else ++ return 0; ++ } else if (c == 'u') { ++ bw = WL_CHANSPEC_BW_40; ++ ctl_sb = WL_CHANSPEC_CTL_SB_UPPER; ++ /* adjust channel to center of 40MHz band */ ++ if (channel > CH_20MHZ_APART) ++ channel -= CH_10MHZ_APART; ++ else ++ return 0; ++ } else { ++ return 0; ++ } ++ ++done: ++ return (channel | band | bw | ctl_sb); ++} ++ ++/* ++ * Verify the chanspec is using a legal set of parameters, i.e. that the ++ * chanspec specified a band, bw, ctl_sb and channel and that the ++ * combination could be legal given any set of circumstances. ++ * RETURNS: TRUE is the chanspec is malformed, false if it looks good. ++ */ ++bool ++wf_chspec_malformed(chanspec_t chanspec) ++{ ++ /* must be 2G or 5G band */ ++ if (!CHSPEC_IS5G(chanspec) && !CHSPEC_IS2G(chanspec)) ++ return TRUE; ++ /* must be 20 or 40 bandwidth */ ++ if (!CHSPEC_IS40(chanspec) && !CHSPEC_IS20(chanspec)) ++ return TRUE; ++ ++ /* 20MHZ b/w must have no ctl sb, 40 must have a ctl sb */ ++ if (CHSPEC_IS20(chanspec)) { ++ if (!CHSPEC_SB_NONE(chanspec)) ++ return TRUE; ++ } else { ++ if (!CHSPEC_SB_UPPER(chanspec) && !CHSPEC_SB_LOWER(chanspec)) ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++/* ++ * This function returns the channel number that control traffic is being sent on, for legacy ++ * channels this is just the channel number, for 40MHZ channels it is the upper or lower 20MHZ ++ * sideband depending on the chanspec selected ++ */ ++uint8 ++wf_chspec_ctlchan(chanspec_t chspec) ++{ ++ uint8 ctl_chan; ++ ++ /* Is there a sideband ? */ ++ if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE) { ++ return CHSPEC_CHANNEL(chspec); ++ } else { ++ /* we only support 40MHZ with sidebands */ ++ ASSERT(CHSPEC_BW(chspec) == WL_CHANSPEC_BW_40); ++ /* chanspec channel holds the centre frequency, use that and the ++ * side band information to reconstruct the control channel number ++ */ ++ if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER) { ++ /* control chan is the upper 20 MHZ SB of the 40MHZ channel */ ++ ctl_chan = UPPER_20_SB(CHSPEC_CHANNEL(chspec)); ++ } else { ++ ASSERT(CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_LOWER); ++ /* control chan is the lower 20 MHZ SB of the 40MHZ channel */ ++ ctl_chan = LOWER_20_SB(CHSPEC_CHANNEL(chspec)); ++ } ++ } ++ ++ return ctl_chan; ++} ++ ++chanspec_t ++wf_chspec_ctlchspec(chanspec_t chspec) ++{ ++ chanspec_t ctl_chspec = 0; ++ uint8 channel; ++ ++ ASSERT(!wf_chspec_malformed(chspec)); ++ ++ /* Is there a sideband ? */ ++ if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE) { ++ return chspec; ++ } else { ++ if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER) { ++ channel = UPPER_20_SB(CHSPEC_CHANNEL(chspec)); ++ } else { ++ channel = LOWER_20_SB(CHSPEC_CHANNEL(chspec)); ++ } ++ ctl_chspec = channel | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE; ++ ctl_chspec |= CHSPEC_BAND(chspec); ++ } ++ return ctl_chspec; ++} ++ ++#else /* D11AC_IOTYPES */ ++ ++/* Definitions for D11AC capable Chanspec type */ ++ ++/* Chanspec ASCII representation with 802.11ac capability: ++ * [ 'g'] ['/' []['/'<1st80channel>'-'<2nd80channel>]] ++ * ++ * : ++ * (optional) 2, 3, 4, 5 for 2.4GHz, 3GHz, 4GHz, and 5GHz respectively. ++ * Default value is 2g if channel <= 14, otherwise 5g. ++ * : ++ * channel number of the 5MHz, 10MHz, 20MHz channel, ++ * or primary channel of 40MHz, 80MHz, 160MHz, or 80+80MHz channel. ++ * : ++ * (optional) 5, 10, 20, 40, 80, 160, or 80+80. Default value is 20. ++ * : ++ * (only for 2.4GHz band 40MHz) U for upper sideband primary, L for lower. ++ * ++ * For 2.4GHz band 40MHz channels, the same primary channel may be the ++ * upper sideband for one 40MHz channel, and the lower sideband for an ++ * overlapping 40MHz channel. The U/L disambiguates which 40MHz channel ++ * is being specified. ++ * ++ * For 40MHz in the 5GHz band and all channel bandwidths greater than ++ * 40MHz, the U/L specificaion is not allowed since the channels are ++ * non-overlapping and the primary sub-band is derived from its ++ * position in the wide bandwidth channel. ++ * ++ * <1st80Channel>: ++ * <2nd80Channel>: ++ * Required for 80+80, otherwise not allowed. ++ * Specifies the center channel of the first and second 80MHz band. ++ * ++ * In its simplest form, it is a 20MHz channel number, with the implied band ++ * of 2.4GHz if channel number <= 14, and 5GHz otherwise. ++ * ++ * To allow for backward compatibility with scripts, the old form for ++ * 40MHz channels is also allowed: ++ * ++ * : ++ * primary channel of 40MHz, channel <= 14 is 2GHz, otherwise 5GHz ++ * : ++ * "U" for upper, "L" for lower (or lower case "u" "l") ++ * ++ * 5 GHz Examples: ++ * Chanspec BW Center Ch Channel Range Primary Ch ++ * 5g8 20MHz 8 - - ++ * 52 20MHz 52 - - ++ * 52/40 40MHz 54 52-56 52 ++ * 56/40 40MHz 54 52-56 56 ++ * 52/80 80MHz 58 52-64 52 ++ * 56/80 80MHz 58 52-64 56 ++ * 60/80 80MHz 58 52-64 60 ++ * 64/80 80MHz 58 52-64 64 ++ * 52/160 160MHz 50 36-64 52 ++ * 36/160 160MGz 50 36-64 36 ++ * 36/80+80/42-106 80+80MHz 42,106 36-48,100-112 36 ++ * ++ * 2 GHz Examples: ++ * Chanspec BW Center Ch Channel Range Primary Ch ++ * 2g8 20MHz 8 - - ++ * 8 20MHz 8 - - ++ * 6 20MHz 6 - - ++ * 6/40l 40MHz 8 6-10 6 ++ * 6l 40MHz 8 6-10 6 ++ * 6/40u 40MHz 4 2-6 6 ++ * 6u 40MHz 4 2-6 6 ++ */ ++ ++/* bandwidth ASCII string */ ++static const char *wf_chspec_bw_str[] = ++{ ++ "5", ++ "10", ++ "20", ++ "40", ++ "80", ++ "160", ++ "80+80", ++ "na" ++}; ++ ++static const uint8 wf_chspec_bw_mhz[] = ++{5, 10, 20, 40, 80, 160, 160}; ++ ++#define WF_NUM_BW \ ++ (sizeof(wf_chspec_bw_mhz)/sizeof(uint8)) ++ ++/* 40MHz channels in 5GHz band */ ++static const uint8 wf_5g_40m_chans[] = ++{38, 46, 54, 62, 102, 110, 118, 126, 134, 142, 151, 159}; ++#define WF_NUM_5G_40M_CHANS \ ++ (sizeof(wf_5g_40m_chans)/sizeof(uint8)) ++ ++/* 80MHz channels in 5GHz band */ ++static const uint8 wf_5g_80m_chans[] = ++{42, 58, 106, 122, 138, 155}; ++#define WF_NUM_5G_80M_CHANS \ ++ (sizeof(wf_5g_80m_chans)/sizeof(uint8)) ++ ++/* 160MHz channels in 5GHz band */ ++static const uint8 wf_5g_160m_chans[] = ++{50, 114}; ++#define WF_NUM_5G_160M_CHANS \ ++ (sizeof(wf_5g_160m_chans)/sizeof(uint8)) ++ ++ ++/* convert bandwidth from chanspec to MHz */ ++static uint ++bw_chspec_to_mhz(chanspec_t chspec) ++{ ++ uint bw; ++ ++ bw = (chspec & WL_CHANSPEC_BW_MASK) >> WL_CHANSPEC_BW_SHIFT; ++ return (bw >= WF_NUM_BW ? 0 : wf_chspec_bw_mhz[bw]); ++} ++ ++/* bw in MHz, return the channel count from the center channel to the ++ * the channel at the edge of the band ++ */ ++static uint8 ++center_chan_to_edge(uint bw) ++{ ++ /* edge channels separated by BW - 10MHz on each side ++ * delta from cf to edge is half of that, ++ * MHz to channel num conversion is 5MHz/channel ++ */ ++ return (uint8)(((bw - 20) / 2) / 5); ++} ++ ++/* return channel number of the low edge of the band ++ * given the center channel and BW ++ */ ++static uint8 ++channel_low_edge(uint center_ch, uint bw) ++{ ++ return (uint8)(center_ch - center_chan_to_edge(bw)); ++} ++ ++/* return side band number given center channel and control channel ++ * return -1 on error ++ */ ++static int ++channel_to_sb(uint center_ch, uint ctl_ch, uint bw) ++{ ++ uint lowest = channel_low_edge(center_ch, bw); ++ uint sb; ++ ++ if ((ctl_ch - lowest) % 4) { ++ /* bad ctl channel, not mult 4 */ ++ return -1; ++ } ++ ++ sb = ((ctl_ch - lowest) / 4); ++ ++ /* sb must be a index to a 20MHz channel in range */ ++ if (sb >= (bw / 20)) { ++ /* ctl_ch must have been too high for the center_ch */ ++ return -1; ++ } ++ ++ return sb; ++} ++ ++/* return control channel given center channel and side band */ ++static uint8 ++channel_to_ctl_chan(uint center_ch, uint bw, uint sb) ++{ ++ return (uint8)(channel_low_edge(center_ch, bw) + sb * 4); ++} ++ ++/* return index of 80MHz channel from channel number ++ * return -1 on error ++ */ ++static int ++channel_80mhz_to_id(uint ch) ++{ ++ uint i; ++ for (i = 0; i < WF_NUM_5G_80M_CHANS; i ++) { ++ if (ch == wf_5g_80m_chans[i]) ++ return i; ++ } ++ ++ return -1; ++} ++ ++/* given a chanspec and a string buffer, format the chanspec as a ++ * string, and return the original pointer a. ++ * Min buffer length must be CHANSPEC_STR_LEN. ++ * On error return NULL ++ */ ++char * ++wf_chspec_ntoa(chanspec_t chspec, char *buf) ++{ ++ const char *band; ++ uint ctl_chan; ++ ++ if (wf_chspec_malformed(chspec)) ++ return NULL; ++ ++ band = ""; ++ ++ /* check for non-default band spec */ ++ if ((CHSPEC_IS2G(chspec) && CHSPEC_CHANNEL(chspec) > CH_MAX_2G_CHANNEL) || ++ (CHSPEC_IS5G(chspec) && CHSPEC_CHANNEL(chspec) <= CH_MAX_2G_CHANNEL)) ++ band = (CHSPEC_IS2G(chspec)) ? "2g" : "5g"; ++ ++ /* ctl channel */ ++ ctl_chan = wf_chspec_ctlchan(chspec); ++ ++ /* bandwidth and ctl sideband */ ++ if (CHSPEC_IS20(chspec)) { ++ snprintf(buf, CHANSPEC_STR_LEN, "%s%d", band, ctl_chan); ++ } else if (!CHSPEC_IS8080(chspec)) { ++ const char *bw; ++ const char *sb = ""; ++ ++ bw = wf_chspec_bw_str[(chspec & WL_CHANSPEC_BW_MASK) >> WL_CHANSPEC_BW_SHIFT]; ++ ++#ifdef CHANSPEC_NEW_40MHZ_FORMAT ++ /* ctl sideband string if needed for 2g 40MHz */ ++ if (CHSPEC_IS40(chspec) && CHSPEC_IS2G(chspec)) { ++ sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l"; ++ } ++ ++ snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s%s", band, ctl_chan, bw, sb); ++#else ++ /* ctl sideband string instead of BW for 40MHz */ ++ if (CHSPEC_IS40(chspec)) { ++ sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l"; ++ snprintf(buf, CHANSPEC_STR_LEN, "%s%d%s", band, ctl_chan, sb); ++ } else { ++ snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s", band, ctl_chan, bw); ++ } ++#endif /* CHANSPEC_NEW_40MHZ_FORMAT */ ++ ++ } else { ++ /* 80+80 */ ++ uint chan1 = (chspec & WL_CHANSPEC_CHAN1_MASK) >> WL_CHANSPEC_CHAN1_SHIFT; ++ uint chan2 = (chspec & WL_CHANSPEC_CHAN2_MASK) >> WL_CHANSPEC_CHAN2_SHIFT; ++ ++ /* convert to channel number */ ++ chan1 = (chan1 < WF_NUM_5G_80M_CHANS) ? wf_5g_80m_chans[chan1] : 0; ++ chan2 = (chan2 < WF_NUM_5G_80M_CHANS) ? wf_5g_80m_chans[chan2] : 0; ++ ++ /* Outputs a max of CHANSPEC_STR_LEN chars including '\0' */ ++ snprintf(buf, CHANSPEC_STR_LEN, "%d/80+80/%d-%d", ctl_chan, chan1, chan2); ++ } ++ ++ return (buf); ++} ++ ++static int ++read_uint(const char **p, unsigned int *num) ++{ ++ unsigned long val; ++ char *endp = NULL; ++ ++ val = strtoul(*p, &endp, 10); ++ /* if endp is the initial pointer value, then a number was not read */ ++ if (endp == *p) ++ return 0; ++ ++ /* advance the buffer pointer to the end of the integer string */ ++ *p = endp; ++ /* return the parsed integer */ ++ *num = (unsigned int)val; ++ ++ return 1; ++} ++ ++/* given a chanspec string, convert to a chanspec. ++ * On error return 0 ++ */ ++chanspec_t ++wf_chspec_aton(const char *a) ++{ ++ chanspec_t chspec; ++ uint chspec_ch, chspec_band, bw, chspec_bw, chspec_sb; ++ uint num, ctl_ch; ++ uint ch1, ch2; ++ char c, sb_ul = '\0'; ++ int i; ++ ++ bw = 20; ++ chspec_sb = 0; ++ chspec_ch = ch1 = ch2 = 0; ++ ++ /* parse channel num or band */ ++ if (!read_uint(&a, &num)) ++ return 0; ++ ++ /* if we are looking at a 'g', then the first number was a band */ ++ c = tolower(a[0]); ++ if (c == 'g') { ++ a ++; /* consume the char */ ++ ++ /* band must be "2" or "5" */ ++ if (num == 2) ++ chspec_band = WL_CHANSPEC_BAND_2G; ++ else if (num == 5) ++ chspec_band = WL_CHANSPEC_BAND_5G; ++ else ++ return 0; ++ ++ /* read the channel number */ ++ if (!read_uint(&a, &ctl_ch)) ++ return 0; ++ ++ c = tolower(a[0]); ++ } ++ else { ++ /* first number is channel, use default for band */ ++ ctl_ch = num; ++ chspec_band = ((ctl_ch <= CH_MAX_2G_CHANNEL) ? ++ WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G); ++ } ++ ++ if (c == '\0') { ++ /* default BW of 20MHz */ ++ chspec_bw = WL_CHANSPEC_BW_20; ++ goto done_read; ++ } ++ ++ a ++; /* consume the 'u','l', or '/' */ ++ ++ /* check 'u'/'l' */ ++ if (c == 'u' || c == 'l') { ++ sb_ul = c; ++ chspec_bw = WL_CHANSPEC_BW_40; ++ goto done_read; ++ } ++ ++ /* next letter must be '/' */ ++ if (c != '/') ++ return 0; ++ ++ /* read bandwidth */ ++ if (!read_uint(&a, &bw)) ++ return 0; ++ ++ /* convert to chspec value */ ++ if (bw == 20) { ++ chspec_bw = WL_CHANSPEC_BW_20; ++ } else if (bw == 40) { ++ chspec_bw = WL_CHANSPEC_BW_40; ++ } else if (bw == 80) { ++ chspec_bw = WL_CHANSPEC_BW_80; ++ } else if (bw == 160) { ++ chspec_bw = WL_CHANSPEC_BW_160; ++ } else { ++ return 0; ++ } ++ ++ /* So far we have g/ ++ * Can now be followed by u/l if bw = 40, ++ * or '+80' if bw = 80, to make '80+80' bw. ++ */ ++ ++ c = tolower(a[0]); ++ ++ /* if we have a 2g/40 channel, we should have a l/u spec now */ ++ if (chspec_band == WL_CHANSPEC_BAND_2G && bw == 40) { ++ if (c == 'u' || c == 'l') { ++ a ++; /* consume the u/l char */ ++ sb_ul = c; ++ goto done_read; ++ } ++ } ++ ++ /* check for 80+80 */ ++ if (c == '+') { ++ /* 80+80 */ ++ static const char *plus80 = "80/"; ++ ++ /* must be looking at '+80/' ++ * check and consume this string. ++ */ ++ chspec_bw = WL_CHANSPEC_BW_8080; ++ ++ a ++; /* consume the char '+' */ ++ ++ /* consume the '80/' string */ ++ for (i = 0; i < 3; i++) { ++ if (*a++ != *plus80++) { ++ return 0; ++ } ++ } ++ ++ /* read primary 80MHz channel */ ++ if (!read_uint(&a, &ch1)) ++ return 0; ++ ++ /* must followed by '-' */ ++ if (a[0] != '-') ++ return 0; ++ a ++; /* consume the char */ ++ ++ /* read secondary 80MHz channel */ ++ if (!read_uint(&a, &ch2)) ++ return 0; ++ } ++ ++done_read: ++ /* skip trailing white space */ ++ while (a[0] == ' ') { ++ a ++; ++ } ++ ++ /* must be end of string */ ++ if (a[0] != '\0') ++ return 0; ++ ++ /* Now have all the chanspec string parts read; ++ * chspec_band, ctl_ch, chspec_bw, sb_ul, ch1, ch2. ++ * chspec_band and chspec_bw are chanspec values. ++ * Need to convert ctl_ch, sb_ul, and ch1,ch2 into ++ * a center channel (or two) and sideband. ++ */ ++ ++ /* if a sb u/l string was given, just use that, ++ * guaranteed to be bw = 40 by sting parse. ++ */ ++ if (sb_ul != '\0') { ++ if (sb_ul == 'l') { ++ chspec_ch = UPPER_20_SB(ctl_ch); ++ chspec_sb = WL_CHANSPEC_CTL_SB_LLL; ++ } else if (sb_ul == 'u') { ++ chspec_ch = LOWER_20_SB(ctl_ch); ++ chspec_sb = WL_CHANSPEC_CTL_SB_LLU; ++ } ++ } ++ /* if the bw is 20, center and sideband are trivial */ ++ else if (chspec_bw == WL_CHANSPEC_BW_20) { ++ chspec_ch = ctl_ch; ++ chspec_sb = 0; ++ } ++ /* if the bw is 40/80/160, not 80+80, a single method ++ * can be used to to find the center and sideband ++ */ ++ else if (chspec_bw != WL_CHANSPEC_BW_8080) { ++ /* figure out ctl sideband based on ctl channel and bandwidth */ ++ const uint8 *center_ch = NULL; ++ int num_ch = 0; ++ int sb = -1; ++ ++ if (chspec_bw == WL_CHANSPEC_BW_40) { ++ center_ch = wf_5g_40m_chans; ++ num_ch = WF_NUM_5G_40M_CHANS; ++ } else if (chspec_bw == WL_CHANSPEC_BW_80) { ++ center_ch = wf_5g_80m_chans; ++ num_ch = WF_NUM_5G_80M_CHANS; ++ } else if (chspec_bw == WL_CHANSPEC_BW_160) { ++ center_ch = wf_5g_160m_chans; ++ num_ch = WF_NUM_5G_160M_CHANS; ++ } else { ++ return 0; ++ } ++ ++ for (i = 0; i < num_ch; i ++) { ++ sb = channel_to_sb(center_ch[i], ctl_ch, bw); ++ if (sb >= 0) { ++ chspec_ch = center_ch[i]; ++ chspec_sb = sb << WL_CHANSPEC_CTL_SB_SHIFT; ++ break; ++ } ++ } ++ ++ /* check for no matching sb/center */ ++ if (sb < 0) { ++ return 0; ++ } ++ } ++ /* Otherwise, bw is 80+80. Figure out channel pair and sb */ ++ else { ++ int ch1_id = 0, ch2_id = 0; ++ int sb; ++ ++ ch1_id = channel_80mhz_to_id(ch1); ++ ch2_id = channel_80mhz_to_id(ch2); ++ ++ /* validate channels */ ++ if (ch1 >= ch2 || ch1_id < 0 || ch2_id < 0) ++ return 0; ++ ++ /* combined channel in chspec */ ++ chspec_ch = (((uint16)ch1_id << WL_CHANSPEC_CHAN1_SHIFT) | ++ ((uint16)ch2_id << WL_CHANSPEC_CHAN2_SHIFT)); ++ ++ /* figure out ctl sideband */ ++ ++ /* does the primary channel fit with the 1st 80MHz channel ? */ ++ sb = channel_to_sb(ch1, ctl_ch, bw); ++ if (sb < 0) { ++ /* no, so does the primary channel fit with the 2nd 80MHz channel ? */ ++ sb = channel_to_sb(ch2, ctl_ch, bw); ++ if (sb < 0) { ++ /* no match for ctl_ch to either 80MHz center channel */ ++ return 0; ++ } ++ /* sb index is 0-3 for the low 80MHz channel, and 4-7 for ++ * the high 80MHz channel. Add 4 to to shift to high set. ++ */ ++ sb += 4; ++ } ++ ++ chspec_sb = sb << WL_CHANSPEC_CTL_SB_SHIFT; ++ } ++ ++ chspec = (chspec_ch | chspec_band | chspec_bw | chspec_sb); ++ ++ if (wf_chspec_malformed(chspec)) ++ return 0; ++ ++ return chspec; ++} ++ ++/* ++ * Verify the chanspec is using a legal set of parameters, i.e. that the ++ * chanspec specified a band, bw, ctl_sb and channel and that the ++ * combination could be legal given any set of circumstances. ++ * RETURNS: TRUE is the chanspec is malformed, false if it looks good. ++ */ ++bool ++wf_chspec_malformed(chanspec_t chanspec) ++{ ++ uint chspec_bw = CHSPEC_BW(chanspec); ++ uint chspec_ch = CHSPEC_CHANNEL(chanspec); ++ ++ /* must be 2G or 5G band */ ++ if (CHSPEC_IS2G(chanspec)) { ++ /* must be valid bandwidth */ ++ if (chspec_bw != WL_CHANSPEC_BW_20 && ++ chspec_bw != WL_CHANSPEC_BW_40) { ++ return TRUE; ++ } ++ } else if (CHSPEC_IS5G(chanspec)) { ++ if (chspec_bw == WL_CHANSPEC_BW_8080) { ++ uint ch1_id, ch2_id; ++ ++ /* channel number in 80+80 must be in range */ ++ ch1_id = CHSPEC_CHAN1(chanspec); ++ ch2_id = CHSPEC_CHAN2(chanspec); ++ if (ch1_id >= WF_NUM_5G_80M_CHANS || ch2_id >= WF_NUM_5G_80M_CHANS) ++ return TRUE; ++ ++ /* ch2 must be above ch1 for the chanspec */ ++ if (ch2_id <= ch1_id) ++ return TRUE; ++ } else if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40 || ++ chspec_bw == WL_CHANSPEC_BW_80 || chspec_bw == WL_CHANSPEC_BW_160) { ++ ++ if (chspec_ch > MAXCHANNEL) { ++ return TRUE; ++ } ++ } else { ++ /* invalid bandwidth */ ++ return TRUE; ++ } ++ } else { ++ /* must be 2G or 5G band */ ++ return TRUE; ++ } ++ ++ /* side band needs to be consistent with bandwidth */ ++ if (chspec_bw == WL_CHANSPEC_BW_20) { ++ if (CHSPEC_CTL_SB(chanspec) != WL_CHANSPEC_CTL_SB_LLL) ++ return TRUE; ++ } else if (chspec_bw == WL_CHANSPEC_BW_40) { ++ if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LLU) ++ return TRUE; ++ } else if (chspec_bw == WL_CHANSPEC_BW_80) { ++ if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LUU) ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++/* ++ * Verify the chanspec specifies a valid channel according to 802.11. ++ * RETURNS: TRUE if the chanspec is a valid 802.11 channel ++ */ ++bool ++wf_chspec_valid(chanspec_t chanspec) ++{ ++ uint chspec_bw = CHSPEC_BW(chanspec); ++ uint chspec_ch = CHSPEC_CHANNEL(chanspec); ++ ++ if (wf_chspec_malformed(chanspec)) ++ return FALSE; ++ ++ if (CHSPEC_IS2G(chanspec)) { ++ /* must be valid bandwidth and channel range */ ++ if (chspec_bw == WL_CHANSPEC_BW_20) { ++ if (chspec_ch >= 1 && chspec_ch <= 14) ++ return TRUE; ++ } else if (chspec_bw == WL_CHANSPEC_BW_40) { ++ if (chspec_ch >= 3 && chspec_ch <= 11) ++ return TRUE; ++ } ++ } else if (CHSPEC_IS5G(chanspec)) { ++ if (chspec_bw == WL_CHANSPEC_BW_8080) { ++ uint16 ch1, ch2; ++ ++ ch1 = wf_5g_80m_chans[CHSPEC_CHAN1(chanspec)]; ++ ch2 = wf_5g_80m_chans[CHSPEC_CHAN2(chanspec)]; ++ ++ /* the two channels must be separated by more than 80MHz by VHT req, ++ * and ch2 above ch1 for the chanspec ++ */ ++ if (ch2 > ch1 + CH_80MHZ_APART) ++ return TRUE; ++ } else { ++ const uint8 *center_ch; ++ uint num_ch, i; ++ ++ if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40) { ++ center_ch = wf_5g_40m_chans; ++ num_ch = WF_NUM_5G_40M_CHANS; ++ } else if (chspec_bw == WL_CHANSPEC_BW_80) { ++ center_ch = wf_5g_80m_chans; ++ num_ch = WF_NUM_5G_80M_CHANS; ++ } else if (chspec_bw == WL_CHANSPEC_BW_160) { ++ center_ch = wf_5g_160m_chans; ++ num_ch = WF_NUM_5G_160M_CHANS; ++ } else { ++ /* invalid bandwidth */ ++ return FALSE; ++ } ++ ++ /* check for a valid center channel */ ++ if (chspec_bw == WL_CHANSPEC_BW_20) { ++ /* We don't have an array of legal 20MHz 5G channels, but they are ++ * each side of the legal 40MHz channels. Check the chanspec ++ * channel against either side of the 40MHz channels. ++ */ ++ for (i = 0; i < num_ch; i ++) { ++ if (chspec_ch == (uint)LOWER_20_SB(center_ch[i]) || ++ chspec_ch == (uint)UPPER_20_SB(center_ch[i])) ++ break; /* match found */ ++ } ++ ++ if (i == num_ch) { ++ /* check for legacy JP channels on failure */ ++ if (chspec_ch == 34 || chspec_ch == 38 || ++ chspec_ch == 42 || chspec_ch == 46) ++ i = 0; ++ } ++ } else { ++ /* check the chanspec channel to each legal channel */ ++ for (i = 0; i < num_ch; i ++) { ++ if (chspec_ch == center_ch[i]) ++ break; /* match found */ ++ } ++ } ++ ++ if (i < num_ch) { ++ /* match found */ ++ return TRUE; ++ } ++ } ++ } ++ ++ return FALSE; ++} ++ ++/* ++ * This function returns the channel number that control traffic is being sent on, for 20MHz ++ * channels this is just the channel number, for 40MHZ, 80MHz, 160MHz channels it is the 20MHZ ++ * sideband depending on the chanspec selected ++ */ ++uint8 ++wf_chspec_ctlchan(chanspec_t chspec) ++{ ++ uint center_chan; ++ uint bw_mhz; ++ uint sb; ++ ++ ASSERT(!wf_chspec_malformed(chspec)); ++ ++ /* Is there a sideband ? */ ++ if (CHSPEC_IS20(chspec)) { ++ return CHSPEC_CHANNEL(chspec); ++ } else { ++ sb = CHSPEC_CTL_SB(chspec) >> WL_CHANSPEC_CTL_SB_SHIFT; ++ ++ if (CHSPEC_IS8080(chspec)) { ++ bw_mhz = 80; ++ ++ if (sb < 4) { ++ center_chan = CHSPEC_CHAN1(chspec); ++ } ++ else { ++ center_chan = CHSPEC_CHAN2(chspec); ++ sb -= 4; ++ } ++ ++ /* convert from channel index to channel number */ ++ center_chan = wf_5g_80m_chans[center_chan]; ++ } ++ else { ++ bw_mhz = bw_chspec_to_mhz(chspec); ++ center_chan = CHSPEC_CHANNEL(chspec) >> WL_CHANSPEC_CHAN_SHIFT; ++ } ++ ++ return (channel_to_ctl_chan(center_chan, bw_mhz, sb)); ++ } ++} ++ ++/* ++ * This function returns the chanspec of the control channel of a given chanspec ++ */ ++chanspec_t ++wf_chspec_ctlchspec(chanspec_t chspec) ++{ ++ chanspec_t ctl_chspec = chspec; ++ uint8 ctl_chan; ++ ++ ASSERT(!wf_chspec_malformed(chspec)); ++ ++ /* Is there a sideband ? */ ++ if (!CHSPEC_IS20(chspec)) { ++ ctl_chan = wf_chspec_ctlchan(chspec); ++ ctl_chspec = ctl_chan | WL_CHANSPEC_BW_20; ++ ctl_chspec |= CHSPEC_BAND(chspec); ++ } ++ return ctl_chspec; ++} ++ ++/* return chanspec given control channel and bandwidth ++ * return 0 on error ++ */ ++uint16 ++wf_channel2chspec(uint ctl_ch, uint bw) ++{ ++ uint16 chspec; ++ const uint8 *center_ch = NULL; ++ int num_ch = 0; ++ int sb = -1; ++ int i = 0; ++ ++ chspec = ((ctl_ch <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G); ++ ++ chspec |= bw; ++ ++ if (bw == WL_CHANSPEC_BW_40) { ++ center_ch = wf_5g_40m_chans; ++ num_ch = WF_NUM_5G_40M_CHANS; ++ bw = 40; ++ } else if (bw == WL_CHANSPEC_BW_80) { ++ center_ch = wf_5g_80m_chans; ++ num_ch = WF_NUM_5G_80M_CHANS; ++ bw = 80; ++ } else if (bw == WL_CHANSPEC_BW_160) { ++ center_ch = wf_5g_160m_chans; ++ num_ch = WF_NUM_5G_160M_CHANS; ++ bw = 160; ++ } else if (bw == WL_CHANSPEC_BW_20) { ++ chspec |= ctl_ch; ++ return chspec; ++ } else { ++ return 0; ++ } ++ ++ for (i = 0; i < num_ch; i ++) { ++ sb = channel_to_sb(center_ch[i], ctl_ch, bw); ++ if (sb >= 0) { ++ chspec |= center_ch[i]; ++ chspec |= (sb << WL_CHANSPEC_CTL_SB_SHIFT); ++ break; ++ } ++ } ++ ++ /* check for no matching sb/center */ ++ if (sb < 0) { ++ return 0; ++ } ++ ++ return chspec; ++} ++#endif /* D11AC_IOTYPES */ ++ ++/* ++ * This function returns the chanspec for the primary 40MHz of an 80MHz channel. ++ * The control sideband specifies the same 20MHz channel that the 80MHz channel is using ++ * as the primary 20MHz channel. ++ */ ++extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec) ++{ ++ chanspec_t chspec40 = chspec; ++ uint center_chan; ++ uint sb; ++ ++ ASSERT(!wf_chspec_malformed(chspec)); ++ ++ if (CHSPEC_IS80(chspec)) { ++ center_chan = CHSPEC_CHANNEL(chspec); ++ sb = CHSPEC_CTL_SB(chspec); ++ ++ if (sb == WL_CHANSPEC_CTL_SB_UL) { ++ /* Primary 40MHz is on upper side */ ++ sb = WL_CHANSPEC_CTL_SB_L; ++ center_chan += CH_20MHZ_APART; ++ } else if (sb == WL_CHANSPEC_CTL_SB_UU) { ++ /* Primary 40MHz is on upper side */ ++ sb = WL_CHANSPEC_CTL_SB_U; ++ center_chan += CH_20MHZ_APART; ++ } else { ++ /* Primary 40MHz is on lower side */ ++ /* sideband bits are the same for LL/LU and L/U */ ++ center_chan -= CH_20MHZ_APART; ++ } ++ ++ /* Create primary 40MHz chanspec */ ++ chspec40 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_40 | ++ sb | center_chan); ++ } ++ ++ return chspec40; ++} ++ ++/* ++ * Return the channel number for a given frequency and base frequency. ++ * The returned channel number is relative to the given base frequency. ++ * If the given base frequency is zero, a base frequency of 5 GHz is assumed for ++ * frequencies from 5 - 6 GHz, and 2.407 GHz is assumed for 2.4 - 2.5 GHz. ++ * ++ * Frequency is specified in MHz. ++ * The base frequency is specified as (start_factor * 500 kHz). ++ * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for ++ * 2.4 GHz and 5 GHz bands. ++ * ++ * The returned channel will be in the range [1, 14] in the 2.4 GHz band ++ * and [0, 200] otherwise. ++ * -1 is returned if the start_factor is WF_CHAN_FACTOR_2_4_G and the ++ * frequency is not a 2.4 GHz channel, or if the frequency is not and even ++ * multiple of 5 MHz from the base frequency to the base plus 1 GHz. ++ * ++ * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 ++ */ ++int ++wf_mhz2channel(uint freq, uint start_factor) ++{ ++ int ch = -1; ++ uint base; ++ int offset; ++ ++ /* take the default channel start frequency */ ++ if (start_factor == 0) { ++ if (freq >= 2400 && freq <= 2500) ++ start_factor = WF_CHAN_FACTOR_2_4_G; ++ else if (freq >= 5000 && freq <= 6000) ++ start_factor = WF_CHAN_FACTOR_5_G; ++ } ++ ++ if (freq == 2484 && start_factor == WF_CHAN_FACTOR_2_4_G) ++ return 14; ++ ++ base = start_factor / 2; ++ ++ /* check that the frequency is in 1GHz range of the base */ ++ if ((freq < base) || (freq > base + 1000)) ++ return -1; ++ ++ offset = freq - base; ++ ch = offset / 5; ++ ++ /* check that frequency is a 5MHz multiple from the base */ ++ if (offset != (ch * 5)) ++ return -1; ++ ++ /* restricted channel range check for 2.4G */ ++ if (start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 13)) ++ return -1; ++ ++ return ch; ++} ++ ++/* ++ * Return the center frequency in MHz of the given channel and base frequency. ++ * The channel number is interpreted relative to the given base frequency. ++ * ++ * The valid channel range is [1, 14] in the 2.4 GHz band and [0, 200] otherwise. ++ * The base frequency is specified as (start_factor * 500 kHz). ++ * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_4_G, and WF_CHAN_FACTOR_5_G ++ * are defined for 2.4 GHz, 4 GHz, and 5 GHz bands. ++ * The channel range of [1, 14] is only checked for a start_factor of ++ * WF_CHAN_FACTOR_2_4_G (4814 = 2407 * 2). ++ * Odd start_factors produce channels on .5 MHz boundaries, in which case ++ * the answer is rounded down to an integral MHz. ++ * -1 is returned for an out of range channel. ++ * ++ * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 ++ */ ++int ++wf_channel2mhz(uint ch, uint start_factor) ++{ ++ int freq; ++ ++ if ((start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 14)) || ++ (ch > 200)) ++ freq = -1; ++ else if ((start_factor == WF_CHAN_FACTOR_2_4_G) && (ch == 14)) ++ freq = 2484; ++ else ++ freq = ch * 5 + start_factor / 2; ++ ++ return freq; ++} +diff --git a/drivers/net/wireless/ap6211/dhd.h b/drivers/net/wireless/ap6211/dhd.h +new file mode 100755 +index 0000000..006a41c +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd.h +@@ -0,0 +1,888 @@ ++/* ++ * Header file describing the internal (inter-module) DHD interfaces. ++ * ++ * Provides type definitions and function prototypes used to link the ++ * DHD OS, bus, and protocol modules. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd.h 373887 2012-12-10 21:58:02Z $ ++ */ ++ ++/**************** ++ * Common types * ++ */ ++ ++#ifndef _dhd_h_ ++#define _dhd_h_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) ++#include ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */ ++/* The kernel threading is sdio-specific */ ++struct task_struct; ++struct sched_param; ++int setScheduler(struct task_struct *p, int policy, struct sched_param *param); ++ ++#define ALL_INTERFACES 0xff ++ ++#include ++#include ++ ++ ++/* Forward decls */ ++struct dhd_bus; ++struct dhd_prot; ++struct dhd_info; ++ ++/* The level of bus communication with the dongle */ ++enum dhd_bus_state { ++ DHD_BUS_DOWN, /* Not ready for frame transfers */ ++ DHD_BUS_LOAD, /* Download access only (CPU reset) */ ++ DHD_BUS_DATA /* Ready for frame transfers */ ++}; ++ ++enum dhd_op_flags { ++/* Firmware requested operation mode */ ++ DHD_FLAG_STA_MODE = BIT(0), /* STA only */ ++ DHD_FLAG_HOSTAP_MODE = BIT(1), /* SOFTAP only */ ++ DHD_FLAG_P2P_MODE = BIT(2), /* P2P Only */ ++ /* STA + P2P */ ++ DHD_FLAG_CONCURR_SINGLE_CHAN_MODE = (DHD_FLAG_STA_MODE | DHD_FLAG_P2P_MODE), ++ DHD_FLAG_CONCURR_MULTI_CHAN_MODE = BIT(4), /* STA + P2P */ ++ /* Current P2P mode for P2P connection */ ++ DHD_FLAG_P2P_GC_MODE = BIT(5), ++ DHD_FLAG_P2P_GO_MODE = BIT(6), ++ DHD_FLAG_MBSS_MODE = BIT(7) /* MBSS in future */ ++}; ++ ++#define MANUFACTRING_FW "WLTEST" ++ ++/* max sequential rxcntl timeouts to set HANG event */ ++#ifndef MAX_CNTL_TIMEOUT ++#define MAX_CNTL_TIMEOUT 2 ++#endif ++ ++#define DHD_SCAN_ASSOC_ACTIVE_TIME 40 /* ms: Embedded default Active setting from DHD */ ++#define DHD_SCAN_UNASSOC_ACTIVE_TIME 80 /* ms: Embedded def. Unassoc Active setting from DHD */ ++#define DHD_SCAN_PASSIVE_TIME 130 /* ms: Embedded default Passive setting from DHD */ ++ ++#ifndef POWERUP_MAX_RETRY ++#define POWERUP_MAX_RETRY 3 /* how many times we retry to power up the chip */ ++#endif ++#ifndef POWERUP_WAIT_MS ++#define POWERUP_WAIT_MS 2000 /* ms: time out in waiting wifi to come up */ ++#endif ++ ++enum dhd_bus_wake_state { ++ WAKE_LOCK_OFF, ++ WAKE_LOCK_PRIV, ++ WAKE_LOCK_DPC, ++ WAKE_LOCK_IOCTL, ++ WAKE_LOCK_DOWNLOAD, ++ WAKE_LOCK_TMOUT, ++ WAKE_LOCK_WATCHDOG, ++ WAKE_LOCK_LINK_DOWN_TMOUT, ++ WAKE_LOCK_PNO_FIND_TMOUT, ++ WAKE_LOCK_SOFTAP_SET, ++ WAKE_LOCK_SOFTAP_STOP, ++ WAKE_LOCK_SOFTAP_START, ++ WAKE_LOCK_SOFTAP_THREAD, ++ WAKE_LOCK_MAX ++}; ++ ++enum dhd_prealloc_index { ++ DHD_PREALLOC_PROT = 0, ++ DHD_PREALLOC_RXBUF, ++ DHD_PREALLOC_DATABUF, ++#if defined(STATIC_WL_PRIV_STRUCT) ++ DHD_PREALLOC_OSL_BUF, ++ DHD_PREALLOC_WIPHY_ESCAN0 = 5, ++#else ++ DHD_PREALLOC_OSL_BUF ++#endif /* STATIC_WL_PRIV_STRUCT */ ++}; ++ ++typedef enum { ++ DHD_IF_NONE = 0, ++ DHD_IF_ADD, ++ DHD_IF_DEL, ++ DHD_IF_CHANGE, ++ DHD_IF_DELETING ++} dhd_if_state_t; ++ ++ ++#if defined(CONFIG_DHD_USE_STATIC_BUF) ++ ++uint8* dhd_os_prealloc(void *osh, int section, uint size); ++void dhd_os_prefree(void *osh, void *addr, uint size); ++#define DHD_OS_PREALLOC(osh, section, size) dhd_os_prealloc(osh, section, size) ++#define DHD_OS_PREFREE(osh, addr, size) dhd_os_prefree(osh, addr, size) ++ ++#else ++ ++#define DHD_OS_PREALLOC(osh, section, size) MALLOC(osh, size) ++#define DHD_OS_PREFREE(osh, addr, size) MFREE(osh, addr, size) ++ ++#endif /* defined(CONFIG_DHD_USE_STATIC_BUF) */ ++ ++/* Packet alignment for most efficient SDIO (can change based on platform) */ ++#ifndef DHD_SDALIGN ++#define DHD_SDALIGN 32 ++#endif ++ ++/* host reordering packts logic */ ++/* followed the structure to hold the reorder buffers (void **p) */ ++typedef struct reorder_info { ++ void **p; ++ uint8 flow_id; ++ uint8 cur_idx; ++ uint8 exp_idx; ++ uint8 max_idx; ++ uint8 pend_pkts; ++} reorder_info_t; ++ ++/* Common structure for module and instance linkage */ ++typedef struct dhd_pub { ++ /* Linkage ponters */ ++ osl_t *osh; /* OSL handle */ ++ struct dhd_bus *bus; /* Bus module handle */ ++ struct dhd_prot *prot; /* Protocol module handle */ ++ struct dhd_info *info; /* Info module handle */ ++ ++ /* Internal dhd items */ ++ bool up; /* Driver up/down (to OS) */ ++ bool txoff; /* Transmit flow-controlled */ ++ bool dongle_reset; /* TRUE = DEVRESET put dongle into reset */ ++ enum dhd_bus_state busstate; ++ uint hdrlen; /* Total DHD header length (proto + bus) */ ++ uint maxctl; /* Max size rxctl request from proto to bus */ ++ uint rxsz; /* Rx buffer size bus module should use */ ++ uint8 wme_dp; /* wme discard priority */ ++ ++ /* Dongle media info */ ++ bool iswl; /* Dongle-resident driver is wl */ ++ ulong drv_version; /* Version of dongle-resident driver */ ++ struct ether_addr mac; /* MAC address obtained from dongle */ ++ dngl_stats_t dstats; /* Stats for dongle-based data */ ++ ++ /* Additional stats for the bus level */ ++ ulong tx_packets; /* Data packets sent to dongle */ ++ ulong tx_multicast; /* Multicast data packets sent to dongle */ ++ ulong tx_errors; /* Errors in sending data to dongle */ ++ ulong tx_ctlpkts; /* Control packets sent to dongle */ ++ ulong tx_ctlerrs; /* Errors sending control frames to dongle */ ++ ulong rx_packets; /* Packets sent up the network interface */ ++ ulong rx_multicast; /* Multicast packets sent up the network interface */ ++ ulong rx_errors; /* Errors processing rx data packets */ ++ ulong rx_ctlpkts; /* Control frames processed from dongle */ ++ ulong rx_ctlerrs; /* Errors in processing rx control frames */ ++ ulong rx_dropped; /* Packets dropped locally (no memory) */ ++ ulong rx_flushed; /* Packets flushed due to unscheduled sendup thread */ ++ ulong wd_dpc_sched; /* Number of times dhd dpc scheduled by watchdog timer */ ++ ++ ulong rx_readahead_cnt; /* Number of packets where header read-ahead was used. */ ++ ulong tx_realloc; /* Number of tx packets we had to realloc for headroom */ ++ ulong fc_packets; /* Number of flow control pkts recvd */ ++ ++ /* Last error return */ ++ int bcmerror; ++ uint tickcnt; ++ ++ /* Last error from dongle */ ++ int dongle_error; ++ ++ uint8 country_code[WLC_CNTRY_BUF_SZ]; ++ ++ /* Suspend disable flag and "in suspend" flag */ ++ int suspend_disable_flag; /* "1" to disable all extra powersaving during suspend */ ++ int in_suspend; /* flag set to 1 when early suspend called */ ++#ifdef PNO_SUPPORT ++ int pno_enable; /* pno status : "1" is pno enable */ ++ int pno_suspend; /* pno suspend status : "1" is pno suspended */ ++#endif /* PNO_SUPPORT */ ++ /* DTIM skip value, default 0(or 1) means wake each DTIM ++ * 3 means skip 2 DTIMs and wake up 3rd DTIM(9th beacon when AP DTIM is 3) ++ */ ++ int suspend_bcn_li_dtim; /* bcn_li_dtim value in suspend mode */ ++#ifdef PKT_FILTER_SUPPORT ++ int early_suspended; /* Early suspend status */ ++ int dhcp_in_progress; /* DHCP period */ ++#endif ++ ++ /* Pkt filter defination */ ++ char * pktfilter[100]; ++ int pktfilter_count; ++ ++ wl_country_t dhd_cspec; /* Current Locale info */ ++ char eventmask[WL_EVENTING_MASK_LEN]; ++ int op_mode; /* STA, HostAPD, WFD, SoftAP */ ++ ++/* Set this to 1 to use a seperate interface (p2p0) for p2p operations. ++ * For ICS MR1 releases it should be disable to be compatable with ICS MR1 Framework ++ * see target dhd-cdc-sdmmc-panda-cfg80211-icsmr1-gpl-debug in Makefile ++ */ ++/* #define WL_ENABLE_P2P_IF 1 */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 ++ struct mutex wl_start_stop_lock; /* lock/unlock for Android start/stop */ ++ struct mutex wl_softap_lock; /* lock/unlock for any SoftAP/STA settings */ ++#endif ++ ++#ifdef WLBTAMP ++ uint16 maxdatablks; ++#endif /* WLBTAMP */ ++#ifdef PROP_TXSTATUS ++ int wlfc_enabled; ++ void* wlfc_state; ++#endif ++ bool dongle_isolation; ++ bool dongle_trap_occured; /* flag for sending HANG event to upper layer */ ++ int hang_was_sent; ++ int rxcnt_timeout; /* counter rxcnt timeout to send HANG */ ++ int txcnt_timeout; /* counter txcnt timeout to send HANG */ ++#ifdef WLMEDIA_HTSF ++ uint8 htsfdlystat_sz; /* Size of delay stats, max 255B */ ++#endif ++ struct reorder_info *reorder_bufs[WLHOST_REORDERDATA_MAXFLOWS]; ++#if defined(ARP_OFFLOAD_SUPPORT) ++ uint32 arp_version; ++#endif ++} dhd_pub_t; ++ ++ ++ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) ++ ++ #define DHD_PM_RESUME_WAIT_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a); ++ #define _DHD_PM_RESUME_WAIT(a, b) do {\ ++ int retry = 0; \ ++ SMP_RD_BARRIER_DEPENDS(); \ ++ while (dhd_mmc_suspend && retry++ != b) { \ ++ SMP_RD_BARRIER_DEPENDS(); \ ++ wait_event_interruptible_timeout(a, !dhd_mmc_suspend, 1); \ ++ } \ ++ } while (0) ++ #define DHD_PM_RESUME_WAIT(a) _DHD_PM_RESUME_WAIT(a, 200) ++ #define DHD_PM_RESUME_WAIT_FOREVER(a) _DHD_PM_RESUME_WAIT(a, ~0) ++ #define DHD_PM_RESUME_RETURN_ERROR(a) do { if (dhd_mmc_suspend) return a; } while (0) ++ #define DHD_PM_RESUME_RETURN do { if (dhd_mmc_suspend) return; } while (0) ++ ++ #define DHD_SPINWAIT_SLEEP_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a); ++ #define SPINWAIT_SLEEP(a, exp, us) do { \ ++ uint countdown = (us) + 9999; \ ++ while ((exp) && (countdown >= 10000)) { \ ++ wait_event_interruptible_timeout(a, FALSE, 1); \ ++ countdown -= 10000; \ ++ } \ ++ } while (0) ++ ++ #else ++ ++ #define DHD_PM_RESUME_WAIT_INIT(a) ++ #define DHD_PM_RESUME_WAIT(a) ++ #define DHD_PM_RESUME_WAIT_FOREVER(a) ++ #define DHD_PM_RESUME_RETURN_ERROR(a) ++ #define DHD_PM_RESUME_RETURN ++ ++ #define DHD_SPINWAIT_SLEEP_INIT(a) ++ #define SPINWAIT_SLEEP(a, exp, us) do { \ ++ uint countdown = (us) + 9; \ ++ while ((exp) && (countdown >= 10)) { \ ++ OSL_DELAY(10); \ ++ countdown -= 10; \ ++ } \ ++ } while (0) ++ ++ #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ ++#ifndef DHDTHREAD ++#undef SPINWAIT_SLEEP ++#define SPINWAIT_SLEEP(a, exp, us) SPINWAIT(exp, us) ++#endif /* DHDTHREAD */ ++#define DHD_IF_VIF 0x01 /* Virtual IF (Hidden from user) */ ++ ++unsigned long dhd_os_spin_lock(dhd_pub_t *pub); ++void dhd_os_spin_unlock(dhd_pub_t *pub, unsigned long flags); ++ ++/* Wakelock Functions */ ++extern int dhd_os_wake_lock(dhd_pub_t *pub); ++extern int dhd_os_wake_unlock(dhd_pub_t *pub); ++extern int dhd_os_wake_lock_timeout(dhd_pub_t *pub); ++extern int dhd_os_wake_lock_rx_timeout_enable(dhd_pub_t *pub, int val); ++extern int dhd_os_wake_lock_ctrl_timeout_enable(dhd_pub_t *pub, int val); ++extern int dhd_os_wd_wake_lock(dhd_pub_t *pub); ++extern int dhd_os_wd_wake_unlock(dhd_pub_t *pub); ++ ++inline static void MUTEX_LOCK_SOFTAP_SET_INIT(dhd_pub_t * dhdp) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 ++ mutex_init(&dhdp->wl_softap_lock); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ ++} ++ ++inline static void MUTEX_LOCK_SOFTAP_SET(dhd_pub_t * dhdp) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 ++ mutex_lock(&dhdp->wl_softap_lock); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ ++} ++ ++inline static void MUTEX_UNLOCK_SOFTAP_SET(dhd_pub_t * dhdp) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 ++ mutex_unlock(&dhdp->wl_softap_lock); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ ++} ++ ++#define DHD_OS_WAKE_LOCK(pub) dhd_os_wake_lock(pub) ++#define DHD_OS_WAKE_UNLOCK(pub) dhd_os_wake_unlock(pub) ++#define DHD_OS_WD_WAKE_LOCK(pub) dhd_os_wd_wake_lock(pub) ++#define DHD_OS_WD_WAKE_UNLOCK(pub) dhd_os_wd_wake_unlock(pub) ++#define DHD_OS_WAKE_LOCK_TIMEOUT(pub) dhd_os_wake_lock_timeout(pub) ++#define DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(pub, val) \ ++ dhd_os_wake_lock_rx_timeout_enable(pub, val) ++#define DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(pub, val) \ ++ dhd_os_wake_lock_ctrl_timeout_enable(pub, val) ++#define DHD_PACKET_TIMEOUT_MS 1000 ++#define DHD_EVENT_TIMEOUT_MS 1500 ++ ++/* interface operations (register, remove) should be atomic, use this lock to prevent race ++ * condition among wifi on/off and interface operation functions ++ */ ++void dhd_net_if_lock(struct net_device *dev); ++void dhd_net_if_unlock(struct net_device *dev); ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 ++extern struct mutex _dhd_sdio_mutex_lock_; ++#endif ++ ++typedef struct dhd_if_event { ++ uint8 ifidx; ++ uint8 action; ++ uint8 flags; ++ uint8 bssidx; ++ uint8 is_AP; ++} dhd_if_event_t; ++ ++typedef enum dhd_attach_states ++{ ++ DHD_ATTACH_STATE_INIT = 0x0, ++ DHD_ATTACH_STATE_NET_ALLOC = 0x1, ++ DHD_ATTACH_STATE_DHD_ALLOC = 0x2, ++ DHD_ATTACH_STATE_ADD_IF = 0x4, ++ DHD_ATTACH_STATE_PROT_ATTACH = 0x8, ++ DHD_ATTACH_STATE_WL_ATTACH = 0x10, ++ DHD_ATTACH_STATE_THREADS_CREATED = 0x20, ++ DHD_ATTACH_STATE_WAKELOCKS_INIT = 0x40, ++ DHD_ATTACH_STATE_CFG80211 = 0x80, ++ DHD_ATTACH_STATE_EARLYSUSPEND_DONE = 0x100, ++ DHD_ATTACH_STATE_DONE = 0x200 ++} dhd_attach_states_t; ++ ++/* Value -1 means we are unsuccessful in creating the kthread. */ ++#define DHD_PID_KT_INVALID -1 ++/* Value -2 means we are unsuccessful in both creating the kthread and tasklet */ ++#define DHD_PID_KT_TL_INVALID -2 ++ ++/* ++ * Exported from dhd OS modules (dhd_linux/dhd_ndis) ++ */ ++ ++/* To allow osl_attach/detach calls from os-independent modules */ ++osl_t *dhd_osl_attach(void *pdev, uint bustype); ++void dhd_osl_detach(osl_t *osh); ++ ++/* Indication from bus module regarding presence/insertion of dongle. ++ * Return dhd_pub_t pointer, used as handle to OS module in later calls. ++ * Returned structure should have bus and prot pointers filled in. ++ * bus_hdrlen specifies required headroom for bus module header. ++ */ ++extern dhd_pub_t *dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen); ++#if defined(WLP2P) && defined(WL_CFG80211) ++/* To allow attach/detach calls corresponding to p2p0 interface */ ++extern int dhd_attach_p2p(dhd_pub_t *); ++extern int dhd_detach_p2p(dhd_pub_t *); ++#endif /* WLP2P && WL_CFG80211 */ ++extern int dhd_net_attach(dhd_pub_t *dhdp, int idx); ++ ++/* Indication from bus module regarding removal/absence of dongle */ ++extern void dhd_detach(dhd_pub_t *dhdp); ++extern void dhd_free(dhd_pub_t *dhdp); ++ ++/* Indication from bus module to change flow-control state */ ++extern void dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool on); ++ ++extern bool dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec); ++ ++/* Receive frame for delivery to OS. Callee disposes of rxp. */ ++extern void dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *rxp, int numpkt, uint8 chan); ++ ++/* Return pointer to interface name */ ++extern char *dhd_ifname(dhd_pub_t *dhdp, int idx); ++ ++/* Request scheduling of the bus dpc */ ++extern void dhd_sched_dpc(dhd_pub_t *dhdp); ++ ++/* Notify tx completion */ ++extern void dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success); ++ ++/* OS independent layer functions */ ++extern int dhd_os_proto_block(dhd_pub_t * pub); ++extern int dhd_os_proto_unblock(dhd_pub_t * pub); ++extern int dhd_os_ioctl_resp_wait(dhd_pub_t * pub, uint * condition, bool * pending); ++extern int dhd_os_ioctl_resp_wake(dhd_pub_t * pub); ++extern unsigned int dhd_os_get_ioctl_resp_timeout(void); ++extern void dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec); ++extern void * dhd_os_open_image(char * filename); ++extern int dhd_os_get_image_block(char * buf, int len, void * image); ++extern void dhd_os_close_image(void * image); ++extern void dhd_os_wd_timer(void *bus, uint wdtick); ++extern void dhd_os_sdlock(dhd_pub_t * pub); ++extern void dhd_os_sdunlock(dhd_pub_t * pub); ++extern void dhd_os_sdlock_txq(dhd_pub_t * pub); ++extern void dhd_os_sdunlock_txq(dhd_pub_t * pub); ++extern void dhd_os_sdlock_rxq(dhd_pub_t * pub); ++extern void dhd_os_sdunlock_rxq(dhd_pub_t * pub); ++extern void dhd_os_sdlock_sndup_rxq(dhd_pub_t * pub); ++extern void dhd_customer_gpio_wlan_ctrl(int onoff); ++extern int dhd_custom_get_mac_address(unsigned char *buf); ++extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t * pub); ++extern void dhd_os_sdlock_eventq(dhd_pub_t * pub); ++extern void dhd_os_sdunlock_eventq(dhd_pub_t * pub); ++extern bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret); ++extern int dhd_os_send_hang_message(dhd_pub_t *dhdp); ++extern void dhd_set_version_info(dhd_pub_t *pub, char *fw); ++ ++#ifdef PNO_SUPPORT ++extern int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled); ++extern int dhd_pno_clean(dhd_pub_t *dhd); ++extern int dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ++ ushort scan_fr, int pno_repeat, int pno_freq_expo_max); ++extern int dhd_pno_get_status(dhd_pub_t *dhd); ++extern int dhd_dev_pno_reset(struct net_device *dev); ++extern int dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local, ++ int nssid, ushort scan_fr, int pno_repeat, int pno_freq_expo_max); ++extern int dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled); ++extern int dhd_dev_get_pno_status(struct net_device *dev); ++#endif /* PNO_SUPPORT */ ++ ++#ifdef PKT_FILTER_SUPPORT ++#define DHD_UNICAST_FILTER_NUM 0 ++#define DHD_BROADCAST_FILTER_NUM 1 ++#define DHD_MULTICAST4_FILTER_NUM 2 ++#define DHD_MULTICAST6_FILTER_NUM 3 ++#define DHD_MDNS_FILTER_NUM 4 ++extern int dhd_os_enable_packet_filter(dhd_pub_t *dhdp, int val); ++extern void dhd_enable_packet_filter(int value, dhd_pub_t *dhd); ++extern int net_os_enable_packet_filter(struct net_device *dev, int val); ++extern int net_os_rxfilter_add_remove(struct net_device *dev, int val, int num); ++#endif /* PKT_FILTER_SUPPORT */ ++ ++extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd); ++extern bool dhd_support_sta_mode(dhd_pub_t *dhd); ++ ++#ifdef DHD_DEBUG ++extern int write_to_file(dhd_pub_t *dhd, uint8 *buf, int size); ++#endif /* DHD_DEBUG */ ++#if defined(OOB_INTR_ONLY) ++extern int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr); ++#endif ++extern void dhd_os_sdtxlock(dhd_pub_t * pub); ++extern void dhd_os_sdtxunlock(dhd_pub_t * pub); ++ ++typedef struct { ++ uint32 limit; /* Expiration time (usec) */ ++ uint32 increment; /* Current expiration increment (usec) */ ++ uint32 elapsed; /* Current elapsed time (usec) */ ++ uint32 tick; /* O/S tick time (usec) */ ++} dhd_timeout_t; ++ ++extern void dhd_timeout_start(dhd_timeout_t *tmo, uint usec); ++extern int dhd_timeout_expired(dhd_timeout_t *tmo); ++ ++extern int dhd_ifname2idx(struct dhd_info *dhd, char *name); ++extern int dhd_net2idx(struct dhd_info *dhd, struct net_device *net); ++extern struct net_device * dhd_idx2net(void *pub, int ifidx); ++extern int net_os_send_hang_message(struct net_device *dev); ++extern int wl_host_event(dhd_pub_t *dhd_pub, int *idx, void *pktdata, ++ wl_event_msg_t *, void **data_ptr); ++extern void wl_event_to_host_order(wl_event_msg_t * evt); ++ ++extern int dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifindex, wl_ioctl_t *ioc, void *buf, int len); ++extern int dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, ++ int ifindex); ++ ++extern void dhd_common_init(osl_t *osh); ++ ++extern int dhd_do_driver_init(struct net_device *net); ++extern int dhd_add_if(struct dhd_info *dhd, int ifidx, void *handle, ++ char *name, uint8 *mac_addr, uint32 flags, uint8 bssidx); ++extern void dhd_del_if(struct dhd_info *dhd, int ifidx); ++ ++extern void dhd_vif_add(struct dhd_info *dhd, int ifidx, char * name); ++extern void dhd_vif_del(struct dhd_info *dhd, int ifidx); ++ ++extern void dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx); ++extern void dhd_vif_sendup(struct dhd_info *dhd, int ifidx, uchar *cp, int len); ++ ++ ++/* Send packet to dongle via data channel */ ++extern int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pkt); ++ ++/* send up locally generated event */ ++extern void dhd_sendup_event_common(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data); ++/* Send event to host */ ++extern void dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data); ++extern int dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag); ++extern uint dhd_bus_status(dhd_pub_t *dhdp); ++extern int dhd_bus_start(dhd_pub_t *dhdp); ++extern int dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size); ++extern void dhd_print_buf(void *pbuf, int len, int bytes_per_line); ++extern bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval); ++extern uint dhd_bus_chip_id(dhd_pub_t *dhdp); ++extern uint dhd_bus_chiprev_id(dhd_pub_t *dhdp); ++extern uint dhd_bus_chippkg_id(dhd_pub_t *dhdp); ++ ++#if defined(KEEP_ALIVE) ++extern int dhd_keep_alive_onoff(dhd_pub_t *dhd); ++#endif /* KEEP_ALIVE */ ++ ++extern bool dhd_is_concurrent_mode(dhd_pub_t *dhd); ++ ++typedef enum cust_gpio_modes { ++ WLAN_RESET_ON, ++ WLAN_RESET_OFF, ++ WLAN_POWER_ON, ++ WLAN_POWER_OFF ++} cust_gpio_modes_t; ++ ++extern int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag); ++extern int wl_iw_send_priv_event(struct net_device *dev, char *flag); ++/* ++ * Insmod parameters for debug/test ++ */ ++ ++/* Watchdog timer interval */ ++extern uint dhd_watchdog_ms; ++ ++#if defined(DHD_DEBUG) ++/* Console output poll interval */ ++extern uint dhd_console_ms; ++#endif /* defined(DHD_DEBUG) */ ++//extern uint android_msg_level; ++#ifdef CONFIG_WIRELESS_EXT ++extern uint iw_msg_level; ++#endif ++#ifdef WL_CFG80211 ++extern uint wl_dbg_level; ++#endif ++extern uint dhd_slpauto; ++ ++/* Use interrupts */ ++extern uint dhd_intr; ++ ++/* Use polling */ ++extern uint dhd_poll; ++ ++/* ARP offload agent mode */ ++extern uint dhd_arp_mode; ++ ++/* ARP offload enable */ ++extern uint dhd_arp_enable; ++ ++/* Pkt filte enable control */ ++extern uint dhd_pkt_filter_enable; ++ ++/* Pkt filter init setup */ ++extern uint dhd_pkt_filter_init; ++ ++/* Pkt filter mode control */ ++extern uint dhd_master_mode; ++ ++/* Roaming mode control */ ++extern uint dhd_roam_disable; ++ ++/* Roaming mode control */ ++extern uint dhd_radio_up; ++ ++/* Initial idletime ticks (may be -1 for immediate idle, 0 for no idle) */ ++extern int dhd_idletime; ++#ifdef DHD_USE_IDLECOUNT ++#define DHD_IDLETIME_TICKS 5 ++#else ++#define DHD_IDLETIME_TICKS 1 ++#endif /* DHD_USE_IDLECOUNT */ ++ ++/* SDIO Drive Strength */ ++extern uint dhd_sdiod_drive_strength; ++ ++/* Override to force tx queueing all the time */ ++extern uint dhd_force_tx_queueing; ++/* Default KEEP_ALIVE Period is 55 sec to prevent AP from sending Keep Alive probe frame */ ++#define DEFAULT_KEEP_ALIVE_VALUE 55000 /* msec */ ++#ifndef CUSTOM_KEEP_ALIVE_SETTING ++#define CUSTOM_KEEP_ALIVE_SETTING DEFAULT_KEEP_ALIVE_VALUE ++#endif /* DEFAULT_KEEP_ALIVE_VALUE */ ++ ++#define NULL_PKT_STR "null_pkt" ++ ++/* hooks for custom glom setting option via Makefile */ ++#define DEFAULT_GLOM_VALUE -1 ++#ifndef CUSTOM_GLOM_SETTING ++#define CUSTOM_GLOM_SETTING DEFAULT_GLOM_VALUE ++#endif ++ ++/* hooks for custom Roaming Trigger setting via Makefile */ ++#define DEFAULT_ROAM_TRIGGER_VALUE -75 /* dBm default roam trigger all band */ ++#define DEFAULT_ROAM_TRIGGER_SETTING -1 ++#ifndef CUSTOM_ROAM_TRIGGER_SETTING ++#define CUSTOM_ROAM_TRIGGER_SETTING DEFAULT_ROAM_TRIGGER_VALUE ++#endif ++ ++/* hooks for custom Roaming Romaing setting via Makefile */ ++#define DEFAULT_ROAM_DELTA_VALUE 10 /* dBm default roam delta all band */ ++#define DEFAULT_ROAM_DELTA_SETTING -1 ++#ifndef CUSTOM_ROAM_DELTA_SETTING ++#define CUSTOM_ROAM_DELTA_SETTING DEFAULT_ROAM_DELTA_VALUE ++#endif ++ ++/* hooks for custom PNO Event wake lock to guarantee enough time ++ for the Platform to detect Event before system suspended ++*/ ++#define DEFAULT_PNO_EVENT_LOCK_xTIME 2 /* multiplay of DHD_PACKET_TIMEOUT_MS */ ++#ifndef CUSTOM_PNO_EVENT_LOCK_xTIME ++#define CUSTOM_PNO_EVENT_LOCK_xTIME DEFAULT_PNO_EVENT_LOCK_xTIME ++#endif ++ ++/* hooks for custom dhd_dpc_prio setting option via Makefile */ ++#define DEFAULT_DHP_DPC_PRIO 1 ++#ifndef CUSTOM_DPC_PRIO_SETTING ++#define CUSTOM_DPC_PRIO_SETTING DEFAULT_DHP_DPC_PRIO ++#endif ++ ++#define DEFAULT_SUSPEND_BCN_LI_DTIM 3 ++#ifndef CUSTOM_SUSPEND_BCN_LI_DTIM ++#define CUSTOM_SUSPEND_BCN_LI_DTIM DEFAULT_SUSPEND_BCN_LI_DTIM ++#endif ++ ++#ifdef SDTEST ++/* Echo packet generator (SDIO), pkts/s */ ++extern uint dhd_pktgen; ++ ++/* Echo packet len (0 => sawtooth, max 1800) */ ++extern uint dhd_pktgen_len; ++#define MAX_PKTGEN_LEN 1800 ++#endif ++ ++ ++/* optionally set by a module_param_string() */ ++#define MOD_PARAM_PATHLEN 2048 ++extern char fw_path[MOD_PARAM_PATHLEN]; ++extern char nv_path[MOD_PARAM_PATHLEN]; ++ ++#define MOD_PARAM_INFOLEN 512 ++ ++#ifdef SOFTAP ++extern char fw_path2[MOD_PARAM_PATHLEN]; ++#endif ++ ++#define FW_PATH_AUTO_SELECT 1 ++extern char firmware_path[MOD_PARAM_PATHLEN]; ++extern void dhd_bus_select_firmware_name_by_chip(struct dhd_bus *bus, char *dst, char *src); ++#define COPY_FW_PATH_BY_CHIP(bus, dst, src) dhd_bus_select_firmware_name_by_chip(bus, dst, src); ++ ++/* Flag to indicate if we should download firmware on driver load */ ++extern uint dhd_download_fw_on_driverload; ++ ++ ++/* For supporting multiple interfaces */ ++#define DHD_MAX_IFS 16 ++#define DHD_DEL_IF -0xe ++#define DHD_BAD_IF -0xf ++#define WL_AUTO_ROAM_TRIGGER -75 ++ ++#ifdef PROP_TXSTATUS ++/* Please be mindful that total pkttag space is 32 octets only */ ++typedef struct dhd_pkttag { ++ /* ++ b[11 ] - 1 = this packet was sent in response to one time packet request, ++ do not increment credit on status for this one. [WLFC_CTL_TYPE_MAC_REQUEST_PACKET]. ++ b[10 ] - 1 = signal-only-packet to firmware [i.e. nothing to piggyback on] ++ b[9 ] - 1 = packet is host->firmware (transmit direction) ++ - 0 = packet received from firmware (firmware->host) ++ b[8 ] - 1 = packet was sent due to credit_request (pspoll), ++ packet does not count against FIFO credit. ++ - 0 = normal transaction, packet counts against FIFO credit ++ b[7 ] - 1 = AP, 0 = STA ++ b[6:4] - AC FIFO number ++ b[3:0] - interface index ++ */ ++ uint16 if_flags; ++ /* destination MAC address for this packet so that not every ++ module needs to open the packet to find this ++ */ ++ uint8 dstn_ether[ETHER_ADDR_LEN]; ++ /* ++ This 32-bit goes from host to device for every packet. ++ */ ++ uint32 htod_tag; ++ /* bus specific stuff */ ++ union { ++ struct { ++ void* stuff; ++ uint32 thing1; ++ uint32 thing2; ++ } sd; ++ struct { ++ void* bus; ++ void* urb; ++ } usb; ++ } bus_specific; ++} dhd_pkttag_t; ++ ++#define DHD_PKTTAG_SET_H2DTAG(tag, h2dvalue) ((dhd_pkttag_t*)(tag))->htod_tag = (h2dvalue) ++#define DHD_PKTTAG_H2DTAG(tag) (((dhd_pkttag_t*)(tag))->htod_tag) ++ ++#define DHD_PKTTAG_IFMASK 0xf ++#define DHD_PKTTAG_IFTYPE_MASK 0x1 ++#define DHD_PKTTAG_IFTYPE_SHIFT 7 ++#define DHD_PKTTAG_FIFO_MASK 0x7 ++#define DHD_PKTTAG_FIFO_SHIFT 4 ++ ++#define DHD_PKTTAG_SIGNALONLY_MASK 0x1 ++#define DHD_PKTTAG_SIGNALONLY_SHIFT 10 ++ ++#define DHD_PKTTAG_ONETIMEPKTRQST_MASK 0x1 ++#define DHD_PKTTAG_ONETIMEPKTRQST_SHIFT 11 ++ ++#define DHD_PKTTAG_PKTDIR_MASK 0x1 ++#define DHD_PKTTAG_PKTDIR_SHIFT 9 ++ ++#define DHD_PKTTAG_CREDITCHECK_MASK 0x1 ++#define DHD_PKTTAG_CREDITCHECK_SHIFT 8 ++ ++#define DHD_PKTTAG_INVALID_FIFOID 0x7 ++ ++#define DHD_PKTTAG_SETFIFO(tag, fifo) ((dhd_pkttag_t*)(tag))->if_flags = \ ++ (((dhd_pkttag_t*)(tag))->if_flags & ~(DHD_PKTTAG_FIFO_MASK << DHD_PKTTAG_FIFO_SHIFT)) | \ ++ (((fifo) & DHD_PKTTAG_FIFO_MASK) << DHD_PKTTAG_FIFO_SHIFT) ++#define DHD_PKTTAG_FIFO(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ ++ DHD_PKTTAG_FIFO_SHIFT) & DHD_PKTTAG_FIFO_MASK) ++ ++#define DHD_PKTTAG_SETIF(tag, if) ((dhd_pkttag_t*)(tag))->if_flags = \ ++ (((dhd_pkttag_t*)(tag))->if_flags & ~DHD_PKTTAG_IFMASK) | ((if) & DHD_PKTTAG_IFMASK) ++#define DHD_PKTTAG_IF(tag) (((dhd_pkttag_t*)(tag))->if_flags & DHD_PKTTAG_IFMASK) ++ ++#define DHD_PKTTAG_SETIFTYPE(tag, isAP) ((dhd_pkttag_t*)(tag))->if_flags = \ ++ (((dhd_pkttag_t*)(tag))->if_flags & \ ++ ~(DHD_PKTTAG_IFTYPE_MASK << DHD_PKTTAG_IFTYPE_SHIFT)) | \ ++ (((isAP) & DHD_PKTTAG_IFTYPE_MASK) << DHD_PKTTAG_IFTYPE_SHIFT) ++#define DHD_PKTTAG_IFTYPE(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ ++ DHD_PKTTAG_IFTYPE_SHIFT) & DHD_PKTTAG_IFTYPE_MASK) ++ ++#define DHD_PKTTAG_SETCREDITCHECK(tag, check) ((dhd_pkttag_t*)(tag))->if_flags = \ ++ (((dhd_pkttag_t*)(tag))->if_flags & \ ++ ~(DHD_PKTTAG_CREDITCHECK_MASK << DHD_PKTTAG_CREDITCHECK_SHIFT)) | \ ++ (((check) & DHD_PKTTAG_CREDITCHECK_MASK) << DHD_PKTTAG_CREDITCHECK_SHIFT) ++#define DHD_PKTTAG_CREDITCHECK(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ ++ DHD_PKTTAG_CREDITCHECK_SHIFT) & DHD_PKTTAG_CREDITCHECK_MASK) ++ ++#define DHD_PKTTAG_SETPKTDIR(tag, dir) ((dhd_pkttag_t*)(tag))->if_flags = \ ++ (((dhd_pkttag_t*)(tag))->if_flags & \ ++ ~(DHD_PKTTAG_PKTDIR_MASK << DHD_PKTTAG_PKTDIR_SHIFT)) | \ ++ (((dir) & DHD_PKTTAG_PKTDIR_MASK) << DHD_PKTTAG_PKTDIR_SHIFT) ++#define DHD_PKTTAG_PKTDIR(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ ++ DHD_PKTTAG_PKTDIR_SHIFT) & DHD_PKTTAG_PKTDIR_MASK) ++ ++#define DHD_PKTTAG_SETSIGNALONLY(tag, signalonly) ((dhd_pkttag_t*)(tag))->if_flags = \ ++ (((dhd_pkttag_t*)(tag))->if_flags & \ ++ ~(DHD_PKTTAG_SIGNALONLY_MASK << DHD_PKTTAG_SIGNALONLY_SHIFT)) | \ ++ (((signalonly) & DHD_PKTTAG_SIGNALONLY_MASK) << DHD_PKTTAG_SIGNALONLY_SHIFT) ++#define DHD_PKTTAG_SIGNALONLY(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ ++ DHD_PKTTAG_SIGNALONLY_SHIFT) & DHD_PKTTAG_SIGNALONLY_MASK) ++ ++#define DHD_PKTTAG_SETONETIMEPKTRQST(tag) ((dhd_pkttag_t*)(tag))->if_flags = \ ++ (((dhd_pkttag_t*)(tag))->if_flags & \ ++ ~(DHD_PKTTAG_ONETIMEPKTRQST_MASK << DHD_PKTTAG_ONETIMEPKTRQST_SHIFT)) | \ ++ (1 << DHD_PKTTAG_ONETIMEPKTRQST_SHIFT) ++#define DHD_PKTTAG_ONETIMEPKTRQST(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ ++ DHD_PKTTAG_ONETIMEPKTRQST_SHIFT) & DHD_PKTTAG_ONETIMEPKTRQST_MASK) ++ ++#define DHD_PKTTAG_SETDSTN(tag, dstn_MAC_ea) memcpy(((dhd_pkttag_t*)((tag)))->dstn_ether, \ ++ (dstn_MAC_ea), ETHER_ADDR_LEN) ++#define DHD_PKTTAG_DSTN(tag) ((dhd_pkttag_t*)(tag))->dstn_ether ++ ++typedef int (*f_commitpkt_t)(void* ctx, void* p, bool wlfc_locked); ++ ++#ifdef PROP_TXSTATUS_DEBUG ++#define DHD_WLFC_CTRINC_MAC_CLOSE(entry) do { (entry)->closed_ct++; } while (0) ++#define DHD_WLFC_CTRINC_MAC_OPEN(entry) do { (entry)->opened_ct++; } while (0) ++#else ++#define DHD_WLFC_CTRINC_MAC_CLOSE(entry) do {} while (0) ++#define DHD_WLFC_CTRINC_MAC_OPEN(entry) do {} while (0) ++#endif ++ ++#endif /* PROP_TXSTATUS */ ++ ++extern void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar); ++extern void dhd_wait_event_wakeup(dhd_pub_t*dhd); ++ ++#define IFLOCK_INIT(lock) *lock = 0 ++#define IFLOCK(lock) while (InterlockedCompareExchange((lock), 1, 0)) \ ++ NdisStallExecution(1); ++#define IFUNLOCK(lock) InterlockedExchange((lock), 0) ++#define IFLOCK_FREE(lock) ++ ++#ifdef PNO_SUPPORT ++extern int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled); ++extern int dhd_pnoenable(dhd_pub_t *dhd, int pfn_enabled); ++extern int dhd_pno_clean(dhd_pub_t *dhd); ++extern int dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ++ ushort scan_fr, int pno_repeat, int pno_freq_expo_max); ++extern int dhd_pno_get_status(dhd_pub_t *dhd); ++extern int dhd_pno_set_add(dhd_pub_t *dhd, wl_pfn_t *netinfo, int nssid, ushort scan_fr, ++ ushort slowscan_fr, uint8 pno_repeat, uint8 pno_freq_expo_max, int16 flags); ++extern int dhd_pno_cfg(dhd_pub_t *dhd, wl_pfn_cfg_t *pcfg); ++extern int dhd_pno_suspend(dhd_pub_t *dhd, int pfn_suspend); ++#endif /* PNO_SUPPORT */ ++#ifdef ARP_OFFLOAD_SUPPORT ++#define MAX_IPV4_ENTRIES 8 ++void dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode); ++void dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable); ++ ++/* dhd_commn arp offload wrapers */ ++void dhd_aoe_hostip_clr(dhd_pub_t *dhd, int idx); ++void dhd_aoe_arp_clr(dhd_pub_t *dhd, int idx); ++int dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen, int idx); ++void dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr, int idx); ++#endif /* ARP_OFFLOAD_SUPPORT */ ++ ++#endif /* _dhd_h_ */ +diff --git a/drivers/net/wireless/ap6211/dhd_bta.c b/drivers/net/wireless/ap6211/dhd_bta.c +new file mode 100755 +index 0000000..3752bbd +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_bta.c +@@ -0,0 +1,338 @@ ++/* ++ * BT-AMP support routines ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd_bta.c 303834 2011-12-20 06:17:39Z $ ++ */ ++#ifndef WLBTAMP ++#error "WLBTAMP is not defined" ++#endif /* WLBTAMP */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++ ++#ifdef SEND_HCI_CMD_VIA_IOCTL ++#define BTA_HCI_CMD_MAX_LEN HCI_CMD_PREAMBLE_SIZE + HCI_CMD_DATA_SIZE ++ ++/* Send HCI cmd via wl iovar HCI_cmd to the dongle. */ ++int ++dhd_bta_docmd(dhd_pub_t *pub, void *cmd_buf, uint cmd_len) ++{ ++ amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)cmd_buf; ++ uint8 buf[BTA_HCI_CMD_MAX_LEN + 16]; ++ uint len = sizeof(buf); ++ wl_ioctl_t ioc; ++ ++ if (cmd_len < HCI_CMD_PREAMBLE_SIZE) ++ return BCME_BADLEN; ++ ++ if ((uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE > cmd_len) ++ return BCME_BADLEN; ++ ++ len = bcm_mkiovar("HCI_cmd", ++ (char *)cmd, (uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE, (char *)buf, len); ++ ++ ++ memset(&ioc, 0, sizeof(ioc)); ++ ++ ioc.cmd = WLC_SET_VAR; ++ ioc.buf = buf; ++ ioc.len = len; ++ ioc.set = TRUE; ++ ++ return dhd_wl_ioctl(pub, &ioc, ioc.buf, ioc.len); ++} ++#else /* !SEND_HCI_CMD_VIA_IOCTL */ ++ ++static void ++dhd_bta_flush_hcidata(dhd_pub_t *pub, uint16 llh) ++{ ++ int prec; ++ struct pktq *q; ++ uint count = 0; ++ ++ q = dhd_bus_txq(pub->bus); ++ if (q == NULL) ++ return; ++ ++ DHD_BTA(("dhd: flushing HCI ACL data for logical link %u...\n", llh)); ++ ++ dhd_os_sdlock_txq(pub); ++ ++ /* Walk through the txq and toss all HCI ACL data packets */ ++ PKTQ_PREC_ITER(q, prec) { ++ void *head_pkt = NULL; ++ ++ while (pktq_ppeek(q, prec) != head_pkt) { ++ void *pkt = pktq_pdeq(q, prec); ++ int ifidx; ++ ++ PKTPULL(pub->osh, pkt, dhd_bus_hdrlen(pub->bus)); ++ dhd_prot_hdrpull(pub, &ifidx, pkt, NULL, NULL); ++ ++ if (PKTLEN(pub->osh, pkt) >= RFC1042_HDR_LEN) { ++ struct ether_header *eh = ++ (struct ether_header *)PKTDATA(pub->osh, pkt); ++ ++ if (ntoh16(eh->ether_type) < ETHER_TYPE_MIN) { ++ struct dot11_llc_snap_header *lsh = ++ (struct dot11_llc_snap_header *)&eh[1]; ++ ++ if (bcmp(lsh, BT_SIG_SNAP_MPROT, ++ DOT11_LLC_SNAP_HDR_LEN - 2) == 0 && ++ ntoh16(lsh->type) == BTA_PROT_L2CAP) { ++ amp_hci_ACL_data_t *ACL_data = ++ (amp_hci_ACL_data_t *)&lsh[1]; ++ uint16 handle = ltoh16(ACL_data->handle); ++ ++ if (HCI_ACL_DATA_HANDLE(handle) == llh) { ++ PKTFREE(pub->osh, pkt, TRUE); ++ count ++; ++ continue; ++ } ++ } ++ } ++ } ++ ++ dhd_prot_hdrpush(pub, ifidx, pkt); ++ PKTPUSH(pub->osh, pkt, dhd_bus_hdrlen(pub->bus)); ++ ++ if (head_pkt == NULL) ++ head_pkt = pkt; ++ pktq_penq(q, prec, pkt); ++ } ++ } ++ ++ dhd_os_sdunlock_txq(pub); ++ ++ DHD_BTA(("dhd: flushed %u packet(s) for logical link %u...\n", count, llh)); ++} ++ ++/* Handle HCI cmd locally. ++ * Return 0: continue to send the cmd across SDIO ++ * < 0: stop, fail ++ * > 0: stop, succuess ++ */ ++static int ++_dhd_bta_docmd(dhd_pub_t *pub, amp_hci_cmd_t *cmd) ++{ ++ int status = 0; ++ ++ switch (ltoh16_ua((uint8 *)&cmd->opcode)) { ++ case HCI_Enhanced_Flush: { ++ eflush_cmd_parms_t *cmdparms = (eflush_cmd_parms_t *)cmd->parms; ++ dhd_bta_flush_hcidata(pub, ltoh16_ua(cmdparms->llh)); ++ break; ++ } ++ default: ++ break; ++ } ++ ++ return status; ++} ++ ++/* Send HCI cmd encapsulated in BT-SIG frame via data channel to the dongle. */ ++int ++dhd_bta_docmd(dhd_pub_t *pub, void *cmd_buf, uint cmd_len) ++{ ++ amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)cmd_buf; ++ struct ether_header *eh; ++ struct dot11_llc_snap_header *lsh; ++ osl_t *osh = pub->osh; ++ uint len; ++ void *p; ++ int status; ++ ++ if (cmd_len < HCI_CMD_PREAMBLE_SIZE) { ++ AP6211_ERR("dhd_bta_docmd: short command, cmd_len %u\n", cmd_len); ++ return BCME_BADLEN; ++ } ++ ++ if ((len = (uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE) > cmd_len) { ++ AP6211_ERR("dhd_bta_docmd: malformed command, len %u cmd_len %u\n", ++ len, cmd_len); ++ /* return BCME_BADLEN; */ ++ } ++ ++ p = PKTGET(osh, pub->hdrlen + RFC1042_HDR_LEN + len, TRUE); ++ if (p == NULL) { ++ AP6211_ERR("dhd_bta_docmd: out of memory\n"); ++ return BCME_NOMEM; ++ } ++ ++ ++ /* intercept and handle the HCI cmd locally */ ++ if ((status = _dhd_bta_docmd(pub, cmd)) > 0) ++ return 0; ++ else if (status < 0) ++ return status; ++ ++ /* copy in HCI cmd */ ++ PKTPULL(osh, p, pub->hdrlen + RFC1042_HDR_LEN); ++ bcopy(cmd, PKTDATA(osh, p), len); ++ ++ /* copy in partial Ethernet header with BT-SIG LLC/SNAP header */ ++ PKTPUSH(osh, p, RFC1042_HDR_LEN); ++ eh = (struct ether_header *)PKTDATA(osh, p); ++ bzero(eh->ether_dhost, ETHER_ADDR_LEN); ++ ETHER_SET_LOCALADDR(eh->ether_dhost); ++ bcopy(&pub->mac, eh->ether_shost, ETHER_ADDR_LEN); ++ eh->ether_type = hton16(len + DOT11_LLC_SNAP_HDR_LEN); ++ lsh = (struct dot11_llc_snap_header *)&eh[1]; ++ bcopy(BT_SIG_SNAP_MPROT, lsh, DOT11_LLC_SNAP_HDR_LEN - 2); ++ lsh->type = 0; ++ ++ return dhd_sendpkt(pub, 0, p); ++} ++#endif /* !SEND_HCI_CMD_VIA_IOCTL */ ++ ++/* Send HCI ACL data to dongle via data channel */ ++int ++dhd_bta_tx_hcidata(dhd_pub_t *pub, void *data_buf, uint data_len) ++{ ++ amp_hci_ACL_data_t *data = (amp_hci_ACL_data_t *)data_buf; ++ struct ether_header *eh; ++ struct dot11_llc_snap_header *lsh; ++ osl_t *osh = pub->osh; ++ uint len; ++ void *p; ++ ++ if (data_len < HCI_ACL_DATA_PREAMBLE_SIZE) { ++ AP6211_ERR("dhd_bta_tx_hcidata: short data_buf, data_len %u\n", data_len); ++ return BCME_BADLEN; ++ } ++ ++ if ((len = (uint)ltoh16(data->dlen) + HCI_ACL_DATA_PREAMBLE_SIZE) > data_len) { ++ AP6211_ERR("dhd_bta_tx_hcidata: malformed hci data, len %u data_len %u\n", ++ len, data_len); ++ /* return BCME_BADLEN; */ ++ } ++ ++ p = PKTGET(osh, pub->hdrlen + RFC1042_HDR_LEN + len, TRUE); ++ if (p == NULL) { ++ AP6211_ERR("dhd_bta_tx_hcidata: out of memory\n"); ++ return BCME_NOMEM; ++ } ++ ++ ++ /* copy in HCI ACL data header and HCI ACL data */ ++ PKTPULL(osh, p, pub->hdrlen + RFC1042_HDR_LEN); ++ bcopy(data, PKTDATA(osh, p), len); ++ ++ /* copy in partial Ethernet header with BT-SIG LLC/SNAP header */ ++ PKTPUSH(osh, p, RFC1042_HDR_LEN); ++ eh = (struct ether_header *)PKTDATA(osh, p); ++ bzero(eh->ether_dhost, ETHER_ADDR_LEN); ++ bcopy(&pub->mac, eh->ether_shost, ETHER_ADDR_LEN); ++ eh->ether_type = hton16(len + DOT11_LLC_SNAP_HDR_LEN); ++ lsh = (struct dot11_llc_snap_header *)&eh[1]; ++ bcopy(BT_SIG_SNAP_MPROT, lsh, DOT11_LLC_SNAP_HDR_LEN - 2); ++ lsh->type = HTON16(BTA_PROT_L2CAP); ++ ++ return dhd_sendpkt(pub, 0, p); ++} ++ ++/* txcomplete callback */ ++void ++dhd_bta_tx_hcidata_complete(dhd_pub_t *dhdp, void *txp, bool success) ++{ ++ uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, txp); ++ amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *)(pktdata + RFC1042_HDR_LEN); ++ uint16 handle = ltoh16(ACL_data->handle); ++ uint16 llh = HCI_ACL_DATA_HANDLE(handle); ++ ++ wl_event_msg_t event; ++ uint8 data[HCI_EVT_PREAMBLE_SIZE + sizeof(num_completed_data_blocks_evt_parms_t)]; ++ amp_hci_event_t *evt; ++ num_completed_data_blocks_evt_parms_t *parms; ++ ++ uint16 len = HCI_EVT_PREAMBLE_SIZE + sizeof(num_completed_data_blocks_evt_parms_t); ++ ++ /* update the event struct */ ++ memset(&event, 0, sizeof(event)); ++ event.version = hton16(BCM_EVENT_MSG_VERSION); ++ event.event_type = hton32(WLC_E_BTA_HCI_EVENT); ++ event.status = 0; ++ event.reason = 0; ++ event.auth_type = 0; ++ event.datalen = hton32(len); ++ event.flags = 0; ++ ++ /* generate Number of Completed Blocks event */ ++ evt = (amp_hci_event_t *)data; ++ evt->ecode = HCI_Number_of_Completed_Data_Blocks; ++ evt->plen = sizeof(num_completed_data_blocks_evt_parms_t); ++ ++ parms = (num_completed_data_blocks_evt_parms_t *)evt->parms; ++ htol16_ua_store(dhdp->maxdatablks, (uint8 *)&parms->num_blocks); ++ parms->num_handles = 1; ++ htol16_ua_store(llh, (uint8 *)&parms->completed[0].handle); ++ parms->completed[0].pkts = 1; ++ parms->completed[0].blocks = 1; ++ ++ dhd_sendup_event_common(dhdp, &event, data); ++} ++ ++/* event callback */ ++void ++dhd_bta_doevt(dhd_pub_t *dhdp, void *data_buf, uint data_len) ++{ ++ amp_hci_event_t *evt = (amp_hci_event_t *)data_buf; ++ ++ switch (evt->ecode) { ++ case HCI_Command_Complete: { ++ cmd_complete_parms_t *parms = (cmd_complete_parms_t *)evt->parms; ++ switch (ltoh16_ua((uint8 *)&parms->opcode)) { ++ case HCI_Read_Data_Block_Size: { ++ read_data_block_size_evt_parms_t *parms2 = ++ (read_data_block_size_evt_parms_t *)parms->parms; ++ dhdp->maxdatablks = ltoh16_ua((uint8 *)&parms2->data_block_num); ++ break; ++ } ++ } ++ break; ++ } ++ ++ case HCI_Flush_Occurred: { ++ flush_occurred_evt_parms_t *evt_parms = (flush_occurred_evt_parms_t *)evt->parms; ++ dhd_bta_flush_hcidata(dhdp, ltoh16_ua((uint8 *)&evt_parms->handle)); ++ break; ++ } ++ default: ++ break; ++ } ++} +diff --git a/drivers/net/wireless/ap6211/dhd_bta.h b/drivers/net/wireless/ap6211/dhd_bta.h +new file mode 100755 +index 0000000..0337f15 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_bta.h +@@ -0,0 +1,39 @@ ++/* ++ * BT-AMP support routines ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd_bta.h 291086 2011-10-21 01:17:24Z $ ++ */ ++#ifndef __dhd_bta_h__ ++#define __dhd_bta_h__ ++ ++struct dhd_pub; ++ ++extern int dhd_bta_docmd(struct dhd_pub *pub, void *cmd_buf, uint cmd_len); ++ ++extern void dhd_bta_doevt(struct dhd_pub *pub, void *data_buf, uint data_len); ++ ++extern int dhd_bta_tx_hcidata(struct dhd_pub *pub, void *data_buf, uint data_len); ++extern void dhd_bta_tx_hcidata_complete(struct dhd_pub *dhdp, void *txp, bool success); ++ ++ ++#endif /* __dhd_bta_h__ */ +diff --git a/drivers/net/wireless/ap6211/dhd_bus.h b/drivers/net/wireless/ap6211/dhd_bus.h +new file mode 100755 +index 0000000..131907d +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_bus.h +@@ -0,0 +1,111 @@ ++/* ++ * Header file describing the internal (inter-module) DHD interfaces. ++ * ++ * Provides type definitions and function prototypes used to link the ++ * DHD OS, bus, and protocol modules. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd_bus.h 347614 2012-07-27 10:24:51Z $ ++ */ ++ ++#ifndef _dhd_bus_h_ ++#define _dhd_bus_h_ ++ ++/* ++ * Exported from dhd bus module (dhd_usb, dhd_sdio) ++ */ ++ ++/* Indicate (dis)interest in finding dongles. */ ++extern int dhd_bus_register(void); ++extern void dhd_bus_unregister(void); ++ ++/* Download firmware image and nvram image */ ++extern bool dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh, ++ char *fw_path, char *nv_path); ++ ++/* Stop bus module: clear pending frames, disable data flow */ ++extern void dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex); ++ ++/* Initialize bus module: prepare for communication w/dongle */ ++extern int dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex); ++ ++/* Get the Bus Idle Time */ ++extern void dhd_bus_getidletime(dhd_pub_t *dhdp, int *idletime); ++ ++/* Set the Bus Idle Time */ ++extern void dhd_bus_setidletime(dhd_pub_t *dhdp, int idle_time); ++ ++/* Send a data frame to the dongle. Callee disposes of txp. */ ++extern int dhd_bus_txdata(struct dhd_bus *bus, void *txp, bool wlfc_locked); ++ ++/* Send/receive a control message to/from the dongle. ++ * Expects caller to enforce a single outstanding transaction. ++ */ ++extern int dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen); ++extern int dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen); ++ ++/* Watchdog timer function */ ++extern bool dhd_bus_watchdog(dhd_pub_t *dhd); ++extern void dhd_disable_intr(dhd_pub_t *dhd); ++ ++#if defined(DHD_DEBUG) ++/* Device console input function */ ++extern int dhd_bus_console_in(dhd_pub_t *dhd, uchar *msg, uint msglen); ++#endif /* defined(DHD_DEBUG) */ ++ ++/* Deferred processing for the bus, return TRUE requests reschedule */ ++extern bool dhd_bus_dpc(struct dhd_bus *bus); ++extern void dhd_bus_isr(bool * InterruptRecognized, bool * QueueMiniportHandleInterrupt, void *arg); ++ ++ ++/* Check for and handle local prot-specific iovar commands */ ++extern int dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name, ++ void *params, int plen, void *arg, int len, bool set); ++ ++/* Add bus dump output to a buffer */ ++extern void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); ++ ++/* Clear any bus counters */ ++extern void dhd_bus_clearcounts(dhd_pub_t *dhdp); ++ ++/* return the dongle chipid */ ++extern uint dhd_bus_chip(struct dhd_bus *bus); ++ ++/* Set user-specified nvram parameters. */ ++extern void dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params); ++ ++extern void *dhd_bus_pub(struct dhd_bus *bus); ++extern void *dhd_bus_txq(struct dhd_bus *bus); ++extern uint dhd_bus_hdrlen(struct dhd_bus *bus); ++ ++ ++#define DHD_SET_BUS_STATE_DOWN(_bus) do { \ ++ (_bus)->dhd->busstate = DHD_BUS_DOWN; \ ++} while (0) ++ ++/* Register a dummy SDIO client driver in order to be notified of new SDIO device */ ++extern int dhd_bus_reg_sdio_notify(void* semaphore); ++extern void dhd_bus_unreg_sdio_notify(void); ++ ++extern void dhd_txglom_enable(dhd_pub_t *dhdp, bool enable); ++ ++#endif /* _dhd_bus_h_ */ +diff --git a/drivers/net/wireless/ap6211/dhd_cdc.c b/drivers/net/wireless/ap6211/dhd_cdc.c +new file mode 100755 +index 0000000..3a7f55b +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_cdc.c +@@ -0,0 +1,3191 @@ ++/* ++ * DHD Protocol Module for CDC and BDC. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd_cdc.c 368762 2012-11-14 21:59:17Z $ ++ * ++ * BDC is like CDC, except it includes a header for data packets to convey ++ * packet priority over the bus, and flags (e.g. to indicate checksum status ++ * for dongle offload.) ++ */ ++ ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++ ++#ifdef PROP_TXSTATUS ++#include ++#include ++#endif ++ ++#include ++ ++#define RETRIES 2 /* # of retries to retrieve matching ioctl response */ ++#define BUS_HEADER_LEN (24+DHD_SDALIGN) /* Must be at least SDPCM_RESERVE ++ * defined in dhd_sdio.c (amount of header tha might be added) ++ * plus any space that might be needed for alignment padding. ++ */ ++#define ROUND_UP_MARGIN 2048 /* Biggest SDIO block size possible for ++ * round off at the end of buffer ++ */ ++ ++#define BUS_RETRIES 1 /* # of retries before aborting a bus tx operation */ ++ ++#ifdef PROP_TXSTATUS ++typedef struct dhd_wlfc_commit_info { ++ uint8 needs_hdr; ++ uint8 ac_fifo_credit_spent; ++ ewlfc_packet_state_t pkt_type; ++ wlfc_mac_descriptor_t* mac_entry; ++ void* p; ++} dhd_wlfc_commit_info_t; ++#endif /* PROP_TXSTATUS */ ++ ++ ++typedef struct dhd_prot { ++ uint16 reqid; ++ uint8 pending; ++ uint32 lastcmd; ++ uint8 bus_header[BUS_HEADER_LEN]; ++ cdc_ioctl_t msg; ++ unsigned char buf[WLC_IOCTL_MAXLEN + ROUND_UP_MARGIN]; ++} dhd_prot_t; ++ ++ ++static int ++dhdcdc_msg(dhd_pub_t *dhd) ++{ ++ int err = 0; ++ dhd_prot_t *prot = dhd->prot; ++ int len = ltoh32(prot->msg.len) + sizeof(cdc_ioctl_t); ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ DHD_OS_WAKE_LOCK(dhd); ++ ++ /* NOTE : cdc->msg.len holds the desired length of the buffer to be ++ * returned. Only up to CDC_MAX_MSG_SIZE of this buffer area ++ * is actually sent to the dongle ++ */ ++ if (len > CDC_MAX_MSG_SIZE) ++ len = CDC_MAX_MSG_SIZE; ++ ++ /* Send request */ ++ err = dhd_bus_txctl(dhd->bus, (uchar*)&prot->msg, len); ++ ++ DHD_OS_WAKE_UNLOCK(dhd); ++ return err; ++} ++ ++static int ++dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len) ++{ ++ int ret; ++ int cdc_len = len + sizeof(cdc_ioctl_t); ++ dhd_prot_t *prot = dhd->prot; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ do { ++ ret = dhd_bus_rxctl(dhd->bus, (uchar*)&prot->msg, cdc_len); ++ if (ret < 0) ++ break; ++ } while (CDC_IOC_ID(ltoh32(prot->msg.flags)) != id); ++ ++ return ret; ++} ++ ++static int ++dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ cdc_ioctl_t *msg = &prot->msg; ++ void *info; ++ int ret = 0, retries = 0; ++ uint32 id, flags = 0; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ AP6211_DEBUG("%s: cmd %d len %d\n", __FUNCTION__, cmd, len); ++ ++ ++ /* Respond "bcmerror" and "bcmerrorstr" with local cache */ ++ if (cmd == WLC_GET_VAR && buf) ++ { ++ if (!strcmp((char *)buf, "bcmerrorstr")) ++ { ++ strncpy((char *)buf, bcmerrorstr(dhd->dongle_error), BCME_STRLEN); ++ goto done; ++ } ++ else if (!strcmp((char *)buf, "bcmerror")) ++ { ++ *(int *)buf = dhd->dongle_error; ++ goto done; ++ } ++ } ++ ++ memset(msg, 0, sizeof(cdc_ioctl_t)); ++ ++ msg->cmd = htol32(cmd); ++ msg->len = htol32(len); ++ msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT); ++ CDC_SET_IF_IDX(msg, ifidx); ++ /* add additional action bits */ ++ action &= WL_IOCTL_ACTION_MASK; ++ msg->flags |= (action << CDCF_IOC_ACTION_SHIFT); ++ msg->flags = htol32(msg->flags); ++ ++ if (buf) ++ memcpy(prot->buf, buf, len); ++ ++ if ((ret = dhdcdc_msg(dhd)) < 0) { ++ if (!dhd->hang_was_sent) ++ AP6211_ERR("dhdcdc_query_ioctl: dhdcdc_msg failed w/status %d\n", ret); ++ goto done; ++ } ++ ++retry: ++ /* wait for interrupt and get first fragment */ ++ if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0) ++ goto done; ++ ++ flags = ltoh32(msg->flags); ++ id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT; ++ ++ if ((id < prot->reqid) && (++retries < RETRIES)) ++ goto retry; ++ if (id != prot->reqid) { ++ AP6211_ERR("%s: %s: unexpected request id %d (expected %d)\n", ++ dhd_ifname(dhd, ifidx), __FUNCTION__, id, prot->reqid); ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ /* Check info buffer */ ++ info = (void*)&msg[1]; ++ ++ /* Copy info buffer */ ++ if (buf) ++ { ++ if (ret < (int)len) ++ len = ret; ++ memcpy(buf, info, len); ++ } ++ ++ /* Check the ERROR flag */ ++ if (flags & CDCF_IOC_ERROR) ++ { ++ ret = ltoh32(msg->status); ++ /* Cache error from dongle */ ++ dhd->dongle_error = ret; ++ } ++ ++done: ++ return ret; ++} ++ ++static int ++dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ cdc_ioctl_t *msg = &prot->msg; ++ int ret = 0; ++ uint32 flags, id; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ AP6211_DEBUG("%s: cmd %d len %d\n", __FUNCTION__, cmd, len); ++ ++ if (dhd->busstate == DHD_BUS_DOWN) { ++ AP6211_ERR("%s : bus is down. we have nothing to do\n", __FUNCTION__); ++ return -EIO; ++ } ++ ++ /* don't talk to the dongle if fw is about to be reloaded */ ++ if (dhd->hang_was_sent) { ++ AP6211_ERR("%s: HANG was sent up earlier. Not talking to the chip\n", ++ __FUNCTION__); ++ return -EIO; ++ } ++ ++ memset(msg, 0, sizeof(cdc_ioctl_t)); ++ ++ msg->cmd = htol32(cmd); ++ msg->len = htol32(len); ++ msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT); ++ CDC_SET_IF_IDX(msg, ifidx); ++ /* add additional action bits */ ++ action &= WL_IOCTL_ACTION_MASK; ++ msg->flags |= (action << CDCF_IOC_ACTION_SHIFT) | CDCF_IOC_SET; ++ msg->flags = htol32(msg->flags); ++ ++ if (buf) ++ memcpy(prot->buf, buf, len); ++ ++ if ((ret = dhdcdc_msg(dhd)) < 0) { ++ AP6211_ERR("%s: dhdcdc_msg failed w/status %d\n", __FUNCTION__, ret); ++ goto done; ++ } ++ ++ if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0) ++ goto done; ++ ++ flags = ltoh32(msg->flags); ++ id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT; ++ ++ if (id != prot->reqid) { ++ AP6211_ERR("%s: %s: unexpected request id %d (expected %d)\n", ++ dhd_ifname(dhd, ifidx), __FUNCTION__, id, prot->reqid); ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ /* Check the ERROR flag */ ++ if (flags & CDCF_IOC_ERROR) ++ { ++ ret = ltoh32(msg->status); ++ /* Cache error from dongle */ ++ dhd->dongle_error = ret; ++ } ++ ++done: ++ return ret; ++} ++ ++ ++int ++dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ int ret = -1; ++ uint8 action; ++#if defined(NDIS630) ++ bool acquired = FALSE; ++#endif ++ ++ if ((dhd->busstate == DHD_BUS_DOWN) || dhd->hang_was_sent) { ++ AP6211_ERR("%s : bus is down. we have nothing to do\n", __FUNCTION__); ++ goto done; ++ } ++#if defined(NDIS630) ++ if (dhd_os_proto_block(dhd)) ++ { ++ acquired = TRUE; ++ } ++ else ++ { ++ /* attempt to acquire protocol mutex timed out. */ ++ ret = -1; ++ return ret; ++ } ++#endif /* NDIS630 */ ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ ASSERT(len <= WLC_IOCTL_MAXLEN); ++ ++ if (len > WLC_IOCTL_MAXLEN) ++ goto done; ++ ++ if (prot->pending == TRUE) { ++ AP6211_ERR("CDC packet is pending!!!! cmd=0x%x (%lu) lastcmd=0x%x (%lu)\n", ++ ioc->cmd, (unsigned long)ioc->cmd, prot->lastcmd, ++ (unsigned long)prot->lastcmd); ++ if ((ioc->cmd == WLC_SET_VAR) || (ioc->cmd == WLC_GET_VAR)) { ++ AP6211_DEBUG("iovar cmd=%s\n", (char*)buf); ++ } ++ goto done; ++ } ++ ++ prot->pending = TRUE; ++ prot->lastcmd = ioc->cmd; ++ action = ioc->set; ++ if (action & WL_IOCTL_ACTION_SET) ++ ret = dhdcdc_set_ioctl(dhd, ifidx, ioc->cmd, buf, len, action); ++ else { ++ ret = dhdcdc_query_ioctl(dhd, ifidx, ioc->cmd, buf, len, action); ++ if (ret > 0) ++ ioc->used = ret - sizeof(cdc_ioctl_t); ++ } ++ ++ /* Too many programs assume ioctl() returns 0 on success */ ++ if (ret >= 0) ++ ret = 0; ++ else { ++ cdc_ioctl_t *msg = &prot->msg; ++ ioc->needed = ltoh32(msg->len); /* len == needed when set/query fails from dongle */ ++ } ++ ++ /* Intercept the wme_dp ioctl here */ ++ if ((!ret) && (ioc->cmd == WLC_SET_VAR) && (!strcmp(buf, "wme_dp"))) { ++ int slen, val = 0; ++ ++ slen = strlen("wme_dp") + 1; ++ if (len >= (int)(slen + sizeof(int))) ++ bcopy(((char *)buf + slen), &val, sizeof(int)); ++ dhd->wme_dp = (uint8) ltoh32(val); ++ } ++ ++ prot->pending = FALSE; ++ ++done: ++#if defined(NDIS630) ++ if (acquired) ++ dhd_os_proto_unblock(dhd); ++#endif ++ return ret; ++} ++ ++int ++dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name, ++ void *params, int plen, void *arg, int len, bool set) ++{ ++ return BCME_UNSUPPORTED; ++} ++ ++#ifdef PROP_TXSTATUS ++void ++dhd_wlfc_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) ++{ ++ int i; ++ uint8* ea; ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhdp->wlfc_state; ++ wlfc_hanger_t* h; ++ wlfc_mac_descriptor_t* mac_table; ++ wlfc_mac_descriptor_t* interfaces; ++ char* iftypes[] = {"STA", "AP", "WDS", "p2pGO", "p2pCL"}; ++ ++ if (wlfc == NULL) { ++ bcm_bprintf(strbuf, "wlfc not initialized yet\n"); ++ return; ++ } ++ h = (wlfc_hanger_t*)wlfc->hanger; ++ if (h == NULL) { ++ bcm_bprintf(strbuf, "wlfc-hanger not initialized yet\n"); ++ } ++ ++ mac_table = wlfc->destination_entries.nodes; ++ interfaces = wlfc->destination_entries.interfaces; ++ bcm_bprintf(strbuf, "---- wlfc stats ----\n"); ++ if (h) { ++ bcm_bprintf(strbuf, "wlfc hanger (pushed,popped,f_push," ++ "f_pop,f_slot, pending) = (%d,%d,%d,%d,%d,%d)\n", ++ h->pushed, ++ h->popped, ++ h->failed_to_push, ++ h->failed_to_pop, ++ h->failed_slotfind, ++ (h->pushed - h->popped)); ++ } ++ ++ bcm_bprintf(strbuf, "wlfc fail(tlv,credit_rqst,mac_update,psmode_update), " ++ "(dq_full,sendq_full, rollback_fail) = (%d,%d,%d,%d), (%d,%d,%d)\n", ++ wlfc->stats.tlv_parse_failed, ++ wlfc->stats.credit_request_failed, ++ wlfc->stats.mac_update_failed, ++ wlfc->stats.psmode_update_failed, ++ wlfc->stats.delayq_full_error, ++ wlfc->stats.sendq_full_error, ++ wlfc->stats.rollback_failed); ++ ++ bcm_bprintf(strbuf, "SENDQ (len,credit,sent) " ++ "(AC0[%d,%d,%d],AC1[%d,%d,%d],AC2[%d,%d,%d],AC3[%d,%d,%d],BC_MC[%d,%d,%d])\n", ++ wlfc->SENDQ.q[0].len, wlfc->FIFO_credit[0], wlfc->stats.sendq_pkts[0], ++ wlfc->SENDQ.q[1].len, wlfc->FIFO_credit[1], wlfc->stats.sendq_pkts[1], ++ wlfc->SENDQ.q[2].len, wlfc->FIFO_credit[2], wlfc->stats.sendq_pkts[2], ++ wlfc->SENDQ.q[3].len, wlfc->FIFO_credit[3], wlfc->stats.sendq_pkts[3], ++ wlfc->SENDQ.q[4].len, wlfc->FIFO_credit[4], wlfc->stats.sendq_pkts[4]); ++ ++#ifdef PROP_TXSTATUS_DEBUG ++ bcm_bprintf(strbuf, "SENDQ dropped: AC[0-3]:(%d,%d,%d,%d), (bcmc,atim):(%d,%d)\n", ++ wlfc->stats.dropped_qfull[0], wlfc->stats.dropped_qfull[1], ++ wlfc->stats.dropped_qfull[2], wlfc->stats.dropped_qfull[3], ++ wlfc->stats.dropped_qfull[4], wlfc->stats.dropped_qfull[5]); ++#endif ++ ++ bcm_bprintf(strbuf, "\n"); ++ for (i = 0; i < WLFC_MAX_IFNUM; i++) { ++ if (interfaces[i].occupied) { ++ char* iftype_desc; ++ ++ if (interfaces[i].iftype > WLC_E_IF_ROLE_P2P_CLIENT) ++ iftype_desc = "hostif_flow_state[i] == OFF) ++ ? " OFF":" ON")); ++ ++ bcm_bprintf(strbuf, "INTERFACE[%d].DELAYQ(len,state,credit)" ++ "= (%d,%s,%d)\n", ++ i, ++ interfaces[i].psq.len, ++ ((interfaces[i].state == ++ WLFC_STATE_OPEN) ? " OPEN":"CLOSE"), ++ interfaces[i].requested_credit); ++ ++ bcm_bprintf(strbuf, "INTERFACE[%d].DELAYQ" ++ "(sup,ac0),(sup,ac1),(sup,ac2),(sup,ac3) = " ++ "(%d,%d),(%d,%d),(%d,%d),(%d,%d)\n", ++ i, ++ interfaces[i].psq.q[0].len, ++ interfaces[i].psq.q[1].len, ++ interfaces[i].psq.q[2].len, ++ interfaces[i].psq.q[3].len, ++ interfaces[i].psq.q[4].len, ++ interfaces[i].psq.q[5].len, ++ interfaces[i].psq.q[6].len, ++ interfaces[i].psq.q[7].len); ++ } ++ } ++ ++ bcm_bprintf(strbuf, "\n"); ++ for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { ++ if (mac_table[i].occupied) { ++ ea = mac_table[i].ea; ++ bcm_bprintf(strbuf, "MAC_table[%d].ea = " ++ "[%02x:%02x:%02x:%02x:%02x:%02x], if:%d \n", i, ++ ea[0], ea[1], ea[2], ea[3], ea[4], ea[5], ++ mac_table[i].interface_id); ++ ++ bcm_bprintf(strbuf, "MAC_table[%d].DELAYQ(len,state,credit)" ++ "= (%d,%s,%d)\n", ++ i, ++ mac_table[i].psq.len, ++ ((mac_table[i].state == ++ WLFC_STATE_OPEN) ? " OPEN":"CLOSE"), ++ mac_table[i].requested_credit); ++#ifdef PROP_TXSTATUS_DEBUG ++ bcm_bprintf(strbuf, "MAC_table[%d]: (opened, closed) = (%d, %d)\n", ++ i, mac_table[i].opened_ct, mac_table[i].closed_ct); ++#endif ++ bcm_bprintf(strbuf, "MAC_table[%d].DELAYQ" ++ "(sup,ac0),(sup,ac1),(sup,ac2),(sup,ac3) = " ++ "(%d,%d),(%d,%d),(%d,%d),(%d,%d)\n", ++ i, ++ mac_table[i].psq.q[0].len, ++ mac_table[i].psq.q[1].len, ++ mac_table[i].psq.q[2].len, ++ mac_table[i].psq.q[3].len, ++ mac_table[i].psq.q[4].len, ++ mac_table[i].psq.q[5].len, ++ mac_table[i].psq.q[6].len, ++ mac_table[i].psq.q[7].len); ++ } ++ } ++ ++#ifdef PROP_TXSTATUS_DEBUG ++ { ++ int avg; ++ int moving_avg = 0; ++ int moving_samples; ++ ++ if (wlfc->stats.latency_sample_count) { ++ moving_samples = sizeof(wlfc->stats.deltas)/sizeof(uint32); ++ ++ for (i = 0; i < moving_samples; i++) ++ moving_avg += wlfc->stats.deltas[i]; ++ moving_avg /= moving_samples; ++ ++ avg = (100 * wlfc->stats.total_status_latency) / ++ wlfc->stats.latency_sample_count; ++ bcm_bprintf(strbuf, "txstatus latency (average, last, moving[%d]) = " ++ "(%d.%d, %03d, %03d)\n", ++ moving_samples, avg/100, (avg - (avg/100)*100), ++ wlfc->stats.latency_most_recent, ++ moving_avg); ++ } ++ } ++ ++ bcm_bprintf(strbuf, "wlfc- fifo[0-5] credit stats: sent = (%d,%d,%d,%d,%d,%d), " ++ "back = (%d,%d,%d,%d,%d,%d)\n", ++ wlfc->stats.fifo_credits_sent[0], ++ wlfc->stats.fifo_credits_sent[1], ++ wlfc->stats.fifo_credits_sent[2], ++ wlfc->stats.fifo_credits_sent[3], ++ wlfc->stats.fifo_credits_sent[4], ++ wlfc->stats.fifo_credits_sent[5], ++ ++ wlfc->stats.fifo_credits_back[0], ++ wlfc->stats.fifo_credits_back[1], ++ wlfc->stats.fifo_credits_back[2], ++ wlfc->stats.fifo_credits_back[3], ++ wlfc->stats.fifo_credits_back[4], ++ wlfc->stats.fifo_credits_back[5]); ++ { ++ uint32 fifo_cr_sent = 0; ++ uint32 fifo_cr_acked = 0; ++ uint32 request_cr_sent = 0; ++ uint32 request_cr_ack = 0; ++ uint32 bc_mc_cr_ack = 0; ++ ++ for (i = 0; i < sizeof(wlfc->stats.fifo_credits_sent)/sizeof(uint32); i++) { ++ fifo_cr_sent += wlfc->stats.fifo_credits_sent[i]; ++ } ++ ++ for (i = 0; i < sizeof(wlfc->stats.fifo_credits_back)/sizeof(uint32); i++) { ++ fifo_cr_acked += wlfc->stats.fifo_credits_back[i]; ++ } ++ ++ for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { ++ if (wlfc->destination_entries.nodes[i].occupied) { ++ request_cr_sent += ++ wlfc->destination_entries.nodes[i].dstncredit_sent_packets; ++ } ++ } ++ for (i = 0; i < WLFC_MAX_IFNUM; i++) { ++ if (wlfc->destination_entries.interfaces[i].occupied) { ++ request_cr_sent += ++ wlfc->destination_entries.interfaces[i].dstncredit_sent_packets; ++ } ++ } ++ for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { ++ if (wlfc->destination_entries.nodes[i].occupied) { ++ request_cr_ack += ++ wlfc->destination_entries.nodes[i].dstncredit_acks; ++ } ++ } ++ for (i = 0; i < WLFC_MAX_IFNUM; i++) { ++ if (wlfc->destination_entries.interfaces[i].occupied) { ++ request_cr_ack += ++ wlfc->destination_entries.interfaces[i].dstncredit_acks; ++ } ++ } ++ bcm_bprintf(strbuf, "wlfc- (sent, status) => pq(%d,%d), vq(%d,%d)," ++ "other:%d, bc_mc:%d, signal-only, (sent,freed): (%d,%d)", ++ fifo_cr_sent, fifo_cr_acked, ++ request_cr_sent, request_cr_ack, ++ wlfc->destination_entries.other.dstncredit_acks, ++ bc_mc_cr_ack, ++ wlfc->stats.signal_only_pkts_sent, wlfc->stats.signal_only_pkts_freed); ++ } ++#endif /* PROP_TXSTATUS_DEBUG */ ++ bcm_bprintf(strbuf, "\n"); ++ bcm_bprintf(strbuf, "wlfc- pkt((in,2bus,txstats,hdrpull),(dropped,hdr_only,wlc_tossed)" ++ "(freed,free_err,rollback)) = " ++ "((%d,%d,%d,%d),(%d,%d,%d),(%d,%d,%d))\n", ++ wlfc->stats.pktin, ++ wlfc->stats.pkt2bus, ++ wlfc->stats.txstatus_in, ++ wlfc->stats.dhd_hdrpulls, ++ ++ wlfc->stats.pktdropped, ++ wlfc->stats.wlfc_header_only_pkt, ++ wlfc->stats.wlc_tossed_pkts, ++ ++ wlfc->stats.pkt_freed, ++ wlfc->stats.pkt_free_err, wlfc->stats.rollback); ++ ++ bcm_bprintf(strbuf, "wlfc- suppress((d11,wlc,err),enq(d11,wl,hq,mac?),retx(d11,wlc,hq)) = " ++ "((%d,%d,%d),(%d,%d,%d,%d),(%d,%d,%d))\n", ++ ++ wlfc->stats.d11_suppress, ++ wlfc->stats.wl_suppress, ++ wlfc->stats.bad_suppress, ++ ++ wlfc->stats.psq_d11sup_enq, ++ wlfc->stats.psq_wlsup_enq, ++ wlfc->stats.psq_hostq_enq, ++ wlfc->stats.mac_handle_notfound, ++ ++ wlfc->stats.psq_d11sup_retx, ++ wlfc->stats.psq_wlsup_retx, ++ wlfc->stats.psq_hostq_retx); ++ return; ++} ++ ++/* Create a place to store all packet pointers submitted to the firmware until ++ a status comes back, suppress or otherwise. ++ ++ hang-er: noun, a contrivance on which things are hung, as a hook. ++*/ ++static void* ++dhd_wlfc_hanger_create(osl_t *osh, int max_items) ++{ ++ int i; ++ wlfc_hanger_t* hanger; ++ ++ /* allow only up to a specific size for now */ ++ ASSERT(max_items == WLFC_HANGER_MAXITEMS); ++ ++ if ((hanger = (wlfc_hanger_t*)MALLOC(osh, WLFC_HANGER_SIZE(max_items))) == NULL) ++ return NULL; ++ ++ memset(hanger, 0, WLFC_HANGER_SIZE(max_items)); ++ hanger->max_items = max_items; ++ ++ for (i = 0; i < hanger->max_items; i++) { ++ hanger->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; ++ } ++ return hanger; ++} ++ ++static int ++dhd_wlfc_hanger_delete(osl_t *osh, void* hanger) ++{ ++ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; ++ ++ if (h) { ++ MFREE(osh, h, WLFC_HANGER_SIZE(h->max_items)); ++ return BCME_OK; ++ } ++ return BCME_BADARG; ++} ++ ++static uint16 ++dhd_wlfc_hanger_get_free_slot(void* hanger) ++{ ++ uint32 i; ++ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; ++ ++ if (h) { ++ for (i = (h->slot_pos + 1); i != h->slot_pos;) { ++ if (h->items[i].state == WLFC_HANGER_ITEM_STATE_FREE) { ++ h->slot_pos = i; ++ return (uint16)i; ++ } ++ (i == h->max_items)? i = 0 : i++; ++ } ++ h->failed_slotfind++; ++ } ++ return WLFC_HANGER_MAXITEMS; ++} ++ ++static int ++dhd_wlfc_hanger_get_genbit(void* hanger, void* pkt, uint32 slot_id, int* gen) ++{ ++ int rc = BCME_OK; ++ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; ++ ++ *gen = 0xff; ++ ++ /* this packet was not pushed at the time it went to the firmware */ ++ if (slot_id == WLFC_HANGER_MAXITEMS) ++ return BCME_NOTFOUND; ++ ++ if (h) { ++ if ((h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE) || ++ (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED)) { ++ *gen = h->items[slot_id].gen; ++ } ++ else { ++ rc = BCME_NOTFOUND; ++ } ++ } ++ else ++ rc = BCME_BADARG; ++ return rc; ++} ++ ++static int ++dhd_wlfc_hanger_pushpkt(void* hanger, void* pkt, uint32 slot_id) ++{ ++ int rc = BCME_OK; ++ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; ++ ++ if (h && (slot_id < WLFC_HANGER_MAXITEMS)) { ++ if (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_FREE) { ++ h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_INUSE; ++ h->items[slot_id].pkt = pkt; ++ h->items[slot_id].identifier = slot_id; ++ h->pushed++; ++ } ++ else { ++ h->failed_to_push++; ++ rc = BCME_NOTFOUND; ++ } ++ } ++ else ++ rc = BCME_BADARG; ++ return rc; ++} ++ ++static int ++dhd_wlfc_hanger_poppkt(void* hanger, uint32 slot_id, void** pktout, int remove_from_hanger) ++{ ++ int rc = BCME_OK; ++ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; ++ ++ /* this packet was not pushed at the time it went to the firmware */ ++ if (slot_id == WLFC_HANGER_MAXITEMS) ++ return BCME_NOTFOUND; ++ ++ if (h) { ++ if (h->items[slot_id].state != WLFC_HANGER_ITEM_STATE_FREE) { ++ *pktout = h->items[slot_id].pkt; ++ if (remove_from_hanger) { ++ h->items[slot_id].state = ++ WLFC_HANGER_ITEM_STATE_FREE; ++ h->items[slot_id].pkt = NULL; ++ h->items[slot_id].identifier = 0; ++ h->items[slot_id].gen = 0xff; ++ h->popped++; ++ } ++ } ++ else { ++ h->failed_to_pop++; ++ rc = BCME_NOTFOUND; ++ } ++ } ++ else ++ rc = BCME_BADARG; ++ return rc; ++} ++ ++static int ++dhd_wlfc_hanger_mark_suppressed(void* hanger, uint32 slot_id, uint8 gen) ++{ ++ int rc = BCME_OK; ++ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; ++ ++ /* this packet was not pushed at the time it went to the firmware */ ++ if (slot_id == WLFC_HANGER_MAXITEMS) ++ return BCME_NOTFOUND; ++ if (h) { ++ h->items[slot_id].gen = gen; ++ if (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE) { ++ h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED; ++ } ++ else ++ rc = BCME_BADARG; ++ } ++ else ++ rc = BCME_BADARG; ++ ++ return rc; ++} ++ ++static int ++_dhd_wlfc_pushheader(athost_wl_status_info_t* ctx, void* p, bool tim_signal, ++ uint8 tim_bmp, uint8 mac_handle, uint32 htodtag) ++{ ++ uint32 wl_pktinfo = 0; ++ uint8* wlh; ++ uint8 dataOffset; ++ uint8 fillers; ++ uint8 tim_signal_len = 0; ++ ++ struct bdc_header *h; ++ ++ if (tim_signal) { ++ tim_signal_len = 1 + 1 + WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP; ++ } ++ ++ /* +2 is for Type[1] and Len[1] in TLV, plus TIM signal */ ++ dataOffset = WLFC_CTL_VALUE_LEN_PKTTAG + 2 + tim_signal_len; ++ fillers = ROUNDUP(dataOffset, 4) - dataOffset; ++ dataOffset += fillers; ++ ++ PKTPUSH(ctx->osh, p, dataOffset); ++ wlh = (uint8*) PKTDATA(ctx->osh, p); ++ ++ wl_pktinfo = htol32(htodtag); ++ ++ wlh[0] = WLFC_CTL_TYPE_PKTTAG; ++ wlh[1] = WLFC_CTL_VALUE_LEN_PKTTAG; ++ memcpy(&wlh[2], &wl_pktinfo, sizeof(uint32)); ++ ++ if (tim_signal_len) { ++ wlh[dataOffset - fillers - tim_signal_len ] = ++ WLFC_CTL_TYPE_PENDING_TRAFFIC_BMP; ++ wlh[dataOffset - fillers - tim_signal_len + 1] = ++ WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP; ++ wlh[dataOffset - fillers - tim_signal_len + 2] = mac_handle; ++ wlh[dataOffset - fillers - tim_signal_len + 3] = tim_bmp; ++ } ++ if (fillers) ++ memset(&wlh[dataOffset - fillers], WLFC_CTL_TYPE_FILLER, fillers); ++ ++ PKTPUSH(ctx->osh, p, BDC_HEADER_LEN); ++ h = (struct bdc_header *)PKTDATA(ctx->osh, p); ++ h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); ++ if (PKTSUMNEEDED(p)) ++ h->flags |= BDC_FLAG_SUM_NEEDED; ++ ++ ++ h->priority = (PKTPRIO(p) & BDC_PRIORITY_MASK); ++ h->flags2 = 0; ++ h->dataOffset = dataOffset >> 2; ++ BDC_SET_IF_IDX(h, DHD_PKTTAG_IF(PKTTAG(p))); ++ return BCME_OK; ++} ++ ++static int ++_dhd_wlfc_pullheader(athost_wl_status_info_t* ctx, void* pktbuf) ++{ ++ struct bdc_header *h; ++ ++ if (PKTLEN(ctx->osh, pktbuf) < BDC_HEADER_LEN) { ++ AP6211_DEBUG("%s: rx data too short (%d < %d)\n", __FUNCTION__, ++ PKTLEN(ctx->osh, pktbuf), BDC_HEADER_LEN); ++ return BCME_ERROR; ++ } ++ h = (struct bdc_header *)PKTDATA(ctx->osh, pktbuf); ++ ++ /* pull BDC header */ ++ PKTPULL(ctx->osh, pktbuf, BDC_HEADER_LEN); ++ ++ if (PKTLEN(ctx->osh, pktbuf) < (h->dataOffset << 2)) { ++ AP6211_DEBUG("%s: rx data too short (%d < %d)\n", __FUNCTION__, ++ PKTLEN(ctx->osh, pktbuf), (h->dataOffset << 2)); ++ return BCME_ERROR; ++ } ++ /* pull wl-header */ ++ PKTPULL(ctx->osh, pktbuf, (h->dataOffset << 2)); ++ return BCME_OK; ++} ++ ++static wlfc_mac_descriptor_t* ++_dhd_wlfc_find_table_entry(athost_wl_status_info_t* ctx, void* p) ++{ ++ int i; ++ wlfc_mac_descriptor_t* table = ctx->destination_entries.nodes; ++ uint8 ifid = DHD_PKTTAG_IF(PKTTAG(p)); ++ uint8* dstn = DHD_PKTTAG_DSTN(PKTTAG(p)); ++ ++ if (((ctx->destination_entries.interfaces[ifid].iftype == WLC_E_IF_ROLE_STA) || ++ ETHER_ISMULTI(dstn) || ++ (ctx->destination_entries.interfaces[ifid].iftype == WLC_E_IF_ROLE_P2P_CLIENT)) && ++ (ctx->destination_entries.interfaces[ifid].occupied)) { ++ return &ctx->destination_entries.interfaces[ifid]; ++ } ++ ++ for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { ++ if (table[i].occupied) { ++ if (table[i].interface_id == ifid) { ++ if (!memcmp(table[i].ea, dstn, ETHER_ADDR_LEN)) ++ return &table[i]; ++ } ++ } ++ } ++ return &ctx->destination_entries.other; ++} ++ ++static int ++_dhd_wlfc_rollback_packet_toq(athost_wl_status_info_t* ctx, ++ void* p, ewlfc_packet_state_t pkt_type, uint32 hslot) ++{ ++ /* ++ put the packet back to the head of queue ++ ++ - a packet from send-q will need to go back to send-q and not delay-q ++ since that will change the order of packets. ++ - suppressed packet goes back to suppress sub-queue ++ - pull out the header, if new or delayed packet ++ ++ Note: hslot is used only when header removal is done. ++ */ ++ wlfc_mac_descriptor_t* entry; ++ void* pktout; ++ int rc = BCME_OK; ++ int prec; ++ ++ entry = _dhd_wlfc_find_table_entry(ctx, p); ++ prec = DHD_PKTTAG_FIFO(PKTTAG(p)); ++ if (entry != NULL) { ++ if (pkt_type == eWLFC_PKTTYPE_SUPPRESSED) { ++ /* wl-header is saved for suppressed packets */ ++ if (WLFC_PKTQ_PENQ_HEAD(&entry->psq, ((prec << 1) + 1), p) == NULL) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ rc = BCME_ERROR; ++ } ++ } ++ else { ++ /* remove header first */ ++ rc = _dhd_wlfc_pullheader(ctx, p); ++ if (rc != BCME_OK) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ /* free the hanger slot */ ++ dhd_wlfc_hanger_poppkt(ctx->hanger, hslot, &pktout, 1); ++ PKTFREE(ctx->osh, p, TRUE); ++ rc = BCME_ERROR; ++ return rc; ++ } ++ ++ if (pkt_type == eWLFC_PKTTYPE_DELAYED) { ++ /* delay-q packets are going to delay-q */ ++ if (WLFC_PKTQ_PENQ_HEAD(&entry->psq, (prec << 1), p) == NULL) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ rc = BCME_ERROR; ++ } ++ } ++ else { ++ /* these are going to SENDQ */ ++ if (WLFC_PKTQ_PENQ_HEAD(&ctx->SENDQ, prec, p) == NULL) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ rc = BCME_ERROR; ++ } ++ } ++ /* free the hanger slot */ ++ dhd_wlfc_hanger_poppkt(ctx->hanger, hslot, &pktout, 1); ++ ++ /* decrement sequence count */ ++ WLFC_DECR_SEQCOUNT(entry, prec); ++ } ++ /* ++ if this packet did not count against FIFO credit, it must have ++ taken a requested_credit from the firmware (for pspoll etc.) ++ */ ++ if (!DHD_PKTTAG_CREDITCHECK(PKTTAG(p))) { ++ entry->requested_credit++; ++ } ++ } ++ else { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ rc = BCME_ERROR; ++ } ++ if (rc != BCME_OK) ++ ctx->stats.rollback_failed++; ++ else ++ ctx->stats.rollback++; ++ ++ return rc; ++} ++ ++static void ++_dhd_wlfc_flow_control_check(athost_wl_status_info_t* ctx, struct pktq* pq, uint8 if_id) ++{ ++ if ((pq->len <= WLFC_FLOWCONTROL_LOWATER) && (ctx->hostif_flow_state[if_id] == ON)) { ++ /* start traffic */ ++ ctx->hostif_flow_state[if_id] = OFF; ++ /* ++ AP6211_DEBUG("qlen:%02d, if:%02d, ->OFF, start traffic %s()\n", ++ pq->len, if_id, __FUNCTION__); ++ */ ++ AP6211_DEBUG("F"); ++ dhd_txflowcontrol(ctx->dhdp, if_id, OFF); ++ ctx->toggle_host_if = 0; ++ } ++ if ((pq->len >= WLFC_FLOWCONTROL_HIWATER) && (ctx->hostif_flow_state[if_id] == OFF)) { ++ /* stop traffic */ ++ ctx->hostif_flow_state[if_id] = ON; ++ /* ++ AP6211_DEBUG("qlen:%02d, if:%02d, ->ON, stop traffic %s()\n", ++ pq->len, if_id, __FUNCTION__); ++ */ ++ AP6211_DEBUG("N"); ++ dhd_txflowcontrol(ctx->dhdp, if_id, ON); ++ ctx->host_ifidx = if_id; ++ ctx->toggle_host_if = 1; ++ } ++ return; ++} ++ ++static int ++_dhd_wlfc_send_signalonly_packet(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, ++ uint8 ta_bmp) ++{ ++ int rc = BCME_OK; ++ void* p = NULL; ++ int dummylen = ((dhd_pub_t *)ctx->dhdp)->hdrlen+ 12; ++ ++ /* allocate a dummy packet */ ++ p = PKTGET(ctx->osh, dummylen, TRUE); ++ if (p) { ++ PKTPULL(ctx->osh, p, dummylen); ++ DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), 0); ++ _dhd_wlfc_pushheader(ctx, p, TRUE, ta_bmp, entry->mac_handle, 0); ++ DHD_PKTTAG_SETSIGNALONLY(PKTTAG(p), 1); ++#ifdef PROP_TXSTATUS_DEBUG ++ ctx->stats.signal_only_pkts_sent++; ++#endif ++ rc = dhd_bus_txdata(((dhd_pub_t *)ctx->dhdp)->bus, p, FALSE); ++ if (rc != BCME_OK) { ++ PKTFREE(ctx->osh, p, TRUE); ++ } ++ } ++ else { ++ AP6211_ERR("%s: couldn't allocate new %d-byte packet\n", ++ __FUNCTION__, dummylen); ++ rc = BCME_NOMEM; ++ } ++ return rc; ++} ++ ++/* Return TRUE if traffic availability changed */ ++static bool ++_dhd_wlfc_traffic_pending_check(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, ++ int prec) ++{ ++ bool rc = FALSE; ++ ++ if (entry->state == WLFC_STATE_CLOSE) { ++ if ((pktq_plen(&entry->psq, (prec << 1)) == 0) && ++ (pktq_plen(&entry->psq, ((prec << 1) + 1)) == 0)) { ++ ++ if (entry->traffic_pending_bmp & NBITVAL(prec)) { ++ rc = TRUE; ++ entry->traffic_pending_bmp = ++ entry->traffic_pending_bmp & ~ NBITVAL(prec); ++ } ++ } ++ else { ++ if (!(entry->traffic_pending_bmp & NBITVAL(prec))) { ++ rc = TRUE; ++ entry->traffic_pending_bmp = ++ entry->traffic_pending_bmp | NBITVAL(prec); ++ } ++ } ++ } ++ if (rc) { ++ /* request a TIM update to firmware at the next piggyback opportunity */ ++ if (entry->traffic_lastreported_bmp != entry->traffic_pending_bmp) { ++ entry->send_tim_signal = 1; ++ _dhd_wlfc_send_signalonly_packet(ctx, entry, entry->traffic_pending_bmp); ++ entry->traffic_lastreported_bmp = entry->traffic_pending_bmp; ++ entry->send_tim_signal = 0; ++ } ++ else { ++ rc = FALSE; ++ } ++ } ++ return rc; ++} ++ ++static int ++_dhd_wlfc_enque_suppressed(athost_wl_status_info_t* ctx, int prec, void* p) ++{ ++ wlfc_mac_descriptor_t* entry; ++ ++ entry = _dhd_wlfc_find_table_entry(ctx, p); ++ if (entry == NULL) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ return BCME_NOTFOUND; ++ } ++ /* ++ - suppressed packets go to sub_queue[2*prec + 1] AND ++ - delayed packets go to sub_queue[2*prec + 0] to ensure ++ order of delivery. ++ */ ++ if (WLFC_PKTQ_PENQ(&entry->psq, ((prec << 1) + 1), p) == NULL) { ++ ctx->stats.delayq_full_error++; ++ /* AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); */ ++ AP6211_DEBUG("s"); ++ return BCME_ERROR; ++ } ++ /* A packet has been pushed, update traffic availability bitmap, if applicable */ ++ _dhd_wlfc_traffic_pending_check(ctx, entry, prec); ++ _dhd_wlfc_flow_control_check(ctx, &entry->psq, DHD_PKTTAG_IF(PKTTAG(p))); ++ return BCME_OK; ++} ++ ++static int ++_dhd_wlfc_pretx_pktprocess(athost_wl_status_info_t* ctx, ++ wlfc_mac_descriptor_t* entry, void* p, int header_needed, uint32* slot) ++{ ++ int rc = BCME_OK; ++ int hslot = WLFC_HANGER_MAXITEMS; ++ bool send_tim_update = FALSE; ++ uint32 htod = 0; ++ uint8 free_ctr; ++ ++ *slot = hslot; ++ ++ if (entry == NULL) { ++ entry = _dhd_wlfc_find_table_entry(ctx, p); ++ } ++ ++ if (entry == NULL) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ return BCME_ERROR; ++ } ++ if (entry->send_tim_signal) { ++ send_tim_update = TRUE; ++ entry->send_tim_signal = 0; ++ entry->traffic_lastreported_bmp = entry->traffic_pending_bmp; ++ } ++ if (header_needed) { ++ hslot = dhd_wlfc_hanger_get_free_slot(ctx->hanger); ++ free_ctr = WLFC_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p))); ++ DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), htod); ++ WLFC_PKTFLAG_SET_GENERATION(htod, entry->generation); ++ entry->transit_count++; ++ } ++ else { ++ hslot = WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); ++ free_ctr = WLFC_PKTID_FREERUNCTR_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); ++ } ++ WLFC_PKTID_HSLOT_SET(htod, hslot); ++ WLFC_PKTID_FREERUNCTR_SET(htod, free_ctr); ++ DHD_PKTTAG_SETPKTDIR(PKTTAG(p), 1); ++ WL_TXSTATUS_SET_FLAGS(htod, WLFC_PKTFLAG_PKTFROMHOST); ++ WL_TXSTATUS_SET_FIFO(htod, DHD_PKTTAG_FIFO(PKTTAG(p))); ++ ++ if (!DHD_PKTTAG_CREDITCHECK(PKTTAG(p))) { ++ /* ++ Indicate that this packet is being sent in response to an ++ explicit request from the firmware side. ++ */ ++ WLFC_PKTFLAG_SET_PKTREQUESTED(htod); ++ } ++ else { ++ WLFC_PKTFLAG_CLR_PKTREQUESTED(htod); ++ } ++ if (header_needed) { ++ rc = _dhd_wlfc_pushheader(ctx, p, send_tim_update, ++ entry->traffic_lastreported_bmp, entry->mac_handle, htod); ++ if (rc == BCME_OK) { ++ DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), htod); ++ /* ++ a new header was created for this packet. ++ push to hanger slot and scrub q. Since bus ++ send succeeded, increment seq number as well. ++ */ ++ rc = dhd_wlfc_hanger_pushpkt(ctx->hanger, p, hslot); ++ if (rc == BCME_OK) { ++ /* increment free running sequence count */ ++ WLFC_INCR_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p))); ++#ifdef PROP_TXSTATUS_DEBUG ++ ((wlfc_hanger_t*)(ctx->hanger))->items[hslot].push_time = ++ OSL_SYSUPTIME(); ++#endif ++ } ++ else { ++ AP6211_DEBUG("%s() hanger_pushpkt() failed, rc: %d\n", ++ __FUNCTION__, rc); ++ } ++ } ++ } ++ else { ++ int gen; ++ ++ /* remove old header */ ++ rc = _dhd_wlfc_pullheader(ctx, p); ++ if (rc == BCME_OK) { ++ hslot = WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); ++ dhd_wlfc_hanger_get_genbit(ctx->hanger, p, hslot, &gen); ++ ++ WLFC_PKTFLAG_SET_GENERATION(htod, gen); ++ free_ctr = WLFC_PKTID_FREERUNCTR_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); ++ /* push new header */ ++ _dhd_wlfc_pushheader(ctx, p, send_tim_update, ++ entry->traffic_lastreported_bmp, entry->mac_handle, htod); ++ } ++ } ++ *slot = hslot; ++ return rc; ++} ++ ++static int ++_dhd_wlfc_is_destination_closed(athost_wl_status_info_t* ctx, ++ wlfc_mac_descriptor_t* entry, int prec) ++{ ++ if (ctx->destination_entries.interfaces[entry->interface_id].iftype == ++ WLC_E_IF_ROLE_P2P_GO) { ++ /* - destination interface is of type p2p GO. ++ For a p2pGO interface, if the destination is OPEN but the interface is ++ CLOSEd, do not send traffic. But if the dstn is CLOSEd while there is ++ destination-specific-credit left send packets. This is because the ++ firmware storing the destination-specific-requested packet in queue. ++ */ ++ if ((entry->state == WLFC_STATE_CLOSE) && (entry->requested_credit == 0) && ++ (entry->requested_packet == 0)) ++ return 1; ++ } ++ /* AP, p2p_go -> unicast desc entry, STA/p2p_cl -> interface desc. entry */ ++ if (((entry->state == WLFC_STATE_CLOSE) && (entry->requested_credit == 0) && ++ (entry->requested_packet == 0)) || ++ (!(entry->ac_bitmap & (1 << prec)))) ++ return 1; ++ ++ return 0; ++} ++ ++static void* ++_dhd_wlfc_deque_delayedq(athost_wl_status_info_t* ctx, ++ int prec, uint8* ac_credit_spent, uint8* needs_hdr, wlfc_mac_descriptor_t** entry_out) ++{ ++ wlfc_mac_descriptor_t* entry; ++ wlfc_mac_descriptor_t* table; ++ uint8 token_pos; ++ int total_entries; ++ void* p = NULL; ++ int pout; ++ int i; ++ ++ *entry_out = NULL; ++ token_pos = ctx->token_pos[prec]; ++ /* most cases a packet will count against FIFO credit */ ++ *ac_credit_spent = 1; ++ *needs_hdr = 1; ++ ++ /* search all entries, include nodes as well as interfaces */ ++ table = (wlfc_mac_descriptor_t*)&ctx->destination_entries; ++ total_entries = sizeof(ctx->destination_entries)/sizeof(wlfc_mac_descriptor_t); ++ ++ for (i = 0; i < total_entries; i++) { ++ entry = &table[(token_pos + i) % total_entries]; ++ if (entry->occupied) { ++ if (!_dhd_wlfc_is_destination_closed(ctx, entry, prec)) { ++ p = pktq_mdeq(&entry->psq, ++ /* higher precedence will be picked up first, ++ * i.e. suppressed packets before delayed ones ++ */ ++ NBITVAL((prec << 1) + 1), &pout); ++ *needs_hdr = 0; ++ ++ if (p == NULL) { ++ if (entry->suppressed == TRUE) { ++ if ((entry->suppr_transit_count <= ++ entry->suppress_count)) { ++ entry->suppressed = FALSE; ++ } else { ++ return NULL; ++ } ++ } ++ /* De-Q from delay Q */ ++ p = pktq_mdeq(&entry->psq, ++ NBITVAL((prec << 1)), ++ &pout); ++ *needs_hdr = 1; ++ } ++ ++ if (p != NULL) { ++ /* did the packet come from suppress sub-queue? */ ++ if (entry->requested_credit > 0) { ++ entry->requested_credit--; ++#ifdef PROP_TXSTATUS_DEBUG ++ entry->dstncredit_sent_packets++; ++#endif ++ /* ++ if the packet was pulled out while destination is in ++ closed state but had a non-zero packets requested, ++ then this should not count against the FIFO credit. ++ That is due to the fact that the firmware will ++ most likely hold onto this packet until a suitable ++ time later to push it to the appropriate AC FIFO. ++ */ ++ if (entry->state == WLFC_STATE_CLOSE) ++ *ac_credit_spent = 0; ++ } ++ else if (entry->requested_packet > 0) { ++ entry->requested_packet--; ++ DHD_PKTTAG_SETONETIMEPKTRQST(PKTTAG(p)); ++ if (entry->state == WLFC_STATE_CLOSE) ++ *ac_credit_spent = 0; ++ } ++ /* move token to ensure fair round-robin */ ++ ctx->token_pos[prec] = ++ (token_pos + i + 1) % total_entries; ++ *entry_out = entry; ++ _dhd_wlfc_flow_control_check(ctx, &entry->psq, ++ DHD_PKTTAG_IF(PKTTAG(p))); ++ /* ++ A packet has been picked up, update traffic ++ availability bitmap, if applicable ++ */ ++ _dhd_wlfc_traffic_pending_check(ctx, entry, prec); ++ return p; ++ } ++ } ++ } ++ } ++ return NULL; ++} ++ ++static void* ++_dhd_wlfc_deque_sendq(athost_wl_status_info_t* ctx, int prec) ++{ ++ wlfc_mac_descriptor_t* entry; ++ void* p; ++ ++ ++ p = pktq_pdeq(&ctx->SENDQ, prec); ++ if (p != NULL) { ++ if (ETHER_ISMULTI(DHD_PKTTAG_DSTN(PKTTAG(p)))) ++ /* bc/mc packets do not have a delay queue */ ++ return p; ++ ++ entry = _dhd_wlfc_find_table_entry(ctx, p); ++ ++ if (entry == NULL) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ return p; ++ } ++ ++ while ((p != NULL)) { ++ /* ++ - suppressed packets go to sub_queue[2*prec + 1] AND ++ - delayed packets go to sub_queue[2*prec + 0] to ensure ++ order of delivery. ++ */ ++ if (WLFC_PKTQ_PENQ(&entry->psq, (prec << 1), p) == NULL) { ++ AP6211_DEBUG("D"); ++ /* dhd_txcomplete(ctx->dhdp, p, FALSE); */ ++ PKTFREE(ctx->osh, p, TRUE); ++ ctx->stats.delayq_full_error++; ++ } ++ /* ++ A packet has been pushed, update traffic availability bitmap, ++ if applicable ++ */ ++ _dhd_wlfc_traffic_pending_check(ctx, entry, prec); ++ ++ p = pktq_pdeq(&ctx->SENDQ, prec); ++ if (p == NULL) ++ break; ++ ++ entry = _dhd_wlfc_find_table_entry(ctx, p); ++ ++ if ((entry == NULL) || (ETHER_ISMULTI(DHD_PKTTAG_DSTN(PKTTAG(p))))) { ++ return p; ++ } ++ } ++ } ++ return p; ++} ++ ++static int ++_dhd_wlfc_mac_entry_update(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, ++ ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea) ++{ ++ int rc = BCME_OK; ++ ++ if (action == eWLFC_MAC_ENTRY_ACTION_ADD) { ++ entry->occupied = 1; ++ entry->state = WLFC_STATE_OPEN; ++ entry->requested_credit = 0; ++ entry->interface_id = ifid; ++ entry->iftype = iftype; ++ entry->ac_bitmap = 0xff; /* update this when handling APSD */ ++ /* for an interface entry we may not care about the MAC address */ ++ if (ea != NULL) ++ memcpy(&entry->ea[0], ea, ETHER_ADDR_LEN); ++ pktq_init(&entry->psq, WLFC_PSQ_PREC_COUNT, WLFC_PSQ_LEN); ++ } ++ else if (action == eWLFC_MAC_ENTRY_ACTION_UPDATE) { ++ entry->occupied = 1; ++ entry->state = WLFC_STATE_OPEN; ++ entry->requested_credit = 0; ++ entry->interface_id = ifid; ++ entry->iftype = iftype; ++ entry->ac_bitmap = 0xff; /* update this when handling APSD */ ++ /* for an interface entry we may not care about the MAC address */ ++ if (ea != NULL) ++ memcpy(&entry->ea[0], ea, ETHER_ADDR_LEN); ++ } ++ else if (action == eWLFC_MAC_ENTRY_ACTION_DEL) { ++ entry->occupied = 0; ++ entry->state = WLFC_STATE_CLOSE; ++ entry->requested_credit = 0; ++ /* enable after packets are queued-deqeued properly. ++ pktq_flush(dhd->osh, &entry->psq, FALSE, NULL, 0); ++ */ ++ } ++ return rc; ++} ++ ++int ++_dhd_wlfc_borrow_credit(athost_wl_status_info_t* ctx, uint8 available_credit_map, int borrower_ac) ++{ ++ int lender_ac; ++ int rc = BCME_ERROR; ++ ++ if (ctx == NULL || available_credit_map == 0) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ return BCME_BADARG; ++ } ++ ++ /* Borrow from lowest priority available AC (including BC/MC credits) */ ++ for (lender_ac = 0; lender_ac <= AC_COUNT; lender_ac++) { ++ if ((available_credit_map && (1 << lender_ac)) && ++ (ctx->FIFO_credit[lender_ac] > 0)) { ++ ctx->credits_borrowed[borrower_ac][lender_ac]++; ++ ctx->FIFO_credit[lender_ac]--; ++ rc = BCME_OK; ++ break; ++ } ++ } ++ ++ return rc; ++} ++ ++int ++dhd_wlfc_interface_entry_update(void* state, ++ ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea) ++{ ++ athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; ++ wlfc_mac_descriptor_t* entry; ++ ++ if (ifid >= WLFC_MAX_IFNUM) ++ return BCME_BADARG; ++ ++ entry = &ctx->destination_entries.interfaces[ifid]; ++ return _dhd_wlfc_mac_entry_update(ctx, entry, action, ifid, iftype, ea); ++} ++ ++int ++dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits) ++{ ++ athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; ++ ++ /* update the AC FIFO credit map */ ++ ctx->FIFO_credit[0] = credits[0]; ++ ctx->FIFO_credit[1] = credits[1]; ++ ctx->FIFO_credit[2] = credits[2]; ++ ctx->FIFO_credit[3] = credits[3]; ++ /* credit for bc/mc packets */ ++ ctx->FIFO_credit[4] = credits[4]; ++ /* credit for ATIM FIFO is not used yet. */ ++ ctx->FIFO_credit[5] = 0; ++ return BCME_OK; ++} ++ ++int ++dhd_wlfc_enque_sendq(void* state, int prec, void* p) ++{ ++ athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; ++ ++ if ((state == NULL) || ++ /* prec = AC_COUNT is used for bc/mc queue */ ++ (prec > AC_COUNT) || ++ (p == NULL)) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ return BCME_BADARG; ++ } ++ if (FALSE == dhd_prec_enq(ctx->dhdp, &ctx->SENDQ, p, prec)) { ++ ctx->stats.sendq_full_error++; ++ /* ++ AP6211_DEBUG("Error: %s():%d, qlen:%d\n", ++ __FUNCTION__, __LINE__, ctx->SENDQ.len); ++ */ ++ WLFC_HOST_FIFO_DROPPEDCTR_INC(ctx, prec); ++ AP6211_DEBUG("Q"); ++ PKTFREE(ctx->osh, p, TRUE); ++ return BCME_ERROR; ++ } ++ ctx->stats.pktin++; ++ /* _dhd_wlfc_flow_control_check(ctx, &ctx->SENDQ, DHD_PKTTAG_IF(PKTTAG(p))); */ ++ return BCME_OK; ++} ++ ++int ++_dhd_wlfc_handle_packet_commit(athost_wl_status_info_t* ctx, int ac, ++ dhd_wlfc_commit_info_t *commit_info, f_commitpkt_t fcommit, void* commit_ctx) ++{ ++ uint32 hslot; ++ int rc; ++ ++ /* ++ if ac_fifo_credit_spent = 0 ++ ++ This packet will not count against the FIFO credit. ++ To ensure the txstatus corresponding to this packet ++ does not provide an implied credit (default behavior) ++ mark the packet accordingly. ++ ++ if ac_fifo_credit_spent = 1 ++ ++ This is a normal packet and it counts against the FIFO ++ credit count. ++ */ ++ DHD_PKTTAG_SETCREDITCHECK(PKTTAG(commit_info->p), commit_info->ac_fifo_credit_spent); ++ rc = _dhd_wlfc_pretx_pktprocess(ctx, commit_info->mac_entry, commit_info->p, ++ commit_info->needs_hdr, &hslot); ++ ++ if (rc == BCME_OK) ++ rc = fcommit(commit_ctx, commit_info->p, TRUE); ++ else ++ ctx->stats.generic_error++; ++ ++ if (rc == BCME_OK) { ++ ctx->stats.pkt2bus++; ++ if (commit_info->ac_fifo_credit_spent) { ++ ctx->stats.sendq_pkts[ac]++; ++ WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac); ++ } ++ } else if (rc == BCME_NORESOURCE) ++ rc = BCME_ERROR; ++ else { ++ /* ++ bus commit has failed, rollback. ++ - remove wl-header for a delayed packet ++ - save wl-header header for suppressed packets ++ */ ++ rc = _dhd_wlfc_rollback_packet_toq(ctx, commit_info->p, ++ (commit_info->pkt_type), hslot); ++ if (rc != BCME_OK) ++ ctx->stats.rollback_failed++; ++ ++ rc = BCME_ERROR; ++ } ++ ++ return rc; ++} ++ ++int ++dhd_wlfc_commit_packets(void* state, f_commitpkt_t fcommit, void* commit_ctx) ++{ ++ int ac; ++ int credit; ++ int rc; ++ dhd_wlfc_commit_info_t commit_info; ++ athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; ++ int credit_count = 0; ++ int bus_retry_count = 0; ++ uint8 ac_available = 0; /* Bitmask for 4 ACs + BC/MC */ ++ ++ if ((state == NULL) || ++ (fcommit == NULL)) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ return BCME_BADARG; ++ } ++ ++ memset(&commit_info, 0, sizeof(commit_info)); ++ ++ /* ++ Commit packets for regular AC traffic. Higher priority first. ++ First, use up FIFO credits available to each AC. Based on distribution ++ and credits left, borrow from other ACs as applicable ++ ++ -NOTE: ++ If the bus between the host and firmware is overwhelmed by the ++ traffic from host, it is possible that higher priority traffic ++ starves the lower priority queue. If that occurs often, we may ++ have to employ weighted round-robin or ucode scheme to avoid ++ low priority packet starvation. ++ */ ++ ++ for (ac = AC_COUNT; ac >= 0; ac--) { ++ ++ int initial_credit_count = ctx->FIFO_credit[ac]; ++ ++ /* packets from SENDQ are fresh and they'd need header and have no MAC entry */ ++ commit_info.needs_hdr = 1; ++ commit_info.mac_entry = NULL; ++ commit_info.pkt_type = eWLFC_PKTTYPE_NEW; ++ ++ do { ++ commit_info.p = _dhd_wlfc_deque_sendq(ctx, ac); ++ if (commit_info.p == NULL) ++ break; ++ else if (ETHER_ISMULTI(DHD_PKTTAG_DSTN(PKTTAG(commit_info.p)))) { ++ ASSERT(ac == AC_COUNT); ++ ++ if (ctx->FIFO_credit[ac]) { ++ rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, ++ fcommit, commit_ctx); ++ ++ /* Bus commits may fail (e.g. flow control); abort after retries */ ++ if (rc == BCME_OK) { ++ if (commit_info.ac_fifo_credit_spent) { ++ (void) _dhd_wlfc_borrow_credit(ctx, ++ ac_available, ac); ++ credit_count--; ++ } ++ } else { ++ bus_retry_count++; ++ if (bus_retry_count >= BUS_RETRIES) { ++ AP6211_ERR(" %s: bus error\n", ++ __FUNCTION__); ++ return rc; ++ } ++ } ++ } ++ } ++ ++ } while (commit_info.p); ++ ++ for (credit = 0; credit < ctx->FIFO_credit[ac];) { ++ commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac, ++ &(commit_info.ac_fifo_credit_spent), ++ &(commit_info.needs_hdr), ++ &(commit_info.mac_entry)); ++ ++ if (commit_info.p == NULL) ++ break; ++ ++ commit_info.pkt_type = (commit_info.needs_hdr) ? eWLFC_PKTTYPE_DELAYED : ++ eWLFC_PKTTYPE_SUPPRESSED; ++ ++ rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, ++ fcommit, commit_ctx); ++ ++ /* Bus commits may fail (e.g. flow control); abort after retries */ ++ if (rc == BCME_OK) { ++ if (commit_info.ac_fifo_credit_spent) { ++ credit++; ++ } ++ } ++ else { ++ bus_retry_count++; ++ if (bus_retry_count >= BUS_RETRIES) { ++ AP6211_ERR("dhd_wlfc_commit_packets(): bus error\n"); ++ ctx->FIFO_credit[ac] -= credit; ++ return rc; ++ } ++ } ++ } ++ ++ ctx->FIFO_credit[ac] -= credit; ++ ++ ++ /* If no credits were used, the queue is idle and can be re-used ++ Note that resv credits cannot be borrowed ++ */ ++ if (initial_credit_count == ctx->FIFO_credit[ac]) { ++ ac_available |= (1 << ac); ++ credit_count += ctx->FIFO_credit[ac]; ++ } ++ } ++ ++ /* We borrow only for AC_BE and only if no other traffic seen for DEFER_PERIOD ++ ++ Note that (ac_available & WLFC_AC_BE_TRAFFIC_ONLY) is done to: ++ a) ignore BC/MC for deferring borrow ++ b) ignore AC_BE being available along with other ACs ++ (this should happen only for pure BC/MC traffic) ++ ++ i.e. AC_VI, AC_VO, AC_BK all MUST be available (i.e. no traffic) and ++ we do not care if AC_BE and BC/MC are available or not ++ */ ++ if ((ac_available & WLFC_AC_BE_TRAFFIC_ONLY) == WLFC_AC_BE_TRAFFIC_ONLY) { ++ ++ if (ctx->allow_credit_borrow) { ++ ac = 1; /* Set ac to AC_BE and borrow credits */ ++ } ++ else { ++ int delta; ++ int curr_t = OSL_SYSUPTIME(); ++ ++ if (curr_t > ctx->borrow_defer_timestamp) ++ delta = curr_t - ctx->borrow_defer_timestamp; ++ else ++ delta = 0xffffffff + curr_t - ctx->borrow_defer_timestamp; ++ ++ if (delta >= WLFC_BORROW_DEFER_PERIOD_MS) { ++ /* Reset borrow but defer to next iteration (defensive borrowing) */ ++ ctx->allow_credit_borrow = TRUE; ++ ctx->borrow_defer_timestamp = 0; ++ } ++ return BCME_OK; ++ } ++ } ++ else { ++ /* If we have multiple AC traffic, turn off borrowing, mark time and bail out */ ++ ctx->allow_credit_borrow = FALSE; ++ ctx->borrow_defer_timestamp = OSL_SYSUPTIME(); ++ return BCME_OK; ++ } ++ ++ /* At this point, borrow all credits only for "ac" (which should be set above to AC_BE) ++ Generically use "ac" only in case we extend to all ACs in future ++ */ ++ for (; (credit_count > 0);) { ++ ++ commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac, ++ &(commit_info.ac_fifo_credit_spent), ++ &(commit_info.needs_hdr), ++ &(commit_info.mac_entry)); ++ if (commit_info.p == NULL) ++ break; ++ ++ commit_info.pkt_type = (commit_info.needs_hdr) ? eWLFC_PKTTYPE_DELAYED : ++ eWLFC_PKTTYPE_SUPPRESSED; ++ ++ rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, ++ fcommit, commit_ctx); ++ ++ /* Bus commits may fail (e.g. flow control); abort after retries */ ++ if (rc == BCME_OK) { ++ if (commit_info.ac_fifo_credit_spent) { ++ (void) _dhd_wlfc_borrow_credit(ctx, ac_available, ac); ++ credit_count--; ++ } ++ } ++ else { ++ bus_retry_count++; ++ if (bus_retry_count >= BUS_RETRIES) { ++ AP6211_ERR("dhd_wlfc_commit_packets(): bus error\n"); ++ return rc; ++ } ++ } ++ } ++ ++ return BCME_OK; ++} ++ ++static uint8 ++dhd_wlfc_find_mac_desc_id_from_mac(dhd_pub_t *dhdp, uint8* ea) ++{ ++ wlfc_mac_descriptor_t* table = ++ ((athost_wl_status_info_t*)dhdp->wlfc_state)->destination_entries.nodes; ++ uint8 table_index; ++ ++ if (ea != NULL) { ++ for (table_index = 0; table_index < WLFC_MAC_DESC_TABLE_SIZE; table_index++) { ++ if ((memcmp(ea, &table[table_index].ea[0], ETHER_ADDR_LEN) == 0) && ++ table[table_index].occupied) ++ return table_index; ++ } ++ } ++ return WLFC_MAC_DESC_ID_INVALID; ++} ++ ++void ++dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success, bool wake_locked) ++{ ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ void* p; ++ int fifo_id; ++ ++ if (!wake_locked) ++ dhd_os_wlfc_block(dhd); ++ ++ if (DHD_PKTTAG_SIGNALONLY(PKTTAG(txp))) { ++#ifdef PROP_TXSTATUS_DEBUG ++ wlfc->stats.signal_only_pkts_freed++; ++#endif ++ if (success) ++ /* is this a signal-only packet? */ ++ PKTFREE(wlfc->osh, txp, TRUE); ++ if (!wake_locked) ++ dhd_os_wlfc_unblock(dhd); ++ return; ++ } ++ if (!success) { ++ AP6211_DEBUG("At: %s():%d, bus_complete() failure for %p, htod_tag:0x%08x\n", ++ __FUNCTION__, __LINE__, txp, DHD_PKTTAG_H2DTAG(PKTTAG(txp))); ++ dhd_wlfc_hanger_poppkt(wlfc->hanger, WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG ++ (PKTTAG(txp))), &p, 1); ++ ++ /* indicate failure and free the packet */ ++ dhd_txcomplete(dhd, txp, FALSE); ++ ++ /* return the credit, if necessary */ ++ if (DHD_PKTTAG_CREDITCHECK(PKTTAG(txp))) { ++ int lender, credit_returned = 0; /* Note that borrower is fifo_id */ ++ ++ fifo_id = DHD_PKTTAG_FIFO(PKTTAG(txp)); ++ ++ /* Return credits to highest priority lender first */ ++ for (lender = AC_COUNT; lender >= 0; lender--) { ++ if (wlfc->credits_borrowed[fifo_id][lender] > 0) { ++ wlfc->FIFO_credit[lender]++; ++ wlfc->credits_borrowed[fifo_id][lender]--; ++ credit_returned = 1; ++ break; ++ } ++ } ++ ++ if (!credit_returned) { ++ wlfc->FIFO_credit[fifo_id]++; ++ } ++ } ++ ++ PKTFREE(wlfc->osh, txp, TRUE); ++ } ++ if (!wake_locked) ++ dhd_os_wlfc_unblock(dhd); ++ return; ++} ++ ++static int ++dhd_wlfc_compressed_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info, uint8 len) ++{ ++ uint8 status_flag; ++ uint32 status; ++ int ret; ++ int remove_from_hanger = 1; ++ void* pktbuf; ++ uint8 fifo_id; ++ uint8 count = 0; ++ uint32 status_g; ++ uint32 hslot, hcnt; ++ wlfc_mac_descriptor_t* entry = NULL; ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ ++ memcpy(&status, pkt_info, sizeof(uint32)); ++ status_flag = WL_TXSTATUS_GET_FLAGS(status); ++ status_g = status & 0xff000000; ++ hslot = (status & 0x00ffff00) >> 8; ++ hcnt = status & 0xff; ++ len = pkt_info[4]; ++ ++ wlfc->stats.txstatus_in++; ++ ++ if (status_flag == WLFC_CTL_PKTFLAG_DISCARD) { ++ wlfc->stats.pkt_freed++; ++ } ++ ++ else if (status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) { ++ wlfc->stats.d11_suppress++; ++ remove_from_hanger = 0; ++ } ++ ++ else if (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS) { ++ wlfc->stats.wl_suppress++; ++ remove_from_hanger = 0; ++ } ++ ++ else if (status_flag == WLFC_CTL_PKTFLAG_TOSSED_BYWLC) { ++ wlfc->stats.wlc_tossed_pkts++; ++ } ++ while (count < len) { ++ status = (status_g << 24) | (hslot << 8) | (hcnt); ++ count++; ++ hslot++; ++ hcnt++; ++ ++ ret = dhd_wlfc_hanger_poppkt(wlfc->hanger, ++ WLFC_PKTID_HSLOT_GET(status), &pktbuf, remove_from_hanger); ++ if (ret != BCME_OK) { ++ /* do something */ ++ continue; ++ } ++ ++ entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); ++ ++ if (!remove_from_hanger) { ++ /* this packet was suppressed */ ++ if (!entry->suppressed || entry->generation != WLFC_PKTID_GEN(status)) { ++ entry->suppressed = TRUE; ++ entry->suppress_count = pktq_mlen(&entry->psq, ++ NBITVAL((WL_TXSTATUS_GET_FIFO(status) << 1) + 1)); ++ entry->suppr_transit_count = entry->transit_count; ++ } ++ entry->generation = WLFC_PKTID_GEN(status); ++ } ++ ++#ifdef PROP_TXSTATUS_DEBUG ++ { ++ uint32 new_t = OSL_SYSUPTIME(); ++ uint32 old_t; ++ uint32 delta; ++ old_t = ((wlfc_hanger_t*)(wlfc->hanger))->items[ ++ WLFC_PKTID_HSLOT_GET(status)].push_time; ++ ++ ++ wlfc->stats.latency_sample_count++; ++ if (new_t > old_t) ++ delta = new_t - old_t; ++ else ++ delta = 0xffffffff + new_t - old_t; ++ wlfc->stats.total_status_latency += delta; ++ wlfc->stats.latency_most_recent = delta; ++ ++ wlfc->stats.deltas[wlfc->stats.idx_delta++] = delta; ++ if (wlfc->stats.idx_delta == sizeof(wlfc->stats.deltas)/sizeof(uint32)) ++ wlfc->stats.idx_delta = 0; ++ } ++#endif /* PROP_TXSTATUS_DEBUG */ ++ ++ fifo_id = DHD_PKTTAG_FIFO(PKTTAG(pktbuf)); ++ ++ /* pick up the implicit credit from this packet */ ++ if (DHD_PKTTAG_CREDITCHECK(PKTTAG(pktbuf))) { ++ if (wlfc->proptxstatus_mode == WLFC_FCMODE_IMPLIED_CREDIT) { ++ ++ int lender, credit_returned = 0; /* Note that borrower is fifo_id */ ++ ++ /* Return credits to highest priority lender first */ ++ for (lender = AC_COUNT; lender >= 0; lender--) { ++ if (wlfc->credits_borrowed[fifo_id][lender] > 0) { ++ wlfc->FIFO_credit[lender]++; ++ wlfc->credits_borrowed[fifo_id][lender]--; ++ credit_returned = 1; ++ break; ++ } ++ } ++ ++ if (!credit_returned) { ++ wlfc->FIFO_credit[fifo_id]++; ++ } ++ } ++ } ++ else { ++ /* ++ if this packet did not count against FIFO credit, it must have ++ taken a requested_credit from the destination entry (for pspoll etc.) ++ */ ++ if (!entry) { ++ ++ entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); ++ } ++ if (!DHD_PKTTAG_ONETIMEPKTRQST(PKTTAG(pktbuf))) ++ entry->requested_credit++; ++#ifdef PROP_TXSTATUS_DEBUG ++ entry->dstncredit_acks++; ++#endif ++ } ++ if ((status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) || ++ (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS)) { ++ ++ ret = _dhd_wlfc_enque_suppressed(wlfc, fifo_id, pktbuf); ++ if (ret != BCME_OK) { ++ /* delay q is full, drop this packet */ ++ dhd_wlfc_hanger_poppkt(wlfc->hanger, WLFC_PKTID_HSLOT_GET(status), ++ &pktbuf, 1); ++ ++ /* indicate failure and free the packet */ ++ dhd_txcomplete(dhd, pktbuf, FALSE); ++ entry->transit_count--; ++ /* packet is transmitted Successfully by dongle ++ * after first suppress. ++ */ ++ if (entry->suppressed) { ++ entry->suppr_transit_count--; ++ } ++ PKTFREE(wlfc->osh, pktbuf, TRUE); ++ } else { ++ /* Mark suppressed to avoid a double free during wlfc cleanup */ ++ ++ dhd_wlfc_hanger_mark_suppressed(wlfc->hanger, ++ WLFC_PKTID_HSLOT_GET(status), WLFC_PKTID_GEN(status)); ++ entry->suppress_count++; ++ } ++ } ++ else { ++ dhd_txcomplete(dhd, pktbuf, TRUE); ++ entry->transit_count--; ++ ++ /* This packet is transmitted Successfully by dongle ++ * even after first suppress. ++ */ ++ if (entry->suppressed) { ++ entry->suppr_transit_count--; ++ } ++ /* free the packet */ ++ PKTFREE(wlfc->osh, pktbuf, TRUE); ++ } ++ } ++ return BCME_OK; ++} ++ ++/* Handle discard or suppress indication */ ++static int ++dhd_wlfc_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info) ++{ ++ uint8 status_flag; ++ uint32 status; ++ int ret; ++ int remove_from_hanger = 1; ++ void* pktbuf; ++ uint8 fifo_id; ++ wlfc_mac_descriptor_t* entry = NULL; ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ ++ memcpy(&status, pkt_info, sizeof(uint32)); ++ status_flag = WL_TXSTATUS_GET_FLAGS(status); ++ wlfc->stats.txstatus_in++; ++ ++ if (status_flag == WLFC_CTL_PKTFLAG_DISCARD) { ++ wlfc->stats.pkt_freed++; ++ } ++ ++ else if (status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) { ++ wlfc->stats.d11_suppress++; ++ remove_from_hanger = 0; ++ } ++ ++ else if (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS) { ++ wlfc->stats.wl_suppress++; ++ remove_from_hanger = 0; ++ } ++ ++ else if (status_flag == WLFC_CTL_PKTFLAG_TOSSED_BYWLC) { ++ wlfc->stats.wlc_tossed_pkts++; ++ } ++ ++ ret = dhd_wlfc_hanger_poppkt(wlfc->hanger, ++ WLFC_PKTID_HSLOT_GET(status), &pktbuf, remove_from_hanger); ++ if (ret != BCME_OK) { ++ /* do something */ ++ return ret; ++ } ++ ++ entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); ++ ++ if (!remove_from_hanger) { ++ /* this packet was suppressed */ ++ if (!entry->suppressed || entry->generation != WLFC_PKTID_GEN(status)) { ++ entry->suppressed = TRUE; ++ entry->suppress_count = pktq_mlen(&entry->psq, ++ NBITVAL((WL_TXSTATUS_GET_FIFO(status) << 1) + 1)); ++ entry->suppr_transit_count = entry->transit_count; ++ } ++ entry->generation = WLFC_PKTID_GEN(status); ++ } ++ ++#ifdef PROP_TXSTATUS_DEBUG ++ { ++ uint32 new_t = OSL_SYSUPTIME(); ++ uint32 old_t; ++ uint32 delta; ++ old_t = ((wlfc_hanger_t*)(wlfc->hanger))->items[ ++ WLFC_PKTID_HSLOT_GET(status)].push_time; ++ ++ ++ wlfc->stats.latency_sample_count++; ++ if (new_t > old_t) ++ delta = new_t - old_t; ++ else ++ delta = 0xffffffff + new_t - old_t; ++ wlfc->stats.total_status_latency += delta; ++ wlfc->stats.latency_most_recent = delta; ++ ++ wlfc->stats.deltas[wlfc->stats.idx_delta++] = delta; ++ if (wlfc->stats.idx_delta == sizeof(wlfc->stats.deltas)/sizeof(uint32)) ++ wlfc->stats.idx_delta = 0; ++ } ++#endif /* PROP_TXSTATUS_DEBUG */ ++ ++ fifo_id = DHD_PKTTAG_FIFO(PKTTAG(pktbuf)); ++ ++ /* pick up the implicit credit from this packet */ ++ if (DHD_PKTTAG_CREDITCHECK(PKTTAG(pktbuf))) { ++ if (wlfc->proptxstatus_mode == WLFC_FCMODE_IMPLIED_CREDIT) { ++ ++ int lender, credit_returned = 0; /* Note that borrower is fifo_id */ ++ ++ /* Return credits to highest priority lender first */ ++ for (lender = AC_COUNT; lender >= 0; lender--) { ++ if (wlfc->credits_borrowed[fifo_id][lender] > 0) { ++ wlfc->FIFO_credit[lender]++; ++ wlfc->credits_borrowed[fifo_id][lender]--; ++ credit_returned = 1; ++ break; ++ } ++ } ++ ++ if (!credit_returned) { ++ wlfc->FIFO_credit[fifo_id]++; ++ } ++ } ++ } ++ else { ++ /* ++ if this packet did not count against FIFO credit, it must have ++ taken a requested_credit from the destination entry (for pspoll etc.) ++ */ ++ if (!entry) { ++ ++ entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); ++ } ++ if (!DHD_PKTTAG_ONETIMEPKTRQST(PKTTAG(pktbuf))) ++ entry->requested_credit++; ++#ifdef PROP_TXSTATUS_DEBUG ++ entry->dstncredit_acks++; ++#endif ++ } ++ if ((status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) || ++ (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS)) { ++ ++ ret = _dhd_wlfc_enque_suppressed(wlfc, fifo_id, pktbuf); ++ if (ret != BCME_OK) { ++ /* delay q is full, drop this packet */ ++ dhd_wlfc_hanger_poppkt(wlfc->hanger, WLFC_PKTID_HSLOT_GET(status), ++ &pktbuf, 1); ++ ++ /* indicate failure and free the packet */ ++ dhd_txcomplete(dhd, pktbuf, FALSE); ++ entry->transit_count--; ++ /* This packet is transmitted Successfully by ++ * dongle even after first suppress. ++ */ ++ if (entry->suppressed) { ++ entry->suppr_transit_count--; ++ } ++ PKTFREE(wlfc->osh, pktbuf, TRUE); ++ } else { ++ /* Mark suppressed to avoid a double free during wlfc cleanup */ ++ dhd_wlfc_hanger_mark_suppressed(wlfc->hanger, ++ WLFC_PKTID_HSLOT_GET(status), WLFC_PKTID_GEN(status)); ++ entry->suppress_count++; ++ } ++ } ++ else { ++ dhd_txcomplete(dhd, pktbuf, TRUE); ++ entry->transit_count--; ++ ++ /* This packet is transmitted Successfully by dongle even after first suppress. */ ++ if (entry->suppressed) { ++ entry->suppr_transit_count--; ++ } ++ /* free the packet */ ++ PKTFREE(wlfc->osh, pktbuf, TRUE); ++ } ++ return BCME_OK; ++} ++ ++static int ++dhd_wlfc_fifocreditback_indicate(dhd_pub_t *dhd, uint8* credits) ++{ ++ int i; ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ for (i = 0; i < WLFC_CTL_VALUE_LEN_FIFO_CREDITBACK; i++) { ++#ifdef PROP_TXSTATUS_DEBUG ++ wlfc->stats.fifo_credits_back[i] += credits[i]; ++#endif ++ /* update FIFO credits */ ++ if (wlfc->proptxstatus_mode == WLFC_FCMODE_EXPLICIT_CREDIT) ++ { ++ int lender; /* Note that borrower is i */ ++ ++ /* Return credits to highest priority lender first */ ++ for (lender = AC_COUNT; (lender >= 0) && (credits[i] > 0); lender--) { ++ if (wlfc->credits_borrowed[i][lender] > 0) { ++ if (credits[i] >= wlfc->credits_borrowed[i][lender]) { ++ credits[i] -= wlfc->credits_borrowed[i][lender]; ++ wlfc->FIFO_credit[lender] += ++ wlfc->credits_borrowed[i][lender]; ++ wlfc->credits_borrowed[i][lender] = 0; ++ } ++ else { ++ wlfc->credits_borrowed[i][lender] -= credits[i]; ++ wlfc->FIFO_credit[lender] += credits[i]; ++ credits[i] = 0; ++ } ++ } ++ } ++ ++ /* If we have more credits left over, these must belong to the AC */ ++ if (credits[i] > 0) { ++ wlfc->FIFO_credit[i] += credits[i]; ++ } ++ } ++ } ++ ++ return BCME_OK; ++} ++ ++static int ++dhd_wlfc_dbg_senum_check(dhd_pub_t *dhd, uint8 *value) ++{ ++ uint32 timestamp; ++ ++ (void)dhd; ++ ++ bcopy(&value[2], ×tamp, sizeof(uint32)); ++ AP6211_DEBUG("RXPKT: SEQ: %d, timestamp %d\n", value[1], timestamp); ++ return BCME_OK; ++} ++ ++ ++static int ++dhd_wlfc_rssi_indicate(dhd_pub_t *dhd, uint8* rssi) ++{ ++ (void)dhd; ++ (void)rssi; ++ return BCME_OK; ++} ++ ++static int ++dhd_wlfc_mac_table_update(dhd_pub_t *dhd, uint8* value, uint8 type) ++{ ++ int rc; ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ wlfc_mac_descriptor_t* table; ++ uint8 existing_index; ++ uint8 table_index; ++ uint8 ifid; ++ uint8* ea; ++ ++ AP6211_DEBUG("%s(), mac [%02x:%02x:%02x:%02x:%02x:%02x],%s,idx:%d,id:0x%02x\n", ++ __FUNCTION__, value[2], value[3], value[4], value[5], value[6], value[7], ++ ((type == WLFC_CTL_TYPE_MACDESC_ADD) ? "ADD":"DEL"), ++ WLFC_MAC_DESC_GET_LOOKUP_INDEX(value[0]), value[0]); ++ ++ table = wlfc->destination_entries.nodes; ++ table_index = WLFC_MAC_DESC_GET_LOOKUP_INDEX(value[0]); ++ ifid = value[1]; ++ ea = &value[2]; ++ ++ if (type == WLFC_CTL_TYPE_MACDESC_ADD) { ++ existing_index = dhd_wlfc_find_mac_desc_id_from_mac(dhd, &value[2]); ++ if (existing_index == WLFC_MAC_DESC_ID_INVALID) { ++ /* this MAC entry does not exist, create one */ ++ if (!table[table_index].occupied) { ++ table[table_index].mac_handle = value[0]; ++ rc = _dhd_wlfc_mac_entry_update(wlfc, &table[table_index], ++ eWLFC_MAC_ENTRY_ACTION_ADD, ifid, ++ wlfc->destination_entries.interfaces[ifid].iftype, ++ ea); ++ } ++ else { ++ /* the space should have been empty, but it's not */ ++ wlfc->stats.mac_update_failed++; ++ } ++ } ++ else { ++ /* ++ there is an existing entry, move it to new index ++ if necessary. ++ */ ++ if (existing_index != table_index) { ++ /* if we already have an entry, free the old one */ ++ table[existing_index].occupied = 0; ++ table[existing_index].state = WLFC_STATE_CLOSE; ++ table[existing_index].requested_credit = 0; ++ table[existing_index].interface_id = 0; ++ /* enable after packets are queued-deqeued properly. ++ pktq_flush(dhd->osh, &table[existing_index].psq, FALSE, NULL, 0); ++ */ ++ } ++ } ++ } ++ if (type == WLFC_CTL_TYPE_MACDESC_DEL) { ++ if (table[table_index].occupied) { ++ rc = _dhd_wlfc_mac_entry_update(wlfc, &table[table_index], ++ eWLFC_MAC_ENTRY_ACTION_DEL, ifid, ++ wlfc->destination_entries.interfaces[ifid].iftype, ++ ea); ++ } ++ else { ++ /* the space should have been occupied, but it's not */ ++ wlfc->stats.mac_update_failed++; ++ } ++ } ++ BCM_REFERENCE(rc); ++ return BCME_OK; ++} ++ ++static int ++dhd_wlfc_psmode_update(dhd_pub_t *dhd, uint8* value, uint8 type) ++{ ++ /* Handle PS on/off indication */ ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ wlfc_mac_descriptor_t* table; ++ wlfc_mac_descriptor_t* desc; ++ uint8 mac_handle = value[0]; ++ int i; ++ ++ table = wlfc->destination_entries.nodes; ++ desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; ++ if (desc->occupied) { ++ /* a fresh PS mode should wipe old ps credits? */ ++ desc->requested_credit = 0; ++ if (type == WLFC_CTL_TYPE_MAC_OPEN) { ++ desc->state = WLFC_STATE_OPEN; ++ DHD_WLFC_CTRINC_MAC_OPEN(desc); ++ } ++ else { ++ desc->state = WLFC_STATE_CLOSE; ++ DHD_WLFC_CTRINC_MAC_CLOSE(desc); ++ /* ++ Indicate to firmware if there is any traffic pending. ++ */ ++ for (i = AC_BE; i < AC_COUNT; i++) { ++ _dhd_wlfc_traffic_pending_check(wlfc, desc, i); ++ } ++ } ++ } ++ else { ++ wlfc->stats.psmode_update_failed++; ++ } ++ return BCME_OK; ++} ++ ++static int ++dhd_wlfc_interface_update(dhd_pub_t *dhd, uint8* value, uint8 type) ++{ ++ /* Handle PS on/off indication */ ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ wlfc_mac_descriptor_t* table; ++ uint8 if_id = value[0]; ++ ++ if (if_id < WLFC_MAX_IFNUM) { ++ table = wlfc->destination_entries.interfaces; ++ if (table[if_id].occupied) { ++ if (type == WLFC_CTL_TYPE_INTERFACE_OPEN) { ++ table[if_id].state = WLFC_STATE_OPEN; ++ /* AP6211_DEBUG("INTERFACE[%d] OPEN\n", if_id); */ ++ } ++ else { ++ table[if_id].state = WLFC_STATE_CLOSE; ++ /* AP6211_DEBUG("INTERFACE[%d] CLOSE\n", if_id); */ ++ } ++ return BCME_OK; ++ } ++ } ++ wlfc->stats.interface_update_failed++; ++ ++ return BCME_OK; ++} ++ ++static int ++dhd_wlfc_credit_request(dhd_pub_t *dhd, uint8* value) ++{ ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ wlfc_mac_descriptor_t* table; ++ wlfc_mac_descriptor_t* desc; ++ uint8 mac_handle; ++ uint8 credit; ++ ++ table = wlfc->destination_entries.nodes; ++ mac_handle = value[1]; ++ credit = value[0]; ++ ++ desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; ++ if (desc->occupied) { ++ desc->requested_credit = credit; ++ ++ desc->ac_bitmap = value[2]; ++ } ++ else { ++ wlfc->stats.credit_request_failed++; ++ } ++ return BCME_OK; ++} ++ ++static int ++dhd_wlfc_packet_request(dhd_pub_t *dhd, uint8* value) ++{ ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ wlfc_mac_descriptor_t* table; ++ wlfc_mac_descriptor_t* desc; ++ uint8 mac_handle; ++ uint8 packet_count; ++ ++ table = wlfc->destination_entries.nodes; ++ mac_handle = value[1]; ++ packet_count = value[0]; ++ ++ desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; ++ if (desc->occupied) { ++ desc->requested_packet = packet_count; ++ ++ desc->ac_bitmap = value[2]; ++ } ++ else { ++ wlfc->stats.packet_request_failed++; ++ } ++ return BCME_OK; ++} ++ ++static void ++dhd_wlfc_reorderinfo_indicate(uint8 *val, uint8 len, uchar *info_buf, uint *info_len) ++{ ++ if (info_len) { ++ if (info_buf) { ++ bcopy(val, info_buf, len); ++ *info_len = len; ++ } ++ else ++ *info_len = 0; ++ } ++} ++ ++static int ++dhd_wlfc_parse_header_info(dhd_pub_t *dhd, void* pktbuf, int tlv_hdr_len, uchar *reorder_info_buf, ++ uint *reorder_info_len) ++{ ++ uint8 type, len; ++ uint8* value; ++ uint8* tmpbuf; ++ uint16 remainder = tlv_hdr_len; ++ uint16 processed = 0; ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ tmpbuf = (uint8*)PKTDATA(dhd->osh, pktbuf); ++ if (remainder) { ++ while ((processed < (WLFC_MAX_PENDING_DATALEN * 2)) && (remainder > 0)) { ++ type = tmpbuf[processed]; ++ if (type == WLFC_CTL_TYPE_FILLER) { ++ remainder -= 1; ++ processed += 1; ++ continue; ++ } ++ ++ len = tmpbuf[processed + 1]; ++ value = &tmpbuf[processed + 2]; ++ ++ if (remainder < (2 + len)) ++ break; ++ ++ remainder -= 2 + len; ++ processed += 2 + len; ++ if (type == WLFC_CTL_TYPE_TXSTATUS) ++ dhd_wlfc_txstatus_update(dhd, value); ++ if (type == WLFC_CTL_TYPE_COMP_TXSTATUS) ++ dhd_wlfc_compressed_txstatus_update(dhd, value, len); ++ ++ else if (type == WLFC_CTL_TYPE_HOST_REORDER_RXPKTS) ++ dhd_wlfc_reorderinfo_indicate(value, len, reorder_info_buf, ++ reorder_info_len); ++ else if (type == WLFC_CTL_TYPE_FIFO_CREDITBACK) ++ dhd_wlfc_fifocreditback_indicate(dhd, value); ++ ++ else if (type == WLFC_CTL_TYPE_RSSI) ++ dhd_wlfc_rssi_indicate(dhd, value); ++ ++ else if (type == WLFC_CTL_TYPE_MAC_REQUEST_CREDIT) ++ dhd_wlfc_credit_request(dhd, value); ++ ++ else if (type == WLFC_CTL_TYPE_MAC_REQUEST_PACKET) ++ dhd_wlfc_packet_request(dhd, value); ++ ++ else if ((type == WLFC_CTL_TYPE_MAC_OPEN) || ++ (type == WLFC_CTL_TYPE_MAC_CLOSE)) ++ dhd_wlfc_psmode_update(dhd, value, type); ++ ++ else if ((type == WLFC_CTL_TYPE_MACDESC_ADD) || ++ (type == WLFC_CTL_TYPE_MACDESC_DEL)) ++ dhd_wlfc_mac_table_update(dhd, value, type); ++ ++ else if (type == WLFC_CTL_TYPE_TRANS_ID) ++ dhd_wlfc_dbg_senum_check(dhd, value); ++ ++ else if ((type == WLFC_CTL_TYPE_INTERFACE_OPEN) || ++ (type == WLFC_CTL_TYPE_INTERFACE_CLOSE)) { ++ dhd_wlfc_interface_update(dhd, value, type); ++ } ++ } ++ if (remainder != 0) { ++ /* trouble..., something is not right */ ++ wlfc->stats.tlv_parse_failed++; ++ } ++ } ++ return BCME_OK; ++} ++ ++int ++dhd_wlfc_init(dhd_pub_t *dhd) ++{ ++ char iovbuf[12]; /* Room for "tlv" + '\0' + parameter */ ++ /* enable all signals & indicate host proptxstatus logic is active */ ++ uint32 tlv = dhd->wlfc_enabled? ++ WLFC_FLAGS_RSSI_SIGNALS | ++ WLFC_FLAGS_XONXOFF_SIGNALS | ++ WLFC_FLAGS_CREDIT_STATUS_SIGNALS | ++ WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE | ++ WLFC_FLAGS_HOST_RXRERODER_ACTIVE : 0; ++ /* WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE | WLFC_FLAGS_HOST_RXRERODER_ACTIVE : 0; */ ++ ++ ++ /* ++ try to enable/disable signaling by sending "tlv" iovar. if that fails, ++ fallback to no flow control? Print a message for now. ++ */ ++ ++ /* enable proptxtstatus signaling by default */ ++ bcm_mkiovar("tlv", (char *)&tlv, 4, iovbuf, sizeof(iovbuf)); ++ if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) < 0) { ++ AP6211_ERR("dhd_wlfc_init(): failed to enable/disable bdcv2 tlv signaling\n"); ++ } ++ else { ++ /* ++ Leaving the message for now, it should be removed after a while; once ++ the tlv situation is stable. ++ */ ++ AP6211_DEBUG("dhd_wlfc_init(): successfully %s bdcv2 tlv signaling, %d\n", ++ dhd->wlfc_enabled?"enabled":"disabled", tlv); ++ } ++ return BCME_OK; ++} ++ ++int ++dhd_wlfc_enable(dhd_pub_t *dhd) ++{ ++ int i; ++ athost_wl_status_info_t* wlfc; ++ ++ AP6211_DEBUG("Enter %s\n", __FUNCTION__); ++ ++ if (!dhd->wlfc_enabled || dhd->wlfc_state) ++ return BCME_OK; ++ ++ /* allocate space to track txstatus propagated from firmware */ ++ dhd->wlfc_state = MALLOC(dhd->osh, sizeof(athost_wl_status_info_t)); ++ if (dhd->wlfc_state == NULL) ++ return BCME_NOMEM; ++ ++ /* initialize state space */ ++ wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; ++ memset(wlfc, 0, sizeof(athost_wl_status_info_t)); ++ ++ /* remember osh & dhdp */ ++ wlfc->osh = dhd->osh; ++ wlfc->dhdp = dhd; ++ ++ wlfc->hanger = ++ dhd_wlfc_hanger_create(dhd->osh, WLFC_HANGER_MAXITEMS); ++ if (wlfc->hanger == NULL) { ++ MFREE(dhd->osh, dhd->wlfc_state, sizeof(athost_wl_status_info_t)); ++ dhd->wlfc_state = NULL; ++ return BCME_NOMEM; ++ } ++ ++ /* initialize all interfaces to accept traffic */ ++ for (i = 0; i < WLFC_MAX_IFNUM; i++) { ++ wlfc->hostif_flow_state[i] = OFF; ++ } ++ ++ /* ++ create the SENDQ containing ++ sub-queues for all AC precedences + 1 for bc/mc traffic ++ */ ++ pktq_init(&wlfc->SENDQ, (AC_COUNT + 1), WLFC_SENDQ_LEN); ++ ++ wlfc->destination_entries.other.state = WLFC_STATE_OPEN; ++ /* bc/mc FIFO is always open [credit aside], i.e. b[5] */ ++ wlfc->destination_entries.other.ac_bitmap = 0x1f; ++ wlfc->destination_entries.other.interface_id = 0; ++ ++ wlfc->proptxstatus_mode = WLFC_FCMODE_EXPLICIT_CREDIT; ++ ++ wlfc->allow_credit_borrow = TRUE; ++ wlfc->borrow_defer_timestamp = 0; ++ ++ return BCME_OK; ++} ++ ++/* release all packet resources */ ++void ++dhd_wlfc_cleanup(dhd_pub_t *dhd) ++{ ++ int i; ++ int total_entries; ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ wlfc_mac_descriptor_t* table; ++ wlfc_hanger_t* h; ++ int prec; ++ void *pkt = NULL; ++ struct pktq *txq = NULL; ++ ++ AP6211_DEBUG("Enter %s\n", __FUNCTION__); ++ if (dhd->wlfc_state == NULL) ++ return; ++ /* flush bus->txq */ ++ txq = dhd_bus_txq(dhd->bus); ++ ++ /* any in the hanger? */ ++ h = (wlfc_hanger_t*)wlfc->hanger; ++ total_entries = sizeof(wlfc->destination_entries)/sizeof(wlfc_mac_descriptor_t); ++ /* search all entries, include nodes as well as interfaces */ ++ table = (wlfc_mac_descriptor_t*)&wlfc->destination_entries; ++ ++ for (i = 0; i < total_entries; i++) { ++ if (table[i].occupied) { ++ if (table[i].psq.len) { ++ AP6211_DEBUG("%s(): DELAYQ[%d].len = %d\n", ++ __FUNCTION__, i, table[i].psq.len); ++ /* release packets held in DELAYQ */ ++ pktq_flush(wlfc->osh, &table[i].psq, TRUE, NULL, 0); ++ } ++ table[i].occupied = 0; ++ } ++ } ++ /* release packets held in SENDQ */ ++ if (wlfc->SENDQ.len) ++ pktq_flush(wlfc->osh, &wlfc->SENDQ, TRUE, NULL, 0); ++ for (prec = 0; prec < txq->num_prec; prec++) { ++ pkt = pktq_pdeq(txq, prec); ++ while (pkt) { ++ for (i = 0; i < h->max_items; i++) { ++ if (pkt == h->items[i].pkt) { ++ if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) { ++ PKTFREE(wlfc->osh, h->items[i].pkt, TRUE); ++ h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; ++ h->items[i].pkt = NULL; ++ h->items[i].identifier = 0; ++ } else if (h->items[i].state == ++ WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED) { ++ /* These are already freed from the psq */ ++ h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; ++ } ++ break; ++ } ++ } ++ pkt = pktq_pdeq(txq, prec); ++ } ++ } ++ /* flush remained pkt in hanger queue, not in bus->txq */ ++ for (i = 0; i < h->max_items; i++) { ++ if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) { ++ PKTFREE(wlfc->osh, h->items[i].pkt, TRUE); ++ h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; ++ } else if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED) { ++ /* These are freed from the psq so no need to free again */ ++ h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; ++ } ++ } ++ ++ return; ++} ++ ++void ++dhd_wlfc_deinit(dhd_pub_t *dhd) ++{ ++ /* cleanup all psq related resources */ ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ ++ AP6211_DEBUG("Enter %s\n", __FUNCTION__); ++ ++ dhd_os_wlfc_block(dhd); ++ if (dhd->wlfc_state == NULL) { ++ dhd_os_wlfc_unblock(dhd); ++ return; ++ } ++ ++#ifdef PROP_TXSTATUS_DEBUG ++ { ++ int i; ++ wlfc_hanger_t* h = (wlfc_hanger_t*)wlfc->hanger; ++ for (i = 0; i < h->max_items; i++) { ++ if (h->items[i].state != WLFC_HANGER_ITEM_STATE_FREE) { ++ AP6211_DEBUG("%s() pkt[%d] = 0x%p, FIFO_credit_used:%d\n", ++ __FUNCTION__, i, h->items[i].pkt, ++ DHD_PKTTAG_CREDITCHECK(PKTTAG(h->items[i].pkt))); ++ } ++ } ++ } ++#endif ++ /* delete hanger */ ++ dhd_wlfc_hanger_delete(dhd->osh, wlfc->hanger); ++ ++ /* free top structure */ ++ MFREE(dhd->osh, dhd->wlfc_state, sizeof(athost_wl_status_info_t)); ++ dhd->wlfc_state = NULL; ++ dhd_os_wlfc_unblock(dhd); ++ ++ return; ++} ++#endif /* PROP_TXSTATUS */ ++ ++void ++dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) ++{ ++ bcm_bprintf(strbuf, "Protocol CDC: reqid %d\n", dhdp->prot->reqid); ++#ifdef PROP_TXSTATUS ++ dhd_os_wlfc_block(dhdp); ++ if (dhdp->wlfc_state) ++ dhd_wlfc_dump(dhdp, strbuf); ++ dhd_os_wlfc_unblock(dhdp); ++#endif ++} ++ ++void ++dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *pktbuf) ++{ ++#ifdef BDC ++ struct bdc_header *h; ++#endif /* BDC */ ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++#ifdef BDC ++ /* Push BDC header used to convey priority for buses that don't */ ++ ++ PKTPUSH(dhd->osh, pktbuf, BDC_HEADER_LEN); ++ ++ h = (struct bdc_header *)PKTDATA(dhd->osh, pktbuf); ++ ++ h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); ++ if (PKTSUMNEEDED(pktbuf)) ++ h->flags |= BDC_FLAG_SUM_NEEDED; ++ ++ ++ h->priority = (PKTPRIO(pktbuf) & BDC_PRIORITY_MASK); ++ h->flags2 = 0; ++ h->dataOffset = 0; ++#endif /* BDC */ ++ BDC_SET_IF_IDX(h, ifidx); ++} ++ ++int ++dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf, uchar *reorder_buf_info, ++ uint *reorder_info_len) ++{ ++#ifdef BDC ++ struct bdc_header *h; ++#endif ++ uint8 data_offset = 0; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++#ifdef BDC ++ if (reorder_info_len) ++ *reorder_info_len = 0; ++ /* Pop BDC header used to convey priority for buses that don't */ ++ ++ if (PKTLEN(dhd->osh, pktbuf) < BDC_HEADER_LEN) { ++ AP6211_ERR("%s: rx data too short (%d < %d)\n", __FUNCTION__, ++ PKTLEN(dhd->osh, pktbuf), BDC_HEADER_LEN); ++ return BCME_ERROR; ++ } ++ ++ h = (struct bdc_header *)PKTDATA(dhd->osh, pktbuf); ++ ++#if defined(NDIS630) ++ h->dataOffset = 0; ++#endif ++ ++ if (!ifidx) { ++ /* for tx packet, skip the analysis */ ++ data_offset = h->dataOffset; ++ PKTPULL(dhd->osh, pktbuf, BDC_HEADER_LEN); ++ goto exit; ++ } ++ ++ if ((*ifidx = BDC_GET_IF_IDX(h)) >= DHD_MAX_IFS) { ++ AP6211_ERR("%s: rx data ifnum out of range (%d)\n", ++ __FUNCTION__, *ifidx); ++ return BCME_ERROR; ++ } ++ ++ if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) != BDC_PROTO_VER) { ++ AP6211_ERR("%s: non-BDC packet received, flags = 0x%x\n", ++ dhd_ifname(dhd, *ifidx), h->flags); ++ if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) == BDC_PROTO_VER_1) ++ h->dataOffset = 0; ++ else ++ return BCME_ERROR; ++ } ++ ++ if (h->flags & BDC_FLAG_SUM_GOOD) { ++ AP6211_DEBUG("%s: BDC packet received with good rx-csum, flags 0x%x\n", ++ dhd_ifname(dhd, *ifidx), h->flags); ++ PKTSETSUMGOOD(pktbuf, TRUE); ++ } ++ ++ PKTSETPRIO(pktbuf, (h->priority & BDC_PRIORITY_MASK)); ++ data_offset = h->dataOffset; ++ PKTPULL(dhd->osh, pktbuf, BDC_HEADER_LEN); ++#endif /* BDC */ ++ ++#if !defined(NDIS630) ++ if (PKTLEN(dhd->osh, pktbuf) < (uint32) (data_offset << 2)) { ++ AP6211_ERR("%s: rx data too short (%d < %d)\n", __FUNCTION__, ++ PKTLEN(dhd->osh, pktbuf), (data_offset * 4)); ++ return BCME_ERROR; ++ } ++#endif ++#ifdef PROP_TXSTATUS ++ if (dhd->wlfc_state && ++ ((athost_wl_status_info_t*)dhd->wlfc_state)->proptxstatus_mode ++ != WLFC_FCMODE_NONE && ++ (!DHD_PKTTAG_PKTDIR(PKTTAG(pktbuf)))) { ++ /* ++ - parse txstatus only for packets that came from the firmware ++ */ ++ dhd_os_wlfc_block(dhd); ++ dhd_wlfc_parse_header_info(dhd, pktbuf, (data_offset << 2), ++ reorder_buf_info, reorder_info_len); ++ ((athost_wl_status_info_t*)dhd->wlfc_state)->stats.dhd_hdrpulls++; ++ dhd_os_wlfc_unblock(dhd); ++ } ++#endif /* PROP_TXSTATUS */ ++ ++exit: ++#if !defined(NDIS630) ++ PKTPULL(dhd->osh, pktbuf, (data_offset << 2)); ++#endif ++ return 0; ++} ++ ++#if defined(PROP_TXSTATUS) ++void ++dhd_wlfc_trigger_pktcommit(dhd_pub_t *dhd) ++{ ++ if (dhd->wlfc_state && ++ (((athost_wl_status_info_t*)dhd->wlfc_state)->proptxstatus_mode ++ != WLFC_FCMODE_NONE)) { ++ dhd_os_wlfc_block(dhd); ++ dhd_wlfc_commit_packets(dhd->wlfc_state, (f_commitpkt_t)dhd_bus_txdata, ++ (void *)dhd->bus); ++ dhd_os_wlfc_unblock(dhd); ++ } ++} ++#endif ++ ++int ++dhd_prot_attach(dhd_pub_t *dhd) ++{ ++ dhd_prot_t *cdc; ++ ++ if (!(cdc = (dhd_prot_t *)DHD_OS_PREALLOC(dhd->osh, DHD_PREALLOC_PROT, ++ sizeof(dhd_prot_t)))) { ++ AP6211_ERR("%s: kmalloc failed\n", __FUNCTION__); ++ goto fail; ++ } ++ memset(cdc, 0, sizeof(dhd_prot_t)); ++ ++ /* ensure that the msg buf directly follows the cdc msg struct */ ++ if ((uintptr)(&cdc->msg + 1) != (uintptr)cdc->buf) { ++ AP6211_ERR("dhd_prot_t is not correctly defined\n"); ++ goto fail; ++ } ++ ++ dhd->prot = cdc; ++#ifdef BDC ++ dhd->hdrlen += BDC_HEADER_LEN; ++#endif ++ dhd->maxctl = WLC_IOCTL_MAXLEN + sizeof(cdc_ioctl_t) + ROUND_UP_MARGIN; ++ return 0; ++ ++fail: ++#ifndef CONFIG_DHD_USE_STATIC_BUF ++ if (cdc != NULL) ++ MFREE(dhd->osh, cdc, sizeof(dhd_prot_t)); ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ return BCME_NOMEM; ++} ++ ++/* ~NOTE~ What if another thread is waiting on the semaphore? Holding it? */ ++void ++dhd_prot_detach(dhd_pub_t *dhd) ++{ ++#ifdef PROP_TXSTATUS ++ dhd_wlfc_deinit(dhd); ++#endif ++#ifndef CONFIG_DHD_USE_STATIC_BUF ++ MFREE(dhd->osh, dhd->prot, sizeof(dhd_prot_t)); ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ dhd->prot = NULL; ++} ++ ++void ++dhd_prot_dstats(dhd_pub_t *dhd) ++{ ++ /* No stats from dongle added yet, copy bus stats */ ++ dhd->dstats.tx_packets = dhd->tx_packets; ++ dhd->dstats.tx_errors = dhd->tx_errors; ++ dhd->dstats.rx_packets = dhd->rx_packets; ++ dhd->dstats.rx_errors = dhd->rx_errors; ++ dhd->dstats.rx_dropped = dhd->rx_dropped; ++ dhd->dstats.multicast = dhd->rx_multicast; ++ return; ++} ++ ++int ++dhd_prot_init(dhd_pub_t *dhd) ++{ ++ int ret = 0; ++ wlc_rev_info_t revinfo; ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ ++ /* Get the device rev info */ ++ memset(&revinfo, 0, sizeof(revinfo)); ++ ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_REVINFO, &revinfo, sizeof(revinfo), FALSE, 0); ++ if (ret < 0) ++ goto done; ++ ++ ++#if defined(WL_CFG80211) ++ if (dhd_download_fw_on_driverload) ++#endif /* defined(WL_CFG80211) */ ++ ret = dhd_preinit_ioctls(dhd); ++ ++#ifdef PROP_TXSTATUS ++ ret = dhd_wlfc_init(dhd); ++#endif ++ ++ /* Always assumes wl for now */ ++ dhd->iswl = TRUE; ++ ++done: ++ return ret; ++} ++ ++void ++dhd_prot_stop(dhd_pub_t *dhd) ++{ ++ /* Nothing to do for CDC */ ++} ++ ++ ++static void ++dhd_get_hostreorder_pkts(void *osh, struct reorder_info *ptr, void **pkt, ++ uint32 *pkt_count, void **pplast, uint8 start, uint8 end) ++{ ++ uint i; ++ void *plast = NULL, *p; ++ uint32 pkt_cnt = 0; ++ ++ if (ptr->pend_pkts == 0) { ++ AP6211_DEBUG("%s: no packets in reorder queue \n", __FUNCTION__); ++ *pplast = NULL; ++ *pkt_count = 0; ++ *pkt = NULL; ++ return; ++ } ++ if (start == end) ++ i = ptr->max_idx + 1; ++ else { ++ if (start > end) ++ i = ((ptr->max_idx + 1) - start) + end; ++ else ++ i = end - start; ++ } ++ while (i) { ++ p = (void *)(ptr->p[start]); ++ ptr->p[start] = NULL; ++ ++ if (p != NULL) { ++ if (plast == NULL) ++ *pkt = p; ++ else ++ PKTSETNEXT(osh, plast, p); ++ ++ plast = p; ++ pkt_cnt++; ++ } ++ i--; ++ if (start++ == ptr->max_idx) ++ start = 0; ++ } ++ *pplast = plast; ++ *pkt_count = (uint32)pkt_cnt; ++} ++ ++int ++dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reorder_info_len, ++ void **pkt, uint32 *pkt_count) ++{ ++ uint8 flow_id, max_idx, cur_idx, exp_idx; ++ struct reorder_info *ptr; ++ uint8 flags; ++ void *cur_pkt, *plast = NULL; ++ uint32 cnt = 0; ++ ++ if (pkt == NULL) { ++ if (pkt_count != NULL) ++ *pkt_count = 0; ++ return 0; ++ } ++ ++ flow_id = reorder_info_buf[WLHOST_REORDERDATA_FLOWID_OFFSET]; ++ flags = reorder_info_buf[WLHOST_REORDERDATA_FLAGS_OFFSET]; ++ ++ AP6211_DEBUG("flow_id %d, flags 0x%02x, idx(%d, %d, %d)\n", flow_id, flags, ++ reorder_info_buf[WLHOST_REORDERDATA_CURIDX_OFFSET], ++ reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET], ++ reorder_info_buf[WLHOST_REORDERDATA_MAXIDX_OFFSET]); ++ ++ /* validate flags and flow id */ ++ if (flags == 0xFF) { ++ AP6211_ERR("%s: invalid flags...so ignore this packet\n", __FUNCTION__); ++ *pkt_count = 1; ++ return 0; ++ } ++ ++ cur_pkt = *pkt; ++ *pkt = NULL; ++ ++ ptr = dhd->reorder_bufs[flow_id]; ++ if (flags & WLHOST_REORDERDATA_DEL_FLOW) { ++ uint32 buf_size = sizeof(struct reorder_info); ++ ++ AP6211_DEBUG("%s: Flags indicating to delete a flow id %d\n", ++ __FUNCTION__, flow_id); ++ ++ if (ptr == NULL) { ++ AP6211_ERR("%s: received flags to cleanup, but no flow (%d) yet\n", ++ __FUNCTION__, flow_id); ++ *pkt_count = 1; ++ *pkt = cur_pkt; ++ return 0; ++ } ++ ++ dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, ++ ptr->exp_idx, ptr->exp_idx); ++ /* set it to the last packet */ ++ if (plast) { ++ PKTSETNEXT(dhd->osh, plast, cur_pkt); ++ cnt++; ++ } ++ else { ++ if (cnt != 0) { ++ AP6211_ERR("%s: del flow: something fishy, pending packets %d\n", ++ __FUNCTION__, cnt); ++ } ++ *pkt = cur_pkt; ++ cnt = 1; ++ } ++ buf_size += ((ptr->max_idx + 1) * sizeof(void *)); ++ MFREE(dhd->osh, ptr, buf_size); ++ dhd->reorder_bufs[flow_id] = NULL; ++ *pkt_count = cnt; ++ return 0; ++ } ++ /* all the other cases depend on the existance of the reorder struct for that flow id */ ++ if (ptr == NULL) { ++ uint32 buf_size_alloc = sizeof(reorder_info_t); ++ max_idx = reorder_info_buf[WLHOST_REORDERDATA_MAXIDX_OFFSET]; ++ ++ buf_size_alloc += ((max_idx + 1) * sizeof(void*)); ++ /* allocate space to hold the buffers, index etc */ ++ ++ AP6211_DEBUG("%s: alloc buffer of size %d size, reorder info id %d, maxidx %d\n", ++ __FUNCTION__, buf_size_alloc, flow_id, max_idx); ++ ptr = (struct reorder_info *)MALLOC(dhd->osh, buf_size_alloc); ++ if (ptr == NULL) { ++ AP6211_ERR("%s: Malloc failed to alloc buffer\n", __FUNCTION__); ++ *pkt_count = 1; ++ return 0; ++ } ++ bzero(ptr, buf_size_alloc); ++ dhd->reorder_bufs[flow_id] = ptr; ++ ptr->p = (void *)(ptr+1); ++ ptr->max_idx = max_idx; ++ } ++ if (flags & WLHOST_REORDERDATA_NEW_HOLE) { ++ AP6211_DEBUG("%s: new hole, so cleanup pending buffers\n", __FUNCTION__); ++ if (ptr->pend_pkts) { ++ dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, ++ ptr->exp_idx, ptr->exp_idx); ++ ptr->pend_pkts = 0; ++ } ++ ptr->cur_idx = reorder_info_buf[WLHOST_REORDERDATA_CURIDX_OFFSET]; ++ ptr->exp_idx = reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET]; ++ ptr->max_idx = reorder_info_buf[WLHOST_REORDERDATA_MAXIDX_OFFSET]; ++ ptr->p[ptr->cur_idx] = cur_pkt; ++ ptr->pend_pkts++; ++ *pkt_count = cnt; ++ } ++ else if (flags & WLHOST_REORDERDATA_CURIDX_VALID) { ++ cur_idx = reorder_info_buf[WLHOST_REORDERDATA_CURIDX_OFFSET]; ++ exp_idx = reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET]; ++ ++ ++ if ((exp_idx == ptr->exp_idx) && (cur_idx != ptr->exp_idx)) { ++ /* still in the current hole */ ++ /* enqueue the current on the buffer chain */ ++ if (ptr->p[cur_idx] != NULL) { ++ AP6211_DEBUG("%s: HOLE: ERROR buffer pending..free it\n", ++ __FUNCTION__); ++ PKTFREE(dhd->osh, ptr->p[cur_idx], TRUE); ++ ptr->p[cur_idx] = NULL; ++ } ++ ptr->p[cur_idx] = cur_pkt; ++ ptr->pend_pkts++; ++ ptr->cur_idx = cur_idx; ++ AP6211_DEBUG("%s: fill up a hole..pending packets is %d\n", ++ __FUNCTION__, ptr->pend_pkts); ++ *pkt_count = 0; ++ *pkt = NULL; ++ } ++ else if (ptr->exp_idx == cur_idx) { ++ /* got the right one ..flush from cur to exp and update exp */ ++ AP6211_DEBUG("%s: got the right one now, cur_idx is %d\n", ++ __FUNCTION__, cur_idx); ++ if (ptr->p[cur_idx] != NULL) { ++ AP6211_DEBUG("%s: Error buffer pending..free it\n", ++ __FUNCTION__); ++ PKTFREE(dhd->osh, ptr->p[cur_idx], TRUE); ++ ptr->p[cur_idx] = NULL; ++ } ++ ptr->p[cur_idx] = cur_pkt; ++ ptr->pend_pkts++; ++ ++ ptr->cur_idx = cur_idx; ++ ptr->exp_idx = exp_idx; ++ ++ dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, ++ cur_idx, exp_idx); ++ ptr->pend_pkts -= (uint8)cnt; ++ *pkt_count = cnt; ++ AP6211_DEBUG("%s: freeing up buffers %d, still pending %d\n", ++ __FUNCTION__, cnt, ptr->pend_pkts); ++ } ++ else { ++ uint8 end_idx; ++ bool flush_current = FALSE; ++ /* both cur and exp are moved now .. */ ++ AP6211_DEBUG("%s:, flow %d, both moved, cur %d(%d), exp %d(%d)\n", ++ __FUNCTION__, flow_id, ptr->cur_idx, cur_idx, ++ ptr->exp_idx, exp_idx); ++ if (flags & WLHOST_REORDERDATA_FLUSH_ALL) ++ end_idx = ptr->exp_idx; ++ else ++ end_idx = exp_idx; ++ ++ /* flush pkts first */ ++ dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, ++ ptr->exp_idx, end_idx); ++ ++ if (cur_idx == ptr->max_idx) { ++ if (exp_idx == 0) ++ flush_current = TRUE; ++ } else { ++ if (exp_idx == cur_idx + 1) ++ flush_current = TRUE; ++ } ++ if (flush_current) { ++ if (plast) ++ PKTSETNEXT(dhd->osh, plast, cur_pkt); ++ else ++ *pkt = cur_pkt; ++ cnt++; ++ } ++ else { ++ ptr->p[cur_idx] = cur_pkt; ++ ptr->pend_pkts++; ++ } ++ ptr->exp_idx = exp_idx; ++ ptr->cur_idx = cur_idx; ++ *pkt_count = cnt; ++ } ++ } ++ else { ++ uint8 end_idx; ++ /* no real packet but update to exp_seq...that means explicit window move */ ++ exp_idx = reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET]; ++ ++ AP6211_DEBUG("%s: move the window, cur_idx is %d, exp is %d, new exp is %d\n", ++ __FUNCTION__, ptr->cur_idx, ptr->exp_idx, exp_idx); ++ if (flags & WLHOST_REORDERDATA_FLUSH_ALL) ++ end_idx = ptr->exp_idx; ++ else ++ end_idx = exp_idx; ++ ++ dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, ptr->exp_idx, end_idx); ++ ptr->pend_pkts -= (uint8)cnt; ++ if (plast) ++ PKTSETNEXT(dhd->osh, plast, cur_pkt); ++ else ++ *pkt = cur_pkt; ++ cnt++; ++ *pkt_count = cnt; ++ /* set the new expected idx */ ++ ptr->exp_idx = exp_idx; ++ } ++ return 0; ++} +diff --git a/drivers/net/wireless/ap6211/dhd_cfg80211.c b/drivers/net/wireless/ap6211/dhd_cfg80211.c +new file mode 100755 +index 0000000..8cb440e +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_cfg80211.c +@@ -0,0 +1,680 @@ ++/* ++ * Linux cfg80211 driver - Dongle Host Driver (DHD) related ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: wl_cfg80211.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $ ++ */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++ ++#ifdef PKT_FILTER_SUPPORT ++#include ++#include ++#endif ++ ++extern struct wl_priv *wlcfg_drv_priv; ++ ++#ifdef PKT_FILTER_SUPPORT ++extern uint dhd_pkt_filter_enable; ++extern uint dhd_master_mode; ++extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode); ++#endif ++ ++static int dhd_dongle_up = FALSE; ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++static s32 wl_dongle_up(struct net_device *ndev, u32 up); ++ ++/** ++ * Function implementations ++ */ ++ ++s32 dhd_cfg80211_init(struct wl_priv *wl) ++{ ++ dhd_dongle_up = FALSE; ++ return 0; ++} ++ ++s32 dhd_cfg80211_deinit(struct wl_priv *wl) ++{ ++ dhd_dongle_up = FALSE; ++ return 0; ++} ++ ++s32 dhd_cfg80211_down(struct wl_priv *wl) ++{ ++ dhd_dongle_up = FALSE; ++ return 0; ++} ++ ++s32 dhd_cfg80211_set_p2p_info(struct wl_priv *wl, int val) ++{ ++ dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); ++ dhd->op_mode |= val; ++ AP6211_ERR("Set : op_mode=0x%04x\n", dhd->op_mode); ++#ifdef ARP_OFFLOAD_SUPPORT ++ if (dhd->arp_version == 1) { ++ /* IF P2P is enabled, disable arpoe */ ++ dhd_arp_offload_set(dhd, 0); ++ dhd_arp_offload_enable(dhd, false); ++ } ++#endif /* ARP_OFFLOAD_SUPPORT */ ++ ++ return 0; ++} ++ ++s32 dhd_cfg80211_clean_p2p_info(struct wl_priv *wl) ++{ ++ dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); ++ dhd->op_mode &= ~(DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE); ++ AP6211_ERR("Clean : op_mode=0x%04x\n", dhd->op_mode); ++ ++#ifdef ARP_OFFLOAD_SUPPORT ++ if (dhd->arp_version == 1) { ++ /* IF P2P is disabled, enable arpoe back for STA mode. */ ++ dhd_arp_offload_set(dhd, dhd_arp_mode); ++ dhd_arp_offload_enable(dhd, true); ++ } ++#endif /* ARP_OFFLOAD_SUPPORT */ ++ ++ return 0; ++} ++ ++static s32 wl_dongle_up(struct net_device *ndev, u32 up) ++{ ++ s32 err = 0; ++ ++ err = wldev_ioctl(ndev, WLC_UP, &up, sizeof(up), true); ++ if (unlikely(err)) { ++ AP6211_ERR("WLC_UP error (%d)\n", err); ++ } ++ return err; ++} ++s32 dhd_config_dongle(struct wl_priv *wl, bool need_lock) ++{ ++#ifndef DHD_SDALIGN ++#define DHD_SDALIGN 32 ++#endif ++ struct net_device *ndev; ++ s32 err = 0; ++ ++ AP6211_DEBUG("In\n"); ++ if (dhd_dongle_up) { ++ AP6211_ERR("Dongle is already up\n"); ++ return err; ++ } ++ ++ ndev = wl_to_prmry_ndev(wl); ++ ++ if (need_lock) ++ rtnl_lock(); ++ ++ err = wl_dongle_up(ndev, 0); ++ if (unlikely(err)) { ++ AP6211_ERR("wl_dongle_up failed\n"); ++ goto default_conf_out; ++ } ++ dhd_dongle_up = true; ++ ++default_conf_out: ++ if (need_lock) ++ rtnl_unlock(); ++ return err; ++ ++} ++ ++ ++/* TODO: clean up the BT-Coex code, it still have some legacy ioctl/iovar functions */ ++#define COEX_DHCP ++ ++#if defined(COEX_DHCP) ++ ++/* use New SCO/eSCO smart YG suppression */ ++#define BT_DHCP_eSCO_FIX ++/* this flag boost wifi pkt priority to max, caution: -not fair to sco */ ++#define BT_DHCP_USE_FLAGS ++/* T1 start SCO/ESCo priority suppression */ ++#define BT_DHCP_OPPR_WIN_TIME 2500 ++/* T2 turn off SCO/SCO supperesion is (timeout) */ ++#define BT_DHCP_FLAG_FORCE_TIME 5500 ++ ++enum wl_cfg80211_btcoex_status { ++ BT_DHCP_IDLE, ++ BT_DHCP_START, ++ BT_DHCP_OPPR_WIN, ++ BT_DHCP_FLAG_FORCE_TIMEOUT ++}; ++ ++/* ++ * get named driver variable to uint register value and return error indication ++ * calling example: dev_wlc_intvar_get_reg(dev, "btc_params",66, ®_value) ++ */ ++static int ++dev_wlc_intvar_get_reg(struct net_device *dev, char *name, ++ uint reg, int *retval) ++{ ++ union { ++ char buf[WLC_IOCTL_SMLEN]; ++ int val; ++ } var; ++ int error; ++ ++ bcm_mkiovar(name, (char *)(®), sizeof(reg), ++ (char *)(&var), sizeof(var.buf)); ++ error = wldev_ioctl(dev, WLC_GET_VAR, (char *)(&var), sizeof(var.buf), false); ++ ++ *retval = dtoh32(var.val); ++ return (error); ++} ++ ++static int ++dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len) ++{ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) ++ char ioctlbuf_local[1024]; ++#else ++ static char ioctlbuf_local[1024]; ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ ++ ++ bcm_mkiovar(name, buf, len, ioctlbuf_local, sizeof(ioctlbuf_local)); ++ ++ return (wldev_ioctl(dev, WLC_SET_VAR, ioctlbuf_local, sizeof(ioctlbuf_local), true)); ++} ++/* ++get named driver variable to uint register value and return error indication ++calling example: dev_wlc_intvar_set_reg(dev, "btc_params",66, value) ++*/ ++static int ++dev_wlc_intvar_set_reg(struct net_device *dev, char *name, char *addr, char * val) ++{ ++ char reg_addr[8]; ++ ++ memset(reg_addr, 0, sizeof(reg_addr)); ++ memcpy((char *)®_addr[0], (char *)addr, 4); ++ memcpy((char *)®_addr[4], (char *)val, 4); ++ ++ return (dev_wlc_bufvar_set(dev, name, (char *)®_addr[0], sizeof(reg_addr))); ++} ++ ++static bool btcoex_is_sco_active(struct net_device *dev) ++{ ++ int ioc_res = 0; ++ bool res = FALSE; ++ int sco_id_cnt = 0; ++ int param27; ++ int i; ++ ++ for (i = 0; i < 12; i++) { ++ ++ ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 27, ¶m27); ++ ++ AP6211_DEBUG("%s, sample[%d], btc params: 27:%x\n", ++ __FUNCTION__, i, param27); ++ ++ if (ioc_res < 0) { ++ AP6211_ERR("%s ioc read btc params error\n", __FUNCTION__); ++ break; ++ } ++ ++ if ((param27 & 0x6) == 2) { /* count both sco & esco */ ++ sco_id_cnt++; ++ } ++ ++ if (sco_id_cnt > 2) { ++ AP6211_DEBUG("%s, sco/esco detected, pkt id_cnt:%d samples:%d\n", ++ __FUNCTION__, sco_id_cnt, i); ++ res = TRUE; ++ break; ++ } ++ ++ msleep(5); ++ } ++ ++ return res; ++} ++ ++#if defined(BT_DHCP_eSCO_FIX) ++/* Enhanced BT COEX settings for eSCO compatibility during DHCP window */ ++static int set_btc_esco_params(struct net_device *dev, bool trump_sco) ++{ ++ static bool saved_status = FALSE; ++ ++ char buf_reg50va_dhcp_on[8] = ++ { 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 }; ++ char buf_reg51va_dhcp_on[8] = ++ { 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; ++ char buf_reg64va_dhcp_on[8] = ++ { 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; ++ char buf_reg65va_dhcp_on[8] = ++ { 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; ++ char buf_reg71va_dhcp_on[8] = ++ { 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; ++ uint32 regaddr; ++ static uint32 saved_reg50; ++ static uint32 saved_reg51; ++ static uint32 saved_reg64; ++ static uint32 saved_reg65; ++ static uint32 saved_reg71; ++ ++ if (trump_sco) { ++ /* this should reduce eSCO agressive retransmit ++ * w/o breaking it ++ */ ++ ++ /* 1st save current */ ++ AP6211_DEBUG("Do new SCO/eSCO coex algo {save &" ++ "override}\n"); ++ if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50, &saved_reg50)) && ++ (!dev_wlc_intvar_get_reg(dev, "btc_params", 51, &saved_reg51)) && ++ (!dev_wlc_intvar_get_reg(dev, "btc_params", 64, &saved_reg64)) && ++ (!dev_wlc_intvar_get_reg(dev, "btc_params", 65, &saved_reg65)) && ++ (!dev_wlc_intvar_get_reg(dev, "btc_params", 71, &saved_reg71))) { ++ saved_status = TRUE; ++ AP6211_DEBUG("%s saved bt_params[50,51,64,65,71]:" ++ "0x%x 0x%x 0x%x 0x%x 0x%x\n", ++ __FUNCTION__, saved_reg50, saved_reg51, ++ saved_reg64, saved_reg65, saved_reg71); ++ } else { ++ AP6211_ERR(":%s: save btc_params failed\n", ++ __FUNCTION__); ++ saved_status = FALSE; ++ return -1; ++ } ++ ++ AP6211_DEBUG("override with [50,51,64,65,71]:" ++ "0x%x 0x%x 0x%x 0x%x 0x%x\n", ++ *(u32 *)(buf_reg50va_dhcp_on+4), ++ *(u32 *)(buf_reg51va_dhcp_on+4), ++ *(u32 *)(buf_reg64va_dhcp_on+4), ++ *(u32 *)(buf_reg65va_dhcp_on+4), ++ *(u32 *)(buf_reg71va_dhcp_on+4)); ++ ++ dev_wlc_bufvar_set(dev, "btc_params", ++ (char *)&buf_reg50va_dhcp_on[0], 8); ++ dev_wlc_bufvar_set(dev, "btc_params", ++ (char *)&buf_reg51va_dhcp_on[0], 8); ++ dev_wlc_bufvar_set(dev, "btc_params", ++ (char *)&buf_reg64va_dhcp_on[0], 8); ++ dev_wlc_bufvar_set(dev, "btc_params", ++ (char *)&buf_reg65va_dhcp_on[0], 8); ++ dev_wlc_bufvar_set(dev, "btc_params", ++ (char *)&buf_reg71va_dhcp_on[0], 8); ++ ++ saved_status = TRUE; ++ } else if (saved_status) { ++ /* restore previously saved bt params */ ++ AP6211_DEBUG("Do new SCO/eSCO coex algo {save &" ++ "override}\n"); ++ ++ regaddr = 50; ++ dev_wlc_intvar_set_reg(dev, "btc_params", ++ (char *)®addr, (char *)&saved_reg50); ++ regaddr = 51; ++ dev_wlc_intvar_set_reg(dev, "btc_params", ++ (char *)®addr, (char *)&saved_reg51); ++ regaddr = 64; ++ dev_wlc_intvar_set_reg(dev, "btc_params", ++ (char *)®addr, (char *)&saved_reg64); ++ regaddr = 65; ++ dev_wlc_intvar_set_reg(dev, "btc_params", ++ (char *)®addr, (char *)&saved_reg65); ++ regaddr = 71; ++ dev_wlc_intvar_set_reg(dev, "btc_params", ++ (char *)®addr, (char *)&saved_reg71); ++ ++ AP6211_DEBUG("restore bt_params[50,51,64,65,71]:" ++ "0x%x 0x%x 0x%x 0x%x 0x%x\n", ++ saved_reg50, saved_reg51, saved_reg64, ++ saved_reg65, saved_reg71); ++ ++ saved_status = FALSE; ++ } else { ++ AP6211_ERR(":%s att to restore not saved BTCOEX params\n", ++ __FUNCTION__); ++ return -1; ++ } ++ return 0; ++} ++#endif /* BT_DHCP_eSCO_FIX */ ++ ++static void ++wl_cfg80211_bt_setflag(struct net_device *dev, bool set) ++{ ++#if defined(BT_DHCP_USE_FLAGS) ++ char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 }; ++ char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00}; ++#endif ++ ++ ++#if defined(BT_DHCP_eSCO_FIX) ++ /* set = 1, save & turn on 0 - off & restore prev settings */ ++ set_btc_esco_params(dev, set); ++#endif ++ ++#if defined(BT_DHCP_USE_FLAGS) ++ AP6211_DEBUG("WI-FI priority boost via bt flags, set:%d\n", set); ++ if (set == TRUE) ++ /* Forcing bt_flag7 */ ++ dev_wlc_bufvar_set(dev, "btc_flags", ++ (char *)&buf_flag7_dhcp_on[0], ++ sizeof(buf_flag7_dhcp_on)); ++ else ++ /* Restoring default bt flag7 */ ++ dev_wlc_bufvar_set(dev, "btc_flags", ++ (char *)&buf_flag7_default[0], ++ sizeof(buf_flag7_default)); ++#endif ++} ++ ++static void wl_cfg80211_bt_timerfunc(ulong data) ++{ ++ struct btcoex_info *bt_local = (struct btcoex_info *)data; ++ AP6211_DEBUG("%s\n", __FUNCTION__); ++ bt_local->timer_on = 0; ++ schedule_work(&bt_local->work); ++} ++ ++static void wl_cfg80211_bt_handler(struct work_struct *work) ++{ ++ struct btcoex_info *btcx_inf; ++ ++ btcx_inf = container_of(work, struct btcoex_info, work); ++ ++ if (btcx_inf->timer_on) { ++ btcx_inf->timer_on = 0; ++ del_timer_sync(&btcx_inf->timer); ++ } ++ ++ switch (btcx_inf->bt_state) { ++ case BT_DHCP_START: ++ /* DHCP started ++ * provide OPPORTUNITY window to get DHCP address ++ */ ++ AP6211_DEBUG("%s bt_dhcp stm: started \n", ++ __FUNCTION__); ++ btcx_inf->bt_state = BT_DHCP_OPPR_WIN; ++ mod_timer(&btcx_inf->timer, ++ jiffies + msecs_to_jiffies(BT_DHCP_OPPR_WIN_TIME)); ++ btcx_inf->timer_on = 1; ++ break; ++ ++ case BT_DHCP_OPPR_WIN: ++ if (btcx_inf->dhcp_done) { ++ AP6211_DEBUG("%s DHCP Done before T1 expiration\n", ++ __FUNCTION__); ++ goto btc_coex_idle; ++ } ++ ++ /* DHCP is not over yet, start lowering BT priority ++ * enforce btc_params + flags if necessary ++ */ ++ AP6211_DEBUG("%s DHCP T1:%d expired\n", __FUNCTION__, ++ BT_DHCP_OPPR_WIN_TIME); ++ if (btcx_inf->dev) ++ wl_cfg80211_bt_setflag(btcx_inf->dev, TRUE); ++ btcx_inf->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT; ++ mod_timer(&btcx_inf->timer, ++ jiffies + msecs_to_jiffies(BT_DHCP_FLAG_FORCE_TIME)); ++ btcx_inf->timer_on = 1; ++ break; ++ ++ case BT_DHCP_FLAG_FORCE_TIMEOUT: ++ if (btcx_inf->dhcp_done) { ++ AP6211_DEBUG("%s DHCP Done before T2 expiration\n", ++ __FUNCTION__); ++ } else { ++ /* Noo dhcp during T1+T2, restore BT priority */ ++ AP6211_DEBUG("%s DHCP wait interval T2:%d" ++ "msec expired\n", __FUNCTION__, ++ BT_DHCP_FLAG_FORCE_TIME); ++ } ++ ++ /* Restoring default bt priority */ ++ if (btcx_inf->dev) ++ wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE); ++btc_coex_idle: ++ btcx_inf->bt_state = BT_DHCP_IDLE; ++ btcx_inf->timer_on = 0; ++ break; ++ ++ default: ++ AP6211_ERR("%s error g_status=%d !!!\n", __FUNCTION__, ++ btcx_inf->bt_state); ++ if (btcx_inf->dev) ++ wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE); ++ btcx_inf->bt_state = BT_DHCP_IDLE; ++ btcx_inf->timer_on = 0; ++ break; ++ } ++ ++ net_os_wake_unlock(btcx_inf->dev); ++} ++ ++int wl_cfg80211_btcoex_init(struct wl_priv *wl) ++{ ++ struct btcoex_info *btco_inf = NULL; ++ ++ btco_inf = kmalloc(sizeof(struct btcoex_info), GFP_KERNEL); ++ if (!btco_inf) ++ return -ENOMEM; ++ ++ btco_inf->bt_state = BT_DHCP_IDLE; ++ btco_inf->ts_dhcp_start = 0; ++ btco_inf->ts_dhcp_ok = 0; ++ /* Set up timer for BT */ ++ btco_inf->timer_ms = 10; ++ init_timer(&btco_inf->timer); ++ btco_inf->timer.data = (ulong)btco_inf; ++ btco_inf->timer.function = wl_cfg80211_bt_timerfunc; ++ ++ btco_inf->dev = wl->wdev->netdev; ++ ++ INIT_WORK(&btco_inf->work, wl_cfg80211_bt_handler); ++ ++ wl->btcoex_info = btco_inf; ++ return 0; ++} ++ ++void wl_cfg80211_btcoex_deinit(struct wl_priv *wl) ++{ ++ if (!wl->btcoex_info) ++ return; ++ ++ if (wl->btcoex_info->timer_on) { ++ wl->btcoex_info->timer_on = 0; ++ del_timer_sync(&wl->btcoex_info->timer); ++ } ++ ++ cancel_work_sync(&wl->btcoex_info->work); ++ ++ kfree(wl->btcoex_info); ++ wl->btcoex_info = NULL; ++} ++#endif ++ ++int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command) ++{ ++ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ char powermode_val = 0; ++ char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 }; ++ char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 }; ++ char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 }; ++ ++ uint32 regaddr; ++ static uint32 saved_reg66; ++ static uint32 saved_reg41; ++ static uint32 saved_reg68; ++ static bool saved_status = FALSE; ++ ++#ifdef COEX_DHCP ++ char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00}; ++ struct btcoex_info *btco_inf = wl->btcoex_info; ++#endif /* COEX_DHCP */ ++ ++#ifdef PKT_FILTER_SUPPORT ++ dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); ++#endif ++ ++ /* Figure out powermode 1 or o command */ ++ strncpy((char *)&powermode_val, command + strlen("BTCOEXMODE") +1, 1); ++ ++ if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) { ++ AP6211_DEBUG("%s: DHCP session starts\n", __FUNCTION__); ++ ++#if defined(DHCP_SCAN_SUPPRESS) ++ /* Suppress scan during the DHCP */ ++ wl_cfg80211_scan_suppress(dev, 1); ++#endif /* OEM_ANDROID */ ++ ++#ifdef PKT_FILTER_SUPPORT ++ dhd->dhcp_in_progress = 1; ++ ++ if (dhd->early_suspended) { ++ AP6211_DEBUG("DHCP in progressing , disable packet filter!!!\n"); ++ dhd_enable_packet_filter(0, dhd); ++ } ++#endif ++ ++ /* Retrieve and saved orig regs value */ ++ if ((saved_status == FALSE) && ++ (!dev_wlc_intvar_get_reg(dev, "btc_params", 66, &saved_reg66)) && ++ (!dev_wlc_intvar_get_reg(dev, "btc_params", 41, &saved_reg41)) && ++ (!dev_wlc_intvar_get_reg(dev, "btc_params", 68, &saved_reg68))) { ++ saved_status = TRUE; ++ AP6211_DEBUG("Saved 0x%x 0x%x 0x%x\n", ++ saved_reg66, saved_reg41, saved_reg68); ++ ++ /* Disable PM mode during dhpc session */ ++ ++ /* Disable PM mode during dhpc session */ ++#ifdef COEX_DHCP ++ /* Start BT timer only for SCO connection */ ++ if (btcoex_is_sco_active(dev)) { ++ /* btc_params 66 */ ++ dev_wlc_bufvar_set(dev, "btc_params", ++ (char *)&buf_reg66va_dhcp_on[0], ++ sizeof(buf_reg66va_dhcp_on)); ++ /* btc_params 41 0x33 */ ++ dev_wlc_bufvar_set(dev, "btc_params", ++ (char *)&buf_reg41va_dhcp_on[0], ++ sizeof(buf_reg41va_dhcp_on)); ++ /* btc_params 68 0x190 */ ++ dev_wlc_bufvar_set(dev, "btc_params", ++ (char *)&buf_reg68va_dhcp_on[0], ++ sizeof(buf_reg68va_dhcp_on)); ++ saved_status = TRUE; ++ ++ btco_inf->bt_state = BT_DHCP_START; ++ btco_inf->timer_on = 1; ++ mod_timer(&btco_inf->timer, btco_inf->timer.expires); ++ AP6211_DEBUG("%s enable BT DHCP Timer\n", ++ __FUNCTION__); ++ } ++#endif /* COEX_DHCP */ ++ } ++ else if (saved_status == TRUE) { ++ AP6211_ERR("%s was called w/o DHCP OFF. Continue\n", __FUNCTION__); ++ } ++ } ++ else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) { ++ ++ ++#ifdef PKT_FILTER_SUPPORT ++ dhd->dhcp_in_progress = 0; ++ AP6211_DEBUG("%s: DHCP is complete \n", __FUNCTION__); ++ ++#if defined(DHCP_SCAN_SUPPRESS) ++ /* Since DHCP is complete, enable the scan back */ ++ wl_cfg80211_scan_suppress(dev, 0); ++#endif /* OEM_ANDROID */ ++ ++ /* Enable packet filtering */ ++ if (dhd->early_suspended) { ++ AP6211_DEBUG("DHCP is complete , enable packet filter!!!\n"); ++ dhd_enable_packet_filter(1, dhd); ++ } ++#endif /* PKT_FILTER_SUPPORT */ ++ ++ /* Restoring PM mode */ ++ ++#ifdef COEX_DHCP ++ /* Stop any bt timer because DHCP session is done */ ++ AP6211_DEBUG("%s disable BT DHCP Timer\n", __FUNCTION__); ++ if (btco_inf->timer_on) { ++ btco_inf->timer_on = 0; ++ del_timer_sync(&btco_inf->timer); ++ ++ if (btco_inf->bt_state != BT_DHCP_IDLE) { ++ /* need to restore original btc flags & extra btc params */ ++ AP6211_DEBUG("%s bt->bt_state:%d\n", ++ __FUNCTION__, btco_inf->bt_state); ++ /* wake up btcoex thread to restore btlags+params */ ++ schedule_work(&btco_inf->work); ++ } ++ } ++ ++ /* Restoring btc_flag paramter anyway */ ++ if (saved_status == TRUE) ++ dev_wlc_bufvar_set(dev, "btc_flags", ++ (char *)&buf_flag7_default[0], sizeof(buf_flag7_default)); ++#endif /* COEX_DHCP */ ++ ++ /* Restore original values */ ++ if (saved_status == TRUE) { ++ regaddr = 66; ++ dev_wlc_intvar_set_reg(dev, "btc_params", ++ (char *)®addr, (char *)&saved_reg66); ++ regaddr = 41; ++ dev_wlc_intvar_set_reg(dev, "btc_params", ++ (char *)®addr, (char *)&saved_reg41); ++ regaddr = 68; ++ dev_wlc_intvar_set_reg(dev, "btc_params", ++ (char *)®addr, (char *)&saved_reg68); ++ ++ AP6211_DEBUG("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n", ++ saved_reg66, saved_reg41, saved_reg68); ++ } ++ saved_status = FALSE; ++ ++ } ++ else { ++ AP6211_ERR("%s Unkwown yet power setting, ignored\n", ++ __FUNCTION__); ++ } ++ ++ snprintf(command, 3, "OK"); ++ ++ return (strlen("OK")); ++} +diff --git a/drivers/net/wireless/ap6211/dhd_cfg80211.h b/drivers/net/wireless/ap6211/dhd_cfg80211.h +new file mode 100755 +index 0000000..922d6ed +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_cfg80211.h +@@ -0,0 +1,44 @@ ++/* ++ * Linux cfg80211 driver - Dongle Host Driver (DHD) related ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: wl_cfg80211.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $ ++ */ ++ ++ ++#ifndef __DHD_CFG80211__ ++#define __DHD_CFG80211__ ++ ++#include ++#include ++ ++s32 dhd_cfg80211_init(struct wl_priv *wl); ++s32 dhd_cfg80211_deinit(struct wl_priv *wl); ++s32 dhd_cfg80211_down(struct wl_priv *wl); ++s32 dhd_cfg80211_set_p2p_info(struct wl_priv *wl, int val); ++s32 dhd_cfg80211_clean_p2p_info(struct wl_priv *wl); ++s32 dhd_config_dongle(struct wl_priv *wl, bool need_lock); ++ ++int wl_cfg80211_btcoex_init(struct wl_priv *wl); ++void wl_cfg80211_btcoex_deinit(struct wl_priv *wl); ++ ++#endif /* __DHD_CFG80211__ */ +diff --git a/drivers/net/wireless/ap6211/dhd_common.c b/drivers/net/wireless/ap6211/dhd_common.c +new file mode 100755 +index 0000000..96c021f +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_common.c +@@ -0,0 +1,2255 @@ ++/* ++ * Broadcom Dongle Host Driver (DHD), common DHD core. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd_common.c 373873 2012-12-10 20:45:58Z $ ++ */ ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++#include ++ ++#ifdef WL_CFG80211 ++#include ++#endif ++#ifdef WLBTAMP ++#include ++#include ++#endif ++#ifdef SET_RANDOM_MAC_SOFTAP ++#include ++#include ++#endif ++ ++#define htod32(i) i ++#define htod16(i) i ++#define dtoh32(i) i ++#define dtoh16(i) i ++#define htodchanspec(i) i ++#define dtohchanspec(i) i ++ ++#ifdef PROP_TXSTATUS ++#include ++#include ++#endif ++ ++#include ++#include ++ ++#ifdef WLMEDIA_HTSF ++extern void htsf_update(struct dhd_info *dhd, void *data); ++#endif ++int dhd_msg_level = DHD_ERROR_VAL; ++ ++ ++#include ++ ++char fw_path[MOD_PARAM_PATHLEN]; ++char nv_path[MOD_PARAM_PATHLEN]; ++ ++#ifdef SOFTAP ++char fw_path2[MOD_PARAM_PATHLEN]; ++extern bool softap_enabled; ++#endif ++ ++/* Last connection success/failure status */ ++uint32 dhd_conn_event; ++uint32 dhd_conn_status; ++uint32 dhd_conn_reason; ++ ++extern int dhd_iscan_request(void * dhdp, uint16 action); ++extern void dhd_ind_scan_confirm(void *h, bool status); ++extern int dhd_iscan_in_progress(void *h); ++void dhd_iscan_lock(void); ++void dhd_iscan_unlock(void); ++extern int dhd_change_mtu(dhd_pub_t *dhd, int new_mtu, int ifidx); ++#if !defined(AP) && defined(WLP2P) ++extern int dhd_get_concurrent_capabilites(dhd_pub_t *dhd); ++#endif ++bool ap_cfg_running = FALSE; ++bool ap_fw_loaded = FALSE; ++ ++ ++#ifdef DHD_DEBUG ++const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR "\nCompiled on " ++ __DATE__ " at " __TIME__; ++#else ++const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR; ++#endif ++ ++void dhd_set_timer(void *bus, uint wdtick); ++ ++/* IOVar table */ ++enum { ++ IOV_VERSION = 1, ++ IOV_WLMSGLEVEL, ++ IOV_MSGLEVEL, ++ IOV_BCMERRORSTR, ++ IOV_BCMERROR, ++ IOV_WDTICK, ++ IOV_DUMP, ++ IOV_CLEARCOUNTS, ++ IOV_LOGDUMP, ++ IOV_LOGCAL, ++ IOV_LOGSTAMP, ++ IOV_GPIOOB, ++ IOV_IOCTLTIMEOUT, ++#ifdef WLBTAMP ++ IOV_HCI_CMD, /* HCI command */ ++ IOV_HCI_ACL_DATA, /* HCI data packet */ ++#endif ++#if defined(DHD_DEBUG) ++ IOV_CONS, ++ IOV_DCONSOLE_POLL, ++#endif /* defined(DHD_DEBUG) */ ++#ifdef PROP_TXSTATUS ++ IOV_PROPTXSTATUS_ENABLE, ++ IOV_PROPTXSTATUS_MODE, ++#endif ++ IOV_BUS_TYPE, ++#ifdef WLMEDIA_HTSF ++ IOV_WLPKTDLYSTAT_SZ, ++#endif ++ IOV_CHANGEMTU, ++ IOV_HOSTREORDER_FLOWS, ++ IOV_LAST ++}; ++ ++const bcm_iovar_t dhd_iovars[] = { ++ {"version", IOV_VERSION, 0, IOVT_BUFFER, sizeof(dhd_version) }, ++ {"wlmsglevel", IOV_WLMSGLEVEL, 0, IOVT_UINT32, 0 }, ++#ifdef DHD_DEBUG ++ {"msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 }, ++#endif /* DHD_DEBUG */ ++ {"bcmerrorstr", IOV_BCMERRORSTR, 0, IOVT_BUFFER, BCME_STRLEN }, ++ {"bcmerror", IOV_BCMERROR, 0, IOVT_INT8, 0 }, ++ {"wdtick", IOV_WDTICK, 0, IOVT_UINT32, 0 }, ++ {"dump", IOV_DUMP, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN }, ++#ifdef DHD_DEBUG ++ {"cons", IOV_CONS, 0, IOVT_BUFFER, 0 }, ++ {"dconpoll", IOV_DCONSOLE_POLL, 0, IOVT_UINT32, 0 }, ++#endif ++ {"clearcounts", IOV_CLEARCOUNTS, 0, IOVT_VOID, 0 }, ++ {"gpioob", IOV_GPIOOB, 0, IOVT_UINT32, 0 }, ++ {"ioctl_timeout", IOV_IOCTLTIMEOUT, 0, IOVT_UINT32, 0 }, ++#ifdef WLBTAMP ++ {"HCI_cmd", IOV_HCI_CMD, 0, IOVT_BUFFER, 0}, ++ {"HCI_ACL_data", IOV_HCI_ACL_DATA, 0, IOVT_BUFFER, 0}, ++#endif ++#ifdef PROP_TXSTATUS ++ {"proptx", IOV_PROPTXSTATUS_ENABLE, 0, IOVT_UINT32, 0 }, ++ /* ++ set the proptxtstatus operation mode: ++ 0 - Do not do any proptxtstatus flow control ++ 1 - Use implied credit from a packet status ++ 2 - Use explicit credit ++ */ ++ {"ptxmode", IOV_PROPTXSTATUS_MODE, 0, IOVT_UINT32, 0 }, ++#endif ++ {"bustype", IOV_BUS_TYPE, 0, IOVT_UINT32, 0}, ++#ifdef WLMEDIA_HTSF ++ {"pktdlystatsz", IOV_WLPKTDLYSTAT_SZ, 0, IOVT_UINT8, 0 }, ++#endif ++ {"changemtu", IOV_CHANGEMTU, 0, IOVT_UINT32, 0 }, ++ {"host_reorder_flows", IOV_HOSTREORDER_FLOWS, 0, IOVT_BUFFER, ++ (WLHOST_REORDERDATA_MAXFLOWS + 1) }, ++ {NULL, 0, 0, 0, 0 } ++}; ++ ++void ++dhd_common_init(osl_t *osh) ++{ ++ int select_type = 0; ++ //aw checkout which wifi had select ++ select_type = ap6211_gpio_wifi_get_mod_type(); ++ ++#ifdef CONFIG_AP6211_FW_PATH ++ //select bcm40181/ap6181/ap6211 ++ if (select_type == 1 || select_type == 7 || select_type == 9) { ++ bcm_strncpy_s(fw_path, sizeof(fw_path), "/lib/firmware/ap6210/fw_bcm40181a2.bin", MOD_PARAM_PATHLEN-1); ++ } ++ //select bcm40183 ++ if (select_type == 2) { ++ bcm_strncpy_s(fw_path, sizeof(fw_path), "/lib/firmware/ap6211/fw_bcm40183b2.bin", MOD_PARAM_PATHLEN-1); ++ } ++ //select ap6330 ++ if (select_type == 8) { ++ bcm_strncpy_s(fw_path, sizeof(fw_path), "/lib/firmware/ap6211/fw_bcm40183b2_ag.bin", MOD_PARAM_PATHLEN-1); ++ } ++ ++#else /* CONFIG_AP6211_FW_PATH */ ++ fw_path[0] = '\0'; ++#endif /* CONFIG_AP6211_FW_PATH */ ++#ifdef CONFIG_AP6211_NVRAM_PATH ++ //select bcm40181 ++ if (select_type == 1) { ++ bcm_strncpy_s(nv_path, sizeof(nv_path), "/lib/firmware/ap6210/nvram_bcm40181.txt", MOD_PARAM_PATHLEN-1); ++ } ++ //select bcm40183 ++ if (select_type == 2) { ++ bcm_strncpy_s(nv_path, sizeof(nv_path), "/lib/firmware/ap6210/nvram_bcm40183.txt", MOD_PARAM_PATHLEN-1); ++ } ++ //select ap6211 ++ if (select_type == 7) { ++ bcm_strncpy_s(nv_path, sizeof(nv_path), "/lib/firmware/ap6210/nvram_ap6210.txt", MOD_PARAM_PATHLEN-1); ++ } ++ ++ //select ap6330 ++ if (select_type == 8) { ++ bcm_strncpy_s(nv_path, sizeof(nv_path), "/lib/firmware/ap6210/nvram_ap6330.txt", MOD_PARAM_PATHLEN-1); ++ } ++ //select ap6181 ++ if (select_type == 9) { ++ bcm_strncpy_s(nv_path, sizeof(nv_path), "/lib/firmware/ap6210/nvram_ap6181.txt", MOD_PARAM_PATHLEN-1); ++ } ++#else /* CONFIG_AP6211_NVRAM_PATH */ ++ nv_path[0] = '\0'; ++#endif /* CONFIG_AP6211_NVRAM_PATH */ ++#ifdef SOFTAP ++ fw_path2[0] = '\0'; ++#endif ++} ++ ++static int ++dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen) ++{ ++ char eabuf[ETHER_ADDR_STR_LEN]; ++ ++ struct bcmstrbuf b; ++ struct bcmstrbuf *strbuf = &b; ++ ++ bcm_binit(strbuf, buf, buflen); ++ ++ /* Base DHD info */ ++ bcm_bprintf(strbuf, "%s\n", dhd_version); ++ bcm_bprintf(strbuf, "\n"); ++ bcm_bprintf(strbuf, "pub.up %d pub.txoff %d pub.busstate %d\n", ++ dhdp->up, dhdp->txoff, dhdp->busstate); ++ bcm_bprintf(strbuf, "pub.hdrlen %d pub.maxctl %d pub.rxsz %d\n", ++ dhdp->hdrlen, dhdp->maxctl, dhdp->rxsz); ++ bcm_bprintf(strbuf, "pub.iswl %d pub.drv_version %ld pub.mac %s\n", ++ dhdp->iswl, dhdp->drv_version, bcm_ether_ntoa(&dhdp->mac, eabuf)); ++ bcm_bprintf(strbuf, "pub.bcmerror %d tickcnt %d\n", dhdp->bcmerror, dhdp->tickcnt); ++ ++ bcm_bprintf(strbuf, "dongle stats:\n"); ++ bcm_bprintf(strbuf, "tx_packets %ld tx_bytes %ld tx_errors %ld tx_dropped %ld\n", ++ dhdp->dstats.tx_packets, dhdp->dstats.tx_bytes, ++ dhdp->dstats.tx_errors, dhdp->dstats.tx_dropped); ++ bcm_bprintf(strbuf, "rx_packets %ld rx_bytes %ld rx_errors %ld rx_dropped %ld\n", ++ dhdp->dstats.rx_packets, dhdp->dstats.rx_bytes, ++ dhdp->dstats.rx_errors, dhdp->dstats.rx_dropped); ++ bcm_bprintf(strbuf, "multicast %ld\n", dhdp->dstats.multicast); ++ ++ bcm_bprintf(strbuf, "bus stats:\n"); ++ bcm_bprintf(strbuf, "tx_packets %ld tx_multicast %ld tx_errors %ld\n", ++ dhdp->tx_packets, dhdp->tx_multicast, dhdp->tx_errors); ++ bcm_bprintf(strbuf, "tx_ctlpkts %ld tx_ctlerrs %ld\n", ++ dhdp->tx_ctlpkts, dhdp->tx_ctlerrs); ++ bcm_bprintf(strbuf, "rx_packets %ld rx_multicast %ld rx_errors %ld \n", ++ dhdp->rx_packets, dhdp->rx_multicast, dhdp->rx_errors); ++ bcm_bprintf(strbuf, "rx_ctlpkts %ld rx_ctlerrs %ld rx_dropped %ld\n", ++ dhdp->rx_ctlpkts, dhdp->rx_ctlerrs, dhdp->rx_dropped); ++ bcm_bprintf(strbuf, "rx_readahead_cnt %ld tx_realloc %ld\n", ++ dhdp->rx_readahead_cnt, dhdp->tx_realloc); ++ bcm_bprintf(strbuf, "\n"); ++ ++ /* Add any prot info */ ++ dhd_prot_dump(dhdp, strbuf); ++ bcm_bprintf(strbuf, "\n"); ++ ++ /* Add any bus info */ ++ dhd_bus_dump(dhdp, strbuf); ++ ++ return (!strbuf->size ? BCME_BUFTOOSHORT : 0); ++} ++ ++int ++dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, int ifindex) ++{ ++ wl_ioctl_t ioc; ++ ++ ioc.cmd = cmd; ++ ioc.buf = arg; ++ ioc.len = len; ++ ioc.set = set; ++ ++ return dhd_wl_ioctl(dhd_pub, ifindex, &ioc, arg, len); ++} ++ ++ ++int ++dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifindex, wl_ioctl_t *ioc, void *buf, int len) ++{ ++ int ret; ++ ++ dhd_os_proto_block(dhd_pub); ++ ++ ret = dhd_prot_ioctl(dhd_pub, ifindex, ioc, buf, len); ++ if ((ret) && (dhd_pub->up)) ++ /* Send hang event only if dhd_open() was success */ ++ dhd_os_check_hang(dhd_pub, ifindex, ret); ++ ++ dhd_os_proto_unblock(dhd_pub); ++ ++ return ret; ++} ++ ++static int ++dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const char *name, ++ void *params, int plen, void *arg, int len, int val_size) ++{ ++ int bcmerror = 0; ++ int32 int_val = 0; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ AP6211_DEBUG("%s: actionid = %d; name %s\n", __FUNCTION__, actionid, name); ++ ++ if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0) ++ goto exit; ++ ++ if (plen >= (int)sizeof(int_val)) ++ bcopy(params, &int_val, sizeof(int_val)); ++ ++ switch (actionid) { ++ case IOV_GVAL(IOV_VERSION): ++ /* Need to have checked buffer length */ ++ bcm_strncpy_s((char*)arg, len, dhd_version, len); ++ break; ++ ++ case IOV_GVAL(IOV_WLMSGLEVEL): ++ //AP6211_DEBUG("android_msg_level=0x%x\n", android_msg_level); ++#if defined(CONFIG_WIRELESS_EXT) ++ int_val = (int32)iw_msg_level; ++ bcopy(&int_val, arg, val_size); ++ AP6211_DEBUG("iw_msg_level=0x%x\n", iw_msg_level); ++#endif ++#ifdef WL_CFG80211 ++ int_val = (int32)wl_dbg_level; ++ bcopy(&int_val, arg, val_size); ++ AP6211_DEBUG("cfg_msg_level=0x%x\n", wl_dbg_level); ++#endif ++ break; ++ ++ case IOV_SVAL(IOV_WLMSGLEVEL): ++#if defined(CONFIG_WIRELESS_EXT) ++ if (int_val & DHD_IW_VAL) { ++ iw_msg_level = (uint)(int_val & 0xFFFF); ++ AP6211_DEBUG("iw_msg_level=0x%x\n", iw_msg_level); ++ } else ++#endif ++#ifdef WL_CFG80211 ++ if (int_val & DHD_CFG_VAL) { ++ wl_cfg80211_enable_trace((u32)(int_val & 0xFFFF)); ++ } else ++#endif ++ { ++ //android_msg_level = (uint)int_val; ++ //AP6211_DEBUG("android_msg_level=0x%x\n", android_msg_level); ++ } ++ break; ++ ++ case IOV_GVAL(IOV_MSGLEVEL): ++ int_val = (int32)dhd_msg_level; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_MSGLEVEL): ++ dhd_msg_level = int_val; ++ break; ++ ++ case IOV_GVAL(IOV_BCMERRORSTR): ++ bcm_strncpy_s((char *)arg, len, bcmerrorstr(dhd_pub->bcmerror), BCME_STRLEN); ++ ((char *)arg)[BCME_STRLEN - 1] = 0x00; ++ break; ++ ++ case IOV_GVAL(IOV_BCMERROR): ++ int_val = (int32)dhd_pub->bcmerror; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_GVAL(IOV_WDTICK): ++ int_val = (int32)dhd_watchdog_ms; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_WDTICK): ++ if (!dhd_pub->up) { ++ bcmerror = BCME_NOTUP; ++ break; ++ } ++ dhd_os_wd_timer(dhd_pub, (uint)int_val); ++ break; ++ ++ case IOV_GVAL(IOV_DUMP): ++ bcmerror = dhd_dump(dhd_pub, arg, len); ++ break; ++ ++#ifdef DHD_DEBUG ++ case IOV_GVAL(IOV_DCONSOLE_POLL): ++ int_val = (int32)dhd_console_ms; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_DCONSOLE_POLL): ++ dhd_console_ms = (uint)int_val; ++ break; ++ ++ case IOV_SVAL(IOV_CONS): ++ if (len > 0) ++ bcmerror = dhd_bus_console_in(dhd_pub, arg, len - 1); ++ break; ++#endif /* DHD_DEBUG */ ++ ++ case IOV_SVAL(IOV_CLEARCOUNTS): ++ dhd_pub->tx_packets = dhd_pub->rx_packets = 0; ++ dhd_pub->tx_errors = dhd_pub->rx_errors = 0; ++ dhd_pub->tx_ctlpkts = dhd_pub->rx_ctlpkts = 0; ++ dhd_pub->tx_ctlerrs = dhd_pub->rx_ctlerrs = 0; ++ dhd_pub->rx_dropped = 0; ++ dhd_pub->rx_readahead_cnt = 0; ++ dhd_pub->tx_realloc = 0; ++ dhd_pub->wd_dpc_sched = 0; ++ memset(&dhd_pub->dstats, 0, sizeof(dhd_pub->dstats)); ++ dhd_bus_clearcounts(dhd_pub); ++#ifdef PROP_TXSTATUS ++ /* clear proptxstatus related counters */ ++ if (dhd_pub->wlfc_state) { ++ athost_wl_status_info_t *wlfc = ++ (athost_wl_status_info_t*)dhd_pub->wlfc_state; ++ wlfc_hanger_t* hanger; ++ ++ memset(&wlfc->stats, 0, sizeof(athost_wl_stat_counters_t)); ++ ++ hanger = (wlfc_hanger_t*)wlfc->hanger; ++ hanger->pushed = 0; ++ hanger->popped = 0; ++ hanger->failed_slotfind = 0; ++ hanger->failed_to_pop = 0; ++ hanger->failed_to_push = 0; ++ } ++#endif /* PROP_TXSTATUS */ ++ break; ++ ++ ++ case IOV_GVAL(IOV_IOCTLTIMEOUT): { ++ int_val = (int32)dhd_os_get_ioctl_resp_timeout(); ++ bcopy(&int_val, arg, sizeof(int_val)); ++ break; ++ } ++ ++ case IOV_SVAL(IOV_IOCTLTIMEOUT): { ++ if (int_val <= 0) ++ bcmerror = BCME_BADARG; ++ else ++ dhd_os_set_ioctl_resp_timeout((unsigned int)int_val); ++ break; ++ } ++ ++#ifdef WLBTAMP ++ case IOV_SVAL(IOV_HCI_CMD): { ++ amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)arg; ++ ++ /* sanity check: command preamble present */ ++ if (len < HCI_CMD_PREAMBLE_SIZE) ++ return BCME_BUFTOOSHORT; ++ ++ /* sanity check: command parameters are present */ ++ if (len < (int)(HCI_CMD_PREAMBLE_SIZE + cmd->plen)) ++ return BCME_BUFTOOSHORT; ++ ++ dhd_bta_docmd(dhd_pub, cmd, len); ++ break; ++ } ++ ++ case IOV_SVAL(IOV_HCI_ACL_DATA): { ++ amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *)arg; ++ ++ /* sanity check: HCI header present */ ++ if (len < HCI_ACL_DATA_PREAMBLE_SIZE) ++ return BCME_BUFTOOSHORT; ++ ++ /* sanity check: ACL data is present */ ++ if (len < (int)(HCI_ACL_DATA_PREAMBLE_SIZE + ACL_data->dlen)) ++ return BCME_BUFTOOSHORT; ++ ++ dhd_bta_tx_hcidata(dhd_pub, ACL_data, len); ++ break; ++ } ++#endif /* WLBTAMP */ ++ ++#ifdef PROP_TXSTATUS ++ case IOV_GVAL(IOV_PROPTXSTATUS_ENABLE): ++ int_val = dhd_pub->wlfc_enabled? 1 : 0; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_PROPTXSTATUS_ENABLE): ++ dhd_pub->wlfc_enabled = int_val? 1 : 0; ++ break; ++ ++ case IOV_GVAL(IOV_PROPTXSTATUS_MODE): { ++ athost_wl_status_info_t *wlfc = ++ (athost_wl_status_info_t*)dhd_pub->wlfc_state; ++ int_val = dhd_pub->wlfc_state ? (int32)wlfc->proptxstatus_mode : 0; ++ bcopy(&int_val, arg, val_size); ++ break; ++ } ++ ++ case IOV_SVAL(IOV_PROPTXSTATUS_MODE): ++ if (dhd_pub->wlfc_state) { ++ athost_wl_status_info_t *wlfc = ++ (athost_wl_status_info_t*)dhd_pub->wlfc_state; ++ wlfc->proptxstatus_mode = int_val & 0xff; ++ } ++ break; ++#endif /* PROP_TXSTATUS */ ++ ++ case IOV_GVAL(IOV_BUS_TYPE): ++ /* The dhd application queries the driver to check if its usb or sdio. */ ++#ifdef AP6211USB ++ int_val = BUS_TYPE_USB; ++#endif ++ int_val = BUS_TYPE_SDIO; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ ++#ifdef WLMEDIA_HTSF ++ case IOV_GVAL(IOV_WLPKTDLYSTAT_SZ): ++ int_val = dhd_pub->htsfdlystat_sz; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_WLPKTDLYSTAT_SZ): ++ dhd_pub->htsfdlystat_sz = int_val & 0xff; ++ AP6211_DEBUG("Setting tsfdlystat_sz:%d\n", dhd_pub->htsfdlystat_sz); ++ break; ++#endif ++ case IOV_SVAL(IOV_CHANGEMTU): ++ int_val &= 0xffff; ++ bcmerror = dhd_change_mtu(dhd_pub, int_val, 0); ++ break; ++ ++ case IOV_GVAL(IOV_HOSTREORDER_FLOWS): ++ { ++ uint i = 0; ++ uint8 *ptr = (uint8 *)arg; ++ uint8 count = 0; ++ ++ ptr++; ++ for (i = 0; i < WLHOST_REORDERDATA_MAXFLOWS; i++) { ++ if (dhd_pub->reorder_bufs[i] != NULL) { ++ *ptr = dhd_pub->reorder_bufs[i]->flow_id; ++ ptr++; ++ count++; ++ } ++ } ++ ptr = (uint8 *)arg; ++ *ptr = count; ++ break; ++ } ++ ++ default: ++ bcmerror = BCME_UNSUPPORTED; ++ break; ++ } ++ ++exit: ++ AP6211_DEBUG("%s: actionid %d, bcmerror %d\n", __FUNCTION__, actionid, bcmerror); ++ return bcmerror; ++} ++ ++/* Store the status of a connection attempt for later retrieval by an iovar */ ++void ++dhd_store_conn_status(uint32 event, uint32 status, uint32 reason) ++{ ++ /* Do not overwrite a WLC_E_PRUNE with a WLC_E_SET_SSID ++ * because an encryption/rsn mismatch results in both events, and ++ * the important information is in the WLC_E_PRUNE. ++ */ ++ if (!(event == WLC_E_SET_SSID && status == WLC_E_STATUS_FAIL && ++ dhd_conn_event == WLC_E_PRUNE)) { ++ dhd_conn_event = event; ++ dhd_conn_status = status; ++ dhd_conn_reason = reason; ++ } ++} ++ ++bool ++dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec) ++{ ++ void *p; ++ int eprec = -1; /* precedence to evict from */ ++ bool discard_oldest; ++ ++ /* Fast case, precedence queue is not full and we are also not ++ * exceeding total queue length ++ */ ++ if (!pktq_pfull(q, prec) && !pktq_full(q)) { ++ pktq_penq(q, prec, pkt); ++ return TRUE; ++ } ++ ++ /* Determine precedence from which to evict packet, if any */ ++ if (pktq_pfull(q, prec)) ++ eprec = prec; ++ else if (pktq_full(q)) { ++ pktq_peek_tail(q, &eprec); ++ if (eprec > prec || eprec < 0) ++ return FALSE; ++ } ++ ++ /* Evict if needed */ ++ if (eprec >= 0) { ++ /* Detect queueing to unconfigured precedence */ ++ ASSERT(!pktq_pempty(q, eprec)); ++ discard_oldest = AC_BITMAP_TST(dhdp->wme_dp, eprec); ++ if (eprec == prec && !discard_oldest) ++ return FALSE; /* refuse newer (incoming) packet */ ++ /* Evict packet according to discard policy */ ++ p = discard_oldest ? pktq_pdeq(q, eprec) : pktq_pdeq_tail(q, eprec); ++ ASSERT(p); ++ ++ PKTFREE(dhdp->osh, p, TRUE); ++ } ++ ++ /* Enqueue */ ++ pktq_penq(q, prec, pkt); ++ ++ return TRUE; ++} ++ ++static int ++dhd_iovar_op(dhd_pub_t *dhd_pub, const char *name, ++ void *params, int plen, void *arg, int len, bool set) ++{ ++ int bcmerror = 0; ++ int val_size; ++ const bcm_iovar_t *vi = NULL; ++ uint32 actionid; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ ASSERT(name); ++ ASSERT(len >= 0); ++ ++ /* Get MUST have return space */ ++ ASSERT(set || (arg && len)); ++ ++ /* Set does NOT take qualifiers */ ++ ASSERT(!set || (!params && !plen)); ++ ++ if ((vi = bcm_iovar_lookup(dhd_iovars, name)) == NULL) { ++ bcmerror = BCME_UNSUPPORTED; ++ goto exit; ++ } ++ ++ AP6211_DEBUG("%s: %s %s, len %d plen %d\n", __FUNCTION__, ++ name, (set ? "set" : "get"), len, plen); ++ ++ /* set up 'params' pointer in case this is a set command so that ++ * the convenience int and bool code can be common to set and get ++ */ ++ if (params == NULL) { ++ params = arg; ++ plen = len; ++ } ++ ++ if (vi->type == IOVT_VOID) ++ val_size = 0; ++ else if (vi->type == IOVT_BUFFER) ++ val_size = len; ++ else ++ /* all other types are integer sized */ ++ val_size = sizeof(int); ++ ++ actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); ++ ++ bcmerror = dhd_doiovar(dhd_pub, vi, actionid, name, params, plen, arg, len, val_size); ++ ++exit: ++ return bcmerror; ++} ++ ++int ++dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buflen) ++{ ++ int bcmerror = 0; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ if (!buf) { ++ return BCME_BADARG; ++ } ++ ++ switch (ioc->cmd) { ++ case DHD_GET_MAGIC: ++ if (buflen < sizeof(int)) ++ bcmerror = BCME_BUFTOOSHORT; ++ else ++ *(int*)buf = DHD_IOCTL_MAGIC; ++ break; ++ ++ case DHD_GET_VERSION: ++ if (buflen < sizeof(int)) ++ bcmerror = -BCME_BUFTOOSHORT; ++ else ++ *(int*)buf = DHD_IOCTL_VERSION; ++ break; ++ ++ case DHD_GET_VAR: ++ case DHD_SET_VAR: { ++ char *arg; ++ uint arglen; ++ ++ /* scan past the name to any arguments */ ++ for (arg = buf, arglen = buflen; *arg && arglen; arg++, arglen--) ++ ; ++ ++ if (*arg) { ++ bcmerror = BCME_BUFTOOSHORT; ++ break; ++ } ++ ++ /* account for the NUL terminator */ ++ arg++, arglen--; ++ ++ /* call with the appropriate arguments */ ++ if (ioc->cmd == DHD_GET_VAR) ++ bcmerror = dhd_iovar_op(dhd_pub, buf, arg, arglen, ++ buf, buflen, IOV_GET); ++ else ++ bcmerror = dhd_iovar_op(dhd_pub, buf, NULL, 0, arg, arglen, IOV_SET); ++ if (bcmerror != BCME_UNSUPPORTED) ++ break; ++ ++ /* not in generic table, try protocol module */ ++ if (ioc->cmd == DHD_GET_VAR) ++ bcmerror = dhd_prot_iovar_op(dhd_pub, buf, arg, ++ arglen, buf, buflen, IOV_GET); ++ else ++ bcmerror = dhd_prot_iovar_op(dhd_pub, buf, ++ NULL, 0, arg, arglen, IOV_SET); ++ if (bcmerror != BCME_UNSUPPORTED) ++ break; ++ ++ /* if still not found, try bus module */ ++ if (ioc->cmd == DHD_GET_VAR) { ++ bcmerror = dhd_bus_iovar_op(dhd_pub, buf, ++ arg, arglen, buf, buflen, IOV_GET); ++ } else { ++ bcmerror = dhd_bus_iovar_op(dhd_pub, buf, ++ NULL, 0, arg, arglen, IOV_SET); ++ } ++ ++ break; ++ } ++ ++ default: ++ bcmerror = BCME_UNSUPPORTED; ++ } ++ ++ return bcmerror; ++} ++ ++#ifdef SHOW_EVENTS ++static void ++wl_show_host_event(wl_event_msg_t *event, void *event_data) ++{ ++ uint i, status, reason; ++ bool group = FALSE, flush_txq = FALSE, link = FALSE; ++ const char *auth_str; ++ const char *event_name; ++ uchar *buf; ++ char err_msg[256], eabuf[ETHER_ADDR_STR_LEN]; ++ uint event_type, flags, auth_type, datalen; ++ ++ event_type = ntoh32(event->event_type); ++ flags = ntoh16(event->flags); ++ status = ntoh32(event->status); ++ reason = ntoh32(event->reason); ++ BCM_REFERENCE(reason); ++ auth_type = ntoh32(event->auth_type); ++ datalen = ntoh32(event->datalen); ++ ++ /* debug dump of event messages */ ++ snprintf(eabuf, sizeof(eabuf), "%02x:%02x:%02x:%02x:%02x:%02x", ++ (uchar)event->addr.octet[0]&0xff, ++ (uchar)event->addr.octet[1]&0xff, ++ (uchar)event->addr.octet[2]&0xff, ++ (uchar)event->addr.octet[3]&0xff, ++ (uchar)event->addr.octet[4]&0xff, ++ (uchar)event->addr.octet[5]&0xff); ++ ++ event_name = "UNKNOWN"; ++ for (i = 0; i < (uint)bcmevent_names_size; i++) ++ if (bcmevent_names[i].event == event_type) ++ event_name = bcmevent_names[i].name; ++ ++ if (flags & WLC_EVENT_MSG_LINK) ++ link = TRUE; ++ if (flags & WLC_EVENT_MSG_GROUP) ++ group = TRUE; ++ if (flags & WLC_EVENT_MSG_FLUSHTXQ) ++ flush_txq = TRUE; ++ ++ switch (event_type) { ++ case WLC_E_START: ++ case WLC_E_DEAUTH: ++ case WLC_E_DISASSOC: ++ AP6211_DEBUG("MACEVENT: %s, MAC %s\n", event_name, eabuf); ++ break; ++ ++ case WLC_E_ASSOC_IND: ++ case WLC_E_REASSOC_IND: ++ ++ AP6211_DEBUG("MACEVENT: %s, MAC %s\n", event_name, eabuf); ++ break; ++ ++ case WLC_E_ASSOC: ++ case WLC_E_REASSOC: ++ if (status == WLC_E_STATUS_SUCCESS) { ++ AP6211_DEBUG("MACEVENT: %s, MAC %s, SUCCESS\n", event_name, eabuf); ++ } else if (status == WLC_E_STATUS_TIMEOUT) { ++ AP6211_DEBUG("MACEVENT: %s, MAC %s, TIMEOUT\n", event_name, eabuf); ++ } else if (status == WLC_E_STATUS_FAIL) { ++ AP6211_DEBUG("MACEVENT: %s, MAC %s, FAILURE, reason %d\n", ++ event_name, eabuf, (int)reason); ++ } else { ++ AP6211_DEBUG("MACEVENT: %s, MAC %s, unexpected status %d\n", ++ event_name, eabuf, (int)status); ++ } ++ break; ++ ++ case WLC_E_DEAUTH_IND: ++ case WLC_E_DISASSOC_IND: ++ AP6211_DEBUG("MACEVENT: %s, MAC %s, reason %d\n", event_name, eabuf, (int)reason); ++ break; ++ ++ case WLC_E_AUTH: ++ case WLC_E_AUTH_IND: ++ if (auth_type == DOT11_OPEN_SYSTEM) ++ auth_str = "Open System"; ++ else if (auth_type == DOT11_SHARED_KEY) ++ auth_str = "Shared Key"; ++ else { ++ snprintf(err_msg, sizeof(err_msg), "AUTH unknown: %d", (int)auth_type); ++ auth_str = err_msg; ++ } ++ if (event_type == WLC_E_AUTH_IND) { ++ AP6211_DEBUG("MACEVENT: %s, MAC %s, %s\n", event_name, eabuf, auth_str); ++ } else if (status == WLC_E_STATUS_SUCCESS) { ++ AP6211_DEBUG("MACEVENT: %s, MAC %s, %s, SUCCESS\n", ++ event_name, eabuf, auth_str); ++ } else if (status == WLC_E_STATUS_TIMEOUT) { ++ AP6211_DEBUG("MACEVENT: %s, MAC %s, %s, TIMEOUT\n", ++ event_name, eabuf, auth_str); ++ } else if (status == WLC_E_STATUS_FAIL) { ++ AP6211_DEBUG("MACEVENT: %s, MAC %s, %s, FAILURE, reason %d\n", ++ event_name, eabuf, auth_str, (int)reason); ++ } ++ BCM_REFERENCE(auth_str); ++ ++ break; ++ ++ case WLC_E_JOIN: ++ case WLC_E_ROAM: ++ case WLC_E_SET_SSID: ++ if (status == WLC_E_STATUS_SUCCESS) { ++ AP6211_DEBUG("MACEVENT: %s, MAC %s\n", event_name, eabuf); ++ } else if (status == WLC_E_STATUS_FAIL) { ++ AP6211_DEBUG("MACEVENT: %s, failed\n", event_name); ++ } else if (status == WLC_E_STATUS_NO_NETWORKS) { ++ AP6211_DEBUG("MACEVENT: %s, no networks found\n", event_name); ++ } else { ++ AP6211_DEBUG("MACEVENT: %s, unexpected status %d\n", ++ event_name, (int)status); ++ } ++ break; ++ ++ case WLC_E_BEACON_RX: ++ if (status == WLC_E_STATUS_SUCCESS) { ++ AP6211_DEBUG("MACEVENT: %s, SUCCESS\n", event_name); ++ } else if (status == WLC_E_STATUS_FAIL) { ++ AP6211_DEBUG("MACEVENT: %s, FAIL\n", event_name); ++ } else { ++ AP6211_DEBUG("MACEVENT: %s, status %d\n", event_name, status); ++ } ++ break; ++ ++ case WLC_E_LINK: ++ AP6211_DEBUG("MACEVENT: %s %s\n", event_name, link?"UP":"DOWN"); ++ BCM_REFERENCE(link); ++ break; ++ ++ case WLC_E_MIC_ERROR: ++ AP6211_DEBUG("MACEVENT: %s, MAC %s, Group %d, Flush %d\n", ++ event_name, eabuf, group, flush_txq); ++ BCM_REFERENCE(group); ++ BCM_REFERENCE(flush_txq); ++ break; ++ ++ case WLC_E_ICV_ERROR: ++ case WLC_E_UNICAST_DECODE_ERROR: ++ case WLC_E_MULTICAST_DECODE_ERROR: ++ AP6211_DEBUG("MACEVENT: %s, MAC %s\n", ++ event_name, eabuf); ++ break; ++ ++ case WLC_E_TXFAIL: ++ AP6211_DEBUG("MACEVENT: %s, RA %s\n", event_name, eabuf); ++ break; ++ ++ case WLC_E_SCAN_COMPLETE: ++ case WLC_E_ASSOC_REQ_IE: ++ case WLC_E_ASSOC_RESP_IE: ++ case WLC_E_PMKID_CACHE: ++ AP6211_DEBUG("MACEVENT: %s\n", event_name); ++ break; ++ ++ case WLC_E_PFN_NET_FOUND: ++ case WLC_E_PFN_NET_LOST: ++ case WLC_E_PFN_SCAN_COMPLETE: ++ case WLC_E_PFN_SCAN_NONE: ++ case WLC_E_PFN_SCAN_ALLGONE: ++ AP6211_DEBUG("PNOEVENT: %s\n", event_name); ++ break; ++ ++ case WLC_E_PSK_SUP: ++ case WLC_E_PRUNE: ++ AP6211_DEBUG("MACEVENT: %s, status %d, reason %d\n", ++ event_name, (int)status, (int)reason); ++ break; ++ ++#ifdef WIFI_ACT_FRAME ++ case WLC_E_ACTION_FRAME: ++ AP6211_DEBUG("MACEVENT: %s Bssid %s\n", event_name, eabuf); ++ break; ++#endif /* WIFI_ACT_FRAME */ ++ ++ case WLC_E_TRACE: { ++ static uint32 seqnum_prev = 0; ++ msgtrace_hdr_t hdr; ++ uint32 nblost; ++ char *s, *p; ++ ++ buf = (uchar *) event_data; ++ memcpy(&hdr, buf, MSGTRACE_HDRLEN); ++ ++ if (hdr.version != MSGTRACE_VERSION) { ++ AP6211_DEBUG("MACEVENT: %s [unsupported version --> " ++ "dhd version:%d dongle version:%d]\n", ++ event_name, MSGTRACE_VERSION, hdr.version); ++ /* Reset datalen to avoid display below */ ++ datalen = 0; ++ break; ++ } ++ ++ /* There are 2 bytes available at the end of data */ ++ buf[MSGTRACE_HDRLEN + ntoh16(hdr.len)] = '\0'; ++ ++ if (ntoh32(hdr.discarded_bytes) || ntoh32(hdr.discarded_printf)) { ++ AP6211_DEBUG("WLC_E_TRACE: [Discarded traces in dongle -->" ++ "discarded_bytes %d discarded_printf %d]\n", ++ ntoh32(hdr.discarded_bytes), ntoh32(hdr.discarded_printf)); ++ } ++ ++ nblost = ntoh32(hdr.seqnum) - seqnum_prev - 1; ++ if (nblost > 0) { ++ AP6211_DEBUG("WLC_E_TRACE: [Event lost --> seqnum %d nblost %d\n", ++ ntoh32(hdr.seqnum), nblost); ++ } ++ seqnum_prev = ntoh32(hdr.seqnum); ++ ++ /* Display the trace buffer. Advance from \n to \n to avoid display big ++ * printf (issue with Linux printk ) ++ */ ++ p = (char *)&buf[MSGTRACE_HDRLEN]; ++ while ((s = strstr(p, "\n")) != NULL) { ++ *s = '\0'; ++ AP6211_DEBUG("%s\n", p); ++ p = s+1; ++ } ++ AP6211_DEBUG("%s\n", p); ++ ++ /* Reset datalen to avoid display below */ ++ datalen = 0; ++ break; ++ } ++ ++ ++ case WLC_E_RSSI: ++ AP6211_DEBUG("MACEVENT: %s %d\n", event_name, ntoh32(*((int *)event_data))); ++ break; ++ ++ case WLC_E_SERVICE_FOUND: ++ case WLC_E_P2PO_ADD_DEVICE: ++ case WLC_E_P2PO_DEL_DEVICE: ++ AP6211_DEBUG("MACEVENT: %s, MAC: %s\n", event_name, eabuf); ++ break; ++ ++ default: ++ AP6211_DEBUG("MACEVENT: %s %d, MAC %s, status %d, reason %d, auth %d\n", ++ event_name, event_type, eabuf, (int)status, (int)reason, ++ (int)auth_type); ++ break; ++ } ++ ++ /* show any appended data */ ++ if (datalen) { ++ buf = (uchar *) event_data; ++ AP6211_DEBUG(" data (%d) : ", datalen); ++ for (i = 0; i < datalen; i++) ++ AP6211_DUMP(" 0x%02x ", *buf++); ++ AP6211_DUMP("\n"); ++ } ++} ++#endif /* SHOW_EVENTS */ ++ ++int ++wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, ++ wl_event_msg_t *event, void **data_ptr) ++{ ++ /* check whether packet is a BRCM event pkt */ ++ bcm_event_t *pvt_data = (bcm_event_t *)pktdata; ++ uint8 *event_data; ++ uint32 type, status, datalen; ++ uint16 flags; ++ int evlen; ++ ++ if (bcmp(BRCM_OUI, &pvt_data->bcm_hdr.oui[0], DOT11_OUI_LEN)) { ++ AP6211_ERR("%s: mismatched OUI, bailing\n", __FUNCTION__); ++ return (BCME_ERROR); ++ } ++ ++ /* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */ ++ if (ntoh16_ua((void *)&pvt_data->bcm_hdr.usr_subtype) != BCMILCP_BCM_SUBTYPE_EVENT) { ++ AP6211_ERR("%s: mismatched subtype, bailing\n", __FUNCTION__); ++ return (BCME_ERROR); ++ } ++ ++ *data_ptr = &pvt_data[1]; ++ event_data = *data_ptr; ++ ++ /* memcpy since BRCM event pkt may be unaligned. */ ++ memcpy(event, &pvt_data->event, sizeof(wl_event_msg_t)); ++ ++ type = ntoh32_ua((void *)&event->event_type); ++ flags = ntoh16_ua((void *)&event->flags); ++ status = ntoh32_ua((void *)&event->status); ++ datalen = ntoh32_ua((void *)&event->datalen); ++ evlen = datalen + sizeof(bcm_event_t); ++ ++ switch (type) { ++#ifdef PROP_TXSTATUS ++ case WLC_E_FIFO_CREDIT_MAP: ++ dhd_wlfc_event(dhd_pub->info); ++ dhd_wlfc_FIFOcreditmap_event(dhd_pub->info, event_data); ++ AP6211_DEBUG("WLC_E_FIFO_CREDIT_MAP:(AC0,AC1,AC2,AC3),(BC_MC),(OTHER): " ++ "(%d,%d,%d,%d),(%d),(%d)\n", event_data[0], event_data[1], ++ event_data[2], ++ event_data[3], event_data[4], event_data[5]); ++ break; ++#endif ++ ++ case WLC_E_IF: ++ { ++ dhd_if_event_t *ifevent = (dhd_if_event_t *)event_data; ++#ifdef PROP_TXSTATUS ++ { ++ uint8* ea = pvt_data->eth.ether_dhost; ++ AP6211_DEBUG("WLC_E_IF: idx:%d, action:%s, iftype:%s, " ++ "[%02x:%02x:%02x:%02x:%02x:%02x]\n", ++ ifevent->ifidx, ++ ((ifevent->action == WLC_E_IF_ADD) ? "ADD":"DEL"), ++ ((ifevent->is_AP == 0) ? "STA":"AP "), ++ ea[0], ea[1], ea[2], ea[3], ea[4], ea[5]); ++ (void)ea; ++ if (ifevent->action == WLC_E_IF_CHANGE) ++ dhd_wlfc_interface_event(dhd_pub->info, ++ eWLFC_MAC_ENTRY_ACTION_UPDATE, ++ ifevent->ifidx, ifevent->is_AP, ea); ++ else ++ dhd_wlfc_interface_event(dhd_pub->info, ++ ((ifevent->action == WLC_E_IF_ADD) ? ++ eWLFC_MAC_ENTRY_ACTION_ADD : eWLFC_MAC_ENTRY_ACTION_DEL), ++ ifevent->ifidx, ifevent->is_AP, ea); ++ ++ ++ /* dhd already has created an interface by default, for 0 */ ++ if (ifevent->ifidx == 0) ++ break; ++ } ++#endif /* PROP_TXSTATUS */ ++ ++#ifdef WL_CFG80211 ++ if (wl_cfg80211_is_progress_ifchange()) { ++ AP6211_ERR("%s: ifidx %d for %s action %d\n", ++ __FUNCTION__, ifevent->ifidx, ++ event->ifname, ifevent->action); ++ if (ifevent->action == WLC_E_IF_ADD || ++ ifevent->action == WLC_E_IF_CHANGE) ++ wl_cfg80211_notify_ifchange(); ++ return (BCME_OK); ++ } ++#endif /* WL_CFG80211 */ ++ if (ifevent->ifidx > 0 && ifevent->ifidx < DHD_MAX_IFS) { ++ if (ifevent->action == WLC_E_IF_ADD) { ++ if (dhd_add_if(dhd_pub->info, ifevent->ifidx, ++ NULL, event->ifname, ++ event->addr.octet, ++ ifevent->flags, ifevent->bssidx)) { ++ AP6211_ERR("%s: dhd_add_if failed!!" ++ " ifidx: %d for %s\n", ++ __FUNCTION__, ++ ifevent->ifidx, ++ event->ifname); ++ return (BCME_ERROR); ++ } ++ } ++ else if (ifevent->action == WLC_E_IF_DEL) ++ dhd_del_if(dhd_pub->info, ifevent->ifidx); ++ } else { ++#ifndef PROP_TXSTATUS ++ AP6211_ERR("%s: Invalid ifidx %d for %s\n", ++ __FUNCTION__, ifevent->ifidx, event->ifname); ++#endif /* !PROP_TXSTATUS */ ++ } ++ } ++ /* send up the if event: btamp user needs it */ ++ *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname); ++ /* push up to external supp/auth */ ++ dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx); ++ break; ++ ++ ++#ifdef WLMEDIA_HTSF ++ case WLC_E_HTSFSYNC: ++ htsf_update(dhd_pub->info, event_data); ++ break; ++#endif /* WLMEDIA_HTSF */ ++#if defined(NDIS630) ++ case WLC_E_NDIS_LINK: ++ break; ++#else /* defined(NDIS630) && defined(BCMDONGLEHOST) */ ++ case WLC_E_NDIS_LINK: { ++ uint32 temp = hton32(WLC_E_LINK); ++ ++ memcpy((void *)(&pvt_data->event.event_type), &temp, ++ sizeof(pvt_data->event.event_type)); ++ } ++#endif ++ /* These are what external supplicant/authenticator wants */ ++ /* fall through */ ++ case WLC_E_LINK: ++ case WLC_E_DEAUTH: ++ case WLC_E_DEAUTH_IND: ++ case WLC_E_DISASSOC: ++ case WLC_E_DISASSOC_IND: ++ AP6211_DEBUG("%s: Link event %d, flags %x, status %x\n", ++ __FUNCTION__, type, flags, status); ++ /* fall through */ ++ default: ++ *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname); ++ /* push up to external supp/auth */ ++ dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx); ++ AP6211_DEBUG("%s: MAC event %d, flags %x, status %x\n", ++ __FUNCTION__, type, flags, status); ++ BCM_REFERENCE(flags); ++ BCM_REFERENCE(status); ++ ++ /* put it back to WLC_E_NDIS_LINK */ ++ if (type == WLC_E_NDIS_LINK) { ++ uint32 temp; ++ ++ temp = ntoh32_ua((void *)&event->event_type); ++ AP6211_DEBUG("Converted to WLC_E_LINK type %d\n", temp); ++ ++ temp = ntoh32(WLC_E_NDIS_LINK); ++ memcpy((void *)(&pvt_data->event.event_type), &temp, ++ sizeof(pvt_data->event.event_type)); ++ } ++ break; ++ } ++ ++#ifdef SHOW_EVENTS ++ wl_show_host_event(event, (void *)event_data); ++#endif /* SHOW_EVENTS */ ++ ++ return (BCME_OK); ++} ++ ++void ++wl_event_to_host_order(wl_event_msg_t * evt) ++{ ++ /* Event struct members passed from dongle to host are stored in network ++ * byte order. Convert all members to host-order. ++ */ ++ evt->event_type = ntoh32(evt->event_type); ++ evt->flags = ntoh16(evt->flags); ++ evt->status = ntoh32(evt->status); ++ evt->reason = ntoh32(evt->reason); ++ evt->auth_type = ntoh32(evt->auth_type); ++ evt->datalen = ntoh32(evt->datalen); ++ evt->version = ntoh16(evt->version); ++} ++ ++void ++dhd_print_buf(void *pbuf, int len, int bytes_per_line) ++{ ++#ifdef DHD_DEBUG ++ int i, j = 0; ++ unsigned char *buf = pbuf; ++ ++ if (bytes_per_line == 0) { ++ bytes_per_line = len; ++ } ++ ++ for (i = 0; i < len; i++) { ++ AP6211_DUMP("%2.2x", *buf++); ++ j++; ++ if (j == bytes_per_line) { ++ AP6211_DUMP("\n"); ++ j = 0; ++ } else { ++ AP6211_DUMP(":"); ++ } ++ } ++ AP6211_DUMP("\n"); ++#endif /* DHD_DEBUG */ ++} ++ ++#ifndef strtoul ++#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) ++#endif ++ ++#ifdef PKT_FILTER_SUPPORT ++/* Convert user's input in hex pattern to byte-size mask */ ++static int ++wl_pattern_atoh(char *src, char *dst) ++{ ++ int i; ++ if (strncmp(src, "0x", 2) != 0 && ++ strncmp(src, "0X", 2) != 0) { ++ AP6211_ERR("Mask invalid format. Needs to start with 0x\n"); ++ return -1; ++ } ++ src = src + 2; /* Skip past 0x */ ++ if (strlen(src) % 2 != 0) { ++ AP6211_ERR("Mask invalid format. Needs to be of even length\n"); ++ return -1; ++ } ++ for (i = 0; *src != '\0'; i++) { ++ char num[3]; ++ bcm_strncpy_s(num, sizeof(num), src, 2); ++ num[2] = '\0'; ++ dst[i] = (uint8)strtoul(num, NULL, 16); ++ src += 2; ++ } ++ return i; ++} ++ ++void ++dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode) ++{ ++ char *argv[8]; ++ int i = 0; ++ const char *str; ++ int buf_len; ++ int str_len; ++ char *arg_save = 0, *arg_org = 0; ++ int rc; ++ char buf[128]; ++ wl_pkt_filter_enable_t enable_parm; ++ wl_pkt_filter_enable_t * pkt_filterp; ++ ++ if (!arg) ++ return; ++ ++ if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) { ++ AP6211_ERR("%s: kmalloc failed\n", __FUNCTION__); ++ goto fail; ++ } ++ arg_org = arg_save; ++ memcpy(arg_save, arg, strlen(arg) + 1); ++ ++ argv[i] = bcmstrtok(&arg_save, " ", 0); ++ ++ i = 0; ++ if (argv[i] == NULL) { ++ AP6211_ERR("No args provided\n"); ++ goto fail; ++ } ++ ++ str = "pkt_filter_enable"; ++ str_len = strlen(str); ++ bcm_strncpy_s(buf, sizeof(buf), str, str_len); ++ buf[str_len] = '\0'; ++ buf_len = str_len + 1; ++ ++ pkt_filterp = (wl_pkt_filter_enable_t *)(buf + str_len + 1); ++ ++ /* Parse packet filter id. */ ++ enable_parm.id = htod32(strtoul(argv[i], NULL, 0)); ++ ++ /* Parse enable/disable value. */ ++ enable_parm.enable = htod32(enable); ++ ++ buf_len += sizeof(enable_parm); ++ memcpy((char *)pkt_filterp, ++ &enable_parm, ++ sizeof(enable_parm)); ++ ++ /* Enable/disable the specified filter. */ ++ rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); ++ rc = rc >= 0 ? 0 : rc; ++ if (rc) ++ AP6211_DEBUG("%s: failed to add pktfilter %s, retcode = %d\n", ++ __FUNCTION__, arg, rc); ++ else ++ AP6211_DEBUG("%s: successfully added pktfilter %s\n", ++ __FUNCTION__, arg); ++ ++ /* Contorl the master mode */ ++ bcm_mkiovar("pkt_filter_mode", (char *)&master_mode, 4, buf, sizeof(buf)); ++ rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); ++ rc = rc >= 0 ? 0 : rc; ++ if (rc) ++ AP6211_DEBUG("%s: failed to add pktfilter %s, retcode = %d\n", ++ __FUNCTION__, arg, rc); ++ ++fail: ++ if (arg_org) ++ MFREE(dhd->osh, arg_org, strlen(arg) + 1); ++} ++ ++void ++dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg) ++{ ++ const char *str; ++ wl_pkt_filter_t pkt_filter; ++ wl_pkt_filter_t *pkt_filterp; ++ int buf_len; ++ int str_len; ++ int rc; ++ uint32 mask_size; ++ uint32 pattern_size; ++ char *argv[8], * buf = 0; ++ int i = 0; ++ char *arg_save = 0, *arg_org = 0; ++#define BUF_SIZE 2048 ++ ++ if (!arg) ++ return; ++ ++ if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) { ++ AP6211_ERR("%s: kmalloc failed\n", __FUNCTION__); ++ goto fail; ++ } ++ ++ arg_org = arg_save; ++ ++ if (!(buf = MALLOC(dhd->osh, BUF_SIZE))) { ++ AP6211_ERR("%s: kmalloc failed\n", __FUNCTION__); ++ goto fail; ++ } ++ ++ memcpy(arg_save, arg, strlen(arg) + 1); ++ ++ if (strlen(arg) > BUF_SIZE) { ++ AP6211_ERR("Not enough buffer %d < %d\n", (int)strlen(arg), (int)sizeof(buf)); ++ goto fail; ++ } ++ ++ argv[i] = bcmstrtok(&arg_save, " ", 0); ++ while (argv[i++]) ++ argv[i] = bcmstrtok(&arg_save, " ", 0); ++ ++ i = 0; ++ if (argv[i] == NULL) { ++ AP6211_ERR("No args provided\n"); ++ goto fail; ++ } ++ ++ str = "pkt_filter_add"; ++ str_len = strlen(str); ++ bcm_strncpy_s(buf, BUF_SIZE, str, str_len); ++ buf[ str_len ] = '\0'; ++ buf_len = str_len + 1; ++ ++ pkt_filterp = (wl_pkt_filter_t *) (buf + str_len + 1); ++ ++ /* Parse packet filter id. */ ++ pkt_filter.id = htod32(strtoul(argv[i], NULL, 0)); ++ ++ if (argv[++i] == NULL) { ++ AP6211_ERR("Polarity not provided\n"); ++ goto fail; ++ } ++ ++ /* Parse filter polarity. */ ++ pkt_filter.negate_match = htod32(strtoul(argv[i], NULL, 0)); ++ ++ if (argv[++i] == NULL) { ++ AP6211_ERR("Filter type not provided\n"); ++ goto fail; ++ } ++ ++ /* Parse filter type. */ ++ pkt_filter.type = htod32(strtoul(argv[i], NULL, 0)); ++ ++ if (argv[++i] == NULL) { ++ AP6211_ERR("Offset not provided\n"); ++ goto fail; ++ } ++ ++ /* Parse pattern filter offset. */ ++ pkt_filter.u.pattern.offset = htod32(strtoul(argv[i], NULL, 0)); ++ ++ if (argv[++i] == NULL) { ++ AP6211_ERR("Bitmask not provided\n"); ++ goto fail; ++ } ++ ++ /* Parse pattern filter mask. */ ++ mask_size = ++ htod32(wl_pattern_atoh(argv[i], (char *) pkt_filterp->u.pattern.mask_and_pattern)); ++ ++ if (argv[++i] == NULL) { ++ AP6211_ERR("Pattern not provided\n"); ++ goto fail; ++ } ++ ++ /* Parse pattern filter pattern. */ ++ pattern_size = ++ htod32(wl_pattern_atoh(argv[i], ++ (char *) &pkt_filterp->u.pattern.mask_and_pattern[mask_size])); ++ ++ if (mask_size != pattern_size) { ++ AP6211_ERR("Mask and pattern not the same size\n"); ++ goto fail; ++ } ++ ++ pkt_filter.u.pattern.size_bytes = mask_size; ++ buf_len += WL_PKT_FILTER_FIXED_LEN; ++ buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size); ++ ++ /* Keep-alive attributes are set in local variable (keep_alive_pkt), and ++ ** then memcpy'ed into buffer (keep_alive_pktp) since there is no ++ ** guarantee that the buffer is properly aligned. ++ */ ++ memcpy((char *)pkt_filterp, ++ &pkt_filter, ++ WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN); ++ ++ rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); ++ rc = rc >= 0 ? 0 : rc; ++ ++ if (rc) ++ AP6211_DEBUG("%s: failed to add pktfilter %s, retcode = %d\n", ++ __FUNCTION__, arg, rc); ++ else ++ AP6211_DEBUG("%s: successfully added pktfilter %s\n", ++ __FUNCTION__, arg); ++ ++fail: ++ if (arg_org) ++ MFREE(dhd->osh, arg_org, strlen(arg) + 1); ++ ++ if (buf) ++ MFREE(dhd->osh, buf, BUF_SIZE); ++} ++#endif /* PKT_FILTER_SUPPORT */ ++ ++/* ========================== */ ++/* ==== ARP OFFLOAD SUPPORT = */ ++/* ========================== */ ++#ifdef ARP_OFFLOAD_SUPPORT ++void ++dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode) ++{ ++ char iovbuf[32]; ++ int retcode; ++ ++ bcm_mkiovar("arp_ol", (char *)&arp_mode, 4, iovbuf, sizeof(iovbuf)); ++ retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++ retcode = retcode >= 0 ? 0 : retcode; ++ if (retcode) ++ AP6211_DEBUG("%s: failed to set ARP offload mode to 0x%x, retcode = %d\n", ++ __FUNCTION__, arp_mode, retcode); ++ else ++ AP6211_DEBUG("%s: successfully set ARP offload mode to 0x%x\n", ++ __FUNCTION__, arp_mode); ++} ++ ++void ++dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable) ++{ ++ char iovbuf[32]; ++ int retcode; ++ ++ bcm_mkiovar("arpoe", (char *)&arp_enable, 4, iovbuf, sizeof(iovbuf)); ++ retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++ retcode = retcode >= 0 ? 0 : retcode; ++ if (retcode) ++ AP6211_DEBUG("%s: failed to enabe ARP offload to %d, retcode = %d\n", ++ __FUNCTION__, arp_enable, retcode); ++ else ++ AP6211_DEBUG("%s: successfully enabed ARP offload to %d\n", ++ __FUNCTION__, arp_enable); ++ if (arp_enable) { ++ uint32 version; ++ bcm_mkiovar("arp_version", 0, 0, iovbuf, sizeof(iovbuf)); ++ retcode = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0); ++ if (retcode) { ++ AP6211_DEBUG("%s: fail to get version (maybe version 1:retcode = %d\n", ++ __FUNCTION__, retcode); ++ dhd->arp_version = 1; ++ } ++ else { ++ memcpy(&version, iovbuf, sizeof(version)); ++ AP6211_DEBUG("%s: ARP Version= %x\n", __FUNCTION__, version); ++ dhd->arp_version = version; ++ } ++ } ++} ++ ++void ++dhd_aoe_arp_clr(dhd_pub_t *dhd, int idx) ++{ ++ int ret = 0; ++ int iov_len = 0; ++ char iovbuf[128]; ++ ++ if (dhd == NULL) return; ++ if (dhd->arp_version == 1) ++ idx = 0; ++ ++ iov_len = bcm_mkiovar("arp_table_clear", 0, 0, iovbuf, sizeof(iovbuf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx) < 0)) ++ AP6211_ERR("%s failed code %d\n", __FUNCTION__, ret); ++} ++ ++void ++dhd_aoe_hostip_clr(dhd_pub_t *dhd, int idx) ++{ ++ int ret = 0; ++ int iov_len = 0; ++ char iovbuf[128]; ++ ++ if (dhd == NULL) return; ++ if (dhd->arp_version == 1) ++ idx = 0; ++ ++ iov_len = bcm_mkiovar("arp_hostip_clear", 0, 0, iovbuf, sizeof(iovbuf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx)) < 0) ++ AP6211_ERR("%s failed code %d\n", __FUNCTION__, ret); ++} ++ ++void ++dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr, int idx) ++{ ++ int iov_len = 0; ++ char iovbuf[32]; ++ int retcode; ++ ++ ++ if (dhd == NULL) return; ++ if (dhd->arp_version == 1) ++ idx = 0; ++ iov_len = bcm_mkiovar("arp_hostip", (char *)&ipaddr, ++ sizeof(ipaddr), iovbuf, sizeof(iovbuf)); ++ retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx); ++ ++ if (retcode) ++ AP6211_DEBUG("%s: ARP ip addr add failed, retcode = %d\n", ++ __FUNCTION__, retcode); ++ else ++ AP6211_DEBUG("%s: sARP H ipaddr entry added \n", ++ __FUNCTION__); ++} ++ ++int ++dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen, int idx) ++{ ++ int retcode, i; ++ int iov_len; ++ uint32 *ptr32 = buf; ++ bool clr_bottom = FALSE; ++ ++ if (!buf) ++ return -1; ++ if (dhd == NULL) return -1; ++ if (dhd->arp_version == 1) ++ idx = 0; ++ ++ iov_len = bcm_mkiovar("arp_hostip", 0, 0, buf, buflen); ++ BCM_REFERENCE(iov_len); ++ retcode = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, buflen, FALSE, idx); ++ ++ if (retcode) { ++ AP6211_DEBUG("%s: ioctl WLC_GET_VAR error %d\n", ++ __FUNCTION__, retcode); ++ ++ return -1; ++ } ++ ++ /* clean up the buf, ascii reminder */ ++ for (i = 0; i < MAX_IPV4_ENTRIES; i++) { ++ if (!clr_bottom) { ++ if (*ptr32 == 0) ++ clr_bottom = TRUE; ++ } else { ++ *ptr32 = 0; ++ } ++ ptr32++; ++ } ++ ++ return 0; ++} ++#endif /* ARP_OFFLOAD_SUPPORT */ ++ ++/* send up locally generated event */ ++void ++dhd_sendup_event_common(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data) ++{ ++ switch (ntoh32(event->event_type)) { ++#ifdef WLBTAMP ++ case WLC_E_BTA_HCI_EVENT: ++ break; ++#endif /* WLBTAMP */ ++ default: ++ break; ++ } ++ ++ /* Call per-port handler. */ ++ dhd_sendup_event(dhdp, event, data); ++} ++ ++ ++/* ++ * returns = TRUE if associated, FALSE if not associated ++ */ ++bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval) ++{ ++ char bssid[6], zbuf[6]; ++ int ret = -1; ++ ++ bzero(bssid, 6); ++ bzero(zbuf, 6); ++ ++ ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BSSID, (char *)&bssid, ETHER_ADDR_LEN, FALSE, 0); ++ AP6211_DEBUG(" %s WLC_GET_BSSID ioctl res = %d\n", __FUNCTION__, ret); ++ ++ if (ret == BCME_NOTASSOCIATED) { ++ AP6211_DEBUG("%s: not associated! res:%d\n", __FUNCTION__, ret); ++ } ++ ++ if (retval) ++ *retval = ret; ++ ++ if (ret < 0) ++ return FALSE; ++ ++ if ((memcmp(bssid, zbuf, ETHER_ADDR_LEN) != 0)) { ++ /* STA is assocoated BSSID is non zero */ ++ ++ if (bss_buf) { ++ /* return bss if caller provided buf */ ++ memcpy(bss_buf, bssid, ETHER_ADDR_LEN); ++ } ++ return TRUE; ++ } else { ++ AP6211_DEBUG("%s: WLC_GET_BSSID ioctl returned zero bssid\n", __FUNCTION__); ++ return FALSE; ++ } ++} ++ ++ ++/* Function to estimate possible DTIM_SKIP value */ ++int ++dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd) ++{ ++ int bcn_li_dtim; ++ int ret = -1; ++ int dtim_assoc = 0; ++ ++ bcn_li_dtim = dhd->suspend_bcn_li_dtim; ++ ++ /* Check if associated */ ++ if (dhd_is_associated(dhd, NULL, NULL) == FALSE) { ++ AP6211_DEBUG("%s NOT assoc ret %d\n", __FUNCTION__, ret); ++ goto exit; ++ } ++ ++ /* if assoc grab ap's dtim value */ ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_DTIMPRD, ++ &dtim_assoc, sizeof(dtim_assoc), FALSE, 0)) < 0) { ++ AP6211_ERR("%s failed code %d\n", __FUNCTION__, ret); ++ goto exit; ++ } ++ ++ AP6211_ERR("%s bcn_li_dtim=%d DTIM=%d Listen=%d\n", ++ __FUNCTION__, bcn_li_dtim, dtim_assoc, LISTEN_INTERVAL); ++ ++ /* if not assocated just eixt */ ++ if (dtim_assoc == 0) { ++ goto exit; ++ } ++ ++ /* check if sta listen interval fits into AP dtim */ ++ if (dtim_assoc > LISTEN_INTERVAL) { ++ /* AP DTIM to big for our Listen Interval : no dtim skiping */ ++ bcn_li_dtim = 1; ++ AP6211_ERR("%s DTIM=%d > Listen=%d : too big ...\n", ++ __FUNCTION__, dtim_assoc, LISTEN_INTERVAL); ++ goto exit; ++ } ++ ++ if ((bcn_li_dtim * dtim_assoc) > LISTEN_INTERVAL) { ++ /* Round up dtim_skip to fit into STAs Listen Interval */ ++ bcn_li_dtim = (int)(LISTEN_INTERVAL / dtim_assoc); ++ AP6211_DEBUG("%s agjust dtim_skip as %d\n", __FUNCTION__, bcn_li_dtim); ++ } ++ ++exit: ++ return bcn_li_dtim; ++} ++ ++/* Check if the mode supports STA MODE */ ++bool dhd_support_sta_mode(dhd_pub_t *dhd) ++{ ++ ++#ifdef WL_CFG80211 ++ if (!(dhd->op_mode & DHD_FLAG_STA_MODE)) ++ return FALSE; ++ else ++#endif /* WL_CFG80211 */ ++ return TRUE; ++} ++ ++#if defined(PNO_SUPPORT) ++int ++dhd_pno_clean(dhd_pub_t *dhd) ++{ ++ char iovbuf[128]; ++ int pfn_enabled = 0; ++ int iov_len = 0; ++ int ret; ++ ++ /* Disable pfn */ ++ iov_len = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) >= 0) { ++ /* clear pfn */ ++ iov_len = bcm_mkiovar("pfnclear", 0, 0, iovbuf, sizeof(iovbuf)); ++ if (iov_len) { ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, ++ iov_len, TRUE, 0)) < 0) { ++ AP6211_ERR("%s failed code %d\n", __FUNCTION__, ret); ++ } ++ } ++ else { ++ ret = -1; ++ AP6211_ERR("%s failed code %d\n", __FUNCTION__, iov_len); ++ } ++ } ++ else ++ AP6211_ERR("%s failed code %d\n", __FUNCTION__, ret); ++ ++ return ret; ++} ++ ++int ++dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled) ++{ ++ char iovbuf[128]; ++ int ret = -1; ++ ++ if ((!dhd) && ((pfn_enabled != 0) || (pfn_enabled != 1))) { ++ AP6211_ERR("%s error exit\n", __FUNCTION__); ++ return ret; ++ } ++ ++#ifndef WL_SCHED_SCAN ++ if (!dhd_support_sta_mode(dhd)) ++ return (ret); ++ ++ memset(iovbuf, 0, sizeof(iovbuf)); ++ ++ if ((pfn_enabled) && (dhd_is_associated(dhd, NULL, NULL) == TRUE)) { ++ AP6211_ERR("%s pno is NOT enable : called in assoc mode , ignore\n", __FUNCTION__); ++ return ret; ++ } ++#endif /* !WL_SCHED_SCAN */ ++ ++ /* Enable/disable PNO */ ++ if ((ret = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf))) > 0) { ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, ++ iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { ++ AP6211_ERR("%s failed for error=%d\n", __FUNCTION__, ret); ++ return ret; ++ } ++ else { ++ dhd->pno_enable = pfn_enabled; ++ AP6211_DEBUG("%s set pno as %s\n", ++ __FUNCTION__, dhd->pno_enable ? "Enable" : "Disable"); ++ } ++ } ++ else AP6211_ERR("%s failed err=%d\n", __FUNCTION__, ret); ++ ++ return ret; ++} ++ ++/* Function to execute combined scan */ ++int ++dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr, ++ int pno_repeat, int pno_freq_expo_max) ++{ ++ int err = -1; ++ char iovbuf[128]; ++ int k, i; ++ wl_pfn_param_t pfn_param; ++ wl_pfn_t pfn_element; ++ uint len = 0; ++ ++ AP6211_DEBUG("%s nssid=%d nchan=%d\n", __FUNCTION__, nssid, scan_fr); ++ ++ if ((!dhd) || (!ssids_local)) { ++ AP6211_ERR("%s error exit(%s %s)\n", __FUNCTION__, ++ (!dhd)?"dhd is null":"", (!ssids_local)?"ssid is null":""); ++ err = -1; ++ return err; ++ } ++#ifndef WL_SCHED_SCAN ++ if (!dhd_support_sta_mode(dhd)) ++ return err; ++#endif /* !WL_SCHED_SCAN */ ++ ++ /* Check for broadcast ssid */ ++ for (k = 0; k < nssid; k++) { ++ if (!ssids_local[k].SSID_len) { ++ AP6211_ERR("%d: Broadcast SSID is ilegal for PNO setting\n", k); ++ return err; ++ } ++ } ++/* #define PNO_DUMP 1 */ ++#ifdef PNO_DUMP ++ { ++ int j; ++ for (j = 0; j < nssid; j++) { ++ AP6211_ERR("%d: scan for %s size =%d\n", j, ++ ssids_local[j].SSID, ssids_local[j].SSID_len); ++ } ++ } ++#endif /* PNO_DUMP */ ++ ++ /* clean up everything */ ++ if ((err = dhd_pno_clean(dhd)) < 0) { ++ AP6211_ERR("%s failed error=%d\n", __FUNCTION__, err); ++ return err; ++ } ++ memset(iovbuf, 0, sizeof(iovbuf)); ++ memset(&pfn_param, 0, sizeof(pfn_param)); ++ memset(&pfn_element, 0, sizeof(pfn_element)); ++ ++ /* set pfn parameters */ ++ pfn_param.version = htod32(PFN_VERSION); ++ pfn_param.flags = htod16((PFN_LIST_ORDER << SORT_CRITERIA_BIT)); ++ ++ /* check and set extra pno params */ ++ if ((pno_repeat != 0) || (pno_freq_expo_max != 0)) { ++ pfn_param.flags |= htod16(ENABLE << ENABLE_ADAPTSCAN_BIT); ++ pfn_param.repeat = (uchar) (pno_repeat); ++ pfn_param.exp = (uchar) (pno_freq_expo_max); ++ } ++ /* set up pno scan fr */ ++ if (scan_fr != 0) ++ pfn_param.scan_freq = htod32(scan_fr); ++ ++ if (pfn_param.scan_freq > PNO_SCAN_MAX_FW_SEC) { ++ AP6211_ERR("%s pno freq above %d sec\n", __FUNCTION__, PNO_SCAN_MAX_FW_SEC); ++ return err; ++ } ++ if (pfn_param.scan_freq < PNO_SCAN_MIN_FW_SEC) { ++ AP6211_ERR("%s pno freq less %d sec\n", __FUNCTION__, PNO_SCAN_MIN_FW_SEC); ++ return err; ++ } ++ ++ len = bcm_mkiovar("pfn_set", (char *)&pfn_param, sizeof(pfn_param), iovbuf, sizeof(iovbuf)); ++ if ((err = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, len, TRUE, 0)) < 0) { ++ AP6211_ERR("%s pfn_set failed for error=%d\n", ++ __FUNCTION__, err); ++ return err; ++ } ++ ++ /* set all pfn ssid */ ++ for (i = 0; i < nssid; i++) { ++ ++ pfn_element.infra = htod32(DOT11_BSSTYPE_INFRASTRUCTURE); ++ pfn_element.auth = (DOT11_OPEN_SYSTEM); ++ pfn_element.wpa_auth = htod32(WPA_AUTH_PFN_ANY); ++ pfn_element.wsec = htod32(0); ++ pfn_element.infra = htod32(1); ++ pfn_element.flags = htod32(ENABLE << WL_PFN_HIDDEN_BIT); ++ memcpy((char *)pfn_element.ssid.SSID, ssids_local[i].SSID, ssids_local[i].SSID_len); ++ pfn_element.ssid.SSID_len = ssids_local[i].SSID_len; ++ ++ if ((len = ++ bcm_mkiovar("pfn_add", (char *)&pfn_element, ++ sizeof(pfn_element), iovbuf, sizeof(iovbuf))) > 0) { ++ if ((err = ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, len, TRUE, 0)) < 0) { ++ AP6211_ERR("%s failed for i=%d error=%d\n", ++ __FUNCTION__, i, err); ++ return err; ++ } ++ else ++ AP6211_DEBUG("%s set OK with PNO time=%d repeat=%d max_adjust=%d\n", ++ __FUNCTION__, pfn_param.scan_freq, ++ pfn_param.repeat, pfn_param.exp); ++ } ++ else AP6211_ERR("%s failed err=%d\n", __FUNCTION__, err); ++ } ++ ++ /* Enable PNO */ ++ /* dhd_pno_enable(dhd, 1); */ ++ return err; ++} ++ ++int ++dhd_pno_get_status(dhd_pub_t *dhd) ++{ ++ int ret = -1; ++ ++ if (!dhd) ++ return ret; ++ else ++ return (dhd->pno_enable); ++} ++ ++#endif /* OEM_ANDROID && PNO_SUPPORT */ ++ ++#if defined(KEEP_ALIVE) ++int dhd_keep_alive_onoff(dhd_pub_t *dhd) ++{ ++ char buf[256]; ++ const char *str; ++ wl_mkeep_alive_pkt_t mkeep_alive_pkt; ++ wl_mkeep_alive_pkt_t *mkeep_alive_pktp; ++ int buf_len; ++ int str_len; ++ int res = -1; ++ ++ if (!dhd_support_sta_mode(dhd)) ++ return res; ++ ++ AP6211_DEBUG("%s execution\n", __FUNCTION__); ++ ++ str = "mkeep_alive"; ++ str_len = strlen(str); ++ strncpy(buf, str, str_len); ++ buf[ str_len ] = '\0'; ++ mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (buf + str_len + 1); ++ mkeep_alive_pkt.period_msec = CUSTOM_KEEP_ALIVE_SETTING; ++ buf_len = str_len + 1; ++ mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); ++ mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); ++ /* Setup keep alive zero for null packet generation */ ++ mkeep_alive_pkt.keep_alive_id = 0; ++ mkeep_alive_pkt.len_bytes = 0; ++ buf_len += WL_MKEEP_ALIVE_FIXED_LEN; ++ bzero(mkeep_alive_pkt.data, sizeof(mkeep_alive_pkt.data)); ++ /* Keep-alive attributes are set in local variable (mkeep_alive_pkt), and ++ * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no ++ * guarantee that the buffer is properly aligned. ++ */ ++ memcpy((char *)mkeep_alive_pktp, &mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN); ++ ++ res = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); ++ ++ return res; ++} ++#endif /* defined(KEEP_ALIVE) */ ++/* Android ComboSCAN support */ ++ ++/* ++ * data parsing from ComboScan tlv list ++*/ ++int ++wl_iw_parse_data_tlv(char** list_str, void *dst, int dst_size, const char token, ++ int input_size, int *bytes_left) ++{ ++ char* str; ++ uint16 short_temp; ++ uint32 int_temp; ++ ++ if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) { ++ AP6211_ERR("%s error paramters\n", __FUNCTION__); ++ return -1; ++ } ++ str = *list_str; ++ ++ /* Clean all dest bytes */ ++ memset(dst, 0, dst_size); ++ while (*bytes_left > 0) { ++ ++ if (str[0] != token) { ++ AP6211_DEBUG("%s NOT Type=%d get=%d left_parse=%d \n", ++ __FUNCTION__, token, str[0], *bytes_left); ++ return -1; ++ } ++ ++ *bytes_left -= 1; ++ str += 1; ++ ++ if (input_size == 1) { ++ memcpy(dst, str, input_size); ++ } ++ else if (input_size == 2) { ++ memcpy(dst, (char *)htod16(memcpy(&short_temp, str, input_size)), ++ input_size); ++ } ++ else if (input_size == 4) { ++ memcpy(dst, (char *)htod32(memcpy(&int_temp, str, input_size)), ++ input_size); ++ } ++ ++ *bytes_left -= input_size; ++ str += input_size; ++ *list_str = str; ++ return 1; ++ } ++ return 1; ++} ++ ++/* ++ * channel list parsing from cscan tlv list ++*/ ++int ++wl_iw_parse_channel_list_tlv(char** list_str, uint16* channel_list, ++ int channel_num, int *bytes_left) ++{ ++ char* str; ++ int idx = 0; ++ ++ if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) { ++ AP6211_ERR("%s error paramters\n", __FUNCTION__); ++ return -1; ++ } ++ str = *list_str; ++ ++ while (*bytes_left > 0) { ++ ++ if (str[0] != CSCAN_TLV_TYPE_CHANNEL_IE) { ++ *list_str = str; ++ AP6211_DEBUG("End channel=%d left_parse=%d %d\n", idx, *bytes_left, str[0]); ++ return idx; ++ } ++ /* Get proper CSCAN_TLV_TYPE_CHANNEL_IE */ ++ *bytes_left -= 1; ++ str += 1; ++ ++ if (str[0] == 0) { ++ /* All channels */ ++ channel_list[idx] = 0x0; ++ } ++ else { ++ channel_list[idx] = (uint16)str[0]; ++ AP6211_DEBUG("%s channel=%d \n", __FUNCTION__, channel_list[idx]); ++ } ++ *bytes_left -= 1; ++ str += 1; ++ ++ if (idx++ > 255) { ++ AP6211_ERR("%s Too many channels \n", __FUNCTION__); ++ return -1; ++ } ++ } ++ ++ *list_str = str; ++ return idx; ++} ++ ++/* ++ * SSIDs list parsing from cscan tlv list ++ */ ++int ++wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid, int max, int *bytes_left) ++{ ++ char* str; ++ int idx = 0; ++ ++ if ((list_str == NULL) || (*list_str == NULL) || (*bytes_left < 0)) { ++ AP6211_ERR("%s error paramters\n", __FUNCTION__); ++ return -1; ++ } ++ str = *list_str; ++ while (*bytes_left > 0) { ++ ++ if (str[0] != CSCAN_TLV_TYPE_SSID_IE) { ++ *list_str = str; ++ AP6211_DEBUG("nssid=%d left_parse=%d %d\n", idx, *bytes_left, str[0]); ++ return idx; ++ } ++ ++ /* Get proper CSCAN_TLV_TYPE_SSID_IE */ ++ *bytes_left -= 1; ++ str += 1; ++ ++ if (str[0] == 0) { ++ /* Broadcast SSID */ ++ ssid[idx].SSID_len = 0; ++ memset((char*)ssid[idx].SSID, 0x0, DOT11_MAX_SSID_LEN); ++ *bytes_left -= 1; ++ str += 1; ++ ++ AP6211_DEBUG("BROADCAST SCAN left=%d\n", *bytes_left); ++ } ++ else if (str[0] <= DOT11_MAX_SSID_LEN) { ++ /* Get proper SSID size */ ++ ssid[idx].SSID_len = str[0]; ++ *bytes_left -= 1; ++ str += 1; ++ ++ /* Get SSID */ ++ if (ssid[idx].SSID_len > *bytes_left) { ++ AP6211_ERR("%s out of memory range len=%d but left=%d\n", ++ __FUNCTION__, ssid[idx].SSID_len, *bytes_left); ++ return -1; ++ } ++ ++ memcpy((char*)ssid[idx].SSID, str, ssid[idx].SSID_len); ++ ++ *bytes_left -= ssid[idx].SSID_len; ++ str += ssid[idx].SSID_len; ++ ++ AP6211_DEBUG("%s :size=%d left=%d\n", ++ (char*)ssid[idx].SSID, ssid[idx].SSID_len, *bytes_left); ++ } ++ else { ++ AP6211_ERR("### SSID size more that %d\n", str[0]); ++ return -1; ++ } ++ ++ if (idx++ > max) { ++ AP6211_ERR("%s number of SSIDs more that %d\n", __FUNCTION__, idx); ++ return -1; ++ } ++ } ++ ++ *list_str = str; ++ return idx; ++} ++ ++/* Parse a comma-separated list from list_str into ssid array, starting ++ * at index idx. Max specifies size of the ssid array. Parses ssids ++ * and returns updated idx; if idx >= max not all fit, the excess have ++ * not been copied. Returns -1 on empty string, or on ssid too long. ++ */ ++int ++wl_iw_parse_ssid_list(char** list_str, wlc_ssid_t* ssid, int idx, int max) ++{ ++ char* str, *ptr; ++ ++ if ((list_str == NULL) || (*list_str == NULL)) ++ return -1; ++ ++ for (str = *list_str; str != NULL; str = ptr) { ++ ++ /* check for next TAG */ ++ if (!strncmp(str, GET_CHANNEL, strlen(GET_CHANNEL))) { ++ *list_str = str + strlen(GET_CHANNEL); ++ return idx; ++ } ++ ++ if ((ptr = strchr(str, ',')) != NULL) { ++ *ptr++ = '\0'; ++ } ++ ++ if (strlen(str) > DOT11_MAX_SSID_LEN) { ++ AP6211_ERR("ssid <%s> exceeds %d\n", str, DOT11_MAX_SSID_LEN); ++ return -1; ++ } ++ ++ if (strlen(str) == 0) ++ ssid[idx].SSID_len = 0; ++ ++ if (idx < max) { ++ bzero(ssid[idx].SSID, sizeof(ssid[idx].SSID)); ++ strncpy((char*)ssid[idx].SSID, str, sizeof(ssid[idx].SSID) - 1); ++ ssid[idx].SSID_len = strlen(str); ++ } ++ idx++; ++ } ++ return idx; ++} ++ ++/* ++ * Parse channel list from iwpriv CSCAN ++ */ ++int ++wl_iw_parse_channel_list(char** list_str, uint16* channel_list, int channel_num) ++{ ++ int num; ++ int val; ++ char* str; ++ char* endptr = NULL; ++ ++ if ((list_str == NULL)||(*list_str == NULL)) ++ return -1; ++ ++ str = *list_str; ++ num = 0; ++ while (strncmp(str, GET_NPROBE, strlen(GET_NPROBE))) { ++ val = (int)strtoul(str, &endptr, 0); ++ if (endptr == str) { ++ AP6211_ERR("could not parse channel number starting at" ++ " substring \"%s\" in list:\n%s\n", ++ str, *list_str); ++ return -1; ++ } ++ str = endptr + strspn(endptr, " ,"); ++ ++ if (num == channel_num) { ++ AP6211_ERR("too many channels (more than %d) in channel list:\n%s\n", ++ channel_num, *list_str); ++ return -1; ++ } ++ ++ channel_list[num++] = (uint16)val; ++ } ++ *list_str = str; ++ return num; ++} +diff --git a/drivers/net/wireless/ap6211/dhd_custom_gpio.c b/drivers/net/wireless/ap6211/dhd_custom_gpio.c +new file mode 100755 +index 0000000..afdb9b3 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_custom_gpio.c +@@ -0,0 +1,313 @@ ++/* ++* Customer code to add GPIO control during WLAN start/stop ++* Copyright (C) 1999-2012, Broadcom Corporation ++* ++* Unless you and Broadcom execute a separate written software license ++* agreement governing use of this software, this software is licensed to you ++* under the terms of the GNU General Public License version 2 (the "GPL"), ++* available at http://www.broadcom.com/licenses/GPLv2.php, with the ++* following added to such license: ++* ++* As a special exception, the copyright holders of this software give you ++* permission to link this software with independent modules, and to copy and ++* distribute the resulting executable under terms of your choice, provided that ++* you also meet, for each linked independent module, the terms and conditions of ++* the license of that module. An independent module is a module which is not ++* derived from this software. The special exception does not apply to any ++* modifications of the software. ++* ++* Notwithstanding the above, under no circumstances may you combine this ++* software in any way with any other Broadcom software provided under a license ++* other than the GPL, without Broadcom's express prior written consent. ++* ++* $Id: dhd_custom_gpio.c 353167 2012-08-24 22:11:30Z $ ++*/ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++ ++extern void sunximmc_rescan_card(unsigned id, unsigned insert); ++ ++#ifdef CUSTOMER_HW ++#include ++#if defined(CUSTOMER_OOB) ++extern int bcm_wlan_get_oob_irq(void); ++#endif ++extern void bcm_wlan_power_off(int); ++extern void bcm_wlan_power_on(int); ++#endif /* CUSTOMER_HW */ ++#if defined(CUSTOMER_HW2) ++#ifdef CONFIG_WIFI_CONTROL_FUNC ++int wifi_set_power(int on, unsigned long msec); ++int wifi_get_irq_number(unsigned long *irq_flags_ptr); ++int wifi_get_mac_addr(unsigned char *buf); ++void *wifi_get_country_code(char *ccode); ++#else ++int wifi_set_power(int on, unsigned long msec) { return -1; } ++int wifi_get_irq_number(unsigned long *irq_flags_ptr) { return -1; } ++int wifi_get_mac_addr(unsigned char *buf) { return -1; } ++void *wifi_get_country_code(char *ccode) { return NULL; } ++#endif /* CONFIG_WIFI_CONTROL_FUNC */ ++#endif ++ ++#if defined(OOB_INTR_ONLY) ++ ++#if defined(BCMLXSDMMC) ++extern int sdioh_mmc_irq(int irq); ++#endif /* (BCMLXSDMMC) */ ++ ++#ifdef CUSTOMER_HW3 ++#include ++#endif ++ ++/* Customer specific Host GPIO defintion */ ++static int dhd_oob_gpio_num = 2; ++ ++module_param(dhd_oob_gpio_num, int, 0644); ++MODULE_PARM_DESC(dhd_oob_gpio_num, "DHD oob gpio number"); ++ ++/* This function will return: ++ * 1) return : Host gpio interrupt number per customer platform ++ * 2) irq_flags_ptr : Type of Host interrupt as Level or Edge ++ * ++ * NOTE : ++ * Customer should check his platform definitions ++ * and his Host Interrupt spec ++ * to figure out the proper setting for his platform. ++ * Broadcom provides just reference settings as example. ++ * ++ */ ++int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr) ++{ ++ int host_oob_irq = -1; ++ ++#if defined(CUSTOMER_HW2) ++ host_oob_irq = wifi_get_irq_number(irq_flags_ptr); ++ ++#elif defined(CUSTOMER_OOB) ++ host_oob_irq = bcm_wlan_get_oob_irq(); ++ AP6211_DEBUG("irq=%d, flags=0x%08lx\n", host_oob_irq, *irq_flags_ptr); ++#else ++#if defined(CUSTOM_OOB_GPIO_NUM) ++ if (dhd_oob_gpio_num < 0) { ++ dhd_oob_gpio_num = CUSTOM_OOB_GPIO_NUM; ++ } ++#endif /* CUSTOMER_OOB_GPIO_NUM */ ++ ++ if (dhd_oob_gpio_num < 0) { ++ AP6211_ERR("%s: ERROR customer specific Host GPIO is NOT defined \n", ++ __FUNCTION__); ++ return (dhd_oob_gpio_num); ++ } ++ ++ AP6211_ERR("%s: customer specific Host GPIO number is (%d)\n", ++ __FUNCTION__, dhd_oob_gpio_num); ++ ++#if defined CUSTOMER_HW ++ AP6211_ERR("%s: should not be here!\n", __FUNCTION__); ++#elif defined CUSTOMER_HW3 ++ gpio_request(dhd_oob_gpio_num, "oob irq"); ++ host_oob_irq = gpio_to_irq(dhd_oob_gpio_num); ++ gpio_direction_input(dhd_oob_gpio_num); ++#endif /* CUSTOMER_HW */ ++#endif ++ ++ return (host_oob_irq); ++} ++#endif ++ ++/* Customer function to control hw specific wlan gpios */ ++void ++dhd_customer_gpio_wlan_ctrl(int onoff) ++{ ++ static int sdc_id = 3; ++ ++ switch (onoff) { ++ case WLAN_RESET_OFF: ++ AP6211_DEBUG("%s: call customer specific GPIO to insert WLAN RESET\n", ++ __FUNCTION__); ++#ifdef CUSTOMER_HW ++ ap6211_gpio_wifi_power(0); ++#endif /* CUSTOMER_HW */ ++#if defined(CUSTOMER_HW2) ++ wifi_set_power(0, 0); ++#endif ++ mdelay(100); ++ AP6211_ERR("WLAN placed in RESET\n"); ++ break; ++ ++ case WLAN_RESET_ON: ++ AP6211_DEBUG("%s: callc customer specific GPIO to remove WLAN RESET\n", ++ __FUNCTION__); ++#ifdef CUSTOMER_HW ++ ap6211_gpio_wifi_power(1); ++#endif /* CUSTOMER_HW */ ++#if defined(CUSTOMER_HW2) ++ wifi_set_power(1, 0); ++#endif ++ mdelay(100); ++ AP6211_ERR("WLAN going back to live\n"); ++ break; ++ ++ case WLAN_POWER_OFF: ++ AP6211_DEBUG("%s: call customer specific GPIO to turn off WL_REG_ON\n", ++ __FUNCTION__); ++#ifdef CUSTOMER_HW ++ ap6211_gpio_wifi_power(0); ++ sunximmc_rescan_card(sdc_id, 0); ++#endif /* CUSTOMER_HW */ ++ AP6211_ERR("WLAN placed in POWER OFF\n"); ++ break; ++ ++ case WLAN_POWER_ON: ++ AP6211_DEBUG("%s: call customer specific GPIO to turn on WL_REG_ON\n", ++ __FUNCTION__); ++#ifdef CUSTOMER_HW ++ ap6211_gpio_wifi_power(1); ++ sunximmc_rescan_card(sdc_id, 1); ++ /* Lets customer power to get stable */ ++#endif /* CUSTOMER_HW */ ++ mdelay(100); ++ AP6211_ERR("WLAN placed in POWER ON\n"); ++ break; ++ } ++} ++ ++#ifdef GET_CUSTOM_MAC_ENABLE ++/* Function to get custom MAC address */ ++int ++dhd_custom_get_mac_address(unsigned char *buf) ++{ ++ int ret = 0; ++ ++ AP6211_DEBUG("%s Enter\n", __FUNCTION__); ++ if (!buf) ++ return -EINVAL; ++ ++ /* Customer access to MAC address stored outside of DHD driver */ ++#if defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) ++ ret = wifi_get_mac_addr(buf); ++#endif ++ ++#ifdef EXAMPLE_GET_MAC ++ /* EXAMPLE code */ ++ { ++ struct ether_addr ea_example = {{0x00, 0x11, 0x22, 0x33, 0x44, 0xFF}}; ++ bcopy((char *)&ea_example, buf, sizeof(struct ether_addr)); ++ } ++#endif /* EXAMPLE_GET_MAC */ ++ ++ return ret; ++} ++#endif /* GET_CUSTOM_MAC_ENABLE */ ++ ++/* Customized Locale table : OPTIONAL feature */ ++const struct cntry_locales_custom translate_custom_table[] = { ++/* Table should be filled out based on custom platform regulatory requirement */ ++#ifdef EXAMPLE_TABLE ++ {"", "XY", 4}, /* Universal if Country code is unknown or empty */ ++ {"US", "US", 69}, /* input ISO "US" to : US regrev 69 */ ++ {"CA", "US", 69}, /* input ISO "CA" to : US regrev 69 */ ++ {"EU", "EU", 5}, /* European union countries to : EU regrev 05 */ ++ {"AT", "EU", 5}, ++ {"BE", "EU", 5}, ++ {"BG", "EU", 5}, ++ {"CY", "EU", 5}, ++ {"CZ", "EU", 5}, ++ {"DK", "EU", 5}, ++ {"EE", "EU", 5}, ++ {"FI", "EU", 5}, ++ {"FR", "EU", 5}, ++ {"DE", "EU", 5}, ++ {"GR", "EU", 5}, ++ {"HU", "EU", 5}, ++ {"IE", "EU", 5}, ++ {"IT", "EU", 5}, ++ {"LV", "EU", 5}, ++ {"LI", "EU", 5}, ++ {"LT", "EU", 5}, ++ {"LU", "EU", 5}, ++ {"MT", "EU", 5}, ++ {"NL", "EU", 5}, ++ {"PL", "EU", 5}, ++ {"PT", "EU", 5}, ++ {"RO", "EU", 5}, ++ {"SK", "EU", 5}, ++ {"SI", "EU", 5}, ++ {"ES", "EU", 5}, ++ {"SE", "EU", 5}, ++ {"GB", "EU", 5}, ++ {"KR", "XY", 3}, ++ {"AU", "XY", 3}, ++ {"CN", "XY", 3}, /* input ISO "CN" to : XY regrev 03 */ ++ {"TW", "XY", 3}, ++ {"AR", "XY", 3}, ++ {"MX", "XY", 3}, ++ {"IL", "IL", 0}, ++ {"CH", "CH", 0}, ++ {"TR", "TR", 0}, ++ {"NO", "NO", 0}, ++#endif /* EXMAPLE_TABLE */ ++}; ++ ++ ++/* Customized Locale convertor ++* input : ISO 3166-1 country abbreviation ++* output: customized cspec ++*/ ++void get_customized_country_code(char *country_iso_code, wl_country_t *cspec) ++{ ++#if defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) ++ ++ struct cntry_locales_custom *cloc_ptr; ++ ++ if (!cspec) ++ return; ++ ++ cloc_ptr = wifi_get_country_code(country_iso_code); ++ if (cloc_ptr) { ++ strlcpy(cspec->ccode, cloc_ptr->custom_locale, WLC_CNTRY_BUF_SZ); ++ cspec->rev = cloc_ptr->custom_locale_rev; ++ } ++ return; ++#else ++ int size, i; ++ ++ size = ARRAYSIZE(translate_custom_table); ++ ++ if (cspec == 0) ++ return; ++ ++ if (size == 0) ++ return; ++ ++ for (i = 0; i < size; i++) { ++ if (strcmp(country_iso_code, translate_custom_table[i].iso_abbrev) == 0) { ++ memcpy(cspec->ccode, ++ translate_custom_table[i].custom_locale, WLC_CNTRY_BUF_SZ); ++ cspec->rev = translate_custom_table[i].custom_locale_rev; ++ return; ++ } ++ } ++#ifdef EXAMPLE_TABLE ++ /* if no country code matched return first universal code from translate_custom_table */ ++ memcpy(cspec->ccode, translate_custom_table[0].custom_locale, WLC_CNTRY_BUF_SZ); ++ cspec->rev = translate_custom_table[0].custom_locale_rev; ++#endif /* EXMAPLE_TABLE */ ++ return; ++#endif /* defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)) */ ++} +diff --git a/drivers/net/wireless/ap6211/dhd_dbg.h b/drivers/net/wireless/ap6211/dhd_dbg.h +new file mode 100755 +index 0000000..67cd2e5 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_dbg.h +@@ -0,0 +1,79 @@ ++/* ++ * Debug/trace/assert driver definitions for Dongle Host Driver. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd_dbg.h 353490 2012-08-27 21:10:02Z $ ++ */ ++ ++#ifndef _dhd_dbg_ ++#define _dhd_dbg_ ++ ++#define USE_NET_RATELIMIT net_ratelimit() ++ ++#if defined(DHD_DEBUG) ++ ++#define DHD_ERROR_ON() (dhd_msg_level & DHD_ERROR_VAL) ++#define DHD_TRACE_ON() (dhd_msg_level & DHD_TRACE_VAL) ++#define DHD_INFO_ON() (dhd_msg_level & DHD_INFO_VAL) ++#define DHD_DATA_ON() (dhd_msg_level & DHD_DATA_VAL) ++#define DHD_CTL_ON() (dhd_msg_level & DHD_CTL_VAL) ++#define DHD_TIMER_ON() (dhd_msg_level & DHD_TIMER_VAL) ++#define DHD_HDRS_ON() (dhd_msg_level & DHD_HDRS_VAL) ++#define DHD_BYTES_ON() (dhd_msg_level & DHD_BYTES_VAL) ++#define DHD_INTR_ON() (dhd_msg_level & DHD_INTR_VAL) ++#define DHD_GLOM_ON() (dhd_msg_level & DHD_GLOM_VAL) ++#define DHD_EVENT_ON() (dhd_msg_level & DHD_EVENT_VAL) ++#define DHD_BTA_ON() (dhd_msg_level & DHD_BTA_VAL) ++#define DHD_ISCAN_ON() (dhd_msg_level & DHD_ISCAN_VAL) ++#define DHD_ARPOE_ON() (dhd_msg_level & DHD_ARPOE_VAL) ++#define DHD_REORDER_ON() (dhd_msg_level & DHD_REORDER_VAL) ++ ++#else /* defined(BCMDBG) || defined(DHD_DEBUG) */ ++ ++#define DHD_ERROR_ON() 0 ++#define DHD_TRACE_ON() 0 ++#define DHD_INFO_ON() 0 ++#define DHD_DATA_ON() 0 ++#define DHD_CTL_ON() 0 ++#define DHD_TIMER_ON() 0 ++#define DHD_HDRS_ON() 0 ++#define DHD_BYTES_ON() 0 ++#define DHD_INTR_ON() 0 ++#define DHD_GLOM_ON() 0 ++#define DHD_EVENT_ON() 0 ++#define DHD_BTA_ON() 0 ++#define DHD_ISCAN_ON() 0 ++#define DHD_ARPOE_ON() 0 ++#define DHD_REORDER_ON() 0 ++#endif ++ ++#define DHD_LOG(args) ++ ++#define DHD_BLOG(cp, size) ++ ++#define DHD_NONE(args) ++extern int dhd_msg_level; ++ ++/* Defines msg bits */ ++#include ++ ++#endif /* _dhd_dbg_ */ +diff --git a/drivers/net/wireless/ap6211/dhd_gpio.c b/drivers/net/wireless/ap6211/dhd_gpio.c +new file mode 100755 +index 0000000..dae0dd3 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_gpio.c +@@ -0,0 +1,47 @@ ++/* ++* Customer code to add GPIO control during WLAN start/stop ++* Copyright (C) 1999-2011, Broadcom Corporation ++* ++* Unless you and Broadcom execute a separate written software license ++* agreement governing use of this software, this software is licensed to you ++* under the terms of the GNU General Public License version 2 (the "GPL"), ++* available at http://www.broadcom.com/licenses/GPLv2.php, with the ++* following added to such license: ++* ++* As a special exception, the copyright holders of this software give you ++* permission to link this software with independent modules, and to copy and ++* distribute the resulting executable under terms of your choice, provided that ++* you also meet, for each linked independent module, the terms and conditions of ++* the license of that module. An independent module is a module which is not ++* derived from this software. The special exception does not apply to any ++* modifications of the software. ++* ++* Notwithstanding the above, under no circumstances may you combine this ++* software in any way with any other Broadcom software provided under a license ++* other than the GPL, without Broadcom's express prior written consent. ++* ++* $Id: dhd_custom_gpio.c,v 1.2.42.1 2010-10-19 00:41:09 Exp $ ++*/ ++ ++#include ++ ++#include ++#include ++ ++#ifdef CUSTOMER_HW ++ ++extern int __gpio_to_irq(unsigned gpio); ++extern int gpio_direction_input(unsigned gpio); ++extern int gpio_request(unsigned gpio, const char *label); ++extern void gpio_free(unsigned gpio); ++ ++#ifdef CUSTOMER_OOB ++extern int wl_host_wake_irqno; ++int bcm_wlan_get_oob_irq(void) ++{ ++ return wl_host_wake_irqno; ++} ++#endif ++ ++ ++#endif /* CUSTOMER_HW */ +diff --git a/drivers/net/wireless/ap6211/dhd_ip.c b/drivers/net/wireless/ap6211/dhd_ip.c +new file mode 100755 +index 0000000..05abc93 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_ip.c +@@ -0,0 +1,111 @@ ++/* ++ * IP Packet Parser Module. ++ * ++ * Copyright (C) 1999-2013, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id$ ++ */ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++ ++/* special values */ ++/* 802.3 llc/snap header */ ++static const uint8 llc_snap_hdr[SNAP_HDR_LEN] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; ++ ++pkt_frag_t pkt_frag_info(osl_t *osh, void *p) ++{ ++ uint8 *frame; ++ int length; ++ uint8 *pt; /* Pointer to type field */ ++ uint16 ethertype; ++ struct ipv4_hdr *iph; /* IP frame pointer */ ++ int ipl; /* IP frame length */ ++ uint16 iph_frag; ++ ++ ASSERT(osh && p); ++ ++ frame = PKTDATA(osh, p); ++ length = PKTLEN(osh, p); ++ ++ /* Process Ethernet II or SNAP-encapsulated 802.3 frames */ ++ if (length < ETHER_HDR_LEN) { ++ AP6211_DEBUG("%s: short eth frame (%d)\n", __FUNCTION__, length); ++ return DHD_PKT_FRAG_NONE; ++ } else if (ntoh16(*(uint16 *)(frame + ETHER_TYPE_OFFSET)) >= ETHER_TYPE_MIN) { ++ /* Frame is Ethernet II */ ++ pt = frame + ETHER_TYPE_OFFSET; ++ } else if (length >= ETHER_HDR_LEN + SNAP_HDR_LEN + ETHER_TYPE_LEN && ++ !bcmp(llc_snap_hdr, frame + ETHER_HDR_LEN, SNAP_HDR_LEN)) { ++ pt = frame + ETHER_HDR_LEN + SNAP_HDR_LEN; ++ } else { ++ AP6211_DEBUG("%s: non-SNAP 802.3 frame\n", __FUNCTION__); ++ return DHD_PKT_FRAG_NONE; ++ } ++ ++ ethertype = ntoh16(*(uint16 *)pt); ++ ++ /* Skip VLAN tag, if any */ ++ if (ethertype == ETHER_TYPE_8021Q) { ++ pt += VLAN_TAG_LEN; ++ ++ if (pt + ETHER_TYPE_LEN > frame + length) { ++ AP6211_DEBUG("%s: short VLAN frame (%d)\n", __FUNCTION__, length); ++ return DHD_PKT_FRAG_NONE; ++ } ++ ++ ethertype = ntoh16(*(uint16 *)pt); ++ } ++ ++ if (ethertype != ETHER_TYPE_IP) { ++ AP6211_DEBUG("%s: non-IP frame (ethertype 0x%x, length %d)\n", ++ __FUNCTION__, ethertype, length); ++ return DHD_PKT_FRAG_NONE; ++ } ++ ++ iph = (struct ipv4_hdr *)(pt + ETHER_TYPE_LEN); ++ ipl = length - (pt + ETHER_TYPE_LEN - frame); ++ ++ /* We support IPv4 only */ ++ if ((ipl < IPV4_OPTIONS_OFFSET) || (IP_VER(iph) != IP_VER_4)) { ++ AP6211_DEBUG("%s: short frame (%d) or non-IPv4\n", __FUNCTION__, ipl); ++ return DHD_PKT_FRAG_NONE; ++ } ++ ++ iph_frag = ntoh16(iph->frag); ++ ++ if (iph_frag & IPV4_FRAG_DONT) { ++ return DHD_PKT_FRAG_NONE; ++ } else if ((iph_frag & IPV4_FRAG_MORE) == 0) { ++ return DHD_PKT_FRAG_LAST; ++ } else { ++ return (iph_frag & IPV4_FRAG_OFFSET_MASK)? DHD_PKT_FRAG_CONT : DHD_PKT_FRAG_FIRST; ++ } ++} +diff --git a/drivers/net/wireless/ap6211/dhd_ip.h b/drivers/net/wireless/ap6211/dhd_ip.h +new file mode 100755 +index 0000000..ceb3877 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_ip.h +@@ -0,0 +1,42 @@ ++/* ++ * Header file describing the common ip parser function. ++ * ++ * Provides type definitions and function prototypes used to parse ip packet. ++ * ++ * Copyright (C) 1999-2013, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id$ ++ */ ++ ++#ifndef _dhd_ip_h_ ++#define _dhd_ip_h_ ++ ++typedef enum pkt_frag ++{ ++ DHD_PKT_FRAG_NONE = 0, ++ DHD_PKT_FRAG_FIRST, ++ DHD_PKT_FRAG_CONT, ++ DHD_PKT_FRAG_LAST ++} pkt_frag_t; ++ ++extern pkt_frag_t pkt_frag_info(osl_t *osh, void *p); ++ ++#endif /* _dhd_ip_h_ */ +diff --git a/drivers/net/wireless/ap6211/dhd_linux.c b/drivers/net/wireless/ap6211/dhd_linux.c +new file mode 100755 +index 0000000..28fe811 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_linux.c +@@ -0,0 +1,6152 @@ ++/* ++ * Broadcom Dongle Host Driver (DHD), Linux-specific network interface ++ * Basically selected code segments from usb-cdc.c and usb-rndis.c ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd_linux.c 374275 2012-12-12 11:44:18Z $ ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef CONFIG_HAS_WAKELOCK ++#include ++#endif ++#ifdef WL_CFG80211 ++#include ++#endif ++ ++#ifdef WLBTAMP ++#include ++#include ++#include ++#endif ++ ++#include ++#include ++ ++#ifdef WLMEDIA_HTSF ++#include ++#include ++ ++#define HTSF_MINLEN 200 /* min. packet length to timestamp */ ++#define HTSF_BUS_DELAY 150 /* assume a fix propagation in us */ ++#define TSMAX 1000 /* max no. of timing record kept */ ++#define NUMBIN 34 ++static uint32 tsidx = 0; ++static uint32 htsf_seqnum = 0; ++uint32 tsfsync; ++struct timeval tsync; ++static uint32 tsport = 5010; ++ ++typedef struct histo_ { ++ uint32 bin[NUMBIN]; ++} histo_t; ++ ++#if !ISPOWEROF2(DHD_SDALIGN) ++#error DHD_SDALIGN is not a power of 2! ++#endif ++ ++static histo_t vi_d1, vi_d2, vi_d3, vi_d4; ++#endif /* WLMEDIA_HTSF */ ++ ++#if defined(PKT_FILTER_SUPPORT) ++#endif /* PKT_FILTER_SUPPORT */ ++ ++#if defined(SOFTAP) ++extern bool ap_cfg_running; ++extern bool ap_fw_loaded; ++#endif ++ ++/* enable HOSTIP cache update from the host side when an eth0:N is up */ ++#define AOE_IP_ALIAS_SUPPORT 1 ++ ++#ifdef BCM_FD_AGGR ++#include ++#include ++#endif ++#ifdef PROP_TXSTATUS ++#include ++#include ++#endif ++ ++#include ++ ++#ifdef ARP_OFFLOAD_SUPPORT ++void aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx); ++static int dhd_device_event(struct notifier_block *this, ++ unsigned long event, ++ void *ptr); ++ ++static struct notifier_block dhd_notifier = { ++ .notifier_call = dhd_device_event ++}; ++#endif /* ARP_OFFLOAD_SUPPORT */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) ++#include ++volatile bool dhd_mmc_suspend = FALSE; ++DECLARE_WAIT_QUEUE_HEAD(dhd_dpc_wait); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ ++ ++#if defined(OOB_INTR_ONLY) ++extern void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable); ++#endif ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (1) ++static void dhd_hang_process(struct work_struct *work); ++#endif ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) ++MODULE_LICENSE("GPL v2"); ++#endif /* LinuxVer */ ++ ++#include ++ ++#ifdef BCM_FD_AGGR ++#define DBUS_RX_BUFFER_SIZE_DHD(net) (BCM_RPC_TP_DNGL_AGG_MAX_BYTE) ++#else ++#ifndef PROP_TXSTATUS ++#define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen) ++#else ++#define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen + 128) ++#endif ++#endif /* BCM_FD_AGGR */ ++ ++#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) ++const char * ++print_tainted() ++{ ++ return ""; ++} ++#endif /* LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) */ ++ ++/* Linux wireless extension support */ ++#if defined(CONFIG_WIRELESS_EXT) ++#include ++extern wl_iw_extra_params_t g_wl_iw_params; ++#endif /* defined(CONFIG_WIRELESS_EXT) */ ++ ++#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) ++#include ++#endif /* defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) */ ++ ++extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd); ++ ++#ifdef PKT_FILTER_SUPPORT ++extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg); ++extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode); ++#endif ++ ++#ifdef READ_MACADDR ++extern int dhd_read_macaddr(struct dhd_info *dhd, struct ether_addr *mac); ++#endif ++#ifdef RDWR_MACADDR ++extern int dhd_check_rdwr_macaddr(struct dhd_info *dhd, dhd_pub_t *dhdp, struct ether_addr *mac); ++extern int dhd_write_rdwr_macaddr(struct ether_addr *mac); ++#endif ++#ifdef WRITE_MACADDR ++extern int dhd_write_macaddr(struct ether_addr *mac); ++#endif ++#ifdef GET_MAC_FROM_OTP ++extern int dhd_check_module_mac(dhd_pub_t *dhd, struct ether_addr *mac); ++#endif ++#ifdef MIMO_ANT_SETTING ++extern int dhd_sel_ant_from_file(dhd_pub_t *dhd); ++#endif ++ ++#ifdef GLOBALCONFIG_WLAN_COUNTRY_CODE ++int dhd_customer_set_country(dhd_pub_t *dhd); ++#endif ++ ++/* Interface control information */ ++typedef struct dhd_if { ++ struct dhd_info *info; /* back pointer to dhd_info */ ++ /* OS/stack specifics */ ++ struct net_device *net; ++ struct net_device_stats stats; ++ int idx; /* iface idx in dongle */ ++ dhd_if_state_t state; /* interface state */ ++ uint subunit; /* subunit */ ++ uint8 mac_addr[ETHER_ADDR_LEN]; /* assigned MAC address */ ++ bool attached; /* Delayed attachment when unset */ ++ bool txflowcontrol; /* Per interface flow control indicator */ ++ char name[IFNAMSIZ+1]; /* linux interface name */ ++ uint8 bssidx; /* bsscfg index for the interface */ ++ bool set_multicast; ++ bool event2cfg80211; /* To determine if pass event to cfg80211 */ ++} dhd_if_t; ++ ++#ifdef WLMEDIA_HTSF ++typedef struct { ++ uint32 low; ++ uint32 high; ++} tsf_t; ++ ++typedef struct { ++ uint32 last_cycle; ++ uint32 last_sec; ++ uint32 last_tsf; ++ uint32 coef; /* scaling factor */ ++ uint32 coefdec1; /* first decimal */ ++ uint32 coefdec2; /* second decimal */ ++} htsf_t; ++ ++typedef struct { ++ uint32 t1; ++ uint32 t2; ++ uint32 t3; ++ uint32 t4; ++} tstamp_t; ++ ++static tstamp_t ts[TSMAX]; ++static tstamp_t maxdelayts; ++static uint32 maxdelay = 0, tspktcnt = 0, maxdelaypktno = 0; ++ ++#endif /* WLMEDIA_HTSF */ ++ ++/* Local private structure (extension of pub) */ ++typedef struct dhd_info { ++#if defined(CONFIG_WIRELESS_EXT) ++ wl_iw_t iw; /* wireless extensions state (must be first) */ ++#endif /* defined(CONFIG_WIRELESS_EXT) */ ++ ++ dhd_pub_t pub; ++ ++ /* For supporting multiple interfaces */ ++ dhd_if_t *iflist[DHD_MAX_IFS]; ++ ++ struct semaphore proto_sem; ++#ifdef PROP_TXSTATUS ++ spinlock_t wlfc_spinlock; ++#endif /* PROP_TXSTATUS */ ++#ifdef WLMEDIA_HTSF ++ htsf_t htsf; ++#endif ++ wait_queue_head_t ioctl_resp_wait; ++ struct timer_list timer; ++ bool wd_timer_valid; ++ struct tasklet_struct tasklet; ++ spinlock_t sdlock; ++ spinlock_t txqlock; ++ spinlock_t dhd_lock; ++#ifdef DHDTHREAD ++ /* Thread based operation */ ++ bool threads_only; ++ struct semaphore sdsem; ++ ++ tsk_ctl_t thr_dpc_ctl; ++ tsk_ctl_t thr_wdt_ctl; ++#endif /* DHDTHREAD */ ++ bool dhd_tasklet_create; ++ tsk_ctl_t thr_sysioc_ctl; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ struct work_struct work_hang; ++#endif ++ ++ /* Wakelocks */ ++#if defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ struct wake_lock *wl_wifi; /* Wifi wakelock */ ++ struct wake_lock *wl_rxwake; /* Wifi rx wakelock */ ++ struct wake_lock *wl_ctrlwake; /* Wifi ctrl wakelock */ ++ struct wake_lock *wl_wdwake; /* Wifi wd wakelock */ ++#endif ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 ++ /* net_device interface lock, prevent race conditions among net_dev interface ++ * calls and wifi_on or wifi_off ++ */ ++ struct mutex dhd_net_if_mutex; ++ struct mutex dhd_suspend_mutex; ++#endif ++ spinlock_t wakelock_spinlock; ++ int wakelock_counter; ++ int wakelock_wd_counter; ++ int wakelock_rx_timeout_enable; ++ int wakelock_ctrl_timeout_enable; ++ ++ /* Thread to issue ioctl for multicast */ ++ unsigned char set_macaddress; ++ struct ether_addr macvalue; ++ wait_queue_head_t ctrl_wait; ++ atomic_t pend_8021x_cnt; ++ dhd_attach_states_t dhd_state; ++ ++#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) ++ struct early_suspend early_suspend; ++#endif /* CONFIG_HAS_EARLYSUSPEND && defined(DHD_USE_EARLYSUSPEND) */ ++ ++#ifdef ARP_OFFLOAD_SUPPORT ++ u32 pend_ipaddr; ++#endif /* ARP_OFFLOAD_SUPPORT */ ++#ifdef BCM_FD_AGGR ++ void *rpc_th; ++ void *rpc_osh; ++ struct timer_list rpcth_timer; ++ bool rpcth_timer_active; ++ bool fdaggr; ++#endif ++} dhd_info_t; ++ ++/* Flag to indicate if we should download firmware on driver load */ ++uint dhd_download_fw_on_driverload = TRUE; ++ ++/* Definitions to provide path to the firmware and nvram ++ * example nvram_path[MOD_PARAM_PATHLEN]="/projects/wlan/nvram.txt" ++ */ ++char firmware_path[MOD_PARAM_PATHLEN]; ++char nvram_path[MOD_PARAM_PATHLEN]; ++ ++/* information string to keep firmware, chio, cheip version info visiable from log */ ++char info_string[MOD_PARAM_INFOLEN]; ++module_param_string(info_string, info_string, MOD_PARAM_INFOLEN, 0444); ++ ++int op_mode = 0; ++int disable_proptx = 0; ++module_param(op_mode, int, 0644); ++extern int wl_control_wl_start(struct net_device *dev); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++struct semaphore dhd_registration_sem; ++struct semaphore dhd_chipup_sem; ++int dhd_registration_check = FALSE; ++ ++#define DHD_REGISTRATION_TIMEOUT 12000 /* msec : allowed time to finished dhd registration */ ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ ++ ++/* Spawn a thread for system ioctls (set mac, set mcast) */ ++uint dhd_sysioc = TRUE; ++module_param(dhd_sysioc, uint, 0); ++ ++/* Error bits */ ++module_param(dhd_msg_level, int, 0); ++#if defined(CONFIG_WIRELESS_EXT) ++module_param(iw_msg_level, int, 0); ++#endif ++#ifdef WL_CFG80211 ++module_param(wl_dbg_level, int, 0); ++#endif ++//module_param(android_msg_level, int, 0); ++ ++/* Disable Prop tx */ ++module_param(disable_proptx, int, 0644); ++ ++/* load firmware and/or nvram values from the filesystem */ ++module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0660); ++module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0); ++ ++/* Watchdog interval */ ++uint dhd_watchdog_ms = 10; ++module_param(dhd_watchdog_ms, uint, 0); ++ ++#if defined(DHD_DEBUG) ++/* Console poll interval */ ++uint dhd_console_ms = 0; ++module_param(dhd_console_ms, uint, 0644); ++#endif /* defined(DHD_DEBUG) */ ++ ++uint dhd_slpauto = TRUE; ++module_param(dhd_slpauto, uint, 0); ++ ++/* ARP offload agent mode : Enable ARP Host Auto-Reply and ARP Peer Auto-Reply */ ++uint dhd_arp_mode = ARP_OL_AGENT | ARP_OL_PEER_AUTO_REPLY; ++module_param(dhd_arp_mode, uint, 0); ++ ++/* ARP offload enable */ ++uint dhd_arp_enable = TRUE; ++module_param(dhd_arp_enable, uint, 0); ++ ++#ifdef PKT_FILTER_SUPPORT ++/* Global Pkt filter enable control */ ++uint dhd_pkt_filter_enable = TRUE; ++module_param(dhd_pkt_filter_enable, uint, 0); ++#endif ++ ++/* Pkt filter init setup */ ++uint dhd_pkt_filter_init = 0; ++module_param(dhd_pkt_filter_init, uint, 0); ++ ++/* Pkt filter mode control */ ++#ifdef GAN_LITE_NAT_KEEPALIVE_FILTER ++uint dhd_master_mode = FALSE; ++#else ++uint dhd_master_mode = TRUE; ++#endif /* GAL_LITE_NAT_KEEPALIVE_FILTER */ ++module_param(dhd_master_mode, uint, 0); ++ ++#ifdef DHDTHREAD ++int dhd_watchdog_prio = 0; ++module_param(dhd_watchdog_prio, int, 0); ++ ++/* DPC thread priority */ ++int dhd_dpc_prio = CUSTOM_DPC_PRIO_SETTING; ++module_param(dhd_dpc_prio, int, 0); ++ ++/* DPC thread priority, -1 to use tasklet */ ++extern int dhd_dongle_memsize; ++module_param(dhd_dongle_memsize, int, 0); ++#endif /* DHDTHREAD */ ++/* Control fw roaming */ ++uint dhd_roam_disable = 0; ++ ++/* Control radio state */ ++uint dhd_radio_up = 1; ++ ++/* Network inteface name */ ++char iface_name[IFNAMSIZ] = {'\0'}; ++module_param_string(iface_name, iface_name, IFNAMSIZ, 0); ++ ++/* The following are specific to the SDIO dongle */ ++ ++/* IOCTL response timeout */ ++int dhd_ioctl_timeout_msec = IOCTL_RESP_TIMEOUT; ++ ++/* Idle timeout for backplane clock */ ++int dhd_idletime = DHD_IDLETIME_TICKS; ++module_param(dhd_idletime, int, 0); ++ ++/* Use polling */ ++uint dhd_poll = FALSE; ++module_param(dhd_poll, uint, 0); ++ ++/* Use interrupts */ ++uint dhd_intr = TRUE; ++module_param(dhd_intr, uint, 0); ++ ++/* SDIO Drive Strength (in milliamps) */ ++uint dhd_sdiod_drive_strength = 6; ++module_param(dhd_sdiod_drive_strength, uint, 0); ++ ++/* Tx/Rx bounds */ ++extern uint dhd_txbound; ++extern uint dhd_rxbound; ++module_param(dhd_txbound, uint, 0); ++module_param(dhd_rxbound, uint, 0); ++ ++/* Deferred transmits */ ++extern uint dhd_deferred_tx; ++module_param(dhd_deferred_tx, uint, 0); ++ ++#ifdef BCMDBGFS ++extern void dhd_dbg_init(dhd_pub_t *dhdp); ++extern void dhd_dbg_remove(void); ++#endif /* BCMDBGFS */ ++ ++/* ++ * the the 2 vars init at init time ++ *benn@cubietech.com ++ */ ++#define WL_HOST_WAKE_DEF_GPIO 86 ++int wl_host_wake_irqno = -1; ++int wl_host_wake = -1; ++ ++ ++#ifdef SDTEST ++/* Echo packet generator (pkts/s) */ ++uint dhd_pktgen = 0; ++module_param(dhd_pktgen, uint, 0); ++ ++/* Echo packet len (0 => sawtooth, max 2040) */ ++uint dhd_pktgen_len = 0; ++module_param(dhd_pktgen_len, uint, 0); ++#endif /* SDTEST */ ++ ++/* Version string to report */ ++#ifdef DHD_DEBUG ++#ifndef SRCBASE ++#define SRCBASE "drivers/net/wireless/ap6211" ++#endif ++#define DHD_COMPILED "\nCompiled in " SRCBASE ++#else ++#define DHD_COMPILED ++#endif /* DHD_DEBUG */ ++ ++static char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR "."; ++#ifdef DHD_DEBUG ++static char dhd_version_info[] = "Compiled in " SRCBASE " on " __DATE__ " at " __TIME__ "."; ++#endif ++ ++static void dhd_net_if_lock_local(dhd_info_t *dhd); ++static void dhd_net_if_unlock_local(dhd_info_t *dhd); ++static void dhd_suspend_lock(dhd_pub_t *dhdp); ++static void dhd_suspend_unlock(dhd_pub_t *dhdp); ++ ++#ifdef WLMEDIA_HTSF ++void htsf_update(dhd_info_t *dhd, void *data); ++tsf_t prev_tsf, cur_tsf; ++ ++uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx); ++static int dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx); ++static void dhd_dump_latency(void); ++static void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf); ++static void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf); ++static void dhd_dump_htsfhisto(histo_t *his, char *s); ++#endif /* WLMEDIA_HTSF */ ++ ++/* Monitor interface */ ++int dhd_monitor_init(void *dhd_pub); ++int dhd_monitor_uninit(void); ++ ++ ++#if defined(CONFIG_WIRELESS_EXT) ++struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev); ++#endif /* defined(CONFIG_WIRELESS_EXT) */ ++ ++static void dhd_dpc(ulong data); ++/* forward decl */ ++extern int dhd_wait_pend8021x(struct net_device *dev); ++ ++#ifdef TOE ++#ifndef BDC ++#error TOE requires BDC ++#endif /* !BDC */ ++static int dhd_toe_get(dhd_info_t *dhd, int idx, uint32 *toe_ol); ++static int dhd_toe_set(dhd_info_t *dhd, int idx, uint32 toe_ol); ++#endif /* TOE */ ++ ++static int dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, ++ wl_event_msg_t *event_ptr, void **data_ptr); ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) ++static int dhd_sleep_pm_callback(struct notifier_block *nfb, unsigned long action, void *ignored) ++{ ++ int ret = NOTIFY_DONE; ++ ++#if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI) || (LINUX_VERSION_CODE <= \ ++ KERNEL_VERSION(2, 6, 39)) ++ switch (action) { ++ case PM_HIBERNATION_PREPARE: ++ case PM_SUSPEND_PREPARE: ++ dhd_mmc_suspend = TRUE; ++ ret = NOTIFY_OK; ++ break; ++ case PM_POST_HIBERNATION: ++ case PM_POST_SUSPEND: ++ dhd_mmc_suspend = FALSE; ++ ret = NOTIFY_OK; ++ break; ++ } ++ smp_mb(); ++#endif ++ return ret; ++} ++ ++static struct notifier_block dhd_sleep_pm_notifier = { ++ .notifier_call = dhd_sleep_pm_callback, ++ .priority = 10 ++}; ++extern int register_pm_notifier(struct notifier_block *nb); ++extern int unregister_pm_notifier(struct notifier_block *nb); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ ++ ++void dhd_set_packet_filter(dhd_pub_t *dhd) ++{ ++#ifdef PKT_FILTER_SUPPORT ++ int i; ++ ++ AP6211_DEBUG("%s: enter\n", __FUNCTION__); ++ if (dhd_pkt_filter_enable) { ++ for (i = 0; i < dhd->pktfilter_count; i++) { ++ dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]); ++ } ++ } ++#endif /* PKT_FILTER_SUPPORT */ ++} ++ ++void dhd_enable_packet_filter(int value, dhd_pub_t *dhd) ++{ ++#ifdef PKT_FILTER_SUPPORT ++ int i; ++ ++ AP6211_DEBUG("%s: enter, value = %d\n", __FUNCTION__, value); ++ /* 1 - Enable packet filter, only allow unicast packet to send up */ ++ /* 0 - Disable packet filter */ ++ if (dhd_pkt_filter_enable && (!value || ++ (dhd_support_sta_mode(dhd) && !dhd->dhcp_in_progress))) { ++ for (i = 0; i < dhd->pktfilter_count; i++) { ++#ifdef PASS_ARP_PACKET ++ if (value && (i == dhd->pktfilter_count -1) && ++ !(dhd->op_mode & (DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE))) { ++ AP6211_DEBUG("Do not turn on ARP white list pkt filter:" ++ "val %d, cnt %d, op_mode 0x%x\n", ++ value, i, dhd->op_mode); ++ continue; ++ } ++#endif ++ dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i], ++ value, dhd_master_mode); ++ } ++ } ++#endif /* PKT_FILTER_SUPPORT */ ++} ++ ++static int dhd_set_suspend(int value, dhd_pub_t *dhd) ++{ ++#if !defined(SUPPORT_PM2_ONLY) ++ int power_mode = PM_MAX; ++#endif ++ /* wl_pkt_filter_enable_t enable_parm; */ ++ char iovbuf[32]; ++ int bcn_li_dtim = 0; /* Default bcn_li_dtim in resume mode is 0 */ ++#ifndef DISABLE_FW_ROAM_SUSPEND ++ uint roamvar = 1; ++#endif ++#ifdef ENABLE_BCN_LI_BCN_WAKEUP ++ int bcn_li_bcn; ++#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ ++#ifdef PASS_ALL_MCAST_PKTS ++ struct dhd_info *dhdinfo = dhd->info; ++ uint32 allmulti; ++ uint i; ++#endif /* PASS_ALL_MCAST_PKTS */ ++ ++ AP6211_DEBUG("%s: enter, value = %d in_suspend=%d\n", ++ __FUNCTION__, value, dhd->in_suspend); ++ ++ dhd_suspend_lock(dhd); ++ if (dhd && dhd->up) { ++ if (value && dhd->in_suspend) { ++#ifdef PKT_FILTER_SUPPORT ++ dhd->early_suspended = 1; ++#endif ++ /* Kernel suspended */ ++ AP6211_ERR("%s: force extra Suspend setting\n", __FUNCTION__); ++ ++#if !defined(SUPPORT_PM2_ONLY) ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, ++ sizeof(power_mode), TRUE, 0); ++#endif ++ /* Enable packet filter, only allow unicast packet to send up */ ++ dhd_enable_packet_filter(1, dhd); ++#ifdef PASS_ALL_MCAST_PKTS ++ allmulti = 0; ++ bcm_mkiovar("allmulti", (char *)&allmulti, ++ 4, iovbuf, sizeof(iovbuf)); ++ for (i = 0; i < DHD_MAX_IFS; i++) { ++ if (dhdinfo->iflist[i] && dhdinfo->iflist[i]->net) ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, ++ sizeof(iovbuf), TRUE, i); ++ } ++#endif /* PASS_ALL_MCAST_PKTS */ ++ ++ /* If DTIM skip is set up as default, force it to wake ++ * each third DTIM for better power savings. Note that ++ * one side effect is a chance to miss BC/MC packet. ++ */ ++ bcn_li_dtim = dhd_get_suspend_bcn_li_dtim(dhd); ++ bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim, ++ 4, iovbuf, sizeof(iovbuf)); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++ ++#ifndef DISABLE_FW_ROAM_SUSPEND ++ /* Disable firmware roaming during suspend */ ++ bcm_mkiovar("roam_off", (char *)&roamvar, 4, ++ iovbuf, sizeof(iovbuf)); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++#endif ++#ifdef ENABLE_BCN_LI_BCN_WAKEUP ++ bcn_li_bcn = 0; ++ bcm_mkiovar("bcn_li_bcn", (char *)&bcn_li_bcn, ++ 4, iovbuf, sizeof(iovbuf)); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ ++ ++ } else { ++#ifdef PKT_FILTER_SUPPORT ++ dhd->early_suspended = 0; ++#endif ++ /* Kernel resumed */ ++ AP6211_ERR("%s: Remove extra suspend setting\n", __FUNCTION__); ++ ++#if !defined(SUPPORT_PM2_ONLY) ++ power_mode = PM_FAST; ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, ++ sizeof(power_mode), TRUE, 0); ++#endif ++ /* disable pkt filter */ ++ dhd_enable_packet_filter(0, dhd); ++#ifdef PASS_ALL_MCAST_PKTS ++ allmulti = 1; ++ bcm_mkiovar("allmulti", (char *)&allmulti, ++ 4, iovbuf, sizeof(iovbuf)); ++ for (i = 0; i < DHD_MAX_IFS; i++) { ++ if (dhdinfo->iflist[i] && dhdinfo->iflist[i]->net) ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, ++ sizeof(iovbuf), TRUE, i); ++ } ++#endif /* PASS_ALL_MCAST_PKTS */ ++ ++ /* restore pre-suspend setting for dtim_skip */ ++ bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim, ++ 4, iovbuf, sizeof(iovbuf)); ++ ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++#ifndef DISABLE_FW_ROAM_SUSPEND ++ roamvar = dhd_roam_disable; ++ bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, ++ sizeof(iovbuf)); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++#endif ++#ifdef ENABLE_BCN_LI_BCN_WAKEUP ++ bcn_li_bcn = 1; ++ bcm_mkiovar("bcn_li_bcn", (char *)&bcn_li_bcn, ++ 4, iovbuf, sizeof(iovbuf)); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ ++ ++ } ++ } ++ ++ dhd_suspend_unlock(dhd); ++ return 0; ++} ++ ++static int dhd_suspend_resume_helper(struct dhd_info *dhd, int val, int force) ++{ ++ dhd_pub_t *dhdp = &dhd->pub; ++ int ret = 0; ++ ++ DHD_OS_WAKE_LOCK(dhdp); ++ /* Set flag when early suspend was called */ ++ dhdp->in_suspend = val; ++ if ((force || !dhdp->suspend_disable_flag) && ++ dhd_support_sta_mode(dhdp)) ++ { ++ ret = dhd_set_suspend(val, dhdp); ++ } ++ ++ DHD_OS_WAKE_UNLOCK(dhdp); ++ return ret; ++} ++ ++#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) ++static void dhd_early_suspend(struct early_suspend *h) ++{ ++ struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend); ++ AP6211_DEBUG("%s: enter\n", __FUNCTION__); ++ ++ if (dhd) ++ dhd_suspend_resume_helper(dhd, 1, 0); ++} ++ ++static void dhd_late_resume(struct early_suspend *h) ++{ ++ struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend); ++ AP6211_DEBUG("%s: enter\n", __FUNCTION__); ++ ++ if (dhd) ++ dhd_suspend_resume_helper(dhd, 0, 0); ++} ++#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ ++ ++/* ++ * Generalized timeout mechanism. Uses spin sleep with exponential back-off until ++ * the sleep time reaches one jiffy, then switches over to task delay. Usage: ++ * ++ * dhd_timeout_start(&tmo, usec); ++ * while (!dhd_timeout_expired(&tmo)) ++ * if (poll_something()) ++ * break; ++ * if (dhd_timeout_expired(&tmo)) ++ * fatal(); ++ */ ++ ++void ++dhd_timeout_start(dhd_timeout_t *tmo, uint usec) ++{ ++ tmo->limit = usec; ++ tmo->increment = 0; ++ tmo->elapsed = 0; ++ tmo->tick = jiffies_to_usecs(1); ++} ++ ++int ++dhd_timeout_expired(dhd_timeout_t *tmo) ++{ ++ /* Does nothing the first call */ ++ if (tmo->increment == 0) { ++ tmo->increment = 1; ++ return 0; ++ } ++ ++ if (tmo->elapsed >= tmo->limit) ++ return 1; ++ ++ /* Add the delay that's about to take place */ ++ tmo->elapsed += tmo->increment; ++ ++ if (tmo->increment < tmo->tick) { ++ OSL_DELAY(tmo->increment); ++ tmo->increment *= 2; ++ if (tmo->increment > tmo->tick) ++ tmo->increment = tmo->tick; ++ } else { ++ wait_queue_head_t delay_wait; ++ DECLARE_WAITQUEUE(wait, current); ++ init_waitqueue_head(&delay_wait); ++ add_wait_queue(&delay_wait, &wait); ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(1); ++ remove_wait_queue(&delay_wait, &wait); ++ set_current_state(TASK_RUNNING); ++ } ++ ++ return 0; ++} ++ ++int ++dhd_net2idx(dhd_info_t *dhd, struct net_device *net) ++{ ++ int i = 0; ++ ++ ASSERT(dhd); ++ while (i < DHD_MAX_IFS) { ++ if (dhd->iflist[i] && (dhd->iflist[i]->net == net)) ++ return i; ++ i++; ++ } ++ ++ return DHD_BAD_IF; ++} ++ ++struct net_device * dhd_idx2net(void *pub, int ifidx) ++{ ++ struct dhd_pub *dhd_pub = (struct dhd_pub *)pub; ++ struct dhd_info *dhd_info; ++ ++ if (!dhd_pub || ifidx < 0 || ifidx >= DHD_MAX_IFS) ++ return NULL; ++ dhd_info = dhd_pub->info; ++ if (dhd_info && dhd_info->iflist[ifidx]) ++ return dhd_info->iflist[ifidx]->net; ++ return NULL; ++} ++ ++int ++dhd_ifname2idx(dhd_info_t *dhd, char *name) ++{ ++ int i = DHD_MAX_IFS; ++ ++ ASSERT(dhd); ++ ++ if (name == NULL || *name == '\0') ++ return 0; ++ ++ while (--i > 0) ++ if (dhd->iflist[i] && !strncmp(dhd->iflist[i]->name, name, IFNAMSIZ)) ++ break; ++ ++ AP6211_DEBUG("%s: return idx %d for \"%s\"\n", __FUNCTION__, i, name); ++ ++ return i; /* default - the primary interface */ ++} ++ ++char * ++dhd_ifname(dhd_pub_t *dhdp, int ifidx) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)dhdp->info; ++ ++ ASSERT(dhd); ++ ++ if (ifidx < 0 || ifidx >= DHD_MAX_IFS) { ++ AP6211_ERR("%s: ifidx %d out of range\n", __FUNCTION__, ifidx); ++ return ""; ++ } ++ ++ if (dhd->iflist[ifidx] == NULL) { ++ AP6211_ERR("%s: null i/f %d\n", __FUNCTION__, ifidx); ++ return ""; ++ } ++ ++ if (dhd->iflist[ifidx]->net) ++ return dhd->iflist[ifidx]->net->name; ++ ++ return ""; ++} ++ ++uint8 * ++dhd_bssidx2bssid(dhd_pub_t *dhdp, int idx) ++{ ++ int i; ++ dhd_info_t *dhd = (dhd_info_t *)dhdp; ++ ++ ASSERT(dhd); ++ for (i = 0; i < DHD_MAX_IFS; i++) ++ if (dhd->iflist[i] && dhd->iflist[i]->bssidx == idx) ++ return dhd->iflist[i]->mac_addr; ++ ++ return NULL; ++} ++ ++ ++static void ++_dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) ++{ ++ struct net_device *dev; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) ++ struct netdev_hw_addr *ha; ++#else ++ struct dev_mc_list *mclist; ++#endif ++ uint32 allmulti, cnt; ++ ++ wl_ioctl_t ioc; ++ char *buf, *bufp; ++ uint buflen; ++ int ret; ++ ++ ASSERT(dhd && dhd->iflist[ifidx]); ++ dev = dhd->iflist[ifidx]->net; ++ if (!dev) ++ return; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) ++ netif_addr_lock_bh(dev); ++#endif ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) ++ cnt = netdev_mc_count(dev); ++#else ++ cnt = dev->mc_count; ++#endif /* LINUX_VERSION_CODE */ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) ++ netif_addr_unlock_bh(dev); ++#endif ++ ++ /* Determine initial value of allmulti flag */ ++ allmulti = (dev->flags & IFF_ALLMULTI) ? TRUE : FALSE; ++#ifdef PASS_ALL_MCAST_PKTS ++#ifdef PKT_FILTER_SUPPORT ++ if (!dhd->pub.early_suspended) ++#endif /* PKT_FILTER_SUPPORT */ ++ allmulti = TRUE; ++#endif /* PASS_ALL_MCAST_PKTS */ ++ ++ /* Send down the multicast list first. */ ++ ++ ++ buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETHER_ADDR_LEN); ++ if (!(bufp = buf = MALLOC(dhd->pub.osh, buflen))) { ++ AP6211_ERR("%s: out of memory for mcast_list, cnt %d\n", ++ dhd_ifname(&dhd->pub, ifidx), cnt); ++ return; ++ } ++ ++ strncpy(bufp, "mcast_list", buflen - 1); ++ bufp[buflen - 1] = '\0'; ++ bufp += strlen("mcast_list") + 1; ++ ++ cnt = htol32(cnt); ++ memcpy(bufp, &cnt, sizeof(cnt)); ++ bufp += sizeof(cnt); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) ++ netif_addr_lock_bh(dev); ++#endif ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) ++ netdev_for_each_mc_addr(ha, dev) { ++ if (!cnt) ++ break; ++ memcpy(bufp, ha->addr, ETHER_ADDR_LEN); ++ bufp += ETHER_ADDR_LEN; ++ cnt--; ++ } ++#else ++ for (mclist = dev->mc_list; (mclist && (cnt > 0)); ++ cnt--, mclist = mclist->next) { ++ memcpy(bufp, (void *)mclist->dmi_addr, ETHER_ADDR_LEN); ++ bufp += ETHER_ADDR_LEN; ++ } ++#endif /* LINUX_VERSION_CODE */ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) ++ netif_addr_unlock_bh(dev); ++#endif ++ ++ memset(&ioc, 0, sizeof(ioc)); ++ ioc.cmd = WLC_SET_VAR; ++ ioc.buf = buf; ++ ioc.len = buflen; ++ ioc.set = TRUE; ++ ++ ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); ++ if (ret < 0) { ++ AP6211_ERR("%s: set mcast_list failed, cnt %d\n", ++ dhd_ifname(&dhd->pub, ifidx), cnt); ++ allmulti = cnt ? TRUE : allmulti; ++ } ++ ++ MFREE(dhd->pub.osh, buf, buflen); ++ ++ /* Now send the allmulti setting. This is based on the setting in the ++ * net_device flags, but might be modified above to be turned on if we ++ * were trying to set some addresses and dongle rejected it... ++ */ ++ ++ buflen = sizeof("allmulti") + sizeof(allmulti); ++ if (!(buf = MALLOC(dhd->pub.osh, buflen))) { ++ AP6211_ERR("%s: out of memory for allmulti\n", dhd_ifname(&dhd->pub, ifidx)); ++ return; ++ } ++ allmulti = htol32(allmulti); ++ ++ if (!bcm_mkiovar("allmulti", (void*)&allmulti, sizeof(allmulti), buf, buflen)) { ++ AP6211_ERR("%s: mkiovar failed for allmulti, datalen %d buflen %u\n", ++ dhd_ifname(&dhd->pub, ifidx), (int)sizeof(allmulti), buflen); ++ MFREE(dhd->pub.osh, buf, buflen); ++ return; ++ } ++ ++ ++ memset(&ioc, 0, sizeof(ioc)); ++ ioc.cmd = WLC_SET_VAR; ++ ioc.buf = buf; ++ ioc.len = buflen; ++ ioc.set = TRUE; ++ ++ ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); ++ if (ret < 0) { ++ AP6211_ERR("%s: set allmulti %d failed\n", ++ dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti)); ++ } ++ ++ MFREE(dhd->pub.osh, buf, buflen); ++ ++ /* Finally, pick up the PROMISC flag as well, like the NIC driver does */ ++ ++ allmulti = (dev->flags & IFF_PROMISC) ? TRUE : FALSE; ++ allmulti = htol32(allmulti); ++ ++ memset(&ioc, 0, sizeof(ioc)); ++ ioc.cmd = WLC_SET_PROMISC; ++ ioc.buf = &allmulti; ++ ioc.len = sizeof(allmulti); ++ ioc.set = TRUE; ++ ++ ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); ++ if (ret < 0) { ++ AP6211_ERR("%s: set promisc %d failed\n", ++ dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti)); ++ } ++} ++ ++int ++_dhd_set_mac_address(dhd_info_t *dhd, int ifidx, struct ether_addr *addr) ++{ ++ char buf[32]; ++ wl_ioctl_t ioc; ++ int ret; ++ ++ if (!bcm_mkiovar("cur_etheraddr", (char*)addr, ETHER_ADDR_LEN, buf, 32)) { ++ AP6211_ERR("%s: mkiovar failed for cur_etheraddr\n", dhd_ifname(&dhd->pub, ifidx)); ++ return -1; ++ } ++ memset(&ioc, 0, sizeof(ioc)); ++ ioc.cmd = WLC_SET_VAR; ++ ioc.buf = buf; ++ ioc.len = 32; ++ ioc.set = TRUE; ++ ++ ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); ++ if (ret < 0) { ++ AP6211_ERR("%s: set cur_etheraddr failed\n", dhd_ifname(&dhd->pub, ifidx)); ++ } else { ++ memcpy(dhd->iflist[ifidx]->net->dev_addr, addr, ETHER_ADDR_LEN); ++ memcpy(dhd->pub.mac.octet, addr, ETHER_ADDR_LEN); ++ } ++ ++ return ret; ++} ++ ++#ifdef SOFTAP ++extern struct net_device *ap_net_dev; ++extern tsk_ctl_t ap_eth_ctl; /* ap netdev heper thread ctl */ ++#endif ++ ++static void ++dhd_op_if(dhd_if_t *ifp) ++{ ++ dhd_info_t *dhd; ++ int ret = 0, err = 0; ++#ifdef SOFTAP ++ unsigned long flags; ++#endif ++ ++ if (!ifp || !ifp->info || !ifp->idx) ++ return; ++ ASSERT(ifp && ifp->info && ifp->idx); /* Virtual interfaces only */ ++ dhd = ifp->info; ++ ++ AP6211_DEBUG("%s: idx %d, state %d\n", __FUNCTION__, ifp->idx, ifp->state); ++ ++#ifdef WL_CFG80211 ++ if (wl_cfg80211_is_progress_ifchange()) ++ return; ++ ++#endif ++ switch (ifp->state) { ++ case DHD_IF_ADD: ++ /* ++ * Delete the existing interface before overwriting it ++ * in case we missed the WLC_E_IF_DEL event. ++ */ ++ if (ifp->net != NULL) { ++ AP6211_ERR("%s: ERROR: netdev:%s already exists, try free & unregister \n", ++ __FUNCTION__, ifp->net->name); ++ netif_stop_queue(ifp->net); ++ unregister_netdev(ifp->net); ++ free_netdev(ifp->net); ++ } ++ /* Allocate etherdev, including space for private structure */ ++ if (!(ifp->net = alloc_etherdev(sizeof(dhd)))) { ++ AP6211_ERR("%s: OOM - alloc_etherdev\n", __FUNCTION__); ++ ret = -ENOMEM; ++ } ++ if (ret == 0) { ++ strncpy(ifp->net->name, ifp->name, IFNAMSIZ); ++ ifp->net->name[IFNAMSIZ - 1] = '\0'; ++ memcpy(netdev_priv(ifp->net), &dhd, sizeof(dhd)); ++#ifdef WL_CFG80211 ++ if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) ++ if (!wl_cfg80211_notify_ifadd(ifp->net, ifp->idx, ifp->bssidx, ++ (void*)dhd_net_attach)) { ++ ifp->state = DHD_IF_NONE; ++ ifp->event2cfg80211 = TRUE; ++ return; ++ } ++#endif ++ if ((err = dhd_net_attach(&dhd->pub, ifp->idx)) != 0) { ++ AP6211_ERR("%s: dhd_net_attach failed, err %d\n", ++ __FUNCTION__, err); ++ ret = -EOPNOTSUPP; ++ } else { ++#if defined(SOFTAP) ++ if (ap_fw_loaded && !(dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)) { ++ /* semaphore that the soft AP CODE waits on */ ++ flags = dhd_os_spin_lock(&dhd->pub); ++ ++ /* save ptr to wl0.1 netdev for use in wl_iw.c */ ++ ap_net_dev = ifp->net; ++ /* signal to the SOFTAP 'sleeper' thread, wl0.1 is ready */ ++ up(&ap_eth_ctl.sema); ++ dhd_os_spin_unlock(&dhd->pub, flags); ++ } ++#endif ++ AP6211_DEBUG(" ==== pid:%x, net_device for if:%s created ===\n\n", ++ current->pid, ifp->net->name); ++ ifp->state = DHD_IF_NONE; ++ } ++ } ++ break; ++ case DHD_IF_DEL: ++ /* Make sure that we don't enter again here if .. */ ++ /* dhd_op_if is called again from some other context */ ++ ifp->state = DHD_IF_DELETING; ++ if (ifp->net != NULL) { ++ AP6211_DEBUG("%s: got 'DHD_IF_DEL' state\n", __FUNCTION__); ++ netif_stop_queue(ifp->net); ++#ifdef WL_CFG80211 ++ if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) { ++ wl_cfg80211_ifdel_ops(ifp->net); ++ } ++#endif ++ unregister_netdev(ifp->net); ++ ret = DHD_DEL_IF; /* Make sure the free_netdev() is called */ ++#ifdef WL_CFG80211 ++ if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) { ++ wl_cfg80211_notify_ifdel(); ++ } ++#endif ++ } ++ break; ++ case DHD_IF_DELETING: ++ break; ++ default: ++ AP6211_ERR("%s: bad op %d\n", __FUNCTION__, ifp->state); ++ ASSERT(!ifp->state); ++ break; ++ } ++ ++ if (ret < 0) { ++ ifp->set_multicast = FALSE; ++ if (ifp->net) { ++ free_netdev(ifp->net); ++ ifp->net = NULL; ++ } ++ dhd->iflist[ifp->idx] = NULL; ++#ifdef SOFTAP ++ flags = dhd_os_spin_lock(&dhd->pub); ++ if (ifp->net == ap_net_dev) ++ ap_net_dev = NULL; /* NULL SOFTAP global wl0.1 as well */ ++ dhd_os_spin_unlock(&dhd->pub, flags); ++#endif /* SOFTAP */ ++ MFREE(dhd->pub.osh, ifp, sizeof(*ifp)); ++ } ++} ++ ++static int ++_dhd_sysioc_thread(void *data) ++{ ++ tsk_ctl_t *tsk = (tsk_ctl_t *)data; ++ dhd_info_t *dhd = (dhd_info_t *)tsk->parent; ++ ++ ++ int i; ++#ifdef SOFTAP ++ bool in_ap = FALSE; ++ unsigned long flags; ++#endif ++#ifndef USE_KTHREAD_API ++ DAEMONIZE("dhd_sysioc"); ++ ++ complete(&tsk->completed); ++#endif ++ ++ while (down_interruptible(&tsk->sema) == 0) { ++ ++ SMP_RD_BARRIER_DEPENDS(); ++ if (tsk->terminated) { ++ break; ++ } ++ ++ dhd_net_if_lock_local(dhd); ++ DHD_OS_WAKE_LOCK(&dhd->pub); ++ ++ for (i = 0; i < DHD_MAX_IFS; i++) { ++ if (dhd->iflist[i]) { ++ AP6211_DEBUG("%s: interface %d\n", __FUNCTION__, i); ++#ifdef SOFTAP ++ flags = dhd_os_spin_lock(&dhd->pub); ++ in_ap = (ap_net_dev != NULL); ++ dhd_os_spin_unlock(&dhd->pub, flags); ++#endif /* SOFTAP */ ++ if (dhd->iflist[i] && dhd->iflist[i]->state) ++ dhd_op_if(dhd->iflist[i]); ++ ++ if (dhd->iflist[i] == NULL) { ++ AP6211_DEBUG("%s: interface %d just been removed,!\n", __FUNCTION__, i); ++ continue; ++ } ++#ifdef SOFTAP ++ if (in_ap && dhd->set_macaddress == i+1) { ++ AP6211_DEBUG("attempt to set MAC for %s in AP Mode," ++ "blocked. \n", dhd->iflist[i]->net->name); ++ dhd->set_macaddress = 0; ++ continue; ++ } ++ ++ if (in_ap && dhd->iflist[i]->set_multicast) { ++ AP6211_DEBUG("attempt to set MULTICAST list for %s" ++ "in AP Mode, blocked. \n", dhd->iflist[i]->net->name); ++ dhd->iflist[i]->set_multicast = FALSE; ++ continue; ++ } ++#endif /* SOFTAP */ ++ if (dhd->pub.up == 0) ++ continue; ++ if (dhd->iflist[i]->set_multicast) { ++ dhd->iflist[i]->set_multicast = FALSE; ++ _dhd_set_multicast_list(dhd, i); ++ } ++ if (dhd->set_macaddress == i+1) { ++ dhd->set_macaddress = 0; ++ if (_dhd_set_mac_address(dhd, i, &dhd->macvalue) == 0) { ++ AP6211_DEBUG( ++ "dhd_sysioc_thread: MACID is overwritten\n"); ++ } else { ++ AP6211_ERR( ++ "dhd_sysioc_thread: _dhd_set_mac_address() failed\n"); ++ } ++ } ++ } ++ } ++ ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ dhd_net_if_unlock_local(dhd); ++ } ++ AP6211_DEBUG("%s: stopped\n", __FUNCTION__); ++ complete_and_exit(&tsk->completed, 0); ++} ++ ++static int ++dhd_set_mac_address(struct net_device *dev, void *addr) ++{ ++ int ret = 0; ++ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ struct sockaddr *sa = (struct sockaddr *)addr; ++ int ifidx; ++ ++ ifidx = dhd_net2idx(dhd, dev); ++ if (ifidx == DHD_BAD_IF) ++ return -1; ++ ++ ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0); ++ memcpy(&dhd->macvalue, sa->sa_data, ETHER_ADDR_LEN); ++ dhd->set_macaddress = ifidx+1; ++ up(&dhd->thr_sysioc_ctl.sema); ++ ++ return ret; ++} ++ ++static void ++dhd_set_multicast_list(struct net_device *dev) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ int ifidx; ++ ++ ifidx = dhd_net2idx(dhd, dev); ++ if (ifidx == DHD_BAD_IF) ++ return; ++ ++ ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0); ++ dhd->iflist[ifidx]->set_multicast = TRUE; ++ up(&dhd->thr_sysioc_ctl.sema); ++} ++ ++#ifdef PROP_TXSTATUS ++int ++dhd_os_wlfc_block(dhd_pub_t *pub) ++{ ++ dhd_info_t *di = (dhd_info_t *)(pub->info); ++ ASSERT(di != NULL); ++ spin_lock_bh(&di->wlfc_spinlock); ++ return 1; ++} ++ ++int ++dhd_os_wlfc_unblock(dhd_pub_t *pub) ++{ ++ dhd_info_t *di = (dhd_info_t *)(pub->info); ++ ++ ASSERT(di != NULL); ++ spin_unlock_bh(&di->wlfc_spinlock); ++ return 1; ++} ++ ++const uint8 wme_fifo2ac[] = { 0, 1, 2, 3, 1, 1 }; ++uint8 prio2fifo[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; ++#define WME_PRIO2AC(prio) wme_fifo2ac[prio2fifo[(prio)]] ++ ++#endif /* PROP_TXSTATUS */ ++int ++dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) ++{ ++ int ret; ++ dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); ++ struct ether_header *eh = NULL; ++ ++ /* Reject if down */ ++ if (!dhdp->up || (dhdp->busstate == DHD_BUS_DOWN)) { ++ /* free the packet here since the caller won't */ ++ PKTFREE(dhdp->osh, pktbuf, TRUE); ++ return -ENODEV; ++ } ++ ++ /* Update multicast statistic */ ++ if (PKTLEN(dhdp->osh, pktbuf) >= ETHER_HDR_LEN) { ++ uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf); ++ eh = (struct ether_header *)pktdata; ++ ++ if (ETHER_ISMULTI(eh->ether_dhost)) ++ dhdp->tx_multicast++; ++ if (ntoh16(eh->ether_type) == ETHER_TYPE_802_1X) ++ atomic_inc(&dhd->pend_8021x_cnt); ++ } else { ++ PKTFREE(dhd->pub.osh, pktbuf, TRUE); ++ return BCME_ERROR; ++ } ++ ++ /* Look into the packet and update the packet priority */ ++#ifndef PKTPRIO_OVERRIDE ++ if (PKTPRIO(pktbuf) == 0) ++#endif ++ pktsetprio(pktbuf, FALSE); ++ ++#ifdef PROP_TXSTATUS ++ if (dhdp->wlfc_state) { ++ /* store the interface ID */ ++ DHD_PKTTAG_SETIF(PKTTAG(pktbuf), ifidx); ++ ++ /* store destination MAC in the tag as well */ ++ DHD_PKTTAG_SETDSTN(PKTTAG(pktbuf), eh->ether_dhost); ++ ++ /* decide which FIFO this packet belongs to */ ++ if (ETHER_ISMULTI(eh->ether_dhost)) ++ /* one additional queue index (highest AC + 1) is used for bc/mc queue */ ++ DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), AC_COUNT); ++ else ++ DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), WME_PRIO2AC(PKTPRIO(pktbuf))); ++ } else ++#endif /* PROP_TXSTATUS */ ++ /* If the protocol uses a data header, apply it */ ++ dhd_prot_hdrpush(dhdp, ifidx, pktbuf); ++ ++ /* Use bus module to send data frame */ ++#ifdef WLMEDIA_HTSF ++ dhd_htsf_addtxts(dhdp, pktbuf); ++#endif ++#ifdef PROP_TXSTATUS ++ dhd_os_wlfc_block(dhdp); ++ if (dhdp->wlfc_state && ((athost_wl_status_info_t*)dhdp->wlfc_state)->proptxstatus_mode ++ != WLFC_FCMODE_NONE) { ++ ret = dhd_wlfc_enque_sendq(dhdp->wlfc_state, DHD_PKTTAG_FIFO(PKTTAG(pktbuf)), ++ pktbuf); ++ dhd_wlfc_commit_packets(dhdp->wlfc_state, (f_commitpkt_t)dhd_bus_txdata, ++ dhdp->bus); ++ if (((athost_wl_status_info_t*)dhdp->wlfc_state)->toggle_host_if) { ++ ((athost_wl_status_info_t*)dhdp->wlfc_state)->toggle_host_if = 0; ++ } ++ dhd_os_wlfc_unblock(dhdp); ++ } ++ else { ++ dhd_os_wlfc_unblock(dhdp); ++ /* non-proptxstatus way */ ++ ret = dhd_bus_txdata(dhdp->bus, pktbuf, FALSE); ++ } ++#else ++ ret = dhd_bus_txdata(dhdp->bus, pktbuf, FALSE); ++#endif /* PROP_TXSTATUS */ ++ ++ return ret; ++} ++ ++int ++dhd_start_xmit(struct sk_buff *skb, struct net_device *net) ++{ ++ int ret; ++ void *pktbuf; ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); ++ int ifidx; ++#ifdef WLMEDIA_HTSF ++ uint8 htsfdlystat_sz = dhd->pub.htsfdlystat_sz; ++#else ++ uint8 htsfdlystat_sz = 0; ++#endif ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ DHD_OS_WAKE_LOCK(&dhd->pub); ++ ++ /* Reject if down */ ++ if (dhd->pub.busstate == DHD_BUS_DOWN || dhd->pub.hang_was_sent) { ++ AP6211_ERR("%s: xmit rejected pub.up=%d busstate=%d \n", ++ __FUNCTION__, dhd->pub.up, dhd->pub.busstate); ++ netif_stop_queue(net); ++ /* Send Event when bus down detected during data session */ ++ if (dhd->pub.up) { ++ AP6211_ERR("%s: Event HANG sent up\n", __FUNCTION__); ++ net_os_send_hang_message(net); ++ } ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) ++ return -ENODEV; ++#else ++ return NETDEV_TX_BUSY; ++#endif ++ } ++ ++ ifidx = dhd_net2idx(dhd, net); ++ if (ifidx == DHD_BAD_IF) { ++ AP6211_ERR("%s: bad ifidx %d\n", __FUNCTION__, ifidx); ++ netif_stop_queue(net); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) ++ return -ENODEV; ++#else ++ return NETDEV_TX_BUSY; ++#endif ++ } ++ ++ /* Make sure there's enough room for any header */ ++ ++ if (skb_headroom(skb) < dhd->pub.hdrlen + htsfdlystat_sz) { ++ struct sk_buff *skb2; ++ ++ AP6211_DEBUG("%s: insufficient headroom\n", ++ dhd_ifname(&dhd->pub, ifidx)); ++ dhd->pub.tx_realloc++; ++ ++ skb2 = skb_realloc_headroom(skb, dhd->pub.hdrlen + htsfdlystat_sz); ++ ++ dev_kfree_skb(skb); ++ if ((skb = skb2) == NULL) { ++ AP6211_ERR("%s: skb_realloc_headroom failed\n", ++ dhd_ifname(&dhd->pub, ifidx)); ++ ret = -ENOMEM; ++ goto done; ++ } ++ } ++ ++ /* Convert to packet */ ++ if (!(pktbuf = PKTFRMNATIVE(dhd->pub.osh, skb))) { ++ AP6211_ERR("%s: PKTFRMNATIVE failed\n", ++ dhd_ifname(&dhd->pub, ifidx)); ++ dev_kfree_skb_any(skb); ++ ret = -ENOMEM; ++ goto done; ++ } ++#ifdef WLMEDIA_HTSF ++ if (htsfdlystat_sz && PKTLEN(dhd->pub.osh, pktbuf) >= ETHER_ADDR_LEN) { ++ uint8 *pktdata = (uint8 *)PKTDATA(dhd->pub.osh, pktbuf); ++ struct ether_header *eh = (struct ether_header *)pktdata; ++ ++ if (!ETHER_ISMULTI(eh->ether_dhost) && ++ (ntoh16(eh->ether_type) == ETHER_TYPE_IP)) { ++ eh->ether_type = hton16(ETHER_TYPE_BRCM_PKTDLYSTATS); ++ } ++ } ++#endif ++ ++ ret = dhd_sendpkt(&dhd->pub, ifidx, pktbuf); ++ ++ ++done: ++ if (ret) ++ dhd->pub.dstats.tx_dropped++; ++ else ++ dhd->pub.tx_packets++; ++ ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ ++ /* Return ok: we always eat the packet */ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) ++ return 0; ++#else ++ return NETDEV_TX_OK; ++#endif ++} ++ ++void ++dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool state) ++{ ++ struct net_device *net; ++ dhd_info_t *dhd = dhdp->info; ++ int i; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ ASSERT(dhd); ++ ++ if (ifidx == ALL_INTERFACES) { ++ /* Flow control on all active interfaces */ ++ dhdp->txoff = state; ++ for (i = 0; i < DHD_MAX_IFS; i++) { ++ if (dhd->iflist[i]) { ++ net = dhd->iflist[i]->net; ++ if (state == ON) ++ netif_stop_queue(net); ++ else ++ netif_wake_queue(net); ++ } ++ } ++ } ++ else { ++ if (dhd->iflist[ifidx]) { ++ net = dhd->iflist[ifidx]->net; ++ if (state == ON) ++ netif_stop_queue(net); ++ else ++ netif_wake_queue(net); ++ } ++ } ++} ++ ++#ifdef DHD_RX_DUMP ++typedef struct { ++ uint16 type; ++ const char *str; ++} PKTTYPE_INFO; ++ ++static const PKTTYPE_INFO packet_type_info[] = ++{ ++ { ETHER_TYPE_IP, "IP" }, ++ { ETHER_TYPE_ARP, "ARP" }, ++ { ETHER_TYPE_BRCM, "BRCM" }, ++ { ETHER_TYPE_802_1X, "802.1X" }, ++ { ETHER_TYPE_WAI, "WAPI" }, ++ { 0, ""} ++}; ++ ++static const char *_get_packet_type_str(uint16 type) ++{ ++ int i; ++ int n = sizeof(packet_type_info)/sizeof(packet_type_info[1]) - 1; ++ ++ for (i = 0; i < n; i++) { ++ if (packet_type_info[i].type == type) ++ return packet_type_info[i].str; ++ } ++ ++ return packet_type_info[n].str; ++} ++#endif /* DHD_RX_DUMP */ ++ ++void ++dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)dhdp->info; ++ struct sk_buff *skb; ++ uchar *eth; ++ uint len; ++ void *data, *pnext = NULL; ++ int i; ++ dhd_if_t *ifp; ++ wl_event_msg_t event; ++ int tout_rx = 0; ++ int tout_ctrl = 0; ++ ++#ifdef DHD_RX_DUMP ++#ifdef DHD_RX_FULL_DUMP ++ int k; ++#endif /* DHD_RX_FULL_DUMP */ ++ char *dump_data; ++ uint16 protocol; ++#endif /* DHD_RX_DUMP */ ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ for (i = 0; pktbuf && i < numpkt; i++, pktbuf = pnext) { ++#ifdef WLBTAMP ++ struct ether_header *eh; ++ struct dot11_llc_snap_header *lsh; ++#endif ++ ++ ifp = dhd->iflist[ifidx]; ++ if (ifp == NULL) { ++ AP6211_ERR("%s: ifp is NULL. drop packet\n", ++ __FUNCTION__); ++ PKTFREE(dhdp->osh, pktbuf, TRUE); ++ continue; ++ } ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) ++ /* Dropping packets before registering net device to avoid kernel panic */ ++#ifndef PROP_TXSTATUS_VSDB ++ if (!ifp->net || ifp->net->reg_state != NETREG_REGISTERED) { ++#else ++ if (!ifp->net || ifp->net->reg_state != NETREG_REGISTERED || !dhd->pub.up) { ++#endif /* PROP_TXSTATUS_VSDB */ ++ AP6211_ERR("%s: net device is NOT registered yet. drop packet\n", ++ __FUNCTION__); ++ PKTFREE(dhdp->osh, pktbuf, TRUE); ++ continue; ++ } ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ ++ ++ pnext = PKTNEXT(dhdp->osh, pktbuf); ++ PKTSETNEXT(wl->sh.osh, pktbuf, NULL); ++ ++#ifdef WLBTAMP ++ eh = (struct ether_header *)PKTDATA(wl->sh.osh, pktbuf); ++ lsh = (struct dot11_llc_snap_header *)&eh[1]; ++ ++ if ((ntoh16(eh->ether_type) < ETHER_TYPE_MIN) && ++ (PKTLEN(wl->sh.osh, pktbuf) >= RFC1042_HDR_LEN) && ++ bcmp(lsh, BT_SIG_SNAP_MPROT, DOT11_LLC_SNAP_HDR_LEN - 2) == 0 && ++ lsh->type == HTON16(BTA_PROT_L2CAP)) { ++ amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *) ++ ((uint8 *)eh + RFC1042_HDR_LEN); ++ ACL_data = NULL; ++ } ++#endif /* WLBTAMP */ ++ ++#ifdef PROP_TXSTATUS ++ if (dhdp->wlfc_state && PKTLEN(wl->sh.osh, pktbuf) == 0) { ++ /* WLFC may send header only packet when ++ there is an urgent message but no packet to ++ piggy-back on ++ */ ++ ((athost_wl_status_info_t*)dhdp->wlfc_state)->stats.wlfc_header_only_pkt++; ++ PKTFREE(dhdp->osh, pktbuf, TRUE); ++ continue; ++ } ++#endif ++ ++ skb = PKTTONATIVE(dhdp->osh, pktbuf); ++ ++ /* Get the protocol, maintain skb around eth_type_trans() ++ * The main reason for this hack is for the limitation of ++ * Linux 2.4 where 'eth_type_trans' uses the 'net->hard_header_len' ++ * to perform skb_pull inside vs ETH_HLEN. Since to avoid ++ * coping of the packet coming from the network stack to add ++ * BDC, Hardware header etc, during network interface registration ++ * we set the 'net->hard_header_len' to ETH_HLEN + extra space required ++ * for BDC, Hardware header etc. and not just the ETH_HLEN ++ */ ++ eth = skb->data; ++ len = skb->len; ++ ++#ifdef DHD_RX_DUMP ++ dump_data = skb->data; ++ protocol = (dump_data[12] << 8) | dump_data[13]; ++ AP6211_ERR("RX DUMP - %s\n", _get_packet_type_str(protocol)); ++ ++#ifdef DHD_RX_FULL_DUMP ++ if (protocol != ETHER_TYPE_BRCM) { ++ for (k = 0; k < skb->len; k++) { ++ AP6211_ERR("%02X ", dump_data[k])); ++ if ((k & 15) == 15) ++ AP6211_ERR("\n"); ++ } ++ AP6211_ERR("\n"); ++ } ++#endif /* DHD_RX_FULL_DUMP */ ++ ++ if (protocol != ETHER_TYPE_BRCM) { ++ if (dump_data[0] == 0xFF) { ++ AP6211_ERR("%s: BROADCAST\n", __FUNCTION__); ++ ++ if ((dump_data[12] == 8) && ++ (dump_data[13] == 6)) { ++ AP6211_ERR("%s: ARP %d\n", ++ __FUNCTION__, dump_data[0x15]); ++ } ++ } else if (dump_data[0] & 1) { ++ AP6211_ERR("%s: MULTICAST: " MACDBG "\n", ++ __FUNCTION__, MAC2STRDBG(dump_data)); ++ } ++ ++ if (protocol == ETHER_TYPE_802_1X) { ++ AP6211_ERR("ETHER_TYPE_802_1X: " ++ "ver %d, type %d, replay %d\n", ++ dump_data[14], dump_data[15], ++ dump_data[30]); ++ } ++ } ++ ++#endif /* DHD_RX_DUMP */ ++ ++ ifp = dhd->iflist[ifidx]; ++ if (ifp == NULL) ++ ifp = dhd->iflist[0]; ++ ++ ASSERT(ifp); ++ skb->dev = ifp->net; ++ skb->protocol = eth_type_trans(skb, skb->dev); ++ ++ if (skb->pkt_type == PACKET_MULTICAST) { ++ dhd->pub.rx_multicast++; ++ } ++ ++ skb->data = eth; ++ skb->len = len; ++ ++#ifdef WLMEDIA_HTSF ++ dhd_htsf_addrxts(dhdp, pktbuf); ++#endif ++ /* Strip header, count, deliver upward */ ++ skb_pull(skb, ETH_HLEN); ++ ++ /* Process special event packets and then discard them */ ++ if (ntoh16(skb->protocol) == ETHER_TYPE_BRCM) { ++ dhd_wl_host_event(dhd, &ifidx, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) ++ skb->mac_header, ++#else ++ skb->mac.raw, ++#endif ++ &event, ++ &data); ++ ++ wl_event_to_host_order(&event); ++ if (!tout_ctrl) ++ tout_ctrl = DHD_PACKET_TIMEOUT_MS; ++#ifdef WLBTAMP ++ if (event.event_type == WLC_E_BTA_HCI_EVENT) { ++ dhd_bta_doevt(dhdp, data, event.datalen); ++ } ++#endif /* WLBTAMP */ ++ ++#if defined(PNO_SUPPORT) ++ if (event.event_type == WLC_E_PFN_NET_FOUND) { ++ /* enforce custom wake lock to garantee that Kernel not suspended */ ++ tout_ctrl = CUSTOM_PNO_EVENT_LOCK_xTIME * DHD_PACKET_TIMEOUT_MS; ++ } ++#endif /* PNO_SUPPORT */ ++ ++#ifdef DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT ++ PKTFREE(dhdp->osh, pktbuf, TRUE); ++ continue; ++#endif ++ } else { ++ tout_rx = DHD_PACKET_TIMEOUT_MS; ++ } ++ ++ ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]); ++ if (dhd->iflist[ifidx] && !dhd->iflist[ifidx]->state) ++ ifp = dhd->iflist[ifidx]; ++ ++ if (ifp->net) ++ ifp->net->last_rx = jiffies; ++ ++ dhdp->dstats.rx_bytes += skb->len; ++ dhdp->rx_packets++; /* Local count */ ++ ++ if (in_interrupt()) { ++ netif_rx(skb); ++ } else { ++ /* If the receive is not processed inside an ISR, ++ * the softirqd must be woken explicitly to service ++ * the NET_RX_SOFTIRQ. In 2.6 kernels, this is handled ++ * by netif_rx_ni(), but in earlier kernels, we need ++ * to do it manually. ++ */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) ++ netif_rx_ni(skb); ++#else ++ ulong flags; ++ netif_rx(skb); ++ local_irq_save(flags); ++ RAISE_RX_SOFTIRQ(); ++ local_irq_restore(flags); ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ ++ } ++ } ++ ++ DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(dhdp, tout_rx); ++ DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhdp, tout_ctrl); ++} ++ ++void ++dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx) ++{ ++ /* Linux version has nothing to do */ ++ return; ++} ++ ++void ++dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); ++ struct ether_header *eh; ++ uint16 type; ++#ifdef WLBTAMP ++ uint len; ++#endif ++ ++ dhd_prot_hdrpull(dhdp, NULL, txp, NULL, NULL); ++ ++ eh = (struct ether_header *)PKTDATA(dhdp->osh, txp); ++ type = ntoh16(eh->ether_type); ++ ++ if (type == ETHER_TYPE_802_1X) ++ atomic_dec(&dhd->pend_8021x_cnt); ++ ++#ifdef WLBTAMP ++ /* Crack open the packet and check to see if it is BT HCI ACL data packet. ++ * If yes generate packet completion event. ++ */ ++ len = PKTLEN(dhdp->osh, txp); ++ ++ /* Generate ACL data tx completion event locally to avoid SDIO bus transaction */ ++ if ((type < ETHER_TYPE_MIN) && (len >= RFC1042_HDR_LEN)) { ++ struct dot11_llc_snap_header *lsh = (struct dot11_llc_snap_header *)&eh[1]; ++ ++ if (bcmp(lsh, BT_SIG_SNAP_MPROT, DOT11_LLC_SNAP_HDR_LEN - 2) == 0 && ++ ntoh16(lsh->type) == BTA_PROT_L2CAP) { ++ ++ dhd_bta_tx_hcidata_complete(dhdp, txp, success); ++ } ++ } ++#endif /* WLBTAMP */ ++} ++ ++static struct net_device_stats * ++dhd_get_stats(struct net_device *net) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); ++ dhd_if_t *ifp; ++ int ifidx; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ ifidx = dhd_net2idx(dhd, net); ++ if (ifidx == DHD_BAD_IF) { ++ AP6211_ERR("%s: BAD_IF\n", __FUNCTION__); ++ return NULL; ++ } ++ ++ ifp = dhd->iflist[ifidx]; ++ ASSERT(dhd && ifp); ++ ++ if (dhd->pub.up) { ++ /* Use the protocol to get dongle stats */ ++ dhd_prot_dstats(&dhd->pub); ++ } ++ ++ /* Copy dongle stats to net device stats */ ++ ifp->stats.rx_packets = dhd->pub.dstats.rx_packets; ++ ifp->stats.tx_packets = dhd->pub.dstats.tx_packets; ++ ifp->stats.rx_bytes = dhd->pub.dstats.rx_bytes; ++ ifp->stats.tx_bytes = dhd->pub.dstats.tx_bytes; ++ ifp->stats.rx_errors = dhd->pub.dstats.rx_errors; ++ ifp->stats.tx_errors = dhd->pub.dstats.tx_errors; ++ ifp->stats.rx_dropped = dhd->pub.dstats.rx_dropped; ++ ifp->stats.tx_dropped = dhd->pub.dstats.tx_dropped; ++ ifp->stats.multicast = dhd->pub.dstats.multicast; ++ ++ return &ifp->stats; ++} ++ ++#ifdef DHDTHREAD ++static int ++dhd_watchdog_thread(void *data) ++{ ++ tsk_ctl_t *tsk = (tsk_ctl_t *)data; ++ dhd_info_t *dhd = (dhd_info_t *)tsk->parent; ++ /* This thread doesn't need any user-level access, ++ * so get rid of all our resources ++ */ ++ if (dhd_watchdog_prio > 0) { ++ struct sched_param param; ++ param.sched_priority = (dhd_watchdog_prio < MAX_RT_PRIO)? ++ dhd_watchdog_prio:(MAX_RT_PRIO-1); ++ setScheduler(current, SCHED_FIFO, ¶m); ++ } ++#ifndef USE_KTHREAD_API ++ DAEMONIZE("dhd_watchdog"); ++ ++ /* Run until signal received */ ++ complete(&tsk->completed); ++#endif ++ ++ while (1) ++ if (down_interruptible (&tsk->sema) == 0) { ++ unsigned long flags; ++ unsigned long jiffies_at_start = jiffies; ++ unsigned long time_lapse; ++ ++ SMP_RD_BARRIER_DEPENDS(); ++ if (tsk->terminated) { ++ break; ++ } ++ ++ dhd_os_sdlock(&dhd->pub); ++ if (dhd->pub.dongle_reset == FALSE) { ++ AP6211_DEBUG("%s:\n", __FUNCTION__); ++ ++ /* Call the bus module watchdog */ ++ dhd_bus_watchdog(&dhd->pub); ++ ++ flags = dhd_os_spin_lock(&dhd->pub); ++ /* Count the tick for reference */ ++ dhd->pub.tickcnt++; ++ time_lapse = jiffies - jiffies_at_start; ++ ++ /* Reschedule the watchdog */ ++ if (dhd->wd_timer_valid) ++ mod_timer(&dhd->timer, ++ jiffies + ++ msecs_to_jiffies(dhd_watchdog_ms) - ++ min(msecs_to_jiffies(dhd_watchdog_ms), time_lapse)); ++ dhd_os_spin_unlock(&dhd->pub, flags); ++ } ++ dhd_os_sdunlock(&dhd->pub); ++ } else { ++ break; ++ } ++ ++ complete_and_exit(&tsk->completed, 0); ++} ++#endif /* DHDTHREAD */ ++ ++static void dhd_watchdog(ulong data) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)data; ++ unsigned long flags; ++ ++ if (dhd->pub.dongle_reset) { ++ return; ++ } ++ ++#ifdef DHDTHREAD ++ if (dhd->thr_wdt_ctl.thr_pid >= 0) { ++ up(&dhd->thr_wdt_ctl.sema); ++ return; ++ } ++#endif /* DHDTHREAD */ ++ ++ dhd_os_sdlock(&dhd->pub); ++ /* Call the bus module watchdog */ ++ dhd_bus_watchdog(&dhd->pub); ++ ++ flags = dhd_os_spin_lock(&dhd->pub); ++ /* Count the tick for reference */ ++ dhd->pub.tickcnt++; ++ ++ /* Reschedule the watchdog */ ++ if (dhd->wd_timer_valid) ++ mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms)); ++ dhd_os_spin_unlock(&dhd->pub, flags); ++ dhd_os_sdunlock(&dhd->pub); ++} ++ ++#ifdef DHDTHREAD ++static int ++dhd_dpc_thread(void *data) ++{ ++ tsk_ctl_t *tsk = (tsk_ctl_t *)data; ++ dhd_info_t *dhd = (dhd_info_t *)tsk->parent; ++ ++ /* This thread doesn't need any user-level access, ++ * so get rid of all our resources ++ */ ++ if (dhd_dpc_prio > 0) ++ { ++ struct sched_param param; ++ param.sched_priority = (dhd_dpc_prio < MAX_RT_PRIO)?dhd_dpc_prio:(MAX_RT_PRIO-1); ++ setScheduler(current, SCHED_FIFO, ¶m); ++ } ++#ifndef USE_KTHREAD_API ++ DAEMONIZE("dhd_dpc"); ++ /* DHD_OS_WAKE_LOCK is called in dhd_sched_dpc[dhd_linux.c] down below */ ++ ++ /* signal: thread has started */ ++ complete(&tsk->completed); ++#endif ++ ++ /* Run until signal received */ ++ while (1) { ++ if (down_interruptible(&tsk->sema) == 0) { ++ ++ SMP_RD_BARRIER_DEPENDS(); ++ if (tsk->terminated) { ++ break; ++ } ++ ++ /* Call bus dpc unless it indicated down (then clean stop) */ ++ if (dhd->pub.busstate != DHD_BUS_DOWN) { ++ if (dhd_bus_dpc(dhd->pub.bus)) { ++ up(&tsk->sema); ++ } ++ else { ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ } ++ } else { ++ if (dhd->pub.up) ++ dhd_bus_stop(dhd->pub.bus, TRUE); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ } ++ } ++ else ++ break; ++ } ++ ++ complete_and_exit(&tsk->completed, 0); ++} ++#endif /* DHDTHREAD */ ++ ++static void ++dhd_dpc(ulong data) ++{ ++ dhd_info_t *dhd; ++ ++ dhd = (dhd_info_t *)data; ++ ++ /* this (tasklet) can be scheduled in dhd_sched_dpc[dhd_linux.c] ++ * down below , wake lock is set, ++ * the tasklet is initialized in dhd_attach() ++ */ ++ /* Call bus dpc unless it indicated down (then clean stop) */ ++ if (dhd->pub.busstate != DHD_BUS_DOWN) { ++ if (dhd_bus_dpc(dhd->pub.bus)) ++ tasklet_schedule(&dhd->tasklet); ++ else ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ } else { ++ dhd_bus_stop(dhd->pub.bus, TRUE); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ } ++} ++ ++void ++dhd_sched_dpc(dhd_pub_t *dhdp) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)dhdp->info; ++ ++ DHD_OS_WAKE_LOCK(dhdp); ++#ifdef DHDTHREAD ++ if (dhd->thr_dpc_ctl.thr_pid >= 0) { ++ up(&dhd->thr_dpc_ctl.sema); ++ return; ++ } ++#endif /* DHDTHREAD */ ++ ++ if (dhd->dhd_tasklet_create) ++ tasklet_schedule(&dhd->tasklet); ++} ++ ++#ifdef TOE ++/* Retrieve current toe component enables, which are kept as a bitmap in toe_ol iovar */ ++static int ++dhd_toe_get(dhd_info_t *dhd, int ifidx, uint32 *toe_ol) ++{ ++ wl_ioctl_t ioc; ++ char buf[32]; ++ int ret; ++ ++ memset(&ioc, 0, sizeof(ioc)); ++ ++ ioc.cmd = WLC_GET_VAR; ++ ioc.buf = buf; ++ ioc.len = (uint)sizeof(buf); ++ ioc.set = FALSE; ++ ++ strncpy(buf, "toe_ol", sizeof(buf) - 1); ++ buf[sizeof(buf) - 1] = '\0'; ++ if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { ++ /* Check for older dongle image that doesn't support toe_ol */ ++ if (ret == -EIO) { ++ AP6211_ERR("%s: toe not supported by device\n", ++ dhd_ifname(&dhd->pub, ifidx)); ++ return -EOPNOTSUPP; ++ } ++ ++ AP6211_DEBUG("%s: could not get toe_ol: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret); ++ return ret; ++ } ++ ++ memcpy(toe_ol, buf, sizeof(uint32)); ++ return 0; ++} ++ ++/* Set current toe component enables in toe_ol iovar, and set toe global enable iovar */ ++static int ++dhd_toe_set(dhd_info_t *dhd, int ifidx, uint32 toe_ol) ++{ ++ wl_ioctl_t ioc; ++ char buf[32]; ++ int toe, ret; ++ ++ memset(&ioc, 0, sizeof(ioc)); ++ ++ ioc.cmd = WLC_SET_VAR; ++ ioc.buf = buf; ++ ioc.len = (uint)sizeof(buf); ++ ioc.set = TRUE; ++ ++ /* Set toe_ol as requested */ ++ ++ strncpy(buf, "toe_ol", sizeof(buf) - 1); ++ buf[sizeof(buf) - 1] = '\0'; ++ memcpy(&buf[sizeof("toe_ol")], &toe_ol, sizeof(uint32)); ++ ++ if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { ++ AP6211_ERR("%s: could not set toe_ol: ret=%d\n", ++ dhd_ifname(&dhd->pub, ifidx), ret); ++ return ret; ++ } ++ ++ /* Enable toe globally only if any components are enabled. */ ++ ++ toe = (toe_ol != 0); ++ ++ strcpy(buf, "toe"); ++ memcpy(&buf[sizeof("toe")], &toe, sizeof(uint32)); ++ ++ if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { ++ AP6211_ERR("%s: could not set toe: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret); ++ return ret; ++ } ++ ++ return 0; ++} ++#endif /* TOE */ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) ++static void ++dhd_ethtool_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); ++ ++ snprintf(info->driver, sizeof(info->driver), "wl"); ++ snprintf(info->version, sizeof(info->version), "%lu", dhd->pub.drv_version); ++} ++ ++struct ethtool_ops dhd_ethtool_ops = { ++ .get_drvinfo = dhd_ethtool_get_drvinfo ++}; ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ ++ ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) ++static int ++dhd_ethtool(dhd_info_t *dhd, void *uaddr) ++{ ++ struct ethtool_drvinfo info; ++ char drvname[sizeof(info.driver)]; ++ uint32 cmd; ++#ifdef TOE ++ struct ethtool_value edata; ++ uint32 toe_cmpnt, csum_dir; ++ int ret; ++#endif ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ /* all ethtool calls start with a cmd word */ ++ if (copy_from_user(&cmd, uaddr, sizeof (uint32))) ++ return -EFAULT; ++ ++ switch (cmd) { ++ case ETHTOOL_GDRVINFO: ++ /* Copy out any request driver name */ ++ if (copy_from_user(&info, uaddr, sizeof(info))) ++ return -EFAULT; ++ strncpy(drvname, info.driver, sizeof(info.driver)); ++ drvname[sizeof(info.driver)-1] = '\0'; ++ ++ /* clear struct for return */ ++ memset(&info, 0, sizeof(info)); ++ info.cmd = cmd; ++ ++ /* if dhd requested, identify ourselves */ ++ if (strcmp(drvname, "?dhd") == 0) { ++ snprintf(info.driver, sizeof(info.driver), "dhd"); ++ strncpy(info.version, EPI_VERSION_STR, sizeof(info.version) - 1); ++ info.version[sizeof(info.version) - 1] = '\0'; ++ } ++ ++ /* otherwise, require dongle to be up */ ++ else if (!dhd->pub.up) { ++ AP6211_ERR("%s: dongle is not up\n", __FUNCTION__); ++ return -ENODEV; ++ } ++ ++ /* finally, report dongle driver type */ ++ else if (dhd->pub.iswl) ++ snprintf(info.driver, sizeof(info.driver), "wl"); ++ else ++ snprintf(info.driver, sizeof(info.driver), "xx"); ++ ++ snprintf(info.version, sizeof(info.version), "%lu", dhd->pub.drv_version); ++ if (copy_to_user(uaddr, &info, sizeof(info))) ++ return -EFAULT; ++ AP6211_DEBUG("%s: given %*s, returning %s\n", __FUNCTION__, ++ (int)sizeof(drvname), drvname, info.driver); ++ break; ++ ++#ifdef TOE ++ /* Get toe offload components from dongle */ ++ case ETHTOOL_GRXCSUM: ++ case ETHTOOL_GTXCSUM: ++ if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 0) ++ return ret; ++ ++ csum_dir = (cmd == ETHTOOL_GTXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL; ++ ++ edata.cmd = cmd; ++ edata.data = (toe_cmpnt & csum_dir) ? 1 : 0; ++ ++ if (copy_to_user(uaddr, &edata, sizeof(edata))) ++ return -EFAULT; ++ break; ++ ++ /* Set toe offload components in dongle */ ++ case ETHTOOL_SRXCSUM: ++ case ETHTOOL_STXCSUM: ++ if (copy_from_user(&edata, uaddr, sizeof(edata))) ++ return -EFAULT; ++ ++ /* Read the current settings, update and write back */ ++ if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 0) ++ return ret; ++ ++ csum_dir = (cmd == ETHTOOL_STXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL; ++ ++ if (edata.data != 0) ++ toe_cmpnt |= csum_dir; ++ else ++ toe_cmpnt &= ~csum_dir; ++ ++ if ((ret = dhd_toe_set(dhd, 0, toe_cmpnt)) < 0) ++ return ret; ++ ++ /* If setting TX checksum mode, tell Linux the new mode */ ++ if (cmd == ETHTOOL_STXCSUM) { ++ if (edata.data) ++ dhd->iflist[0]->net->features |= NETIF_F_IP_CSUM; ++ else ++ dhd->iflist[0]->net->features &= ~NETIF_F_IP_CSUM; ++ } ++ ++ break; ++#endif /* TOE */ ++ ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ return 0; ++} ++#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */ ++ ++static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error) ++{ ++ dhd_info_t * dhd; ++ ++ if (!dhdp) ++ return FALSE; ++ ++ dhd = (dhd_info_t *)dhdp->info; ++ if (dhd->thr_sysioc_ctl.thr_pid < 0) { ++ AP6211_ERR("%s : skipped due to negative pid - unloading?\n", __FUNCTION__); ++ return FALSE; ++ } ++ ++ if ((error == -ETIMEDOUT) || (error == -EREMOTEIO) || ++ ((dhdp->busstate == DHD_BUS_DOWN) && (!dhdp->dongle_reset))) { ++ AP6211_ERR("%s: Event HANG send up due to re=%d te=%d e=%d s=%d\n", __FUNCTION__, ++ dhdp->rxcnt_timeout, dhdp->txcnt_timeout, error, dhdp->busstate); ++ net_os_send_hang_message(net); ++ return TRUE; ++ } ++ return FALSE; ++} ++ ++static int ++dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); ++ dhd_ioctl_t ioc; ++ int bcmerror = 0; ++ int buflen = 0; ++ void *buf = NULL; ++ uint driver = 0; ++ int ifidx; ++ int ret; ++ ++ DHD_OS_WAKE_LOCK(&dhd->pub); ++ ++ /* send to dongle only if we are not waiting for reload already */ ++ if (dhd->pub.hang_was_sent) { ++ AP6211_ERR("%s: HANG was sent up earlier\n", __FUNCTION__); ++ DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(&dhd->pub, DHD_EVENT_TIMEOUT_MS); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ return OSL_ERROR(BCME_DONGLE_DOWN); ++ } ++ ++ ifidx = dhd_net2idx(dhd, net); ++ AP6211_DEBUG("%s: ifidx %d, cmd 0x%04x\n", __FUNCTION__, ifidx, cmd); ++ ++ if (ifidx == DHD_BAD_IF) { ++ AP6211_ERR("%s: BAD IF\n", __FUNCTION__); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ return -1; ++ } ++ ++#if defined(CONFIG_WIRELESS_EXT) ++ /* linux wireless extensions */ ++ if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) { ++ /* may recurse, do NOT lock */ ++ ret = wl_iw_ioctl(net, ifr, cmd); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ return ret; ++ } ++#endif /* defined(CONFIG_WIRELESS_EXT) */ ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) ++ if (cmd == SIOCETHTOOL) { ++ ret = dhd_ethtool(dhd, (void*)ifr->ifr_data); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ return ret; ++ } ++#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */ ++ ++ if (cmd == SIOCDEVPRIVATE+1) { ++ ret = wl_android_priv_cmd(net, ifr, cmd); ++ dhd_check_hang(net, &dhd->pub, ret); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ return ret; ++ } ++ ++ if (cmd != SIOCDEVPRIVATE) { ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ return -EOPNOTSUPP; ++ } ++ ++ memset(&ioc, 0, sizeof(ioc)); ++ ++ /* Copy the ioc control structure part of ioctl request */ ++ if (copy_from_user(&ioc, ifr->ifr_data, sizeof(wl_ioctl_t))) { ++ bcmerror = BCME_BADADDR; ++ goto done; ++ } ++ ++ /* Copy out any buffer passed */ ++ if (ioc.buf) { ++ if (ioc.len == 0) { ++ AP6211_DEBUG("%s: ioc.len=0, returns BCME_BADARG \n", __FUNCTION__); ++ bcmerror = BCME_BADARG; ++ goto done; ++ } ++ buflen = MIN(ioc.len, DHD_IOCTL_MAXLEN); ++ /* optimization for direct ioctl calls from kernel */ ++ /* ++ if (segment_eq(get_fs(), KERNEL_DS)) { ++ buf = ioc.buf; ++ } else { ++ */ ++ { ++ if (!(buf = (char*)MALLOC(dhd->pub.osh, buflen))) { ++ bcmerror = BCME_NOMEM; ++ goto done; ++ } ++ if (copy_from_user(buf, ioc.buf, buflen)) { ++ bcmerror = BCME_BADADDR; ++ goto done; ++ } ++ } ++ } ++ ++ /* To differentiate between wl and dhd read 4 more byes */ ++ if ((copy_from_user(&driver, (char *)ifr->ifr_data + sizeof(wl_ioctl_t), ++ sizeof(uint)) != 0)) { ++ bcmerror = BCME_BADADDR; ++ goto done; ++ } ++ ++ if (!capable(CAP_NET_ADMIN)) { ++ bcmerror = BCME_EPERM; ++ goto done; ++ } ++ ++ /* check for local dhd ioctl and handle it */ ++ if (driver == DHD_IOCTL_MAGIC) { ++ bcmerror = dhd_ioctl((void *)&dhd->pub, &ioc, buf, buflen); ++ if (bcmerror) ++ dhd->pub.bcmerror = bcmerror; ++ goto done; ++ } ++ ++ /* send to dongle (must be up, and wl). */ ++ if (dhd->pub.busstate != DHD_BUS_DATA) { ++ bcmerror = BCME_DONGLE_DOWN; ++ goto done; ++ } ++ ++ if (!dhd->pub.iswl) { ++ bcmerror = BCME_DONGLE_DOWN; ++ goto done; ++ } ++ ++ /* ++ * Flush the TX queue if required for proper message serialization: ++ * Intercept WLC_SET_KEY IOCTL - serialize M4 send and set key IOCTL to ++ * prevent M4 encryption and ++ * intercept WLC_DISASSOC IOCTL - serialize WPS-DONE and WLC_DISASSOC IOCTL to ++ * prevent disassoc frame being sent before WPS-DONE frame. ++ */ ++ if (ioc.cmd == WLC_SET_KEY || ++ (ioc.cmd == WLC_SET_VAR && ioc.buf != NULL && ++ strncmp("wsec_key", ioc.buf, 9) == 0) || ++ (ioc.cmd == WLC_SET_VAR && ioc.buf != NULL && ++ strncmp("bsscfg:wsec_key", ioc.buf, 15) == 0) || ++ ioc.cmd == WLC_DISASSOC) ++ dhd_wait_pend8021x(net); ++ ++#ifdef WLMEDIA_HTSF ++ if (ioc.buf) { ++ /* short cut wl ioctl calls here */ ++ if (strcmp("htsf", ioc.buf) == 0) { ++ dhd_ioctl_htsf_get(dhd, 0); ++ return BCME_OK; ++ } ++ ++ if (strcmp("htsflate", ioc.buf) == 0) { ++ if (ioc.set) { ++ memset(ts, 0, sizeof(tstamp_t)*TSMAX); ++ memset(&maxdelayts, 0, sizeof(tstamp_t)); ++ maxdelay = 0; ++ tspktcnt = 0; ++ maxdelaypktno = 0; ++ memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN); ++ memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN); ++ memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN); ++ memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN); ++ } else { ++ dhd_dump_latency(); ++ } ++ return BCME_OK; ++ } ++ if (strcmp("htsfclear", ioc.buf) == 0) { ++ memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN); ++ memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN); ++ memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN); ++ memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN); ++ htsf_seqnum = 0; ++ return BCME_OK; ++ } ++ if (strcmp("htsfhis", ioc.buf) == 0) { ++ dhd_dump_htsfhisto(&vi_d1, "H to D"); ++ dhd_dump_htsfhisto(&vi_d2, "D to D"); ++ dhd_dump_htsfhisto(&vi_d3, "D to H"); ++ dhd_dump_htsfhisto(&vi_d4, "H to H"); ++ return BCME_OK; ++ } ++ if (strcmp("tsport", ioc.buf) == 0) { ++ if (ioc.set) { ++ memcpy(&tsport, ioc.buf + 7, 4); ++ } else { ++ AP6211_ERR("current timestamp port: %d \n", tsport); ++ } ++ return BCME_OK; ++ } ++ } ++#endif /* WLMEDIA_HTSF */ ++ ++ if ((ioc.cmd == WLC_SET_VAR || ioc.cmd == WLC_GET_VAR) && ++ ioc.buf != NULL && strncmp("rpc_", ioc.buf, 4) == 0) { ++#ifdef BCM_FD_AGGR ++ bcmerror = dhd_fdaggr_ioctl(&dhd->pub, ifidx, (wl_ioctl_t *)&ioc, buf, buflen); ++#else ++ bcmerror = BCME_UNSUPPORTED; ++#endif ++ goto done; ++ } ++ bcmerror = dhd_wl_ioctl(&dhd->pub, ifidx, (wl_ioctl_t *)&ioc, buf, buflen); ++ ++done: ++ dhd_check_hang(net, &dhd->pub, bcmerror); ++ ++ if (!bcmerror && buf && ioc.buf) { ++ if (copy_to_user(ioc.buf, buf, buflen)) ++ bcmerror = -EFAULT; ++ } ++ ++ if (buf) ++ MFREE(dhd->pub.osh, buf, buflen); ++ ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ ++ return OSL_ERROR(bcmerror); ++} ++ ++#ifdef WL_CFG80211 ++static int ++dhd_cleanup_virt_ifaces(dhd_info_t *dhd) ++{ ++ int i = 1; /* Leave ifidx 0 [Primary Interface] */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ int rollback_lock = FALSE; ++#endif ++ ++ AP6211_DEBUG("%s: Enter \n", __func__); ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ /* release lock for unregister_netdev */ ++ if (rtnl_is_locked()) { ++ rtnl_unlock(); ++ rollback_lock = TRUE; ++ } ++#endif ++ ++ for (i = 1; i < DHD_MAX_IFS; i++) { ++ dhd_net_if_lock_local(dhd); ++ if (dhd->iflist[i]) { ++ AP6211_DEBUG("Deleting IF: %d \n", i); ++ if ((dhd->iflist[i]->state != DHD_IF_DEL) && ++ (dhd->iflist[i]->state != DHD_IF_DELETING)) { ++ dhd->iflist[i]->state = DHD_IF_DEL; ++ dhd->iflist[i]->idx = i; ++ dhd_op_if(dhd->iflist[i]); ++ } ++ } ++ dhd_net_if_unlock_local(dhd); ++ } ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ if (rollback_lock) ++ rtnl_lock(); ++#endif ++ ++ return 0; ++} ++#endif /* WL_CFG80211 */ ++ ++ ++static int ++dhd_stop(struct net_device *net) ++{ ++ int ifidx = 0; ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); ++ DHD_OS_WAKE_LOCK(&dhd->pub); ++ AP6211_DEBUG("%s: Enter %p\n", __FUNCTION__, net); ++ if (dhd->pub.up == 0) { ++ goto exit; ++ } ++ ifidx = dhd_net2idx(dhd, net); ++ BCM_REFERENCE(ifidx); ++ ++ /* Set state and stop OS transmissions */ ++ netif_stop_queue(net); ++ dhd->pub.up = 0; ++ ++#ifdef WL_CFG80211 ++ if (ifidx == 0) { ++ wl_cfg80211_down(NULL); ++ ++ /* ++ * For CFG80211: Clean up all the left over virtual interfaces ++ * when the primary Interface is brought down. [ifconfig wlan0 down] ++ */ ++ if ((dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) && ++ (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)) { ++ dhd_cleanup_virt_ifaces(dhd); ++ } ++ } ++#endif ++ ++#ifdef PROP_TXSTATUS ++ dhd_os_wlfc_block(&dhd->pub); ++ dhd_wlfc_cleanup(&dhd->pub); ++ dhd_os_wlfc_unblock(&dhd->pub); ++#endif ++ /* Stop the protocol module */ ++ dhd_prot_stop(&dhd->pub); ++ ++ OLD_MOD_DEC_USE_COUNT; ++exit: ++#if defined(WL_CFG80211) ++ if (ifidx == 0) { ++ if (!dhd_download_fw_on_driverload) ++ wl_android_wifi_off(net); ++ } ++#endif ++ dhd->pub.rxcnt_timeout = 0; ++ dhd->pub.txcnt_timeout = 0; ++ ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ return 0; ++} ++ ++static int ++dhd_open(struct net_device *net) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); ++#ifdef TOE ++ uint32 toe_ol; ++#endif ++ int ifidx; ++ int32 ret = 0; ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 ++ if (mutex_is_locked(&_dhd_sdio_mutex_lock_) != 0) { ++ AP6211_ERR("%s : dhd_open: call dev open before insmod complete!\n", __FUNCTION__); ++ } ++ mutex_lock(&_dhd_sdio_mutex_lock_); ++#endif ++ ++ AP6211_DEBUG("%s, firmware path %s\n", __func__, firmware_path); ++ ++ DHD_OS_WAKE_LOCK(&dhd->pub); ++ /* Update FW path if it was changed */ ++ if (strlen(firmware_path) != 0) { ++ if (firmware_path[strlen(firmware_path)-1] == '\n') ++ firmware_path[strlen(firmware_path)-1] = '\0'; ++ COPY_FW_PATH_BY_CHIP( dhd->pub.bus, fw_path, firmware_path); ++ } ++ ++ ++ dhd->pub.dongle_trap_occured = 0; ++ dhd->pub.hang_was_sent = 0; ++#if !defined(WL_CFG80211) ++ /* ++ * Force start if ifconfig_up gets called before START command ++ * We keep WEXT's wl_control_wl_start to provide backward compatibility ++ * This should be removed in the future ++ */ ++ ret = wl_control_wl_start(net); ++ if (ret != 0) { ++ AP6211_ERR("%s: failed with code %d\n", __FUNCTION__, ret); ++ ret = -1; ++ goto exit; ++ } ++#endif ++ ++ ifidx = dhd_net2idx(dhd, net); ++ AP6211_DEBUG("%s: ifidx %d\n", __FUNCTION__, ifidx); ++ ++ if (ifidx < 0) { ++ AP6211_ERR("%s: Error: called with invalid IF\n", __FUNCTION__); ++ ret = -1; ++ goto exit; ++ } ++ ++ if (!dhd->iflist[ifidx] || dhd->iflist[ifidx]->state == DHD_IF_DEL) { ++ AP6211_ERR("%s: Error: called when IF already deleted\n", __FUNCTION__); ++ ret = -1; ++ goto exit; ++ } ++ ++ if (ifidx == 0) { ++ atomic_set(&dhd->pend_8021x_cnt, 0); ++#if defined(WL_CFG80211) ++ AP6211_ERR("%s\n", dhd_version); ++#if defined(DHD_DEBUG) ++ AP6211_ERR("%s\n", dhd_version_info); ++#endif ++ ++ if (!dhd_download_fw_on_driverload) { ++ ret = wl_android_wifi_on(net); ++ if (ret != 0) { ++ AP6211_ERR("%s: failed with code %d\n", __FUNCTION__, ret); ++ ret = -1; ++ goto exit; ++ } ++ } else { ++ } ++#endif ++ ++ if (dhd->pub.busstate != DHD_BUS_DATA) { ++ ++ /* try to bring up bus */ ++ if ((ret = dhd_bus_start(&dhd->pub)) != 0) { ++ AP6211_ERR("%s: failed with code %d\n", __FUNCTION__, ret); ++ ret = -1; ++ goto exit; ++ } ++ ++ } ++ ++ /* dhd_prot_init has been called in dhd_bus_start or wl_android_wifi_on */ ++ memcpy(net->dev_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN); ++ ++#ifdef TOE ++ /* Get current TOE mode from dongle */ ++ if (dhd_toe_get(dhd, ifidx, &toe_ol) >= 0 && (toe_ol & TOE_TX_CSUM_OL) != 0) ++ dhd->iflist[ifidx]->net->features |= NETIF_F_IP_CSUM; ++ else ++ dhd->iflist[ifidx]->net->features &= ~NETIF_F_IP_CSUM; ++#endif /* TOE */ ++ ++#if defined(WL_CFG80211) ++ if (unlikely(wl_cfg80211_up(NULL))) { ++ AP6211_ERR("%s: failed to bring up cfg80211\n", __FUNCTION__); ++ ret = -1; ++ goto exit; ++ } ++#endif /* WL_CFG80211 */ ++ } ++ ++ /* Allow transmit calls */ ++ netif_start_queue(net); ++ dhd->pub.up = 1; ++ ++#ifdef BCMDBGFS ++ dhd_dbg_init(&dhd->pub); ++#endif ++ ++ OLD_MOD_INC_USE_COUNT; ++exit: ++ if (ret) ++ dhd_stop(net); ++ ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 ++ mutex_unlock(&_dhd_sdio_mutex_lock_); ++#endif ++ return ret; ++} ++ ++int dhd_do_driver_init(struct net_device *net) ++{ ++ dhd_info_t *dhd = NULL; ++ ++ if (!net) { ++ AP6211_ERR("Primary Interface not initialized \n"); ++ return -EINVAL; ++ } ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 ++#ifdef MULTIPLE_SUPPLICANT ++ if (mutex_is_locked(&_dhd_sdio_mutex_lock_) != 0) { ++ AP6211_ERR("%s : dhdsdio_probe is already running!\n", __FUNCTION__); ++ return 0; ++ } ++#endif /* MULTIPLE_SUPPLICANT */ ++#endif ++ ++ dhd = *(dhd_info_t **)netdev_priv(net); ++ ++ /* If driver is already initialized, do nothing ++ */ ++ if (dhd->pub.busstate == DHD_BUS_DATA) { ++ AP6211_DEBUG("Driver already Inititalized. Nothing to do"); ++ return 0; ++ } ++ ++ if (dhd_open(net) < 0) { ++ AP6211_ERR("Driver Init Failed \n"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++osl_t * ++dhd_osl_attach(void *pdev, uint bustype) ++{ ++ return osl_attach(pdev, bustype, TRUE); ++} ++ ++void ++dhd_osl_detach(osl_t *osh) ++{ ++ if (MALLOCED(osh)) { ++ AP6211_ERR("%s: MEMORY LEAK %d bytes\n", __FUNCTION__, MALLOCED(osh)); ++ } ++ osl_detach(osh); ++#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ dhd_registration_check = FALSE; ++ up(&dhd_registration_sem); ++#if defined(BCMLXSDMMC) ++ up(&dhd_chipup_sem); ++#endif ++#endif ++} ++ ++int ++dhd_add_if(dhd_info_t *dhd, int ifidx, void *handle, char *name, ++ uint8 *mac_addr, uint32 flags, uint8 bssidx) ++{ ++ dhd_if_t *ifp; ++ ++ AP6211_DEBUG("%s: idx %d, handle->%p\n", __FUNCTION__, ifidx, handle); ++ ++ ASSERT(dhd && (ifidx < DHD_MAX_IFS)); ++ ++ ifp = dhd->iflist[ifidx]; ++ if (ifp != NULL) { ++ if (ifp->net != NULL) { ++ netif_stop_queue(ifp->net); ++ unregister_netdev(ifp->net); ++ free_netdev(ifp->net); ++ } ++ } else ++ if ((ifp = MALLOC(dhd->pub.osh, sizeof(dhd_if_t))) == NULL) { ++ AP6211_ERR("%s: OOM - dhd_if_t\n", __FUNCTION__); ++ return -ENOMEM; ++ } ++ ++ memset(ifp, 0, sizeof(dhd_if_t)); ++ ifp->event2cfg80211 = FALSE; ++ ifp->info = dhd; ++ dhd->iflist[ifidx] = ifp; ++ strncpy(ifp->name, name, IFNAMSIZ); ++ ifp->name[IFNAMSIZ] = '\0'; ++ if (mac_addr != NULL) ++ memcpy(&ifp->mac_addr, mac_addr, ETHER_ADDR_LEN); ++ ++ if (handle == NULL) { ++ ifp->state = DHD_IF_ADD; ++ ifp->idx = ifidx; ++ ifp->bssidx = bssidx; ++ ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0); ++ up(&dhd->thr_sysioc_ctl.sema); ++ } else ++ ifp->net = (struct net_device *)handle; ++ ++ if (ifidx == 0) { ++ ifp->event2cfg80211 = TRUE; ++ } ++ ++ return 0; ++} ++ ++void ++dhd_del_if(dhd_info_t *dhd, int ifidx) ++{ ++ dhd_if_t *ifp; ++ ++ AP6211_DEBUG("%s: idx %d\n", __FUNCTION__, ifidx); ++ ++ ASSERT(dhd && ifidx && (ifidx < DHD_MAX_IFS)); ++ ifp = dhd->iflist[ifidx]; ++ if (!ifp) { ++ AP6211_ERR("%s: Null interface\n", __FUNCTION__); ++ return; ++ } ++ ++ ifp->state = DHD_IF_DEL; ++ ifp->idx = ifidx; ++ ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0); ++ up(&dhd->thr_sysioc_ctl.sema); ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) ++static struct net_device_ops dhd_ops_pri = { ++ .ndo_open = dhd_open, ++ .ndo_stop = dhd_stop, ++ .ndo_get_stats = dhd_get_stats, ++ .ndo_do_ioctl = dhd_ioctl_entry, ++ .ndo_start_xmit = dhd_start_xmit, ++ .ndo_set_mac_address = dhd_set_mac_address, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) ++ .ndo_set_rx_mode = dhd_set_multicast_list, ++#else ++ .ndo_set_multicast_list = dhd_set_multicast_list, ++#endif ++}; ++ ++static struct net_device_ops dhd_ops_virt = { ++ .ndo_get_stats = dhd_get_stats, ++ .ndo_do_ioctl = dhd_ioctl_entry, ++ .ndo_start_xmit = dhd_start_xmit, ++ .ndo_set_mac_address = dhd_set_mac_address, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) ++ .ndo_set_rx_mode = dhd_set_multicast_list, ++#else ++ .ndo_set_multicast_list = dhd_set_multicast_list, ++#endif ++}; ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) */ ++ ++dhd_pub_t * ++dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) ++{ ++ dhd_info_t *dhd = NULL; ++ struct net_device *net = NULL; ++ ++ dhd_attach_states_t dhd_state = DHD_ATTACH_STATE_INIT; ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ AP6211_DEBUG("%s, firmware path %s\n", __func__, firmware_path); ++ ++ /* updates firmware nvram path if it was provided as module parameters */ ++ if ((firmware_path != NULL) && (firmware_path[0] != '\0')) ++ COPY_FW_PATH_BY_CHIP(bus, fw_path, firmware_path); ++ if (strlen(nvram_path) != 0) { ++ strncpy(nv_path, nvram_path, sizeof(nv_path) -1); ++ nv_path[sizeof(nv_path) -1] = '\0'; ++ } ++ ++ /* Allocate etherdev, including space for private structure */ ++ if (!(net = alloc_etherdev(sizeof(dhd)))) { ++ AP6211_ERR("%s: OOM - alloc_etherdev\n", __FUNCTION__); ++ goto fail; ++ } ++ dhd_state |= DHD_ATTACH_STATE_NET_ALLOC; ++ ++ /* Allocate primary dhd_info */ ++ if (!(dhd = MALLOC(osh, sizeof(dhd_info_t)))) { ++ AP6211_ERR("%s: OOM - alloc dhd_info\n", __FUNCTION__); ++ goto fail; ++ } ++ memset(dhd, 0, sizeof(dhd_info_t)); ++ ++#ifdef DHDTHREAD ++ dhd->thr_dpc_ctl.thr_pid = DHD_PID_KT_TL_INVALID; ++ dhd->thr_wdt_ctl.thr_pid = DHD_PID_KT_INVALID; ++#endif /* DHDTHREAD */ ++ dhd->dhd_tasklet_create = FALSE; ++ dhd->thr_sysioc_ctl.thr_pid = DHD_PID_KT_INVALID; ++ dhd_state |= DHD_ATTACH_STATE_DHD_ALLOC; ++ ++ /* ++ * Save the dhd_info into the priv ++ */ ++ memcpy((void *)netdev_priv(net), &dhd, sizeof(dhd)); ++ dhd->pub.osh = osh; ++ ++ /* Link to info module */ ++ dhd->pub.info = dhd; ++ /* Link to bus module */ ++ dhd->pub.bus = bus; ++ dhd->pub.hdrlen = bus_hdrlen; ++ ++ /* Set network interface name if it was provided as module parameter */ ++ if (iface_name[0]) { ++ int len; ++ char ch; ++ strncpy(net->name, iface_name, IFNAMSIZ); ++ net->name[IFNAMSIZ - 1] = 0; ++ len = strlen(net->name); ++ ch = net->name[len - 1]; ++ if ((ch > '9' || ch < '0') && (len < IFNAMSIZ - 2)) ++ strcat(net->name, "%d"); ++ } ++ ++ if (dhd_add_if(dhd, 0, (void *)net, net->name, NULL, 0, 0) == DHD_BAD_IF) ++ goto fail; ++ dhd_state |= DHD_ATTACH_STATE_ADD_IF; ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) ++ net->open = NULL; ++#else ++ net->netdev_ops = NULL; ++#endif ++ ++ sema_init(&dhd->proto_sem, 1); ++ ++#ifdef PROP_TXSTATUS ++ spin_lock_init(&dhd->wlfc_spinlock); ++#ifdef PROP_TXSTATUS_VSDB ++ dhd->pub.wlfc_enabled = FALSE; ++#else ++ dhd->pub.wlfc_enabled = TRUE; ++#endif /* PROP_TXSTATUS_VSDB */ ++#endif /* PROP_TXSTATUS */ ++ ++ /* Initialize other structure content */ ++ init_waitqueue_head(&dhd->ioctl_resp_wait); ++ init_waitqueue_head(&dhd->ctrl_wait); ++ ++ /* Initialize the spinlocks */ ++ spin_lock_init(&dhd->sdlock); ++ spin_lock_init(&dhd->txqlock); ++ spin_lock_init(&dhd->dhd_lock); ++ ++ /* Initialize Wakelock stuff */ ++ spin_lock_init(&dhd->wakelock_spinlock); ++ dhd->wakelock_counter = 0; ++ dhd->wakelock_wd_counter = 0; ++ dhd->wakelock_rx_timeout_enable = 0; ++ dhd->wakelock_ctrl_timeout_enable = 0; ++#ifdef CONFIG_HAS_WAKELOCK ++ dhd->wl_wifi = MALLOC(osh, sizeof(struct wake_lock)); ++ dhd->wl_rxwake = MALLOC(osh, sizeof(struct wake_lock)); ++ dhd->wl_ctrlwake = MALLOC(osh, sizeof(struct wake_lock)); ++ dhd->wl_wdwake = MALLOC(osh, sizeof(struct wake_lock)); ++ if (!dhd->wl_wifi || !dhd->wl_rxwake || !dhd->wl_ctrlwake || !dhd->wl_wdwake) { ++ AP6211_ERR("%s: mem alloc for wake lock failed\n", __FUNCTION__); ++ goto fail; ++ } ++ wake_lock_init(dhd->wl_wifi, WAKE_LOCK_SUSPEND, "wlan_wake"); ++ wake_lock_init(dhd->wl_rxwake, WAKE_LOCK_SUSPEND, "wlan_rx_wake"); ++ wake_lock_init(dhd->wl_ctrlwake, WAKE_LOCK_SUSPEND, "wlan_ctrl_wake"); ++ wake_lock_init(dhd->wl_wdwake, WAKE_LOCK_SUSPEND, "wlan_wd_wake"); ++#endif /* CONFIG_HAS_WAKELOCK */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 ++ mutex_init(&dhd->dhd_net_if_mutex); ++ mutex_init(&dhd->dhd_suspend_mutex); ++#endif ++ dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT; ++ ++ /* Attach and link in the protocol */ ++ if (dhd_prot_attach(&dhd->pub) != 0) { ++ AP6211_ERR("dhd_prot_attach failed\n"); ++ goto fail; ++ } ++ dhd_state |= DHD_ATTACH_STATE_PROT_ATTACH; ++ ++#ifdef WL_CFG80211 ++ /* Attach and link in the cfg80211 */ ++ if (unlikely(wl_cfg80211_attach(net, &dhd->pub))) { ++ AP6211_ERR("wl_cfg80211_attach failed\n"); ++ goto fail; ++ } ++ ++ dhd_monitor_init(&dhd->pub); ++ dhd_state |= DHD_ATTACH_STATE_CFG80211; ++#endif ++#if defined(CONFIG_WIRELESS_EXT) ++ /* Attach and link in the iw */ ++ if (!(dhd_state & DHD_ATTACH_STATE_CFG80211)) { ++ if (wl_iw_attach(net, (void *)&dhd->pub) != 0) { ++ AP6211_ERR("wl_iw_attach failed\n"); ++ goto fail; ++ } ++ dhd_state |= DHD_ATTACH_STATE_WL_ATTACH; ++ } ++#endif /* defined(CONFIG_WIRELESS_EXT) */ ++ ++ ++ /* Set up the watchdog timer */ ++ init_timer(&dhd->timer); ++ dhd->timer.data = (ulong)dhd; ++ dhd->timer.function = dhd_watchdog; ++ ++#ifdef DHDTHREAD ++ /* Initialize thread based operation and lock */ ++ sema_init(&dhd->sdsem, 1); ++ if ((dhd_watchdog_prio >= 0) && (dhd_dpc_prio >= 0)) { ++ dhd->threads_only = TRUE; ++ } ++ else { ++ dhd->threads_only = FALSE; ++ } ++ ++ if (dhd_watchdog_prio >= 0) { ++ /* Initialize watchdog thread */ ++#ifdef USE_KTHREAD_API ++ PROC_START2(dhd_watchdog_thread, dhd, &dhd->thr_wdt_ctl, 0, "dhd_watchdog_thread"); ++#else ++ PROC_START(dhd_watchdog_thread, dhd, &dhd->thr_wdt_ctl, 0); ++#endif ++ } else { ++ dhd->thr_wdt_ctl.thr_pid = -1; ++ } ++ ++ /* Set up the bottom half handler */ ++ if (dhd_dpc_prio >= 0) { ++ /* Initialize DPC thread */ ++#ifdef USE_KTHREAD_API ++ PROC_START2(dhd_dpc_thread, dhd, &dhd->thr_dpc_ctl, 0, "dhd_dpc"); ++#else ++ PROC_START(dhd_dpc_thread, dhd, &dhd->thr_dpc_ctl, 0); ++#endif ++ } else { ++ /* use tasklet for dpc */ ++ tasklet_init(&dhd->tasklet, dhd_dpc, (ulong)dhd); ++ dhd->thr_dpc_ctl.thr_pid = -1; ++ } ++#else ++ /* Set up the bottom half handler */ ++ tasklet_init(&dhd->tasklet, dhd_dpc, (ulong)dhd); ++ dhd->dhd_tasklet_create = TRUE; ++#endif /* DHDTHREAD */ ++ ++ if (dhd_sysioc) { ++#ifdef USE_KTHREAD_API ++ PROC_START2(_dhd_sysioc_thread, dhd, &dhd->thr_sysioc_ctl, 0, "dhd_sysioc"); ++#else ++ PROC_START(_dhd_sysioc_thread, dhd, &dhd->thr_sysioc_ctl, 0); ++#endif ++ } else { ++ dhd->thr_sysioc_ctl.thr_pid = -1; ++ } ++ dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (1) ++ INIT_WORK(&dhd->work_hang, dhd_hang_process); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ ++ /* ++ * Save the dhd_info into the priv ++ */ ++ memcpy(netdev_priv(net), &dhd, sizeof(dhd)); ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) ++ register_pm_notifier(&dhd_sleep_pm_notifier); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ ++ ++#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) ++ dhd->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 20; ++ dhd->early_suspend.suspend = dhd_early_suspend; ++ dhd->early_suspend.resume = dhd_late_resume; ++ register_early_suspend(&dhd->early_suspend); ++ dhd_state |= DHD_ATTACH_STATE_EARLYSUSPEND_DONE; ++#endif ++ ++#ifdef ARP_OFFLOAD_SUPPORT ++ dhd->pend_ipaddr = 0; ++ register_inetaddr_notifier(&dhd_notifier); ++#endif /* ARP_OFFLOAD_SUPPORT */ ++#ifdef IPV6 ++ register_inet6addr_notifier(&dhd_notifier_ipv6); ++#endif ++ ++#ifdef DHDTCPACK_SUPPRESS ++ dhd->pub.tcp_ack_info_cnt = 0; ++ bzero(dhd->pub.tcp_ack_info_tbl, sizeof(struct tcp_ack_info)*MAXTCPSTREAMS); ++#endif /* DHDTCPACK_SUPPRESS */ ++ ++ dhd_state |= DHD_ATTACH_STATE_DONE; ++ dhd->dhd_state = dhd_state; ++ return &dhd->pub; ++ ++fail: ++ if (dhd_state < DHD_ATTACH_STATE_DHD_ALLOC) { ++ if (net) free_netdev(net); ++ } else { ++ AP6211_DEBUG("%s: Calling dhd_detach dhd_state 0x%x &dhd->pub %p\n", ++ __FUNCTION__, dhd_state, &dhd->pub); ++ dhd->dhd_state = dhd_state; ++ dhd_detach(&dhd->pub); ++ dhd_free(&dhd->pub); ++ } ++ ++ return NULL; ++} ++ ++int ++dhd_bus_start(dhd_pub_t *dhdp) ++{ ++ int ret = -1; ++ dhd_info_t *dhd = (dhd_info_t*)dhdp->info; ++ unsigned long flags; ++ ++ ASSERT(dhd); ++ ++ AP6211_DEBUG("Enter %s:\n", __FUNCTION__); ++ ++#ifdef DHDTHREAD ++ if (dhd->threads_only) ++ dhd_os_sdlock(dhdp); ++#endif /* DHDTHREAD */ ++ ++ ++ /* try to download image and nvram to the dongle */ ++ if ((dhd->pub.busstate == DHD_BUS_DOWN) && ++ (fw_path != NULL) && (fw_path[0] != '\0') && ++ (nv_path != NULL) && (nv_path[0] != '\0')) { ++ /* wake lock moved to dhdsdio_download_firmware */ ++ if (!(dhd_bus_download_firmware(dhd->pub.bus, dhd->pub.osh, ++ fw_path, nv_path))) { ++ AP6211_ERR("%s: dhdsdio_probe_download failed. firmware = %s nvram = %s\n", ++ __FUNCTION__, fw_path, nv_path); ++#ifdef DHDTHREAD ++ if (dhd->threads_only) ++ dhd_os_sdunlock(dhdp); ++#endif /* DHDTHREAD */ ++ return -1; ++ } ++ } ++ if (dhd->pub.busstate != DHD_BUS_LOAD) { ++#ifdef DHDTHREAD ++ if (dhd->threads_only) ++ dhd_os_sdunlock(dhdp); ++#endif /* DHDTHREAD */ ++ return -ENETDOWN; ++ } ++ ++ /* Start the watchdog timer */ ++ dhd->pub.tickcnt = 0; ++ dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms); ++ ++ /* Bring up the bus */ ++ if ((ret = dhd_bus_init(&dhd->pub, FALSE)) != 0) { ++ ++ AP6211_ERR("%s, dhd_bus_init failed %d\n", __FUNCTION__, ret); ++#ifdef DHDTHREAD ++ if (dhd->threads_only) ++ dhd_os_sdunlock(dhdp); ++#endif /* DHDTHREAD */ ++ return ret; ++ } ++ bcmsdh_set_drvdata(dhdp); ++#if defined(OOB_INTR_ONLY) ++ /* Host registration for OOB interrupt */ ++ if (bcmsdh_register_oob_intr(dhdp)) { ++ /* deactivate timer and wait for the handler to finish */ ++ ++ flags = dhd_os_spin_lock(&dhd->pub); ++ dhd->wd_timer_valid = FALSE; ++ dhd_os_spin_unlock(&dhd->pub, flags); ++ del_timer_sync(&dhd->timer); ++ AP6211_ERR("%s Host failed to register for OOB\n", __FUNCTION__); ++#ifdef DHDTHREAD ++ if (dhd->threads_only) ++ dhd_os_sdunlock(dhdp); ++#endif /* DHDTHREAD */ ++ DHD_OS_WD_WAKE_UNLOCK(&dhd->pub); ++ return -ENODEV; ++ } ++ ++ /* Enable oob at firmware */ ++ dhd_enable_oob_intr(dhd->pub.bus, TRUE); ++#endif ++ ++ /* If bus is not ready, can't come up */ ++ if (dhd->pub.busstate != DHD_BUS_DATA) { ++ flags = dhd_os_spin_lock(&dhd->pub); ++ dhd->wd_timer_valid = FALSE; ++ dhd_os_spin_unlock(&dhd->pub, flags); ++ del_timer_sync(&dhd->timer); ++ AP6211_ERR("%s failed bus is not ready\n", __FUNCTION__); ++#ifdef DHDTHREAD ++ if (dhd->threads_only) ++ dhd_os_sdunlock(dhdp); ++#endif /* DHDTHREAD */ ++ DHD_OS_WD_WAKE_UNLOCK(&dhd->pub); ++ return -ENODEV; ++ } ++ ++#ifdef DHDTHREAD ++ if (dhd->threads_only) ++ dhd_os_sdunlock(dhdp); ++#endif /* DHDTHREAD */ ++ ++#ifdef BCMSDIOH_TXGLOM ++ if ((dhd->pub.busstate == DHD_BUS_DATA) && bcmsdh_glom_enabled()) { ++ dhd_txglom_enable(dhdp, TRUE); ++ } ++#endif ++ ++#ifdef READ_MACADDR ++ dhd_read_macaddr(dhd); ++#endif ++ ++ /* Bus is ready, do any protocol initialization */ ++ if ((ret = dhd_prot_init(&dhd->pub)) < 0) ++ return ret; ++ ++#ifdef WRITE_MACADDR ++ dhd_write_macaddr(dhd->pub.mac.octet); ++#endif ++ ++#ifdef ARP_OFFLOAD_SUPPORT ++ if (dhd->pend_ipaddr) { ++#ifdef AOE_IP_ALIAS_SUPPORT ++ aoe_update_host_ipv4_table(&dhd->pub, dhd->pend_ipaddr, TRUE, 0); ++#endif /* AOE_IP_ALIAS_SUPPORT */ ++ dhd->pend_ipaddr = 0; ++ } ++#endif /* ARP_OFFLOAD_SUPPORT */ ++ ++ return 0; ++} ++ ++bool dhd_is_concurrent_mode(dhd_pub_t *dhd) ++{ ++ if (!dhd) ++ return FALSE; ++ ++ if (dhd->op_mode & DHD_FLAG_CONCURR_MULTI_CHAN_MODE) ++ return TRUE; ++ else if ((dhd->op_mode & DHD_FLAG_CONCURR_SINGLE_CHAN_MODE) == ++ DHD_FLAG_CONCURR_SINGLE_CHAN_MODE) ++ return TRUE; ++ else ++ return FALSE; ++} ++ ++#if !defined(AP) && defined(WLP2P) ++/* From Android JerryBean release, the concurrent mode is enabled by default and the firmware ++ * name would be fw_bcmdhd.bin. So we need to determine whether P2P is enabled in the STA ++ * firmware and accordingly enable concurrent mode (Apply P2P settings). SoftAP firmware ++ * would still be named as fw_bcmdhd_apsta. ++ */ ++uint32 ++dhd_get_concurrent_capabilites(dhd_pub_t *dhd) ++{ ++ int32 ret = 0; ++ char buf[WLC_IOCTL_SMLEN]; ++ bool mchan_supported = FALSE; ++ /* if dhd->op_mode is already set for HOSTAP, ++ * that means we only will use the mode as it is ++ */ ++ if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) ++ return 0; ++ memset(buf, 0, sizeof(buf)); ++ bcm_mkiovar("cap", 0, 0, buf, sizeof(buf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), ++ FALSE, 0)) < 0) { ++ AP6211_ERR("%s: Get Capability failed (error=%d)\n", ++ __FUNCTION__, ret); ++ return 0; ++ } ++ if (strstr(buf, "vsdb")) { ++ mchan_supported = TRUE; ++ } ++ if (strstr(buf, "p2p") == NULL) { ++ AP6211_DEBUG("Chip does not support p2p\n"); ++ return 0; ++ } ++ else { ++ /* Chip supports p2p but ensure that p2p is really implemented in firmware or not */ ++ memset(buf, 0, sizeof(buf)); ++ bcm_mkiovar("p2p", 0, 0, buf, sizeof(buf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), ++ FALSE, 0)) < 0) { ++ AP6211_ERR("%s: Get P2P failed (error=%d)\n", __FUNCTION__, ret); ++ return 0; ++ } ++ else { ++ if (buf[0] == 1) { ++ /* By default, chip supports single chan concurrency, ++ * now lets check for mchan ++ */ ++ ret = DHD_FLAG_CONCURR_SINGLE_CHAN_MODE; ++ if (mchan_supported) ++ ret |= DHD_FLAG_CONCURR_MULTI_CHAN_MODE; ++#if defined(WL_ENABLE_P2P_IF) ++ /* For customer_hw4, although ICS, ++ * we still support concurrent mode ++ */ ++ return ret; ++#else ++ return 0; ++#endif ++ } ++ } ++ } ++ return 0; ++} ++#endif ++int ++dhd_preinit_ioctls(dhd_pub_t *dhd) ++{ ++ int ret = 0; ++ char eventmask[WL_EVENTING_MASK_LEN]; ++ char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */ ++ ++#if !defined(WL_CFG80211) ++ uint up = 0; ++#endif /* !defined(WL_CFG80211) */ ++ uint power_mode = PM_FAST; ++ uint32 dongle_align = DHD_SDALIGN; ++ uint32 glom = CUSTOM_GLOM_SETTING; ++#if defined(VSDB) || defined(ROAM_ENABLE) ++ uint bcn_timeout = 8; ++#else ++ uint bcn_timeout = 4; ++#endif ++#ifdef ENABLE_BCN_LI_BCN_WAKEUP ++ uint32 bcn_li_bcn = 1; ++#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ ++ uint retry_max = 3; ++#if defined(ARP_OFFLOAD_SUPPORT) ++ int arpoe = 1; ++#endif ++ int scan_assoc_time = DHD_SCAN_ASSOC_ACTIVE_TIME; ++ int scan_unassoc_time = DHD_SCAN_UNASSOC_ACTIVE_TIME; ++ int scan_passive_time = DHD_SCAN_PASSIVE_TIME; ++ char buf[WLC_IOCTL_SMLEN]; ++ char *ptr; ++ uint32 listen_interval = LISTEN_INTERVAL; /* Default Listen Interval in Beacons */ ++#ifdef ROAM_ENABLE ++ uint roamvar = 0; ++ int roam_trigger[2] = {CUSTOM_ROAM_TRIGGER_SETTING, WLC_BAND_ALL}; ++ int roam_scan_period[2] = {10, WLC_BAND_ALL}; ++ int roam_delta[2] = {CUSTOM_ROAM_DELTA_SETTING, WLC_BAND_ALL}; ++#ifdef FULL_ROAMING_SCAN_PERIOD_60_SEC ++ int roam_fullscan_period = 60; ++#else /* FULL_ROAMING_SCAN_PERIOD_60_SEC */ ++ int roam_fullscan_period = 120; ++#endif /* FULL_ROAMING_SCAN_PERIOD_60_SEC */ ++#else ++#ifdef DISABLE_BUILTIN_ROAM ++ uint roamvar = 1; ++#endif /* DISABLE_BUILTIN_ROAM */ ++#endif /* ROAM_ENABLE */ ++ ++#if defined(SOFTAP) ++ uint dtim = 1; ++#endif ++#if (defined(AP) && !defined(WLP2P)) || (!defined(AP) && defined(WL_CFG80211)) ++ uint32 mpc = 0; /* Turn MPC off for AP/APSTA mode */ ++ struct ether_addr p2p_ea; ++#endif ++ uint32 mimo_bw_cap = 1; /* Turn HT40 on in 2.4 GHz */ ++ ++#if defined(AP) || defined(WLP2P) ++ uint32 apsta = 1; /* Enable APSTA mode */ ++#endif /* defined(AP) || defined(WLP2P) */ ++#ifdef GET_CUSTOM_MAC_ENABLE ++ struct ether_addr ea_addr; ++#endif /* GET_CUSTOM_MAC_ENABLE */ ++#ifdef DISABLE_11N ++ uint32 nmode = 0; ++#else ++#ifdef AMPDU_HOSTREORDER ++ uint32 hostreorder = 1; ++#endif ++#endif /* DISABLE_11N */ ++ dhd->suspend_bcn_li_dtim = CUSTOM_SUSPEND_BCN_LI_DTIM; ++#ifdef PROP_TXSTATUS ++#ifdef PROP_TXSTATUS_VSDB ++ dhd->wlfc_enabled = FALSE; ++ /* enable WLFC only if the firmware is VSDB */ ++#else ++ dhd->wlfc_enabled = TRUE; ++#endif /* PROP_TXSTATUS_VSDB */ ++#endif /* PROP_TXSTATUS */ ++ AP6211_DEBUG("Enter %s\n", __FUNCTION__); ++ dhd->op_mode = 0; ++#ifdef GET_CUSTOM_MAC_ENABLE ++ ret = dhd_custom_get_mac_address(ea_addr.octet); ++ if (!ret) { ++ memset(buf, 0, sizeof(buf)); ++ bcm_mkiovar("cur_etheraddr", (void *)&ea_addr, ETHER_ADDR_LEN, buf, sizeof(buf)); ++ ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); ++ if (ret < 0) { ++ AP6211_ERR("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret); ++ return BCME_NOTUP; ++ } ++ memcpy(dhd->mac.octet, ea_addr.octet, ETHER_ADDR_LEN); ++ } else { ++#endif /* GET_CUSTOM_MAC_ENABLE */ ++ /* Get the default device MAC address directly from firmware */ ++ memset(buf, 0, sizeof(buf)); ++ bcm_mkiovar("cur_etheraddr", 0, 0, buf, sizeof(buf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), ++ FALSE, 0)) < 0) { ++ AP6211_ERR("%s: can't get MAC address , error=%d\n", __FUNCTION__, ret); ++ return BCME_NOTUP; ++ } ++ /* Update public MAC address after reading from Firmware */ ++ memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN); ++ ++#ifdef GET_CUSTOM_MAC_ENABLE ++ } ++#endif /* GET_CUSTOM_MAC_ENABLE */ ++ ++ AP6211_DEBUG("Firmware = %s\n", fw_path); ++ ++ if ((!op_mode && strstr(fw_path, "_apsta") != NULL) || ++ (op_mode == DHD_FLAG_HOSTAP_MODE)) { ++#ifdef SET_RANDOM_MAC_SOFTAP ++ uint rand_mac; ++#endif ++ dhd->op_mode = DHD_FLAG_HOSTAP_MODE; ++#if defined(ARP_OFFLOAD_SUPPORT) ++ arpoe = 0; ++#endif ++#ifdef PKT_FILTER_SUPPORT ++ dhd_pkt_filter_enable = FALSE; ++#endif ++#ifdef SET_RANDOM_MAC_SOFTAP ++ srandom32((uint)jiffies); ++ rand_mac = random32(); ++ iovbuf[0] = 0x02; /* locally administered bit */ ++ iovbuf[1] = 0x1A; ++ iovbuf[2] = 0x11; ++ iovbuf[3] = (unsigned char)(rand_mac & 0x0F) | 0xF0; ++ iovbuf[4] = (unsigned char)(rand_mac >> 8); ++ iovbuf[5] = (unsigned char)(rand_mac >> 16); ++ ++ bcm_mkiovar("cur_etheraddr", (void *)iovbuf, ETHER_ADDR_LEN, buf, sizeof(buf)); ++ ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); ++ if (ret < 0) { ++ AP6211_ERR("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret); ++ } else ++ memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN); ++#endif /* SET_RANDOM_MAC_SOFTAP */ ++#if !defined(AP) && defined(WL_CFG80211) ++ /* Turn off MPC in AP mode */ ++ bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, ++ sizeof(iovbuf), TRUE, 0)) < 0) { ++ AP6211_ERR("%s mpc for HostAPD failed %d\n", __FUNCTION__, ret); ++ } ++#endif ++ ++ } ++ else { ++ uint32 concurrent_mode = 0; ++ if ((!op_mode && strstr(fw_path, "_p2p") != NULL) || ++ (op_mode == DHD_FLAG_P2P_MODE)) { ++#if defined(ARP_OFFLOAD_SUPPORT) ++ arpoe = 0; ++#endif ++#ifdef PKT_FILTER_SUPPORT ++ dhd_pkt_filter_enable = FALSE; ++#endif ++ dhd->op_mode = DHD_FLAG_P2P_MODE; ++ } ++ else ++ dhd->op_mode = DHD_FLAG_STA_MODE; ++#if !defined(AP) && defined(WLP2P) ++ if ((concurrent_mode = dhd_get_concurrent_capabilites(dhd))) { ++#if defined(ARP_OFFLOAD_SUPPORT) ++ arpoe = 1; ++#endif ++ dhd->op_mode |= concurrent_mode; ++ } ++ ++ /* Check if we are enabling p2p */ ++ if (dhd->op_mode & DHD_FLAG_P2P_MODE) { ++ bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, ++ iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { ++ AP6211_ERR("%s APSTA for P2P failed ret= %d\n", __FUNCTION__, ret); ++ } ++ ++ memcpy(&p2p_ea, &dhd->mac, ETHER_ADDR_LEN); ++ ETHER_SET_LOCALADDR(&p2p_ea); ++ bcm_mkiovar("p2p_da_override", (char *)&p2p_ea, ++ ETHER_ADDR_LEN, iovbuf, sizeof(iovbuf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, ++ iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { ++ AP6211_ERR("%s p2p_da_override ret= %d\n", __FUNCTION__, ret); ++ } else { ++ AP6211_DEBUG("dhd_preinit_ioctls: p2p_da_override succeeded\n"); ++ } ++ } ++#else ++ (void)concurrent_mode; ++#endif ++ } ++ ++ AP6211_ERR("Firmware up: op_mode=0x%04x, " ++ "Broadcom Dongle Host Driver mac="MACDBG"\n", ++ dhd->op_mode, ++ MAC2STRDBG(dhd->mac.octet)); ++ /* Set Country code */ ++ if (dhd->dhd_cspec.ccode[0] != 0) { ++ bcm_mkiovar("country", (char *)&dhd->dhd_cspec, ++ sizeof(wl_country_t), iovbuf, sizeof(iovbuf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) ++ AP6211_ERR("%s: country code setting failed\n", __FUNCTION__); ++ } ++ ++ /* Set Listen Interval */ ++ bcm_mkiovar("assoc_listen", (char *)&listen_interval, 4, iovbuf, sizeof(iovbuf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) ++ AP6211_ERR("%s assoc_listen failed %d\n", __FUNCTION__, ret); ++ ++#if defined(ROAM_ENABLE) || defined(DISABLE_BUILTIN_ROAM) ++ /* Disable built-in roaming to allowed ext supplicant to take care of roaming */ ++ bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf)); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++#endif /* ROAM_ENABLE || DISABLE_BUILTIN_ROAM */ ++#ifdef ROAM_ENABLE ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_TRIGGER, roam_trigger, ++ sizeof(roam_trigger), TRUE, 0)) < 0) ++ AP6211_ERR("%s: roam trigger set failed %d\n", __FUNCTION__, ret); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_SCAN_PERIOD, roam_scan_period, ++ sizeof(roam_scan_period), TRUE, 0)) < 0) ++ AP6211_ERR("%s: roam scan period set failed %d\n", __FUNCTION__, ret); ++ if ((dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_DELTA, roam_delta, ++ sizeof(roam_delta), TRUE, 0)) < 0) ++ AP6211_ERR("%s: roam delta set failed %d\n", __FUNCTION__, ret); ++ bcm_mkiovar("fullroamperiod", (char *)&roam_fullscan_period, 4, iovbuf, sizeof(iovbuf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) ++ AP6211_ERR("%s: roam fullscan period set failed %d\n", __FUNCTION__, ret); ++#endif /* ROAM_ENABLE */ ++ ++ /* Set PowerSave mode */ ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode), TRUE, 0); ++ ++ /* Match Host and Dongle rx alignment */ ++ bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf)); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++ ++ if (glom != DEFAULT_GLOM_VALUE) { ++ AP6211_DEBUG("%s set glom=0x%X\n", __FUNCTION__, glom); ++ bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf)); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++ } ++ ++ /* Setup timeout if Beacons are lost and roam is off to report link down */ ++ bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf)); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++ /* Setup assoc_retry_max count to reconnect target AP in dongle */ ++ bcm_mkiovar("assoc_retry_max", (char *)&retry_max, 4, iovbuf, sizeof(iovbuf)); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++#if defined(AP) && !defined(WLP2P) ++ /* Turn off MPC in AP mode */ ++ bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf)); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++ bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf)); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++#endif /* defined(AP) && !defined(WLP2P) */ ++ ++ if (dhd_bus_chip_id(dhd) == BCM43341_CHIP_ID || dhd_bus_chip_id(dhd) == BCM4324_CHIP_ID) { ++ /* Turn on HT40 in 2.4 GHz */ ++ bcm_mkiovar("mimo_bw_cap", (char *)&mimo_bw_cap, 4, iovbuf, sizeof(iovbuf)); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++ } ++ ++#if defined(SOFTAP) ++ if (ap_fw_loaded == TRUE) { ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_DTIMPRD, (char *)&dtim, sizeof(dtim), TRUE, 0); ++ } ++#endif ++ ++#if defined(KEEP_ALIVE) ++ { ++ /* Set Keep Alive : be sure to use FW with -keepalive */ ++ int res; ++ ++#if defined(SOFTAP) ++ if (ap_fw_loaded == FALSE) ++#endif ++ if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) { ++ if ((res = dhd_keep_alive_onoff(dhd)) < 0) ++ AP6211_ERR("%s set keeplive failed %d\n", ++ __FUNCTION__, res); ++ } ++ } ++#endif /* defined(KEEP_ALIVE) */ ++ ++ /* Read event_msgs mask */ ++ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0)) < 0) { ++ AP6211_ERR("%s read Event mask failed %d\n", __FUNCTION__, ret); ++ goto done; ++ } ++ bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN); ++ ++ /* Setup event_msgs */ ++ setbit(eventmask, WLC_E_SET_SSID); ++ setbit(eventmask, WLC_E_PRUNE); ++ setbit(eventmask, WLC_E_AUTH); ++ setbit(eventmask, WLC_E_ASSOC); ++ setbit(eventmask, WLC_E_REASSOC); ++ setbit(eventmask, WLC_E_REASSOC_IND); ++ setbit(eventmask, WLC_E_DEAUTH); ++ setbit(eventmask, WLC_E_DEAUTH_IND); ++ setbit(eventmask, WLC_E_DISASSOC_IND); ++ setbit(eventmask, WLC_E_DISASSOC); ++ setbit(eventmask, WLC_E_JOIN); ++ setbit(eventmask, WLC_E_ASSOC_IND); ++ setbit(eventmask, WLC_E_PSK_SUP); ++ setbit(eventmask, WLC_E_LINK); ++ setbit(eventmask, WLC_E_NDIS_LINK); ++ setbit(eventmask, WLC_E_MIC_ERROR); ++ setbit(eventmask, WLC_E_ASSOC_REQ_IE); ++ setbit(eventmask, WLC_E_ASSOC_RESP_IE); ++#ifndef WL_CFG80211 ++ setbit(eventmask, WLC_E_PMKID_CACHE); ++ setbit(eventmask, WLC_E_TXFAIL); ++#endif ++ setbit(eventmask, WLC_E_JOIN_START); ++ setbit(eventmask, WLC_E_SCAN_COMPLETE); ++#ifdef WLMEDIA_HTSF ++ setbit(eventmask, WLC_E_HTSFSYNC); ++#endif /* WLMEDIA_HTSF */ ++#ifdef PNO_SUPPORT ++ setbit(eventmask, WLC_E_PFN_NET_FOUND); ++#endif /* PNO_SUPPORT */ ++ /* enable dongle roaming event */ ++ setbit(eventmask, WLC_E_ROAM); ++#ifdef WL_CFG80211 ++ setbit(eventmask, WLC_E_ESCAN_RESULT); ++ if (dhd->op_mode & DHD_FLAG_P2P_MODE) { ++ setbit(eventmask, WLC_E_ACTION_FRAME_RX); ++ setbit(eventmask, WLC_E_P2P_DISC_LISTEN_COMPLETE); ++ } ++#endif /* WL_CFG80211 */ ++ ++ /* Write updated Event mask */ ++ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { ++ AP6211_ERR("%s Set Event mask failed %d\n", __FUNCTION__, ret); ++ goto done; ++ } ++ ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_CHANNEL_TIME, (char *)&scan_assoc_time, ++ sizeof(scan_assoc_time), TRUE, 0); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time, ++ sizeof(scan_unassoc_time), TRUE, 0); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_PASSIVE_TIME, (char *)&scan_passive_time, ++ sizeof(scan_passive_time), TRUE, 0); ++ ++#ifdef ARP_OFFLOAD_SUPPORT ++ /* Set and enable ARP offload feature for STA only */ ++#if defined(SOFTAP) ++ if (arpoe && !ap_fw_loaded) { ++#else ++ if (arpoe) { ++#endif ++ dhd_arp_offload_enable(dhd, TRUE); ++ dhd_arp_offload_set(dhd, dhd_arp_mode); ++ } else { ++ dhd_arp_offload_enable(dhd, FALSE); ++ dhd_arp_offload_set(dhd, 0); ++ } ++ dhd_arp_enable = arpoe; ++#endif /* ARP_OFFLOAD_SUPPORT */ ++ ++#ifdef PKT_FILTER_SUPPORT ++ /* Setup default defintions for pktfilter , enable in suspend */ ++ dhd->pktfilter_count = 5; ++ /* Setup filter to allow only unicast */ ++ dhd->pktfilter[0] = "100 0 0 0 0x01 0x00"; ++ dhd->pktfilter[1] = NULL; ++ dhd->pktfilter[2] = NULL; ++ dhd->pktfilter[3] = NULL; ++ /* Add filter to pass multicastDNS packet and NOT filter out as Broadcast */ ++ dhd->pktfilter[4] = "104 0 0 0 0xFFFFFFFFFFFF 0x01005E0000FB"; ++ dhd_set_packet_filter(dhd); ++ ++#if defined(SOFTAP) ++ if (ap_fw_loaded) { ++ dhd_enable_packet_filter(0, dhd); ++ } ++#endif /* defined(SOFTAP) */ ++ ++#endif /* PKT_FILTER_SUPPORT */ ++#ifdef DISABLE_11N ++ bcm_mkiovar("nmode", (char *)&nmode, 4, iovbuf, sizeof(iovbuf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) ++ AP6211_ERR("%s wl nmode 0 failed %d\n", __FUNCTION__, ret); ++#else ++#ifdef AMPDU_HOSTREORDER ++ bcm_mkiovar("ampdu_hostreorder", (char *)&hostreorder, 4, buf, sizeof(buf)); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); ++#endif /* AMPDU_HOSTREORDER */ ++#endif /* DISABLE_11N */ ++ ++#if !defined(WL_CFG80211) ++ /* Force STA UP */ ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&up, sizeof(up), TRUE, 0)) < 0) { ++ AP6211_ERR("%s Setting WL UP failed %d\n", __FUNCTION__, ret); ++ goto done; ++ } ++#endif ++ ++#ifdef ENABLE_BCN_LI_BCN_WAKEUP ++ bcm_mkiovar("bcn_li_bcn", (char *)&bcn_li_bcn, 4, iovbuf, sizeof(iovbuf)); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ ++ ++ /* query for 'ver' to get version info from firmware */ ++ memset(buf, 0, sizeof(buf)); ++ ptr = buf; ++ bcm_mkiovar("ver", (char *)&buf, 4, buf, sizeof(buf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), FALSE, 0)) < 0) ++ AP6211_ERR("%s failed %d\n", __FUNCTION__, ret); ++ else { ++ bcmstrtok(&ptr, "\n", 0); ++ /* Print fw version info */ ++ AP6211_ERR("Firmware version = %s\n", buf); ++ ++ dhd_set_version_info(dhd, buf); ++ ++ DHD_BLOG(buf, strlen(buf) + 1); ++ DHD_BLOG(dhd_version, strlen(dhd_version) + 1); ++ DHD_BLOG(dhd_version_info, strlen(dhd_version_info) +1); ++ ++ /* Check and adjust IOCTL response timeout for Manufactring firmware */ ++ if (strstr(buf, MANUFACTRING_FW) != NULL) { ++ dhd_os_set_ioctl_resp_timeout(20000); ++ AP6211_ERR("%s : adjust IOCTL response time for Manufactring Firmware\n", ++ __FUNCTION__); ++ } ++ } ++ ++done: ++ return ret; ++} ++ ++ ++int ++dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, int set) ++{ ++ char buf[strlen(name) + 1 + cmd_len]; ++ int len = sizeof(buf); ++ wl_ioctl_t ioc; ++ int ret; ++ ++ len = bcm_mkiovar(name, cmd_buf, cmd_len, buf, len); ++ ++ memset(&ioc, 0, sizeof(ioc)); ++ ++ ioc.cmd = set? WLC_SET_VAR : WLC_GET_VAR; ++ ioc.buf = buf; ++ ioc.len = len; ++ ioc.set = TRUE; ++ ++ ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len); ++ if (!set && ret >= 0) ++ memcpy(cmd_buf, buf, cmd_len); ++ ++ return ret; ++} ++ ++int dhd_change_mtu(dhd_pub_t *dhdp, int new_mtu, int ifidx) ++{ ++ struct dhd_info *dhd = dhdp->info; ++ struct net_device *dev = NULL; ++ ++ ASSERT(dhd && dhd->iflist[ifidx]); ++ dev = dhd->iflist[ifidx]->net; ++ ASSERT(dev); ++ ++ if (netif_running(dev)) { ++ AP6211_ERR("%s: Must be down to change its MTU", dev->name); ++ return BCME_NOTDOWN; ++ } ++ ++#define DHD_MIN_MTU 1500 ++#define DHD_MAX_MTU 1752 ++ ++ if ((new_mtu < DHD_MIN_MTU) || (new_mtu > DHD_MAX_MTU)) { ++ AP6211_ERR("%s: MTU size %d is invalid.\n", __FUNCTION__, new_mtu); ++ return BCME_BADARG; ++ } ++ ++ dev->mtu = new_mtu; ++ return 0; ++} ++ ++#ifdef ARP_OFFLOAD_SUPPORT ++/* add or remove AOE host ip(s) (up to 8 IPs on the interface) */ ++void ++aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx) ++{ ++ u32 ipv4_buf[MAX_IPV4_ENTRIES]; /* temp save for AOE host_ip table */ ++ int i; ++ int ret; ++ ++ bzero(ipv4_buf, sizeof(ipv4_buf)); ++ ++ /* display what we've got */ ++ ret = dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf), idx); ++ AP6211_DEBUG("%s: hostip table read from Dongle:\n", __FUNCTION__); ++#ifdef AOE_DBG ++ dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */ ++#endif ++ /* now we saved hoste_ip table, clr it in the dongle AOE */ ++ dhd_aoe_hostip_clr(dhd_pub, idx); ++ ++ if (ret) { ++ AP6211_ERR("%s failed\n", __FUNCTION__); ++ return; ++ } ++ ++ for (i = 0; i < MAX_IPV4_ENTRIES; i++) { ++ if (add && (ipv4_buf[i] == 0)) { ++ ipv4_buf[i] = ipa; ++ add = FALSE; /* added ipa to local table */ ++ AP6211_DEBUG("%s: Saved new IP in temp arp_hostip[%d]\n", ++ __FUNCTION__, i); ++ } else if (ipv4_buf[i] == ipa) { ++ ipv4_buf[i] = 0; ++ AP6211_DEBUG("%s: removed IP:%x from temp table %d\n", ++ __FUNCTION__, ipa, i); ++ } ++ ++ if (ipv4_buf[i] != 0) { ++ /* add back host_ip entries from our local cache */ ++ dhd_arp_offload_add_ip(dhd_pub, ipv4_buf[i], idx); ++ AP6211_DEBUG("%s: added IP:%x to dongle arp_hostip[%d]\n\n", ++ __FUNCTION__, ipv4_buf[i], i); ++ } ++ } ++#ifdef AOE_DBG ++ /* see the resulting hostip table */ ++ dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf), idx); ++ AP6211_DEBUG("%s: read back arp_hostip table:\n", __FUNCTION__); ++ dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */ ++#endif ++} ++ ++/* ++ * Notification mechanism from kernel to our driver. This function is called by the Linux kernel ++ * whenever there is an event related to an IP address. ++ * ptr : kernel provided pointer to IP address that has changed ++ */ ++static int dhd_device_event(struct notifier_block *this, ++ unsigned long event, ++ void *ptr) ++{ ++ struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; ++ ++ dhd_info_t *dhd; ++ dhd_pub_t *dhd_pub; ++ int idx; ++ ++ if (!dhd_arp_enable) ++ return NOTIFY_DONE; ++ if (!ifa || !(ifa->ifa_dev->dev)) ++ return NOTIFY_DONE; ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) ++ /* Filter notifications meant for non Broadcom devices */ ++ if ((ifa->ifa_dev->dev->netdev_ops != &dhd_ops_pri) && ++ (ifa->ifa_dev->dev->netdev_ops != &dhd_ops_virt)) { ++#ifdef WLP2P ++ if (!wl_cfgp2p_is_ifops(ifa->ifa_dev->dev->netdev_ops)) ++#endif ++ return NOTIFY_DONE; ++ } ++#endif /* LINUX_VERSION_CODE */ ++ ++ dhd = *(dhd_info_t **)netdev_priv(ifa->ifa_dev->dev); ++ if (!dhd) ++ return NOTIFY_DONE; ++ ++ dhd_pub = &dhd->pub; ++ ++ if (dhd_pub->arp_version == 1) { ++ idx = 0; ++ } ++ else { ++ for (idx = 0; idx < DHD_MAX_IFS; idx++) { ++ if (dhd->iflist[idx] && dhd->iflist[idx]->net == ifa->ifa_dev->dev) ++ break; ++ } ++ if (idx < DHD_MAX_IFS) ++ AP6211_DEBUG("ifidx : %p %s %d\n", dhd->iflist[idx]->net, ++ dhd->iflist[idx]->name, dhd->iflist[idx]->idx); ++ else { ++ AP6211_ERR("Cannot find ifidx for(%s) set to 0\n", ifa->ifa_label); ++ idx = 0; ++ } ++ } ++ ++ switch (event) { ++ case NETDEV_UP: ++ AP6211_DEBUG("%s: [%s] Up IP: 0x%x\n", ++ __FUNCTION__, ifa->ifa_label, ifa->ifa_address); ++ ++ if (dhd->pub.busstate != DHD_BUS_DATA) { ++ AP6211_ERR("%s: bus not ready, exit\n", __FUNCTION__); ++ if (dhd->pend_ipaddr) { ++ AP6211_ERR("%s: overwrite pending ipaddr: 0x%x\n", ++ __FUNCTION__, dhd->pend_ipaddr); ++ } ++ dhd->pend_ipaddr = ifa->ifa_address; ++ break; ++ } ++ ++#ifdef AOE_IP_ALIAS_SUPPORT ++ AP6211_DEBUG("%s:add aliased IP to AOE hostip cache\n", ++ __FUNCTION__); ++ aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE, idx); ++#endif ++ break; ++ ++ case NETDEV_DOWN: ++ AP6211_DEBUG("%s: [%s] Down IP: 0x%x\n", ++ __FUNCTION__, ifa->ifa_label, ifa->ifa_address); ++ dhd->pend_ipaddr = 0; ++#ifdef AOE_IP_ALIAS_SUPPORT ++ AP6211_DEBUG("%s:interface is down, AOE clr all for this if\n", ++ __FUNCTION__); ++ aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, FALSE, idx); ++#else ++ dhd_aoe_hostip_clr(&dhd->pub, idx); ++ dhd_aoe_arp_clr(&dhd->pub, idx); ++#endif /* AOE_IP_ALIAS_SUPPORT */ ++ break; ++ ++ default: ++ AP6211_DEBUG("%s: do noting for [%s] Event: %lu\n", ++ __func__, ifa->ifa_label, event); ++ break; ++ } ++ return NOTIFY_DONE; ++} ++#endif /* ARP_OFFLOAD_SUPPORT */ ++ ++int ++dhd_net_attach(dhd_pub_t *dhdp, int ifidx) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)dhdp->info; ++ struct net_device *net = NULL; ++ int err = 0; ++ uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x11, 0x22, 0x33 }; ++ ++ AP6211_DEBUG("%s: ifidx %d\n", __FUNCTION__, ifidx); ++ ++ ASSERT(dhd && dhd->iflist[ifidx]); ++ ++ net = dhd->iflist[ifidx]->net; ++ ASSERT(net); ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) ++ ASSERT(!net->open); ++ net->get_stats = dhd_get_stats; ++ net->do_ioctl = dhd_ioctl_entry; ++ net->hard_start_xmit = dhd_start_xmit; ++ net->set_mac_address = dhd_set_mac_address; ++ net->set_multicast_list = dhd_set_multicast_list; ++ net->open = net->stop = NULL; ++#else ++ ASSERT(!net->netdev_ops); ++ net->netdev_ops = &dhd_ops_virt; ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ ++ ++ /* Ok, link into the network layer... */ ++ if (ifidx == 0) { ++ /* ++ * device functions for the primary interface only ++ */ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) ++ net->open = dhd_open; ++ net->stop = dhd_stop; ++#else ++ net->netdev_ops = &dhd_ops_pri; ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ ++ if (!ETHER_ISNULLADDR(dhd->pub.mac.octet)) ++ memcpy(temp_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN); ++ } else { ++ /* ++ * We have to use the primary MAC for virtual interfaces ++ */ ++ memcpy(temp_addr, dhd->iflist[ifidx]->mac_addr, ETHER_ADDR_LEN); ++ /* ++ * Android sets the locally administered bit to indicate that this is a ++ * portable hotspot. This will not work in simultaneous AP/STA mode, ++ * nor with P2P. Need to set the Donlge's MAC address, and then use that. ++ */ ++ if (!memcmp(temp_addr, dhd->iflist[0]->mac_addr, ++ ETHER_ADDR_LEN)) { ++ AP6211_ERR("%s interface [%s]: set locally administered bit in MAC\n", ++ __func__, net->name); ++ temp_addr[0] |= 0x02; ++ } ++ } ++ ++ net->hard_header_len = ETH_HLEN + dhd->pub.hdrlen; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) ++ net->ethtool_ops = &dhd_ethtool_ops; ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ ++ ++#if defined(CONFIG_WIRELESS_EXT) ++#if WIRELESS_EXT < 19 ++ net->get_wireless_stats = dhd_get_wireless_stats; ++#endif /* WIRELESS_EXT < 19 */ ++#if WIRELESS_EXT > 12 ++ net->wireless_handlers = (struct iw_handler_def *)&wl_iw_handler_def; ++#endif /* WIRELESS_EXT > 12 */ ++#endif /* defined(CONFIG_WIRELESS_EXT) */ ++ ++ dhd->pub.rxsz = DBUS_RX_BUFFER_SIZE_DHD(net); ++ ++ memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN); ++ ++ if ((err = register_netdev(net)) != 0) { ++ AP6211_ERR("couldn't register the net device, err %d\n", err); ++ goto fail; ++ } ++ AP6211_ERR("Broadcom Dongle Host Driver: register interface [%s] MAC: "MACDBG"\n", ++ net->name, ++ MAC2STRDBG(net->dev_addr)); ++ ++#if defined(SOFTAP) && defined(CONFIG_WIRELESS_EXT) && !defined(WL_CFG80211) ++ wl_iw_iscan_set_scan_broadcast_prep(net, 1); ++#endif ++ ++#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ if (ifidx == 0) { ++ dhd_registration_check = TRUE; ++ up(&dhd_registration_sem); ++ } ++#endif ++ return 0; ++ ++fail: ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) ++ net->open = NULL; ++#else ++ net->netdev_ops = NULL; ++#endif ++ return err; ++} ++ ++void ++dhd_bus_detach(dhd_pub_t *dhdp) ++{ ++ dhd_info_t *dhd; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ if (dhdp) { ++ dhd = (dhd_info_t *)dhdp->info; ++ if (dhd) { ++ ++ /* ++ * In case of Android cfg80211 driver, the bus is down in dhd_stop, ++ * calling stop again will cuase SD read/write errors. ++ */ ++ if (dhd->pub.busstate != DHD_BUS_DOWN) { ++ /* Stop the protocol module */ ++ dhd_prot_stop(&dhd->pub); ++ ++ /* Stop the bus module */ ++ dhd_bus_stop(dhd->pub.bus, TRUE); ++ } ++ ++#if defined(OOB_INTR_ONLY) ++ bcmsdh_unregister_oob_intr(); ++#endif ++ } ++ } ++} ++ ++ ++void dhd_detach(dhd_pub_t *dhdp) ++{ ++ dhd_info_t *dhd; ++ unsigned long flags; ++ int timer_valid = FALSE; ++ ++ if (!dhdp) ++ return; ++ ++ dhd = (dhd_info_t *)dhdp->info; ++ if (!dhd) ++ return; ++ ++ AP6211_DEBUG("%s: Enter state 0x%x\n", __FUNCTION__, dhd->dhd_state); ++#ifdef ARP_OFFLOAD_SUPPORT ++ unregister_inetaddr_notifier(&dhd_notifier); ++#endif /* ARP_OFFLOAD_SUPPORT */ ++#ifdef IPV6 ++ unregister_inet6addr_notifier(&dhd_notifier_ipv6); ++#endif ++ ++ dhd->pub.up = 0; ++ if (!(dhd->dhd_state & DHD_ATTACH_STATE_DONE)) { ++ /* Give sufficient time for threads to start running in case ++ * dhd_attach() has failed ++ */ ++ osl_delay(1000*100); ++ } ++ ++ if (dhd->dhd_state & DHD_ATTACH_STATE_PROT_ATTACH) { ++ dhd_bus_detach(dhdp); ++ ++ if (dhdp->prot) ++ dhd_prot_detach(dhdp); ++ } ++ ++#ifdef ARP_OFFLOAD_SUPPORT ++ unregister_inetaddr_notifier(&dhd_notifier); ++#endif /* ARP_OFFLOAD_SUPPORT */ ++ ++#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) ++ if (dhd->dhd_state & DHD_ATTACH_STATE_EARLYSUSPEND_DONE) { ++ if (dhd->early_suspend.suspend) ++ unregister_early_suspend(&dhd->early_suspend); ++ } ++#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ cancel_work_sync(&dhd->work_hang); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ ++ ++#if defined(CONFIG_WIRELESS_EXT) ++ if (dhd->dhd_state & DHD_ATTACH_STATE_WL_ATTACH) { ++ /* Detatch and unlink in the iw */ ++ wl_iw_detach(); ++ } ++#endif /* defined(CONFIG_WIRELESS_EXT) */ ++ ++ if (dhd->thr_sysioc_ctl.thr_pid >= 0) { ++ PROC_STOP(&dhd->thr_sysioc_ctl); ++ } ++ ++ /* delete all interfaces, start with virtual */ ++ if (dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) { ++ int i = 1; ++ dhd_if_t *ifp; ++ ++ /* Cleanup virtual interfaces */ ++ for (i = 1; i < DHD_MAX_IFS; i++) { ++ dhd_net_if_lock_local(dhd); ++ if (dhd->iflist[i]) { ++ dhd->iflist[i]->state = DHD_IF_DEL; ++ dhd->iflist[i]->idx = i; ++ dhd_op_if(dhd->iflist[i]); ++ } ++ ++ dhd_net_if_unlock_local(dhd); ++ } ++ /* delete primary interface 0 */ ++ ifp = dhd->iflist[0]; ++ ASSERT(ifp); ++ ASSERT(ifp->net); ++ if (ifp && ifp->net) { ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) ++ if (ifp->net->open) ++#else ++ if (ifp->net->netdev_ops == &dhd_ops_pri) ++#endif ++ { ++ unregister_netdev(ifp->net); ++ free_netdev(ifp->net); ++ ifp->net = NULL; ++ MFREE(dhd->pub.osh, ifp, sizeof(*ifp)); ++ dhd->iflist[0] = NULL; ++ } ++ } ++ } ++ ++ /* Clear the watchdog timer */ ++ flags = dhd_os_spin_lock(&dhd->pub); ++ timer_valid = dhd->wd_timer_valid; ++ dhd->wd_timer_valid = FALSE; ++ dhd_os_spin_unlock(&dhd->pub, flags); ++ if (timer_valid) ++ del_timer_sync(&dhd->timer); ++ ++ if (dhd->dhd_state & DHD_ATTACH_STATE_THREADS_CREATED) { ++#ifdef DHDTHREAD ++ if (dhd->thr_wdt_ctl.thr_pid >= 0) { ++ PROC_STOP(&dhd->thr_wdt_ctl); ++ } ++ ++ if (dhd->thr_dpc_ctl.thr_pid >= 0) { ++ PROC_STOP(&dhd->thr_dpc_ctl); ++ } ++ else ++#endif /* DHDTHREAD */ ++ tasklet_kill(&dhd->tasklet); ++ } ++ ++#ifdef WL_CFG80211 ++ if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) { ++ wl_cfg80211_detach(NULL); ++ dhd_monitor_uninit(); ++ } ++#endif ++ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) ++ unregister_pm_notifier(&dhd_sleep_pm_notifier); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ ++ /* && defined(CONFIG_PM_SLEEP) */ ++ ++ if (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT) { ++#ifdef CONFIG_HAS_WAKELOCK ++ dhd->wakelock_counter = 0; ++ dhd->wakelock_wd_counter = 0; ++ dhd->wakelock_rx_timeout_enable = 0; ++ dhd->wakelock_ctrl_timeout_enable = 0; ++ if (dhd->wl_wifi) { ++ wake_lock_destroy(dhd->wl_wifi); ++ MFREE(dhd->pub.osh, dhd->wl_wifi, sizeof(struct wake_lock)); ++ dhd->wl_wifi = NULL; ++ } ++ if (dhd->wl_rxwake) { ++ wake_lock_destroy(dhd->wl_rxwake); ++ MFREE(dhd->pub.osh, dhd->wl_rxwake, sizeof(struct wake_lock)); ++ dhd->wl_rxwake = NULL; ++ } ++ if (dhd->wl_ctrlwake) { ++ wake_lock_destroy(dhd->wl_ctrlwake); ++ MFREE(dhd->pub.osh, dhd->wl_ctrlwake, sizeof(struct wake_lock)); ++ dhd->wl_ctrlwake = NULL; ++ } ++ if (dhd->wl_wdwake) { ++ wake_lock_destroy(dhd->wl_wdwake); ++ MFREE(dhd->pub.osh, dhd->wl_wdwake, sizeof(struct wake_lock)); ++ dhd->wl_wdwake = NULL; ++ } ++#endif /* CONFIG_HAS_WAKELOCK */ ++ } ++} ++ ++ ++void ++dhd_free(dhd_pub_t *dhdp) ++{ ++ dhd_info_t *dhd; ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ if (dhdp) { ++ int i; ++ for (i = 0; i < ARRAYSIZE(dhdp->reorder_bufs); i++) { ++ if (dhdp->reorder_bufs[i]) { ++ reorder_info_t *ptr; ++ uint32 buf_size = sizeof(struct reorder_info); ++ ++ ptr = dhdp->reorder_bufs[i]; ++ ++ buf_size += ((ptr->max_idx + 1) * sizeof(void*)); ++ AP6211_DEBUG("free flow id buf %d, maxidx is %d, buf_size %d\n", ++ i, ptr->max_idx, buf_size); ++ ++ MFREE(dhdp->osh, dhdp->reorder_bufs[i], buf_size); ++ dhdp->reorder_bufs[i] = NULL; ++ } ++ } ++ dhd = (dhd_info_t *)dhdp->info; ++ if (dhd) ++ MFREE(dhd->pub.osh, dhd, sizeof(*dhd)); ++ } ++} ++ ++static void __exit ++dhd_module_cleanup(void) ++{ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ dhd_bus_unregister(); ++ ++#if defined(CONFIG_WIFI_CONTROL_FUNC) ++ wl_android_wifictrl_func_del(); ++#endif /* CONFIG_WIFI_CONTROL_FUNC */ ++ wl_android_exit(); ++ ++ /* Call customer gpio to turn off power with WL_REG_ON signal */ ++ dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF); ++ ++ if (wl_host_wake > 0) ++ gpio_free(wl_host_wake); ++ wl_host_wake = -1; ++ ++ /*sw_rfkill_exit(); The comment must remove when we use the Bluetooth*/ ++ ap6211_gpio_wifi_exit(); ++} ++ ++ ++static int __init ++dhd_module_init(void) ++{ ++ int error = 0; ++ ++#if 1 && defined(BCMLXSDMMC) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ int retry = POWERUP_MAX_RETRY; ++ int chip_up = 0; ++#endif ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ AP6211_INFO("--->The Drive has been modified for BananaPro by LeMaker team<---\n"); ++ ++ ap6211_gpio_wifi_init(); ++ /*sw_rfkill_init(); The comment must remove when we use the Bluetooth*/ ++ ++ if (gpio_request(WL_HOST_WAKE_DEF_GPIO, "wl_host_wake")) { ++ AP6211_ERR("[%s] get wl_host_wake gpio failed\n", __FUNCTION__); ++ wl_host_wake = -1; ++ return -1; ++ } ++ wl_host_wake = WL_HOST_WAKE_DEF_GPIO; ++ gpio_direction_input(wl_host_wake); ++ wl_host_wake_irqno = gpio_to_irq(wl_host_wake); ++ AP6211_DEBUG("got gpio%d, mapped to irqno%d\n", wl_host_wake, wl_host_wake_irqno); ++ ++ wl_android_init(); ++ ++#if defined(DHDTHREAD) ++ /* Sanity check on the module parameters */ ++ do { ++ /* Both watchdog and DPC as tasklets are ok */ ++ if ((dhd_watchdog_prio < 0) && (dhd_dpc_prio < 0)) ++ break; ++ ++ /* If both watchdog and DPC are threads, TX must be deferred */ ++ if ((dhd_watchdog_prio >= 0) && (dhd_dpc_prio >= 0) && dhd_deferred_tx) ++ break; ++ ++ AP6211_ERR("Invalid module parameters.\n"); ++ return -EINVAL; ++ } while (0); ++#endif ++ ++#if 1 && defined(BCMLXSDMMC) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ do { ++ sema_init(&dhd_chipup_sem, 0); ++ dhd_bus_reg_sdio_notify(&dhd_chipup_sem); ++ dhd_customer_gpio_wlan_ctrl(WLAN_POWER_ON); ++#if defined(CONFIG_WIFI_CONTROL_FUNC) ++ if (wl_android_wifictrl_func_add() < 0) { ++ dhd_bus_unreg_sdio_notify(); ++ goto fail_1; ++ } ++#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */ ++ if (down_timeout(&dhd_chipup_sem, ++ msecs_to_jiffies(POWERUP_WAIT_MS)) == 0) { ++ dhd_bus_unreg_sdio_notify(); ++ chip_up = 1; ++ break; ++ } ++ AP6211_ERR("failed to power up wifi chip, retry again (%d left) **\n\n", ++ retry+1); ++ dhd_bus_unreg_sdio_notify(); ++#if defined(CONFIG_WIFI_CONTROL_FUNC) ++ wl_android_wifictrl_func_del(); ++#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */ ++ dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF); ++ } while (retry-- > 0); ++ ++ if (!chip_up) { ++ AP6211_ERR("failed to power up wifi chip, max retry reached, exits **\n\n"); ++ return -ENODEV; ++ } ++#else ++ dhd_customer_gpio_wlan_ctrl(WLAN_POWER_ON); ++#if defined(CONFIG_WIFI_CONTROL_FUNC) ++ if (wl_android_wifictrl_func_add() < 0) ++ goto fail_1; ++#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */ ++ ++#endif ++ ++#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ sema_init(&dhd_registration_sem, 0); ++#endif ++ ++ ++ error = dhd_bus_register(); ++ ++ if (!error) ++ AP6211_DEBUG("%s\n", dhd_version); ++ else { ++ AP6211_ERR("%s: sdio_register_driver failed\n", __FUNCTION__); ++ goto fail_1; ++ } ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ /* ++ * Wait till MMC sdio_register_driver callback called and made driver attach. ++ * It's needed to make sync up exit from dhd insmod and ++ * Kernel MMC sdio device callback registration ++ */ ++ if ((down_timeout(&dhd_registration_sem, ++ msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)) != 0) || ++ (dhd_registration_check != TRUE)) { ++ error = -ENODEV; ++ AP6211_ERR("%s: sdio_register_driver timeout or error \n", __FUNCTION__); ++ goto fail_2; ++ } ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ ++#if defined(WL_CFG80211) ++ wl_android_post_init(); ++#endif /* defined(WL_CFG80211) */ ++ ++ return error; ++ ++#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++fail_2: ++ dhd_bus_unregister(); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ ++ ++fail_1: ++ ++#if defined(CONFIG_WIFI_CONTROL_FUNC) ++ wl_android_wifictrl_func_del(); ++#endif ++ ++ /* Call customer gpio to turn off power with WL_REG_ON signal */ ++ dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF); ++ ++ return error; ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) ++late_initcall(dhd_module_init); ++#else ++module_init(dhd_module_init); ++#endif ++ ++module_exit(dhd_module_cleanup); ++ ++/* ++ * OS specific functions required to implement DHD driver in OS independent way ++ */ ++int ++dhd_os_proto_block(dhd_pub_t *pub) ++{ ++ dhd_info_t * dhd = (dhd_info_t *)(pub->info); ++ ++ if (dhd) { ++ down(&dhd->proto_sem); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++int ++dhd_os_proto_unblock(dhd_pub_t *pub) ++{ ++ dhd_info_t * dhd = (dhd_info_t *)(pub->info); ++ ++ if (dhd) { ++ up(&dhd->proto_sem); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++unsigned int ++dhd_os_get_ioctl_resp_timeout(void) ++{ ++ return ((unsigned int)dhd_ioctl_timeout_msec); ++} ++ ++void ++dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec) ++{ ++ dhd_ioctl_timeout_msec = (int)timeout_msec; ++} ++ ++int ++dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending) ++{ ++ dhd_info_t * dhd = (dhd_info_t *)(pub->info); ++ int timeout; ++ ++ /* Convert timeout in millsecond to jiffies */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ timeout = msecs_to_jiffies(dhd_ioctl_timeout_msec); ++#else ++ timeout = dhd_ioctl_timeout_msec * HZ / 1000; ++#endif ++ ++ timeout = wait_event_timeout(dhd->ioctl_resp_wait, (*condition), timeout); ++ return timeout; ++} ++ ++int ++dhd_os_ioctl_resp_wake(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ ++ if (waitqueue_active(&dhd->ioctl_resp_wait)) { ++ wake_up(&dhd->ioctl_resp_wait); ++ } ++ ++ return 0; ++} ++ ++void ++dhd_os_wd_timer(void *bus, uint wdtick) ++{ ++ dhd_pub_t *pub = bus; ++ dhd_info_t *dhd = (dhd_info_t *)pub->info; ++ unsigned long flags; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ if (!dhd) ++ return; ++ if (wdtick) ++ DHD_OS_WD_WAKE_LOCK(pub); ++ ++ flags = dhd_os_spin_lock(pub); ++ ++ /* don't start the wd until fw is loaded */ ++ if (pub->busstate == DHD_BUS_DOWN) { ++ dhd_os_spin_unlock(pub, flags); ++ DHD_OS_WD_WAKE_UNLOCK(pub); ++ return; ++ } ++ ++ /* totally stop the timer */ ++ if (!wdtick && dhd->wd_timer_valid == TRUE) { ++ dhd->wd_timer_valid = FALSE; ++ dhd_os_spin_unlock(pub, flags); ++#ifdef DHDTHREAD ++ del_timer_sync(&dhd->timer); ++#else ++ del_timer(&dhd->timer); ++#endif /* DHDTHREAD */ ++ /* Unlock when timer deleted */ ++ DHD_OS_WD_WAKE_UNLOCK(pub); ++ return; ++ } ++ ++ if (wdtick) { ++ dhd_watchdog_ms = (uint)wdtick; ++ /* Re arm the timer, at last watchdog period */ ++ mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms)); ++ dhd->wd_timer_valid = TRUE; ++ } ++ dhd_os_spin_unlock(pub, flags); ++} ++ ++void * ++dhd_os_open_image(char *filename) ++{ ++ struct file *fp; ++ ++ fp = filp_open(filename, O_RDONLY, 0); ++ /* ++ * 2.6.11 (FC4) supports filp_open() but later revs don't? ++ * Alternative: ++ * fp = open_namei(AT_FDCWD, filename, O_RD, 0); ++ * ??? ++ */ ++ if (IS_ERR(fp)) ++ fp = NULL; ++ ++ return fp; ++} ++ ++int ++dhd_os_get_image_block(char *buf, int len, void *image) ++{ ++ struct file *fp = (struct file *)image; ++ int rdlen; ++ ++ if (!image) ++ return 0; ++ ++ rdlen = kernel_read(fp, fp->f_pos, buf, len); ++ if (rdlen > 0) ++ fp->f_pos += rdlen; ++ ++ return rdlen; ++} ++ ++void ++dhd_os_close_image(void *image) ++{ ++ if (image) ++ filp_close((struct file *)image, NULL); ++} ++ ++ ++void ++dhd_os_sdlock(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd; ++ ++ dhd = (dhd_info_t *)(pub->info); ++ ++#ifdef DHDTHREAD ++ if (dhd->threads_only) ++ down(&dhd->sdsem); ++ else ++#endif /* DHDTHREAD */ ++ spin_lock_bh(&dhd->sdlock); ++} ++ ++void ++dhd_os_sdunlock(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd; ++ ++ dhd = (dhd_info_t *)(pub->info); ++ ++#ifdef DHDTHREAD ++ if (dhd->threads_only) ++ up(&dhd->sdsem); ++ else ++#endif /* DHDTHREAD */ ++ spin_unlock_bh(&dhd->sdlock); ++} ++ ++void ++dhd_os_sdlock_txq(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd; ++ ++ dhd = (dhd_info_t *)(pub->info); ++ spin_lock_bh(&dhd->txqlock); ++} ++ ++void ++dhd_os_sdunlock_txq(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd; ++ ++ dhd = (dhd_info_t *)(pub->info); ++ spin_unlock_bh(&dhd->txqlock); ++} ++ ++void ++dhd_os_sdlock_rxq(dhd_pub_t *pub) ++{ ++} ++ ++void ++dhd_os_sdunlock_rxq(dhd_pub_t *pub) ++{ ++} ++ ++void ++dhd_os_sdtxlock(dhd_pub_t *pub) ++{ ++ dhd_os_sdlock(pub); ++} ++ ++void ++dhd_os_sdtxunlock(dhd_pub_t *pub) ++{ ++ dhd_os_sdunlock(pub); ++} ++ ++#if defined(CONFIG_DHD_USE_STATIC_BUF) ++uint8* dhd_os_prealloc(void *osh, int section, uint size) ++{ ++ return (uint8*)wl_android_prealloc(section, size); ++} ++ ++void dhd_os_prefree(void *osh, void *addr, uint size) ++{ ++} ++#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */ ++ ++#if defined(CONFIG_WIRELESS_EXT) ++struct iw_statistics * ++dhd_get_wireless_stats(struct net_device *dev) ++{ ++ int res = 0; ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ if (!dhd->pub.up) { ++ return NULL; ++ } ++ ++ res = wl_iw_get_wireless_stats(dev, &dhd->iw.wstats); ++ ++ if (res == 0) ++ return &dhd->iw.wstats; ++ else ++ return NULL; ++} ++#endif /* defined(CONFIG_WIRELESS_EXT) */ ++ ++static int ++dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, ++ wl_event_msg_t *event, void **data) ++{ ++ int bcmerror = 0; ++ ASSERT(dhd != NULL); ++ ++ bcmerror = wl_host_event(&dhd->pub, ifidx, pktdata, event, data); ++ if (bcmerror != BCME_OK) ++ return (bcmerror); ++ ++#if defined(CONFIG_WIRELESS_EXT) ++ if (event->bsscfgidx == 0) { ++ /* ++ * Wireless ext is on primary interface only ++ */ ++ ++ ASSERT(dhd->iflist[*ifidx] != NULL); ++ ASSERT(dhd->iflist[*ifidx]->net != NULL); ++ ++ if (dhd->iflist[*ifidx]->net) { ++ wl_iw_event(dhd->iflist[*ifidx]->net, event, *data); ++ } ++ } ++#endif /* defined(CONFIG_WIRELESS_EXT) */ ++ ++#ifdef WL_CFG80211 ++ if ((ntoh32(event->event_type) == WLC_E_IF) && ++ (((dhd_if_event_t *)*data)->action == WLC_E_IF_ADD)) ++ /* If ADD_IF has been called directly by wl utility then we ++ * should not report this. In case if ADD_IF was called from ++ * CFG stack, then too this event need not be reported back ++ */ ++ return (BCME_OK); ++ if ((wl_cfg80211_is_progress_ifchange() || ++ wl_cfg80211_is_progress_ifadd()) && (*ifidx != 0)) { ++ /* ++ * If IF_ADD/CHANGE operation is going on, ++ * discard any event received on the virtual I/F ++ */ ++ return (BCME_OK); ++ } ++ ++ ASSERT(dhd->iflist[*ifidx] != NULL); ++ ASSERT(dhd->iflist[*ifidx]->net != NULL); ++ if (dhd->iflist[*ifidx]->event2cfg80211 && dhd->iflist[*ifidx]->net) { ++ wl_cfg80211_event(dhd->iflist[*ifidx]->net, event, *data); ++ } ++#endif /* defined(WL_CFG80211) */ ++ ++ return (bcmerror); ++} ++ ++/* send up locally generated event */ ++void ++dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data) ++{ ++ switch (ntoh32(event->event_type)) { ++#ifdef WLBTAMP ++ /* Send up locally generated AMP HCI Events */ ++ case WLC_E_BTA_HCI_EVENT: { ++ struct sk_buff *p, *skb; ++ bcm_event_t *msg; ++ wl_event_msg_t *p_bcm_event; ++ char *ptr; ++ uint32 len; ++ uint32 pktlen; ++ dhd_if_t *ifp; ++ dhd_info_t *dhd; ++ uchar *eth; ++ int ifidx; ++ ++ len = ntoh32(event->datalen); ++ pktlen = sizeof(bcm_event_t) + len + 2; ++ dhd = dhdp->info; ++ ifidx = dhd_ifname2idx(dhd, event->ifname); ++ ++ if ((p = PKTGET(dhdp->osh, pktlen, FALSE))) { ++ ASSERT(ISALIGNED((uintptr)PKTDATA(dhdp->osh, p), sizeof(uint32))); ++ ++ msg = (bcm_event_t *) PKTDATA(dhdp->osh, p); ++ ++ bcopy(&dhdp->mac, &msg->eth.ether_dhost, ETHER_ADDR_LEN); ++ bcopy(&dhdp->mac, &msg->eth.ether_shost, ETHER_ADDR_LEN); ++ ETHER_TOGGLE_LOCALADDR(&msg->eth.ether_shost); ++ ++ msg->eth.ether_type = hton16(ETHER_TYPE_BRCM); ++ ++ /* BCM Vendor specific header... */ ++ msg->bcm_hdr.subtype = hton16(BCMILCP_SUBTYPE_VENDOR_LONG); ++ msg->bcm_hdr.version = BCMILCP_BCM_SUBTYPEHDR_VERSION; ++ bcopy(BRCM_OUI, &msg->bcm_hdr.oui[0], DOT11_OUI_LEN); ++ ++ /* vendor spec header length + pvt data length (private indication ++ * hdr + actual message itself) ++ */ ++ msg->bcm_hdr.length = hton16(BCMILCP_BCM_SUBTYPEHDR_MINLENGTH + ++ BCM_MSG_LEN + sizeof(wl_event_msg_t) + (uint16)len); ++ msg->bcm_hdr.usr_subtype = hton16(BCMILCP_BCM_SUBTYPE_EVENT); ++ ++ PKTSETLEN(dhdp->osh, p, (sizeof(bcm_event_t) + len + 2)); ++ ++ /* copy wl_event_msg_t into sk_buf */ ++ ++ /* pointer to wl_event_msg_t in sk_buf */ ++ p_bcm_event = &msg->event; ++ bcopy(event, p_bcm_event, sizeof(wl_event_msg_t)); ++ ++ /* copy hci event into sk_buf */ ++ bcopy(data, (p_bcm_event + 1), len); ++ ++ msg->bcm_hdr.length = hton16(sizeof(wl_event_msg_t) + ++ ntoh16(msg->bcm_hdr.length)); ++ PKTSETLEN(dhdp->osh, p, (sizeof(bcm_event_t) + len + 2)); ++ ++ ptr = (char *)(msg + 1); ++ /* Last 2 bytes of the message are 0x00 0x00 to signal that there ++ * are no ethertypes which are following this ++ */ ++ ptr[len+0] = 0x00; ++ ptr[len+1] = 0x00; ++ ++ skb = PKTTONATIVE(dhdp->osh, p); ++ eth = skb->data; ++ len = skb->len; ++ ++ ifp = dhd->iflist[ifidx]; ++ if (ifp == NULL) ++ ifp = dhd->iflist[0]; ++ ++ ASSERT(ifp); ++ skb->dev = ifp->net; ++ skb->protocol = eth_type_trans(skb, skb->dev); ++ ++ skb->data = eth; ++ skb->len = len; ++ ++ /* Strip header, count, deliver upward */ ++ skb_pull(skb, ETH_HLEN); ++ ++ /* Send the packet */ ++ if (in_interrupt()) { ++ netif_rx(skb); ++ } else { ++ netif_rx_ni(skb); ++ } ++ } ++ else { ++ /* Could not allocate a sk_buf */ ++ AP6211_ERR("%s: unable to alloc sk_buf", __FUNCTION__); ++ } ++ break; ++ } /* case WLC_E_BTA_HCI_EVENT */ ++#endif /* WLBTAMP */ ++ ++ default: ++ break; ++ } ++} ++ ++void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar) ++{ ++#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) ++ struct dhd_info *dhdinfo = dhd->info; ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ int timeout = msecs_to_jiffies(IOCTL_RESP_TIMEOUT); ++#else ++ int timeout = (IOCTL_RESP_TIMEOUT / 1000) * HZ; ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ ++ ++ dhd_os_sdunlock(dhd); ++ wait_event_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), timeout); ++ dhd_os_sdlock(dhd); ++#endif ++ return; ++} ++ ++void dhd_wait_event_wakeup(dhd_pub_t *dhd) ++{ ++#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) ++ struct dhd_info *dhdinfo = dhd->info; ++ if (waitqueue_active(&dhdinfo->ctrl_wait)) ++ wake_up(&dhdinfo->ctrl_wait); ++#endif ++ return; ++} ++ ++int ++dhd_dev_reset(struct net_device *dev, uint8 flag) ++{ ++ int ret; ++ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ if (flag == TRUE) { ++ /* Issue wl down command before resetting the chip */ ++ if (dhd_wl_ioctl_cmd(&dhd->pub, WLC_DOWN, NULL, 0, TRUE, 0) < 0) { ++ AP6211_DEBUG("%s: wl down failed\n", __FUNCTION__); ++ } ++ } ++ ++ ret = dhd_bus_devreset(&dhd->pub, flag); ++ if (ret) { ++ AP6211_ERR("%s: dhd_bus_devreset: %d\n", __FUNCTION__, ret); ++ return ret; ++ } ++ ++ return ret; ++} ++ ++int net_os_set_suspend_disable(struct net_device *dev, int val) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ int ret = 0; ++ ++ if (dhd) { ++ ret = dhd->pub.suspend_disable_flag; ++ dhd->pub.suspend_disable_flag = val; ++ } ++ return ret; ++} ++ ++int net_os_set_suspend(struct net_device *dev, int val, int force) ++{ ++ int ret = 0; ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ if (dhd) { ++#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) ++ ret = dhd_set_suspend(val, &dhd->pub); ++#else ++ ret = dhd_suspend_resume_helper(dhd, val, force); ++#endif ++#ifdef WL_CFG80211 ++ wl_cfg80211_update_power_mode(dev); ++#endif ++ } ++ return ret; ++} ++ ++int net_os_set_suspend_bcn_li_dtim(struct net_device *dev, int val) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ if (dhd) ++ dhd->pub.suspend_bcn_li_dtim = val; ++ ++ return 0; ++} ++ ++#ifdef PKT_FILTER_SUPPORT ++int net_os_rxfilter_add_remove(struct net_device *dev, int add_remove, int num) ++{ ++#ifndef GAN_LITE_NAT_KEEPALIVE_FILTER ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ char *filterp = NULL; ++ int ret = 0; ++ ++ if (!dhd || (num == DHD_UNICAST_FILTER_NUM) || ++ (num == DHD_MDNS_FILTER_NUM)) ++ return ret; ++ if (num >= dhd->pub.pktfilter_count) ++ return -EINVAL; ++ if (add_remove) { ++ switch (num) { ++ case DHD_BROADCAST_FILTER_NUM: ++ filterp = "101 0 0 0 0xFFFFFFFFFFFF 0xFFFFFFFFFFFF"; ++ break; ++ case DHD_MULTICAST4_FILTER_NUM: ++ filterp = "102 0 0 0 0xFFFFFF 0x01005E"; ++ break; ++ case DHD_MULTICAST6_FILTER_NUM: ++ filterp = "103 0 0 0 0xFFFF 0x3333"; ++ break; ++ default: ++ return -EINVAL; ++ } ++ } ++ dhd->pub.pktfilter[num] = filterp; ++ dhd_pktfilter_offload_set(&dhd->pub, dhd->pub.pktfilter[num]); ++ return ret; ++#else ++ return 0; ++#endif /* GAN_LITE_NAT_KEEPALIVE_FILTER */ ++} ++ ++int dhd_os_enable_packet_filter(dhd_pub_t *dhdp, int val) ++{ ++ int ret = 0; ++ ++ /* Packet filtering is set only if we still in early-suspend and ++ * we need either to turn it ON or turn it OFF ++ * We can always turn it OFF in case of early-suspend, but we turn it ++ * back ON only if suspend_disable_flag was not set ++ */ ++ if (dhdp && dhdp->up) { ++ if (dhdp->in_suspend) { ++ if (!val || (val && !dhdp->suspend_disable_flag)) ++ dhd_enable_packet_filter(val, dhdp); ++ } ++ } ++ return ret; ++} ++ ++/* function to enable/disable packet for Network device */ ++int net_os_enable_packet_filter(struct net_device *dev, int val) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ return dhd_os_enable_packet_filter(&dhd->pub, val); ++} ++#endif /* PKT_FILTER_SUPPORT */ ++ ++int ++dhd_dev_init_ioctl(struct net_device *dev) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ return dhd_preinit_ioctls(&dhd->pub); ++} ++ ++#ifdef PNO_SUPPORT ++/* Linux wrapper to call common dhd_pno_clean */ ++int ++dhd_dev_pno_reset(struct net_device *dev) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ return (dhd_pno_clean(&dhd->pub)); ++} ++ ++ ++/* Linux wrapper to call common dhd_pno_enable */ ++int ++dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ return (dhd_pno_enable(&dhd->pub, pfn_enabled)); ++} ++ ++ ++/* Linux wrapper to call common dhd_pno_set */ ++int ++dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid, ++ ushort scan_fr, int pno_repeat, int pno_freq_expo_max) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ return (dhd_pno_set(&dhd->pub, ssids_local, nssid, scan_fr, pno_repeat, pno_freq_expo_max)); ++} ++ ++/* Linux wrapper to get pno status */ ++int ++dhd_dev_get_pno_status(struct net_device *dev) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ return (dhd_pno_get_status(&dhd->pub)); ++} ++ ++#endif /* PNO_SUPPORT */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (1) ++static void dhd_hang_process(struct work_struct *work) ++{ ++ dhd_info_t *dhd; ++ struct net_device *dev; ++ ++ dhd = (dhd_info_t *)container_of(work, dhd_info_t, work_hang); ++ dev = dhd->iflist[0]->net; ++ ++ if (dev) { ++ rtnl_lock(); ++ dev_close(dev); ++ rtnl_unlock(); ++#if defined(WL_WIRELESS_EXT) ++ wl_iw_send_priv_event(dev, "HANG"); ++#endif ++#if defined(WL_CFG80211) ++ wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED); ++#endif ++ } ++} ++ ++int dhd_os_send_hang_message(dhd_pub_t *dhdp) ++{ ++ int ret = 0; ++ if (dhdp) { ++ if (!dhdp->hang_was_sent) { ++ dhdp->hang_was_sent = 1; ++ schedule_work(&dhdp->info->work_hang); ++ } ++ } ++ return ret; ++} ++ ++int net_os_send_hang_message(struct net_device *dev) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ int ret = 0; ++ ++ if (dhd) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ ret = dhd_os_send_hang_message(&dhd->pub); ++#else ++ ret = wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED); ++#endif ++ return ret; ++} ++#endif /* (OEM_ANDROID) */ ++ ++void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ if (dhd && dhd->pub.up) { ++ memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t)); ++#ifdef WL_CFG80211 ++ wl_update_wiphybands(NULL, true); ++#endif ++ } ++} ++ ++void dhd_bus_band_set(struct net_device *dev, uint band) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ if (dhd && dhd->pub.up) { ++#ifdef WL_CFG80211 ++ wl_update_wiphybands(NULL, true); ++#endif ++ } ++} ++ ++void dhd_net_if_lock(struct net_device *dev) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ dhd_net_if_lock_local(dhd); ++} ++ ++void dhd_net_if_unlock(struct net_device *dev) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ dhd_net_if_unlock_local(dhd); ++} ++ ++static void dhd_net_if_lock_local(dhd_info_t *dhd) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 ++ if (dhd) ++ mutex_lock(&dhd->dhd_net_if_mutex); ++#endif ++} ++ ++static void dhd_net_if_unlock_local(dhd_info_t *dhd) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 ++ if (dhd) ++ mutex_unlock(&dhd->dhd_net_if_mutex); ++#endif ++} ++ ++static void dhd_suspend_lock(dhd_pub_t *pub) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ if (dhd) ++ mutex_lock(&dhd->dhd_suspend_mutex); ++#endif ++} ++ ++static void dhd_suspend_unlock(dhd_pub_t *pub) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ if (dhd) ++ mutex_unlock(&dhd->dhd_suspend_mutex); ++#endif ++} ++ ++unsigned long dhd_os_spin_lock(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ unsigned long flags = 0; ++ ++ if (dhd) ++ spin_lock_irqsave(&dhd->dhd_lock, flags); ++ ++ return flags; ++} ++ ++void dhd_os_spin_unlock(dhd_pub_t *pub, unsigned long flags) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ ++ if (dhd) ++ spin_unlock_irqrestore(&dhd->dhd_lock, flags); ++} ++ ++static int ++dhd_get_pend_8021x_cnt(dhd_info_t *dhd) ++{ ++ return (atomic_read(&dhd->pend_8021x_cnt)); ++} ++ ++#define MAX_WAIT_FOR_8021X_TX 25 ++ ++int ++dhd_wait_pend8021x(struct net_device *dev) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ int timeout = msecs_to_jiffies(10); ++ int ntimes = MAX_WAIT_FOR_8021X_TX; ++ int pend = dhd_get_pend_8021x_cnt(dhd); ++ ++ while (ntimes && pend) { ++ if (pend) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(timeout); ++ set_current_state(TASK_RUNNING); ++ ntimes--; ++ } ++ pend = dhd_get_pend_8021x_cnt(dhd); ++ } ++ if (ntimes == 0) ++ AP6211_ERR("%s: TIMEOUT\n", __FUNCTION__); ++ return pend; ++} ++ ++#ifdef DHD_DEBUG ++int ++write_to_file(dhd_pub_t *dhd, uint8 *buf, int size) ++{ ++ int ret = 0; ++ struct file *fp; ++ mm_segment_t old_fs; ++ loff_t pos = 0; ++ ++ /* change to KERNEL_DS address limit */ ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ /* open file to write */ ++ fp = filp_open("/tmp/mem_dump", O_WRONLY|O_CREAT, 0640); ++ if (!fp) { ++ AP6211_ERR("%s: open file error\n", __FUNCTION__); ++ ret = -1; ++ goto exit; ++ } ++ ++ /* Write buf to file */ ++ fp->f_op->write(fp, buf, size, &pos); ++ ++exit: ++ /* free buf before return */ ++ MFREE(dhd->osh, buf, size); ++ /* close file before return */ ++ if (fp) ++ filp_close(fp, current->files); ++ /* restore previous address limit */ ++ set_fs(old_fs); ++ ++ return ret; ++} ++#endif /* DHD_DEBUG */ ++ ++int dhd_os_wake_lock_timeout(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ unsigned long flags; ++ int ret = 0; ++ ++ if (dhd) { ++ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); ++ ret = dhd->wakelock_rx_timeout_enable > dhd->wakelock_ctrl_timeout_enable ? ++ dhd->wakelock_rx_timeout_enable : dhd->wakelock_ctrl_timeout_enable; ++#ifdef CONFIG_HAS_WAKELOCK ++ if (dhd->wakelock_rx_timeout_enable) ++ wake_lock_timeout(dhd->wl_rxwake, ++ msecs_to_jiffies(dhd->wakelock_rx_timeout_enable)); ++ if (dhd->wakelock_ctrl_timeout_enable) ++ wake_lock_timeout(dhd->wl_ctrlwake, ++ msecs_to_jiffies(dhd->wakelock_ctrl_timeout_enable)); ++#endif ++ dhd->wakelock_rx_timeout_enable = 0; ++ dhd->wakelock_ctrl_timeout_enable = 0; ++ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); ++ } ++ return ret; ++} ++ ++int net_os_wake_lock_timeout(struct net_device *dev) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ int ret = 0; ++ ++ if (dhd) ++ ret = dhd_os_wake_lock_timeout(&dhd->pub); ++ return ret; ++} ++ ++int dhd_os_wake_lock_rx_timeout_enable(dhd_pub_t *pub, int val) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ unsigned long flags; ++ ++ if (dhd) { ++ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); ++ if (val > dhd->wakelock_rx_timeout_enable) ++ dhd->wakelock_rx_timeout_enable = val; ++ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); ++ } ++ return 0; ++} ++ ++int dhd_os_wake_lock_ctrl_timeout_enable(dhd_pub_t *pub, int val) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ unsigned long flags; ++ ++ if (dhd) { ++ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); ++ if (val > dhd->wakelock_ctrl_timeout_enable) ++ dhd->wakelock_ctrl_timeout_enable = val; ++ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); ++ } ++ return 0; ++} ++ ++int net_os_wake_lock_rx_timeout_enable(struct net_device *dev, int val) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ int ret = 0; ++ ++ if (dhd) ++ ret = dhd_os_wake_lock_rx_timeout_enable(&dhd->pub, val); ++ return ret; ++} ++ ++int net_os_wake_lock_ctrl_timeout_enable(struct net_device *dev, int val) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ int ret = 0; ++ ++ if (dhd) ++ ret = dhd_os_wake_lock_ctrl_timeout_enable(&dhd->pub, val); ++ return ret; ++} ++ ++int dhd_os_wake_lock(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ unsigned long flags; ++ int ret = 0; ++ ++ if (dhd) { ++ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); ++#ifdef CONFIG_HAS_WAKELOCK ++ if (!dhd->wakelock_counter) ++ wake_lock(dhd->wl_wifi); ++#endif ++ dhd->wakelock_counter++; ++ ret = dhd->wakelock_counter; ++ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); ++ } ++ return ret; ++} ++ ++int net_os_wake_lock(struct net_device *dev) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ int ret = 0; ++ ++ if (dhd) ++ ret = dhd_os_wake_lock(&dhd->pub); ++ return ret; ++} ++ ++int dhd_os_wake_unlock(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ unsigned long flags; ++ int ret = 0; ++ ++ dhd_os_wake_lock_timeout(pub); ++ if (dhd) { ++ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); ++ if (dhd->wakelock_counter) { ++ dhd->wakelock_counter--; ++#ifdef CONFIG_HAS_WAKELOCK ++ if (!dhd->wakelock_counter) ++ wake_unlock(dhd->wl_wifi); ++#endif ++ ret = dhd->wakelock_counter; ++ } ++ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); ++ } ++ return ret; ++} ++ ++int dhd_os_check_wakelock(void *dhdp) ++{ ++#ifdef CONFIG_HAS_WAKELOCK ++ dhd_pub_t *pub = (dhd_pub_t *)dhdp; ++ dhd_info_t *dhd; ++ ++ if (!pub) ++ return 0; ++ dhd = (dhd_info_t *)(pub->info); ++ ++ /* Indicate to the SD Host to avoid going to suspend if internal locks are up */ ++ if (dhd && (wake_lock_active(dhd->wl_wifi) || ++ (wake_lock_active(dhd->wl_wdwake)))) ++ return 1; ++#endif ++ return 0; ++} ++ ++int net_os_wake_unlock(struct net_device *dev) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ int ret = 0; ++ ++ if (dhd) ++ ret = dhd_os_wake_unlock(&dhd->pub); ++ return ret; ++} ++ ++int dhd_os_wd_wake_lock(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ unsigned long flags; ++ int ret = 0; ++ ++ if (dhd) { ++ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); ++#ifdef CONFIG_HAS_WAKELOCK ++ /* if wakelock_wd_counter was never used : lock it at once */ ++ if (!dhd->wakelock_wd_counter) { ++ if (dhd->wl_wdwake) ++ wake_lock(dhd->wl_wdwake); ++ else { ++ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); ++ return 0; ++ } ++ } ++#endif ++ dhd->wakelock_wd_counter++; ++ ret = dhd->wakelock_wd_counter; ++ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); ++ } ++ return ret; ++} ++ ++int dhd_os_wd_wake_unlock(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ unsigned long flags; ++ int ret = 0; ++ ++ if (dhd) { ++ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); ++ if (dhd->wakelock_wd_counter) { ++ dhd->wakelock_wd_counter = 0; ++#ifdef CONFIG_HAS_WAKELOCK ++ wake_unlock(dhd->wl_wdwake); ++#endif ++ } ++ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); ++ } ++ return ret; ++} ++ ++int dhd_os_check_if_up(void *dhdp) ++{ ++ dhd_pub_t *pub = (dhd_pub_t *)dhdp; ++ ++ if (!pub) ++ return 0; ++ return pub->up; ++} ++ ++/* function to collect firmware, chip id and chip version info */ ++void dhd_set_version_info(dhd_pub_t *dhdp, char *fw) ++{ ++ int i; ++ ++ i = snprintf(info_string, sizeof(info_string), "Driver: %s\n Firmware: %s ", EPI_VERSION_STR, fw); ++ ++ if (!dhdp) ++ return; ++ ++ i = snprintf(&info_string[i], sizeof(info_string) - i, ++ "\n Chip: %x Rev %x Pkg %x", dhd_bus_chip_id(dhdp), ++ dhd_bus_chiprev_id(dhdp), dhd_bus_chippkg_id(dhdp)); ++ AP6211_ERR("Chip: %x Rev %x Pkg %x", dhd_bus_chip_id(dhdp), dhd_bus_chiprev_id(dhdp), dhd_bus_chippkg_id(dhdp)); ++} ++ ++int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd) ++{ ++ int ifidx; ++ int ret = 0; ++ dhd_info_t *dhd = NULL; ++ ++ if (!net || !netdev_priv(net)) { ++ AP6211_ERR("%s invalid parameter\n", __FUNCTION__); ++ return -EINVAL; ++ } ++ ++ dhd = *(dhd_info_t **)netdev_priv(net); ++ ifidx = dhd_net2idx(dhd, net); ++ if (ifidx == DHD_BAD_IF) { ++ AP6211_ERR("%s bad ifidx\n", __FUNCTION__); ++ return -ENODEV; ++ } ++ ++ DHD_OS_WAKE_LOCK(&dhd->pub); ++ ret = dhd_wl_ioctl(&dhd->pub, ifidx, ioc, ioc->buf, ioc->len); ++ dhd_check_hang(net, &dhd->pub, ret); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ ++ return ret; ++} ++ ++bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret) ++{ ++ struct net_device *net; ++ ++ net = dhd_idx2net(dhdp, ifidx); ++ return dhd_check_hang(net, dhdp, ret); ++} ++ ++ ++#ifdef PROP_TXSTATUS ++extern int dhd_wlfc_interface_entry_update(void* state, ewlfc_mac_entry_action_t action, uint8 ifid, ++ uint8 iftype, uint8* ea); ++extern int dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits); ++ ++int dhd_wlfc_interface_event(struct dhd_info *dhd, ++ ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea) ++{ ++ int status; ++ ++ dhd_os_wlfc_block(&dhd->pub); ++ if (dhd->pub.wlfc_state == NULL) { ++ dhd_os_wlfc_unblock(&dhd->pub); ++ return BCME_OK; ++ } ++ ++ status = dhd_wlfc_interface_entry_update(dhd->pub.wlfc_state, action, ifid, iftype, ea); ++ dhd_os_wlfc_unblock(&dhd->pub); ++ return status; ++} ++ ++int dhd_wlfc_FIFOcreditmap_event(struct dhd_info *dhd, uint8* event_data) ++{ ++ int status; ++ ++ dhd_os_wlfc_block(&dhd->pub); ++ if (dhd->pub.wlfc_state == NULL) { ++ dhd_os_wlfc_unblock(&dhd->pub); ++ return BCME_OK; ++ } ++ ++ status = dhd_wlfc_FIFOcreditmap_update(dhd->pub.wlfc_state, event_data); ++ dhd_os_wlfc_unblock(&dhd->pub); ++ return status; ++} ++ ++int dhd_wlfc_event(struct dhd_info *dhd) ++{ ++ int status; ++ ++ dhd_os_wlfc_block(&dhd->pub); ++ status = dhd_wlfc_enable(&dhd->pub); ++ dhd_os_wlfc_unblock(&dhd->pub); ++ return status; ++} ++#endif /* PROP_TXSTATUS */ ++ ++#ifdef BCMDBGFS ++ ++#include ++ ++extern uint32 dhd_readregl(void *bp, uint32 addr); ++extern uint32 dhd_writeregl(void *bp, uint32 addr, uint32 data); ++ ++typedef struct dhd_dbgfs { ++ struct dentry *debugfs_dir; ++ struct dentry *debugfs_mem; ++ dhd_pub_t *dhdp; ++ uint32 size; ++} dhd_dbgfs_t; ++ ++dhd_dbgfs_t g_dbgfs; ++ ++static int ++dhd_dbg_state_open(struct inode *inode, struct file *file) ++{ ++ file->private_data = inode->i_private; ++ return 0; ++} ++ ++static ssize_t ++dhd_dbg_state_read(struct file *file, char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ ssize_t rval; ++ uint32 tmp; ++ loff_t pos = *ppos; ++ size_t ret; ++ ++ if (pos < 0) ++ return -EINVAL; ++ if (pos >= g_dbgfs.size || !count) ++ return 0; ++ if (count > g_dbgfs.size - pos) ++ count = g_dbgfs.size - pos; ++ ++ /* Basically enforce aligned 4 byte reads. It's up to the user to work out the details */ ++ tmp = dhd_readregl(g_dbgfs.dhdp->bus, file->f_pos & (~3)); ++ ++ ret = copy_to_user(ubuf, &tmp, 4); ++ if (ret == count) ++ return -EFAULT; ++ ++ count -= ret; ++ *ppos = pos + count; ++ rval = count; ++ ++ return rval; ++} ++ ++ ++static ssize_t ++dhd_debugfs_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) ++{ ++ loff_t pos = *ppos; ++ size_t ret; ++ uint32 buf; ++ ++ if (pos < 0) ++ return -EINVAL; ++ if (pos >= g_dbgfs.size || !count) ++ return 0; ++ if (count > g_dbgfs.size - pos) ++ count = g_dbgfs.size - pos; ++ ++ ret = copy_from_user(&buf, ubuf, sizeof(uint32)); ++ if (ret == count) ++ return -EFAULT; ++ ++ /* Basically enforce aligned 4 byte writes. It's up to the user to work out the details */ ++ dhd_writeregl(g_dbgfs.dhdp->bus, file->f_pos & (~3), buf); ++ ++ return count; ++} ++ ++ ++loff_t ++dhd_debugfs_lseek(struct file *file, loff_t off, int whence) ++{ ++ loff_t pos = -1; ++ ++ switch (whence) { ++ case 0: ++ pos = off; ++ break; ++ case 1: ++ pos = file->f_pos + off; ++ break; ++ case 2: ++ pos = g_dbgfs.size - off; ++ } ++ return (pos < 0 || pos > g_dbgfs.size) ? -EINVAL : (file->f_pos = pos); ++} ++ ++static const struct file_operations dhd_dbg_state_ops = { ++ .read = dhd_dbg_state_read, ++ .write = dhd_debugfs_write, ++ .open = dhd_dbg_state_open, ++ .llseek = dhd_debugfs_lseek ++}; ++ ++static void dhd_dbg_create(void) ++{ ++ if (g_dbgfs.debugfs_dir) { ++ g_dbgfs.debugfs_mem = debugfs_create_file("mem", 0644, g_dbgfs.debugfs_dir, ++ NULL, &dhd_dbg_state_ops); ++ } ++} ++ ++void dhd_dbg_init(dhd_pub_t *dhdp) ++{ ++ int err; ++ ++ g_dbgfs.dhdp = dhdp; ++ g_dbgfs.size = 0x20000000; /* Allow access to various cores regs */ ++ ++ g_dbgfs.debugfs_dir = debugfs_create_dir("dhd", 0); ++ if (IS_ERR(g_dbgfs.debugfs_dir)) { ++ err = PTR_ERR(g_dbgfs.debugfs_dir); ++ g_dbgfs.debugfs_dir = NULL; ++ return; ++ } ++ ++ dhd_dbg_create(); ++ ++ return; ++} ++ ++void dhd_dbg_remove(void) ++{ ++ debugfs_remove(g_dbgfs.debugfs_mem); ++ debugfs_remove(g_dbgfs.debugfs_dir); ++ ++ bzero((unsigned char *) &g_dbgfs, sizeof(g_dbgfs)); ++ ++} ++#endif /* ifdef BCMDBGFS */ ++ ++#ifdef WLMEDIA_HTSF ++ ++static ++void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); ++ struct sk_buff *skb; ++ uint32 htsf = 0; ++ uint16 dport = 0, oldmagic = 0xACAC; ++ char *p1; ++ htsfts_t ts; ++ ++ /* timestamp packet */ ++ ++ p1 = (char*) PKTDATA(dhdp->osh, pktbuf); ++ ++ if (PKTLEN(dhdp->osh, pktbuf) > HTSF_MINLEN) { ++/* memcpy(&proto, p1+26, 4); */ ++ memcpy(&dport, p1+40, 2); ++/* proto = ((ntoh32(proto))>> 16) & 0xFF; */ ++ dport = ntoh16(dport); ++ } ++ ++ /* timestamp only if icmp or udb iperf with port 5555 */ ++/* if (proto == 17 && dport == tsport) { */ ++ if (dport >= tsport && dport <= tsport + 20) { ++ ++ skb = (struct sk_buff *) pktbuf; ++ ++ htsf = dhd_get_htsf(dhd, 0); ++ memset(skb->data + 44, 0, 2); /* clear checksum */ ++ memcpy(skb->data+82, &oldmagic, 2); ++ memcpy(skb->data+84, &htsf, 4); ++ ++ memset(&ts, 0, sizeof(htsfts_t)); ++ ts.magic = HTSFMAGIC; ++ ts.prio = PKTPRIO(pktbuf); ++ ts.seqnum = htsf_seqnum++; ++ ts.c10 = get_cycles(); ++ ts.t10 = htsf; ++ ts.endmagic = HTSFENDMAGIC; ++ ++ memcpy(skb->data + HTSF_HOSTOFFSET, &ts, sizeof(ts)); ++ } ++} ++ ++static void dhd_dump_htsfhisto(histo_t *his, char *s) ++{ ++ int pktcnt = 0, curval = 0, i; ++ for (i = 0; i < (NUMBIN-2); i++) { ++ curval += 500; ++ AP6211_DUMP("%d ", his->bin[i]); ++ pktcnt += his->bin[i]; ++ } ++ AP6211_DUMP(" max: %d TotPkt: %d neg: %d [%s]\n", his->bin[NUMBIN-2], pktcnt, ++ his->bin[NUMBIN-1], s); ++} ++ ++static ++void sorttobin(int value, histo_t *histo) ++{ ++ int i, binval = 0; ++ ++ if (value < 0) { ++ histo->bin[NUMBIN-1]++; ++ return; ++ } ++ if (value > histo->bin[NUMBIN-2]) /* store the max value */ ++ histo->bin[NUMBIN-2] = value; ++ ++ for (i = 0; i < (NUMBIN-2); i++) { ++ binval += 500; /* 500m s bins */ ++ if (value <= binval) { ++ histo->bin[i]++; ++ return; ++ } ++ } ++ histo->bin[NUMBIN-3]++; ++} ++ ++static ++void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)dhdp->info; ++ struct sk_buff *skb; ++ char *p1; ++ uint16 old_magic; ++ int d1, d2, d3, end2end; ++ htsfts_t *htsf_ts; ++ uint32 htsf; ++ ++ skb = PKTTONATIVE(dhdp->osh, pktbuf); ++ p1 = (char*)PKTDATA(dhdp->osh, pktbuf); ++ ++ if (PKTLEN(osh, pktbuf) > HTSF_MINLEN) { ++ memcpy(&old_magic, p1+78, 2); ++ htsf_ts = (htsfts_t*) (p1 + HTSF_HOSTOFFSET - 4); ++ } ++ else ++ return; ++ ++ if (htsf_ts->magic == HTSFMAGIC) { ++ htsf_ts->tE0 = dhd_get_htsf(dhd, 0); ++ htsf_ts->cE0 = get_cycles(); ++ } ++ ++ if (old_magic == 0xACAC) { ++ ++ tspktcnt++; ++ htsf = dhd_get_htsf(dhd, 0); ++ memcpy(skb->data+92, &htsf, sizeof(uint32)); ++ ++ memcpy(&ts[tsidx].t1, skb->data+80, 16); ++ ++ d1 = ts[tsidx].t2 - ts[tsidx].t1; ++ d2 = ts[tsidx].t3 - ts[tsidx].t2; ++ d3 = ts[tsidx].t4 - ts[tsidx].t3; ++ end2end = ts[tsidx].t4 - ts[tsidx].t1; ++ ++ sorttobin(d1, &vi_d1); ++ sorttobin(d2, &vi_d2); ++ sorttobin(d3, &vi_d3); ++ sorttobin(end2end, &vi_d4); ++ ++ if (end2end > 0 && end2end > maxdelay) { ++ maxdelay = end2end; ++ maxdelaypktno = tspktcnt; ++ memcpy(&maxdelayts, &ts[tsidx], 16); ++ } ++ if (++tsidx >= TSMAX) ++ tsidx = 0; ++ } ++} ++ ++uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx) ++{ ++ uint32 htsf = 0, cur_cycle, delta, delta_us; ++ uint32 factor, baseval, baseval2; ++ cycles_t t; ++ ++ t = get_cycles(); ++ cur_cycle = t; ++ ++ if (cur_cycle > dhd->htsf.last_cycle) ++ delta = cur_cycle - dhd->htsf.last_cycle; ++ else { ++ delta = cur_cycle + (0xFFFFFFFF - dhd->htsf.last_cycle); ++ } ++ ++ delta = delta >> 4; ++ ++ if (dhd->htsf.coef) { ++ /* times ten to get the first digit */ ++ factor = (dhd->htsf.coef*10 + dhd->htsf.coefdec1); ++ baseval = (delta*10)/factor; ++ baseval2 = (delta*10)/(factor+1); ++ delta_us = (baseval - (((baseval - baseval2) * dhd->htsf.coefdec2)) / 10); ++ htsf = (delta_us << 4) + dhd->htsf.last_tsf + HTSF_BUS_DELAY; ++ } ++ else { ++ AP6211_ERR("-------dhd->htsf.coef = 0 -------\n"); ++ } ++ ++ return htsf; ++} ++ ++static void dhd_dump_latency(void) ++{ ++ int i, max = 0; ++ int d1, d2, d3, d4, d5; ++ ++ AP6211_DEBUG("T1 T2 T3 T4 d1 d2 t4-t1 i \n"); ++ for (i = 0; i < TSMAX; i++) { ++ d1 = ts[i].t2 - ts[i].t1; ++ d2 = ts[i].t3 - ts[i].t2; ++ d3 = ts[i].t4 - ts[i].t3; ++ d4 = ts[i].t4 - ts[i].t1; ++ d5 = ts[max].t4-ts[max].t1; ++ if (d4 > d5 && d4 > 0) { ++ max = i; ++ } ++ AP6211_DUMP("%08X %08X %08X %08X \t%d %d %d %d i=%d\n", ++ ts[i].t1, ts[i].t2, ts[i].t3, ts[i].t4, ++ d1, d2, d3, d4, i); ++ } ++ ++ AP6211_DEBUG("current idx = %d \n", tsidx); ++ ++ AP6211_DEBUG("Highest latency %d pkt no.%d total=%d\n", maxdelay, maxdelaypktno, tspktcnt); ++ AP6211_DEBUG("%08X %08X %08X %08X \t%d %d %d %d\n", ++ maxdelayts.t1, maxdelayts.t2, maxdelayts.t3, maxdelayts.t4, ++ maxdelayts.t2 - maxdelayts.t1, ++ maxdelayts.t3 - maxdelayts.t2, ++ maxdelayts.t4 - maxdelayts.t3, ++ maxdelayts.t4 - maxdelayts.t1); ++} ++ ++ ++static int ++dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx) ++{ ++ wl_ioctl_t ioc; ++ char buf[32]; ++ int ret; ++ uint32 s1, s2; ++ ++ struct tsf { ++ uint32 low; ++ uint32 high; ++ } tsf_buf; ++ ++ memset(&ioc, 0, sizeof(ioc)); ++ memset(&tsf_buf, 0, sizeof(tsf_buf)); ++ ++ ioc.cmd = WLC_GET_VAR; ++ ioc.buf = buf; ++ ioc.len = (uint)sizeof(buf); ++ ioc.set = FALSE; ++ ++ strncpy(buf, "tsf", sizeof(buf) - 1); ++ buf[sizeof(buf) - 1] = '\0'; ++ s1 = dhd_get_htsf(dhd, 0); ++ if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { ++ if (ret == -EIO) { ++ AP6211_ERR("%s: tsf is not supported by device\n", ++ dhd_ifname(&dhd->pub, ifidx)); ++ return -EOPNOTSUPP; ++ } ++ return ret; ++ } ++ s2 = dhd_get_htsf(dhd, 0); ++ ++ memcpy(&tsf_buf, buf, sizeof(tsf_buf)); ++ AP6211_DEBUG("TSF_h=%04X lo=%08X Calc:htsf=%08X, coef=%d.%d%d delta=%d ", ++ tsf_buf.high, tsf_buf.low, s2, dhd->htsf.coef, dhd->htsf.coefdec1, ++ dhd->htsf.coefdec2, s2-tsf_buf.low); ++ AP6211_DEBUG("lasttsf=%08X lastcycle=%08X\n", dhd->htsf.last_tsf, dhd->htsf.last_cycle); ++ return 0; ++} ++ ++void htsf_update(dhd_info_t *dhd, void *data) ++{ ++ static ulong cur_cycle = 0, prev_cycle = 0; ++ uint32 htsf, tsf_delta = 0; ++ uint32 hfactor = 0, cyc_delta, dec1 = 0, dec2, dec3, tmp; ++ ulong b, a; ++ cycles_t t; ++ ++ /* cycles_t in inlcude/mips/timex.h */ ++ ++ t = get_cycles(); ++ ++ prev_cycle = cur_cycle; ++ cur_cycle = t; ++ ++ if (cur_cycle > prev_cycle) ++ cyc_delta = cur_cycle - prev_cycle; ++ else { ++ b = cur_cycle; ++ a = prev_cycle; ++ cyc_delta = cur_cycle + (0xFFFFFFFF - prev_cycle); ++ } ++ ++ if (data == NULL) ++ AP6211_DEBUG(" tsf update ata point er is null \n"); ++ ++ memcpy(&prev_tsf, &cur_tsf, sizeof(tsf_t)); ++ memcpy(&cur_tsf, data, sizeof(tsf_t)); ++ ++ if (cur_tsf.low == 0) { ++ AP6211_DEBUG(" ---- 0 TSF, do not update, return\n"); ++ return; ++ } ++ ++ if (cur_tsf.low > prev_tsf.low) ++ tsf_delta = (cur_tsf.low - prev_tsf.low); ++ else { ++ AP6211_DEBUG(" ---- tsf low is smaller cur_tsf= %08X, prev_tsf=%08X, \n", ++ cur_tsf.low, prev_tsf.low); ++ if (cur_tsf.high > prev_tsf.high) { ++ tsf_delta = cur_tsf.low + (0xFFFFFFFF - prev_tsf.low); ++ AP6211_DEBUG(" ---- Wrap around tsf coutner adjusted TSF=%08X\n", tsf_delta); ++ } ++ else ++ return; /* do not update */ ++ } ++ ++ if (tsf_delta) { ++ hfactor = cyc_delta / tsf_delta; ++ tmp = (cyc_delta - (hfactor * tsf_delta))*10; ++ dec1 = tmp/tsf_delta; ++ dec2 = ((tmp - dec1*tsf_delta)*10) / tsf_delta; ++ tmp = (tmp - (dec1*tsf_delta))*10; ++ dec3 = ((tmp - dec2*tsf_delta)*10) / tsf_delta; ++ ++ if (dec3 > 4) { ++ if (dec2 == 9) { ++ dec2 = 0; ++ if (dec1 == 9) { ++ dec1 = 0; ++ hfactor++; ++ } ++ else { ++ dec1++; ++ } ++ } ++ else ++ dec2++; ++ } ++ } ++ ++ if (hfactor) { ++ htsf = ((cyc_delta * 10) / (hfactor*10+dec1)) + prev_tsf.low; ++ dhd->htsf.coef = hfactor; ++ dhd->htsf.last_cycle = cur_cycle; ++ dhd->htsf.last_tsf = cur_tsf.low; ++ dhd->htsf.coefdec1 = dec1; ++ dhd->htsf.coefdec2 = dec2; ++ } ++ else { ++ htsf = prev_tsf.low; ++ } ++} ++ ++#endif /* WLMEDIA_HTSF */ +diff --git a/drivers/net/wireless/ap6211/dhd_linux_sched.c b/drivers/net/wireless/ap6211/dhd_linux_sched.c +new file mode 100755 +index 0000000..290caf7 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_linux_sched.c +@@ -0,0 +1,39 @@ ++/* ++ * Expose some of the kernel scheduler routines ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd_linux_sched.c 291086 2011-10-21 01:17:24Z $ ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++int setScheduler(struct task_struct *p, int policy, struct sched_param *param) ++{ ++ int rc = 0; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) ++ rc = sched_setscheduler(p, policy, param); ++#endif /* LinuxVer */ ++ return rc; ++} +diff --git a/drivers/net/wireless/ap6211/dhd_pno.c b/drivers/net/wireless/ap6211/dhd_pno.c +new file mode 100755 +index 0000000..317a063 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_pno.c +@@ -0,0 +1,1838 @@ ++/* ++ * Broadcom Dongle Host Driver (DHD) ++ * Prefered Network Offload and Wi-Fi Location Service(WLS) code. ++ * ++ * Copyright (C) 1999-2013, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd_pno.c 420056 2013-08-24 00:53:12Z $ ++ */ ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#ifdef __BIG_ENDIAN ++#include ++#define htod32(i) (bcmswap32(i)) ++#define htod16(i) (bcmswap16(i)) ++#define dtoh32(i) (bcmswap32(i)) ++#define dtoh16(i) (bcmswap16(i)) ++#define htodchanspec(i) htod16(i) ++#define dtohchanspec(i) dtoh16(i) ++#else ++#define htod32(i) i ++#define htod16(i) i ++#define dtoh32(i) i ++#define dtoh16(i) i ++#define htodchanspec(i) i ++#define dtohchanspec(i) i ++#endif /* IL_BIGENDINA */ ++ ++#define NULL_CHECK(p, s, err) \ ++ do { \ ++ if (!(p)) { \ ++ printf("NULL POINTER (%s) : %s\n", __FUNCTION__, (s)); \ ++ err = BCME_ERROR; \ ++ return err; \ ++ } \ ++ } while (0) ++#define PNO_GET_PNOSTATE(dhd) ((dhd_pno_status_info_t *)dhd->pno_state) ++#define PNO_BESTNET_LEN 1024 ++#define PNO_ON 1 ++#define PNO_OFF 0 ++#define CHANNEL_2G_MAX 14 ++#define MAX_NODE_CNT 5 ++#define WLS_SUPPORTED(pno_state) (pno_state->wls_supported == TRUE) ++#define TIME_DIFF(timestamp1, timestamp2) (abs((uint32)(timestamp1/1000) \ ++ - (uint32)(timestamp2/1000))) ++ ++#define ENTRY_OVERHEAD strlen("bssid=\nssid=\nfreq=\nlevel=\nage=\ndist=\ndistSd=\n====") ++#define TIME_MIN_DIFF 5 ++static inline bool ++is_dfs(uint16 channel) ++{ ++ if (channel >= 52 && channel <= 64) /* class 2 */ ++ return TRUE; ++ else if (channel >= 100 && channel <= 140) /* class 4 */ ++ return TRUE; ++ else ++ return FALSE; ++} ++static int ++_dhd_pno_clean(dhd_pub_t *dhd) ++{ ++ int pfn = 0; ++ int err; ++ dhd_pno_status_info_t *_pno_state; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ AP6211_DEBUG("%s enter\n", __FUNCTION__); ++ /* Disable PNO */ ++ err = dhd_iovar(dhd, 0, "pfn", (char *)&pfn, sizeof(pfn), 1); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to execute pfn(error : %d)\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ _pno_state->pno_status = DHD_PNO_DISABLED; ++ err = dhd_iovar(dhd, 0, "pfnclear", NULL, 0, 1); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to execute pfnclear(error : %d)\n", ++ __FUNCTION__, err); ++ } ++exit: ++ return err; ++} ++ ++static int ++_dhd_pno_suspend(dhd_pub_t *dhd) ++{ ++ int err; ++ int suspend = 1; ++ dhd_pno_status_info_t *_pno_state; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ AP6211_DEBUG("%s enter\n", __FUNCTION__); ++ err = dhd_iovar(dhd, 0, "pfn_suspend", (char *)&suspend, sizeof(suspend), 1); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to suspend pfn(error :%d)\n", __FUNCTION__, err); ++ goto exit; ++ ++ } ++ _pno_state->pno_status = DHD_PNO_SUSPEND; ++exit: ++ return err; ++} ++static int ++_dhd_pno_enable(dhd_pub_t *dhd, int enable) ++{ ++ int err = BCME_OK; ++ dhd_pno_status_info_t *_pno_state; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ AP6211_DEBUG("%s enter\n", __FUNCTION__); ++ ++ if (enable & 0xfffe) { ++ AP6211_ERR("%s invalid value\n", __FUNCTION__); ++ err = BCME_BADARG; ++ goto exit; ++ } ++ if (!dhd_support_sta_mode(dhd)) { ++ AP6211_ERR("PNO is not allowed for non-STA mode"); ++ err = BCME_BADOPTION; ++ goto exit; ++ } ++ if (enable) { ++ if ((_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) && ++ dhd_is_associated(dhd, NULL, NULL)) { ++ AP6211_ERR("%s Legacy PNO mode cannot be enabled " ++ "in assoc mode , ignore it\n", __FUNCTION__); ++ err = BCME_BADOPTION; ++ goto exit; ++ } ++ } ++ /* Enable/Disable PNO */ ++ err = dhd_iovar(dhd, 0, "pfn", (char *)&enable, sizeof(enable), 1); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to execute pfn_set\n", __FUNCTION__); ++ goto exit; ++ } ++ _pno_state->pno_status = (enable)? ++ DHD_PNO_ENABLED : DHD_PNO_DISABLED; ++ if (!enable) ++ _pno_state->pno_mode = DHD_PNO_NONE_MODE; ++ ++ AP6211_DEBUG("%s set pno as %s\n", ++ __FUNCTION__, enable ? "Enable" : "Disable"); ++exit: ++ return err; ++} ++ ++static int ++_dhd_pno_set(dhd_pub_t *dhd, const dhd_pno_params_t *pno_params, dhd_pno_mode_t mode) ++{ ++ int err = BCME_OK; ++ wl_pfn_param_t pfn_param; ++ dhd_pno_params_t *_params; ++ dhd_pno_status_info_t *_pno_state; ++ bool combined_scan = FALSE; ++ AP6211_DEBUG("%s enter\n", __FUNCTION__); ++ ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ ++ memset(&pfn_param, 0, sizeof(pfn_param)); ++ ++ /* set pfn parameters */ ++ pfn_param.version = htod32(PFN_VERSION); ++ pfn_param.flags = ((PFN_LIST_ORDER << SORT_CRITERIA_BIT) | ++ (ENABLE << IMMEDIATE_SCAN_BIT) | (ENABLE << REPORT_SEPERATELY_BIT)); ++ if (mode == DHD_PNO_LEGACY_MODE) { ++ /* check and set extra pno params */ ++ if ((pno_params->params_legacy.pno_repeat != 0) || ++ (pno_params->params_legacy.pno_freq_expo_max != 0)) { ++ pfn_param.flags |= htod16(ENABLE << ENABLE_ADAPTSCAN_BIT); ++ pfn_param.repeat = (uchar) (pno_params->params_legacy.pno_repeat); ++ pfn_param.exp = (uchar) (pno_params->params_legacy.pno_freq_expo_max); ++ } ++ /* set up pno scan fr */ ++ if (pno_params->params_legacy.scan_fr != 0) ++ pfn_param.scan_freq = htod32(pno_params->params_legacy.scan_fr); ++ if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { ++ AP6211_DEBUG("will enable combined scan with BATCHIG SCAN MODE\n"); ++ mode |= DHD_PNO_BATCH_MODE; ++ combined_scan = TRUE; ++ } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { ++ AP6211_DEBUG("will enable combined scan with HOTLIST SCAN MODE\n"); ++ mode |= DHD_PNO_HOTLIST_MODE; ++ combined_scan = TRUE; ++ } ++ } ++ if (mode & (DHD_PNO_BATCH_MODE | DHD_PNO_HOTLIST_MODE)) { ++ /* Scan frequency of 30 sec */ ++ pfn_param.scan_freq = htod32(30); ++ /* slow adapt scan is off by default */ ++ pfn_param.slow_freq = htod32(0); ++ /* RSSI margin of 30 dBm */ ++ pfn_param.rssi_margin = htod16(30); ++ /* Network timeout 60 sec */ ++ pfn_param.lost_network_timeout = htod32(60); ++ /* best n = 2 by default */ ++ pfn_param.bestn = DEFAULT_BESTN; ++ /* mscan m=0 by default, so not record best networks by default */ ++ pfn_param.mscan = DEFAULT_MSCAN; ++ /* default repeat = 10 */ ++ pfn_param.repeat = DEFAULT_REPEAT; ++ /* by default, maximum scan interval = 2^2 ++ * scan_freq when adaptive scan is turned on ++ */ ++ pfn_param.exp = DEFAULT_EXP; ++ if (mode == DHD_PNO_BATCH_MODE) { ++ /* In case of BATCH SCAN */ ++ if (pno_params->params_batch.bestn) ++ pfn_param.bestn = pno_params->params_batch.bestn; ++ if (pno_params->params_batch.scan_fr) ++ pfn_param.scan_freq = htod32(pno_params->params_batch.scan_fr); ++ if (pno_params->params_batch.mscan) ++ pfn_param.mscan = pno_params->params_batch.mscan; ++ /* enable broadcast scan */ ++ pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT); ++ } else if (mode == DHD_PNO_HOTLIST_MODE) { ++ /* In case of HOTLIST SCAN */ ++ if (pno_params->params_hotlist.scan_fr) ++ pfn_param.scan_freq = htod32(pno_params->params_hotlist.scan_fr); ++ pfn_param.bestn = 0; ++ pfn_param.repeat = 0; ++ /* enable broadcast scan */ ++ pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT); ++ } ++ if (combined_scan) { ++ /* Disable Adaptive Scan */ ++ pfn_param.flags &= ~(htod16(ENABLE << ENABLE_ADAPTSCAN_BIT)); ++ pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT); ++ pfn_param.repeat = 0; ++ pfn_param.exp = 0; ++ if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { ++ /* In case of Legacy PNO + BATCH SCAN */ ++ _params = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]); ++ if (_params->params_batch.bestn) ++ pfn_param.bestn = _params->params_batch.bestn; ++ if (_params->params_batch.scan_fr) ++ pfn_param.scan_freq = htod32(_params->params_batch.scan_fr); ++ if (_params->params_batch.mscan) ++ pfn_param.mscan = _params->params_batch.mscan; ++ } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { ++ /* In case of Legacy PNO + HOTLIST SCAN */ ++ _params = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]); ++ if (_params->params_hotlist.scan_fr) ++ pfn_param.scan_freq = htod32(_params->params_hotlist.scan_fr); ++ pfn_param.bestn = 0; ++ pfn_param.repeat = 0; ++ } ++ } ++ } ++ if (pfn_param.scan_freq < htod32(PNO_SCAN_MIN_FW_SEC) || ++ pfn_param.scan_freq > htod32(PNO_SCAN_MAX_FW_SEC)) { ++ AP6211_ERR("%s pno freq(%d sec) is not valid \n", ++ __FUNCTION__, PNO_SCAN_MIN_FW_SEC); ++ err = BCME_BADARG; ++ goto exit; ++ } ++ if (mode == DHD_PNO_BATCH_MODE) { ++ int _tmp = pfn_param.bestn; ++ /* set bestn to calculate the max mscan which firmware supports */ ++ err = dhd_iovar(dhd, 0, "pfnmem", (char *)&_tmp, sizeof(_tmp), 1); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to set pfnmscan\n", __FUNCTION__); ++ goto exit; ++ } ++ /* get max mscan which the firmware supports */ ++ err = dhd_iovar(dhd, 0, "pfnmem", (char *)&_tmp, sizeof(_tmp), 0); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to get pfnmscan\n", __FUNCTION__); ++ goto exit; ++ } ++ AP6211_DEBUG(" returned mscan : %d, set bestn : %d\n", _tmp, pfn_param.bestn); ++ pfn_param.mscan = MIN(pfn_param.mscan, _tmp); ++ } ++ err = dhd_iovar(dhd, 0, "pfn_set", (char *)&pfn_param, sizeof(pfn_param), 1); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to execute pfn_set\n", __FUNCTION__); ++ goto exit; ++ } ++ /* need to return mscan if this is for batch scan instead of err */ ++ err = (mode == DHD_PNO_BATCH_MODE)? pfn_param.mscan : err; ++exit: ++ return err; ++} ++static int ++_dhd_pno_add_ssid(dhd_pub_t *dhd, wlc_ssid_t* ssids_list, int nssid) ++{ ++ int err = BCME_OK; ++ int i = 0; ++ wl_pfn_t pfn_element; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ if (nssid) { ++ NULL_CHECK(ssids_list, "ssid list is NULL", err); ++ } ++ memset(&pfn_element, 0, sizeof(pfn_element)); ++ { ++ int j; ++ for (j = 0; j < nssid; j++) { ++ AP6211_DEBUG("%d: scan for %s size = %d\n", j, ++ ssids_list[j].SSID, ssids_list[j].SSID_len); ++ } ++ } ++ /* Check for broadcast ssid */ ++ for (i = 0; i < nssid; i++) { ++ if (!ssids_list[i].SSID_len) { ++ AP6211_ERR("%d: Broadcast SSID is ilegal for PNO setting\n", i); ++ err = BCME_ERROR; ++ goto exit; ++ } ++ } ++ /* set all pfn ssid */ ++ for (i = 0; i < nssid; i++) { ++ pfn_element.infra = htod32(DOT11_BSSTYPE_INFRASTRUCTURE); ++ pfn_element.auth = (DOT11_OPEN_SYSTEM); ++ pfn_element.wpa_auth = htod32(WPA_AUTH_PFN_ANY); ++ pfn_element.wsec = htod32(0); ++ pfn_element.infra = htod32(1); ++ pfn_element.flags = htod32(ENABLE << WL_PFN_HIDDEN_BIT); ++ memcpy((char *)pfn_element.ssid.SSID, ssids_list[i].SSID, ++ ssids_list[i].SSID_len); ++ pfn_element.ssid.SSID_len = ssids_list[i].SSID_len; ++ err = dhd_iovar(dhd, 0, "pfn_add", (char *)&pfn_element, ++ sizeof(pfn_element), 1); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to execute pfn_add\n", __FUNCTION__); ++ goto exit; ++ } ++ } ++exit: ++ return err; ++} ++/* qsort compare function */ ++static int ++_dhd_pno_cmpfunc(const void *a, const void *b) ++{ ++ return (*(uint16*)a - *(uint16*)b); ++} ++static int ++_dhd_pno_chan_merge(uint16 *d_chan_list, int *nchan, ++ uint16 *chan_list1, int nchan1, uint16 *chan_list2, int nchan2) ++{ ++ int err = BCME_OK; ++ int i = 0, j = 0, k = 0; ++ uint16 tmp; ++ NULL_CHECK(d_chan_list, "d_chan_list is NULL", err); ++ NULL_CHECK(nchan, "nchan is NULL", err); ++ NULL_CHECK(chan_list1, "chan_list1 is NULL", err); ++ NULL_CHECK(chan_list2, "chan_list2 is NULL", err); ++ /* chan_list1 and chan_list2 should be sorted at first */ ++ while (i < nchan1 && j < nchan2) { ++ tmp = chan_list1[i] < chan_list2[j]? ++ chan_list1[i++] : chan_list2[j++]; ++ for (; i < nchan1 && chan_list1[i] == tmp; i++); ++ for (; j < nchan2 && chan_list2[j] == tmp; j++); ++ d_chan_list[k++] = tmp; ++ } ++ ++ while (i < nchan1) { ++ tmp = chan_list1[i++]; ++ for (; i < nchan1 && chan_list1[i] == tmp; i++); ++ d_chan_list[k++] = tmp; ++ } ++ ++ while (j < nchan2) { ++ tmp = chan_list2[j++]; ++ for (; j < nchan2 && chan_list2[j] == tmp; j++); ++ d_chan_list[k++] = tmp; ++ ++ } ++ *nchan = k; ++ return err; ++} ++static int ++_dhd_pno_get_channels(dhd_pub_t *dhd, uint16 *d_chan_list, ++ int *nchan, uint8 band, bool skip_dfs) ++{ ++ int err = BCME_OK; ++ int i, j; ++ uint32 chan_buf[WL_NUMCHANNELS + 1]; ++ wl_uint32_list_t *list; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ if (*nchan) { ++ NULL_CHECK(d_chan_list, "d_chan_list is NULL", err); ++ } ++ list = (wl_uint32_list_t *) (void *)chan_buf; ++ list->count = htod32(WL_NUMCHANNELS); ++ err = dhd_wl_ioctl_cmd(dhd, WLC_GET_VALID_CHANNELS, chan_buf, sizeof(chan_buf), FALSE, 0); ++ if (err < 0) { ++ AP6211_ERR("failed to get channel list (err: %d)\n", err); ++ goto exit; ++ } ++ for (i = 0, j = 0; i < dtoh32(list->count) && i < *nchan; i++) { ++ if (band == WLC_BAND_2G) { ++ if (dtoh32(list->element[i]) > CHANNEL_2G_MAX) ++ continue; ++ } else if (band == WLC_BAND_5G) { ++ if (dtoh32(list->element[i]) <= CHANNEL_2G_MAX) ++ continue; ++ if (skip_dfs && is_dfs(dtoh32(list->element[i]))) ++ continue; ++ ++ } else { /* All channels */ ++ if (skip_dfs && is_dfs(dtoh32(list->element[i]))) ++ continue; ++ } ++ d_chan_list[j++] = dtoh32(list->element[i]); ++ } ++ *nchan = j; ++exit: ++ return err; ++} ++static int ++_dhd_pno_convert_format(dhd_pub_t *dhd, struct dhd_pno_batch_params *params_batch, ++ char *buf, int nbufsize) ++{ ++ int err = BCME_OK; ++ int bytes_written = 0, nreadsize = 0; ++ int t_delta = 0; ++ int nleftsize = nbufsize; ++ uint8 cnt = 0; ++ char *bp = buf; ++ char eabuf[ETHER_ADDR_STR_LEN]; ++#ifdef PNO_DEBUG ++ char *_base_bp; ++ char msg[150]; ++#endif ++ dhd_pno_bestnet_entry_t *iter, *next; ++ dhd_pno_scan_results_t *siter, *snext; ++ dhd_pno_best_header_t *phead, *pprev; ++ NULL_CHECK(params_batch, "params_batch is NULL", err); ++ if (nbufsize > 0) ++ NULL_CHECK(buf, "buf is NULL", err); ++ /* initialize the buffer */ ++ memset(buf, 0, nbufsize); ++ AP6211_DEBUG("%s enter \n", __FUNCTION__); ++ /* # of scans */ ++ if (!params_batch->get_batch.batch_started) { ++ bp += nreadsize = sprintf(bp, "scancount=%d\n", ++ params_batch->get_batch.expired_tot_scan_cnt); ++ nleftsize -= nreadsize; ++ params_batch->get_batch.batch_started = TRUE; ++ } ++ AP6211_DEBUG("%s scancount %d\n", __FUNCTION__, params_batch->get_batch.expired_tot_scan_cnt); ++ /* preestimate scan count until which scan result this report is going to end */ ++ list_for_each_entry_safe(siter, snext, ++ ¶ms_batch->get_batch.expired_scan_results_list, list) { ++ phead = siter->bestnetheader; ++ while (phead != NULL) { ++ /* if left_size is less than bestheader total size , stop this */ ++ if (nleftsize <= ++ (phead->tot_size + phead->tot_cnt * ENTRY_OVERHEAD)) ++ goto exit; ++ /* increase scan count */ ++ cnt++; ++ /* # best of each scan */ ++ AP6211_DEBUG("\n", cnt - 1, phead->tot_cnt); ++ /* attribute of the scan */ ++ if (phead->reason & PNO_STATUS_ABORT_MASK) { ++ bp += nreadsize = sprintf(bp, "trunc\n"); ++ nleftsize -= nreadsize; ++ } ++ list_for_each_entry_safe(iter, next, ++ &phead->entry_list, list) { ++ t_delta = jiffies_to_msecs(jiffies - iter->recorded_time); ++#ifdef PNO_DEBUG ++ _base_bp = bp; ++ memset(msg, 0, sizeof(msg)); ++#endif ++ /* BSSID info */ ++ bp += nreadsize = sprintf(bp, "bssid=%s\n", ++ bcm_ether_ntoa((const struct ether_addr *)&iter->BSSID, eabuf)); ++ nleftsize -= nreadsize; ++ /* SSID */ ++ bp += nreadsize = sprintf(bp, "ssid=%s\n", iter->SSID); ++ nleftsize -= nreadsize; ++ /* channel */ ++ bp += nreadsize = sprintf(bp, "freq=%d\n", ++ wf_channel2mhz(iter->channel, ++ iter->channel <= CH_MAX_2G_CHANNEL? ++ WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); ++ nleftsize -= nreadsize; ++ /* RSSI */ ++ bp += nreadsize = sprintf(bp, "level=%d\n", iter->RSSI); ++ nleftsize -= nreadsize; ++ /* add the time consumed in Driver to the timestamp of firmware */ ++ iter->timestamp += t_delta; ++ bp += nreadsize = sprintf(bp, "age=%d\n", iter->timestamp); ++ nleftsize -= nreadsize; ++ /* RTT0 */ ++ bp += nreadsize = sprintf(bp, "dist=%d\n", ++ (iter->rtt0 == 0)? -1 : iter->rtt0); ++ nleftsize -= nreadsize; ++ /* RTT1 */ ++ bp += nreadsize = sprintf(bp, "distSd=%d\n", ++ (iter->rtt0 == 0)? -1 : iter->rtt1); ++ nleftsize -= nreadsize; ++ bp += nreadsize = sprintf(bp, "%s", AP_END_MARKER); ++ nleftsize -= nreadsize; ++ list_del(&iter->list); ++ MFREE(dhd->osh, iter, BESTNET_ENTRY_SIZE); ++#ifdef PNO_DEBUG ++ memcpy(msg, _base_bp, bp - _base_bp); ++ AP6211_DEBUG("Entry : \n%s", msg); ++#endif ++ } ++ bp += nreadsize = sprintf(bp, "%s", SCAN_END_MARKER); ++ AP6211_DEBUG("%s", SCAN_END_MARKER); ++ nleftsize -= nreadsize; ++ pprev = phead; ++ /* reset the header */ ++ siter->bestnetheader = phead = phead->next; ++ MFREE(dhd->osh, pprev, BEST_HEADER_SIZE); ++ ++ siter->cnt_header--; ++ } ++ if (phead == NULL) { ++ /* we store all entry in this scan , so it is ok to delete */ ++ list_del(&siter->list); ++ MFREE(dhd->osh, siter, SCAN_RESULTS_SIZE); ++ } ++ } ++exit: ++ if (cnt < params_batch->get_batch.expired_tot_scan_cnt) { ++ AP6211_ERR("Buffer size is small to save all batch entry," ++ " cnt : %d (remained_scan_cnt): %d\n", ++ cnt, params_batch->get_batch.expired_tot_scan_cnt - cnt); ++ } ++ params_batch->get_batch.expired_tot_scan_cnt -= cnt; ++ /* set FALSE only if the link list is empty after returning the data */ ++ if (list_empty(¶ms_batch->get_batch.expired_scan_results_list)) { ++ params_batch->get_batch.batch_started = FALSE; ++ bp += sprintf(bp, "%s", RESULTS_END_MARKER); ++ AP6211_DEBUG("%s", RESULTS_END_MARKER); ++ AP6211_DEBUG("%s : Getting the batching data is complete\n", __FUNCTION__); ++ } ++ /* return used memory in buffer */ ++ bytes_written = (int32)(bp - buf); ++ return bytes_written; ++} ++static int ++_dhd_pno_clear_all_batch_results(dhd_pub_t *dhd, struct list_head *head, bool only_last) ++{ ++ int err = BCME_OK; ++ int removed_scan_cnt = 0; ++ dhd_pno_scan_results_t *siter, *snext; ++ dhd_pno_best_header_t *phead, *pprev; ++ dhd_pno_bestnet_entry_t *iter, *next; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(head, "head is NULL", err); ++ NULL_CHECK(head->next, "head->next is NULL", err); ++ AP6211_DEBUG("%s enter\n", __FUNCTION__); ++ list_for_each_entry_safe(siter, snext, ++ head, list) { ++ if (only_last) { ++ /* in case that we need to delete only last one */ ++ if (!list_is_last(&siter->list, head)) { ++ /* skip if the one is not last */ ++ continue; ++ } ++ } ++ /* delete all data belong if the one is last */ ++ phead = siter->bestnetheader; ++ while (phead != NULL) { ++ removed_scan_cnt++; ++ list_for_each_entry_safe(iter, next, ++ &phead->entry_list, list) { ++ list_del(&iter->list); ++ MFREE(dhd->osh, iter, BESTNET_ENTRY_SIZE); ++ } ++ pprev = phead; ++ phead = phead->next; ++ MFREE(dhd->osh, pprev, BEST_HEADER_SIZE); ++ } ++ if (phead == NULL) { ++ /* it is ok to delete top node */ ++ list_del(&siter->list); ++ MFREE(dhd->osh, siter, SCAN_RESULTS_SIZE); ++ } ++ } ++ return removed_scan_cnt; ++} ++ ++static int ++_dhd_pno_cfg(dhd_pub_t *dhd, uint16 *channel_list, int nchan) ++{ ++ int err = BCME_OK; ++ int i = 0; ++ wl_pfn_cfg_t pfncfg_param; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ if (nchan) { ++ NULL_CHECK(channel_list, "nchan is NULL", err); ++ } ++ AP6211_DEBUG("%s enter : nchan : %d\n", __FUNCTION__, nchan); ++ memset(&pfncfg_param, 0, sizeof(wl_pfn_cfg_t)); ++ /* Setup default values */ ++ pfncfg_param.reporttype = htod32(WL_PFN_REPORT_ALLNET); ++ pfncfg_param.channel_num = htod32(0); ++ ++ for (i = 0; i < nchan && nchan < WL_NUMCHANNELS; i++) ++ pfncfg_param.channel_list[i] = channel_list[i]; ++ ++ pfncfg_param.channel_num = htod32(nchan); ++ err = dhd_iovar(dhd, 0, "pfn_cfg", (char *)&pfncfg_param, sizeof(pfncfg_param), 1); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to execute pfn_cfg\n", __FUNCTION__); ++ goto exit; ++ } ++exit: ++ return err; ++} ++static int ++_dhd_pno_reinitialize_prof(dhd_pub_t *dhd, dhd_pno_params_t *params, dhd_pno_mode_t mode) ++{ ++ int err = BCME_OK; ++ dhd_pno_status_info_t *_pno_state; ++ NULL_CHECK(dhd, "dhd is NULL\n", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL\n", err); ++ AP6211_DEBUG("%s enter\n", __FUNCTION__); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ mutex_lock(&_pno_state->pno_mutex); ++ switch (mode) { ++ case DHD_PNO_LEGACY_MODE: { ++ struct dhd_pno_ssid *iter, *next; ++ if (params->params_legacy.nssid > 0) { ++ list_for_each_entry_safe(iter, next, ++ ¶ms->params_legacy.ssid_list, list) { ++ list_del(&iter->list); ++ kfree(iter); ++ } ++ } ++ params->params_legacy.scan_fr = 0; ++ params->params_legacy.pno_freq_expo_max = 0; ++ params->params_legacy.pno_repeat = 0; ++ params->params_legacy.nchan = 0; ++ memset(params->params_legacy.chan_list, 0, ++ sizeof(params->params_legacy.chan_list)); ++ break; ++ } ++ case DHD_PNO_BATCH_MODE: { ++ params->params_batch.scan_fr = 0; ++ params->params_batch.mscan = 0; ++ params->params_batch.nchan = 0; ++ params->params_batch.rtt = 0; ++ params->params_batch.bestn = 0; ++ params->params_batch.nchan = 0; ++ params->params_batch.band = WLC_BAND_AUTO; ++ memset(params->params_batch.chan_list, 0, ++ sizeof(params->params_batch.chan_list)); ++ params->params_batch.get_batch.batch_started = FALSE; ++ params->params_batch.get_batch.buf = NULL; ++ params->params_batch.get_batch.bufsize = 0; ++ params->params_batch.get_batch.reason = 0; ++ _dhd_pno_clear_all_batch_results(dhd, ++ ¶ms->params_batch.get_batch.scan_results_list, FALSE); ++ _dhd_pno_clear_all_batch_results(dhd, ++ ¶ms->params_batch.get_batch.expired_scan_results_list, FALSE); ++ params->params_batch.get_batch.tot_scan_cnt = 0; ++ params->params_batch.get_batch.expired_tot_scan_cnt = 0; ++ params->params_batch.get_batch.top_node_cnt = 0; ++ INIT_LIST_HEAD(¶ms->params_batch.get_batch.scan_results_list); ++ INIT_LIST_HEAD(¶ms->params_batch.get_batch.expired_scan_results_list); ++ break; ++ } ++ case DHD_PNO_HOTLIST_MODE: { ++ struct dhd_pno_bssid *iter, *next; ++ if (params->params_hotlist.nbssid > 0) { ++ list_for_each_entry_safe(iter, next, ++ ¶ms->params_hotlist.bssid_list, list) { ++ list_del(&iter->list); ++ kfree(iter); ++ } ++ } ++ params->params_hotlist.scan_fr = 0; ++ params->params_hotlist.nbssid = 0; ++ params->params_hotlist.nchan = 0; ++ params->params_batch.band = WLC_BAND_AUTO; ++ memset(params->params_hotlist.chan_list, 0, ++ sizeof(params->params_hotlist.chan_list)); ++ break; ++ } ++ default: ++ AP6211_ERR("%s : unknown mode : %d\n", __FUNCTION__, mode); ++ break; ++ } ++ mutex_unlock(&_pno_state->pno_mutex); ++ return err; ++} ++static int ++_dhd_pno_add_bssid(dhd_pub_t *dhd, wl_pfn_bssid_t *p_pfn_bssid, int nbssid) ++{ ++ int err = BCME_OK; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ if (nbssid) { ++ NULL_CHECK(p_pfn_bssid, "bssid list is NULL", err); ++ } ++ err = dhd_iovar(dhd, 0, "pfn_add_bssid", (char *)&p_pfn_bssid, ++ sizeof(wl_pfn_bssid_t) * nbssid, 1); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to execute pfn_cfg\n", __FUNCTION__); ++ goto exit; ++ } ++exit: ++ return err; ++} ++int ++dhd_pno_stop_for_ssid(dhd_pub_t *dhd) ++{ ++ int err = BCME_OK; ++ uint32 mode = 0; ++ dhd_pno_status_info_t *_pno_state; ++ dhd_pno_params_t *_params; ++ wl_pfn_bssid_t *p_pfn_bssid; ++ NULL_CHECK(dhd, "dev is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ if (!(_pno_state->pno_mode & DHD_PNO_LEGACY_MODE)) { ++ AP6211_ERR("%s : LEGACY PNO MODE is not enabled\n", __FUNCTION__); ++ goto exit; ++ } ++ AP6211_DEBUG("%s enter\n", __FUNCTION__); ++ _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; ++ /* restart Batch mode if the batch mode is on */ ++ if (_pno_state->pno_mode & (DHD_PNO_BATCH_MODE | DHD_PNO_HOTLIST_MODE)) { ++ /* retrieve the batching data from firmware into host */ ++ dhd_pno_get_for_batch(dhd, NULL, 0, PNO_STATUS_DISABLE); ++ /* save current pno_mode before calling dhd_pno_clean */ ++ mode = _pno_state->pno_mode; ++ _dhd_pno_clean(dhd); ++ /* restore previous pno_mode */ ++ _pno_state->pno_mode = mode; ++ if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { ++ _params = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]); ++ /* restart BATCH SCAN */ ++ err = dhd_pno_set_for_batch(dhd, &_params->params_batch); ++ if (err < 0) { ++ _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; ++ AP6211_ERR("%s : failed to restart batch scan(err: %d)\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { ++ /* restart HOTLIST SCAN */ ++ struct dhd_pno_bssid *iter, *next; ++ _params = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]); ++ p_pfn_bssid = kzalloc(sizeof(wl_pfn_bssid_t) * ++ _params->params_hotlist.nbssid, GFP_KERNEL); ++ if (p_pfn_bssid == NULL) { ++ AP6211_ERR("%s : failed to allocate wl_pfn_bssid_t array" ++ " (count: %d)", ++ __FUNCTION__, _params->params_hotlist.nbssid); ++ err = BCME_ERROR; ++ _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; ++ goto exit; ++ } ++ /* convert dhd_pno_bssid to wl_pfn_bssid */ ++ list_for_each_entry_safe(iter, next, ++ &_params->params_hotlist.bssid_list, list) { ++ memcpy(&p_pfn_bssid->macaddr, ++ &iter->macaddr, ETHER_ADDR_LEN); ++ p_pfn_bssid->flags = iter->flags; ++ p_pfn_bssid++; ++ } ++ err = dhd_pno_set_for_hotlist(dhd, p_pfn_bssid, &_params->params_hotlist); ++ if (err < 0) { ++ _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; ++ AP6211_ERR("%s : failed to restart hotlist scan(err: %d)\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ } ++ } else { ++ err = _dhd_pno_clean(dhd); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to call _dhd_pno_clean (err: %d)\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ } ++exit: ++ return err; ++} ++ ++int ++dhd_pno_enable(dhd_pub_t *dhd, int enable) ++{ ++ int err = BCME_OK; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ AP6211_DEBUG("%s enter\n", __FUNCTION__); ++ return (_dhd_pno_enable(dhd, enable)); ++} ++ ++int ++dhd_pno_set_for_ssid(dhd_pub_t *dhd, wlc_ssid_t* ssid_list, int nssid, ++ uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan) ++{ ++ struct dhd_pno_ssid *_pno_ssid; ++ dhd_pno_params_t *_params; ++ dhd_pno_params_t *_params2; ++ dhd_pno_status_info_t *_pno_state; ++ uint16 _chan_list[WL_NUMCHANNELS]; ++ int32 tot_nchan = 0; ++ int err = BCME_OK; ++ int i; ++ int mode = 0; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ ++ if (!dhd_support_sta_mode(dhd)) { ++ err = BCME_BADOPTION; ++ goto exit; ++ } ++ AP6211_DEBUG("%s enter : scan_fr :%d, pno_repeat :%d," ++ "pno_freq_expo_max: %d, nchan :%d\n", __FUNCTION__, ++ scan_fr, pno_repeat, pno_freq_expo_max, nchan); ++ ++ _params = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); ++ if (!(_pno_state->pno_mode & DHD_PNO_LEGACY_MODE)) { ++ _pno_state->pno_mode |= DHD_PNO_LEGACY_MODE; ++ err = _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to reinitialize profile (err %d)\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ } ++ memset(_chan_list, 0, sizeof(_chan_list)); ++ tot_nchan = nchan; ++ if (tot_nchan > 0 && channel_list) { ++ for (i = 0; i < nchan; i++) ++ _params->params_legacy.chan_list[i] = _chan_list[i] = channel_list[i]; ++ } ++ if (_pno_state->pno_mode & (DHD_PNO_BATCH_MODE | DHD_PNO_HOTLIST_MODE)) { ++ AP6211_DEBUG("BATCH SCAN is on progress in firmware\n"); ++ /* retrieve the batching data from firmware into host */ ++ dhd_pno_get_for_batch(dhd, NULL, 0, PNO_STATUS_DISABLE); ++ /* store current pno_mode before disabling pno */ ++ mode = _pno_state->pno_mode; ++ err = _dhd_pno_enable(dhd, PNO_OFF); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to disable PNO\n", __FUNCTION__); ++ goto exit; ++ } ++ /* restore the previous mode */ ++ _pno_state->pno_mode = mode; ++ /* use superset of channel list between two mode */ ++ if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { ++ _params2 = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]); ++ if (_params2->params_batch.nchan > 0 && nchan > 0) { ++ err = _dhd_pno_chan_merge(_chan_list, &tot_nchan, ++ &_params2->params_batch.chan_list[0], ++ _params2->params_batch.nchan, ++ &channel_list[0], nchan); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to merge channel list" ++ " between legacy and batch\n", ++ __FUNCTION__); ++ goto exit; ++ } ++ } else { ++ AP6211_DEBUG("superset channel will use" ++ " all channels in firmware\n"); ++ } ++ } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { ++ _params2 = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]); ++ if (_params2->params_hotlist.nchan > 0 && nchan > 0) { ++ err = _dhd_pno_chan_merge(_chan_list, &tot_nchan, ++ &_params2->params_hotlist.chan_list[0], ++ _params2->params_hotlist.nchan, ++ &channel_list[0], nchan); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to merge channel list" ++ " between legacy and hotlist\n", ++ __FUNCTION__); ++ goto exit; ++ } ++ } ++ } ++ } ++ _params->params_legacy.scan_fr = scan_fr; ++ _params->params_legacy.pno_repeat = pno_repeat; ++ _params->params_legacy.pno_freq_expo_max = pno_freq_expo_max; ++ _params->params_legacy.nchan = nchan; ++ _params->params_legacy.nssid = nssid; ++ INIT_LIST_HEAD(&_params->params_legacy.ssid_list); ++ if ((err = _dhd_pno_set(dhd, _params, DHD_PNO_LEGACY_MODE)) < 0) { ++ AP6211_ERR("failed to set call pno_set (err %d) in firmware\n", err); ++ goto exit; ++ } ++ if ((err = _dhd_pno_add_ssid(dhd, ssid_list, nssid)) < 0) { ++ AP6211_ERR("failed to add ssid list (err %d) in firmware\n", err); ++ goto exit; ++ } ++ for (i = 0; i < nssid; i++) { ++ _pno_ssid = kzalloc(sizeof(struct dhd_pno_ssid), GFP_KERNEL); ++ if (_pno_ssid == NULL) { ++ AP6211_ERR("%s : failed to allocate struct dhd_pno_ssid\n", ++ __FUNCTION__); ++ goto exit; ++ } ++ _pno_ssid->SSID_len = ssid_list[i].SSID_len; ++ memcpy(_pno_ssid->SSID, ssid_list[i].SSID, _pno_ssid->SSID_len); ++ list_add_tail(&_pno_ssid->list, &_params->params_legacy.ssid_list); ++ ++ } ++ if (tot_nchan > 0) { ++ if ((err = _dhd_pno_cfg(dhd, _chan_list, tot_nchan)) < 0) { ++ AP6211_ERR("%s : failed to set call pno_cfg (err %d) in firmware\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ } ++ if (_pno_state->pno_status == DHD_PNO_DISABLED) { ++ if ((err = _dhd_pno_enable(dhd, PNO_ON)) < 0) ++ AP6211_ERR("%s : failed to enable PNO\n", __FUNCTION__); ++ } ++exit: ++ /* clear mode in case of error */ ++ if (err < 0) ++ _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; ++ return err; ++} ++int ++dhd_pno_set_for_batch(dhd_pub_t *dhd, struct dhd_pno_batch_params *batch_params) ++{ ++ int err = BCME_OK; ++ uint16 _chan_list[WL_NUMCHANNELS]; ++ int rem_nchan = 0, tot_nchan = 0; ++ int mode = 0, mscan = 0; ++ int i = 0; ++ dhd_pno_params_t *_params; ++ dhd_pno_params_t *_params2; ++ dhd_pno_status_info_t *_pno_state; ++ wlc_ssid_t *p_ssid_list = NULL; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ NULL_CHECK(batch_params, "batch_params is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ AP6211_DEBUG("%s enter\n", __FUNCTION__); ++ if (!dhd_support_sta_mode(dhd)) { ++ err = BCME_BADOPTION; ++ goto exit; ++ } ++ if (!WLS_SUPPORTED(_pno_state)) { ++ AP6211_ERR("%s : wifi location service is not supported\n", __FUNCTION__); ++ err = BCME_UNSUPPORTED; ++ goto exit; ++ } ++ _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]; ++ if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) { ++ _pno_state->pno_mode |= DHD_PNO_BATCH_MODE; ++ err = _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_BATCH_MODE); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to call _dhd_pno_reinitialize_prof\n", ++ __FUNCTION__); ++ goto exit; ++ } ++ } ++ _params->params_batch.scan_fr = batch_params->scan_fr; ++ _params->params_batch.bestn = batch_params->bestn; ++ _params->params_batch.mscan = (batch_params->mscan)? ++ batch_params->mscan : DEFAULT_BATCH_MSCAN; ++ _params->params_batch.nchan = batch_params->nchan; ++ memcpy(_params->params_batch.chan_list, batch_params->chan_list, ++ sizeof(_params->params_batch.chan_list)); ++ ++ memset(_chan_list, 0, sizeof(_chan_list)); ++ ++ rem_nchan = ARRAYSIZE(batch_params->chan_list) - batch_params->nchan; ++ if (batch_params->band == WLC_BAND_2G || batch_params->band == WLC_BAND_5G) { ++ /* get a valid channel list based on band B or A */ ++ err = _dhd_pno_get_channels(dhd, ++ &_params->params_batch.chan_list[batch_params->nchan], ++ &rem_nchan, batch_params->band, FALSE); ++ if (err < 0) { ++ AP6211_ERR("%s: failed to get valid channel list(band : %d)\n", ++ __FUNCTION__, batch_params->band); ++ goto exit; ++ } ++ /* now we need to update nchan because rem_chan has valid channel count */ ++ _params->params_batch.nchan += rem_nchan; ++ /* need to sort channel list */ ++ sort(_params->params_batch.chan_list, _params->params_batch.nchan, ++ sizeof(_params->params_batch.chan_list[0]), _dhd_pno_cmpfunc, NULL); ++ } ++#ifdef PNO_DEBUG ++{ ++ AP6211_DEBUG("Channel list : "); ++ for (i = 0; i < _params->params_batch.nchan; i++) { ++ AP6211_DEBUG("%d ", _params->params_batch.chan_list[i]); ++ } ++ AP6211_DEBUG("\n"); ++} ++#endif ++ if (_params->params_batch.nchan) { ++ /* copy the channel list into local array */ ++ memcpy(_chan_list, _params->params_batch.chan_list, sizeof(_chan_list)); ++ tot_nchan = _params->params_batch.nchan; ++ } ++ if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { ++ struct dhd_pno_ssid *iter, *next; ++ AP6211_DEBUG("PNO SSID is on progress in firmware\n"); ++ /* store current pno_mode before disabling pno */ ++ mode = _pno_state->pno_mode; ++ err = _dhd_pno_enable(dhd, PNO_OFF); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to disable PNO\n", __FUNCTION__); ++ goto exit; ++ } ++ /* restore the previous mode */ ++ _pno_state->pno_mode = mode; ++ /* Use the superset for channelist between two mode */ ++ _params2 = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); ++ if (_params2->params_legacy.nchan > 0 && _params->params_batch.nchan > 0) { ++ err = _dhd_pno_chan_merge(_chan_list, &tot_nchan, ++ &_params2->params_legacy.chan_list[0], ++ _params2->params_legacy.nchan, ++ &_params->params_batch.chan_list[0], _params->params_batch.nchan); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to merge channel list" ++ " between legacy and batch\n", ++ __FUNCTION__); ++ goto exit; ++ } ++ } else { ++ AP6211_DEBUG("superset channel will use all channels in firmware\n"); ++ } ++ p_ssid_list = kzalloc(sizeof(wlc_ssid_t) * ++ _params2->params_legacy.nssid, GFP_KERNEL); ++ if (p_ssid_list == NULL) { ++ AP6211_ERR("%s : failed to allocate wlc_ssid_t array (count: %d)", ++ __FUNCTION__, _params2->params_legacy.nssid); ++ err = BCME_ERROR; ++ _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; ++ goto exit; ++ } ++ i = 0; ++ /* convert dhd_pno_ssid to dhd_pno_ssid */ ++ list_for_each_entry_safe(iter, next, &_params2->params_legacy.ssid_list, list) { ++ p_ssid_list[i].SSID_len = iter->SSID_len; ++ memcpy(p_ssid_list->SSID, iter->SSID, p_ssid_list[i].SSID_len); ++ i++; ++ } ++ if ((err = _dhd_pno_add_ssid(dhd, p_ssid_list, ++ _params2->params_legacy.nssid)) < 0) { ++ AP6211_ERR("failed to add ssid list (err %d) in firmware\n", err); ++ goto exit; ++ } ++ } ++ if ((err = _dhd_pno_set(dhd, _params, DHD_PNO_BATCH_MODE)) < 0) { ++ AP6211_ERR("%s : failed to set call pno_set (err %d) in firmware\n", ++ __FUNCTION__, err); ++ goto exit; ++ } else { ++ /* we need to return mscan */ ++ mscan = err; ++ } ++ if (tot_nchan > 0) { ++ if ((err = _dhd_pno_cfg(dhd, _chan_list, tot_nchan)) < 0) { ++ AP6211_ERR("%s : failed to set call pno_cfg (err %d) in firmware\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ } ++ if (_pno_state->pno_status == DHD_PNO_DISABLED) { ++ if ((err = _dhd_pno_enable(dhd, PNO_ON)) < 0) ++ AP6211_ERR("%s : failed to enable PNO\n", __FUNCTION__); ++ } ++exit: ++ /* clear mode in case of error */ ++ if (err < 0) ++ _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; ++ else { ++ /* return #max scan firmware can do */ ++ err = mscan; ++ } ++ if (p_ssid_list) ++ kfree(p_ssid_list); ++ return err; ++} ++ ++static int ++_dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason) ++{ ++ int err = BCME_OK; ++ int i, j; ++ uint32 timestamp = 0; ++ dhd_pno_params_t *_params = NULL; ++ dhd_pno_status_info_t *_pno_state = NULL; ++ wl_pfn_lscanresults_t *plbestnet = NULL; ++ wl_pfn_lnet_info_t *plnetinfo; ++ dhd_pno_bestnet_entry_t *pbestnet_entry; ++ dhd_pno_best_header_t *pbestnetheader = NULL; ++ dhd_pno_scan_results_t *pscan_results = NULL, *siter, *snext; ++ bool allocate_header = FALSE; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ if (!dhd_support_sta_mode(dhd)) { ++ err = BCME_BADOPTION; ++ goto exit; ++ } ++ AP6211_DEBUG("%s enter\n", __FUNCTION__); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ ++ if (!WLS_SUPPORTED(_pno_state)) { ++ AP6211_ERR("%s : wifi location service is not supported\n", __FUNCTION__); ++ err = BCME_UNSUPPORTED; ++ goto exit; ++ } ++ if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) { ++ AP6211_ERR("%s: Batching SCAN mode is not enabled\n", __FUNCTION__); ++ goto exit; ++ } ++ mutex_lock(&_pno_state->pno_mutex); ++ _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]; ++ if (buf && bufsize) { ++ if (!list_empty(&_params->params_batch.get_batch.expired_scan_results_list)) { ++ /* need to check whether we have cashed data or not */ ++ AP6211_DEBUG("%s: have cashed batching data in Driver\n", ++ __FUNCTION__); ++ /* convert to results format */ ++ goto convert_format; ++ } else { ++ /* this is a first try to get batching results */ ++ if (!list_empty(&_params->params_batch.get_batch.scan_results_list)) { ++ /* move the scan_results_list to expired_scan_results_lists */ ++ list_for_each_entry_safe(siter, snext, ++ &_params->params_batch.get_batch.scan_results_list, list) { ++ list_move_tail(&siter->list, ++ &_params->params_batch.get_batch.expired_scan_results_list); ++ } ++ _params->params_batch.get_batch.top_node_cnt = 0; ++ _params->params_batch.get_batch.expired_tot_scan_cnt = ++ _params->params_batch.get_batch.tot_scan_cnt; ++ _params->params_batch.get_batch.tot_scan_cnt = 0; ++ goto convert_format; ++ } ++ } ++ } ++ /* create dhd_pno_scan_results_t whenever we got event WLC_E_PFN_BEST_BATCHING */ ++ pscan_results = (dhd_pno_scan_results_t *)MALLOC(dhd->osh, SCAN_RESULTS_SIZE); ++ if (pscan_results == NULL) { ++ err = BCME_NOMEM; ++ AP6211_ERR("failed to allocate dhd_pno_scan_results_t\n"); ++ goto exit; ++ } ++ pscan_results->bestnetheader = NULL; ++ pscan_results->cnt_header = 0; ++ /* add the element into list unless total node cnt is less than MAX_NODE_ CNT */ ++ if (_params->params_batch.get_batch.top_node_cnt < MAX_NODE_CNT) { ++ list_add(&pscan_results->list, &_params->params_batch.get_batch.scan_results_list); ++ _params->params_batch.get_batch.top_node_cnt++; ++ } else { ++ int _removed_scan_cnt; ++ /* remove oldest one and add new one */ ++ AP6211_DEBUG("%s : Remove oldest node and add new one\n", __FUNCTION__); ++ _removed_scan_cnt = _dhd_pno_clear_all_batch_results(dhd, ++ &_params->params_batch.get_batch.scan_results_list, TRUE); ++ _params->params_batch.get_batch.tot_scan_cnt -= _removed_scan_cnt; ++ list_add(&pscan_results->list, &_params->params_batch.get_batch.scan_results_list); ++ ++ } ++ plbestnet = (wl_pfn_lscanresults_t *)MALLOC(dhd->osh, PNO_BESTNET_LEN); ++ NULL_CHECK(plbestnet, "failed to allocate buffer for bestnet", err); ++ AP6211_DEBUG("%s enter\n", __FUNCTION__); ++ memset(plbestnet, 0, PNO_BESTNET_LEN); ++ while (plbestnet->status != PFN_COMPLETE) { ++ memset(plbestnet, 0, PNO_BESTNET_LEN); ++ err = dhd_iovar(dhd, 0, "pfnlbest", (char *)plbestnet, PNO_BESTNET_LEN, 0); ++ if (err < 0) { ++ if (err == BCME_EPERM) { ++ AP6211_ERR("we cannot get the batching data " ++ "during scanning in firmware, try again\n,"); ++ msleep(500); ++ continue; ++ } else { ++ AP6211_ERR("%s : failed to execute pfnlbest (err :%d)\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ } ++ AP6211_DEBUG("ver %d, status : %d, count %d\n", plbestnet->version, ++ plbestnet->status, plbestnet->count); ++ if (plbestnet->version != PFN_SCANRESULT_VERSION) { ++ err = BCME_VERSION; ++ AP6211_ERR("bestnet version(%d) is mismatch with Driver version(%d)\n", ++ plbestnet->version, PFN_SCANRESULT_VERSION); ++ goto exit; ++ } ++ plnetinfo = plbestnet->netinfo; ++ for (i = 0; i < plbestnet->count; i++) { ++ pbestnet_entry = (dhd_pno_bestnet_entry_t *) ++ MALLOC(dhd->osh, BESTNET_ENTRY_SIZE); ++ if (pbestnet_entry == NULL) { ++ err = BCME_NOMEM; ++ AP6211_ERR("failed to allocate dhd_pno_bestnet_entry\n"); ++ goto exit; ++ } ++ pbestnet_entry->recorded_time = jiffies; /* record the current time */ ++ /* create header for the first entry */ ++ allocate_header = (i == 0)? TRUE : FALSE; ++ /* check whether the new generation is started or not */ ++ if (timestamp && (TIME_DIFF(timestamp, plnetinfo->timestamp) ++ > TIME_MIN_DIFF)) ++ allocate_header = TRUE; ++ timestamp = plnetinfo->timestamp; ++ if (allocate_header) { ++ pbestnetheader = (dhd_pno_best_header_t *) ++ MALLOC(dhd->osh, BEST_HEADER_SIZE); ++ if (pbestnetheader == NULL) { ++ err = BCME_NOMEM; ++ if (pbestnet_entry) ++ MFREE(dhd->osh, pbestnet_entry, ++ BESTNET_ENTRY_SIZE); ++ AP6211_ERR("failed to allocate dhd_pno_bestnet_entry\n"); ++ goto exit; ++ } ++ /* increase total cnt of bestnet header */ ++ pscan_results->cnt_header++; ++ /* need to record the reason to call dhd_pno_get_for_bach */ ++ if (reason) ++ pbestnetheader->reason = (ENABLE << reason); ++ memset(pbestnetheader, 0, BEST_HEADER_SIZE); ++ /* initialize the head of linked list */ ++ INIT_LIST_HEAD(&(pbestnetheader->entry_list)); ++ /* link the pbestnet heaer into existed list */ ++ if (pscan_results->bestnetheader == NULL) ++ /* In case of header */ ++ pscan_results->bestnetheader = pbestnetheader; ++ else { ++ dhd_pno_best_header_t *head = pscan_results->bestnetheader; ++ pscan_results->bestnetheader = pbestnetheader; ++ pbestnetheader->next = head; ++ } ++ } ++ /* fills the best network info */ ++ pbestnet_entry->channel = plnetinfo->pfnsubnet.channel; ++ pbestnet_entry->RSSI = plnetinfo->RSSI; ++ if (plnetinfo->flags & PFN_PARTIAL_SCAN_MASK) { ++ /* if RSSI is positive value, we assume that ++ * this scan is aborted by other scan ++ */ ++ AP6211_DEBUG("This scan is aborted\n"); ++ pbestnetheader->reason = (ENABLE << PNO_STATUS_ABORT); ++ } ++ pbestnet_entry->rtt0 = plnetinfo->rtt0; ++ pbestnet_entry->rtt1 = plnetinfo->rtt1; ++ pbestnet_entry->timestamp = plnetinfo->timestamp; ++ pbestnet_entry->SSID_len = plnetinfo->pfnsubnet.SSID_len; ++ memcpy(pbestnet_entry->SSID, plnetinfo->pfnsubnet.SSID, ++ pbestnet_entry->SSID_len); ++ memcpy(&pbestnet_entry->BSSID, &plnetinfo->pfnsubnet.BSSID, ETHER_ADDR_LEN); ++ /* add the element into list */ ++ list_add_tail(&pbestnet_entry->list, &pbestnetheader->entry_list); ++ /* increase best entry count */ ++ pbestnetheader->tot_cnt++; ++ pbestnetheader->tot_size += BESTNET_ENTRY_SIZE; ++ AP6211_DEBUG("Header %d\n", pscan_results->cnt_header - 1); ++ AP6211_DEBUG("\tSSID : "); ++ for (j = 0; j < plnetinfo->pfnsubnet.SSID_len; j++) ++ AP6211_DEBUG("%c", plnetinfo->pfnsubnet.SSID[j]); ++ AP6211_DEBUG("\n"); ++ AP6211_DEBUG("\tBSSID: %02x:%02x:%02x:%02x:%02x:%02x\n", ++ plnetinfo->pfnsubnet.BSSID.octet[0], ++ plnetinfo->pfnsubnet.BSSID.octet[1], ++ plnetinfo->pfnsubnet.BSSID.octet[2], ++ plnetinfo->pfnsubnet.BSSID.octet[3], ++ plnetinfo->pfnsubnet.BSSID.octet[4], ++ plnetinfo->pfnsubnet.BSSID.octet[5]); ++ AP6211_DEBUG("\tchannel: %d, RSSI: %d, timestamp: %d ms\n", ++ plnetinfo->pfnsubnet.channel, ++ plnetinfo->RSSI, plnetinfo->timestamp); ++ AP6211_DEBUG("\tRTT0 : %d, RTT1: %d\n", plnetinfo->rtt0, plnetinfo->rtt1); ++ plnetinfo++; ++ } ++ } ++ /* increase total scan count using current scan count */ ++ _params->params_batch.get_batch.tot_scan_cnt += pscan_results->cnt_header; ++ ++ if (buf && bufsize) { ++ /* This is a first try to get batching results */ ++ if (!list_empty(&_params->params_batch.get_batch.scan_results_list)) { ++ /* move the scan_results_list to expired_scan_results_lists */ ++ list_for_each_entry_safe(siter, snext, ++ &_params->params_batch.get_batch.scan_results_list, list) { ++ list_move_tail(&siter->list, ++ &_params->params_batch.get_batch.expired_scan_results_list); ++ } ++ /* reset gloval values after moving to expired list */ ++ _params->params_batch.get_batch.top_node_cnt = 0; ++ _params->params_batch.get_batch.expired_tot_scan_cnt = ++ _params->params_batch.get_batch.tot_scan_cnt; ++ _params->params_batch.get_batch.tot_scan_cnt = 0; ++ } ++convert_format: ++ err = _dhd_pno_convert_format(dhd, &_params->params_batch, buf, bufsize); ++ if (err < 0) { ++ AP6211_ERR("failed to convert the data into upper layer format\n"); ++ goto exit; ++ } ++ } ++exit: ++ if (plbestnet) ++ MFREE(dhd->osh, plbestnet, PNO_BESTNET_LEN); ++ _params->params_batch.get_batch.buf = NULL; ++ _params->params_batch.get_batch.bufsize = 0; ++ mutex_unlock(&_pno_state->pno_mutex); ++ complete(&_pno_state->get_batch_done); ++ return err; ++} ++static void ++_dhd_pno_get_batch_handler(struct work_struct *work) ++{ ++ dhd_pno_status_info_t *_pno_state; ++ dhd_pub_t *dhd; ++ struct dhd_pno_batch_params *params_batch; ++ AP6211_DEBUG("%s enter\n", __FUNCTION__); ++ _pno_state = container_of(work, struct dhd_pno_status_info, work); ++ dhd = _pno_state->dhd; ++ if (dhd == NULL) { ++ AP6211_ERR("%s : dhd is NULL\n", __FUNCTION__); ++ return; ++ } ++ params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch; ++ _dhd_pno_get_for_batch(dhd, params_batch->get_batch.buf, ++ params_batch->get_batch.bufsize, params_batch->get_batch.reason); ++ ++} ++ ++int ++dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason) ++{ ++ int err = BCME_OK; ++ dhd_pno_status_info_t *_pno_state; ++ struct dhd_pno_batch_params *params_batch; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ if (!dhd_support_sta_mode(dhd)) { ++ err = BCME_BADOPTION; ++ goto exit; ++ } ++ AP6211_DEBUG("%s enter\n", __FUNCTION__); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ ++ if (!WLS_SUPPORTED(_pno_state)) { ++ AP6211_ERR("%s : wifi location service is not supported\n", __FUNCTION__); ++ err = BCME_UNSUPPORTED; ++ goto exit; ++ } ++ params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch; ++ if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) { ++ AP6211_ERR("%s: Batching SCAN mode is not enabled\n", __FUNCTION__); ++ goto exit; ++ } ++ params_batch->get_batch.buf = buf; ++ params_batch->get_batch.bufsize = bufsize; ++ params_batch->get_batch.reason = reason; ++ schedule_work(&_pno_state->work); ++ wait_for_completion(&_pno_state->get_batch_done); ++exit: ++ return err; ++} ++ ++int ++dhd_pno_stop_for_batch(dhd_pub_t *dhd) ++{ ++ int err = BCME_OK; ++ int mode = 0; ++ int i = 0; ++ dhd_pno_status_info_t *_pno_state; ++ dhd_pno_params_t *_params; ++ wl_pfn_bssid_t *p_pfn_bssid; ++ wlc_ssid_t *p_ssid_list = NULL; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ AP6211_DEBUG("%s enter\n", __FUNCTION__); ++ if (!dhd_support_sta_mode(dhd)) { ++ err = BCME_BADOPTION; ++ goto exit; ++ } ++ if (!WLS_SUPPORTED(_pno_state)) { ++ AP6211_ERR("%s : wifi location service is not supported\n", ++ __FUNCTION__); ++ err = BCME_UNSUPPORTED; ++ goto exit; ++ } ++ if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) { ++ AP6211_ERR("%s : PNO BATCH MODE is not enabled\n", __FUNCTION__); ++ goto exit; ++ } ++ _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; ++ if (_pno_state->pno_mode & (DHD_PNO_LEGACY_MODE | DHD_PNO_HOTLIST_MODE)) { ++ mode = _pno_state->pno_mode; ++ _dhd_pno_clean(dhd); ++ _pno_state->pno_mode = mode; ++ /* restart Legacy PNO if the Legacy PNO is on */ ++ if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { ++ struct dhd_pno_legacy_params *_params_legacy; ++ struct dhd_pno_ssid *iter, *next; ++ _params_legacy = ++ &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy); ++ p_ssid_list = kzalloc(sizeof(wlc_ssid_t) * ++ _params_legacy->nssid, GFP_KERNEL); ++ if (p_ssid_list == NULL) { ++ AP6211_ERR("%s : failed to allocate wlc_ssid_t array (count: %d)", ++ __FUNCTION__, _params_legacy->nssid); ++ err = BCME_ERROR; ++ _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; ++ goto exit; ++ } ++ i = 0; ++ /* convert dhd_pno_ssid to dhd_pno_ssid */ ++ list_for_each_entry_safe(iter, next, &_params_legacy->ssid_list, list) { ++ p_ssid_list[i].SSID_len = iter->SSID_len; ++ memcpy(p_ssid_list[i].SSID, iter->SSID, p_ssid_list[i].SSID_len); ++ i++; ++ } ++ err = dhd_pno_set_for_ssid(dhd, p_ssid_list, _params_legacy->nssid, ++ _params_legacy->scan_fr, _params_legacy->pno_repeat, ++ _params_legacy->pno_freq_expo_max, _params_legacy->chan_list, ++ _params_legacy->nchan); ++ if (err < 0) { ++ _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; ++ AP6211_ERR("%s : failed to restart legacy PNO scan(err: %d)\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { ++ struct dhd_pno_bssid *iter, *next; ++ _params = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]); ++ p_pfn_bssid = kzalloc(sizeof(wl_pfn_bssid_t) * ++ _params->params_hotlist.nbssid, GFP_KERNEL); ++ if (p_pfn_bssid == NULL) { ++ AP6211_ERR("%s : failed to allocate wl_pfn_bssid_t array" ++ " (count: %d)", ++ __FUNCTION__, _params->params_hotlist.nbssid); ++ err = BCME_ERROR; ++ _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; ++ goto exit; ++ } ++ i = 0; ++ /* convert dhd_pno_bssid to wl_pfn_bssid */ ++ list_for_each_entry_safe(iter, next, ++ &_params->params_hotlist.bssid_list, list) { ++ memcpy(&p_pfn_bssid[i].macaddr, &iter->macaddr, ETHER_ADDR_LEN); ++ p_pfn_bssid[i].flags = iter->flags; ++ i++; ++ } ++ err = dhd_pno_set_for_hotlist(dhd, p_pfn_bssid, &_params->params_hotlist); ++ if (err < 0) { ++ _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; ++ AP6211_ERR("%s : failed to restart hotlist scan(err: %d)\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ } ++ } else { ++ err = _dhd_pno_clean(dhd); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to call _dhd_pno_clean (err: %d)\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ } ++exit: ++ _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]; ++ _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_BATCH_MODE); ++ if (p_ssid_list) ++ kfree(p_ssid_list); ++ return err; ++} ++ ++int ++dhd_pno_set_for_hotlist(dhd_pub_t *dhd, wl_pfn_bssid_t *p_pfn_bssid, ++ struct dhd_pno_hotlist_params *hotlist_params) ++{ ++ int err = BCME_OK; ++ int i; ++ uint16 _chan_list[WL_NUMCHANNELS]; ++ int rem_nchan = 0; ++ int tot_nchan = 0; ++ int mode = 0; ++ dhd_pno_params_t *_params; ++ dhd_pno_params_t *_params2; ++ struct dhd_pno_bssid *_pno_bssid; ++ dhd_pno_status_info_t *_pno_state; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ NULL_CHECK(hotlist_params, "hotlist_params is NULL", err); ++ NULL_CHECK(p_pfn_bssid, "p_pfn_bssid is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ AP6211_DEBUG("%s enter\n", __FUNCTION__); ++ ++ if (!dhd_support_sta_mode(dhd)) { ++ err = BCME_BADOPTION; ++ goto exit; ++ } ++ if (!WLS_SUPPORTED(_pno_state)) { ++ AP6211_ERR("%s : wifi location service is not supported\n", __FUNCTION__); ++ err = BCME_UNSUPPORTED; ++ goto exit; ++ } ++ _params = &_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]; ++ if (!(_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE)) { ++ _pno_state->pno_mode |= DHD_PNO_HOTLIST_MODE; ++ err = _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_HOTLIST_MODE); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to call _dhd_pno_reinitialize_prof\n", ++ __FUNCTION__); ++ goto exit; ++ } ++ } ++ _params->params_batch.nchan = hotlist_params->nchan; ++ _params->params_batch.scan_fr = hotlist_params->scan_fr; ++ if (hotlist_params->nchan) ++ memcpy(_params->params_hotlist.chan_list, hotlist_params->chan_list, ++ sizeof(_params->params_hotlist.chan_list)); ++ memset(_chan_list, 0, sizeof(_chan_list)); ++ ++ rem_nchan = ARRAYSIZE(hotlist_params->chan_list) - hotlist_params->nchan; ++ if (hotlist_params->band == WLC_BAND_2G || hotlist_params->band == WLC_BAND_5G) { ++ /* get a valid channel list based on band B or A */ ++ err = _dhd_pno_get_channels(dhd, ++ &_params->params_hotlist.chan_list[hotlist_params->nchan], ++ &rem_nchan, hotlist_params->band, FALSE); ++ if (err < 0) { ++ AP6211_ERR("%s: failed to get valid channel list(band : %d)\n", ++ __FUNCTION__, hotlist_params->band); ++ goto exit; ++ } ++ /* now we need to update nchan because rem_chan has valid channel count */ ++ _params->params_hotlist.nchan += rem_nchan; ++ /* need to sort channel list */ ++ sort(_params->params_hotlist.chan_list, _params->params_hotlist.nchan, ++ sizeof(_params->params_hotlist.chan_list[0]), _dhd_pno_cmpfunc, NULL); ++ } ++#ifdef PNO_DEBUG ++{ ++ int i; ++ AP6211_DEBUG("Channel list : "); ++ for (i = 0; i < _params->params_batch.nchan; i++) { ++ AP6211_DEBUG("%d ", _params->params_batch.chan_list[i]); ++ } ++ AP6211_DEBUG("\n"); ++} ++#endif ++ if (_params->params_hotlist.nchan) { ++ /* copy the channel list into local array */ ++ memcpy(_chan_list, _params->params_hotlist.chan_list, ++ sizeof(_chan_list)); ++ tot_nchan = _params->params_hotlist.nchan; ++ } ++ if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { ++ AP6211_DEBUG("PNO SSID is on progress in firmware\n"); ++ /* store current pno_mode before disabling pno */ ++ mode = _pno_state->pno_mode; ++ err = _dhd_pno_enable(dhd, PNO_OFF); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to disable PNO\n", __FUNCTION__); ++ goto exit; ++ } ++ /* restore the previous mode */ ++ _pno_state->pno_mode = mode; ++ /* Use the superset for channelist between two mode */ ++ _params2 = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); ++ if (_params2->params_legacy.nchan > 0 && ++ _params->params_hotlist.nchan > 0) { ++ err = _dhd_pno_chan_merge(_chan_list, &tot_nchan, ++ &_params2->params_legacy.chan_list[0], ++ _params2->params_legacy.nchan, ++ &_params->params_hotlist.chan_list[0], ++ _params->params_hotlist.nchan); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to merge channel list" ++ "between legacy and hotlist\n", ++ __FUNCTION__); ++ goto exit; ++ } ++ } ++ ++ } ++ ++ INIT_LIST_HEAD(&(_params->params_hotlist.bssid_list)); ++ ++ err = _dhd_pno_add_bssid(dhd, p_pfn_bssid, hotlist_params->nbssid); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to call _dhd_pno_add_bssid(err :%d)\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ if ((err = _dhd_pno_set(dhd, _params, DHD_PNO_HOTLIST_MODE)) < 0) { ++ AP6211_ERR("%s : failed to set call pno_set (err %d) in firmware\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ if (tot_nchan > 0) { ++ if ((err = _dhd_pno_cfg(dhd, _chan_list, tot_nchan)) < 0) { ++ AP6211_ERR("%s : failed to set call pno_cfg (err %d) in firmware\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ } ++ for (i = 0; i < hotlist_params->nbssid; i++) { ++ _pno_bssid = kzalloc(sizeof(struct dhd_pno_bssid), GFP_KERNEL); ++ NULL_CHECK(_pno_bssid, "_pfn_bssid is NULL", err); ++ memcpy(&_pno_bssid->macaddr, &p_pfn_bssid[i].macaddr, ETHER_ADDR_LEN); ++ _pno_bssid->flags = p_pfn_bssid[i].flags; ++ list_add_tail(&_pno_bssid->list, &_params->params_hotlist.bssid_list); ++ } ++ _params->params_hotlist.nbssid = hotlist_params->nbssid; ++ if (_pno_state->pno_status == DHD_PNO_DISABLED) { ++ if ((err = _dhd_pno_enable(dhd, PNO_ON)) < 0) ++ AP6211_ERR("%s : failed to enable PNO\n", __FUNCTION__); ++ } ++exit: ++ /* clear mode in case of error */ ++ if (err < 0) ++ _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; ++ return err; ++} ++ ++int ++dhd_pno_stop_for_hotlist(dhd_pub_t *dhd) ++{ ++ int err = BCME_OK; ++ uint32 mode = 0; ++ dhd_pno_status_info_t *_pno_state; ++ dhd_pno_params_t *_params; ++ wlc_ssid_t *p_ssid_list; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ ++ if (!WLS_SUPPORTED(_pno_state)) { ++ AP6211_ERR("%s : wifi location service is not supported\n", ++ __FUNCTION__); ++ err = BCME_UNSUPPORTED; ++ goto exit; ++ } ++ ++ if (!(_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE)) { ++ AP6211_ERR("%s : Hotlist MODE is not enabled\n", ++ __FUNCTION__); ++ goto exit; ++ } ++ _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; ++ ++ if (_pno_state->pno_mode & (DHD_PNO_LEGACY_MODE | DHD_PNO_BATCH_MODE)) { ++ /* retrieve the batching data from firmware into host */ ++ dhd_pno_get_for_batch(dhd, NULL, 0, PNO_STATUS_DISABLE); ++ /* save current pno_mode before calling dhd_pno_clean */ ++ mode = _pno_state->pno_mode; ++ err = _dhd_pno_clean(dhd); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to call _dhd_pno_clean (err: %d)\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ /* restore previos pno mode */ ++ _pno_state->pno_mode = mode; ++ if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { ++ /* restart Legacy PNO Scan */ ++ struct dhd_pno_legacy_params *_params_legacy; ++ struct dhd_pno_ssid *iter, *next; ++ _params_legacy = ++ &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy); ++ p_ssid_list = ++ kzalloc(sizeof(wlc_ssid_t) * _params_legacy->nssid, GFP_KERNEL); ++ if (p_ssid_list == NULL) { ++ AP6211_ERR("%s : failed to allocate wlc_ssid_t array (count: %d)", ++ __FUNCTION__, _params_legacy->nssid); ++ err = BCME_ERROR; ++ _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; ++ goto exit; ++ } ++ /* convert dhd_pno_ssid to dhd_pno_ssid */ ++ list_for_each_entry_safe(iter, next, &_params_legacy->ssid_list, list) { ++ p_ssid_list->SSID_len = iter->SSID_len; ++ memcpy(p_ssid_list->SSID, iter->SSID, p_ssid_list->SSID_len); ++ p_ssid_list++; ++ } ++ err = dhd_pno_set_for_ssid(dhd, p_ssid_list, _params_legacy->nssid, ++ _params_legacy->scan_fr, _params_legacy->pno_repeat, ++ _params_legacy->pno_freq_expo_max, _params_legacy->chan_list, ++ _params_legacy->nchan); ++ if (err < 0) { ++ _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; ++ AP6211_ERR("%s : failed to restart legacy PNO scan(err: %d)\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ } else if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { ++ /* restart Batching Scan */ ++ _params = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]); ++ /* restart BATCH SCAN */ ++ err = dhd_pno_set_for_batch(dhd, &_params->params_batch); ++ if (err < 0) { ++ _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; ++ AP6211_ERR("%s : failed to restart batch scan(err: %d)\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ } ++ } else { ++ err = _dhd_pno_clean(dhd); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to call _dhd_pno_clean (err: %d)\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ } ++exit: ++ return err; ++} ++ ++int ++dhd_pno_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) ++{ ++ int err = BCME_OK; ++ uint status, event_type, flags, datalen; ++ dhd_pno_status_info_t *_pno_state; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ if (!WLS_SUPPORTED(_pno_state)) { ++ AP6211_ERR("%s : wifi location service is not supported\n", __FUNCTION__); ++ err = BCME_UNSUPPORTED; ++ goto exit; ++ } ++ event_type = ntoh32(event->event_type); ++ flags = ntoh16(event->flags); ++ status = ntoh32(event->status); ++ datalen = ntoh32(event->datalen); ++ AP6211_DEBUG("%s enter : event_type :%d\n", __FUNCTION__, event_type); ++ switch (event_type) { ++ case WLC_E_PFN_BSSID_NET_FOUND: ++ case WLC_E_PFN_BSSID_NET_LOST: ++ /* XXX : how can we inform this to framework ? */ ++ /* TODO : need to implement event logic using generic netlink */ ++ break; ++ case WLC_E_PFN_BEST_BATCHING: ++ { ++ struct dhd_pno_batch_params *params_batch; ++ params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch; ++ AP6211_DEBUG("%s : WLC_E_PFN_BEST_BATCHING\n", __FUNCTION__); ++ params_batch->get_batch.buf = NULL; ++ params_batch->get_batch.bufsize = 0; ++ params_batch->get_batch.reason = PNO_STATUS_EVENT; ++ schedule_work(&_pno_state->work); ++ break; ++ } ++ default: ++ AP6211_ERR("unknown event : %d\n", event_type); ++ } ++exit: ++ return err; ++} ++ ++int dhd_pno_init(dhd_pub_t *dhd) ++{ ++ int err = BCME_OK; ++ dhd_pno_status_info_t *_pno_state; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ AP6211_DEBUG("%s enter\n", __FUNCTION__); ++ UNUSED_PARAMETER(_dhd_pno_suspend); ++ if (dhd->pno_state) ++ goto exit; ++ dhd->pno_state = MALLOC(dhd->osh, sizeof(dhd_pno_status_info_t)); ++ memset(dhd->pno_state, 0, sizeof(dhd_pno_status_info_t)); ++ NULL_CHECK(dhd, "failed to create dhd_pno_state", err); ++ /* need to check whether current firmware support batching and hotlist scan */ ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ _pno_state->wls_supported = TRUE; ++ _pno_state->dhd = dhd; ++ mutex_init(&_pno_state->pno_mutex); ++ INIT_WORK(&_pno_state->work, _dhd_pno_get_batch_handler); ++ init_completion(&_pno_state->get_batch_done); ++ err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, 0); ++ if (err == BCME_UNSUPPORTED) { ++ _pno_state->wls_supported = FALSE; ++ AP6211_DEBUG("Current firmware doesn't support" ++ " Android Location Service\n"); ++ } ++exit: ++ return err; ++} ++int dhd_pno_deinit(dhd_pub_t *dhd) ++{ ++ int err = BCME_OK; ++ dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ AP6211_DEBUG("%s enter\n", __FUNCTION__); ++ cancel_work_sync(&_pno_state->work); ++ if (dhd->pno_state) ++ MFREE(dhd->osh, dhd->pno_state, sizeof(dhd_pno_status_info_t)); ++ dhd->pno_state = NULL; ++ return err; ++} +diff --git a/drivers/net/wireless/ap6211/dhd_pno.h b/drivers/net/wireless/ap6211/dhd_pno.h +new file mode 100755 +index 0000000..1e02db1 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_pno.h +@@ -0,0 +1,249 @@ ++/* ++ * Header file of Broadcom Dongle Host Driver (DHD) ++ * Prefered Network Offload code and Wi-Fi Location Service(WLS) code. ++ * Copyright (C) 1999-2013, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd_pno.h 419969 2013-08-23 18:54:36Z $ ++ */ ++ ++#ifndef __DHD_PNO_H__ ++#define __DHD_PNO_H__ ++ ++#define PNO_TLV_PREFIX 'S' ++#define PNO_TLV_VERSION '1' ++#define PNO_TLV_SUBTYPE_LEGACY_PNO '2' ++#define PNO_TLV_RESERVED '0' ++ ++#define PNO_BATCHING_SET "SET" ++#define PNO_BATCHING_GET "GET" ++#define PNO_BATCHING_STOP "STOP" ++ ++#define PNO_PARAMS_DELIMETER " " ++#define PNO_PARAM_CHANNEL_DELIMETER "," ++#define PNO_PARAM_VALUE_DELLIMETER '=' ++#define PNO_PARAM_SCANFREQ "SCANFREQ" ++#define PNO_PARAM_BESTN "BESTN" ++#define PNO_PARAM_MSCAN "MSCAN" ++#define PNO_PARAM_CHANNEL "CHANNEL" ++#define PNO_PARAM_RTT "RTT" ++ ++#define PNO_TLV_TYPE_SSID_IE 'S' ++#define PNO_TLV_TYPE_TIME 'T' ++#define PNO_TLV_FREQ_REPEAT 'R' ++#define PNO_TLV_FREQ_EXPO_MAX 'M' ++ ++#define MAXNUM_SSID_PER_ADD 16 ++#define MAXNUM_PNO_PARAMS 2 ++#define PNO_TLV_COMMON_LENGTH 1 ++#define DEFAULT_BATCH_MSCAN 16 ++ ++#define RESULTS_END_MARKER "----\n" ++#define SCAN_END_MARKER "####\n" ++#define AP_END_MARKER "====\n" ++ ++enum scan_status { ++ /* SCAN ABORT by other scan */ ++ PNO_STATUS_ABORT, ++ /* RTT is presence or not */ ++ PNO_STATUS_RTT_PRESENCE, ++ /* Disable PNO by Driver */ ++ PNO_STATUS_DISABLE, ++ /* NORMAL BATCHING GET */ ++ PNO_STATUS_NORMAL, ++ /* WLC_E_PFN_BEST_BATCHING */ ++ PNO_STATUS_EVENT, ++ PNO_STATUS_MAX ++}; ++#define PNO_STATUS_ABORT_MASK 0x0001 ++#define PNO_STATUS_RTT_MASK 0x0002 ++#define PNO_STATUS_DISABLE_MASK 0x0004 ++#define PNO_STATUS_OOM_MASK 0x0010 ++ ++enum index_mode { ++ INDEX_OF_LEGACY_PARAMS, ++ INDEX_OF_BATCH_PARAMS, ++ INDEX_OF_HOTLIST_PARAMS, ++ INDEX_MODE_MAX ++}; ++enum dhd_pno_status { ++ DHD_PNO_DISABLED, ++ DHD_PNO_ENABLED, ++ DHD_PNO_SUSPEND ++}; ++typedef struct cmd_tlv { ++ char prefix; ++ char version; ++ char subtype; ++ char reserved; ++} cmd_tlv_t; ++typedef enum dhd_pno_mode { ++ /* Wi-Fi Legacy PNO Mode */ ++ DHD_PNO_NONE_MODE = 0, ++ DHD_PNO_LEGACY_MODE = (1 << (0)), ++ /* Wi-Fi Android BATCH SCAN Mode */ ++ DHD_PNO_BATCH_MODE = (1 << (1)), ++ /* Wi-Fi Android Hotlist SCAN Mode */ ++ DHD_PNO_HOTLIST_MODE = (1 << (2)) ++} dhd_pno_mode_t; ++struct dhd_pno_ssid { ++ uint32 SSID_len; ++ uchar SSID[DOT11_MAX_SSID_LEN]; ++ struct list_head list; ++}; ++struct dhd_pno_bssid { ++ struct ether_addr macaddr; ++ /* Bit4: suppress_lost, Bit3: suppress_found */ ++ uint16 flags; ++ struct list_head list; ++}; ++typedef struct dhd_pno_bestnet_entry { ++ struct ether_addr BSSID; ++ uint8 SSID_len; ++ uint8 SSID[DOT11_MAX_SSID_LEN]; ++ int8 RSSI; ++ uint8 channel; ++ uint32 timestamp; ++ uint16 rtt0; /* distance_cm based on RTT */ ++ uint16 rtt1; /* distance_cm based on sample standard deviation */ ++ unsigned long recorded_time; ++ struct list_head list; ++} dhd_pno_bestnet_entry_t; ++#define BESTNET_ENTRY_SIZE (sizeof(dhd_pno_bestnet_entry_t)) ++ ++typedef struct dhd_pno_bestnet_header { ++ struct dhd_pno_bestnet_header *next; ++ uint8 reason; ++ uint32 tot_cnt; ++ uint32 tot_size; ++ struct list_head entry_list; ++} dhd_pno_best_header_t; ++#define BEST_HEADER_SIZE (sizeof(dhd_pno_best_header_t)) ++ ++typedef struct dhd_pno_scan_results { ++ dhd_pno_best_header_t *bestnetheader; ++ uint8 cnt_header; ++ struct list_head list; ++} dhd_pno_scan_results_t; ++#define SCAN_RESULTS_SIZE (sizeof(dhd_pno_scan_results_t)) ++ ++struct dhd_pno_get_batch_info { ++ /* info related to get batch */ ++ char *buf; ++ bool batch_started; ++ uint32 tot_scan_cnt; ++ uint32 expired_tot_scan_cnt; ++ uint32 top_node_cnt; ++ uint32 bufsize; ++ int reason; ++ struct list_head scan_results_list; ++ struct list_head expired_scan_results_list; ++}; ++struct dhd_pno_legacy_params { ++ uint16 scan_fr; ++ uint16 chan_list[WL_NUMCHANNELS]; ++ uint16 nchan; ++ int pno_repeat; ++ int pno_freq_expo_max; ++ int nssid; ++ struct list_head ssid_list; ++}; ++struct dhd_pno_batch_params { ++ int32 scan_fr; ++ uint8 bestn; ++ uint8 mscan; ++ uint8 band; ++ uint16 chan_list[WL_NUMCHANNELS]; ++ uint16 nchan; ++ uint16 rtt; ++ struct dhd_pno_get_batch_info get_batch; ++}; ++struct dhd_pno_hotlist_params { ++ uint8 band; ++ int32 scan_fr; ++ uint16 chan_list[WL_NUMCHANNELS]; ++ uint16 nchan; ++ uint16 nbssid; ++ struct list_head bssid_list; ++}; ++typedef union dhd_pno_params { ++ struct dhd_pno_legacy_params params_legacy; ++ struct dhd_pno_batch_params params_batch; ++ struct dhd_pno_hotlist_params params_hotlist; ++} dhd_pno_params_t; ++typedef struct dhd_pno_status_info { ++ dhd_pub_t *dhd; ++ struct work_struct work; ++ struct mutex pno_mutex; ++ struct completion get_batch_done; ++ bool wls_supported; /* wifi location service supported or not */ ++ enum dhd_pno_status pno_status; ++ enum dhd_pno_mode pno_mode; ++ dhd_pno_params_t pno_params_arr[INDEX_MODE_MAX]; ++ struct list_head head_list; ++} dhd_pno_status_info_t; ++ ++/* wrapper functions */ ++extern int ++dhd_dev_pno_enable(struct net_device *dev, int enable); ++ ++extern int ++dhd_dev_pno_stop_for_ssid(struct net_device *dev); ++ ++extern int ++dhd_dev_pno_set_for_ssid(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid, ++ uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan); ++ ++extern int ++dhd_dev_pno_set_for_batch(struct net_device *dev, ++ struct dhd_pno_batch_params *batch_params); ++ ++extern int ++dhd_dev_pno_get_for_batch(struct net_device *dev, char *buf, int bufsize); ++ ++extern int ++dhd_dev_pno_stop_for_batch(struct net_device *dev); ++ ++extern int ++dhd_dev_pno_set_for_hotlist(struct net_device *dev, wl_pfn_bssid_t *p_pfn_bssid, ++ struct dhd_pno_hotlist_params *hotlist_params); ++ ++/* dhd pno fuctions */ ++extern int dhd_pno_stop_for_ssid(dhd_pub_t *dhd); ++extern int dhd_pno_enable(dhd_pub_t *dhd, int enable); ++extern int dhd_pno_set_for_ssid(dhd_pub_t *dhd, wlc_ssid_t* ssid_list, int nssid, ++ uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan); ++ ++extern int dhd_pno_set_for_batch(dhd_pub_t *dhd, struct dhd_pno_batch_params *batch_params); ++ ++extern int dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason); ++ ++ ++extern int dhd_pno_stop_for_batch(dhd_pub_t *dhd); ++ ++extern int dhd_pno_set_for_hotlist(dhd_pub_t *dhd, wl_pfn_bssid_t *p_pfn_bssid, ++ struct dhd_pno_hotlist_params *hotlist_params); ++ ++extern int dhd_pno_stop_for_hotlist(dhd_pub_t *dhd); ++ ++extern int dhd_pno_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data); ++extern int dhd_pno_init(dhd_pub_t *dhd); ++extern int dhd_pno_deinit(dhd_pub_t *dhd); ++#endif /* __DHD_PNO_H__ */ +diff --git a/drivers/net/wireless/ap6211/dhd_proto.h b/drivers/net/wireless/ap6211/dhd_proto.h +new file mode 100755 +index 0000000..09d5468 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_proto.h +@@ -0,0 +1,113 @@ ++/* ++ * Header file describing the internal (inter-module) DHD interfaces. ++ * ++ * Provides type definitions and function prototypes used to link the ++ * DHD OS, bus, and protocol modules. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd_proto.h 343390 2012-07-06 22:34:19Z $ ++ */ ++ ++#ifndef _dhd_proto_h_ ++#define _dhd_proto_h_ ++ ++#include ++#include ++ ++#ifndef IOCTL_RESP_TIMEOUT ++#define IOCTL_RESP_TIMEOUT 2000 /* In milli second default value for Production FW */ ++#endif /* IOCTL_RESP_TIMEOUT */ ++ ++/* ++ * Exported from the dhd protocol module (dhd_cdc, dhd_rndis) ++ */ ++ ++/* Linkage, sets prot link and updates hdrlen in pub */ ++extern int dhd_prot_attach(dhd_pub_t *dhdp); ++ ++/* Unlink, frees allocated protocol memory (including dhd_prot) */ ++extern void dhd_prot_detach(dhd_pub_t *dhdp); ++ ++/* Initialize protocol: sync w/dongle state. ++ * Sets dongle media info (iswl, drv_version, mac address). ++ */ ++extern int dhd_prot_init(dhd_pub_t *dhdp); ++ ++/* Stop protocol: sync w/dongle state. */ ++extern void dhd_prot_stop(dhd_pub_t *dhdp); ++#ifdef PROP_TXSTATUS ++extern int dhd_wlfc_init(dhd_pub_t *dhd); ++extern void dhd_wlfc_deinit(dhd_pub_t *dhd); ++#endif /* PROP_TXSTATUS */ ++ ++/* Add any protocol-specific data header. ++ * Caller must reserve prot_hdrlen prepend space. ++ */ ++extern void dhd_prot_hdrpush(dhd_pub_t *, int ifidx, void *txp); ++ ++/* Remove any protocol-specific data header. */ ++extern int dhd_prot_hdrpull(dhd_pub_t *, int *ifidx, void *rxp, uchar *buf, uint *len); ++ ++/* Use protocol to issue ioctl to dongle */ ++extern int dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len); ++ ++/* Handles a protocol control response asynchronously */ ++extern int dhd_prot_ctl_complete(dhd_pub_t *dhd); ++ ++/* Check for and handle local prot-specific iovar commands */ ++extern int dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name, ++ void *params, int plen, void *arg, int len, bool set); ++ ++/* Add prot dump output to a buffer */ ++extern void dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); ++ ++/* Update local copy of dongle statistics */ ++extern void dhd_prot_dstats(dhd_pub_t *dhdp); ++ ++extern int dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buflen); ++ ++extern int dhd_preinit_ioctls(dhd_pub_t *dhd); ++ ++#ifdef PROP_TXSTATUS ++extern int dhd_wlfc_enque_sendq(void* state, int prec, void* p); ++extern int dhd_wlfc_commit_packets(void* state, f_commitpkt_t fcommit, void* commit_ctx); ++extern void dhd_wlfc_cleanup(dhd_pub_t *dhd); ++#endif /* PROP_TXSTATUS */ ++ ++extern int dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, ++ uint reorder_info_len, void **pkt, uint32 *free_buf_count); ++ ++ ++/******************************** ++ * For version-string expansion * ++ */ ++#if defined(BDC) ++#define DHD_PROTOCOL "bdc" ++#elif defined(CDC) ++#define DHD_PROTOCOL "cdc" ++#elif defined(RNDIS) ++#define DHD_PROTOCOL "rndis" ++#else ++#define DHD_PROTOCOL "unknown" ++#endif /* proto */ ++ ++#endif /* _dhd_proto_h_ */ +diff --git a/drivers/net/wireless/ap6211/dhd_sdio.c b/drivers/net/wireless/ap6211/dhd_sdio.c +new file mode 100755 +index 0000000..786f287 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_sdio.c +@@ -0,0 +1,7856 @@ ++/* ++ * DHD Bus Module for SDIO ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd_sdio.c 373330 2012-12-07 04:46:17Z $ ++ */ ++ ++#include ++#include ++#include ++ ++#ifdef BCMEMBEDIMAGE ++#include BCMEMBEDIMAGE ++#endif /* BCMEMBEDIMAGE */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#if defined(DHD_DEBUG) ++#include ++#include ++#endif /* defined(DHD_DEBUG) */ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#ifndef DHDSDIO_MEM_DUMP_FNAME ++#define DHDSDIO_MEM_DUMP_FNAME "mem_dump" ++#endif ++ ++#define QLEN 256 /* bulk rx and tx queue lengths */ ++#define FCHI (QLEN - 10) ++#define FCLOW (FCHI / 2) ++#define PRIOMASK 7 ++ ++#define TXRETRIES 2 /* # of retries for tx frames */ ++ ++#define DHD_RXBOUND 50 /* Default for max rx frames in one scheduling */ ++ ++#define DHD_TXBOUND 20 /* Default for max tx frames in one scheduling */ ++ ++#define DHD_TXMINMAX 1 /* Max tx frames if rx still pending */ ++ ++#define MEMBLOCK 2048 /* Block size used for downloading of dongle image */ ++#define MAX_NVRAMBUF_SIZE 4096 /* max nvram buf size */ ++#define MAX_DATA_BUF (32 * 1024) /* Must be large enough to hold biggest possible glom */ ++ ++#ifndef DHD_FIRSTREAD ++#define DHD_FIRSTREAD 32 ++#endif ++#if !ISPOWEROF2(DHD_FIRSTREAD) ++#error DHD_FIRSTREAD is not a power of 2! ++#endif ++ ++#ifdef BCMSDIOH_TXGLOM ++/* Total length of TX frame header for dongle protocol */ ++#define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN + SDPCM_SWHEADER_LEN) ++/* Total length of RX frame for dongle protocol */ ++#else ++/* Total length of TX frame header for dongle protocol */ ++#define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN) ++#endif ++ ++#define SDPCM_HDRLEN_RX (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN) ++ ++#ifdef SDTEST ++#define SDPCM_RESERVE (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN) ++#else ++#define SDPCM_RESERVE (SDPCM_HDRLEN + DHD_SDALIGN) ++#endif ++ ++/* Space for header read, limit for data packets */ ++#ifndef MAX_HDR_READ ++#define MAX_HDR_READ 32 ++#endif ++#if !ISPOWEROF2(MAX_HDR_READ) ++#error MAX_HDR_READ is not a power of 2! ++#endif ++ ++#define MAX_RX_DATASZ 2048 ++ ++/* Maximum milliseconds to wait for F2 to come up */ ++#define DHD_WAIT_F2RDY 3000 ++ ++/* Bump up limit on waiting for HT to account for first startup; ++ * if the image is doing a CRC calculation before programming the PMU ++ * for HT availability, it could take a couple hundred ms more, so ++ * max out at a 1 second (1000000us). ++ */ ++#if (PMU_MAX_TRANSITION_DLY <= 1000000) ++#undef PMU_MAX_TRANSITION_DLY ++#define PMU_MAX_TRANSITION_DLY 1000000 ++#endif ++ ++/* Value for ChipClockCSR during initial setup */ ++#define DHD_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ) ++#define DHD_INIT_CLKCTL2 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP) ++ ++/* Flags for SDH calls */ ++#define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED) ++ ++/* Packet free applicable unconditionally for sdio and sdspi. Conditional if ++ * bufpool was present for gspi bus. ++ */ ++#define PKTFREE2() if ((bus->bus != SPI_BUS) || bus->usebufpool) \ ++ PKTFREE(bus->dhd->osh, pkt, FALSE); ++DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep); ++#if defined(OOB_INTR_ONLY) ++extern void bcmsdh_set_irq(int flag); ++#endif ++#ifdef PROP_TXSTATUS ++extern void dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success, bool wlfc_locked); ++extern void dhd_wlfc_trigger_pktcommit(dhd_pub_t *dhd); ++#endif ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) ++DEFINE_MUTEX(_dhd_sdio_mutex_lock_); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ ++ ++#ifdef DHD_DEBUG ++/* Device console log buffer state */ ++#define CONSOLE_LINE_MAX 192 ++#define CONSOLE_BUFFER_MAX 2024 ++typedef struct dhd_console { ++ uint count; /* Poll interval msec counter */ ++ uint log_addr; /* Log struct address (fixed) */ ++ hndrte_log_t log; /* Log struct (host copy) */ ++ uint bufsize; /* Size of log buffer */ ++ uint8 *buf; /* Log buffer (host copy) */ ++ uint last; /* Last buffer read index */ ++} dhd_console_t; ++#endif /* DHD_DEBUG */ ++ ++#define REMAP_ENAB(bus) ((bus)->remap) ++#define REMAP_ISADDR(bus, a) (((a) >= ((bus)->orig_ramsize)) && ((a) < ((bus)->ramsize))) ++#define KSO_ENAB(bus) ((bus)->kso) ++#define SR_ENAB(bus) ((bus)->_srenab) ++#define SLPAUTO_ENAB(bus) ((SR_ENAB(bus)) && ((bus)->_slpauto)) ++#define MIN_RSRC_ADDR (SI_ENUM_BASE + 0x618) ++#define MIN_RSRC_SR 0x3 ++#define CORE_CAPEXT_ADDR (SI_ENUM_BASE + 0x64c) ++#define CORE_CAPEXT_SR_SUPPORTED_MASK (1 << 1) ++#define RCTL_MACPHY_DISABLE_MASK (1 << 26) ++#define RCTL_LOGIC_DISABLE_MASK (1 << 27) ++ ++#define OOB_WAKEUP_ENAB(bus) ((bus)->_oobwakeup) ++#define GPIO_DEV_SRSTATE 16 /* Host gpio17 mapped to device gpio0 SR state */ ++#define GPIO_DEV_SRSTATE_TIMEOUT 320000 /* 320ms */ ++#define GPIO_DEV_WAKEUP 17 /* Host gpio17 mapped to device gpio1 wakeup */ ++#define CC_CHIPCTRL2_GPIO1_WAKEUP (1 << 0) ++ ++#define CC_PMUCC3 (0x3) ++/* Private data for SDIO bus interaction */ ++typedef struct dhd_bus { ++ dhd_pub_t *dhd; ++ ++ bcmsdh_info_t *sdh; /* Handle for BCMSDH calls */ ++ si_t *sih; /* Handle for SI calls */ ++ char *vars; /* Variables (from CIS and/or other) */ ++ uint varsz; /* Size of variables buffer */ ++ uint32 sbaddr; /* Current SB window pointer (-1, invalid) */ ++ ++ sdpcmd_regs_t *regs; /* Registers for SDIO core */ ++ uint sdpcmrev; /* SDIO core revision */ ++ uint armrev; /* CPU core revision */ ++ uint ramrev; /* SOCRAM core revision */ ++ uint32 ramsize; /* Size of RAM in SOCRAM (bytes) */ ++ uint32 orig_ramsize; /* Size of RAM in SOCRAM (bytes) */ ++ uint32 srmemsize; /* Size of SRMEM */ ++ ++ uint32 bus; /* gSPI or SDIO bus */ ++ uint32 hostintmask; /* Copy of Host Interrupt Mask */ ++ uint32 intstatus; /* Intstatus bits (events) pending */ ++ bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */ ++ bool fcstate; /* State of dongle flow-control */ ++ ++ uint16 cl_devid; /* cached devid for dhdsdio_probe_attach() */ ++ char *fw_path; /* module_param: path to firmware image */ ++ char *nv_path; /* module_param: path to nvram vars file */ ++ const char *nvram_params; /* user specified nvram params. */ ++ ++ uint blocksize; /* Block size of SDIO transfers */ ++ uint roundup; /* Max roundup limit */ ++ ++ struct pktq txq; /* Queue length used for flow-control */ ++ uint8 flowcontrol; /* per prio flow control bitmask */ ++ uint8 tx_seq; /* Transmit sequence number (next) */ ++ uint8 tx_max; /* Maximum transmit sequence allowed */ ++ ++ uint8 hdrbuf[MAX_HDR_READ + DHD_SDALIGN]; ++ uint8 *rxhdr; /* Header of current rx frame (in hdrbuf) */ ++ uint16 nextlen; /* Next Read Len from last header */ ++ uint8 rx_seq; /* Receive sequence number (expected) */ ++ bool rxskip; /* Skip receive (awaiting NAK ACK) */ ++ ++ void *glomd; /* Packet containing glomming descriptor */ ++ void *glom; /* Packet chain for glommed superframe */ ++ uint glomerr; /* Glom packet read errors */ ++ ++ uint8 *rxbuf; /* Buffer for receiving control packets */ ++ uint rxblen; /* Allocated length of rxbuf */ ++ uint8 *rxctl; /* Aligned pointer into rxbuf */ ++ uint8 *databuf; /* Buffer for receiving big glom packet */ ++ uint8 *dataptr; /* Aligned pointer into databuf */ ++ uint rxlen; /* Length of valid data in buffer */ ++ ++ uint8 sdpcm_ver; /* Bus protocol reported by dongle */ ++ ++ bool intr; /* Use interrupts */ ++ bool poll; /* Use polling */ ++ bool ipend; /* Device interrupt is pending */ ++ bool intdis; /* Interrupts disabled by isr */ ++ uint intrcount; /* Count of device interrupt callbacks */ ++ uint lastintrs; /* Count as of last watchdog timer */ ++ uint spurious; /* Count of spurious interrupts */ ++ uint pollrate; /* Ticks between device polls */ ++ uint polltick; /* Tick counter */ ++ uint pollcnt; /* Count of active polls */ ++ ++#ifdef DHD_DEBUG ++ dhd_console_t console; /* Console output polling support */ ++ uint console_addr; /* Console address from shared struct */ ++#endif /* DHD_DEBUG */ ++ ++ uint regfails; /* Count of R_REG/W_REG failures */ ++ ++ uint clkstate; /* State of sd and backplane clock(s) */ ++ bool activity; /* Activity flag for clock down */ ++ int32 idletime; /* Control for activity timeout */ ++ int32 idlecount; /* Activity timeout counter */ ++ int32 idleclock; /* How to set bus driver when idle */ ++ int32 sd_divisor; /* Speed control to bus driver */ ++ int32 sd_mode; /* Mode control to bus driver */ ++ int32 sd_rxchain; /* If bcmsdh api accepts PKT chains */ ++ bool use_rxchain; /* If dhd should use PKT chains */ ++ bool sleeping; /* Is SDIO bus sleeping? */ ++ uint rxflow_mode; /* Rx flow control mode */ ++ bool rxflow; /* Is rx flow control on */ ++ uint prev_rxlim_hit; /* Is prev rx limit exceeded (per dpc schedule) */ ++ bool alp_only; /* Don't use HT clock (ALP only) */ ++ /* Field to decide if rx of control frames happen in rxbuf or lb-pool */ ++ bool usebufpool; ++ ++#ifdef SDTEST ++ /* external loopback */ ++ bool ext_loop; ++ uint8 loopid; ++ ++ /* pktgen configuration */ ++ uint pktgen_freq; /* Ticks between bursts */ ++ uint pktgen_count; /* Packets to send each burst */ ++ uint pktgen_print; /* Bursts between count displays */ ++ uint pktgen_total; /* Stop after this many */ ++ uint pktgen_minlen; /* Minimum packet data len */ ++ uint pktgen_maxlen; /* Maximum packet data len */ ++ uint pktgen_mode; /* Configured mode: tx, rx, or echo */ ++ uint pktgen_stop; /* Number of tx failures causing stop */ ++ ++ /* active pktgen fields */ ++ uint pktgen_tick; /* Tick counter for bursts */ ++ uint pktgen_ptick; /* Burst counter for printing */ ++ uint pktgen_sent; /* Number of test packets generated */ ++ uint pktgen_rcvd; /* Number of test packets received */ ++ uint pktgen_prev_time; /* Time at which previous stats where printed */ ++ uint pktgen_prev_sent; /* Number of test packets generated when ++ * previous stats were printed ++ */ ++ uint pktgen_prev_rcvd; /* Number of test packets received when ++ * previous stats were printed ++ */ ++ uint pktgen_fail; /* Number of failed send attempts */ ++ uint16 pktgen_len; /* Length of next packet to send */ ++#define PKTGEN_RCV_IDLE (0) ++#define PKTGEN_RCV_ONGOING (1) ++ uint16 pktgen_rcv_state; /* receive state */ ++ uint pktgen_rcvd_rcvsession; /* test pkts rcvd per rcv session. */ ++#endif /* SDTEST */ ++ ++ /* Some additional counters */ ++ uint tx_sderrs; /* Count of tx attempts with sd errors */ ++ uint fcqueued; /* Tx packets that got queued */ ++ uint rxrtx; /* Count of rtx requests (NAK to dongle) */ ++ uint rx_toolong; /* Receive frames too long to receive */ ++ uint rxc_errors; /* SDIO errors when reading control frames */ ++ uint rx_hdrfail; /* SDIO errors on header reads */ ++ uint rx_badhdr; /* Bad received headers (roosync?) */ ++ uint rx_badseq; /* Mismatched rx sequence number */ ++ uint fc_rcvd; /* Number of flow-control events received */ ++ uint fc_xoff; /* Number which turned on flow-control */ ++ uint fc_xon; /* Number which turned off flow-control */ ++ uint rxglomfail; /* Failed deglom attempts */ ++ uint rxglomframes; /* Number of glom frames (superframes) */ ++ uint rxglompkts; /* Number of packets from glom frames */ ++ uint f2rxhdrs; /* Number of header reads */ ++ uint f2rxdata; /* Number of frame data reads */ ++ uint f2txdata; /* Number of f2 frame writes */ ++ uint f1regdata; /* Number of f1 register accesses */ ++ ++ uint8 *ctrl_frame_buf; ++ uint32 ctrl_frame_len; ++ bool ctrl_frame_stat; ++ uint32 rxint_mode; /* rx interrupt mode */ ++ bool remap; /* Contiguous 1MB RAM: 512K socram + 512K devram ++ * Available with socram rev 16 ++ * Remap region not DMA-able ++ */ ++ bool kso; ++ bool _slpauto; ++ bool _oobwakeup; ++ bool _srenab; ++ bool readframes; ++ bool reqbussleep; ++ uint32 resetinstr; ++ uint32 dongle_ram_base; ++#ifdef BCMSDIOH_TXGLOM ++ void *glom_pkt_arr[SDPCM_MAXGLOM_SIZE]; /* Array of pkts for glomming */ ++ uint16 glom_cnt; /* Number of pkts in the glom array */ ++ uint16 glom_total_len; /* Total length of pkts in glom array */ ++ bool glom_enable; /* Flag to indicate whether tx glom is enabled/disabled */ ++ uint8 glom_mode; /* Glom mode - 0-copy mode, 1 - Multi-descriptor mode */ ++ uint32 glomsize; /* Glom size limitation */ ++#endif ++} dhd_bus_t; ++ ++/* clkstate */ ++#define CLK_NONE 0 ++#define CLK_SDONLY 1 ++#define CLK_PENDING 2 /* Not used yet */ ++#define CLK_AVAIL 3 ++ ++#define DHD_NOPMU(dhd) (FALSE) ++ ++#ifdef DHD_DEBUG ++static int qcount[NUMPRIO]; ++static int tx_packets[NUMPRIO]; ++#endif /* DHD_DEBUG */ ++ ++/* Deferred transmit */ ++const uint dhd_deferred_tx = 1; ++ ++extern uint dhd_watchdog_ms; ++extern void dhd_os_wd_timer(void *bus, uint wdtick); ++ ++/* Tx/Rx bounds */ ++uint dhd_txbound; ++uint dhd_rxbound; ++uint dhd_txminmax = DHD_TXMINMAX; ++ ++/* override the RAM size if possible */ ++#define DONGLE_MIN_MEMSIZE (128 *1024) ++int dhd_dongle_memsize; ++ ++static bool dhd_doflow; ++static bool dhd_alignctl; ++ ++static bool sd1idle; ++ ++static bool retrydata; ++#define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata) ++ ++#if defined(SDIO_CRC_ERROR_FIX) ++static uint watermark = 48; ++static uint mesbusyctrl = 80; ++#else ++static const uint watermark = 8; ++static const uint mesbusyctrl = 0; ++#endif ++static const uint firstread = DHD_FIRSTREAD; ++ ++#define HDATLEN (firstread - (SDPCM_HDRLEN)) ++ ++/* Retry count for register access failures */ ++static const uint retry_limit = 2; ++ ++/* Force even SD lengths (some host controllers mess up on odd bytes) */ ++static bool forcealign; ++ ++#define FW_TYPE_STA 0 ++#define FW_TYPE_APSTA 1 ++#define FW_TYPE_P2P 2 ++#define FW_TYPE_MFG 3 ++#define FW_TYPE_G 0 ++#define FW_TYPE_AG 1 ++ ++const static char *bcm40183b2_fw_name[] = { ++ "fw_bcm40183b2.bin", ++ "fw_bcm40183b2_apsta.bin", ++ "fw_bcm40183b2_p2p.bin", ++ "fw_bcm40183b2_mfg.bin" ++}; ++ ++const static char *bcm40183b2ag_fw_name[] = { ++ "fw_bcm40183b2_ag.bin", ++ "fw_bcm40183b2_ag_apsta.bin", ++ "fw_bcm40183b2_ag_p2p.bin", ++ "fw_bcm40183b2_ag_mfg.bin" ++}; ++ ++const static char *bcm40181a0_fw_name[] = { ++ "fw_bcm40181a0.bin", ++ "fw_bcm40181a0_apsta.bin", ++ "fw_bcm40181a0_p2p.bin", ++ "fw_bcm40181a0_mfg.bin" ++}; ++ ++const static char *bcm40181a2_fw_name[] = { ++ "fw_bcm40181a2.bin", ++ "fw_bcm40181a2_apsta.bin", ++ "fw_bcm40181a2_p2p.bin", ++ "fw_bcm40181a2_mfg.bin" ++}; ++ ++const static char *bcm43341b0ag_fw_name[] = { ++ "fw_bcm43341b0_ag.bin", ++ "fw_bcm43341b0_ag_apsta.bin", ++ "fw_bcm43341b0_ag_p2p.bin", ++ "fw_bcm43341b0_ag_mfg.bin" ++}; ++ ++const static char *bcm43241b4ag_fw_name[] = { ++ "fw_bcm43241b4_ag.bin", ++ "fw_bcm43241b4_ag_apsta.bin", ++ "fw_bcm43241b4_ag_p2p.bin", ++ "fw_bcm43241b4_ag_mfg.bin" ++}; ++ ++#define BCM4330B2_CHIP_REV 4 ++#define BCM43362A0_CHIP_REV 0 ++#define BCM43362A2_CHIP_REV 1 ++#define BCM43341B0_CHIP_REV 2 ++#define BCM43241B4_CHIP_REV 5 ++ ++#define ALIGNMENT 4 ++ ++#if defined(OOB_INTR_ONLY) && defined(HW_OOB) ++extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable); ++#endif ++ ++#if defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) ++#error OOB_INTR_ONLY is NOT working with SDIO_ISR_THREAD ++#endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */ ++#define PKTALIGN(osh, p, len, align) \ ++ do { \ ++ uint datalign; \ ++ datalign = (uintptr)PKTDATA((osh), (p)); \ ++ datalign = ROUNDUP(datalign, (align)) - datalign; \ ++ ASSERT(datalign < (align)); \ ++ ASSERT(PKTLEN((osh), (p)) >= ((len) + datalign)); \ ++ if (datalign) \ ++ PKTPULL((osh), (p), datalign); \ ++ PKTSETLEN((osh), (p), (len)); \ ++ } while (0) ++ ++/* Limit on rounding up frames */ ++static const uint max_roundup = 512; ++ ++/* Try doing readahead */ ++static bool dhd_readahead; ++ ++ ++/* To check if there's window offered */ ++#define DATAOK(bus) \ ++ (((uint8)(bus->tx_max - bus->tx_seq) > 1) && \ ++ (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0)) ++ ++/* To check if there's window offered for ctrl frame */ ++#define TXCTLOK(bus) \ ++ (((uint8)(bus->tx_max - bus->tx_seq) != 0) && \ ++ (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0)) ++ ++/* Number of pkts available in dongle for data RX */ ++#define DATABUFCNT(bus) \ ++ ((uint8)(bus->tx_max - bus->tx_seq) - 1) ++ ++/* Macros to get register read/write status */ ++/* NOTE: these assume a local dhdsdio_bus_t *bus! */ ++#define R_SDREG(regvar, regaddr, retryvar) \ ++do { \ ++ retryvar = 0; \ ++ do { \ ++ regvar = R_REG(bus->dhd->osh, regaddr); \ ++ } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \ ++ if (retryvar) { \ ++ bus->regfails += (retryvar-1); \ ++ if (retryvar > retry_limit) { \ ++ AP6211_ERR("%s: FAILED" #regvar "READ, LINE %d\n", \ ++ __FUNCTION__, __LINE__); \ ++ regvar = 0; \ ++ } \ ++ } \ ++} while (0) ++ ++#define W_SDREG(regval, regaddr, retryvar) \ ++do { \ ++ retryvar = 0; \ ++ do { \ ++ W_REG(bus->dhd->osh, regaddr, regval); \ ++ } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \ ++ if (retryvar) { \ ++ bus->regfails += (retryvar-1); \ ++ if (retryvar > retry_limit) \ ++ AP6211_ERR("%s: FAILED REGISTER WRITE, LINE %d\n", \ ++ __FUNCTION__, __LINE__); \ ++ } \ ++} while (0) ++ ++#define BUS_WAKE(bus) \ ++ do { \ ++ bus->idlecount = 0; \ ++ if ((bus)->sleeping) \ ++ dhdsdio_bussleep((bus), FALSE); \ ++ } while (0); ++ ++/* ++ * pktavail interrupts from dongle to host can be managed in 3 different ways ++ * whenever there is a packet available in dongle to transmit to host. ++ * ++ * Mode 0: Dongle writes the software host mailbox and host is interrupted. ++ * Mode 1: (sdiod core rev >= 4) ++ * Device sets a new bit in the intstatus whenever there is a packet ++ * available in fifo. Host can't clear this specific status bit until all the ++ * packets are read from the FIFO. No need to ack dongle intstatus. ++ * Mode 2: (sdiod core rev >= 4) ++ * Device sets a bit in the intstatus, and host acks this by writing ++ * one to this bit. Dongle won't generate anymore packet interrupts ++ * until host reads all the packets from the dongle and reads a zero to ++ * figure that there are no more packets. No need to disable host ints. ++ * Need to ack the intstatus. ++ */ ++ ++#define SDIO_DEVICE_HMB_RXINT 0 /* default old way */ ++#define SDIO_DEVICE_RXDATAINT_MODE_0 1 /* from sdiod rev 4 */ ++#define SDIO_DEVICE_RXDATAINT_MODE_1 2 /* from sdiod rev 4 */ ++ ++ ++#define FRAME_AVAIL_MASK(bus) \ ++ ((bus->rxint_mode == SDIO_DEVICE_HMB_RXINT) ? I_HMB_FRAME_IND : I_XMTDATA_AVAIL) ++ ++#define DHD_BUS SDIO_BUS ++ ++#define PKT_AVAILABLE(bus, intstatus) ((intstatus) & (FRAME_AVAIL_MASK(bus))) ++ ++#define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE) ++ ++#define GSPI_PR55150_BAILOUT ++ ++#ifdef SDTEST ++static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq); ++static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint count); ++#endif ++ ++#ifdef DHD_DEBUG ++static int dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size); ++static int dhd_serialconsole(dhd_bus_t *bus, bool get, bool enable, int *bcmerror); ++#endif /* DHD_DEBUG */ ++ ++static int dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap); ++static int dhdsdio_download_state(dhd_bus_t *bus, bool enter); ++ ++static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh); ++static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh); ++static void dhdsdio_disconnect(void *ptr); ++static bool dhdsdio_chipmatch(uint16 chipid); ++static bool dhdsdio_probe_attach(dhd_bus_t *bus, osl_t *osh, void *sdh, ++ void * regsva, uint16 devid); ++static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh); ++static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh); ++static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, ++ bool reset_flag); ++ ++static void dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size); ++static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, ++ uint8 *buf, uint nbytes, ++ void *pkt, bcmsdh_cmplt_fn_t complete, void *handle); ++static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, ++ uint8 *buf, uint nbytes, ++ void *pkt, bcmsdh_cmplt_fn_t complete, void *handle); ++#ifdef BCMSDIOH_TXGLOM ++static void dhd_bcmsdh_glom_post(dhd_bus_t *bus, uint8 *frame, uint len); ++static void dhd_bcmsdh_glom_clear(dhd_bus_t *bus); ++#endif ++ ++static bool dhdsdio_download_firmware(dhd_bus_t *bus, osl_t *osh, void *sdh); ++static int _dhdsdio_download_firmware(dhd_bus_t *bus); ++ ++static int dhdsdio_download_code_file(dhd_bus_t *bus, char *image_path); ++static int dhdsdio_download_nvram(dhd_bus_t *bus); ++#ifdef BCMEMBEDIMAGE ++static int dhdsdio_download_code_array(dhd_bus_t *bus); ++#endif ++static int dhdsdio_bussleep(dhd_bus_t *bus, bool sleep); ++static int dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok); ++static uint8 dhdsdio_sleepcsr_get(dhd_bus_t *bus); ++ ++#ifdef WLMEDIA_HTSF ++#include ++extern uint32 dhd_get_htsf(void *dhd, int ifidx); ++#endif /* WLMEDIA_HTSF */ ++ ++static void ++dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size) ++{ ++ int32 min_size = DONGLE_MIN_MEMSIZE; ++ /* Restrict the memsize to user specified limit */ ++ AP6211_DEBUG("user: Restrict the dongle ram size to %d, min accepted %d\n", ++ dhd_dongle_memsize, min_size); ++ if ((dhd_dongle_memsize > min_size) && ++ (dhd_dongle_memsize < (int32)bus->orig_ramsize)) ++ bus->ramsize = dhd_dongle_memsize; ++} ++ ++static int ++dhdsdio_set_siaddr_window(dhd_bus_t *bus, uint32 address) ++{ ++ int err = 0; ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, ++ (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err); ++ if (!err) ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID, ++ (address >> 16) & SBSDIO_SBADDRMID_MASK, &err); ++ if (!err) ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH, ++ (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err); ++ return err; ++} ++ ++ ++#ifdef USE_OOB_GPIO1 ++static int ++dhdsdio_oobwakeup_init(dhd_bus_t *bus) ++{ ++ uint32 val, addr, data; ++ ++ bcmsdh_gpioouten(bus->sdh, GPIO_DEV_WAKEUP); ++ ++ addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); ++ data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); ++ ++ /* Set device for gpio1 wakeup */ ++ bcmsdh_reg_write(bus->sdh, addr, 4, 2); ++ val = bcmsdh_reg_read(bus->sdh, data, 4); ++ val |= CC_CHIPCTRL2_GPIO1_WAKEUP; ++ bcmsdh_reg_write(bus->sdh, data, 4, val); ++ ++ bus->_oobwakeup = TRUE; ++ ++ return 0; ++} ++#endif /* USE_OOB_GPIO1 */ ++ ++/* ++ * Query if FW is in SR mode ++ */ ++static bool ++dhdsdio_sr_cap(dhd_bus_t *bus) ++{ ++ bool cap = FALSE; ++ uint32 min = 0, core_capext, addr, data; ++ if (bus->sih->chip == BCM4324_CHIP_ID) { ++ addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); ++ data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); ++ bcmsdh_reg_write(bus->sdh, addr, 4, 3); ++ core_capext = bcmsdh_reg_read(bus->sdh, data, 4); ++ } else if (bus->sih->chip == BCM4330_CHIP_ID || bus->sih->chip == BCM43362_CHIP_ID) { ++ core_capext = FALSE; ++ } else if (bus->sih->chip == BCM4335_CHIP_ID) { ++ core_capext = TRUE; ++ } else { ++ core_capext = bcmsdh_reg_read(bus->sdh, CORE_CAPEXT_ADDR, 4); ++ core_capext = (core_capext & CORE_CAPEXT_SR_SUPPORTED_MASK); ++ } ++ if (!(core_capext)) ++ return FALSE; ++ ++ if (bus->sih->chip == BCM4324_CHIP_ID) { ++ /* FIX: Should change to query SR control register instead */ ++ min = bcmsdh_reg_read(bus->sdh, MIN_RSRC_ADDR, 4); ++ if (min == MIN_RSRC_SR) ++ cap = TRUE; ++ } else if (bus->sih->chip == BCM4335_CHIP_ID) { ++ uint32 enabval = 0; ++ addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); ++ data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); ++ bcmsdh_reg_write(bus->sdh, addr, 4, CC_PMUCC3); ++ enabval = bcmsdh_reg_read(bus->sdh, data, 4); ++ ++ if (enabval) ++ cap = TRUE; ++ } else { ++ data = bcmsdh_reg_read(bus->sdh, ++ SI_ENUM_BASE + OFFSETOF(chipcregs_t, retention_ctl), 4); ++ if ((data & (RCTL_MACPHY_DISABLE_MASK | RCTL_LOGIC_DISABLE_MASK)) == 0) ++ cap = TRUE; ++ } ++ ++ return cap; ++} ++ ++static int ++dhdsdio_srwar_init(dhd_bus_t *bus) ++{ ++ ++ bcmsdh_gpio_init(bus->sdh); ++ ++#ifdef USE_OOB_GPIO1 ++ dhdsdio_oobwakeup_init(bus); ++#endif ++ ++ ++ return 0; ++} ++ ++static int ++dhdsdio_sr_init(dhd_bus_t *bus) ++{ ++ uint8 val; ++ int err = 0; ++ ++ if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2)) ++ dhdsdio_srwar_init(bus); ++ ++ val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL); ++ val |= 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT; ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, ++ 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT, &err); ++ val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL); ++ ++ /* Add CMD14 Support */ ++ dhdsdio_devcap_set(bus, ++ (SDIOD_CCCR_BRCM_CARDCAP_CMD14_SUPPORT | SDIOD_CCCR_BRCM_CARDCAP_CMD14_EXT)); ++ ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, SBSDIO_FORCE_HT, &err); ++ ++ bus->_slpauto = dhd_slpauto ? TRUE : FALSE; ++ ++ bus->_srenab = TRUE; ++ ++ return 0; ++} ++ ++/* ++ * FIX: Be sure KSO bit is enabled ++ * Currently, it's defaulting to 0 which should be 1. ++ */ ++static int ++dhdsdio_clk_kso_init(dhd_bus_t *bus) ++{ ++ uint8 val; ++ int err = 0; ++ ++ /* set flag */ ++ bus->kso = TRUE; ++ ++ /* ++ * Enable KeepSdioOn (KSO) bit for normal operation ++ * Default is 0 (4334A0) so set it. Fixed in B0. ++ */ ++ val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, NULL); ++ if (!(val & SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) { ++ val |= (SBSDIO_FUNC1_SLEEPCSR_KSO_EN << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT); ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, val, &err); ++ if (err) ++ AP6211_ERR("%s: SBSDIO_FUNC1_SLEEPCSR err: 0x%x\n", __FUNCTION__, err); ++ } ++ ++ return 0; ++} ++ ++#define KSO_DBG(x) ++#define MAX_KSO_ATTEMPTS 64 ++static int ++dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on) ++{ ++ uint8 wr_val = 0, rd_val, cmp_val, bmask; ++ int err = 0; ++ int try_cnt = 0; ++ ++ KSO_DBG(("%s> op:%s\n", __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"))); ++ ++ wr_val |= (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT); ++ ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err); ++ ++ if (on) { ++ cmp_val = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK | SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK; ++ bmask = cmp_val; ++ ++ msleep(3); ++ ++ } else { ++ /* Put device to sleep, turn off KSO */ ++ cmp_val = 0; ++ bmask = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK; ++ } ++ ++ do { ++ rd_val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err); ++ if (((rd_val & bmask) == cmp_val) && !err) ++ break; ++ ++ KSO_DBG(("%s> KSO wr/rd retry:%d, ERR:%x \n", __FUNCTION__, try_cnt, err)); ++ OSL_DELAY(50); ++ ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err); ++ ++ } while (try_cnt++ < MAX_KSO_ATTEMPTS); ++ ++ ++ if (try_cnt > 1) { ++ KSO_DBG(("%s> op:%s, try_cnt:%d, rd_val:%x, ERR:%x \n", ++ __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err)); ++ } ++ ++ if (try_cnt > MAX_KSO_ATTEMPTS) { ++ AP6211_ERR("%s> op:%s, ERROR: try_cnt:%d, rd_val:%x, ERR:%x \n", ++ __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err); ++ } ++ return err; ++} ++ ++static int ++dhdsdio_clk_kso_iovar(dhd_bus_t *bus, bool on) ++{ ++ int err = 0; ++ ++ if (on == FALSE) { ++ ++ BUS_WAKE(bus); ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ ++ AP6211_DEBUG("%s: KSO disable clk: 0x%x\n", __FUNCTION__, ++ bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, &err)); ++ dhdsdio_clk_kso_enab(bus, FALSE); ++ } else { ++ AP6211_DEBUG("%s: KSO enable\n", __FUNCTION__); ++ ++ /* Make sure we have SD bus access */ ++ if (bus->clkstate == CLK_NONE) { ++ AP6211_DEBUG("%s: Request SD clk\n", __FUNCTION__); ++ dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); ++ } ++ ++ /* Double-write to be safe in case transition of AOS */ ++ dhdsdio_clk_kso_enab(bus, TRUE); ++ dhdsdio_clk_kso_enab(bus, TRUE); ++ OSL_DELAY(4000); ++ ++ /* Wait for device ready during transition to wake-up */ ++ SPINWAIT(((dhdsdio_sleepcsr_get(bus)) != ++ (SBSDIO_FUNC1_SLEEPCSR_KSO_MASK | ++ SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)), ++ (10000)); ++ ++ AP6211_DEBUG("%s: sleepcsr: 0x%x\n", __FUNCTION__, ++ dhdsdio_sleepcsr_get(bus)); ++ } ++ ++ bus->kso = on; ++ BCM_REFERENCE(err); ++ ++ return 0; ++} ++ ++static uint8 ++dhdsdio_sleepcsr_get(dhd_bus_t *bus) ++{ ++ int err = 0; ++ uint8 val = 0; ++ ++ val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err); ++ if (err) ++ AP6211_DEBUG("Failed to read SLEEPCSR: %d\n", err); ++ ++ return val; ++} ++ ++uint8 ++dhdsdio_devcap_get(dhd_bus_t *bus) ++{ ++ return bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, NULL); ++} ++ ++static int ++dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap) ++{ ++ int err = 0; ++ ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, cap, &err); ++ if (err) ++ AP6211_ERR("%s: devcap set err: 0x%x\n", __FUNCTION__, err); ++ ++ return 0; ++} ++ ++static int ++dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on) ++{ ++ int err = 0, retry; ++ uint8 val; ++ ++ retry = 0; ++ if (on == TRUE) { ++ /* Enter Sleep */ ++ ++ /* Be sure we request clk before going to sleep ++ * so we can wake-up with clk request already set ++ * else device can go back to sleep immediately ++ */ ++ if (!SLPAUTO_ENAB(bus)) ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ else { ++ val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); ++ if ((val & SBSDIO_CSR_MASK) == 0) { ++ AP6211_DEBUG("%s: No clock before enter sleep:0x%x\n", ++ __FUNCTION__, val); ++ ++ /* Reset clock request */ ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, ++ SBSDIO_ALP_AVAIL_REQ, &err); ++ AP6211_DEBUG("%s: clock before sleep:0x%x\n", __FUNCTION__, ++ bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, &err)); ++ } ++ } ++ ++ AP6211_DEBUG("%s: clk before sleep: 0x%x\n", __FUNCTION__, ++ bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, &err)); ++#ifdef USE_CMD14 ++ err = bcmsdh_sleep(bus->sdh, TRUE); ++#else ++ err = dhdsdio_clk_kso_enab(bus, FALSE); ++ if (OOB_WAKEUP_ENAB(bus)) ++ err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, FALSE); /* GPIO_1 is off */ ++#endif ++ } else { ++ /* Exit Sleep */ ++ /* Make sure we have SD bus access */ ++ if (bus->clkstate == CLK_NONE) { ++ AP6211_DEBUG("%s: Request SD clk\n", __FUNCTION__); ++ dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); ++ } ++ ++ if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2)) { ++ SPINWAIT((bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) != TRUE), ++ GPIO_DEV_SRSTATE_TIMEOUT); ++ ++ if (bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) == FALSE) { ++ AP6211_ERR("ERROR: GPIO_DEV_SRSTATE still low!\n"); ++ } ++ } ++#ifdef USE_CMD14 ++ err = bcmsdh_sleep(bus->sdh, FALSE); ++ if (SLPAUTO_ENAB(bus) && (err != 0)) { ++ OSL_DELAY(10000); ++ AP6211_DEBUG("%s: Resync device sleep\n", __FUNCTION__); ++ ++ /* Toggle sleep to resync with host and device */ ++ err = bcmsdh_sleep(bus->sdh, TRUE); ++ OSL_DELAY(10000); ++ err = bcmsdh_sleep(bus->sdh, FALSE); ++ ++ if (err) { ++ OSL_DELAY(10000); ++ AP6211_ERR("%s: CMD14 exit failed again!\n", __FUNCTION__); ++ ++ /* Toggle sleep to resync with host and device */ ++ err = bcmsdh_sleep(bus->sdh, TRUE); ++ OSL_DELAY(10000); ++ err = bcmsdh_sleep(bus->sdh, FALSE); ++ if (err) { ++ AP6211_ERR("%s: CMD14 exit failed twice!\n", __FUNCTION__); ++ AP6211_ERR("%s: FATAL: Device non-response!\n", ++ __FUNCTION__); ++ err = 0; ++ } ++ } ++ } ++#else ++ if (OOB_WAKEUP_ENAB(bus)) ++ err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, TRUE); /* GPIO_1 is on */ ++ ++ do { ++ err = dhdsdio_clk_kso_enab(bus, TRUE); ++ if (err) ++ OSL_DELAY(10000); ++ } while ((err != 0) && (++retry < 3)); ++ ++ if (err != 0) { ++ AP6211_ERR("ERROR: kso set failed retry: %d\n", retry); ++ err = 0; /* continue anyway */ ++ } ++#endif /* !USE_CMD14 */ ++ ++ if (err == 0) { ++ uint8 csr; ++ ++ /* Wait for device ready during transition to wake-up */ ++ SPINWAIT((((csr = dhdsdio_sleepcsr_get(bus)) & ++ SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK) != ++ (SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)), (20000)); ++ ++ AP6211_DEBUG("%s: ExitSleep sleepcsr: 0x%x\n", __FUNCTION__, csr); ++ ++ if (!(csr & SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)) { ++ AP6211_ERR("%s:ERROR: ExitSleep device NOT Ready! 0x%x\n", ++ __FUNCTION__, csr); ++ err = BCME_NODEVICE; ++ } ++ ++ SPINWAIT((((csr = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, &err)) & SBSDIO_HT_AVAIL) != ++ (SBSDIO_HT_AVAIL)), (10000)); ++ ++ } ++ } ++ ++ /* Update if successful */ ++ if (err == 0) ++ bus->kso = on ? FALSE : TRUE; ++ else { ++ AP6211_ERR("%s: Sleep request failed: on:%d err:%d\n", __FUNCTION__, on, err); ++ if (!on && retry > 2) ++ bus->kso = TRUE; ++ } ++ ++ return err; ++} ++ ++/* Turn backplane clock on or off */ ++static int ++dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok) ++{ ++#define HT_AVAIL_ERROR_MAX 10 ++ static int ht_avail_error = 0; ++ int err; ++ uint8 clkctl, clkreq, devctl; ++ bcmsdh_info_t *sdh; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++#if defined(OOB_INTR_ONLY) ++ pendok = FALSE; ++#endif ++ clkctl = 0; ++ sdh = bus->sdh; ++ ++ ++ if (!KSO_ENAB(bus)) ++ return BCME_OK; ++ ++ if (SLPAUTO_ENAB(bus)) { ++ bus->clkstate = (on ? CLK_AVAIL : CLK_SDONLY); ++ return BCME_OK; ++ } ++ ++ if (on) { ++ /* Request HT Avail */ ++ clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ; ++ ++ ++ ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err); ++ if (err) { ++ ht_avail_error++; ++ if (ht_avail_error < HT_AVAIL_ERROR_MAX) { ++ AP6211_ERR("%s: HT Avail request error: %d\n", __FUNCTION__, err); ++ } ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) ++ else if (ht_avail_error == HT_AVAIL_ERROR_MAX) { ++ dhd_os_send_hang_message(bus->dhd); ++ } ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */ ++ return BCME_ERROR; ++ } else { ++ ht_avail_error = 0; ++ } ++ ++ if (pendok && ++ ((bus->sih->buscoretype == PCMCIA_CORE_ID) && (bus->sih->buscorerev == 9))) { ++ uint32 dummy, retries; ++ R_SDREG(dummy, &bus->regs->clockctlstatus, retries); ++ BCM_REFERENCE(dummy); ++ } ++ ++ /* Check current status */ ++ clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); ++ if (err) { ++ AP6211_ERR("%s: HT Avail read error: %d\n", __FUNCTION__, err); ++ return BCME_ERROR; ++ } ++ ++ /* Go to pending and await interrupt if appropriate */ ++ if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) { ++ /* Allow only clock-available interrupt */ ++ devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); ++ if (err) { ++ AP6211_ERR("%s: Devctl access error setting CA: %d\n", ++ __FUNCTION__, err); ++ return BCME_ERROR; ++ } ++ ++ devctl |= SBSDIO_DEVCTL_CA_INT_ONLY; ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); ++ AP6211_DEBUG("CLKCTL: set PENDING\n"); ++ bus->clkstate = CLK_PENDING; ++ return BCME_OK; ++ } else if (bus->clkstate == CLK_PENDING) { ++ /* Cancel CA-only interrupt filter */ ++ devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); ++ devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); ++ } ++ ++ /* Otherwise, wait here (polling) for HT Avail */ ++ if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) { ++ SPINWAIT_SLEEP(sdioh_spinwait_sleep, ++ ((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, &err)), ++ !SBSDIO_CLKAV(clkctl, bus->alp_only)), PMU_MAX_TRANSITION_DLY); ++ } ++ if (err) { ++ AP6211_ERR("%s: HT Avail request error: %d\n", __FUNCTION__, err); ++ return BCME_ERROR; ++ } ++ if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) { ++ AP6211_ERR("%s: HT Avail timeout (%d): clkctl 0x%02x\n", ++ __FUNCTION__, PMU_MAX_TRANSITION_DLY, clkctl); ++ return BCME_ERROR; ++ } ++ ++ /* Mark clock available */ ++ bus->clkstate = CLK_AVAIL; ++ AP6211_DEBUG("CLKCTL: turned ON\n"); ++ ++#if defined(DHD_DEBUG) ++ if (bus->alp_only == TRUE) { ++#if !defined(BCMLXSDMMC) ++ if (!SBSDIO_ALPONLY(clkctl)) { ++ AP6211_ERR("%s: HT Clock, when ALP Only\n", __FUNCTION__); ++ } ++#endif /* !defined(BCMLXSDMMC) */ ++ } else { ++ if (SBSDIO_ALPONLY(clkctl)) { ++ AP6211_ERR("%s: HT Clock should be on.\n", __FUNCTION__); ++ } ++ } ++#endif /* defined (DHD_DEBUG) */ ++ ++ bus->activity = TRUE; ++#ifdef DHD_USE_IDLECOUNT ++ bus->idlecount = 0; ++#endif /* DHD_USE_IDLECOUNT */ ++ } else { ++ clkreq = 0; ++ if (bus->clkstate == CLK_PENDING) { ++ /* Cancel CA-only interrupt filter */ ++ devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); ++ devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); ++ } ++ ++ bus->clkstate = CLK_SDONLY; ++ if (!SR_ENAB(bus)) { ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err); ++ AP6211_DEBUG("CLKCTL: turned OFF\n"); ++ if (err) { ++ AP6211_ERR("%s: Failed access turning clock off: %d\n", ++ __FUNCTION__, err); ++ return BCME_ERROR; ++ } ++ } ++ } ++ return BCME_OK; ++} ++ ++/* Change idle/active SD state */ ++static int ++dhdsdio_sdclk(dhd_bus_t *bus, bool on) ++{ ++ int err; ++ int32 iovalue; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ if (on) { ++ if (bus->idleclock == DHD_IDLE_STOP) { ++ /* Turn on clock and restore mode */ ++ iovalue = 1; ++ err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0, ++ &iovalue, sizeof(iovalue), TRUE); ++ if (err) { ++ AP6211_ERR("%s: error enabling sd_clock: %d\n", ++ __FUNCTION__, err); ++ return BCME_ERROR; ++ } ++ ++ iovalue = bus->sd_mode; ++ err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0, ++ &iovalue, sizeof(iovalue), TRUE); ++ if (err) { ++ AP6211_ERR("%s: error changing sd_mode: %d\n", ++ __FUNCTION__, err); ++ return BCME_ERROR; ++ } ++ } else if (bus->idleclock != DHD_IDLE_ACTIVE) { ++ /* Restore clock speed */ ++ iovalue = bus->sd_divisor; ++ err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0, ++ &iovalue, sizeof(iovalue), TRUE); ++ if (err) { ++ AP6211_ERR("%s: error restoring sd_divisor: %d\n", ++ __FUNCTION__, err); ++ return BCME_ERROR; ++ } ++ } ++ bus->clkstate = CLK_SDONLY; ++ } else { ++ /* Stop or slow the SD clock itself */ ++ if ((bus->sd_divisor == -1) || (bus->sd_mode == -1)) { ++ AP6211_DEBUG("%s: can't idle clock, divisor %d mode %d\n", ++ __FUNCTION__, bus->sd_divisor, bus->sd_mode); ++ return BCME_ERROR; ++ } ++ if (bus->idleclock == DHD_IDLE_STOP) { ++ if (sd1idle) { ++ /* Change to SD1 mode and turn off clock */ ++ iovalue = 1; ++ err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0, ++ &iovalue, sizeof(iovalue), TRUE); ++ if (err) { ++ AP6211_ERR("%s: error changing sd_clock: %d\n", ++ __FUNCTION__, err); ++ return BCME_ERROR; ++ } ++ } ++ ++ iovalue = 0; ++ err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0, ++ &iovalue, sizeof(iovalue), TRUE); ++ if (err) { ++ AP6211_ERR("%s: error disabling sd_clock: %d\n", ++ __FUNCTION__, err); ++ return BCME_ERROR; ++ } ++ } else if (bus->idleclock != DHD_IDLE_ACTIVE) { ++ /* Set divisor to idle value */ ++ iovalue = bus->idleclock; ++ err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0, ++ &iovalue, sizeof(iovalue), TRUE); ++ if (err) { ++ AP6211_ERR("%s: error changing sd_divisor: %d\n", ++ __FUNCTION__, err); ++ return BCME_ERROR; ++ } ++ } ++ bus->clkstate = CLK_NONE; ++ } ++ ++ return BCME_OK; ++} ++ ++/* Transition SD and backplane clock readiness */ ++static int ++dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok) ++{ ++ int ret = BCME_OK; ++#ifdef DHD_DEBUG ++ uint oldstate = bus->clkstate; ++#endif /* DHD_DEBUG */ ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ /* Early exit if we're already there */ ++ if (bus->clkstate == target) { ++ if (target == CLK_AVAIL) { ++ dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); ++ bus->activity = TRUE; ++#ifdef DHD_USE_IDLECOUNT ++ bus->idlecount = 0; ++#endif /* DHD_USE_IDLECOUNT */ ++ } ++ return ret; ++ } ++ ++ switch (target) { ++ case CLK_AVAIL: ++ /* Make sure SD clock is available */ ++ if (bus->clkstate == CLK_NONE) ++ dhdsdio_sdclk(bus, TRUE); ++ /* Now request HT Avail on the backplane */ ++ ret = dhdsdio_htclk(bus, TRUE, pendok); ++ if (ret == BCME_OK) { ++ dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); ++ bus->activity = TRUE; ++#ifdef DHD_USE_IDLECOUNT ++ bus->idlecount = 0; ++#endif /* DHD_USE_IDLECOUNT */ ++ } ++ break; ++ ++ case CLK_SDONLY: ++ /* Remove HT request, or bring up SD clock */ ++ if (bus->clkstate == CLK_NONE) ++ ret = dhdsdio_sdclk(bus, TRUE); ++ else if (bus->clkstate == CLK_AVAIL) ++ ret = dhdsdio_htclk(bus, FALSE, FALSE); ++ else ++ AP6211_DEBUG("dhdsdio_clkctl: request for %d -> %d\n", ++ bus->clkstate, target); ++ if (ret == BCME_OK) { ++ dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); ++ } ++ break; ++ ++ case CLK_NONE: ++ /* Make sure to remove HT request */ ++ if (bus->clkstate == CLK_AVAIL) ++ ret = dhdsdio_htclk(bus, FALSE, FALSE); ++ /* Now remove the SD clock */ ++ ret = dhdsdio_sdclk(bus, FALSE); ++#ifdef DHD_DEBUG ++ if (dhd_console_ms == 0) ++#endif /* DHD_DEBUG */ ++ if (bus->poll == 0) ++ dhd_os_wd_timer(bus->dhd, 0); ++ break; ++ } ++#ifdef DHD_DEBUG ++ AP6211_DEBUG("dhdsdio_clkctl: %d -> %d\n", oldstate, bus->clkstate); ++#endif /* DHD_DEBUG */ ++ ++ return ret; ++} ++ ++static int ++dhdsdio_bussleep(dhd_bus_t *bus, bool sleep) ++{ ++ int err = 0; ++ bcmsdh_info_t *sdh = bus->sdh; ++ sdpcmd_regs_t *regs = bus->regs; ++ uint retries = 0; ++ ++ AP6211_DEBUG("dhdsdio_bussleep: request %s (currently %s)\n", ++ (sleep ? "SLEEP" : "WAKE"), ++ (bus->sleeping ? "SLEEP" : "WAKE")); ++ ++ /* Done if we're already in the requested state */ ++ if (sleep == bus->sleeping) ++ return BCME_OK; ++ ++ /* Going to sleep: set the alarm and turn off the lights... */ ++ if (sleep) { ++ /* Don't sleep if something is pending */ ++ if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq)) ++ return BCME_BUSY; ++ ++ ++ if (!SLPAUTO_ENAB(bus)) { ++ /* Disable SDIO interrupts (no longer interested) */ ++ bcmsdh_intr_disable(bus->sdh); ++ ++ /* Make sure the controller has the bus up */ ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ ++ /* Tell device to start using OOB wakeup */ ++ W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries); ++ if (retries > retry_limit) ++ AP6211_ERR("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"); ++ ++ /* Turn off our contribution to the HT clock request */ ++ dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); ++ ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, ++ SBSDIO_FORCE_HW_CLKREQ_OFF, NULL); ++ ++ /* Isolate the bus */ ++ if (bus->sih->chip != BCM4329_CHIP_ID && ++ bus->sih->chip != BCM4319_CHIP_ID) { ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, ++ SBSDIO_DEVCTL_PADS_ISO, NULL); ++ } ++ } else { ++ /* Leave interrupts enabled since device can exit sleep and ++ * interrupt host ++ */ ++ err = dhdsdio_clk_devsleep_iovar(bus, TRUE /* sleep */); ++ } ++ ++ /* Change state */ ++ bus->sleeping = TRUE; ++ ++ } else { ++ /* Waking up: bus power up is ok, set local state */ ++ ++ if (!SLPAUTO_ENAB(bus)) { ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, &err); ++ ++ /* Force pad isolation off if possible (in case power never toggled) */ ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, 0, NULL); ++ ++ ++ /* Make sure the controller has the bus up */ ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ ++ /* Send misc interrupt to indicate OOB not needed */ ++ W_SDREG(0, ®s->tosbmailboxdata, retries); ++ if (retries <= retry_limit) ++ W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries); ++ ++ if (retries > retry_limit) ++ AP6211_ERR("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"); ++ ++ /* Make sure we have SD bus access */ ++ dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); ++ ++ /* Enable interrupts again */ ++ if (bus->intr && (bus->dhd->busstate == DHD_BUS_DATA)) { ++ bus->intdis = FALSE; ++ bcmsdh_intr_enable(bus->sdh); ++ } ++ } else { ++ err = dhdsdio_clk_devsleep_iovar(bus, FALSE /* wake */); ++ } ++ ++ if (err == 0) { ++ /* Change state */ ++ bus->sleeping = FALSE; ++ } ++ } ++ ++ return err; ++} ++ ++#if defined(OOB_INTR_ONLY) ++void ++dhd_enable_oob_intr(struct dhd_bus *bus, bool enable) ++{ ++#if defined(HW_OOB) ++ bcmsdh_enable_hw_oob_intr(bus->sdh, enable); ++#else ++ sdpcmd_regs_t *regs = bus->regs; ++ uint retries = 0; ++ ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ if (enable == TRUE) { ++ ++ /* Tell device to start using OOB wakeup */ ++ W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries); ++ if (retries > retry_limit) ++ AP6211_ERR("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"); ++ ++ } else { ++ /* Send misc interrupt to indicate OOB not needed */ ++ W_SDREG(0, ®s->tosbmailboxdata, retries); ++ if (retries <= retry_limit) ++ W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries); ++ } ++ ++ /* Turn off our contribution to the HT clock request */ ++ dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); ++#endif /* !defined(HW_OOB) */ ++} ++#endif ++ ++/* Writes a HW/SW header into the packet and sends it. */ ++/* Assumes: (a) header space already there, (b) caller holds lock */ ++static int ++dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_only) ++{ ++ int ret; ++ osl_t *osh; ++ uint8 *frame; ++ uint16 len, pad1 = 0; ++ uint32 swheader; ++ uint retries = 0; ++ bcmsdh_info_t *sdh; ++ void *new; ++ int i; ++ int pkt_cnt; ++#ifdef BCMSDIOH_TXGLOM ++ uint8 *frame_tmp; ++#endif ++#ifdef WLMEDIA_HTSF ++ char *p; ++ htsfts_t *htsf_ts; ++#endif ++ ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ sdh = bus->sdh; ++ osh = bus->dhd->osh; ++ ++ if (bus->dhd->dongle_reset) { ++ ret = BCME_NOTREADY; ++ goto done; ++ } ++ ++ frame = (uint8*)PKTDATA(osh, pkt); ++ ++#ifdef WLMEDIA_HTSF ++ if (PKTLEN(osh, pkt) >= 100) { ++ p = PKTDATA(osh, pkt); ++ htsf_ts = (htsfts_t*) (p + HTSF_HOSTOFFSET + 12); ++ if (htsf_ts->magic == HTSFMAGIC) { ++ htsf_ts->c20 = get_cycles(); ++ htsf_ts->t20 = dhd_get_htsf(bus->dhd->info, 0); ++ } ++ } ++#endif /* WLMEDIA_HTSF */ ++ ++ /* Add alignment padding, allocate new packet if needed */ ++ if (!((uintptr)frame & 1) && (pad1 = ((uintptr)frame % DHD_SDALIGN))) { ++ if (PKTHEADROOM(osh, pkt) < pad1) { ++ AP6211_ERR("%s: insufficient headroom %d for %d pad1\n", ++ __FUNCTION__, (int)PKTHEADROOM(osh, pkt), pad1); ++ bus->dhd->tx_realloc++; ++ new = PKTGET(osh, (PKTLEN(osh, pkt) + DHD_SDALIGN), TRUE); ++ if (!new) { ++ AP6211_ERR("%s: couldn't allocate new %d-byte packet\n", ++ __FUNCTION__, PKTLEN(osh, pkt) + DHD_SDALIGN); ++ ret = BCME_NOMEM; ++ goto done; ++ } ++ ++ PKTALIGN(osh, new, PKTLEN(osh, pkt), DHD_SDALIGN); ++ bcopy(PKTDATA(osh, pkt), PKTDATA(osh, new), PKTLEN(osh, pkt)); ++ if (free_pkt) ++ PKTFREE(osh, pkt, TRUE); ++ /* free the pkt if canned one is not used */ ++ free_pkt = TRUE; ++ pkt = new; ++ frame = (uint8*)PKTDATA(osh, pkt); ++ ASSERT(((uintptr)frame % DHD_SDALIGN) == 0); ++ pad1 = 0; ++ } else { ++ PKTPUSH(osh, pkt, pad1); ++ frame = (uint8*)PKTDATA(osh, pkt); ++ ++ ASSERT((pad1 + SDPCM_HDRLEN) <= (int) PKTLEN(osh, pkt)); ++ bzero(frame, pad1 + SDPCM_HDRLEN); ++ } ++ } ++ ASSERT(pad1 < DHD_SDALIGN); ++ ++ /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */ ++ len = (uint16)PKTLEN(osh, pkt); ++ *(uint16*)frame = htol16(len); ++ *(((uint16*)frame) + 1) = htol16(~len); ++ ++#ifdef BCMSDIOH_TXGLOM ++ if (bus->glom_enable) { ++ uint32 hwheader1 = 0, hwheader2 = 0, act_len = len; ++ ++ /* Software tag: channel, sequence number, data offset */ ++ swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | ++ ((bus->tx_seq + bus->glom_cnt) % SDPCM_SEQUENCE_WRAP) | ++ (((pad1 + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); ++ htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN); ++ htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN + sizeof(swheader)); ++ ++ if (queue_only) { ++ if (forcealign && (len & (ALIGNMENT - 1))) ++ len = ROUNDUP(len, ALIGNMENT); ++ /* Hardware extention tag */ ++ /* 2byte frame length, 1byte-, 1byte frame flag, ++ * 2byte-hdrlength, 2byte padlenght ++ */ ++ hwheader1 = (act_len - SDPCM_FRAMETAG_LEN) | (0 << 24); ++ hwheader2 = (len - act_len) << 16; ++ htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN); ++ htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4); ++ /* Post the frame pointer to sdio glom array */ ++ dhd_bcmsdh_glom_post(bus, frame, len); ++ /* Save the pkt pointer in bus glom array */ ++ bus->glom_pkt_arr[bus->glom_cnt] = pkt; ++ bus->glom_total_len += len; ++ bus->glom_cnt++; ++ return BCME_OK; ++ } else { ++ /* Raise len to next SDIO block to eliminate tail command */ ++ if (bus->roundup && bus->blocksize && ++ ((bus->glom_total_len + len) > bus->blocksize)) { ++ uint16 pad2 = bus->blocksize - ++ ((bus->glom_total_len + len) % bus->blocksize); ++ if ((pad2 <= bus->roundup) && (pad2 < bus->blocksize)) { ++ len += pad2; ++ } else { ++ } ++ } else if ((bus->glom_total_len + len) % DHD_SDALIGN) { ++ len += DHD_SDALIGN ++ - ((bus->glom_total_len + len) % DHD_SDALIGN); ++ } ++ if (forcealign && (len & (ALIGNMENT - 1))) { ++ len = ROUNDUP(len, ALIGNMENT); ++ } ++ ++ /* Hardware extention tag */ ++ /* 2byte frame length, 1byte-, 1byte frame flag, ++ * 2byte-hdrlength, 2byte padlenght ++ */ ++ hwheader1 = (act_len - SDPCM_FRAMETAG_LEN) | (1 << 24); ++ hwheader2 = (len - act_len) << 16; ++ htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN); ++ htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4); ++ ++ /* Post the frame pointer to sdio glom array */ ++ dhd_bcmsdh_glom_post(bus, frame, len); ++ /* Save the pkt pointer in bus glom array */ ++ bus->glom_pkt_arr[bus->glom_cnt] = pkt; ++ bus->glom_cnt++; ++ bus->glom_total_len += len; ++ ++ /* Update the total length on the first pkt */ ++ frame_tmp = (uint8*)PKTDATA(osh, bus->glom_pkt_arr[0]); ++ *(uint16*)frame_tmp = htol16(bus->glom_total_len); ++ *(((uint16*)frame_tmp) + 1) = htol16(~bus->glom_total_len); ++ } ++ } else ++#endif /* BCMSDIOH_TXGLOM */ ++ { ++ /* Software tag: channel, sequence number, data offset */ ++ swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq | ++ (((pad1 + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); ++ htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN); ++ htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader)); ++ ++#ifdef DHD_DEBUG ++ if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets)) { ++ tx_packets[PKTPRIO(pkt)]++; ++ } ++ if (DHD_BYTES_ON() && ++ (((DHD_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) || ++ (DHD_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) { ++ prhex("Tx Frame", frame, len); ++ } else if (DHD_HDRS_ON()) { ++ prhex("TxHdr", frame, MIN(len, 16)); ++ } ++#endif ++ ++ /* Raise len to next SDIO block to eliminate tail command */ ++ if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { ++ uint16 pad2 = bus->blocksize - (len % bus->blocksize); ++ if ((pad2 <= bus->roundup) && (pad2 < bus->blocksize)) ++#ifdef NOTUSED ++ if (pad2 <= PKTTAILROOM(osh, pkt)) ++#endif /* NOTUSED */ ++ len += pad2; ++ } else if (len % DHD_SDALIGN) { ++ len += DHD_SDALIGN - (len % DHD_SDALIGN); ++ } ++ ++ /* Some controllers have trouble with odd bytes -- round to even */ ++ if (forcealign && (len & (ALIGNMENT - 1))) { ++#ifdef NOTUSED ++ if (PKTTAILROOM(osh, pkt)) ++#endif ++ len = ROUNDUP(len, ALIGNMENT); ++#ifdef NOTUSED ++ else ++ AP6211_DEBUG("%s: sending unrounded %d-byte packet\n", __FUNCTION__, len); ++#endif ++ } ++ } ++ ++ do { ++ ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, ++ frame, len, pkt, NULL, NULL); ++ bus->f2txdata++; ++ ASSERT(ret != BCME_PENDING); ++ ++ if (ret == BCME_NODEVICE) { ++ AP6211_ERR("%s: Device asleep already\n", __FUNCTION__); ++ } else if (ret < 0) { ++ /* On failure, abort the command and terminate the frame */ ++ AP6211_ERR("%s: sdio error %d, abort command and terminate frame.\n", ++ __FUNCTION__, ret); ++ bus->tx_sderrs++; ++ ++ bcmsdh_abort(sdh, SDIO_FUNC_2); ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, ++ SFC_WF_TERM, NULL); ++ bus->f1regdata++; ++ ++ for (i = 0; i < 3; i++) { ++ uint8 hi, lo; ++ hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_WFRAMEBCHI, NULL); ++ lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_WFRAMEBCLO, NULL); ++ bus->f1regdata += 2; ++ if ((hi == 0) && (lo == 0)) ++ break; ++ } ++ } ++ if (ret == 0) { ++#ifdef BCMSDIOH_TXGLOM ++ if (bus->glom_enable) { ++ bus->tx_seq = (bus->tx_seq + bus->glom_cnt) % SDPCM_SEQUENCE_WRAP; ++ } else ++#endif ++ { ++ bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; ++ } ++ } ++ } while ((ret < 0) && retrydata && retries++ < TXRETRIES); ++ ++done: ++ ++#ifdef BCMSDIOH_TXGLOM ++ if (bus->glom_enable) { ++ dhd_bcmsdh_glom_clear(bus); ++ pkt_cnt = bus->glom_cnt; ++ } else ++#endif ++ { ++ pkt_cnt = 1; ++ } ++ /* restore pkt buffer pointer before calling tx complete routine */ ++ while (pkt_cnt) { ++#ifdef BCMSDIOH_TXGLOM ++ uint32 doff; ++ if (bus->glom_enable) { ++ pkt = bus->glom_pkt_arr[bus->glom_cnt - pkt_cnt]; ++ frame = (uint8*)PKTDATA(osh, pkt); ++ doff = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN); ++ doff = (doff & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT; ++ PKTPULL(osh, pkt, doff); ++ } else ++#endif ++ { ++ PKTPULL(osh, pkt, SDPCM_HDRLEN + pad1); ++ } ++#ifdef PROP_TXSTATUS ++ if (bus->dhd->wlfc_state) { ++ dhd_os_sdunlock(bus->dhd); ++ dhd_wlfc_txcomplete(bus->dhd, pkt, ret == 0, FALSE); ++ dhd_os_sdlock(bus->dhd); ++ } else { ++#endif /* PROP_TXSTATUS */ ++#ifdef SDTEST ++ if (chan != SDPCM_TEST_CHANNEL) { ++ dhd_txcomplete(bus->dhd, pkt, ret != 0); ++ } ++#else /* SDTEST */ ++ dhd_txcomplete(bus->dhd, pkt, ret != 0); ++#endif /* SDTEST */ ++ if (free_pkt) ++ PKTFREE(osh, pkt, TRUE); ++ ++#ifdef PROP_TXSTATUS ++ } ++#endif ++ pkt_cnt--; ++ } ++ ++#ifdef BCMSDIOH_TXGLOM ++ /* Reset the glom array */ ++ if (bus->glom_enable) { ++ bus->glom_cnt = 0; ++ bus->glom_total_len = 0; ++ } ++#endif ++ return ret; ++} ++ ++int ++dhd_bus_txdata(struct dhd_bus *bus, void *pkt, bool wlfc_locked) ++{ ++ int ret = BCME_ERROR; ++ osl_t *osh; ++ uint datalen, prec; ++#ifdef DHD_TX_DUMP ++ uint8 *dump_data; ++ uint16 protocol; ++#ifdef DHD_TX_FULL_DUMP ++ int i; ++#endif /* DHD_TX_FULL_DUMP */ ++#endif /* DHD_TX_DUMP */ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ osh = bus->dhd->osh; ++ datalen = PKTLEN(osh, pkt); ++ ++#ifdef SDTEST ++ /* Push the test header if doing loopback */ ++ if (bus->ext_loop) { ++ uint8* data; ++ PKTPUSH(osh, pkt, SDPCM_TEST_HDRLEN); ++ data = PKTDATA(osh, pkt); ++ *data++ = SDPCM_TEST_ECHOREQ; ++ *data++ = (uint8)bus->loopid++; ++ *data++ = (datalen >> 0); ++ *data++ = (datalen >> 8); ++ datalen += SDPCM_TEST_HDRLEN; ++ } ++#endif /* SDTEST */ ++ ++#ifdef DHD_TX_DUMP ++ dump_data = PKTDATA(osh, pkt); ++ dump_data += 4; /* skip 4 bytes header */ ++ protocol = (dump_data[12] << 8) | dump_data[13]; ++#ifdef DHD_TX_FULL_DUMP ++ AP6211_DEBUG("TX DUMP\n"); ++ ++ for (i = 0; i < (datalen - 4); i++) { ++ DHD_CONT("%02X ", dump_data[i]); ++ if ((i & 15) == 15) ++ DHD_CONT("\n"); ++ } ++ AP6211_DEBUG("\n"); ++ ++#endif /* DHD_TX_FULL_DUMP */ ++ if (protocol == ETHER_TYPE_802_1X) { ++ AP6211_DEBUG("ETHER_TYPE_802_1X: ver %d, type %d, replay %d\n", ++ dump_data[14], dump_data[15], dump_data[30]); ++ } ++#endif /* DHD_TX_DUMP */ ++ ++ /* Add space for the header */ ++ PKTPUSH(osh, pkt, SDPCM_HDRLEN); ++ ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2)); ++ ++ prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK)); ++#ifndef DHDTHREAD ++ /* Lock: we're about to use shared data/code (and SDIO) */ ++ dhd_os_sdlock(bus->dhd); ++#endif /* DHDTHREAD */ ++ ++ /* Check for existing queue, current flow-control, pending event, or pending clock */ ++ if (dhd_deferred_tx || bus->fcstate || pktq_len(&bus->txq) || bus->dpc_sched || ++ (!DATAOK(bus)) || (bus->flowcontrol & NBITVAL(prec)) || ++ (bus->clkstate != CLK_AVAIL)) { ++ AP6211_DEBUG("%s: deferring pktq len %d\n", __FUNCTION__, ++ pktq_len(&bus->txq)); ++ bus->fcqueued++; ++ ++ /* Priority based enq */ ++ dhd_os_sdlock_txq(bus->dhd); ++ if (dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec) == FALSE) { ++ PKTPULL(osh, pkt, SDPCM_HDRLEN); ++#ifndef DHDTHREAD ++ /* Need to also release txqlock before releasing sdlock. ++ * This thread still has txqlock and releases sdlock. ++ * Deadlock happens when dpc() grabs sdlock first then ++ * attempts to grab txqlock. ++ */ ++ dhd_os_sdunlock_txq(bus->dhd); ++ dhd_os_sdunlock(bus->dhd); ++#endif ++#ifdef PROP_TXSTATUS ++ if (bus->dhd->wlfc_state) ++ dhd_wlfc_txcomplete(bus->dhd, pkt, FALSE, wlfc_locked); ++ else ++#endif ++ dhd_txcomplete(bus->dhd, pkt, FALSE); ++#ifndef DHDTHREAD ++ dhd_os_sdlock(bus->dhd); ++ dhd_os_sdlock_txq(bus->dhd); ++#endif ++#ifdef PROP_TXSTATUS ++ /* let the caller decide whether to free the packet */ ++ if (!bus->dhd->wlfc_state) ++#endif ++ PKTFREE(osh, pkt, TRUE); ++ ret = BCME_NORESOURCE; ++ } ++ else ++ ret = BCME_OK; ++ dhd_os_sdunlock_txq(bus->dhd); ++ ++ if ((pktq_len(&bus->txq) >= FCHI) && dhd_doflow) ++ dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON); ++ ++#ifdef DHD_DEBUG ++ if (pktq_plen(&bus->txq, prec) > qcount[prec]) ++ qcount[prec] = pktq_plen(&bus->txq, prec); ++#endif ++ /* Schedule DPC if needed to send queued packet(s) */ ++ if (dhd_deferred_tx && !bus->dpc_sched) { ++ bus->dpc_sched = TRUE; ++ dhd_sched_dpc(bus->dhd); ++ } ++ } else { ++#ifdef DHDTHREAD ++ /* Lock: we're about to use shared data/code (and SDIO) */ ++ dhd_os_sdlock(bus->dhd); ++#endif /* DHDTHREAD */ ++ ++ /* Otherwise, send it now */ ++ BUS_WAKE(bus); ++ /* Make sure back plane ht clk is on, no pending allowed */ ++ dhdsdio_clkctl(bus, CLK_AVAIL, TRUE); ++#ifndef SDTEST ++ ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE, FALSE); ++#else ++ ret = dhdsdio_txpkt(bus, pkt, ++ (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), TRUE, FALSE); ++#endif ++ if (ret) ++ bus->dhd->tx_errors++; ++ else ++ bus->dhd->dstats.tx_bytes += datalen; ++ ++ if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { ++ bus->activity = FALSE; ++ dhdsdio_clkctl(bus, CLK_NONE, TRUE); ++ } ++ ++#ifdef DHDTHREAD ++ dhd_os_sdunlock(bus->dhd); ++#endif /* DHDTHREAD */ ++ } ++ ++#ifndef DHDTHREAD ++ dhd_os_sdunlock(bus->dhd); ++#endif /* DHDTHREAD */ ++ ++ return ret; ++} ++ ++static uint ++dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes) ++{ ++ void *pkt; ++ uint32 intstatus = 0; ++ uint retries = 0; ++ int ret = 0, prec_out; ++ uint cnt = 0; ++ uint datalen; ++ uint8 tx_prec_map; ++#ifdef BCMSDIOH_TXGLOM ++ uint i; ++ uint8 glom_cnt; ++#endif ++ ++ dhd_pub_t *dhd = bus->dhd; ++ sdpcmd_regs_t *regs = bus->regs; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ if (!KSO_ENAB(bus)) { ++ AP6211_DEBUG("%s: Device asleep\n", __FUNCTION__); ++ return BCME_NODEVICE; ++ } ++ ++ tx_prec_map = ~bus->flowcontrol; ++ ++ /* Send frames until the limit or some other event */ ++ for (cnt = 0; (cnt < maxframes) && DATAOK(bus); cnt++) { ++#ifdef BCMSDIOH_TXGLOM ++ if (bus->glom_enable) { ++ glom_cnt = MIN(DATABUFCNT(bus), bus->glomsize); ++ glom_cnt = MIN(glom_cnt, pktq_mlen(&bus->txq, tx_prec_map)); ++ glom_cnt = MIN(glom_cnt, maxframes-cnt); ++ ++ /* Limiting the size to 2pkts in case of copy */ ++ if (bus->glom_mode == SDPCM_TXGLOM_CPY) ++ glom_cnt = MIN(glom_cnt, 5); ++ ++ if (glom_cnt == 0) ++ break; ++ datalen = 0; ++ for (i = 0; i < glom_cnt; i++) { ++ dhd_os_sdlock_txq(bus->dhd); ++ if ((pkt = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out)) == NULL) { ++ /* This case should not happen */ ++ AP6211_DEBUG("No pkts in the queue for glomming\n"); ++ dhd_os_sdunlock_txq(bus->dhd); ++ break; ++ } ++ dhd_os_sdunlock_txq(bus->dhd); ++ ++ datalen += (PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN); ++#ifndef SDTEST ++ ret = dhdsdio_txpkt(bus, ++ pkt, ++ SDPCM_DATA_CHANNEL, ++ TRUE, ++ (i == (glom_cnt-1))? FALSE: TRUE); ++#else ++ ret = dhdsdio_txpkt(bus, ++ pkt, ++ (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), ++ TRUE, ++ (i == (glom_cnt-1))? FALSE: TRUE); ++#endif ++ } ++ cnt += i-1; ++ } else ++#endif /* BCMSDIOH_TXGLOM */ ++ { ++ dhd_os_sdlock_txq(bus->dhd); ++ if ((pkt = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out)) == NULL) { ++ dhd_os_sdunlock_txq(bus->dhd); ++ break; ++ } ++ dhd_os_sdunlock_txq(bus->dhd); ++ datalen = PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN; ++ ++#ifndef SDTEST ++ ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE, FALSE); ++#else ++ ret = dhdsdio_txpkt(bus, ++ pkt, ++ (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), ++ TRUE, ++ FALSE); ++#endif ++ } ++ ++ if (ret) ++ bus->dhd->tx_errors++; ++ else ++ bus->dhd->dstats.tx_bytes += datalen; ++ ++ /* In poll mode, need to check for other events */ ++ if (!bus->intr && cnt) ++ { ++ /* Check device status, signal pending interrupt */ ++ R_SDREG(intstatus, ®s->intstatus, retries); ++ bus->f2txdata++; ++ if (bcmsdh_regfail(bus->sdh)) ++ break; ++ if (intstatus & bus->hostintmask) ++ bus->ipend = TRUE; ++ } ++ } ++ ++ /* Deflow-control stack if needed */ ++ if (dhd_doflow && dhd->up && (dhd->busstate == DHD_BUS_DATA) && ++ dhd->txoff && (pktq_len(&bus->txq) < FCLOW)) ++ dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF); ++ ++ return cnt; ++} ++ ++int ++dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen) ++{ ++ uint8 *frame; ++ uint16 len; ++ uint32 swheader; ++ uint retries = 0; ++ bcmsdh_info_t *sdh = bus->sdh; ++ uint8 doff = 0; ++ int ret = -1; ++ int i; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ if (bus->dhd->dongle_reset) ++ return -EIO; ++ ++ /* Back the pointer to make a room for bus header */ ++ frame = msg - SDPCM_HDRLEN; ++ len = (msglen += SDPCM_HDRLEN); ++ ++ /* Add alignment padding (optional for ctl frames) */ ++ if (dhd_alignctl) { ++ if ((doff = ((uintptr)frame % DHD_SDALIGN))) { ++ frame -= doff; ++ len += doff; ++ msglen += doff; ++ bzero(frame, doff + SDPCM_HDRLEN); ++ } ++ ASSERT(doff < DHD_SDALIGN); ++ } ++ doff += SDPCM_HDRLEN; ++ ++ /* Round send length to next SDIO block */ ++ if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { ++ uint16 pad = bus->blocksize - (len % bus->blocksize); ++ if ((pad <= bus->roundup) && (pad < bus->blocksize)) ++ len += pad; ++ } else if (len % DHD_SDALIGN) { ++ len += DHD_SDALIGN - (len % DHD_SDALIGN); ++ } ++ ++ /* Satisfy length-alignment requirements */ ++ if (forcealign && (len & (ALIGNMENT - 1))) ++ len = ROUNDUP(len, ALIGNMENT); ++ ++ ASSERT(ISALIGNED((uintptr)frame, 2)); ++ ++ ++ /* Need to lock here to protect txseq and SDIO tx calls */ ++ dhd_os_sdlock(bus->dhd); ++ ++ BUS_WAKE(bus); ++ ++ /* Make sure backplane clock is on */ ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ ++ /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */ ++ *(uint16*)frame = htol16((uint16)msglen); ++ *(((uint16*)frame) + 1) = htol16(~msglen); ++ ++#ifdef BCMSDIOH_TXGLOM ++ if (bus->glom_enable) { ++ uint32 hwheader1, hwheader2; ++ /* Software tag: channel, sequence number, data offset */ ++ swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) ++ | bus->tx_seq ++ | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); ++ htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN); ++ htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN ++ + SDPCM_HWEXT_LEN + sizeof(swheader)); ++ ++ hwheader1 = (msglen - SDPCM_FRAMETAG_LEN) | (1 << 24); ++ hwheader2 = (len - (msglen)) << 16; ++ htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN); ++ htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4); ++ ++ *(uint16*)frame = htol16(len); ++ *(((uint16*)frame) + 1) = htol16(~(len)); ++ } else ++#endif /* BCMSDIOH_TXGLOM */ ++ { ++ /* Software tag: channel, sequence number, data offset */ ++ swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) ++ | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); ++ htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN); ++ htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader)); ++ } ++ if (!TXCTLOK(bus)) { ++ AP6211_DEBUG("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n", ++ __FUNCTION__, bus->tx_max, bus->tx_seq); ++ bus->ctrl_frame_stat = TRUE; ++ /* Send from dpc */ ++ bus->ctrl_frame_buf = frame; ++ bus->ctrl_frame_len = len; ++ ++ if (!bus->dpc_sched) { ++ bus->dpc_sched = TRUE; ++ dhd_sched_dpc(bus->dhd); ++ } ++ if (bus->ctrl_frame_stat) { ++ dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat); ++ } ++ ++ if (bus->ctrl_frame_stat == FALSE) { ++ AP6211_DEBUG("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__); ++ ret = 0; ++ } else { ++ bus->dhd->txcnt_timeout++; ++ if (!bus->dhd->hang_was_sent) { ++ AP6211_DEBUG("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n", ++ __FUNCTION__, bus->dhd->txcnt_timeout); ++ } ++ ret = -1; ++ bus->ctrl_frame_stat = FALSE; ++ goto done; ++ } ++ } ++ ++ bus->dhd->txcnt_timeout = 0; ++ ++ if (ret == -1) { ++#ifdef DHD_DEBUG ++ if (DHD_BYTES_ON() && DHD_CTL_ON()) { ++ prhex("Tx Frame", frame, len); ++ } else if (DHD_HDRS_ON()) { ++ prhex("TxHdr", frame, MIN(len, 16)); ++ } ++#endif ++ ++ do { ++ ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, ++ frame, len, NULL, NULL, NULL); ++ ASSERT(ret != BCME_PENDING); ++ ++ if (ret == BCME_NODEVICE) { ++ AP6211_DEBUG("%s: Device asleep already\n", __FUNCTION__); ++ } else if (ret < 0) { ++ /* On failure, abort the command and terminate the frame */ ++ AP6211_DEBUG("%s: sdio error %d, abort command and terminate frame.\n", ++ __FUNCTION__, ret); ++ bus->tx_sderrs++; ++ ++ bcmsdh_abort(sdh, SDIO_FUNC_2); ++ ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, ++ SFC_WF_TERM, NULL); ++ bus->f1regdata++; ++ ++ for (i = 0; i < 3; i++) { ++ uint8 hi, lo; ++ hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_WFRAMEBCHI, NULL); ++ lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_WFRAMEBCLO, NULL); ++ bus->f1regdata += 2; ++ if ((hi == 0) && (lo == 0)) ++ break; ++ } ++ } ++ if (ret == 0) { ++ bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; ++ } ++ } while ((ret < 0) && retries++ < TXRETRIES); ++ } ++ ++done: ++ if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { ++ bus->activity = FALSE; ++ dhdsdio_clkctl(bus, CLK_NONE, TRUE); ++ } ++ ++ dhd_os_sdunlock(bus->dhd); ++ ++ if (ret) ++ bus->dhd->tx_ctlerrs++; ++ else ++ bus->dhd->tx_ctlpkts++; ++ ++ if (bus->dhd->txcnt_timeout >= MAX_CNTL_TIMEOUT) ++ return -ETIMEDOUT; ++ ++ return ret ? -EIO : 0; ++} ++ ++int ++dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen) ++{ ++ int timeleft; ++ uint rxlen = 0; ++ bool pending; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ if (bus->dhd->dongle_reset) ++ return -EIO; ++ ++ /* Wait until control frame is available */ ++ timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen, &pending); ++ ++ dhd_os_sdlock(bus->dhd); ++ rxlen = bus->rxlen; ++ bcopy(bus->rxctl, msg, MIN(msglen, rxlen)); ++ bus->rxlen = 0; ++ dhd_os_sdunlock(bus->dhd); ++ ++ if (rxlen) { ++ AP6211_DEBUG("%s: resumed on rxctl frame, got %d expected %d\n", ++ __FUNCTION__, rxlen, msglen); ++ } else if (timeleft == 0) { ++#ifdef DHD_DEBUG ++ uint32 status, retry = 0; ++ R_SDREG(status, &bus->regs->intstatus, retry); ++ AP6211_DEBUG("%s: resumed on timeout, INT status=0x%08X\n", ++ __FUNCTION__, status); ++#else ++ AP6211_DEBUG("%s: resumed on timeout\n", __FUNCTION__); ++#endif /* DHD_DEBUG */ ++#ifdef DHD_DEBUG ++ dhd_os_sdlock(bus->dhd); ++ dhdsdio_checkdied(bus, NULL, 0); ++ dhd_os_sdunlock(bus->dhd); ++#endif /* DHD_DEBUG */ ++ } else if (pending == TRUE) { ++ /* signal pending */ ++ AP6211_DEBUG("%s: signal pending\n", __FUNCTION__); ++ return -EINTR; ++ } else { ++ AP6211_DEBUG("%s: resumed for unknown reason?\n", __FUNCTION__); ++#ifdef DHD_DEBUG ++ dhd_os_sdlock(bus->dhd); ++ dhdsdio_checkdied(bus, NULL, 0); ++ dhd_os_sdunlock(bus->dhd); ++#endif /* DHD_DEBUG */ ++ } ++ if (timeleft == 0) { ++ bus->dhd->rxcnt_timeout++; ++ AP6211_DEBUG("%s: rxcnt_timeout=%d\n", __FUNCTION__, bus->dhd->rxcnt_timeout); ++ } ++ else ++ bus->dhd->rxcnt_timeout = 0; ++ ++ if (rxlen) ++ bus->dhd->rx_ctlpkts++; ++ else ++ bus->dhd->rx_ctlerrs++; ++ ++ if (bus->dhd->rxcnt_timeout >= MAX_CNTL_TIMEOUT) ++ return -ETIMEDOUT; ++ ++ if (bus->dhd->dongle_trap_occured) ++ return -EREMOTEIO; ++ ++ return rxlen ? (int)rxlen : -EIO; ++} ++ ++/* IOVar table */ ++enum { ++ IOV_INTR = 1, ++ IOV_POLLRATE, ++ IOV_SDREG, ++ IOV_SBREG, ++ IOV_SDCIS, ++ IOV_MEMBYTES, ++ IOV_MEMSIZE, ++#ifdef DHD_DEBUG ++ IOV_CHECKDIED, ++ IOV_SERIALCONS, ++#endif /* DHD_DEBUG */ ++ IOV_SET_DOWNLOAD_STATE, ++ IOV_SOCRAM_STATE, ++ IOV_FORCEEVEN, ++ IOV_SDIOD_DRIVE, ++ IOV_READAHEAD, ++ IOV_SDRXCHAIN, ++ IOV_ALIGNCTL, ++ IOV_SDALIGN, ++ IOV_DEVRESET, ++ IOV_CPU, ++#if defined(SDIO_CRC_ERROR_FIX) ++ IOV_WATERMARK, ++ IOV_MESBUSYCTRL, ++#endif /* SDIO_CRC_ERROR_FIX */ ++#ifdef SDTEST ++ IOV_PKTGEN, ++ IOV_EXTLOOP, ++#endif /* SDTEST */ ++ IOV_SPROM, ++ IOV_TXBOUND, ++ IOV_RXBOUND, ++ IOV_TXMINMAX, ++ IOV_IDLETIME, ++ IOV_IDLECLOCK, ++ IOV_SD1IDLE, ++ IOV_SLEEP, ++ IOV_DONGLEISOLATION, ++ IOV_KSO, ++ IOV_DEVSLEEP, ++ IOV_DEVCAP, ++ IOV_VARS, ++#ifdef SOFTAP ++ IOV_FWPATH, ++#endif ++ IOV_TXGLOMSIZE, ++ IOV_TXGLOMMODE ++}; ++ ++const bcm_iovar_t dhdsdio_iovars[] = { ++ {"intr", IOV_INTR, 0, IOVT_BOOL, 0 }, ++ {"sleep", IOV_SLEEP, 0, IOVT_BOOL, 0 }, ++ {"pollrate", IOV_POLLRATE, 0, IOVT_UINT32, 0 }, ++ {"idletime", IOV_IDLETIME, 0, IOVT_INT32, 0 }, ++ {"idleclock", IOV_IDLECLOCK, 0, IOVT_INT32, 0 }, ++ {"sd1idle", IOV_SD1IDLE, 0, IOVT_BOOL, 0 }, ++ {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) }, ++ {"memsize", IOV_MEMSIZE, 0, IOVT_UINT32, 0 }, ++ {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, IOVT_BOOL, 0 }, ++ {"socram_state", IOV_SOCRAM_STATE, 0, IOVT_BOOL, 0 }, ++ {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 }, ++ {"sdiod_drive", IOV_SDIOD_DRIVE, 0, IOVT_UINT32, 0 }, ++ {"readahead", IOV_READAHEAD, 0, IOVT_BOOL, 0 }, ++ {"sdrxchain", IOV_SDRXCHAIN, 0, IOVT_BOOL, 0 }, ++ {"alignctl", IOV_ALIGNCTL, 0, IOVT_BOOL, 0 }, ++ {"sdalign", IOV_SDALIGN, 0, IOVT_BOOL, 0 }, ++ {"devreset", IOV_DEVRESET, 0, IOVT_BOOL, 0 }, ++#ifdef DHD_DEBUG ++ {"sdreg", IOV_SDREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, ++ {"sbreg", IOV_SBREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, ++ {"sd_cis", IOV_SDCIS, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN }, ++ {"forcealign", IOV_FORCEEVEN, 0, IOVT_BOOL, 0 }, ++ {"txbound", IOV_TXBOUND, 0, IOVT_UINT32, 0 }, ++ {"rxbound", IOV_RXBOUND, 0, IOVT_UINT32, 0 }, ++ {"txminmax", IOV_TXMINMAX, 0, IOVT_UINT32, 0 }, ++ {"cpu", IOV_CPU, 0, IOVT_BOOL, 0 }, ++#ifdef DHD_DEBUG ++ {"checkdied", IOV_CHECKDIED, 0, IOVT_BUFFER, 0 }, ++ {"serial", IOV_SERIALCONS, 0, IOVT_UINT32, 0 }, ++#endif /* DHD_DEBUG */ ++#endif /* DHD_DEBUG */ ++#ifdef SDTEST ++ {"extloop", IOV_EXTLOOP, 0, IOVT_BOOL, 0 }, ++ {"pktgen", IOV_PKTGEN, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t) }, ++#endif /* SDTEST */ ++#if defined(SDIO_CRC_ERROR_FIX) ++ {"watermark", IOV_WATERMARK, 0, IOVT_UINT32, 0 }, ++ {"mesbusyctrl", IOV_MESBUSYCTRL, 0, IOVT_UINT32, 0 }, ++#endif /* SDIO_CRC_ERROR_FIX */ ++ {"devcap", IOV_DEVCAP, 0, IOVT_UINT32, 0 }, ++ {"dngl_isolation", IOV_DONGLEISOLATION, 0, IOVT_UINT32, 0 }, ++ {"kso", IOV_KSO, 0, IOVT_UINT32, 0 }, ++ {"devsleep", IOV_DEVSLEEP, 0, IOVT_UINT32, 0 }, ++#ifdef SOFTAP ++ {"fwpath", IOV_FWPATH, 0, IOVT_BUFFER, 0 }, ++#endif ++ {"txglomsize", IOV_TXGLOMSIZE, 0, IOVT_UINT32, 0 }, ++ {"txglommode", IOV_TXGLOMMODE, 0, IOVT_UINT32, 0 }, ++ {NULL, 0, 0, 0, 0 } ++}; ++ ++static void ++dhd_dump_pct(struct bcmstrbuf *strbuf, char *desc, uint num, uint div) ++{ ++ uint q1, q2; ++ ++ if (!div) { ++ bcm_bprintf(strbuf, "%s N/A", desc); ++ } else { ++ q1 = num / div; ++ q2 = (100 * (num - (q1 * div))) / div; ++ bcm_bprintf(strbuf, "%s %d.%02d", desc, q1, q2); ++ } ++} ++ ++void ++dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ ++ bcm_bprintf(strbuf, "Bus SDIO structure:\n"); ++ bcm_bprintf(strbuf, "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n", ++ bus->hostintmask, bus->intstatus, bus->sdpcm_ver); ++ bcm_bprintf(strbuf, "fcstate %d qlen %d tx_seq %d, max %d, rxskip %d rxlen %d rx_seq %d\n", ++ bus->fcstate, pktq_len(&bus->txq), bus->tx_seq, bus->tx_max, bus->rxskip, ++ bus->rxlen, bus->rx_seq); ++ bcm_bprintf(strbuf, "intr %d intrcount %d lastintrs %d spurious %d\n", ++ bus->intr, bus->intrcount, bus->lastintrs, bus->spurious); ++ bcm_bprintf(strbuf, "pollrate %d pollcnt %d regfails %d\n", ++ bus->pollrate, bus->pollcnt, bus->regfails); ++ ++ bcm_bprintf(strbuf, "\nAdditional counters:\n"); ++ bcm_bprintf(strbuf, "tx_sderrs %d fcqueued %d rxrtx %d rx_toolong %d rxc_errors %d\n", ++ bus->tx_sderrs, bus->fcqueued, bus->rxrtx, bus->rx_toolong, ++ bus->rxc_errors); ++ bcm_bprintf(strbuf, "rx_hdrfail %d badhdr %d badseq %d\n", ++ bus->rx_hdrfail, bus->rx_badhdr, bus->rx_badseq); ++ bcm_bprintf(strbuf, "fc_rcvd %d, fc_xoff %d, fc_xon %d\n", ++ bus->fc_rcvd, bus->fc_xoff, bus->fc_xon); ++ bcm_bprintf(strbuf, "rxglomfail %d, rxglomframes %d, rxglompkts %d\n", ++ bus->rxglomfail, bus->rxglomframes, bus->rxglompkts); ++ bcm_bprintf(strbuf, "f2rx (hdrs/data) %d (%d/%d), f2tx %d f1regs %d\n", ++ (bus->f2rxhdrs + bus->f2rxdata), bus->f2rxhdrs, bus->f2rxdata, ++ bus->f2txdata, bus->f1regdata); ++ { ++ dhd_dump_pct(strbuf, "\nRx: pkts/f2rd", bus->dhd->rx_packets, ++ (bus->f2rxhdrs + bus->f2rxdata)); ++ dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->rx_packets, bus->f1regdata); ++ dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->rx_packets, ++ (bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata)); ++ dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->rx_packets, bus->intrcount); ++ bcm_bprintf(strbuf, "\n"); ++ ++ dhd_dump_pct(strbuf, "Rx: glom pct", (100 * bus->rxglompkts), ++ bus->dhd->rx_packets); ++ dhd_dump_pct(strbuf, ", pkts/glom", bus->rxglompkts, bus->rxglomframes); ++ bcm_bprintf(strbuf, "\n"); ++ ++ dhd_dump_pct(strbuf, "Tx: pkts/f2wr", bus->dhd->tx_packets, bus->f2txdata); ++ dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->tx_packets, bus->f1regdata); ++ dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->tx_packets, ++ (bus->f2txdata + bus->f1regdata)); ++ dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->tx_packets, bus->intrcount); ++ bcm_bprintf(strbuf, "\n"); ++ ++ dhd_dump_pct(strbuf, "Total: pkts/f2rw", ++ (bus->dhd->tx_packets + bus->dhd->rx_packets), ++ (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata)); ++ dhd_dump_pct(strbuf, ", pkts/f1sd", ++ (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->f1regdata); ++ dhd_dump_pct(strbuf, ", pkts/sd", ++ (bus->dhd->tx_packets + bus->dhd->rx_packets), ++ (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata)); ++ dhd_dump_pct(strbuf, ", pkts/int", ++ (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->intrcount); ++ bcm_bprintf(strbuf, "\n\n"); ++ } ++ ++#ifdef SDTEST ++ if (bus->pktgen_count) { ++ bcm_bprintf(strbuf, "pktgen config and count:\n"); ++ bcm_bprintf(strbuf, "freq %d count %d print %d total %d min %d len %d\n", ++ bus->pktgen_freq, bus->pktgen_count, bus->pktgen_print, ++ bus->pktgen_total, bus->pktgen_minlen, bus->pktgen_maxlen); ++ bcm_bprintf(strbuf, "send attempts %d rcvd %d fail %d\n", ++ bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail); ++ } ++#endif /* SDTEST */ ++#ifdef DHD_DEBUG ++ bcm_bprintf(strbuf, "dpc_sched %d host interrupt%spending\n", ++ bus->dpc_sched, (bcmsdh_intr_pending(bus->sdh) ? " " : " not ")); ++ bcm_bprintf(strbuf, "blocksize %d roundup %d\n", bus->blocksize, bus->roundup); ++#endif /* DHD_DEBUG */ ++ bcm_bprintf(strbuf, "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n", ++ bus->clkstate, bus->activity, bus->idletime, bus->idlecount, bus->sleeping); ++} ++ ++void ++dhd_bus_clearcounts(dhd_pub_t *dhdp) ++{ ++ dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus; ++ ++ bus->intrcount = bus->lastintrs = bus->spurious = bus->regfails = 0; ++ bus->rxrtx = bus->rx_toolong = bus->rxc_errors = 0; ++ bus->rx_hdrfail = bus->rx_badhdr = bus->rx_badseq = 0; ++ bus->tx_sderrs = bus->fc_rcvd = bus->fc_xoff = bus->fc_xon = 0; ++ bus->rxglomfail = bus->rxglomframes = bus->rxglompkts = 0; ++ bus->f2rxhdrs = bus->f2rxdata = bus->f2txdata = bus->f1regdata = 0; ++} ++ ++#ifdef SDTEST ++static int ++dhdsdio_pktgen_get(dhd_bus_t *bus, uint8 *arg) ++{ ++ dhd_pktgen_t pktgen; ++ ++ pktgen.version = DHD_PKTGEN_VERSION; ++ pktgen.freq = bus->pktgen_freq; ++ pktgen.count = bus->pktgen_count; ++ pktgen.print = bus->pktgen_print; ++ pktgen.total = bus->pktgen_total; ++ pktgen.minlen = bus->pktgen_minlen; ++ pktgen.maxlen = bus->pktgen_maxlen; ++ pktgen.numsent = bus->pktgen_sent; ++ pktgen.numrcvd = bus->pktgen_rcvd; ++ pktgen.numfail = bus->pktgen_fail; ++ pktgen.mode = bus->pktgen_mode; ++ pktgen.stop = bus->pktgen_stop; ++ ++ bcopy(&pktgen, arg, sizeof(pktgen)); ++ ++ return 0; ++} ++ ++static int ++dhdsdio_pktgen_set(dhd_bus_t *bus, uint8 *arg) ++{ ++ dhd_pktgen_t pktgen; ++ uint oldcnt, oldmode; ++ ++ bcopy(arg, &pktgen, sizeof(pktgen)); ++ if (pktgen.version != DHD_PKTGEN_VERSION) ++ return BCME_BADARG; ++ ++ oldcnt = bus->pktgen_count; ++ oldmode = bus->pktgen_mode; ++ ++ bus->pktgen_freq = pktgen.freq; ++ bus->pktgen_count = pktgen.count; ++ bus->pktgen_print = pktgen.print; ++ bus->pktgen_total = pktgen.total; ++ bus->pktgen_minlen = pktgen.minlen; ++ bus->pktgen_maxlen = pktgen.maxlen; ++ bus->pktgen_mode = pktgen.mode; ++ bus->pktgen_stop = pktgen.stop; ++ ++ bus->pktgen_tick = bus->pktgen_ptick = 0; ++ bus->pktgen_prev_time = jiffies; ++ bus->pktgen_len = MAX(bus->pktgen_len, bus->pktgen_minlen); ++ bus->pktgen_len = MIN(bus->pktgen_len, bus->pktgen_maxlen); ++ ++ /* Clear counts for a new pktgen (mode change, or was stopped) */ ++ if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode)) { ++ bus->pktgen_sent = bus->pktgen_prev_sent = bus->pktgen_rcvd = 0; ++ bus->pktgen_prev_rcvd = bus->pktgen_fail = 0; ++ } ++ ++ return 0; ++} ++#endif /* SDTEST */ ++ ++static void ++dhdsdio_devram_remap(dhd_bus_t *bus, bool val) ++{ ++ uint8 enable, protect, remap; ++ ++ si_socdevram(bus->sih, FALSE, &enable, &protect, &remap); ++ remap = val ? TRUE : FALSE; ++ si_socdevram(bus->sih, TRUE, &enable, &protect, &remap); ++} ++ ++static int ++dhdsdio_membytes(dhd_bus_t *bus, bool write, uint32 address, uint8 *data, uint size) ++{ ++ int bcmerror = 0; ++ uint32 sdaddr; ++ uint dsize; ++ ++ /* In remap mode, adjust address beyond socram and redirect ++ * to devram at SOCDEVRAM_BP_ADDR since remap address > orig_ramsize ++ * is not backplane accessible ++ */ ++ if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address)) { ++ address -= bus->orig_ramsize; ++ address += SOCDEVRAM_BP_ADDR; ++ } ++ ++ /* Determine initial transfer parameters */ ++ sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK; ++ if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK) ++ dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr); ++ else ++ dsize = size; ++ ++ /* Set the backplane window to include the start address */ ++ if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) { ++ AP6211_ERR("%s: window change failed\n", __FUNCTION__); ++ goto xfer_done; ++ } ++ ++ /* Do the transfer(s) */ ++ while (size) { ++ AP6211_DEBUG("%s: %s %d bytes at offset 0x%08x in window 0x%08x\n", ++ __FUNCTION__, (write ? "write" : "read"), dsize, sdaddr, ++ (address & SBSDIO_SBWINDOW_MASK)); ++ if ((bcmerror = bcmsdh_rwdata(bus->sdh, write, sdaddr, data, dsize))) { ++ AP6211_ERR("%s: membytes transfer failed\n", __FUNCTION__); ++ break; ++ } ++ ++ /* Adjust for next transfer (if any) */ ++ if ((size -= dsize)) { ++ data += dsize; ++ address += dsize; ++ if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) { ++ AP6211_ERR("%s: window change failed\n", __FUNCTION__); ++ break; ++ } ++ sdaddr = 0; ++ dsize = MIN(SBSDIO_SB_OFT_ADDR_LIMIT, size); ++ } ++ ++ } ++ ++xfer_done: ++ /* Return the window to backplane enumeration space for core access */ ++ if (dhdsdio_set_siaddr_window(bus, bcmsdh_cur_sbwad(bus->sdh))) { ++ AP6211_ERR("%s: FAILED to set window back to 0x%x\n", __FUNCTION__, ++ bcmsdh_cur_sbwad(bus->sdh)); ++ } ++ ++ return bcmerror; ++} ++ ++#ifdef DHD_DEBUG ++static int ++dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh) ++{ ++ uint32 addr; ++ int rv, i; ++ uint32 shaddr = 0; ++ ++ shaddr = bus->dongle_ram_base + bus->ramsize - 4; ++ i = 0; ++ do { ++ /* Read last word in memory to determine address of sdpcm_shared structure */ ++ if ((rv = dhdsdio_membytes(bus, FALSE, shaddr, (uint8 *)&addr, 4)) < 0) ++ return rv; ++ ++ addr = ltoh32(addr); ++ ++ AP6211_DEBUG("sdpcm_shared address 0x%08X\n", addr); ++ ++ /* ++ * Check if addr is valid. ++ * NVRAM length at the end of memory should have been overwritten. ++ */ ++ if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) { ++ if ((bus->srmemsize > 0) && (i++ == 0)) { ++ shaddr -= bus->srmemsize; ++ } else { ++ AP6211_ERR("%s: address (0x%08x) of sdpcm_shared invalid\n", ++ __FUNCTION__, addr); ++ return BCME_ERROR; ++ } ++ } else ++ break; ++ } while (i < 2); ++ ++ /* Read hndrte_shared structure */ ++ if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)sh, sizeof(sdpcm_shared_t))) < 0) ++ return rv; ++ ++ /* Endianness */ ++ sh->flags = ltoh32(sh->flags); ++ sh->trap_addr = ltoh32(sh->trap_addr); ++ sh->assert_exp_addr = ltoh32(sh->assert_exp_addr); ++ sh->assert_file_addr = ltoh32(sh->assert_file_addr); ++ sh->assert_line = ltoh32(sh->assert_line); ++ sh->console_addr = ltoh32(sh->console_addr); ++ sh->msgtrace_addr = ltoh32(sh->msgtrace_addr); ++ ++ if ((sh->flags & SDPCM_SHARED_VERSION_MASK) == 3 && SDPCM_SHARED_VERSION == 1) ++ return BCME_OK; ++ ++ if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) { ++ AP6211_ERR("%s: sdpcm_shared version %d in dhd " ++ "is different than sdpcm_shared version %d in dongle\n", ++ __FUNCTION__, SDPCM_SHARED_VERSION, ++ sh->flags & SDPCM_SHARED_VERSION_MASK); ++ return BCME_ERROR; ++ } ++ ++ return BCME_OK; ++} ++ ++#define CONSOLE_LINE_MAX 192 ++ ++static int ++dhdsdio_readconsole(dhd_bus_t *bus) ++{ ++ dhd_console_t *c = &bus->console; ++ uint8 line[CONSOLE_LINE_MAX], ch; ++ uint32 n, idx, addr; ++ int rv; ++ ++ /* Don't do anything until FWREADY updates console address */ ++ if (bus->console_addr == 0) ++ return 0; ++ ++ if (!KSO_ENAB(bus)) ++ return 0; ++ ++ /* Read console log struct */ ++ addr = bus->console_addr + OFFSETOF(hndrte_cons_t, log); ++ if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&c->log, sizeof(c->log))) < 0) ++ return rv; ++ ++ /* Allocate console buffer (one time only) */ ++ if (c->buf == NULL) { ++ c->bufsize = ltoh32(c->log.buf_size); ++ if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL) ++ return BCME_NOMEM; ++ } ++ ++ idx = ltoh32(c->log.idx); ++ ++ /* Protect against corrupt value */ ++ if (idx > c->bufsize) ++ return BCME_ERROR; ++ ++ /* Skip reading the console buffer if the index pointer has not moved */ ++ if (idx == c->last) ++ return BCME_OK; ++ ++ /* Read the console buffer */ ++ addr = ltoh32(c->log.buf); ++ if ((rv = dhdsdio_membytes(bus, FALSE, addr, c->buf, c->bufsize)) < 0) ++ return rv; ++ ++ while (c->last != idx) { ++ for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) { ++ if (c->last == idx) { ++ /* This would output a partial line. Instead, back up ++ * the buffer pointer and output this line next time around. ++ */ ++ if (c->last >= n) ++ c->last -= n; ++ else ++ c->last = c->bufsize - n; ++ goto break2; ++ } ++ ch = c->buf[c->last]; ++ c->last = (c->last + 1) % c->bufsize; ++ if (ch == '\n') ++ break; ++ line[n] = ch; ++ } ++ ++ if (n > 0) { ++ if (line[n - 1] == '\r') ++ n--; ++ line[n] = 0; ++ AP6211_DEBUG("CONSOLE: %s\n", line); ++ } ++ } ++break2: ++ ++ return BCME_OK; ++} ++ ++static int ++dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size) ++{ ++ int bcmerror = 0; ++ uint msize = 512; ++ char *mbuffer = NULL; ++ char *console_buffer = NULL; ++ uint maxstrlen = 256; ++ char *str = NULL; ++ trap_t tr; ++ sdpcm_shared_t sdpcm_shared; ++ struct bcmstrbuf strbuf; ++ uint32 console_ptr, console_size, console_index; ++ uint8 line[CONSOLE_LINE_MAX], ch; ++ uint32 n, i, addr; ++ int rv; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ if (data == NULL) { ++ /* ++ * Called after a rx ctrl timeout. "data" is NULL. ++ * allocate memory to trace the trap or assert. ++ */ ++ size = msize; ++ mbuffer = data = MALLOC(bus->dhd->osh, msize); ++ if (mbuffer == NULL) { ++ AP6211_ERR("%s: MALLOC(%d) failed \n", __FUNCTION__, msize); ++ bcmerror = BCME_NOMEM; ++ goto done; ++ } ++ } ++ ++ if ((str = MALLOC(bus->dhd->osh, maxstrlen)) == NULL) { ++ AP6211_ERR("%s: MALLOC(%d) failed \n", __FUNCTION__, maxstrlen); ++ bcmerror = BCME_NOMEM; ++ goto done; ++ } ++ ++ if ((bcmerror = dhdsdio_readshared(bus, &sdpcm_shared)) < 0) ++ goto done; ++ ++ bcm_binit(&strbuf, data, size); ++ ++ bcm_bprintf(&strbuf, "msgtrace address : 0x%08X\nconsole address : 0x%08X\n", ++ sdpcm_shared.msgtrace_addr, sdpcm_shared.console_addr); ++ ++ if ((sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) == 0) { ++ /* NOTE: Misspelled assert is intentional - DO NOT FIX. ++ * (Avoids conflict with real asserts for programmatic parsing of output.) ++ */ ++ bcm_bprintf(&strbuf, "Assrt not built in dongle\n"); ++ } ++ ++ if ((sdpcm_shared.flags & (SDPCM_SHARED_ASSERT|SDPCM_SHARED_TRAP)) == 0) { ++ /* NOTE: Misspelled assert is intentional - DO NOT FIX. ++ * (Avoids conflict with real asserts for programmatic parsing of output.) ++ */ ++ bcm_bprintf(&strbuf, "No trap%s in dongle", ++ (sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) ++ ?"/assrt" :""); ++ } else { ++ if (sdpcm_shared.flags & SDPCM_SHARED_ASSERT) { ++ /* Download assert */ ++ bcm_bprintf(&strbuf, "Dongle assert"); ++ if (sdpcm_shared.assert_exp_addr != 0) { ++ str[0] = '\0'; ++ if ((bcmerror = dhdsdio_membytes(bus, FALSE, ++ sdpcm_shared.assert_exp_addr, ++ (uint8 *)str, maxstrlen)) < 0) ++ goto done; ++ ++ str[maxstrlen - 1] = '\0'; ++ bcm_bprintf(&strbuf, " expr \"%s\"", str); ++ } ++ ++ if (sdpcm_shared.assert_file_addr != 0) { ++ str[0] = '\0'; ++ if ((bcmerror = dhdsdio_membytes(bus, FALSE, ++ sdpcm_shared.assert_file_addr, ++ (uint8 *)str, maxstrlen)) < 0) ++ goto done; ++ ++ str[maxstrlen - 1] = '\0'; ++ bcm_bprintf(&strbuf, " file \"%s\"", str); ++ } ++ ++ bcm_bprintf(&strbuf, " line %d ", sdpcm_shared.assert_line); ++ } ++ ++ if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) { ++ bus->dhd->dongle_trap_occured = TRUE; ++ if ((bcmerror = dhdsdio_membytes(bus, FALSE, ++ sdpcm_shared.trap_addr, ++ (uint8*)&tr, sizeof(trap_t))) < 0) ++ goto done; ++ ++ bcm_bprintf(&strbuf, ++ "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x," ++ "lp 0x%x, rpc 0x%x Trap offset 0x%x, " ++ "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, " ++ "r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n\n", ++ ltoh32(tr.type), ltoh32(tr.epc), ltoh32(tr.cpsr), ltoh32(tr.spsr), ++ ltoh32(tr.r13), ltoh32(tr.r14), ltoh32(tr.pc), ++ ltoh32(sdpcm_shared.trap_addr), ++ ltoh32(tr.r0), ltoh32(tr.r1), ltoh32(tr.r2), ltoh32(tr.r3), ++ ltoh32(tr.r4), ltoh32(tr.r5), ltoh32(tr.r6), ltoh32(tr.r7)); ++ ++ addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log); ++ if ((rv = dhdsdio_membytes(bus, FALSE, addr, ++ (uint8 *)&console_ptr, sizeof(console_ptr))) < 0) ++ goto printbuf; ++ ++ addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.buf_size); ++ if ((rv = dhdsdio_membytes(bus, FALSE, addr, ++ (uint8 *)&console_size, sizeof(console_size))) < 0) ++ goto printbuf; ++ ++ addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.idx); ++ if ((rv = dhdsdio_membytes(bus, FALSE, addr, ++ (uint8 *)&console_index, sizeof(console_index))) < 0) ++ goto printbuf; ++ ++ console_ptr = ltoh32(console_ptr); ++ console_size = ltoh32(console_size); ++ console_index = ltoh32(console_index); ++ ++ if (console_size > CONSOLE_BUFFER_MAX || ++ !(console_buffer = MALLOC(bus->dhd->osh, console_size))) ++ goto printbuf; ++ ++ if ((rv = dhdsdio_membytes(bus, FALSE, console_ptr, ++ (uint8 *)console_buffer, console_size)) < 0) ++ goto printbuf; ++ ++ for (i = 0, n = 0; i < console_size; i += n + 1) { ++ for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) { ++ ch = console_buffer[(console_index + i + n) % console_size]; ++ if (ch == '\n') ++ break; ++ line[n] = ch; ++ } ++ ++ ++ if (n > 0) { ++ if (line[n - 1] == '\r') ++ n--; ++ line[n] = 0; ++ /* Don't use DHD_ERROR macro since we print ++ * a lot of information quickly. The macro ++ * will truncate a lot of the printfs ++ */ ++ ++ if (dhd_msg_level & DHD_ERROR_VAL) ++ AP6211_DEBUG("CONSOLE: %s\n", line); ++ } ++ } ++ } ++ } ++ ++printbuf: ++ if (sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) { ++ AP6211_DEBUG("%s: %s\n", __FUNCTION__, strbuf.origbuf); ++ } ++ ++ ++done: ++ if (mbuffer) ++ MFREE(bus->dhd->osh, mbuffer, msize); ++ if (str) ++ MFREE(bus->dhd->osh, str, maxstrlen); ++ if (console_buffer) ++ MFREE(bus->dhd->osh, console_buffer, console_size); ++ ++ return bcmerror; ++} ++#endif /* #ifdef DHD_DEBUG */ ++ ++ ++int ++dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len) ++{ ++ int bcmerror = BCME_OK; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ /* Basic sanity checks */ ++ if (bus->dhd->up) { ++ bcmerror = BCME_NOTDOWN; ++ goto err; ++ } ++ if (!len) { ++ bcmerror = BCME_BUFTOOSHORT; ++ goto err; ++ } ++ ++ /* Free the old ones and replace with passed variables */ ++ if (bus->vars) ++ MFREE(bus->dhd->osh, bus->vars, bus->varsz); ++ ++ bus->vars = MALLOC(bus->dhd->osh, len); ++ bus->varsz = bus->vars ? len : 0; ++ if (bus->vars == NULL) { ++ bcmerror = BCME_NOMEM; ++ goto err; ++ } ++ ++ /* Copy the passed variables, which should include the terminating double-null */ ++ bcopy(arg, bus->vars, bus->varsz); ++err: ++ return bcmerror; ++} ++ ++#ifdef DHD_DEBUG ++ ++#define CC_PLL_CHIPCTRL_SERIAL_ENAB (1 << 24) ++#define CC_CHIPCTRL_JTAG_SEL (1 << 3) ++#define CC_CHIPCTRL_GPIO_SEL (0x3) ++#define CC_PLL_CHIPCTRL_SERIAL_ENAB_4334 (1 << 28) ++ ++static int ++dhd_serialconsole(dhd_bus_t *bus, bool set, bool enable, int *bcmerror) ++{ ++ int int_val; ++ uint32 addr, data, uart_enab = 0; ++ uint32 jtag_sel = CC_CHIPCTRL_JTAG_SEL; ++ uint32 gpio_sel = CC_CHIPCTRL_GPIO_SEL; ++ ++ addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); ++ data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); ++ *bcmerror = 0; ++ ++ bcmsdh_reg_write(bus->sdh, addr, 4, 1); ++ if (bcmsdh_regfail(bus->sdh)) { ++ *bcmerror = BCME_SDIO_ERROR; ++ return -1; ++ } ++ int_val = bcmsdh_reg_read(bus->sdh, data, 4); ++ if (bcmsdh_regfail(bus->sdh)) { ++ *bcmerror = BCME_SDIO_ERROR; ++ return -1; ++ } ++ if (bus->sih->chip == BCM4330_CHIP_ID) { ++ uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB; ++ } ++ else if (bus->sih->chip == BCM4334_CHIP_ID || ++ bus->sih->chip == BCM43341_CHIP_ID) { ++ if (enable) { ++ /* Moved to PMU chipcontrol 1 from 4330 */ ++ int_val &= ~gpio_sel; ++ int_val |= jtag_sel; ++ } else { ++ int_val |= gpio_sel; ++ int_val &= ~jtag_sel; ++ } ++ uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB_4334; ++ } ++ ++ if (!set) ++ return (int_val & uart_enab); ++ if (enable) ++ int_val |= uart_enab; ++ else ++ int_val &= ~uart_enab; ++ bcmsdh_reg_write(bus->sdh, data, 4, int_val); ++ if (bcmsdh_regfail(bus->sdh)) { ++ *bcmerror = BCME_SDIO_ERROR; ++ return -1; ++ } ++ if (bus->sih->chip == BCM4330_CHIP_ID) { ++ uint32 chipcontrol; ++ addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol); ++ chipcontrol = bcmsdh_reg_read(bus->sdh, addr, 4); ++ chipcontrol &= ~jtag_sel; ++ if (enable) { ++ chipcontrol |= jtag_sel; ++ chipcontrol &= ~gpio_sel; ++ } ++ bcmsdh_reg_write(bus->sdh, addr, 4, chipcontrol); ++ } ++ ++ return (int_val & uart_enab); ++} ++#endif ++ ++static int ++dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name, ++ void *params, int plen, void *arg, int len, int val_size) ++{ ++ int bcmerror = 0; ++ int32 int_val = 0; ++ bool bool_val = 0; ++ ++ AP6211_DEBUG("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n", ++ __FUNCTION__, actionid, name, params, plen, arg, len, val_size); ++ ++ if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0) ++ goto exit; ++ ++ if (plen >= (int)sizeof(int_val)) ++ bcopy(params, &int_val, sizeof(int_val)); ++ ++ bool_val = (int_val != 0) ? TRUE : FALSE; ++ ++ ++ /* Some ioctls use the bus */ ++ dhd_os_sdlock(bus->dhd); ++ ++ /* Check if dongle is in reset. If so, only allow DEVRESET iovars */ ++ if (bus->dhd->dongle_reset && !(actionid == IOV_SVAL(IOV_DEVRESET) || ++ actionid == IOV_GVAL(IOV_DEVRESET))) { ++ bcmerror = BCME_NOTREADY; ++ goto exit; ++ } ++ ++ /* ++ * Special handling for keepSdioOn: New SDIO Wake-up Mechanism ++ */ ++ if ((vi->varid == IOV_KSO) && (IOV_ISSET(actionid))) { ++ dhdsdio_clk_kso_iovar(bus, bool_val); ++ goto exit; ++ } else if ((vi->varid == IOV_DEVSLEEP) && (IOV_ISSET(actionid))) { ++ { ++ dhdsdio_clk_devsleep_iovar(bus, bool_val); ++ if (!SLPAUTO_ENAB(bus) && (bool_val == FALSE) && (bus->ipend)) { ++ AP6211_DEBUG("INT pending in devsleep 1, dpc_sched: %d\n", ++ bus->dpc_sched); ++ if (!bus->dpc_sched) { ++ bus->dpc_sched = TRUE; ++ dhd_sched_dpc(bus->dhd); ++ } ++ } ++ } ++ goto exit; ++ } ++ ++ /* Handle sleep stuff before any clock mucking */ ++ if (vi->varid == IOV_SLEEP) { ++ if (IOV_ISSET(actionid)) { ++ bcmerror = dhdsdio_bussleep(bus, bool_val); ++ } else { ++ int_val = (int32)bus->sleeping; ++ bcopy(&int_val, arg, val_size); ++ } ++ goto exit; ++ } ++ ++ /* Request clock to allow SDIO accesses */ ++ if (!bus->dhd->dongle_reset) { ++ BUS_WAKE(bus); ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ } ++ ++ switch (actionid) { ++ case IOV_GVAL(IOV_INTR): ++ int_val = (int32)bus->intr; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_INTR): ++ bus->intr = bool_val; ++ bus->intdis = FALSE; ++ if (bus->dhd->up) { ++ if (bus->intr) { ++ AP6211_DEBUG("%s: enable SDIO device interrupts\n", __FUNCTION__); ++ bcmsdh_intr_enable(bus->sdh); ++ } else { ++ AP6211_DEBUG("%s: disable SDIO interrupts\n", __FUNCTION__); ++ bcmsdh_intr_disable(bus->sdh); ++ } ++ } ++ break; ++ ++ case IOV_GVAL(IOV_POLLRATE): ++ int_val = (int32)bus->pollrate; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_POLLRATE): ++ bus->pollrate = (uint)int_val; ++ bus->poll = (bus->pollrate != 0); ++ break; ++ ++ case IOV_GVAL(IOV_IDLETIME): ++ int_val = bus->idletime; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_IDLETIME): ++ if ((int_val < 0) && (int_val != DHD_IDLE_IMMEDIATE)) { ++ bcmerror = BCME_BADARG; ++ } else { ++ bus->idletime = int_val; ++ } ++ break; ++ ++ case IOV_GVAL(IOV_IDLECLOCK): ++ int_val = (int32)bus->idleclock; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_IDLECLOCK): ++ bus->idleclock = int_val; ++ break; ++ ++ case IOV_GVAL(IOV_SD1IDLE): ++ int_val = (int32)sd1idle; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_SD1IDLE): ++ sd1idle = bool_val; ++ break; ++ ++ ++ case IOV_SVAL(IOV_MEMBYTES): ++ case IOV_GVAL(IOV_MEMBYTES): ++ { ++ uint32 address; ++ uint size, dsize; ++ uint8 *data; ++ ++ bool set = (actionid == IOV_SVAL(IOV_MEMBYTES)); ++ ++ ASSERT(plen >= 2*sizeof(int)); ++ ++ address = (uint32)int_val; ++ bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val)); ++ size = (uint)int_val; ++ ++ /* Do some validation */ ++ dsize = set ? plen - (2 * sizeof(int)) : len; ++ if (dsize < size) { ++ AP6211_ERR("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n", ++ __FUNCTION__, (set ? "set" : "get"), address, size, dsize); ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ ++ AP6211_DEBUG("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__, ++ (set ? "write" : "read"), size, address); ++ ++ /* If we know about SOCRAM, check for a fit */ ++ if ((bus->orig_ramsize) && ++ ((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize))) ++ { ++ uint8 enable, protect, remap; ++ si_socdevram(bus->sih, FALSE, &enable, &protect, &remap); ++ if (!enable || protect) { ++ AP6211_ERR("%s: ramsize 0x%08x doesn't have %d bytes at 0x%08x\n", ++ __FUNCTION__, bus->orig_ramsize, size, address); ++ AP6211_DEBUG("%s: socram enable %d, protect %d\n", ++ __FUNCTION__, enable, protect); ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ ++ if (!REMAP_ENAB(bus) && (address >= SOCDEVRAM_ARM_ADDR)) { ++ uint32 devramsize = si_socdevram_size(bus->sih); ++ if ((address < SOCDEVRAM_ARM_ADDR) || ++ (address + size > (SOCDEVRAM_ARM_ADDR + devramsize))) { ++ AP6211_ERR("%s: bad address 0x%08x, size 0x%08x\n", ++ __FUNCTION__, address, size); ++ AP6211_DEBUG("%s: socram range 0x%08x,size 0x%08x\n", ++ __FUNCTION__, SOCDEVRAM_ARM_ADDR, devramsize); ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ /* move it such that address is real now */ ++ address -= SOCDEVRAM_ARM_ADDR; ++ address += SOCDEVRAM_BP_ADDR; ++ AP6211_DEBUG("%s: Request to %s %d bytes @ Mapped address 0x%08x\n", ++ __FUNCTION__, (set ? "write" : "read"), size, address); ++ } else if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address) && remap) { ++ /* Can not access remap region while devram remap bit is set ++ * ROM content would be returned in this case ++ */ ++ AP6211_ERR("%s: Need to disable remap for address 0x%08x\n", ++ __FUNCTION__, address); ++ bcmerror = BCME_ERROR; ++ break; ++ } ++ } ++ ++ /* Generate the actual data pointer */ ++ data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg; ++ ++ /* Call to do the transfer */ ++ bcmerror = dhdsdio_membytes(bus, set, address, data, size); ++ ++ break; ++ } ++ ++ case IOV_GVAL(IOV_MEMSIZE): ++ int_val = (int32)bus->ramsize; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_GVAL(IOV_SDIOD_DRIVE): ++ int_val = (int32)dhd_sdiod_drive_strength; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_SDIOD_DRIVE): ++ dhd_sdiod_drive_strength = int_val; ++ si_sdiod_drive_strength_init(bus->sih, bus->dhd->osh, dhd_sdiod_drive_strength); ++ break; ++ ++ case IOV_SVAL(IOV_SET_DOWNLOAD_STATE): ++ bcmerror = dhdsdio_download_state(bus, bool_val); ++ break; ++ ++ case IOV_SVAL(IOV_SOCRAM_STATE): ++ bcmerror = dhdsdio_download_state(bus, bool_val); ++ break; ++ ++ case IOV_SVAL(IOV_VARS): ++ bcmerror = dhdsdio_downloadvars(bus, arg, len); ++ break; ++ ++ case IOV_GVAL(IOV_READAHEAD): ++ int_val = (int32)dhd_readahead; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_READAHEAD): ++ if (bool_val && !dhd_readahead) ++ bus->nextlen = 0; ++ dhd_readahead = bool_val; ++ break; ++ ++ case IOV_GVAL(IOV_SDRXCHAIN): ++ int_val = (int32)bus->use_rxchain; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_SDRXCHAIN): ++ if (bool_val && !bus->sd_rxchain) ++ bcmerror = BCME_UNSUPPORTED; ++ else ++ bus->use_rxchain = bool_val; ++ break; ++ case IOV_GVAL(IOV_ALIGNCTL): ++ int_val = (int32)dhd_alignctl; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_ALIGNCTL): ++ dhd_alignctl = bool_val; ++ break; ++ ++ case IOV_GVAL(IOV_SDALIGN): ++ int_val = DHD_SDALIGN; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++#ifdef DHD_DEBUG ++ case IOV_GVAL(IOV_VARS): ++ if (bus->varsz < (uint)len) ++ bcopy(bus->vars, arg, bus->varsz); ++ else ++ bcmerror = BCME_BUFTOOSHORT; ++ break; ++#endif /* DHD_DEBUG */ ++ ++#ifdef DHD_DEBUG ++ case IOV_GVAL(IOV_SDREG): ++ { ++ sdreg_t *sd_ptr; ++ uint32 addr, size; ++ ++ sd_ptr = (sdreg_t *)params; ++ ++ addr = (uintptr)bus->regs + sd_ptr->offset; ++ size = sd_ptr->func; ++ int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size); ++ if (bcmsdh_regfail(bus->sdh)) ++ bcmerror = BCME_SDIO_ERROR; ++ bcopy(&int_val, arg, sizeof(int32)); ++ break; ++ } ++ ++ case IOV_SVAL(IOV_SDREG): ++ { ++ sdreg_t *sd_ptr; ++ uint32 addr, size; ++ ++ sd_ptr = (sdreg_t *)params; ++ ++ addr = (uintptr)bus->regs + sd_ptr->offset; ++ size = sd_ptr->func; ++ bcmsdh_reg_write(bus->sdh, addr, size, sd_ptr->value); ++ if (bcmsdh_regfail(bus->sdh)) ++ bcmerror = BCME_SDIO_ERROR; ++ break; ++ } ++ ++ /* Same as above, but offset is not backplane (not SDIO core) */ ++ case IOV_GVAL(IOV_SBREG): ++ { ++ sdreg_t sdreg; ++ uint32 addr, size; ++ ++ bcopy(params, &sdreg, sizeof(sdreg)); ++ ++ addr = SI_ENUM_BASE + sdreg.offset; ++ size = sdreg.func; ++ int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size); ++ if (bcmsdh_regfail(bus->sdh)) ++ bcmerror = BCME_SDIO_ERROR; ++ bcopy(&int_val, arg, sizeof(int32)); ++ break; ++ } ++ ++ case IOV_SVAL(IOV_SBREG): ++ { ++ sdreg_t sdreg; ++ uint32 addr, size; ++ ++ bcopy(params, &sdreg, sizeof(sdreg)); ++ ++ addr = SI_ENUM_BASE + sdreg.offset; ++ size = sdreg.func; ++ bcmsdh_reg_write(bus->sdh, addr, size, sdreg.value); ++ if (bcmsdh_regfail(bus->sdh)) ++ bcmerror = BCME_SDIO_ERROR; ++ break; ++ } ++ ++ case IOV_GVAL(IOV_SDCIS): ++ { ++ *(char *)arg = 0; ++ ++ bcmstrcat(arg, "\nFunc 0\n"); ++ bcmsdh_cis_read(bus->sdh, 0x10, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT); ++ bcmstrcat(arg, "\nFunc 1\n"); ++ bcmsdh_cis_read(bus->sdh, 0x11, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT); ++ bcmstrcat(arg, "\nFunc 2\n"); ++ bcmsdh_cis_read(bus->sdh, 0x12, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT); ++ break; ++ } ++ ++ case IOV_GVAL(IOV_FORCEEVEN): ++ int_val = (int32)forcealign; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_FORCEEVEN): ++ forcealign = bool_val; ++ break; ++ ++ case IOV_GVAL(IOV_TXBOUND): ++ int_val = (int32)dhd_txbound; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_TXBOUND): ++ dhd_txbound = (uint)int_val; ++ break; ++ ++ case IOV_GVAL(IOV_RXBOUND): ++ int_val = (int32)dhd_rxbound; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_RXBOUND): ++ dhd_rxbound = (uint)int_val; ++ break; ++ ++ case IOV_GVAL(IOV_TXMINMAX): ++ int_val = (int32)dhd_txminmax; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_TXMINMAX): ++ dhd_txminmax = (uint)int_val; ++ break; ++ ++ case IOV_GVAL(IOV_SERIALCONS): ++ int_val = dhd_serialconsole(bus, FALSE, 0, &bcmerror); ++ if (bcmerror != 0) ++ break; ++ ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_SERIALCONS): ++ dhd_serialconsole(bus, TRUE, bool_val, &bcmerror); ++ break; ++ ++ ++ ++#endif /* DHD_DEBUG */ ++ ++ ++#ifdef SDTEST ++ case IOV_GVAL(IOV_EXTLOOP): ++ int_val = (int32)bus->ext_loop; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_EXTLOOP): ++ bus->ext_loop = bool_val; ++ break; ++ ++ case IOV_GVAL(IOV_PKTGEN): ++ bcmerror = dhdsdio_pktgen_get(bus, arg); ++ break; ++ ++ case IOV_SVAL(IOV_PKTGEN): ++ bcmerror = dhdsdio_pktgen_set(bus, arg); ++ break; ++#endif /* SDTEST */ ++ ++#if defined(SDIO_CRC_ERROR_FIX) ++ case IOV_GVAL(IOV_WATERMARK): ++ int_val = (int32)watermark; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_WATERMARK): ++ watermark = (uint)int_val; ++ watermark = (watermark > SBSDIO_WATERMARK_MASK) ? SBSDIO_WATERMARK_MASK : watermark; ++ AP6211_DEBUG("Setting watermark as 0x%x.\n", watermark); ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, NULL); ++ break; ++ ++ case IOV_GVAL(IOV_MESBUSYCTRL): ++ int_val = (int32)mesbusyctrl; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_MESBUSYCTRL): ++ mesbusyctrl = (uint)int_val; ++ mesbusyctrl = (mesbusyctrl > SBSDIO_MESBUSYCTRL_MASK) ++ ? SBSDIO_MESBUSYCTRL_MASK : mesbusyctrl; ++ AP6211_DEBUG("Setting mesbusyctrl as 0x%x.\n", mesbusyctrl); ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, ++ ((uint8)mesbusyctrl | 0x80), NULL); ++ break; ++#endif /* SDIO_CRC_ERROR_FIX */ ++ ++ case IOV_GVAL(IOV_DONGLEISOLATION): ++ int_val = bus->dhd->dongle_isolation; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_DONGLEISOLATION): ++ bus->dhd->dongle_isolation = bool_val; ++ break; ++ ++ case IOV_SVAL(IOV_DEVRESET): ++ AP6211_DEBUG("%s: Called set IOV_DEVRESET=%d dongle_reset=%d busstate=%d\n", ++ __FUNCTION__, bool_val, bus->dhd->dongle_reset, ++ bus->dhd->busstate); ++ ++ ASSERT(bus->dhd->osh); ++ /* ASSERT(bus->cl_devid); */ ++ ++ dhd_bus_devreset(bus->dhd, (uint8)bool_val); ++ ++ break; ++#ifdef SOFTAP ++ case IOV_GVAL(IOV_FWPATH): ++ { ++ uint32 fw_path_len; ++ ++ fw_path_len = strlen(bus->fw_path); ++ AP6211_DEBUG("[softap] get fwpath, l=%d\n", len); ++ ++ if (fw_path_len > len-1) { ++ bcmerror = BCME_BUFTOOSHORT; ++ break; ++ } ++ ++ if (fw_path_len) { ++ bcopy(bus->fw_path, arg, fw_path_len); ++ ((uchar*)arg)[fw_path_len] = 0; ++ } ++ break; ++ } ++ ++ case IOV_SVAL(IOV_FWPATH): ++ AP6211_DEBUG("[softap] set fwpath, idx=%d\n", int_val); ++ ++ switch (int_val) { ++ case 1: ++ bus->fw_path = fw_path; /* ordinary one */ ++ break; ++ case 2: ++ bus->fw_path = fw_path2; ++ break; ++ default: ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ ++ AP6211_DEBUG("[softap] new fw path: %s\n", (bus->fw_path[0] ? bus->fw_path : "NULL")); ++ break; ++ ++#endif /* SOFTAP */ ++ case IOV_GVAL(IOV_DEVRESET): ++ AP6211_DEBUG("%s: Called get IOV_DEVRESET\n", __FUNCTION__); ++ ++ /* Get its status */ ++ int_val = (bool) bus->dhd->dongle_reset; ++ bcopy(&int_val, arg, val_size); ++ ++ break; ++ ++ case IOV_GVAL(IOV_KSO): ++ int_val = dhdsdio_sleepcsr_get(bus); ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_GVAL(IOV_DEVCAP): ++ int_val = dhdsdio_devcap_get(bus); ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_DEVCAP): ++ dhdsdio_devcap_set(bus, (uint8) int_val); ++ break; ++ ++#ifdef BCMSDIOH_TXGLOM ++ case IOV_GVAL(IOV_TXGLOMSIZE): ++ int_val = (int32)bus->glomsize; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_TXGLOMSIZE): ++ if (int_val > SDPCM_MAXGLOM_SIZE) { ++ bcmerror = BCME_ERROR; ++ } else { ++ bus->glomsize = (uint)int_val; ++ } ++ break; ++ case IOV_GVAL(IOV_TXGLOMMODE): ++ int_val = (int32)bus->glom_mode; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_TXGLOMMODE): ++ if ((int_val != SDPCM_TXGLOM_CPY) && (int_val != SDPCM_TXGLOM_MDESC)) { ++ bcmerror = BCME_RANGE; ++ } else { ++ if ((bus->glom_mode = bcmsdh_set_mode(bus->sdh, (uint)int_val)) != int_val) ++ bcmerror = BCME_ERROR; ++ } ++ break; ++#endif /* BCMSDIOH_TXGLOM */ ++ default: ++ bcmerror = BCME_UNSUPPORTED; ++ break; ++ } ++ ++exit: ++ if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { ++ bus->activity = FALSE; ++ dhdsdio_clkctl(bus, CLK_NONE, TRUE); ++ } ++ ++ dhd_os_sdunlock(bus->dhd); ++ ++ return bcmerror; ++} ++ ++static int ++dhdsdio_write_vars(dhd_bus_t *bus) ++{ ++ int bcmerror = 0; ++ uint32 varsize, phys_size; ++ uint32 varaddr; ++ uint8 *vbuffer; ++ uint32 varsizew; ++#ifdef DHD_DEBUG ++ uint8 *nvram_ularray; ++#endif /* DHD_DEBUG */ ++ ++ /* Even if there are no vars are to be written, we still need to set the ramsize. */ ++ varsize = bus->varsz ? ROUNDUP(bus->varsz, 4) : 0; ++ varaddr = (bus->ramsize - 4) - varsize; ++ ++ varaddr += bus->dongle_ram_base; ++ ++ if (bus->vars) { ++ if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 7)) { ++ if (((varaddr & 0x3C) == 0x3C) && (varsize > 4)) { ++ AP6211_DEBUG("PR85623WAR in place\n"); ++ varsize += 4; ++ varaddr -= 4; ++ } ++ } ++ ++ vbuffer = (uint8 *)MALLOC(bus->dhd->osh, varsize); ++ if (!vbuffer) ++ return BCME_NOMEM; ++ ++ bzero(vbuffer, varsize); ++ bcopy(bus->vars, vbuffer, bus->varsz); ++ ++ /* Write the vars list */ ++ bcmerror = dhdsdio_membytes(bus, TRUE, varaddr, vbuffer, varsize); ++#ifdef DHD_DEBUG ++ /* Verify NVRAM bytes */ ++ AP6211_DEBUG("Compare NVRAM dl & ul; varsize=%d\n", varsize); ++ nvram_ularray = (uint8*)MALLOC(bus->dhd->osh, varsize); ++ if (!nvram_ularray) ++ return BCME_NOMEM; ++ ++ /* Upload image to verify downloaded contents. */ ++ memset(nvram_ularray, 0xaa, varsize); ++ ++ /* Read the vars list to temp buffer for comparison */ ++ bcmerror = dhdsdio_membytes(bus, FALSE, varaddr, nvram_ularray, varsize); ++ if (bcmerror) { ++ AP6211_ERR("%s: error %d on reading %d nvram bytes at 0x%08x\n", ++ __FUNCTION__, bcmerror, varsize, varaddr); ++ } ++ /* Compare the org NVRAM with the one read from RAM */ ++ if (memcmp(vbuffer, nvram_ularray, varsize)) { ++ AP6211_ERR("%s: Downloaded NVRAM image is corrupted.\n", __FUNCTION__); ++ } else ++ AP6211_DEBUG("%s: Download, Upload and compare of NVRAM succeeded.\n", ++ __FUNCTION__); ++ ++ MFREE(bus->dhd->osh, nvram_ularray, varsize); ++#endif /* DHD_DEBUG */ ++ ++ MFREE(bus->dhd->osh, vbuffer, varsize); ++ } ++ ++ phys_size = REMAP_ENAB(bus) ? bus->ramsize : bus->orig_ramsize; ++ ++ phys_size += bus->dongle_ram_base; ++ ++ /* adjust to the user specified RAM */ ++ AP6211_DEBUG("Physical memory size: %d, usable memory size: %d\n", ++ phys_size, bus->ramsize); ++ AP6211_DEBUG("Vars are at %d, orig varsize is %d\n", ++ varaddr, varsize); ++ varsize = ((phys_size - 4) - varaddr); ++ ++ /* ++ * Determine the length token: ++ * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits. ++ */ ++ if (bcmerror) { ++ varsizew = 0; ++ } else { ++ varsizew = varsize / 4; ++ varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF); ++ varsizew = htol32(varsizew); ++ } ++ ++ AP6211_DEBUG("New varsize is %d, length token=0x%08x\n", varsize, varsizew); ++ ++ /* Write the length token to the last word */ ++ bcmerror = dhdsdio_membytes(bus, TRUE, (phys_size - 4), ++ (uint8*)&varsizew, 4); ++ ++ return bcmerror; ++} ++ ++static int ++dhdsdio_download_state(dhd_bus_t *bus, bool enter) ++{ ++ uint retries; ++ int bcmerror = 0; ++ int foundcr4 = 0; ++ ++ /* To enter download state, disable ARM and reset SOCRAM. ++ * To exit download state, simply reset ARM (default is RAM boot). ++ */ ++ if (enter) { ++ bus->alp_only = TRUE; ++ ++ if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) && ++ !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) { ++ if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { ++ foundcr4 = 1; ++ } else { ++ AP6211_ERR("%s: Failed to find ARM core!\n", __FUNCTION__); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ } ++ ++ if (!foundcr4) { ++ si_core_disable(bus->sih, 0); ++ if (bcmsdh_regfail(bus->sdh)) { ++ bcmerror = BCME_SDIO_ERROR; ++ goto fail; ++ } ++ ++ if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { ++ AP6211_ERR("%s: Failed to find SOCRAM core!\n", __FUNCTION__); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ ++ si_core_reset(bus->sih, 0, 0); ++ if (bcmsdh_regfail(bus->sdh)) { ++ AP6211_ERR("%s: Failure trying reset SOCRAM core?\n", __FUNCTION__); ++ bcmerror = BCME_SDIO_ERROR; ++ goto fail; ++ } ++ ++ /* Disable remap for download */ ++ if (REMAP_ENAB(bus) && si_socdevram_remap_isenb(bus->sih)) ++ dhdsdio_devram_remap(bus, FALSE); ++ ++ /* Clear the top bit of memory */ ++ if (bus->ramsize) { ++ uint32 zeros = 0; ++ if (dhdsdio_membytes(bus, TRUE, bus->ramsize - 4, (uint8*)&zeros, 4) < 0) { ++ bcmerror = BCME_SDIO_ERROR; ++ goto fail; ++ } ++ } ++ } else { ++ /* For CR4, ++ * Halt ARM ++ * Remove ARM reset ++ * Read RAM base address [0x18_0000] ++ * [next] Download firmware ++ * [done at else] Populate the reset vector ++ * [done at else] Remove ARM halt ++ */ ++ /* Halt ARM & remove reset */ ++ si_core_reset(bus->sih, SICF_CPUHALT, SICF_CPUHALT); ++ } ++ } else { ++ if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { ++ if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { ++ AP6211_ERR("%s: Failed to find SOCRAM core!\n", __FUNCTION__); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ ++ if (!si_iscoreup(bus->sih)) { ++ AP6211_ERR("%s: SOCRAM core is down after reset?\n", __FUNCTION__); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ ++ if ((bcmerror = dhdsdio_write_vars(bus))) { ++ AP6211_ERR("%s: could not write vars to RAM\n", __FUNCTION__); ++ goto fail; ++ } ++ ++ /* Enable remap before ARM reset but after vars. ++ * No backplane access in remap mode ++ */ ++ if (REMAP_ENAB(bus) && !si_socdevram_remap_isenb(bus->sih)) ++ dhdsdio_devram_remap(bus, TRUE); ++ ++ if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) && ++ !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) { ++ AP6211_ERR("%s: Can't change back to SDIO core?\n", __FUNCTION__); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries); ++ ++ ++ if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) && ++ !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) { ++ AP6211_ERR("%s: Failed to find ARM core!\n", __FUNCTION__); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ } else { ++ /* cr4 has no socram, but tcm's */ ++ /* write vars */ ++ if ((bcmerror = dhdsdio_write_vars(bus))) { ++ AP6211_ERR("%s: could not write vars to RAM\n", __FUNCTION__); ++ goto fail; ++ } ++ ++ if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) && ++ !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) { ++ AP6211_ERR("%s: Can't change back to SDIO core?\n", __FUNCTION__); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries); ++ ++ /* switch back to arm core again */ ++ if (!(si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) { ++ AP6211_ERR("%s: Failed to find ARM CR4 core!\n", __FUNCTION__); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ /* write address 0 with reset instruction */ ++ bcmerror = dhdsdio_membytes(bus, TRUE, 0, ++ (uint8 *)&bus->resetinstr, sizeof(bus->resetinstr)); ++ ++ /* now remove reset and halt and continue to run CR4 */ ++ } ++ ++ si_core_reset(bus->sih, 0, 0); ++ if (bcmsdh_regfail(bus->sdh)) { ++ AP6211_ERR("%s: Failure trying to reset ARM core?\n", __FUNCTION__); ++ bcmerror = BCME_SDIO_ERROR; ++ goto fail; ++ } ++ ++ /* Allow HT Clock now that the ARM is running. */ ++ bus->alp_only = FALSE; ++ ++ bus->dhd->busstate = DHD_BUS_LOAD; ++ } ++ ++fail: ++ /* Always return to SDIOD core */ ++ if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) ++ si_setcore(bus->sih, SDIOD_CORE_ID, 0); ++ ++ return bcmerror; ++} ++ ++int ++dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name, ++ void *params, int plen, void *arg, int len, bool set) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ const bcm_iovar_t *vi = NULL; ++ int bcmerror = 0; ++ int val_size; ++ uint32 actionid; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ ASSERT(name); ++ ASSERT(len >= 0); ++ ++ /* Get MUST have return space */ ++ ASSERT(set || (arg && len)); ++ ++ /* Set does NOT take qualifiers */ ++ ASSERT(!set || (!params && !plen)); ++ ++ /* Look up var locally; if not found pass to host driver */ ++ if ((vi = bcm_iovar_lookup(dhdsdio_iovars, name)) == NULL) { ++ dhd_os_sdlock(bus->dhd); ++ ++ BUS_WAKE(bus); ++ ++ /* Turn on clock in case SD command needs backplane */ ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ ++ bcmerror = bcmsdh_iovar_op(bus->sdh, name, params, plen, arg, len, set); ++ ++ /* Check for bus configuration changes of interest */ ++ ++ /* If it was divisor change, read the new one */ ++ if (set && strcmp(name, "sd_divisor") == 0) { ++ if (bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0, ++ &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) { ++ bus->sd_divisor = -1; ++ AP6211_ERR("%s: fail on %s get\n", __FUNCTION__, name); ++ } else { ++ AP6211_DEBUG("%s: noted %s update, value now %d\n", ++ __FUNCTION__, name, bus->sd_divisor); ++ } ++ } ++ /* If it was a mode change, read the new one */ ++ if (set && strcmp(name, "sd_mode") == 0) { ++ if (bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0, ++ &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) { ++ bus->sd_mode = -1; ++ AP6211_ERR("%s: fail on %s get\n", __FUNCTION__, name); ++ } else { ++ AP6211_DEBUG("%s: noted %s update, value now %d\n", ++ __FUNCTION__, name, bus->sd_mode); ++ } ++ } ++ /* Similar check for blocksize change */ ++ if (set && strcmp(name, "sd_blocksize") == 0) { ++ int32 fnum = 2; ++ if (bcmsdh_iovar_op(bus->sdh, "sd_blocksize", &fnum, sizeof(int32), ++ &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) { ++ bus->blocksize = 0; ++ AP6211_ERR("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"); ++ } else { ++ AP6211_DEBUG("%s: noted %s update, value now %d\n", ++ __FUNCTION__, "sd_blocksize", bus->blocksize); ++ } ++ } ++ bus->roundup = MIN(max_roundup, bus->blocksize); ++ ++ if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { ++ bus->activity = FALSE; ++ dhdsdio_clkctl(bus, CLK_NONE, TRUE); ++ } ++ ++ dhd_os_sdunlock(bus->dhd); ++ goto exit; ++ } ++ ++ AP6211_DEBUG("%s: %s %s, len %d plen %d\n", __FUNCTION__, ++ name, (set ? "set" : "get"), len, plen); ++ ++ /* set up 'params' pointer in case this is a set command so that ++ * the convenience int and bool code can be common to set and get ++ */ ++ if (params == NULL) { ++ params = arg; ++ plen = len; ++ } ++ ++ if (vi->type == IOVT_VOID) ++ val_size = 0; ++ else if (vi->type == IOVT_BUFFER) ++ val_size = len; ++ else ++ /* all other types are integer sized */ ++ val_size = sizeof(int); ++ ++ actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); ++ bcmerror = dhdsdio_doiovar(bus, vi, actionid, name, params, plen, arg, len, val_size); ++ ++exit: ++ return bcmerror; ++} ++ ++void ++dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex) ++{ ++ osl_t *osh; ++ uint32 local_hostintmask; ++ uint8 saveclk, dat; ++ uint retries; ++ int err; ++ if (!bus->dhd) ++ return; ++ ++ osh = bus->dhd->osh; ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ bcmsdh_waitlockfree(NULL); ++ ++ if (enforce_mutex) ++ dhd_os_sdlock(bus->dhd); ++ ++ if ((bus->dhd->busstate == DHD_BUS_DOWN) || bus->dhd->hang_was_sent) { ++ /* if Firmware already hangs disbale any interrupt */ ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ bus->hostintmask = 0; ++ bcmsdh_intr_disable(bus->sdh); ++ } else { ++ BUS_WAKE(bus); ++ ++ if (KSO_ENAB(bus)) { ++ /* Mask the interrupt */ ++ dat = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_INTEN, NULL); ++ dat &= ~(INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN); ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_INTEN, dat, NULL); ++ } ++ ++ /* Change our idea of bus state */ ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ ++ if (KSO_ENAB(bus)) { ++ ++ /* Enable clock for device interrupts */ ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ ++ /* Disable and clear interrupts at the chip level also */ ++ W_SDREG(0, &bus->regs->hostintmask, retries); ++ local_hostintmask = bus->hostintmask; ++ bus->hostintmask = 0; ++ ++ /* Force clocks on backplane to be sure F2 interrupt propagates */ ++ saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); ++ if (!err) { ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, ++ (saveclk | SBSDIO_FORCE_HT), &err); ++ } ++ if (err) { ++ AP6211_ERR("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err); ++ } ++ ++ /* Turn off the bus (F2), free any pending packets */ ++ AP6211_DEBUG("%s: disable SDIO interrupts\n", __FUNCTION__); ++ bcmsdh_intr_disable(bus->sdh); ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL); ++ ++ /* Clear any pending interrupts now that F2 is disabled */ ++ W_SDREG(local_hostintmask, &bus->regs->intstatus, retries); ++ } ++ ++ /* Turn off the backplane clock (only) */ ++ dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); ++ } ++ ++ /* Clear the data packet queues */ ++ pktq_flush(osh, &bus->txq, TRUE, NULL, 0); ++ ++ /* Clear any held glomming stuff */ ++ if (bus->glomd) ++ PKTFREE(osh, bus->glomd, FALSE); ++ ++ if (bus->glom) ++ PKTFREE(osh, bus->glom, FALSE); ++ ++ bus->glom = bus->glomd = NULL; ++ ++ /* Clear rx control and wake any waiters */ ++ bus->rxlen = 0; ++ dhd_os_ioctl_resp_wake(bus->dhd); ++ ++ /* Reset some F2 state stuff */ ++ bus->rxskip = FALSE; ++ bus->tx_seq = bus->rx_seq = 0; ++ ++ if (enforce_mutex) ++ dhd_os_sdunlock(bus->dhd); ++} ++ ++#ifdef BCMSDIOH_TXGLOM ++void ++dhd_txglom_enable(dhd_pub_t *dhdp, bool enable) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ ++ char buf[256]; ++ uint32 rxglom; ++ int32 ret; ++ ++ if (enable) { ++ rxglom = 1; ++ memset(buf, 0, sizeof(buf)); ++ bcm_mkiovar("bus:rxglom", ++ (void *)&rxglom, ++ 4, buf, sizeof(buf)); ++ ret = dhd_wl_ioctl_cmd(dhdp, ++ WLC_SET_VAR, buf, ++ sizeof(buf), TRUE, 0); ++ if (!(ret < 0)) { ++ bus->glom_enable = TRUE; ++ } ++ } else { ++ bus->glom_enable = FALSE; ++ } ++} ++#endif /* BCMSDIOH_TXGLOM */ ++ ++int ++dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ dhd_timeout_t tmo; ++ uint retries = 0; ++ uint8 ready, enable; ++ int err, ret = 0; ++ uint8 saveclk; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ ASSERT(bus->dhd); ++ if (!bus->dhd) ++ return 0; ++ ++ if (enforce_mutex) ++ dhd_os_sdlock(bus->dhd); ++ ++ /* Make sure backplane clock is on, needed to generate F2 interrupt */ ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ if (bus->clkstate != CLK_AVAIL) { ++ AP6211_ERR("%s: clock state is wrong. state = %d\n", __FUNCTION__, bus->clkstate); ++ ret = -1; ++ goto exit; ++ } ++ ++ ++ /* Force clocks on backplane to be sure F2 interrupt propagates */ ++ saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); ++ if (!err) { ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, ++ (saveclk | SBSDIO_FORCE_HT), &err); ++ } ++ if (err) { ++ AP6211_ERR("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err); ++ ret = -1; ++ goto exit; ++ } ++ ++ /* Enable function 2 (frame transfers) */ ++ W_SDREG((SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT), ++ &bus->regs->tosbmailboxdata, retries); ++ enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2); ++ ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL); ++ ++ /* Give the dongle some time to do its thing and set IOR2 */ ++ dhd_timeout_start(&tmo, DHD_WAIT_F2RDY * 1000); ++ ++ ready = 0; ++ while (ready != enable && !dhd_timeout_expired(&tmo)) ++ ready = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL); ++ ++ AP6211_DEBUG("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n", ++ __FUNCTION__, enable, ready, tmo.elapsed); ++ ++ ++ /* If F2 successfully enabled, set core and enable interrupts */ ++ if (ready == enable) { ++ /* Make sure we're talking to the core. */ ++ if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0))) ++ bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0); ++ ASSERT(bus->regs != NULL); ++ ++ /* Set up the interrupt mask and enable interrupts */ ++ bus->hostintmask = HOSTINTMASK; ++ /* corerev 4 could use the newer interrupt logic to detect the frames */ ++ if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 4) && ++ (bus->rxint_mode != SDIO_DEVICE_HMB_RXINT)) { ++ bus->hostintmask &= ~I_HMB_FRAME_IND; ++ bus->hostintmask |= I_XMTDATA_AVAIL; ++ } ++ W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries); ++#ifdef SDIO_CRC_ERROR_FIX ++ if (bus->blocksize < 512) { ++ mesbusyctrl = watermark = bus->blocksize / 4; ++ } ++#endif /* SDIO_CRC_ERROR_FIX */ ++ ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, &err); ++#ifdef SDIO_CRC_ERROR_FIX ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, ++ (uint8)mesbusyctrl|0x80, &err); ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, ++ SBSDIO_DEVCTL_EN_F2_BLK_WATERMARK, NULL); ++#endif /* SDIO_CRC_ERROR_FIX */ ++ ++ /* Set bus state according to enable result */ ++ dhdp->busstate = DHD_BUS_DATA; ++ ++ /* bcmsdh_intr_unmask(bus->sdh); */ ++ ++ bus->intdis = FALSE; ++ if (bus->intr) { ++ AP6211_DEBUG("%s: enable SDIO device interrupts\n", __FUNCTION__); ++ bcmsdh_intr_enable(bus->sdh); ++ } else { ++ AP6211_DEBUG("%s: disable SDIO interrupts\n", __FUNCTION__); ++ bcmsdh_intr_disable(bus->sdh); ++ } ++ ++ } ++ ++ ++ else { ++ /* Disable F2 again */ ++ enable = SDIO_FUNC_ENABLE_1; ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL); ++ } ++ ++ if (dhdsdio_sr_cap(bus)) ++ dhdsdio_sr_init(bus); ++ else ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err); ++ ++ /* If we didn't come up, turn off backplane clock */ ++ if (dhdp->busstate != DHD_BUS_DATA) ++ dhdsdio_clkctl(bus, CLK_NONE, FALSE); ++ ++exit: ++ if (enforce_mutex) ++ dhd_os_sdunlock(bus->dhd); ++ ++ return ret; ++} ++ ++static void ++dhdsdio_rxfail(dhd_bus_t *bus, bool abort, bool rtx) ++{ ++ bcmsdh_info_t *sdh = bus->sdh; ++ sdpcmd_regs_t *regs = bus->regs; ++ uint retries = 0; ++ uint16 lastrbc; ++ uint8 hi, lo; ++ int err; ++ ++ AP6211_ERR("%s: %sterminate frame%s\n", __FUNCTION__, ++ (abort ? "abort command, " : ""), (rtx ? ", send NAK" : "")); ++ ++ if (!KSO_ENAB(bus)) { ++ AP6211_ERR("%s: Device asleep\n", __FUNCTION__); ++ return; ++ } ++ ++ if (abort) { ++ bcmsdh_abort(sdh, SDIO_FUNC_2); ++ } ++ ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM, &err); ++ bus->f1regdata++; ++ ++ /* Wait until the packet has been flushed (device/FIFO stable) */ ++ for (lastrbc = retries = 0xffff; retries > 0; retries--) { ++ hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCHI, NULL); ++ lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, NULL); ++ bus->f1regdata += 2; ++ ++ if ((hi == 0) && (lo == 0)) ++ break; ++ ++ if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) { ++ AP6211_DEBUG("%s: count growing: last 0x%04x now 0x%04x\n", ++ __FUNCTION__, lastrbc, ((hi << 8) + lo)); ++ } ++ lastrbc = (hi << 8) + lo; ++ } ++ ++ if (!retries) { ++ AP6211_ERR("%s: count never zeroed: last 0x%04x\n", __FUNCTION__, lastrbc); ++ } else { ++ AP6211_DEBUG("%s: flush took %d iterations\n", __FUNCTION__, (0xffff - retries)); ++ } ++ ++ if (rtx) { ++ bus->rxrtx++; ++ W_SDREG(SMB_NAK, ®s->tosbmailbox, retries); ++ bus->f1regdata++; ++ if (retries <= retry_limit) { ++ bus->rxskip = TRUE; ++ } ++ } ++ ++ /* Clear partial in any case */ ++ bus->nextlen = 0; ++ ++ /* If we can't reach the device, signal failure */ ++ if (err || bcmsdh_regfail(sdh)) ++ bus->dhd->busstate = DHD_BUS_DOWN; ++} ++ ++static void ++dhdsdio_read_control(dhd_bus_t *bus, uint8 *hdr, uint len, uint doff) ++{ ++ bcmsdh_info_t *sdh = bus->sdh; ++ uint rdlen, pad; ++ ++ int sdret; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ /* Control data already received in aligned rxctl */ ++ if ((bus->bus == SPI_BUS) && (!bus->usebufpool)) ++ goto gotpkt; ++ ++ ASSERT(bus->rxbuf); ++ /* Set rxctl for frame (w/optional alignment) */ ++ bus->rxctl = bus->rxbuf; ++ if (dhd_alignctl) { ++ bus->rxctl += firstread; ++ if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN))) ++ bus->rxctl += (DHD_SDALIGN - pad); ++ bus->rxctl -= firstread; ++ } ++ ASSERT(bus->rxctl >= bus->rxbuf); ++ ++ /* Copy the already-read portion over */ ++ bcopy(hdr, bus->rxctl, firstread); ++ if (len <= firstread) ++ goto gotpkt; ++ ++ /* Copy the full data pkt in gSPI case and process ioctl. */ ++ if (bus->bus == SPI_BUS) { ++ bcopy(hdr, bus->rxctl, len); ++ goto gotpkt; ++ } ++ ++ /* Raise rdlen to next SDIO block to avoid tail command */ ++ rdlen = len - firstread; ++ if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) { ++ pad = bus->blocksize - (rdlen % bus->blocksize); ++ if ((pad <= bus->roundup) && (pad < bus->blocksize) && ++ ((len + pad) < bus->dhd->maxctl)) ++ rdlen += pad; ++ } else if (rdlen % DHD_SDALIGN) { ++ rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN); ++ } ++ ++ /* Satisfy length-alignment requirements */ ++ if (forcealign && (rdlen & (ALIGNMENT - 1))) ++ rdlen = ROUNDUP(rdlen, ALIGNMENT); ++ ++ /* Drop if the read is too big or it exceeds our maximum */ ++ if ((rdlen + firstread) > bus->dhd->maxctl) { ++ AP6211_ERR("%s: %d-byte control read exceeds %d-byte buffer\n", ++ __FUNCTION__, rdlen, bus->dhd->maxctl); ++ bus->dhd->rx_errors++; ++ dhdsdio_rxfail(bus, FALSE, FALSE); ++ goto done; ++ } ++ ++ if ((len - doff) > bus->dhd->maxctl) { ++ AP6211_ERR("%s: %d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n", ++ __FUNCTION__, len, (len - doff), bus->dhd->maxctl); ++ bus->dhd->rx_errors++; bus->rx_toolong++; ++ dhdsdio_rxfail(bus, FALSE, FALSE); ++ goto done; ++ } ++ ++ ++ /* Read remainder of frame body into the rxctl buffer */ ++ sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, ++ (bus->rxctl + firstread), rdlen, NULL, NULL, NULL); ++ bus->f2rxdata++; ++ ASSERT(sdret != BCME_PENDING); ++ ++ /* Control frame failures need retransmission */ ++ if (sdret < 0) { ++ AP6211_ERR("%s: read %d control bytes failed: %d\n", __FUNCTION__, rdlen, sdret); ++ bus->rxc_errors++; /* dhd.rx_ctlerrs is higher level */ ++ dhdsdio_rxfail(bus, TRUE, TRUE); ++ goto done; ++ } ++ ++gotpkt: ++ ++#ifdef DHD_DEBUG ++ if (DHD_BYTES_ON() && DHD_CTL_ON()) { ++ prhex("RxCtrl", bus->rxctl, len); ++ } ++#endif ++ ++ /* Point to valid data and indicate its length */ ++ bus->rxctl += doff; ++ bus->rxlen = len - doff; ++ ++done: ++ /* Awake any waiters */ ++ dhd_os_ioctl_resp_wake(bus->dhd); ++} ++ ++static uint8 ++dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq) ++{ ++ uint16 dlen, totlen; ++ uint8 *dptr, num = 0; ++ ++ uint16 sublen, check; ++ void *pfirst, *plast, *pnext; ++ void * list_tail[DHD_MAX_IFS] = { NULL }; ++ void * list_head[DHD_MAX_IFS] = { NULL }; ++ uint8 idx; ++ osl_t *osh = bus->dhd->osh; ++ ++ int errcode; ++ uint8 chan, seq, doff, sfdoff; ++ uint8 txmax; ++ uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN]; ++ uint reorder_info_len; ++ ++ int ifidx = 0; ++ bool usechain = bus->use_rxchain; ++ ++ /* If packets, issue read(s) and send up packet chain */ ++ /* Return sequence numbers consumed? */ ++ ++ AP6211_DEBUG("dhdsdio_rxglom: start: glomd %p glom %p\n", bus->glomd, bus->glom); ++ ++ /* If there's a descriptor, generate the packet chain */ ++ if (bus->glomd) { ++ dhd_os_sdlock_rxq(bus->dhd); ++ ++ pfirst = plast = pnext = NULL; ++ dlen = (uint16)PKTLEN(osh, bus->glomd); ++ dptr = PKTDATA(osh, bus->glomd); ++ if (!dlen || (dlen & 1)) { ++ AP6211_ERR("%s: bad glomd len (%d), ignore descriptor\n", ++ __FUNCTION__, dlen); ++ dlen = 0; ++ } ++ ++ for (totlen = num = 0; dlen; num++) { ++ /* Get (and move past) next length */ ++ sublen = ltoh16_ua(dptr); ++ dlen -= sizeof(uint16); ++ dptr += sizeof(uint16); ++ if ((sublen < SDPCM_HDRLEN_RX) || ++ ((num == 0) && (sublen < (2 * SDPCM_HDRLEN_RX)))) { ++ AP6211_ERR("%s: descriptor len %d bad: %d\n", ++ __FUNCTION__, num, sublen); ++ pnext = NULL; ++ break; ++ } ++ if (sublen % DHD_SDALIGN) { ++ AP6211_ERR("%s: sublen %d not a multiple of %d\n", ++ __FUNCTION__, sublen, DHD_SDALIGN); ++ usechain = FALSE; ++ } ++ totlen += sublen; ++ ++ /* For last frame, adjust read len so total is a block multiple */ ++ if (!dlen) { ++ sublen += (ROUNDUP(totlen, bus->blocksize) - totlen); ++ totlen = ROUNDUP(totlen, bus->blocksize); ++ } ++ ++ /* Allocate/chain packet for next subframe */ ++ if ((pnext = PKTGET(osh, sublen + DHD_SDALIGN, FALSE)) == NULL) { ++ AP6211_ERR("%s: PKTGET failed, num %d len %d\n", ++ __FUNCTION__, num, sublen); ++ break; ++ } ++ ASSERT(!PKTLINK(pnext)); ++ if (!pfirst) { ++ ASSERT(!plast); ++ pfirst = plast = pnext; ++ } else { ++ ASSERT(plast); ++ PKTSETNEXT(osh, plast, pnext); ++ plast = pnext; ++ } ++ ++ /* Adhere to start alignment requirements */ ++ PKTALIGN(osh, pnext, sublen, DHD_SDALIGN); ++ } ++ ++ /* If all allocations succeeded, save packet chain in bus structure */ ++ if (pnext) { ++ AP6211_DEBUG("%s: allocated %d-byte packet chain for %d subframes\n", ++ __FUNCTION__, totlen, num); ++ if (DHD_GLOM_ON() && bus->nextlen) { ++ if (totlen != bus->nextlen) { ++ AP6211_DEBUG("%s: glomdesc mismatch: nextlen %d glomdesc %d " ++ "rxseq %d\n", __FUNCTION__, bus->nextlen, ++ totlen, rxseq); ++ } ++ } ++ bus->glom = pfirst; ++ pfirst = pnext = NULL; ++ } else { ++ if (pfirst) ++ PKTFREE(osh, pfirst, FALSE); ++ bus->glom = NULL; ++ num = 0; ++ } ++ ++ /* Done with descriptor packet */ ++ PKTFREE(osh, bus->glomd, FALSE); ++ bus->glomd = NULL; ++ bus->nextlen = 0; ++ ++ dhd_os_sdunlock_rxq(bus->dhd); ++ } ++ ++ /* Ok -- either we just generated a packet chain, or had one from before */ ++ if (bus->glom) { ++ if (DHD_GLOM_ON()) { ++ AP6211_DEBUG("%s: attempt superframe read, packet chain:\n", __FUNCTION__); ++ for (pnext = bus->glom; pnext; pnext = PKTNEXT(osh, pnext)) { ++ AP6211_DEBUG(" %p: %p len 0x%04x (%d)\n", ++ pnext, (uint8*)PKTDATA(osh, pnext), ++ PKTLEN(osh, pnext), PKTLEN(osh, pnext)); ++ } ++ } ++ ++ pfirst = bus->glom; ++ dlen = (uint16)pkttotlen(osh, pfirst); ++ ++ /* Do an SDIO read for the superframe. Configurable iovar to ++ * read directly into the chained packet, or allocate a large ++ * packet and and copy into the chain. ++ */ ++ if (usechain) { ++ errcode = dhd_bcmsdh_recv_buf(bus, ++ bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2, ++ F2SYNC, (uint8*)PKTDATA(osh, pfirst), ++ dlen, pfirst, NULL, NULL); ++ } else if (bus->dataptr) { ++ errcode = dhd_bcmsdh_recv_buf(bus, ++ bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2, ++ F2SYNC, bus->dataptr, ++ dlen, NULL, NULL, NULL); ++ sublen = (uint16)pktfrombuf(osh, pfirst, 0, dlen, bus->dataptr); ++ if (sublen != dlen) { ++ AP6211_ERR("%s: FAILED TO COPY, dlen %d sublen %d\n", ++ __FUNCTION__, dlen, sublen); ++ errcode = -1; ++ } ++ pnext = NULL; ++ } else { ++ AP6211_ERR("COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", dlen); ++ errcode = -1; ++ } ++ bus->f2rxdata++; ++ ASSERT(errcode != BCME_PENDING); ++ ++ /* On failure, kill the superframe, allow a couple retries */ ++ if (errcode < 0) { ++ AP6211_ERR("%s: glom read of %d bytes failed: %d\n", ++ __FUNCTION__, dlen, errcode); ++ bus->dhd->rx_errors++; ++ ++ if (bus->glomerr++ < 3) { ++ dhdsdio_rxfail(bus, TRUE, TRUE); ++ } else { ++ bus->glomerr = 0; ++ dhdsdio_rxfail(bus, TRUE, FALSE); ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE(osh, bus->glom, FALSE); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ bus->rxglomfail++; ++ bus->glom = NULL; ++ } ++ return 0; ++ } ++ ++#ifdef DHD_DEBUG ++ if (DHD_GLOM_ON()) { ++ prhex("SUPERFRAME", PKTDATA(osh, pfirst), ++ MIN(PKTLEN(osh, pfirst), 48)); ++ } ++#endif ++ ++ ++ /* Validate the superframe header */ ++ dptr = (uint8 *)PKTDATA(osh, pfirst); ++ sublen = ltoh16_ua(dptr); ++ check = ltoh16_ua(dptr + sizeof(uint16)); ++ ++ chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); ++ seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]); ++ bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; ++ if ((bus->nextlen << 4) > MAX_RX_DATASZ) { ++ AP6211_DEBUG("%s: got frame w/nextlen too large (%d) seq %d\n", ++ __FUNCTION__, bus->nextlen, seq); ++ bus->nextlen = 0; ++ } ++ doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); ++ txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); ++ ++ errcode = 0; ++ if ((uint16)~(sublen^check)) { ++ AP6211_ERR("%s (superframe): HW hdr error: len/check 0x%04x/0x%04x\n", ++ __FUNCTION__, sublen, check); ++ errcode = -1; ++ } else if (ROUNDUP(sublen, bus->blocksize) != dlen) { ++ AP6211_ERR("%s (superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n", ++ __FUNCTION__, sublen, ROUNDUP(sublen, bus->blocksize), dlen); ++ errcode = -1; ++ } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != SDPCM_GLOM_CHANNEL) { ++ AP6211_ERR("%s (superframe): bad channel %d\n", __FUNCTION__, ++ SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN])); ++ errcode = -1; ++ } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) { ++ AP6211_ERR("%s (superframe): got second descriptor?\n", __FUNCTION__); ++ errcode = -1; ++ } else if ((doff < SDPCM_HDRLEN_RX) || ++ (doff > (PKTLEN(osh, pfirst) - SDPCM_HDRLEN_RX))) { ++ AP6211_ERR("%s (superframe): Bad data offset %d: HW %d pkt %d min %d\n", ++ __FUNCTION__, doff, sublen, PKTLEN(osh, pfirst), ++ SDPCM_HDRLEN_RX); ++ errcode = -1; ++ } ++ ++ /* Check sequence number of superframe SW header */ ++ if (rxseq != seq) { ++ AP6211_DEBUG("%s: (superframe) rx_seq %d, expected %d\n", ++ __FUNCTION__, seq, rxseq); ++ bus->rx_badseq++; ++ rxseq = seq; ++ } ++ ++ /* Check window for sanity */ ++ if ((uint8)(txmax - bus->tx_seq) > 0x40) { ++ AP6211_ERR("%s: got unlikely tx max %d with tx_seq %d\n", ++ __FUNCTION__, txmax, bus->tx_seq); ++ txmax = bus->tx_max; ++ } ++ bus->tx_max = txmax; ++ ++ /* Remove superframe header, remember offset */ ++ PKTPULL(osh, pfirst, doff); ++ sfdoff = doff; ++ ++ /* Validate all the subframe headers */ ++ for (num = 0, pnext = pfirst; pnext && !errcode; ++ num++, pnext = PKTNEXT(osh, pnext)) { ++ dptr = (uint8 *)PKTDATA(osh, pnext); ++ dlen = (uint16)PKTLEN(osh, pnext); ++ sublen = ltoh16_ua(dptr); ++ check = ltoh16_ua(dptr + sizeof(uint16)); ++ chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); ++ doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); ++#ifdef DHD_DEBUG ++ if (DHD_GLOM_ON()) { ++ prhex("subframe", dptr, 32); ++ } ++#endif ++ ++ if ((uint16)~(sublen^check)) { ++ AP6211_ERR("%s (subframe %d): HW hdr error: " ++ "len/check 0x%04x/0x%04x\n", ++ __FUNCTION__, num, sublen, check); ++ errcode = -1; ++ } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN_RX)) { ++ AP6211_ERR("%s (subframe %d): length mismatch: " ++ "len 0x%04x, expect 0x%04x\n", ++ __FUNCTION__, num, sublen, dlen); ++ errcode = -1; ++ } else if ((chan != SDPCM_DATA_CHANNEL) && ++ (chan != SDPCM_EVENT_CHANNEL)) { ++ AP6211_ERR("%s (subframe %d): bad channel %d\n", ++ __FUNCTION__, num, chan); ++ errcode = -1; ++ } else if ((doff < SDPCM_HDRLEN_RX) || (doff > sublen)) { ++ AP6211_ERR("%s (subframe %d): Bad data offset %d: HW %d min %d\n", ++ __FUNCTION__, num, doff, sublen, SDPCM_HDRLEN_RX); ++ errcode = -1; ++ } ++ } ++ ++ if (errcode) { ++ /* Terminate frame on error, request a couple retries */ ++ if (bus->glomerr++ < 3) { ++ /* Restore superframe header space */ ++ PKTPUSH(osh, pfirst, sfdoff); ++ dhdsdio_rxfail(bus, TRUE, TRUE); ++ } else { ++ bus->glomerr = 0; ++ dhdsdio_rxfail(bus, TRUE, FALSE); ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE(osh, bus->glom, FALSE); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ bus->rxglomfail++; ++ bus->glom = NULL; ++ } ++ bus->nextlen = 0; ++ return 0; ++ } ++ ++ /* Basic SD framing looks ok - process each packet (header) */ ++ bus->glom = NULL; ++ plast = NULL; ++ ++ dhd_os_sdlock_rxq(bus->dhd); ++ for (num = 0; pfirst; rxseq++, pfirst = pnext) { ++ pnext = PKTNEXT(osh, pfirst); ++ PKTSETNEXT(osh, pfirst, NULL); ++ ++ dptr = (uint8 *)PKTDATA(osh, pfirst); ++ sublen = ltoh16_ua(dptr); ++ chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); ++ seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]); ++ doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); ++ ++ AP6211_DEBUG("%s: Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n", ++ __FUNCTION__, num, pfirst, PKTDATA(osh, pfirst), ++ PKTLEN(osh, pfirst), sublen, chan, seq); ++ ++ ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL)); ++ ++ if (rxseq != seq) { ++ AP6211_DEBUG("%s: rx_seq %d, expected %d\n", ++ __FUNCTION__, seq, rxseq); ++ bus->rx_badseq++; ++ rxseq = seq; ++ } ++ ++#ifdef DHD_DEBUG ++ if (DHD_BYTES_ON() && DHD_DATA_ON()) { ++ prhex("Rx Subframe Data", dptr, dlen); ++ } ++#endif ++ ++ PKTSETLEN(osh, pfirst, sublen); ++ PKTPULL(osh, pfirst, doff); ++ ++ reorder_info_len = sizeof(reorder_info_buf); ++ ++ if (PKTLEN(osh, pfirst) == 0) { ++ PKTFREE(bus->dhd->osh, pfirst, FALSE); ++ continue; ++ } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pfirst, reorder_info_buf, ++ &reorder_info_len) != 0) { ++ AP6211_ERR("%s: rx protocol error\n", __FUNCTION__); ++ bus->dhd->rx_errors++; ++ PKTFREE(osh, pfirst, FALSE); ++ continue; ++ } ++ if (reorder_info_len) { ++ uint32 free_buf_count; ++ void *ppfirst; ++ ++ ppfirst = pfirst; ++ /* Reordering info from the firmware */ ++ dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf, ++ reorder_info_len, &ppfirst, &free_buf_count); ++ ++ if (free_buf_count == 0) { ++ continue; ++ } ++ else { ++ void *temp; ++ ++ /* go to the end of the chain and attach the pnext there */ ++ temp = ppfirst; ++ while (PKTNEXT(osh, temp) != NULL) { ++ temp = PKTNEXT(osh, temp); ++ } ++ pfirst = temp; ++ if (list_tail[ifidx] == NULL) { ++ list_head[ifidx] = ppfirst; ++ list_tail[ifidx] = pfirst; ++ } ++ else { ++ PKTSETNEXT(osh, list_tail[ifidx], ppfirst); ++ list_tail[ifidx] = pfirst; ++ } ++ } ++ ++ num += (uint8)free_buf_count; ++ } ++ else { ++ /* this packet will go up, link back into chain and count it */ ++ ++ if (list_tail[ifidx] == NULL) { ++ list_head[ifidx] = list_tail[ifidx] = pfirst; ++ } ++ else { ++ PKTSETNEXT(osh, list_tail[ifidx], pfirst); ++ list_tail[ifidx] = pfirst; ++ } ++ num++; ++ } ++#ifdef DHD_DEBUG ++ if (DHD_GLOM_ON()) { ++ AP6211_DEBUG("%s subframe %d to stack, %p(%p/%d) nxt/lnk %p/%p\n", ++ __FUNCTION__, num, pfirst, ++ PKTDATA(osh, pfirst), PKTLEN(osh, pfirst), ++ PKTNEXT(osh, pfirst), PKTLINK(pfirst)); ++ prhex("", (uint8 *)PKTDATA(osh, pfirst), ++ MIN(PKTLEN(osh, pfirst), 32)); ++ } ++#endif /* DHD_DEBUG */ ++ } ++ dhd_os_sdunlock_rxq(bus->dhd); ++ ++ for (idx = 0; idx < DHD_MAX_IFS; idx++) { ++ if (list_head[idx]) { ++ void *temp; ++ uint8 cnt = 0; ++ temp = list_head[idx]; ++ do { ++ temp = PKTNEXT(osh, temp); ++ cnt++; ++ } while (temp); ++ if (cnt) { ++ dhd_os_sdunlock(bus->dhd); ++ dhd_rx_frame(bus->dhd, idx, list_head[idx], cnt, 0); ++ dhd_os_sdlock(bus->dhd); ++ } ++ } ++ } ++ bus->rxglomframes++; ++ bus->rxglompkts += num; ++ } ++ return num; ++} ++ ++ ++/* Return TRUE if there may be more frames to read */ ++static uint ++dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) ++{ ++ osl_t *osh = bus->dhd->osh; ++ bcmsdh_info_t *sdh = bus->sdh; ++ ++ uint16 len, check; /* Extracted hardware header fields */ ++ uint8 chan, seq, doff; /* Extracted software header fields */ ++ uint8 fcbits; /* Extracted fcbits from software header */ ++ uint8 delta; ++ ++ void *pkt; /* Packet for event or data frames */ ++ uint16 pad; /* Number of pad bytes to read */ ++ uint16 rdlen; /* Total number of bytes to read */ ++ uint8 rxseq; /* Next sequence number to expect */ ++ uint rxleft = 0; /* Remaining number of frames allowed */ ++ int sdret; /* Return code from bcmsdh calls */ ++ uint8 txmax; /* Maximum tx sequence offered */ ++ bool len_consistent; /* Result of comparing readahead len and len from hw-hdr */ ++ uint8 *rxbuf; ++ int ifidx = 0; ++ uint rxcount = 0; /* Total frames read */ ++ uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN]; ++ uint reorder_info_len; ++ uint pkt_count; ++ ++#if defined(DHD_DEBUG) || defined(SDTEST) ++ bool sdtest = FALSE; /* To limit message spew from test mode */ ++#endif ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ bus->readframes = TRUE; ++ ++ if (!KSO_ENAB(bus)) { ++ AP6211_DEBUG("%s: KSO off\n", __FUNCTION__); ++ bus->readframes = FALSE; ++ return 0; ++ } ++ ++ ASSERT(maxframes); ++ ++#ifdef SDTEST ++ /* Allow pktgen to override maxframes */ ++ if (bus->pktgen_count && (bus->pktgen_mode == DHD_PKTGEN_RECV)) { ++ maxframes = bus->pktgen_count; ++ sdtest = TRUE; ++ } ++#endif ++ ++ /* Not finished unless we encounter no more frames indication */ ++ *finished = FALSE; ++ ++ ++ for (rxseq = bus->rx_seq, rxleft = maxframes; ++ !bus->rxskip && rxleft && bus->dhd->busstate != DHD_BUS_DOWN; ++ rxseq++, rxleft--) { ++ ++#ifdef DHDTHREAD ++ /* terence: fix got unlikely tx max for 43362a0*/ ++ if (bus->sih->chip!=BCM43362_CHIP_ID && bus->sih->chiprev!=BCM43362A0_CHIP_REV) { ++ /* tx more to improve rx performance */ ++ if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate && ++ pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) { ++ dhdsdio_sendfromq(bus, dhd_txbound); ++ } ++ } ++#endif /* DHDTHREAD */ ++ ++ /* Handle glomming separately */ ++ if (bus->glom || bus->glomd) { ++ uint8 cnt; ++ AP6211_DEBUG("%s: calling rxglom: glomd %p, glom %p\n", ++ __FUNCTION__, bus->glomd, bus->glom); ++ cnt = dhdsdio_rxglom(bus, rxseq); ++ AP6211_DEBUG("%s: rxglom returned %d\n", __FUNCTION__, cnt); ++ rxseq += cnt - 1; ++ rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1; ++ continue; ++ } ++ ++ /* Try doing single read if we can */ ++ if (dhd_readahead && bus->nextlen) { ++ uint16 nextlen = bus->nextlen; ++ bus->nextlen = 0; ++ ++ if (bus->bus == SPI_BUS) { ++ rdlen = len = nextlen; ++ } ++ else { ++ rdlen = len = nextlen << 4; ++ ++ /* Pad read to blocksize for efficiency */ ++ if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) { ++ pad = bus->blocksize - (rdlen % bus->blocksize); ++ if ((pad <= bus->roundup) && (pad < bus->blocksize) && ++ ((rdlen + pad + firstread) < MAX_RX_DATASZ)) ++ rdlen += pad; ++ } else if (rdlen % DHD_SDALIGN) { ++ rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN); ++ } ++ } ++ ++ /* We use bus->rxctl buffer in WinXP for initial control pkt receives. ++ * Later we use buffer-poll for data as well as control packets. ++ * This is required because dhd receives full frame in gSPI unlike SDIO. ++ * After the frame is received we have to distinguish whether it is data ++ * or non-data frame. ++ */ ++ /* Allocate a packet buffer */ ++ dhd_os_sdlock_rxq(bus->dhd); ++ if (!(pkt = PKTGET(osh, rdlen + DHD_SDALIGN, FALSE))) { ++ if (bus->bus == SPI_BUS) { ++ bus->usebufpool = FALSE; ++ bus->rxctl = bus->rxbuf; ++ if (dhd_alignctl) { ++ bus->rxctl += firstread; ++ if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN))) ++ bus->rxctl += (DHD_SDALIGN - pad); ++ bus->rxctl -= firstread; ++ } ++ ASSERT(bus->rxctl >= bus->rxbuf); ++ rxbuf = bus->rxctl; ++ /* Read the entire frame */ ++ sdret = dhd_bcmsdh_recv_buf(bus, ++ bcmsdh_cur_sbwad(sdh), ++ SDIO_FUNC_2, ++ F2SYNC, rxbuf, rdlen, ++ NULL, NULL, NULL); ++ bus->f2rxdata++; ++ ASSERT(sdret != BCME_PENDING); ++ ++ ++ /* Control frame failures need retransmission */ ++ if (sdret < 0) { ++ AP6211_ERR("%s: read %d control bytes failed: %d\n", ++ __FUNCTION__, rdlen, sdret); ++ /* dhd.rx_ctlerrs is higher level */ ++ bus->rxc_errors++; ++ dhd_os_sdunlock_rxq(bus->dhd); ++ dhdsdio_rxfail(bus, TRUE, ++ (bus->bus == SPI_BUS) ? FALSE : TRUE); ++ continue; ++ } ++ } else { ++ /* Give up on data, request rtx of events */ ++ AP6211_ERR("%s (nextlen): PKTGET failed: len %d rdlen %d " ++ "expected rxseq %d\n", ++ __FUNCTION__, len, rdlen, rxseq); ++ /* Just go try again w/normal header read */ ++ dhd_os_sdunlock_rxq(bus->dhd); ++ continue; ++ } ++ } else { ++ if (bus->bus == SPI_BUS) ++ bus->usebufpool = TRUE; ++ ++ ASSERT(!PKTLINK(pkt)); ++ PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN); ++ rxbuf = (uint8 *)PKTDATA(osh, pkt); ++ /* Read the entire frame */ ++ sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), ++ SDIO_FUNC_2, ++ F2SYNC, rxbuf, rdlen, ++ pkt, NULL, NULL); ++ bus->f2rxdata++; ++ ASSERT(sdret != BCME_PENDING); ++ ++ if (sdret < 0) { ++ AP6211_ERR("%s (nextlen): read %d bytes failed: %d\n", ++ __FUNCTION__, rdlen, sdret); ++ PKTFREE(bus->dhd->osh, pkt, FALSE); ++ bus->dhd->rx_errors++; ++ dhd_os_sdunlock_rxq(bus->dhd); ++ /* Force retry w/normal header read. Don't attempt NAK for ++ * gSPI ++ */ ++ dhdsdio_rxfail(bus, TRUE, ++ (bus->bus == SPI_BUS) ? FALSE : TRUE); ++ continue; ++ } ++ } ++ dhd_os_sdunlock_rxq(bus->dhd); ++ ++ /* Now check the header */ ++ bcopy(rxbuf, bus->rxhdr, SDPCM_HDRLEN_RX); ++ ++ /* Extract hardware header fields */ ++ len = ltoh16_ua(bus->rxhdr); ++ check = ltoh16_ua(bus->rxhdr + sizeof(uint16)); ++ ++ /* All zeros means readahead info was bad */ ++ if (!(len|check)) { ++ AP6211_DEBUG("%s (nextlen): read zeros in HW header???\n", ++ __FUNCTION__); ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE2(); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ GSPI_PR55150_BAILOUT; ++ continue; ++ } ++ ++ /* Validate check bytes */ ++ if ((uint16)~(len^check)) { ++ AP6211_ERR("%s (nextlen): HW hdr error: nextlen/len/check" ++ " 0x%04x/0x%04x/0x%04x\n", __FUNCTION__, nextlen, ++ len, check); ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE2(); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ bus->rx_badhdr++; ++ dhdsdio_rxfail(bus, FALSE, FALSE); ++ GSPI_PR55150_BAILOUT; ++ continue; ++ } ++ ++ /* Validate frame length */ ++ if (len < SDPCM_HDRLEN_RX) { ++ AP6211_ERR("%s (nextlen): HW hdr length invalid: %d\n", ++ __FUNCTION__, len); ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE2(); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ GSPI_PR55150_BAILOUT; ++ continue; ++ } ++ ++ /* Check for consistency with readahead info */ ++ len_consistent = (nextlen != (ROUNDUP(len, 16) >> 4)); ++ if (len_consistent) { ++ /* Mismatch, force retry w/normal header (may be >4K) */ ++ AP6211_ERR("%s (nextlen): mismatch, nextlen %d len %d rnd %d; " ++ "expected rxseq %d\n", ++ __FUNCTION__, nextlen, len, ROUNDUP(len, 16), rxseq); ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE2(); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ dhdsdio_rxfail(bus, TRUE, (bus->bus == SPI_BUS) ? FALSE : TRUE); ++ GSPI_PR55150_BAILOUT; ++ continue; ++ } ++ ++ ++ /* Extract software header fields */ ++ chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ ++ bus->nextlen = ++ bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; ++ if ((bus->nextlen << 4) > MAX_RX_DATASZ) { ++ AP6211_DEBUG("%s (nextlen): got frame w/nextlen too large" ++ " (%d), seq %d\n", __FUNCTION__, bus->nextlen, ++ seq); ++ bus->nextlen = 0; ++ } ++ ++ bus->dhd->rx_readahead_cnt ++; ++ /* Handle Flow Control */ ++ fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ ++ delta = 0; ++ if (~bus->flowcontrol & fcbits) { ++ bus->fc_xoff++; ++ delta = 1; ++ } ++ if (bus->flowcontrol & ~fcbits) { ++ bus->fc_xon++; ++ delta = 1; ++ } ++ ++ if (delta) { ++ bus->fc_rcvd++; ++ bus->flowcontrol = fcbits; ++ } ++ ++ /* Check and update sequence number */ ++ if (rxseq != seq) { ++ AP6211_DEBUG("%s (nextlen): rx_seq %d, expected %d\n", ++ __FUNCTION__, seq, rxseq); ++ bus->rx_badseq++; ++ rxseq = seq; ++ } ++ ++ /* Check window for sanity */ ++ if ((uint8)(txmax - bus->tx_seq) > 0x40) { ++ AP6211_ERR("%s: got unlikely tx max %d with tx_seq %d\n", ++ __FUNCTION__, txmax, bus->tx_seq); ++ txmax = bus->tx_max; ++ } ++ bus->tx_max = txmax; ++ ++#ifdef DHD_DEBUG ++ if (DHD_BYTES_ON() && DHD_DATA_ON()) { ++ prhex("Rx Data", rxbuf, len); ++ } else if (DHD_HDRS_ON()) { ++ prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN_RX); ++ } ++#endif ++ ++ if (chan == SDPCM_CONTROL_CHANNEL) { ++ if (bus->bus == SPI_BUS) { ++ dhdsdio_read_control(bus, rxbuf, len, doff); ++ if (bus->usebufpool) { ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE(bus->dhd->osh, pkt, FALSE); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ } ++ continue; ++ } else { ++ AP6211_ERR("%s (nextlen): readahead on control" ++ " packet %d?\n", __FUNCTION__, seq); ++ /* Force retry w/normal header read */ ++ bus->nextlen = 0; ++ dhdsdio_rxfail(bus, FALSE, TRUE); ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE2(); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ continue; ++ } ++ } ++ ++ if ((bus->bus == SPI_BUS) && !bus->usebufpool) { ++ AP6211_ERR("Received %d bytes on %d channel. Running out of " ++ "rx pktbuf's or not yet malloced.\n", len, chan); ++ continue; ++ } ++ ++ /* Validate data offset */ ++ if ((doff < SDPCM_HDRLEN_RX) || (doff > len)) { ++ AP6211_ERR("%s (nextlen): bad data offset %d: HW len %d min %d\n", ++ __FUNCTION__, doff, len, SDPCM_HDRLEN_RX); ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE2(); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ ASSERT(0); ++ dhdsdio_rxfail(bus, FALSE, FALSE); ++ continue; ++ } ++ ++ /* All done with this one -- now deliver the packet */ ++ goto deliver; ++ } ++ /* gSPI frames should not be handled in fractions */ ++ if (bus->bus == SPI_BUS) { ++ break; ++ } ++ ++ /* Read frame header (hardware and software) */ ++ sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, ++ bus->rxhdr, firstread, NULL, NULL, NULL); ++ bus->f2rxhdrs++; ++ ASSERT(sdret != BCME_PENDING); ++ ++ if (sdret < 0) { ++ AP6211_ERR("%s: RXHEADER FAILED: %d\n", __FUNCTION__, sdret); ++ bus->rx_hdrfail++; ++ dhdsdio_rxfail(bus, TRUE, TRUE); ++ continue; ++ } ++ ++#ifdef DHD_DEBUG ++ if (DHD_BYTES_ON() || DHD_HDRS_ON()) { ++ prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN_RX); ++ } ++#endif ++ ++ /* Extract hardware header fields */ ++ len = ltoh16_ua(bus->rxhdr); ++ check = ltoh16_ua(bus->rxhdr + sizeof(uint16)); ++ ++ /* All zeros means no more frames */ ++ if (!(len|check)) { ++ *finished = TRUE; ++ break; ++ } ++ ++ /* Validate check bytes */ ++ if ((uint16)~(len^check)) { ++ AP6211_ERR("%s: HW hdr error: len/check 0x%04x/0x%04x\n", ++ __FUNCTION__, len, check); ++ bus->rx_badhdr++; ++ dhdsdio_rxfail(bus, FALSE, FALSE); ++ continue; ++ } ++ ++ /* Validate frame length */ ++ if (len < SDPCM_HDRLEN_RX) { ++ AP6211_ERR("%s: HW hdr length invalid: %d\n", __FUNCTION__, len); ++ continue; ++ } ++ ++ /* Extract software header fields */ ++ chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ ++ /* Validate data offset */ ++ if ((doff < SDPCM_HDRLEN_RX) || (doff > len)) { ++ AP6211_ERR("%s: Bad data offset %d: HW len %d, min %d seq %d\n", ++ __FUNCTION__, doff, len, SDPCM_HDRLEN_RX, seq); ++ bus->rx_badhdr++; ++ ASSERT(0); ++ dhdsdio_rxfail(bus, FALSE, FALSE); ++ continue; ++ } ++ ++ /* Save the readahead length if there is one */ ++ bus->nextlen = bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; ++ if ((bus->nextlen << 4) > MAX_RX_DATASZ) { ++ AP6211_DEBUG("%s (nextlen): got frame w/nextlen too large (%d), seq %d\n", ++ __FUNCTION__, bus->nextlen, seq); ++ bus->nextlen = 0; ++ } ++ ++ /* Handle Flow Control */ ++ fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ ++ delta = 0; ++ if (~bus->flowcontrol & fcbits) { ++ bus->fc_xoff++; ++ delta = 1; ++ } ++ if (bus->flowcontrol & ~fcbits) { ++ bus->fc_xon++; ++ delta = 1; ++ } ++ ++ if (delta) { ++ bus->fc_rcvd++; ++ bus->flowcontrol = fcbits; ++ } ++ ++ /* Check and update sequence number */ ++ if (rxseq != seq) { ++ AP6211_DEBUG("%s: rx_seq %d, expected %d\n", __FUNCTION__, seq, rxseq); ++ bus->rx_badseq++; ++ rxseq = seq; ++ } ++ ++ /* Check window for sanity */ ++ if ((uint8)(txmax - bus->tx_seq) > 0x40) { ++ AP6211_ERR("%s: got unlikely tx max %d with tx_seq %d\n", ++ __FUNCTION__, txmax, bus->tx_seq); ++ txmax = bus->tx_max; ++ } ++ bus->tx_max = txmax; ++ ++ /* Call a separate function for control frames */ ++ if (chan == SDPCM_CONTROL_CHANNEL) { ++ dhdsdio_read_control(bus, bus->rxhdr, len, doff); ++ continue; ++ } ++ ++ ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL) || ++ (chan == SDPCM_TEST_CHANNEL) || (chan == SDPCM_GLOM_CHANNEL)); ++ ++ /* Length to read */ ++ rdlen = (len > firstread) ? (len - firstread) : 0; ++ ++ /* May pad read to blocksize for efficiency */ ++ if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) { ++ pad = bus->blocksize - (rdlen % bus->blocksize); ++ if ((pad <= bus->roundup) && (pad < bus->blocksize) && ++ ((rdlen + pad + firstread) < MAX_RX_DATASZ)) ++ rdlen += pad; ++ } else if (rdlen % DHD_SDALIGN) { ++ rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN); ++ } ++ ++ /* Satisfy length-alignment requirements */ ++ if (forcealign && (rdlen & (ALIGNMENT - 1))) ++ rdlen = ROUNDUP(rdlen, ALIGNMENT); ++ ++ if ((rdlen + firstread) > MAX_RX_DATASZ) { ++ /* Too long -- skip this frame */ ++ AP6211_ERR("%s: too long: len %d rdlen %d\n", __FUNCTION__, len, rdlen); ++ bus->dhd->rx_errors++; bus->rx_toolong++; ++ dhdsdio_rxfail(bus, FALSE, FALSE); ++ continue; ++ } ++ ++ dhd_os_sdlock_rxq(bus->dhd); ++ if (!(pkt = PKTGET(osh, (rdlen + firstread + DHD_SDALIGN), FALSE))) { ++ /* Give up on data, request rtx of events */ ++ AP6211_ERR("%s: PKTGET failed: rdlen %d chan %d\n", ++ __FUNCTION__, rdlen, chan); ++ bus->dhd->rx_dropped++; ++ dhd_os_sdunlock_rxq(bus->dhd); ++ dhdsdio_rxfail(bus, FALSE, RETRYCHAN(chan)); ++ continue; ++ } ++ dhd_os_sdunlock_rxq(bus->dhd); ++ ++ ASSERT(!PKTLINK(pkt)); ++ ++ /* Leave room for what we already read, and align remainder */ ++ ASSERT(firstread < (PKTLEN(osh, pkt))); ++ PKTPULL(osh, pkt, firstread); ++ PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN); ++ ++ /* Read the remaining frame data */ ++ sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, ++ ((uint8 *)PKTDATA(osh, pkt)), rdlen, pkt, NULL, NULL); ++ bus->f2rxdata++; ++ ASSERT(sdret != BCME_PENDING); ++ ++ if (sdret < 0) { ++ AP6211_ERR("%s: read %d %s bytes failed: %d\n", __FUNCTION__, rdlen, ++ ((chan == SDPCM_EVENT_CHANNEL) ? "event" : ++ ((chan == SDPCM_DATA_CHANNEL) ? "data" : "test")), sdret); ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE(bus->dhd->osh, pkt, FALSE); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ bus->dhd->rx_errors++; ++ dhdsdio_rxfail(bus, TRUE, RETRYCHAN(chan)); ++ continue; ++ } ++ ++ /* Copy the already-read portion */ ++ PKTPUSH(osh, pkt, firstread); ++ bcopy(bus->rxhdr, PKTDATA(osh, pkt), firstread); ++ ++#ifdef DHD_DEBUG ++ if (DHD_BYTES_ON() && DHD_DATA_ON()) { ++ prhex("Rx Data", PKTDATA(osh, pkt), len); ++ } ++#endif ++ ++deliver: ++ /* Save superframe descriptor and allocate packet frame */ ++ if (chan == SDPCM_GLOM_CHANNEL) { ++ if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) { ++ AP6211_DEBUG("%s: got glom descriptor, %d bytes:\n", ++ __FUNCTION__, len); ++#ifdef DHD_DEBUG ++ if (DHD_GLOM_ON()) { ++ prhex("Glom Data", PKTDATA(osh, pkt), len); ++ } ++#endif ++ PKTSETLEN(osh, pkt, len); ++ ASSERT(doff == SDPCM_HDRLEN_RX); ++ PKTPULL(osh, pkt, SDPCM_HDRLEN_RX); ++ bus->glomd = pkt; ++ } else { ++ AP6211_ERR("%s: glom superframe w/o descriptor!\n", __FUNCTION__); ++ dhdsdio_rxfail(bus, FALSE, FALSE); ++ } ++ continue; ++ } ++ ++ /* Fill in packet len and prio, deliver upward */ ++ PKTSETLEN(osh, pkt, len); ++ PKTPULL(osh, pkt, doff); ++ ++#ifdef SDTEST ++ /* Test channel packets are processed separately */ ++ if (chan == SDPCM_TEST_CHANNEL) { ++ dhdsdio_testrcv(bus, pkt, seq); ++ continue; ++ } ++#endif /* SDTEST */ ++ ++ if (PKTLEN(osh, pkt) == 0) { ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE(bus->dhd->osh, pkt, FALSE); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ continue; ++ } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pkt, reorder_info_buf, ++ &reorder_info_len) != 0) { ++ AP6211_ERR("%s: rx protocol error\n", __FUNCTION__); ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE(bus->dhd->osh, pkt, FALSE); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ bus->dhd->rx_errors++; ++ continue; ++ } ++ if (reorder_info_len) { ++ /* Reordering info from the firmware */ ++ dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf, reorder_info_len, ++ &pkt, &pkt_count); ++ if (pkt_count == 0) ++ continue; ++ } ++ else ++ pkt_count = 1; ++ ++ ++ /* Unlock during rx call */ ++ dhd_os_sdunlock(bus->dhd); ++ dhd_rx_frame(bus->dhd, ifidx, pkt, pkt_count, chan); ++ dhd_os_sdlock(bus->dhd); ++ } ++ rxcount = maxframes - rxleft; ++#ifdef DHD_DEBUG ++ /* Message if we hit the limit */ ++ if (!rxleft && !sdtest) ++ AP6211_DEBUG("%s: hit rx limit of %d frames\n", __FUNCTION__, maxframes); ++ else ++#endif /* DHD_DEBUG */ ++ AP6211_DEBUG("%s: processed %d frames\n", __FUNCTION__, rxcount); ++ /* Back off rxseq if awaiting rtx, update rx_seq */ ++ if (bus->rxskip) ++ rxseq--; ++ bus->rx_seq = rxseq; ++ ++ if (bus->reqbussleep) ++ { ++ dhdsdio_bussleep(bus, TRUE); ++ bus->reqbussleep = FALSE; ++ } ++ bus->readframes = FALSE; ++ ++ return rxcount; ++} ++ ++static uint32 ++dhdsdio_hostmail(dhd_bus_t *bus) ++{ ++ sdpcmd_regs_t *regs = bus->regs; ++ uint32 intstatus = 0; ++ uint32 hmb_data; ++ uint8 fcbits; ++ uint retries = 0; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ /* Read mailbox data and ack that we did so */ ++ R_SDREG(hmb_data, ®s->tohostmailboxdata, retries); ++ if (retries <= retry_limit) ++ W_SDREG(SMB_INT_ACK, ®s->tosbmailbox, retries); ++ bus->f1regdata += 2; ++ ++ /* Dongle recomposed rx frames, accept them again */ ++ if (hmb_data & HMB_DATA_NAKHANDLED) { ++ AP6211_DEBUG("Dongle reports NAK handled, expect rtx of %d\n", bus->rx_seq); ++ if (!bus->rxskip) { ++ AP6211_ERR("%s: unexpected NAKHANDLED!\n", __FUNCTION__); ++ } ++ bus->rxskip = FALSE; ++ intstatus |= FRAME_AVAIL_MASK(bus); ++ } ++ ++ /* ++ * DEVREADY does not occur with gSPI. ++ */ ++ if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) { ++ bus->sdpcm_ver = (hmb_data & HMB_DATA_VERSION_MASK) >> HMB_DATA_VERSION_SHIFT; ++ if (bus->sdpcm_ver != SDPCM_PROT_VERSION) ++ AP6211_ERR("Version mismatch, dongle reports %d, expecting %d\n", ++ bus->sdpcm_ver, SDPCM_PROT_VERSION); ++ else ++ AP6211_ERR("Dongle ready, protocol version %d\n", bus->sdpcm_ver); ++ /* make sure for the SDIO_DEVICE_RXDATAINT_MODE_1 corecontrol is proper */ ++ if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) && ++ (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) { ++ uint32 val; ++ ++ val = R_REG(bus->dhd->osh, &bus->regs->corecontrol); ++ val &= ~CC_XMTDATAAVAIL_MODE; ++ val |= CC_XMTDATAAVAIL_CTRL; ++ W_REG(bus->dhd->osh, &bus->regs->corecontrol, val); ++ ++ val = R_REG(bus->dhd->osh, &bus->regs->corecontrol); ++ } ++ ++#ifdef DHD_DEBUG ++ /* Retrieve console state address now that firmware should have updated it */ ++ { ++ sdpcm_shared_t shared; ++ if (dhdsdio_readshared(bus, &shared) == 0) ++ bus->console_addr = shared.console_addr; ++ } ++#endif /* DHD_DEBUG */ ++ } ++ ++ /* ++ * Flow Control has been moved into the RX headers and this out of band ++ * method isn't used any more. Leave this here for possibly remaining backward ++ * compatible with older dongles ++ */ ++ if (hmb_data & HMB_DATA_FC) { ++ fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >> HMB_DATA_FCDATA_SHIFT; ++ ++ if (fcbits & ~bus->flowcontrol) ++ bus->fc_xoff++; ++ if (bus->flowcontrol & ~fcbits) ++ bus->fc_xon++; ++ ++ bus->fc_rcvd++; ++ bus->flowcontrol = fcbits; ++ } ++ ++#ifdef DHD_DEBUG ++ /* At least print a message if FW halted */ ++ if (hmb_data & HMB_DATA_FWHALT) { ++ AP6211_ERR("INTERNAL ERROR: FIRMWARE HALTED : set BUS DOWN\n"); ++ dhdsdio_checkdied(bus, NULL, 0); ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ } ++#endif /* DHD_DEBUG */ ++ ++ /* Shouldn't be any others */ ++ if (hmb_data & ~(HMB_DATA_DEVREADY | ++ HMB_DATA_FWHALT | ++ HMB_DATA_NAKHANDLED | ++ HMB_DATA_FC | ++ HMB_DATA_FWREADY | ++ HMB_DATA_FCDATA_MASK | ++ HMB_DATA_VERSION_MASK)) { ++ AP6211_ERR("Unknown mailbox data content: 0x%02x\n", hmb_data); ++ } ++ ++ return intstatus; ++} ++ ++static bool ++dhdsdio_dpc(dhd_bus_t *bus) ++{ ++ bcmsdh_info_t *sdh = bus->sdh; ++ sdpcmd_regs_t *regs = bus->regs; ++ uint32 intstatus, newstatus = 0; ++ uint retries = 0; ++ uint rxlimit = dhd_rxbound; /* Rx frames to read before resched */ ++ uint txlimit = dhd_txbound; /* Tx frames to send before resched */ ++ uint framecnt = 0; /* Temporary counter of tx/rx frames */ ++ bool rxdone = TRUE; /* Flag for no more read data */ ++ bool resched = FALSE; /* Flag indicating resched wanted */ ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ if (bus->dhd->busstate == DHD_BUS_DOWN) { ++ AP6211_ERR("%s: Bus down, ret\n", __FUNCTION__); ++ bus->intstatus = 0; ++ return 0; ++ } ++ ++ /* Start with leftover status bits */ ++ intstatus = bus->intstatus; ++ ++ dhd_os_sdlock(bus->dhd); ++ ++ if (!SLPAUTO_ENAB(bus) && !KSO_ENAB(bus)) { ++ AP6211_ERR("%s: Device asleep\n", __FUNCTION__); ++ goto exit; ++ } ++ ++ /* If waiting for HTAVAIL, check status */ ++ if (!SLPAUTO_ENAB(bus) && (bus->clkstate == CLK_PENDING)) { ++ int err; ++ uint8 clkctl, devctl = 0; ++ ++#ifdef DHD_DEBUG ++ /* Check for inconsistent device control */ ++ devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); ++ if (err) { ++ AP6211_ERR("%s: error reading DEVCTL: %d\n", __FUNCTION__, err); ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ } else { ++ ASSERT(devctl & SBSDIO_DEVCTL_CA_INT_ONLY); ++ } ++#endif /* DHD_DEBUG */ ++ ++ /* Read CSR, if clock on switch to AVAIL, else ignore */ ++ clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); ++ if (err) { ++ AP6211_ERR("%s: error reading CSR: %d\n", __FUNCTION__, err); ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ } ++ ++ AP6211_DEBUG("DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", devctl, clkctl); ++ ++ if (SBSDIO_HTAV(clkctl)) { ++ devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); ++ if (err) { ++ AP6211_ERR("%s: error reading DEVCTL: %d\n", ++ __FUNCTION__, err); ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ } ++ devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); ++ if (err) { ++ AP6211_ERR("%s: error writing DEVCTL: %d\n", ++ __FUNCTION__, err); ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ } ++ bus->clkstate = CLK_AVAIL; ++ } else { ++ goto clkwait; ++ } ++ } ++ ++ BUS_WAKE(bus); ++ ++ /* Make sure backplane clock is on */ ++ dhdsdio_clkctl(bus, CLK_AVAIL, TRUE); ++ if (bus->clkstate != CLK_AVAIL) ++ goto clkwait; ++ ++ /* Pending interrupt indicates new device status */ ++ if (bus->ipend) { ++ bus->ipend = FALSE; ++ R_SDREG(newstatus, ®s->intstatus, retries); ++ bus->f1regdata++; ++ if (bcmsdh_regfail(bus->sdh)) ++ newstatus = 0; ++ newstatus &= bus->hostintmask; ++ bus->fcstate = !!(newstatus & I_HMB_FC_STATE); ++ if (newstatus) { ++ bus->f1regdata++; ++ if ((bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_0) && ++ (newstatus == I_XMTDATA_AVAIL)) { ++ } ++ else ++ W_SDREG(newstatus, ®s->intstatus, retries); ++ } ++ } ++ ++ /* Merge new bits with previous */ ++ intstatus |= newstatus; ++ bus->intstatus = 0; ++ ++ /* Handle flow-control change: read new state in case our ack ++ * crossed another change interrupt. If change still set, assume ++ * FC ON for safety, let next loop through do the debounce. ++ */ ++ if (intstatus & I_HMB_FC_CHANGE) { ++ intstatus &= ~I_HMB_FC_CHANGE; ++ W_SDREG(I_HMB_FC_CHANGE, ®s->intstatus, retries); ++ R_SDREG(newstatus, ®s->intstatus, retries); ++ bus->f1regdata += 2; ++ bus->fcstate = !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE)); ++ intstatus |= (newstatus & bus->hostintmask); ++ } ++ ++ /* Just being here means nothing more to do for chipactive */ ++ if (intstatus & I_CHIPACTIVE) { ++ /* ASSERT(bus->clkstate == CLK_AVAIL); */ ++ intstatus &= ~I_CHIPACTIVE; ++ } ++ ++ /* Handle host mailbox indication */ ++ if (intstatus & I_HMB_HOST_INT) { ++ intstatus &= ~I_HMB_HOST_INT; ++ intstatus |= dhdsdio_hostmail(bus); ++ } ++ ++ /* Generally don't ask for these, can get CRC errors... */ ++ if (intstatus & I_WR_OOSYNC) { ++ AP6211_DEBUG("Dongle reports WR_OOSYNC\n"); ++ intstatus &= ~I_WR_OOSYNC; ++ } ++ ++ if (intstatus & I_RD_OOSYNC) { ++ AP6211_DEBUG("Dongle reports RD_OOSYNC\n"); ++ intstatus &= ~I_RD_OOSYNC; ++ } ++ ++ if (intstatus & I_SBINT) { ++ AP6211_DEBUG("Dongle reports SBINT\n"); ++ intstatus &= ~I_SBINT; ++ } ++ ++ /* Would be active due to wake-wlan in gSPI */ ++ if (intstatus & I_CHIPACTIVE) { ++ AP6211_DEBUG("Dongle reports CHIPACTIVE\n"); ++ intstatus &= ~I_CHIPACTIVE; ++ } ++ ++ /* Ignore frame indications if rxskip is set */ ++ if (bus->rxskip) { ++ intstatus &= ~FRAME_AVAIL_MASK(bus); ++ } ++ ++ /* On frame indication, read available frames */ ++ if (PKT_AVAILABLE(bus, intstatus)) { ++ framecnt = dhdsdio_readframes(bus, rxlimit, &rxdone); ++ if (rxdone || bus->rxskip) ++ intstatus &= ~FRAME_AVAIL_MASK(bus); ++ rxlimit -= MIN(framecnt, rxlimit); ++ } ++ ++ /* Keep still-pending events for next scheduling */ ++ bus->intstatus = intstatus; ++ ++clkwait: ++ /* Re-enable interrupts to detect new device events (mailbox, rx frame) ++ * or clock availability. (Allows tx loop to check ipend if desired.) ++ * (Unless register access seems hosed, as we may not be able to ACK...) ++ */ ++ if (bus->intr && bus->intdis && !bcmsdh_regfail(sdh)) { ++ AP6211_DEBUG("%s: enable SDIO interrupts, rxdone %d framecnt %d\n", ++ __FUNCTION__, rxdone, framecnt); ++ bus->intdis = FALSE; ++#if defined(OOB_INTR_ONLY) ++ bcmsdh_oob_intr_set(1); ++#endif /* defined(OOB_INTR_ONLY) */ ++ bcmsdh_intr_enable(sdh); ++ } ++ ++#if defined(OOB_INTR_ONLY) && !defined(HW_OOB) ++ /* In case of SW-OOB(using edge trigger), ++ * Check interrupt status in the dongle again after enable irq on the host. ++ * and rechedule dpc if interrupt is pended in the dongle. ++ * There is a chance to miss OOB interrupt while irq is disabled on the host. ++ * No need to do this with HW-OOB(level trigger) ++ */ ++ R_SDREG(newstatus, ®s->intstatus, retries); ++ if (bcmsdh_regfail(bus->sdh)) ++ newstatus = 0; ++ if (newstatus & bus->hostintmask) { ++ bus->ipend = TRUE; ++ resched = TRUE; ++ } ++#endif /* defined(OOB_INTR_ONLY) && !defined(HW_OOB) */ ++#ifdef PROP_TXSTATUS ++ dhd_wlfc_trigger_pktcommit(bus->dhd); ++#endif ++ if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) { ++ int ret, i; ++ ++ uint8* frame_seq = bus->ctrl_frame_buf + SDPCM_FRAMETAG_LEN; ++ ++ if (*frame_seq != bus->tx_seq) { ++ AP6211_DEBUG("%s IOCTL frame seq lag detected!" ++ " frm_seq:%d != bus->tx_seq:%d, corrected\n", ++ __FUNCTION__, *frame_seq, bus->tx_seq); ++ *frame_seq = bus->tx_seq; ++ } ++ ++ ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, ++ (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len, ++ NULL, NULL, NULL); ++ ASSERT(ret != BCME_PENDING); ++ if (ret == BCME_NODEVICE) { ++ AP6211_ERR("%s: Device asleep already\n", __FUNCTION__); ++ } else if (ret < 0) { ++ /* On failure, abort the command and terminate the frame */ ++ AP6211_DEBUG("%s: sdio error %d, abort command and terminate frame.\n", ++ __FUNCTION__, ret); ++ bus->tx_sderrs++; ++ ++ bcmsdh_abort(sdh, SDIO_FUNC_2); ++ ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, ++ SFC_WF_TERM, NULL); ++ bus->f1regdata++; ++ ++ for (i = 0; i < 3; i++) { ++ uint8 hi, lo; ++ hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_WFRAMEBCHI, NULL); ++ lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_WFRAMEBCLO, NULL); ++ bus->f1regdata += 2; ++ if ((hi == 0) && (lo == 0)) ++ break; ++ } ++ } ++ if (ret == 0) { ++ bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; ++ } ++ ++ bus->ctrl_frame_stat = FALSE; ++ dhd_wait_event_wakeup(bus->dhd); ++ } ++ /* Send queued frames (limit 1 if rx may still be pending) */ ++ else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate && ++ pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && DATAOK(bus)) { ++ framecnt = rxdone ? txlimit : MIN(txlimit, dhd_txminmax); ++ framecnt = dhdsdio_sendfromq(bus, framecnt); ++ txlimit -= framecnt; ++ } ++ /* Resched the DPC if ctrl cmd is pending on bus credit */ ++ if (bus->ctrl_frame_stat) ++ resched = TRUE; ++ ++ /* Resched if events or tx frames are pending, else await next interrupt */ ++ /* On failed register access, all bets are off: no resched or interrupts */ ++ if ((bus->dhd->busstate == DHD_BUS_DOWN) || bcmsdh_regfail(sdh)) { ++ if ((bus->sih && bus->sih->buscorerev >= 12) && !(dhdsdio_sleepcsr_get(bus) & ++ SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) { ++ /* Bus failed because of KSO */ ++ AP6211_ERR("%s: Bus failed due to KSO\n", __FUNCTION__); ++ bus->kso = FALSE; ++ } else { ++ AP6211_ERR("%s: failed backplane access over SDIO, halting operation\n", ++ __FUNCTION__); ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ bus->intstatus = 0; ++ } ++ } else if (bus->clkstate == CLK_PENDING) { ++ /* Awaiting I_CHIPACTIVE; don't resched */ ++ } else if (bus->intstatus || bus->ipend || ++ (!bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) || ++ PKT_AVAILABLE(bus, bus->intstatus)) { /* Read multiple frames */ ++ resched = TRUE; ++ } ++ ++ bus->dpc_sched = resched; ++ ++ /* If we're done for now, turn off clock request. */ ++ if ((bus->idletime == DHD_IDLE_IMMEDIATE) && (bus->clkstate != CLK_PENDING)) { ++ bus->activity = FALSE; ++ dhdsdio_clkctl(bus, CLK_NONE, FALSE); ++ } ++ ++exit: ++ dhd_os_sdunlock(bus->dhd); ++ return resched; ++} ++ ++bool ++dhd_bus_dpc(struct dhd_bus *bus) ++{ ++ bool resched; ++ ++ /* Call the DPC directly. */ ++ AP6211_DEBUG("Calling dhdsdio_dpc() from %s\n", __FUNCTION__); ++ resched = dhdsdio_dpc(bus); ++ ++ return resched; ++} ++ ++void ++dhdsdio_isr(void *arg) ++{ ++ dhd_bus_t *bus = (dhd_bus_t*)arg; ++ bcmsdh_info_t *sdh; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ if (!bus) { ++ AP6211_ERR("%s : bus is null pointer , exit \n", __FUNCTION__); ++ return; ++ } ++ sdh = bus->sdh; ++ ++ if (bus->dhd->busstate == DHD_BUS_DOWN) { ++ AP6211_ERR("%s : bus is down. we have nothing to do\n", __FUNCTION__); ++ return; ++ } ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ /* Count the interrupt call */ ++ bus->intrcount++; ++ bus->ipend = TRUE; ++ ++ /* Shouldn't get this interrupt if we're sleeping? */ ++ if (!SLPAUTO_ENAB(bus)) { ++ if (bus->sleeping) { ++ AP6211_ERR("INTERRUPT WHILE SLEEPING??\n"); ++ return; ++ } else if (!KSO_ENAB(bus)) { ++ AP6211_ERR("ISR in devsleep 1\n"); ++ } ++ } ++ ++ /* Disable additional interrupts (is this needed now)? */ ++ if (bus->intr) { ++ AP6211_DEBUG("%s: disable SDIO interrupts\n", __FUNCTION__); ++ } else { ++ AP6211_ERR("dhdsdio_isr() w/o interrupt configured!\n"); ++ } ++ ++ bcmsdh_intr_disable(sdh); ++ bus->intdis = TRUE; ++ ++#if defined(SDIO_ISR_THREAD) ++ AP6211_DEBUG("Calling dhdsdio_dpc() from %s\n", __FUNCTION__); ++ DHD_OS_WAKE_LOCK(bus->dhd); ++ while (dhdsdio_dpc(bus)); ++ DHD_OS_WAKE_UNLOCK(bus->dhd); ++#else ++ bus->dpc_sched = TRUE; ++ dhd_sched_dpc(bus->dhd); ++#endif ++ ++} ++ ++#ifdef SDTEST ++static void ++dhdsdio_pktgen_init(dhd_bus_t *bus) ++{ ++ /* Default to specified length, or full range */ ++ if (dhd_pktgen_len) { ++ bus->pktgen_maxlen = MIN(dhd_pktgen_len, MAX_PKTGEN_LEN); ++ bus->pktgen_minlen = bus->pktgen_maxlen; ++ } else { ++ bus->pktgen_maxlen = MAX_PKTGEN_LEN; ++ bus->pktgen_minlen = 0; ++ } ++ bus->pktgen_len = (uint16)bus->pktgen_minlen; ++ ++ /* Default to per-watchdog burst with 10s print time */ ++ bus->pktgen_freq = 1; ++ bus->pktgen_print = dhd_watchdog_ms ? (10000/dhd_watchdog_ms):0; ++ bus->pktgen_count = (dhd_pktgen * dhd_watchdog_ms + 999) / 1000; ++ ++ /* Default to echo mode */ ++ bus->pktgen_mode = DHD_PKTGEN_ECHO; ++ bus->pktgen_stop = 1; ++} ++ ++static void ++dhdsdio_pktgen(dhd_bus_t *bus) ++{ ++ void *pkt; ++ uint8 *data; ++ uint pktcount; ++ uint fillbyte; ++ osl_t *osh = bus->dhd->osh; ++ uint16 len; ++ ulong time_lapse; ++ uint sent_pkts; ++ uint rcvd_pkts; ++ ++ /* Display current count if appropriate */ ++ if (bus->pktgen_print && (++bus->pktgen_ptick >= bus->pktgen_print)) { ++ bus->pktgen_ptick = 0; ++ AP6211_DEBUG("%s: send attempts %d, rcvd %d, errors %d\n", ++ __FUNCTION__, bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail); ++ ++ /* Print throughput stats only for constant length packet runs */ ++ if (bus->pktgen_minlen == bus->pktgen_maxlen) { ++ time_lapse = jiffies - bus->pktgen_prev_time; ++ bus->pktgen_prev_time = jiffies; ++ sent_pkts = bus->pktgen_sent - bus->pktgen_prev_sent; ++ bus->pktgen_prev_sent = bus->pktgen_sent; ++ rcvd_pkts = bus->pktgen_rcvd - bus->pktgen_prev_rcvd; ++ bus->pktgen_prev_rcvd = bus->pktgen_rcvd; ++ ++ AP6211_DEBUG("%s: Tx Throughput %d kbps, Rx Throughput %d kbps\n", ++ __FUNCTION__, ++ (sent_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8, ++ (rcvd_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8); ++ } ++ } ++ ++ /* For recv mode, just make sure dongle has started sending */ ++ if (bus->pktgen_mode == DHD_PKTGEN_RECV) { ++ if (bus->pktgen_rcv_state == PKTGEN_RCV_IDLE) { ++ bus->pktgen_rcv_state = PKTGEN_RCV_ONGOING; ++ dhdsdio_sdtest_set(bus, bus->pktgen_total); ++ } ++ return; ++ } ++ ++ /* Otherwise, generate or request the specified number of packets */ ++ for (pktcount = 0; pktcount < bus->pktgen_count; pktcount++) { ++ /* Stop if total has been reached */ ++ if (bus->pktgen_total && (bus->pktgen_sent >= bus->pktgen_total)) { ++ bus->pktgen_count = 0; ++ break; ++ } ++ ++ /* Allocate an appropriate-sized packet */ ++ if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) { ++ len = SDPCM_TEST_PKT_CNT_FLD_LEN; ++ } else { ++ len = bus->pktgen_len; ++ } ++ if (!(pkt = PKTGET(osh, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN), ++ TRUE))) {; ++ AP6211_ERR("%s: PKTGET failed!\n", __FUNCTION__); ++ break; ++ } ++ PKTALIGN(osh, pkt, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN); ++ data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN; ++ ++ /* Write test header cmd and extra based on mode */ ++ switch (bus->pktgen_mode) { ++ case DHD_PKTGEN_ECHO: ++ *data++ = SDPCM_TEST_ECHOREQ; ++ *data++ = (uint8)bus->pktgen_sent; ++ break; ++ ++ case DHD_PKTGEN_SEND: ++ *data++ = SDPCM_TEST_DISCARD; ++ *data++ = (uint8)bus->pktgen_sent; ++ break; ++ ++ case DHD_PKTGEN_RXBURST: ++ *data++ = SDPCM_TEST_BURST; ++ *data++ = (uint8)bus->pktgen_count; /* Just for backward compatability */ ++ break; ++ ++ default: ++ AP6211_ERR("Unrecognized pktgen mode %d\n", bus->pktgen_mode); ++ PKTFREE(osh, pkt, TRUE); ++ bus->pktgen_count = 0; ++ return; ++ } ++ ++ /* Write test header length field */ ++ *data++ = (bus->pktgen_len >> 0); ++ *data++ = (bus->pktgen_len >> 8); ++ ++ /* Write frame count in a 4 byte field adjucent to SDPCM test header for ++ * burst mode ++ */ ++ if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) { ++ *data++ = (uint8)(bus->pktgen_count >> 0); ++ *data++ = (uint8)(bus->pktgen_count >> 8); ++ *data++ = (uint8)(bus->pktgen_count >> 16); ++ *data++ = (uint8)(bus->pktgen_count >> 24); ++ } else { ++ ++ /* Then fill in the remainder -- N/A for burst */ ++ for (fillbyte = 0; fillbyte < len; fillbyte++) ++ *data++ = SDPCM_TEST_FILL(fillbyte, (uint8)bus->pktgen_sent); ++ } ++ ++#ifdef DHD_DEBUG ++ if (DHD_BYTES_ON() && DHD_DATA_ON()) { ++ data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN; ++ prhex("dhdsdio_pktgen: Tx Data", data, PKTLEN(osh, pkt) - SDPCM_HDRLEN); ++ } ++#endif ++ ++ /* Send it */ ++ if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE, FALSE)) { ++ bus->pktgen_fail++; ++ if (bus->pktgen_stop && bus->pktgen_stop == bus->pktgen_fail) ++ bus->pktgen_count = 0; ++ } ++ bus->pktgen_sent++; ++ ++ /* Bump length if not fixed, wrap at max */ ++ if (++bus->pktgen_len > bus->pktgen_maxlen) ++ bus->pktgen_len = (uint16)bus->pktgen_minlen; ++ ++ /* Special case for burst mode: just send one request! */ ++ if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) ++ break; ++ } ++} ++ ++static void ++dhdsdio_sdtest_set(dhd_bus_t *bus, uint count) ++{ ++ void *pkt; ++ uint8 *data; ++ osl_t *osh = bus->dhd->osh; ++ ++ /* Allocate the packet */ ++ if (!(pkt = PKTGET(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + ++ SDPCM_TEST_PKT_CNT_FLD_LEN + DHD_SDALIGN, TRUE))) { ++ AP6211_ERR("%s: PKTGET failed!\n", __FUNCTION__); ++ return; ++ } ++ PKTALIGN(osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + ++ SDPCM_TEST_PKT_CNT_FLD_LEN), DHD_SDALIGN); ++ data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN; ++ ++ /* Fill in the test header */ ++ *data++ = SDPCM_TEST_SEND; ++ *data++ = (count > 0)?TRUE:FALSE; ++ *data++ = (bus->pktgen_maxlen >> 0); ++ *data++ = (bus->pktgen_maxlen >> 8); ++ *data++ = (uint8)(count >> 0); ++ *data++ = (uint8)(count >> 8); ++ *data++ = (uint8)(count >> 16); ++ *data++ = (uint8)(count >> 24); ++ ++ /* Send it */ ++ if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE, FALSE)) ++ bus->pktgen_fail++; ++} ++ ++ ++static void ++dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq) ++{ ++ osl_t *osh = bus->dhd->osh; ++ uint8 *data; ++ uint pktlen; ++ ++ uint8 cmd; ++ uint8 extra; ++ uint16 len; ++ uint16 offset; ++ ++ /* Check for min length */ ++ if ((pktlen = PKTLEN(osh, pkt)) < SDPCM_TEST_HDRLEN) { ++ AP6211_ERR("dhdsdio_restrcv: toss runt frame, pktlen %d\n", pktlen); ++ PKTFREE(osh, pkt, FALSE); ++ return; ++ } ++ ++ /* Extract header fields */ ++ data = PKTDATA(osh, pkt); ++ cmd = *data++; ++ extra = *data++; ++ len = *data++; len += *data++ << 8; ++ AP6211_DEBUG("%s:cmd:%d, xtra:%d,len:%d\n", __FUNCTION__, cmd, extra, len); ++ /* Check length for relevant commands */ ++ if (cmd == SDPCM_TEST_DISCARD || cmd == SDPCM_TEST_ECHOREQ || cmd == SDPCM_TEST_ECHORSP) { ++ if (pktlen != len + SDPCM_TEST_HDRLEN) { ++ AP6211_ERR("dhdsdio_testrcv: frame length mismatch, pktlen %d seq %d" ++ " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len); ++ PKTFREE(osh, pkt, FALSE); ++ return; ++ } ++ } ++ ++ /* Process as per command */ ++ switch (cmd) { ++ case SDPCM_TEST_ECHOREQ: ++ /* Rx->Tx turnaround ok (even on NDIS w/current implementation) */ ++ *(uint8 *)(PKTDATA(osh, pkt)) = SDPCM_TEST_ECHORSP; ++ if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE, FALSE) == 0) { ++ bus->pktgen_sent++; ++ } else { ++ bus->pktgen_fail++; ++ PKTFREE(osh, pkt, FALSE); ++ } ++ bus->pktgen_rcvd++; ++ break; ++ ++ case SDPCM_TEST_ECHORSP: ++ if (bus->ext_loop) { ++ PKTFREE(osh, pkt, FALSE); ++ bus->pktgen_rcvd++; ++ break; ++ } ++ ++ for (offset = 0; offset < len; offset++, data++) { ++ if (*data != SDPCM_TEST_FILL(offset, extra)) { ++ AP6211_ERR("dhdsdio_testrcv: echo data mismatch: " ++ "offset %d (len %d) expect 0x%02x rcvd 0x%02x\n", ++ offset, len, SDPCM_TEST_FILL(offset, extra), *data); ++ break; ++ } ++ } ++ PKTFREE(osh, pkt, FALSE); ++ bus->pktgen_rcvd++; ++ break; ++ ++ case SDPCM_TEST_DISCARD: ++ { ++ int i = 0; ++ uint8 *prn = data; ++ uint8 testval = extra; ++ for (i = 0; i < len; i++) { ++ if (*prn != testval) { ++ AP6211_ERR("DIErr@Pkt#:%d,Ix:%d, expected:0x%x, got:0x%x\n", ++ i, bus->pktgen_rcvd_rcvsession, testval, *prn); ++ prn++; testval++; ++ } ++ } ++ } ++ PKTFREE(osh, pkt, FALSE); ++ bus->pktgen_rcvd++; ++ break; ++ ++ case SDPCM_TEST_BURST: ++ case SDPCM_TEST_SEND: ++ default: ++ AP6211_DEBUG("dhdsdio_testrcv: unsupported or unknown command, pktlen %d seq %d" ++ " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len); ++ PKTFREE(osh, pkt, FALSE); ++ break; ++ } ++ ++ /* For recv mode, stop at limit (and tell dongle to stop sending) */ ++ if (bus->pktgen_mode == DHD_PKTGEN_RECV) { ++ if (bus->pktgen_rcv_state != PKTGEN_RCV_IDLE) { ++ bus->pktgen_rcvd_rcvsession++; ++ ++ if (bus->pktgen_total && ++ (bus->pktgen_rcvd_rcvsession >= bus->pktgen_total)) { ++ bus->pktgen_count = 0; ++ AP6211_ERR("Pktgen:rcv test complete!\n"); ++ bus->pktgen_rcv_state = PKTGEN_RCV_IDLE; ++ dhdsdio_sdtest_set(bus, FALSE); ++ bus->pktgen_rcvd_rcvsession = 0; ++ } ++ } ++ } ++} ++#endif /* SDTEST */ ++ ++extern void ++dhd_disable_intr(dhd_pub_t *dhdp) ++{ ++ dhd_bus_t *bus; ++ bus = dhdp->bus; ++ bcmsdh_intr_disable(bus->sdh); ++} ++ ++extern bool ++dhd_bus_watchdog(dhd_pub_t *dhdp) ++{ ++ dhd_bus_t *bus; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ bus = dhdp->bus; ++ ++ if (bus->dhd->dongle_reset) ++ return FALSE; ++ ++ /* Ignore the timer if simulating bus down */ ++ if (!SLPAUTO_ENAB(bus) && bus->sleeping) ++ return FALSE; ++ ++ if (dhdp->busstate == DHD_BUS_DOWN) ++ return FALSE; ++ ++ /* Poll period: check device if appropriate. */ ++ if (!SLPAUTO_ENAB(bus) && (bus->poll && (++bus->polltick >= bus->pollrate))) { ++ uint32 intstatus = 0; ++ ++ /* Reset poll tick */ ++ bus->polltick = 0; ++ ++ /* Check device if no interrupts */ ++ if (!bus->intr || (bus->intrcount == bus->lastintrs)) { ++ ++ if (!bus->dpc_sched) { ++ uint8 devpend; ++ devpend = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, ++ SDIOD_CCCR_INTPEND, NULL); ++ intstatus = devpend & (INTR_STATUS_FUNC1 | INTR_STATUS_FUNC2); ++ } ++ ++ /* If there is something, make like the ISR and schedule the DPC */ ++ if (intstatus) { ++ bus->pollcnt++; ++ bus->ipend = TRUE; ++ if (bus->intr) { ++ bcmsdh_intr_disable(bus->sdh); ++ } ++ bus->dpc_sched = TRUE; ++ dhd_sched_dpc(bus->dhd); ++ ++ } ++ } ++ ++ /* Update interrupt tracking */ ++ bus->lastintrs = bus->intrcount; ++ } ++ ++#ifdef DHD_DEBUG ++ /* Poll for console output periodically */ ++ if (dhdp->busstate == DHD_BUS_DATA && dhd_console_ms != 0) { ++ bus->console.count += dhd_watchdog_ms; ++ if (bus->console.count >= dhd_console_ms) { ++ bus->console.count -= dhd_console_ms; ++ /* Make sure backplane clock is on */ ++ if (SLPAUTO_ENAB(bus)) ++ dhdsdio_bussleep(bus, FALSE); ++ else ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ if (dhdsdio_readconsole(bus) < 0) ++ dhd_console_ms = 0; /* On error, stop trying */ ++ } ++ } ++#endif /* DHD_DEBUG */ ++ ++#ifdef SDTEST ++ /* Generate packets if configured */ ++ if (bus->pktgen_count && (++bus->pktgen_tick >= bus->pktgen_freq)) { ++ /* Make sure backplane clock is on */ ++ if (SLPAUTO_ENAB(bus)) ++ dhdsdio_bussleep(bus, FALSE); ++ else ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ bus->pktgen_tick = 0; ++ dhdsdio_pktgen(bus); ++ } ++#endif ++ ++ /* On idle timeout clear activity flag and/or turn off clock */ ++#ifdef DHD_USE_IDLECOUNT ++ if (bus->activity) ++ bus->activity = FALSE; ++ else { ++ bus->idlecount++; ++ ++ if (bus->idlecount >= bus->idletime) { ++ AP6211_DEBUG("%s: DHD Idle state!!\n", __FUNCTION__); ++ ++ if (SLPAUTO_ENAB(bus)) { ++ if (dhdsdio_bussleep(bus, TRUE) != BCME_BUSY) ++ dhd_os_wd_timer(bus->dhd, 0); ++ } else ++ dhdsdio_clkctl(bus, CLK_NONE, FALSE); ++ ++ bus->idlecount = 0; ++ } ++ } ++#else ++ if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) { ++ if (++bus->idlecount > bus->idletime) { ++ bus->idlecount = 0; ++ if (bus->activity) { ++ bus->activity = FALSE; ++ if (SLPAUTO_ENAB(bus)) { ++ if (!bus->readframes) ++ dhdsdio_bussleep(bus, TRUE); ++ else ++ bus->reqbussleep = TRUE; ++ } ++ else ++ dhdsdio_clkctl(bus, CLK_NONE, FALSE); ++ } ++ } ++ } ++#endif /* DHD_USE_IDLECOUNT */ ++ ++ return bus->ipend; ++} ++ ++#ifdef DHD_DEBUG ++extern int ++dhd_bus_console_in(dhd_pub_t *dhdp, uchar *msg, uint msglen) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ uint32 addr, val; ++ int rv; ++ void *pkt; ++ ++ /* Address could be zero if CONSOLE := 0 in dongle Makefile */ ++ if (bus->console_addr == 0) ++ return BCME_UNSUPPORTED; ++ ++ /* Exclusive bus access */ ++ dhd_os_sdlock(bus->dhd); ++ ++ /* Don't allow input if dongle is in reset */ ++ if (bus->dhd->dongle_reset) { ++ dhd_os_sdunlock(bus->dhd); ++ return BCME_NOTREADY; ++ } ++ ++ /* Request clock to allow SDIO accesses */ ++ BUS_WAKE(bus); ++ /* No pend allowed since txpkt is called later, ht clk has to be on */ ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ ++ /* Zero cbuf_index */ ++ addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf_idx); ++ val = htol32(0); ++ if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0) ++ goto done; ++ ++ /* Write message into cbuf */ ++ addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf); ++ if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)msg, msglen)) < 0) ++ goto done; ++ ++ /* Write length into vcons_in */ ++ addr = bus->console_addr + OFFSETOF(hndrte_cons_t, vcons_in); ++ val = htol32(msglen); ++ if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0) ++ goto done; ++ ++ /* Bump dongle by sending an empty packet on the event channel. ++ * sdpcm_sendup (RX) checks for virtual console input. ++ */ ++ if ((pkt = PKTGET(bus->dhd->osh, 4 + SDPCM_RESERVE, TRUE)) != NULL) ++ dhdsdio_txpkt(bus, pkt, SDPCM_EVENT_CHANNEL, TRUE, FALSE); ++ ++done: ++ if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { ++ bus->activity = FALSE; ++ dhdsdio_clkctl(bus, CLK_NONE, TRUE); ++ } ++ ++ dhd_os_sdunlock(bus->dhd); ++ ++ return rv; ++} ++#endif /* DHD_DEBUG */ ++ ++#ifdef DHD_DEBUG ++static void ++dhd_dump_cis(uint fn, uint8 *cis) ++{ ++ uint byte, tag, tdata; ++ AP6211_DEBUG("Function %d CIS:\n", fn); ++ ++ for (tdata = byte = 0; byte < SBSDIO_CIS_SIZE_LIMIT; byte++) { ++ if ((byte % 16) == 0) ++ AP6211_DUMP(" "); ++ AP6211_DUMP("%02x ", cis[byte]); ++ if ((byte % 16) == 15) ++ AP6211_DUMP("\n"); ++ if (!tdata--) { ++ tag = cis[byte]; ++ if (tag == 0xff) ++ break; ++ else if (!tag) ++ tdata = 0; ++ else if ((byte + 1) < SBSDIO_CIS_SIZE_LIMIT) ++ tdata = cis[byte + 1] + 1; ++ else ++ AP6211_DUMP("]"); ++ } ++ } ++ if ((byte % 16) != 15) ++ AP6211_DUMP("\n"); ++} ++#endif /* DHD_DEBUG */ ++ ++static bool ++dhdsdio_chipmatch(uint16 chipid) ++{ ++ if (chipid == BCM4325_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM4329_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM4315_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM4319_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM4336_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM4330_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM43237_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM43362_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM4314_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM4334_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM43341_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM43239_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM4324_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM4335_CHIP_ID) ++ return TRUE; ++ return FALSE; ++} ++ ++static void * ++dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, ++ uint16 func, uint bustype, void *regsva, osl_t * osh, void *sdh) ++{ ++ int ret; ++ dhd_bus_t *bus; ++#ifdef GET_CUSTOM_MAC_ENABLE ++ struct ether_addr ea_addr; ++#endif /* GET_CUSTOM_MAC_ENABLE */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) ++ ++ if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) { ++ AP6211_DEBUG("%s : no mutex held. set lock\n", __FUNCTION__); ++ } ++ else { ++ AP6211_DEBUG("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__); ++ } ++ mutex_lock(&_dhd_sdio_mutex_lock_); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ ++ ++ /* Init global variables at run-time, not as part of the declaration. ++ * This is required to support init/de-init of the driver. Initialization ++ * of globals as part of the declaration results in non-deterministic ++ * behavior since the value of the globals may be different on the ++ * first time that the driver is initialized vs subsequent initializations. ++ */ ++ dhd_txbound = DHD_TXBOUND; ++ dhd_rxbound = DHD_RXBOUND; ++ dhd_alignctl = TRUE; ++ sd1idle = TRUE; ++ dhd_readahead = TRUE; ++ retrydata = FALSE; ++ dhd_doflow = FALSE; ++ dhd_dongle_memsize = 0; ++ dhd_txminmax = DHD_TXMINMAX; ++ ++ forcealign = TRUE; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ AP6211_DEBUG("%s: venid 0x%04x devid 0x%04x\n", __FUNCTION__, venid, devid); ++ ++ /* We make assumptions about address window mappings */ ++ ASSERT((uintptr)regsva == SI_ENUM_BASE); ++ ++ /* BCMSDH passes venid and devid based on CIS parsing -- but low-power start ++ * means early parse could fail, so here we should get either an ID ++ * we recognize OR (-1) indicating we must request power first. ++ */ ++ /* Check the Vendor ID */ ++ switch (venid) { ++ case 0x0000: ++ case VENDOR_BROADCOM: ++ break; ++ default: ++ AP6211_ERR("%s: unknown vendor: 0x%04x\n", ++ __FUNCTION__, venid); ++ goto forcereturn; ++ } ++ ++ /* Check the Device ID and make sure it's one that we support */ ++ switch (devid) { ++ case BCM4325_D11DUAL_ID: /* 4325 802.11a/g id */ ++ case BCM4325_D11G_ID: /* 4325 802.11g 2.4Ghz band id */ ++ case BCM4325_D11A_ID: /* 4325 802.11a 5Ghz band id */ ++ AP6211_DEBUG("%s: found 4325 Dongle\n", __FUNCTION__); ++ break; ++ case BCM4329_D11N_ID: /* 4329 802.11n dualband device */ ++ case BCM4329_D11N2G_ID: /* 4329 802.11n 2.4G device */ ++ case BCM4329_D11N5G_ID: /* 4329 802.11n 5G device */ ++ case 0x4329: ++ AP6211_DEBUG("%s: found 4329 Dongle\n", __FUNCTION__); ++ break; ++ case BCM4315_D11DUAL_ID: /* 4315 802.11a/g id */ ++ case BCM4315_D11G_ID: /* 4315 802.11g id */ ++ case BCM4315_D11A_ID: /* 4315 802.11a id */ ++ AP6211_DEBUG("%s: found 4315 Dongle\n", __FUNCTION__); ++ break; ++ case BCM4319_D11N_ID: /* 4319 802.11n id */ ++ case BCM4319_D11N2G_ID: /* 4319 802.11n2g id */ ++ case BCM4319_D11N5G_ID: /* 4319 802.11n5g id */ ++ AP6211_DEBUG("%s: found 4319 Dongle\n", __FUNCTION__); ++ break; ++ case 0: ++ AP6211_DEBUG("%s: allow device id 0, will check chip internals\n", ++ __FUNCTION__); ++ break; ++ ++ default: ++ AP6211_ERR("%s: skipping 0x%04x/0x%04x, not a dongle\n", ++ __FUNCTION__, venid, devid); ++ goto forcereturn; ++ } ++ ++ if (osh == NULL) { ++ /* Ask the OS interface part for an OSL handle */ ++ if (!(osh = dhd_osl_attach(sdh, DHD_BUS))) { ++ AP6211_ERR("%s: osl_attach failed!\n", __FUNCTION__); ++ goto forcereturn; ++ } ++ } ++ ++ /* Allocate private bus interface state */ ++ if (!(bus = MALLOC(osh, sizeof(dhd_bus_t)))) { ++ AP6211_ERR("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__); ++ goto fail; ++ } ++ bzero(bus, sizeof(dhd_bus_t)); ++ bus->sdh = sdh; ++ bus->cl_devid = (uint16)devid; ++ bus->bus = DHD_BUS; ++ bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1; ++ bus->usebufpool = FALSE; /* Use bufpool if allocated, else use locally malloced rxbuf */ ++ ++ /* attach the common module */ ++ dhd_common_init(osh); ++ ++ /* attempt to attach to the dongle */ ++ if (!(dhdsdio_probe_attach(bus, osh, sdh, regsva, devid))) { ++ AP6211_ERR("%s: dhdsdio_probe_attach failed\n", __FUNCTION__); ++ goto fail; ++ } ++ ++ /* Attach to the dhd/OS/network interface */ ++ if (!(bus->dhd = dhd_attach(osh, bus, SDPCM_RESERVE))) { ++ AP6211_ERR("%s: dhd_attach failed\n", __FUNCTION__); ++ goto fail; ++ } ++ ++ /* Allocate buffers */ ++ if (!(dhdsdio_probe_malloc(bus, osh, sdh))) { ++ AP6211_ERR("%s: dhdsdio_probe_malloc failed\n", __FUNCTION__); ++ goto fail; ++ } ++ ++ if (!(dhdsdio_probe_init(bus, osh, sdh))) { ++ AP6211_ERR("%s: dhdsdio_probe_init failed\n", __FUNCTION__); ++ goto fail; ++ } ++ ++ if (bus->intr) { ++ /* Register interrupt callback, but mask it (not operational yet). */ ++ AP6211_DEBUG("%s: disable SDIO interrupts (not interested yet)\n", __FUNCTION__); ++ bcmsdh_intr_disable(sdh); ++ if ((ret = bcmsdh_intr_reg(sdh, dhdsdio_isr, bus)) != 0) { ++ AP6211_ERR("%s: FAILED: bcmsdh_intr_reg returned %d\n", ++ __FUNCTION__, ret); ++ goto fail; ++ } ++ AP6211_DEBUG("%s: registered SDIO interrupt function ok\n", __FUNCTION__); ++ } else { ++ AP6211_DEBUG("%s: SDIO interrupt function is NOT registered due to polling mode\n", ++ __FUNCTION__); ++ } ++ ++ AP6211_DEBUG("%s: completed!!\n", __FUNCTION__); ++ ++#ifdef GET_CUSTOM_MAC_ENABLE ++ /* Read MAC address from external customer place */ ++ memset(&ea_addr, 0, sizeof(ea_addr)); ++ ret = dhd_custom_get_mac_address(ea_addr.octet); ++ if (!ret) { ++ memcpy(bus->dhd->mac.octet, (void *)&ea_addr, ETHER_ADDR_LEN); ++ } ++#endif /* GET_CUSTOM_MAC_ENABLE */ ++ ++ /* if firmware path present try to download and bring up bus */ ++ if (dhd_download_fw_on_driverload) { ++ if ((ret = dhd_bus_start(bus->dhd)) != 0) { ++ AP6211_ERR("%s: dhd_bus_start failed\n", __FUNCTION__); ++ goto fail; ++ } ++ } ++ /* Ok, have the per-port tell the stack we're open for business */ ++ if (dhd_net_attach(bus->dhd, 0) != 0) { ++ AP6211_ERR("%s: Net attach failed!!\n", __FUNCTION__); ++ goto fail; ++ } ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) ++ mutex_unlock(&_dhd_sdio_mutex_lock_); ++ AP6211_DEBUG("%s : the lock is released.\n", __FUNCTION__); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ ++ ++ return bus; ++ ++fail: ++ dhdsdio_release(bus, osh); ++ ++forcereturn: ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) ++ mutex_unlock(&_dhd_sdio_mutex_lock_); ++ AP6211_DEBUG("%s : the lock is released.\n", __FUNCTION__); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ ++ ++ return NULL; ++} ++ ++static bool ++dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, ++ uint16 devid) ++{ ++ int err = 0; ++ uint8 clkctl = 0; ++ ++ bus->alp_only = TRUE; ++ bus->sih = NULL; ++ ++ /* Return the window to backplane enumeration space for core access */ ++ if (dhdsdio_set_siaddr_window(bus, SI_ENUM_BASE)) { ++ AP6211_ERR("%s: FAILED to return to SI_ENUM_BASE\n", __FUNCTION__); ++ } ++ ++#ifdef DHD_DEBUG ++ AP6211_DEBUG("F1 signature read @0x18000000=0x%4x\n", ++ bcmsdh_reg_read(bus->sdh, SI_ENUM_BASE, 4)); ++ ++#endif /* DHD_DEBUG */ ++ ++ ++ /* Force PLL off until si_attach() programs PLL control regs */ ++ ++ ++ ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, DHD_INIT_CLKCTL1, &err); ++ if (!err) ++ clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); ++ ++ if (err || ((clkctl & ~SBSDIO_AVBITS) != DHD_INIT_CLKCTL1)) { ++ AP6211_ERR("dhdsdio_probe: ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n", ++ err, DHD_INIT_CLKCTL1, clkctl); ++ goto fail; ++ } ++ ++#ifdef DHD_DEBUG ++ if (DHD_INFO_ON()) { ++ uint fn, numfn; ++ uint8 *cis[SDIOD_MAX_IOFUNCS]; ++ int err = 0; ++ ++ numfn = bcmsdh_query_iofnum(sdh); ++ ASSERT(numfn <= SDIOD_MAX_IOFUNCS); ++ ++ /* Make sure ALP is available before trying to read CIS */ ++ SPINWAIT(((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, NULL)), ++ !SBSDIO_ALPAV(clkctl)), PMU_MAX_TRANSITION_DLY); ++ ++ /* Now request ALP be put on the bus */ ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, ++ DHD_INIT_CLKCTL2, &err); ++ OSL_DELAY(65); ++ ++ for (fn = 0; fn <= numfn; fn++) { ++ if (!(cis[fn] = MALLOC(osh, SBSDIO_CIS_SIZE_LIMIT))) { ++ AP6211_DEBUG("dhdsdio_probe: fn %d cis malloc failed\n", fn); ++ break; ++ } ++ bzero(cis[fn], SBSDIO_CIS_SIZE_LIMIT); ++ ++ if ((err = bcmsdh_cis_read(sdh, fn, cis[fn], SBSDIO_CIS_SIZE_LIMIT))) { ++ AP6211_DEBUG("dhdsdio_probe: fn %d cis read err %d\n", fn, err); ++ MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT); ++ break; ++ } ++ dhd_dump_cis(fn, cis[fn]); ++ } ++ ++ while (fn-- > 0) { ++ ASSERT(cis[fn]); ++ MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT); ++ } ++ ++ if (err) { ++ AP6211_ERR("dhdsdio_probe: failure reading or parsing CIS\n"); ++ goto fail; ++ } ++ } ++#endif /* DHD_DEBUG */ ++ ++ /* si_attach() will provide an SI handle and scan the backplane */ ++ if (!(bus->sih = si_attach((uint)devid, osh, regsva, DHD_BUS, sdh, ++ &bus->vars, &bus->varsz))) { ++ AP6211_ERR("%s: si_attach failed!\n", __FUNCTION__); ++ goto fail; ++ } ++ ++ bcmsdh_chipinfo(sdh, bus->sih->chip, bus->sih->chiprev); ++ ++ if (!dhdsdio_chipmatch((uint16)bus->sih->chip)) { ++ AP6211_ERR("%s: unsupported chip: 0x%04x\n", ++ __FUNCTION__, bus->sih->chip); ++ goto fail; ++ } ++ ++ if (bus->sih->buscorerev >= 12) ++ dhdsdio_clk_kso_init(bus); ++ else ++ bus->kso = TRUE; ++ ++ if (CST4330_CHIPMODE_SDIOD(bus->sih->chipst)) { ++ } ++ ++ si_sdiod_drive_strength_init(bus->sih, osh, dhd_sdiod_drive_strength); ++ ++ ++ /* Get info on the ARM and SOCRAM cores... */ ++ if (!DHD_NOPMU(bus)) { ++ if ((si_setcore(bus->sih, ARM7S_CORE_ID, 0)) || ++ (si_setcore(bus->sih, ARMCM3_CORE_ID, 0)) || ++ (si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) { ++ bus->armrev = si_corerev(bus->sih); ++ } else { ++ AP6211_ERR("%s: failed to find ARM core!\n", __FUNCTION__); ++ goto fail; ++ } ++ ++ if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { ++ if (!(bus->orig_ramsize = si_socram_size(bus->sih))) { ++ AP6211_ERR("%s: failed to find SOCRAM memory!\n", __FUNCTION__); ++ goto fail; ++ } ++ } else { ++ /* cr4 has a different way to find the RAM size from TCM's */ ++ if (!(bus->orig_ramsize = si_tcm_size(bus->sih))) { ++ AP6211_ERR("%s: failed to find CR4-TCM memory!\n", __FUNCTION__); ++ goto fail; ++ } ++ /* also populate base address */ ++ bus->dongle_ram_base = CR4_RAM_BASE; ++ } ++ bus->ramsize = bus->orig_ramsize; ++ if (dhd_dongle_memsize) ++ dhd_dongle_setmemsize(bus, dhd_dongle_memsize); ++ ++ AP6211_DEBUG("DHD: dongle ram size is set to %d(orig %d)\n", ++ bus->ramsize, bus->orig_ramsize); ++ ++ bus->srmemsize = si_socram_srmem_size(bus->sih); ++ } ++ ++ /* ...but normally deal with the SDPCMDEV core */ ++ if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) && ++ !(bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0))) { ++ AP6211_ERR("%s: failed to find SDIODEV core!\n", __FUNCTION__); ++ goto fail; ++ } ++ bus->sdpcmrev = si_corerev(bus->sih); ++ ++ /* Set core control so an SDIO reset does a backplane reset */ ++ OR_REG(osh, &bus->regs->corecontrol, CC_BPRESEN); ++ bus->rxint_mode = SDIO_DEVICE_HMB_RXINT; ++ ++ if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) && ++ (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) ++ { ++ uint32 val; ++ ++ val = R_REG(osh, &bus->regs->corecontrol); ++ val &= ~CC_XMTDATAAVAIL_MODE; ++ val |= CC_XMTDATAAVAIL_CTRL; ++ W_REG(osh, &bus->regs->corecontrol, val); ++ } ++ ++ ++ pktq_init(&bus->txq, (PRIOMASK + 1), QLEN); ++ ++ /* Locate an appropriately-aligned portion of hdrbuf */ ++ bus->rxhdr = (uint8 *)ROUNDUP((uintptr)&bus->hdrbuf[0], DHD_SDALIGN); ++ ++ /* Set the poll and/or interrupt flags */ ++ bus->intr = (bool)dhd_intr; ++ if ((bus->poll = (bool)dhd_poll)) ++ bus->pollrate = 1; ++ ++#ifdef BCMSDIOH_TXGLOM ++ /* Setting default Glom mode */ ++ bus->glom_mode = SDPCM_TXGLOM_CPY; ++ /* Setting default Glom size */ ++ bus->glomsize = SDPCM_DEFGLOM_SIZE; ++#endif ++ ++ return TRUE; ++ ++fail: ++ if (bus->sih != NULL) { ++ si_detach(bus->sih); ++ bus->sih = NULL; ++ } ++ return FALSE; ++} ++ ++static bool ++dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh) ++{ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ if (bus->dhd->maxctl) { ++ bus->rxblen = ROUNDUP((bus->dhd->maxctl + SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN; ++ if (!(bus->rxbuf = DHD_OS_PREALLOC(osh, DHD_PREALLOC_RXBUF, bus->rxblen))) { ++ AP6211_ERR("%s: MALLOC of %d-byte rxbuf failed\n", ++ __FUNCTION__, bus->rxblen); ++ goto fail; ++ } ++ } ++ /* Allocate buffer to receive glomed packet */ ++ if (!(bus->databuf = DHD_OS_PREALLOC(osh, DHD_PREALLOC_DATABUF, MAX_DATA_BUF))) { ++ AP6211_ERR("%s: MALLOC of %d-byte databuf failed\n", ++ __FUNCTION__, MAX_DATA_BUF); ++ /* release rxbuf which was already located as above */ ++ if (!bus->rxblen) ++ DHD_OS_PREFREE(osh, bus->rxbuf, bus->rxblen); ++ goto fail; ++ } ++ ++ /* Align the buffer */ ++ if ((uintptr)bus->databuf % DHD_SDALIGN) ++ bus->dataptr = bus->databuf + (DHD_SDALIGN - ((uintptr)bus->databuf % DHD_SDALIGN)); ++ else ++ bus->dataptr = bus->databuf; ++ ++ return TRUE; ++ ++fail: ++ return FALSE; ++} ++ ++static bool ++dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh) ++{ ++ int32 fnum; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++#ifdef SDTEST ++ dhdsdio_pktgen_init(bus); ++#endif /* SDTEST */ ++ ++ /* Disable F2 to clear any intermediate frame state on the dongle */ ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL); ++ ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ bus->sleeping = FALSE; ++ bus->rxflow = FALSE; ++ bus->prev_rxlim_hit = 0; ++ ++ /* Done with backplane-dependent accesses, can drop clock... */ ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL); ++ ++ /* ...and initialize clock/power states */ ++ bus->clkstate = CLK_SDONLY; ++ bus->idletime = (int32)dhd_idletime; ++ bus->idleclock = DHD_IDLE_ACTIVE; ++ ++ /* Query the SD clock speed */ ++ if (bcmsdh_iovar_op(sdh, "sd_divisor", NULL, 0, ++ &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) { ++ AP6211_ERR("%s: fail on %s get\n", __FUNCTION__, "sd_divisor"); ++ bus->sd_divisor = -1; ++ } else { ++ AP6211_DEBUG("%s: Initial value for %s is %d\n", ++ __FUNCTION__, "sd_divisor", bus->sd_divisor); ++ } ++ ++ /* Query the SD bus mode */ ++ if (bcmsdh_iovar_op(sdh, "sd_mode", NULL, 0, ++ &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) { ++ AP6211_ERR("%s: fail on %s get\n", __FUNCTION__, "sd_mode"); ++ bus->sd_mode = -1; ++ } else { ++ AP6211_DEBUG("%s: Initial value for %s is %d\n", ++ __FUNCTION__, "sd_mode", bus->sd_mode); ++ } ++ ++ /* Query the F2 block size, set roundup accordingly */ ++ fnum = 2; ++ if (bcmsdh_iovar_op(sdh, "sd_blocksize", &fnum, sizeof(int32), ++ &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) { ++ bus->blocksize = 0; ++ AP6211_ERR("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"); ++ } else { ++ AP6211_DEBUG("%s: Initial value for %s is %d\n", ++ __FUNCTION__, "sd_blocksize", bus->blocksize); ++ } ++ bus->roundup = MIN(max_roundup, bus->blocksize); ++ ++ /* Query if bus module supports packet chaining, default to use if supported */ ++ if (bcmsdh_iovar_op(sdh, "sd_rxchain", NULL, 0, ++ &bus->sd_rxchain, sizeof(int32), FALSE) != BCME_OK) { ++ bus->sd_rxchain = FALSE; ++ } else { ++ AP6211_DEBUG("%s: bus module (through bcmsdh API) %s chaining\n", ++ __FUNCTION__, (bus->sd_rxchain ? "supports" : "does not support")); ++ } ++ bus->use_rxchain = (bool)bus->sd_rxchain; ++ ++ return TRUE; ++} ++ ++void ++dhd_bus_select_firmware_name_by_chip(struct dhd_bus *bus, char *dst, char *src) ++{ ++ int fw_type, ag_type; ++ static uint chip, chiprev, first=1; ++ int i; ++ ++ if (first) { ++ chip = bus->sih->chip; ++ chiprev = bus->sih->chiprev; ++ first = 0; ++ } ++ if (src[0] == '\0') { ++#ifdef CONFIG_AP6211_FW_PATH ++ bcm_strncpy_s(src, sizeof(fw_path), CONFIG_AP6211_FW_PATH, MOD_PARAM_PATHLEN-1); ++ if (src[0] == '\0') ++#endif ++ { ++ AP6211_DEBUG("src firmware path is null\n"); ++ return; ++ } ++ } ++ ++ strcpy(dst, src); ++#ifndef FW_PATH_AUTO_SELECT ++ return; ++#endif ++ ++ /* find out the last '/' */ ++ i = strlen(dst); ++ while (i>0){ ++ if (dst[i] == '/') break; ++ i--; ++ } ++#ifdef BAND_AG ++ ag_type = FW_TYPE_AG; ++#else ++ ag_type = strstr(&dst[i], "_ag") ? FW_TYPE_AG : FW_TYPE_G; ++#endif ++ fw_type = (strstr(&dst[i], "_mfg") ? ++ FW_TYPE_MFG : (strstr(&dst[i], "_apsta") ? ++ FW_TYPE_APSTA : (strstr(&dst[i], "_p2p") ? ++ FW_TYPE_P2P : FW_TYPE_STA))); ++ ++ ++ switch (chip) { ++ case BCM4330_CHIP_ID: ++ if (ag_type == FW_TYPE_G) { ++ if (chiprev == BCM4330B2_CHIP_REV) ++ strcpy(&dst[i+1], bcm40183b2_fw_name[fw_type]); ++ break; ++ } else { ++ if (chiprev == BCM4330B2_CHIP_REV) ++ strcpy(&dst[i+1], bcm40183b2ag_fw_name[fw_type]); ++ break; ++ } ++ case BCM43362_CHIP_ID: ++ if (chiprev == BCM43362A0_CHIP_REV) ++ strcpy(&dst[i+1], bcm40181a0_fw_name[fw_type]); ++ else ++ strcpy(&dst[i+1], bcm40181a2_fw_name[fw_type]); ++ break; ++ case BCM43341_CHIP_ID: ++ if (chiprev == BCM43341B0_CHIP_REV) ++ strcpy(&dst[i+1], bcm43341b0ag_fw_name[fw_type]); ++ break; ++ case BCM4324_CHIP_ID: ++ if (chiprev == BCM43241B4_CHIP_REV) ++ strcpy(&dst[i+1], bcm43241b4ag_fw_name[fw_type]); ++ break; ++ } ++ ++ AP6211_DEBUG("%s: firmware_path=%s\n", __FUNCTION__, dst); ++} ++ ++bool ++dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh, ++ char *pfw_path, char *pnv_path) ++{ ++ bool ret; ++ bus->fw_path = pfw_path; ++ bus->nv_path = pnv_path; ++ ++ ret = dhdsdio_download_firmware(bus, osh, bus->sdh); ++ ++ ++ return ret; ++} ++ ++static bool ++dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh) ++{ ++ bool ret; ++ ++ DHD_OS_WAKE_LOCK(bus->dhd); ++ ++ /* Download the firmware */ ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ ++ AP6211_ERR("Final fw_path=%s\n", bus->fw_path); ++ AP6211_ERR("Final nv_path=%s\n", bus->nv_path); ++ ret = _dhdsdio_download_firmware(bus) == 0; ++ ++ dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); ++ ++ DHD_OS_WAKE_UNLOCK(bus->dhd); ++ return ret; ++} ++ ++/* Detach and free everything */ ++static void ++dhdsdio_release(dhd_bus_t *bus, osl_t *osh) ++{ ++ bool dongle_isolation = FALSE; ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ if (bus) { ++ ASSERT(osh); ++ ++ if (bus->dhd) { ++ dongle_isolation = bus->dhd->dongle_isolation; ++ dhd_detach(bus->dhd); ++ } ++ ++ /* De-register interrupt handler */ ++ bcmsdh_intr_disable(bus->sdh); ++ bcmsdh_intr_dereg(bus->sdh); ++ ++ if (bus->dhd) { ++ dhdsdio_release_dongle(bus, osh, dongle_isolation, TRUE); ++ dhd_free(bus->dhd); ++ bus->dhd = NULL; ++ } ++ ++ dhdsdio_release_malloc(bus, osh); ++ ++#ifdef DHD_DEBUG ++ if (bus->console.buf != NULL) ++ MFREE(osh, bus->console.buf, bus->console.bufsize); ++#endif ++ ++ MFREE(osh, bus, sizeof(dhd_bus_t)); ++ } ++ ++ if (osh) ++ dhd_osl_detach(osh); ++ ++ AP6211_DEBUG("%s: Disconnected\n", __FUNCTION__); ++} ++ ++static void ++dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh) ++{ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ if (bus->dhd && bus->dhd->dongle_reset) ++ return; ++ ++ if (bus->rxbuf) { ++#ifndef CONFIG_DHD_USE_STATIC_BUF ++ MFREE(osh, bus->rxbuf, bus->rxblen); ++#endif ++ bus->rxctl = bus->rxbuf = NULL; ++ bus->rxlen = 0; ++ } ++ ++ if (bus->databuf) { ++#ifndef CONFIG_DHD_USE_STATIC_BUF ++ MFREE(osh, bus->databuf, MAX_DATA_BUF); ++#endif ++ bus->databuf = NULL; ++ } ++ ++ if (bus->vars && bus->varsz) { ++ MFREE(osh, bus->vars, bus->varsz); ++ bus->vars = NULL; ++ } ++ ++} ++ ++ ++static void ++dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool reset_flag) ++{ ++ AP6211_DEBUG("%s: Enter bus->dhd %p bus->dhd->dongle_reset %d \n", __FUNCTION__, ++ bus->dhd, bus->dhd->dongle_reset); ++ ++ if ((bus->dhd && bus->dhd->dongle_reset) && reset_flag) ++ return; ++ ++ if (bus->sih) { ++#if !defined(BCMLXSDMMC) ++ if (bus->dhd) { ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ } ++ if (KSO_ENAB(bus) && (dongle_isolation == FALSE)) ++ si_watchdog(bus->sih, 4); ++#endif /* !defined(BCMLXSDMMC) */ ++ if (bus->dhd) { ++ dhdsdio_clkctl(bus, CLK_NONE, FALSE); ++ } ++ si_detach(bus->sih); ++ bus->sih = NULL; ++ if (bus->vars && bus->varsz) ++ MFREE(osh, bus->vars, bus->varsz); ++ bus->vars = NULL; ++ } ++ ++ AP6211_DEBUG("%s: Disconnected\n", __FUNCTION__); ++} ++ ++static void ++dhdsdio_disconnect(void *ptr) ++{ ++ dhd_bus_t *bus = (dhd_bus_t *)ptr; ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) ++ ++ if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) { ++ AP6211_DEBUG("%s : no mutex held. set lock\n", __FUNCTION__); ++ } ++ else { ++ AP6211_DEBUG("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__); ++ } ++ mutex_lock(&_dhd_sdio_mutex_lock_); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ if (bus) { ++ ASSERT(bus->dhd); ++ dhdsdio_release(bus, bus->dhd->osh); ++ } ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) ++ mutex_unlock(&_dhd_sdio_mutex_lock_); ++ AP6211_ERR("%s : the lock is released.\n", __FUNCTION__); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ ++ ++ AP6211_DEBUG("%s: Disconnected\n", __FUNCTION__); ++} ++ ++ ++/* Register/Unregister functions are called by the main DHD entry ++ * point (e.g. module insertion) to link with the bus driver, in ++ * order to look for or await the device. ++ */ ++ ++static bcmsdh_driver_t dhd_sdio = { ++ dhdsdio_probe, ++ dhdsdio_disconnect ++}; ++ ++int ++dhd_bus_register(void) ++{ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ return bcmsdh_register(&dhd_sdio); ++} ++ ++void ++dhd_bus_unregister(void) ++{ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ bcmsdh_unregister(); ++} ++ ++#if defined(BCMLXSDMMC) ++/* Register a dummy SDIO client driver in order to be notified of new SDIO device */ ++int dhd_bus_reg_sdio_notify(void* semaphore) ++{ ++ return bcmsdh_reg_sdio_notify(semaphore); ++} ++ ++void dhd_bus_unreg_sdio_notify(void) ++{ ++ bcmsdh_unreg_sdio_notify(); ++} ++#endif /* defined(BCMLXSDMMC) */ ++ ++#ifdef BCMEMBEDIMAGE ++static int ++dhdsdio_download_code_array(struct dhd_bus *bus) ++{ ++ int bcmerror = -1; ++ int offset = 0; ++ unsigned char *ularray = NULL; ++ ++ AP6211_ERR("%s: download embedded firmware...\n", __FUNCTION__); ++ ++ /* Download image */ ++ while ((offset + MEMBLOCK) < sizeof(dlarray)) { ++ bcmerror = dhdsdio_membytes(bus, TRUE, offset, ++ (uint8 *) (dlarray + offset), MEMBLOCK); ++ if (bcmerror) { ++ AP6211_ERR("%s: error %d on writing %d membytes at 0x%08x\n", ++ __FUNCTION__, bcmerror, MEMBLOCK, offset); ++ goto err; ++ } ++ ++ offset += MEMBLOCK; ++ } ++ ++ if (offset < sizeof(dlarray)) { ++ bcmerror = dhdsdio_membytes(bus, TRUE, offset, ++ (uint8 *) (dlarray + offset), sizeof(dlarray) - offset); ++ if (bcmerror) { ++ AP6211_ERR("%s: error %d on writing %d membytes at 0x%08x\n", ++ __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset); ++ goto err; ++ } ++ } ++ ++#ifdef DHD_DEBUG ++ /* Upload and compare the downloaded code */ ++ { ++ ularray = MALLOC(bus->dhd->osh, bus->ramsize); ++ /* Upload image to verify downloaded contents. */ ++ offset = 0; ++ memset(ularray, 0xaa, bus->ramsize); ++ while ((offset + MEMBLOCK) < sizeof(dlarray)) { ++ bcmerror = dhdsdio_membytes(bus, FALSE, offset, ularray + offset, MEMBLOCK); ++ if (bcmerror) { ++ AP6211_ERR("%s: error %d on reading %d membytes at 0x%08x\n", ++ __FUNCTION__, bcmerror, MEMBLOCK, offset); ++ goto err; ++ } ++ ++ offset += MEMBLOCK; ++ } ++ ++ if (offset < sizeof(dlarray)) { ++ bcmerror = dhdsdio_membytes(bus, FALSE, offset, ++ ularray + offset, sizeof(dlarray) - offset); ++ if (bcmerror) { ++ AP6211_ERR("%s: error %d on reading %d membytes at 0x%08x\n", ++ __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset); ++ goto err; ++ } ++ } ++ ++ if (memcmp(dlarray, ularray, sizeof(dlarray))) { ++ AP6211_ERR("%s: Downloaded image is corrupted (%s, %s, %s).\n", ++ __FUNCTION__, dlimagename, dlimagever, dlimagedate); ++ goto err; ++ } else ++ AP6211_ERR("%s: Download, Upload and compare succeeded (%s, %s, %s).\n", ++ __FUNCTION__, dlimagename, dlimagever, dlimagedate); ++ ++ } ++#endif /* DHD_DEBUG */ ++ ++err: ++ if (ularray) ++ MFREE(bus->dhd->osh, ularray, bus->ramsize); ++ return bcmerror; ++} ++#endif /* BCMEMBEDIMAGE */ ++ ++static int ++dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path) ++{ ++ int bcmerror = -1; ++ int offset = 0; ++ int len; ++ void *image = NULL; ++ uint8 *memblock = NULL, *memptr; ++ uint8 *memptr_tmp = NULL; // terence: check downloaded firmware is correct ++ ++ AP6211_ERR("download firmware %s\n", pfw_path); ++ ++ image = dhd_os_open_image(pfw_path); ++ if (image == NULL) ++ goto err; ++ ++ memptr = memblock = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN); ++ if (memblock == NULL) { ++ AP6211_ERR("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK); ++ goto err; ++ } ++ if (dhd_msg_level & DHD_TRACE_VAL) { ++ memptr_tmp = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN); ++ if (memptr_tmp == NULL) { ++ AP6211_ERR("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK); ++ goto err; ++ } ++ } ++ if ((uint32)(uintptr)memblock % DHD_SDALIGN) ++ memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN)); ++ ++ /* Download image */ ++ while ((len = dhd_os_get_image_block((char*)memptr, MEMBLOCK, image))) { ++ if (len < 0) { ++ AP6211_ERR("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__, len); ++ bcmerror = BCME_ERROR; ++ goto err; ++ } ++ bcmerror = dhdsdio_membytes(bus, TRUE, offset, memptr, len); ++ if (bcmerror) { ++ AP6211_ERR("%s: error %d on writing %d membytes at 0x%08x\n", ++ __FUNCTION__, bcmerror, MEMBLOCK, offset); ++ goto err; ++ } ++ ++ if (dhd_msg_level & DHD_TRACE_VAL) { ++ bcmerror = dhdsdio_membytes(bus, FALSE, offset, memptr_tmp, len); ++ if (bcmerror) { ++ AP6211_ERR("%s: error %d on reading %d membytes at 0x%08x\n", ++ __FUNCTION__, bcmerror, MEMBLOCK, offset); ++ goto err; ++ } ++ if (memcmp(memptr_tmp, memptr, len)) { ++ AP6211_ERR("%s: Downloaded image is corrupted.\n", __FUNCTION__); ++ goto err; ++ } else ++ AP6211_ERR("%s: Download, Upload and compare succeeded.\n", __FUNCTION__); ++ } ++ offset += MEMBLOCK; ++ } ++ ++err: ++ if (memblock) ++ MFREE(bus->dhd->osh, memblock, MEMBLOCK + DHD_SDALIGN); ++ if (dhd_msg_level & DHD_TRACE_VAL) { ++ if (memptr_tmp) ++ MFREE(bus->dhd->osh, memptr_tmp, MEMBLOCK + DHD_SDALIGN); ++ } ++ ++ if (image) ++ dhd_os_close_image(image); ++ ++ return bcmerror; ++} ++ ++/* ++ EXAMPLE: nvram_array ++ nvram_arry format: ++ name=value ++ Use carriage return at the end of each assignment, and an empty string with ++ carriage return at the end of array. ++ ++ For example: ++ unsigned char nvram_array[] = {"name1=value1\n", "name2=value2\n", "\n"}; ++ Hex values start with 0x, and mac addr format: xx:xx:xx:xx:xx:xx. ++ ++ Search "EXAMPLE: nvram_array" to see how the array is activated. ++*/ ++ ++void ++dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params) ++{ ++ bus->nvram_params = nvram_params; ++} ++ ++static int ++dhdsdio_download_nvram(struct dhd_bus *bus) ++{ ++ int bcmerror = -1; ++ uint len; ++ void * image = NULL; ++ char * memblock = NULL; ++ char *bufp; ++ char *pnv_path; ++ bool nvram_file_exists; ++ ++ pnv_path = bus->nv_path; ++ ++ nvram_file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0')); ++ if (!nvram_file_exists && (bus->nvram_params == NULL)) ++ return (0); ++ ++ if (nvram_file_exists) { ++ image = dhd_os_open_image(pnv_path); ++ if (image == NULL) ++ goto err; ++ } ++ ++ memblock = MALLOC(bus->dhd->osh, MAX_NVRAMBUF_SIZE); ++ if (memblock == NULL) { ++ AP6211_ERR("%s: Failed to allocate memory %d bytes\n", ++ __FUNCTION__, MAX_NVRAMBUF_SIZE); ++ goto err; ++ } ++ ++ /* Download variables */ ++ if (nvram_file_exists) { ++ len = dhd_os_get_image_block(memblock, MAX_NVRAMBUF_SIZE, image); ++ } ++ else { ++ len = strlen(bus->nvram_params); ++ ASSERT(len <= MAX_NVRAMBUF_SIZE); ++ memcpy(memblock, bus->nvram_params, len); ++ } ++ if (len > 0 && len < MAX_NVRAMBUF_SIZE) { ++ bufp = (char *)memblock; ++ bufp[len] = 0; ++ len = process_nvram_vars(bufp, len); ++ if (len % 4) { ++ len += 4 - (len % 4); ++ } ++ bufp += len; ++ *bufp++ = 0; ++ if (len) ++ bcmerror = dhdsdio_downloadvars(bus, memblock, len + 1); ++ if (bcmerror) { ++ AP6211_ERR("%s: error downloading vars: %d\n", ++ __FUNCTION__, bcmerror); ++ } ++ } ++ else { ++ AP6211_ERR("%s: error reading nvram file: %d\n", ++ __FUNCTION__, len); ++ bcmerror = BCME_SDIO_ERROR; ++ } ++ ++err: ++ if (memblock) ++ MFREE(bus->dhd->osh, memblock, MAX_NVRAMBUF_SIZE); ++ ++ if (image) ++ dhd_os_close_image(image); ++ ++ return bcmerror; ++} ++ ++static int ++_dhdsdio_download_firmware(struct dhd_bus *bus) ++{ ++ int bcmerror = -1; ++ ++ bool embed = FALSE; /* download embedded firmware */ ++ bool dlok = FALSE; /* download firmware succeeded */ ++ ++ /* Out immediately if no image to download */ ++ if ((bus->fw_path == NULL) || (bus->fw_path[0] == '\0')) { ++#ifdef BCMEMBEDIMAGE ++ embed = TRUE; ++#else ++ return 0; ++#endif ++ } ++ ++ /* Keep arm in reset */ ++ if (dhdsdio_download_state(bus, TRUE)) { ++ AP6211_ERR("%s: error placing ARM core in reset\n", __FUNCTION__); ++ goto err; ++ } ++ ++ /* External image takes precedence if specified */ ++ if ((bus->fw_path != NULL) && (bus->fw_path[0] != '\0')) { ++ if (dhdsdio_download_code_file(bus, bus->fw_path)) { ++ AP6211_ERR("%s: dongle image file download failed\n", __FUNCTION__); ++#ifdef BCMEMBEDIMAGE ++ embed = TRUE; ++#else ++ goto err; ++#endif ++ } ++ else { ++ embed = FALSE; ++ dlok = TRUE; ++ } ++ } ++#ifdef BCMEMBEDIMAGE ++ if (embed) { ++ if (dhdsdio_download_code_array(bus)) { ++ AP6211_ERR("%s: dongle image array download failed\n", __FUNCTION__); ++ goto err; ++ } ++ else { ++ dlok = TRUE; ++ } ++ } ++#else ++ BCM_REFERENCE(embed); ++#endif ++ if (!dlok) { ++ AP6211_ERR("%s: dongle image download failed\n", __FUNCTION__); ++ goto err; ++ } ++ ++ /* EXAMPLE: nvram_array */ ++ /* If a valid nvram_arry is specified as above, it can be passed down to dongle */ ++ /* dhd_bus_set_nvram_params(bus, (char *)&nvram_array); */ ++ ++ /* External nvram takes precedence if specified */ ++ if (dhdsdio_download_nvram(bus)) { ++ AP6211_ERR("%s: dongle nvram file download failed\n", __FUNCTION__); ++ goto err; ++ } ++ ++ /* Take arm out of reset */ ++ if (dhdsdio_download_state(bus, FALSE)) { ++ AP6211_ERR("%s: error getting out of ARM core reset\n", __FUNCTION__); ++ goto err; ++ } ++ ++ bcmerror = 0; ++ ++err: ++ return bcmerror; ++} ++ ++static int ++dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes, ++ void *pkt, bcmsdh_cmplt_fn_t complete, void *handle) ++{ ++ int status; ++ ++ if (!KSO_ENAB(bus)) { ++ AP6211_ERR("%s: Device asleep\n", __FUNCTION__); ++ return BCME_NODEVICE; ++ } ++ ++ status = bcmsdh_recv_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle); ++ ++ return status; ++} ++ ++static int ++dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes, ++ void *pkt, bcmsdh_cmplt_fn_t complete, void *handle) ++{ ++ if (!KSO_ENAB(bus)) { ++ AP6211_ERR("%s: Device asleep\n", __FUNCTION__); ++ return BCME_NODEVICE; ++ } ++ ++ return (bcmsdh_send_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle)); ++} ++ ++#ifdef BCMSDIOH_TXGLOM ++static void ++dhd_bcmsdh_glom_post(dhd_bus_t *bus, uint8 *frame, uint len) ++{ ++ bcmsdh_glom_post(bus->sdh, frame, len); ++} ++ ++static void ++dhd_bcmsdh_glom_clear(dhd_bus_t *bus) ++{ ++ bcmsdh_glom_clear(bus->sdh); ++} ++#endif ++ ++uint ++dhd_bus_chip(struct dhd_bus *bus) ++{ ++ ASSERT(bus->sih != NULL); ++ return bus->sih->chip; ++} ++ ++void * ++dhd_bus_pub(struct dhd_bus *bus) ++{ ++ return bus->dhd; ++} ++ ++void * ++dhd_bus_txq(struct dhd_bus *bus) ++{ ++ return &bus->txq; ++} ++ ++uint ++dhd_bus_hdrlen(struct dhd_bus *bus) ++{ ++ return SDPCM_HDRLEN; ++} ++ ++int ++dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) ++{ ++ int bcmerror = 0; ++ dhd_bus_t *bus; ++ ++ bus = dhdp->bus; ++ ++ if (flag == TRUE) { ++ if (!bus->dhd->dongle_reset) { ++ dhd_os_sdlock(dhdp); ++ dhd_os_wd_timer(dhdp, 0); ++#if !defined(IGNORE_ETH0_DOWN) ++ /* Force flow control as protection when stop come before ifconfig_down */ ++ dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON); ++#endif /* !defined(IGNORE_ETH0_DOWN) */ ++ /* Expect app to have torn down any connection before calling */ ++ /* Stop the bus, disable F2 */ ++ dhd_bus_stop(bus, FALSE); ++ ++#if defined(OOB_INTR_ONLY) ++ /* Clean up any pending IRQ */ ++ bcmsdh_set_irq(FALSE); ++#endif ++ ++ /* Clean tx/rx buffer pointers, detach from the dongle */ ++ dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE, TRUE); ++ ++ bus->dhd->dongle_reset = TRUE; ++ bus->dhd->up = FALSE; ++#ifdef BCMSDIOH_TXGLOM ++ dhd_txglom_enable(dhdp, FALSE); ++#endif ++ dhd_os_sdunlock(dhdp); ++ ++ AP6211_ERR("%s: WLAN OFF DONE\n", __FUNCTION__); ++ /* App can now remove power from device */ ++ } else ++ bcmerror = BCME_SDIO_ERROR; ++ } else { ++ /* App must have restored power to device before calling */ ++ ++ AP6211_ERR("%s: WLAN ON\n", __FUNCTION__); ++ ++ if (bus->dhd->dongle_reset) { ++ /* Turn on WLAN */ ++#ifdef DHDTHREAD ++ dhd_os_sdlock(dhdp); ++#endif /* DHDTHREAD */ ++ /* Reset SD client */ ++ bcmsdh_reset(bus->sdh); ++ ++ /* Attempt to re-attach & download */ ++ if (dhdsdio_probe_attach(bus, bus->dhd->osh, bus->sdh, ++ (uint32 *)SI_ENUM_BASE, ++ bus->cl_devid)) { ++ /* Attempt to download binary to the dongle */ ++ COPY_FW_PATH_BY_CHIP(bus, fw_path, firmware_path); // terence ++ if (dhdsdio_probe_init(bus, bus->dhd->osh, bus->sdh) && ++ dhdsdio_download_firmware(bus, bus->dhd->osh, bus->sdh)) { ++ ++ /* Re-init bus, enable F2 transfer */ ++ bcmerror = dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE); ++ if (bcmerror == BCME_OK) { ++#if defined(OOB_INTR_ONLY) ++ bcmsdh_set_irq(TRUE); ++ dhd_enable_oob_intr(bus, TRUE); ++#endif ++ ++ bus->dhd->dongle_reset = FALSE; ++ bus->dhd->up = TRUE; ++ ++#if !defined(IGNORE_ETH0_DOWN) ++ /* Restore flow control */ ++ dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF); ++#endif ++ dhd_os_wd_timer(dhdp, dhd_watchdog_ms); ++#ifdef BCMSDIOH_TXGLOM ++ if ((dhdp->busstate == DHD_BUS_DATA) && ++ bcmsdh_glom_enabled()) { ++ dhd_txglom_enable(dhdp, TRUE); ++ } ++#endif /* BCMSDIOH_TXGLOM */ ++ AP6211_ERR("%s: WLAN ON DONE\n", __FUNCTION__); ++ } else { ++ dhd_bus_stop(bus, FALSE); ++ dhdsdio_release_dongle(bus, bus->dhd->osh, ++ TRUE, FALSE); ++ } ++ } else ++ bcmerror = BCME_SDIO_ERROR; ++ } else ++ bcmerror = BCME_SDIO_ERROR; ++ ++#ifdef DHDTHREAD ++ dhd_os_sdunlock(dhdp); ++#endif /* DHDTHREAD */ ++ } else { ++ bcmerror = BCME_SDIO_ERROR; ++ AP6211_DEBUG("%s called when dongle is not in reset\n", ++ __FUNCTION__); ++ AP6211_DEBUG("Will call dhd_bus_start instead\n"); ++ sdioh_start(NULL, 1); ++#if defined(HW_OOB) ++ bcmsdh_config_hw_oob_intr(bus->sdh, bus->sih->chip); // terence 20120615: fix for OOB initial issue ++#endif ++ COPY_FW_PATH_BY_CHIP(bus, fw_path, firmware_path); ++ if ((bcmerror = dhd_bus_start(dhdp)) != 0) ++ AP6211_ERR("%s: dhd_bus_start fail with %d\n", ++ __FUNCTION__, bcmerror); ++ } ++ } ++ return bcmerror; ++} ++ ++/* Get Chip ID version */ ++uint dhd_bus_chip_id(dhd_pub_t *dhdp) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ ++ return bus->sih->chip; ++} ++ ++/* Get Chip Rev ID version */ ++uint dhd_bus_chiprev_id(dhd_pub_t *dhdp) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ ++ return bus->sih->chiprev; ++} ++ ++/* Get Chip Pkg ID version */ ++uint dhd_bus_chippkg_id(dhd_pub_t *dhdp) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ ++ return bus->sih->chippkg; ++} ++ ++int ++dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size) ++{ ++ dhd_bus_t *bus; ++ ++ bus = dhdp->bus; ++ return dhdsdio_membytes(bus, set, address, data, size); ++} +diff --git a/drivers/net/wireless/ap6211/dhd_wlfc.c b/drivers/net/wireless/ap6211/dhd_wlfc.c +new file mode 100755 +index 0000000..93b4ca3 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_wlfc.c +@@ -0,0 +1,2441 @@ ++/* ++ * DHD PROP_TXSTATUS Module. ++ * ++ * Copyright (C) 1999-2013, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd_wlfc.c 412994 2013-07-17 12:38:03Z $ ++ * ++ */ ++ ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++ ++#ifdef PROP_TXSTATUS ++#include ++#include ++#endif ++ ++ ++ ++ ++#define BUS_RETRIES 1 /* # of retries before aborting a bus tx operation */ ++ ++#ifdef PROP_TXSTATUS ++typedef struct dhd_wlfc_commit_info { ++ uint8 needs_hdr; ++ uint8 ac_fifo_credit_spent; ++ ewlfc_packet_state_t pkt_type; ++ wlfc_mac_descriptor_t* mac_entry; ++ void* p; ++} dhd_wlfc_commit_info_t; ++#endif /* PROP_TXSTATUS */ ++ ++ ++#ifdef PROP_TXSTATUS ++ ++#define DHD_WLFC_QMON_COMPLETE(entry) ++ ++void ++dhd_wlfc_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) ++{ ++ int i; ++ uint8* ea; ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhdp->wlfc_state; ++ wlfc_hanger_t* h; ++ wlfc_mac_descriptor_t* mac_table; ++ wlfc_mac_descriptor_t* interfaces; ++ char* iftypes[] = {"STA", "AP", "WDS", "p2pGO", "p2pCL"}; ++ ++ if (wlfc == NULL) { ++ bcm_bprintf(strbuf, "wlfc not initialized yet\n"); ++ return; ++ } ++ h = (wlfc_hanger_t*)wlfc->hanger; ++ if (h == NULL) { ++ bcm_bprintf(strbuf, "wlfc-hanger not initialized yet\n"); ++ } ++ ++ mac_table = wlfc->destination_entries.nodes; ++ interfaces = wlfc->destination_entries.interfaces; ++ bcm_bprintf(strbuf, "---- wlfc stats ----\n"); ++ if (h) { ++ bcm_bprintf(strbuf, "wlfc hanger (pushed,popped,f_push," ++ "f_pop,f_slot, pending) = (%d,%d,%d,%d,%d,%d)\n", ++ h->pushed, ++ h->popped, ++ h->failed_to_push, ++ h->failed_to_pop, ++ h->failed_slotfind, ++ (h->pushed - h->popped)); ++ } ++ ++ bcm_bprintf(strbuf, "wlfc fail(tlv,credit_rqst,mac_update,psmode_update), " ++ "(dq_full,rollback_fail) = (%d,%d,%d,%d), (%d,%d)\n", ++ wlfc->stats.tlv_parse_failed, ++ wlfc->stats.credit_request_failed, ++ wlfc->stats.mac_update_failed, ++ wlfc->stats.psmode_update_failed, ++ wlfc->stats.delayq_full_error, ++ wlfc->stats.rollback_failed); ++ ++ bcm_bprintf(strbuf, "PKTS (credit,sent) " ++ "(AC0[%d,%d],AC1[%d,%d],AC2[%d,%d],AC3[%d,%d],BC_MC[%d,%d])\n", ++ wlfc->FIFO_credit[0], wlfc->stats.send_pkts[0], ++ wlfc->FIFO_credit[1], wlfc->stats.send_pkts[1], ++ wlfc->FIFO_credit[2], wlfc->stats.send_pkts[2], ++ wlfc->FIFO_credit[3], wlfc->stats.send_pkts[3], ++ wlfc->FIFO_credit[4], wlfc->stats.send_pkts[4]); ++ ++ bcm_bprintf(strbuf, "\n"); ++ for (i = 0; i < WLFC_MAX_IFNUM; i++) { ++ if (interfaces[i].occupied) { ++ char* iftype_desc; ++ ++ if (interfaces[i].iftype > WLC_E_IF_ROLE_P2P_CLIENT) ++ iftype_desc = "hostif_flow_state[i] == OFF) ++ ? " OFF":" ON")); ++ ++ bcm_bprintf(strbuf, "INTERFACE[%d].DELAYQ(len,state,credit)" ++ "= (%d,%s,%d)\n", ++ i, ++ interfaces[i].psq.len, ++ ((interfaces[i].state == ++ WLFC_STATE_OPEN) ? " OPEN":"CLOSE"), ++ interfaces[i].requested_credit); ++ ++ bcm_bprintf(strbuf, "INTERFACE[%d].DELAYQ" ++ "(sup,ac0),(sup,ac1),(sup,ac2),(sup,ac3) = " ++ "(%d,%d),(%d,%d),(%d,%d),(%d,%d)\n", ++ i, ++ interfaces[i].psq.q[0].len, ++ interfaces[i].psq.q[1].len, ++ interfaces[i].psq.q[2].len, ++ interfaces[i].psq.q[3].len, ++ interfaces[i].psq.q[4].len, ++ interfaces[i].psq.q[5].len, ++ interfaces[i].psq.q[6].len, ++ interfaces[i].psq.q[7].len); ++ } ++ } ++ ++ bcm_bprintf(strbuf, "\n"); ++ for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { ++ if (mac_table[i].occupied) { ++ ea = mac_table[i].ea; ++ bcm_bprintf(strbuf, "MAC_table[%d].ea = " ++ "[%02x:%02x:%02x:%02x:%02x:%02x], if:%d \n", i, ++ ea[0], ea[1], ea[2], ea[3], ea[4], ea[5], ++ mac_table[i].interface_id); ++ ++ bcm_bprintf(strbuf, "MAC_table[%d].DELAYQ(len,state,credit)" ++ "= (%d,%s,%d)\n", ++ i, ++ mac_table[i].psq.len, ++ ((mac_table[i].state == ++ WLFC_STATE_OPEN) ? " OPEN":"CLOSE"), ++ mac_table[i].requested_credit); ++#ifdef PROP_TXSTATUS_DEBUG ++ bcm_bprintf(strbuf, "MAC_table[%d]: (opened, closed) = (%d, %d)\n", ++ i, mac_table[i].opened_ct, mac_table[i].closed_ct); ++#endif ++ bcm_bprintf(strbuf, "MAC_table[%d].DELAYQ" ++ "(sup,ac0),(sup,ac1),(sup,ac2),(sup,ac3) = " ++ "(%d,%d),(%d,%d),(%d,%d),(%d,%d)\n", ++ i, ++ mac_table[i].psq.q[0].len, ++ mac_table[i].psq.q[1].len, ++ mac_table[i].psq.q[2].len, ++ mac_table[i].psq.q[3].len, ++ mac_table[i].psq.q[4].len, ++ mac_table[i].psq.q[5].len, ++ mac_table[i].psq.q[6].len, ++ mac_table[i].psq.q[7].len); ++ } ++ } ++ ++#ifdef PROP_TXSTATUS_DEBUG ++ { ++ int avg; ++ int moving_avg = 0; ++ int moving_samples; ++ ++ if (wlfc->stats.latency_sample_count) { ++ moving_samples = sizeof(wlfc->stats.deltas)/sizeof(uint32); ++ ++ for (i = 0; i < moving_samples; i++) ++ moving_avg += wlfc->stats.deltas[i]; ++ moving_avg /= moving_samples; ++ ++ avg = (100 * wlfc->stats.total_status_latency) / ++ wlfc->stats.latency_sample_count; ++ bcm_bprintf(strbuf, "txstatus latency (average, last, moving[%d]) = " ++ "(%d.%d, %03d, %03d)\n", ++ moving_samples, avg/100, (avg - (avg/100)*100), ++ wlfc->stats.latency_most_recent, ++ moving_avg); ++ } ++ } ++ ++ bcm_bprintf(strbuf, "wlfc- fifo[0-5] credit stats: sent = (%d,%d,%d,%d,%d,%d), " ++ "back = (%d,%d,%d,%d,%d,%d)\n", ++ wlfc->stats.fifo_credits_sent[0], ++ wlfc->stats.fifo_credits_sent[1], ++ wlfc->stats.fifo_credits_sent[2], ++ wlfc->stats.fifo_credits_sent[3], ++ wlfc->stats.fifo_credits_sent[4], ++ wlfc->stats.fifo_credits_sent[5], ++ ++ wlfc->stats.fifo_credits_back[0], ++ wlfc->stats.fifo_credits_back[1], ++ wlfc->stats.fifo_credits_back[2], ++ wlfc->stats.fifo_credits_back[3], ++ wlfc->stats.fifo_credits_back[4], ++ wlfc->stats.fifo_credits_back[5]); ++ { ++ uint32 fifo_cr_sent = 0; ++ uint32 fifo_cr_acked = 0; ++ uint32 request_cr_sent = 0; ++ uint32 request_cr_ack = 0; ++ uint32 bc_mc_cr_ack = 0; ++ ++ for (i = 0; i < sizeof(wlfc->stats.fifo_credits_sent)/sizeof(uint32); i++) { ++ fifo_cr_sent += wlfc->stats.fifo_credits_sent[i]; ++ } ++ ++ for (i = 0; i < sizeof(wlfc->stats.fifo_credits_back)/sizeof(uint32); i++) { ++ fifo_cr_acked += wlfc->stats.fifo_credits_back[i]; ++ } ++ ++ for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { ++ if (wlfc->destination_entries.nodes[i].occupied) { ++ request_cr_sent += ++ wlfc->destination_entries.nodes[i].dstncredit_sent_packets; ++ } ++ } ++ for (i = 0; i < WLFC_MAX_IFNUM; i++) { ++ if (wlfc->destination_entries.interfaces[i].occupied) { ++ request_cr_sent += ++ wlfc->destination_entries.interfaces[i].dstncredit_sent_packets; ++ } ++ } ++ for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { ++ if (wlfc->destination_entries.nodes[i].occupied) { ++ request_cr_ack += ++ wlfc->destination_entries.nodes[i].dstncredit_acks; ++ } ++ } ++ for (i = 0; i < WLFC_MAX_IFNUM; i++) { ++ if (wlfc->destination_entries.interfaces[i].occupied) { ++ request_cr_ack += ++ wlfc->destination_entries.interfaces[i].dstncredit_acks; ++ } ++ } ++ bcm_bprintf(strbuf, "wlfc- (sent, status) => pq(%d,%d), vq(%d,%d)," ++ "other:%d, bc_mc:%d, signal-only, (sent,freed): (%d,%d)", ++ fifo_cr_sent, fifo_cr_acked, ++ request_cr_sent, request_cr_ack, ++ wlfc->destination_entries.other.dstncredit_acks, ++ bc_mc_cr_ack, ++ wlfc->stats.signal_only_pkts_sent, wlfc->stats.signal_only_pkts_freed); ++ } ++#endif /* PROP_TXSTATUS_DEBUG */ ++ bcm_bprintf(strbuf, "\n"); ++ bcm_bprintf(strbuf, "wlfc- pkt((in,2bus,txstats,hdrpull),(dropped,hdr_only,wlc_tossed)" ++ "(freed,free_err,rollback)) = " ++ "((%d,%d,%d,%d),(%d,%d,%d),(%d,%d,%d))\n", ++ wlfc->stats.pktin, ++ wlfc->stats.pkt2bus, ++ wlfc->stats.txstatus_in, ++ wlfc->stats.dhd_hdrpulls, ++ ++ wlfc->stats.pktdropped, ++ wlfc->stats.wlfc_header_only_pkt, ++ wlfc->stats.wlc_tossed_pkts, ++ ++ wlfc->stats.pkt_freed, ++ wlfc->stats.pkt_free_err, wlfc->stats.rollback); ++ ++ bcm_bprintf(strbuf, "wlfc- suppress((d11,wlc,err),enq(d11,wl,hq,mac?),retx(d11,wlc,hq)) = " ++ "((%d,%d,%d),(%d,%d,%d,%d),(%d,%d,%d))\n", ++ ++ wlfc->stats.d11_suppress, ++ wlfc->stats.wl_suppress, ++ wlfc->stats.bad_suppress, ++ ++ wlfc->stats.psq_d11sup_enq, ++ wlfc->stats.psq_wlsup_enq, ++ wlfc->stats.psq_hostq_enq, ++ wlfc->stats.mac_handle_notfound, ++ ++ wlfc->stats.psq_d11sup_retx, ++ wlfc->stats.psq_wlsup_retx, ++ wlfc->stats.psq_hostq_retx); ++ bcm_bprintf(strbuf, "wlfc- generic error: %d", wlfc->stats.generic_error); ++ ++ return; ++} ++ ++/* Create a place to store all packet pointers submitted to the firmware until ++ a status comes back, suppress or otherwise. ++ ++ hang-er: noun, a contrivance on which things are hung, as a hook. ++*/ ++static void* ++dhd_wlfc_hanger_create(osl_t *osh, int max_items) ++{ ++ int i; ++ wlfc_hanger_t* hanger; ++ ++ /* allow only up to a specific size for now */ ++ ASSERT(max_items == WLFC_HANGER_MAXITEMS); ++ ++ if ((hanger = (wlfc_hanger_t*)MALLOC(osh, WLFC_HANGER_SIZE(max_items))) == NULL) ++ return NULL; ++ ++ memset(hanger, 0, WLFC_HANGER_SIZE(max_items)); ++ hanger->max_items = max_items; ++ ++ for (i = 0; i < hanger->max_items; i++) { ++ hanger->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; ++ } ++ return hanger; ++} ++ ++static int ++dhd_wlfc_hanger_delete(osl_t *osh, void* hanger) ++{ ++ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; ++ ++ if (h) { ++ MFREE(osh, h, WLFC_HANGER_SIZE(h->max_items)); ++ return BCME_OK; ++ } ++ return BCME_BADARG; ++} ++ ++static uint16 ++dhd_wlfc_hanger_get_free_slot(void* hanger) ++{ ++ uint32 i; ++ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; ++ ++ if (h) { ++ i = h->slot_pos + 1; ++ if (i == h->max_items) { ++ i = 0; ++ } ++ while (i != h->slot_pos) { ++ if (h->items[i].state == WLFC_HANGER_ITEM_STATE_FREE) { ++ h->slot_pos = i; ++ return (uint16)i; ++ } ++ i++; ++ if (i == h->max_items) ++ i = 0; ++ } ++ h->failed_slotfind++; ++ } ++ return WLFC_HANGER_MAXITEMS; ++} ++ ++static int ++dhd_wlfc_hanger_get_genbit(void* hanger, void* pkt, uint32 slot_id, int* gen) ++{ ++ int rc = BCME_OK; ++ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; ++ ++ *gen = 0xff; ++ ++ /* this packet was not pushed at the time it went to the firmware */ ++ if (slot_id == WLFC_HANGER_MAXITEMS) ++ return BCME_NOTFOUND; ++ ++ if (h) { ++ if ((h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE) || ++ (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED)) { ++ *gen = h->items[slot_id].gen; ++ } ++ else { ++ rc = BCME_NOTFOUND; ++ } ++ } ++ else ++ rc = BCME_BADARG; ++ return rc; ++} ++ ++static int ++dhd_wlfc_hanger_pushpkt(void* hanger, void* pkt, uint32 slot_id) ++{ ++ int rc = BCME_OK; ++ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; ++ ++ if (h && (slot_id < WLFC_HANGER_MAXITEMS)) { ++ if (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_FREE) { ++ h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_INUSE; ++ h->items[slot_id].pkt = pkt; ++ h->items[slot_id].identifier = slot_id; ++ h->pushed++; ++ } ++ else { ++ h->failed_to_push++; ++ rc = BCME_NOTFOUND; ++ } ++ } ++ else ++ rc = BCME_BADARG; ++ return rc; ++} ++ ++static int ++dhd_wlfc_hanger_poppkt(void* hanger, uint32 slot_id, void** pktout, int remove_from_hanger) ++{ ++ int rc = BCME_OK; ++ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; ++ ++ /* this packet was not pushed at the time it went to the firmware */ ++ if (slot_id == WLFC_HANGER_MAXITEMS) ++ return BCME_NOTFOUND; ++ ++ if (h) { ++ if (h->items[slot_id].state != WLFC_HANGER_ITEM_STATE_FREE) { ++ *pktout = h->items[slot_id].pkt; ++ if (remove_from_hanger) { ++ h->items[slot_id].state = ++ WLFC_HANGER_ITEM_STATE_FREE; ++ h->items[slot_id].pkt = NULL; ++ h->items[slot_id].identifier = 0; ++ h->items[slot_id].gen = 0xff; ++ h->popped++; ++ } ++ } ++ else { ++ h->failed_to_pop++; ++ rc = BCME_NOTFOUND; ++ } ++ } ++ else ++ rc = BCME_BADARG; ++ return rc; ++} ++ ++static int ++dhd_wlfc_hanger_mark_suppressed(void* hanger, uint32 slot_id, uint8 gen) ++{ ++ int rc = BCME_OK; ++ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; ++ ++ /* this packet was not pushed at the time it went to the firmware */ ++ if (slot_id == WLFC_HANGER_MAXITEMS) ++ return BCME_NOTFOUND; ++ if (h) { ++ h->items[slot_id].gen = gen; ++ if (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE) { ++ h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED; ++ } ++ else ++ rc = BCME_BADARG; ++ } ++ else ++ rc = BCME_BADARG; ++ ++ return rc; ++} ++ ++static int ++_dhd_wlfc_pushheader(athost_wl_status_info_t* ctx, void* p, bool tim_signal, ++ uint8 tim_bmp, uint8 mac_handle, uint32 htodtag) ++{ ++ uint32 wl_pktinfo = 0; ++ uint8* wlh; ++ uint8 dataOffset; ++ uint8 fillers; ++ uint8 tim_signal_len = 0; ++ ++ struct bdc_header *h; ++ ++ if (tim_signal) { ++ tim_signal_len = 1 + 1 + WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP; ++ } ++ ++ /* +2 is for Type[1] and Len[1] in TLV, plus TIM signal */ ++ dataOffset = WLFC_CTL_VALUE_LEN_PKTTAG + 2 + tim_signal_len; ++ fillers = ROUNDUP(dataOffset, 4) - dataOffset; ++ dataOffset += fillers; ++ ++ PKTPUSH(ctx->osh, p, dataOffset); ++ wlh = (uint8*) PKTDATA(ctx->osh, p); ++ ++ wl_pktinfo = htol32(htodtag); ++ ++ wlh[0] = WLFC_CTL_TYPE_PKTTAG; ++ wlh[1] = WLFC_CTL_VALUE_LEN_PKTTAG; ++ memcpy(&wlh[2], &wl_pktinfo, sizeof(uint32)); ++ ++ if (tim_signal_len) { ++ wlh[dataOffset - fillers - tim_signal_len ] = ++ WLFC_CTL_TYPE_PENDING_TRAFFIC_BMP; ++ wlh[dataOffset - fillers - tim_signal_len + 1] = ++ WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP; ++ wlh[dataOffset - fillers - tim_signal_len + 2] = mac_handle; ++ wlh[dataOffset - fillers - tim_signal_len + 3] = tim_bmp; ++ } ++ if (fillers) ++ memset(&wlh[dataOffset - fillers], WLFC_CTL_TYPE_FILLER, fillers); ++ ++ PKTPUSH(ctx->osh, p, BDC_HEADER_LEN); ++ h = (struct bdc_header *)PKTDATA(ctx->osh, p); ++ h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); ++ if (PKTSUMNEEDED(p)) ++ h->flags |= BDC_FLAG_SUM_NEEDED; ++ ++ ++ h->priority = (PKTPRIO(p) & BDC_PRIORITY_MASK); ++ h->flags2 = 0; ++ h->dataOffset = dataOffset >> 2; ++ BDC_SET_IF_IDX(h, DHD_PKTTAG_IF(PKTTAG(p))); ++ return BCME_OK; ++} ++ ++static int ++_dhd_wlfc_pullheader(athost_wl_status_info_t* ctx, void* pktbuf) ++{ ++ struct bdc_header *h; ++ ++ if (PKTLEN(ctx->osh, pktbuf) < BDC_HEADER_LEN) { ++ AP6211_DEBUG("%s: rx data too short (%d < %d)\n", __FUNCTION__, ++ PKTLEN(ctx->osh, pktbuf), BDC_HEADER_LEN); ++ return BCME_ERROR; ++ } ++ h = (struct bdc_header *)PKTDATA(ctx->osh, pktbuf); ++ ++ /* pull BDC header */ ++ PKTPULL(ctx->osh, pktbuf, BDC_HEADER_LEN); ++ ++ if (PKTLEN(ctx->osh, pktbuf) < (h->dataOffset << 2)) { ++ AP6211_DEBUG("%s: rx data too short (%d < %d)\n", __FUNCTION__, ++ PKTLEN(ctx->osh, pktbuf), (h->dataOffset << 2)); ++ return BCME_ERROR; ++ } ++ ++ /* pull wl-header */ ++ PKTPULL(ctx->osh, pktbuf, (h->dataOffset << 2)); ++ return BCME_OK; ++} ++ ++static wlfc_mac_descriptor_t* ++_dhd_wlfc_find_table_entry(athost_wl_status_info_t* ctx, void* p) ++{ ++ int i; ++ wlfc_mac_descriptor_t* table = ctx->destination_entries.nodes; ++ uint8 ifid = DHD_PKTTAG_IF(PKTTAG(p)); ++ uint8* dstn = DHD_PKTTAG_DSTN(PKTTAG(p)); ++ wlfc_mac_descriptor_t* entry = NULL; ++ int iftype = ctx->destination_entries.interfaces[ifid].iftype; ++ ++ /* Multicast destination and P2P clients get the interface entry. ++ * STA gets the interface entry if there is no exact match. For ++ * example, TDLS destinations have their own entry. ++ */ ++ if ((iftype == WLC_E_IF_ROLE_STA || ETHER_ISMULTI(dstn) || ++ iftype == WLC_E_IF_ROLE_P2P_CLIENT) && ++ (ctx->destination_entries.interfaces[ifid].occupied)) { ++ entry = &ctx->destination_entries.interfaces[ifid]; ++ } ++ ++ if (entry != NULL && ETHER_ISMULTI(dstn)) ++ return entry; ++ ++ for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { ++ if (table[i].occupied) { ++ if (table[i].interface_id == ifid) { ++ if (!memcmp(table[i].ea, dstn, ETHER_ADDR_LEN)) { ++ entry = &table[i]; ++ break; ++ } ++ } ++ } ++ } ++ ++ return entry != NULL ? entry : &ctx->destination_entries.other; ++} ++ ++static int ++_dhd_wlfc_rollback_packet_toq(athost_wl_status_info_t* ctx, ++ void* p, ewlfc_packet_state_t pkt_type, uint32 hslot) ++{ ++ /* ++ put the packet back to the head of queue ++ ++ - suppressed packet goes back to suppress sub-queue ++ - pull out the header, if new or delayed packet ++ ++ Note: hslot is used only when header removal is done. ++ */ ++ wlfc_mac_descriptor_t* entry; ++ void* pktout; ++ int rc = BCME_OK; ++ int prec; ++ ++ entry = _dhd_wlfc_find_table_entry(ctx, p); ++ prec = DHD_PKTTAG_FIFO(PKTTAG(p)); ++ if (entry != NULL) { ++ if (pkt_type == eWLFC_PKTTYPE_SUPPRESSED) { ++ /* wl-header is saved for suppressed packets */ ++ if (WLFC_PKTQ_PENQ_HEAD(&entry->psq, ((prec << 1) + 1), p) == NULL) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ rc = BCME_ERROR; ++ } ++ } ++ else { ++ /* remove header first */ ++ rc = _dhd_wlfc_pullheader(ctx, p); ++ if (rc != BCME_OK) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ /* free the hanger slot */ ++ dhd_wlfc_hanger_poppkt(ctx->hanger, hslot, &pktout, 1); ++ PKTFREE(ctx->osh, p, TRUE); ++ ctx->stats.rollback_failed++; ++ return BCME_ERROR; ++ } ++ ++ if (pkt_type == eWLFC_PKTTYPE_DELAYED) { ++ /* delay-q packets are going to delay-q */ ++ if (WLFC_PKTQ_PENQ_HEAD(&entry->psq, (prec << 1), p) == NULL) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ rc = BCME_ERROR; ++ } ++ } ++ ++ /* free the hanger slot */ ++ dhd_wlfc_hanger_poppkt(ctx->hanger, hslot, &pktout, 1); ++ ++ /* decrement sequence count */ ++ WLFC_DECR_SEQCOUNT(entry, prec); ++ } ++ /* ++ if this packet did not count against FIFO credit, it must have ++ taken a requested_credit from the firmware (for pspoll etc.) ++ */ ++ if (!DHD_PKTTAG_CREDITCHECK(PKTTAG(p))) { ++ entry->requested_credit++; ++ } ++ } ++ else { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ rc = BCME_ERROR; ++ } ++ if (rc != BCME_OK) ++ ctx->stats.rollback_failed++; ++ else ++ ctx->stats.rollback++; ++ ++ return rc; ++} ++ ++static void ++_dhd_wlfc_flow_control_check(athost_wl_status_info_t* ctx, struct pktq* pq, uint8 if_id) ++{ ++ dhd_pub_t *dhdp; ++ ++ ASSERT(ctx); ++ ++ dhdp = (dhd_pub_t *)ctx->dhdp; ++ ++ if (dhdp && dhdp->skip_fc && dhdp->skip_fc()) ++ return; ++ ++ if ((pq->len <= WLFC_FLOWCONTROL_LOWATER) && (ctx->hostif_flow_state[if_id] == ON)) { ++ /* start traffic */ ++ ctx->hostif_flow_state[if_id] = OFF; ++ /* ++ AP6211_DEBUG("qlen:%02d, if:%02d, ->OFF, start traffic %s()\n", ++ pq->len, if_id, __FUNCTION__); ++ */ ++ AP6211_DEBUG("F"); ++ ++ dhd_txflowcontrol(ctx->dhdp, if_id, OFF); ++ ++ ctx->toggle_host_if = 0; ++ } ++ if ((pq->len >= WLFC_FLOWCONTROL_HIWATER) && (ctx->hostif_flow_state[if_id] == OFF)) { ++ /* stop traffic */ ++ ctx->hostif_flow_state[if_id] = ON; ++ /* ++ AP6211_DEBUG("qlen:%02d, if:%02d, ->ON, stop traffic %s()\n", ++ pq->len, if_id, __FUNCTION__); ++ */ ++ AP6211_DEBUG("N"); ++ ++ dhd_txflowcontrol(ctx->dhdp, if_id, ON); ++ ++ ctx->host_ifidx = if_id; ++ ctx->toggle_host_if = 1; ++ } ++ ++ return; ++} ++ ++static int ++_dhd_wlfc_send_signalonly_packet(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, ++ uint8 ta_bmp) ++{ ++ int rc = BCME_OK; ++ void* p = NULL; ++ int dummylen = ((dhd_pub_t *)ctx->dhdp)->hdrlen+ 12; ++ ++ /* allocate a dummy packet */ ++ p = PKTGET(ctx->osh, dummylen, TRUE); ++ if (p) { ++ PKTPULL(ctx->osh, p, dummylen); ++ DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), 0); ++ _dhd_wlfc_pushheader(ctx, p, TRUE, ta_bmp, entry->mac_handle, 0); ++ DHD_PKTTAG_SETSIGNALONLY(PKTTAG(p), 1); ++#ifdef PROP_TXSTATUS_DEBUG ++ ctx->stats.signal_only_pkts_sent++; ++#endif ++ rc = dhd_bus_txdata(((dhd_pub_t *)ctx->dhdp)->bus, p); ++ if (rc != BCME_OK) { ++ PKTFREE(ctx->osh, p, TRUE); ++ } ++ } ++ else { ++ AP6211_ERR("%s: couldn't allocate new %d-byte packet\n", ++ __FUNCTION__, dummylen); ++ rc = BCME_NOMEM; ++ } ++ return rc; ++} ++ ++/* Return TRUE if traffic availability changed */ ++static bool ++_dhd_wlfc_traffic_pending_check(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, ++ int prec) ++{ ++ bool rc = FALSE; ++ ++ if (entry->state == WLFC_STATE_CLOSE) { ++ if ((pktq_plen(&entry->psq, (prec << 1)) == 0) && ++ (pktq_plen(&entry->psq, ((prec << 1) + 1)) == 0)) { ++ ++ if (entry->traffic_pending_bmp & NBITVAL(prec)) { ++ rc = TRUE; ++ entry->traffic_pending_bmp = ++ entry->traffic_pending_bmp & ~ NBITVAL(prec); ++ } ++ } ++ else { ++ if (!(entry->traffic_pending_bmp & NBITVAL(prec))) { ++ rc = TRUE; ++ entry->traffic_pending_bmp = ++ entry->traffic_pending_bmp | NBITVAL(prec); ++ } ++ } ++ } ++ if (rc) { ++ /* request a TIM update to firmware at the next piggyback opportunity */ ++ if (entry->traffic_lastreported_bmp != entry->traffic_pending_bmp) { ++ entry->send_tim_signal = 1; ++ _dhd_wlfc_send_signalonly_packet(ctx, entry, entry->traffic_pending_bmp); ++ entry->traffic_lastreported_bmp = entry->traffic_pending_bmp; ++ entry->send_tim_signal = 0; ++ } ++ else { ++ rc = FALSE; ++ } ++ } ++ return rc; ++} ++ ++static int ++_dhd_wlfc_enque_suppressed(athost_wl_status_info_t* ctx, int prec, void* p) ++{ ++ wlfc_mac_descriptor_t* entry; ++ ++ entry = _dhd_wlfc_find_table_entry(ctx, p); ++ if (entry == NULL) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ return BCME_NOTFOUND; ++ } ++ /* ++ - suppressed packets go to sub_queue[2*prec + 1] AND ++ - delayed packets go to sub_queue[2*prec + 0] to ensure ++ order of delivery. ++ */ ++ if (WLFC_PKTQ_PENQ(&entry->psq, ((prec << 1) + 1), p) == NULL) { ++ ctx->stats.delayq_full_error++; ++ /* AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); */ ++ AP6211_DEBUG("s"); ++ return BCME_ERROR; ++ } ++ /* A packet has been pushed, update traffic availability bitmap, if applicable */ ++ _dhd_wlfc_traffic_pending_check(ctx, entry, prec); ++ _dhd_wlfc_flow_control_check(ctx, &entry->psq, DHD_PKTTAG_IF(PKTTAG(p))); ++ return BCME_OK; ++} ++ ++static int ++_dhd_wlfc_pretx_pktprocess(athost_wl_status_info_t* ctx, ++ wlfc_mac_descriptor_t* entry, void* p, int header_needed, uint32* slot) ++{ ++ int rc = BCME_OK; ++ int hslot = WLFC_HANGER_MAXITEMS; ++ bool send_tim_update = FALSE; ++ uint32 htod = 0; ++ uint8 free_ctr; ++ ++ *slot = hslot; ++ ++ if (entry == NULL) { ++ entry = _dhd_wlfc_find_table_entry(ctx, p); ++ } ++ ++ if (entry == NULL) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ return BCME_ERROR; ++ } ++ if (entry->send_tim_signal) { ++ send_tim_update = TRUE; ++ entry->send_tim_signal = 0; ++ entry->traffic_lastreported_bmp = entry->traffic_pending_bmp; ++ } ++ if (header_needed) { ++ hslot = dhd_wlfc_hanger_get_free_slot(ctx->hanger); ++ free_ctr = WLFC_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p))); ++ DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), htod); ++ WLFC_PKTFLAG_SET_GENERATION(htod, entry->generation); ++ entry->transit_count++; ++ } ++ else { ++ hslot = WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); ++ free_ctr = WLFC_PKTID_FREERUNCTR_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); ++ } ++ WLFC_PKTID_HSLOT_SET(htod, hslot); ++ WLFC_PKTID_FREERUNCTR_SET(htod, free_ctr); ++ DHD_PKTTAG_SETPKTDIR(PKTTAG(p), 1); ++ WL_TXSTATUS_SET_FLAGS(htod, WLFC_PKTFLAG_PKTFROMHOST); ++ WL_TXSTATUS_SET_FIFO(htod, DHD_PKTTAG_FIFO(PKTTAG(p))); ++ ++ ++ if (!DHD_PKTTAG_CREDITCHECK(PKTTAG(p))) { ++ /* ++ Indicate that this packet is being sent in response to an ++ explicit request from the firmware side. ++ */ ++ WLFC_PKTFLAG_SET_PKTREQUESTED(htod); ++ } ++ else { ++ WLFC_PKTFLAG_CLR_PKTREQUESTED(htod); ++ } ++ if (header_needed) { ++ rc = _dhd_wlfc_pushheader(ctx, p, send_tim_update, ++ entry->traffic_lastreported_bmp, entry->mac_handle, htod); ++ if (rc == BCME_OK) { ++ DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), htod); ++ /* ++ a new header was created for this packet. ++ push to hanger slot and scrub q. Since bus ++ send succeeded, increment seq number as well. ++ */ ++ rc = dhd_wlfc_hanger_pushpkt(ctx->hanger, p, hslot); ++ if (rc == BCME_OK) { ++ /* increment free running sequence count */ ++ WLFC_INCR_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p))); ++#ifdef PROP_TXSTATUS_DEBUG ++ ((wlfc_hanger_t*)(ctx->hanger))->items[hslot].push_time = ++ OSL_SYSUPTIME(); ++#endif ++ } ++ else { ++ AP6211_DEBUG("%s() hanger_pushpkt() failed, rc: %d\n", ++ __FUNCTION__, rc); ++ } ++ } ++ } ++ else { ++ int gen; ++ ++ /* remove old header */ ++ rc = _dhd_wlfc_pullheader(ctx, p); ++ if (rc == BCME_OK) { ++ hslot = WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); ++ dhd_wlfc_hanger_get_genbit(ctx->hanger, p, hslot, &gen); ++ ++ WLFC_PKTFLAG_SET_GENERATION(htod, gen); ++ free_ctr = WLFC_PKTID_FREERUNCTR_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); ++ /* push new header */ ++ _dhd_wlfc_pushheader(ctx, p, send_tim_update, ++ entry->traffic_lastreported_bmp, entry->mac_handle, htod); ++ } ++ } ++ *slot = hslot; ++ return rc; ++} ++ ++static int ++_dhd_wlfc_is_destination_closed(athost_wl_status_info_t* ctx, ++ wlfc_mac_descriptor_t* entry, int prec) ++{ ++ if (ctx->destination_entries.interfaces[entry->interface_id].iftype == ++ WLC_E_IF_ROLE_P2P_GO) { ++ /* - destination interface is of type p2p GO. ++ For a p2pGO interface, if the destination is OPEN but the interface is ++ CLOSEd, do not send traffic. But if the dstn is CLOSEd while there is ++ destination-specific-credit left send packets. This is because the ++ firmware storing the destination-specific-requested packet in queue. ++ */ ++ if ((entry->state == WLFC_STATE_CLOSE) && (entry->requested_credit == 0) && ++ (entry->requested_packet == 0)) ++ return 1; ++ } ++ /* AP, p2p_go -> unicast desc entry, STA/p2p_cl -> interface desc. entry */ ++ if (((entry->state == WLFC_STATE_CLOSE) && (entry->requested_credit == 0) && ++ (entry->requested_packet == 0)) || ++ (!(entry->ac_bitmap & (1 << prec)))) ++ return 1; ++ ++ return 0; ++} ++ ++static void* ++_dhd_wlfc_deque_delayedq(athost_wl_status_info_t* ctx, ++ int prec, uint8* ac_credit_spent, uint8* needs_hdr, wlfc_mac_descriptor_t** entry_out) ++{ ++ wlfc_mac_descriptor_t* entry; ++ wlfc_mac_descriptor_t* table; ++ uint8 token_pos; ++ int total_entries; ++ void* p = NULL; ++ int pout; ++ int i; ++ ++ *entry_out = NULL; ++ token_pos = ctx->token_pos[prec]; ++ /* most cases a packet will count against FIFO credit */ ++ *ac_credit_spent = 1; ++ *needs_hdr = 1; ++ ++ /* search all entries, include nodes as well as interfaces */ ++ table = (wlfc_mac_descriptor_t*)&ctx->destination_entries; ++ total_entries = sizeof(ctx->destination_entries)/sizeof(wlfc_mac_descriptor_t); ++ ++ for (i = 0; i < total_entries; i++) { ++ entry = &table[(token_pos + i) % total_entries]; ++ if (entry->occupied && !entry->deleting) { ++ if (!_dhd_wlfc_is_destination_closed(ctx, entry, prec)) { ++ p = pktq_mdeq(&entry->psq, ++ /* higher precedence will be picked up first, ++ * i.e. suppressed packets before delayed ones ++ */ ++ NBITVAL((prec << 1) + 1), &pout); ++ *needs_hdr = 0; ++ ++ if (p == NULL) { ++ if (entry->suppressed == TRUE) { ++ if ((entry->suppr_transit_count <= ++ entry->suppress_count)) { ++ entry->suppressed = FALSE; ++ } else { ++ return NULL; ++ } ++ } ++ /* De-Q from delay Q */ ++ p = pktq_mdeq(&entry->psq, ++ NBITVAL((prec << 1)), ++ &pout); ++ *needs_hdr = 1; ++ } ++ ++ if (p != NULL) { ++ /* did the packet come from suppress sub-queue? */ ++ if (entry->requested_credit > 0) { ++ entry->requested_credit--; ++#ifdef PROP_TXSTATUS_DEBUG ++ entry->dstncredit_sent_packets++; ++#endif ++ /* ++ if the packet was pulled out while destination is in ++ closed state but had a non-zero packets requested, ++ then this should not count against the FIFO credit. ++ That is due to the fact that the firmware will ++ most likely hold onto this packet until a suitable ++ time later to push it to the appropriate AC FIFO. ++ */ ++ if (entry->state == WLFC_STATE_CLOSE) ++ *ac_credit_spent = 0; ++ } ++ else if (entry->requested_packet > 0) { ++ entry->requested_packet--; ++ DHD_PKTTAG_SETONETIMEPKTRQST(PKTTAG(p)); ++ if (entry->state == WLFC_STATE_CLOSE) ++ *ac_credit_spent = 0; ++ } ++ /* move token to ensure fair round-robin */ ++ ctx->token_pos[prec] = ++ (token_pos + i + 1) % total_entries; ++ *entry_out = entry; ++ _dhd_wlfc_flow_control_check(ctx, &entry->psq, ++ DHD_PKTTAG_IF(PKTTAG(p))); ++ /* ++ A packet has been picked up, update traffic ++ availability bitmap, if applicable ++ */ ++ _dhd_wlfc_traffic_pending_check(ctx, entry, prec); ++ return p; ++ } ++ } ++ } ++ } ++ return NULL; ++} ++ ++void * ++_dhd_wlfc_pktq_peek_tail(struct pktq *pq, int *prec_out) ++{ ++ int prec; ++ ++ ASSERT(pq); ++ ++ if (pq->len == 0) ++ return NULL; ++ ++ for (prec = 0; prec < pq->hi_prec; prec++) ++ /* only pick packets from dealyed-q */ ++ if (((prec & 1) == 0) && pq->q[prec].head) ++ break; ++ ++ if (prec_out) ++ *prec_out = prec; ++ ++ return (pq->q[prec].tail); ++} ++ ++bool ++_dhd_wlfc_prec_enq_with_drop(dhd_pub_t *dhdp, struct pktq *pq, void *pkt, int prec) ++{ ++ void *p = NULL; ++ int eprec = -1; /* precedence to evict from */ ++ ++ ASSERT(dhdp && pq && pkt); ++ ASSERT(prec >= 0 && prec < pq->num_prec); ++ ++ /* Fast case, precedence queue is not full and we are also not ++ * exceeding total queue length ++ */ ++ if (!pktq_pfull(pq, prec) && !pktq_full(pq)) { ++ pktq_penq(pq, prec, pkt); ++ return TRUE; ++ } ++ ++ /* Determine precedence from which to evict packet, if any */ ++ if (pktq_pfull(pq, prec)) ++ eprec = prec; ++ else if (pktq_full(pq)) { ++ p = _dhd_wlfc_pktq_peek_tail(pq, &eprec); ++ if (!p) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ return FALSE; ++ } ++ if ((eprec > prec) || (eprec < 0)) { ++ if (!pktq_pempty(pq, prec)) { ++ eprec = prec; ++ } else { ++ return FALSE; ++ } ++ } ++ } ++ ++ /* Evict if needed */ ++ if (eprec >= 0) { ++ /* Detect queueing to unconfigured precedence */ ++ ASSERT(!pktq_pempty(pq, eprec)); ++ /* Evict all fragmented frames */ ++ dhd_prec_drop_pkts(dhdp->osh, pq, eprec); ++ } ++ ++ /* Enqueue */ ++ p = pktq_penq(pq, prec, pkt); ++ if (!p) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++static int ++_dhd_wlfc_enque_delayq(athost_wl_status_info_t* ctx, void* pktbuf, int prec) ++{ ++ wlfc_mac_descriptor_t* entry; ++ ++ if (pktbuf != NULL) { ++ entry = _dhd_wlfc_find_table_entry(ctx, pktbuf); ++ ++ if (entry == NULL) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ return BCME_ERROR; ++ } ++ ++ /* ++ - suppressed packets go to sub_queue[2*prec + 1] AND ++ - delayed packets go to sub_queue[2*prec + 0] to ensure ++ order of delivery. ++ */ ++ if (_dhd_wlfc_prec_enq_with_drop(ctx->dhdp, &entry->psq, pktbuf, (prec << 1)) ++ == FALSE) { ++ AP6211_DEBUG("D"); ++ /* dhd_txcomplete(ctx->dhdp, pktbuf, FALSE); */ ++ PKTFREE(ctx->osh, pktbuf, TRUE); ++ ctx->stats.delayq_full_error++; ++ return BCME_ERROR; ++ } ++ ++ /* ++ A packet has been pushed, update traffic availability bitmap, ++ if applicable ++ */ ++ _dhd_wlfc_traffic_pending_check(ctx, entry, prec); ++ ++ } ++ return BCME_OK; ++} ++ ++bool ifpkt_fn(void* p, int ifid) ++{ ++ return (ifid == DHD_PKTTAG_IF(PKTTAG(p))); ++} ++ ++static int ++_dhd_wlfc_mac_entry_update(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, ++ ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea) ++{ ++ int rc = BCME_OK; ++ ++ if (action == eWLFC_MAC_ENTRY_ACTION_ADD) { ++ entry->occupied = 1; ++ entry->state = WLFC_STATE_OPEN; ++ entry->requested_credit = 0; ++ entry->interface_id = ifid; ++ entry->iftype = iftype; ++ entry->ac_bitmap = 0xff; /* update this when handling APSD */ ++ /* for an interface entry we may not care about the MAC address */ ++ if (ea != NULL) ++ memcpy(&entry->ea[0], ea, ETHER_ADDR_LEN); ++ pktq_init(&entry->psq, WLFC_PSQ_PREC_COUNT, WLFC_PSQ_LEN); ++ } ++ else if (action == eWLFC_MAC_ENTRY_ACTION_UPDATE) { ++ entry->occupied = 1; ++ entry->state = WLFC_STATE_OPEN; ++ entry->requested_credit = 0; ++ entry->interface_id = ifid; ++ entry->iftype = iftype; ++ entry->ac_bitmap = 0xff; /* update this when handling APSD */ ++ /* for an interface entry we may not care about the MAC address */ ++ if (ea != NULL) ++ memcpy(&entry->ea[0], ea, ETHER_ADDR_LEN); ++ } ++ else if (action == eWLFC_MAC_ENTRY_ACTION_DEL) { ++ /* When the entry is deleted, the packets that are queued in the entry must be ++ cleanup. The cleanup action should be before the occupied is set as 0. The ++ flag deleting is set to avoid de-queue action when these queues are being ++ cleanup ++ */ ++ entry->deleting = 1; ++ dhd_wlfc_cleanup(ctx->dhdp, ifpkt_fn, ifid); ++ _dhd_wlfc_flow_control_check(ctx, &entry->psq, ifid); ++ entry->deleting = 0; ++ ++ entry->occupied = 0; ++ entry->suppressed = 0; ++ entry->state = WLFC_STATE_CLOSE; ++ entry->requested_credit = 0; ++ entry->transit_count = 0; ++ entry->suppr_transit_count = 0; ++ entry->suppress_count = 0; ++ memset(&entry->ea[0], 0, ETHER_ADDR_LEN); ++ ++ /* enable after packets are queued-deqeued properly. ++ pktq_flush(dhd->osh, &entry->psq, FALSE, NULL, 0); ++ */ ++ } ++ return rc; ++} ++ ++int ++_dhd_wlfc_borrow_credit(athost_wl_status_info_t* ctx, uint8 available_credit_map, int borrower_ac) ++{ ++ int lender_ac; ++ int rc = BCME_ERROR; ++ ++ if (ctx == NULL || available_credit_map == 0) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ return BCME_BADARG; ++ } ++ ++ /* Borrow from lowest priority available AC (including BC/MC credits) */ ++ for (lender_ac = 0; lender_ac <= AC_COUNT; lender_ac++) { ++ if ((available_credit_map && (1 << lender_ac)) && ++ (ctx->FIFO_credit[lender_ac] > 0)) { ++ ctx->credits_borrowed[borrower_ac][lender_ac]++; ++ ctx->FIFO_credit[lender_ac]--; ++ rc = BCME_OK; ++ break; ++ } ++ } ++ ++ return rc; ++} ++ ++int ++dhd_wlfc_interface_entry_update(void* state, ++ ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea) ++{ ++ athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; ++ wlfc_mac_descriptor_t* entry; ++ int ret; ++ ++ if (ifid >= WLFC_MAX_IFNUM) ++ return BCME_BADARG; ++ ++ entry = &ctx->destination_entries.interfaces[ifid]; ++ ret = _dhd_wlfc_mac_entry_update(ctx, entry, action, ifid, iftype, ea); ++ return ret; ++} ++ ++int ++dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits) ++{ ++ athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; ++ ++ /* update the AC FIFO credit map */ ++ ctx->FIFO_credit[0] = credits[0]; ++ ctx->FIFO_credit[1] = credits[1]; ++ ctx->FIFO_credit[2] = credits[2]; ++ ctx->FIFO_credit[3] = credits[3]; ++ /* credit for bc/mc packets */ ++ ctx->FIFO_credit[4] = credits[4]; ++ /* credit for ATIM FIFO is not used yet. */ ++ ctx->FIFO_credit[5] = 0; ++ return BCME_OK; ++} ++ ++int ++_dhd_wlfc_handle_packet_commit(athost_wl_status_info_t* ctx, int ac, ++ dhd_wlfc_commit_info_t *commit_info, f_commitpkt_t fcommit, void* commit_ctx) ++{ ++ uint32 hslot; ++ int rc; ++ ++ /* ++ if ac_fifo_credit_spent = 0 ++ ++ This packet will not count against the FIFO credit. ++ To ensure the txstatus corresponding to this packet ++ does not provide an implied credit (default behavior) ++ mark the packet accordingly. ++ ++ if ac_fifo_credit_spent = 1 ++ ++ This is a normal packet and it counts against the FIFO ++ credit count. ++ */ ++ DHD_PKTTAG_SETCREDITCHECK(PKTTAG(commit_info->p), commit_info->ac_fifo_credit_spent); ++ rc = _dhd_wlfc_pretx_pktprocess(ctx, commit_info->mac_entry, commit_info->p, ++ commit_info->needs_hdr, &hslot); ++ ++ if (rc == BCME_OK) ++ rc = fcommit(commit_ctx, commit_info->p); ++ else ++ ctx->stats.generic_error++; ++ ++ if (rc == BCME_OK) { ++ ctx->stats.pkt2bus++; ++ if (commit_info->ac_fifo_credit_spent) { ++ ctx->stats.send_pkts[ac]++; ++ WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac); ++ } ++ } else if (rc == BCME_NORESOURCE) ++ rc = BCME_ERROR; ++ else { ++ /* ++ bus commit has failed, rollback. ++ - remove wl-header for a delayed packet ++ - save wl-header header for suppressed packets ++ */ ++ rc = _dhd_wlfc_rollback_packet_toq(ctx, commit_info->p, ++ (commit_info->pkt_type), hslot); ++ ++ rc = BCME_ERROR; ++ } ++ ++ return rc; ++} ++ ++int ++dhd_wlfc_commit_packets(void* state, f_commitpkt_t fcommit, void* commit_ctx, void *pktbuf) ++{ ++ int ac; ++ int credit; ++ int rc; ++ dhd_wlfc_commit_info_t commit_info; ++ athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; ++ int credit_count = 0; ++ int bus_retry_count = 0; ++ uint8 ac_available = 0; /* Bitmask for 4 ACs + BC/MC */ ++ ++ if ((state == NULL) || ++ (fcommit == NULL)) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ return BCME_BADARG; ++ } ++ ++ memset(&commit_info, 0, sizeof(commit_info)); ++ ++ /* ++ Commit packets for regular AC traffic. Higher priority first. ++ First, use up FIFO credits available to each AC. Based on distribution ++ and credits left, borrow from other ACs as applicable ++ ++ -NOTE: ++ If the bus between the host and firmware is overwhelmed by the ++ traffic from host, it is possible that higher priority traffic ++ starves the lower priority queue. If that occurs often, we may ++ have to employ weighted round-robin or ucode scheme to avoid ++ low priority packet starvation. ++ */ ++ ++ if (pktbuf) { ++ ac = DHD_PKTTAG_FIFO(PKTTAG(pktbuf)); ++ if (ETHER_ISMULTI(DHD_PKTTAG_DSTN(PKTTAG(pktbuf)))) { ++ ASSERT(ac == AC_COUNT); ++ commit_info.needs_hdr = 1; ++ commit_info.mac_entry = NULL; ++ commit_info.pkt_type = eWLFC_PKTTYPE_NEW; ++ commit_info.p = pktbuf; ++ if (ctx->FIFO_credit[ac]) { ++ rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, ++ fcommit, commit_ctx); ++ ++ /* Bus commits may fail (e.g. flow control); abort after retries */ ++ if (rc == BCME_OK) { ++ if (commit_info.ac_fifo_credit_spent) { ++ (void) _dhd_wlfc_borrow_credit(ctx, ++ ac_available, ac); ++ credit_count--; ++ } ++ } else { ++ bus_retry_count++; ++ if (bus_retry_count >= BUS_RETRIES) { ++ AP6211_ERR(" %s: bus error %d\n", ++ __FUNCTION__, rc); ++ return rc; ++ } ++ } ++ } ++ } ++ else { ++ /* en-queue the packets to respective queue. */ ++ rc = _dhd_wlfc_enque_delayq(ctx, pktbuf, ac); ++ } ++ } ++ ++ for (ac = AC_COUNT; ac >= 0; ac--) { ++ ++ bool bQueueIdle = TRUE; ++ ++ /* packets from delayQ with less priority are fresh and they'd need header and ++ * have no MAC entry ++ */ ++ commit_info.needs_hdr = 1; ++ commit_info.mac_entry = NULL; ++ commit_info.pkt_type = eWLFC_PKTTYPE_NEW; ++ ++ for (credit = 0; credit < ctx->FIFO_credit[ac];) { ++ commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac, ++ &(commit_info.ac_fifo_credit_spent), ++ &(commit_info.needs_hdr), ++ &(commit_info.mac_entry)); ++ ++ if (commit_info.p == NULL) ++ break; ++ ++ bQueueIdle = FALSE; ++ ++ commit_info.pkt_type = (commit_info.needs_hdr) ? eWLFC_PKTTYPE_DELAYED : ++ eWLFC_PKTTYPE_SUPPRESSED; ++ ++ rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, ++ fcommit, commit_ctx); ++ ++ /* Bus commits may fail (e.g. flow control); abort after retries */ ++ if (rc == BCME_OK) { ++ if (commit_info.ac_fifo_credit_spent) { ++ credit++; ++ } ++ } ++ else { ++ bus_retry_count++; ++ if (bus_retry_count >= BUS_RETRIES) { ++ AP6211_ERR("%s: bus error %d\n", __FUNCTION__, rc); ++ ctx->FIFO_credit[ac] -= credit; ++ return rc; ++ } ++ } ++ } ++ ++ ctx->FIFO_credit[ac] -= credit; ++ ++ ++ /* If no pkts can be dequed, the credit can be borrowed */ ++ if (bQueueIdle) { ++ ac_available |= (1 << ac); ++ credit_count += ctx->FIFO_credit[ac]; ++ } ++ } ++ ++ /* We borrow only for AC_BE and only if no other traffic seen for DEFER_PERIOD ++ ++ Note that (ac_available & WLFC_AC_BE_TRAFFIC_ONLY) is done to: ++ a) ignore BC/MC for deferring borrow ++ b) ignore AC_BE being available along with other ACs ++ (this should happen only for pure BC/MC traffic) ++ ++ i.e. AC_VI, AC_VO, AC_BK all MUST be available (i.e. no traffic) and ++ we do not care if AC_BE and BC/MC are available or not ++ */ ++ if ((ac_available & WLFC_AC_BE_TRAFFIC_ONLY) == WLFC_AC_BE_TRAFFIC_ONLY) { ++ ++ if (ctx->allow_credit_borrow) { ++ ac = 1; /* Set ac to AC_BE and borrow credits */ ++ } ++ else { ++ int delta; ++ int curr_t = OSL_SYSUPTIME(); ++ ++ if (curr_t > ctx->borrow_defer_timestamp) ++ delta = curr_t - ctx->borrow_defer_timestamp; ++ else ++ delta = 0xffffffff + curr_t - ctx->borrow_defer_timestamp; ++ ++ if (delta >= WLFC_BORROW_DEFER_PERIOD_MS) { ++ /* Reset borrow but defer to next iteration (defensive borrowing) */ ++ ctx->allow_credit_borrow = TRUE; ++ ctx->borrow_defer_timestamp = 0; ++ } ++ return BCME_OK; ++ } ++ } ++ else { ++ /* If we have multiple AC traffic, turn off borrowing, mark time and bail out */ ++ ctx->allow_credit_borrow = FALSE; ++ ctx->borrow_defer_timestamp = OSL_SYSUPTIME(); ++ return BCME_OK; ++ } ++ ++ /* At this point, borrow all credits only for "ac" (which should be set above to AC_BE) ++ Generically use "ac" only in case we extend to all ACs in future ++ */ ++ for (; (credit_count > 0);) { ++ ++ commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac, ++ &(commit_info.ac_fifo_credit_spent), ++ &(commit_info.needs_hdr), ++ &(commit_info.mac_entry)); ++ if (commit_info.p == NULL) ++ break; ++ ++ commit_info.pkt_type = (commit_info.needs_hdr) ? eWLFC_PKTTYPE_DELAYED : ++ eWLFC_PKTTYPE_SUPPRESSED; ++ ++ rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, ++ fcommit, commit_ctx); ++ ++ /* Bus commits may fail (e.g. flow control); abort after retries */ ++ if (rc == BCME_OK) { ++ if (commit_info.ac_fifo_credit_spent) { ++ (void) _dhd_wlfc_borrow_credit(ctx, ac_available, ac); ++ credit_count--; ++ } ++ } ++ else { ++ bus_retry_count++; ++ if (bus_retry_count >= BUS_RETRIES) { ++ AP6211_ERR("%s: bus error %d\n", __FUNCTION__, rc); ++ return rc; ++ } ++ } ++ } ++ return BCME_OK; ++} ++ ++static uint8 ++dhd_wlfc_find_mac_desc_id_from_mac(dhd_pub_t *dhdp, uint8* ea) ++{ ++ wlfc_mac_descriptor_t* table = ++ ((athost_wl_status_info_t*)dhdp->wlfc_state)->destination_entries.nodes; ++ uint8 table_index; ++ ++ if (ea != NULL) { ++ for (table_index = 0; table_index < WLFC_MAC_DESC_TABLE_SIZE; table_index++) { ++ if ((memcmp(ea, &table[table_index].ea[0], ETHER_ADDR_LEN) == 0) && ++ table[table_index].occupied) ++ return table_index; ++ } ++ } ++ return WLFC_MAC_DESC_ID_INVALID; ++} ++ ++void ++dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success) ++{ ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ void* p; ++ int fifo_id; ++ ++ if (DHD_PKTTAG_SIGNALONLY(PKTTAG(txp))) { ++#ifdef PROP_TXSTATUS_DEBUG ++ wlfc->stats.signal_only_pkts_freed++; ++#endif ++ /* is this a signal-only packet? */ ++ if (success) ++ PKTFREE(wlfc->osh, txp, TRUE); ++ return; ++ } ++ if (!success) { ++ AP6211_DEBUG("At: %s():%d, bus_complete() failure for %p, htod_tag:0x%08x\n", ++ __FUNCTION__, __LINE__, txp, DHD_PKTTAG_H2DTAG(PKTTAG(txp))); ++ dhd_wlfc_hanger_poppkt(wlfc->hanger, WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG ++ (PKTTAG(txp))), &p, 1); ++ ++ /* indicate failure and free the packet */ ++ dhd_txcomplete(dhd, txp, FALSE); ++ ++ /* return the credit, if necessary */ ++ if (DHD_PKTTAG_CREDITCHECK(PKTTAG(txp))) { ++ int lender, credit_returned = 0; /* Note that borrower is fifo_id */ ++ ++ fifo_id = DHD_PKTTAG_FIFO(PKTTAG(txp)); ++ ++ /* Return credits to highest priority lender first */ ++ for (lender = AC_COUNT; lender >= 0; lender--) { ++ if (wlfc->credits_borrowed[fifo_id][lender] > 0) { ++ wlfc->FIFO_credit[lender]++; ++ wlfc->credits_borrowed[fifo_id][lender]--; ++ credit_returned = 1; ++ break; ++ } ++ } ++ ++ if (!credit_returned) { ++ wlfc->FIFO_credit[fifo_id]++; ++ } ++ } ++ ++ PKTFREE(wlfc->osh, txp, TRUE); ++ } ++ return; ++} ++ ++static int ++dhd_wlfc_compressed_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info, uint8 len) ++{ ++ uint8 status_flag; ++ uint32 status; ++ int ret; ++ int remove_from_hanger = 1; ++ void* pktbuf; ++ uint8 fifo_id; ++ uint8 count = 0; ++ uint32 status_g; ++ uint32 hslot, hcnt; ++ wlfc_mac_descriptor_t* entry = NULL; ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ ++ memcpy(&status, pkt_info, sizeof(uint32)); ++ status_flag = WL_TXSTATUS_GET_FLAGS(status); ++ status_g = status & 0xff000000; ++ hslot = (status & 0x00ffff00) >> 8; ++ hcnt = status & 0xff; ++ len = pkt_info[4]; ++ ++ wlfc->stats.txstatus_in++; ++ ++ if (status_flag == WLFC_CTL_PKTFLAG_DISCARD) { ++ wlfc->stats.pkt_freed++; ++ } ++ ++ else if (status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) { ++ wlfc->stats.d11_suppress++; ++ remove_from_hanger = 0; ++ } ++ ++ else if (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS) { ++ wlfc->stats.wl_suppress++; ++ remove_from_hanger = 0; ++ } ++ ++ else if (status_flag == WLFC_CTL_PKTFLAG_TOSSED_BYWLC) { ++ wlfc->stats.wlc_tossed_pkts++; ++ } ++ while (count < len) { ++ status = (status_g << 24) | (hslot << 8) | (hcnt); ++ count++; ++ hslot++; ++ hcnt++; ++ ++ ret = dhd_wlfc_hanger_poppkt(wlfc->hanger, ++ WLFC_PKTID_HSLOT_GET(status), &pktbuf, remove_from_hanger); ++ if (ret != BCME_OK) { ++ /* do something */ ++ continue; ++ } ++ ++ entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); ++ ++ if (!remove_from_hanger) { ++ /* this packet was suppressed */ ++ if (!entry->suppressed || entry->generation != WLFC_PKTID_GEN(status)) { ++ entry->suppressed = TRUE; ++ entry->suppress_count = pktq_mlen(&entry->psq, ++ NBITVAL((WL_TXSTATUS_GET_FIFO(status) << 1) + 1)); ++ entry->suppr_transit_count = entry->transit_count; ++ } ++ entry->generation = WLFC_PKTID_GEN(status); ++ } ++ ++#ifdef PROP_TXSTATUS_DEBUG ++ { ++ uint32 new_t = OSL_SYSUPTIME(); ++ uint32 old_t; ++ uint32 delta; ++ old_t = ((wlfc_hanger_t*)(wlfc->hanger))->items[ ++ WLFC_PKTID_HSLOT_GET(status)].push_time; ++ ++ ++ wlfc->stats.latency_sample_count++; ++ if (new_t > old_t) ++ delta = new_t - old_t; ++ else ++ delta = 0xffffffff + new_t - old_t; ++ wlfc->stats.total_status_latency += delta; ++ wlfc->stats.latency_most_recent = delta; ++ ++ wlfc->stats.deltas[wlfc->stats.idx_delta++] = delta; ++ if (wlfc->stats.idx_delta == sizeof(wlfc->stats.deltas)/sizeof(uint32)) ++ wlfc->stats.idx_delta = 0; ++ } ++#endif /* PROP_TXSTATUS_DEBUG */ ++ ++ fifo_id = DHD_PKTTAG_FIFO(PKTTAG(pktbuf)); ++ ++ /* pick up the implicit credit from this packet */ ++ if (DHD_PKTTAG_CREDITCHECK(PKTTAG(pktbuf))) { ++ if (wlfc->proptxstatus_mode == WLFC_FCMODE_IMPLIED_CREDIT) { ++ ++ int lender, credit_returned = 0; /* Note that borrower is fifo_id */ ++ ++ /* Return credits to highest priority lender first */ ++ for (lender = AC_COUNT; lender >= 0; lender--) { ++ if (wlfc->credits_borrowed[fifo_id][lender] > 0) { ++ wlfc->FIFO_credit[lender]++; ++ wlfc->credits_borrowed[fifo_id][lender]--; ++ credit_returned = 1; ++ break; ++ } ++ } ++ ++ if (!credit_returned) { ++ wlfc->FIFO_credit[fifo_id]++; ++ } ++ } ++ } ++ else { ++ /* ++ if this packet did not count against FIFO credit, it must have ++ taken a requested_credit from the destination entry (for pspoll etc.) ++ */ ++ if (!entry) { ++ ++ entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); ++ } ++ if (!DHD_PKTTAG_ONETIMEPKTRQST(PKTTAG(pktbuf))) ++ entry->requested_credit++; ++#ifdef PROP_TXSTATUS_DEBUG ++ entry->dstncredit_acks++; ++#endif ++ } ++ if ((status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) || ++ (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS)) { ++ ++ ret = _dhd_wlfc_enque_suppressed(wlfc, fifo_id, pktbuf); ++ if (ret != BCME_OK) { ++ /* delay q is full, drop this packet */ ++ dhd_wlfc_hanger_poppkt(wlfc->hanger, WLFC_PKTID_HSLOT_GET(status), ++ &pktbuf, 1); ++ ++ /* indicate failure and free the packet */ ++ dhd_txcomplete(dhd, pktbuf, FALSE); ++ entry->transit_count--; ++ DHD_WLFC_QMON_COMPLETE(entry); ++ /* packet is transmitted Successfully by dongle ++ * after first suppress. ++ */ ++ if (entry->suppressed) { ++ entry->suppr_transit_count--; ++ } ++ PKTFREE(wlfc->osh, pktbuf, TRUE); ++ } else { ++ /* Mark suppressed to avoid a double free during wlfc cleanup */ ++ ++ dhd_wlfc_hanger_mark_suppressed(wlfc->hanger, ++ WLFC_PKTID_HSLOT_GET(status), WLFC_PKTID_GEN(status)); ++ entry->suppress_count++; ++ } ++ } ++ else { ++ dhd_txcomplete(dhd, pktbuf, TRUE); ++ entry->transit_count--; ++ DHD_WLFC_QMON_COMPLETE(entry); ++ ++ /* This packet is transmitted Successfully by dongle ++ * even after first suppress. ++ */ ++ if (entry->suppressed) { ++ entry->suppr_transit_count--; ++ } ++ /* free the packet */ ++ PKTFREE(wlfc->osh, pktbuf, TRUE); ++ } ++ } ++ return BCME_OK; ++} ++ ++/* Handle discard or suppress indication */ ++static int ++dhd_wlfc_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info) ++{ ++ uint8 status_flag; ++ uint32 status; ++ int ret; ++ int remove_from_hanger = 1; ++ void* pktbuf; ++ uint8 fifo_id; ++ wlfc_mac_descriptor_t* entry = NULL; ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ ++ memcpy(&status, pkt_info, sizeof(uint32)); ++ status_flag = WL_TXSTATUS_GET_FLAGS(status); ++ wlfc->stats.txstatus_in++; ++ ++ if (status_flag == WLFC_CTL_PKTFLAG_DISCARD) { ++ wlfc->stats.pkt_freed++; ++ } ++ ++ else if (status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) { ++ wlfc->stats.d11_suppress++; ++ remove_from_hanger = 0; ++ } ++ ++ else if (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS) { ++ wlfc->stats.wl_suppress++; ++ remove_from_hanger = 0; ++ } ++ ++ else if (status_flag == WLFC_CTL_PKTFLAG_TOSSED_BYWLC) { ++ wlfc->stats.wlc_tossed_pkts++; ++ } ++ ++ ret = dhd_wlfc_hanger_poppkt(wlfc->hanger, ++ WLFC_PKTID_HSLOT_GET(status), &pktbuf, remove_from_hanger); ++ if (ret != BCME_OK) { ++ /* do something */ ++ return ret; ++ } ++ ++ entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); ++ ++ if (!remove_from_hanger) { ++ /* this packet was suppressed */ ++ if (!entry->suppressed || entry->generation != WLFC_PKTID_GEN(status)) { ++ entry->suppressed = TRUE; ++ entry->suppress_count = pktq_mlen(&entry->psq, ++ NBITVAL((WL_TXSTATUS_GET_FIFO(status) << 1) + 1)); ++ entry->suppr_transit_count = entry->transit_count; ++ } ++ entry->generation = WLFC_PKTID_GEN(status); ++ } ++ ++#ifdef PROP_TXSTATUS_DEBUG ++ { ++ uint32 new_t = OSL_SYSUPTIME(); ++ uint32 old_t; ++ uint32 delta; ++ old_t = ((wlfc_hanger_t*)(wlfc->hanger))->items[ ++ WLFC_PKTID_HSLOT_GET(status)].push_time; ++ ++ ++ wlfc->stats.latency_sample_count++; ++ if (new_t > old_t) ++ delta = new_t - old_t; ++ else ++ delta = 0xffffffff + new_t - old_t; ++ wlfc->stats.total_status_latency += delta; ++ wlfc->stats.latency_most_recent = delta; ++ ++ wlfc->stats.deltas[wlfc->stats.idx_delta++] = delta; ++ if (wlfc->stats.idx_delta == sizeof(wlfc->stats.deltas)/sizeof(uint32)) ++ wlfc->stats.idx_delta = 0; ++ } ++#endif /* PROP_TXSTATUS_DEBUG */ ++ ++ fifo_id = DHD_PKTTAG_FIFO(PKTTAG(pktbuf)); ++ ++ /* pick up the implicit credit from this packet */ ++ if (DHD_PKTTAG_CREDITCHECK(PKTTAG(pktbuf))) { ++ if (wlfc->proptxstatus_mode == WLFC_FCMODE_IMPLIED_CREDIT) { ++ ++ int lender, credit_returned = 0; /* Note that borrower is fifo_id */ ++ ++ /* Return credits to highest priority lender first */ ++ for (lender = AC_COUNT; lender >= 0; lender--) { ++ if (wlfc->credits_borrowed[fifo_id][lender] > 0) { ++ wlfc->FIFO_credit[lender]++; ++ wlfc->credits_borrowed[fifo_id][lender]--; ++ credit_returned = 1; ++ break; ++ } ++ } ++ ++ if (!credit_returned) { ++ wlfc->FIFO_credit[fifo_id]++; ++ } ++ } ++ } ++ else { ++ /* ++ if this packet did not count against FIFO credit, it must have ++ taken a requested_credit from the destination entry (for pspoll etc.) ++ */ ++ if (!entry) { ++ ++ entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); ++ } ++ if (!DHD_PKTTAG_ONETIMEPKTRQST(PKTTAG(pktbuf))) ++ entry->requested_credit++; ++#ifdef PROP_TXSTATUS_DEBUG ++ entry->dstncredit_acks++; ++#endif ++ } ++ if ((status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) || ++ (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS)) { ++ ++ ret = _dhd_wlfc_enque_suppressed(wlfc, fifo_id, pktbuf); ++ if (ret != BCME_OK) { ++ /* delay q is full, drop this packet */ ++ dhd_wlfc_hanger_poppkt(wlfc->hanger, WLFC_PKTID_HSLOT_GET(status), ++ &pktbuf, 1); ++ ++ /* indicate failure and free the packet */ ++ dhd_txcomplete(dhd, pktbuf, FALSE); ++ entry->transit_count--; ++ DHD_WLFC_QMON_COMPLETE(entry); ++ /* This packet is transmitted Successfully by ++ * dongle even after first suppress. ++ */ ++ if (entry->suppressed) { ++ entry->suppr_transit_count--; ++ } ++ PKTFREE(wlfc->osh, pktbuf, TRUE); ++ } else { ++ /* Mark suppressed to avoid a double free during wlfc cleanup */ ++ ++ dhd_wlfc_hanger_mark_suppressed(wlfc->hanger, ++ WLFC_PKTID_HSLOT_GET(status), WLFC_PKTID_GEN(status)); ++ entry->suppress_count++; ++ } ++ } ++ else { ++ dhd_txcomplete(dhd, pktbuf, TRUE); ++ entry->transit_count--; ++ DHD_WLFC_QMON_COMPLETE(entry); ++ ++ /* This packet is transmitted Successfully by dongle even after first suppress. */ ++ if (entry->suppressed) { ++ entry->suppr_transit_count--; ++ } ++ /* free the packet */ ++ PKTFREE(wlfc->osh, pktbuf, TRUE); ++ } ++ return BCME_OK; ++} ++ ++static int ++dhd_wlfc_fifocreditback_indicate(dhd_pub_t *dhd, uint8* credits) ++{ ++ int i; ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ for (i = 0; i < WLFC_CTL_VALUE_LEN_FIFO_CREDITBACK; i++) { ++#ifdef PROP_TXSTATUS_DEBUG ++ wlfc->stats.fifo_credits_back[i] += credits[i]; ++#endif ++ /* update FIFO credits */ ++ if (wlfc->proptxstatus_mode == WLFC_FCMODE_EXPLICIT_CREDIT) ++ { ++ int lender; /* Note that borrower is i */ ++ ++ /* Return credits to highest priority lender first */ ++ for (lender = AC_COUNT; (lender >= 0) && (credits[i] > 0); lender--) { ++ if (wlfc->credits_borrowed[i][lender] > 0) { ++ if (credits[i] >= wlfc->credits_borrowed[i][lender]) { ++ credits[i] -= wlfc->credits_borrowed[i][lender]; ++ wlfc->FIFO_credit[lender] += ++ wlfc->credits_borrowed[i][lender]; ++ wlfc->credits_borrowed[i][lender] = 0; ++ } ++ else { ++ wlfc->credits_borrowed[i][lender] -= credits[i]; ++ wlfc->FIFO_credit[lender] += credits[i]; ++ credits[i] = 0; ++ } ++ } ++ } ++ ++ /* If we have more credits left over, these must belong to the AC */ ++ if (credits[i] > 0) { ++ wlfc->FIFO_credit[i] += credits[i]; ++ } ++ } ++ } ++ ++ return BCME_OK; ++} ++ ++static int ++dhd_wlfc_dbg_senum_check(dhd_pub_t *dhd, uint8 *value) ++{ ++ uint32 timestamp; ++ ++ (void)dhd; ++ ++ bcopy(&value[2], ×tamp, sizeof(uint32)); ++ AP6211_DEBUG("RXPKT: SEQ: %d, timestamp %d\n", value[1], timestamp); ++ return BCME_OK; ++} ++ ++ ++static int ++dhd_wlfc_rssi_indicate(dhd_pub_t *dhd, uint8* rssi) ++{ ++ (void)dhd; ++ (void)rssi; ++ return BCME_OK; ++} ++ ++static int ++dhd_wlfc_mac_table_update(dhd_pub_t *dhd, uint8* value, uint8 type) ++{ ++ int rc; ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ wlfc_mac_descriptor_t* table; ++ uint8 existing_index; ++ uint8 table_index; ++ uint8 ifid; ++ uint8* ea; ++ ++ AP6211_DEBUG("%s(), mac [%02x:%02x:%02x:%02x:%02x:%02x],%s,idx:%d,id:0x%02x\n", ++ __FUNCTION__, value[2], value[3], value[4], value[5], value[6], value[7], ++ ((type == WLFC_CTL_TYPE_MACDESC_ADD) ? "ADD":"DEL"), ++ WLFC_MAC_DESC_GET_LOOKUP_INDEX(value[0]), value[0]); ++ ++ table = wlfc->destination_entries.nodes; ++ table_index = WLFC_MAC_DESC_GET_LOOKUP_INDEX(value[0]); ++ ifid = value[1]; ++ ea = &value[2]; ++ ++ if (type == WLFC_CTL_TYPE_MACDESC_ADD) { ++ existing_index = dhd_wlfc_find_mac_desc_id_from_mac(dhd, &value[2]); ++ if (existing_index == WLFC_MAC_DESC_ID_INVALID) { ++ /* this MAC entry does not exist, create one */ ++ if (!table[table_index].occupied) { ++ table[table_index].mac_handle = value[0]; ++ rc = _dhd_wlfc_mac_entry_update(wlfc, &table[table_index], ++ eWLFC_MAC_ENTRY_ACTION_ADD, ifid, ++ wlfc->destination_entries.interfaces[ifid].iftype, ++ ea); ++ } ++ else { ++ /* the space should have been empty, but it's not */ ++ wlfc->stats.mac_update_failed++; ++ } ++ } ++ else { ++ /* ++ there is an existing entry, move it to new index ++ if necessary. ++ */ ++ if (existing_index != table_index) { ++ /* if we already have an entry, free the old one */ ++ table[existing_index].occupied = 0; ++ table[existing_index].state = WLFC_STATE_CLOSE; ++ table[existing_index].requested_credit = 0; ++ table[existing_index].interface_id = 0; ++ /* enable after packets are queued-deqeued properly. ++ pktq_flush(dhd->osh, &table[existing_index].psq, FALSE, NULL, 0); ++ */ ++ } ++ } ++ } ++ if (type == WLFC_CTL_TYPE_MACDESC_DEL) { ++ if (table[table_index].occupied) { ++ rc = _dhd_wlfc_mac_entry_update(wlfc, &table[table_index], ++ eWLFC_MAC_ENTRY_ACTION_DEL, ifid, ++ wlfc->destination_entries.interfaces[ifid].iftype, ++ ea); ++ } ++ else { ++ /* the space should have been occupied, but it's not */ ++ wlfc->stats.mac_update_failed++; ++ } ++ } ++ BCM_REFERENCE(rc); ++ return BCME_OK; ++} ++ ++static int ++dhd_wlfc_psmode_update(dhd_pub_t *dhd, uint8* value, uint8 type) ++{ ++ /* Handle PS on/off indication */ ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ wlfc_mac_descriptor_t* table; ++ wlfc_mac_descriptor_t* desc; ++ uint8 mac_handle = value[0]; ++ int i; ++ ++ table = wlfc->destination_entries.nodes; ++ desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; ++ if (desc->occupied) { ++ /* a fresh PS mode should wipe old ps credits? */ ++ desc->requested_credit = 0; ++ if (type == WLFC_CTL_TYPE_MAC_OPEN) { ++ desc->state = WLFC_STATE_OPEN; ++ DHD_WLFC_CTRINC_MAC_OPEN(desc); ++ } ++ else { ++ desc->state = WLFC_STATE_CLOSE; ++ DHD_WLFC_CTRINC_MAC_CLOSE(desc); ++ /* ++ Indicate to firmware if there is any traffic pending. ++ */ ++ for (i = AC_BE; i < AC_COUNT; i++) { ++ _dhd_wlfc_traffic_pending_check(wlfc, desc, i); ++ } ++ } ++ } ++ else { ++ wlfc->stats.psmode_update_failed++; ++ } ++ return BCME_OK; ++} ++ ++static int ++dhd_wlfc_interface_update(dhd_pub_t *dhd, uint8* value, uint8 type) ++{ ++ /* Handle PS on/off indication */ ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ wlfc_mac_descriptor_t* table; ++ uint8 if_id = value[0]; ++ ++ if (if_id < WLFC_MAX_IFNUM) { ++ table = wlfc->destination_entries.interfaces; ++ if (table[if_id].occupied) { ++ if (type == WLFC_CTL_TYPE_INTERFACE_OPEN) { ++ table[if_id].state = WLFC_STATE_OPEN; ++ /* AP6211_DEBUG("INTERFACE[%d] OPEN\n", if_id); */ ++ } ++ else { ++ table[if_id].state = WLFC_STATE_CLOSE; ++ /* AP6211_DEBUG("INTERFACE[%d] CLOSE\n", if_id); */ ++ } ++ return BCME_OK; ++ } ++ } ++ wlfc->stats.interface_update_failed++; ++ ++ return BCME_OK; ++} ++ ++static int ++dhd_wlfc_credit_request(dhd_pub_t *dhd, uint8* value) ++{ ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ wlfc_mac_descriptor_t* table; ++ wlfc_mac_descriptor_t* desc; ++ uint8 mac_handle; ++ uint8 credit; ++ ++ table = wlfc->destination_entries.nodes; ++ mac_handle = value[1]; ++ credit = value[0]; ++ ++ desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; ++ if (desc->occupied) { ++ desc->requested_credit = credit; ++ ++ desc->ac_bitmap = value[2]; ++ } ++ else { ++ wlfc->stats.credit_request_failed++; ++ } ++ return BCME_OK; ++} ++ ++static int ++dhd_wlfc_packet_request(dhd_pub_t *dhd, uint8* value) ++{ ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ wlfc_mac_descriptor_t* table; ++ wlfc_mac_descriptor_t* desc; ++ uint8 mac_handle; ++ uint8 packet_count; ++ ++ table = wlfc->destination_entries.nodes; ++ mac_handle = value[1]; ++ packet_count = value[0]; ++ ++ desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; ++ if (desc->occupied) { ++ desc->requested_packet = packet_count; ++ ++ desc->ac_bitmap = value[2]; ++ } ++ else { ++ wlfc->stats.packet_request_failed++; ++ } ++ return BCME_OK; ++} ++ ++static void ++dhd_wlfc_reorderinfo_indicate(uint8 *val, uint8 len, uchar *info_buf, uint *info_len) ++{ ++ if (info_len) { ++ if (info_buf) { ++ bcopy(val, info_buf, len); ++ *info_len = len; ++ } ++ else ++ *info_len = 0; ++ } ++} ++ ++int ++dhd_wlfc_parse_header_info(dhd_pub_t *dhd, void* pktbuf, int tlv_hdr_len, uchar *reorder_info_buf, ++ uint *reorder_info_len) ++{ ++ uint8 type, len; ++ uint8* value; ++ uint8* tmpbuf; ++ uint16 remainder = tlv_hdr_len; ++ uint16 processed = 0; ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ tmpbuf = (uint8*)PKTDATA(dhd->osh, pktbuf); ++ if (remainder) { ++ while ((processed < (WLFC_MAX_PENDING_DATALEN * 2)) && (remainder > 0)) { ++ type = tmpbuf[processed]; ++ if (type == WLFC_CTL_TYPE_FILLER) { ++ remainder -= 1; ++ processed += 1; ++ continue; ++ } ++ ++ len = tmpbuf[processed + 1]; ++ value = &tmpbuf[processed + 2]; ++ ++ if (remainder < (2 + len)) ++ break; ++ ++ remainder -= 2 + len; ++ processed += 2 + len; ++ if (type == WLFC_CTL_TYPE_TXSTATUS) ++ dhd_wlfc_txstatus_update(dhd, value); ++ if (type == WLFC_CTL_TYPE_COMP_TXSTATUS) ++ dhd_wlfc_compressed_txstatus_update(dhd, value, len); ++ ++ else if (type == WLFC_CTL_TYPE_HOST_REORDER_RXPKTS) ++ dhd_wlfc_reorderinfo_indicate(value, len, reorder_info_buf, ++ reorder_info_len); ++ else if (type == WLFC_CTL_TYPE_FIFO_CREDITBACK) ++ dhd_wlfc_fifocreditback_indicate(dhd, value); ++ ++ else if (type == WLFC_CTL_TYPE_RSSI) ++ dhd_wlfc_rssi_indicate(dhd, value); ++ ++ else if (type == WLFC_CTL_TYPE_MAC_REQUEST_CREDIT) ++ dhd_wlfc_credit_request(dhd, value); ++ ++ else if (type == WLFC_CTL_TYPE_MAC_REQUEST_PACKET) ++ dhd_wlfc_packet_request(dhd, value); ++ ++ else if ((type == WLFC_CTL_TYPE_MAC_OPEN) || ++ (type == WLFC_CTL_TYPE_MAC_CLOSE)) ++ dhd_wlfc_psmode_update(dhd, value, type); ++ ++ else if ((type == WLFC_CTL_TYPE_MACDESC_ADD) || ++ (type == WLFC_CTL_TYPE_MACDESC_DEL)) ++ dhd_wlfc_mac_table_update(dhd, value, type); ++ ++ else if (type == WLFC_CTL_TYPE_TRANS_ID) ++ dhd_wlfc_dbg_senum_check(dhd, value); ++ ++ else if ((type == WLFC_CTL_TYPE_INTERFACE_OPEN) || ++ (type == WLFC_CTL_TYPE_INTERFACE_CLOSE)) { ++ dhd_wlfc_interface_update(dhd, value, type); ++ } ++ } ++ if (remainder != 0) { ++ /* trouble..., something is not right */ ++ wlfc->stats.tlv_parse_failed++; ++ } ++ } ++ return BCME_OK; ++} ++ ++int ++dhd_wlfc_init(dhd_pub_t *dhd) ++{ ++ char iovbuf[12]; /* Room for "tlv" + '\0' + parameter */ ++ /* enable all signals & indicate host proptxstatus logic is active */ ++ uint32 tlv = dhd->wlfc_enabled? ++ WLFC_FLAGS_RSSI_SIGNALS | ++ WLFC_FLAGS_XONXOFF_SIGNALS | ++ WLFC_FLAGS_CREDIT_STATUS_SIGNALS | ++ WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE | ++ WLFC_FLAGS_HOST_RXRERODER_ACTIVE : 0; ++ /* WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE | WLFC_FLAGS_HOST_RXRERODER_ACTIVE : 0; */ ++ ++ ++ /* ++ try to enable/disable signaling by sending "tlv" iovar. if that fails, ++ fallback to no flow control? Print a message for now. ++ */ ++ ++ /* enable proptxtstatus signaling by default */ ++ bcm_mkiovar("tlv", (char *)&tlv, 4, iovbuf, sizeof(iovbuf)); ++ if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) < 0) { ++ AP6211_ERR("dhd_wlfc_init(): failed to enable/disable bdcv2 tlv signaling\n"); ++ } ++ else { ++ /* ++ Leaving the message for now, it should be removed after a while; once ++ the tlv situation is stable. ++ */ ++ AP6211_ERR("dhd_wlfc_init(): successfully %s bdcv2 tlv signaling, %d\n", ++ dhd->wlfc_enabled?"enabled":"disabled", tlv); ++ } ++ return BCME_OK; ++} ++ ++int ++dhd_wlfc_enable(dhd_pub_t *dhd) ++{ ++ int i; ++ athost_wl_status_info_t* wlfc; ++ ++ if (!dhd->wlfc_enabled || dhd->wlfc_state) ++ return BCME_OK; ++ ++ /* allocate space to track txstatus propagated from firmware */ ++ dhd->wlfc_state = MALLOC(dhd->osh, sizeof(athost_wl_status_info_t)); ++ if (dhd->wlfc_state == NULL) ++ return BCME_NOMEM; ++ ++ /* initialize state space */ ++ wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; ++ memset(wlfc, 0, sizeof(athost_wl_status_info_t)); ++ ++ /* remember osh & dhdp */ ++ wlfc->osh = dhd->osh; ++ wlfc->dhdp = dhd; ++ ++ wlfc->hanger = ++ dhd_wlfc_hanger_create(dhd->osh, WLFC_HANGER_MAXITEMS); ++ if (wlfc->hanger == NULL) { ++ MFREE(dhd->osh, dhd->wlfc_state, sizeof(athost_wl_status_info_t)); ++ dhd->wlfc_state = NULL; ++ AP6211_ERR("Failed to malloc dhd->wlfc_state\n"); ++ return BCME_NOMEM; ++ } ++ ++ /* initialize all interfaces to accept traffic */ ++ for (i = 0; i < WLFC_MAX_IFNUM; i++) { ++ wlfc->hostif_flow_state[i] = OFF; ++ } ++ ++ wlfc->destination_entries.other.state = WLFC_STATE_OPEN; ++ /* bc/mc FIFO is always open [credit aside], i.e. b[5] */ ++ wlfc->destination_entries.other.ac_bitmap = 0x1f; ++ wlfc->destination_entries.other.interface_id = 0; ++ ++ wlfc->proptxstatus_mode = WLFC_FCMODE_EXPLICIT_CREDIT; ++ ++ wlfc->allow_credit_borrow = TRUE; ++ wlfc->borrow_defer_timestamp = 0; ++ ++ return BCME_OK; ++} ++ ++/* release all packet resources */ ++void ++dhd_wlfc_cleanup(dhd_pub_t *dhd, ifpkt_cb_t fn, int arg) ++{ ++ int i; ++ int total_entries; ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ wlfc_mac_descriptor_t* table; ++ wlfc_hanger_t* h; ++ int prec; ++ void *pkt = NULL; ++ struct pktq *txq = NULL; ++ if (dhd->wlfc_state == NULL) ++ return; ++ /* flush bus->txq */ ++ txq = dhd_bus_txq(dhd->bus); ++ /* any in the hanger? */ ++ h = (wlfc_hanger_t*)wlfc->hanger; ++ total_entries = sizeof(wlfc->destination_entries)/sizeof(wlfc_mac_descriptor_t); ++ /* search all entries, include nodes as well as interfaces */ ++ table = (wlfc_mac_descriptor_t*)&wlfc->destination_entries; ++ ++ for (i = 0; i < total_entries; i++) { ++ if (table[i].occupied && (fn == NULL || (arg == table[i].interface_id))) { ++ if (table[i].psq.len) { ++ AP6211_DEBUG("%s(): DELAYQ[%d].len = %d\n", ++ __FUNCTION__, i, table[i].psq.len); ++ /* release packets held in DELAYQ */ ++ pktq_flush(wlfc->osh, &table[i].psq, TRUE, fn, arg); ++ } ++ if (fn == NULL) ++ table[i].occupied = 0; ++ } ++ } ++ for (prec = 0; prec < txq->num_prec; prec++) { ++ pkt = pktq_pdeq_with_fn(txq, prec, fn, arg); ++ while (pkt) { ++ for (i = 0; i < h->max_items; i++) { ++ if (pkt == h->items[i].pkt) { ++ if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) { ++ PKTFREE(wlfc->osh, h->items[i].pkt, TRUE); ++ h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; ++ } else if (h->items[i].state == ++ WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED) { ++ /* These are already freed from the psq */ ++ h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; ++ } ++ break; ++ } ++ } ++ pkt = pktq_pdeq(txq, prec); ++ } ++ } ++ /* flush remained pkt in hanger queue, not in bus->txq */ ++ for (i = 0; i < h->max_items; i++) { ++ if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) { ++ if (fn == NULL || (*fn)(h->items[i].pkt, arg)) { ++ PKTFREE(wlfc->osh, h->items[i].pkt, TRUE); ++ h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; ++ } ++ } else if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED) { ++ if (fn == NULL || (*fn)(h->items[i].pkt, arg)) { ++ /* These are freed from the psq so no need to free again */ ++ h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; ++ } ++ } ++ } ++ return; ++} ++ ++void ++dhd_wlfc_deinit(dhd_pub_t *dhd) ++{ ++ /* cleanup all psq related resources */ ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ ++ dhd_os_wlfc_block(dhd); ++ if (dhd->wlfc_state == NULL) { ++ dhd_os_wlfc_unblock(dhd); ++ return; ++ } ++ ++#ifdef PROP_TXSTATUS_DEBUG ++ { ++ int i; ++ wlfc_hanger_t* h = (wlfc_hanger_t*)wlfc->hanger; ++ for (i = 0; i < h->max_items; i++) { ++ if (h->items[i].state != WLFC_HANGER_ITEM_STATE_FREE) { ++ AP6211_DEBUG("%s() pkt[%d] = 0x%p, FIFO_credit_used:%d\n", ++ __FUNCTION__, i, h->items[i].pkt, ++ DHD_PKTTAG_CREDITCHECK(PKTTAG(h->items[i].pkt))); ++ } ++ } ++ } ++#endif ++ /* delete hanger */ ++ dhd_wlfc_hanger_delete(dhd->osh, wlfc->hanger); ++ ++ /* free top structure */ ++ MFREE(dhd->osh, dhd->wlfc_state, sizeof(athost_wl_status_info_t)); ++ dhd->wlfc_state = NULL; ++ dhd_os_wlfc_unblock(dhd); ++ ++ return; ++} ++#endif /* PROP_TXSTATUS */ +diff --git a/drivers/net/wireless/ap6211/dhd_wlfc.h b/drivers/net/wireless/ap6211/dhd_wlfc.h +new file mode 100755 +index 0000000..42b350c +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_wlfc.h +@@ -0,0 +1,288 @@ ++/* ++* Copyright (C) 1999-2012, Broadcom Corporation ++* ++* Unless you and Broadcom execute a separate written software license ++* agreement governing use of this software, this software is licensed to you ++* under the terms of the GNU General Public License version 2 (the "GPL"), ++* available at http://www.broadcom.com/licenses/GPLv2.php, with the ++* following added to such license: ++* ++* As a special exception, the copyright holders of this software give you ++* permission to link this software with independent modules, and to copy and ++* distribute the resulting executable under terms of your choice, provided that ++* you also meet, for each linked independent module, the terms and conditions of ++* the license of that module. An independent module is a module which is not ++* derived from this software. The special exception does not apply to any ++* modifications of the software. ++* ++* Notwithstanding the above, under no circumstances may you combine this ++* software in any way with any other Broadcom software provided under a license ++* other than the GPL, without Broadcom's express prior written consent. ++* $Id: dhd_wlfc.h 361006 2012-10-05 07:45:51Z $ ++* ++*/ ++#ifndef __wlfc_host_driver_definitions_h__ ++#define __wlfc_host_driver_definitions_h__ ++ ++/* 16 bits will provide an absolute max of 65536 slots */ ++#define WLFC_HANGER_MAXITEMS 1024 ++ ++#define WLFC_HANGER_ITEM_STATE_FREE 1 ++#define WLFC_HANGER_ITEM_STATE_INUSE 2 ++#define WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED 3 ++#define WLFC_PKTID_HSLOT_MASK 0xffff /* allow 16 bits only */ ++#define WLFC_PKTID_HSLOT_SHIFT 8 ++ ++/* x -> TXSTATUS TAG to/from firmware */ ++#define WLFC_PKTID_HSLOT_GET(x) \ ++ (((x) >> WLFC_PKTID_HSLOT_SHIFT) & WLFC_PKTID_HSLOT_MASK) ++#define WLFC_PKTID_HSLOT_SET(var, slot) \ ++ ((var) = ((var) & ~(WLFC_PKTID_HSLOT_MASK << WLFC_PKTID_HSLOT_SHIFT)) | \ ++ (((slot) & WLFC_PKTID_HSLOT_MASK) << WLFC_PKTID_HSLOT_SHIFT)) ++ ++#define WLFC_PKTID_FREERUNCTR_MASK 0xff ++ ++#define WLFC_PKTID_FREERUNCTR_GET(x) ((x) & WLFC_PKTID_FREERUNCTR_MASK) ++#define WLFC_PKTID_FREERUNCTR_SET(var, ctr) \ ++ ((var) = (((var) & ~WLFC_PKTID_FREERUNCTR_MASK) | \ ++ (((ctr) & WLFC_PKTID_FREERUNCTR_MASK)))) ++ ++#define WLFC_PKTQ_PENQ(pq, prec, p) ((pktq_full((pq)) || pktq_pfull((pq), (prec)))? \ ++ NULL : pktq_penq((pq), (prec), (p))) ++#define WLFC_PKTQ_PENQ_HEAD(pq, prec, p) ((pktq_full((pq)) || pktq_pfull((pq), (prec))) ? \ ++ NULL : pktq_penq_head((pq), (prec), (p))) ++ ++typedef enum ewlfc_packet_state { ++ eWLFC_PKTTYPE_NEW, ++ eWLFC_PKTTYPE_DELAYED, ++ eWLFC_PKTTYPE_SUPPRESSED, ++ eWLFC_PKTTYPE_MAX ++} ewlfc_packet_state_t; ++ ++typedef enum ewlfc_mac_entry_action { ++ eWLFC_MAC_ENTRY_ACTION_ADD, ++ eWLFC_MAC_ENTRY_ACTION_DEL, ++ eWLFC_MAC_ENTRY_ACTION_UPDATE, ++ eWLFC_MAC_ENTRY_ACTION_MAX ++} ewlfc_mac_entry_action_t; ++ ++typedef struct wlfc_hanger_item { ++ uint8 state; ++ uint8 gen; ++ uint8 pad[2]; ++ uint32 identifier; ++ void* pkt; ++#ifdef PROP_TXSTATUS_DEBUG ++ uint32 push_time; ++#endif ++} wlfc_hanger_item_t; ++ ++typedef struct wlfc_hanger { ++ int max_items; ++ uint32 pushed; ++ uint32 popped; ++ uint32 failed_to_push; ++ uint32 failed_to_pop; ++ uint32 failed_slotfind; ++ wlfc_hanger_item_t items[1]; ++ uint32 slot_pos; ++} wlfc_hanger_t; ++ ++#define WLFC_HANGER_SIZE(n) ((sizeof(wlfc_hanger_t) - \ ++ sizeof(wlfc_hanger_item_t)) + ((n)*sizeof(wlfc_hanger_item_t))) ++ ++#define WLFC_STATE_OPEN 1 ++#define WLFC_STATE_CLOSE 2 ++ ++#define WLFC_PSQ_PREC_COUNT ((AC_COUNT + 1) * 2) /* 2 for each AC traffic and bc/mc */ ++ ++#define WLFC_PSQ_LEN 2048 ++ ++#define WLFC_SENDQ_LEN 256 ++ ++ ++#define WLFC_FLOWCONTROL_HIWATER (2048 - 256) ++#define WLFC_FLOWCONTROL_LOWATER 256 ++ ++ ++typedef struct wlfc_mac_descriptor { ++ uint8 occupied; ++ uint8 interface_id; ++ uint8 iftype; ++ uint8 state; ++ uint8 ac_bitmap; /* for APSD */ ++ uint8 requested_credit; ++ uint8 requested_packet; ++ uint8 ea[ETHER_ADDR_LEN]; ++ /* ++ maintain (MAC,AC) based seq count for ++ packets going to the device. As well as bc/mc. ++ */ ++ uint8 seq[AC_COUNT + 1]; ++ uint8 generation; ++ struct pktq psq; ++ /* The AC pending bitmap that was reported to the fw at last change */ ++ uint8 traffic_lastreported_bmp; ++ /* The new AC pending bitmap */ ++ uint8 traffic_pending_bmp; ++ /* 1= send on next opportunity */ ++ uint8 send_tim_signal; ++ uint8 mac_handle; ++ uint transit_count; ++ uint suppr_transit_count; ++ uint suppress_count; ++ uint8 suppressed; ++ ++#ifdef PROP_TXSTATUS_DEBUG ++ uint32 dstncredit_sent_packets; ++ uint32 dstncredit_acks; ++ uint32 opened_ct; ++ uint32 closed_ct; ++#endif ++} wlfc_mac_descriptor_t; ++ ++#define WLFC_DECR_SEQCOUNT(entry, prec) do { if (entry->seq[(prec)] == 0) {\ ++ entry->seq[prec] = 0xff; } else entry->seq[prec]--;} while (0) ++ ++#define WLFC_INCR_SEQCOUNT(entry, prec) entry->seq[(prec)]++ ++#define WLFC_SEQCOUNT(entry, prec) entry->seq[(prec)] ++ ++typedef struct athost_wl_stat_counters { ++ uint32 pktin; ++ uint32 pkt2bus; ++ uint32 pktdropped; ++ uint32 tlv_parse_failed; ++ uint32 rollback; ++ uint32 rollback_failed; ++ uint32 sendq_full_error; ++ uint32 delayq_full_error; ++ uint32 credit_request_failed; ++ uint32 packet_request_failed; ++ uint32 mac_update_failed; ++ uint32 psmode_update_failed; ++ uint32 interface_update_failed; ++ uint32 wlfc_header_only_pkt; ++ uint32 txstatus_in; ++ uint32 d11_suppress; ++ uint32 wl_suppress; ++ uint32 bad_suppress; ++ uint32 pkt_freed; ++ uint32 pkt_free_err; ++ uint32 psq_wlsup_retx; ++ uint32 psq_wlsup_enq; ++ uint32 psq_d11sup_retx; ++ uint32 psq_d11sup_enq; ++ uint32 psq_hostq_retx; ++ uint32 psq_hostq_enq; ++ uint32 mac_handle_notfound; ++ uint32 wlc_tossed_pkts; ++ uint32 dhd_hdrpulls; ++ uint32 generic_error; ++ /* an extra one for bc/mc traffic */ ++ uint32 sendq_pkts[AC_COUNT + 1]; ++#ifdef PROP_TXSTATUS_DEBUG ++ /* all pkt2bus -> txstatus latency accumulated */ ++ uint32 latency_sample_count; ++ uint32 total_status_latency; ++ uint32 latency_most_recent; ++ int idx_delta; ++ uint32 deltas[10]; ++ uint32 fifo_credits_sent[6]; ++ uint32 fifo_credits_back[6]; ++ uint32 dropped_qfull[6]; ++ uint32 signal_only_pkts_sent; ++ uint32 signal_only_pkts_freed; ++#endif ++} athost_wl_stat_counters_t; ++ ++#ifdef PROP_TXSTATUS_DEBUG ++#define WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac) do { \ ++ (ctx)->stats.fifo_credits_sent[(ac)]++;} while (0) ++#define WLFC_HOST_FIFO_CREDIT_INC_BACKCTRS(ctx, ac) do { \ ++ (ctx)->stats.fifo_credits_back[(ac)]++;} while (0) ++#define WLFC_HOST_FIFO_DROPPEDCTR_INC(ctx, ac) do { \ ++ (ctx)->stats.dropped_qfull[(ac)]++;} while (0) ++#else ++#define WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac) do {} while (0) ++#define WLFC_HOST_FIFO_CREDIT_INC_BACKCTRS(ctx, ac) do {} while (0) ++#define WLFC_HOST_FIFO_DROPPEDCTR_INC(ctx, ac) do {} while (0) ++#endif ++ ++#define WLFC_FCMODE_NONE 0 ++#define WLFC_FCMODE_IMPLIED_CREDIT 1 ++#define WLFC_FCMODE_EXPLICIT_CREDIT 2 ++ ++/* How long to defer borrowing in milliseconds */ ++#define WLFC_BORROW_DEFER_PERIOD_MS 100 ++ ++/* Mask to represent available ACs (note: BC/MC is ignored */ ++#define WLFC_AC_MASK 0xF ++ ++/* Mask to check for only on-going AC_BE traffic */ ++#define WLFC_AC_BE_TRAFFIC_ONLY 0xD ++ ++typedef struct athost_wl_status_info { ++ uint8 last_seqid_to_wlc; ++ ++ /* OSL handle */ ++ osl_t* osh; ++ /* dhd pub */ ++ void* dhdp; ++ ++ /* stats */ ++ athost_wl_stat_counters_t stats; ++ ++ /* the additional ones are for bc/mc and ATIM FIFO */ ++ int FIFO_credit[AC_COUNT + 2]; ++ ++ /* Credit borrow counts for each FIFO from each of the other FIFOs */ ++ int credits_borrowed[AC_COUNT + 2][AC_COUNT + 2]; ++ ++ struct pktq SENDQ; ++ ++ /* packet hanger and MAC->handle lookup table */ ++ void* hanger; ++ struct { ++ /* table for individual nodes */ ++ wlfc_mac_descriptor_t nodes[WLFC_MAC_DESC_TABLE_SIZE]; ++ /* table for interfaces */ ++ wlfc_mac_descriptor_t interfaces[WLFC_MAX_IFNUM]; ++ /* OS may send packets to unknown (unassociated) destinations */ ++ /* A place holder for bc/mc and packets to unknown destinations */ ++ wlfc_mac_descriptor_t other; ++ } destination_entries; ++ /* token position for different priority packets */ ++ uint8 token_pos[AC_COUNT+1]; ++ /* ON/OFF state for flow control to the host network interface */ ++ uint8 hostif_flow_state[WLFC_MAX_IFNUM]; ++ uint8 host_ifidx; ++ /* to flow control an OS interface */ ++ uint8 toggle_host_if; ++ ++ /* ++ Mode in which the dhd flow control shall operate. Must be set before ++ traffic starts to the device. ++ 0 - Do not do any proptxtstatus flow control ++ 1 - Use implied credit from a packet status ++ 2 - Use explicit credit ++ */ ++ uint8 proptxstatus_mode; ++ ++ /* To borrow credits */ ++ uint8 allow_credit_borrow; ++ ++ /* Timestamp to compute how long to defer borrowing for */ ++ uint32 borrow_defer_timestamp; ++ ++ bool wlfc_locked; ++} athost_wl_status_info_t; ++ ++int dhd_wlfc_enable(dhd_pub_t *dhd); ++int dhd_wlfc_interface_event(struct dhd_info *, ++ ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea); ++int dhd_wlfc_FIFOcreditmap_event(struct dhd_info *dhd, uint8* event_data); ++int dhd_wlfc_event(struct dhd_info *dhd); ++int dhd_os_wlfc_block(dhd_pub_t *pub); ++int dhd_os_wlfc_unblock(dhd_pub_t *pub); ++ ++#endif /* __wlfc_host_driver_definitions_h__ */ +diff --git a/drivers/net/wireless/ap6211/dngl_stats.h b/drivers/net/wireless/ap6211/dngl_stats.h +new file mode 100755 +index 0000000..5e5a2e2 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dngl_stats.h +@@ -0,0 +1,43 @@ ++/* ++ * Common stats definitions for clients of dongle ++ * ports ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dngl_stats.h 241182 2011-02-17 21:50:03Z $ ++ */ ++ ++#ifndef _dngl_stats_h_ ++#define _dngl_stats_h_ ++ ++typedef struct { ++ unsigned long rx_packets; /* total packets received */ ++ unsigned long tx_packets; /* total packets transmitted */ ++ unsigned long rx_bytes; /* total bytes received */ ++ unsigned long tx_bytes; /* total bytes transmitted */ ++ unsigned long rx_errors; /* bad packets received */ ++ unsigned long tx_errors; /* packet transmit problems */ ++ unsigned long rx_dropped; /* packets dropped by dongle */ ++ unsigned long tx_dropped; /* packets dropped by dongle */ ++ unsigned long multicast; /* multicast packets received */ ++} dngl_stats_t; ++ ++#endif /* _dngl_stats_h_ */ +diff --git a/drivers/net/wireless/ap6211/dngl_wlhdr.h b/drivers/net/wireless/ap6211/dngl_wlhdr.h +new file mode 100755 +index 0000000..0e37df6 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dngl_wlhdr.h +@@ -0,0 +1,40 @@ ++/* ++ * Dongle WL Header definitions ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dngl_wlhdr.h 241182 2011-02-17 21:50:03Z $ ++ */ ++ ++#ifndef _dngl_wlhdr_h_ ++#define _dngl_wlhdr_h_ ++ ++typedef struct wl_header { ++ uint8 type; /* Header type */ ++ uint8 version; /* Header version */ ++ int8 rssi; /* RSSI */ ++ uint8 pad; /* Unused */ ++} wl_header_t; ++ ++#define WL_HEADER_LEN sizeof(wl_header_t) ++#define WL_HEADER_TYPE 0 ++#define WL_HEADER_VER 1 ++#endif /* _dngl_wlhdr_h_ */ +diff --git a/drivers/net/wireless/ap6211/hndpmu.c b/drivers/net/wireless/ap6211/hndpmu.c +new file mode 100755 +index 0000000..e639015 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/hndpmu.c +@@ -0,0 +1,208 @@ ++/* ++ * Misc utility routines for accessing PMU corerev specific features ++ * of the SiliconBackplane-based Broadcom chips. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: hndpmu.c 354194 2012-08-30 08:39:03Z $ ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define PMU_ERROR(args) ++ ++#define PMU_MSG(args) ++ ++/* To check in verbose debugging messages not intended ++ * to be on except on private builds. ++ */ ++#define PMU_NONE(args) ++ ++ ++/* SDIO Pad drive strength to select value mappings. ++ * The last strength value in each table must be 0 (the tri-state value). ++ */ ++typedef struct { ++ uint8 strength; /* Pad Drive Strength in mA */ ++ uint8 sel; /* Chip-specific select value */ ++} sdiod_drive_str_t; ++ ++/* SDIO Drive Strength to sel value table for PMU Rev 1 */ ++static const sdiod_drive_str_t sdiod_drive_strength_tab1[] = { ++ {4, 0x2}, ++ {2, 0x3}, ++ {1, 0x0}, ++ {0, 0x0} }; ++ ++/* SDIO Drive Strength to sel value table for PMU Rev 2, 3 */ ++static const sdiod_drive_str_t sdiod_drive_strength_tab2[] = { ++ {12, 0x7}, ++ {10, 0x6}, ++ {8, 0x5}, ++ {6, 0x4}, ++ {4, 0x2}, ++ {2, 0x1}, ++ {0, 0x0} }; ++ ++/* SDIO Drive Strength to sel value table for PMU Rev 8 (1.8V) */ ++static const sdiod_drive_str_t sdiod_drive_strength_tab3[] = { ++ {32, 0x7}, ++ {26, 0x6}, ++ {22, 0x5}, ++ {16, 0x4}, ++ {12, 0x3}, ++ {8, 0x2}, ++ {4, 0x1}, ++ {0, 0x0} }; ++ ++/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.8v) */ ++static const sdiod_drive_str_t sdiod_drive_strength_tab4_1v8[] = { ++ {32, 0x6}, ++ {26, 0x7}, ++ {22, 0x4}, ++ {16, 0x5}, ++ {12, 0x2}, ++ {8, 0x3}, ++ {4, 0x0}, ++ {0, 0x1} }; ++ ++/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.2v) */ ++ ++/* SDIO Drive Strength to sel value table for PMU Rev 11 (2.5v) */ ++ ++/* SDIO Drive Strength to sel value table for PMU Rev 13 (1.8v) */ ++static const sdiod_drive_str_t sdiod_drive_strength_tab5_1v8[] = { ++ {6, 0x7}, ++ {5, 0x6}, ++ {4, 0x5}, ++ {3, 0x4}, ++ {2, 0x2}, ++ {1, 0x1}, ++ {0, 0x0} }; ++ ++/* SDIO Drive Strength to sel value table for PMU Rev 13 (3.3v) */ ++ ++/* SDIO Drive Strength to sel value table for PMU Rev 17 (1.8v) */ ++static const sdiod_drive_str_t sdiod_drive_strength_tab6_1v8[] = { ++ {3, 0x3}, ++ {2, 0x2}, ++ {1, 0x1}, ++ {0, 0x0} }; ++ ++#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu)) ++ ++void ++si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength) ++{ ++ chipcregs_t *cc; ++ uint origidx, intr_val = 0; ++ sdiod_drive_str_t *str_tab = NULL; ++ uint32 str_mask = 0; ++ uint32 str_shift = 0; ++ ++ if (!(sih->cccaps & CC_CAP_PMU)) { ++ return; ++ } ++ ++ /* Remember original core before switch to chipc */ ++ cc = (chipcregs_t *) si_switch_core(sih, CC_CORE_ID, &origidx, &intr_val); ++ ++ switch (SDIOD_DRVSTR_KEY(sih->chip, sih->pmurev)) { ++ case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1): ++ str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab1; ++ str_mask = 0x30000000; ++ str_shift = 28; ++ break; ++ case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 2): ++ case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 3): ++ case SDIOD_DRVSTR_KEY(BCM4315_CHIP_ID, 4): ++ str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab2; ++ str_mask = 0x00003800; ++ str_shift = 11; ++ break; ++ case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8): ++ case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 11): ++ if (sih->pmurev == 8) { ++ str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab3; ++ } ++ else if (sih->pmurev == 11) { ++ str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8; ++ } ++ str_mask = 0x00003800; ++ str_shift = 11; ++ break; ++ case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12): ++ str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8; ++ str_mask = 0x00003800; ++ str_shift = 11; ++ break; ++ case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13): ++ str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab5_1v8; ++ str_mask = 0x00003800; ++ str_shift = 11; ++ break; ++ case SDIOD_DRVSTR_KEY(BCM4334_CHIP_ID, 17): ++ str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab6_1v8; ++ str_mask = 0x00001800; ++ str_shift = 11; ++ break; ++ default: ++ PMU_MSG(("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n", ++ bcm_chipname(sih->chip, chn, 8), sih->chiprev, sih->pmurev)); ++ ++ break; ++ } ++ ++ if (str_tab != NULL && cc != NULL) { ++ uint32 cc_data_temp; ++ int i; ++ ++ /* Pick the lowest available drive strength equal or greater than the ++ * requested strength. Drive strength of 0 requests tri-state. ++ */ ++ for (i = 0; drivestrength < str_tab[i].strength; i++) ++ ; ++ ++ if (i > 0 && drivestrength > str_tab[i].strength) ++ i--; ++ ++ W_REG(osh, &cc->chipcontrol_addr, 1); ++ cc_data_temp = R_REG(osh, &cc->chipcontrol_data); ++ cc_data_temp &= ~str_mask; ++ cc_data_temp |= str_tab[i].sel << str_shift; ++ W_REG(osh, &cc->chipcontrol_data, cc_data_temp); ++ ++ PMU_MSG(("SDIO: %dmA drive strength requested; set to %dmA\n", ++ drivestrength, str_tab[i].strength)); ++ } ++ ++ /* Return to original core */ ++ si_restore_core(sih, origidx, intr_val); ++} +diff --git a/drivers/net/wireless/ap6211/include/Makefile b/drivers/net/wireless/ap6211/include/Makefile +new file mode 100755 +index 0000000..8483b54 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/Makefile +@@ -0,0 +1,54 @@ ++#!/bin/bash ++# ++# This script serves following purpose: ++# ++# 1. It generates native version information by querying ++# automerger maintained database to see where src/include ++# came from ++# 2. For select components, as listed in compvers.sh ++# it generates component version files ++# ++# Copyright 2005, Broadcom, Inc. ++# ++# $Id: Makefile 241686 2011-02-19 00:22:45Z prakashd $ ++# ++ ++SRCBASE := .. ++ ++TARGETS := epivers.h ++ ++ifdef VERBOSE ++export VERBOSE ++endif ++ ++all release: epivers compvers ++ ++# Generate epivers.h for native branch version ++epivers: ++ bash epivers.sh ++ ++# Generate epivers.h for native branch version ++compvers: ++ @if [ -s "compvers.sh" ]; then \ ++ echo "Generating component versions, if any"; \ ++ bash compvers.sh; \ ++ else \ ++ echo "Skipping component version generation"; \ ++ fi ++ ++# Generate epivers.h for native branch version ++clean_compvers: ++ @if [ -s "compvers.sh" ]; then \ ++ echo "bash compvers.sh clean"; \ ++ bash compvers.sh clean; \ ++ else \ ++ echo "Skipping component version clean"; \ ++ fi ++ ++clean: ++ rm -f $(TARGETS) *.prev ++ ++clean_all: clean clean_compvers ++ ++.PHONY: all release clean epivers compvers clean_compvers ++ +diff --git a/drivers/net/wireless/ap6211/include/aidmp.h b/drivers/net/wireless/ap6211/include/aidmp.h +new file mode 100755 +index 0000000..d557079 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/aidmp.h +@@ -0,0 +1,375 @@ ++/* ++ * Broadcom AMBA Interconnect definitions. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: aidmp.h 241182 2011-02-17 21:50:03Z $ ++ */ ++ ++#ifndef _AIDMP_H ++#define _AIDMP_H ++ ++/* Manufacturer Ids */ ++#define MFGID_ARM 0x43b ++#define MFGID_BRCM 0x4bf ++#define MFGID_MIPS 0x4a7 ++ ++/* Component Classes */ ++#define CC_SIM 0 ++#define CC_EROM 1 ++#define CC_CORESIGHT 9 ++#define CC_VERIF 0xb ++#define CC_OPTIMO 0xd ++#define CC_GEN 0xe ++#define CC_PRIMECELL 0xf ++ ++/* Enumeration ROM registers */ ++#define ER_EROMENTRY 0x000 ++#define ER_REMAPCONTROL 0xe00 ++#define ER_REMAPSELECT 0xe04 ++#define ER_MASTERSELECT 0xe10 ++#define ER_ITCR 0xf00 ++#define ER_ITIP 0xf04 ++ ++/* Erom entries */ ++#define ER_TAG 0xe ++#define ER_TAG1 0x6 ++#define ER_VALID 1 ++#define ER_CI 0 ++#define ER_MP 2 ++#define ER_ADD 4 ++#define ER_END 0xe ++#define ER_BAD 0xffffffff ++ ++/* EROM CompIdentA */ ++#define CIA_MFG_MASK 0xfff00000 ++#define CIA_MFG_SHIFT 20 ++#define CIA_CID_MASK 0x000fff00 ++#define CIA_CID_SHIFT 8 ++#define CIA_CCL_MASK 0x000000f0 ++#define CIA_CCL_SHIFT 4 ++ ++/* EROM CompIdentB */ ++#define CIB_REV_MASK 0xff000000 ++#define CIB_REV_SHIFT 24 ++#define CIB_NSW_MASK 0x00f80000 ++#define CIB_NSW_SHIFT 19 ++#define CIB_NMW_MASK 0x0007c000 ++#define CIB_NMW_SHIFT 14 ++#define CIB_NSP_MASK 0x00003e00 ++#define CIB_NSP_SHIFT 9 ++#define CIB_NMP_MASK 0x000001f0 ++#define CIB_NMP_SHIFT 4 ++ ++/* EROM MasterPortDesc */ ++#define MPD_MUI_MASK 0x0000ff00 ++#define MPD_MUI_SHIFT 8 ++#define MPD_MP_MASK 0x000000f0 ++#define MPD_MP_SHIFT 4 ++ ++/* EROM AddrDesc */ ++#define AD_ADDR_MASK 0xfffff000 ++#define AD_SP_MASK 0x00000f00 ++#define AD_SP_SHIFT 8 ++#define AD_ST_MASK 0x000000c0 ++#define AD_ST_SHIFT 6 ++#define AD_ST_SLAVE 0x00000000 ++#define AD_ST_BRIDGE 0x00000040 ++#define AD_ST_SWRAP 0x00000080 ++#define AD_ST_MWRAP 0x000000c0 ++#define AD_SZ_MASK 0x00000030 ++#define AD_SZ_SHIFT 4 ++#define AD_SZ_4K 0x00000000 ++#define AD_SZ_8K 0x00000010 ++#define AD_SZ_16K 0x00000020 ++#define AD_SZ_SZD 0x00000030 ++#define AD_AG32 0x00000008 ++#define AD_ADDR_ALIGN 0x00000fff ++#define AD_SZ_BASE 0x00001000 /* 4KB */ ++ ++/* EROM SizeDesc */ ++#define SD_SZ_MASK 0xfffff000 ++#define SD_SG32 0x00000008 ++#define SD_SZ_ALIGN 0x00000fff ++ ++ ++#ifndef _LANGUAGE_ASSEMBLY ++ ++typedef volatile struct _aidmp { ++ uint32 oobselina30; /* 0x000 */ ++ uint32 oobselina74; /* 0x004 */ ++ uint32 PAD[6]; ++ uint32 oobselinb30; /* 0x020 */ ++ uint32 oobselinb74; /* 0x024 */ ++ uint32 PAD[6]; ++ uint32 oobselinc30; /* 0x040 */ ++ uint32 oobselinc74; /* 0x044 */ ++ uint32 PAD[6]; ++ uint32 oobselind30; /* 0x060 */ ++ uint32 oobselind74; /* 0x064 */ ++ uint32 PAD[38]; ++ uint32 oobselouta30; /* 0x100 */ ++ uint32 oobselouta74; /* 0x104 */ ++ uint32 PAD[6]; ++ uint32 oobseloutb30; /* 0x120 */ ++ uint32 oobseloutb74; /* 0x124 */ ++ uint32 PAD[6]; ++ uint32 oobseloutc30; /* 0x140 */ ++ uint32 oobseloutc74; /* 0x144 */ ++ uint32 PAD[6]; ++ uint32 oobseloutd30; /* 0x160 */ ++ uint32 oobseloutd74; /* 0x164 */ ++ uint32 PAD[38]; ++ uint32 oobsynca; /* 0x200 */ ++ uint32 oobseloutaen; /* 0x204 */ ++ uint32 PAD[6]; ++ uint32 oobsyncb; /* 0x220 */ ++ uint32 oobseloutben; /* 0x224 */ ++ uint32 PAD[6]; ++ uint32 oobsyncc; /* 0x240 */ ++ uint32 oobseloutcen; /* 0x244 */ ++ uint32 PAD[6]; ++ uint32 oobsyncd; /* 0x260 */ ++ uint32 oobseloutden; /* 0x264 */ ++ uint32 PAD[38]; ++ uint32 oobaextwidth; /* 0x300 */ ++ uint32 oobainwidth; /* 0x304 */ ++ uint32 oobaoutwidth; /* 0x308 */ ++ uint32 PAD[5]; ++ uint32 oobbextwidth; /* 0x320 */ ++ uint32 oobbinwidth; /* 0x324 */ ++ uint32 oobboutwidth; /* 0x328 */ ++ uint32 PAD[5]; ++ uint32 oobcextwidth; /* 0x340 */ ++ uint32 oobcinwidth; /* 0x344 */ ++ uint32 oobcoutwidth; /* 0x348 */ ++ uint32 PAD[5]; ++ uint32 oobdextwidth; /* 0x360 */ ++ uint32 oobdinwidth; /* 0x364 */ ++ uint32 oobdoutwidth; /* 0x368 */ ++ uint32 PAD[37]; ++ uint32 ioctrlset; /* 0x400 */ ++ uint32 ioctrlclear; /* 0x404 */ ++ uint32 ioctrl; /* 0x408 */ ++ uint32 PAD[61]; ++ uint32 iostatus; /* 0x500 */ ++ uint32 PAD[127]; ++ uint32 ioctrlwidth; /* 0x700 */ ++ uint32 iostatuswidth; /* 0x704 */ ++ uint32 PAD[62]; ++ uint32 resetctrl; /* 0x800 */ ++ uint32 resetstatus; /* 0x804 */ ++ uint32 resetreadid; /* 0x808 */ ++ uint32 resetwriteid; /* 0x80c */ ++ uint32 PAD[60]; ++ uint32 errlogctrl; /* 0x900 */ ++ uint32 errlogdone; /* 0x904 */ ++ uint32 errlogstatus; /* 0x908 */ ++ uint32 errlogaddrlo; /* 0x90c */ ++ uint32 errlogaddrhi; /* 0x910 */ ++ uint32 errlogid; /* 0x914 */ ++ uint32 errloguser; /* 0x918 */ ++ uint32 errlogflags; /* 0x91c */ ++ uint32 PAD[56]; ++ uint32 intstatus; /* 0xa00 */ ++ uint32 PAD[255]; ++ uint32 config; /* 0xe00 */ ++ uint32 PAD[63]; ++ uint32 itcr; /* 0xf00 */ ++ uint32 PAD[3]; ++ uint32 itipooba; /* 0xf10 */ ++ uint32 itipoobb; /* 0xf14 */ ++ uint32 itipoobc; /* 0xf18 */ ++ uint32 itipoobd; /* 0xf1c */ ++ uint32 PAD[4]; ++ uint32 itipoobaout; /* 0xf30 */ ++ uint32 itipoobbout; /* 0xf34 */ ++ uint32 itipoobcout; /* 0xf38 */ ++ uint32 itipoobdout; /* 0xf3c */ ++ uint32 PAD[4]; ++ uint32 itopooba; /* 0xf50 */ ++ uint32 itopoobb; /* 0xf54 */ ++ uint32 itopoobc; /* 0xf58 */ ++ uint32 itopoobd; /* 0xf5c */ ++ uint32 PAD[4]; ++ uint32 itopoobain; /* 0xf70 */ ++ uint32 itopoobbin; /* 0xf74 */ ++ uint32 itopoobcin; /* 0xf78 */ ++ uint32 itopoobdin; /* 0xf7c */ ++ uint32 PAD[4]; ++ uint32 itopreset; /* 0xf90 */ ++ uint32 PAD[15]; ++ uint32 peripherialid4; /* 0xfd0 */ ++ uint32 peripherialid5; /* 0xfd4 */ ++ uint32 peripherialid6; /* 0xfd8 */ ++ uint32 peripherialid7; /* 0xfdc */ ++ uint32 peripherialid0; /* 0xfe0 */ ++ uint32 peripherialid1; /* 0xfe4 */ ++ uint32 peripherialid2; /* 0xfe8 */ ++ uint32 peripherialid3; /* 0xfec */ ++ uint32 componentid0; /* 0xff0 */ ++ uint32 componentid1; /* 0xff4 */ ++ uint32 componentid2; /* 0xff8 */ ++ uint32 componentid3; /* 0xffc */ ++} aidmp_t; ++ ++#endif /* _LANGUAGE_ASSEMBLY */ ++ ++/* Out-of-band Router registers */ ++#define OOB_BUSCONFIG 0x020 ++#define OOB_STATUSA 0x100 ++#define OOB_STATUSB 0x104 ++#define OOB_STATUSC 0x108 ++#define OOB_STATUSD 0x10c ++#define OOB_ENABLEA0 0x200 ++#define OOB_ENABLEA1 0x204 ++#define OOB_ENABLEA2 0x208 ++#define OOB_ENABLEA3 0x20c ++#define OOB_ENABLEB0 0x280 ++#define OOB_ENABLEB1 0x284 ++#define OOB_ENABLEB2 0x288 ++#define OOB_ENABLEB3 0x28c ++#define OOB_ENABLEC0 0x300 ++#define OOB_ENABLEC1 0x304 ++#define OOB_ENABLEC2 0x308 ++#define OOB_ENABLEC3 0x30c ++#define OOB_ENABLED0 0x380 ++#define OOB_ENABLED1 0x384 ++#define OOB_ENABLED2 0x388 ++#define OOB_ENABLED3 0x38c ++#define OOB_ITCR 0xf00 ++#define OOB_ITIPOOBA 0xf10 ++#define OOB_ITIPOOBB 0xf14 ++#define OOB_ITIPOOBC 0xf18 ++#define OOB_ITIPOOBD 0xf1c ++#define OOB_ITOPOOBA 0xf30 ++#define OOB_ITOPOOBB 0xf34 ++#define OOB_ITOPOOBC 0xf38 ++#define OOB_ITOPOOBD 0xf3c ++ ++/* DMP wrapper registers */ ++#define AI_OOBSELINA30 0x000 ++#define AI_OOBSELINA74 0x004 ++#define AI_OOBSELINB30 0x020 ++#define AI_OOBSELINB74 0x024 ++#define AI_OOBSELINC30 0x040 ++#define AI_OOBSELINC74 0x044 ++#define AI_OOBSELIND30 0x060 ++#define AI_OOBSELIND74 0x064 ++#define AI_OOBSELOUTA30 0x100 ++#define AI_OOBSELOUTA74 0x104 ++#define AI_OOBSELOUTB30 0x120 ++#define AI_OOBSELOUTB74 0x124 ++#define AI_OOBSELOUTC30 0x140 ++#define AI_OOBSELOUTC74 0x144 ++#define AI_OOBSELOUTD30 0x160 ++#define AI_OOBSELOUTD74 0x164 ++#define AI_OOBSYNCA 0x200 ++#define AI_OOBSELOUTAEN 0x204 ++#define AI_OOBSYNCB 0x220 ++#define AI_OOBSELOUTBEN 0x224 ++#define AI_OOBSYNCC 0x240 ++#define AI_OOBSELOUTCEN 0x244 ++#define AI_OOBSYNCD 0x260 ++#define AI_OOBSELOUTDEN 0x264 ++#define AI_OOBAEXTWIDTH 0x300 ++#define AI_OOBAINWIDTH 0x304 ++#define AI_OOBAOUTWIDTH 0x308 ++#define AI_OOBBEXTWIDTH 0x320 ++#define AI_OOBBINWIDTH 0x324 ++#define AI_OOBBOUTWIDTH 0x328 ++#define AI_OOBCEXTWIDTH 0x340 ++#define AI_OOBCINWIDTH 0x344 ++#define AI_OOBCOUTWIDTH 0x348 ++#define AI_OOBDEXTWIDTH 0x360 ++#define AI_OOBDINWIDTH 0x364 ++#define AI_OOBDOUTWIDTH 0x368 ++ ++ ++#define AI_IOCTRLSET 0x400 ++#define AI_IOCTRLCLEAR 0x404 ++#define AI_IOCTRL 0x408 ++#define AI_IOSTATUS 0x500 ++#define AI_RESETCTRL 0x800 ++#define AI_RESETSTATUS 0x804 ++ ++#define AI_IOCTRLWIDTH 0x700 ++#define AI_IOSTATUSWIDTH 0x704 ++ ++#define AI_RESETREADID 0x808 ++#define AI_RESETWRITEID 0x80c ++#define AI_ERRLOGCTRL 0xa00 ++#define AI_ERRLOGDONE 0xa04 ++#define AI_ERRLOGSTATUS 0xa08 ++#define AI_ERRLOGADDRLO 0xa0c ++#define AI_ERRLOGADDRHI 0xa10 ++#define AI_ERRLOGID 0xa14 ++#define AI_ERRLOGUSER 0xa18 ++#define AI_ERRLOGFLAGS 0xa1c ++#define AI_INTSTATUS 0xa00 ++#define AI_CONFIG 0xe00 ++#define AI_ITCR 0xf00 ++#define AI_ITIPOOBA 0xf10 ++#define AI_ITIPOOBB 0xf14 ++#define AI_ITIPOOBC 0xf18 ++#define AI_ITIPOOBD 0xf1c ++#define AI_ITIPOOBAOUT 0xf30 ++#define AI_ITIPOOBBOUT 0xf34 ++#define AI_ITIPOOBCOUT 0xf38 ++#define AI_ITIPOOBDOUT 0xf3c ++#define AI_ITOPOOBA 0xf50 ++#define AI_ITOPOOBB 0xf54 ++#define AI_ITOPOOBC 0xf58 ++#define AI_ITOPOOBD 0xf5c ++#define AI_ITOPOOBAIN 0xf70 ++#define AI_ITOPOOBBIN 0xf74 ++#define AI_ITOPOOBCIN 0xf78 ++#define AI_ITOPOOBDIN 0xf7c ++#define AI_ITOPRESET 0xf90 ++#define AI_PERIPHERIALID4 0xfd0 ++#define AI_PERIPHERIALID5 0xfd4 ++#define AI_PERIPHERIALID6 0xfd8 ++#define AI_PERIPHERIALID7 0xfdc ++#define AI_PERIPHERIALID0 0xfe0 ++#define AI_PERIPHERIALID1 0xfe4 ++#define AI_PERIPHERIALID2 0xfe8 ++#define AI_PERIPHERIALID3 0xfec ++#define AI_COMPONENTID0 0xff0 ++#define AI_COMPONENTID1 0xff4 ++#define AI_COMPONENTID2 0xff8 ++#define AI_COMPONENTID3 0xffc ++ ++/* resetctrl */ ++#define AIRC_RESET 1 ++ ++/* config */ ++#define AICFG_OOB 0x00000020 ++#define AICFG_IOS 0x00000010 ++#define AICFG_IOC 0x00000008 ++#define AICFG_TO 0x00000004 ++#define AICFG_ERRL 0x00000002 ++#define AICFG_RST 0x00000001 ++ ++/* bit defines for AI_OOBSELOUTB74 reg */ ++#define OOB_SEL_OUTEN_B_5 15 ++#define OOB_SEL_OUTEN_B_6 23 ++ ++#endif /* _AIDMP_H */ +diff --git a/drivers/net/wireless/ap6211/include/bcm_cfg.h b/drivers/net/wireless/ap6211/include/bcm_cfg.h +new file mode 100755 +index 0000000..ecff4f4 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcm_cfg.h +@@ -0,0 +1,29 @@ ++/* ++ * BCM common config options ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcm_cfg.h 294399 2011-11-07 03:31:22Z $ ++ */ ++ ++#ifndef _bcm_cfg_h_ ++#define _bcm_cfg_h_ ++#endif /* _bcm_cfg_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/bcm_mpool_pub.h b/drivers/net/wireless/ap6211/include/bcm_mpool_pub.h +new file mode 100755 +index 0000000..8fe3de7 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcm_mpool_pub.h +@@ -0,0 +1,361 @@ ++/* ++ * Memory pools library, Public interface ++ * ++ * API Overview ++ * ++ * This package provides a memory allocation subsystem based on pools of ++ * homogenous objects. ++ * ++ * Instrumentation is available for reporting memory utilization both ++ * on a per-data-structure basis and system wide. ++ * ++ * There are two main types defined in this API. ++ * ++ * pool manager: A singleton object that acts as a factory for ++ * pool allocators. It also is used for global ++ * instrumentation, such as reporting all blocks ++ * in use across all data structures. The pool manager ++ * creates and provides individual memory pools ++ * upon request to application code. ++ * ++ * memory pool: An object for allocating homogenous memory blocks. ++ * ++ * Global identifiers in this module use the following prefixes: ++ * bcm_mpm_* Memory pool manager ++ * bcm_mp_* Memory pool ++ * ++ * There are two main types of memory pools: ++ * ++ * prealloc: The contiguous memory block of objects can either be supplied ++ * by the client or malloc'ed by the memory manager. The objects are ++ * allocated out of a block of memory and freed back to the block. ++ * ++ * heap: The memory pool allocator uses the heap (malloc/free) for memory. ++ * In this case, the pool allocator is just providing statistics ++ * and instrumentation on top of the heap, without modifying the heap ++ * allocation implementation. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id$ ++ */ ++ ++#ifndef _BCM_MPOOL_PUB_H ++#define _BCM_MPOOL_PUB_H 1 ++ ++#include /* needed for uint16 */ ++ ++ ++/* ++************************************************************************** ++* ++* Type definitions, handles ++* ++************************************************************************** ++*/ ++ ++/* Forward declaration of OSL handle. */ ++struct osl_info; ++ ++/* Forward declaration of string buffer. */ ++struct bcmstrbuf; ++ ++/* ++ * Opaque type definition for the pool manager handle. This object is used for global ++ * memory pool operations such as obtaining a new pool, deleting a pool, iterating and ++ * instrumentation/debugging. ++ */ ++struct bcm_mpm_mgr; ++typedef struct bcm_mpm_mgr *bcm_mpm_mgr_h; ++ ++/* ++ * Opaque type definition for an instance of a pool. This handle is used for allocating ++ * and freeing memory through the pool, as well as management/instrumentation on this ++ * specific pool. ++ */ ++struct bcm_mp_pool; ++typedef struct bcm_mp_pool *bcm_mp_pool_h; ++ ++ ++/* ++ * To make instrumentation more readable, every memory ++ * pool must have a readable name. Pool names are up to ++ * 8 bytes including '\0' termination. (7 printable characters.) ++ */ ++#define BCM_MP_NAMELEN 8 ++ ++ ++/* ++ * Type definition for pool statistics. ++ */ ++typedef struct bcm_mp_stats { ++ char name[BCM_MP_NAMELEN]; /* Name of this pool. */ ++ unsigned int objsz; /* Object size allocated in this pool */ ++ uint16 nobj; /* Total number of objects in this pool */ ++ uint16 num_alloc; /* Number of objects currently allocated */ ++ uint16 high_water; /* Max number of allocated objects. */ ++ uint16 failed_alloc; /* Failed allocations. */ ++} bcm_mp_stats_t; ++ ++ ++/* ++************************************************************************** ++* ++* API Routines on the pool manager. ++* ++************************************************************************** ++*/ ++ ++/* ++ * bcm_mpm_init() - initialize the whole memory pool system. ++ * ++ * Parameters: ++ * osh: INPUT Operating system handle. Needed for heap memory allocation. ++ * max_pools: INPUT Maximum number of mempools supported. ++ * mgr: OUTPUT The handle is written with the new pools manager object/handle. ++ * ++ * Returns: ++ * BCME_OK Object initialized successfully. May be used. ++ * BCME_NOMEM Initialization failed due to no memory. Object must not be used. ++ */ ++int bcm_mpm_init(struct osl_info *osh, int max_pools, bcm_mpm_mgr_h *mgrp); ++ ++ ++/* ++ * bcm_mpm_deinit() - de-initialize the whole memory pool system. ++ * ++ * Parameters: ++ * mgr: INPUT Pointer to pool manager handle. ++ * ++ * Returns: ++ * BCME_OK Memory pool manager successfully de-initialized. ++ * other Indicated error occured during de-initialization. ++ */ ++int bcm_mpm_deinit(bcm_mpm_mgr_h *mgrp); ++ ++/* ++ * bcm_mpm_create_prealloc_pool() - Create a new pool for fixed size objects. The ++ * pool uses a contiguous block of pre-alloced ++ * memory. The memory block may either be provided ++ * by the client or dynamically allocated by the ++ * pool manager. ++ * ++ * Parameters: ++ * mgr: INPUT The handle to the pool manager ++ * obj_sz: INPUT Size of objects that will be allocated by the new pool ++ * Must be >= sizeof(void *). ++ * nobj: INPUT Maximum number of concurrently existing objects to support ++ * memstart INPUT Pointer to the memory to use, or NULL to malloc() ++ * memsize INPUT Number of bytes referenced from memstart (for error checking). ++ * Must be 0 if 'memstart' is NULL. ++ * poolname INPUT For instrumentation, the name of the pool ++ * newp: OUTPUT The handle for the new pool, if creation is successful ++ * ++ * Returns: ++ * BCME_OK Pool created ok. ++ * other Pool not created due to indicated error. newpoolp set to NULL. ++ * ++ * ++ */ ++int bcm_mpm_create_prealloc_pool(bcm_mpm_mgr_h mgr, ++ unsigned int obj_sz, ++ int nobj, ++ void *memstart, ++ unsigned int memsize, ++ char poolname[BCM_MP_NAMELEN], ++ bcm_mp_pool_h *newp); ++ ++ ++/* ++ * bcm_mpm_delete_prealloc_pool() - Delete a memory pool. This should only be called after ++ * all memory objects have been freed back to the pool. ++ * ++ * Parameters: ++ * mgr: INPUT The handle to the pools manager ++ * pool: INPUT The handle of the pool to delete ++ * ++ * Returns: ++ * BCME_OK Pool deleted ok. ++ * other Pool not deleted due to indicated error. ++ * ++ */ ++int bcm_mpm_delete_prealloc_pool(bcm_mpm_mgr_h mgr, bcm_mp_pool_h *poolp); ++ ++/* ++ * bcm_mpm_create_heap_pool() - Create a new pool for fixed size objects. The memory ++ * pool allocator uses the heap (malloc/free) for memory. ++ * In this case, the pool allocator is just providing ++ * statistics and instrumentation on top of the heap, ++ * without modifying the heap allocation implementation. ++ * ++ * Parameters: ++ * mgr: INPUT The handle to the pool manager ++ * obj_sz: INPUT Size of objects that will be allocated by the new pool ++ * poolname INPUT For instrumentation, the name of the pool ++ * newp: OUTPUT The handle for the new pool, if creation is successful ++ * ++ * Returns: ++ * BCME_OK Pool created ok. ++ * other Pool not created due to indicated error. newpoolp set to NULL. ++ * ++ * ++ */ ++int bcm_mpm_create_heap_pool(bcm_mpm_mgr_h mgr, unsigned int obj_sz, ++ char poolname[BCM_MP_NAMELEN], ++ bcm_mp_pool_h *newp); ++ ++ ++/* ++ * bcm_mpm_delete_heap_pool() - Delete a memory pool. This should only be called after ++ * all memory objects have been freed back to the pool. ++ * ++ * Parameters: ++ * mgr: INPUT The handle to the pools manager ++ * pool: INPUT The handle of the pool to delete ++ * ++ * Returns: ++ * BCME_OK Pool deleted ok. ++ * other Pool not deleted due to indicated error. ++ * ++ */ ++int bcm_mpm_delete_heap_pool(bcm_mpm_mgr_h mgr, bcm_mp_pool_h *poolp); ++ ++ ++/* ++ * bcm_mpm_stats() - Return stats for all pools ++ * ++ * Parameters: ++ * mgr: INPUT The handle to the pools manager ++ * stats: OUTPUT Array of pool statistics. ++ * nentries: MOD Max elements in 'stats' array on INPUT. Actual number ++ * of array elements copied to 'stats' on OUTPUT. ++ * ++ * Returns: ++ * BCME_OK Ok ++ * other Error getting stats. ++ * ++ */ ++int bcm_mpm_stats(bcm_mpm_mgr_h mgr, bcm_mp_stats_t *stats, int *nentries); ++ ++ ++/* ++ * bcm_mpm_dump() - Display statistics on all pools ++ * ++ * Parameters: ++ * mgr: INPUT The handle to the pools manager ++ * b: OUTPUT Output buffer. ++ * ++ * Returns: ++ * BCME_OK Ok ++ * other Error during dump. ++ * ++ */ ++int bcm_mpm_dump(bcm_mpm_mgr_h mgr, struct bcmstrbuf *b); ++ ++ ++/* ++ * bcm_mpm_get_obj_size() - The size of memory objects may need to be padded to ++ * compensate for alignment requirements of the objects. ++ * This function provides the padded object size. If clients ++ * pre-allocate a memory slab for a memory pool, the ++ * padded object size should be used by the client to allocate ++ * the memory slab (in order to provide sufficent space for ++ * the maximum number of objects). ++ * ++ * Parameters: ++ * mgr: INPUT The handle to the pools manager. ++ * obj_sz: INPUT Input object size. ++ * padded_obj_sz: OUTPUT Padded object size. ++ * ++ * Returns: ++ * BCME_OK Ok ++ * BCME_BADARG Bad arguments. ++ * ++ */ ++int bcm_mpm_get_obj_size(bcm_mpm_mgr_h mgr, unsigned int obj_sz, unsigned int *padded_obj_sz); ++ ++ ++/* ++*************************************************************************** ++* ++* API Routines on a specific pool. ++* ++*************************************************************************** ++*/ ++ ++ ++/* ++ * bcm_mp_alloc() - Allocate a memory pool object. ++ * ++ * Parameters: ++ * pool: INPUT The handle to the pool. ++ * ++ * Returns: ++ * A pointer to the new object. NULL on error. ++ * ++ */ ++void* bcm_mp_alloc(bcm_mp_pool_h pool); ++ ++/* ++ * bcm_mp_free() - Free a memory pool object. ++ * ++ * Parameters: ++ * pool: INPUT The handle to the pool. ++ * objp: INPUT A pointer to the object to free. ++ * ++ * Returns: ++ * BCME_OK Ok ++ * other Error during free. ++ * ++ */ ++int bcm_mp_free(bcm_mp_pool_h pool, void *objp); ++ ++/* ++ * bcm_mp_stats() - Return stats for this pool ++ * ++ * Parameters: ++ * pool: INPUT The handle to the pool ++ * stats: OUTPUT Pool statistics ++ * ++ * Returns: ++ * BCME_OK Ok ++ * other Error getting statistics. ++ * ++ */ ++int bcm_mp_stats(bcm_mp_pool_h pool, bcm_mp_stats_t *stats); ++ ++ ++/* ++ * bcm_mp_dump() - Dump a pool ++ * ++ * Parameters: ++ * pool: INPUT The handle to the pool ++ * b OUTPUT Output buffer ++ * ++ * Returns: ++ * BCME_OK Ok ++ * other Error during dump. ++ * ++ */ ++int bcm_mp_dump(bcm_mp_pool_h pool, struct bcmstrbuf *b); ++ ++ ++#endif /* _BCM_MPOOL_PUB_H */ +diff --git a/drivers/net/wireless/ap6211/include/bcmcdc.h b/drivers/net/wireless/ap6211/include/bcmcdc.h +new file mode 100755 +index 0000000..a1d1271 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcmcdc.h +@@ -0,0 +1,132 @@ ++/* ++ * CDC network driver ioctl/indication encoding ++ * Broadcom 802.11abg Networking Device Driver ++ * ++ * Definitions subject to change without notice. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmcdc.h 318308 2012-03-02 02:23:42Z $ ++ */ ++#ifndef _bcmcdc_h_ ++#define _bcmcdc_h_ ++#include ++ ++typedef struct cdc_ioctl { ++ uint32 cmd; /* ioctl command value */ ++ uint32 len; /* lower 16: output buflen; upper 16: input buflen (excludes header) */ ++ uint32 flags; /* flag defns given below */ ++ uint32 status; /* status code returned from the device */ ++} cdc_ioctl_t; ++ ++/* Max valid buffer size that can be sent to the dongle */ ++#define CDC_MAX_MSG_SIZE ETHER_MAX_LEN ++ ++/* len field is divided into input and output buffer lengths */ ++#define CDCL_IOC_OUTLEN_MASK 0x0000FFFF /* maximum or expected response length, */ ++ /* excluding IOCTL header */ ++#define CDCL_IOC_OUTLEN_SHIFT 0 ++#define CDCL_IOC_INLEN_MASK 0xFFFF0000 /* input buffer length, excluding IOCTL header */ ++#define CDCL_IOC_INLEN_SHIFT 16 ++ ++/* CDC flag definitions */ ++#define CDCF_IOC_ERROR 0x01 /* 0=success, 1=ioctl cmd failed */ ++#define CDCF_IOC_SET 0x02 /* 0=get, 1=set cmd */ ++#define CDCF_IOC_OVL_IDX_MASK 0x3c /* overlay region index mask */ ++#define CDCF_IOC_OVL_RSV 0x40 /* 1=reserve this overlay region */ ++#define CDCF_IOC_OVL 0x80 /* 1=this ioctl corresponds to an overlay */ ++#define CDCF_IOC_ACTION_MASK 0xfe /* SET/GET, OVL_IDX, OVL_RSV, OVL mask */ ++#define CDCF_IOC_ACTION_SHIFT 1 /* SET/GET, OVL_IDX, OVL_RSV, OVL shift */ ++#define CDCF_IOC_IF_MASK 0xF000 /* I/F index */ ++#define CDCF_IOC_IF_SHIFT 12 ++#define CDCF_IOC_ID_MASK 0xFFFF0000 /* used to uniquely id an ioctl req/resp pairing */ ++#define CDCF_IOC_ID_SHIFT 16 /* # of bits of shift for ID Mask */ ++ ++#define CDC_IOC_IF_IDX(flags) (((flags) & CDCF_IOC_IF_MASK) >> CDCF_IOC_IF_SHIFT) ++#define CDC_IOC_ID(flags) (((flags) & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT) ++ ++#define CDC_GET_IF_IDX(hdr) \ ++ ((int)((((hdr)->flags) & CDCF_IOC_IF_MASK) >> CDCF_IOC_IF_SHIFT)) ++#define CDC_SET_IF_IDX(hdr, idx) \ ++ ((hdr)->flags = (((hdr)->flags & ~CDCF_IOC_IF_MASK) | ((idx) << CDCF_IOC_IF_SHIFT))) ++ ++/* ++ * BDC header ++ * ++ * The BDC header is used on data packets to convey priority across USB. ++ */ ++ ++struct bdc_header { ++ uint8 flags; /* Flags */ ++ uint8 priority; /* 802.1d Priority 0:2 bits, 4:7 USB flow control info */ ++ uint8 flags2; ++ uint8 dataOffset; /* Offset from end of BDC header to packet data, in ++ * 4-byte words. Leaves room for optional headers. ++ */ ++}; ++ ++#define BDC_HEADER_LEN 4 ++ ++/* flags field bitmap */ ++#define BDC_FLAG_80211_PKT 0x01 /* Packet is in 802.11 format (dongle -> host) */ ++#define BDC_FLAG_SUM_GOOD 0x04 /* Dongle has verified good RX checksums */ ++#define BDC_FLAG_SUM_NEEDED 0x08 /* Dongle needs to do TX checksums: host->device */ ++#define BDC_FLAG_EVENT_MSG 0x08 /* Payload contains an event msg: device->host */ ++#define BDC_FLAG_VER_MASK 0xf0 /* Protocol version mask */ ++#define BDC_FLAG_VER_SHIFT 4 /* Protocol version shift */ ++ ++/* priority field bitmap */ ++#define BDC_PRIORITY_MASK 0x07 ++#define BDC_PRIORITY_FC_MASK 0xf0 /* flow control info mask */ ++#define BDC_PRIORITY_FC_SHIFT 4 /* flow control info shift */ ++ ++/* flags2 field bitmap */ ++#define BDC_FLAG2_IF_MASK 0x0f /* interface index (host <-> dongle) */ ++#define BDC_FLAG2_IF_SHIFT 0 ++#define BDC_FLAG2_FC_FLAG 0x10 /* flag to indicate if pkt contains */ ++ /* FLOW CONTROL info only */ ++ ++/* version numbers */ ++#define BDC_PROTO_VER_1 1 /* Old Protocol version */ ++#define BDC_PROTO_VER 2 /* Protocol version */ ++ ++/* flags2.if field access macros */ ++#define BDC_GET_IF_IDX(hdr) \ ++ ((int)((((hdr)->flags2) & BDC_FLAG2_IF_MASK) >> BDC_FLAG2_IF_SHIFT)) ++#define BDC_SET_IF_IDX(hdr, idx) \ ++ ((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_IF_MASK) | ((idx) << BDC_FLAG2_IF_SHIFT))) ++ ++#define BDC_FLAG2_PAD_MASK 0xf0 ++#define BDC_FLAG_PAD_MASK 0x03 ++#define BDC_FLAG2_PAD_SHIFT 2 ++#define BDC_FLAG_PAD_SHIFT 0 ++#define BDC_FLAG2_PAD_IDX 0x3c ++#define BDC_FLAG_PAD_IDX 0x03 ++#define BDC_GET_PAD_LEN(hdr) \ ++ ((int)(((((hdr)->flags2) & BDC_FLAG2_PAD_MASK) >> BDC_FLAG2_PAD_SHIFT) | \ ++ ((((hdr)->flags) & BDC_FLAG_PAD_MASK) >> BDC_FLAG_PAD_SHIFT))) ++#define BDC_SET_PAD_LEN(hdr, idx) \ ++ ((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_PAD_MASK) | \ ++ (((idx) & BDC_FLAG2_PAD_IDX) << BDC_FLAG2_PAD_SHIFT))); \ ++ ((hdr)->flags = (((hdr)->flags & ~BDC_FLAG_PAD_MASK) | \ ++ (((idx) & BDC_FLAG_PAD_IDX) << BDC_FLAG_PAD_SHIFT))) ++ ++#endif /* _bcmcdc_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/bcmdefs.h b/drivers/net/wireless/ap6211/include/bcmdefs.h +new file mode 100755 +index 0000000..00906e3 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcmdefs.h +@@ -0,0 +1,270 @@ ++/* ++ * Misc system wide definitions ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmdefs.h 316830 2012-02-23 20:29:22Z $ ++ */ ++ ++#ifndef _bcmdefs_h_ ++#define _bcmdefs_h_ ++ ++/* ++ * One doesn't need to include this file explicitly, gets included automatically if ++ * typedefs.h is included. ++ */ ++ ++/* Use BCM_REFERENCE to suppress warnings about intentionally-unused function ++ * arguments or local variables. ++ */ ++#define BCM_REFERENCE(data) ((void)(data)) ++ ++/* Compile-time assert can be used in place of ASSERT if the expression evaluates ++ * to a constant at compile time. ++ */ ++#define STATIC_ASSERT(expr) { \ ++ /* Make sure the expression is constant. */ \ ++ typedef enum { _STATIC_ASSERT_NOT_CONSTANT = (expr) } _static_assert_e; \ ++ /* Make sure the expression is true. */ \ ++ typedef char STATIC_ASSERT_FAIL[(expr) ? 1 : -1]; \ ++} ++ ++/* Reclaiming text and data : ++ * The following macros specify special linker sections that can be reclaimed ++ * after a system is considered 'up'. ++ * BCMATTACHFN is also used for detach functions (it's not worth having a BCMDETACHFN, ++ * as in most cases, the attach function calls the detach function to clean up on error). ++ */ ++ ++#define bcmreclaimed 0 ++#define _data _data ++#define _fn _fn ++#define BCMPREATTACHDATA(_data) _data ++#define BCMPREATTACHFN(_fn) _fn ++#define _data _data ++#define _fn _fn ++#define _fn _fn ++#define BCMNMIATTACHFN(_fn) _fn ++#define BCMNMIATTACHDATA(_data) _data ++#define CONST const ++#ifndef BCMFASTPATH ++#define BCMFASTPATH ++#define BCMFASTPATH_HOST ++#endif /* BCMFASTPATH */ ++ ++ ++/* Put some library data/code into ROM to reduce RAM requirements */ ++#define _data _data ++#define BCMROMDAT_NAME(_data) _data ++#define _fn _fn ++#define _fn _fn ++#define STATIC static ++#define BCMROMDAT_ARYSIZ(data) ARRAYSIZE(data) ++#define BCMROMDAT_SIZEOF(data) sizeof(data) ++#define BCMROMDAT_APATCH(data) ++#define BCMROMDAT_SPATCH(data) ++ ++/* Bus types */ ++#define SI_BUS 0 /* SOC Interconnect */ ++#define PCI_BUS 1 /* PCI target */ ++#define PCMCIA_BUS 2 /* PCMCIA target */ ++#define SDIO_BUS 3 /* SDIO target */ ++#define JTAG_BUS 4 /* JTAG */ ++#define USB_BUS 5 /* USB (does not support R/W REG) */ ++#define SPI_BUS 6 /* gSPI target */ ++#define RPC_BUS 7 /* RPC target */ ++ ++/* Allows size optimization for single-bus image */ ++#ifdef BCMBUSTYPE ++#define BUSTYPE(bus) (BCMBUSTYPE) ++#else ++#define BUSTYPE(bus) (bus) ++#endif ++ ++/* Allows size optimization for single-backplane image */ ++#ifdef BCMCHIPTYPE ++#define CHIPTYPE(bus) (BCMCHIPTYPE) ++#else ++#define CHIPTYPE(bus) (bus) ++#endif ++ ++ ++/* Allows size optimization for SPROM support */ ++#if defined(BCMSPROMBUS) ++#define SPROMBUS (BCMSPROMBUS) ++#elif defined(SI_PCMCIA_SROM) ++#define SPROMBUS (PCMCIA_BUS) ++#else ++#define SPROMBUS (PCI_BUS) ++#endif ++ ++/* Allows size optimization for single-chip image */ ++#ifdef BCMCHIPID ++#define CHIPID(chip) (BCMCHIPID) ++#else ++#define CHIPID(chip) (chip) ++#endif ++ ++#ifdef BCMCHIPREV ++#define CHIPREV(rev) (BCMCHIPREV) ++#else ++#define CHIPREV(rev) (rev) ++#endif ++ ++/* Defines for DMA Address Width - Shared between OSL and HNDDMA */ ++#define DMADDR_MASK_32 0x0 /* Address mask for 32-bits */ ++#define DMADDR_MASK_30 0xc0000000 /* Address mask for 30-bits */ ++#define DMADDR_MASK_0 0xffffffff /* Address mask for 0-bits (hi-part) */ ++ ++#define DMADDRWIDTH_30 30 /* 30-bit addressing capability */ ++#define DMADDRWIDTH_32 32 /* 32-bit addressing capability */ ++#define DMADDRWIDTH_63 63 /* 64-bit addressing capability */ ++#define DMADDRWIDTH_64 64 /* 64-bit addressing capability */ ++ ++#ifdef BCMDMA64OSL ++typedef struct { ++ uint32 loaddr; ++ uint32 hiaddr; ++} dma64addr_t; ++ ++typedef dma64addr_t dmaaddr_t; ++#define PHYSADDRHI(_pa) ((_pa).hiaddr) ++#define PHYSADDRHISET(_pa, _val) \ ++ do { \ ++ (_pa).hiaddr = (_val); \ ++ } while (0) ++#define PHYSADDRLO(_pa) ((_pa).loaddr) ++#define PHYSADDRLOSET(_pa, _val) \ ++ do { \ ++ (_pa).loaddr = (_val); \ ++ } while (0) ++ ++#else ++typedef unsigned long dmaaddr_t; ++#define PHYSADDRHI(_pa) (0) ++#define PHYSADDRHISET(_pa, _val) ++#define PHYSADDRLO(_pa) ((_pa)) ++#define PHYSADDRLOSET(_pa, _val) \ ++ do { \ ++ (_pa) = (_val); \ ++ } while (0) ++#endif /* BCMDMA64OSL */ ++ ++/* One physical DMA segment */ ++typedef struct { ++ dmaaddr_t addr; ++ uint32 length; ++} hnddma_seg_t; ++ ++#define MAX_DMA_SEGS 4 ++ ++ ++typedef struct { ++ void *oshdmah; /* Opaque handle for OSL to store its information */ ++ uint origsize; /* Size of the virtual packet */ ++ uint nsegs; ++ hnddma_seg_t segs[MAX_DMA_SEGS]; ++} hnddma_seg_map_t; ++ ++ ++/* packet headroom necessary to accommodate the largest header in the system, (i.e TXOFF). ++ * By doing, we avoid the need to allocate an extra buffer for the header when bridging to WL. ++ * There is a compile time check in wlc.c which ensure that this value is at least as big ++ * as TXOFF. This value is used in dma_rxfill (hnddma.c). ++ */ ++ ++#if defined(BCM_RPC_NOCOPY) || defined(BCM_RCP_TXNOCOPY) ++/* add 40 bytes to allow for extra RPC header and info */ ++#define BCMEXTRAHDROOM 220 ++#else /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY */ ++#define BCMEXTRAHDROOM 172 ++#endif /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY */ ++ ++/* Packet alignment for most efficient SDIO (can change based on platform) */ ++#ifndef SDALIGN ++#define SDALIGN 32 ++#endif ++ ++/* Headroom required for dongle-to-host communication. Packets allocated ++ * locally in the dongle (e.g. for CDC ioctls or RNDIS messages) should ++ * leave this much room in front for low-level message headers which may ++ * be needed to get across the dongle bus to the host. (These messages ++ * don't go over the network, so room for the full WL header above would ++ * be a waste.). ++*/ ++#define BCMDONGLEHDRSZ 12 ++#define BCMDONGLEPADSZ 16 ++ ++#define BCMDONGLEOVERHEAD (BCMDONGLEHDRSZ + BCMDONGLEPADSZ) ++ ++ ++#if defined(NO_BCMDBG_ASSERT) ++# undef BCMDBG_ASSERT ++# undef BCMASSERT_LOG ++#endif ++ ++#if defined(BCMASSERT_LOG) ++#define BCMASSERT_SUPPORT ++#endif ++ ++/* Macros for doing definition and get/set of bitfields ++ * Usage example, e.g. a three-bit field (bits 4-6): ++ * #define _M BITFIELD_MASK(3) ++ * #define _S 4 ++ * ... ++ * regval = R_REG(osh, ®s->regfoo); ++ * field = GFIELD(regval, ); ++ * regval = SFIELD(regval, , 1); ++ * W_REG(osh, ®s->regfoo, regval); ++ */ ++#define BITFIELD_MASK(width) \ ++ (((unsigned)1 << (width)) - 1) ++#define GFIELD(val, field) \ ++ (((val) >> field ## _S) & field ## _M) ++#define SFIELD(val, field, bits) \ ++ (((val) & (~(field ## _M << field ## _S))) | \ ++ ((unsigned)(bits) << field ## _S)) ++ ++/* define BCMSMALL to remove misc features for memory-constrained environments */ ++#ifdef BCMSMALL ++#undef BCMSPACE ++#define bcmspace FALSE /* if (bcmspace) code is discarded */ ++#else ++#define BCMSPACE ++#define bcmspace TRUE /* if (bcmspace) code is retained */ ++#endif ++ ++/* Max. nvram variable table size */ ++#define MAXSZ_NVRAM_VARS 4096 ++ ++ ++/* Max size for reclaimable NVRAM array */ ++#ifdef DL_NVRAM ++#define NVRAM_ARRAY_MAXSIZE DL_NVRAM ++#else ++#define NVRAM_ARRAY_MAXSIZE MAXSZ_NVRAM_VARS ++#endif /* DL_NVRAM */ ++ ++#ifdef BCMUSBDEV_ENABLED ++extern uint32 gFWID; ++#endif ++ ++#endif /* _bcmdefs_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/bcmdevs.h b/drivers/net/wireless/ap6211/include/bcmdevs.h +new file mode 100755 +index 0000000..c3dd89f +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcmdevs.h +@@ -0,0 +1,503 @@ ++/* ++ * Broadcom device-specific manifest constants. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmdevs.h 329854 2012-04-27 01:42:28Z $ ++ */ ++ ++#ifndef _BCMDEVS_H ++#define _BCMDEVS_H ++ ++/* PCI vendor IDs */ ++#define VENDOR_EPIGRAM 0xfeda ++#define VENDOR_BROADCOM 0x14e4 ++#define VENDOR_3COM 0x10b7 ++#define VENDOR_NETGEAR 0x1385 ++#define VENDOR_DIAMOND 0x1092 ++#define VENDOR_INTEL 0x8086 ++#define VENDOR_DELL 0x1028 ++#define VENDOR_HP 0x103c ++#define VENDOR_HP_COMPAQ 0x0e11 ++#define VENDOR_APPLE 0x106b ++#define VENDOR_SI_IMAGE 0x1095 /* Silicon Image, used by Arasan SDIO Host */ ++#define VENDOR_BUFFALO 0x1154 /* Buffalo vendor id */ ++#define VENDOR_TI 0x104c /* Texas Instruments */ ++#define VENDOR_RICOH 0x1180 /* Ricoh */ ++#define VENDOR_JMICRON 0x197b ++ ++ ++/* PCMCIA vendor IDs */ ++#define VENDOR_BROADCOM_PCMCIA 0x02d0 ++ ++/* SDIO vendor IDs */ ++#define VENDOR_BROADCOM_SDIO 0x00BF ++ ++/* DONGLE VID/PIDs */ ++#define BCM_DNGL_VID 0x0a5c ++#define BCM_DNGL_BL_PID_4328 0xbd12 ++#define BCM_DNGL_BL_PID_4322 0xbd13 ++#define BCM_DNGL_BL_PID_4319 0xbd16 ++#define BCM_DNGL_BL_PID_43236 0xbd17 ++#define BCM_DNGL_BL_PID_4332 0xbd18 ++#define BCM_DNGL_BL_PID_4330 0xbd19 ++#define BCM_DNGL_BL_PID_4334 0xbd1a ++#define BCM_DNGL_BL_PID_43239 0xbd1b ++#define BCM_DNGL_BL_PID_4324 0xbd1c ++#define BCM_DNGL_BL_PID_4360 0xbd1d ++ ++#define BCM_DNGL_BDC_PID 0x0bdc ++#define BCM_DNGL_JTAG_PID 0x4a44 ++ ++/* HW USB BLOCK [CPULESS USB] PIDs */ ++#define BCM_HWUSB_PID_43239 43239 ++ ++/* PCI Device IDs */ ++#define BCM4210_DEVICE_ID 0x1072 /* never used */ ++#define BCM4230_DEVICE_ID 0x1086 /* never used */ ++#define BCM4401_ENET_ID 0x170c /* 4401b0 production enet cards */ ++#define BCM3352_DEVICE_ID 0x3352 /* bcm3352 device id */ ++#define BCM3360_DEVICE_ID 0x3360 /* bcm3360 device id */ ++#define BCM4211_DEVICE_ID 0x4211 ++#define BCM4231_DEVICE_ID 0x4231 ++#define BCM4303_D11B_ID 0x4303 /* 4303 802.11b */ ++#define BCM4311_D11G_ID 0x4311 /* 4311 802.11b/g id */ ++#define BCM4311_D11DUAL_ID 0x4312 /* 4311 802.11a/b/g id */ ++#define BCM4311_D11A_ID 0x4313 /* 4311 802.11a id */ ++#define BCM4328_D11DUAL_ID 0x4314 /* 4328/4312 802.11a/g id */ ++#define BCM4328_D11G_ID 0x4315 /* 4328/4312 802.11g id */ ++#define BCM4328_D11A_ID 0x4316 /* 4328/4312 802.11a id */ ++#define BCM4318_D11G_ID 0x4318 /* 4318 802.11b/g id */ ++#define BCM4318_D11DUAL_ID 0x4319 /* 4318 802.11a/b/g id */ ++#define BCM4318_D11A_ID 0x431a /* 4318 802.11a id */ ++#define BCM4325_D11DUAL_ID 0x431b /* 4325 802.11a/g id */ ++#define BCM4325_D11G_ID 0x431c /* 4325 802.11g id */ ++#define BCM4325_D11A_ID 0x431d /* 4325 802.11a id */ ++#define BCM4306_D11G_ID 0x4320 /* 4306 802.11g */ ++#define BCM4306_D11A_ID 0x4321 /* 4306 802.11a */ ++#define BCM4306_UART_ID 0x4322 /* 4306 uart */ ++#define BCM4306_V90_ID 0x4323 /* 4306 v90 codec */ ++#define BCM4306_D11DUAL_ID 0x4324 /* 4306 dual A+B */ ++#define BCM4306_D11G_ID2 0x4325 /* BCM4306_D11G_ID; INF w/loose binding war */ ++#define BCM4321_D11N_ID 0x4328 /* 4321 802.11n dualband id */ ++#define BCM4321_D11N2G_ID 0x4329 /* 4321 802.11n 2.4Ghz band id */ ++#define BCM4321_D11N5G_ID 0x432a /* 4321 802.11n 5Ghz band id */ ++#define BCM4322_D11N_ID 0x432b /* 4322 802.11n dualband device */ ++#define BCM4322_D11N2G_ID 0x432c /* 4322 802.11n 2.4GHz device */ ++#define BCM4322_D11N5G_ID 0x432d /* 4322 802.11n 5GHz device */ ++#define BCM4329_D11N_ID 0x432e /* 4329 802.11n dualband device */ ++#define BCM4329_D11N2G_ID 0x432f /* 4329 802.11n 2.4G device */ ++#define BCM4329_D11N5G_ID 0x4330 /* 4329 802.11n 5G device */ ++#define BCM4315_D11DUAL_ID 0x4334 /* 4315 802.11a/g id */ ++#define BCM4315_D11G_ID 0x4335 /* 4315 802.11g id */ ++#define BCM4315_D11A_ID 0x4336 /* 4315 802.11a id */ ++#define BCM4319_D11N_ID 0x4337 /* 4319 802.11n dualband device */ ++#define BCM4319_D11N2G_ID 0x4338 /* 4319 802.11n 2.4G device */ ++#define BCM4319_D11N5G_ID 0x4339 /* 4319 802.11n 5G device */ ++#define BCM43231_D11N2G_ID 0x4340 /* 43231 802.11n 2.4GHz device */ ++#define BCM43221_D11N2G_ID 0x4341 /* 43221 802.11n 2.4GHz device */ ++#define BCM43222_D11N_ID 0x4350 /* 43222 802.11n dualband device */ ++#define BCM43222_D11N2G_ID 0x4351 /* 43222 802.11n 2.4GHz device */ ++#define BCM43222_D11N5G_ID 0x4352 /* 43222 802.11n 5GHz device */ ++#define BCM43224_D11N_ID 0x4353 /* 43224 802.11n dualband device */ ++#define BCM43224_D11N_ID_VEN1 0x0576 /* Vendor specific 43224 802.11n db device */ ++#define BCM43226_D11N_ID 0x4354 /* 43226 802.11n dualband device */ ++#define BCM43236_D11N_ID 0x4346 /* 43236 802.11n dualband device */ ++#define BCM43236_D11N2G_ID 0x4347 /* 43236 802.11n 2.4GHz device */ ++#define BCM43236_D11N5G_ID 0x4348 /* 43236 802.11n 5GHz device */ ++#define BCM43225_D11N2G_ID 0x4357 /* 43225 802.11n 2.4GHz device */ ++#define BCM43421_D11N_ID 0xA99D /* 43421 802.11n dualband device */ ++#define BCM4313_D11N2G_ID 0x4727 /* 4313 802.11n 2.4G device */ ++#define BCM4330_D11N_ID 0x4360 /* 4330 802.11n dualband device */ ++#define BCM4330_D11N2G_ID 0x4361 /* 4330 802.11n 2.4G device */ ++#define BCM4330_D11N5G_ID 0x4362 /* 4330 802.11n 5G device */ ++#define BCM4336_D11N_ID 0x4343 /* 4336 802.11n 2.4GHz device */ ++#define BCM6362_D11N_ID 0x435f /* 6362 802.11n dualband device */ ++#define BCM4331_D11N_ID 0x4331 /* 4331 802.11n dualband id */ ++#define BCM4331_D11N2G_ID 0x4332 /* 4331 802.11n 2.4Ghz band id */ ++#define BCM4331_D11N5G_ID 0x4333 /* 4331 802.11n 5Ghz band id */ ++#define BCM43237_D11N_ID 0x4355 /* 43237 802.11n dualband device */ ++#define BCM43237_D11N5G_ID 0x4356 /* 43237 802.11n 5GHz device */ ++#define BCM43227_D11N2G_ID 0x4358 /* 43228 802.11n 2.4GHz device */ ++#define BCM43228_D11N_ID 0x4359 /* 43228 802.11n DualBand device */ ++#define BCM43228_D11N5G_ID 0x435a /* 43228 802.11n 5GHz device */ ++#define BCM43362_D11N_ID 0x4363 /* 43362 802.11n 2.4GHz device */ ++#define BCM43239_D11N_ID 0x4370 /* 43239 802.11n dualband device */ ++#define BCM4324_D11N_ID 0x4374 /* 4324 802.11n dualband device */ ++#define BCM43217_D11N2G_ID 0x43a9 /* 43217 802.11n 2.4GHz device */ ++#define BCM43131_D11N2G_ID 0x43aa /* 43131 802.11n 2.4GHz device */ ++#define BCM4314_D11N2G_ID 0x4364 /* 4314 802.11n 2.4G device */ ++#define BCM43142_D11N2G_ID 0x4365 /* 43142 802.11n 2.4G device */ ++#define BCM4334_D11N_ID 0x4380 /* 4334 802.11n dualband device */ ++#define BCM4334_D11N2G_ID 0x4381 /* 4334 802.11n 2.4G device */ ++#define BCM4334_D11N5G_ID 0x4382 /* 4334 802.11n 5G device */ ++#define BCM43341_D11N_ID 0x4386 /* 43341 802.11n dualband device */ ++#define BCM43341_D11N2G_ID 0x4387 /* 43341 802.11n 2.4G device */ ++#define BCM43341_D11N5G_ID 0x4388 /* 43341 802.11n 5G device */ ++#define BCM4360_D11AC_ID 0x43a0 ++#define BCM4360_D11AC2G_ID 0x43a1 ++#define BCM4360_D11AC5G_ID 0x43a2 ++ ++/* PCI Subsystem ID */ ++#define BCM943228HMB_SSID_VEN1 0x0607 ++#define BCM94313HMGBL_SSID_VEN1 0x0608 ++#define BCM94313HMG_SSID_VEN1 0x0609 ++ ++ ++#define BCM4335_D11AC_ID 0x43ae ++#define BCM4335_D11AC2G_ID 0x43af ++#define BCM4335_D11AC5G_ID 0x43b0 ++#define BCM4352_D11AC_ID 0x43b1 /* 4352 802.11ac dualband device */ ++#define BCM4352_D11AC2G_ID 0x43b2 /* 4352 802.11ac 2.4G device */ ++#define BCM4352_D11AC5G_ID 0x43b3 /* 4352 802.11ac 5G device */ ++ ++#define BCMGPRS_UART_ID 0x4333 /* Uart id used by 4306/gprs card */ ++#define BCMGPRS2_UART_ID 0x4344 /* Uart id used by 4306/gprs card */ ++#define FPGA_JTAGM_ID 0x43f0 /* FPGA jtagm device id */ ++#define BCM_JTAGM_ID 0x43f1 /* BCM jtagm device id */ ++#define SDIOH_FPGA_ID 0x43f2 /* sdio host fpga */ ++#define BCM_SDIOH_ID 0x43f3 /* BCM sdio host id */ ++#define SDIOD_FPGA_ID 0x43f4 /* sdio device fpga */ ++#define SPIH_FPGA_ID 0x43f5 /* PCI SPI Host Controller FPGA */ ++#define BCM_SPIH_ID 0x43f6 /* Synopsis SPI Host Controller */ ++#define MIMO_FPGA_ID 0x43f8 /* FPGA mimo minimacphy device id */ ++#define BCM_JTAGM2_ID 0x43f9 /* BCM alternate jtagm device id */ ++#define SDHCI_FPGA_ID 0x43fa /* Standard SDIO Host Controller FPGA */ ++#define BCM4402_ENET_ID 0x4402 /* 4402 enet */ ++#define BCM4402_V90_ID 0x4403 /* 4402 v90 codec */ ++#define BCM4410_DEVICE_ID 0x4410 /* bcm44xx family pci iline */ ++#define BCM4412_DEVICE_ID 0x4412 /* bcm44xx family pci enet */ ++#define BCM4430_DEVICE_ID 0x4430 /* bcm44xx family cardbus iline */ ++#define BCM4432_DEVICE_ID 0x4432 /* bcm44xx family cardbus enet */ ++#define BCM4704_ENET_ID 0x4706 /* 4704 enet (Use 47XX_ENET_ID instead!) */ ++#define BCM4710_DEVICE_ID 0x4710 /* 4710 primary function 0 */ ++#define BCM47XX_AUDIO_ID 0x4711 /* 47xx audio codec */ ++#define BCM47XX_V90_ID 0x4712 /* 47xx v90 codec */ ++#define BCM47XX_ENET_ID 0x4713 /* 47xx enet */ ++#define BCM47XX_EXT_ID 0x4714 /* 47xx external i/f */ ++#define BCM47XX_GMAC_ID 0x4715 /* 47xx Unimac based GbE */ ++#define BCM47XX_USBH_ID 0x4716 /* 47xx usb host */ ++#define BCM47XX_USBD_ID 0x4717 /* 47xx usb device */ ++#define BCM47XX_IPSEC_ID 0x4718 /* 47xx ipsec */ ++#define BCM47XX_ROBO_ID 0x4719 /* 47xx/53xx roboswitch core */ ++#define BCM47XX_USB20H_ID 0x471a /* 47xx usb 2.0 host */ ++#define BCM47XX_USB20D_ID 0x471b /* 47xx usb 2.0 device */ ++#define BCM47XX_ATA100_ID 0x471d /* 47xx parallel ATA */ ++#define BCM47XX_SATAXOR_ID 0x471e /* 47xx serial ATA & XOR DMA */ ++#define BCM47XX_GIGETH_ID 0x471f /* 47xx GbE (5700) */ ++#define BCM4712_MIPS_ID 0x4720 /* 4712 base devid */ ++#define BCM4716_DEVICE_ID 0x4722 /* 4716 base devid */ ++#define BCM47XX_SMBUS_EMU_ID 0x47fe /* 47xx emulated SMBus device */ ++#define BCM47XX_XOR_EMU_ID 0x47ff /* 47xx emulated XOR engine */ ++#define EPI41210_DEVICE_ID 0xa0fa /* bcm4210 */ ++#define EPI41230_DEVICE_ID 0xa10e /* bcm4230 */ ++#define JINVANI_SDIOH_ID 0x4743 /* Jinvani SDIO Gold Host */ ++#define BCM27XX_SDIOH_ID 0x2702 /* BCM27xx Standard SDIO Host */ ++#define PCIXX21_FLASHMEDIA_ID 0x803b /* TI PCI xx21 Standard Host Controller */ ++#define PCIXX21_SDIOH_ID 0x803c /* TI PCI xx21 Standard Host Controller */ ++#define R5C822_SDIOH_ID 0x0822 /* Ricoh Co Ltd R5C822 SD/SDIO/MMC/MS/MSPro Host */ ++#define JMICRON_SDIOH_ID 0x2381 /* JMicron Standard SDIO Host Controller */ ++ ++/* Chip IDs */ ++#define BCM4306_CHIP_ID 0x4306 /* 4306 chipcommon chipid */ ++#define BCM4311_CHIP_ID 0x4311 /* 4311 PCIe 802.11a/b/g */ ++#define BCM43111_CHIP_ID 43111 /* 43111 chipcommon chipid (OTP chipid) */ ++#define BCM43112_CHIP_ID 43112 /* 43112 chipcommon chipid (OTP chipid) */ ++#define BCM4312_CHIP_ID 0x4312 /* 4312 chipcommon chipid */ ++#define BCM4313_CHIP_ID 0x4313 /* 4313 chip id */ ++#define BCM43131_CHIP_ID 43131 /* 43131 chip id (OTP chipid) */ ++#define BCM4315_CHIP_ID 0x4315 /* 4315 chip id */ ++#define BCM4318_CHIP_ID 0x4318 /* 4318 chipcommon chipid */ ++#define BCM4319_CHIP_ID 0x4319 /* 4319 chip id */ ++#define BCM4320_CHIP_ID 0x4320 /* 4320 chipcommon chipid */ ++#define BCM4321_CHIP_ID 0x4321 /* 4321 chipcommon chipid */ ++#define BCM43217_CHIP_ID 43217 /* 43217 chip id (OTP chipid) */ ++#define BCM4322_CHIP_ID 0x4322 /* 4322 chipcommon chipid */ ++#define BCM43221_CHIP_ID 43221 /* 43221 chipcommon chipid (OTP chipid) */ ++#define BCM43222_CHIP_ID 43222 /* 43222 chipcommon chipid */ ++#define BCM43224_CHIP_ID 43224 /* 43224 chipcommon chipid */ ++#define BCM43225_CHIP_ID 43225 /* 43225 chipcommon chipid */ ++#define BCM43227_CHIP_ID 43227 /* 43227 chipcommon chipid */ ++#define BCM43228_CHIP_ID 43228 /* 43228 chipcommon chipid */ ++#define BCM43226_CHIP_ID 43226 /* 43226 chipcommon chipid */ ++#define BCM43231_CHIP_ID 43231 /* 43231 chipcommon chipid (OTP chipid) */ ++#define BCM43234_CHIP_ID 43234 /* 43234 chipcommon chipid */ ++#define BCM43235_CHIP_ID 43235 /* 43235 chipcommon chipid */ ++#define BCM43236_CHIP_ID 43236 /* 43236 chipcommon chipid */ ++#define BCM43237_CHIP_ID 43237 /* 43237 chipcommon chipid */ ++#define BCM43238_CHIP_ID 43238 /* 43238 chipcommon chipid */ ++#define BCM43239_CHIP_ID 43239 /* 43239 chipcommon chipid */ ++#define BCM43420_CHIP_ID 43420 /* 43222 chipcommon chipid (OTP, RBBU) */ ++#define BCM43421_CHIP_ID 43421 /* 43224 chipcommon chipid (OTP, RBBU) */ ++#define BCM43428_CHIP_ID 43428 /* 43228 chipcommon chipid (OTP, RBBU) */ ++#define BCM43431_CHIP_ID 43431 /* 4331 chipcommon chipid (OTP, RBBU) */ ++#define BCM43460_CHIP_ID 43460 /* 4360 chipcommon chipid (OTP, RBBU) */ ++#define BCM4325_CHIP_ID 0x4325 /* 4325 chip id */ ++#define BCM4328_CHIP_ID 0x4328 /* 4328 chip id */ ++#define BCM4329_CHIP_ID 0x4329 /* 4329 chipcommon chipid */ ++#define BCM4331_CHIP_ID 0x4331 /* 4331 chipcommon chipid */ ++#define BCM4336_CHIP_ID 0x4336 /* 4336 chipcommon chipid */ ++#define BCM43362_CHIP_ID 43362 /* 43362 chipcommon chipid */ ++#define BCM4330_CHIP_ID 0x4330 /* 4330 chipcommon chipid */ ++#define BCM6362_CHIP_ID 0x6362 /* 6362 chipcommon chipid */ ++#define BCM4314_CHIP_ID 0x4314 /* 4314 chipcommon chipid */ ++#define BCM43142_CHIP_ID 43142 /* 43142 chipcommon chipid */ ++#define BCM4324_CHIP_ID 0x4324 /* 4324 chipcommon chipid */ ++#define BCM43242_CHIP_ID 43242 /* 43242 chipcommon chipid */ ++#define BCM4334_CHIP_ID 0x4334 /* 4334 chipcommon chipid */ ++#define BCM4360_CHIP_ID 0x4360 /* 4360 chipcommon chipid */ ++#define BCM4352_CHIP_ID 0x4352 /* 4352 chipcommon chipid */ ++#define BCM43526_CHIP_ID 0xAA06 ++#define BCM43341_CHIP_ID 43341 /* 43341 chipcommon chipid */ ++#define BCM43342_CHIP_ID 43342 /* 43342 chipcommon chipid */ ++ ++#define BCM4335_CHIP_ID 0x4335 ++ ++#define BCM4342_CHIP_ID 4342 /* 4342 chipcommon chipid (OTP, RBBU) */ ++#define BCM4402_CHIP_ID 0x4402 /* 4402 chipid */ ++#define BCM4704_CHIP_ID 0x4704 /* 4704 chipcommon chipid */ ++#define BCM4706_CHIP_ID 0x5300 /* 4706 chipcommon chipid */ ++#define BCM4710_CHIP_ID 0x4710 /* 4710 chipid */ ++#define BCM4712_CHIP_ID 0x4712 /* 4712 chipcommon chipid */ ++#define BCM4716_CHIP_ID 0x4716 /* 4716 chipcommon chipid */ ++#define BCM47162_CHIP_ID 47162 /* 47162 chipcommon chipid */ ++#define BCM4748_CHIP_ID 0x4748 /* 4716 chipcommon chipid (OTP, RBBU) */ ++#define BCM4749_CHIP_ID 0x4749 /* 5357 chipcommon chipid (OTP, RBBU) */ ++#define BCM4785_CHIP_ID 0x4785 /* 4785 chipcommon chipid */ ++#define BCM5350_CHIP_ID 0x5350 /* 5350 chipcommon chipid */ ++#define BCM5352_CHIP_ID 0x5352 /* 5352 chipcommon chipid */ ++#define BCM5354_CHIP_ID 0x5354 /* 5354 chipcommon chipid */ ++#define BCM5365_CHIP_ID 0x5365 /* 5365 chipcommon chipid */ ++#define BCM5356_CHIP_ID 0x5356 /* 5356 chipcommon chipid */ ++#define BCM5357_CHIP_ID 0x5357 /* 5357 chipcommon chipid */ ++#define BCM53572_CHIP_ID 53572 /* 53572 chipcommon chipid */ ++ ++/* Package IDs */ ++#define BCM4303_PKG_ID 2 /* 4303 package id */ ++#define BCM4309_PKG_ID 1 /* 4309 package id */ ++#define BCM4712LARGE_PKG_ID 0 /* 340pin 4712 package id */ ++#define BCM4712SMALL_PKG_ID 1 /* 200pin 4712 package id */ ++#define BCM4712MID_PKG_ID 2 /* 225pin 4712 package id */ ++#define BCM4328USBD11G_PKG_ID 2 /* 4328 802.11g USB package id */ ++#define BCM4328USBDUAL_PKG_ID 3 /* 4328 802.11a/g USB package id */ ++#define BCM4328SDIOD11G_PKG_ID 4 /* 4328 802.11g SDIO package id */ ++#define BCM4328SDIODUAL_PKG_ID 5 /* 4328 802.11a/g SDIO package id */ ++#define BCM4329_289PIN_PKG_ID 0 /* 4329 289-pin package id */ ++#define BCM4329_182PIN_PKG_ID 1 /* 4329N 182-pin package id */ ++#define BCM5354E_PKG_ID 1 /* 5354E package id */ ++#define BCM4716_PKG_ID 8 /* 4716 package id */ ++#define BCM4717_PKG_ID 9 /* 4717 package id */ ++#define BCM4718_PKG_ID 10 /* 4718 package id */ ++#define BCM5356_PKG_NONMODE 1 /* 5356 package without nmode suppport */ ++#define BCM5358U_PKG_ID 8 /* 5358U package id */ ++#define BCM5358_PKG_ID 9 /* 5358 package id */ ++#define BCM47186_PKG_ID 10 /* 47186 package id */ ++#define BCM5357_PKG_ID 11 /* 5357 package id */ ++#define BCM5356U_PKG_ID 12 /* 5356U package id */ ++#define BCM53572_PKG_ID 8 /* 53572 package id */ ++#define BCM5357C0_PKG_ID 8 /* 5357c0 package id (the same as 53572) */ ++#define BCM47188_PKG_ID 9 /* 47188 package id */ ++#define BCM5358C0_PKG_ID 0xa /* 5358c0 package id */ ++#define BCM5356C0_PKG_ID 0xb /* 5356c0 package id */ ++#define BCM4331TT_PKG_ID 8 /* 4331 12x12 package id */ ++#define BCM4331TN_PKG_ID 9 /* 4331 12x9 package id */ ++#define BCM4331TNA0_PKG_ID 0xb /* 4331 12x9 package id */ ++#define BCM4706L_PKG_ID 1 /* 4706L package id */ ++ ++#define HDLSIM5350_PKG_ID 1 /* HDL simulator package id for a 5350 */ ++#define HDLSIM_PKG_ID 14 /* HDL simulator package id */ ++#define HWSIM_PKG_ID 15 /* Hardware simulator package id */ ++#define BCM43224_FAB_CSM 0x8 /* the chip is manufactured by CSM */ ++#define BCM43224_FAB_SMIC 0xa /* the chip is manufactured by SMIC */ ++#define BCM4336_WLBGA_PKG_ID 0x8 ++#define BCM4330_WLBGA_PKG_ID 0x0 ++#define BCM4314PCIE_ARM_PKG_ID (8 | 0) /* 4314 QFN PCI package id, bit 3 tie high */ ++#define BCM4314SDIO_PKG_ID (8 | 1) /* 4314 QFN SDIO package id */ ++#define BCM4314PCIE_PKG_ID (8 | 2) /* 4314 QFN PCI (ARM-less) package id */ ++#define BCM4314SDIO_ARM_PKG_ID (8 | 3) /* 4314 QFN SDIO (ARM-less) package id */ ++#define BCM4314SDIO_FPBGA_PKG_ID (8 | 4) /* 4314 FpBGA SDIO package id */ ++#define BCM4314DEV_PKG_ID (8 | 6) /* 4314 Developement package id */ ++ ++#define PCIXX21_FLASHMEDIA0_ID 0x8033 /* TI PCI xx21 Standard Host Controller */ ++#define PCIXX21_SDIOH0_ID 0x8034 /* TI PCI xx21 Standard Host Controller */ ++ ++/* boardflags */ ++#define BFL_BTC2WIRE 0x00000001 /* old 2wire Bluetooth coexistence, OBSOLETE */ ++#define BFL_BTCOEX 0x00000001 /* Board supports BTCOEX */ ++#define BFL_PACTRL 0x00000002 /* Board has gpio 9 controlling the PA */ ++#define BFL_AIRLINEMODE 0x00000004 /* Board implements gpio 13 radio disable indication, UNUSED */ ++#define BFL_ADCDIV 0x00000008 /* Board has the rssi ADC divider */ ++#define BFL_RFPLL 0x00000008 /* ACPHY: Changing RFPLL BW to be 150 MHz */ ++#define BFL_ENETROBO 0x00000010 /* Board has robo switch or core */ ++#define BFL_NOPLLDOWN 0x00000020 /* Not ok to power down the chip pll and oscillator */ ++#define BFL_CCKHIPWR 0x00000040 /* Can do high-power CCK transmission */ ++#define BFL_ENETADM 0x00000080 /* Board has ADMtek switch */ ++#define BFL_ENETVLAN 0x00000100 /* Board has VLAN capability */ ++#define BFL_UNUSED 0x00000200 ++#define BFL_NOPCI 0x00000400 /* Board leaves PCI floating */ ++#define BFL_FEM 0x00000800 /* Board supports the Front End Module */ ++#define BFL_EXTLNA 0x00001000 /* Board has an external LNA in 2.4GHz band */ ++#define BFL_HGPA 0x00002000 /* Board has a high gain PA */ ++#define BFL_BTC2WIRE_ALTGPIO 0x00004000 /* Board's BTC 2wire is in the alternate gpios */ ++#define BFL_ALTIQ 0x00008000 /* Alternate I/Q settings */ ++#define BFL_NOPA 0x00010000 /* Board has no PA */ ++#define BFL_RSSIINV 0x00020000 /* Board's RSSI uses positive slope(not TSSI) */ ++#define BFL_PAREF 0x00040000 /* Board uses the PARef LDO */ ++#define BFL_3TSWITCH 0x00080000 /* Board uses a triple throw switch shared with BT */ ++#define BFL_PHASESHIFT 0x00100000 /* Board can support phase shifter */ ++#define BFL_BUCKBOOST 0x00200000 /* Power topology uses BUCKBOOST */ ++#define BFL_FEM_BT 0x00400000 /* Board has FEM and switch to share antenna w/ BT */ ++#define BFL_NOCBUCK 0x00800000 /* Power topology doesn't use CBUCK */ ++#define BFL_CCKFAVOREVM 0x01000000 /* Favor CCK EVM over spectral mask */ ++#define BFL_PALDO 0x02000000 /* Power topology uses PALDO */ ++#define BFL_LNLDO2_2P5 0x04000000 /* Select 2.5V as LNLDO2 output voltage */ ++#define BFL_FASTPWR 0x08000000 ++#define BFL_UCPWRCTL_MININDX 0x08000000 /* Enforce min power index to avoid FEM damage */ ++#define BFL_EXTLNA_5GHz 0x10000000 /* Board has an external LNA in 5GHz band */ ++#define BFL_TRSW_1by2 0x20000000 /* Board has 2 TRSW's in 1by2 designs */ ++#define BFL_LO_TRSW_R_5GHz 0x40000000 /* In 5G do not throw TRSW to T for clipLO gain */ ++#define BFL_ELNA_GAINDEF 0x80000000 /* Backoff InitGain based on elna_2g/5g field ++ * when this flag is set ++ */ ++#define BFL_EXTLNA_TX 0x20000000 /* Temp boardflag to indicate to */ ++ ++/* boardflags2 */ ++#define BFL2_RXBB_INT_REG_DIS 0x00000001 /* Board has an external rxbb regulator */ ++#define BFL2_APLL_WAR 0x00000002 /* Flag to implement alternative A-band PLL settings */ ++#define BFL2_TXPWRCTRL_EN 0x00000004 /* Board permits enabling TX Power Control */ ++#define BFL2_2X4_DIV 0x00000008 /* Board supports the 2X4 diversity switch */ ++#define BFL2_5G_PWRGAIN 0x00000010 /* Board supports 5G band power gain */ ++#define BFL2_PCIEWAR_OVR 0x00000020 /* Board overrides ASPM and Clkreq settings */ ++#define BFL2_CAESERS_BRD 0x00000040 /* Board is Caesers brd (unused by sw) */ ++#define BFL2_BTC3WIRE 0x00000080 /* Board support legacy 3 wire or 4 wire */ ++#define BFL2_BTCLEGACY 0x00000080 /* Board support legacy 3/4 wire, to replace ++ * BFL2_BTC3WIRE ++ */ ++#define BFL2_SKWRKFEM_BRD 0x00000100 /* 4321mcm93 board uses Skyworks FEM */ ++#define BFL2_SPUR_WAR 0x00000200 /* Board has a WAR for clock-harmonic spurs */ ++#define BFL2_GPLL_WAR 0x00000400 /* Flag to narrow G-band PLL loop b/w */ ++#define BFL2_TRISTATE_LED 0x00000800 /* Tri-state the LED */ ++#define BFL2_SINGLEANT_CCK 0x00001000 /* Tx CCK pkts on Ant 0 only */ ++#define BFL2_2G_SPUR_WAR 0x00002000 /* WAR to reduce and avoid clock-harmonic spurs in 2G */ ++#define BFL2_BPHY_ALL_TXCORES 0x00004000 /* Transmit bphy frames using all tx cores */ ++#define BFL2_FCC_BANDEDGE_WAR 0x00008000 /* Activates WAR to improve FCC bandedge performance */ ++#define BFL2_GPLL_WAR2 0x00010000 /* Flag to widen G-band PLL loop b/w */ ++#define BFL2_IPALVLSHIFT_3P3 0x00020000 ++#define BFL2_INTERNDET_TXIQCAL 0x00040000 /* Use internal envelope detector for TX IQCAL */ ++#define BFL2_XTALBUFOUTEN 0x00080000 /* Keep the buffered Xtal output from radio on */ ++ /* Most drivers will turn it off without this flag */ ++ /* to save power. */ ++ ++#define BFL2_ANAPACTRL_2G 0x00100000 /* 2G ext PAs are controlled by analog PA ctrl lines */ ++#define BFL2_ANAPACTRL_5G 0x00200000 /* 5G ext PAs are controlled by analog PA ctrl lines */ ++#define BFL2_ELNACTRL_TRSW_2G 0x00400000 /* AZW4329: 2G gmode_elna_gain controls TR Switch */ ++#define BFL2_BT_SHARE_ANT0 0x00800000 /* share core0 antenna with BT */ ++#define BFL2_TEMPSENSE_HIGHER 0x01000000 /* The tempsense threshold can sustain higher value ++ * than programmed. The exact delta is decided by ++ * driver per chip/boardtype. This can be used ++ * when tempsense qualification happens after shipment ++ */ ++#define BFL2_BTC3WIREONLY 0x02000000 /* standard 3 wire btc only. 4 wire not supported */ ++#define BFL2_PWR_NOMINAL 0x04000000 /* 0: power reduction on, 1: no power reduction */ ++#define BFL2_EXTLNA_PWRSAVE 0x08000000 /* boardflag to enable ucode to apply power save */ ++ /* ucode control of eLNA during Tx */ ++#define BFL2_4313_RADIOREG 0x10000000 ++ /* board rework */ ++#define BFL2_SDR_EN 0x20000000 /* SDR enabled or disabled */ ++ ++/* board specific GPIO assignment, gpio 0-3 are also customer-configurable led */ ++#define BOARD_GPIO_BTC3W_IN 0x850 /* bit 4 is RF_ACTIVE, bit 6 is STATUS, bit 11 is PRI */ ++#define BOARD_GPIO_BTC3W_OUT 0x020 /* bit 5 is TX_CONF */ ++#define BOARD_GPIO_BTCMOD_IN 0x010 /* bit 4 is the alternate BT Coexistence Input */ ++#define BOARD_GPIO_BTCMOD_OUT 0x020 /* bit 5 is the alternate BT Coexistence Out */ ++#define BOARD_GPIO_BTC_IN 0x080 /* bit 7 is BT Coexistence Input */ ++#define BOARD_GPIO_BTC_OUT 0x100 /* bit 8 is BT Coexistence Out */ ++#define BOARD_GPIO_PACTRL 0x200 /* bit 9 controls the PA on new 4306 boards */ ++#define BOARD_GPIO_12 0x1000 /* gpio 12 */ ++#define BOARD_GPIO_13 0x2000 /* gpio 13 */ ++#define BOARD_GPIO_BTC4_IN 0x0800 /* gpio 11, coex4, in */ ++#define BOARD_GPIO_BTC4_BT 0x2000 /* gpio 12, coex4, bt active */ ++#define BOARD_GPIO_BTC4_STAT 0x4000 /* gpio 14, coex4, status */ ++#define BOARD_GPIO_BTC4_WLAN 0x8000 /* gpio 15, coex4, wlan active */ ++#define BOARD_GPIO_1_WLAN_PWR 0x02 /* throttle WLAN power on X21 board */ ++#define BOARD_GPIO_3_WLAN_PWR 0x08 /* throttle WLAN power on X28 board */ ++#define BOARD_GPIO_4_WLAN_PWR 0x10 /* throttle WLAN power on X19 board */ ++ ++#define GPIO_BTC4W_OUT_4312 0x010 /* bit 4 is BT_IODISABLE */ ++#define GPIO_BTC4W_OUT_43224 0x020 /* bit 5 is BT_IODISABLE */ ++#define GPIO_BTC4W_OUT_43224_SHARED 0x0e0 /* bit 5 is BT_IODISABLE */ ++#define GPIO_BTC4W_OUT_43225 0x0e0 /* bit 5 BT_IODISABLE, bit 6 SW_BT, bit 7 SW_WL */ ++#define GPIO_BTC4W_OUT_43421 0x020 /* bit 5 is BT_IODISABLE */ ++#define GPIO_BTC4W_OUT_4313 0x060 /* bit 5 SW_BT, bit 6 SW_WL */ ++#define GPIO_BTC4W_OUT_4331_SHARED 0x010 /* GPIO 4 */ ++ ++#define PCI_CFG_GPIO_SCS 0x10 /* PCI config space bit 4 for 4306c0 slow clock source */ ++#define PCI_CFG_GPIO_HWRAD 0x20 /* PCI config space GPIO 13 for hw radio disable */ ++#define PCI_CFG_GPIO_XTAL 0x40 /* PCI config space GPIO 14 for Xtal power-up */ ++#define PCI_CFG_GPIO_PLL 0x80 /* PCI config space GPIO 15 for PLL power-down */ ++ ++/* power control defines */ ++#define PLL_DELAY 150 /* us pll on delay */ ++#define FREF_DELAY 200 /* us fref change delay */ ++#define MIN_SLOW_CLK 32 /* us Slow clock period */ ++#define XTAL_ON_DELAY 1000 /* us crystal power-on delay */ ++ ++ ++/* 43341 Boards */ ++#define BCM943341WLABGS_SSID 0x062d ++ ++/* # of GPIO pins */ ++#define GPIO_NUMPINS 32 ++ ++/* These values are used by dhd host driver. */ ++#define RDL_RAM_BASE_4319 0x60000000 ++#define RDL_RAM_BASE_4329 0x60000000 ++#define RDL_RAM_SIZE_4319 0x48000 ++#define RDL_RAM_SIZE_4329 0x48000 ++#define RDL_RAM_SIZE_43236 0x70000 ++#define RDL_RAM_BASE_43236 0x60000000 ++#define RDL_RAM_SIZE_4328 0x60000 ++#define RDL_RAM_BASE_4328 0x80000000 ++#define RDL_RAM_SIZE_4322 0x60000 ++#define RDL_RAM_BASE_4322 0x60000000 ++ ++/* generic defs for nvram "muxenab" bits */ ++#define MUXENAB_UART 0x00000001 ++#define MUXENAB_GPIO 0x00000002 ++#define MUXENAB_ERCX 0x00000004 /* External Radio BT coex */ ++#define MUXENAB_JTAG 0x00000008 ++#define MUXENAB_HOST_WAKE 0x00000010 /* configure GPIO for SDIO host_wake */ ++#define MUXENAB_I2S_EN 0x00000020 ++#define MUXENAB_I2S_MASTER 0x00000040 ++#define MUXENAB_I2S_FULL 0x00000080 ++#define MUXENAB_SFLASH 0x00000100 ++#define MUXENAB_RFSWCTRL0 0x00000200 ++#define MUXENAB_RFSWCTRL1 0x00000400 ++#define MUXENAB_RFSWCTRL2 0x00000800 ++#define MUXENAB_SECI 0x00001000 ++#define MUXENAB_BT_LEGACY 0x00002000 ++#define MUXENAB_HOST_WAKE1 0x00004000 /* configure alternative GPIO for SDIO host_wake */ ++ ++/* Boot flags */ ++#define FLASH_KERNEL_NFLASH 0x00000001 ++#define FLASH_BOOT_NFLASH 0x00000002 ++ ++#endif /* _BCMDEVS_H */ +diff --git a/drivers/net/wireless/ap6211/include/bcmendian.h b/drivers/net/wireless/ap6211/include/bcmendian.h +new file mode 100755 +index 0000000..0cf9145 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcmendian.h +@@ -0,0 +1,299 @@ ++/* ++ * Byte order utilities ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmendian.h 241182 2011-02-17 21:50:03Z $ ++ * ++ * This file by default provides proper behavior on little-endian architectures. ++ * On big-endian architectures, IL_BIGENDIAN should be defined. ++ */ ++ ++#ifndef _BCMENDIAN_H_ ++#define _BCMENDIAN_H_ ++ ++#include ++ ++/* Reverse the bytes in a 16-bit value */ ++#define BCMSWAP16(val) \ ++ ((uint16)((((uint16)(val) & (uint16)0x00ffU) << 8) | \ ++ (((uint16)(val) & (uint16)0xff00U) >> 8))) ++ ++/* Reverse the bytes in a 32-bit value */ ++#define BCMSWAP32(val) \ ++ ((uint32)((((uint32)(val) & (uint32)0x000000ffU) << 24) | \ ++ (((uint32)(val) & (uint32)0x0000ff00U) << 8) | \ ++ (((uint32)(val) & (uint32)0x00ff0000U) >> 8) | \ ++ (((uint32)(val) & (uint32)0xff000000U) >> 24))) ++ ++/* Reverse the two 16-bit halves of a 32-bit value */ ++#define BCMSWAP32BY16(val) \ ++ ((uint32)((((uint32)(val) & (uint32)0x0000ffffU) << 16) | \ ++ (((uint32)(val) & (uint32)0xffff0000U) >> 16))) ++ ++/* Byte swapping macros ++ * Host <=> Network (Big Endian) for 16- and 32-bit values ++ * Host <=> Little-Endian for 16- and 32-bit values ++ */ ++#ifndef hton16 ++#define HTON16(i) BCMSWAP16(i) ++#define hton16(i) bcmswap16(i) ++#define HTON32(i) BCMSWAP32(i) ++#define hton32(i) bcmswap32(i) ++#define NTOH16(i) BCMSWAP16(i) ++#define ntoh16(i) bcmswap16(i) ++#define NTOH32(i) BCMSWAP32(i) ++#define ntoh32(i) bcmswap32(i) ++#define LTOH16(i) (i) ++#define ltoh16(i) (i) ++#define LTOH32(i) (i) ++#define ltoh32(i) (i) ++#define HTOL16(i) (i) ++#define htol16(i) (i) ++#define HTOL32(i) (i) ++#define htol32(i) (i) ++#endif /* hton16 */ ++ ++#define ltoh16_buf(buf, i) ++#define htol16_buf(buf, i) ++ ++/* Unaligned loads and stores in host byte order */ ++#define load32_ua(a) ltoh32_ua(a) ++#define store32_ua(a, v) htol32_ua_store(v, a) ++#define load16_ua(a) ltoh16_ua(a) ++#define store16_ua(a, v) htol16_ua_store(v, a) ++ ++#define _LTOH16_UA(cp) ((cp)[0] | ((cp)[1] << 8)) ++#define _LTOH32_UA(cp) ((cp)[0] | ((cp)[1] << 8) | ((cp)[2] << 16) | ((cp)[3] << 24)) ++#define _NTOH16_UA(cp) (((cp)[0] << 8) | (cp)[1]) ++#define _NTOH32_UA(cp) (((cp)[0] << 24) | ((cp)[1] << 16) | ((cp)[2] << 8) | (cp)[3]) ++ ++#define ltoh_ua(ptr) \ ++ (sizeof(*(ptr)) == sizeof(uint8) ? *(const uint8 *)(ptr) : \ ++ sizeof(*(ptr)) == sizeof(uint16) ? _LTOH16_UA((const uint8 *)(ptr)) : \ ++ sizeof(*(ptr)) == sizeof(uint32) ? _LTOH32_UA((const uint8 *)(ptr)) : \ ++ *(uint8 *)0) ++ ++#define ntoh_ua(ptr) \ ++ (sizeof(*(ptr)) == sizeof(uint8) ? *(const uint8 *)(ptr) : \ ++ sizeof(*(ptr)) == sizeof(uint16) ? _NTOH16_UA((const uint8 *)(ptr)) : \ ++ sizeof(*(ptr)) == sizeof(uint32) ? _NTOH32_UA((const uint8 *)(ptr)) : \ ++ *(uint8 *)0) ++ ++#ifdef __GNUC__ ++ ++/* GNU macro versions avoid referencing the argument multiple times, while also ++ * avoiding the -fno-inline used in ROM builds. ++ */ ++ ++#define bcmswap16(val) ({ \ ++ uint16 _val = (val); \ ++ BCMSWAP16(_val); \ ++}) ++ ++#define bcmswap32(val) ({ \ ++ uint32 _val = (val); \ ++ BCMSWAP32(_val); \ ++}) ++ ++#define bcmswap32by16(val) ({ \ ++ uint32 _val = (val); \ ++ BCMSWAP32BY16(_val); \ ++}) ++ ++#define bcmswap16_buf(buf, len) ({ \ ++ uint16 *_buf = (uint16 *)(buf); \ ++ uint _wds = (len) / 2; \ ++ while (_wds--) { \ ++ *_buf = bcmswap16(*_buf); \ ++ _buf++; \ ++ } \ ++}) ++ ++#define htol16_ua_store(val, bytes) ({ \ ++ uint16 _val = (val); \ ++ uint8 *_bytes = (uint8 *)(bytes); \ ++ _bytes[0] = _val & 0xff; \ ++ _bytes[1] = _val >> 8; \ ++}) ++ ++#define htol32_ua_store(val, bytes) ({ \ ++ uint32 _val = (val); \ ++ uint8 *_bytes = (uint8 *)(bytes); \ ++ _bytes[0] = _val & 0xff; \ ++ _bytes[1] = (_val >> 8) & 0xff; \ ++ _bytes[2] = (_val >> 16) & 0xff; \ ++ _bytes[3] = _val >> 24; \ ++}) ++ ++#define hton16_ua_store(val, bytes) ({ \ ++ uint16 _val = (val); \ ++ uint8 *_bytes = (uint8 *)(bytes); \ ++ _bytes[0] = _val >> 8; \ ++ _bytes[1] = _val & 0xff; \ ++}) ++ ++#define hton32_ua_store(val, bytes) ({ \ ++ uint32 _val = (val); \ ++ uint8 *_bytes = (uint8 *)(bytes); \ ++ _bytes[0] = _val >> 24; \ ++ _bytes[1] = (_val >> 16) & 0xff; \ ++ _bytes[2] = (_val >> 8) & 0xff; \ ++ _bytes[3] = _val & 0xff; \ ++}) ++ ++#define ltoh16_ua(bytes) ({ \ ++ const uint8 *_bytes = (const uint8 *)(bytes); \ ++ _LTOH16_UA(_bytes); \ ++}) ++ ++#define ltoh32_ua(bytes) ({ \ ++ const uint8 *_bytes = (const uint8 *)(bytes); \ ++ _LTOH32_UA(_bytes); \ ++}) ++ ++#define ntoh16_ua(bytes) ({ \ ++ const uint8 *_bytes = (const uint8 *)(bytes); \ ++ _NTOH16_UA(_bytes); \ ++}) ++ ++#define ntoh32_ua(bytes) ({ \ ++ const uint8 *_bytes = (const uint8 *)(bytes); \ ++ _NTOH32_UA(_bytes); \ ++}) ++ ++#else /* !__GNUC__ */ ++ ++/* Inline versions avoid referencing the argument multiple times */ ++static INLINE uint16 ++bcmswap16(uint16 val) ++{ ++ return BCMSWAP16(val); ++} ++ ++static INLINE uint32 ++bcmswap32(uint32 val) ++{ ++ return BCMSWAP32(val); ++} ++ ++static INLINE uint32 ++bcmswap32by16(uint32 val) ++{ ++ return BCMSWAP32BY16(val); ++} ++ ++/* Reverse pairs of bytes in a buffer (not for high-performance use) */ ++/* buf - start of buffer of shorts to swap */ ++/* len - byte length of buffer */ ++static INLINE void ++bcmswap16_buf(uint16 *buf, uint len) ++{ ++ len = len / 2; ++ ++ while (len--) { ++ *buf = bcmswap16(*buf); ++ buf++; ++ } ++} ++ ++/* ++ * Store 16-bit value to unaligned little-endian byte array. ++ */ ++static INLINE void ++htol16_ua_store(uint16 val, uint8 *bytes) ++{ ++ bytes[0] = val & 0xff; ++ bytes[1] = val >> 8; ++} ++ ++/* ++ * Store 32-bit value to unaligned little-endian byte array. ++ */ ++static INLINE void ++htol32_ua_store(uint32 val, uint8 *bytes) ++{ ++ bytes[0] = val & 0xff; ++ bytes[1] = (val >> 8) & 0xff; ++ bytes[2] = (val >> 16) & 0xff; ++ bytes[3] = val >> 24; ++} ++ ++/* ++ * Store 16-bit value to unaligned network-(big-)endian byte array. ++ */ ++static INLINE void ++hton16_ua_store(uint16 val, uint8 *bytes) ++{ ++ bytes[0] = val >> 8; ++ bytes[1] = val & 0xff; ++} ++ ++/* ++ * Store 32-bit value to unaligned network-(big-)endian byte array. ++ */ ++static INLINE void ++hton32_ua_store(uint32 val, uint8 *bytes) ++{ ++ bytes[0] = val >> 24; ++ bytes[1] = (val >> 16) & 0xff; ++ bytes[2] = (val >> 8) & 0xff; ++ bytes[3] = val & 0xff; ++} ++ ++/* ++ * Load 16-bit value from unaligned little-endian byte array. ++ */ ++static INLINE uint16 ++ltoh16_ua(const void *bytes) ++{ ++ return _LTOH16_UA((const uint8 *)bytes); ++} ++ ++/* ++ * Load 32-bit value from unaligned little-endian byte array. ++ */ ++static INLINE uint32 ++ltoh32_ua(const void *bytes) ++{ ++ return _LTOH32_UA((const uint8 *)bytes); ++} ++ ++/* ++ * Load 16-bit value from unaligned big-(network-)endian byte array. ++ */ ++static INLINE uint16 ++ntoh16_ua(const void *bytes) ++{ ++ return _NTOH16_UA((const uint8 *)bytes); ++} ++ ++/* ++ * Load 32-bit value from unaligned big-(network-)endian byte array. ++ */ ++static INLINE uint32 ++ntoh32_ua(const void *bytes) ++{ ++ return _NTOH32_UA((const uint8 *)bytes); ++} ++ ++#endif /* !__GNUC__ */ ++#endif /* !_BCMENDIAN_H_ */ +diff --git a/drivers/net/wireless/ap6211/include/bcmpcispi.h b/drivers/net/wireless/ap6211/include/bcmpcispi.h +new file mode 100755 +index 0000000..44b263c +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcmpcispi.h +@@ -0,0 +1,181 @@ ++/* ++ * Broadcom PCI-SPI Host Controller Register Definitions ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmpcispi.h 241182 2011-02-17 21:50:03Z $ ++ */ ++#ifndef _BCM_PCI_SPI_H ++#define _BCM_PCI_SPI_H ++ ++/* cpp contortions to concatenate w/arg prescan */ ++#ifndef PAD ++#define _PADLINE(line) pad ## line ++#define _XSTR(line) _PADLINE(line) ++#define PAD _XSTR(__LINE__) ++#endif /* PAD */ ++ ++ ++typedef volatile struct { ++ uint32 spih_ctrl; /* 0x00 SPI Control Register */ ++ uint32 spih_stat; /* 0x04 SPI Status Register */ ++ uint32 spih_data; /* 0x08 SPI Data Register, 32-bits wide */ ++ uint32 spih_ext; /* 0x0C SPI Extension Register */ ++ uint32 PAD[4]; /* 0x10-0x1F PADDING */ ++ ++ uint32 spih_gpio_ctrl; /* 0x20 SPI GPIO Control Register */ ++ uint32 spih_gpio_data; /* 0x24 SPI GPIO Data Register */ ++ uint32 PAD[6]; /* 0x28-0x3F PADDING */ ++ ++ uint32 spih_int_edge; /* 0x40 SPI Interrupt Edge Register (0=Level, 1=Edge) */ ++ uint32 spih_int_pol; /* 0x44 SPI Interrupt Polarity Register (0=Active Low, */ ++ /* 1=Active High) */ ++ uint32 spih_int_mask; /* 0x48 SPI Interrupt Mask */ ++ uint32 spih_int_status; /* 0x4C SPI Interrupt Status */ ++ uint32 PAD[4]; /* 0x50-0x5F PADDING */ ++ ++ uint32 spih_hex_disp; /* 0x60 SPI 4-digit hex display value */ ++ uint32 spih_current_ma; /* 0x64 SPI SD card current consumption in mA */ ++ uint32 PAD[1]; /* 0x68 PADDING */ ++ uint32 spih_disp_sel; /* 0x6c SPI 4-digit hex display mode select (1=current) */ ++ uint32 PAD[4]; /* 0x70-0x7F PADDING */ ++ uint32 PAD[8]; /* 0x80-0x9F PADDING */ ++ uint32 PAD[8]; /* 0xA0-0xBF PADDING */ ++ uint32 spih_pll_ctrl; /* 0xC0 PLL Control Register */ ++ uint32 spih_pll_status; /* 0xC4 PLL Status Register */ ++ uint32 spih_xtal_freq; /* 0xC8 External Clock Frequency in units of 10000Hz */ ++ uint32 spih_clk_count; /* 0xCC External Clock Count Register */ ++ ++} spih_regs_t; ++ ++typedef volatile struct { ++ uint32 cfg_space[0x40]; /* 0x000-0x0FF PCI Configuration Space (Read Only) */ ++ uint32 P_IMG_CTRL0; /* 0x100 PCI Image0 Control Register */ ++ ++ uint32 P_BA0; /* 0x104 32 R/W PCI Image0 Base Address register */ ++ uint32 P_AM0; /* 0x108 32 R/W PCI Image0 Address Mask register */ ++ uint32 P_TA0; /* 0x10C 32 R/W PCI Image0 Translation Address register */ ++ uint32 P_IMG_CTRL1; /* 0x110 32 R/W PCI Image1 Control register */ ++ uint32 P_BA1; /* 0x114 32 R/W PCI Image1 Base Address register */ ++ uint32 P_AM1; /* 0x118 32 R/W PCI Image1 Address Mask register */ ++ uint32 P_TA1; /* 0x11C 32 R/W PCI Image1 Translation Address register */ ++ uint32 P_IMG_CTRL2; /* 0x120 32 R/W PCI Image2 Control register */ ++ uint32 P_BA2; /* 0x124 32 R/W PCI Image2 Base Address register */ ++ uint32 P_AM2; /* 0x128 32 R/W PCI Image2 Address Mask register */ ++ uint32 P_TA2; /* 0x12C 32 R/W PCI Image2 Translation Address register */ ++ uint32 P_IMG_CTRL3; /* 0x130 32 R/W PCI Image3 Control register */ ++ uint32 P_BA3; /* 0x134 32 R/W PCI Image3 Base Address register */ ++ uint32 P_AM3; /* 0x138 32 R/W PCI Image3 Address Mask register */ ++ uint32 P_TA3; /* 0x13C 32 R/W PCI Image3 Translation Address register */ ++ uint32 P_IMG_CTRL4; /* 0x140 32 R/W PCI Image4 Control register */ ++ uint32 P_BA4; /* 0x144 32 R/W PCI Image4 Base Address register */ ++ uint32 P_AM4; /* 0x148 32 R/W PCI Image4 Address Mask register */ ++ uint32 P_TA4; /* 0x14C 32 R/W PCI Image4 Translation Address register */ ++ uint32 P_IMG_CTRL5; /* 0x150 32 R/W PCI Image5 Control register */ ++ uint32 P_BA5; /* 0x154 32 R/W PCI Image5 Base Address register */ ++ uint32 P_AM5; /* 0x158 32 R/W PCI Image5 Address Mask register */ ++ uint32 P_TA5; /* 0x15C 32 R/W PCI Image5 Translation Address register */ ++ uint32 P_ERR_CS; /* 0x160 32 R/W PCI Error Control and Status register */ ++ uint32 P_ERR_ADDR; /* 0x164 32 R PCI Erroneous Address register */ ++ uint32 P_ERR_DATA; /* 0x168 32 R PCI Erroneous Data register */ ++ ++ uint32 PAD[5]; /* 0x16C-0x17F PADDING */ ++ ++ uint32 WB_CONF_SPC_BAR; /* 0x180 32 R WISHBONE Configuration Space Base Address */ ++ uint32 W_IMG_CTRL1; /* 0x184 32 R/W WISHBONE Image1 Control register */ ++ uint32 W_BA1; /* 0x188 32 R/W WISHBONE Image1 Base Address register */ ++ uint32 W_AM1; /* 0x18C 32 R/W WISHBONE Image1 Address Mask register */ ++ uint32 W_TA1; /* 0x190 32 R/W WISHBONE Image1 Translation Address reg */ ++ uint32 W_IMG_CTRL2; /* 0x194 32 R/W WISHBONE Image2 Control register */ ++ uint32 W_BA2; /* 0x198 32 R/W WISHBONE Image2 Base Address register */ ++ uint32 W_AM2; /* 0x19C 32 R/W WISHBONE Image2 Address Mask register */ ++ uint32 W_TA2; /* 0x1A0 32 R/W WISHBONE Image2 Translation Address reg */ ++ uint32 W_IMG_CTRL3; /* 0x1A4 32 R/W WISHBONE Image3 Control register */ ++ uint32 W_BA3; /* 0x1A8 32 R/W WISHBONE Image3 Base Address register */ ++ uint32 W_AM3; /* 0x1AC 32 R/W WISHBONE Image3 Address Mask register */ ++ uint32 W_TA3; /* 0x1B0 32 R/W WISHBONE Image3 Translation Address reg */ ++ uint32 W_IMG_CTRL4; /* 0x1B4 32 R/W WISHBONE Image4 Control register */ ++ uint32 W_BA4; /* 0x1B8 32 R/W WISHBONE Image4 Base Address register */ ++ uint32 W_AM4; /* 0x1BC 32 R/W WISHBONE Image4 Address Mask register */ ++ uint32 W_TA4; /* 0x1C0 32 R/W WISHBONE Image4 Translation Address reg */ ++ uint32 W_IMG_CTRL5; /* 0x1C4 32 R/W WISHBONE Image5 Control register */ ++ uint32 W_BA5; /* 0x1C8 32 R/W WISHBONE Image5 Base Address register */ ++ uint32 W_AM5; /* 0x1CC 32 R/W WISHBONE Image5 Address Mask register */ ++ uint32 W_TA5; /* 0x1D0 32 R/W WISHBONE Image5 Translation Address reg */ ++ uint32 W_ERR_CS; /* 0x1D4 32 R/W WISHBONE Error Control and Status reg */ ++ uint32 W_ERR_ADDR; /* 0x1D8 32 R WISHBONE Erroneous Address register */ ++ uint32 W_ERR_DATA; /* 0x1DC 32 R WISHBONE Erroneous Data register */ ++ uint32 CNF_ADDR; /* 0x1E0 32 R/W Configuration Cycle register */ ++ uint32 CNF_DATA; /* 0x1E4 32 R/W Configuration Cycle Generation Data reg */ ++ ++ uint32 INT_ACK; /* 0x1E8 32 R Interrupt Acknowledge register */ ++ uint32 ICR; /* 0x1EC 32 R/W Interrupt Control register */ ++ uint32 ISR; /* 0x1F0 32 R/W Interrupt Status register */ ++} spih_pciregs_t; ++ ++/* ++ * PCI Core interrupt enable and status bit definitions. ++ */ ++ ++/* PCI Core ICR Register bit definitions */ ++#define PCI_INT_PROP_EN (1 << 0) /* Interrupt Propagation Enable */ ++#define PCI_WB_ERR_INT_EN (1 << 1) /* Wishbone Error Interrupt Enable */ ++#define PCI_PCI_ERR_INT_EN (1 << 2) /* PCI Error Interrupt Enable */ ++#define PCI_PAR_ERR_INT_EN (1 << 3) /* Parity Error Interrupt Enable */ ++#define PCI_SYS_ERR_INT_EN (1 << 4) /* System Error Interrupt Enable */ ++#define PCI_SOFTWARE_RESET (1U << 31) /* Software reset of the PCI Core. */ ++ ++ ++/* PCI Core ISR Register bit definitions */ ++#define PCI_INT_PROP_ST (1 << 0) /* Interrupt Propagation Status */ ++#define PCI_WB_ERR_INT_ST (1 << 1) /* Wishbone Error Interrupt Status */ ++#define PCI_PCI_ERR_INT_ST (1 << 2) /* PCI Error Interrupt Status */ ++#define PCI_PAR_ERR_INT_ST (1 << 3) /* Parity Error Interrupt Status */ ++#define PCI_SYS_ERR_INT_ST (1 << 4) /* System Error Interrupt Status */ ++ ++ ++/* Registers on the Wishbone bus */ ++#define SPIH_CTLR_INTR (1 << 0) /* SPI Host Controller Core Interrupt */ ++#define SPIH_DEV_INTR (1 << 1) /* SPI Device Interrupt */ ++#define SPIH_WFIFO_INTR (1 << 2) /* SPI Tx FIFO Empty Intr (FPGA Rev >= 8) */ ++ ++/* GPIO Bit definitions */ ++#define SPIH_CS (1 << 0) /* SPI Chip Select (active low) */ ++#define SPIH_SLOT_POWER (1 << 1) /* SD Card Slot Power Enable */ ++#define SPIH_CARD_DETECT (1 << 2) /* SD Card Detect */ ++ ++/* SPI Status Register Bit definitions */ ++#define SPIH_STATE_MASK 0x30 /* SPI Transfer State Machine state mask */ ++#define SPIH_STATE_SHIFT 4 /* SPI Transfer State Machine state shift */ ++#define SPIH_WFFULL (1 << 3) /* SPI Write FIFO Full */ ++#define SPIH_WFEMPTY (1 << 2) /* SPI Write FIFO Empty */ ++#define SPIH_RFFULL (1 << 1) /* SPI Read FIFO Full */ ++#define SPIH_RFEMPTY (1 << 0) /* SPI Read FIFO Empty */ ++ ++#define SPIH_EXT_CLK (1U << 31) /* Use External Clock as PLL Clock source. */ ++ ++#define SPIH_PLL_NO_CLK (1 << 1) /* Set to 1 if the PLL's input clock is lost. */ ++#define SPIH_PLL_LOCKED (1 << 3) /* Set to 1 when the PLL is locked. */ ++ ++/* Spin bit loop bound check */ ++#define SPI_SPIN_BOUND 0xf4240 /* 1 million */ ++ ++#endif /* _BCM_PCI_SPI_H */ +diff --git a/drivers/net/wireless/ap6211/include/bcmperf.h b/drivers/net/wireless/ap6211/include/bcmperf.h +new file mode 100755 +index 0000000..7438307 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcmperf.h +@@ -0,0 +1,36 @@ ++/* ++ * Performance counters software interface. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmperf.h 241182 2011-02-17 21:50:03Z $ ++ */ ++/* essai */ ++#ifndef _BCMPERF_H_ ++#define _BCMPERF_H_ ++/* get cache hits and misses */ ++#define BCMPERF_ENABLE_INSTRCOUNT() ++#define BCMPERF_ENABLE_ICACHE_MISS() ++#define BCMPERF_ENABLE_ICACHE_HIT() ++#define BCMPERF_GETICACHE_MISS(x) ((x) = 0) ++#define BCMPERF_GETICACHE_HIT(x) ((x) = 0) ++#define BCMPERF_GETINSTRCOUNT(x) ((x) = 0) ++#endif /* _BCMPERF_H_ */ +diff --git a/drivers/net/wireless/ap6211/include/bcmsdbus.h b/drivers/net/wireless/ap6211/include/bcmsdbus.h +new file mode 100755 +index 0000000..2fa706d +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcmsdbus.h +@@ -0,0 +1,152 @@ ++/* ++ * Definitions for API from sdio common code (bcmsdh) to individual ++ * host controller drivers. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmsdbus.h 347614 2012-07-27 10:24:51Z $ ++ */ ++ ++#ifndef _sdio_api_h_ ++#define _sdio_api_h_ ++ ++ ++#define SDIOH_API_RC_SUCCESS (0x00) ++#define SDIOH_API_RC_FAIL (0x01) ++#define SDIOH_API_SUCCESS(status) (status == 0) ++ ++#define SDIOH_READ 0 /* Read request */ ++#define SDIOH_WRITE 1 /* Write request */ ++ ++#define SDIOH_DATA_FIX 0 /* Fixed addressing */ ++#define SDIOH_DATA_INC 1 /* Incremental addressing */ ++ ++#define SDIOH_CMD_TYPE_NORMAL 0 /* Normal command */ ++#define SDIOH_CMD_TYPE_APPEND 1 /* Append command */ ++#define SDIOH_CMD_TYPE_CUTTHRU 2 /* Cut-through command */ ++ ++#define SDIOH_DATA_PIO 0 /* PIO mode */ ++#define SDIOH_DATA_DMA 1 /* DMA mode */ ++ ++#ifdef BCMSDIOH_TXGLOM ++/* Max number of glommed pkts */ ++#define SDPCM_MAXGLOM_SIZE 10 ++#define SDPCM_DEFGLOM_SIZE 3 ++ ++#define SDPCM_TXGLOM_CPY 0 /* SDIO 2.0 should use copy mode */ ++#define SDPCM_TXGLOM_MDESC 1 /* SDIO 3.0 should use multi-desc mode */ ++#endif ++ ++ ++typedef int SDIOH_API_RC; ++ ++/* SDio Host structure */ ++typedef struct sdioh_info sdioh_info_t; ++ ++/* callback function, taking one arg */ ++typedef void (*sdioh_cb_fn_t)(void *); ++ ++/* attach, return handler on success, NULL if failed. ++ * The handler shall be provided by all subsequent calls. No local cache ++ * cfghdl points to the starting address of pci device mapped memory ++ */ ++extern sdioh_info_t * sdioh_attach(osl_t *osh, void *cfghdl, uint irq); ++extern SDIOH_API_RC sdioh_detach(osl_t *osh, sdioh_info_t *si); ++extern SDIOH_API_RC sdioh_interrupt_register(sdioh_info_t *si, sdioh_cb_fn_t fn, void *argh); ++extern SDIOH_API_RC sdioh_interrupt_deregister(sdioh_info_t *si); ++ ++/* query whether SD interrupt is enabled or not */ ++extern SDIOH_API_RC sdioh_interrupt_query(sdioh_info_t *si, bool *onoff); ++ ++/* enable or disable SD interrupt */ ++extern SDIOH_API_RC sdioh_interrupt_set(sdioh_info_t *si, bool enable_disable); ++ ++#if defined(DHD_DEBUG) ++extern bool sdioh_interrupt_pending(sdioh_info_t *si); ++#endif ++ ++/* read or write one byte using cmd52 */ ++extern SDIOH_API_RC sdioh_request_byte(sdioh_info_t *si, uint rw, uint fnc, uint addr, uint8 *byte); ++ ++/* read or write 2/4 bytes using cmd53 */ ++extern SDIOH_API_RC sdioh_request_word(sdioh_info_t *si, uint cmd_type, uint rw, uint fnc, ++ uint addr, uint32 *word, uint nbyte); ++ ++/* read or write any buffer using cmd53 */ ++extern SDIOH_API_RC sdioh_request_buffer(sdioh_info_t *si, uint pio_dma, uint fix_inc, ++ uint rw, uint fnc_num, uint32 addr, uint regwidth, uint32 buflen, uint8 *buffer, ++ void *pkt); ++ ++#ifdef BCMSDIOH_TXGLOM ++extern void sdioh_glom_post(sdioh_info_t *sd, uint8 *frame, uint len); ++extern void sdioh_glom_clear(sdioh_info_t *sd); ++extern uint sdioh_set_mode(sdioh_info_t *sd, uint mode); ++extern bool sdioh_glom_enabled(void); ++#else ++#define sdioh_glom_post(a, b, c) ++#define sdioh_glom_clear(a) ++#define sdioh_set_mode(a) (0) ++#define sdioh_glom_enabled() (FALSE) ++#endif ++ ++/* get cis data */ ++extern SDIOH_API_RC sdioh_cis_read(sdioh_info_t *si, uint fuc, uint8 *cis, uint32 length); ++ ++extern SDIOH_API_RC sdioh_cfg_read(sdioh_info_t *si, uint fuc, uint32 addr, uint8 *data); ++extern SDIOH_API_RC sdioh_cfg_write(sdioh_info_t *si, uint fuc, uint32 addr, uint8 *data); ++ ++/* query number of io functions */ ++extern uint sdioh_query_iofnum(sdioh_info_t *si); ++ ++/* handle iovars */ ++extern int sdioh_iovar_op(sdioh_info_t *si, const char *name, ++ void *params, int plen, void *arg, int len, bool set); ++ ++/* Issue abort to the specified function and clear controller as needed */ ++extern int sdioh_abort(sdioh_info_t *si, uint fnc); ++ ++/* Start and Stop SDIO without re-enumerating the SD card. */ ++extern int sdioh_start(sdioh_info_t *si, int stage); ++extern int sdioh_stop(sdioh_info_t *si); ++ ++/* Wait system lock free */ ++extern int sdioh_waitlockfree(sdioh_info_t *si); ++ ++/* Reset and re-initialize the device */ ++extern int sdioh_sdio_reset(sdioh_info_t *si); ++ ++/* Helper function */ ++void *bcmsdh_get_sdioh(bcmsdh_info_t *sdh); ++ ++ ++ ++#if defined(BCMSDIOH_STD) ++ #define SDIOH_SLEEP_ENABLED ++#endif ++extern SDIOH_API_RC sdioh_sleep(sdioh_info_t *si, bool enab); ++ ++/* GPIO support */ ++extern SDIOH_API_RC sdioh_gpio_init(sdioh_info_t *sd); ++extern bool sdioh_gpioin(sdioh_info_t *sd, uint32 gpio); ++extern SDIOH_API_RC sdioh_gpioouten(sdioh_info_t *sd, uint32 gpio); ++extern SDIOH_API_RC sdioh_gpioout(sdioh_info_t *sd, uint32 gpio, bool enab); ++ ++#endif /* _sdio_api_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/bcmsdh.h b/drivers/net/wireless/ap6211/include/bcmsdh.h +new file mode 100755 +index 0000000..8e5a563 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcmsdh.h +@@ -0,0 +1,247 @@ ++/* ++ * SDIO host client driver interface of Broadcom HNBU ++ * export functions to client drivers ++ * abstract OS and BUS specific details of SDIO ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmsdh.h 347614 2012-07-27 10:24:51Z $ ++ */ ++ ++/** ++ * @file bcmsdh.h ++ */ ++ ++#ifndef _bcmsdh_h_ ++#define _bcmsdh_h_ ++ ++#define BCMSDH_ERROR_VAL 0x0001 /* Error */ ++#define BCMSDH_INFO_VAL 0x0002 /* Info */ ++extern const uint bcmsdh_msglevel; ++ ++#define BCMSDH_ERROR(x) ++#define BCMSDH_INFO(x) ++ ++#if (defined(BCMSDIOH_STD) || defined(BCMSDIOH_BCM) || defined(BCMSDIOH_SPI)) ++#define BCMSDH_ADAPTER ++#endif /* BCMSDIO && (BCMSDIOH_STD || BCMSDIOH_BCM || BCMSDIOH_SPI) */ ++ ++/* forward declarations */ ++typedef struct bcmsdh_info bcmsdh_info_t; ++typedef void (*bcmsdh_cb_fn_t)(void *); ++ ++/* Attach and build an interface to the underlying SD host driver. ++ * - Allocates resources (structs, arrays, mem, OS handles, etc) needed by bcmsdh. ++ * - Returns the bcmsdh handle and virtual address base for register access. ++ * The returned handle should be used in all subsequent calls, but the bcmsh ++ * implementation may maintain a single "default" handle (e.g. the first or ++ * most recent one) to enable single-instance implementations to pass NULL. ++ */ ++ ++#if 0 && (NDISVER >= 0x0630) && 1 ++extern bcmsdh_info_t *bcmsdh_attach(osl_t *osh, void *cfghdl, ++ void **regsva, uint irq, shared_info_t *sh); ++#else ++extern bcmsdh_info_t *bcmsdh_attach(osl_t *osh, void *cfghdl, void **regsva, uint irq); ++#endif ++ ++/* Detach - freeup resources allocated in attach */ ++extern int bcmsdh_detach(osl_t *osh, void *sdh); ++ ++/* Query if SD device interrupts are enabled */ ++extern bool bcmsdh_intr_query(void *sdh); ++ ++/* Enable/disable SD interrupt */ ++extern int bcmsdh_intr_enable(void *sdh); ++extern int bcmsdh_intr_disable(void *sdh); ++ ++/* Register/deregister device interrupt handler. */ ++extern int bcmsdh_intr_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh); ++extern int bcmsdh_intr_dereg(void *sdh); ++/* Enable/disable SD card interrupt forward */ ++extern void bcmsdh_intr_forward(void *sdh, bool pass); ++ ++#if defined(DHD_DEBUG) ++/* Query pending interrupt status from the host controller */ ++extern bool bcmsdh_intr_pending(void *sdh); ++#endif ++ ++/* Register a callback to be called if and when bcmsdh detects ++ * device removal. No-op in the case of non-removable/hardwired devices. ++ */ ++extern int bcmsdh_devremove_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh); ++ ++/* Access SDIO address space (e.g. CCCR) using CMD52 (single-byte interface). ++ * fn: function number ++ * addr: unmodified SDIO-space address ++ * data: data byte to write ++ * err: pointer to error code (or NULL) ++ */ ++extern uint8 bcmsdh_cfg_read(void *sdh, uint func, uint32 addr, int *err); ++extern void bcmsdh_cfg_write(void *sdh, uint func, uint32 addr, uint8 data, int *err); ++ ++/* Read/Write 4bytes from/to cfg space */ ++extern uint32 bcmsdh_cfg_read_word(void *sdh, uint fnc_num, uint32 addr, int *err); ++extern void bcmsdh_cfg_write_word(void *sdh, uint fnc_num, uint32 addr, uint32 data, int *err); ++ ++/* Read CIS content for specified function. ++ * fn: function whose CIS is being requested (0 is common CIS) ++ * cis: pointer to memory location to place results ++ * length: number of bytes to read ++ * Internally, this routine uses the values from the cis base regs (0x9-0xB) ++ * to form an SDIO-space address to read the data from. ++ */ ++extern int bcmsdh_cis_read(void *sdh, uint func, uint8 *cis, uint length); ++ ++/* Synchronous access to device (client) core registers via CMD53 to F1. ++ * addr: backplane address (i.e. >= regsva from attach) ++ * size: register width in bytes (2 or 4) ++ * data: data for register write ++ */ ++extern uint32 bcmsdh_reg_read(void *sdh, uint32 addr, uint size); ++extern uint32 bcmsdh_reg_write(void *sdh, uint32 addr, uint size, uint32 data); ++ ++/* set sb address window */ ++extern int bcmsdhsdio_set_sbaddr_window(void *sdh, uint32 address, bool force_set); ++ ++/* Indicate if last reg read/write failed */ ++extern bool bcmsdh_regfail(void *sdh); ++ ++/* Buffer transfer to/from device (client) core via cmd53. ++ * fn: function number ++ * addr: backplane address (i.e. >= regsva from attach) ++ * flags: backplane width, address increment, sync/async ++ * buf: pointer to memory data buffer ++ * nbytes: number of bytes to transfer to/from buf ++ * pkt: pointer to packet associated with buf (if any) ++ * complete: callback function for command completion (async only) ++ * handle: handle for completion callback (first arg in callback) ++ * Returns 0 or error code. ++ * NOTE: Async operation is not currently supported. ++ */ ++typedef void (*bcmsdh_cmplt_fn_t)(void *handle, int status, bool sync_waiting); ++extern int bcmsdh_send_buf(void *sdh, uint32 addr, uint fn, uint flags, ++ uint8 *buf, uint nbytes, void *pkt, ++ bcmsdh_cmplt_fn_t complete_fn, void *handle); ++extern int bcmsdh_recv_buf(void *sdh, uint32 addr, uint fn, uint flags, ++ uint8 *buf, uint nbytes, void *pkt, ++ bcmsdh_cmplt_fn_t complete_fn, void *handle); ++ ++extern void bcmsdh_glom_post(void *sdh, uint8 *frame, uint len); ++extern void bcmsdh_glom_clear(void *sdh); ++extern uint bcmsdh_set_mode(void *sdh, uint mode); ++extern bool bcmsdh_glom_enabled(void); ++/* Flags bits */ ++#define SDIO_REQ_4BYTE 0x1 /* Four-byte target (backplane) width (vs. two-byte) */ ++#define SDIO_REQ_FIXED 0x2 /* Fixed address (FIFO) (vs. incrementing address) */ ++#define SDIO_REQ_ASYNC 0x4 /* Async request (vs. sync request) */ ++#define SDIO_BYTE_MODE 0x8 /* Byte mode request(non-block mode) */ ++ ++/* Pending (non-error) return code */ ++#define BCME_PENDING 1 ++ ++/* Read/write to memory block (F1, no FIFO) via CMD53 (sync only). ++ * rw: read or write (0/1) ++ * addr: direct SDIO address ++ * buf: pointer to memory data buffer ++ * nbytes: number of bytes to transfer to/from buf ++ * Returns 0 or error code. ++ */ ++extern int bcmsdh_rwdata(void *sdh, uint rw, uint32 addr, uint8 *buf, uint nbytes); ++ ++/* Issue an abort to the specified function */ ++extern int bcmsdh_abort(void *sdh, uint fn); ++ ++/* Start SDIO Host Controller communication */ ++extern int bcmsdh_start(void *sdh, int stage); ++ ++/* Stop SDIO Host Controller communication */ ++extern int bcmsdh_stop(void *sdh); ++ ++/* Wait system lock free */ ++extern int bcmsdh_waitlockfree(void *sdh); ++ ++/* Returns the "Device ID" of target device on the SDIO bus. */ ++extern int bcmsdh_query_device(void *sdh); ++ ++/* Returns the number of IO functions reported by the device */ ++extern uint bcmsdh_query_iofnum(void *sdh); ++ ++/* Miscellaneous knob tweaker. */ ++extern int bcmsdh_iovar_op(void *sdh, const char *name, ++ void *params, int plen, void *arg, int len, bool set); ++ ++/* Reset and reinitialize the device */ ++extern int bcmsdh_reset(bcmsdh_info_t *sdh); ++ ++/* helper functions */ ++ ++extern void *bcmsdh_get_sdioh(bcmsdh_info_t *sdh); ++ ++/* callback functions */ ++typedef struct { ++ /* attach to device */ ++ void *(*attach)(uint16 vend_id, uint16 dev_id, uint16 bus, uint16 slot, ++ uint16 func, uint bustype, void * regsva, osl_t * osh, ++ void * param); ++ /* detach from device */ ++ void (*detach)(void *ch); ++} bcmsdh_driver_t; ++ ++/* platform specific/high level functions */ ++extern int bcmsdh_register(bcmsdh_driver_t *driver); ++extern void bcmsdh_unregister(void); ++extern bool bcmsdh_chipmatch(uint16 vendor, uint16 device); ++extern void bcmsdh_device_remove(void * sdh); ++ ++extern int bcmsdh_reg_sdio_notify(void* semaphore); ++extern void bcmsdh_unreg_sdio_notify(void); ++ ++extern int bcmsdh_set_drvdata(void * dhdp); ++ ++#if defined(OOB_INTR_ONLY) ++extern int bcmsdh_register_oob_intr(void * dhdp); ++extern void bcmsdh_unregister_oob_intr(void); ++extern void bcmsdh_oob_intr_set(bool enable); ++#endif ++#if defined(HW_OOB) ++void bcmsdh_config_hw_oob_intr(bcmsdh_info_t *sdh, uint chip); ++#endif ++ ++/* Function to pass device-status bits to DHD. */ ++extern uint32 bcmsdh_get_dstatus(void *sdh); ++ ++/* Function to return current window addr */ ++extern uint32 bcmsdh_cur_sbwad(void *sdh); ++ ++/* Function to pass chipid and rev to lower layers for controlling pr's */ ++extern void bcmsdh_chipinfo(void *sdh, uint32 chip, uint32 chiprev); ++ ++ ++extern int bcmsdh_sleep(void *sdh, bool enab); ++ ++/* GPIO support */ ++extern int bcmsdh_gpio_init(void *sd); ++extern bool bcmsdh_gpioin(void *sd, uint32 gpio); ++extern int bcmsdh_gpioouten(void *sd, uint32 gpio); ++extern int bcmsdh_gpioout(void *sd, uint32 gpio, bool enab); ++ ++#endif /* _bcmsdh_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/bcmsdh_sdmmc.h b/drivers/net/wireless/ap6211/include/bcmsdh_sdmmc.h +new file mode 100755 +index 0000000..a169588 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcmsdh_sdmmc.h +@@ -0,0 +1,109 @@ ++/* ++ * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmsdh_sdmmc.h 366812 2012-11-05 13:49:32Z $ ++ */ ++ ++#ifndef __BCMSDH_SDMMC_H__ ++#define __BCMSDH_SDMMC_H__ ++ ++#define sd_sync_dma(sd, read, nbytes) ++#define sd_init_dma(sd) ++#define sd_ack_intr(sd) ++#define sd_wakeup(sd); ++ ++/* Allocate/init/free per-OS private data */ ++extern int sdioh_sdmmc_osinit(sdioh_info_t *sd); ++extern void sdioh_sdmmc_osfree(sdioh_info_t *sd); ++ ++#define BLOCK_SIZE_4318 64 ++#define BLOCK_SIZE_4328 512 ++ ++/* internal return code */ ++#define SUCCESS 0 ++#define ERROR 1 ++ ++/* private bus modes */ ++#define SDIOH_MODE_SD4 2 ++#define CLIENT_INTR 0x100 /* Get rid of this! */ ++ ++struct sdioh_info { ++ osl_t *osh; /* osh handler */ ++ bool client_intr_enabled; /* interrupt connnected flag */ ++ bool intr_handler_valid; /* client driver interrupt handler valid */ ++ sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ ++ void *intr_handler_arg; /* argument to call interrupt handler */ ++ uint16 intmask; /* Current active interrupts */ ++ void *sdos_info; /* Pointer to per-OS private data */ ++ ++ uint irq; /* Client irq */ ++ int intrcount; /* Client interrupts */ ++ ++ bool sd_use_dma; /* DMA on CMD53 */ ++ bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */ ++ /* Must be on for sd_multiblock to be effective */ ++ bool use_client_ints; /* If this is false, make sure to restore */ ++ int sd_mode; /* SD1/SD4/SPI */ ++ int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */ ++ uint8 num_funcs; /* Supported funcs on client */ ++ uint32 com_cis_ptr; ++ uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; ++ ++#define SDIOH_SDMMC_MAX_SG_ENTRIES 32 ++ struct scatterlist sg_list[SDIOH_SDMMC_MAX_SG_ENTRIES]; ++ bool use_rxchain; ++}; ++ ++/************************************************************ ++ * Internal interfaces: per-port references into bcmsdh_sdmmc.c ++ */ ++ ++/* Global message bits */ ++extern uint sd_msglevel; ++ ++/* OS-independent interrupt handler */ ++extern bool check_client_intr(sdioh_info_t *sd); ++ ++/* Core interrupt enable/disable of device interrupts */ ++extern void sdioh_sdmmc_devintr_on(sdioh_info_t *sd); ++extern void sdioh_sdmmc_devintr_off(sdioh_info_t *sd); ++ ++ ++/************************************************************** ++ * Internal interfaces: bcmsdh_sdmmc.c references to per-port code ++ */ ++ ++/* Register mapping routines */ ++extern uint32 *sdioh_sdmmc_reg_map(osl_t *osh, int32 addr, int size); ++extern void sdioh_sdmmc_reg_unmap(osl_t *osh, int32 addr, int size); ++ ++/* Interrupt (de)registration routines */ ++extern int sdioh_sdmmc_register_irq(sdioh_info_t *sd, uint irq); ++extern void sdioh_sdmmc_free_irq(uint irq, sdioh_info_t *sd); ++ ++typedef struct _BCMSDH_SDMMC_INSTANCE { ++ sdioh_info_t *sd; ++ struct sdio_func *func[SDIOD_MAX_IOFUNCS]; ++} BCMSDH_SDMMC_INSTANCE, *PBCMSDH_SDMMC_INSTANCE; ++ ++#endif /* __BCMSDH_SDMMC_H__ */ +diff --git a/drivers/net/wireless/ap6211/include/bcmsdpcm.h b/drivers/net/wireless/ap6211/include/bcmsdpcm.h +new file mode 100755 +index 0000000..fb2ec3a +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcmsdpcm.h +@@ -0,0 +1,281 @@ ++/* ++ * Broadcom SDIO/PCMCIA ++ * Software-specific definitions shared between device and host side ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmsdpcm.h 362722 2012-10-12 23:55:55Z $ ++ */ ++ ++#ifndef _bcmsdpcm_h_ ++#define _bcmsdpcm_h_ ++ ++/* ++ * Software allocation of To SB Mailbox resources ++ */ ++ ++/* intstatus bits */ ++#define I_SMB_NAK I_SMB_SW0 /* To SB Mailbox Frame NAK */ ++#define I_SMB_INT_ACK I_SMB_SW1 /* To SB Mailbox Host Interrupt ACK */ ++#define I_SMB_USE_OOB I_SMB_SW2 /* To SB Mailbox Use OOB Wakeup */ ++#define I_SMB_DEV_INT I_SMB_SW3 /* To SB Mailbox Miscellaneous Interrupt */ ++ ++#define I_TOSBMAIL (I_SMB_NAK | I_SMB_INT_ACK | I_SMB_USE_OOB | I_SMB_DEV_INT) ++ ++/* tosbmailbox bits corresponding to intstatus bits */ ++#define SMB_NAK (1 << 0) /* To SB Mailbox Frame NAK */ ++#define SMB_INT_ACK (1 << 1) /* To SB Mailbox Host Interrupt ACK */ ++#define SMB_USE_OOB (1 << 2) /* To SB Mailbox Use OOB Wakeup */ ++#define SMB_DEV_INT (1 << 3) /* To SB Mailbox Miscellaneous Interrupt */ ++#define SMB_MASK 0x0000000f /* To SB Mailbox Mask */ ++ ++/* tosbmailboxdata */ ++#define SMB_DATA_VERSION_MASK 0x00ff0000 /* host protocol version (sent with F2 enable) */ ++#define SMB_DATA_VERSION_SHIFT 16 /* host protocol version (sent with F2 enable) */ ++ ++/* ++ * Software allocation of To Host Mailbox resources ++ */ ++ ++/* intstatus bits */ ++#define I_HMB_FC_STATE I_HMB_SW0 /* To Host Mailbox Flow Control State */ ++#define I_HMB_FC_CHANGE I_HMB_SW1 /* To Host Mailbox Flow Control State Changed */ ++#define I_HMB_FRAME_IND I_HMB_SW2 /* To Host Mailbox Frame Indication */ ++#define I_HMB_HOST_INT I_HMB_SW3 /* To Host Mailbox Miscellaneous Interrupt */ ++ ++#define I_TOHOSTMAIL (I_HMB_FC_CHANGE | I_HMB_FRAME_IND | I_HMB_HOST_INT) ++ ++/* tohostmailbox bits corresponding to intstatus bits */ ++#define HMB_FC_ON (1 << 0) /* To Host Mailbox Flow Control State */ ++#define HMB_FC_CHANGE (1 << 1) /* To Host Mailbox Flow Control State Changed */ ++#define HMB_FRAME_IND (1 << 2) /* To Host Mailbox Frame Indication */ ++#define HMB_HOST_INT (1 << 3) /* To Host Mailbox Miscellaneous Interrupt */ ++#define HMB_MASK 0x0000000f /* To Host Mailbox Mask */ ++ ++/* tohostmailboxdata */ ++#define HMB_DATA_NAKHANDLED 0x01 /* we're ready to retransmit NAK'd frame to host */ ++#define HMB_DATA_DEVREADY 0x02 /* we're ready to to talk to host after enable */ ++#define HMB_DATA_FC 0x04 /* per prio flowcontrol update flag to host */ ++#define HMB_DATA_FWREADY 0x08 /* firmware is ready for protocol activity */ ++#define HMB_DATA_FWHALT 0x10 /* firmware has halted operation */ ++ ++#define HMB_DATA_FCDATA_MASK 0xff000000 /* per prio flowcontrol data */ ++#define HMB_DATA_FCDATA_SHIFT 24 /* per prio flowcontrol data */ ++ ++#define HMB_DATA_VERSION_MASK 0x00ff0000 /* device protocol version (with devready) */ ++#define HMB_DATA_VERSION_SHIFT 16 /* device protocol version (with devready) */ ++ ++/* ++ * Software-defined protocol header ++ */ ++ ++/* Current protocol version */ ++#define SDPCM_PROT_VERSION 4 ++ ++/* SW frame header */ ++#define SDPCM_SEQUENCE_MASK 0x000000ff /* Sequence Number Mask */ ++#define SDPCM_PACKET_SEQUENCE(p) (((uint8 *)p)[0] & 0xff) /* p starts w/SW Header */ ++ ++#define SDPCM_CHANNEL_MASK 0x00000f00 /* Channel Number Mask */ ++#define SDPCM_CHANNEL_SHIFT 8 /* Channel Number Shift */ ++#define SDPCM_PACKET_CHANNEL(p) (((uint8 *)p)[1] & 0x0f) /* p starts w/SW Header */ ++ ++#define SDPCM_FLAGS_MASK 0x0000f000 /* Mask of flag bits */ ++#define SDPCM_FLAGS_SHIFT 12 /* Flag bits shift */ ++#define SDPCM_PACKET_FLAGS(p) ((((uint8 *)p)[1] & 0xf0) >> 4) /* p starts w/SW Header */ ++ ++/* Next Read Len: lookahead length of next frame, in 16-byte units (rounded up) */ ++#define SDPCM_NEXTLEN_MASK 0x00ff0000 /* Next Read Len Mask */ ++#define SDPCM_NEXTLEN_SHIFT 16 /* Next Read Len Shift */ ++#define SDPCM_NEXTLEN_VALUE(p) ((((uint8 *)p)[2] & 0xff) << 4) /* p starts w/SW Header */ ++#define SDPCM_NEXTLEN_OFFSET 2 ++ ++/* Data Offset from SOF (HW Tag, SW Tag, Pad) */ ++#define SDPCM_DOFFSET_OFFSET 3 /* Data Offset */ ++#define SDPCM_DOFFSET_VALUE(p) (((uint8 *)p)[SDPCM_DOFFSET_OFFSET] & 0xff) ++#define SDPCM_DOFFSET_MASK 0xff000000 ++#define SDPCM_DOFFSET_SHIFT 24 ++ ++#define SDPCM_FCMASK_OFFSET 4 /* Flow control */ ++#define SDPCM_FCMASK_VALUE(p) (((uint8 *)p)[SDPCM_FCMASK_OFFSET ] & 0xff) ++#define SDPCM_WINDOW_OFFSET 5 /* Credit based fc */ ++#define SDPCM_WINDOW_VALUE(p) (((uint8 *)p)[SDPCM_WINDOW_OFFSET] & 0xff) ++#define SDPCM_VERSION_OFFSET 6 /* Version # */ ++#define SDPCM_VERSION_VALUE(p) (((uint8 *)p)[SDPCM_VERSION_OFFSET] & 0xff) ++#define SDPCM_UNUSED_OFFSET 7 /* Spare */ ++#define SDPCM_UNUSED_VALUE(p) (((uint8 *)p)[SDPCM_UNUSED_OFFSET] & 0xff) ++ ++#define SDPCM_SWHEADER_LEN 8 /* SW header is 64 bits */ ++ ++/* logical channel numbers */ ++#define SDPCM_CONTROL_CHANNEL 0 /* Control Request/Response Channel Id */ ++#define SDPCM_EVENT_CHANNEL 1 /* Asyc Event Indication Channel Id */ ++#define SDPCM_DATA_CHANNEL 2 /* Data Xmit/Recv Channel Id */ ++#define SDPCM_GLOM_CHANNEL 3 /* For coalesced packets (superframes) */ ++#define SDPCM_TEST_CHANNEL 15 /* Reserved for test/debug packets */ ++#define SDPCM_MAX_CHANNEL 15 ++ ++#define SDPCM_SEQUENCE_WRAP 256 /* wrap-around val for eight-bit frame seq number */ ++ ++#define SDPCM_FLAG_RESVD0 0x01 ++#define SDPCM_FLAG_RESVD1 0x02 ++#define SDPCM_FLAG_GSPI_TXENAB 0x04 ++#define SDPCM_FLAG_GLOMDESC 0x08 /* Superframe descriptor mask */ ++ ++/* For GLOM_CHANNEL frames, use a flag to indicate descriptor frame */ ++#define SDPCM_GLOMDESC_FLAG (SDPCM_FLAG_GLOMDESC << SDPCM_FLAGS_SHIFT) ++ ++#define SDPCM_GLOMDESC(p) (((uint8 *)p)[1] & 0x80) ++ ++/* For TEST_CHANNEL packets, define another 4-byte header */ ++#define SDPCM_TEST_HDRLEN 4 /* Generally: Cmd(1), Ext(1), Len(2); ++ * Semantics of Ext byte depend on command. ++ * Len is current or requested frame length, not ++ * including test header; sent little-endian. ++ */ ++#define SDPCM_TEST_PKT_CNT_FLD_LEN 4 /* Packet count filed legth */ ++#define SDPCM_TEST_DISCARD 0x01 /* Receiver discards. Ext is a pattern id. */ ++#define SDPCM_TEST_ECHOREQ 0x02 /* Echo request. Ext is a pattern id. */ ++#define SDPCM_TEST_ECHORSP 0x03 /* Echo response. Ext is a pattern id. */ ++#define SDPCM_TEST_BURST 0x04 /* Receiver to send a burst. Ext is a frame count ++ * (Backward compatabilty) Set frame count in a ++ * 4 byte filed adjacent to the HDR ++ */ ++#define SDPCM_TEST_SEND 0x05 /* Receiver sets send mode. Ext is boolean on/off ++ * Set frame count in a 4 byte filed adjacent to ++ * the HDR ++ */ ++ ++/* Handy macro for filling in datagen packets with a pattern */ ++#define SDPCM_TEST_FILL(byteno, id) ((uint8)(id + byteno)) ++ ++/* ++ * Software counters (first part matches hardware counters) ++ */ ++ ++typedef volatile struct { ++ uint32 cmd52rd; /* Cmd52RdCount, SDIO: cmd52 reads */ ++ uint32 cmd52wr; /* Cmd52WrCount, SDIO: cmd52 writes */ ++ uint32 cmd53rd; /* Cmd53RdCount, SDIO: cmd53 reads */ ++ uint32 cmd53wr; /* Cmd53WrCount, SDIO: cmd53 writes */ ++ uint32 abort; /* AbortCount, SDIO: aborts */ ++ uint32 datacrcerror; /* DataCrcErrorCount, SDIO: frames w/CRC error */ ++ uint32 rdoutofsync; /* RdOutOfSyncCount, SDIO/PCMCIA: Rd Frm out of sync */ ++ uint32 wroutofsync; /* RdOutOfSyncCount, SDIO/PCMCIA: Wr Frm out of sync */ ++ uint32 writebusy; /* WriteBusyCount, SDIO: device asserted "busy" */ ++ uint32 readwait; /* ReadWaitCount, SDIO: no data ready for a read cmd */ ++ uint32 readterm; /* ReadTermCount, SDIO: read frame termination cmds */ ++ uint32 writeterm; /* WriteTermCount, SDIO: write frames termination cmds */ ++ uint32 rxdescuflo; /* receive descriptor underflows */ ++ uint32 rxfifooflo; /* receive fifo overflows */ ++ uint32 txfifouflo; /* transmit fifo underflows */ ++ uint32 runt; /* runt (too short) frames recv'd from bus */ ++ uint32 badlen; /* frame's rxh len does not match its hw tag len */ ++ uint32 badcksum; /* frame's hw tag chksum doesn't agree with len value */ ++ uint32 seqbreak; /* break in sequence # space from one rx frame to the next */ ++ uint32 rxfcrc; /* frame rx header indicates crc error */ ++ uint32 rxfwoos; /* frame rx header indicates write out of sync */ ++ uint32 rxfwft; /* frame rx header indicates write frame termination */ ++ uint32 rxfabort; /* frame rx header indicates frame aborted */ ++ uint32 woosint; /* write out of sync interrupt */ ++ uint32 roosint; /* read out of sync interrupt */ ++ uint32 rftermint; /* read frame terminate interrupt */ ++ uint32 wftermint; /* write frame terminate interrupt */ ++} sdpcmd_cnt_t; ++ ++/* ++ * Register Access Macros ++ */ ++ ++#define SDIODREV_IS(var, val) ((var) == (val)) ++#define SDIODREV_GE(var, val) ((var) >= (val)) ++#define SDIODREV_GT(var, val) ((var) > (val)) ++#define SDIODREV_LT(var, val) ((var) < (val)) ++#define SDIODREV_LE(var, val) ((var) <= (val)) ++ ++#define SDIODDMAREG32(h, dir, chnl) \ ++ ((dir) == DMA_TX ? \ ++ (void *)(uintptr)&((h)->regs->dma.sdiod32.dma32regs[chnl].xmt) : \ ++ (void *)(uintptr)&((h)->regs->dma.sdiod32.dma32regs[chnl].rcv)) ++ ++#define SDIODDMAREG64(h, dir, chnl) \ ++ ((dir) == DMA_TX ? \ ++ (void *)(uintptr)&((h)->regs->dma.sdiod64.dma64regs[chnl].xmt) : \ ++ (void *)(uintptr)&((h)->regs->dma.sdiod64.dma64regs[chnl].rcv)) ++ ++#define SDIODDMAREG(h, dir, chnl) \ ++ (SDIODREV_LT((h)->corerev, 1) ? \ ++ SDIODDMAREG32((h), (dir), (chnl)) : \ ++ SDIODDMAREG64((h), (dir), (chnl))) ++ ++#define PCMDDMAREG(h, dir, chnl) \ ++ ((dir) == DMA_TX ? \ ++ (void *)(uintptr)&((h)->regs->dma.pcm32.dmaregs.xmt) : \ ++ (void *)(uintptr)&((h)->regs->dma.pcm32.dmaregs.rcv)) ++ ++#define SDPCMDMAREG(h, dir, chnl, coreid) \ ++ ((coreid) == SDIOD_CORE_ID ? \ ++ SDIODDMAREG(h, dir, chnl) : \ ++ PCMDDMAREG(h, dir, chnl)) ++ ++#define SDIODFIFOREG(h, corerev) \ ++ (SDIODREV_LT((corerev), 1) ? \ ++ ((dma32diag_t *)(uintptr)&((h)->regs->dma.sdiod32.dmafifo)) : \ ++ ((dma32diag_t *)(uintptr)&((h)->regs->dma.sdiod64.dmafifo))) ++ ++#define PCMDFIFOREG(h) \ ++ ((dma32diag_t *)(uintptr)&((h)->regs->dma.pcm32.dmafifo)) ++ ++#define SDPCMFIFOREG(h, coreid, corerev) \ ++ ((coreid) == SDIOD_CORE_ID ? \ ++ SDIODFIFOREG(h, corerev) : \ ++ PCMDFIFOREG(h)) ++ ++/* ++ * Shared structure between dongle and the host. ++ * The structure contains pointers to trap or assert information. ++ */ ++#define SDPCM_SHARED_VERSION 0x0001 ++#define SDPCM_SHARED_VERSION_MASK 0x00FF ++#define SDPCM_SHARED_ASSERT_BUILT 0x0100 ++#define SDPCM_SHARED_ASSERT 0x0200 ++#define SDPCM_SHARED_TRAP 0x0400 ++#define SDPCM_SHARED_IN_BRPT 0x0800 ++#define SDPCM_SHARED_SET_BRPT 0x1000 ++#define SDPCM_SHARED_PENDING_BRPT 0x2000 ++ ++typedef struct { ++ uint32 flags; ++ uint32 trap_addr; ++ uint32 assert_exp_addr; ++ uint32 assert_file_addr; ++ uint32 assert_line; ++ uint32 console_addr; /* Address of hndrte_cons_t */ ++ uint32 msgtrace_addr; ++ uint32 brpt_addr; ++} sdpcm_shared_t; ++ ++extern sdpcm_shared_t sdpcm_shared; ++ ++/* Function can be used to notify host of FW halt */ ++extern void sdpcmd_fwhalt(void); ++ ++#endif /* _bcmsdpcm_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/bcmsdspi.h b/drivers/net/wireless/ap6211/include/bcmsdspi.h +new file mode 100755 +index 0000000..9a7496b +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcmsdspi.h +@@ -0,0 +1,119 @@ ++/* ++ * SD-SPI Protocol Conversion - BCMSDH->SPI Translation Layer ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmsdspi.h 294363 2011-11-06 23:02:20Z $ ++ */ ++#ifndef _BCM_SD_SPI_H ++#define _BCM_SD_SPI_H ++ ++#define BLOCK_SIZE_4318 64 ++#define BLOCK_SIZE_4328 512 ++ ++/* internal return code */ ++#define SUCCESS 0 ++#undef ERROR ++#define ERROR 1 ++ ++/* private bus modes */ ++#define SDIOH_MODE_SPI 0 ++ ++#define USE_BLOCKMODE 0x2 /* Block mode can be single block or multi */ ++#define USE_MULTIBLOCK 0x4 ++ ++struct sdioh_info { ++ uint cfg_bar; /* pci cfg address for bar */ ++ uint32 caps; /* cached value of capabilities reg */ ++ uint bar0; /* BAR0 for PCI Device */ ++ osl_t *osh; /* osh handler */ ++ void *controller; /* Pointer to SPI Controller's private data struct */ ++ ++ uint lockcount; /* nest count of sdspi_lock() calls */ ++ bool client_intr_enabled; /* interrupt connnected flag */ ++ bool intr_handler_valid; /* client driver interrupt handler valid */ ++ sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ ++ void *intr_handler_arg; /* argument to call interrupt handler */ ++ bool initialized; /* card initialized */ ++ uint32 target_dev; /* Target device ID */ ++ uint32 intmask; /* Current active interrupts */ ++ void *sdos_info; /* Pointer to per-OS private data */ ++ ++ uint32 controller_type; /* Host controller type */ ++ uint8 version; /* Host Controller Spec Compliance Version */ ++ uint irq; /* Client irq */ ++ uint32 intrcount; /* Client interrupts */ ++ uint32 local_intrcount; /* Controller interrupts */ ++ bool host_init_done; /* Controller initted */ ++ bool card_init_done; /* Client SDIO interface initted */ ++ bool polled_mode; /* polling for command completion */ ++ ++ bool sd_use_dma; /* DMA on CMD53 */ ++ bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */ ++ /* Must be on for sd_multiblock to be effective */ ++ bool use_client_ints; /* If this is false, make sure to restore */ ++ bool got_hcint; /* Host Controller interrupt. */ ++ /* polling hack in wl_linux.c:wl_timer() */ ++ int adapter_slot; /* Maybe dealing with multiple slots/controllers */ ++ int sd_mode; /* SD1/SD4/SPI */ ++ int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */ ++ uint32 data_xfer_count; /* Current register transfer size */ ++ uint32 cmd53_wr_data; /* Used to pass CMD53 write data */ ++ uint32 card_response; /* Used to pass back response status byte */ ++ uint32 card_rsp_data; /* Used to pass back response data word */ ++ uint16 card_rca; /* Current Address */ ++ uint8 num_funcs; /* Supported funcs on client */ ++ uint32 com_cis_ptr; ++ uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; ++ void *dma_buf; ++ ulong dma_phys; ++ int r_cnt; /* rx count */ ++ int t_cnt; /* tx_count */ ++}; ++ ++/************************************************************ ++ * Internal interfaces: per-port references into bcmsdspi.c ++ */ ++ ++/* Global message bits */ ++extern uint sd_msglevel; ++ ++/************************************************************** ++ * Internal interfaces: bcmsdspi.c references to per-port code ++ */ ++ ++/* Register mapping routines */ ++extern uint32 *spi_reg_map(osl_t *osh, uintptr addr, int size); ++extern void spi_reg_unmap(osl_t *osh, uintptr addr, int size); ++ ++/* Interrupt (de)registration routines */ ++extern int spi_register_irq(sdioh_info_t *sd, uint irq); ++extern void spi_free_irq(uint irq, sdioh_info_t *sd); ++ ++/* OS-specific interrupt wrappers (atomic interrupt enable/disable) */ ++extern void spi_lock(sdioh_info_t *sd); ++extern void spi_unlock(sdioh_info_t *sd); ++ ++/* Allocate/init/free per-OS private data */ ++extern int spi_osinit(sdioh_info_t *sd); ++extern void spi_osfree(sdioh_info_t *sd); ++ ++#endif /* _BCM_SD_SPI_H */ +diff --git a/drivers/net/wireless/ap6211/include/bcmsdstd.h b/drivers/net/wireless/ap6211/include/bcmsdstd.h +new file mode 100755 +index 0000000..1c854b2 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcmsdstd.h +@@ -0,0 +1,248 @@ ++0/* ++ * 'Standard' SDIO HOST CONTROLLER driver ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmsdstd.h 347614 2012-07-27 10:24:51Z $ ++ */ ++#ifndef _BCM_SD_STD_H ++#define _BCM_SD_STD_H ++ ++#define sd_sync_dma(sd, read, nbytes) ++#define sd_init_dma(sd) ++#define sd_ack_intr(sd) ++#define sd_wakeup(sd); ++/* Allocate/init/free per-OS private data */ ++extern int sdstd_osinit(sdioh_info_t *sd); ++extern void sdstd_osfree(sdioh_info_t *sd); ++ ++#define BLOCK_SIZE_4318 64 ++#define BLOCK_SIZE_4328 512 ++ ++/* internal return code */ ++#define SUCCESS 0 ++#define ERROR 1 ++ ++/* private bus modes */ ++#define SDIOH_MODE_SPI 0 ++#define SDIOH_MODE_SD1 1 ++#define SDIOH_MODE_SD4 2 ++ ++#define MAX_SLOTS 6 /* For PCI: Only 6 BAR entries => 6 slots */ ++#define SDIOH_REG_WINSZ 0x100 /* Number of registers in Standard Host Controller */ ++ ++#define SDIOH_TYPE_ARASAN_HDK 1 ++#define SDIOH_TYPE_BCM27XX 2 ++#define SDIOH_TYPE_TI_PCIXX21 4 /* TI PCIxx21 Standard Host Controller */ ++#define SDIOH_TYPE_RICOH_R5C822 5 /* Ricoh Co Ltd R5C822 SD/SDIO/MMC/MS/MSPro Host Adapter */ ++#define SDIOH_TYPE_JMICRON 6 /* JMicron Standard SDIO Host Controller */ ++ ++/* For linux, allow yielding for dongle */ ++#define BCMSDYIELD ++ ++/* Expected card status value for CMD7 */ ++#define SDIOH_CMD7_EXP_STATUS 0x00001E00 ++ ++#define RETRIES_LARGE 100000 ++#define sdstd_os_yield(sd) do {} while (0) ++#define RETRIES_SMALL 100 ++ ++ ++#define USE_BLOCKMODE 0x2 /* Block mode can be single block or multi */ ++#define USE_MULTIBLOCK 0x4 ++ ++#define USE_FIFO 0x8 /* Fifo vs non-fifo */ ++ ++#define CLIENT_INTR 0x100 /* Get rid of this! */ ++ ++#define HC_INTR_RETUNING 0x1000 ++ ++ ++#ifdef BCMSDIOH_TXGLOM ++/* Setting the MAX limit to 10 */ ++#define SDIOH_MAXGLOM_SIZE 10 ++ ++typedef struct glom_buf { ++ uint32 count; /* Total number of pkts queued */ ++ void *dma_buf_arr[SDIOH_MAXGLOM_SIZE]; /* Frame address */ ++ ulong dma_phys_arr[SDIOH_MAXGLOM_SIZE]; /* DMA_MAPed address of frames */ ++ uint16 nbytes[SDIOH_MAXGLOM_SIZE]; /* Size of each frame */ ++} glom_buf_t; ++#endif ++ ++struct sdioh_info { ++ uint cfg_bar; /* pci cfg address for bar */ ++ uint32 caps; /* cached value of capabilities reg */ ++ uint32 curr_caps; /* max current capabilities reg */ ++ ++ osl_t *osh; /* osh handler */ ++ volatile char *mem_space; /* pci device memory va */ ++ uint lockcount; /* nest count of sdstd_lock() calls */ ++ bool client_intr_enabled; /* interrupt connnected flag */ ++ bool intr_handler_valid; /* client driver interrupt handler valid */ ++ sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ ++ void *intr_handler_arg; /* argument to call interrupt handler */ ++ bool initialized; /* card initialized */ ++ uint target_dev; /* Target device ID */ ++ uint16 intmask; /* Current active interrupts */ ++ void *sdos_info; /* Pointer to per-OS private data */ ++ ++ uint32 controller_type; /* Host controller type */ ++ uint8 version; /* Host Controller Spec Compliance Version */ ++ uint irq; /* Client irq */ ++ int intrcount; /* Client interrupts */ ++ int local_intrcount; /* Controller interrupts */ ++ bool host_init_done; /* Controller initted */ ++ bool card_init_done; /* Client SDIO interface initted */ ++ bool polled_mode; /* polling for command completion */ ++ ++ bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */ ++ /* Must be on for sd_multiblock to be effective */ ++ bool use_client_ints; /* If this is false, make sure to restore */ ++ /* polling hack in wl_linux.c:wl_timer() */ ++ int adapter_slot; /* Maybe dealing with multiple slots/controllers */ ++ int sd_mode; /* SD1/SD4/SPI */ ++ int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */ ++ uint32 data_xfer_count; /* Current transfer */ ++ uint16 card_rca; /* Current Address */ ++ int8 sd_dma_mode; /* DMA Mode (PIO, SDMA, ... ADMA2) on CMD53 */ ++ uint8 num_funcs; /* Supported funcs on client */ ++ uint32 com_cis_ptr; ++ uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; ++ void *dma_buf; /* DMA Buffer virtual address */ ++ ulong dma_phys; /* DMA Buffer physical address */ ++ void *adma2_dscr_buf; /* ADMA2 Descriptor Buffer virtual address */ ++ ulong adma2_dscr_phys; /* ADMA2 Descriptor Buffer physical address */ ++ ++ /* adjustments needed to make the dma align properly */ ++ void *dma_start_buf; ++ ulong dma_start_phys; ++ uint alloced_dma_size; ++ void *adma2_dscr_start_buf; ++ ulong adma2_dscr_start_phys; ++ uint alloced_adma2_dscr_size; ++ ++ int r_cnt; /* rx count */ ++ int t_cnt; /* tx_count */ ++ bool got_hcint; /* local interrupt flag */ ++ uint16 last_intrstatus; /* to cache intrstatus */ ++ int host_UHSISupported; /* whether UHSI is supported for HC. */ ++ int card_UHSI_voltage_Supported; /* whether UHSI is supported for ++ * Card in terms of Voltage [1.8 or 3.3]. ++ */ ++ int global_UHSI_Supp; /* type of UHSI support in both host and card. ++ * HOST_SDR_UNSUPP: capabilities not supported/matched ++ * HOST_SDR_12_25: SDR12 and SDR25 supported ++ * HOST_SDR_50_104_DDR: one of SDR50/SDR104 or DDR50 supptd ++ */ ++ volatile int sd3_dat_state; /* data transfer state used for retuning check */ ++ volatile int sd3_tun_state; /* tuning state used for retuning check */ ++ bool sd3_tuning_reqd; /* tuning requirement parameter */ ++ uint32 caps3; /* cached value of 32 MSbits capabilities reg (SDIO 3.0) */ ++#ifdef BCMSDIOH_TXGLOM ++ glom_buf_t glom_info; /* pkt information used for glomming */ ++ uint txglom_mode; /* Txglom mode: 0 - copy, 1 - multi-descriptor */ ++#endif ++}; ++ ++#define DMA_MODE_NONE 0 ++#define DMA_MODE_SDMA 1 ++#define DMA_MODE_ADMA1 2 ++#define DMA_MODE_ADMA2 3 ++#define DMA_MODE_ADMA2_64 4 ++#define DMA_MODE_AUTO -1 ++ ++#define USE_DMA(sd) ((bool)((sd->sd_dma_mode > 0) ? TRUE : FALSE)) ++ ++/* States for Tuning and corr data */ ++#define TUNING_IDLE 0 ++#define TUNING_START 1 ++#define TUNING_START_AFTER_DAT 2 ++#define TUNING_ONGOING 3 ++ ++#define DATA_TRANSFER_IDLE 0 ++#define DATA_TRANSFER_ONGOING 1 ++ ++#define CHECK_TUNING_PRE_DATA 1 ++#define CHECK_TUNING_POST_DATA 2 ++ ++/************************************************************ ++ * Internal interfaces: per-port references into bcmsdstd.c ++ */ ++ ++/* Global message bits */ ++extern uint sd_msglevel; ++ ++/* OS-independent interrupt handler */ ++extern bool check_client_intr(sdioh_info_t *sd); ++ ++/* Core interrupt enable/disable of device interrupts */ ++extern void sdstd_devintr_on(sdioh_info_t *sd); ++extern void sdstd_devintr_off(sdioh_info_t *sd); ++ ++/* Enable/disable interrupts for local controller events */ ++extern void sdstd_intrs_on(sdioh_info_t *sd, uint16 norm, uint16 err); ++extern void sdstd_intrs_off(sdioh_info_t *sd, uint16 norm, uint16 err); ++ ++/* Wait for specified interrupt and error bits to be set */ ++extern void sdstd_spinbits(sdioh_info_t *sd, uint16 norm, uint16 err); ++ ++ ++/************************************************************** ++ * Internal interfaces: bcmsdstd.c references to per-port code ++ */ ++ ++/* Register mapping routines */ ++extern uint32 *sdstd_reg_map(osl_t *osh, int32 addr, int size); ++extern void sdstd_reg_unmap(osl_t *osh, int32 addr, int size); ++ ++/* Interrupt (de)registration routines */ ++extern int sdstd_register_irq(sdioh_info_t *sd, uint irq); ++extern void sdstd_free_irq(uint irq, sdioh_info_t *sd); ++ ++/* OS-specific interrupt wrappers (atomic interrupt enable/disable) */ ++extern void sdstd_lock(sdioh_info_t *sd); ++extern void sdstd_unlock(sdioh_info_t *sd); ++extern void sdstd_waitlockfree(sdioh_info_t *sd); ++ ++/* OS-specific wait-for-interrupt-or-status */ ++extern int sdstd_waitbits(sdioh_info_t *sd, uint16 norm, uint16 err, bool yield, uint16 *bits); ++ ++/* used by bcmsdstd_linux [implemented in sdstd] */ ++extern void sdstd_3_enable_retuning_int(sdioh_info_t *sd); ++extern void sdstd_3_disable_retuning_int(sdioh_info_t *sd); ++extern bool sdstd_3_is_retuning_int_set(sdioh_info_t *sd); ++extern void sdstd_3_check_and_do_tuning(sdioh_info_t *sd, int tuning_param); ++extern bool sdstd_3_check_and_set_retuning(sdioh_info_t *sd); ++extern int sdstd_3_get_tune_state(sdioh_info_t *sd); ++extern int sdstd_3_get_data_state(sdioh_info_t *sd); ++extern void sdstd_3_set_tune_state(sdioh_info_t *sd, int state); ++extern void sdstd_3_set_data_state(sdioh_info_t *sd, int state); ++extern uint8 sdstd_3_get_tuning_exp(sdioh_info_t *sd); ++extern uint32 sdstd_3_get_uhsi_clkmode(sdioh_info_t *sd); ++extern int sdstd_3_clk_tuning(sdioh_info_t *sd, uint32 sd3ClkMode); ++ ++/* used by sdstd [implemented in bcmsdstd_linux/ndis] */ ++extern void sdstd_3_start_tuning(sdioh_info_t *sd); ++extern void sdstd_3_osinit_tuning(sdioh_info_t *sd); ++extern void sdstd_3_osclean_tuning(sdioh_info_t *sd); ++ ++#endif /* _BCM_SD_STD_H */ +diff --git a/drivers/net/wireless/ap6211/include/bcmspi.h b/drivers/net/wireless/ap6211/include/bcmspi.h +new file mode 100755 +index 0000000..e226cb1 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcmspi.h +@@ -0,0 +1,40 @@ ++/* ++ * Broadcom SPI Low-Level Hardware Driver API ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmspi.h 241182 2011-02-17 21:50:03Z $ ++ */ ++#ifndef _BCM_SPI_H ++#define _BCM_SPI_H ++ ++extern void spi_devintr_off(sdioh_info_t *sd); ++extern void spi_devintr_on(sdioh_info_t *sd); ++extern bool spi_start_clock(sdioh_info_t *sd, uint16 new_sd_divisor); ++extern bool spi_controller_highspeed_mode(sdioh_info_t *sd, bool hsmode); ++extern bool spi_check_client_intr(sdioh_info_t *sd, int *is_dev_intr); ++extern bool spi_hw_attach(sdioh_info_t *sd); ++extern bool spi_hw_detach(sdioh_info_t *sd); ++extern void spi_sendrecv(sdioh_info_t *sd, uint8 *msg_out, uint8 *msg_in, int msglen); ++extern void spi_spinbits(sdioh_info_t *sd); ++extern void spi_waitbits(sdioh_info_t *sd, bool yield); ++ ++#endif /* _BCM_SPI_H */ +diff --git a/drivers/net/wireless/ap6211/include/bcmutils.h b/drivers/net/wireless/ap6211/include/bcmutils.h +new file mode 100755 +index 0000000..71af3dc +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcmutils.h +@@ -0,0 +1,808 @@ ++/* ++ * Misc useful os-independent macros and functions. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmutils.h 354837 2012-09-04 06:58:44Z $ ++ */ ++ ++#ifndef _bcmutils_h_ ++#define _bcmutils_h_ ++ ++#define bcm_strcpy_s(dst, noOfElements, src) strcpy((dst), (src)) ++#define bcm_strncpy_s(dst, noOfElements, src, count) strncpy((dst), (src), (count)) ++#define bcm_strcat_s(dst, noOfElements, src) strcat((dst), (src)) ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#ifdef PKTQ_LOG ++#include ++#endif ++ ++/* ctype replacement */ ++#define _BCM_U 0x01 /* upper */ ++#define _BCM_L 0x02 /* lower */ ++#define _BCM_D 0x04 /* digit */ ++#define _BCM_C 0x08 /* cntrl */ ++#define _BCM_P 0x10 /* punct */ ++#define _BCM_S 0x20 /* white space (space/lf/tab) */ ++#define _BCM_X 0x40 /* hex digit */ ++#define _BCM_SP 0x80 /* hard space (0x20) */ ++ ++extern const unsigned char bcm_ctype[]; ++#define bcm_ismask(x) (bcm_ctype[(int)(unsigned char)(x)]) ++ ++#define bcm_isalnum(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L|_BCM_D)) != 0) ++#define bcm_isalpha(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L)) != 0) ++#define bcm_iscntrl(c) ((bcm_ismask(c)&(_BCM_C)) != 0) ++#define bcm_isdigit(c) ((bcm_ismask(c)&(_BCM_D)) != 0) ++#define bcm_isgraph(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D)) != 0) ++#define bcm_islower(c) ((bcm_ismask(c)&(_BCM_L)) != 0) ++#define bcm_isprint(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D|_BCM_SP)) != 0) ++#define bcm_ispunct(c) ((bcm_ismask(c)&(_BCM_P)) != 0) ++#define bcm_isspace(c) ((bcm_ismask(c)&(_BCM_S)) != 0) ++#define bcm_isupper(c) ((bcm_ismask(c)&(_BCM_U)) != 0) ++#define bcm_isxdigit(c) ((bcm_ismask(c)&(_BCM_D|_BCM_X)) != 0) ++#define bcm_tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c)) ++#define bcm_toupper(c) (bcm_islower((c)) ? ((c) + 'A' - 'a') : (c)) ++ ++/* Buffer structure for collecting string-formatted data ++* using bcm_bprintf() API. ++* Use bcm_binit() to initialize before use ++*/ ++ ++struct bcmstrbuf { ++ char *buf; /* pointer to current position in origbuf */ ++ unsigned int size; /* current (residual) size in bytes */ ++ char *origbuf; /* unmodified pointer to orignal buffer */ ++ unsigned int origsize; /* unmodified orignal buffer size in bytes */ ++}; ++ ++/* ** driver-only section ** */ ++#ifdef BCMDRIVER ++#include ++ ++#define GPIO_PIN_NOTDEFINED 0x20 /* Pin not defined */ ++ ++/* ++ * Spin at most 'us' microseconds while 'exp' is true. ++ * Caller should explicitly test 'exp' when this completes ++ * and take appropriate error action if 'exp' is still true. ++ */ ++#define SPINWAIT(exp, us) { \ ++ uint countdown = (us) + 9; \ ++ while ((exp) && (countdown >= 10)) {\ ++ OSL_DELAY(10); \ ++ countdown -= 10; \ ++ } \ ++} ++ ++/* osl multi-precedence packet queue */ ++#ifndef PKTQ_LEN_DEFAULT ++#define PKTQ_LEN_DEFAULT 128 /* Max 128 packets */ ++#endif ++#ifndef PKTQ_MAX_PREC ++#define PKTQ_MAX_PREC 16 /* Maximum precedence levels */ ++#endif ++ ++typedef struct pktq_prec { ++ void *head; /* first packet to dequeue */ ++ void *tail; /* last packet to dequeue */ ++ uint16 len; /* number of queued packets */ ++ uint16 max; /* maximum number of queued packets */ ++} pktq_prec_t; ++ ++#ifdef PKTQ_LOG ++typedef struct { ++ uint32 requested; /* packets requested to be stored */ ++ uint32 stored; /* packets stored */ ++ uint32 saved; /* packets saved, ++ because a lowest priority queue has given away one packet ++ */ ++ uint32 selfsaved; /* packets saved, ++ because an older packet from the same queue has been dropped ++ */ ++ uint32 full_dropped; /* packets dropped, ++ because pktq is full with higher precedence packets ++ */ ++ uint32 dropped; /* packets dropped because pktq per that precedence is full */ ++ uint32 sacrificed; /* packets dropped, ++ in order to save one from a queue of a highest priority ++ */ ++ uint32 busy; /* packets droped because of hardware/transmission error */ ++ uint32 retry; /* packets re-sent because they were not received */ ++ uint32 ps_retry; /* packets retried again prior to moving power save mode */ ++ uint32 retry_drop; /* packets finally dropped after retry limit */ ++ uint32 max_avail; /* the high-water mark of the queue capacity for packets - ++ goes to zero as queue fills ++ */ ++ uint32 max_used; /* the high-water mark of the queue utilisation for packets - ++ increases with use ('inverse' of max_avail) ++ */ ++ uint32 queue_capacity; /* the maximum capacity of the queue */ ++} pktq_counters_t; ++#endif /* PKTQ_LOG */ ++ ++ ++#define PKTQ_COMMON \ ++ uint16 num_prec; /* number of precedences in use */ \ ++ uint16 hi_prec; /* rapid dequeue hint (>= highest non-empty prec) */ \ ++ uint16 max; /* total max packets */ \ ++ uint16 len; /* total number of packets */ ++ ++/* multi-priority pkt queue */ ++struct pktq { ++ PKTQ_COMMON ++ /* q array must be last since # of elements can be either PKTQ_MAX_PREC or 1 */ ++ struct pktq_prec q[PKTQ_MAX_PREC]; ++#ifdef PKTQ_LOG ++ pktq_counters_t _prec_cnt[PKTQ_MAX_PREC]; /* Counters per queue */ ++#endif ++}; ++ ++/* simple, non-priority pkt queue */ ++struct spktq { ++ PKTQ_COMMON ++ /* q array must be last since # of elements can be either PKTQ_MAX_PREC or 1 */ ++ struct pktq_prec q[1]; ++}; ++ ++#define PKTQ_PREC_ITER(pq, prec) for (prec = (pq)->num_prec - 1; prec >= 0; prec--) ++ ++/* fn(pkt, arg). return true if pkt belongs to if */ ++typedef bool (*ifpkt_cb_t)(void*, int); ++ ++#ifdef BCMPKTPOOL ++#define POOL_ENAB(pool) ((pool) && (pool)->inited) ++#define SHARED_POOL (pktpool_shared) ++#else /* BCMPKTPOOL */ ++#define POOL_ENAB(bus) 0 ++#define SHARED_POOL ((struct pktpool *)NULL) ++#endif /* BCMPKTPOOL */ ++ ++#ifndef PKTPOOL_LEN_MAX ++#define PKTPOOL_LEN_MAX 40 ++#endif /* PKTPOOL_LEN_MAX */ ++#define PKTPOOL_CB_MAX 3 ++ ++struct pktpool; ++typedef void (*pktpool_cb_t)(struct pktpool *pool, void *arg); ++typedef struct { ++ pktpool_cb_t cb; ++ void *arg; ++} pktpool_cbinfo_t; ++ ++#ifdef BCMDBG_POOL ++/* pkt pool debug states */ ++#define POOL_IDLE 0 ++#define POOL_RXFILL 1 ++#define POOL_RXDH 2 ++#define POOL_RXD11 3 ++#define POOL_TXDH 4 ++#define POOL_TXD11 5 ++#define POOL_AMPDU 6 ++#define POOL_TXENQ 7 ++ ++typedef struct { ++ void *p; ++ uint32 cycles; ++ uint32 dur; ++} pktpool_dbg_t; ++ ++typedef struct { ++ uint8 txdh; /* tx to host */ ++ uint8 txd11; /* tx to d11 */ ++ uint8 enq; /* waiting in q */ ++ uint8 rxdh; /* rx from host */ ++ uint8 rxd11; /* rx from d11 */ ++ uint8 rxfill; /* dma_rxfill */ ++ uint8 idle; /* avail in pool */ ++} pktpool_stats_t; ++#endif /* BCMDBG_POOL */ ++ ++typedef struct pktpool { ++ bool inited; ++ uint16 r; ++ uint16 w; ++ uint16 len; ++ uint16 maxlen; ++ uint16 plen; ++ bool istx; ++ bool empty; ++ uint8 cbtoggle; ++ uint8 cbcnt; ++ uint8 ecbcnt; ++ bool emptycb_disable; ++ pktpool_cbinfo_t *availcb_excl; ++ pktpool_cbinfo_t cbs[PKTPOOL_CB_MAX]; ++ pktpool_cbinfo_t ecbs[PKTPOOL_CB_MAX]; ++ void *q[PKTPOOL_LEN_MAX + 1]; ++ ++#ifdef BCMDBG_POOL ++ uint8 dbg_cbcnt; ++ pktpool_cbinfo_t dbg_cbs[PKTPOOL_CB_MAX]; ++ uint16 dbg_qlen; ++ pktpool_dbg_t dbg_q[PKTPOOL_LEN_MAX + 1]; ++#endif ++} pktpool_t; ++ ++extern pktpool_t *pktpool_shared; ++ ++extern int pktpool_init(osl_t *osh, pktpool_t *pktp, int *pktplen, int plen, bool istx); ++extern int pktpool_deinit(osl_t *osh, pktpool_t *pktp); ++extern int pktpool_fill(osl_t *osh, pktpool_t *pktp, bool minimal); ++extern void* pktpool_get(pktpool_t *pktp); ++extern void pktpool_free(pktpool_t *pktp, void *p); ++extern int pktpool_add(pktpool_t *pktp, void *p); ++extern uint16 pktpool_avail(pktpool_t *pktp); ++extern int pktpool_avail_notify_normal(osl_t *osh, pktpool_t *pktp); ++extern int pktpool_avail_notify_exclusive(osl_t *osh, pktpool_t *pktp, pktpool_cb_t cb); ++extern int pktpool_avail_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); ++extern int pktpool_empty_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); ++extern int pktpool_setmaxlen(pktpool_t *pktp, uint16 maxlen); ++extern int pktpool_setmaxlen_strict(osl_t *osh, pktpool_t *pktp, uint16 maxlen); ++extern void pktpool_emptycb_disable(pktpool_t *pktp, bool disable); ++extern bool pktpool_emptycb_disabled(pktpool_t *pktp); ++ ++#define POOLPTR(pp) ((pktpool_t *)(pp)) ++#define pktpool_len(pp) (POOLPTR(pp)->len - 1) ++#define pktpool_plen(pp) (POOLPTR(pp)->plen) ++#define pktpool_maxlen(pp) (POOLPTR(pp)->maxlen) ++ ++#ifdef BCMDBG_POOL ++extern int pktpool_dbg_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); ++extern int pktpool_start_trigger(pktpool_t *pktp, void *p); ++extern int pktpool_dbg_dump(pktpool_t *pktp); ++extern int pktpool_dbg_notify(pktpool_t *pktp); ++extern int pktpool_stats_dump(pktpool_t *pktp, pktpool_stats_t *stats); ++#endif /* BCMDBG_POOL */ ++ ++/* forward definition of ether_addr structure used by some function prototypes */ ++ ++struct ether_addr; ++ ++extern int ether_isbcast(const void *ea); ++extern int ether_isnulladdr(const void *ea); ++ ++/* operations on a specific precedence in packet queue */ ++ ++#define pktq_psetmax(pq, prec, _max) ((pq)->q[prec].max = (_max)) ++#define pktq_pmax(pq, prec) ((pq)->q[prec].max) ++#define pktq_plen(pq, prec) ((pq)->q[prec].len) ++#define pktq_pavail(pq, prec) ((pq)->q[prec].max - (pq)->q[prec].len) ++#define pktq_pfull(pq, prec) ((pq)->q[prec].len >= (pq)->q[prec].max) ++#define pktq_pempty(pq, prec) ((pq)->q[prec].len == 0) ++ ++#define pktq_ppeek(pq, prec) ((pq)->q[prec].head) ++#define pktq_ppeek_tail(pq, prec) ((pq)->q[prec].tail) ++ ++extern void *pktq_penq(struct pktq *pq, int prec, void *p); ++extern void *pktq_penq_head(struct pktq *pq, int prec, void *p); ++extern void *pktq_pdeq(struct pktq *pq, int prec); ++extern void *pktq_pdeq_prev(struct pktq *pq, int prec, void *prev_p); ++extern void *pktq_pdeq_tail(struct pktq *pq, int prec); ++/* Empty the queue at particular precedence level */ ++extern void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, ++ ifpkt_cb_t fn, int arg); ++/* Remove a specified packet from its queue */ ++extern bool pktq_pdel(struct pktq *pq, void *p, int prec); ++ ++/* operations on a set of precedences in packet queue */ ++ ++extern int pktq_mlen(struct pktq *pq, uint prec_bmp); ++extern void *pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out); ++extern void *pktq_mpeek(struct pktq *pq, uint prec_bmp, int *prec_out); ++ ++/* operations on packet queue as a whole */ ++ ++#define pktq_len(pq) ((int)(pq)->len) ++#define pktq_max(pq) ((int)(pq)->max) ++#define pktq_avail(pq) ((int)((pq)->max - (pq)->len)) ++#define pktq_full(pq) ((pq)->len >= (pq)->max) ++#define pktq_empty(pq) ((pq)->len == 0) ++ ++/* operations for single precedence queues */ ++#define pktenq(pq, p) pktq_penq(((struct pktq *)(void *)pq), 0, (p)) ++#define pktenq_head(pq, p) pktq_penq_head(((struct pktq *)(void *)pq), 0, (p)) ++#define pktdeq(pq) pktq_pdeq(((struct pktq *)(void *)pq), 0) ++#define pktdeq_tail(pq) pktq_pdeq_tail(((struct pktq *)(void *)pq), 0) ++#define pktqinit(pq, len) pktq_init(((struct pktq *)(void *)pq), 1, len) ++ ++extern void pktq_init(struct pktq *pq, int num_prec, int max_len); ++extern void pktq_set_max_plen(struct pktq *pq, int prec, int max_len); ++ ++/* prec_out may be NULL if caller is not interested in return value */ ++extern void *pktq_deq(struct pktq *pq, int *prec_out); ++extern void *pktq_deq_tail(struct pktq *pq, int *prec_out); ++extern void *pktq_peek(struct pktq *pq, int *prec_out); ++extern void *pktq_peek_tail(struct pktq *pq, int *prec_out); ++extern void pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg); ++ ++/* externs */ ++/* packet */ ++extern uint pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf); ++extern uint pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf); ++extern uint pkttotlen(osl_t *osh, void *p); ++extern void *pktlast(osl_t *osh, void *p); ++extern uint pktsegcnt(osl_t *osh, void *p); ++extern uint pktsegcnt_war(osl_t *osh, void *p); ++extern uint8 *pktoffset(osl_t *osh, void *p, uint offset); ++ ++/* Get priority from a packet and pass it back in scb (or equiv) */ ++#define PKTPRIO_VDSCP 0x100 /* DSCP prio found after VLAN tag */ ++#define PKTPRIO_VLAN 0x200 /* VLAN prio found */ ++#define PKTPRIO_UPD 0x400 /* DSCP used to update VLAN prio */ ++#define PKTPRIO_DSCP 0x800 /* DSCP prio found */ ++ ++extern uint pktsetprio(void *pkt, bool update_vtag); ++ ++/* string */ ++extern int bcm_atoi(const char *s); ++extern ulong bcm_strtoul(const char *cp, char **endp, uint base); ++extern char *bcmstrstr(const char *haystack, const char *needle); ++extern char *bcmstrcat(char *dest, const char *src); ++extern char *bcmstrncat(char *dest, const char *src, uint size); ++extern ulong wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen); ++char* bcmstrtok(char **string, const char *delimiters, char *tokdelim); ++int bcmstricmp(const char *s1, const char *s2); ++int bcmstrnicmp(const char* s1, const char* s2, int cnt); ++ ++ ++/* ethernet address */ ++extern char *bcm_ether_ntoa(const struct ether_addr *ea, char *buf); ++extern int bcm_ether_atoe(const char *p, struct ether_addr *ea); ++ ++/* ip address */ ++struct ipv4_addr; ++extern char *bcm_ip_ntoa(struct ipv4_addr *ia, char *buf); ++ ++/* delay */ ++extern void bcm_mdelay(uint ms); ++/* variable access */ ++#define NVRAM_RECLAIM_CHECK(name) ++ ++extern char *getvar(char *vars, const char *name); ++extern int getintvar(char *vars, const char *name); ++extern int getintvararray(char *vars, const char *name, int index); ++extern int getintvararraysize(char *vars, const char *name); ++extern uint getgpiopin(char *vars, char *pin_name, uint def_pin); ++#define bcm_perf_enable() ++#define bcmstats(fmt) ++#define bcmlog(fmt, a1, a2) ++#define bcmdumplog(buf, size) *buf = '\0' ++#define bcmdumplogent(buf, idx) -1 ++ ++#define bcmtslog(tstamp, fmt, a1, a2) ++#define bcmprinttslogs() ++#define bcmprinttstamp(us) ++#define bcmdumptslog(buf, size) ++ ++extern char *bcm_nvram_vars(uint *length); ++extern int bcm_nvram_cache(void *sih); ++ ++/* Support for sharing code across in-driver iovar implementations. ++ * The intent is that a driver use this structure to map iovar names ++ * to its (private) iovar identifiers, and the lookup function to ++ * find the entry. Macros are provided to map ids and get/set actions ++ * into a single number space for a switch statement. ++ */ ++ ++/* iovar structure */ ++typedef struct bcm_iovar { ++ const char *name; /* name for lookup and display */ ++ uint16 varid; /* id for switch */ ++ uint16 flags; /* driver-specific flag bits */ ++ uint16 type; /* base type of argument */ ++ uint16 minlen; /* min length for buffer vars */ ++} bcm_iovar_t; ++ ++/* varid definitions are per-driver, may use these get/set bits */ ++ ++/* IOVar action bits for id mapping */ ++#define IOV_GET 0 /* Get an iovar */ ++#define IOV_SET 1 /* Set an iovar */ ++ ++/* Varid to actionid mapping */ ++#define IOV_GVAL(id) ((id) * 2) ++#define IOV_SVAL(id) ((id) * 2 + IOV_SET) ++#define IOV_ISSET(actionid) ((actionid & IOV_SET) == IOV_SET) ++#define IOV_ID(actionid) (actionid >> 1) ++ ++/* flags are per-driver based on driver attributes */ ++ ++extern const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name); ++extern int bcm_iovar_lencheck(const bcm_iovar_t *table, void *arg, int len, bool set); ++#if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \ ++ defined(WLMSG_PRPKT) || defined(WLMSG_WSEC) ++extern int bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len); ++#endif ++#endif /* BCMDRIVER */ ++ ++/* Base type definitions */ ++#define IOVT_VOID 0 /* no value (implictly set only) */ ++#define IOVT_BOOL 1 /* any value ok (zero/nonzero) */ ++#define IOVT_INT8 2 /* integer values are range-checked */ ++#define IOVT_UINT8 3 /* unsigned int 8 bits */ ++#define IOVT_INT16 4 /* int 16 bits */ ++#define IOVT_UINT16 5 /* unsigned int 16 bits */ ++#define IOVT_INT32 6 /* int 32 bits */ ++#define IOVT_UINT32 7 /* unsigned int 32 bits */ ++#define IOVT_BUFFER 8 /* buffer is size-checked as per minlen */ ++#define BCM_IOVT_VALID(type) (((unsigned int)(type)) <= IOVT_BUFFER) ++ ++/* Initializer for IOV type strings */ ++#define BCM_IOV_TYPE_INIT { \ ++ "void", \ ++ "bool", \ ++ "int8", \ ++ "uint8", \ ++ "int16", \ ++ "uint16", \ ++ "int32", \ ++ "uint32", \ ++ "buffer", \ ++ "" } ++ ++#define BCM_IOVT_IS_INT(type) (\ ++ (type == IOVT_BOOL) || \ ++ (type == IOVT_INT8) || \ ++ (type == IOVT_UINT8) || \ ++ (type == IOVT_INT16) || \ ++ (type == IOVT_UINT16) || \ ++ (type == IOVT_INT32) || \ ++ (type == IOVT_UINT32)) ++ ++/* ** driver/apps-shared section ** */ ++ ++#define BCME_STRLEN 64 /* Max string length for BCM errors */ ++#define VALID_BCMERROR(e) ((e <= 0) && (e >= BCME_LAST)) ++ ++ ++/* ++ * error codes could be added but the defined ones shouldn't be changed/deleted ++ * these error codes are exposed to the user code ++ * when ever a new error code is added to this list ++ * please update errorstring table with the related error string and ++ * update osl files with os specific errorcode map ++*/ ++ ++#define BCME_OK 0 /* Success */ ++#define BCME_ERROR -1 /* Error generic */ ++#define BCME_BADARG -2 /* Bad Argument */ ++#define BCME_BADOPTION -3 /* Bad option */ ++#define BCME_NOTUP -4 /* Not up */ ++#define BCME_NOTDOWN -5 /* Not down */ ++#define BCME_NOTAP -6 /* Not AP */ ++#define BCME_NOTSTA -7 /* Not STA */ ++#define BCME_BADKEYIDX -8 /* BAD Key Index */ ++#define BCME_RADIOOFF -9 /* Radio Off */ ++#define BCME_NOTBANDLOCKED -10 /* Not band locked */ ++#define BCME_NOCLK -11 /* No Clock */ ++#define BCME_BADRATESET -12 /* BAD Rate valueset */ ++#define BCME_BADBAND -13 /* BAD Band */ ++#define BCME_BUFTOOSHORT -14 /* Buffer too short */ ++#define BCME_BUFTOOLONG -15 /* Buffer too long */ ++#define BCME_BUSY -16 /* Busy */ ++#define BCME_NOTASSOCIATED -17 /* Not Associated */ ++#define BCME_BADSSIDLEN -18 /* Bad SSID len */ ++#define BCME_OUTOFRANGECHAN -19 /* Out of Range Channel */ ++#define BCME_BADCHAN -20 /* Bad Channel */ ++#define BCME_BADADDR -21 /* Bad Address */ ++#define BCME_NORESOURCE -22 /* Not Enough Resources */ ++#define BCME_UNSUPPORTED -23 /* Unsupported */ ++#define BCME_BADLEN -24 /* Bad length */ ++#define BCME_NOTREADY -25 /* Not Ready */ ++#define BCME_EPERM -26 /* Not Permitted */ ++#define BCME_NOMEM -27 /* No Memory */ ++#define BCME_ASSOCIATED -28 /* Associated */ ++#define BCME_RANGE -29 /* Not In Range */ ++#define BCME_NOTFOUND -30 /* Not Found */ ++#define BCME_WME_NOT_ENABLED -31 /* WME Not Enabled */ ++#define BCME_TSPEC_NOTFOUND -32 /* TSPEC Not Found */ ++#define BCME_ACM_NOTSUPPORTED -33 /* ACM Not Supported */ ++#define BCME_NOT_WME_ASSOCIATION -34 /* Not WME Association */ ++#define BCME_SDIO_ERROR -35 /* SDIO Bus Error */ ++#define BCME_DONGLE_DOWN -36 /* Dongle Not Accessible */ ++#define BCME_VERSION -37 /* Incorrect version */ ++#define BCME_TXFAIL -38 /* TX failure */ ++#define BCME_RXFAIL -39 /* RX failure */ ++#define BCME_NODEVICE -40 /* Device not present */ ++#define BCME_NMODE_DISABLED -41 /* NMODE disabled */ ++#define BCME_NONRESIDENT -42 /* access to nonresident overlay */ ++#define BCME_LAST BCME_NONRESIDENT ++ ++/* These are collection of BCME Error strings */ ++#define BCMERRSTRINGTABLE { \ ++ "OK", \ ++ "Undefined error", \ ++ "Bad Argument", \ ++ "Bad Option", \ ++ "Not up", \ ++ "Not down", \ ++ "Not AP", \ ++ "Not STA", \ ++ "Bad Key Index", \ ++ "Radio Off", \ ++ "Not band locked", \ ++ "No clock", \ ++ "Bad Rate valueset", \ ++ "Bad Band", \ ++ "Buffer too short", \ ++ "Buffer too long", \ ++ "Busy", \ ++ "Not Associated", \ ++ "Bad SSID len", \ ++ "Out of Range Channel", \ ++ "Bad Channel", \ ++ "Bad Address", \ ++ "Not Enough Resources", \ ++ "Unsupported", \ ++ "Bad length", \ ++ "Not Ready", \ ++ "Not Permitted", \ ++ "No Memory", \ ++ "Associated", \ ++ "Not In Range", \ ++ "Not Found", \ ++ "WME Not Enabled", \ ++ "TSPEC Not Found", \ ++ "ACM Not Supported", \ ++ "Not WME Association", \ ++ "SDIO Bus Error", \ ++ "Dongle Not Accessible", \ ++ "Incorrect version", \ ++ "TX Failure", \ ++ "RX Failure", \ ++ "Device Not Present", \ ++ "NMODE Disabled", \ ++ "Nonresident overlay access", \ ++} ++ ++#ifndef ABS ++#define ABS(a) (((a) < 0) ? -(a) : (a)) ++#endif /* ABS */ ++ ++#ifndef MIN ++#define MIN(a, b) (((a) < (b)) ? (a) : (b)) ++#endif /* MIN */ ++ ++#ifndef MAX ++#define MAX(a, b) (((a) > (b)) ? (a) : (b)) ++#endif /* MAX */ ++ ++#define CEIL(x, y) (((x) + ((y) - 1)) / (y)) ++#define ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) ++#define ISALIGNED(a, x) (((uintptr)(a) & ((x) - 1)) == 0) ++#define ALIGN_ADDR(addr, boundary) (void *)(((uintptr)(addr) + (boundary) - 1) \ ++ & ~((boundary) - 1)) ++#define ALIGN_SIZE(size, boundary) (((size) + (boundary) - 1) \ ++ & ~((boundary) - 1)) ++#define ISPOWEROF2(x) ((((x) - 1) & (x)) == 0) ++#define VALID_MASK(mask) !((mask) & ((mask) + 1)) ++ ++#ifndef OFFSETOF ++#ifdef __ARMCC_VERSION ++/* ++ * The ARM RVCT compiler complains when using OFFSETOF where a constant ++ * expression is expected, such as an initializer for a static object. ++ * offsetof from the runtime library doesn't have that problem. ++ */ ++#include ++#define OFFSETOF(type, member) offsetof(type, member) ++#else ++#define OFFSETOF(type, member) ((uint)(uintptr)&((type *)0)->member) ++#endif /* __ARMCC_VERSION */ ++#endif /* OFFSETOF */ ++ ++#ifndef ARRAYSIZE ++#define ARRAYSIZE(a) (sizeof(a) / sizeof(a[0])) ++#endif ++ ++/* Reference a function; used to prevent a static function from being optimized out */ ++extern void *_bcmutils_dummy_fn; ++#define REFERENCE_FUNCTION(f) (_bcmutils_dummy_fn = (void *)(f)) ++ ++/* bit map related macros */ ++#ifndef setbit ++#ifndef NBBY /* the BSD family defines NBBY */ ++#define NBBY 8 /* 8 bits per byte */ ++#endif /* #ifndef NBBY */ ++#define setbit(a, i) (((uint8 *)a)[(i) / NBBY] |= 1 << ((i) % NBBY)) ++#define clrbit(a, i) (((uint8 *)a)[(i) / NBBY] &= ~(1 << ((i) % NBBY))) ++#define isset(a, i) (((const uint8 *)a)[(i) / NBBY] & (1 << ((i) % NBBY))) ++#define isclr(a, i) ((((const uint8 *)a)[(i) / NBBY] & (1 << ((i) % NBBY))) == 0) ++#endif /* setbit */ ++ ++#define NBITS(type) (sizeof(type) * 8) ++#define NBITVAL(nbits) (1 << (nbits)) ++#define MAXBITVAL(nbits) ((1 << (nbits)) - 1) ++#define NBITMASK(nbits) MAXBITVAL(nbits) ++#define MAXNBVAL(nbyte) MAXBITVAL((nbyte) * 8) ++ ++/* basic mux operation - can be optimized on several architectures */ ++#define MUX(pred, true, false) ((pred) ? (true) : (false)) ++ ++/* modulo inc/dec - assumes x E [0, bound - 1] */ ++#define MODDEC(x, bound) MUX((x) == 0, (bound) - 1, (x) - 1) ++#define MODINC(x, bound) MUX((x) == (bound) - 1, 0, (x) + 1) ++ ++/* modulo inc/dec, bound = 2^k */ ++#define MODDEC_POW2(x, bound) (((x) - 1) & ((bound) - 1)) ++#define MODINC_POW2(x, bound) (((x) + 1) & ((bound) - 1)) ++ ++/* modulo add/sub - assumes x, y E [0, bound - 1] */ ++#define MODADD(x, y, bound) \ ++ MUX((x) + (y) >= (bound), (x) + (y) - (bound), (x) + (y)) ++#define MODSUB(x, y, bound) \ ++ MUX(((int)(x)) - ((int)(y)) < 0, (x) - (y) + (bound), (x) - (y)) ++ ++/* module add/sub, bound = 2^k */ ++#define MODADD_POW2(x, y, bound) (((x) + (y)) & ((bound) - 1)) ++#define MODSUB_POW2(x, y, bound) (((x) - (y)) & ((bound) - 1)) ++ ++/* crc defines */ ++#define CRC8_INIT_VALUE 0xff /* Initial CRC8 checksum value */ ++#define CRC8_GOOD_VALUE 0x9f /* Good final CRC8 checksum value */ ++#define CRC16_INIT_VALUE 0xffff /* Initial CRC16 checksum value */ ++#define CRC16_GOOD_VALUE 0xf0b8 /* Good final CRC16 checksum value */ ++#define CRC32_INIT_VALUE 0xffffffff /* Initial CRC32 checksum value */ ++#define CRC32_GOOD_VALUE 0xdebb20e3 /* Good final CRC32 checksum value */ ++ ++/* use for direct output of MAC address in printf etc */ ++#define MACF "%02x:%02x:%02x:%02x:%02x:%02x" ++#define ETHERP_TO_MACF(ea) ((struct ether_addr *) (ea))->octet[0], \ ++ ((struct ether_addr *) (ea))->octet[1], \ ++ ((struct ether_addr *) (ea))->octet[2], \ ++ ((struct ether_addr *) (ea))->octet[3], \ ++ ((struct ether_addr *) (ea))->octet[4], \ ++ ((struct ether_addr *) (ea))->octet[5] ++ ++#define ETHER_TO_MACF(ea) (ea).octet[0], \ ++ (ea).octet[1], \ ++ (ea).octet[2], \ ++ (ea).octet[3], \ ++ (ea).octet[4], \ ++ (ea).octet[5] ++#if !defined(SIMPLE_MAC_PRINT) ++#define MACDBG "%02x:%02x:%02x:%02x:%02x:%02x" ++#define MAC2STRDBG(ea) (ea)[0], (ea)[1], (ea)[2], (ea)[3], (ea)[4], (ea)[5] ++#else ++#define MACDBG "%02x:%02x:%02x" ++#define MAC2STRDBG(ea) (ea)[0], (ea)[4], (ea)[5] ++#endif /* SIMPLE_MAC_PRINT */ ++ ++/* bcm_format_flags() bit description structure */ ++typedef struct bcm_bit_desc { ++ uint32 bit; ++ const char* name; ++} bcm_bit_desc_t; ++ ++/* tag_ID/length/value_buffer tuple */ ++typedef struct bcm_tlv { ++ uint8 id; ++ uint8 len; ++ uint8 data[1]; ++} bcm_tlv_t; ++ ++/* Check that bcm_tlv_t fits into the given buflen */ ++#define bcm_valid_tlv(elt, buflen) ((buflen) >= 2 && (int)(buflen) >= (int)(2 + (elt)->len)) ++ ++/* buffer length for ethernet address from bcm_ether_ntoa() */ ++#define ETHER_ADDR_STR_LEN 18 /* 18-bytes of Ethernet address buffer length */ ++ ++/* crypto utility function */ ++/* 128-bit xor: *dst = *src1 xor *src2. dst1, src1 and src2 may have any alignment */ ++static INLINE void ++xor_128bit_block(const uint8 *src1, const uint8 *src2, uint8 *dst) ++{ ++ if ( ++#ifdef __i386__ ++ 1 || ++#endif ++ (((uintptr)src1 | (uintptr)src2 | (uintptr)dst) & 3) == 0) { ++ /* ARM CM3 rel time: 1229 (727 if alignment check could be omitted) */ ++ /* x86 supports unaligned. This version runs 6x-9x faster on x86. */ ++ ((uint32 *)dst)[0] = ((const uint32 *)src1)[0] ^ ((const uint32 *)src2)[0]; ++ ((uint32 *)dst)[1] = ((const uint32 *)src1)[1] ^ ((const uint32 *)src2)[1]; ++ ((uint32 *)dst)[2] = ((const uint32 *)src1)[2] ^ ((const uint32 *)src2)[2]; ++ ((uint32 *)dst)[3] = ((const uint32 *)src1)[3] ^ ((const uint32 *)src2)[3]; ++ } else { ++ /* ARM CM3 rel time: 4668 (4191 if alignment check could be omitted) */ ++ int k; ++ for (k = 0; k < 16; k++) ++ dst[k] = src1[k] ^ src2[k]; ++ } ++} ++ ++/* externs */ ++/* crc */ ++extern uint8 hndcrc8(uint8 *p, uint nbytes, uint8 crc); ++extern uint16 hndcrc16(uint8 *p, uint nbytes, uint16 crc); ++extern uint32 hndcrc32(uint8 *p, uint nbytes, uint32 crc); ++ ++/* format/print */ ++#if defined(DHD_DEBUG) || defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || \ ++ defined(WLMSG_ASSOC) ++extern int bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len); ++#endif ++ ++#if defined(DHD_DEBUG) || defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || \ ++ defined(WLMSG_ASSOC) || defined(WLMEDIA_PEAKRATE) ++extern int bcm_format_hex(char *str, const void *bytes, int len); ++#endif ++ ++extern const char *bcm_crypto_algo_name(uint algo); ++extern char *bcm_chipname(uint chipid, char *buf, uint len); ++extern char *bcm_brev_str(uint32 brev, char *buf); ++extern void printbig(char *buf); ++extern void prhex(const char *msg, uchar *buf, uint len); ++ ++/* IE parsing */ ++extern bcm_tlv_t *bcm_next_tlv(bcm_tlv_t *elt, int *buflen); ++extern bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key); ++extern bcm_tlv_t *bcm_parse_ordered_tlvs(void *buf, int buflen, uint key); ++ ++/* bcmerror */ ++extern const char *bcmerrorstr(int bcmerror); ++extern bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key); ++ ++/* multi-bool data type: set of bools, mbool is true if any is set */ ++typedef uint32 mbool; ++#define mboolset(mb, bit) ((mb) |= (bit)) /* set one bool */ ++#define mboolclr(mb, bit) ((mb) &= ~(bit)) /* clear one bool */ ++#define mboolisset(mb, bit) (((mb) & (bit)) != 0) /* TRUE if one bool is set */ ++#define mboolmaskset(mb, mask, val) ((mb) = (((mb) & ~(mask)) | (val))) ++ ++/* generic datastruct to help dump routines */ ++struct fielddesc { ++ const char *nameandfmt; ++ uint32 offset; ++ uint32 len; ++}; ++ ++extern void bcm_binit(struct bcmstrbuf *b, char *buf, uint size); ++extern void bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, uint8 *buf, int len); ++ ++extern void bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount); ++extern int bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes); ++extern void bcm_print_bytes(const char *name, const uchar *cdata, int len); ++ ++typedef uint32 (*bcmutl_rdreg_rtn)(void *arg0, uint arg1, uint32 offset); ++extern uint bcmdumpfields(bcmutl_rdreg_rtn func_ptr, void *arg0, uint arg1, struct fielddesc *str, ++ char *buf, uint32 bufsize); ++extern uint bcm_bitcount(uint8 *bitmap, uint bytelength); ++ ++extern int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...); ++ ++/* power conversion */ ++extern uint16 bcm_qdbm_to_mw(uint8 qdbm); ++extern uint8 bcm_mw_to_qdbm(uint16 mw); ++extern uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint len); ++ ++unsigned int process_nvram_vars(char *varbuf, unsigned int len); ++ ++#ifdef __cplusplus ++ } ++#endif ++ ++#endif /* _bcmutils_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/bcmwifi_channels.h b/drivers/net/wireless/ap6211/include/bcmwifi_channels.h +new file mode 100755 +index 0000000..bc57aca +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcmwifi_channels.h +@@ -0,0 +1,490 @@ ++/* ++ * Misc utility routines for WL and Apps ++ * This header file housing the define and function prototype use by ++ * both the wl driver, tools & Apps. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmwifi_channels.h 309193 2012-01-19 00:03:57Z $ ++ */ ++ ++#ifndef _bcmwifi_channels_h_ ++#define _bcmwifi_channels_h_ ++ ++ ++/* A chanspec holds the channel number, band, bandwidth and control sideband */ ++typedef uint16 chanspec_t; ++ ++/* channel defines */ ++#define CH_UPPER_SB 0x01 ++#define CH_LOWER_SB 0x02 ++#define CH_EWA_VALID 0x04 ++#define CH_80MHZ_APART 16 ++#define CH_40MHZ_APART 8 ++#define CH_20MHZ_APART 4 ++#define CH_10MHZ_APART 2 ++#define CH_5MHZ_APART 1 /* 2G band channels are 5 Mhz apart */ ++#define CH_MAX_2G_CHANNEL 14 /* Max channel in 2G band */ ++#define MAXCHANNEL 224 /* max # supported channels. The max channel no is 216, ++ * this is that + 1 rounded up to a multiple of NBBY (8). ++ * DO NOT MAKE it > 255: channels are uint8's all over ++ */ ++#define CHSPEC_CTLOVLP(sp1, sp2, sep) ABS(wf_chspec_ctlchan(sp1) - wf_chspec_ctlchan(sp2)) < (sep) ++ ++/* All builds use the new 11ac ratespec/chanspec */ ++#undef D11AC_IOTYPES ++#define D11AC_IOTYPES ++ ++#ifndef D11AC_IOTYPES ++ ++#define WL_CHANSPEC_CHAN_MASK 0x00ff ++#define WL_CHANSPEC_CHAN_SHIFT 0 ++ ++#define WL_CHANSPEC_CTL_SB_MASK 0x0300 ++#define WL_CHANSPEC_CTL_SB_SHIFT 8 ++#define WL_CHANSPEC_CTL_SB_LOWER 0x0100 ++#define WL_CHANSPEC_CTL_SB_UPPER 0x0200 ++#define WL_CHANSPEC_CTL_SB_NONE 0x0300 ++ ++#define WL_CHANSPEC_BW_MASK 0x0C00 ++#define WL_CHANSPEC_BW_SHIFT 10 ++#define WL_CHANSPEC_BW_10 0x0400 ++#define WL_CHANSPEC_BW_20 0x0800 ++#define WL_CHANSPEC_BW_40 0x0C00 ++ ++#define WL_CHANSPEC_BAND_MASK 0xf000 ++#define WL_CHANSPEC_BAND_SHIFT 12 ++#ifdef WL_CHANSPEC_BAND_5G ++#undef WL_CHANSPEC_BAND_5G ++#endif ++#ifdef WL_CHANSPEC_BAND_2G ++#undef WL_CHANSPEC_BAND_2G ++#endif ++#define WL_CHANSPEC_BAND_5G 0x1000 ++#define WL_CHANSPEC_BAND_2G 0x2000 ++#define INVCHANSPEC 255 ++ ++/* channel defines */ ++#define LOWER_20_SB(channel) (((channel) > CH_10MHZ_APART) ? ((channel) - CH_10MHZ_APART) : 0) ++#define UPPER_20_SB(channel) (((channel) < (MAXCHANNEL - CH_10MHZ_APART)) ? \ ++ ((channel) + CH_10MHZ_APART) : 0) ++#define CHSPEC_WLCBANDUNIT(chspec) (CHSPEC_IS5G(chspec) ? BAND_5G_INDEX : BAND_2G_INDEX) ++#define CH20MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_20 | \ ++ WL_CHANSPEC_CTL_SB_NONE | (((channel) <= CH_MAX_2G_CHANNEL) ? \ ++ WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G)) ++#define NEXT_20MHZ_CHAN(channel) (((channel) < (MAXCHANNEL - CH_20MHZ_APART)) ? \ ++ ((channel) + CH_20MHZ_APART) : 0) ++#define CH40MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ ++ ((channel) | (ctlsb) | WL_CHANSPEC_BW_40 | \ ++ ((channel) <= CH_MAX_2G_CHANNEL ? WL_CHANSPEC_BAND_2G : \ ++ WL_CHANSPEC_BAND_5G)) ++#define CHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_CHANSPEC_CHAN_MASK)) ++#define CHSPEC_BAND(chspec) ((chspec) & WL_CHANSPEC_BAND_MASK) ++ ++/* chanspec stores radio channel & flags to indicate control channel location, i.e. upper/lower */ ++#define CHSPEC_CTL_SB(chspec) ((chspec) & WL_CHANSPEC_CTL_SB_MASK) ++#define CHSPEC_BW(chspec) ((chspec) & WL_CHANSPEC_BW_MASK) ++ ++#ifdef WL11N_20MHZONLY ++ ++#define CHSPEC_IS10(chspec) 0 ++#define CHSPEC_IS20(chspec) 1 ++#ifndef CHSPEC_IS40 ++#define CHSPEC_IS40(chspec) 0 ++#endif ++ ++#else /* !WL11N_20MHZONLY */ ++ ++#define CHSPEC_IS10(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_10) ++#define CHSPEC_IS20(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20) ++#ifndef CHSPEC_IS40 ++#define CHSPEC_IS40(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40) ++#endif ++ ++#endif /* !WL11N_20MHZONLY */ ++ ++#define CHSPEC_IS5G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_5G) ++#define CHSPEC_IS2G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_2G) ++#define CHSPEC_SB_NONE(chspec) (((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_NONE) ++#define CHSPEC_SB_UPPER(chspec) (((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_UPPER) ++#define CHSPEC_SB_LOWER(chspec) (((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_LOWER) ++#define CHSPEC_CTL_CHAN(chspec) ((CHSPEC_SB_LOWER(chspec)) ? \ ++ (LOWER_20_SB(((chspec) & WL_CHANSPEC_CHAN_MASK))) : \ ++ (UPPER_20_SB(((chspec) & WL_CHANSPEC_CHAN_MASK)))) ++#define CHSPEC2WLC_BAND(chspec) (CHSPEC_IS5G(chspec) ? WLC_BAND_5G : WLC_BAND_2G) ++ ++#define CHANSPEC_STR_LEN 8 ++ ++#else /* D11AC_IOTYPES */ ++ ++#define WL_CHANSPEC_CHAN_MASK 0x00ff ++#define WL_CHANSPEC_CHAN_SHIFT 0 ++#define WL_CHANSPEC_CHAN1_MASK 0x000f ++#define WL_CHANSPEC_CHAN1_SHIFT 0 ++#define WL_CHANSPEC_CHAN2_MASK 0x00f0 ++#define WL_CHANSPEC_CHAN2_SHIFT 4 ++ ++#define WL_CHANSPEC_CTL_SB_MASK 0x0700 ++#define WL_CHANSPEC_CTL_SB_SHIFT 8 ++#define WL_CHANSPEC_CTL_SB_LLL 0x0000 ++#define WL_CHANSPEC_CTL_SB_LLU 0x0100 ++#define WL_CHANSPEC_CTL_SB_LUL 0x0200 ++#define WL_CHANSPEC_CTL_SB_LUU 0x0300 ++#define WL_CHANSPEC_CTL_SB_ULL 0x0400 ++#define WL_CHANSPEC_CTL_SB_ULU 0x0500 ++#define WL_CHANSPEC_CTL_SB_UUL 0x0600 ++#define WL_CHANSPEC_CTL_SB_UUU 0x0700 ++#define WL_CHANSPEC_CTL_SB_LL WL_CHANSPEC_CTL_SB_LLL ++#define WL_CHANSPEC_CTL_SB_LU WL_CHANSPEC_CTL_SB_LLU ++#define WL_CHANSPEC_CTL_SB_UL WL_CHANSPEC_CTL_SB_LUL ++#define WL_CHANSPEC_CTL_SB_UU WL_CHANSPEC_CTL_SB_LUU ++#define WL_CHANSPEC_CTL_SB_L WL_CHANSPEC_CTL_SB_LLL ++#define WL_CHANSPEC_CTL_SB_U WL_CHANSPEC_CTL_SB_LLU ++#define WL_CHANSPEC_CTL_SB_LOWER WL_CHANSPEC_CTL_SB_LLL ++#define WL_CHANSPEC_CTL_SB_UPPER WL_CHANSPEC_CTL_SB_LLU ++ ++#define WL_CHANSPEC_BW_MASK 0x3800 ++#define WL_CHANSPEC_BW_SHIFT 11 ++#define WL_CHANSPEC_BW_5 0x0000 ++#define WL_CHANSPEC_BW_10 0x0800 ++#define WL_CHANSPEC_BW_20 0x1000 ++#define WL_CHANSPEC_BW_40 0x1800 ++#define WL_CHANSPEC_BW_80 0x2000 ++#define WL_CHANSPEC_BW_160 0x2800 ++#define WL_CHANSPEC_BW_8080 0x3000 ++ ++#define WL_CHANSPEC_BAND_MASK 0xc000 ++#define WL_CHANSPEC_BAND_SHIFT 14 ++#define WL_CHANSPEC_BAND_2G 0x0000 ++#define WL_CHANSPEC_BAND_3G 0x4000 ++#define WL_CHANSPEC_BAND_4G 0x8000 ++#define WL_CHANSPEC_BAND_5G 0xc000 ++#define INVCHANSPEC 255 ++ ++/* channel defines */ ++#define LOWER_20_SB(channel) (((channel) > CH_10MHZ_APART) ? \ ++ ((channel) - CH_10MHZ_APART) : 0) ++#define UPPER_20_SB(channel) (((channel) < (MAXCHANNEL - CH_10MHZ_APART)) ? \ ++ ((channel) + CH_10MHZ_APART) : 0) ++#define LOWER_40_SB(channel) ((channel) - CH_20MHZ_APART) ++#define UPPER_40_SB(channel) ((channel) + CH_20MHZ_APART) ++#define CHSPEC_WLCBANDUNIT(chspec) (CHSPEC_IS5G(chspec) ? BAND_5G_INDEX : BAND_2G_INDEX) ++#define CH20MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_20 | \ ++ (((channel) <= CH_MAX_2G_CHANNEL) ? \ ++ WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G)) ++#define NEXT_20MHZ_CHAN(channel) (((channel) < (MAXCHANNEL - CH_20MHZ_APART)) ? \ ++ ((channel) + CH_20MHZ_APART) : 0) ++#define CH40MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ ++ ((channel) | (ctlsb) | WL_CHANSPEC_BW_40 | \ ++ ((channel) <= CH_MAX_2G_CHANNEL ? WL_CHANSPEC_BAND_2G : \ ++ WL_CHANSPEC_BAND_5G)) ++#define CH80MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ ++ ((channel) | (ctlsb) | \ ++ WL_CHANSPEC_BW_80 | WL_CHANSPEC_BAND_5G) ++#define CH160MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ ++ ((channel) | (ctlsb) | \ ++ WL_CHANSPEC_BW_160 | WL_CHANSPEC_BAND_5G) ++ ++/* simple MACROs to get different fields of chanspec */ ++#define CHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_CHANSPEC_CHAN_MASK)) ++#define CHSPEC_CHAN1(chspec) ((chspec) & WL_CHANSPEC_CHAN1_MASK) ++#define CHSPEC_CHAN2(chspec) ((chspec) & WL_CHANSPEC_CHAN2_MASK) ++#define CHSPEC_BAND(chspec) ((chspec) & WL_CHANSPEC_BAND_MASK) ++#define CHSPEC_CTL_SB(chspec) ((chspec) & WL_CHANSPEC_CTL_SB_MASK) ++#define CHSPEC_BW(chspec) ((chspec) & WL_CHANSPEC_BW_MASK) ++ ++#ifdef WL11N_20MHZONLY ++ ++#define CHSPEC_IS10(chspec) 0 ++#define CHSPEC_IS20(chspec) 1 ++#ifndef CHSPEC_IS40 ++#define CHSPEC_IS40(chspec) 0 ++#endif ++#ifndef CHSPEC_IS80 ++#define CHSPEC_IS80(chspec) 0 ++#endif ++#ifndef CHSPEC_IS160 ++#define CHSPEC_IS160(chspec) 0 ++#endif ++#ifndef CHSPEC_IS8080 ++#define CHSPEC_IS8080(chspec) 0 ++#endif ++ ++#else /* !WL11N_20MHZONLY */ ++ ++#define CHSPEC_IS10(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_10) ++#define CHSPEC_IS20(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20) ++#ifndef CHSPEC_IS40 ++#define CHSPEC_IS40(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40) ++#endif ++#ifndef CHSPEC_IS80 ++#define CHSPEC_IS80(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_80) ++#endif ++#ifndef CHSPEC_IS160 ++#define CHSPEC_IS160(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_160) ++#endif ++#ifndef CHSPEC_IS8080 ++#define CHSPEC_IS8080(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_8080) ++#endif ++ ++#endif /* !WL11N_20MHZONLY */ ++ ++#define CHSPEC_IS5G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_5G) ++#define CHSPEC_IS2G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_2G) ++#define CHSPEC_SB_UPPER(chspec) \ ++ ((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_UPPER) && \ ++ (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)) ++#define CHSPEC_SB_LOWER(chspec) \ ++ ((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_LOWER) && \ ++ (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)) ++#define CHSPEC2WLC_BAND(chspec) (CHSPEC_IS5G(chspec) ? WLC_BAND_5G : WLC_BAND_2G) ++ ++/** ++ * Number of chars needed for wf_chspec_ntoa() destination character buffer. ++ */ ++#define CHANSPEC_STR_LEN 20 ++ ++ ++/* Legacy Chanspec defines ++ * These are the defines for the previous format of the chanspec_t ++ */ ++#define WL_LCHANSPEC_CHAN_MASK 0x00ff ++#define WL_LCHANSPEC_CHAN_SHIFT 0 ++ ++#define WL_LCHANSPEC_CTL_SB_MASK 0x0300 ++#define WL_LCHANSPEC_CTL_SB_SHIFT 8 ++#define WL_LCHANSPEC_CTL_SB_LOWER 0x0100 ++#define WL_LCHANSPEC_CTL_SB_UPPER 0x0200 ++#define WL_LCHANSPEC_CTL_SB_NONE 0x0300 ++ ++#define WL_LCHANSPEC_BW_MASK 0x0C00 ++#define WL_LCHANSPEC_BW_SHIFT 10 ++#define WL_LCHANSPEC_BW_10 0x0400 ++#define WL_LCHANSPEC_BW_20 0x0800 ++#define WL_LCHANSPEC_BW_40 0x0C00 ++ ++#define WL_LCHANSPEC_BAND_MASK 0xf000 ++#define WL_LCHANSPEC_BAND_SHIFT 12 ++#define WL_LCHANSPEC_BAND_5G 0x1000 ++#define WL_LCHANSPEC_BAND_2G 0x2000 ++ ++#define LCHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_LCHANSPEC_CHAN_MASK)) ++#define LCHSPEC_BAND(chspec) ((chspec) & WL_LCHANSPEC_BAND_MASK) ++#define LCHSPEC_CTL_SB(chspec) ((chspec) & WL_LCHANSPEC_CTL_SB_MASK) ++#define LCHSPEC_BW(chspec) ((chspec) & WL_LCHANSPEC_BW_MASK) ++#define LCHSPEC_IS10(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_10) ++#define LCHSPEC_IS20(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_20) ++#define LCHSPEC_IS40(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40) ++#define LCHSPEC_IS5G(chspec) (((chspec) & WL_LCHANSPEC_BAND_MASK) == WL_LCHANSPEC_BAND_5G) ++#define LCHSPEC_IS2G(chspec) (((chspec) & WL_LCHANSPEC_BAND_MASK) == WL_LCHANSPEC_BAND_2G) ++ ++#define LCHSPEC_CREATE(chan, band, bw, sb) ((uint16)((chan) | (sb) | (bw) | (band))) ++ ++#endif /* D11AC_IOTYPES */ ++ ++/* ++ * WF_CHAN_FACTOR_* constants are used to calculate channel frequency ++ * given a channel number. ++ * chan_freq = chan_factor * 500Mhz + chan_number * 5 ++ */ ++ ++/** ++ * Channel Factor for the starting frequence of 2.4 GHz channels. ++ * The value corresponds to 2407 MHz. ++ */ ++#define WF_CHAN_FACTOR_2_4_G 4814 /* 2.4 GHz band, 2407 MHz */ ++ ++/** ++ * Channel Factor for the starting frequence of 5 GHz channels. ++ * The value corresponds to 5000 MHz. ++ */ ++#define WF_CHAN_FACTOR_5_G 10000 /* 5 GHz band, 5000 MHz */ ++ ++/** ++ * Channel Factor for the starting frequence of 4.9 GHz channels. ++ * The value corresponds to 4000 MHz. ++ */ ++#define WF_CHAN_FACTOR_4_G 8000 /* 4.9 GHz band for Japan */ ++ ++/* defined rate in 500kbps */ ++#define WLC_MAXRATE 108 /* in 500kbps units */ ++#define WLC_RATE_1M 2 /* in 500kbps units */ ++#define WLC_RATE_2M 4 /* in 500kbps units */ ++#define WLC_RATE_5M5 11 /* in 500kbps units */ ++#define WLC_RATE_11M 22 /* in 500kbps units */ ++#define WLC_RATE_6M 12 /* in 500kbps units */ ++#define WLC_RATE_9M 18 /* in 500kbps units */ ++#define WLC_RATE_12M 24 /* in 500kbps units */ ++#define WLC_RATE_18M 36 /* in 500kbps units */ ++#define WLC_RATE_24M 48 /* in 500kbps units */ ++#define WLC_RATE_36M 72 /* in 500kbps units */ ++#define WLC_RATE_48M 96 /* in 500kbps units */ ++#define WLC_RATE_54M 108 /* in 500kbps units */ ++ ++#define WLC_2G_25MHZ_OFFSET 5 /* 2.4GHz band channel offset */ ++ ++/** ++ * Convert chanspec to ascii string ++ * ++ * @param chspec chanspec format ++ * @param buf ascii string of chanspec ++ * ++ * @return pointer to buf with room for at least CHANSPEC_STR_LEN bytes ++ * ++ * @see CHANSPEC_STR_LEN ++ */ ++extern char * wf_chspec_ntoa(chanspec_t chspec, char *buf); ++ ++/** ++ * Convert ascii string to chanspec ++ * ++ * @param a pointer to input string ++ * ++ * @return >= 0 if successful or 0 otherwise ++ */ ++extern chanspec_t wf_chspec_aton(const char *a); ++ ++/** ++ * Verify the chanspec fields are valid. ++ * ++ * Verify the chanspec is using a legal set field values, i.e. that the chanspec ++ * specified a band, bw, ctl_sb and channel and that the combination could be ++ * legal given some set of circumstances. ++ * ++ * @param chanspec input chanspec to verify ++ * ++ * @return TRUE if the chanspec is malformed, FALSE if it looks good. ++ */ ++extern bool wf_chspec_malformed(chanspec_t chanspec); ++ ++/** ++ * Verify the chanspec specifies a valid channel according to 802.11. ++ * ++ * @param chanspec input chanspec to verify ++ * ++ * @return TRUE if the chanspec is a valid 802.11 channel ++ */ ++extern bool wf_chspec_valid(chanspec_t chanspec); ++ ++/** ++ * Return the primary (control) channel. ++ * ++ * This function returns the channel number of the primary 20MHz channel. For ++ * 20MHz channels this is just the channel number. For 40MHz or wider channels ++ * it is the primary 20MHz channel specified by the chanspec. ++ * ++ * @param chspec input chanspec ++ * ++ * @return Returns the channel number of the primary 20MHz channel ++ */ ++extern uint8 wf_chspec_ctlchan(chanspec_t chspec); ++ ++/** ++ * Return the primary (control) chanspec. ++ * ++ * This function returns the chanspec of the primary 20MHz channel. For 20MHz ++ * channels this is just the chanspec. For 40MHz or wider channels it is the ++ * chanspec of the primary 20MHZ channel specified by the chanspec. ++ * ++ * @param chspec input chanspec ++ * ++ * @return Returns the chanspec of the primary 20MHz channel ++ */ ++extern chanspec_t wf_chspec_ctlchspec(chanspec_t chspec); ++ ++/** ++ * Return a channel number corresponding to a frequency. ++ * ++ * This function returns the chanspec for the primary 40MHz of an 80MHz channel. ++ * The control sideband specifies the same 20MHz channel that the 80MHz channel is using ++ * as the primary 20MHz channel. ++ */ ++extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec); ++ ++/* ++ * Return the channel number for a given frequency and base frequency. ++ * The returned channel number is relative to the given base frequency. ++ * If the given base frequency is zero, a base frequency of 5 GHz is assumed for ++ * frequencies from 5 - 6 GHz, and 2.407 GHz is assumed for 2.4 - 2.5 GHz. ++ * ++ * Frequency is specified in MHz. ++ * The base frequency is specified as (start_factor * 500 kHz). ++ * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for ++ * 2.4 GHz and 5 GHz bands. ++ * ++ * The returned channel will be in the range [1, 14] in the 2.4 GHz band ++ * and [0, 200] otherwise. ++ * -1 is returned if the start_factor is WF_CHAN_FACTOR_2_4_G and the ++ * frequency is not a 2.4 GHz channel, or if the frequency is not and even ++ * multiple of 5 MHz from the base frequency to the base plus 1 GHz. ++ * ++ * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 ++ * ++ * @param freq frequency in MHz ++ * @param start_factor base frequency in 500 kHz units, e.g. 10000 for 5 GHz ++ * ++ * @return Returns a channel number ++ * ++ * @see WF_CHAN_FACTOR_2_4_G ++ * @see WF_CHAN_FACTOR_5_G ++ */ ++extern int wf_mhz2channel(uint freq, uint start_factor); ++ ++/** ++ * Return the center frequency in MHz of the given channel and base frequency. ++ * ++ * Return the center frequency in MHz of the given channel and base frequency. ++ * The channel number is interpreted relative to the given base frequency. ++ * ++ * The valid channel range is [1, 14] in the 2.4 GHz band and [0, 200] otherwise. ++ * The base frequency is specified as (start_factor * 500 kHz). ++ * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for ++ * 2.4 GHz and 5 GHz bands. ++ * The channel range of [1, 14] is only checked for a start_factor of ++ * WF_CHAN_FACTOR_2_4_G (4814). ++ * Odd start_factors produce channels on .5 MHz boundaries, in which case ++ * the answer is rounded down to an integral MHz. ++ * -1 is returned for an out of range channel. ++ * ++ * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 ++ * ++ * @param channel input channel number ++ * @param start_factor base frequency in 500 kHz units, e.g. 10000 for 5 GHz ++ * ++ * @return Returns a frequency in MHz ++ * ++ * @see WF_CHAN_FACTOR_2_4_G ++ * @see WF_CHAN_FACTOR_5_G ++ */ ++extern int wf_channel2mhz(uint channel, uint start_factor); ++ ++/** ++ * Convert ctl chan and bw to chanspec ++ * ++ * @param ctl_ch channel ++ * @param bw bandwidth ++ * ++ * @return > 0 if successful or 0 otherwise ++ * ++ */ ++extern uint16 wf_channel2chspec(uint ctl_ch, uint bw); ++ ++#endif /* _bcmwifi_channels_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/bcmwifi_rates.h b/drivers/net/wireless/ap6211/include/bcmwifi_rates.h +new file mode 100755 +index 0000000..ddc6ab5 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcmwifi_rates.h +@@ -0,0 +1,318 @@ ++/* ++ * Indices for 802.11 a/b/g/n/ac 1-3 chain symmetric transmit rates ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmwifi_rates.h 252708 2011-04-12 06:45:56Z $ ++ */ ++ ++#ifndef _bcmwifi_rates_h_ ++#define _bcmwifi_rates_h_ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif /* __cplusplus */ ++ ++ ++#define WL_RATESET_SZ_DSSS 4 ++#define WL_RATESET_SZ_OFDM 8 ++#define WL_RATESET_SZ_HT_MCS 8 ++#define WL_RATESET_SZ_VHT_MCS 10 ++ ++#define WL_TX_CHAINS_MAX 3 ++ ++#define WL_RATE_DISABLED (-128) /* Power value corresponding to unsupported rate */ ++ ++/* Transmit channel bandwidths */ ++typedef enum wl_tx_bw { ++ WL_TX_BW_20, ++ WL_TX_BW_40, ++ WL_TX_BW_80, ++ WL_TX_BW_20IN40, ++ WL_TX_BW_20IN80, ++ WL_TX_BW_40IN80, ++ WL_TX_BW_ALL ++} wl_tx_bw_t; ++ ++ ++/* ++ * Transmit modes. ++ * Not all modes are listed here, only those required for disambiguation. e.g. SPEXP is not listed ++ */ ++typedef enum wl_tx_mode { ++ WL_TX_MODE_NONE, ++ WL_TX_MODE_STBC, ++ WL_TX_MODE_CDD, ++ WL_TX_MODE_SDM ++} wl_tx_mode_t; ++ ++ ++/* Number of transmit chains */ ++typedef enum wl_tx_chains { ++ WL_TX_CHAINS_1 = 1, ++ WL_TX_CHAINS_2, ++ WL_TX_CHAINS_3 ++} wl_tx_chains_t; ++ ++ ++/* Number of transmit streams */ ++typedef enum wl_tx_nss { ++ WL_TX_NSS_1 = 1, ++ WL_TX_NSS_2, ++ WL_TX_NSS_3 ++} wl_tx_nss_t; ++ ++ ++typedef enum clm_rates { ++ /************ ++ * 1 chain * ++ ************ ++ */ ++ ++ /* 1 Stream */ ++ WL_RATE_1X1_DSSS_1 = 0, ++ WL_RATE_1X1_DSSS_2 = 1, ++ WL_RATE_1X1_DSSS_5_5 = 2, ++ WL_RATE_1X1_DSSS_11 = 3, ++ ++ WL_RATE_1X1_OFDM_6 = 4, ++ WL_RATE_1X1_OFDM_9 = 5, ++ WL_RATE_1X1_OFDM_12 = 6, ++ WL_RATE_1X1_OFDM_18 = 7, ++ WL_RATE_1X1_OFDM_24 = 8, ++ WL_RATE_1X1_OFDM_36 = 9, ++ WL_RATE_1X1_OFDM_48 = 10, ++ WL_RATE_1X1_OFDM_54 = 11, ++ ++ WL_RATE_1X1_MCS0 = 12, ++ WL_RATE_1X1_MCS1 = 13, ++ WL_RATE_1X1_MCS2 = 14, ++ WL_RATE_1X1_MCS3 = 15, ++ WL_RATE_1X1_MCS4 = 16, ++ WL_RATE_1X1_MCS5 = 17, ++ WL_RATE_1X1_MCS6 = 18, ++ WL_RATE_1X1_MCS7 = 19, ++ ++ WL_RATE_1X1_VHT0SS1 = 12, ++ WL_RATE_1X1_VHT1SS1 = 13, ++ WL_RATE_1X1_VHT2SS1 = 14, ++ WL_RATE_1X1_VHT3SS1 = 15, ++ WL_RATE_1X1_VHT4SS1 = 16, ++ WL_RATE_1X1_VHT5SS1 = 17, ++ WL_RATE_1X1_VHT6SS1 = 18, ++ WL_RATE_1X1_VHT7SS1 = 19, ++ WL_RATE_1X1_VHT8SS1 = 20, ++ WL_RATE_1X1_VHT9SS1 = 21, ++ ++ ++ /************ ++ * 2 chains * ++ ************ ++ */ ++ ++ /* 1 Stream expanded + 1 */ ++ WL_RATE_1X2_DSSS_1 = 22, ++ WL_RATE_1X2_DSSS_2 = 23, ++ WL_RATE_1X2_DSSS_5_5 = 24, ++ WL_RATE_1X2_DSSS_11 = 25, ++ ++ WL_RATE_1X2_CDD_OFDM_6 = 26, ++ WL_RATE_1X2_CDD_OFDM_9 = 27, ++ WL_RATE_1X2_CDD_OFDM_12 = 28, ++ WL_RATE_1X2_CDD_OFDM_18 = 29, ++ WL_RATE_1X2_CDD_OFDM_24 = 30, ++ WL_RATE_1X2_CDD_OFDM_36 = 31, ++ WL_RATE_1X2_CDD_OFDM_48 = 32, ++ WL_RATE_1X2_CDD_OFDM_54 = 33, ++ ++ WL_RATE_1X2_CDD_MCS0 = 34, ++ WL_RATE_1X2_CDD_MCS1 = 35, ++ WL_RATE_1X2_CDD_MCS2 = 36, ++ WL_RATE_1X2_CDD_MCS3 = 37, ++ WL_RATE_1X2_CDD_MCS4 = 38, ++ WL_RATE_1X2_CDD_MCS5 = 39, ++ WL_RATE_1X2_CDD_MCS6 = 40, ++ WL_RATE_1X2_CDD_MCS7 = 41, ++ ++ WL_RATE_1X2_VHT0SS1 = 34, ++ WL_RATE_1X2_VHT1SS1 = 35, ++ WL_RATE_1X2_VHT2SS1 = 36, ++ WL_RATE_1X2_VHT3SS1 = 37, ++ WL_RATE_1X2_VHT4SS1 = 38, ++ WL_RATE_1X2_VHT5SS1 = 39, ++ WL_RATE_1X2_VHT6SS1 = 40, ++ WL_RATE_1X2_VHT7SS1 = 41, ++ WL_RATE_1X2_VHT8SS1 = 42, ++ WL_RATE_1X2_VHT9SS1 = 43, ++ ++ /* 2 Streams */ ++ WL_RATE_2X2_STBC_MCS0 = 44, ++ WL_RATE_2X2_STBC_MCS1 = 45, ++ WL_RATE_2X2_STBC_MCS2 = 46, ++ WL_RATE_2X2_STBC_MCS3 = 47, ++ WL_RATE_2X2_STBC_MCS4 = 48, ++ WL_RATE_2X2_STBC_MCS5 = 49, ++ WL_RATE_2X2_STBC_MCS6 = 50, ++ WL_RATE_2X2_STBC_MCS7 = 51, ++ ++ WL_RATE_2X2_STBC_VHT0SS1 = 44, ++ WL_RATE_2X2_STBC_VHT1SS1 = 45, ++ WL_RATE_2X2_STBC_VHT2SS1 = 46, ++ WL_RATE_2X2_STBC_VHT3SS1 = 47, ++ WL_RATE_2X2_STBC_VHT4SS1 = 48, ++ WL_RATE_2X2_STBC_VHT5SS1 = 49, ++ WL_RATE_2X2_STBC_VHT6SS1 = 50, ++ WL_RATE_2X2_STBC_VHT7SS1 = 51, ++ WL_RATE_2X2_STBC_VHT8SS1 = 52, ++ WL_RATE_2X2_STBC_VHT9SS1 = 53, ++ ++ WL_RATE_2X2_SDM_MCS8 = 54, ++ WL_RATE_2X2_SDM_MCS9 = 55, ++ WL_RATE_2X2_SDM_MCS10 = 56, ++ WL_RATE_2X2_SDM_MCS11 = 57, ++ WL_RATE_2X2_SDM_MCS12 = 58, ++ WL_RATE_2X2_SDM_MCS13 = 59, ++ WL_RATE_2X2_SDM_MCS14 = 60, ++ WL_RATE_2X2_SDM_MCS15 = 61, ++ ++ WL_RATE_2X2_VHT0SS2 = 54, ++ WL_RATE_2X2_VHT1SS2 = 55, ++ WL_RATE_2X2_VHT2SS2 = 56, ++ WL_RATE_2X2_VHT3SS2 = 57, ++ WL_RATE_2X2_VHT4SS2 = 58, ++ WL_RATE_2X2_VHT5SS2 = 59, ++ WL_RATE_2X2_VHT6SS2 = 60, ++ WL_RATE_2X2_VHT7SS2 = 61, ++ WL_RATE_2X2_VHT8SS2 = 62, ++ WL_RATE_2X2_VHT9SS2 = 63, ++ ++ ++ /************ ++ * 3 chains * ++ ************ ++ */ ++ ++ /* 1 Stream expanded + 2 */ ++ WL_RATE_1X3_DSSS_1 = 64, ++ WL_RATE_1X3_DSSS_2 = 65, ++ WL_RATE_1X3_DSSS_5_5 = 66, ++ WL_RATE_1X3_DSSS_11 = 67, ++ ++ WL_RATE_1X3_CDD_OFDM_6 = 68, ++ WL_RATE_1X3_CDD_OFDM_9 = 69, ++ WL_RATE_1X3_CDD_OFDM_12 = 70, ++ WL_RATE_1X3_CDD_OFDM_18 = 71, ++ WL_RATE_1X3_CDD_OFDM_24 = 72, ++ WL_RATE_1X3_CDD_OFDM_36 = 73, ++ WL_RATE_1X3_CDD_OFDM_48 = 74, ++ WL_RATE_1X3_CDD_OFDM_54 = 75, ++ ++ WL_RATE_1X3_CDD_MCS0 = 76, ++ WL_RATE_1X3_CDD_MCS1 = 77, ++ WL_RATE_1X3_CDD_MCS2 = 78, ++ WL_RATE_1X3_CDD_MCS3 = 79, ++ WL_RATE_1X3_CDD_MCS4 = 80, ++ WL_RATE_1X3_CDD_MCS5 = 81, ++ WL_RATE_1X3_CDD_MCS6 = 82, ++ WL_RATE_1X3_CDD_MCS7 = 83, ++ ++ WL_RATE_1X3_VHT0SS1 = 76, ++ WL_RATE_1X3_VHT1SS1 = 77, ++ WL_RATE_1X3_VHT2SS1 = 78, ++ WL_RATE_1X3_VHT3SS1 = 79, ++ WL_RATE_1X3_VHT4SS1 = 80, ++ WL_RATE_1X3_VHT5SS1 = 81, ++ WL_RATE_1X3_VHT6SS1 = 82, ++ WL_RATE_1X3_VHT7SS1 = 83, ++ WL_RATE_1X3_VHT8SS1 = 84, ++ WL_RATE_1X3_VHT9SS1 = 85, ++ ++ /* 2 Streams expanded + 1 */ ++ WL_RATE_2X3_STBC_MCS0 = 86, ++ WL_RATE_2X3_STBC_MCS1 = 87, ++ WL_RATE_2X3_STBC_MCS2 = 88, ++ WL_RATE_2X3_STBC_MCS3 = 89, ++ WL_RATE_2X3_STBC_MCS4 = 90, ++ WL_RATE_2X3_STBC_MCS5 = 91, ++ WL_RATE_2X3_STBC_MCS6 = 92, ++ WL_RATE_2X3_STBC_MCS7 = 93, ++ ++ WL_RATE_2X3_STBC_VHT0SS1 = 86, ++ WL_RATE_2X3_STBC_VHT1SS1 = 87, ++ WL_RATE_2X3_STBC_VHT2SS1 = 88, ++ WL_RATE_2X3_STBC_VHT3SS1 = 89, ++ WL_RATE_2X3_STBC_VHT4SS1 = 90, ++ WL_RATE_2X3_STBC_VHT5SS1 = 91, ++ WL_RATE_2X3_STBC_VHT6SS1 = 92, ++ WL_RATE_2X3_STBC_VHT7SS1 = 93, ++ WL_RATE_2X3_STBC_VHT8SS1 = 94, ++ WL_RATE_2X3_STBC_VHT9SS1 = 95, ++ ++ WL_RATE_2X3_SDM_MCS8 = 96, ++ WL_RATE_2X3_SDM_MCS9 = 97, ++ WL_RATE_2X3_SDM_MCS10 = 98, ++ WL_RATE_2X3_SDM_MCS11 = 99, ++ WL_RATE_2X3_SDM_MCS12 = 100, ++ WL_RATE_2X3_SDM_MCS13 = 101, ++ WL_RATE_2X3_SDM_MCS14 = 102, ++ WL_RATE_2X3_SDM_MCS15 = 103, ++ ++ WL_RATE_2X3_VHT0SS2 = 96, ++ WL_RATE_2X3_VHT1SS2 = 97, ++ WL_RATE_2X3_VHT2SS2 = 98, ++ WL_RATE_2X3_VHT3SS2 = 99, ++ WL_RATE_2X3_VHT4SS2 = 100, ++ WL_RATE_2X3_VHT5SS2 = 101, ++ WL_RATE_2X3_VHT6SS2 = 102, ++ WL_RATE_2X3_VHT7SS2 = 103, ++ WL_RATE_2X3_VHT8SS2 = 104, ++ WL_RATE_2X3_VHT9SS2 = 105, ++ ++ /* 3 Streams */ ++ WL_RATE_3X3_SDM_MCS16 = 106, ++ WL_RATE_3X3_SDM_MCS17 = 107, ++ WL_RATE_3X3_SDM_MCS18 = 108, ++ WL_RATE_3X3_SDM_MCS19 = 109, ++ WL_RATE_3X3_SDM_MCS20 = 110, ++ WL_RATE_3X3_SDM_MCS21 = 111, ++ WL_RATE_3X3_SDM_MCS22 = 112, ++ WL_RATE_3X3_SDM_MCS23 = 113, ++ ++ WL_RATE_3X3_VHT0SS3 = 106, ++ WL_RATE_3X3_VHT1SS3 = 107, ++ WL_RATE_3X3_VHT2SS3 = 108, ++ WL_RATE_3X3_VHT3SS3 = 109, ++ WL_RATE_3X3_VHT4SS3 = 110, ++ WL_RATE_3X3_VHT5SS3 = 111, ++ WL_RATE_3X3_VHT6SS3 = 112, ++ WL_RATE_3X3_VHT7SS3 = 113, ++ WL_RATE_3X3_VHT8SS3 = 114, ++ WL_RATE_3X3_VHT9SS3 = 115, ++ ++ /* Number of rate codes */ ++ WL_NUMRATES = 116 ++} clm_rates_t; ++ ++#ifdef __cplusplus ++} ++#endif /* __cplusplus */ ++ ++#endif /* _bcmwifi_rates_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/dhdioctl.h b/drivers/net/wireless/ap6211/include/dhdioctl.h +new file mode 100755 +index 0000000..6909dc2 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/dhdioctl.h +@@ -0,0 +1,136 @@ ++/* ++ * Definitions for ioctls to access DHD iovars. ++ * Based on wlioctl.h (for Broadcom 802.11abg driver). ++ * (Moves towards generic ioctls for BCM drivers/iovars.) ++ * ++ * Definitions subject to change without notice. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhdioctl.h 354894 2012-09-04 12:34:07Z $ ++ */ ++ ++#ifndef _dhdioctl_h_ ++#define _dhdioctl_h_ ++ ++#include ++ ++ ++/* require default structure packing */ ++#define BWL_DEFAULT_PACKING ++#include ++ ++ ++/* Linux network driver ioctl encoding */ ++typedef struct dhd_ioctl { ++ uint cmd; /* common ioctl definition */ ++ void *buf; /* pointer to user buffer */ ++ uint len; /* length of user buffer */ ++ bool set; /* get or set request (optional) */ ++ uint used; /* bytes read or written (optional) */ ++ uint needed; /* bytes needed (optional) */ ++ uint driver; /* to identify target driver */ ++} dhd_ioctl_t; ++ ++/* Underlying BUS definition */ ++enum { ++ BUS_TYPE_USB = 0, /* for USB dongles */ ++ BUS_TYPE_SDIO /* for SDIO dongles */ ++}; ++ ++/* per-driver magic numbers */ ++#define DHD_IOCTL_MAGIC 0x00444944 ++ ++/* bump this number if you change the ioctl interface */ ++#define DHD_IOCTL_VERSION 1 ++ ++#define DHD_IOCTL_MAXLEN 8192 /* max length ioctl buffer required */ ++#define DHD_IOCTL_SMLEN 256 /* "small" length ioctl buffer required */ ++ ++/* common ioctl definitions */ ++#define DHD_GET_MAGIC 0 ++#define DHD_GET_VERSION 1 ++#define DHD_GET_VAR 2 ++#define DHD_SET_VAR 3 ++ ++/* message levels */ ++#define DHD_ERROR_VAL 0x0001 ++#define DHD_TRACE_VAL 0x0002 ++#define DHD_INFO_VAL 0x0004 ++#define DHD_DATA_VAL 0x0008 ++#define DHD_CTL_VAL 0x0010 ++#define DHD_TIMER_VAL 0x0020 ++#define DHD_HDRS_VAL 0x0040 ++#define DHD_BYTES_VAL 0x0080 ++#define DHD_INTR_VAL 0x0100 ++#define DHD_LOG_VAL 0x0200 ++#define DHD_GLOM_VAL 0x0400 ++#define DHD_EVENT_VAL 0x0800 ++#define DHD_BTA_VAL 0x1000 ++#if 0 && (NDISVER >= 0x0630) && 1 ++#define DHD_SCAN_VAL 0x2000 ++#else ++#define DHD_ISCAN_VAL 0x2000 ++#endif ++#define DHD_ARPOE_VAL 0x4000 ++#define DHD_REORDER_VAL 0x8000 ++#define DHD_IW_VAL 0x10000 ++#define DHD_CFG_VAL 0x20000 ++ ++#ifdef SDTEST ++/* For pktgen iovar */ ++typedef struct dhd_pktgen { ++ uint version; /* To allow structure change tracking */ ++ uint freq; /* Max ticks between tx/rx attempts */ ++ uint count; /* Test packets to send/rcv each attempt */ ++ uint print; /* Print counts every attempts */ ++ uint total; /* Total packets (or bursts) */ ++ uint minlen; /* Minimum length of packets to send */ ++ uint maxlen; /* Maximum length of packets to send */ ++ uint numsent; /* Count of test packets sent */ ++ uint numrcvd; /* Count of test packets received */ ++ uint numfail; /* Count of test send failures */ ++ uint mode; /* Test mode (type of test packets) */ ++ uint stop; /* Stop after this many tx failures */ ++} dhd_pktgen_t; ++ ++/* Version in case structure changes */ ++#define DHD_PKTGEN_VERSION 2 ++ ++/* Type of test packets to use */ ++#define DHD_PKTGEN_ECHO 1 /* Send echo requests */ ++#define DHD_PKTGEN_SEND 2 /* Send discard packets */ ++#define DHD_PKTGEN_RXBURST 3 /* Request dongle send N packets */ ++#define DHD_PKTGEN_RECV 4 /* Continuous rx from continuous tx dongle */ ++#endif /* SDTEST */ ++ ++/* Enter idle immediately (no timeout) */ ++#define DHD_IDLE_IMMEDIATE (-1) ++ ++/* Values for idleclock iovar: other values are the sd_divisor to use when idle */ ++#define DHD_IDLE_ACTIVE 0 /* Do not request any SD clock change when idle */ ++#define DHD_IDLE_STOP (-1) /* Request SD clock be stopped (and use SD1 mode) */ ++ ++ ++/* require default structure packing */ ++#include ++ ++#endif /* _dhdioctl_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/epivers.h b/drivers/net/wireless/ap6211/include/epivers.h +new file mode 100755 +index 0000000..cff9ebd +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/epivers.h +@@ -0,0 +1,56 @@ ++/* ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: epivers.h.in,v 13.33 2010-09-08 22:08:53 csm Exp $ ++ * ++*/ ++ ++#ifndef _epivers_h_ ++#define _epivers_h_ ++ ++#define EPI_MAJOR_VERSION 1 ++ ++#define EPI_MINOR_VERSION 28 ++ ++#define EPI_RC_NUMBER 23 ++ ++#define EPI_INCREMENTAL_NUMBER 0 ++ ++#define EPI_BUILD_NUMBER 0 ++ ++#define EPI_VERSION 1, 28, 23, 0 ++ ++#define EPI_VERSION_NUM 0x011c1700 ++ ++#define EPI_VERSION_DEV 1.28.23 ++ ++/* Driver Version String, ASCII, 32 chars max */ ++#ifdef BCMINTERNAL ++#define EPI_VERSION_STR "1.28.23.3 (r BCMINT)" ++#else ++#ifdef WLTEST ++#define EPI_VERSION_STR "1.28.23.3 (r WLTEST)" ++#else ++#define EPI_VERSION_STR "1.28.23.3 (r)" ++#endif ++#endif /* BCMINTERNAL */ ++ ++#endif /* _epivers_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/hndpmu.h b/drivers/net/wireless/ap6211/include/hndpmu.h +new file mode 100755 +index 0000000..c41def6 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/hndpmu.h +@@ -0,0 +1,36 @@ ++/* ++ * HND SiliconBackplane PMU support. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: hndpmu.h 241182 2011-02-17 21:50:03Z $ ++ */ ++ ++#ifndef _hndpmu_h_ ++#define _hndpmu_h_ ++ ++ ++extern void si_pmu_otp_power(si_t *sih, osl_t *osh, bool on); ++extern void si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength); ++ ++extern void si_pmu_minresmask_htavail_set(si_t *sih, osl_t *osh, bool set_clear); ++ ++#endif /* _hndpmu_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/hndrte_armtrap.h b/drivers/net/wireless/ap6211/include/hndrte_armtrap.h +new file mode 100755 +index 0000000..90d9799 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/hndrte_armtrap.h +@@ -0,0 +1,88 @@ ++/* ++ * HNDRTE arm trap handling. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: hndrte_armtrap.h 261365 2011-05-24 20:42:23Z $ ++ */ ++ ++#ifndef _hndrte_armtrap_h ++#define _hndrte_armtrap_h ++ ++ ++/* ARM trap handling */ ++ ++/* Trap types defined by ARM (see arminc.h) */ ++ ++/* Trap locations in lo memory */ ++#define TRAP_STRIDE 4 ++#define FIRST_TRAP TR_RST ++#define LAST_TRAP (TR_FIQ * TRAP_STRIDE) ++ ++#if defined(__ARM_ARCH_4T__) ++#define MAX_TRAP_TYPE (TR_FIQ + 1) ++#elif defined(__ARM_ARCH_7M__) ++#define MAX_TRAP_TYPE (TR_ISR + ARMCM3_NUMINTS) ++#endif /* __ARM_ARCH_7M__ */ ++ ++/* The trap structure is defined here as offsets for assembly */ ++#define TR_TYPE 0x00 ++#define TR_EPC 0x04 ++#define TR_CPSR 0x08 ++#define TR_SPSR 0x0c ++#define TR_REGS 0x10 ++#define TR_REG(n) (TR_REGS + (n) * 4) ++#define TR_SP TR_REG(13) ++#define TR_LR TR_REG(14) ++#define TR_PC TR_REG(15) ++ ++#define TRAP_T_SIZE 80 ++ ++#ifndef _LANGUAGE_ASSEMBLY ++ ++#include ++ ++typedef struct _trap_struct { ++ uint32 type; ++ uint32 epc; ++ uint32 cpsr; ++ uint32 spsr; ++ uint32 r0; /* a1 */ ++ uint32 r1; /* a2 */ ++ uint32 r2; /* a3 */ ++ uint32 r3; /* a4 */ ++ uint32 r4; /* v1 */ ++ uint32 r5; /* v2 */ ++ uint32 r6; /* v3 */ ++ uint32 r7; /* v4 */ ++ uint32 r8; /* v5 */ ++ uint32 r9; /* sb/v6 */ ++ uint32 r10; /* sl/v7 */ ++ uint32 r11; /* fp/v8 */ ++ uint32 r12; /* ip */ ++ uint32 r13; /* sp */ ++ uint32 r14; /* lr */ ++ uint32 pc; /* r15 */ ++} trap_t; ++ ++#endif /* !_LANGUAGE_ASSEMBLY */ ++ ++#endif /* _hndrte_armtrap_h */ +diff --git a/drivers/net/wireless/ap6211/include/hndrte_cons.h b/drivers/net/wireless/ap6211/include/hndrte_cons.h +new file mode 100755 +index 0000000..57abbbd +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/hndrte_cons.h +@@ -0,0 +1,67 @@ ++/* ++ * Console support for hndrte. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: hndrte_cons.h 300516 2011-12-04 17:39:44Z $ ++ */ ++#ifndef _HNDRTE_CONS_H ++#define _HNDRTE_CONS_H ++ ++#include ++ ++#define CBUF_LEN (128) ++ ++#define LOG_BUF_LEN 1024 ++ ++typedef struct { ++ uint32 buf; /* Can't be pointer on (64-bit) hosts */ ++ uint buf_size; ++ uint idx; ++ char *_buf_compat; /* redundant pointer for backward compat. */ ++} hndrte_log_t; ++ ++typedef struct { ++ /* Virtual UART ++ * When there is no UART (e.g. Quickturn), the host should write a complete ++ * input line directly into cbuf and then write the length into vcons_in. ++ * This may also be used when there is a real UART (at risk of conflicting with ++ * the real UART). vcons_out is currently unused. ++ */ ++ volatile uint vcons_in; ++ volatile uint vcons_out; ++ ++ /* Output (logging) buffer ++ * Console output is written to a ring buffer log_buf at index log_idx. ++ * The host may read the output when it sees log_idx advance. ++ * Output will be lost if the output wraps around faster than the host polls. ++ */ ++ hndrte_log_t log; ++ ++ /* Console input line buffer ++ * Characters are read one at a time into cbuf until is received, then ++ * the buffer is processed as a command line. Also used for virtual UART. ++ */ ++ uint cbuf_idx; ++ char cbuf[CBUF_LEN]; ++} hndrte_cons_t; ++ ++#endif /* _HNDRTE_CONS_H */ +diff --git a/drivers/net/wireless/ap6211/include/hndsoc.h b/drivers/net/wireless/ap6211/include/hndsoc.h +new file mode 100755 +index 0000000..66640c3 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/hndsoc.h +@@ -0,0 +1,235 @@ ++/* ++ * Broadcom HND chip & on-chip-interconnect-related definitions. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: hndsoc.h 309193 2012-01-19 00:03:57Z $ ++ */ ++ ++#ifndef _HNDSOC_H ++#define _HNDSOC_H ++ ++/* Include the soci specific files */ ++#include ++#include ++ ++/* ++ * SOC Interconnect Address Map. ++ * All regions may not exist on all chips. ++ */ ++#define SI_SDRAM_BASE 0x00000000 /* Physical SDRAM */ ++#define SI_PCI_MEM 0x08000000 /* Host Mode sb2pcitranslation0 (64 MB) */ ++#define SI_PCI_MEM_SZ (64 * 1024 * 1024) ++#define SI_PCI_CFG 0x0c000000 /* Host Mode sb2pcitranslation1 (64 MB) */ ++#define SI_SDRAM_SWAPPED 0x10000000 /* Byteswapped Physical SDRAM */ ++#define SI_SDRAM_R2 0x80000000 /* Region 2 for sdram (512 MB) */ ++ ++#define SI_ENUM_BASE 0x18000000 /* Enumeration space base */ ++ ++#define SI_WRAP_BASE 0x18100000 /* Wrapper space base */ ++#define SI_CORE_SIZE 0x1000 /* each core gets 4Kbytes for registers */ ++#define SI_MAXCORES 16 /* Max cores (this is arbitrary, for software ++ * convenience and could be changed if we ++ * make any larger chips ++ */ ++ ++#define SI_FASTRAM 0x19000000 /* On-chip RAM on chips that also have DDR */ ++#define SI_FASTRAM_SWAPPED 0x19800000 ++ ++#define SI_FLASH2 0x1c000000 /* Flash Region 2 (region 1 shadowed here) */ ++#define SI_FLASH2_SZ 0x02000000 /* Size of Flash Region 2 */ ++#define SI_ARMCM3_ROM 0x1e000000 /* ARM Cortex-M3 ROM */ ++#define SI_FLASH1 0x1fc00000 /* MIPS Flash Region 1 */ ++#define SI_FLASH1_SZ 0x00400000 /* MIPS Size of Flash Region 1 */ ++#define SI_ARM7S_ROM 0x20000000 /* ARM7TDMI-S ROM */ ++#define SI_ARMCR4_ROM 0x000f0000 /* ARM Cortex-R4 ROM */ ++#define SI_ARMCM3_SRAM2 0x60000000 /* ARM Cortex-M3 SRAM Region 2 */ ++#define SI_ARM7S_SRAM2 0x80000000 /* ARM7TDMI-S SRAM Region 2 */ ++#define SI_ARM_FLASH1 0xffff0000 /* ARM Flash Region 1 */ ++#define SI_ARM_FLASH1_SZ 0x00010000 /* ARM Size of Flash Region 1 */ ++ ++#define SI_PCI_DMA 0x40000000 /* Client Mode sb2pcitranslation2 (1 GB) */ ++#define SI_PCI_DMA2 0x80000000 /* Client Mode sb2pcitranslation2 (1 GB) */ ++#define SI_PCI_DMA_SZ 0x40000000 /* Client Mode sb2pcitranslation2 size in bytes */ ++#define SI_PCIE_DMA_L32 0x00000000 /* PCIE Client Mode sb2pcitranslation2 ++ * (2 ZettaBytes), low 32 bits ++ */ ++#define SI_PCIE_DMA_H32 0x80000000 /* PCIE Client Mode sb2pcitranslation2 ++ * (2 ZettaBytes), high 32 bits ++ */ ++ ++/* core codes */ ++#define NODEV_CORE_ID 0x700 /* Invalid coreid */ ++#define CC_CORE_ID 0x800 /* chipcommon core */ ++#define ILINE20_CORE_ID 0x801 /* iline20 core */ ++#define SRAM_CORE_ID 0x802 /* sram core */ ++#define SDRAM_CORE_ID 0x803 /* sdram core */ ++#define PCI_CORE_ID 0x804 /* pci core */ ++#define MIPS_CORE_ID 0x805 /* mips core */ ++#define ENET_CORE_ID 0x806 /* enet mac core */ ++#define CODEC_CORE_ID 0x807 /* v90 codec core */ ++#define USB_CORE_ID 0x808 /* usb 1.1 host/device core */ ++#define ADSL_CORE_ID 0x809 /* ADSL core */ ++#define ILINE100_CORE_ID 0x80a /* iline100 core */ ++#define IPSEC_CORE_ID 0x80b /* ipsec core */ ++#define UTOPIA_CORE_ID 0x80c /* utopia core */ ++#define PCMCIA_CORE_ID 0x80d /* pcmcia core */ ++#define SOCRAM_CORE_ID 0x80e /* internal memory core */ ++#define MEMC_CORE_ID 0x80f /* memc sdram core */ ++#define OFDM_CORE_ID 0x810 /* OFDM phy core */ ++#define EXTIF_CORE_ID 0x811 /* external interface core */ ++#define D11_CORE_ID 0x812 /* 802.11 MAC core */ ++#define APHY_CORE_ID 0x813 /* 802.11a phy core */ ++#define BPHY_CORE_ID 0x814 /* 802.11b phy core */ ++#define GPHY_CORE_ID 0x815 /* 802.11g phy core */ ++#define MIPS33_CORE_ID 0x816 /* mips3302 core */ ++#define USB11H_CORE_ID 0x817 /* usb 1.1 host core */ ++#define USB11D_CORE_ID 0x818 /* usb 1.1 device core */ ++#define USB20H_CORE_ID 0x819 /* usb 2.0 host core */ ++#define USB20D_CORE_ID 0x81a /* usb 2.0 device core */ ++#define SDIOH_CORE_ID 0x81b /* sdio host core */ ++#define ROBO_CORE_ID 0x81c /* roboswitch core */ ++#define ATA100_CORE_ID 0x81d /* parallel ATA core */ ++#define SATAXOR_CORE_ID 0x81e /* serial ATA & XOR DMA core */ ++#define GIGETH_CORE_ID 0x81f /* gigabit ethernet core */ ++#define PCIE_CORE_ID 0x820 /* pci express core */ ++#define NPHY_CORE_ID 0x821 /* 802.11n 2x2 phy core */ ++#define SRAMC_CORE_ID 0x822 /* SRAM controller core */ ++#define MINIMAC_CORE_ID 0x823 /* MINI MAC/phy core */ ++#define ARM11_CORE_ID 0x824 /* ARM 1176 core */ ++#define ARM7S_CORE_ID 0x825 /* ARM7tdmi-s core */ ++#define LPPHY_CORE_ID 0x826 /* 802.11a/b/g phy core */ ++#define PMU_CORE_ID 0x827 /* PMU core */ ++#define SSNPHY_CORE_ID 0x828 /* 802.11n single-stream phy core */ ++#define SDIOD_CORE_ID 0x829 /* SDIO device core */ ++#define ARMCM3_CORE_ID 0x82a /* ARM Cortex M3 core */ ++#define HTPHY_CORE_ID 0x82b /* 802.11n 4x4 phy core */ ++#define MIPS74K_CORE_ID 0x82c /* mips 74k core */ ++#define GMAC_CORE_ID 0x82d /* Gigabit MAC core */ ++#define DMEMC_CORE_ID 0x82e /* DDR1/2 memory controller core */ ++#define PCIERC_CORE_ID 0x82f /* PCIE Root Complex core */ ++#define OCP_CORE_ID 0x830 /* OCP2OCP bridge core */ ++#define SC_CORE_ID 0x831 /* shared common core */ ++#define AHB_CORE_ID 0x832 /* OCP2AHB bridge core */ ++#define SPIH_CORE_ID 0x833 /* SPI host core */ ++#define I2S_CORE_ID 0x834 /* I2S core */ ++#define DMEMS_CORE_ID 0x835 /* SDR/DDR1 memory controller core */ ++#define DEF_SHIM_COMP 0x837 /* SHIM component in ubus/6362 */ ++ ++#define ACPHY_CORE_ID 0x83b /* Dot11 ACPHY */ ++#define PCIE2_CORE_ID 0x83c /* pci express Gen2 core */ ++#define USB30D_CORE_ID 0x83d /* usb 3.0 device core */ ++#define ARMCR4_CORE_ID 0x83e /* ARM CR4 CPU */ ++#define APB_BRIDGE_CORE_ID 0x135 /* APB bridge core ID */ ++#define AXI_CORE_ID 0x301 /* AXI/GPV core ID */ ++#define EROM_CORE_ID 0x366 /* EROM core ID */ ++#define OOB_ROUTER_CORE_ID 0x367 /* OOB router core ID */ ++#define DEF_AI_COMP 0xfff /* Default component, in ai chips it maps all ++ * unused address ranges ++ */ ++ ++#define CC_4706_CORE_ID 0x500 /* chipcommon core */ ++#define SOCRAM_4706_CORE_ID 0x50e /* internal memory core */ ++#define GMAC_COMMON_4706_CORE_ID 0x5dc /* Gigabit MAC core */ ++#define GMAC_4706_CORE_ID 0x52d /* Gigabit MAC core */ ++#define AMEMC_CORE_ID 0x52e /* DDR1/2 memory controller core */ ++#define ALTA_CORE_ID 0x534 /* I2S core */ ++#define DDR23_PHY_CORE_ID 0x5dd ++ ++#define SI_PCI1_MEM 0x40000000 /* Host Mode sb2pcitranslation0 (64 MB) */ ++#define SI_PCI1_CFG 0x44000000 /* Host Mode sb2pcitranslation1 (64 MB) */ ++#define SI_PCIE1_DMA_H32 0xc0000000 /* PCIE Client Mode sb2pcitranslation2 ++ * (2 ZettaBytes), high 32 bits ++ */ ++#define CC_4706B0_CORE_REV 0x8000001f /* chipcommon core */ ++#define SOCRAM_4706B0_CORE_REV 0x80000005 /* internal memory core */ ++#define GMAC_4706B0_CORE_REV 0x80000000 /* Gigabit MAC core */ ++ ++/* There are TWO constants on all HND chips: SI_ENUM_BASE above, ++ * and chipcommon being the first core: ++ */ ++#define SI_CC_IDX 0 ++ ++/* SOC Interconnect types (aka chip types) */ ++#define SOCI_SB 0 ++#define SOCI_AI 1 ++#define SOCI_UBUS 2 ++ ++/* Common core control flags */ ++#define SICF_BIST_EN 0x8000 ++#define SICF_PME_EN 0x4000 ++#define SICF_CORE_BITS 0x3ffc ++#define SICF_FGC 0x0002 ++#define SICF_CLOCK_EN 0x0001 ++ ++/* Common core status flags */ ++#define SISF_BIST_DONE 0x8000 ++#define SISF_BIST_ERROR 0x4000 ++#define SISF_GATED_CLK 0x2000 ++#define SISF_DMA64 0x1000 ++#define SISF_CORE_BITS 0x0fff ++ ++/* A register that is common to all cores to ++ * communicate w/PMU regarding clock control. ++ */ ++#define SI_CLK_CTL_ST 0x1e0 /* clock control and status */ ++ ++/* clk_ctl_st register */ ++#define CCS_FORCEALP 0x00000001 /* force ALP request */ ++#define CCS_FORCEHT 0x00000002 /* force HT request */ ++#define CCS_FORCEILP 0x00000004 /* force ILP request */ ++#define CCS_ALPAREQ 0x00000008 /* ALP Avail Request */ ++#define CCS_HTAREQ 0x00000010 /* HT Avail Request */ ++#define CCS_FORCEHWREQOFF 0x00000020 /* Force HW Clock Request Off */ ++#define CCS_HQCLKREQ 0x00000040 /* HQ Clock Required */ ++#define CCS_USBCLKREQ 0x00000100 /* USB Clock Req */ ++#define CCS_ERSRC_REQ_MASK 0x00000700 /* external resource requests */ ++#define CCS_ERSRC_REQ_SHIFT 8 ++#define CCS_ALPAVAIL 0x00010000 /* ALP is available */ ++#define CCS_HTAVAIL 0x00020000 /* HT is available */ ++#define CCS_BP_ON_APL 0x00040000 /* RO: Backplane is running on ALP clock */ ++#define CCS_BP_ON_HT 0x00080000 /* RO: Backplane is running on HT clock */ ++#define CCS_ERSRC_STS_MASK 0x07000000 /* external resource status */ ++#define CCS_ERSRC_STS_SHIFT 24 ++ ++#define CCS0_HTAVAIL 0x00010000 /* HT avail in chipc and pcmcia on 4328a0 */ ++#define CCS0_ALPAVAIL 0x00020000 /* ALP avail in chipc and pcmcia on 4328a0 */ ++ ++/* Not really related to SOC Interconnect, but a couple of software ++ * conventions for the use the flash space: ++ */ ++ ++/* Minumum amount of flash we support */ ++#define FLASH_MIN 0x00020000 /* Minimum flash size */ ++ ++/* A boot/binary may have an embedded block that describes its size */ ++#define BISZ_OFFSET 0x3e0 /* At this offset into the binary */ ++#define BISZ_MAGIC 0x4249535a /* Marked with this value: 'BISZ' */ ++#define BISZ_MAGIC_IDX 0 /* Word 0: magic */ ++#define BISZ_TXTST_IDX 1 /* 1: text start */ ++#define BISZ_TXTEND_IDX 2 /* 2: text end */ ++#define BISZ_DATAST_IDX 3 /* 3: data start */ ++#define BISZ_DATAEND_IDX 4 /* 4: data end */ ++#define BISZ_BSSST_IDX 5 /* 5: bss start */ ++#define BISZ_BSSEND_IDX 6 /* 6: bss end */ ++#define BISZ_SIZE 7 /* descriptor size in 32-bit integers */ ++ ++#endif /* _HNDSOC_H */ +diff --git a/drivers/net/wireless/ap6211/include/linux_osl.h b/drivers/net/wireless/ap6211/include/linux_osl.h +new file mode 100755 +index 0000000..ca28f6b +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/linux_osl.h +@@ -0,0 +1,430 @@ ++/* ++ * Linux OS Independent Layer ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: linux_osl.h 354452 2012-08-31 04:59:17Z $ ++ */ ++ ++#ifndef _linux_osl_h_ ++#define _linux_osl_h_ ++ ++#include ++ ++/* Linux Kernel: File Operations: start */ ++extern void * osl_os_open_image(char * filename); ++extern int osl_os_get_image_block(char * buf, int len, void * image); ++extern void osl_os_close_image(void * image); ++extern int osl_os_image_size(void *image); ++/* Linux Kernel: File Operations: end */ ++ ++#ifdef BCMDRIVER ++ ++/* OSL initialization */ ++extern osl_t *osl_attach(void *pdev, uint bustype, bool pkttag); ++extern void osl_detach(osl_t *osh); ++ ++/* Global ASSERT type */ ++extern uint32 g_assert_type; ++ ++/* ASSERT */ ++#if defined(BCMASSERT_LOG) ++ #define ASSERT(exp) \ ++ do { if (!(exp)) osl_assert(#exp, __FILE__, __LINE__); } while (0) ++extern void osl_assert(const char *exp, const char *file, int line); ++#else ++ #ifdef __GNUC__ ++ #define GCC_VERSION \ ++ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) ++ #if GCC_VERSION > 30100 ++ #define ASSERT(exp) do {} while (0) ++ #else ++ /* ASSERT could cause segmentation fault on GCC3.1, use empty instead */ ++ #define ASSERT(exp) ++ #endif /* GCC_VERSION > 30100 */ ++ #endif /* __GNUC__ */ ++#endif ++ ++/* microsecond delay */ ++#define OSL_DELAY(usec) osl_delay(usec) ++extern void osl_delay(uint usec); ++ ++#define OSL_PCMCIA_READ_ATTR(osh, offset, buf, size) \ ++ osl_pcmcia_read_attr((osh), (offset), (buf), (size)) ++#define OSL_PCMCIA_WRITE_ATTR(osh, offset, buf, size) \ ++ osl_pcmcia_write_attr((osh), (offset), (buf), (size)) ++extern void osl_pcmcia_read_attr(osl_t *osh, uint offset, void *buf, int size); ++extern void osl_pcmcia_write_attr(osl_t *osh, uint offset, void *buf, int size); ++ ++/* PCI configuration space access macros */ ++#define OSL_PCI_READ_CONFIG(osh, offset, size) \ ++ osl_pci_read_config((osh), (offset), (size)) ++#define OSL_PCI_WRITE_CONFIG(osh, offset, size, val) \ ++ osl_pci_write_config((osh), (offset), (size), (val)) ++extern uint32 osl_pci_read_config(osl_t *osh, uint offset, uint size); ++extern void osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val); ++ ++/* PCI device bus # and slot # */ ++#define OSL_PCI_BUS(osh) osl_pci_bus(osh) ++#define OSL_PCI_SLOT(osh) osl_pci_slot(osh) ++extern uint osl_pci_bus(osl_t *osh); ++extern uint osl_pci_slot(osl_t *osh); ++extern struct pci_dev *osl_pci_device(osl_t *osh); ++ ++/* Pkttag flag should be part of public information */ ++typedef struct { ++ bool pkttag; ++ uint pktalloced; /* Number of allocated packet buffers */ ++ bool mmbus; /* Bus supports memory-mapped register accesses */ ++ pktfree_cb_fn_t tx_fn; /* Callback function for PKTFREE */ ++ void *tx_ctx; /* Context to the callback function */ ++ void *unused[3]; ++} osl_pubinfo_t; ++ ++#define PKTFREESETCB(osh, _tx_fn, _tx_ctx) \ ++ do { \ ++ ((osl_pubinfo_t*)osh)->tx_fn = _tx_fn; \ ++ ((osl_pubinfo_t*)osh)->tx_ctx = _tx_ctx; \ ++ } while (0) ++ ++ ++/* host/bus architecture-specific byte swap */ ++#define BUS_SWAP32(v) (v) ++ ++ #define MALLOC(osh, size) osl_malloc((osh), (size)) ++ #define MFREE(osh, addr, size) osl_mfree((osh), (addr), (size)) ++ #define MALLOCED(osh) osl_malloced((osh)) ++ extern void *osl_malloc(osl_t *osh, uint size); ++ extern void osl_mfree(osl_t *osh, void *addr, uint size); ++ extern uint osl_malloced(osl_t *osh); ++ ++#define NATIVE_MALLOC(osh, size) kmalloc(size, GFP_ATOMIC) ++#define NATIVE_MFREE(osh, addr, size) kfree(addr) ++ ++#define MALLOC_FAILED(osh) osl_malloc_failed((osh)) ++extern uint osl_malloc_failed(osl_t *osh); ++ ++/* allocate/free shared (dma-able) consistent memory */ ++#define DMA_CONSISTENT_ALIGN osl_dma_consistent_align() ++#define DMA_ALLOC_CONSISTENT(osh, size, align, tot, pap, dmah) \ ++ osl_dma_alloc_consistent((osh), (size), (align), (tot), (pap)) ++#define DMA_FREE_CONSISTENT(osh, va, size, pa, dmah) \ ++ osl_dma_free_consistent((osh), (void*)(va), (size), (pa)) ++extern uint osl_dma_consistent_align(void); ++extern void *osl_dma_alloc_consistent(osl_t *osh, uint size, uint16 align, uint *tot, ulong *pap); ++extern void osl_dma_free_consistent(osl_t *osh, void *va, uint size, ulong pa); ++ ++/* map/unmap direction */ ++#define DMA_TX 1 /* TX direction for DMA */ ++#define DMA_RX 2 /* RX direction for DMA */ ++ ++/* map/unmap shared (dma-able) memory */ ++#define DMA_UNMAP(osh, pa, size, direction, p, dmah) \ ++ osl_dma_unmap((osh), (pa), (size), (direction)) ++extern uint osl_dma_map(osl_t *osh, void *va, uint size, int direction); ++extern void osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction); ++ ++/* API for DMA addressing capability */ ++#define OSL_DMADDRWIDTH(osh, addrwidth) do {} while (0) ++ ++/* register access macros */ ++ #include ++ #define OSL_WRITE_REG(osh, r, v) (bcmsdh_reg_write(NULL, (uintptr)(r), sizeof(*(r)), (v))) ++ #define OSL_READ_REG(osh, r) (bcmsdh_reg_read(NULL, (uintptr)(r), sizeof(*(r)))) ++ ++ #define SELECT_BUS_WRITE(osh, mmap_op, bus_op) if (((osl_pubinfo_t*)(osh))->mmbus) \ ++ mmap_op else bus_op ++ #define SELECT_BUS_READ(osh, mmap_op, bus_op) (((osl_pubinfo_t*)(osh))->mmbus) ? \ ++ mmap_op : bus_op ++ ++#define OSL_ERROR(bcmerror) osl_error(bcmerror) ++extern int osl_error(int bcmerror); ++ ++/* the largest reasonable packet buffer driver uses for ethernet MTU in bytes */ ++#define PKTBUFSZ 2048 /* largest reasonable packet buffer, driver uses for ethernet MTU */ ++ ++/* ++ * BINOSL selects the slightly slower function-call-based binary compatible osl. ++ * Macros expand to calls to functions defined in linux_osl.c . ++ */ ++#include /* use current 2.4.x calling conventions */ ++#include /* for vsn/printf's */ ++#include /* for mem*, str* */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 29) ++#define OSL_SYSUPTIME() ((uint32)jiffies_to_msecs(jiffies)) ++#else ++#define OSL_SYSUPTIME() ((uint32)jiffies * (1000 / HZ)) ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 29) */ ++#define printf(fmt, args...) pr_info(fmt , ## args) ++#include /* for vsn/printf's */ ++#include /* for mem*, str* */ ++/* bcopy's: Linux kernel doesn't provide these (anymore) */ ++#define bcopy(src, dst, len) memcpy((dst), (src), (len)) ++#define bcmp(b1, b2, len) memcmp((b1), (b2), (len)) ++#define bzero(b, len) memset((b), '\0', (len)) ++ ++/* register access macros */ ++ ++#define R_REG(osh, r) (\ ++ SELECT_BUS_READ(osh, \ ++ ({ \ ++ __typeof(*(r)) __osl_v; \ ++ BCM_REFERENCE(osh); \ ++ switch (sizeof(*(r))) { \ ++ case sizeof(uint8): __osl_v = \ ++ readb((volatile uint8*)(r)); break; \ ++ case sizeof(uint16): __osl_v = \ ++ readw((volatile uint16*)(r)); break; \ ++ case sizeof(uint32): __osl_v = \ ++ readl((volatile uint32*)(r)); break; \ ++ } \ ++ __osl_v; \ ++ }), \ ++ OSL_READ_REG(osh, r)) \ ++) ++ ++#define W_REG(osh, r, v) do { \ ++ BCM_REFERENCE(osh); \ ++ SELECT_BUS_WRITE(osh, \ ++ switch (sizeof(*(r))) { \ ++ case sizeof(uint8): writeb((uint8)(v), (volatile uint8*)(r)); break; \ ++ case sizeof(uint16): writew((uint16)(v), (volatile uint16*)(r)); break; \ ++ case sizeof(uint32): writel((uint32)(v), (volatile uint32*)(r)); break; \ ++ }, \ ++ (OSL_WRITE_REG(osh, r, v))); \ ++ } while (0) ++ ++#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v)) ++#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v)) ++ ++/* bcopy, bcmp, and bzero functions */ ++#define bcopy(src, dst, len) memcpy((dst), (src), (len)) ++#define bcmp(b1, b2, len) memcmp((b1), (b2), (len)) ++#define bzero(b, len) memset((b), '\0', (len)) ++ ++/* uncached/cached virtual address */ ++#define OSL_UNCACHED(va) ((void *)va) ++#define OSL_CACHED(va) ((void *)va) ++ ++#define OSL_PREF_RANGE_LD(va, sz) ++#define OSL_PREF_RANGE_ST(va, sz) ++ ++/* get processor cycle count */ ++#if defined(__i386__) ++#define OSL_GETCYCLES(x) rdtscl((x)) ++#else ++#define OSL_GETCYCLES(x) ((x) = 0) ++#endif ++ ++/* dereference an address that may cause a bus exception */ ++#define BUSPROBE(val, addr) ({ (val) = R_REG(NULL, (addr)); 0; }) ++ ++/* map/unmap physical to virtual I/O */ ++#if !defined(CONFIG_MMC_MSM7X00A) ++#define REG_MAP(pa, size) ioremap_nocache((unsigned long)(pa), (unsigned long)(size)) ++#else ++#define REG_MAP(pa, size) (void *)(0) ++#endif /* !defined(CONFIG_MMC_MSM7X00A */ ++#define REG_UNMAP(va) iounmap((va)) ++ ++/* shared (dma-able) memory access macros */ ++#define R_SM(r) *(r) ++#define W_SM(r, v) (*(r) = (v)) ++#define BZERO_SM(r, len) memset((r), '\0', (len)) ++ ++/* Because the non BINOSL implemenation of the PKT OSL routines are macros (for ++ * performance reasons), we need the Linux headers. ++ */ ++#include /* use current 2.4.x calling conventions */ ++ ++/* packet primitives */ ++#define PKTGET(osh, len, send) osl_pktget((osh), (len)) ++#define PKTDUP(osh, skb) osl_pktdup((osh), (skb)) ++#define PKTLIST_DUMP(osh, buf) ++#define PKTDBG_TRACE(osh, pkt, bit) ++#define PKTFREE(osh, skb, send) osl_pktfree((osh), (skb), (send)) ++#ifdef CONFIG_DHD_USE_STATIC_BUF ++#define PKTGET_STATIC(osh, len, send) osl_pktget_static((osh), (len)) ++#define PKTFREE_STATIC(osh, skb, send) osl_pktfree_static((osh), (skb), (send)) ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++#define PKTDATA(osh, skb) (((struct sk_buff*)(skb))->data) ++#define PKTLEN(osh, skb) (((struct sk_buff*)(skb))->len) ++#define PKTHEADROOM(osh, skb) (PKTDATA(osh, skb)-(((struct sk_buff*)(skb))->head)) ++#define PKTTAILROOM(osh, skb) ((((struct sk_buff*)(skb))->end)-(((struct sk_buff*)(skb))->tail)) ++#define PKTNEXT(osh, skb) (((struct sk_buff*)(skb))->next) ++#define PKTSETNEXT(osh, skb, x) (((struct sk_buff*)(skb))->next = (struct sk_buff*)(x)) ++#define PKTSETLEN(osh, skb, len) __skb_trim((struct sk_buff*)(skb), (len)) ++#define PKTPUSH(osh, skb, bytes) skb_push((struct sk_buff*)(skb), (bytes)) ++#define PKTPULL(osh, skb, bytes) skb_pull((struct sk_buff*)(skb), (bytes)) ++#define PKTTAG(skb) ((void*)(((struct sk_buff*)(skb))->cb)) ++#define PKTALLOCED(osh) ((osl_pubinfo_t *)(osh))->pktalloced ++#define PKTSETPOOL(osh, skb, x, y) do {} while (0) ++#define PKTPOOL(osh, skb) FALSE ++#define PKTSHRINK(osh, m) (m) ++ ++#ifdef CTFPOOL ++#define CTFPOOL_REFILL_THRESH 3 ++typedef struct ctfpool { ++ void *head; ++ spinlock_t lock; ++ uint max_obj; ++ uint curr_obj; ++ uint obj_size; ++ uint refills; ++ uint fast_allocs; ++ uint fast_frees; ++ uint slow_allocs; ++} ctfpool_t; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) ++#define FASTBUF (1 << 16) ++#define CTFBUF (1 << 17) ++#define PKTSETFAST(osh, skb) ((((struct sk_buff*)(skb))->mac_len) |= FASTBUF) ++#define PKTCLRFAST(osh, skb) ((((struct sk_buff*)(skb))->mac_len) &= (~FASTBUF)) ++#define PKTSETCTF(osh, skb) ((((struct sk_buff*)(skb))->mac_len) |= CTFBUF) ++#define PKTCLRCTF(osh, skb) ((((struct sk_buff*)(skb))->mac_len) &= (~CTFBUF)) ++#define PKTISFAST(osh, skb) ((((struct sk_buff*)(skb))->mac_len) & FASTBUF) ++#define PKTISCTF(osh, skb) ((((struct sk_buff*)(skb))->mac_len) & CTFBUF) ++#define PKTFAST(osh, skb) (((struct sk_buff*)(skb))->mac_len) ++#else ++#define FASTBUF (1 << 0) ++#define CTFBUF (1 << 1) ++#define PKTSETFAST(osh, skb) ((((struct sk_buff*)(skb))->__unused) |= FASTBUF) ++#define PKTCLRFAST(osh, skb) ((((struct sk_buff*)(skb))->__unused) &= (~FASTBUF)) ++#define PKTSETCTF(osh, skb) ((((struct sk_buff*)(skb))->__unused) |= CTFBUF) ++#define PKTCLRCTF(osh, skb) ((((struct sk_buff*)(skb))->__unused) &= (~CTFBUF)) ++#define PKTISFAST(osh, skb) ((((struct sk_buff*)(skb))->__unused) & FASTBUF) ++#define PKTISCTF(osh, skb) ((((struct sk_buff*)(skb))->__unused) & CTFBUF) ++#define PKTFAST(osh, skb) (((struct sk_buff*)(skb))->__unused) ++#endif /* 2.6.22 */ ++ ++#define CTFPOOLPTR(osh, skb) (((struct sk_buff*)(skb))->sk) ++#define CTFPOOLHEAD(osh, skb) (((ctfpool_t *)((struct sk_buff*)(skb))->sk)->head) ++ ++extern void *osl_ctfpool_add(osl_t *osh); ++extern void osl_ctfpool_replenish(osl_t *osh, uint thresh); ++extern int32 osl_ctfpool_init(osl_t *osh, uint numobj, uint size); ++extern void osl_ctfpool_cleanup(osl_t *osh); ++extern void osl_ctfpool_stats(osl_t *osh, void *b); ++#endif /* CTFPOOL */ ++ ++ ++#ifdef HNDCTF ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) ++#define SKIPCT (1 << 18) ++#define PKTSETSKIPCT(osh, skb) (((struct sk_buff*)(skb))->mac_len |= SKIPCT) ++#define PKTCLRSKIPCT(osh, skb) (((struct sk_buff*)(skb))->mac_len &= (~SKIPCT)) ++#define PKTSKIPCT(osh, skb) (((struct sk_buff*)(skb))->mac_len & SKIPCT) ++#else /* 2.6.22 */ ++#define SKIPCT (1 << 2) ++#define PKTSETSKIPCT(osh, skb) (((struct sk_buff*)(skb))->__unused |= SKIPCT) ++#define PKTCLRSKIPCT(osh, skb) (((struct sk_buff*)(skb))->__unused &= (~SKIPCT)) ++#define PKTSKIPCT(osh, skb) (((struct sk_buff*)(skb))->__unused & SKIPCT) ++#endif /* 2.6.22 */ ++#else /* HNDCTF */ ++#define PKTSETSKIPCT(osh, skb) ++#define PKTCLRSKIPCT(osh, skb) ++#define PKTSKIPCT(osh, skb) ++#endif /* HNDCTF */ ++ ++extern void osl_pktfree(osl_t *osh, void *skb, bool send); ++extern void *osl_pktget_static(osl_t *osh, uint len); ++extern void osl_pktfree_static(osl_t *osh, void *skb, bool send); ++ ++extern void *osl_pkt_frmnative(osl_t *osh, void *skb); ++extern void *osl_pktget(osl_t *osh, uint len); ++extern void *osl_pktdup(osl_t *osh, void *skb); ++extern struct sk_buff *osl_pkt_tonative(osl_t *osh, void *pkt); ++#define PKTFRMNATIVE(osh, skb) osl_pkt_frmnative(((osl_t *)osh), (struct sk_buff*)(skb)) ++#define PKTTONATIVE(osh, pkt) osl_pkt_tonative((osl_t *)(osh), (pkt)) ++ ++#define PKTLINK(skb) (((struct sk_buff*)(skb))->prev) ++#define PKTSETLINK(skb, x) (((struct sk_buff*)(skb))->prev = (struct sk_buff*)(x)) ++#define PKTPRIO(skb) (((struct sk_buff*)(skb))->priority) ++#define PKTSETPRIO(skb, x) (((struct sk_buff*)(skb))->priority = (x)) ++#define PKTSUMNEEDED(skb) (((struct sk_buff*)(skb))->ip_summed == CHECKSUM_HW) ++#define PKTSETSUMGOOD(skb, x) (((struct sk_buff*)(skb))->ip_summed = \ ++ ((x) ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE)) ++/* PKTSETSUMNEEDED and PKTSUMGOOD are not possible because skb->ip_summed is overloaded */ ++#define PKTSHARED(skb) (((struct sk_buff*)(skb))->cloned) ++ ++#define DMA_MAP(osh, va, size, direction, p, dmah) \ ++ osl_dma_map((osh), (va), (size), (direction)) ++ ++#ifdef PKTC ++/* Use 8 bytes of skb tstamp field to store below info */ ++struct chain_node { ++ struct sk_buff *link; ++ unsigned int flags:3, pkts:9, bytes:20; ++}; ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) ++#define CHAIN_NODE(skb) ((struct chain_node*)&(((struct sk_buff*)skb)->tstamp)) ++#else ++#define CHAIN_NODE(skb) ((struct chain_node*)&(((struct sk_buff*)skb)->stamp)) ++#endif ++ ++#define PKTCCNT(skb) (CHAIN_NODE(skb)->pkts) ++#define PKTCLEN(skb) (CHAIN_NODE(skb)->bytes) ++#define PKTCFLAGS(skb) (CHAIN_NODE(skb)->flags) ++#define PKTCSETCNT(skb, c) (CHAIN_NODE(skb)->pkts = (c) & ((1 << 9) - 1)) ++#define PKTCSETLEN(skb, l) (CHAIN_NODE(skb)->bytes = (l) & ((1 << 20) - 1)) ++#define PKTCSETFLAG(skb, fb) (CHAIN_NODE(skb)->flags |= (fb)) ++#define PKTCCLRFLAG(skb, fb) (CHAIN_NODE(skb)->flags &= ~(fb)) ++#define PKTCLINK(skb) (CHAIN_NODE(skb)->link) ++#define PKTSETCLINK(skb, x) (CHAIN_NODE(skb)->link = (struct sk_buff*)(x)) ++#define PKTISCHAINED(skb) (PKTCLINK(skb) != NULL) ++#define FOREACH_CHAINED_PKT(skb, nskb) \ ++ for (; (skb) != NULL; (skb) = (nskb)) \ ++ if ((nskb) = PKTCLINK(skb), PKTSETCLINK((skb), NULL), 1) ++#define PKTCFREE(osh, skb, send) \ ++do { \ ++ void *nskb; \ ++ ASSERT((skb) != NULL); \ ++ FOREACH_CHAINED_PKT((skb), nskb) { \ ++ PKTFREE((osh), (skb), (send)); \ ++ } \ ++} while (0) ++#endif /* PKTC */ ++ ++#else /* ! BCMDRIVER */ ++ ++ ++/* ASSERT */ ++ #define ASSERT(exp) do {} while (0) ++ ++/* MALLOC and MFREE */ ++#define MALLOC(o, l) malloc(l) ++#define MFREE(o, p, l) free(p) ++#include ++ ++/* str* and mem* functions */ ++#include ++ ++/* *printf functions */ ++#include ++ ++/* bcopy, bcmp, and bzero */ ++extern void bcopy(const void *src, void *dst, size_t len); ++extern int bcmp(const void *b1, const void *b2, size_t len); ++extern void bzero(void *b, size_t len); ++#endif /* ! BCMDRIVER */ ++ ++#endif /* _linux_osl_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/linuxver.h b/drivers/net/wireless/ap6211/include/linuxver.h +new file mode 100755 +index 0000000..e01b8f0 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/linuxver.h +@@ -0,0 +1,652 @@ ++/* ++ * Linux-specific abstractions to gain some independence from linux kernel versions. ++ * Pave over some 2.2 versus 2.4 versus 2.6 kernel differences. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: linuxver.h 366812 2012-11-05 13:49:32Z $ ++ */ ++ ++#ifndef _linuxver_h_ ++#define _linuxver_h_ ++ ++#include ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) ++#include ++#else ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)) ++#include ++#else ++#include ++#endif ++#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) */ ++#include ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0)) ++/* __NO_VERSION__ must be defined for all linkables except one in 2.2 */ ++#ifdef __UNDEF_NO_VERSION__ ++#undef __NO_VERSION__ ++#else ++#define __NO_VERSION__ ++#endif ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0) */ ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0) ++#define module_param(_name_, _type_, _perm_) MODULE_PARM(_name_, "i") ++#define module_param_string(_name_, _string_, _size_, _perm_) \ ++ MODULE_PARM(_string_, "c" __MODULE_STRING(_size_)) ++#endif ++ ++/* linux/malloc.h is deprecated, use linux/slab.h instead. */ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 9)) ++#include ++#else ++#include ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++#include ++#else ++#include ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)) ++#undef IP_TOS ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)) */ ++#include ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 41)) ++#include ++#else ++#include ++#ifndef work_struct ++#define work_struct tq_struct ++#endif ++#ifndef INIT_WORK ++#define INIT_WORK(_work, _func, _data) INIT_TQUEUE((_work), (_func), (_data)) ++#endif ++#ifndef schedule_work ++#define schedule_work(_work) schedule_task((_work)) ++#endif ++#ifndef flush_scheduled_work ++#define flush_scheduled_work() flush_scheduled_tasks() ++#endif ++#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 41) */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) ++#define DAEMONIZE(a) daemonize(a); \ ++ allow_signal(SIGKILL); \ ++ allow_signal(SIGTERM); ++#else /* Linux 2.4 (w/o preemption patch) */ ++#define RAISE_RX_SOFTIRQ() \ ++ cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ) ++#define DAEMONIZE(a) daemonize(); \ ++ do { if (a) \ ++ strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a)))); \ ++ } while (0); ++#endif /* LINUX_VERSION_CODE */ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) ++#define MY_INIT_WORK(_work, _func) INIT_WORK(_work, _func) ++#else ++#define MY_INIT_WORK(_work, _func) INIT_WORK(_work, _func, _work) ++#if !(LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 18) && defined(RHEL_MAJOR) && \ ++ (RHEL_MAJOR == 5)) ++/* Exclude RHEL 5 */ ++typedef void (*work_func_t)(void *work); ++#endif ++#endif /* >= 2.6.20 */ ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) ++/* Some distributions have their own 2.6.x compatibility layers */ ++#ifndef IRQ_NONE ++typedef void irqreturn_t; ++#define IRQ_NONE ++#define IRQ_HANDLED ++#define IRQ_RETVAL(x) ++#endif ++#else ++typedef irqreturn_t(*FN_ISR) (int irq, void *dev_id, struct pt_regs *ptregs); ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) */ ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) ++#define IRQF_SHARED SA_SHIRQ ++#endif /* < 2.6.18 */ ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 17) ++#ifdef CONFIG_NET_RADIO ++#define CONFIG_WIRELESS_EXT ++#endif ++#endif /* < 2.6.17 */ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 67) ++#define MOD_INC_USE_COUNT ++#define MOD_DEC_USE_COUNT ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 67) */ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) ++#include ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) ++#include ++#endif ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) ++#include ++#else ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) ++#include ++#endif ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) */ ++ ++ ++ ++#ifndef __exit ++#define __exit ++#endif ++#ifndef __devexit ++#define __devexit ++#endif ++#ifndef __devinit ++#define __devinit __init ++#endif ++#ifndef __devinitdata ++#define __devinitdata ++#endif ++#ifndef __devexit_p ++#define __devexit_p(x) x ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)) ++ ++#define pci_get_drvdata(dev) (dev)->sysdata ++#define pci_set_drvdata(dev, value) (dev)->sysdata = (value) ++ ++/* ++ * New-style (2.4.x) PCI/hot-pluggable PCI/CardBus registration ++ */ ++ ++struct pci_device_id { ++ unsigned int vendor, device; /* Vendor and device ID or PCI_ANY_ID */ ++ unsigned int subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */ ++ unsigned int class, class_mask; /* (class,subclass,prog-if) triplet */ ++ unsigned long driver_data; /* Data private to the driver */ ++}; ++ ++struct pci_driver { ++ struct list_head node; ++ char *name; ++ const struct pci_device_id *id_table; /* NULL if wants all devices */ ++ int (*probe)(struct pci_dev *dev, ++ const struct pci_device_id *id); /* New device inserted */ ++ void (*remove)(struct pci_dev *dev); /* Device removed (NULL if not a hot-plug ++ * capable driver) ++ */ ++ void (*suspend)(struct pci_dev *dev); /* Device suspended */ ++ void (*resume)(struct pci_dev *dev); /* Device woken up */ ++}; ++ ++#define MODULE_DEVICE_TABLE(type, name) ++#define PCI_ANY_ID (~0) ++ ++/* compatpci.c */ ++#define pci_module_init pci_register_driver ++extern int pci_register_driver(struct pci_driver *drv); ++extern void pci_unregister_driver(struct pci_driver *drv); ++ ++#endif /* PCI registration */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)) ++#define pci_module_init pci_register_driver ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18)) ++#ifdef MODULE ++#define module_init(x) int init_module(void) { return x(); } ++#define module_exit(x) void cleanup_module(void) { x(); } ++#else ++#define module_init(x) __initcall(x); ++#define module_exit(x) __exitcall(x); ++#endif ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18) */ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) ++#define WL_USE_NETDEV_OPS ++#else ++#undef WL_USE_NETDEV_OPS ++#endif ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) && defined(CONFIG_RFKILL) ++#define WL_CONFIG_RFKILL ++#else ++#undef WL_CONFIG_RFKILL ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 48)) ++#define list_for_each(pos, head) \ ++ for (pos = (head)->next; pos != (head); pos = pos->next) ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 13)) ++#define pci_resource_start(dev, bar) ((dev)->base_address[(bar)]) ++#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 44)) ++#define pci_resource_start(dev, bar) ((dev)->resource[(bar)].start) ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 23)) ++#define pci_enable_device(dev) do { } while (0) ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 14)) ++#define net_device device ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 42)) ++ ++/* ++ * DMA mapping ++ * ++ * See linux/Documentation/DMA-mapping.txt ++ */ ++ ++#ifndef PCI_DMA_TODEVICE ++#define PCI_DMA_TODEVICE 1 ++#define PCI_DMA_FROMDEVICE 2 ++#endif ++ ++typedef u32 dma_addr_t; ++ ++/* Pure 2^n version of get_order */ ++static inline int get_order(unsigned long size) ++{ ++ int order; ++ ++ size = (size-1) >> (PAGE_SHIFT-1); ++ order = -1; ++ do { ++ size >>= 1; ++ order++; ++ } while (size); ++ return order; ++} ++ ++static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, ++ dma_addr_t *dma_handle) ++{ ++ void *ret; ++ int gfp = GFP_ATOMIC | GFP_DMA; ++ ++ ret = (void *)__get_free_pages(gfp, get_order(size)); ++ ++ if (ret != NULL) { ++ memset(ret, 0, size); ++ *dma_handle = virt_to_bus(ret); ++ } ++ return ret; ++} ++static inline void pci_free_consistent(struct pci_dev *hwdev, size_t size, ++ void *vaddr, dma_addr_t dma_handle) ++{ ++ free_pages((unsigned long)vaddr, get_order(size)); ++} ++#define pci_map_single(cookie, address, size, dir) virt_to_bus(address) ++#define pci_unmap_single(cookie, address, size, dir) ++ ++#endif /* DMA mapping */ ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 43)) ++ ++#define dev_kfree_skb_any(a) dev_kfree_skb(a) ++#define netif_down(dev) do { (dev)->start = 0; } while (0) ++ ++/* pcmcia-cs provides its own netdevice compatibility layer */ ++#ifndef _COMPAT_NETDEVICE_H ++ ++/* ++ * SoftNet ++ * ++ * For pre-softnet kernels we need to tell the upper layer not to ++ * re-enter start_xmit() while we are in there. However softnet ++ * guarantees not to enter while we are in there so there is no need ++ * to do the netif_stop_queue() dance unless the transmit queue really ++ * gets stuck. This should also improve performance according to tests ++ * done by Aman Singla. ++ */ ++ ++#define dev_kfree_skb_irq(a) dev_kfree_skb(a) ++#define netif_wake_queue(dev) \ ++ do { clear_bit(0, &(dev)->tbusy); mark_bh(NET_BH); } while (0) ++#define netif_stop_queue(dev) set_bit(0, &(dev)->tbusy) ++ ++static inline void netif_start_queue(struct net_device *dev) ++{ ++ dev->tbusy = 0; ++ dev->interrupt = 0; ++ dev->start = 1; ++} ++ ++#define netif_queue_stopped(dev) (dev)->tbusy ++#define netif_running(dev) (dev)->start ++ ++#endif /* _COMPAT_NETDEVICE_H */ ++ ++#define netif_device_attach(dev) netif_start_queue(dev) ++#define netif_device_detach(dev) netif_stop_queue(dev) ++ ++/* 2.4.x renamed bottom halves to tasklets */ ++#define tasklet_struct tq_struct ++static inline void tasklet_schedule(struct tasklet_struct *tasklet) ++{ ++ queue_task(tasklet, &tq_immediate); ++ mark_bh(IMMEDIATE_BH); ++} ++ ++static inline void tasklet_init(struct tasklet_struct *tasklet, ++ void (*func)(unsigned long), ++ unsigned long data) ++{ ++ tasklet->next = NULL; ++ tasklet->sync = 0; ++ tasklet->routine = (void (*)(void *))func; ++ tasklet->data = (void *)data; ++} ++#define tasklet_kill(tasklet) { do {} while (0); } ++ ++/* 2.4.x introduced del_timer_sync() */ ++#define del_timer_sync(timer) del_timer(timer) ++ ++#else ++ ++#define netif_down(dev) ++ ++#endif /* SoftNet */ ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 3)) ++ ++/* ++ * Emit code to initialise a tq_struct's routine and data pointers ++ */ ++#define PREPARE_TQUEUE(_tq, _routine, _data) \ ++ do { \ ++ (_tq)->routine = _routine; \ ++ (_tq)->data = _data; \ ++ } while (0) ++ ++/* ++ * Emit code to initialise all of a tq_struct ++ */ ++#define INIT_TQUEUE(_tq, _routine, _data) \ ++ do { \ ++ INIT_LIST_HEAD(&(_tq)->list); \ ++ (_tq)->sync = 0; \ ++ PREPARE_TQUEUE((_tq), (_routine), (_data)); \ ++ } while (0) ++ ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 3) */ ++ ++/* Power management related macro & routines */ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 9) ++#define PCI_SAVE_STATE(a, b) pci_save_state(a) ++#define PCI_RESTORE_STATE(a, b) pci_restore_state(a) ++#else ++#define PCI_SAVE_STATE(a, b) pci_save_state(a, b) ++#define PCI_RESTORE_STATE(a, b) pci_restore_state(a, b) ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 6)) ++static inline int ++pci_save_state(struct pci_dev *dev, u32 *buffer) ++{ ++ int i; ++ if (buffer) { ++ for (i = 0; i < 16; i++) ++ pci_read_config_dword(dev, i * 4, &buffer[i]); ++ } ++ return 0; ++} ++ ++static inline int ++pci_restore_state(struct pci_dev *dev, u32 *buffer) ++{ ++ int i; ++ ++ if (buffer) { ++ for (i = 0; i < 16; i++) ++ pci_write_config_dword(dev, i * 4, buffer[i]); ++ } ++ /* ++ * otherwise, write the context information we know from bootup. ++ * This works around a problem where warm-booting from Windows ++ * combined with a D3(hot)->D0 transition causes PCI config ++ * header data to be forgotten. ++ */ ++ else { ++ for (i = 0; i < 6; i ++) ++ pci_write_config_dword(dev, ++ PCI_BASE_ADDRESS_0 + (i * 4), ++ pci_resource_start(dev, i)); ++ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); ++ } ++ return 0; ++} ++#endif /* PCI power management */ ++ ++/* Old cp0 access macros deprecated in 2.4.19 */ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 19)) ++#define read_c0_count() read_32bit_cp0_register(CP0_COUNT) ++#endif ++ ++/* Module refcount handled internally in 2.6.x */ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)) ++#ifndef SET_MODULE_OWNER ++#define SET_MODULE_OWNER(dev) do {} while (0) ++#define OLD_MOD_INC_USE_COUNT MOD_INC_USE_COUNT ++#define OLD_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT ++#else ++#define OLD_MOD_INC_USE_COUNT do {} while (0) ++#define OLD_MOD_DEC_USE_COUNT do {} while (0) ++#endif ++#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) */ ++#ifndef SET_MODULE_OWNER ++#define SET_MODULE_OWNER(dev) do {} while (0) ++#endif ++#ifndef MOD_INC_USE_COUNT ++#define MOD_INC_USE_COUNT do {} while (0) ++#endif ++#ifndef MOD_DEC_USE_COUNT ++#define MOD_DEC_USE_COUNT do {} while (0) ++#endif ++#define OLD_MOD_INC_USE_COUNT MOD_INC_USE_COUNT ++#define OLD_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) */ ++ ++#ifndef SET_NETDEV_DEV ++#define SET_NETDEV_DEV(net, pdev) do {} while (0) ++#endif ++ ++#ifndef HAVE_FREE_NETDEV ++#define free_netdev(dev) kfree(dev) ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) ++/* struct packet_type redefined in 2.6.x */ ++#define af_packet_priv data ++#endif ++ ++/* suspend args */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11) ++#define DRV_SUSPEND_STATE_TYPE pm_message_t ++#else ++#define DRV_SUSPEND_STATE_TYPE uint32 ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) ++#define CHECKSUM_HW CHECKSUM_PARTIAL ++#endif ++ ++typedef struct { ++ void *parent; /* some external entity that the thread supposed to work for */ ++ struct task_struct *p_task; ++ long thr_pid; ++ int prio; /* priority */ ++ struct semaphore sema; ++ int terminated; ++ struct completion completed; ++} tsk_ctl_t; ++ ++ ++/* requires tsk_ctl_t tsk argument, the caller's priv data is passed in owner ptr */ ++/* note this macro assumes there may be only one context waiting on thread's completion */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) ++#define SMP_RD_BARRIER_DEPENDS(x) smp_read_barrier_depends(x) ++#else ++#define SMP_RD_BARRIER_DEPENDS(x) smp_rmb(x) ++#endif ++ ++ ++#define PROC_START(thread_func, owner, tsk_ctl, flags) \ ++{ \ ++ sema_init(&((tsk_ctl)->sema), 0); \ ++ init_completion(&((tsk_ctl)->completed)); \ ++ (tsk_ctl)->parent = owner; \ ++ (tsk_ctl)->terminated = FALSE; \ ++ (tsk_ctl)->thr_pid = kernel_thread(thread_func, tsk_ctl, flags); \ ++ if ((tsk_ctl)->thr_pid > 0) \ ++ wait_for_completion(&((tsk_ctl)->completed)); \ ++} ++ ++#ifdef USE_KTHREAD_API ++#define PROC_START2(thread_func, owner, tsk_ctl, flags, name) \ ++{ \ ++ sema_init(&((tsk_ctl)->sema), 0); \ ++ init_completion(&((tsk_ctl)->completed)); \ ++ (tsk_ctl)->parent = owner; \ ++ (tsk_ctl)->terminated = FALSE; \ ++ (tsk_ctl)->p_task = kthread_run(thread_func, tsk_ctl, (char*)name); \ ++ (tsk_ctl)->thr_pid = (tsk_ctl)->p_task->pid; \ ++} ++#endif ++ ++#define PROC_STOP(tsk_ctl) \ ++{ \ ++ (tsk_ctl)->terminated = TRUE; \ ++ smp_wmb(); \ ++ up(&((tsk_ctl)->sema)); \ ++ wait_for_completion(&((tsk_ctl)->completed)); \ ++ (tsk_ctl)->thr_pid = -1; \ ++} ++ ++/* ----------------------- */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) ++#define KILL_PROC(nr, sig) \ ++{ \ ++struct task_struct *tsk; \ ++struct pid *pid; \ ++pid = find_get_pid((pid_t)nr); \ ++tsk = pid_task(pid, PIDTYPE_PID); \ ++if (tsk) send_sig(sig, tsk, 1); \ ++} ++#else ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (LINUX_VERSION_CODE <= \ ++ KERNEL_VERSION(2, 6, 30)) ++#define KILL_PROC(pid, sig) \ ++{ \ ++ struct task_struct *tsk; \ ++ tsk = find_task_by_vpid(pid); \ ++ if (tsk) send_sig(sig, tsk, 1); \ ++} ++#else ++#define KILL_PROC(pid, sig) \ ++{ \ ++ kill_proc(pid, sig, 1); \ ++} ++#endif ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) ++#include ++#include ++#else ++#include ++ ++#define __wait_event_interruptible_timeout(wq, condition, ret) \ ++do { \ ++ wait_queue_t __wait; \ ++ init_waitqueue_entry(&__wait, current); \ ++ \ ++ add_wait_queue(&wq, &__wait); \ ++ for (;;) { \ ++ set_current_state(TASK_INTERRUPTIBLE); \ ++ if (condition) \ ++ break; \ ++ if (!signal_pending(current)) { \ ++ ret = schedule_timeout(ret); \ ++ if (!ret) \ ++ break; \ ++ continue; \ ++ } \ ++ ret = -ERESTARTSYS; \ ++ break; \ ++ } \ ++ current->state = TASK_RUNNING; \ ++ remove_wait_queue(&wq, &__wait); \ ++} while (0) ++ ++#define wait_event_interruptible_timeout(wq, condition, timeout) \ ++({ \ ++ long __ret = timeout; \ ++ if (!(condition)) \ ++ __wait_event_interruptible_timeout(wq, condition, __ret); \ ++ __ret; \ ++}) ++ ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) */ ++ ++/* ++For < 2.6.24, wl creates its own netdev but doesn't ++align the priv area like the genuine alloc_netdev(). ++Since netdev_priv() always gives us the aligned address, it will ++not match our unaligned address for < 2.6.24 ++*/ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)) ++#define DEV_PRIV(dev) (dev->priv) ++#else ++#define DEV_PRIV(dev) netdev_priv(dev) ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) ++#define WL_ISR(i, d, p) wl_isr((i), (d)) ++#else ++#define WL_ISR(i, d, p) wl_isr((i), (d), (p)) ++#endif /* < 2.6.20 */ ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) ++#define netdev_priv(dev) dev->priv ++#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) */ ++ ++#endif /* _linuxver_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/miniopt.h b/drivers/net/wireless/ap6211/include/miniopt.h +new file mode 100755 +index 0000000..c1eca68 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/miniopt.h +@@ -0,0 +1,77 @@ ++/* ++ * Command line options parser. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * $Id: miniopt.h 241182 2011-02-17 21:50:03Z $ ++ */ ++ ++ ++#ifndef MINI_OPT_H ++#define MINI_OPT_H ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* ---- Include Files ---------------------------------------------------- */ ++/* ---- Constants and Types ---------------------------------------------- */ ++ ++#define MINIOPT_MAXKEY 128 /* Max options */ ++typedef struct miniopt { ++ ++ /* These are persistent after miniopt_init() */ ++ const char* name; /* name for prompt in error strings */ ++ const char* flags; /* option chars that take no args */ ++ bool longflags; /* long options may be flags */ ++ bool opt_end; /* at end of options (passed a "--") */ ++ ++ /* These are per-call to miniopt() */ ++ ++ int consumed; /* number of argv entries cosumed in ++ * the most recent call to miniopt() ++ */ ++ bool positional; ++ bool good_int; /* 'val' member is the result of a sucessful ++ * strtol conversion of the option value ++ */ ++ char opt; ++ char key[MINIOPT_MAXKEY]; ++ char* valstr; /* positional param, or value for the option, ++ * or null if the option had ++ * no accompanying value ++ */ ++ uint uval; /* strtol translation of valstr */ ++ int val; /* strtol translation of valstr */ ++} miniopt_t; ++ ++void miniopt_init(miniopt_t *t, const char* name, const char* flags, bool longflags); ++int miniopt(miniopt_t *t, char **argv); ++ ++ ++/* ---- Variable Externs ------------------------------------------------- */ ++/* ---- Function Prototypes ---------------------------------------------- */ ++ ++ ++#ifdef __cplusplus ++ } ++#endif ++ ++#endif /* MINI_OPT_H */ +diff --git a/drivers/net/wireless/ap6211/include/msgtrace.h b/drivers/net/wireless/ap6211/include/msgtrace.h +new file mode 100755 +index 0000000..7c5fd81 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/msgtrace.h +@@ -0,0 +1,74 @@ ++/* ++ * Trace messages sent over HBUS ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: msgtrace.h 281527 2011-09-02 17:12:53Z $ ++ */ ++ ++#ifndef _MSGTRACE_H ++#define _MSGTRACE_H ++ ++#ifndef _TYPEDEFS_H_ ++#include ++#endif ++ ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++#define MSGTRACE_VERSION 1 ++ ++/* Message trace header */ ++typedef BWL_PRE_PACKED_STRUCT struct msgtrace_hdr { ++ uint8 version; ++ uint8 spare; ++ uint16 len; /* Len of the trace */ ++ uint32 seqnum; /* Sequence number of message. Useful if the messsage has been lost ++ * because of DMA error or a bus reset (ex: SDIO Func2) ++ */ ++ uint32 discarded_bytes; /* Number of discarded bytes because of trace overflow */ ++ uint32 discarded_printf; /* Number of discarded printf because of trace overflow */ ++} BWL_POST_PACKED_STRUCT msgtrace_hdr_t; ++ ++#define MSGTRACE_HDRLEN sizeof(msgtrace_hdr_t) ++ ++/* The hbus driver generates traces when sending a trace message. This causes endless traces. ++ * This flag must be set to TRUE in any hbus traces. The flag is reset in the function msgtrace_put. ++ * This prevents endless traces but generates hasardous lost of traces only in bus device code. ++ * It is recommendat to set this flag in macro SD_TRACE but not in SD_ERROR for avoiding missing ++ * hbus error traces. hbus error trace should not generates endless traces. ++ */ ++extern bool msgtrace_hbus_trace; ++ ++typedef void (*msgtrace_func_send_t)(void *hdl1, void *hdl2, uint8 *hdr, ++ uint16 hdrlen, uint8 *buf, uint16 buflen); ++extern void msgtrace_start(void); ++extern void msgtrace_stop(void); ++extern void msgtrace_sent(void); ++extern void msgtrace_put(char *buf, int count); ++extern void msgtrace_init(void *hdl1, void *hdl2, msgtrace_func_send_t func_send); ++extern bool msgtrace_event_enabled(void); ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* _MSGTRACE_H */ +diff --git a/drivers/net/wireless/ap6211/include/osl.h b/drivers/net/wireless/ap6211/include/osl.h +new file mode 100755 +index 0000000..0a11d23 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/osl.h +@@ -0,0 +1,90 @@ ++/* ++ * OS Abstraction Layer ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: osl.h 320905 2012-03-13 15:33:25Z $ ++ */ ++ ++#ifndef _osl_h_ ++#define _osl_h_ ++ ++/* osl handle type forward declaration */ ++typedef struct osl_info osl_t; ++typedef struct osl_dmainfo osldma_t; ++ ++#define OSL_PKTTAG_SZ 32 /* Size of PktTag */ ++ ++/* Drivers use PKTFREESETCB to register a callback function when a packet is freed by OSL */ ++typedef void (*pktfree_cb_fn_t)(void *ctx, void *pkt, unsigned int status); ++ ++/* Drivers use REGOPSSET() to register register read/write funcitons */ ++typedef unsigned int (*osl_rreg_fn_t)(void *ctx, volatile void *reg, unsigned int size); ++typedef void (*osl_wreg_fn_t)(void *ctx, volatile void *reg, unsigned int val, unsigned int size); ++ ++ ++#include ++ ++#ifndef PKTDBG_TRACE ++#define PKTDBG_TRACE(osh, pkt, bit) ++#endif ++ ++#define PKTCTFMAP(osh, p) ++ ++/* -------------------------------------------------------------------------- ++** Register manipulation macros. ++*/ ++ ++#define SET_REG(osh, r, mask, val) W_REG((osh), (r), ((R_REG((osh), r) & ~(mask)) | (val))) ++ ++#ifndef AND_REG ++#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v)) ++#endif /* !AND_REG */ ++ ++#ifndef OR_REG ++#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v)) ++#endif /* !OR_REG */ ++ ++#if !defined(OSL_SYSUPTIME) ++#define OSL_SYSUPTIME() (0) ++#define OSL_SYSUPTIME_SUPPORT FALSE ++#else ++#define OSL_SYSUPTIME_SUPPORT TRUE ++#endif /* OSL_SYSUPTIME */ ++ ++#if !defined(PKTC) ++#define PKTCCNT(skb) (0) ++#define PKTCLEN(skb) (0) ++#define PKTCFLAGS(skb) (0) ++#define PKTCSETCNT(skb, c) ++#define PKTCSETLEN(skb, l) ++#define PKTCSETFLAG(skb, fb) ++#define PKTCCLRFLAG(skb, fb) ++#define PKTCLINK(skb) PKTLINK(skb) ++#define PKTSETCLINK(skb, x) PKTSETLINK((skb), (x)) ++#define PKTISCHAINED(skb) FALSE ++#define FOREACH_CHAINED_PKT(skb, nskb) \ ++ for ((nskb) = NULL; (skb) != NULL; (skb) = (nskb)) ++#define PKTCFREE PKTFREE ++#endif ++ ++ ++#endif /* _osl_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/packed_section_end.h b/drivers/net/wireless/ap6211/include/packed_section_end.h +new file mode 100755 +index 0000000..0779b04 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/packed_section_end.h +@@ -0,0 +1,59 @@ ++/* ++ * Declare directives for structure packing. No padding will be provided ++ * between the members of packed structures, and therefore, there is no ++ * guarantee that structure members will be aligned. ++ * ++ * Declaring packed structures is compiler specific. In order to handle all ++ * cases, packed structures should be delared as: ++ * ++ * #include ++ * ++ * typedef BWL_PRE_PACKED_STRUCT struct foobar_t { ++ * some_struct_members; ++ * } BWL_POST_PACKED_STRUCT foobar_t; ++ * ++ * #include ++ * ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * $Id: packed_section_end.h 241182 2011-02-17 21:50:03Z $ ++ */ ++ ++ ++/* Error check - BWL_PACKED_SECTION is defined in packed_section_start.h ++ * and undefined in packed_section_end.h. If it is NOT defined at this ++ * point, then there is a missing include of packed_section_start.h. ++ */ ++#ifdef BWL_PACKED_SECTION ++ #undef BWL_PACKED_SECTION ++#else ++ #error "BWL_PACKED_SECTION is NOT defined!" ++#endif ++ ++ ++ ++ ++/* Compiler-specific directives for structure packing are declared in ++ * packed_section_start.h. This marks the end of the structure packing section, ++ * so, undef them here. ++ */ ++#undef BWL_PRE_PACKED_STRUCT ++#undef BWL_POST_PACKED_STRUCT +diff --git a/drivers/net/wireless/ap6211/include/packed_section_start.h b/drivers/net/wireless/ap6211/include/packed_section_start.h +new file mode 100755 +index 0000000..ee93a4b +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/packed_section_start.h +@@ -0,0 +1,63 @@ ++/* ++ * Declare directives for structure packing. No padding will be provided ++ * between the members of packed structures, and therefore, there is no ++ * guarantee that structure members will be aligned. ++ * ++ * Declaring packed structures is compiler specific. In order to handle all ++ * cases, packed structures should be delared as: ++ * ++ * #include ++ * ++ * typedef BWL_PRE_PACKED_STRUCT struct foobar_t { ++ * some_struct_members; ++ * } BWL_POST_PACKED_STRUCT foobar_t; ++ * ++ * #include ++ * ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * $Id: packed_section_start.h 286783 2011-09-29 06:18:57Z $ ++ */ ++ ++ ++/* Error check - BWL_PACKED_SECTION is defined in packed_section_start.h ++ * and undefined in packed_section_end.h. If it is already defined at this ++ * point, then there is a missing include of packed_section_end.h. ++ */ ++#ifdef BWL_PACKED_SECTION ++ #error "BWL_PACKED_SECTION is already defined!" ++#else ++ #define BWL_PACKED_SECTION ++#endif ++ ++ ++ ++ ++/* Declare compiler-specific directives for structure packing. */ ++#if defined(__GNUC__) || defined(__lint) ++ #define BWL_PRE_PACKED_STRUCT ++ #define BWL_POST_PACKED_STRUCT __attribute__ ((packed)) ++#elif defined(__CC_ARM) ++ #define BWL_PRE_PACKED_STRUCT __packed ++ #define BWL_POST_PACKED_STRUCT ++#else ++ #error "Unknown compiler!" ++#endif +diff --git a/drivers/net/wireless/ap6211/include/pcicfg.h b/drivers/net/wireless/ap6211/include/pcicfg.h +new file mode 100755 +index 0000000..0278bb2 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/pcicfg.h +@@ -0,0 +1,100 @@ ++/* ++ * pcicfg.h: PCI configuration constants and structures. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: pcicfg.h 309193 2012-01-19 00:03:57Z $ ++ */ ++ ++#ifndef _h_pcicfg_ ++#define _h_pcicfg_ ++ ++/* A structure for the config registers is nice, but in most ++ * systems the config space is not memory mapped, so we need ++ * field offsetts. :-( ++ */ ++#define PCI_CFG_VID 0 ++#define PCI_CFG_DID 2 ++#define PCI_CFG_CMD 4 ++#define PCI_CFG_STAT 6 ++#define PCI_CFG_REV 8 ++#define PCI_CFG_PROGIF 9 ++#define PCI_CFG_SUBCL 0xa ++#define PCI_CFG_BASECL 0xb ++#define PCI_CFG_CLSZ 0xc ++#define PCI_CFG_LATTIM 0xd ++#define PCI_CFG_HDR 0xe ++#define PCI_CFG_BIST 0xf ++#define PCI_CFG_BAR0 0x10 ++#define PCI_CFG_BAR1 0x14 ++#define PCI_CFG_BAR2 0x18 ++#define PCI_CFG_BAR3 0x1c ++#define PCI_CFG_BAR4 0x20 ++#define PCI_CFG_BAR5 0x24 ++#define PCI_CFG_CIS 0x28 ++#define PCI_CFG_SVID 0x2c ++#define PCI_CFG_SSID 0x2e ++#define PCI_CFG_ROMBAR 0x30 ++#define PCI_CFG_CAPPTR 0x34 ++#define PCI_CFG_INT 0x3c ++#define PCI_CFG_PIN 0x3d ++#define PCI_CFG_MINGNT 0x3e ++#define PCI_CFG_MAXLAT 0x3f ++#define PCI_BAR0_WIN 0x80 /* backplane addres space accessed by BAR0 */ ++#define PCI_BAR1_WIN 0x84 /* backplane addres space accessed by BAR1 */ ++#define PCI_SPROM_CONTROL 0x88 /* sprom property control */ ++#define PCI_BAR1_CONTROL 0x8c /* BAR1 region burst control */ ++#define PCI_INT_STATUS 0x90 /* PCI and other cores interrupts */ ++#define PCI_INT_MASK 0x94 /* mask of PCI and other cores interrupts */ ++#define PCI_TO_SB_MB 0x98 /* signal backplane interrupts */ ++#define PCI_BACKPLANE_ADDR 0xa0 /* address an arbitrary location on the system backplane */ ++#define PCI_BACKPLANE_DATA 0xa4 /* data at the location specified by above address */ ++#define PCI_CLK_CTL_ST 0xa8 /* pci config space clock control/status (>=rev14) */ ++#define PCI_BAR0_WIN2 0xac /* backplane addres space accessed by second 4KB of BAR0 */ ++#define PCI_GPIO_IN 0xb0 /* pci config space gpio input (>=rev3) */ ++#define PCI_GPIO_OUT 0xb4 /* pci config space gpio output (>=rev3) */ ++#define PCI_GPIO_OUTEN 0xb8 /* pci config space gpio output enable (>=rev3) */ ++ ++#define PCI_BAR0_SHADOW_OFFSET (2 * 1024) /* bar0 + 2K accesses sprom shadow (in pci core) */ ++#define PCI_BAR0_SPROM_OFFSET (4 * 1024) /* bar0 + 4K accesses external sprom */ ++#define PCI_BAR0_PCIREGS_OFFSET (6 * 1024) /* bar0 + 6K accesses pci core registers */ ++#define PCI_BAR0_PCISBR_OFFSET (4 * 1024) /* pci core SB registers are at the end of the ++ * 8KB window, so their address is the "regular" ++ * address plus 4K ++ */ ++/* ++ * PCIE GEN2 changed some of the above locations for ++ * Bar0WrapperBase, SecondaryBAR0Window and SecondaryBAR0WrapperBase ++ * BAR0 maps 32K of register space ++*/ ++#define PCIE2_BAR0_WIN2 0x70 /* backplane addres space accessed by second 4KB of BAR0 */ ++#define PCIE2_BAR0_CORE2_WIN 0x74 /* backplane addres space accessed by second 4KB of BAR0 */ ++#define PCIE2_BAR0_CORE2_WIN2 0x78 /* backplane addres space accessed by second 4KB of BAR0 */ ++ ++#define PCI_BAR0_WINSZ (16 * 1024) /* bar0 window size Match with corerev 13 */ ++/* On pci corerev >= 13 and all pcie, the bar0 is now 16KB and it maps: */ ++#define PCI_16KB0_PCIREGS_OFFSET (8 * 1024) /* bar0 + 8K accesses pci/pcie core registers */ ++#define PCI_16KB0_CCREGS_OFFSET (12 * 1024) /* bar0 + 12K accesses chipc core registers */ ++#define PCI_16KBB0_WINSZ (16 * 1024) /* bar0 window size */ ++ ++ ++#define PCI_CONFIG_SPACE_SIZE 256 ++#endif /* _h_pcicfg_ */ +diff --git a/drivers/net/wireless/ap6211/include/proto/802.11.h b/drivers/net/wireless/ap6211/include/proto/802.11.h +new file mode 100755 +index 0000000..15cd56c +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/proto/802.11.h +@@ -0,0 +1,2355 @@ ++/* ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * Fundamental types and constants relating to 802.11 ++ * ++ * $Id: 802.11.h 346820 2012-07-24 13:53:12Z $ ++ */ ++ ++#ifndef _802_11_H_ ++#define _802_11_H_ ++ ++#ifndef _TYPEDEFS_H_ ++#include ++#endif ++ ++#ifndef _NET_ETHERNET_H_ ++#include ++#endif ++ ++#include ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++ ++#define DOT11_TU_TO_US 1024 /* 802.11 Time Unit is 1024 microseconds */ ++ ++/* Generic 802.11 frame constants */ ++#define DOT11_A3_HDR_LEN 24 /* d11 header length with A3 */ ++#define DOT11_A4_HDR_LEN 30 /* d11 header length with A4 */ ++#define DOT11_MAC_HDR_LEN DOT11_A3_HDR_LEN /* MAC header length */ ++#define DOT11_FCS_LEN 4 /* d11 FCS length */ ++#define DOT11_ICV_LEN 4 /* d11 ICV length */ ++#define DOT11_ICV_AES_LEN 8 /* d11 ICV/AES length */ ++#define DOT11_QOS_LEN 2 /* d11 QoS length */ ++#define DOT11_HTC_LEN 4 /* d11 HT Control field length */ ++ ++#define DOT11_KEY_INDEX_SHIFT 6 /* d11 key index shift */ ++#define DOT11_IV_LEN 4 /* d11 IV length */ ++#define DOT11_IV_TKIP_LEN 8 /* d11 IV TKIP length */ ++#define DOT11_IV_AES_OCB_LEN 4 /* d11 IV/AES/OCB length */ ++#define DOT11_IV_AES_CCM_LEN 8 /* d11 IV/AES/CCM length */ ++#define DOT11_IV_MAX_LEN 8 /* maximum iv len for any encryption */ ++ ++/* Includes MIC */ ++#define DOT11_MAX_MPDU_BODY_LEN 2304 /* max MPDU body length */ ++/* A4 header + QoS + CCMP + PDU + ICV + FCS = 2352 */ ++#define DOT11_MAX_MPDU_LEN (DOT11_A4_HDR_LEN + \ ++ DOT11_QOS_LEN + \ ++ DOT11_IV_AES_CCM_LEN + \ ++ DOT11_MAX_MPDU_BODY_LEN + \ ++ DOT11_ICV_LEN + \ ++ DOT11_FCS_LEN) /* d11 max MPDU length */ ++ ++#define DOT11_MAX_SSID_LEN 32 /* d11 max ssid length */ ++ ++/* dot11RTSThreshold */ ++#define DOT11_DEFAULT_RTS_LEN 2347 /* d11 default RTS length */ ++#define DOT11_MAX_RTS_LEN 2347 /* d11 max RTS length */ ++ ++/* dot11FragmentationThreshold */ ++#define DOT11_MIN_FRAG_LEN 256 /* d11 min fragmentation length */ ++#define DOT11_MAX_FRAG_LEN 2346 /* Max frag is also limited by aMPDUMaxLength ++ * of the attached PHY ++ */ ++#define DOT11_DEFAULT_FRAG_LEN 2346 /* d11 default fragmentation length */ ++ ++/* dot11BeaconPeriod */ ++#define DOT11_MIN_BEACON_PERIOD 1 /* d11 min beacon period */ ++#define DOT11_MAX_BEACON_PERIOD 0xFFFF /* d11 max beacon period */ ++ ++/* dot11DTIMPeriod */ ++#define DOT11_MIN_DTIM_PERIOD 1 /* d11 min DTIM period */ ++#define DOT11_MAX_DTIM_PERIOD 0xFF /* d11 max DTIM period */ ++ ++/* 802.2 LLC/SNAP header used by 802.11 per 802.1H */ ++#define DOT11_LLC_SNAP_HDR_LEN 8 /* d11 LLC/SNAP header length */ ++#define DOT11_OUI_LEN 3 /* d11 OUI length */ ++BWL_PRE_PACKED_STRUCT struct dot11_llc_snap_header { ++ uint8 dsap; /* always 0xAA */ ++ uint8 ssap; /* always 0xAA */ ++ uint8 ctl; /* always 0x03 */ ++ uint8 oui[DOT11_OUI_LEN]; /* RFC1042: 0x00 0x00 0x00 ++ * Bridge-Tunnel: 0x00 0x00 0xF8 ++ */ ++ uint16 type; /* ethertype */ ++} BWL_POST_PACKED_STRUCT; ++ ++/* RFC1042 header used by 802.11 per 802.1H */ ++#define RFC1042_HDR_LEN (ETHER_HDR_LEN + DOT11_LLC_SNAP_HDR_LEN) /* RCF1042 header length */ ++ ++/* Generic 802.11 MAC header */ ++/* ++ * N.B.: This struct reflects the full 4 address 802.11 MAC header. ++ * The fields are defined such that the shorter 1, 2, and 3 ++ * address headers just use the first k fields. ++ */ ++BWL_PRE_PACKED_STRUCT struct dot11_header { ++ uint16 fc; /* frame control */ ++ uint16 durid; /* duration/ID */ ++ struct ether_addr a1; /* address 1 */ ++ struct ether_addr a2; /* address 2 */ ++ struct ether_addr a3; /* address 3 */ ++ uint16 seq; /* sequence control */ ++ struct ether_addr a4; /* address 4 */ ++} BWL_POST_PACKED_STRUCT; ++ ++/* Control frames */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_rts_frame { ++ uint16 fc; /* frame control */ ++ uint16 durid; /* duration/ID */ ++ struct ether_addr ra; /* receiver address */ ++ struct ether_addr ta; /* transmitter address */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_RTS_LEN 16 /* d11 RTS frame length */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_cts_frame { ++ uint16 fc; /* frame control */ ++ uint16 durid; /* duration/ID */ ++ struct ether_addr ra; /* receiver address */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_CTS_LEN 10 /* d11 CTS frame length */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_ack_frame { ++ uint16 fc; /* frame control */ ++ uint16 durid; /* duration/ID */ ++ struct ether_addr ra; /* receiver address */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_ACK_LEN 10 /* d11 ACK frame length */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_ps_poll_frame { ++ uint16 fc; /* frame control */ ++ uint16 durid; /* AID */ ++ struct ether_addr bssid; /* receiver address, STA in AP */ ++ struct ether_addr ta; /* transmitter address */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_PS_POLL_LEN 16 /* d11 PS poll frame length */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_cf_end_frame { ++ uint16 fc; /* frame control */ ++ uint16 durid; /* duration/ID */ ++ struct ether_addr ra; /* receiver address */ ++ struct ether_addr bssid; /* transmitter address, STA in AP */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_CS_END_LEN 16 /* d11 CF-END frame length */ ++ ++/* RWL wifi protocol: The Vendor Specific Action frame is defined for vendor-specific signaling ++* category+OUI+vendor specific content ( this can be variable) ++*/ ++BWL_PRE_PACKED_STRUCT struct dot11_action_wifi_vendor_specific { ++ uint8 category; ++ uint8 OUI[3]; ++ uint8 type; ++ uint8 subtype; ++ uint8 data[1040]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_action_wifi_vendor_specific dot11_action_wifi_vendor_specific_t; ++ ++/* generic vender specific action frame with variable length */ ++BWL_PRE_PACKED_STRUCT struct dot11_action_vs_frmhdr { ++ uint8 category; ++ uint8 OUI[3]; ++ uint8 type; ++ uint8 subtype; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_action_vs_frmhdr dot11_action_vs_frmhdr_t; ++#define DOT11_ACTION_VS_HDR_LEN 6 ++ ++#define BCM_ACTION_OUI_BYTE0 0x00 ++#define BCM_ACTION_OUI_BYTE1 0x90 ++#define BCM_ACTION_OUI_BYTE2 0x4c ++ ++/* BA/BAR Control parameters */ ++#define DOT11_BA_CTL_POLICY_NORMAL 0x0000 /* normal ack */ ++#define DOT11_BA_CTL_POLICY_NOACK 0x0001 /* no ack */ ++#define DOT11_BA_CTL_POLICY_MASK 0x0001 /* ack policy mask */ ++ ++#define DOT11_BA_CTL_MTID 0x0002 /* multi tid BA */ ++#define DOT11_BA_CTL_COMPRESSED 0x0004 /* compressed bitmap */ ++ ++#define DOT11_BA_CTL_NUMMSDU_MASK 0x0FC0 /* num msdu in bitmap mask */ ++#define DOT11_BA_CTL_NUMMSDU_SHIFT 6 /* num msdu in bitmap shift */ ++ ++#define DOT11_BA_CTL_TID_MASK 0xF000 /* tid mask */ ++#define DOT11_BA_CTL_TID_SHIFT 12 /* tid shift */ ++ ++/* control frame header (BA/BAR) */ ++BWL_PRE_PACKED_STRUCT struct dot11_ctl_header { ++ uint16 fc; /* frame control */ ++ uint16 durid; /* duration/ID */ ++ struct ether_addr ra; /* receiver address */ ++ struct ether_addr ta; /* transmitter address */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_CTL_HDR_LEN 16 /* control frame hdr len */ ++ ++/* BAR frame payload */ ++BWL_PRE_PACKED_STRUCT struct dot11_bar { ++ uint16 bar_control; /* BAR Control */ ++ uint16 seqnum; /* Starting Sequence control */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_BAR_LEN 4 /* BAR frame payload length */ ++ ++#define DOT11_BA_BITMAP_LEN 128 /* bitmap length */ ++#define DOT11_BA_CMP_BITMAP_LEN 8 /* compressed bitmap length */ ++/* BA frame payload */ ++BWL_PRE_PACKED_STRUCT struct dot11_ba { ++ uint16 ba_control; /* BA Control */ ++ uint16 seqnum; /* Starting Sequence control */ ++ uint8 bitmap[DOT11_BA_BITMAP_LEN]; /* Block Ack Bitmap */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_BA_LEN 4 /* BA frame payload len (wo bitmap) */ ++ ++/* Management frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_management_header { ++ uint16 fc; /* frame control */ ++ uint16 durid; /* duration/ID */ ++ struct ether_addr da; /* receiver address */ ++ struct ether_addr sa; /* transmitter address */ ++ struct ether_addr bssid; /* BSS ID */ ++ uint16 seq; /* sequence control */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_MGMT_HDR_LEN 24 /* d11 management header length */ ++ ++/* Management frame payloads */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_bcn_prb { ++ uint32 timestamp[2]; ++ uint16 beacon_interval; ++ uint16 capability; ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_BCN_PRB_LEN 12 /* 802.11 beacon/probe frame fixed length */ ++#define DOT11_BCN_PRB_FIXED_LEN 12 /* 802.11 beacon/probe frame fixed length */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_auth { ++ uint16 alg; /* algorithm */ ++ uint16 seq; /* sequence control */ ++ uint16 status; /* status code */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_AUTH_FIXED_LEN 6 /* length of auth frame without challenge IE */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_assoc_req { ++ uint16 capability; /* capability information */ ++ uint16 listen; /* listen interval */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_ASSOC_REQ_FIXED_LEN 4 /* length of assoc frame without info elts */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_reassoc_req { ++ uint16 capability; /* capability information */ ++ uint16 listen; /* listen interval */ ++ struct ether_addr ap; /* Current AP address */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_REASSOC_REQ_FIXED_LEN 10 /* length of assoc frame without info elts */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_assoc_resp { ++ uint16 capability; /* capability information */ ++ uint16 status; /* status code */ ++ uint16 aid; /* association ID */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_ASSOC_RESP_FIXED_LEN 6 /* length of assoc resp frame without info elts */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_action_measure { ++ uint8 category; ++ uint8 action; ++ uint8 token; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_ACTION_MEASURE_LEN 3 /* d11 action measurement header length */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_action_ht_ch_width { ++ uint8 category; ++ uint8 action; ++ uint8 ch_width; ++} BWL_POST_PACKED_STRUCT; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_action_ht_mimops { ++ uint8 category; ++ uint8 action; ++ uint8 control; ++} BWL_POST_PACKED_STRUCT; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_action_sa_query { ++ uint8 category; ++ uint8 action; ++ uint16 id; ++} BWL_POST_PACKED_STRUCT; ++ ++#define SM_PWRSAVE_ENABLE 1 ++#define SM_PWRSAVE_MODE 2 ++ ++/* ************* 802.11h related definitions. ************* */ ++BWL_PRE_PACKED_STRUCT struct dot11_power_cnst { ++ uint8 id; ++ uint8 len; ++ uint8 power; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_power_cnst dot11_power_cnst_t; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_power_cap { ++ uint8 min; ++ uint8 max; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_power_cap dot11_power_cap_t; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_tpc_rep { ++ uint8 id; ++ uint8 len; ++ uint8 tx_pwr; ++ uint8 margin; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_tpc_rep dot11_tpc_rep_t; ++#define DOT11_MNG_IE_TPC_REPORT_LEN 2 /* length of IE data, not including 2 byte header */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_supp_channels { ++ uint8 id; ++ uint8 len; ++ uint8 first_channel; ++ uint8 num_channels; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_supp_channels dot11_supp_channels_t; ++ ++/* Extension Channel Offset IE: 802.11n-D1.0 spec. added sideband ++ * offset for 40MHz operation. The possible 3 values are: ++ * 1 = above control channel ++ * 3 = below control channel ++ * 0 = no extension channel ++ */ ++BWL_PRE_PACKED_STRUCT struct dot11_extch { ++ uint8 id; /* IE ID, 62, DOT11_MNG_EXT_CHANNEL_OFFSET */ ++ uint8 len; /* IE length */ ++ uint8 extch; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_extch dot11_extch_ie_t; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_brcm_extch { ++ uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ ++ uint8 len; /* IE length */ ++ uint8 oui[3]; /* Proprietary OUI, BRCM_PROP_OUI */ ++ uint8 type; /* type inidicates what follows */ ++ uint8 extch; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_brcm_extch dot11_brcm_extch_ie_t; ++ ++#define BRCM_EXTCH_IE_LEN 5 ++#define BRCM_EXTCH_IE_TYPE 53 /* 802.11n ID not yet assigned */ ++#define DOT11_EXTCH_IE_LEN 1 ++#define DOT11_EXT_CH_MASK 0x03 /* extension channel mask */ ++#define DOT11_EXT_CH_UPPER 0x01 /* ext. ch. on upper sb */ ++#define DOT11_EXT_CH_LOWER 0x03 /* ext. ch. on lower sb */ ++#define DOT11_EXT_CH_NONE 0x00 /* no extension ch. */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_action_frmhdr { ++ uint8 category; ++ uint8 action; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_ACTION_FRMHDR_LEN 2 ++ ++/* CSA IE data structure */ ++BWL_PRE_PACKED_STRUCT struct dot11_channel_switch { ++ uint8 id; /* id DOT11_MNG_CHANNEL_SWITCH_ID */ ++ uint8 len; /* length of IE */ ++ uint8 mode; /* mode 0 or 1 */ ++ uint8 channel; /* channel switch to */ ++ uint8 count; /* number of beacons before switching */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_channel_switch dot11_chan_switch_ie_t; ++ ++#define DOT11_SWITCH_IE_LEN 3 /* length of IE data, not including 2 byte header */ ++/* CSA mode - 802.11h-2003 $7.3.2.20 */ ++#define DOT11_CSA_MODE_ADVISORY 0 /* no DOT11_CSA_MODE_NO_TX restriction imposed */ ++#define DOT11_CSA_MODE_NO_TX 1 /* no transmission upon receiving CSA frame. */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_action_switch_channel { ++ uint8 category; ++ uint8 action; ++ dot11_chan_switch_ie_t chan_switch_ie; /* for switch IE */ ++ dot11_brcm_extch_ie_t extch_ie; /* extension channel offset */ ++} BWL_POST_PACKED_STRUCT; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_csa_body { ++ uint8 mode; /* mode 0 or 1 */ ++ uint8 reg; /* regulatory class */ ++ uint8 channel; /* channel switch to */ ++ uint8 count; /* number of beacons before switching */ ++} BWL_POST_PACKED_STRUCT; ++ ++/* 11n Extended Channel Switch IE data structure */ ++BWL_PRE_PACKED_STRUCT struct dot11_ext_csa { ++ uint8 id; /* id DOT11_MNG_EXT_CHANNEL_SWITCH_ID */ ++ uint8 len; /* length of IE */ ++ struct dot11_csa_body b; /* body of the ie */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_ext_csa dot11_ext_csa_ie_t; ++#define DOT11_EXT_CSA_IE_LEN 4 /* length of extended channel switch IE body */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_action_ext_csa { ++ uint8 category; ++ uint8 action; ++ dot11_ext_csa_ie_t chan_switch_ie; /* for switch IE */ ++} BWL_POST_PACKED_STRUCT; ++ ++BWL_PRE_PACKED_STRUCT struct dot11y_action_ext_csa { ++ uint8 category; ++ uint8 action; ++ struct dot11_csa_body b; /* body of the ie */ ++} BWL_POST_PACKED_STRUCT; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_obss_coex { ++ uint8 id; ++ uint8 len; ++ uint8 info; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_obss_coex dot11_obss_coex_t; ++#define DOT11_OBSS_COEXINFO_LEN 1 /* length of OBSS Coexistence INFO IE */ ++ ++#define DOT11_OBSS_COEX_INFO_REQ 0x01 ++#define DOT11_OBSS_COEX_40MHZ_INTOLERANT 0x02 ++#define DOT11_OBSS_COEX_20MHZ_WIDTH_REQ 0x04 ++ ++BWL_PRE_PACKED_STRUCT struct dot11_obss_chanlist { ++ uint8 id; ++ uint8 len; ++ uint8 regclass; ++ uint8 chanlist[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_obss_chanlist dot11_obss_chanlist_t; ++#define DOT11_OBSS_CHANLIST_FIXED_LEN 1 /* fixed length of regclass */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_extcap_ie { ++ uint8 id; ++ uint8 len; ++ uint8 cap[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_extcap_ie dot11_extcap_ie_t; ++ ++#define DOT11_EXTCAP_LEN_MAX 7 ++#define DOT11_EXTCAP_LEN_COEX 1 ++#define DOT11_EXTCAP_LEN_BT 3 ++#define DOT11_EXTCAP_LEN_IW 4 ++#define DOT11_EXTCAP_LEN_SI 6 ++ ++#define DOT11_EXTCAP_LEN_TDLS 5 ++BWL_PRE_PACKED_STRUCT struct dot11_extcap { ++ uint8 extcap[DOT11_EXTCAP_LEN_TDLS]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_extcap dot11_extcap_t; ++ ++/* TDLS Capabilities */ ++#define TDLS_CAP_TDLS 37 /* TDLS support */ ++#define TDLS_CAP_PU_BUFFER_STA 28 /* TDLS Peer U-APSD buffer STA support */ ++#define TDLS_CAP_PEER_PSM 20 /* TDLS Peer PSM support */ ++#define TDLS_CAP_CH_SW 30 /* TDLS Channel switch */ ++#define TDLS_CAP_PROH 38 /* TDLS prohibited */ ++#define TDLS_CAP_CH_SW_PROH 39 /* TDLS Channel switch prohibited */ ++ ++#define TDLS_CAP_MAX_BIT 39 /* TDLS max bit defined in ext cap */ ++ ++/* 802.11h/802.11k Measurement Request/Report IEs */ ++/* Measurement Type field */ ++#define DOT11_MEASURE_TYPE_BASIC 0 /* d11 measurement basic type */ ++#define DOT11_MEASURE_TYPE_CCA 1 /* d11 measurement CCA type */ ++#define DOT11_MEASURE_TYPE_RPI 2 /* d11 measurement RPI type */ ++#define DOT11_MEASURE_TYPE_CHLOAD 3 /* d11 measurement Channel Load type */ ++#define DOT11_MEASURE_TYPE_NOISE 4 /* d11 measurement Noise Histogram type */ ++#define DOT11_MEASURE_TYPE_BEACON 5 /* d11 measurement Beacon type */ ++#define DOT11_MEASURE_TYPE_FRAME 6 /* d11 measurement Frame type */ ++#define DOT11_MEASURE_TYPE_STATS 7 /* d11 measurement STA Statistics type */ ++#define DOT11_MEASURE_TYPE_LCI 8 /* d11 measurement LCI type */ ++#define DOT11_MEASURE_TYPE_TXSTREAM 9 /* d11 measurement TX Stream type */ ++#define DOT11_MEASURE_TYPE_PAUSE 255 /* d11 measurement pause type */ ++ ++/* Measurement Request Modes */ ++#define DOT11_MEASURE_MODE_PARALLEL (1<<0) /* d11 measurement parallel */ ++#define DOT11_MEASURE_MODE_ENABLE (1<<1) /* d11 measurement enable */ ++#define DOT11_MEASURE_MODE_REQUEST (1<<2) /* d11 measurement request */ ++#define DOT11_MEASURE_MODE_REPORT (1<<3) /* d11 measurement report */ ++#define DOT11_MEASURE_MODE_DUR (1<<4) /* d11 measurement dur mandatory */ ++/* Measurement Report Modes */ ++#define DOT11_MEASURE_MODE_LATE (1<<0) /* d11 measurement late */ ++#define DOT11_MEASURE_MODE_INCAPABLE (1<<1) /* d11 measurement incapable */ ++#define DOT11_MEASURE_MODE_REFUSED (1<<2) /* d11 measurement refuse */ ++/* Basic Measurement Map bits */ ++#define DOT11_MEASURE_BASIC_MAP_BSS ((uint8)(1<<0)) /* d11 measurement basic map BSS */ ++#define DOT11_MEASURE_BASIC_MAP_OFDM ((uint8)(1<<1)) /* d11 measurement map OFDM */ ++#define DOT11_MEASURE_BASIC_MAP_UKNOWN ((uint8)(1<<2)) /* d11 measurement map unknown */ ++#define DOT11_MEASURE_BASIC_MAP_RADAR ((uint8)(1<<3)) /* d11 measurement map radar */ ++#define DOT11_MEASURE_BASIC_MAP_UNMEAS ((uint8)(1<<4)) /* d11 measurement map unmeasuremnt */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_meas_req { ++ uint8 id; ++ uint8 len; ++ uint8 token; ++ uint8 mode; ++ uint8 type; ++ uint8 channel; ++ uint8 start_time[8]; ++ uint16 duration; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_meas_req dot11_meas_req_t; ++#define DOT11_MNG_IE_MREQ_LEN 14 /* d11 measurement request IE length */ ++/* length of Measure Request IE data not including variable len */ ++#define DOT11_MNG_IE_MREQ_FIXED_LEN 3 /* d11 measurement request IE fixed length */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_meas_rep { ++ uint8 id; ++ uint8 len; ++ uint8 token; ++ uint8 mode; ++ uint8 type; ++ BWL_PRE_PACKED_STRUCT union ++ { ++ BWL_PRE_PACKED_STRUCT struct { ++ uint8 channel; ++ uint8 start_time[8]; ++ uint16 duration; ++ uint8 map; ++ } BWL_POST_PACKED_STRUCT basic; ++ uint8 data[1]; ++ } BWL_POST_PACKED_STRUCT rep; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_meas_rep dot11_meas_rep_t; ++ ++/* length of Measure Report IE data not including variable len */ ++#define DOT11_MNG_IE_MREP_FIXED_LEN 3 /* d11 measurement response IE fixed length */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_meas_rep_basic { ++ uint8 channel; ++ uint8 start_time[8]; ++ uint16 duration; ++ uint8 map; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_meas_rep_basic dot11_meas_rep_basic_t; ++#define DOT11_MEASURE_BASIC_REP_LEN 12 /* d11 measurement basic report length */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_quiet { ++ uint8 id; ++ uint8 len; ++ uint8 count; /* TBTTs until beacon interval in quiet starts */ ++ uint8 period; /* Beacon intervals between periodic quiet periods ? */ ++ uint16 duration; /* Length of quiet period, in TU's */ ++ uint16 offset; /* TU's offset from TBTT in Count field */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_quiet dot11_quiet_t; ++ ++BWL_PRE_PACKED_STRUCT struct chan_map_tuple { ++ uint8 channel; ++ uint8 map; ++} BWL_POST_PACKED_STRUCT; ++typedef struct chan_map_tuple chan_map_tuple_t; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_ibss_dfs { ++ uint8 id; ++ uint8 len; ++ uint8 eaddr[ETHER_ADDR_LEN]; ++ uint8 interval; ++ chan_map_tuple_t map[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_ibss_dfs dot11_ibss_dfs_t; ++ ++/* WME Elements */ ++#define WME_OUI "\x00\x50\xf2" /* WME OUI */ ++#define WME_OUI_LEN 3 ++#define WME_OUI_TYPE 2 /* WME type */ ++#define WME_TYPE 2 /* WME type, deprecated */ ++#define WME_SUBTYPE_IE 0 /* Information Element */ ++#define WME_SUBTYPE_PARAM_IE 1 /* Parameter Element */ ++#define WME_SUBTYPE_TSPEC 2 /* Traffic Specification */ ++#define WME_VER 1 /* WME version */ ++ ++/* WME Access Category Indices (ACIs) */ ++#define AC_BE 0 /* Best Effort */ ++#define AC_BK 1 /* Background */ ++#define AC_VI 2 /* Video */ ++#define AC_VO 3 /* Voice */ ++#define AC_COUNT 4 /* number of ACs */ ++ ++typedef uint8 ac_bitmap_t; /* AC bitmap of (1 << AC_xx) */ ++ ++#define AC_BITMAP_NONE 0x0 /* No ACs */ ++#define AC_BITMAP_ALL 0xf /* All ACs */ ++#define AC_BITMAP_TST(ab, ac) (((ab) & (1 << (ac))) != 0) ++#define AC_BITMAP_SET(ab, ac) (((ab) |= (1 << (ac)))) ++#define AC_BITMAP_RESET(ab, ac) (((ab) &= ~(1 << (ac)))) ++ ++/* WME Information Element (IE) */ ++BWL_PRE_PACKED_STRUCT struct wme_ie { ++ uint8 oui[3]; ++ uint8 type; ++ uint8 subtype; ++ uint8 version; ++ uint8 qosinfo; ++} BWL_POST_PACKED_STRUCT; ++typedef struct wme_ie wme_ie_t; ++#define WME_IE_LEN 7 /* WME IE length */ ++ ++BWL_PRE_PACKED_STRUCT struct edcf_acparam { ++ uint8 ACI; ++ uint8 ECW; ++ uint16 TXOP; /* stored in network order (ls octet first) */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct edcf_acparam edcf_acparam_t; ++ ++/* WME Parameter Element (PE) */ ++BWL_PRE_PACKED_STRUCT struct wme_param_ie { ++ uint8 oui[3]; ++ uint8 type; ++ uint8 subtype; ++ uint8 version; ++ uint8 qosinfo; ++ uint8 rsvd; ++ edcf_acparam_t acparam[AC_COUNT]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct wme_param_ie wme_param_ie_t; ++#define WME_PARAM_IE_LEN 24 /* WME Parameter IE length */ ++ ++/* QoS Info field for IE as sent from AP */ ++#define WME_QI_AP_APSD_MASK 0x80 /* U-APSD Supported mask */ ++#define WME_QI_AP_APSD_SHIFT 7 /* U-APSD Supported shift */ ++#define WME_QI_AP_COUNT_MASK 0x0f /* Parameter set count mask */ ++#define WME_QI_AP_COUNT_SHIFT 0 /* Parameter set count shift */ ++ ++/* QoS Info field for IE as sent from STA */ ++#define WME_QI_STA_MAXSPLEN_MASK 0x60 /* Max Service Period Length mask */ ++#define WME_QI_STA_MAXSPLEN_SHIFT 5 /* Max Service Period Length shift */ ++#define WME_QI_STA_APSD_ALL_MASK 0xf /* APSD all AC bits mask */ ++#define WME_QI_STA_APSD_ALL_SHIFT 0 /* APSD all AC bits shift */ ++#define WME_QI_STA_APSD_BE_MASK 0x8 /* APSD AC_BE mask */ ++#define WME_QI_STA_APSD_BE_SHIFT 3 /* APSD AC_BE shift */ ++#define WME_QI_STA_APSD_BK_MASK 0x4 /* APSD AC_BK mask */ ++#define WME_QI_STA_APSD_BK_SHIFT 2 /* APSD AC_BK shift */ ++#define WME_QI_STA_APSD_VI_MASK 0x2 /* APSD AC_VI mask */ ++#define WME_QI_STA_APSD_VI_SHIFT 1 /* APSD AC_VI shift */ ++#define WME_QI_STA_APSD_VO_MASK 0x1 /* APSD AC_VO mask */ ++#define WME_QI_STA_APSD_VO_SHIFT 0 /* APSD AC_VO shift */ ++ ++/* ACI */ ++#define EDCF_AIFSN_MIN 1 /* AIFSN minimum value */ ++#define EDCF_AIFSN_MAX 15 /* AIFSN maximum value */ ++#define EDCF_AIFSN_MASK 0x0f /* AIFSN mask */ ++#define EDCF_ACM_MASK 0x10 /* ACM mask */ ++#define EDCF_ACI_MASK 0x60 /* ACI mask */ ++#define EDCF_ACI_SHIFT 5 /* ACI shift */ ++#define EDCF_AIFSN_SHIFT 12 /* 4 MSB(0xFFF) in ifs_ctl for AC idx */ ++ ++/* ECW */ ++#define EDCF_ECW_MIN 0 /* cwmin/cwmax exponent minimum value */ ++#define EDCF_ECW_MAX 15 /* cwmin/cwmax exponent maximum value */ ++#define EDCF_ECW2CW(exp) ((1 << (exp)) - 1) ++#define EDCF_ECWMIN_MASK 0x0f /* cwmin exponent form mask */ ++#define EDCF_ECWMAX_MASK 0xf0 /* cwmax exponent form mask */ ++#define EDCF_ECWMAX_SHIFT 4 /* cwmax exponent form shift */ ++ ++/* TXOP */ ++#define EDCF_TXOP_MIN 0 /* TXOP minimum value */ ++#define EDCF_TXOP_MAX 65535 /* TXOP maximum value */ ++#define EDCF_TXOP2USEC(txop) ((txop) << 5) ++ ++/* Default BE ACI value for non-WME connection STA */ ++#define NON_EDCF_AC_BE_ACI_STA 0x02 ++ ++/* Default EDCF parameters that AP advertises for STA to use; WMM draft Table 12 */ ++#define EDCF_AC_BE_ACI_STA 0x03 /* STA ACI value for best effort AC */ ++#define EDCF_AC_BE_ECW_STA 0xA4 /* STA ECW value for best effort AC */ ++#define EDCF_AC_BE_TXOP_STA 0x0000 /* STA TXOP value for best effort AC */ ++#define EDCF_AC_BK_ACI_STA 0x27 /* STA ACI value for background AC */ ++#define EDCF_AC_BK_ECW_STA 0xA4 /* STA ECW value for background AC */ ++#define EDCF_AC_BK_TXOP_STA 0x0000 /* STA TXOP value for background AC */ ++#define EDCF_AC_VI_ACI_STA 0x42 /* STA ACI value for video AC */ ++#define EDCF_AC_VI_ECW_STA 0x43 /* STA ECW value for video AC */ ++#define EDCF_AC_VI_TXOP_STA 0x005e /* STA TXOP value for video AC */ ++#define EDCF_AC_VO_ACI_STA 0x62 /* STA ACI value for audio AC */ ++#define EDCF_AC_VO_ECW_STA 0x32 /* STA ECW value for audio AC */ ++#define EDCF_AC_VO_TXOP_STA 0x002f /* STA TXOP value for audio AC */ ++ ++/* Default EDCF parameters that AP uses; WMM draft Table 14 */ ++#define EDCF_AC_BE_ACI_AP 0x03 /* AP ACI value for best effort AC */ ++#define EDCF_AC_BE_ECW_AP 0x64 /* AP ECW value for best effort AC */ ++#define EDCF_AC_BE_TXOP_AP 0x0000 /* AP TXOP value for best effort AC */ ++#define EDCF_AC_BK_ACI_AP 0x27 /* AP ACI value for background AC */ ++#define EDCF_AC_BK_ECW_AP 0xA4 /* AP ECW value for background AC */ ++#define EDCF_AC_BK_TXOP_AP 0x0000 /* AP TXOP value for background AC */ ++#define EDCF_AC_VI_ACI_AP 0x41 /* AP ACI value for video AC */ ++#define EDCF_AC_VI_ECW_AP 0x43 /* AP ECW value for video AC */ ++#define EDCF_AC_VI_TXOP_AP 0x005e /* AP TXOP value for video AC */ ++#define EDCF_AC_VO_ACI_AP 0x61 /* AP ACI value for audio AC */ ++#define EDCF_AC_VO_ECW_AP 0x32 /* AP ECW value for audio AC */ ++#define EDCF_AC_VO_TXOP_AP 0x002f /* AP TXOP value for audio AC */ ++ ++/* EDCA Parameter IE */ ++BWL_PRE_PACKED_STRUCT struct edca_param_ie { ++ uint8 qosinfo; ++ uint8 rsvd; ++ edcf_acparam_t acparam[AC_COUNT]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct edca_param_ie edca_param_ie_t; ++#define EDCA_PARAM_IE_LEN 18 /* EDCA Parameter IE length */ ++ ++/* QoS Capability IE */ ++BWL_PRE_PACKED_STRUCT struct qos_cap_ie { ++ uint8 qosinfo; ++} BWL_POST_PACKED_STRUCT; ++typedef struct qos_cap_ie qos_cap_ie_t; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_qbss_load_ie { ++ uint8 id; /* 11, DOT11_MNG_QBSS_LOAD_ID */ ++ uint8 length; ++ uint16 station_count; /* total number of STAs associated */ ++ uint8 channel_utilization; /* % of time, normalized to 255, QAP sensed medium busy */ ++ uint16 aac; /* available admission capacity */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_qbss_load_ie dot11_qbss_load_ie_t; ++#define BSS_LOAD_IE_SIZE 7 /* BSS load IE size */ ++ ++/* nom_msdu_size */ ++#define FIXED_MSDU_SIZE 0x8000 /* MSDU size is fixed */ ++#define MSDU_SIZE_MASK 0x7fff /* (Nominal or fixed) MSDU size */ ++ ++/* surplus_bandwidth */ ++/* Represented as 3 bits of integer, binary point, 13 bits fraction */ ++#define INTEGER_SHIFT 13 /* integer shift */ ++#define FRACTION_MASK 0x1FFF /* fraction mask */ ++ ++/* Management Notification Frame */ ++BWL_PRE_PACKED_STRUCT struct dot11_management_notification { ++ uint8 category; /* DOT11_ACTION_NOTIFICATION */ ++ uint8 action; ++ uint8 token; ++ uint8 status; ++ uint8 data[1]; /* Elements */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_MGMT_NOTIFICATION_LEN 4 /* Fixed length */ ++ ++/* Timeout Interval IE */ ++BWL_PRE_PACKED_STRUCT struct ti_ie { ++ uint8 ti_type; ++ uint32 ti_val; ++} BWL_POST_PACKED_STRUCT; ++typedef struct ti_ie ti_ie_t; ++#define TI_TYPE_REASSOC_DEADLINE 1 ++#define TI_TYPE_KEY_LIFETIME 2 ++ ++/* WME Action Codes */ ++#define WME_ADDTS_REQUEST 0 /* WME ADDTS request */ ++#define WME_ADDTS_RESPONSE 1 /* WME ADDTS response */ ++#define WME_DELTS_REQUEST 2 /* WME DELTS request */ ++ ++/* WME Setup Response Status Codes */ ++#define WME_ADMISSION_ACCEPTED 0 /* WME admission accepted */ ++#define WME_INVALID_PARAMETERS 1 /* WME invalide parameters */ ++#define WME_ADMISSION_REFUSED 3 /* WME admission refused */ ++ ++/* Macro to take a pointer to a beacon or probe response ++ * body and return the char* pointer to the SSID info element ++ */ ++#define BCN_PRB_SSID(body) ((char*)(body) + DOT11_BCN_PRB_LEN) ++ ++/* Authentication frame payload constants */ ++#define DOT11_OPEN_SYSTEM 0 /* d11 open authentication */ ++#define DOT11_SHARED_KEY 1 /* d11 shared authentication */ ++#define DOT11_FAST_BSS 2 /* d11 fast bss authentication */ ++#define DOT11_CHALLENGE_LEN 128 /* d11 challenge text length */ ++ ++/* Frame control macros */ ++#define FC_PVER_MASK 0x3 /* PVER mask */ ++#define FC_PVER_SHIFT 0 /* PVER shift */ ++#define FC_TYPE_MASK 0xC /* type mask */ ++#define FC_TYPE_SHIFT 2 /* type shift */ ++#define FC_SUBTYPE_MASK 0xF0 /* subtype mask */ ++#define FC_SUBTYPE_SHIFT 4 /* subtype shift */ ++#define FC_TODS 0x100 /* to DS */ ++#define FC_TODS_SHIFT 8 /* to DS shift */ ++#define FC_FROMDS 0x200 /* from DS */ ++#define FC_FROMDS_SHIFT 9 /* from DS shift */ ++#define FC_MOREFRAG 0x400 /* more frag. */ ++#define FC_MOREFRAG_SHIFT 10 /* more frag. shift */ ++#define FC_RETRY 0x800 /* retry */ ++#define FC_RETRY_SHIFT 11 /* retry shift */ ++#define FC_PM 0x1000 /* PM */ ++#define FC_PM_SHIFT 12 /* PM shift */ ++#define FC_MOREDATA 0x2000 /* more data */ ++#define FC_MOREDATA_SHIFT 13 /* more data shift */ ++#define FC_WEP 0x4000 /* WEP */ ++#define FC_WEP_SHIFT 14 /* WEP shift */ ++#define FC_ORDER 0x8000 /* order */ ++#define FC_ORDER_SHIFT 15 /* order shift */ ++ ++/* sequence control macros */ ++#define SEQNUM_SHIFT 4 /* seq. number shift */ ++#define SEQNUM_MAX 0x1000 /* max seqnum + 1 */ ++#define FRAGNUM_MASK 0xF /* frag. number mask */ ++ ++/* Frame Control type/subtype defs */ ++ ++/* FC Types */ ++#define FC_TYPE_MNG 0 /* management type */ ++#define FC_TYPE_CTL 1 /* control type */ ++#define FC_TYPE_DATA 2 /* data type */ ++ ++/* Management Subtypes */ ++#define FC_SUBTYPE_ASSOC_REQ 0 /* assoc. request */ ++#define FC_SUBTYPE_ASSOC_RESP 1 /* assoc. response */ ++#define FC_SUBTYPE_REASSOC_REQ 2 /* reassoc. request */ ++#define FC_SUBTYPE_REASSOC_RESP 3 /* reassoc. response */ ++#define FC_SUBTYPE_PROBE_REQ 4 /* probe request */ ++#define FC_SUBTYPE_PROBE_RESP 5 /* probe response */ ++#define FC_SUBTYPE_BEACON 8 /* beacon */ ++#define FC_SUBTYPE_ATIM 9 /* ATIM */ ++#define FC_SUBTYPE_DISASSOC 10 /* disassoc. */ ++#define FC_SUBTYPE_AUTH 11 /* authentication */ ++#define FC_SUBTYPE_DEAUTH 12 /* de-authentication */ ++#define FC_SUBTYPE_ACTION 13 /* action */ ++#define FC_SUBTYPE_ACTION_NOACK 14 /* action no-ack */ ++ ++/* Control Subtypes */ ++#define FC_SUBTYPE_CTL_WRAPPER 7 /* Control Wrapper */ ++#define FC_SUBTYPE_BLOCKACK_REQ 8 /* Block Ack Req */ ++#define FC_SUBTYPE_BLOCKACK 9 /* Block Ack */ ++#define FC_SUBTYPE_PS_POLL 10 /* PS poll */ ++#define FC_SUBTYPE_RTS 11 /* RTS */ ++#define FC_SUBTYPE_CTS 12 /* CTS */ ++#define FC_SUBTYPE_ACK 13 /* ACK */ ++#define FC_SUBTYPE_CF_END 14 /* CF-END */ ++#define FC_SUBTYPE_CF_END_ACK 15 /* CF-END ACK */ ++ ++/* Data Subtypes */ ++#define FC_SUBTYPE_DATA 0 /* Data */ ++#define FC_SUBTYPE_DATA_CF_ACK 1 /* Data + CF-ACK */ ++#define FC_SUBTYPE_DATA_CF_POLL 2 /* Data + CF-Poll */ ++#define FC_SUBTYPE_DATA_CF_ACK_POLL 3 /* Data + CF-Ack + CF-Poll */ ++#define FC_SUBTYPE_NULL 4 /* Null */ ++#define FC_SUBTYPE_CF_ACK 5 /* CF-Ack */ ++#define FC_SUBTYPE_CF_POLL 6 /* CF-Poll */ ++#define FC_SUBTYPE_CF_ACK_POLL 7 /* CF-Ack + CF-Poll */ ++#define FC_SUBTYPE_QOS_DATA 8 /* QoS Data */ ++#define FC_SUBTYPE_QOS_DATA_CF_ACK 9 /* QoS Data + CF-Ack */ ++#define FC_SUBTYPE_QOS_DATA_CF_POLL 10 /* QoS Data + CF-Poll */ ++#define FC_SUBTYPE_QOS_DATA_CF_ACK_POLL 11 /* QoS Data + CF-Ack + CF-Poll */ ++#define FC_SUBTYPE_QOS_NULL 12 /* QoS Null */ ++#define FC_SUBTYPE_QOS_CF_POLL 14 /* QoS CF-Poll */ ++#define FC_SUBTYPE_QOS_CF_ACK_POLL 15 /* QoS CF-Ack + CF-Poll */ ++ ++/* Data Subtype Groups */ ++#define FC_SUBTYPE_ANY_QOS(s) (((s) & 8) != 0) ++#define FC_SUBTYPE_ANY_NULL(s) (((s) & 4) != 0) ++#define FC_SUBTYPE_ANY_CF_POLL(s) (((s) & 2) != 0) ++#define FC_SUBTYPE_ANY_CF_ACK(s) (((s) & 1) != 0) ++ ++/* Type/Subtype Combos */ ++#define FC_KIND_MASK (FC_TYPE_MASK | FC_SUBTYPE_MASK) /* FC kind mask */ ++ ++#define FC_KIND(t, s) (((t) << FC_TYPE_SHIFT) | ((s) << FC_SUBTYPE_SHIFT)) /* FC kind */ ++ ++#define FC_SUBTYPE(fc) (((fc) & FC_SUBTYPE_MASK) >> FC_SUBTYPE_SHIFT) /* Subtype from FC */ ++#define FC_TYPE(fc) (((fc) & FC_TYPE_MASK) >> FC_TYPE_SHIFT) /* Type from FC */ ++ ++#define FC_ASSOC_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ASSOC_REQ) /* assoc. request */ ++#define FC_ASSOC_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ASSOC_RESP) /* assoc. response */ ++#define FC_REASSOC_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_REASSOC_REQ) /* reassoc. request */ ++#define FC_REASSOC_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_REASSOC_RESP) /* reassoc. response */ ++#define FC_PROBE_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_PROBE_REQ) /* probe request */ ++#define FC_PROBE_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_PROBE_RESP) /* probe response */ ++#define FC_BEACON FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_BEACON) /* beacon */ ++#define FC_DISASSOC FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_DISASSOC) /* disassoc */ ++#define FC_AUTH FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_AUTH) /* authentication */ ++#define FC_DEAUTH FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_DEAUTH) /* deauthentication */ ++#define FC_ACTION FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ACTION) /* action */ ++#define FC_ACTION_NOACK FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ACTION_NOACK) /* action no-ack */ ++ ++#define FC_CTL_WRAPPER FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CTL_WRAPPER) /* Control Wrapper */ ++#define FC_BLOCKACK_REQ FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_BLOCKACK_REQ) /* Block Ack Req */ ++#define FC_BLOCKACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_BLOCKACK) /* Block Ack */ ++#define FC_PS_POLL FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_PS_POLL) /* PS poll */ ++#define FC_RTS FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_RTS) /* RTS */ ++#define FC_CTS FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CTS) /* CTS */ ++#define FC_ACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_ACK) /* ACK */ ++#define FC_CF_END FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CF_END) /* CF-END */ ++#define FC_CF_END_ACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CF_END_ACK) /* CF-END ACK */ ++ ++#define FC_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_DATA) /* data */ ++#define FC_NULL_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_NULL) /* null data */ ++#define FC_DATA_CF_ACK FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_DATA_CF_ACK) /* data CF ACK */ ++#define FC_QOS_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_QOS_DATA) /* QoS data */ ++#define FC_QOS_NULL FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_QOS_NULL) /* QoS null */ ++ ++/* QoS Control Field */ ++ ++/* 802.1D Priority */ ++#define QOS_PRIO_SHIFT 0 /* QoS priority shift */ ++#define QOS_PRIO_MASK 0x0007 /* QoS priority mask */ ++#define QOS_PRIO(qos) (((qos) & QOS_PRIO_MASK) >> QOS_PRIO_SHIFT) /* QoS priority */ ++ ++/* Traffic Identifier */ ++#define QOS_TID_SHIFT 0 /* QoS TID shift */ ++#define QOS_TID_MASK 0x000f /* QoS TID mask */ ++#define QOS_TID(qos) (((qos) & QOS_TID_MASK) >> QOS_TID_SHIFT) /* QoS TID */ ++ ++/* End of Service Period (U-APSD) */ ++#define QOS_EOSP_SHIFT 4 /* QoS End of Service Period shift */ ++#define QOS_EOSP_MASK 0x0010 /* QoS End of Service Period mask */ ++#define QOS_EOSP(qos) (((qos) & QOS_EOSP_MASK) >> QOS_EOSP_SHIFT) /* Qos EOSP */ ++ ++/* Ack Policy */ ++#define QOS_ACK_NORMAL_ACK 0 /* Normal Ack */ ++#define QOS_ACK_NO_ACK 1 /* No Ack (eg mcast) */ ++#define QOS_ACK_NO_EXP_ACK 2 /* No Explicit Ack */ ++#define QOS_ACK_BLOCK_ACK 3 /* Block Ack */ ++#define QOS_ACK_SHIFT 5 /* QoS ACK shift */ ++#define QOS_ACK_MASK 0x0060 /* QoS ACK mask */ ++#define QOS_ACK(qos) (((qos) & QOS_ACK_MASK) >> QOS_ACK_SHIFT) /* QoS ACK */ ++ ++/* A-MSDU flag */ ++#define QOS_AMSDU_SHIFT 7 /* AMSDU shift */ ++#define QOS_AMSDU_MASK 0x0080 /* AMSDU mask */ ++ ++/* Management Frames */ ++ ++/* Management Frame Constants */ ++ ++/* Fixed fields */ ++#define DOT11_MNG_AUTH_ALGO_LEN 2 /* d11 management auth. algo. length */ ++#define DOT11_MNG_AUTH_SEQ_LEN 2 /* d11 management auth. seq. length */ ++#define DOT11_MNG_BEACON_INT_LEN 2 /* d11 management beacon interval length */ ++#define DOT11_MNG_CAP_LEN 2 /* d11 management cap. length */ ++#define DOT11_MNG_AP_ADDR_LEN 6 /* d11 management AP address length */ ++#define DOT11_MNG_LISTEN_INT_LEN 2 /* d11 management listen interval length */ ++#define DOT11_MNG_REASON_LEN 2 /* d11 management reason length */ ++#define DOT11_MNG_AID_LEN 2 /* d11 management AID length */ ++#define DOT11_MNG_STATUS_LEN 2 /* d11 management status length */ ++#define DOT11_MNG_TIMESTAMP_LEN 8 /* d11 management timestamp length */ ++ ++/* DUR/ID field in assoc resp is 0xc000 | AID */ ++#define DOT11_AID_MASK 0x3fff /* d11 AID mask */ ++ ++/* Reason Codes */ ++#define DOT11_RC_RESERVED 0 /* d11 RC reserved */ ++#define DOT11_RC_UNSPECIFIED 1 /* Unspecified reason */ ++#define DOT11_RC_AUTH_INVAL 2 /* Previous authentication no longer valid */ ++#define DOT11_RC_DEAUTH_LEAVING 3 /* Deauthenticated because sending station ++ * is leaving (or has left) IBSS or ESS ++ */ ++#define DOT11_RC_INACTIVITY 4 /* Disassociated due to inactivity */ ++#define DOT11_RC_BUSY 5 /* Disassociated because AP is unable to handle ++ * all currently associated stations ++ */ ++#define DOT11_RC_INVAL_CLASS_2 6 /* Class 2 frame received from ++ * nonauthenticated station ++ */ ++#define DOT11_RC_INVAL_CLASS_3 7 /* Class 3 frame received from ++ * nonassociated station ++ */ ++#define DOT11_RC_DISASSOC_LEAVING 8 /* Disassociated because sending station is ++ * leaving (or has left) BSS ++ */ ++#define DOT11_RC_NOT_AUTH 9 /* Station requesting (re)association is not ++ * authenticated with responding station ++ */ ++#define DOT11_RC_BAD_PC 10 /* Unacceptable power capability element */ ++#define DOT11_RC_BAD_CHANNELS 11 /* Unacceptable supported channels element */ ++/* 12 is unused */ ++ ++/* 32-39 are QSTA specific reasons added in 11e */ ++#define DOT11_RC_UNSPECIFIED_QOS 32 /* unspecified QoS-related reason */ ++#define DOT11_RC_INSUFFCIENT_BW 33 /* QAP lacks sufficient bandwidth */ ++#define DOT11_RC_EXCESSIVE_FRAMES 34 /* excessive number of frames need ack */ ++#define DOT11_RC_TX_OUTSIDE_TXOP 35 /* transmitting outside the limits of txop */ ++#define DOT11_RC_LEAVING_QBSS 36 /* QSTA is leaving the QBSS (or restting) */ ++#define DOT11_RC_BAD_MECHANISM 37 /* does not want to use the mechanism */ ++#define DOT11_RC_SETUP_NEEDED 38 /* mechanism needs a setup */ ++#define DOT11_RC_TIMEOUT 39 /* timeout */ ++ ++#define DOT11_RC_MAX 23 /* Reason codes > 23 are reserved */ ++ ++#define DOT11_RC_TDLS_PEER_UNREACH 25 ++#define DOT11_RC_TDLS_DOWN_UNSPECIFIED 26 ++ ++/* Status Codes */ ++#define DOT11_SC_SUCCESS 0 /* Successful */ ++#define DOT11_SC_FAILURE 1 /* Unspecified failure */ ++#define DOT11_SC_TDLS_WAKEUP_SCH_ALT 2 /* TDLS wakeup schedule rejected but alternative */ ++ /* schedule provided */ ++#define DOT11_SC_TDLS_WAKEUP_SCH_REJ 3 /* TDLS wakeup schedule rejected */ ++#define DOT11_SC_TDLS_SEC_DISABLED 5 /* TDLS Security disabled */ ++#define DOT11_SC_LIFETIME_REJ 6 /* Unacceptable lifetime */ ++#define DOT11_SC_NOT_SAME_BSS 7 /* Not in same BSS */ ++#define DOT11_SC_CAP_MISMATCH 10 /* Cannot support all requested ++ * capabilities in the Capability ++ * Information field ++ */ ++#define DOT11_SC_REASSOC_FAIL 11 /* Reassociation denied due to inability ++ * to confirm that association exists ++ */ ++#define DOT11_SC_ASSOC_FAIL 12 /* Association denied due to reason ++ * outside the scope of this standard ++ */ ++#define DOT11_SC_AUTH_MISMATCH 13 /* Responding station does not support ++ * the specified authentication ++ * algorithm ++ */ ++#define DOT11_SC_AUTH_SEQ 14 /* Received an Authentication frame ++ * with authentication transaction ++ * sequence number out of expected ++ * sequence ++ */ ++#define DOT11_SC_AUTH_CHALLENGE_FAIL 15 /* Authentication rejected because of ++ * challenge failure ++ */ ++#define DOT11_SC_AUTH_TIMEOUT 16 /* Authentication rejected due to timeout ++ * waiting for next frame in sequence ++ */ ++#define DOT11_SC_ASSOC_BUSY_FAIL 17 /* Association denied because AP is ++ * unable to handle additional ++ * associated stations ++ */ ++#define DOT11_SC_ASSOC_RATE_MISMATCH 18 /* Association denied due to requesting ++ * station not supporting all of the ++ * data rates in the BSSBasicRateSet ++ * parameter ++ */ ++#define DOT11_SC_ASSOC_SHORT_REQUIRED 19 /* Association denied due to requesting ++ * station not supporting the Short ++ * Preamble option ++ */ ++#define DOT11_SC_ASSOC_PBCC_REQUIRED 20 /* Association denied due to requesting ++ * station not supporting the PBCC ++ * Modulation option ++ */ ++#define DOT11_SC_ASSOC_AGILITY_REQUIRED 21 /* Association denied due to requesting ++ * station not supporting the Channel ++ * Agility option ++ */ ++#define DOT11_SC_ASSOC_SPECTRUM_REQUIRED 22 /* Association denied because Spectrum ++ * Management capability is required. ++ */ ++#define DOT11_SC_ASSOC_BAD_POWER_CAP 23 /* Association denied because the info ++ * in the Power Cap element is ++ * unacceptable. ++ */ ++#define DOT11_SC_ASSOC_BAD_SUP_CHANNELS 24 /* Association denied because the info ++ * in the Supported Channel element is ++ * unacceptable ++ */ ++#define DOT11_SC_ASSOC_SHORTSLOT_REQUIRED 25 /* Association denied due to requesting ++ * station not supporting the Short Slot ++ * Time option ++ */ ++#define DOT11_SC_ASSOC_ERPBCC_REQUIRED 26 /* Association denied due to requesting ++ * station not supporting the ER-PBCC ++ * Modulation option ++ */ ++#define DOT11_SC_ASSOC_DSSOFDM_REQUIRED 27 /* Association denied due to requesting ++ * station not supporting the DSS-OFDM ++ * option ++ */ ++#define DOT11_SC_ASSOC_R0KH_UNREACHABLE 28 /* Association denied due to AP ++ * being unable to reach the R0 Key Holder ++ */ ++#define DOT11_SC_ASSOC_TRY_LATER 30 /* Association denied temporarily, try again later ++ */ ++#define DOT11_SC_ASSOC_MFP_VIOLATION 31 /* Association denied due to Robust Management ++ * frame policy violation ++ */ ++ ++#define DOT11_SC_DECLINED 37 /* request declined */ ++#define DOT11_SC_INVALID_PARAMS 38 /* One or more params have invalid values */ ++#define DOT11_SC_INVALID_PAIRWISE_CIPHER 42 /* invalid pairwise cipher */ ++#define DOT11_SC_INVALID_AKMP 43 /* Association denied due to invalid AKMP */ ++#define DOT11_SC_INVALID_RSNIE_CAP 45 /* invalid RSN IE capabilities */ ++#define DOT11_SC_DLS_NOT_ALLOWED 48 /* DLS is not allowed in the BSS by policy */ ++#define DOT11_SC_INVALID_PMKID 53 /* Association denied due to invalid PMKID */ ++#define DOT11_SC_INVALID_MDID 54 /* Association denied due to invalid MDID */ ++#define DOT11_SC_INVALID_FTIE 55 /* Association denied due to invalid FTIE */ ++ ++#define DOT11_SC_UNEXP_MSG 70 /* Unexpected message */ ++#define DOT11_SC_INVALID_SNONCE 71 /* Invalid SNonce */ ++#define DOT11_SC_INVALID_RSNIE 72 /* Invalid contents of RSNIE */ ++ ++/* Info Elts, length of INFORMATION portion of Info Elts */ ++#define DOT11_MNG_DS_PARAM_LEN 1 /* d11 management DS parameter length */ ++#define DOT11_MNG_IBSS_PARAM_LEN 2 /* d11 management IBSS parameter length */ ++ ++/* TIM Info element has 3 bytes fixed info in INFORMATION field, ++ * followed by 1 to 251 bytes of Partial Virtual Bitmap ++ */ ++#define DOT11_MNG_TIM_FIXED_LEN 3 /* d11 management TIM fixed length */ ++#define DOT11_MNG_TIM_DTIM_COUNT 0 /* d11 management DTIM count */ ++#define DOT11_MNG_TIM_DTIM_PERIOD 1 /* d11 management DTIM period */ ++#define DOT11_MNG_TIM_BITMAP_CTL 2 /* d11 management TIM BITMAP control */ ++#define DOT11_MNG_TIM_PVB 3 /* d11 management TIM PVB */ ++ ++/* TLV defines */ ++#define TLV_TAG_OFF 0 /* tag offset */ ++#define TLV_LEN_OFF 1 /* length offset */ ++#define TLV_HDR_LEN 2 /* header length */ ++#define TLV_BODY_OFF 2 /* body offset */ ++ ++/* Management Frame Information Element IDs */ ++#define DOT11_MNG_SSID_ID 0 /* d11 management SSID id */ ++#define DOT11_MNG_RATES_ID 1 /* d11 management rates id */ ++#define DOT11_MNG_FH_PARMS_ID 2 /* d11 management FH parameter id */ ++#define DOT11_MNG_DS_PARMS_ID 3 /* d11 management DS parameter id */ ++#define DOT11_MNG_CF_PARMS_ID 4 /* d11 management CF parameter id */ ++#define DOT11_MNG_TIM_ID 5 /* d11 management TIM id */ ++#define DOT11_MNG_IBSS_PARMS_ID 6 /* d11 management IBSS parameter id */ ++#define DOT11_MNG_COUNTRY_ID 7 /* d11 management country id */ ++#define DOT11_MNG_HOPPING_PARMS_ID 8 /* d11 management hopping parameter id */ ++#define DOT11_MNG_HOPPING_TABLE_ID 9 /* d11 management hopping table id */ ++#define DOT11_MNG_REQUEST_ID 10 /* d11 management request id */ ++#define DOT11_MNG_QBSS_LOAD_ID 11 /* d11 management QBSS Load id */ ++#define DOT11_MNG_EDCA_PARAM_ID 12 /* 11E EDCA Parameter id */ ++#define DOT11_MNG_CHALLENGE_ID 16 /* d11 management chanllenge id */ ++#define DOT11_MNG_PWR_CONSTRAINT_ID 32 /* 11H PowerConstraint */ ++#define DOT11_MNG_PWR_CAP_ID 33 /* 11H PowerCapability */ ++#define DOT11_MNG_TPC_REQUEST_ID 34 /* 11H TPC Request */ ++#define DOT11_MNG_TPC_REPORT_ID 35 /* 11H TPC Report */ ++#define DOT11_MNG_SUPP_CHANNELS_ID 36 /* 11H Supported Channels */ ++#define DOT11_MNG_CHANNEL_SWITCH_ID 37 /* 11H ChannelSwitch Announcement */ ++#define DOT11_MNG_MEASURE_REQUEST_ID 38 /* 11H MeasurementRequest */ ++#define DOT11_MNG_MEASURE_REPORT_ID 39 /* 11H MeasurementReport */ ++#define DOT11_MNG_QUIET_ID 40 /* 11H Quiet */ ++#define DOT11_MNG_IBSS_DFS_ID 41 /* 11H IBSS_DFS */ ++#define DOT11_MNG_ERP_ID 42 /* d11 management ERP id */ ++#define DOT11_MNG_TS_DELAY_ID 43 /* d11 management TS Delay id */ ++#define DOT11_MNG_HT_CAP 45 /* d11 mgmt HT cap id */ ++#define DOT11_MNG_QOS_CAP_ID 46 /* 11E QoS Capability id */ ++#define DOT11_MNG_NONERP_ID 47 /* d11 management NON-ERP id */ ++#define DOT11_MNG_RSN_ID 48 /* d11 management RSN id */ ++#define DOT11_MNG_EXT_RATES_ID 50 /* d11 management ext. rates id */ ++#define DOT11_MNG_AP_CHREP_ID 51 /* 11k AP Channel report id */ ++#define DOT11_MNG_NBR_REP_ID 52 /* 11k Neighbor report id */ ++#define DOT11_MNG_MDIE_ID 54 /* 11r Mobility domain id */ ++#define DOT11_MNG_FTIE_ID 55 /* 11r Fast Bss Transition id */ ++#define DOT11_MNG_FT_TI_ID 56 /* 11r Timeout Interval id */ ++#define DOT11_MNG_REGCLASS_ID 59 /* d11 management regulatory class id */ ++#define DOT11_MNG_EXT_CSA_ID 60 /* d11 Extended CSA */ ++#define DOT11_MNG_HT_ADD 61 /* d11 mgmt additional HT info */ ++#define DOT11_MNG_EXT_CHANNEL_OFFSET 62 /* d11 mgmt ext channel offset */ ++#ifdef BCMWAPI_WAI ++#define DOT11_MNG_WAPI_ID 68 /* d11 management WAPI id */ ++#endif ++#define DOT11_MNG_WAPI_ID 68 /* d11 management WAPI id */ ++#define DOT11_MNG_TIME_ADVERTISE_ID 69 /* 11p time advertisement */ ++#define DOT11_MNG_RRM_CAP_ID 70 /* 11k radio measurement capability */ ++#define DOT11_MNG_HT_BSS_COEXINFO_ID 72 /* d11 mgmt OBSS Coexistence INFO */ ++#define DOT11_MNG_HT_BSS_CHANNEL_REPORT_ID 73 /* d11 mgmt OBSS Intolerant Channel list */ ++#define DOT11_MNG_HT_OBSS_ID 74 /* d11 mgmt OBSS HT info */ ++#define DOT11_MNG_CHANNEL_USAGE 97 /* 11v channel usage */ ++#define DOT11_MNG_TIME_ZONE_ID 98 /* 11v time zone */ ++#define DOT11_MNG_LINK_IDENTIFIER_ID 101 /* 11z TDLS Link Identifier IE */ ++#define DOT11_MNG_WAKEUP_SCHEDULE_ID 102 /* 11z TDLS Wakeup Schedule IE */ ++#define DOT11_MNG_CHANNEL_SWITCH_TIMING_ID 104 /* 11z TDLS Channel Switch Timing IE */ ++#define DOT11_MNG_PTI_CONTROL_ID 105 /* 11z TDLS PTI Control IE */ ++#define DOT11_MNG_PU_BUFFER_STATUS_ID 106 /* 11z TDLS PU Buffer Status IE */ ++#define DOT11_MNG_INTERWORKING_ID 107 /* 11u interworking */ ++#define DOT11_MNG_ADVERTISEMENT_ID 108 /* 11u advertisement protocol */ ++#define DOT11_MNG_EXP_BW_REQ_ID 109 /* 11u expedited bandwith request */ ++#define DOT11_MNG_QOS_MAP_ID 110 /* 11u QoS map set */ ++#define DOT11_MNG_ROAM_CONSORT_ID 111 /* 11u roaming consortium */ ++#define DOT11_MNG_EMERGCY_ALERT_ID 112 /* 11u emergency alert identifier */ ++#define DOT11_MNG_EXT_CAP_ID 127 /* d11 mgmt ext capability */ ++#define DOT11_MNG_VHT_CAP_ID 191 /* d11 mgmt VHT cap id */ ++#define DOT11_MNG_VHT_OPERATION_ID 192 /* d11 mgmt VHT op id */ ++ ++#define DOT11_MNG_WPA_ID 221 /* d11 management WPA id */ ++#define DOT11_MNG_PROPR_ID 221 /* d11 management proprietary id */ ++/* should start using this one instead of above two */ ++#define DOT11_MNG_VS_ID 221 /* d11 management Vendor Specific IE */ ++ ++/* Rate element Basic flag and rate mask */ ++#define DOT11_RATE_BASIC 0x80 /* flag for a Basic Rate */ ++#define DOT11_RATE_MASK 0x7F /* mask for numeric part of rate */ ++ ++/* ERP info element bit values */ ++#define DOT11_MNG_ERP_LEN 1 /* ERP is currently 1 byte long */ ++#define DOT11_MNG_NONERP_PRESENT 0x01 /* NonERP (802.11b) STAs are present ++ *in the BSS ++ */ ++#define DOT11_MNG_USE_PROTECTION 0x02 /* Use protection mechanisms for ++ *ERP-OFDM frames ++ */ ++#define DOT11_MNG_BARKER_PREAMBLE 0x04 /* Short Preambles: 0 == allowed, ++ * 1 == not allowed ++ */ ++/* TS Delay element offset & size */ ++#define DOT11_MGN_TS_DELAY_LEN 4 /* length of TS DELAY IE */ ++#define TS_DELAY_FIELD_SIZE 4 /* TS DELAY field size */ ++ ++/* Capability Information Field */ ++#define DOT11_CAP_ESS 0x0001 /* d11 cap. ESS */ ++#define DOT11_CAP_IBSS 0x0002 /* d11 cap. IBSS */ ++#define DOT11_CAP_POLLABLE 0x0004 /* d11 cap. pollable */ ++#define DOT11_CAP_POLL_RQ 0x0008 /* d11 cap. poll request */ ++#define DOT11_CAP_PRIVACY 0x0010 /* d11 cap. privacy */ ++#define DOT11_CAP_SHORT 0x0020 /* d11 cap. short */ ++#define DOT11_CAP_PBCC 0x0040 /* d11 cap. PBCC */ ++#define DOT11_CAP_AGILITY 0x0080 /* d11 cap. agility */ ++#define DOT11_CAP_SPECTRUM 0x0100 /* d11 cap. spectrum */ ++#define DOT11_CAP_SHORTSLOT 0x0400 /* d11 cap. shortslot */ ++#define DOT11_CAP_RRM 0x1000 /* d11 cap. 11k radio measurement */ ++#define DOT11_CAP_CCK_OFDM 0x2000 /* d11 cap. CCK/OFDM */ ++ ++/* Extended capabilities IE bitfields */ ++/* 20/40 BSS Coexistence Management support bit position */ ++#define DOT11_EXT_CAP_OBSS_COEX_MGMT 0 ++/* scheduled PSMP support bit position */ ++#define DOT11_EXT_CAP_SPSMP 6 ++/* BSS Transition Management support bit position */ ++#define DOT11_EXT_CAP_BSS_TRANSITION_MGMT 19 ++/* Interworking support bit position */ ++#define DOT11_EXT_CAP_IW 31 ++/* service Interval granularity bit position and mask */ ++#define DOT11_EXT_CAP_SI 41 ++#define DOT11_EXT_CAP_SI_MASK 0x0E ++ ++/* ++ * Action Frame Constants ++ */ ++#define DOT11_ACTION_HDR_LEN 2 /* action frame category + action field */ ++#define DOT11_ACTION_CAT_OFF 0 /* category offset */ ++#define DOT11_ACTION_ACT_OFF 1 /* action offset */ ++ ++/* Action Category field (sec 7.3.1.11) */ ++#define DOT11_ACTION_CAT_ERR_MASK 0x80 /* category error mask */ ++#define DOT11_ACTION_CAT_MASK 0x7F /* category mask */ ++#define DOT11_ACTION_CAT_SPECT_MNG 0 /* category spectrum management */ ++#define DOT11_ACTION_CAT_QOS 1 /* category QoS */ ++#define DOT11_ACTION_CAT_DLS 2 /* category DLS */ ++#define DOT11_ACTION_CAT_BLOCKACK 3 /* category block ack */ ++#define DOT11_ACTION_CAT_PUBLIC 4 /* category public */ ++#define DOT11_ACTION_CAT_RRM 5 /* category radio measurements */ ++#define DOT11_ACTION_CAT_FBT 6 /* category fast bss transition */ ++#define DOT11_ACTION_CAT_HT 7 /* category for HT */ ++#define DOT11_ACTION_CAT_SA_QUERY 8 /* security association query */ ++#define DOT11_ACTION_CAT_PDPA 9 /* protected dual of public action */ ++#define DOT11_ACTION_CAT_BSSMGMT 10 /* category for BSS transition management */ ++#define DOT11_ACTION_NOTIFICATION 17 ++#define DOT11_ACTION_CAT_VSP 126 /* protected vendor specific */ ++#define DOT11_ACTION_CAT_VS 127 /* category Vendor Specific */ ++ ++/* Spectrum Management Action IDs (sec 7.4.1) */ ++#define DOT11_SM_ACTION_M_REQ 0 /* d11 action measurement request */ ++#define DOT11_SM_ACTION_M_REP 1 /* d11 action measurement response */ ++#define DOT11_SM_ACTION_TPC_REQ 2 /* d11 action TPC request */ ++#define DOT11_SM_ACTION_TPC_REP 3 /* d11 action TPC response */ ++#define DOT11_SM_ACTION_CHANNEL_SWITCH 4 /* d11 action channel switch */ ++#define DOT11_SM_ACTION_EXT_CSA 5 /* d11 extened CSA for 11n */ ++ ++/* HT action ids */ ++#define DOT11_ACTION_ID_HT_CH_WIDTH 0 /* notify channel width action id */ ++#define DOT11_ACTION_ID_HT_MIMO_PS 1 /* mimo ps action id */ ++ ++/* Public action ids */ ++#define DOT11_PUB_ACTION_BSS_COEX_MNG 0 /* 20/40 Coexistence Management action id */ ++#define DOT11_PUB_ACTION_CHANNEL_SWITCH 4 /* d11 action channel switch */ ++ ++/* Block Ack action types */ ++#define DOT11_BA_ACTION_ADDBA_REQ 0 /* ADDBA Req action frame type */ ++#define DOT11_BA_ACTION_ADDBA_RESP 1 /* ADDBA Resp action frame type */ ++#define DOT11_BA_ACTION_DELBA 2 /* DELBA action frame type */ ++ ++/* ADDBA action parameters */ ++#define DOT11_ADDBA_PARAM_AMSDU_SUP 0x0001 /* AMSDU supported under BA */ ++#define DOT11_ADDBA_PARAM_POLICY_MASK 0x0002 /* policy mask(ack vs delayed) */ ++#define DOT11_ADDBA_PARAM_POLICY_SHIFT 1 /* policy shift */ ++#define DOT11_ADDBA_PARAM_TID_MASK 0x003c /* tid mask */ ++#define DOT11_ADDBA_PARAM_TID_SHIFT 2 /* tid shift */ ++#define DOT11_ADDBA_PARAM_BSIZE_MASK 0xffc0 /* buffer size mask */ ++#define DOT11_ADDBA_PARAM_BSIZE_SHIFT 6 /* buffer size shift */ ++ ++#define DOT11_ADDBA_POLICY_DELAYED 0 /* delayed BA policy */ ++#define DOT11_ADDBA_POLICY_IMMEDIATE 1 /* immediate BA policy */ ++ ++/* Fast Transition action types */ ++#define DOT11_FT_ACTION_FT_RESERVED 0 ++#define DOT11_FT_ACTION_FT_REQ 1 /* FBT request - for over-the-DS FBT */ ++#define DOT11_FT_ACTION_FT_RES 2 /* FBT response - for over-the-DS FBT */ ++#define DOT11_FT_ACTION_FT_CON 3 /* FBT confirm - for OTDS with RRP */ ++#define DOT11_FT_ACTION_FT_ACK 4 /* FBT ack */ ++ ++/* DLS action types */ ++#define DOT11_DLS_ACTION_REQ 0 /* DLS Request */ ++#define DOT11_DLS_ACTION_RESP 1 /* DLS Response */ ++#define DOT11_DLS_ACTION_TD 2 /* DLS Teardown */ ++ ++/* Wireless Network Management (WNM) action types */ ++#define DOT11_WNM_ACTION_EVENT_REQ 0 ++#define DOT11_WNM_ACTION_EVENT_REP 1 ++#define DOT11_WNM_ACTION_DIAG_REQ 2 ++#define DOT11_WNM_ACTION_DIAG_REP 3 ++#define DOT11_WNM_ACTION_LOC_CFG_REQ 4 ++#define DOT11_WNM_ACTION_LOC_RFG_RESP 5 ++#define DOT11_WNM_ACTION_BSS_TRANS_QURY 6 ++#define DOT11_WNM_ACTION_BSS_TRANS_REQ 7 ++#define DOT11_WNM_ACTION_BSS_TRANS_RESP 8 ++#define DOT11_WNM_ACTION_FMS_REQ 9 ++#define DOT11_WNM_ACTION_FMS_RESP 10 ++#define DOT11_WNM_ACTION_COL_INTRFRNCE_REQ 11 ++#define DOT11_WNM_ACTION_COL_INTRFRNCE_REP 12 ++#define DOT11_WNM_ACTION_TFS_REQ 13 ++#define DOT11_WNM_ACTION_TFS_RESP 14 ++#define DOT11_WNM_ACTION_TFS_NOTIFY 15 ++#define DOT11_WNM_ACTION_WNM_SLEEP_REQ 16 ++#define DOT11_WNM_ACTION_WNM_SLEEP_RESP 17 ++#define DOT11_WNM_ACTION_TIM_BCAST_REQ 18 ++#define DOT11_WNM_ACTION_TIM_BCAST_RESP 19 ++#define DOT11_WNM_ACTION_QOS_TRFC_CAP_UPD 20 ++#define DOT11_WNM_ACTION_CHAN_USAGE_REQ 21 ++#define DOT11_WNM_ACTION_CHAN_USAGE_RESP 22 ++#define DOT11_WNM_ACTION_DMS_REQ 23 ++#define DOT11_WNM_ACTION_DMS_RESP 24 ++#define DOT11_WNM_ACTION_TMNG_MEASUR_REQ 25 ++#define DOT11_WNM_ACTION_NOTFCTN_REQ 26 ++#define DOT11_WNM_ACTION_NOTFCTN_RES 27 ++ ++#define DOT11_MNG_COUNTRY_ID_LEN 3 ++ ++/* DLS Request frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_dls_req { ++ uint8 category; /* category of action frame (2) */ ++ uint8 action; /* DLS action: req (0) */ ++ struct ether_addr da; /* destination address */ ++ struct ether_addr sa; /* source address */ ++ uint16 cap; /* capability */ ++ uint16 timeout; /* timeout value */ ++ uint8 data[1]; /* IE:support rate, extend support rate, HT cap */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_dls_req dot11_dls_req_t; ++#define DOT11_DLS_REQ_LEN 18 /* Fixed length */ ++ ++/* DLS response frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_dls_resp { ++ uint8 category; /* category of action frame (2) */ ++ uint8 action; /* DLS action: req (0) */ ++ uint16 status; /* status code field */ ++ struct ether_addr da; /* destination address */ ++ struct ether_addr sa; /* source address */ ++ uint8 data[1]; /* optional: capability, rate ... */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_dls_resp dot11_dls_resp_t; ++#define DOT11_DLS_RESP_LEN 16 /* Fixed length */ ++ ++ ++/* BSS Management Transition Query frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_bss_trans_query { ++ uint8 category; /* category of action frame (10) */ ++ uint8 action; /* WNM action: trans_query (6) */ ++ uint8 token; /* dialog token */ ++ uint8 reason; /* transition query reason */ ++ uint8 data[1]; /* Elements */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_bss_trans_query dot11_bss_trans_query_t; ++#define DOT11_BSS_TRANS_QUERY_LEN 4 /* Fixed length */ ++ ++/* BSS Management Transition Request frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_bss_trans_req { ++ uint8 category; /* category of action frame (10) */ ++ uint8 action; /* WNM action: trans_req (7) */ ++ uint8 token; /* dialog token */ ++ uint8 reqmode; /* transition request mode */ ++ uint16 disassoc_tmr; /* disassociation timer */ ++ uint8 validity_intrvl; /* validity interval */ ++ uint8 data[1]; /* optional: BSS term duration, ... */ ++ /* ...session info URL, list */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_bss_trans_req dot11_bss_trans_req_t; ++#define DOT11_BSS_TRANS_REQ_LEN 7 /* Fixed length */ ++ ++#define DOT11_BSS_TERM_DUR_LEN 12 /* Fixed length if present */ ++ ++ ++/* BSS Mgmt Transition Request Mode Field - 802.11v */ ++#define DOT11_BSS_TRNS_REQMODE_PREF_LIST_INCL 0x01 ++#define DOT11_BSS_TRNS_REQMODE_ABRIDGED 0x02 ++#define DOT11_BSS_TRNS_REQMODE_DISASSOC_IMMINENT 0x04 ++#define DOT11_BSS_TRNS_REQMODE_BSS_TERM_INCL 0x08 ++#define DOT11_BSS_TRNS_REQMODE_ESS_DISASSOC_IMNT 0x10 ++ ++ ++/* BSS Management transition response frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_bss_trans_res { ++ uint8 category; /* category of action frame (10) */ ++ uint8 action; /* WNM action: trans_res (8) */ ++ uint8 token; /* dialog token */ ++ uint8 status; /* transition status */ ++ uint8 term_delay; /* validity interval */ ++ uint8 data[1]; /* optional: BSS term duration, ... */ ++ /* ...session info URL, list */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_bss_trans_res dot11_bss_trans_res_t; ++#define DOT11_BSS_TRANS_RES_LEN 5 /* Fixed length */ ++ ++/* BSS Mgmt Transition Response Status Field */ ++#define DOT11_BSS_TRNS_RES_STATUS_ACCEPT 0 ++#define DOT11_BSS_TRNS_RES_STATUS_REJECT 1 ++#define DOT11_BSS_TRNS_RES_STATUS_REJ_INSUFF_BCN 2 ++#define DOT11_BSS_TRNS_RES_STATUS_REJ_INSUFF_CAP 3 ++#define DOT11_BSS_TRNS_RES_STATUS_REJ_TERM_UNDESIRED 4 ++#define DOT11_BSS_TRNS_RES_STATUS_REJ_TERM_DELAY_REQ 5 ++#define DOT11_BSS_TRNS_RES_STATUS_REJ_BSS_LIST_PROVIDED 6 ++#define DOT11_BSS_TRNS_RES_STATUS_REJ_NO_SUITABLE_BSS 7 ++#define DOT11_BSS_TRNS_RES_STATUS_REJ_LEAVING_ESS 8 ++ ++ ++/* Neighbor Report BSSID Information Field */ ++#define DOT11_NBR_RPRT_BSSID_INFO_REACHABILTY 0x0003 ++#define DOT11_NBR_RPRT_BSSID_INFO_SEC 0x0004 ++#define DOT11_NBR_RPRT_BSSID_INFO_KEY_SCOPE 0x0008 ++#define DOT11_NBR_RPRT_BSSID_INFO_CAP 0x03f0 ++ ++#define DOT11_NBR_RPRT_BSSID_INFO_CAP_SPEC_MGMT 0x0010 ++#define DOT11_NBR_RPRT_BSSID_INFO_CAP_QOS 0x0020 ++#define DOT11_NBR_RPRT_BSSID_INFO_CAP_APSD 0x0040 ++#define DOT11_NBR_RPRT_BSSID_INFO_CAP_RDIO_MSMT 0x0080 ++#define DOT11_NBR_RPRT_BSSID_INFO_CAP_DEL_BA 0x0100 ++#define DOT11_NBR_RPRT_BSSID_INFO_CAP_IMM_BA 0x0200 ++ ++/* Neighbor Report Subelements */ ++#define DOT11_NBR_RPRT_SUBELEM_BSS_CANDDT_PREF_ID 3 ++ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_addba_req { ++ uint8 category; /* category of action frame (3) */ ++ uint8 action; /* action: addba req */ ++ uint8 token; /* identifier */ ++ uint16 addba_param_set; /* parameter set */ ++ uint16 timeout; /* timeout in seconds */ ++ uint16 start_seqnum; /* starting sequence number */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_addba_req dot11_addba_req_t; ++#define DOT11_ADDBA_REQ_LEN 9 /* length of addba req frame */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_addba_resp { ++ uint8 category; /* category of action frame (3) */ ++ uint8 action; /* action: addba resp */ ++ uint8 token; /* identifier */ ++ uint16 status; /* status of add request */ ++ uint16 addba_param_set; /* negotiated parameter set */ ++ uint16 timeout; /* negotiated timeout in seconds */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_addba_resp dot11_addba_resp_t; ++#define DOT11_ADDBA_RESP_LEN 9 /* length of addba resp frame */ ++ ++/* DELBA action parameters */ ++#define DOT11_DELBA_PARAM_INIT_MASK 0x0800 /* initiator mask */ ++#define DOT11_DELBA_PARAM_INIT_SHIFT 11 /* initiator shift */ ++#define DOT11_DELBA_PARAM_TID_MASK 0xf000 /* tid mask */ ++#define DOT11_DELBA_PARAM_TID_SHIFT 12 /* tid shift */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_delba { ++ uint8 category; /* category of action frame (3) */ ++ uint8 action; /* action: addba req */ ++ uint16 delba_param_set; /* paarmeter set */ ++ uint16 reason; /* reason for dellba */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_delba dot11_delba_t; ++#define DOT11_DELBA_LEN 6 /* length of delba frame */ ++ ++/* SA Query action field value */ ++#define SA_QUERY_REQUEST 0 ++#define SA_QUERY_RESPONSE 1 ++ ++/* ************* 802.11r related definitions. ************* */ ++ ++/* Over-the-DS Fast Transition Request frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_ft_req { ++ uint8 category; /* category of action frame (6) */ ++ uint8 action; /* action: ft req */ ++ uint8 sta_addr[ETHER_ADDR_LEN]; ++ uint8 tgt_ap_addr[ETHER_ADDR_LEN]; ++ uint8 data[1]; /* Elements */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_ft_req dot11_ft_req_t; ++#define DOT11_FT_REQ_FIXED_LEN 14 ++ ++/* Over-the-DS Fast Transition Response frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_ft_res { ++ uint8 category; /* category of action frame (6) */ ++ uint8 action; /* action: ft resp */ ++ uint8 sta_addr[ETHER_ADDR_LEN]; ++ uint8 tgt_ap_addr[ETHER_ADDR_LEN]; ++ uint16 status; /* status code */ ++ uint8 data[1]; /* Elements */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_ft_res dot11_ft_res_t; ++#define DOT11_FT_RES_FIXED_LEN 16 ++ ++ ++/* ************* 802.11k related definitions. ************* */ ++ ++/* Radio measurements enabled capability ie */ ++ ++#define DOT11_RRM_CAP_LEN 5 /* length of rrm cap bitmap */ ++BWL_PRE_PACKED_STRUCT struct dot11_rrm_cap_ie { ++ uint8 cap[DOT11_RRM_CAP_LEN]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rrm_cap_ie dot11_rrm_cap_ie_t; ++ ++/* Bitmap definitions for cap ie */ ++#define DOT11_RRM_CAP_LINK 0 ++#define DOT11_RRM_CAP_NEIGHBOR_REPORT 1 ++#define DOT11_RRM_CAP_PARALLEL 2 ++#define DOT11_RRM_CAP_REPEATED 3 ++#define DOT11_RRM_CAP_BCN_PASSIVE 4 ++#define DOT11_RRM_CAP_BCN_ACTIVE 5 ++#define DOT11_RRM_CAP_BCN_TABLE 6 ++#define DOT11_RRM_CAP_BCN_REP_COND 7 ++#define DOT11_RRM_CAP_AP_CHANREP 16 ++ ++ ++/* Operating Class (formerly "Regulatory Class") definitions */ ++#define DOT11_OP_CLASS_NONE 255 ++ ++ ++/* Radio Measurements action ids */ ++#define DOT11_RM_ACTION_RM_REQ 0 /* Radio measurement request */ ++#define DOT11_RM_ACTION_RM_REP 1 /* Radio measurement report */ ++#define DOT11_RM_ACTION_LM_REQ 2 /* Link measurement request */ ++#define DOT11_RM_ACTION_LM_REP 3 /* Link measurement report */ ++#define DOT11_RM_ACTION_NR_REQ 4 /* Neighbor report request */ ++#define DOT11_RM_ACTION_NR_REP 5 /* Neighbor report response */ ++ ++/* Generic radio measurement action frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_rm_action { ++ uint8 category; /* category of action frame (5) */ ++ uint8 action; /* radio measurement action */ ++ uint8 token; /* dialog token */ ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rm_action dot11_rm_action_t; ++#define DOT11_RM_ACTION_LEN 3 ++ ++BWL_PRE_PACKED_STRUCT struct dot11_rmreq { ++ uint8 category; /* category of action frame (5) */ ++ uint8 action; /* radio measurement action */ ++ uint8 token; /* dialog token */ ++ uint16 reps; /* no. of repetitions */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rmreq dot11_rmreq_t; ++#define DOT11_RMREQ_LEN 5 ++ ++BWL_PRE_PACKED_STRUCT struct dot11_rm_ie { ++ uint8 id; ++ uint8 len; ++ uint8 token; ++ uint8 mode; ++ uint8 type; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rm_ie dot11_rm_ie_t; ++#define DOT11_RM_IE_LEN 5 ++ ++/* Definitions for "mode" bits in rm req */ ++#define DOT11_RMREQ_MODE_PARALLEL 1 ++#define DOT11_RMREQ_MODE_ENABLE 2 ++#define DOT11_RMREQ_MODE_REQUEST 4 ++#define DOT11_RMREQ_MODE_REPORT 8 ++#define DOT11_RMREQ_MODE_DURMAND 0x10 /* Duration Mandatory */ ++ ++/* Definitions for "mode" bits in rm rep */ ++#define DOT11_RMREP_MODE_LATE 1 ++#define DOT11_RMREP_MODE_INCAPABLE 2 ++#define DOT11_RMREP_MODE_REFUSED 4 ++ ++BWL_PRE_PACKED_STRUCT struct dot11_rmreq_bcn { ++ uint8 id; ++ uint8 len; ++ uint8 token; ++ uint8 mode; ++ uint8 type; ++ uint8 reg; ++ uint8 channel; ++ uint16 interval; ++ uint16 duration; ++ uint8 bcn_mode; ++ struct ether_addr bssid; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rmreq_bcn dot11_rmreq_bcn_t; ++#define DOT11_RMREQ_BCN_LEN 18 ++ ++BWL_PRE_PACKED_STRUCT struct dot11_rmrep_bcn { ++ uint8 reg; ++ uint8 channel; ++ uint32 starttime[2]; ++ uint16 duration; ++ uint8 frame_info; ++ uint8 rcpi; ++ uint8 rsni; ++ struct ether_addr bssid; ++ uint8 antenna_id; ++ uint32 parent_tsf; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rmrep_bcn dot11_rmrep_bcn_t; ++#define DOT11_RMREP_BCN_LEN 26 ++ ++/* Beacon request measurement mode */ ++#define DOT11_RMREQ_BCN_PASSIVE 0 ++#define DOT11_RMREQ_BCN_ACTIVE 1 ++#define DOT11_RMREQ_BCN_TABLE 2 ++ ++/* Sub-element IDs for Beacon Request */ ++#define DOT11_RMREQ_BCN_SSID_ID 0 ++#define DOT11_RMREQ_BCN_REPINFO_ID 1 ++#define DOT11_RMREQ_BCN_REPDET_ID 2 ++#define DOT11_RMREQ_BCN_REQUEST_ID 10 ++#define DOT11_RMREQ_BCN_APCHREP_ID 51 ++ ++/* Reporting Detail element definition */ ++#define DOT11_RMREQ_BCN_REPDET_FIXED 0 /* Fixed length fields only */ ++#define DOT11_RMREQ_BCN_REPDET_REQUEST 1 /* + requested information elems */ ++#define DOT11_RMREQ_BCN_REPDET_ALL 2 /* All fields */ ++ ++/* Sub-element IDs for Beacon Report */ ++#define DOT11_RMREP_BCN_FRM_BODY 1 ++ ++/* Neighbor measurement report */ ++BWL_PRE_PACKED_STRUCT struct dot11_rmrep_nbr { ++ struct ether_addr bssid; ++ uint32 bssid_info; ++ uint8 reg; ++ uint8 channel; ++ uint8 phytype; ++ uchar sub_elements[1]; /* Variable size data */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rmrep_nbr dot11_rmrep_nbr_t; ++#define DOT11_RMREP_NBR_LEN 13 ++ ++/* MLME Enumerations */ ++#define DOT11_BSSTYPE_INFRASTRUCTURE 0 /* d11 infrastructure */ ++#define DOT11_BSSTYPE_INDEPENDENT 1 /* d11 independent */ ++#define DOT11_BSSTYPE_ANY 2 /* d11 any BSS type */ ++#define DOT11_SCANTYPE_ACTIVE 0 /* d11 scan active */ ++#define DOT11_SCANTYPE_PASSIVE 1 /* d11 scan passive */ ++ ++/* Link Measurement */ ++BWL_PRE_PACKED_STRUCT struct dot11_lmreq { ++ uint8 category; /* category of action frame (5) */ ++ uint8 action; /* radio measurement action */ ++ uint8 token; /* dialog token */ ++ uint8 txpwr; /* Transmit Power Used */ ++ uint8 maxtxpwr; /* Max Transmit Power */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_lmreq dot11_lmreq_t; ++#define DOT11_LMREQ_LEN 5 ++ ++BWL_PRE_PACKED_STRUCT struct dot11_lmrep { ++ uint8 category; /* category of action frame (5) */ ++ uint8 action; /* radio measurement action */ ++ uint8 token; /* dialog token */ ++ dot11_tpc_rep_t tpc; /* TPC element */ ++ uint8 rxant; /* Receive Antenna ID */ ++ uint8 txant; /* Transmit Antenna ID */ ++ uint8 rcpi; /* RCPI */ ++ uint8 rsni; /* RSNI */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_lmrep dot11_lmrep_t; ++#define DOT11_LMREP_LEN 11 ++ ++/* 802.11 BRCM "Compromise" Pre N constants */ ++#define PREN_PREAMBLE 24 /* green field preamble time */ ++#define PREN_MM_EXT 12 /* extra mixed mode preamble time */ ++#define PREN_PREAMBLE_EXT 4 /* extra preamble (multiply by unique_streams-1) */ ++ ++/* 802.11N PHY constants */ ++#define RIFS_11N_TIME 2 /* NPHY RIFS time */ ++ ++/* 802.11 HT PLCP format 802.11n-2009, sec 20.3.9.4.3 ++ * HT-SIG is composed of two 24 bit parts, HT-SIG1 and HT-SIG2 ++ */ ++/* HT-SIG1 */ ++#define HT_SIG1_MCS_MASK 0x00007F ++#define HT_SIG1_CBW 0x000080 ++#define HT_SIG1_HT_LENGTH 0xFFFF00 ++ ++/* HT-SIG2 */ ++#define HT_SIG2_SMOOTHING 0x000001 ++#define HT_SIG2_NOT_SOUNDING 0x000002 ++#define HT_SIG2_RESERVED 0x000004 ++#define HT_SIG2_AGGREGATION 0x000008 ++#define HT_SIG2_STBC_MASK 0x000030 ++#define HT_SIG2_STBC_SHIFT 4 ++#define HT_SIG2_FEC_CODING 0x000040 ++#define HT_SIG2_SHORT_GI 0x000080 ++#define HT_SIG2_ESS_MASK 0x000300 ++#define HT_SIG2_ESS_SHIFT 8 ++#define HT_SIG2_CRC 0x03FC00 ++#define HT_SIG2_TAIL 0x1C0000 ++ ++/* 802.11 A PHY constants */ ++#define APHY_SLOT_TIME 9 /* APHY slot time */ ++#define APHY_SIFS_TIME 16 /* APHY SIFS time */ ++#define APHY_DIFS_TIME (APHY_SIFS_TIME + (2 * APHY_SLOT_TIME)) /* APHY DIFS time */ ++#define APHY_PREAMBLE_TIME 16 /* APHY preamble time */ ++#define APHY_SIGNAL_TIME 4 /* APHY signal time */ ++#define APHY_SYMBOL_TIME 4 /* APHY symbol time */ ++#define APHY_SERVICE_NBITS 16 /* APHY service nbits */ ++#define APHY_TAIL_NBITS 6 /* APHY tail nbits */ ++#define APHY_CWMIN 15 /* APHY cwmin */ ++ ++/* 802.11 B PHY constants */ ++#define BPHY_SLOT_TIME 20 /* BPHY slot time */ ++#define BPHY_SIFS_TIME 10 /* BPHY SIFS time */ ++#define BPHY_DIFS_TIME 50 /* BPHY DIFS time */ ++#define BPHY_PLCP_TIME 192 /* BPHY PLCP time */ ++#define BPHY_PLCP_SHORT_TIME 96 /* BPHY PLCP short time */ ++#define BPHY_CWMIN 31 /* BPHY cwmin */ ++ ++/* 802.11 G constants */ ++#define DOT11_OFDM_SIGNAL_EXTENSION 6 /* d11 OFDM signal extension */ ++ ++#define PHY_CWMAX 1023 /* PHY cwmax */ ++ ++#define DOT11_MAXNUMFRAGS 16 /* max # fragments per MSDU */ ++ ++/* 802.11 AC (VHT) constants */ ++ ++typedef int vht_group_id_t; ++ ++/* for VHT-A1 */ ++/* SIG-A1 reserved bits */ ++#define VHT_SIGA1_CONST_MASK 0x800004 ++ ++#define VHT_SIGA1_20MHZ_VAL 0x000000 ++#define VHT_SIGA1_40MHZ_VAL 0x000001 ++#define VHT_SIGA1_80MHZ_VAL 0x000002 ++#define VHT_SIGA1_160MHZ_VAL 0x000003 ++ ++#define VHT_SIGA1_STBC 0x000008 ++ ++#define VHT_SIGA1_GID_MAX_GID 0x3f ++#define VHT_SIGA1_GID_SHIFT 4 ++#define VHT_SIGA1_GID_TO_AP 0x00 ++#define VHT_SIGA1_GID_NOT_TO_AP 0x3f ++ ++#define VHT_SIGA1_NSTS_SHIFT 10 ++#define VHT_SIGA1_NSTS_SHIFT_MASK_USER0 0x001C00 ++ ++#define VHT_SIGA1_PARTIAL_AID_SHIFT 13 ++ ++/* for VHT-A2 */ ++#define VHT_SIGA2_GI_NONE 0x000000 ++#define VHT_SIGA2_GI_SHORT 0x000001 ++#define VHT_SIGA2_GI_W_MOD10 0x000002 ++#define VHT_SIGA2_CODING_LDPC 0x000004 ++#define VHT_SIGA2_BEAMFORM_ENABLE 0x000100 ++#define VHT_SIGA2_MCS_SHIFT 4 ++ ++#define VHT_SIGA2_B9_RESERVED 0x000200 ++#define VHT_SIGA2_TAIL_MASK 0xfc0000 ++#define VHT_SIGA2_TAIL_VALUE 0x000000 ++ ++#define VHT_SIGA2_SVC_BITS 16 ++#define VHT_SIGA2_TAIL_BITS 6 ++ ++ ++/* dot11Counters Table - 802.11 spec., Annex D */ ++typedef struct d11cnt { ++ uint32 txfrag; /* dot11TransmittedFragmentCount */ ++ uint32 txmulti; /* dot11MulticastTransmittedFrameCount */ ++ uint32 txfail; /* dot11FailedCount */ ++ uint32 txretry; /* dot11RetryCount */ ++ uint32 txretrie; /* dot11MultipleRetryCount */ ++ uint32 rxdup; /* dot11FrameduplicateCount */ ++ uint32 txrts; /* dot11RTSSuccessCount */ ++ uint32 txnocts; /* dot11RTSFailureCount */ ++ uint32 txnoack; /* dot11ACKFailureCount */ ++ uint32 rxfrag; /* dot11ReceivedFragmentCount */ ++ uint32 rxmulti; /* dot11MulticastReceivedFrameCount */ ++ uint32 rxcrc; /* dot11FCSErrorCount */ ++ uint32 txfrmsnt; /* dot11TransmittedFrameCount */ ++ uint32 rxundec; /* dot11WEPUndecryptableCount */ ++} d11cnt_t; ++ ++/* OUI for BRCM proprietary IE */ ++#define BRCM_PROP_OUI "\x00\x90\x4C" /* Broadcom proprietary OUI */ ++ ++ ++/* BRCM OUI: Used in the proprietary(221) IE in all broadcom devices */ ++#define BRCM_OUI "\x00\x10\x18" /* Broadcom OUI */ ++ ++/* BRCM info element */ ++BWL_PRE_PACKED_STRUCT struct brcm_ie { ++ uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ ++ uint8 len; /* IE length */ ++ uint8 oui[3]; /* Proprietary OUI, BRCM_OUI */ ++ uint8 ver; /* type/ver of this IE */ ++ uint8 assoc; /* # of assoc STAs */ ++ uint8 flags; /* misc flags */ ++ uint8 flags1; /* misc flags */ ++ uint16 amsdu_mtu_pref; /* preferred A-MSDU MTU */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct brcm_ie brcm_ie_t; ++#define BRCM_IE_LEN 11 /* BRCM IE length */ ++#define BRCM_IE_VER 2 /* BRCM IE version */ ++#define BRCM_IE_LEGACY_AES_VER 1 /* BRCM IE legacy AES version */ ++ ++/* brcm_ie flags */ ++#define BRF_LZWDS 0x4 /* lazy wds enabled */ ++#define BRF_BLOCKACK 0x8 /* BlockACK capable */ ++ ++/* brcm_ie flags1 */ ++#define BRF1_AMSDU 0x1 /* A-MSDU capable */ ++#define BRF1_WMEPS 0x4 /* AP is capable of handling WME + PS w/o APSD */ ++#define BRF1_PSOFIX 0x8 /* AP has fixed PS mode out-of-order packets */ ++#define BRF1_RX_LARGE_AGG 0x10 /* device can rx large aggregates */ ++#define BRF1_RFAWARE_DCS 0x20 /* RFAWARE dynamic channel selection (DCS) */ ++#define BRF1_SOFTAP 0x40 /* Configure as Broadcom SOFTAP */ ++ ++/* Vendor IE structure */ ++BWL_PRE_PACKED_STRUCT struct vndr_ie { ++ uchar id; ++ uchar len; ++ uchar oui [3]; ++ uchar data [1]; /* Variable size data */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct vndr_ie vndr_ie_t; ++ ++#define VNDR_IE_HDR_LEN 2 /* id + len field */ ++#define VNDR_IE_MIN_LEN 3 /* size of the oui field */ ++#define VNDR_IE_FIXED_LEN (VNDR_IE_HDR_LEN + VNDR_IE_MIN_LEN) ++#define VNDR_IE_MAX_LEN 256 /* verdor IE max length */ ++ ++/* ************* HT definitions. ************* */ ++#define MCSSET_LEN 16 /* 16-bits per 8-bit set to give 128-bits bitmap of MCS Index */ ++#define MAX_MCS_NUM (128) /* max mcs number = 128 */ ++ ++BWL_PRE_PACKED_STRUCT struct ht_cap_ie { ++ uint16 cap; ++ uint8 params; ++ uint8 supp_mcs[MCSSET_LEN]; ++ uint16 ext_htcap; ++ uint32 txbf_cap; ++ uint8 as_cap; ++} BWL_POST_PACKED_STRUCT; ++typedef struct ht_cap_ie ht_cap_ie_t; ++ ++/* CAP IE: HT 1.0 spec. simply stole a 802.11 IE, we use our prop. IE until this is resolved */ ++/* the capability IE is primarily used to convey this nodes abilities */ ++BWL_PRE_PACKED_STRUCT struct ht_prop_cap_ie { ++ uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ ++ uint8 len; /* IE length */ ++ uint8 oui[3]; /* Proprietary OUI, BRCM_PROP_OUI */ ++ uint8 type; /* type inidicates what follows */ ++ ht_cap_ie_t cap_ie; ++} BWL_POST_PACKED_STRUCT; ++typedef struct ht_prop_cap_ie ht_prop_cap_ie_t; ++ ++#define HT_PROP_IE_OVERHEAD 4 /* overhead bytes for prop oui ie */ ++#define HT_CAP_IE_LEN 26 /* HT capability len (based on .11n d2.0) */ ++#define HT_CAP_IE_TYPE 51 ++ ++#define HT_CAP_LDPC_CODING 0x0001 /* Support for rx of LDPC coded pkts */ ++#define HT_CAP_40MHZ 0x0002 /* FALSE:20Mhz, TRUE:20/40MHZ supported */ ++#define HT_CAP_MIMO_PS_MASK 0x000C /* Mimo PS mask */ ++#define HT_CAP_MIMO_PS_SHIFT 0x0002 /* Mimo PS shift */ ++#define HT_CAP_MIMO_PS_OFF 0x0003 /* Mimo PS, no restriction */ ++#define HT_CAP_MIMO_PS_RTS 0x0001 /* Mimo PS, send RTS/CTS around MIMO frames */ ++#define HT_CAP_MIMO_PS_ON 0x0000 /* Mimo PS, MIMO disallowed */ ++#define HT_CAP_GF 0x0010 /* Greenfield preamble support */ ++#define HT_CAP_SHORT_GI_20 0x0020 /* 20MHZ short guard interval support */ ++#define HT_CAP_SHORT_GI_40 0x0040 /* 40Mhz short guard interval support */ ++#define HT_CAP_TX_STBC 0x0080 /* Tx STBC support */ ++#define HT_CAP_RX_STBC_MASK 0x0300 /* Rx STBC mask */ ++#define HT_CAP_RX_STBC_SHIFT 8 /* Rx STBC shift */ ++#define HT_CAP_DELAYED_BA 0x0400 /* delayed BA support */ ++#define HT_CAP_MAX_AMSDU 0x0800 /* Max AMSDU size in bytes , 0=3839, 1=7935 */ ++ ++#define HT_CAP_DSSS_CCK 0x1000 /* DSSS/CCK supported by the BSS */ ++#define HT_CAP_PSMP 0x2000 /* Power Save Multi Poll support */ ++#define HT_CAP_40MHZ_INTOLERANT 0x4000 /* 40MHz Intolerant */ ++#define HT_CAP_LSIG_TXOP 0x8000 /* L-SIG TXOP protection support */ ++ ++#define HT_CAP_RX_STBC_NO 0x0 /* no rx STBC support */ ++#define HT_CAP_RX_STBC_ONE_STREAM 0x1 /* rx STBC support of 1 spatial stream */ ++#define HT_CAP_RX_STBC_TWO_STREAM 0x2 /* rx STBC support of 1-2 spatial streams */ ++#define HT_CAP_RX_STBC_THREE_STREAM 0x3 /* rx STBC support of 1-3 spatial streams */ ++ ++#define VHT_MAX_MPDU 11454 /* max mpdu size for now (bytes) */ ++#define VHT_MPDU_MSDU_DELTA 56 /* Difference in spec - vht mpdu, amsdu len */ ++/* Max AMSDU len - per spec */ ++#define VHT_MAX_AMSDU (VHT_MAX_MPDU - VHT_MPDU_MSDU_DELTA) ++ ++#define HT_MAX_AMSDU 7935 /* max amsdu size (bytes) per the HT spec */ ++#define HT_MIN_AMSDU 3835 /* min amsdu size (bytes) per the HT spec */ ++ ++#define HT_PARAMS_RX_FACTOR_MASK 0x03 /* ampdu rcv factor mask */ ++#define HT_PARAMS_DENSITY_MASK 0x1C /* ampdu density mask */ ++#define HT_PARAMS_DENSITY_SHIFT 2 /* ampdu density shift */ ++ ++/* HT/AMPDU specific define */ ++#define AMPDU_MAX_MPDU_DENSITY 7 /* max mpdu density; in 1/4 usec units */ ++#define AMPDU_DENSITY_NONE 0 /* No density requirement */ ++#define AMPDU_DENSITY_1over4_US 1 /* 1/4 us density */ ++#define AMPDU_DENSITY_1over2_US 2 /* 1/2 us density */ ++#define AMPDU_DENSITY_1_US 3 /* 1 us density */ ++#define AMPDU_DENSITY_2_US 4 /* 2 us density */ ++#define AMPDU_DENSITY_4_US 5 /* 4 us density */ ++#define AMPDU_DENSITY_8_US 6 /* 8 us density */ ++#define AMPDU_DENSITY_16_US 7 /* 16 us density */ ++#define AMPDU_RX_FACTOR_8K 0 /* max rcv ampdu len (8kb) */ ++#define AMPDU_RX_FACTOR_16K 1 /* max rcv ampdu len (16kb) */ ++#define AMPDU_RX_FACTOR_32K 2 /* max rcv ampdu len (32kb) */ ++#define AMPDU_RX_FACTOR_64K 3 /* max rcv ampdu len (64kb) */ ++#define AMPDU_RX_FACTOR_BASE 8*1024 /* ampdu factor base for rx len */ ++ ++#define AMPDU_DELIMITER_LEN 4 /* length of ampdu delimiter */ ++#define AMPDU_DELIMITER_LEN_MAX 63 /* max length of ampdu delimiter(enforced in HW) */ ++ ++#define HT_CAP_EXT_PCO 0x0001 ++#define HT_CAP_EXT_PCO_TTIME_MASK 0x0006 ++#define HT_CAP_EXT_PCO_TTIME_SHIFT 1 ++#define HT_CAP_EXT_MCS_FEEDBACK_MASK 0x0300 ++#define HT_CAP_EXT_MCS_FEEDBACK_SHIFT 8 ++#define HT_CAP_EXT_HTC 0x0400 ++#define HT_CAP_EXT_RD_RESP 0x0800 ++ ++BWL_PRE_PACKED_STRUCT struct ht_add_ie { ++ uint8 ctl_ch; /* control channel number */ ++ uint8 byte1; /* ext ch,rec. ch. width, RIFS support */ ++ uint16 opmode; /* operation mode */ ++ uint16 misc_bits; /* misc bits */ ++ uint8 basic_mcs[MCSSET_LEN]; /* required MCS set */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct ht_add_ie ht_add_ie_t; ++ ++/* ADD IE: HT 1.0 spec. simply stole a 802.11 IE, we use our prop. IE until this is resolved */ ++/* the additional IE is primarily used to convey the current BSS configuration */ ++BWL_PRE_PACKED_STRUCT struct ht_prop_add_ie { ++ uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ ++ uint8 len; /* IE length */ ++ uint8 oui[3]; /* Proprietary OUI, BRCM_PROP_OUI */ ++ uint8 type; /* indicates what follows */ ++ ht_add_ie_t add_ie; ++} BWL_POST_PACKED_STRUCT; ++typedef struct ht_prop_add_ie ht_prop_add_ie_t; ++ ++#define HT_ADD_IE_LEN 22 ++#define HT_ADD_IE_TYPE 52 ++ ++/* byte1 defn's */ ++#define HT_BW_ANY 0x04 /* set, STA can use 20 or 40MHz */ ++#define HT_RIFS_PERMITTED 0x08 /* RIFS allowed */ ++ ++/* opmode defn's */ ++#define HT_OPMODE_MASK 0x0003 /* protection mode mask */ ++#define HT_OPMODE_SHIFT 0 /* protection mode shift */ ++#define HT_OPMODE_PURE 0x0000 /* protection mode PURE */ ++#define HT_OPMODE_OPTIONAL 0x0001 /* protection mode optional */ ++#define HT_OPMODE_HT20IN40 0x0002 /* protection mode 20MHz HT in 40MHz BSS */ ++#define HT_OPMODE_MIXED 0x0003 /* protection mode Mixed Mode */ ++#define HT_OPMODE_NONGF 0x0004 /* protection mode non-GF */ ++#define DOT11N_TXBURST 0x0008 /* Tx burst limit */ ++#define DOT11N_OBSS_NONHT 0x0010 /* OBSS Non-HT STA present */ ++ ++/* misc_bites defn's */ ++#define HT_BASIC_STBC_MCS 0x007f /* basic STBC MCS */ ++#define HT_DUAL_STBC_PROT 0x0080 /* Dual STBC Protection */ ++#define HT_SECOND_BCN 0x0100 /* Secondary beacon support */ ++#define HT_LSIG_TXOP 0x0200 /* L-SIG TXOP Protection full support */ ++#define HT_PCO_ACTIVE 0x0400 /* PCO active */ ++#define HT_PCO_PHASE 0x0800 /* PCO phase */ ++#define HT_DUALCTS_PROTECTION 0x0080 /* DUAL CTS protection needed */ ++ ++/* Tx Burst Limits */ ++#define DOT11N_2G_TXBURST_LIMIT 6160 /* 2G band Tx burst limit per 802.11n Draft 1.10 (usec) */ ++#define DOT11N_5G_TXBURST_LIMIT 3080 /* 5G band Tx burst limit per 802.11n Draft 1.10 (usec) */ ++ ++/* Macros for opmode */ ++#define GET_HT_OPMODE(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ ++ >> HT_OPMODE_SHIFT) ++#define HT_MIXEDMODE_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ ++ == HT_OPMODE_MIXED) /* mixed mode present */ ++#define HT_HT20_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ ++ == HT_OPMODE_HT20IN40) /* 20MHz HT present */ ++#define HT_OPTIONAL_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ ++ == HT_OPMODE_OPTIONAL) /* Optional protection present */ ++#define HT_USE_PROTECTION(add_ie) (HT_HT20_PRESENT((add_ie)) || \ ++ HT_MIXEDMODE_PRESENT((add_ie))) /* use protection */ ++#define HT_NONGF_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_NONGF) \ ++ == HT_OPMODE_NONGF) /* non-GF present */ ++#define DOT11N_TXBURST_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_TXBURST) \ ++ == DOT11N_TXBURST) /* Tx Burst present */ ++#define DOT11N_OBSS_NONHT_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_OBSS_NONHT) \ ++ == DOT11N_OBSS_NONHT) /* OBSS Non-HT present */ ++ ++BWL_PRE_PACKED_STRUCT struct obss_params { ++ uint16 passive_dwell; ++ uint16 active_dwell; ++ uint16 bss_widthscan_interval; ++ uint16 passive_total; ++ uint16 active_total; ++ uint16 chanwidth_transition_dly; ++ uint16 activity_threshold; ++} BWL_POST_PACKED_STRUCT; ++typedef struct obss_params obss_params_t; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_obss_ie { ++ uint8 id; ++ uint8 len; ++ obss_params_t obss_params; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_obss_ie dot11_obss_ie_t; ++#define DOT11_OBSS_SCAN_IE_LEN sizeof(obss_params_t) /* HT OBSS len (based on 802.11n d3.0) */ ++ ++/* HT control field */ ++#define HT_CTRL_LA_TRQ 0x00000002 /* sounding request */ ++#define HT_CTRL_LA_MAI 0x0000003C /* MCS request or antenna selection indication */ ++#define HT_CTRL_LA_MAI_SHIFT 2 ++#define HT_CTRL_LA_MAI_MRQ 0x00000004 /* MCS request */ ++#define HT_CTRL_LA_MAI_MSI 0x00000038 /* MCS request sequence identifier */ ++#define HT_CTRL_LA_MFSI 0x000001C0 /* MFB sequence identifier */ ++#define HT_CTRL_LA_MFSI_SHIFT 6 ++#define HT_CTRL_LA_MFB_ASELC 0x0000FE00 /* MCS feedback, antenna selection command/data */ ++#define HT_CTRL_LA_MFB_ASELC_SH 9 ++#define HT_CTRL_LA_ASELC_CMD 0x00000C00 /* ASEL command */ ++#define HT_CTRL_LA_ASELC_DATA 0x0000F000 /* ASEL data */ ++#define HT_CTRL_CAL_POS 0x00030000 /* Calibration position */ ++#define HT_CTRL_CAL_SEQ 0x000C0000 /* Calibration sequence */ ++#define HT_CTRL_CSI_STEERING 0x00C00000 /* CSI/Steering */ ++#define HT_CTRL_CSI_STEER_SHIFT 22 ++#define HT_CTRL_CSI_STEER_NFB 0 /* no fedback required */ ++#define HT_CTRL_CSI_STEER_CSI 1 /* CSI, H matrix */ ++#define HT_CTRL_CSI_STEER_NCOM 2 /* non-compressed beamforming */ ++#define HT_CTRL_CSI_STEER_COM 3 /* compressed beamforming */ ++#define HT_CTRL_NDP_ANNOUNCE 0x01000000 /* NDP announcement */ ++#define HT_CTRL_AC_CONSTRAINT 0x40000000 /* AC Constraint */ ++#define HT_CTRL_RDG_MOREPPDU 0x80000000 /* RDG/More PPDU */ ++ ++#define HT_OPMODE_OPTIONAL 0x0001 /* protection mode optional */ ++#define HT_OPMODE_HT20IN40 0x0002 /* protection mode 20MHz HT in 40MHz BSS */ ++#define HT_OPMODE_MIXED 0x0003 /* protection mode Mixed Mode */ ++#define HT_OPMODE_NONGF 0x0004 /* protection mode non-GF */ ++#define DOT11N_TXBURST 0x0008 /* Tx burst limit */ ++#define DOT11N_OBSS_NONHT 0x0010 /* OBSS Non-HT STA present */ ++ ++/* ************* VHT definitions. ************* */ ++ ++BWL_PRE_PACKED_STRUCT struct vht_cap_ie { ++ uint32 vht_cap_info; ++ /* supported MCS set - 64 bit field */ ++ uint16 rx_mcs_map; ++ uint16 rx_max_rate; ++ uint16 tx_mcs_map; ++ uint16 tx_max_rate; ++} BWL_POST_PACKED_STRUCT; ++typedef struct vht_cap_ie vht_cap_ie_t; ++/* 4B cap_info + 8B supp_mcs */ ++#define VHT_CAP_IE_LEN 12 ++/* 32bit - cap info */ ++#define VHT_CAP_INFO_MAX_MPDU_LEN_MASK 0x00000003 ++#define VHT_CAP_INFO_SUPP_CHAN_WIDTH_MASK 0x0000000c ++#define VHT_CAP_INFO_LDPC 0x00000010 ++#define VHT_CAP_INFO_SGI_80MHZ 0x00000020 ++ ++#define VHT_CAP_INFO_SGI_160MHZ 0x00000040 ++#define VHT_CAP_INFO_TX_STBC 0x00000080 ++ ++#define VHT_CAP_INFO_RX_STBC_MASK 0x00000700 ++#define VHT_CAP_INFO_RX_STBC_SHIFT 8 ++#define VHT_CAP_INFO_SU_BEAMFMR 0x00000800 ++#define VHT_CAP_INFO_SU_BEAMFMEE 0x00001000 ++#define VHT_CAP_INFO_NUM_BMFMR_ANT_MASK 0x0000e000 ++#define VHT_CAP_INFO_NUM_BMFMR_ANT_SHIFT 13 ++ ++#define VHT_CAP_INFO_NUM_SOUNDING_DIM_MASK 0x00070000 ++#define VHT_CAP_INFO_NUM_SOUNDING_DIM_SHIFT 16 ++#define VHT_CAP_INFO_MU_BEAMFMR 0x00080000 ++#define VHT_CAP_INFO_MU_BEAMFMEE 0x00100000 ++#define VHT_CAP_INFO_TXOPPS 0x00200000 ++#define VHT_CAP_INFO_HTCVHT 0x00400000 ++#define VHT_CAP_INFO_AMPDU_MAXLEN_EXP_MASK 0x03800000 ++#define VHT_CAP_INFO_AMPDU_MAXLEN_EXP_SHIFT 23 ++ ++#define VHT_CAP_INFO_LINK_ADAPT_CAP_MASK 0x0c000000 ++#define VHT_CAP_INFO_LINK_ADAPT_CAP_SHIFT 26 ++ ++/* 64-bit Supp MCS. */ ++#define VHT_CAP_SUPP_MCS_RX_HIGHEST_RATE_MASK 0x1fff ++#define VHT_CAP_SUPP_MCS_RX_HIGHEST_RATE_SHIFT 0 ++ ++#define VHT_CAP_SUPP_MCS_TX_HIGHEST_RATE_MASK 0x1fff ++#define VHT_CAP_SUPP_MCS_TX_HIGHEST_RATE_SHIFT 0 ++ ++#define VHT_CAP_MCS_MAP_0_7 0 ++#define VHT_CAP_MCS_MAP_0_8 1 ++#define VHT_CAP_MCS_MAP_0_9 2 ++#define VHT_CAP_MCS_MAP_NONE 3 ++ ++#define VHT_CAP_MCS_MAP_NSS_MAX 8 ++ ++/* VHT Capabilities Supported Channel Width */ ++typedef enum vht_cap_chan_width { ++ VHT_CAP_CHAN_WIDTH_20_40 = 0x00, ++ VHT_CAP_CHAN_WIDTH_80 = 0x04, ++ VHT_CAP_CHAN_WIDTH_160 = 0x08 ++} vht_cap_chan_width_t; ++ ++/* VHT Capabilities Supported max MPDU LEN */ ++typedef enum vht_cap_max_mpdu_len { ++ VHT_CAP_MPDU_MAX_4K = 0x00, ++ VHT_CAP_MPDU_MAX_8K = 0x01, ++ VHT_CAP_MPDU_MAX_11K = 0x02 ++} vht_cap_max_mpdu_len_t; ++ ++/* VHT Operation Element */ ++BWL_PRE_PACKED_STRUCT struct vht_op_ie { ++ uint8 chan_width; ++ uint8 chan1; ++ uint8 chan2; ++ uint16 supp_mcs; /* same def as above in vht cap */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct vht_op_ie vht_op_ie_t; ++/* 3B VHT Op info + 2B Basic MCS */ ++#define VHT_OP_IE_LEN 5 ++ ++typedef enum vht_op_chan_width { ++ VHT_OP_CHAN_WIDTH_20_40 = 0, ++ VHT_OP_CHAN_WIDTH_80 = 1, ++ VHT_OP_CHAN_WIDTH_160 = 2, ++ VHT_OP_CHAN_WIDTH_80_80 = 3 ++} vht_op_chan_width_t; ++ ++/* Def for rx & tx basic mcs maps - ea ss num has 2 bits of info */ ++#define VHT_MCS_MAP_GET_SS_IDX(nss) (((nss)-1)*2) ++#define VHT_MCS_MAP_GET_MCS_PER_SS(nss, mcsMap) \ ++ (((mcsMap) >> VHT_MCS_MAP_GET_SS_IDX(nss)) & 0x3) ++#define VHT_MCS_MAP_SET_MCS_PER_SS(nss, numMcs, mcsMap) \ ++ ((mcsMap) |= (((numMcs) & 0x3) << VHT_MCS_MAP_GET_SS_IDX(nss))) ++ ++/* ************* WPA definitions. ************* */ ++#define WPA_OUI "\x00\x50\xF2" /* WPA OUI */ ++#define WPA_OUI_LEN 3 /* WPA OUI length */ ++#define WPA_OUI_TYPE 1 ++#define WPA_VERSION 1 /* WPA version */ ++#define WPA2_OUI "\x00\x0F\xAC" /* WPA2 OUI */ ++#define WPA2_OUI_LEN 3 /* WPA2 OUI length */ ++#define WPA2_VERSION 1 /* WPA2 version */ ++#define WPA2_VERSION_LEN 2 /* WAP2 version length */ ++ ++/* ************* WPS definitions. ************* */ ++#define WPS_OUI "\x00\x50\xF2" /* WPS OUI */ ++#define WPS_OUI_LEN 3 /* WPS OUI length */ ++#define WPS_OUI_TYPE 4 ++ ++/* ************* WFA definitions. ************* */ ++ ++#ifdef P2P_IE_OVRD ++#define WFA_OUI MAC_OUI ++#else ++#define WFA_OUI "\x50\x6F\x9A" /* WFA OUI */ ++#endif /* P2P_IE_OVRD */ ++#define WFA_OUI_LEN 3 /* WFA OUI length */ ++#ifdef P2P_IE_OVRD ++#define WFA_OUI_TYPE_P2P MAC_OUI_TYPE_P2P ++#else ++#define WFA_OUI_TYPE_P2P 9 ++#endif ++ ++#define WFA_OUI_TYPE_TPC 8 ++#ifdef WLTDLS ++#define WFA_OUI_TYPE_WFD 10 ++#endif /* WTDLS */ ++ ++/* RSN authenticated key managment suite */ ++#define RSN_AKM_NONE 0 /* None (IBSS) */ ++#define RSN_AKM_UNSPECIFIED 1 /* Over 802.1x */ ++#define RSN_AKM_PSK 2 /* Pre-shared Key */ ++#define RSN_AKM_FBT_1X 3 /* Fast Bss transition using 802.1X */ ++#define RSN_AKM_FBT_PSK 4 /* Fast Bss transition using Pre-shared Key */ ++#define RSN_AKM_MFP_1X 5 /* SHA256 key derivation, using 802.1X */ ++#define RSN_AKM_MFP_PSK 6 /* SHA256 key derivation, using Pre-shared Key */ ++#define RSN_AKM_TPK 7 /* TPK(TDLS Peer Key) handshake */ ++ ++/* Key related defines */ ++#define DOT11_MAX_DEFAULT_KEYS 4 /* number of default keys */ ++#define DOT11_MAX_KEY_SIZE 32 /* max size of any key */ ++#define DOT11_MAX_IV_SIZE 16 /* max size of any IV */ ++#define DOT11_EXT_IV_FLAG (1<<5) /* flag to indicate IV is > 4 bytes */ ++#define DOT11_WPA_KEY_RSC_LEN 8 /* WPA RSC key len */ ++ ++#define WEP1_KEY_SIZE 5 /* max size of any WEP key */ ++#define WEP1_KEY_HEX_SIZE 10 /* size of WEP key in hex. */ ++#define WEP128_KEY_SIZE 13 /* max size of any WEP key */ ++#define WEP128_KEY_HEX_SIZE 26 /* size of WEP key in hex. */ ++#define TKIP_MIC_SIZE 8 /* size of TKIP MIC */ ++#define TKIP_EOM_SIZE 7 /* max size of TKIP EOM */ ++#define TKIP_EOM_FLAG 0x5a /* TKIP EOM flag byte */ ++#define TKIP_KEY_SIZE 32 /* size of any TKIP key */ ++#define TKIP_MIC_AUTH_TX 16 /* offset to Authenticator MIC TX key */ ++#define TKIP_MIC_AUTH_RX 24 /* offset to Authenticator MIC RX key */ ++#define TKIP_MIC_SUP_RX TKIP_MIC_AUTH_TX /* offset to Supplicant MIC RX key */ ++#define TKIP_MIC_SUP_TX TKIP_MIC_AUTH_RX /* offset to Supplicant MIC TX key */ ++#define AES_KEY_SIZE 16 /* size of AES key */ ++#define AES_MIC_SIZE 8 /* size of AES MIC */ ++#define BIP_KEY_SIZE 16 /* size of BIP key */ ++ ++/* WCN */ ++#define WCN_OUI "\x00\x50\xf2" /* WCN OUI */ ++#define WCN_TYPE 4 /* WCN type */ ++#ifdef BCMWAPI_WPI ++#define SMS4_KEY_LEN 16 ++#define SMS4_WPI_CBC_MAC_LEN 16 ++#endif ++ ++ ++/* 802.11r protocol definitions */ ++ ++/* Mobility Domain IE */ ++BWL_PRE_PACKED_STRUCT struct dot11_mdid_ie { ++ uint8 id; ++ uint8 len; ++ uint16 mdid; /* Mobility Domain Id */ ++ uint8 cap; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_mdid_ie dot11_mdid_ie_t; ++ ++#define FBT_MDID_CAP_OVERDS 0x01 /* Fast Bss transition over the DS support */ ++#define FBT_MDID_CAP_RRP 0x02 /* Resource request protocol support */ ++ ++/* Fast Bss Transition IE */ ++BWL_PRE_PACKED_STRUCT struct dot11_ft_ie { ++ uint8 id; ++ uint8 len; ++ uint16 mic_control; /* Mic Control */ ++ uint8 mic[16]; ++ uint8 anonce[32]; ++ uint8 snonce[32]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_ft_ie dot11_ft_ie_t; ++ ++#define TIE_TYPE_RESERVED 0 ++#define TIE_TYPE_REASSOC_DEADLINE 1 ++#define TIE_TYPE_KEY_LIEFTIME 2 ++#define TIE_TYPE_ASSOC_COMEBACK 3 ++BWL_PRE_PACKED_STRUCT struct dot11_timeout_ie { ++ uint8 id; ++ uint8 len; ++ uint8 type; /* timeout interval type */ ++ uint32 value; /* timeout interval value */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_timeout_ie dot11_timeout_ie_t; ++ ++ ++/* GTK ie */ ++BWL_PRE_PACKED_STRUCT struct dot11_gtk_ie { ++ uint8 id; ++ uint8 len; ++ uint16 key_info; ++ uint8 key_len; ++ uint8 rsc[8]; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_gtk_ie dot11_gtk_ie_t; ++ ++#define BSSID_INVALID "\x00\x00\x00\x00\x00\x00" ++#define BSSID_BROADCAST "\xFF\xFF\xFF\xFF\xFF\xFF" ++ ++ ++/* ************* WMM Parameter definitions. ************* */ ++#define WMM_OUI "\x00\x50\xF2" /* WNN OUI */ ++#define WMM_OUI_LEN 3 /* WMM OUI length */ ++#define WMM_OUI_TYPE 2 /* WMM OUT type */ ++#define WMM_VERSION 1 ++#define WMM_VERSION_LEN 1 ++ ++/* WMM OUI subtype */ ++#define WMM_OUI_SUBTYPE_PARAMETER 1 ++#define WMM_PARAMETER_IE_LEN 24 ++ ++/* Link Identifier Element */ ++BWL_PRE_PACKED_STRUCT struct link_id_ie { ++ uint8 id; ++ uint8 len; ++ struct ether_addr bssid; ++ struct ether_addr tdls_init_mac; ++ struct ether_addr tdls_resp_mac; ++} BWL_POST_PACKED_STRUCT; ++typedef struct link_id_ie link_id_ie_t; ++#define TDLS_LINK_ID_IE_LEN 18 ++ ++/* Link Wakeup Schedule Element */ ++BWL_PRE_PACKED_STRUCT struct wakeup_sch_ie { ++ uint8 id; ++ uint8 len; ++ uint32 offset; /* in ms between TSF0 and start of 1st Awake Window */ ++ uint32 interval; /* in ms bwtween the start of 2 Awake Windows */ ++ uint32 awake_win_slots; /* in backof slots, duration of Awake Window */ ++ uint32 max_wake_win; /* in ms, max duration of Awake Window */ ++ uint16 idle_cnt; /* number of consecutive Awake Windows */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wakeup_sch_ie wakeup_sch_ie_t; ++#define TDLS_WAKEUP_SCH_IE_LEN 18 ++ ++/* Channel Switch Timing Element */ ++BWL_PRE_PACKED_STRUCT struct channel_switch_timing_ie { ++ uint8 id; ++ uint8 len; ++ uint16 switch_time; /* in ms, time to switch channels */ ++ uint16 switch_timeout; /* in ms */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct channel_switch_timing_ie channel_switch_timing_ie_t; ++#define TDLS_CHANNEL_SWITCH_TIMING_IE_LEN 4 ++ ++/* PTI Control Element */ ++BWL_PRE_PACKED_STRUCT struct pti_control_ie { ++ uint8 id; ++ uint8 len; ++ uint8 tid; ++ uint16 seq_control; ++} BWL_POST_PACKED_STRUCT; ++typedef struct pti_control_ie pti_control_ie_t; ++#define TDLS_PTI_CONTROL_IE_LEN 3 ++ ++/* PU Buffer Status Element */ ++BWL_PRE_PACKED_STRUCT struct pu_buffer_status_ie { ++ uint8 id; ++ uint8 len; ++ uint8 status; ++} BWL_POST_PACKED_STRUCT; ++typedef struct pu_buffer_status_ie pu_buffer_status_ie_t; ++#define TDLS_PU_BUFFER_STATUS_IE_LEN 1 ++#define TDLS_PU_BUFFER_STATUS_AC_BK 1 ++#define TDLS_PU_BUFFER_STATUS_AC_BE 2 ++#define TDLS_PU_BUFFER_STATUS_AC_VI 4 ++#define TDLS_PU_BUFFER_STATUS_AC_VO 8 ++ ++#ifdef BCMWAPI_WAI ++#define WAPI_IE_MIN_LEN 20 /* WAPI IE min length */ ++#define WAPI_VERSION 1 /* WAPI version */ ++#define WAPI_VERSION_LEN 2 /* WAPI version length */ ++#define WAPI_OUI "\x00\x14\x72" /* WAPI OUI */ ++#define WAPI_OUI_LEN DOT11_OUI_LEN /* WAPI OUI length */ ++#endif /* BCMWAPI_WAI */ ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* _802_11_H_ */ +diff --git a/drivers/net/wireless/ap6211/include/proto/802.11_bta.h b/drivers/net/wireless/ap6211/include/proto/802.11_bta.h +new file mode 100755 +index 0000000..3ee5a74 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/proto/802.11_bta.h +@@ -0,0 +1,45 @@ ++/* ++ * BT-AMP (BlueTooth Alternate Mac and Phy) 802.11 PAL (Protocol Adaptation Layer) ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: 802.11_bta.h 294267 2011-11-04 23:41:52Z $ ++*/ ++ ++#ifndef _802_11_BTA_H_ ++#define _802_11_BTA_H_ ++ ++#define BT_SIG_SNAP_MPROT "\xAA\xAA\x03\x00\x19\x58" ++ ++/* BT-AMP 802.11 PAL Protocols */ ++#define BTA_PROT_L2CAP 1 ++#define BTA_PROT_ACTIVITY_REPORT 2 ++#define BTA_PROT_SECURITY 3 ++#define BTA_PROT_LINK_SUPERVISION_REQUEST 4 ++#define BTA_PROT_LINK_SUPERVISION_REPLY 5 ++ ++/* BT-AMP 802.11 PAL AMP_ASSOC Type IDs */ ++#define BTA_TYPE_ID_MAC_ADDRESS 1 ++#define BTA_TYPE_ID_PREFERRED_CHANNELS 2 ++#define BTA_TYPE_ID_CONNECTED_CHANNELS 3 ++#define BTA_TYPE_ID_CAPABILITIES 4 ++#define BTA_TYPE_ID_VERSION 5 ++#endif /* _802_11_bta_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/proto/802.11e.h b/drivers/net/wireless/ap6211/include/proto/802.11e.h +new file mode 100755 +index 0000000..f391e68 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/proto/802.11e.h +@@ -0,0 +1,131 @@ ++/* ++ * 802.11e protocol header file ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: 802.11e.h 241182 2011-02-17 21:50:03Z $ ++ */ ++ ++#ifndef _802_11e_H_ ++#define _802_11e_H_ ++ ++#ifndef _TYPEDEFS_H_ ++#include ++#endif ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++ ++/* WME Traffic Specification (TSPEC) element */ ++#define WME_TSPEC_HDR_LEN 2 /* WME TSPEC header length */ ++#define WME_TSPEC_BODY_OFF 2 /* WME TSPEC body offset */ ++ ++#define WME_CATEGORY_CODE_OFFSET 0 /* WME Category code offset */ ++#define WME_ACTION_CODE_OFFSET 1 /* WME Action code offset */ ++#define WME_TOKEN_CODE_OFFSET 2 /* WME Token code offset */ ++#define WME_STATUS_CODE_OFFSET 3 /* WME Status code offset */ ++ ++BWL_PRE_PACKED_STRUCT struct tsinfo { ++ uint8 octets[3]; ++} BWL_POST_PACKED_STRUCT; ++ ++typedef struct tsinfo tsinfo_t; ++ ++/* 802.11e TSPEC IE */ ++typedef BWL_PRE_PACKED_STRUCT struct tspec { ++ uint8 oui[DOT11_OUI_LEN]; /* WME_OUI */ ++ uint8 type; /* WME_TYPE */ ++ uint8 subtype; /* WME_SUBTYPE_TSPEC */ ++ uint8 version; /* WME_VERSION */ ++ tsinfo_t tsinfo; /* TS Info bit field */ ++ uint16 nom_msdu_size; /* (Nominal or fixed) MSDU Size (bytes) */ ++ uint16 max_msdu_size; /* Maximum MSDU Size (bytes) */ ++ uint32 min_srv_interval; /* Minimum Service Interval (us) */ ++ uint32 max_srv_interval; /* Maximum Service Interval (us) */ ++ uint32 inactivity_interval; /* Inactivity Interval (us) */ ++ uint32 suspension_interval; /* Suspension Interval (us) */ ++ uint32 srv_start_time; /* Service Start Time (us) */ ++ uint32 min_data_rate; /* Minimum Data Rate (bps) */ ++ uint32 mean_data_rate; /* Mean Data Rate (bps) */ ++ uint32 peak_data_rate; /* Peak Data Rate (bps) */ ++ uint32 max_burst_size; /* Maximum Burst Size (bytes) */ ++ uint32 delay_bound; /* Delay Bound (us) */ ++ uint32 min_phy_rate; /* Minimum PHY Rate (bps) */ ++ uint16 surplus_bw; /* Surplus Bandwidth Allowance (range 1.0-8.0) */ ++ uint16 medium_time; /* Medium Time (32 us/s periods) */ ++} BWL_POST_PACKED_STRUCT tspec_t; ++ ++#define WME_TSPEC_LEN (sizeof(tspec_t)) /* not including 2-bytes of header */ ++ ++/* ts_info */ ++/* 802.1D priority is duplicated - bits 13-11 AND bits 3-1 */ ++#define TS_INFO_TID_SHIFT 1 /* TS info. TID shift */ ++#define TS_INFO_TID_MASK (0xf << TS_INFO_TID_SHIFT) /* TS info. TID mask */ ++#define TS_INFO_CONTENTION_SHIFT 7 /* TS info. contention shift */ ++#define TS_INFO_CONTENTION_MASK (0x1 << TS_INFO_CONTENTION_SHIFT) /* TS info. contention mask */ ++#define TS_INFO_DIRECTION_SHIFT 5 /* TS info. direction shift */ ++#define TS_INFO_DIRECTION_MASK (0x3 << TS_INFO_DIRECTION_SHIFT) /* TS info. direction mask */ ++#define TS_INFO_PSB_SHIFT 2 /* TS info. PSB bit Shift */ ++#define TS_INFO_PSB_MASK (1 << TS_INFO_PSB_SHIFT) /* TS info. PSB mask */ ++#define TS_INFO_UPLINK (0 << TS_INFO_DIRECTION_SHIFT) /* TS info. uplink */ ++#define TS_INFO_DOWNLINK (1 << TS_INFO_DIRECTION_SHIFT) /* TS info. downlink */ ++#define TS_INFO_BIDIRECTIONAL (3 << TS_INFO_DIRECTION_SHIFT) /* TS info. bidirectional */ ++#define TS_INFO_USER_PRIO_SHIFT 3 /* TS info. user priority shift */ ++/* TS info. user priority mask */ ++#define TS_INFO_USER_PRIO_MASK (0x7 << TS_INFO_USER_PRIO_SHIFT) ++ ++/* Macro to get/set bit(s) field in TSINFO */ ++#define WLC_CAC_GET_TID(pt) ((((pt).octets[0]) & TS_INFO_TID_MASK) >> TS_INFO_TID_SHIFT) ++#define WLC_CAC_GET_DIR(pt) ((((pt).octets[0]) & \ ++ TS_INFO_DIRECTION_MASK) >> TS_INFO_DIRECTION_SHIFT) ++#define WLC_CAC_GET_PSB(pt) ((((pt).octets[1]) & TS_INFO_PSB_MASK) >> TS_INFO_PSB_SHIFT) ++#define WLC_CAC_GET_USER_PRIO(pt) ((((pt).octets[1]) & \ ++ TS_INFO_USER_PRIO_MASK) >> TS_INFO_USER_PRIO_SHIFT) ++ ++#define WLC_CAC_SET_TID(pt, id) ((((pt).octets[0]) & (~TS_INFO_TID_MASK)) | \ ++ ((id) << TS_INFO_TID_SHIFT)) ++#define WLC_CAC_SET_USER_PRIO(pt, prio) ((((pt).octets[0]) & (~TS_INFO_USER_PRIO_MASK)) | \ ++ ((prio) << TS_INFO_USER_PRIO_SHIFT)) ++ ++/* 802.11e QBSS Load IE */ ++#define QBSS_LOAD_IE_LEN 5 /* QBSS Load IE length */ ++#define QBSS_LOAD_AAC_OFF 3 /* AAC offset in IE */ ++ ++#define CAC_ADDTS_RESP_TIMEOUT 300 /* default ADDTS response timeout in ms */ ++ ++/* 802.11e ADDTS status code */ ++#define DOT11E_STATUS_ADMISSION_ACCEPTED 0 /* TSPEC Admission accepted status */ ++#define DOT11E_STATUS_ADDTS_INVALID_PARAM 1 /* TSPEC invalid parameter status */ ++#define DOT11E_STATUS_ADDTS_REFUSED_NSBW 3 /* ADDTS refused (non-sufficient BW) */ ++#define DOT11E_STATUS_ADDTS_REFUSED_AWHILE 47 /* ADDTS refused but could retry later */ ++ ++/* 802.11e DELTS status code */ ++#define DOT11E_STATUS_QSTA_LEAVE_QBSS 36 /* STA leave QBSS */ ++#define DOT11E_STATUS_END_TS 37 /* END TS */ ++#define DOT11E_STATUS_UNKNOWN_TS 38 /* UNKNOWN TS */ ++#define DOT11E_STATUS_QSTA_REQ_TIMEOUT 39 /* STA ADDTS request timeout */ ++ ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* _802_11e_CAC_H_ */ +diff --git a/drivers/net/wireless/ap6211/include/proto/802.1d.h b/drivers/net/wireless/ap6211/include/proto/802.1d.h +new file mode 100755 +index 0000000..f11cc6c +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/proto/802.1d.h +@@ -0,0 +1,50 @@ ++/* ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * Fundamental types and constants relating to 802.1D ++ * ++ * $Id: 802.1d.h 241182 2011-02-17 21:50:03Z $ ++ */ ++ ++#ifndef _802_1_D_ ++#define _802_1_D_ ++ ++/* 802.1D priority defines */ ++#define PRIO_8021D_NONE 2 /* None = - */ ++#define PRIO_8021D_BK 1 /* BK - Background */ ++#define PRIO_8021D_BE 0 /* BE - Best-effort */ ++#define PRIO_8021D_EE 3 /* EE - Excellent-effort */ ++#define PRIO_8021D_CL 4 /* CL - Controlled Load */ ++#define PRIO_8021D_VI 5 /* Vi - Video */ ++#define PRIO_8021D_VO 6 /* Vo - Voice */ ++#define PRIO_8021D_NC 7 /* NC - Network Control */ ++#define MAXPRIO 7 /* 0-7 */ ++#define NUMPRIO (MAXPRIO + 1) ++ ++#define ALLPRIO -1 /* All prioirty */ ++ ++/* Converts prio to precedence since the numerical value of ++ * PRIO_8021D_BE and PRIO_8021D_NONE are swapped. ++ */ ++#define PRIO2PREC(prio) \ ++ (((prio) == PRIO_8021D_NONE || (prio) == PRIO_8021D_BE) ? ((prio^2)) : (prio)) ++ ++#endif /* _802_1_D__ */ +diff --git a/drivers/net/wireless/ap6211/include/proto/bcmeth.h b/drivers/net/wireless/ap6211/include/proto/bcmeth.h +new file mode 100755 +index 0000000..91ae75c +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/proto/bcmeth.h +@@ -0,0 +1,112 @@ ++/* ++ * Broadcom Ethernettype protocol definitions ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmeth.h 294352 2011-11-06 19:23:00Z $ ++ */ ++ ++/* ++ * Broadcom Ethernet protocol defines ++ */ ++ ++#ifndef _BCMETH_H_ ++#define _BCMETH_H_ ++ ++#ifndef _TYPEDEFS_H_ ++#include ++#endif ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++/* ETHER_TYPE_BRCM is defined in ethernet.h */ ++ ++/* ++ * Following the 2byte BRCM ether_type is a 16bit BRCM subtype field ++ * in one of two formats: (only subtypes 32768-65535 are in use now) ++ * ++ * subtypes 0-32767: ++ * 8 bit subtype (0-127) ++ * 8 bit length in bytes (0-255) ++ * ++ * subtypes 32768-65535: ++ * 16 bit big-endian subtype ++ * 16 bit big-endian length in bytes (0-65535) ++ * ++ * length is the number of additional bytes beyond the 4 or 6 byte header ++ * ++ * Reserved values: ++ * 0 reserved ++ * 5-15 reserved for iLine protocol assignments ++ * 17-126 reserved, assignable ++ * 127 reserved ++ * 32768 reserved ++ * 32769-65534 reserved, assignable ++ * 65535 reserved ++ */ ++ ++/* ++ * While adding the subtypes and their specific processing code make sure ++ * bcmeth_bcm_hdr_t is the first data structure in the user specific data structure definition ++ */ ++ ++#define BCMILCP_SUBTYPE_RATE 1 ++#define BCMILCP_SUBTYPE_LINK 2 ++#define BCMILCP_SUBTYPE_CSA 3 ++#define BCMILCP_SUBTYPE_LARQ 4 ++#define BCMILCP_SUBTYPE_VENDOR 5 ++#define BCMILCP_SUBTYPE_FLH 17 ++ ++#define BCMILCP_SUBTYPE_VENDOR_LONG 32769 ++#define BCMILCP_SUBTYPE_CERT 32770 ++#define BCMILCP_SUBTYPE_SES 32771 ++ ++ ++#define BCMILCP_BCM_SUBTYPE_RESERVED 0 ++#define BCMILCP_BCM_SUBTYPE_EVENT 1 ++#define BCMILCP_BCM_SUBTYPE_SES 2 ++/* ++ * The EAPOL type is not used anymore. Instead EAPOL messages are now embedded ++ * within BCMILCP_BCM_SUBTYPE_EVENT type messages ++ */ ++/* #define BCMILCP_BCM_SUBTYPE_EAPOL 3 */ ++#define BCMILCP_BCM_SUBTYPE_DPT 4 ++ ++#define BCMILCP_BCM_SUBTYPEHDR_MINLENGTH 8 ++#define BCMILCP_BCM_SUBTYPEHDR_VERSION 0 ++ ++/* These fields are stored in network order */ ++typedef BWL_PRE_PACKED_STRUCT struct bcmeth_hdr ++{ ++ uint16 subtype; /* Vendor specific..32769 */ ++ uint16 length; ++ uint8 version; /* Version is 0 */ ++ uint8 oui[3]; /* Broadcom OUI */ ++ /* user specific Data */ ++ uint16 usr_subtype; ++} BWL_POST_PACKED_STRUCT bcmeth_hdr_t; ++ ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* _BCMETH_H_ */ +diff --git a/drivers/net/wireless/ap6211/include/proto/bcmevent.h b/drivers/net/wireless/ap6211/include/proto/bcmevent.h +new file mode 100755 +index 0000000..c439707 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/proto/bcmevent.h +@@ -0,0 +1,368 @@ ++/* ++ * Broadcom Event protocol definitions ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * Dependencies: proto/bcmeth.h ++ * ++ * $Id: bcmevent.h 374275 2012-12-12 11:44:18Z $ ++ * ++ */ ++ ++/* ++ * Broadcom Ethernet Events protocol defines ++ * ++ */ ++ ++#ifndef _BCMEVENT_H_ ++#define _BCMEVENT_H_ ++ ++#ifndef _TYPEDEFS_H_ ++#include ++#endif ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++#define BCM_EVENT_MSG_VERSION 2 /* wl_event_msg_t struct version */ ++#define BCM_MSG_IFNAME_MAX 16 /* max length of interface name */ ++ ++/* flags */ ++#define WLC_EVENT_MSG_LINK 0x01 /* link is up */ ++#define WLC_EVENT_MSG_FLUSHTXQ 0x02 /* flush tx queue on MIC error */ ++#define WLC_EVENT_MSG_GROUP 0x04 /* group MIC error */ ++#define WLC_EVENT_MSG_UNKBSS 0x08 /* unknown source bsscfg */ ++#define WLC_EVENT_MSG_UNKIF 0x10 /* unknown source OS i/f */ ++ ++/* these fields are stored in network order */ ++ ++/* version 1 */ ++typedef BWL_PRE_PACKED_STRUCT struct ++{ ++ uint16 version; ++ uint16 flags; /* see flags below */ ++ uint32 event_type; /* Message (see below) */ ++ uint32 status; /* Status code (see below) */ ++ uint32 reason; /* Reason code (if applicable) */ ++ uint32 auth_type; /* WLC_E_AUTH */ ++ uint32 datalen; /* data buf */ ++ struct ether_addr addr; /* Station address (if applicable) */ ++ char ifname[BCM_MSG_IFNAME_MAX]; /* name of the packet incoming interface */ ++} BWL_POST_PACKED_STRUCT wl_event_msg_v1_t; ++ ++/* the current version */ ++typedef BWL_PRE_PACKED_STRUCT struct ++{ ++ uint16 version; ++ uint16 flags; /* see flags below */ ++ uint32 event_type; /* Message (see below) */ ++ uint32 status; /* Status code (see below) */ ++ uint32 reason; /* Reason code (if applicable) */ ++ uint32 auth_type; /* WLC_E_AUTH */ ++ uint32 datalen; /* data buf */ ++ struct ether_addr addr; /* Station address (if applicable) */ ++ char ifname[BCM_MSG_IFNAME_MAX]; /* name of the packet incoming interface */ ++ uint8 ifidx; /* destination OS i/f index */ ++ uint8 bsscfgidx; /* source bsscfg index */ ++} BWL_POST_PACKED_STRUCT wl_event_msg_t; ++ ++/* used by driver msgs */ ++typedef BWL_PRE_PACKED_STRUCT struct bcm_event { ++ struct ether_header eth; ++ bcmeth_hdr_t bcm_hdr; ++ wl_event_msg_t event; ++ /* data portion follows */ ++} BWL_POST_PACKED_STRUCT bcm_event_t; ++ ++#define BCM_MSG_LEN (sizeof(bcm_event_t) - sizeof(bcmeth_hdr_t) - sizeof(struct ether_header)) ++ ++/* Event messages */ ++#define WLC_E_SET_SSID 0 /* indicates status of set SSID */ ++#define WLC_E_JOIN 1 /* differentiates join IBSS from found (WLC_E_START) IBSS */ ++#define WLC_E_START 2 /* STA founded an IBSS or AP started a BSS */ ++#define WLC_E_AUTH 3 /* 802.11 AUTH request */ ++#define WLC_E_AUTH_IND 4 /* 802.11 AUTH indication */ ++#define WLC_E_DEAUTH 5 /* 802.11 DEAUTH request */ ++#define WLC_E_DEAUTH_IND 6 /* 802.11 DEAUTH indication */ ++#define WLC_E_ASSOC 7 /* 802.11 ASSOC request */ ++#define WLC_E_ASSOC_IND 8 /* 802.11 ASSOC indication */ ++#define WLC_E_REASSOC 9 /* 802.11 REASSOC request */ ++#define WLC_E_REASSOC_IND 10 /* 802.11 REASSOC indication */ ++#define WLC_E_DISASSOC 11 /* 802.11 DISASSOC request */ ++#define WLC_E_DISASSOC_IND 12 /* 802.11 DISASSOC indication */ ++#define WLC_E_QUIET_START 13 /* 802.11h Quiet period started */ ++#define WLC_E_QUIET_END 14 /* 802.11h Quiet period ended */ ++#define WLC_E_BEACON_RX 15 /* BEACONS received/lost indication */ ++#define WLC_E_LINK 16 /* generic link indication */ ++#define WLC_E_MIC_ERROR 17 /* TKIP MIC error occurred */ ++#define WLC_E_NDIS_LINK 18 /* NDIS style link indication */ ++#define WLC_E_ROAM 19 /* roam attempt occurred: indicate status & reason */ ++#define WLC_E_TXFAIL 20 /* change in dot11FailedCount (txfail) */ ++#define WLC_E_PMKID_CACHE 21 /* WPA2 pmkid cache indication */ ++#define WLC_E_RETROGRADE_TSF 22 /* current AP's TSF value went backward */ ++#define WLC_E_PRUNE 23 /* AP was pruned from join list for reason */ ++#define WLC_E_AUTOAUTH 24 /* report AutoAuth table entry match for join attempt */ ++#define WLC_E_EAPOL_MSG 25 /* Event encapsulating an EAPOL message */ ++#define WLC_E_SCAN_COMPLETE 26 /* Scan results are ready or scan was aborted */ ++#define WLC_E_ADDTS_IND 27 /* indicate to host addts fail/success */ ++#define WLC_E_DELTS_IND 28 /* indicate to host delts fail/success */ ++#define WLC_E_BCNSENT_IND 29 /* indicate to host of beacon transmit */ ++#define WLC_E_BCNRX_MSG 30 /* Send the received beacon up to the host */ ++#define WLC_E_BCNLOST_MSG 31 /* indicate to host loss of beacon */ ++#define WLC_E_ROAM_PREP 32 /* before attempting to roam */ ++#define WLC_E_PFN_NET_FOUND 33 /* PFN network found event */ ++#define WLC_E_PFN_NET_LOST 34 /* PFN network lost event */ ++#define WLC_E_RESET_COMPLETE 35 ++#define WLC_E_JOIN_START 36 ++#define WLC_E_ROAM_START 37 ++#define WLC_E_ASSOC_START 38 ++#define WLC_E_IBSS_ASSOC 39 ++#define WLC_E_RADIO 40 ++#define WLC_E_PSM_WATCHDOG 41 /* PSM microcode watchdog fired */ ++#define WLC_E_PROBREQ_MSG 44 /* probe request received */ ++#define WLC_E_SCAN_CONFIRM_IND 45 ++#define WLC_E_PSK_SUP 46 /* WPA Handshake fail */ ++#define WLC_E_COUNTRY_CODE_CHANGED 47 ++#define WLC_E_EXCEEDED_MEDIUM_TIME 48 /* WMMAC excedded medium time */ ++#define WLC_E_ICV_ERROR 49 /* WEP ICV error occurred */ ++#define WLC_E_UNICAST_DECODE_ERROR 50 /* Unsupported unicast encrypted frame */ ++#define WLC_E_MULTICAST_DECODE_ERROR 51 /* Unsupported multicast encrypted frame */ ++#define WLC_E_TRACE 52 ++#ifdef WLBTAMP ++#define WLC_E_BTA_HCI_EVENT 53 /* BT-AMP HCI event */ ++#endif ++#define WLC_E_IF 54 /* I/F change (for dongle host notification) */ ++#define WLC_E_P2P_DISC_LISTEN_COMPLETE 55 /* listen state expires */ ++#define WLC_E_RSSI 56 /* indicate RSSI change based on configured levels */ ++#define WLC_E_PFN_SCAN_COMPLETE 57 /* PFN completed scan of network list */ ++#define WLC_E_EXTLOG_MSG 58 ++#define WLC_E_ACTION_FRAME 59 /* Action frame Rx */ ++#define WLC_E_ACTION_FRAME_COMPLETE 60 /* Action frame Tx complete */ ++#define WLC_E_PRE_ASSOC_IND 61 /* assoc request received */ ++#define WLC_E_PRE_REASSOC_IND 62 /* re-assoc request received */ ++#define WLC_E_CHANNEL_ADOPTED 63 ++#define WLC_E_AP_STARTED 64 /* AP started */ ++#define WLC_E_DFS_AP_STOP 65 /* AP stopped due to DFS */ ++#define WLC_E_DFS_AP_RESUME 66 /* AP resumed due to DFS */ ++#define WLC_E_WAI_STA_EVENT 67 /* WAI stations event */ ++#define WLC_E_WAI_MSG 68 /* event encapsulating an WAI message */ ++#define WLC_E_ESCAN_RESULT 69 /* escan result event */ ++#define WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE 70 /* action frame off channel complete */ ++#define WLC_E_PROBRESP_MSG 71 /* probe response received */ ++#define WLC_E_P2P_PROBREQ_MSG 72 /* P2P Probe request received */ ++#define WLC_E_DCS_REQUEST 73 ++ ++#define WLC_E_FIFO_CREDIT_MAP 74 /* credits for D11 FIFOs. [AC0,AC1,AC2,AC3,BC_MC,ATIM] */ ++ ++#define WLC_E_ACTION_FRAME_RX 75 /* Received action frame event WITH ++ * wl_event_rx_frame_data_t header ++ */ ++#define WLC_E_WAKE_EVENT 76 /* Wake Event timer fired, used for wake WLAN test mode */ ++#define WLC_E_RM_COMPLETE 77 /* Radio measurement complete */ ++#define WLC_E_HTSFSYNC 78 /* Synchronize TSF with the host */ ++#define WLC_E_OVERLAY_REQ 79 /* request an overlay IOCTL/iovar from the host */ ++#define WLC_E_CSA_COMPLETE_IND 80 /* 802.11 CHANNEL SWITCH ACTION completed */ ++#define WLC_E_EXCESS_PM_WAKE_EVENT 81 /* excess PM Wake Event to inform host */ ++#define WLC_E_PFN_SCAN_NONE 82 /* no PFN networks around */ ++#define WLC_E_PFN_SCAN_ALLGONE 83 /* last found PFN network gets lost */ ++#define WLC_E_GTK_PLUMBED 84 ++#define WLC_E_ASSOC_IND_NDIS 85 /* 802.11 ASSOC indication for NDIS only */ ++#define WLC_E_REASSOC_IND_NDIS 86 /* 802.11 REASSOC indication for NDIS only */ ++#define WLC_E_ASSOC_REQ_IE 87 ++#define WLC_E_ASSOC_RESP_IE 88 ++#define WLC_E_ASSOC_RECREATED 89 /* association recreated on resume */ ++#define WLC_E_ACTION_FRAME_RX_NDIS 90 /* rx action frame event for NDIS only */ ++#define WLC_E_AUTH_REQ 91 /* authentication request received */ ++#define WLC_E_TDLS_PEER_EVENT 92 /* discovered peer, connected or disconnected peer */ ++#define WLC_E_SPEEDY_RECREATE_FAIL 93 /* fast assoc recreation failed */ ++#define WLC_E_SERVICE_FOUND 102 /* desired service found */ ++#define WLC_E_GAS_FRAGMENT_RX 103 /* GAS fragment received */ ++#define WLC_E_GAS_COMPLETE 104 /* GAS sessions all complete */ ++#define WLC_E_P2PO_ADD_DEVICE 105 /* New device found by p2p offload */ ++#define WLC_E_P2PO_DEL_DEVICE 106 /* device has been removed by p2p offload */ ++#define WLC_E_LAST 107 /* highest val + 1 for range checking */ ++ ++ ++/* Table of event name strings for UIs and debugging dumps */ ++typedef struct { ++ uint event; ++ const char *name; ++} bcmevent_name_t; ++ ++extern const bcmevent_name_t bcmevent_names[]; ++extern const int bcmevent_names_size; ++ ++/* Event status codes */ ++#define WLC_E_STATUS_SUCCESS 0 /* operation was successful */ ++#define WLC_E_STATUS_FAIL 1 /* operation failed */ ++#define WLC_E_STATUS_TIMEOUT 2 /* operation timed out */ ++#define WLC_E_STATUS_NO_NETWORKS 3 /* failed due to no matching network found */ ++#define WLC_E_STATUS_ABORT 4 /* operation was aborted */ ++#define WLC_E_STATUS_NO_ACK 5 /* protocol failure: packet not ack'd */ ++#define WLC_E_STATUS_UNSOLICITED 6 /* AUTH or ASSOC packet was unsolicited */ ++#define WLC_E_STATUS_ATTEMPT 7 /* attempt to assoc to an auto auth configuration */ ++#define WLC_E_STATUS_PARTIAL 8 /* scan results are incomplete */ ++#define WLC_E_STATUS_NEWSCAN 9 /* scan aborted by another scan */ ++#define WLC_E_STATUS_NEWASSOC 10 /* scan aborted due to assoc in progress */ ++#define WLC_E_STATUS_11HQUIET 11 /* 802.11h quiet period started */ ++#define WLC_E_STATUS_SUPPRESS 12 /* user disabled scanning (WLC_SET_SCANSUPPRESS) */ ++#define WLC_E_STATUS_NOCHANS 13 /* no allowable channels to scan */ ++#define WLC_E_STATUS_CS_ABORT 15 /* abort channel select */ ++#define WLC_E_STATUS_ERROR 16 /* request failed due to error */ ++ ++/* roam reason codes */ ++#define WLC_E_REASON_INITIAL_ASSOC 0 /* initial assoc */ ++#define WLC_E_REASON_LOW_RSSI 1 /* roamed due to low RSSI */ ++#define WLC_E_REASON_DEAUTH 2 /* roamed due to DEAUTH indication */ ++#define WLC_E_REASON_DISASSOC 3 /* roamed due to DISASSOC indication */ ++#define WLC_E_REASON_BCNS_LOST 4 /* roamed due to lost beacons */ ++#define WLC_E_REASON_MINTXRATE 9 /* roamed because at mintxrate for too long */ ++#define WLC_E_REASON_TXFAIL 10 /* We can hear AP, but AP can't hear us */ ++ ++/* Roam codes used primarily by CCX */ ++#define WLC_E_REASON_FAST_ROAM_FAILED 5 /* roamed due to fast roam failure */ ++#define WLC_E_REASON_DIRECTED_ROAM 6 /* roamed due to request by AP */ ++#define WLC_E_REASON_TSPEC_REJECTED 7 /* roamed due to TSPEC rejection */ ++#define WLC_E_REASON_BETTER_AP 8 /* roamed due to finding better AP */ ++ ++ ++#define WLC_E_REASON_REQUESTED_ROAM 11 /* roamed due to BSS Mgmt Transition request by AP */ ++ ++/* prune reason codes */ ++#define WLC_E_PRUNE_ENCR_MISMATCH 1 /* encryption mismatch */ ++#define WLC_E_PRUNE_BCAST_BSSID 2 /* AP uses a broadcast BSSID */ ++#define WLC_E_PRUNE_MAC_DENY 3 /* STA's MAC addr is in AP's MAC deny list */ ++#define WLC_E_PRUNE_MAC_NA 4 /* STA's MAC addr is not in AP's MAC allow list */ ++#define WLC_E_PRUNE_REG_PASSV 5 /* AP not allowed due to regulatory restriction */ ++#define WLC_E_PRUNE_SPCT_MGMT 6 /* AP does not support STA locale spectrum mgmt */ ++#define WLC_E_PRUNE_RADAR 7 /* AP is on a radar channel of STA locale */ ++#define WLC_E_RSN_MISMATCH 8 /* STA does not support AP's RSN */ ++#define WLC_E_PRUNE_NO_COMMON_RATES 9 /* No rates in common with AP */ ++#define WLC_E_PRUNE_BASIC_RATES 10 /* STA does not support all basic rates of BSS */ ++#define WLC_E_PRUNE_CIPHER_NA 12 /* BSS's cipher not supported */ ++#define WLC_E_PRUNE_KNOWN_STA 13 /* AP is already known to us as a STA */ ++#define WLC_E_PRUNE_WDS_PEER 15 /* AP is already known to us as a WDS peer */ ++#define WLC_E_PRUNE_QBSS_LOAD 16 /* QBSS LOAD - AAC is too low */ ++#define WLC_E_PRUNE_HOME_AP 17 /* prune home AP */ ++ ++/* WPA failure reason codes carried in the WLC_E_PSK_SUP event */ ++#define WLC_E_SUP_OTHER 0 /* Other reason */ ++#define WLC_E_SUP_DECRYPT_KEY_DATA 1 /* Decryption of key data failed */ ++#define WLC_E_SUP_BAD_UCAST_WEP128 2 /* Illegal use of ucast WEP128 */ ++#define WLC_E_SUP_BAD_UCAST_WEP40 3 /* Illegal use of ucast WEP40 */ ++#define WLC_E_SUP_UNSUP_KEY_LEN 4 /* Unsupported key length */ ++#define WLC_E_SUP_PW_KEY_CIPHER 5 /* Unicast cipher mismatch in pairwise key */ ++#define WLC_E_SUP_MSG3_TOO_MANY_IE 6 /* WPA IE contains > 1 RSN IE in key msg 3 */ ++#define WLC_E_SUP_MSG3_IE_MISMATCH 7 /* WPA IE mismatch in key message 3 */ ++#define WLC_E_SUP_NO_INSTALL_FLAG 8 /* INSTALL flag unset in 4-way msg */ ++#define WLC_E_SUP_MSG3_NO_GTK 9 /* encapsulated GTK missing from msg 3 */ ++#define WLC_E_SUP_GRP_KEY_CIPHER 10 /* Multicast cipher mismatch in group key */ ++#define WLC_E_SUP_GRP_MSG1_NO_GTK 11 /* encapsulated GTK missing from group msg 1 */ ++#define WLC_E_SUP_GTK_DECRYPT_FAIL 12 /* GTK decrypt failure */ ++#define WLC_E_SUP_SEND_FAIL 13 /* message send failure */ ++#define WLC_E_SUP_DEAUTH 14 /* received FC_DEAUTH */ ++#define WLC_E_SUP_WPA_PSK_TMO 15 /* WPA PSK 4-way handshake timeout */ ++ ++/* Event data for events that include frames received over the air */ ++/* WLC_E_PROBRESP_MSG ++ * WLC_E_P2P_PROBREQ_MSG ++ * WLC_E_ACTION_FRAME_RX ++ */ ++typedef BWL_PRE_PACKED_STRUCT struct wl_event_rx_frame_data { ++ uint16 version; ++ uint16 channel; /* Matches chanspec_t format from bcmwifi_channels.h */ ++ int32 rssi; ++ uint32 mactime; ++ uint32 rate; ++} BWL_POST_PACKED_STRUCT wl_event_rx_frame_data_t; ++ ++#define BCM_RX_FRAME_DATA_VERSION 1 ++ ++/* WLC_E_IF event data */ ++typedef struct wl_event_data_if { ++ uint8 ifidx; /* RTE virtual device index (for dongle) */ ++ uint8 opcode; /* see I/F opcode */ ++ uint8 reserved; ++ uint8 bssidx; /* bsscfg index */ ++ uint8 role; /* see I/F role */ ++} wl_event_data_if_t; ++ ++/* opcode in WLC_E_IF event */ ++#define WLC_E_IF_ADD 1 /* bsscfg add */ ++#define WLC_E_IF_DEL 2 /* bsscfg delete */ ++#define WLC_E_IF_CHANGE 3 /* bsscfg role change */ ++ ++/* I/F role code in WLC_E_IF event */ ++#define WLC_E_IF_ROLE_STA 0 /* Infra STA */ ++#define WLC_E_IF_ROLE_AP 1 /* Access Point */ ++#define WLC_E_IF_ROLE_WDS 2 /* WDS link */ ++#define WLC_E_IF_ROLE_P2P_GO 3 /* P2P Group Owner */ ++#define WLC_E_IF_ROLE_P2P_CLIENT 4 /* P2P Client */ ++#ifdef WLBTAMP ++#define WLC_E_IF_ROLE_BTA_CREATOR 5 /* BT-AMP Creator */ ++#define WLC_E_IF_ROLE_BTA_ACCEPTOR 6 /* BT-AMP Acceptor */ ++#endif ++ ++/* Reason codes for LINK */ ++#define WLC_E_LINK_BCN_LOSS 1 /* Link down because of beacon loss */ ++#define WLC_E_LINK_DISASSOC 2 /* Link down because of disassoc */ ++#define WLC_E_LINK_ASSOC_REC 3 /* Link down because assoc recreate failed */ ++#define WLC_E_LINK_BSSCFG_DIS 4 /* Link down due to bsscfg down */ ++ ++/* reason codes for WLC_E_OVERLAY_REQ event */ ++#define WLC_E_OVL_DOWNLOAD 0 /* overlay download request */ ++#define WLC_E_OVL_UPDATE_IND 1 /* device indication of host overlay update */ ++ ++/* reason codes for WLC_E_TDLS_PEER_EVENT event */ ++#define WLC_E_TDLS_PEER_DISCOVERED 0 /* peer is ready to establish TDLS */ ++#define WLC_E_TDLS_PEER_CONNECTED 1 ++#define WLC_E_TDLS_PEER_DISCONNECTED 2 ++ ++/* GAS event data */ ++typedef BWL_PRE_PACKED_STRUCT struct wl_event_gas { ++ uint16 channel; /* channel of GAS protocol */ ++ uint8 dialog_token; /* GAS dialog token */ ++ uint8 fragment_id; /* fragment id */ ++ uint16 status_code; /* status code on GAS completion */ ++ uint16 data_len; /* length of data to follow */ ++ uint8 data[1]; /* variable length specified by data_len */ ++} BWL_POST_PACKED_STRUCT wl_event_gas_t; ++ ++/* service discovery TLV */ ++typedef BWL_PRE_PACKED_STRUCT struct wl_sd_tlv { ++ uint16 length; /* length of response_data */ ++ uint8 protocol; /* service protocol type */ ++ uint8 transaction_id; /* service transaction id */ ++ uint8 status_code; /* status code */ ++ uint8 data[1]; /* response data */ ++} BWL_POST_PACKED_STRUCT wl_sd_tlv_t; ++ ++/* service discovery event data */ ++typedef BWL_PRE_PACKED_STRUCT struct wl_event_sd { ++ uint16 channel; /* channel */ ++ uint8 count; /* number of tlvs */ ++ wl_sd_tlv_t tlv[1]; /* service discovery TLV */ ++} BWL_POST_PACKED_STRUCT wl_event_sd_t; ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* _BCMEVENT_H_ */ +diff --git a/drivers/net/wireless/ap6211/include/proto/bcmip.h b/drivers/net/wireless/ap6211/include/proto/bcmip.h +new file mode 100755 +index 0000000..52cd71d +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/proto/bcmip.h +@@ -0,0 +1,210 @@ ++/* ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * Fundamental constants relating to IP Protocol ++ * ++ * $Id: bcmip.h 290206 2011-10-17 19:13:51Z $ ++ */ ++ ++#ifndef _bcmip_h_ ++#define _bcmip_h_ ++ ++#ifndef _TYPEDEFS_H_ ++#include ++#endif ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++ ++/* IPV4 and IPV6 common */ ++#define IP_VER_OFFSET 0x0 /* offset to version field */ ++#define IP_VER_MASK 0xf0 /* version mask */ ++#define IP_VER_SHIFT 4 /* version shift */ ++#define IP_VER_4 4 /* version number for IPV4 */ ++#define IP_VER_6 6 /* version number for IPV6 */ ++ ++#define IP_VER(ip_body) \ ++ ((((uint8 *)(ip_body))[IP_VER_OFFSET] & IP_VER_MASK) >> IP_VER_SHIFT) ++ ++#define IP_PROT_ICMP 0x1 /* ICMP protocol */ ++#define IP_PROT_IGMP 0x2 /* IGMP protocol */ ++#define IP_PROT_TCP 0x6 /* TCP protocol */ ++#define IP_PROT_UDP 0x11 /* UDP protocol type */ ++#define IP_PROT_ICMP6 0x3a /* ICMPv6 protocol type */ ++ ++/* IPV4 field offsets */ ++#define IPV4_VER_HL_OFFSET 0 /* version and ihl byte offset */ ++#define IPV4_TOS_OFFSET 1 /* type of service offset */ ++#define IPV4_PKTLEN_OFFSET 2 /* packet length offset */ ++#define IPV4_PKTFLAG_OFFSET 6 /* more-frag,dont-frag flag offset */ ++#define IPV4_PROT_OFFSET 9 /* protocol type offset */ ++#define IPV4_CHKSUM_OFFSET 10 /* IP header checksum offset */ ++#define IPV4_SRC_IP_OFFSET 12 /* src IP addr offset */ ++#define IPV4_DEST_IP_OFFSET 16 /* dest IP addr offset */ ++#define IPV4_OPTIONS_OFFSET 20 /* IP options offset */ ++ ++/* IPV4 field decodes */ ++#define IPV4_VER_MASK 0xf0 /* IPV4 version mask */ ++#define IPV4_VER_SHIFT 4 /* IPV4 version shift */ ++ ++#define IPV4_HLEN_MASK 0x0f /* IPV4 header length mask */ ++#define IPV4_HLEN(ipv4_body) (4 * (((uint8 *)(ipv4_body))[IPV4_VER_HL_OFFSET] & IPV4_HLEN_MASK)) ++ ++#define IPV4_ADDR_LEN 4 /* IPV4 address length */ ++ ++#define IPV4_ADDR_NULL(a) ((((uint8 *)(a))[0] | ((uint8 *)(a))[1] | \ ++ ((uint8 *)(a))[2] | ((uint8 *)(a))[3]) == 0) ++ ++#define IPV4_ADDR_BCAST(a) ((((uint8 *)(a))[0] & ((uint8 *)(a))[1] & \ ++ ((uint8 *)(a))[2] & ((uint8 *)(a))[3]) == 0xff) ++ ++#define IPV4_TOS_DSCP_MASK 0xfc /* DiffServ codepoint mask */ ++#define IPV4_TOS_DSCP_SHIFT 2 /* DiffServ codepoint shift */ ++ ++#define IPV4_TOS(ipv4_body) (((uint8 *)(ipv4_body))[IPV4_TOS_OFFSET]) ++ ++#define IPV4_TOS_PREC_MASK 0xe0 /* Historical precedence mask */ ++#define IPV4_TOS_PREC_SHIFT 5 /* Historical precedence shift */ ++ ++#define IPV4_TOS_LOWDELAY 0x10 /* Lowest delay requested */ ++#define IPV4_TOS_THROUGHPUT 0x8 /* Best throughput requested */ ++#define IPV4_TOS_RELIABILITY 0x4 /* Most reliable delivery requested */ ++ ++#define IPV4_PROT(ipv4_body) (((uint8 *)(ipv4_body))[IPV4_PROT_OFFSET]) ++ ++#define IPV4_FRAG_RESV 0x8000 /* Reserved */ ++#define IPV4_FRAG_DONT 0x4000 /* Don't fragment */ ++#define IPV4_FRAG_MORE 0x2000 /* More fragments */ ++#define IPV4_FRAG_OFFSET_MASK 0x1fff /* Fragment offset */ ++ ++#define IPV4_ADDR_STR_LEN 16 /* Max IP address length in string format */ ++ ++/* IPV4 packet formats */ ++BWL_PRE_PACKED_STRUCT struct ipv4_addr { ++ uint8 addr[IPV4_ADDR_LEN]; ++} BWL_POST_PACKED_STRUCT; ++ ++BWL_PRE_PACKED_STRUCT struct ipv4_hdr { ++ uint8 version_ihl; /* Version and Internet Header Length */ ++ uint8 tos; /* Type Of Service */ ++ uint16 tot_len; /* Number of bytes in packet (max 65535) */ ++ uint16 id; ++ uint16 frag; /* 3 flag bits and fragment offset */ ++ uint8 ttl; /* Time To Live */ ++ uint8 prot; /* Protocol */ ++ uint16 hdr_chksum; /* IP header checksum */ ++ uint8 src_ip[IPV4_ADDR_LEN]; /* Source IP Address */ ++ uint8 dst_ip[IPV4_ADDR_LEN]; /* Destination IP Address */ ++} BWL_POST_PACKED_STRUCT; ++ ++/* IPV6 field offsets */ ++#define IPV6_PAYLOAD_LEN_OFFSET 4 /* payload length offset */ ++#define IPV6_NEXT_HDR_OFFSET 6 /* next header/protocol offset */ ++#define IPV6_HOP_LIMIT_OFFSET 7 /* hop limit offset */ ++#define IPV6_SRC_IP_OFFSET 8 /* src IP addr offset */ ++#define IPV6_DEST_IP_OFFSET 24 /* dst IP addr offset */ ++ ++/* IPV6 field decodes */ ++#define IPV6_TRAFFIC_CLASS(ipv6_body) \ ++ (((((uint8 *)(ipv6_body))[0] & 0x0f) << 4) | \ ++ ((((uint8 *)(ipv6_body))[1] & 0xf0) >> 4)) ++ ++#define IPV6_FLOW_LABEL(ipv6_body) \ ++ (((((uint8 *)(ipv6_body))[1] & 0x0f) << 16) | \ ++ (((uint8 *)(ipv6_body))[2] << 8) | \ ++ (((uint8 *)(ipv6_body))[3])) ++ ++#define IPV6_PAYLOAD_LEN(ipv6_body) \ ++ ((((uint8 *)(ipv6_body))[IPV6_PAYLOAD_LEN_OFFSET + 0] << 8) | \ ++ ((uint8 *)(ipv6_body))[IPV6_PAYLOAD_LEN_OFFSET + 1]) ++ ++#define IPV6_NEXT_HDR(ipv6_body) \ ++ (((uint8 *)(ipv6_body))[IPV6_NEXT_HDR_OFFSET]) ++ ++#define IPV6_PROT(ipv6_body) IPV6_NEXT_HDR(ipv6_body) ++ ++#define IPV6_ADDR_LEN 16 /* IPV6 address length */ ++ ++/* IPV4 TOS or IPV6 Traffic Classifier or 0 */ ++#define IP_TOS46(ip_body) \ ++ (IP_VER(ip_body) == IP_VER_4 ? IPV4_TOS(ip_body) : \ ++ IP_VER(ip_body) == IP_VER_6 ? IPV6_TRAFFIC_CLASS(ip_body) : 0) ++ ++/* IPV6 extension headers (options) */ ++#define IPV6_EXTHDR_HOP 0 ++#define IPV6_EXTHDR_ROUTING 43 ++#define IPV6_EXTHDR_FRAGMENT 44 ++#define IPV6_EXTHDR_AUTH 51 ++#define IPV6_EXTHDR_NONE 59 ++#define IPV6_EXTHDR_DEST 60 ++ ++#define IPV6_EXTHDR(prot) (((prot) == IPV6_EXTHDR_HOP) || \ ++ ((prot) == IPV6_EXTHDR_ROUTING) || \ ++ ((prot) == IPV6_EXTHDR_FRAGMENT) || \ ++ ((prot) == IPV6_EXTHDR_AUTH) || \ ++ ((prot) == IPV6_EXTHDR_NONE) || \ ++ ((prot) == IPV6_EXTHDR_DEST)) ++ ++#define IPV6_MIN_HLEN 40 ++ ++#define IPV6_EXTHDR_LEN(eh) ((((struct ipv6_exthdr *)(eh))->hdrlen + 1) << 3) ++ ++BWL_PRE_PACKED_STRUCT struct ipv6_exthdr { ++ uint8 nexthdr; ++ uint8 hdrlen; ++} BWL_POST_PACKED_STRUCT; ++ ++BWL_PRE_PACKED_STRUCT struct ipv6_exthdr_frag { ++ uint8 nexthdr; ++ uint8 rsvd; ++ uint16 frag_off; ++ uint32 ident; ++} BWL_POST_PACKED_STRUCT; ++ ++static INLINE int32 ++ipv6_exthdr_len(uint8 *h, uint8 *proto) ++{ ++ uint16 len = 0, hlen; ++ struct ipv6_exthdr *eh = (struct ipv6_exthdr *)h; ++ ++ while (IPV6_EXTHDR(eh->nexthdr)) { ++ if (eh->nexthdr == IPV6_EXTHDR_NONE) ++ return -1; ++ else if (eh->nexthdr == IPV6_EXTHDR_FRAGMENT) ++ hlen = 8; ++ else if (eh->nexthdr == IPV6_EXTHDR_AUTH) ++ hlen = (eh->hdrlen + 2) << 2; ++ else ++ hlen = IPV6_EXTHDR_LEN(eh); ++ ++ len += hlen; ++ eh = (struct ipv6_exthdr *)(h + len); ++ } ++ ++ *proto = eh->nexthdr; ++ return len; ++} ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* _bcmip_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/proto/bt_amp_hci.h b/drivers/net/wireless/ap6211/include/proto/bt_amp_hci.h +new file mode 100755 +index 0000000..8617985 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/proto/bt_amp_hci.h +@@ -0,0 +1,441 @@ ++/* ++ * BT-AMP (BlueTooth Alternate Mac and Phy) HCI (Host/Controller Interface) ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bt_amp_hci.h 294267 2011-11-04 23:41:52Z $ ++*/ ++ ++#ifndef _bt_amp_hci_h ++#define _bt_amp_hci_h ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++ ++/* AMP HCI CMD packet format */ ++typedef BWL_PRE_PACKED_STRUCT struct amp_hci_cmd { ++ uint16 opcode; ++ uint8 plen; ++ uint8 parms[1]; ++} BWL_POST_PACKED_STRUCT amp_hci_cmd_t; ++ ++#define HCI_CMD_PREAMBLE_SIZE OFFSETOF(amp_hci_cmd_t, parms) ++#define HCI_CMD_DATA_SIZE 255 ++ ++/* AMP HCI CMD opcode layout */ ++#define HCI_CMD_OPCODE(ogf, ocf) ((((ogf) & 0x3F) << 10) | ((ocf) & 0x03FF)) ++#define HCI_CMD_OGF(opcode) ((uint8)(((opcode) >> 10) & 0x3F)) ++#define HCI_CMD_OCF(opcode) ((opcode) & 0x03FF) ++ ++/* AMP HCI command opcodes */ ++#define HCI_Read_Failed_Contact_Counter HCI_CMD_OPCODE(0x05, 0x0001) ++#define HCI_Reset_Failed_Contact_Counter HCI_CMD_OPCODE(0x05, 0x0002) ++#define HCI_Read_Link_Quality HCI_CMD_OPCODE(0x05, 0x0003) ++#define HCI_Read_Local_AMP_Info HCI_CMD_OPCODE(0x05, 0x0009) ++#define HCI_Read_Local_AMP_ASSOC HCI_CMD_OPCODE(0x05, 0x000A) ++#define HCI_Write_Remote_AMP_ASSOC HCI_CMD_OPCODE(0x05, 0x000B) ++#define HCI_Create_Physical_Link HCI_CMD_OPCODE(0x01, 0x0035) ++#define HCI_Accept_Physical_Link_Request HCI_CMD_OPCODE(0x01, 0x0036) ++#define HCI_Disconnect_Physical_Link HCI_CMD_OPCODE(0x01, 0x0037) ++#define HCI_Create_Logical_Link HCI_CMD_OPCODE(0x01, 0x0038) ++#define HCI_Accept_Logical_Link HCI_CMD_OPCODE(0x01, 0x0039) ++#define HCI_Disconnect_Logical_Link HCI_CMD_OPCODE(0x01, 0x003A) ++#define HCI_Logical_Link_Cancel HCI_CMD_OPCODE(0x01, 0x003B) ++#define HCI_Flow_Spec_Modify HCI_CMD_OPCODE(0x01, 0x003C) ++#define HCI_Write_Flow_Control_Mode HCI_CMD_OPCODE(0x01, 0x0067) ++#define HCI_Read_Best_Effort_Flush_Timeout HCI_CMD_OPCODE(0x01, 0x0069) ++#define HCI_Write_Best_Effort_Flush_Timeout HCI_CMD_OPCODE(0x01, 0x006A) ++#define HCI_Short_Range_Mode HCI_CMD_OPCODE(0x01, 0x006B) ++#define HCI_Reset HCI_CMD_OPCODE(0x03, 0x0003) ++#define HCI_Read_Connection_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0015) ++#define HCI_Write_Connection_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0016) ++#define HCI_Read_Link_Supervision_Timeout HCI_CMD_OPCODE(0x03, 0x0036) ++#define HCI_Write_Link_Supervision_Timeout HCI_CMD_OPCODE(0x03, 0x0037) ++#define HCI_Enhanced_Flush HCI_CMD_OPCODE(0x03, 0x005F) ++#define HCI_Read_Logical_Link_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0061) ++#define HCI_Write_Logical_Link_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0062) ++#define HCI_Set_Event_Mask_Page_2 HCI_CMD_OPCODE(0x03, 0x0063) ++#define HCI_Read_Location_Data_Command HCI_CMD_OPCODE(0x03, 0x0064) ++#define HCI_Write_Location_Data_Command HCI_CMD_OPCODE(0x03, 0x0065) ++#define HCI_Read_Local_Version_Info HCI_CMD_OPCODE(0x04, 0x0001) ++#define HCI_Read_Local_Supported_Commands HCI_CMD_OPCODE(0x04, 0x0002) ++#define HCI_Read_Buffer_Size HCI_CMD_OPCODE(0x04, 0x0005) ++#define HCI_Read_Data_Block_Size HCI_CMD_OPCODE(0x04, 0x000A) ++ ++/* AMP HCI command parameters */ ++typedef BWL_PRE_PACKED_STRUCT struct read_local_cmd_parms { ++ uint8 plh; ++ uint8 offset[2]; /* length so far */ ++ uint8 max_remote[2]; ++} BWL_POST_PACKED_STRUCT read_local_cmd_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct write_remote_cmd_parms { ++ uint8 plh; ++ uint8 offset[2]; ++ uint8 len[2]; ++ uint8 frag[1]; ++} BWL_POST_PACKED_STRUCT write_remote_cmd_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct phy_link_cmd_parms { ++ uint8 plh; ++ uint8 key_length; ++ uint8 key_type; ++ uint8 key[1]; ++} BWL_POST_PACKED_STRUCT phy_link_cmd_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct dis_phy_link_cmd_parms { ++ uint8 plh; ++ uint8 reason; ++} BWL_POST_PACKED_STRUCT dis_phy_link_cmd_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct log_link_cmd_parms { ++ uint8 plh; ++ uint8 txflow[16]; ++ uint8 rxflow[16]; ++} BWL_POST_PACKED_STRUCT log_link_cmd_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct ext_flow_spec { ++ uint8 id; ++ uint8 service_type; ++ uint8 max_sdu[2]; ++ uint8 sdu_ia_time[4]; ++ uint8 access_latency[4]; ++ uint8 flush_timeout[4]; ++} BWL_POST_PACKED_STRUCT ext_flow_spec_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct log_link_cancel_cmd_parms { ++ uint8 plh; ++ uint8 tx_fs_ID; ++} BWL_POST_PACKED_STRUCT log_link_cancel_cmd_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct flow_spec_mod_cmd_parms { ++ uint8 llh[2]; ++ uint8 txflow[16]; ++ uint8 rxflow[16]; ++} BWL_POST_PACKED_STRUCT flow_spec_mod_cmd_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct plh_pad { ++ uint8 plh; ++ uint8 pad; ++} BWL_POST_PACKED_STRUCT plh_pad_t; ++ ++typedef BWL_PRE_PACKED_STRUCT union hci_handle { ++ uint16 bredr; ++ plh_pad_t amp; ++} BWL_POST_PACKED_STRUCT hci_handle_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct ls_to_cmd_parms { ++ hci_handle_t handle; ++ uint8 timeout[2]; ++} BWL_POST_PACKED_STRUCT ls_to_cmd_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct befto_cmd_parms { ++ uint8 llh[2]; ++ uint8 befto[4]; ++} BWL_POST_PACKED_STRUCT befto_cmd_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct srm_cmd_parms { ++ uint8 plh; ++ uint8 srm; ++} BWL_POST_PACKED_STRUCT srm_cmd_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct ld_cmd_parms { ++ uint8 ld_aware; ++ uint8 ld[2]; ++ uint8 ld_opts; ++ uint8 l_opts; ++} BWL_POST_PACKED_STRUCT ld_cmd_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct eflush_cmd_parms { ++ uint8 llh[2]; ++ uint8 packet_type; ++} BWL_POST_PACKED_STRUCT eflush_cmd_parms_t; ++ ++/* Generic AMP extended flow spec service types */ ++#define EFS_SVCTYPE_NO_TRAFFIC 0 ++#define EFS_SVCTYPE_BEST_EFFORT 1 ++#define EFS_SVCTYPE_GUARANTEED 2 ++ ++/* AMP HCI event packet format */ ++typedef BWL_PRE_PACKED_STRUCT struct amp_hci_event { ++ uint8 ecode; ++ uint8 plen; ++ uint8 parms[1]; ++} BWL_POST_PACKED_STRUCT amp_hci_event_t; ++ ++#define HCI_EVT_PREAMBLE_SIZE OFFSETOF(amp_hci_event_t, parms) ++ ++/* AMP HCI event codes */ ++#define HCI_Command_Complete 0x0E ++#define HCI_Command_Status 0x0F ++#define HCI_Flush_Occurred 0x11 ++#define HCI_Enhanced_Flush_Complete 0x39 ++#define HCI_Physical_Link_Complete 0x40 ++#define HCI_Channel_Select 0x41 ++#define HCI_Disconnect_Physical_Link_Complete 0x42 ++#define HCI_Logical_Link_Complete 0x45 ++#define HCI_Disconnect_Logical_Link_Complete 0x46 ++#define HCI_Flow_Spec_Modify_Complete 0x47 ++#define HCI_Number_of_Completed_Data_Blocks 0x48 ++#define HCI_Short_Range_Mode_Change_Complete 0x4C ++#define HCI_Status_Change_Event 0x4D ++#define HCI_Vendor_Specific 0xFF ++ ++/* AMP HCI event mask bit positions */ ++#define HCI_Physical_Link_Complete_Event_Mask 0x0001 ++#define HCI_Channel_Select_Event_Mask 0x0002 ++#define HCI_Disconnect_Physical_Link_Complete_Event_Mask 0x0004 ++#define HCI_Logical_Link_Complete_Event_Mask 0x0020 ++#define HCI_Disconnect_Logical_Link_Complete_Event_Mask 0x0040 ++#define HCI_Flow_Spec_Modify_Complete_Event_Mask 0x0080 ++#define HCI_Number_of_Completed_Data_Blocks_Event_Mask 0x0100 ++#define HCI_Short_Range_Mode_Change_Complete_Event_Mask 0x1000 ++#define HCI_Status_Change_Event_Mask 0x2000 ++#define HCI_All_Event_Mask 0x31e7 ++/* AMP HCI event parameters */ ++typedef BWL_PRE_PACKED_STRUCT struct cmd_status_parms { ++ uint8 status; ++ uint8 cmdpkts; ++ uint16 opcode; ++} BWL_POST_PACKED_STRUCT cmd_status_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct cmd_complete_parms { ++ uint8 cmdpkts; ++ uint16 opcode; ++ uint8 parms[1]; ++} BWL_POST_PACKED_STRUCT cmd_complete_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct flush_occurred_evt_parms { ++ uint16 handle; ++} BWL_POST_PACKED_STRUCT flush_occurred_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct write_remote_evt_parms { ++ uint8 status; ++ uint8 plh; ++} BWL_POST_PACKED_STRUCT write_remote_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct read_local_evt_parms { ++ uint8 status; ++ uint8 plh; ++ uint16 len; ++ uint8 frag[1]; ++} BWL_POST_PACKED_STRUCT read_local_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct read_local_info_evt_parms { ++ uint8 status; ++ uint8 AMP_status; ++ uint32 bandwidth; ++ uint32 gbandwidth; ++ uint32 latency; ++ uint32 PDU_size; ++ uint8 ctrl_type; ++ uint16 PAL_cap; ++ uint16 AMP_ASSOC_len; ++ uint32 max_flush_timeout; ++ uint32 be_flush_timeout; ++} BWL_POST_PACKED_STRUCT read_local_info_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct log_link_evt_parms { ++ uint8 status; ++ uint16 llh; ++ uint8 plh; ++ uint8 tx_fs_ID; ++} BWL_POST_PACKED_STRUCT log_link_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct disc_log_link_evt_parms { ++ uint8 status; ++ uint16 llh; ++ uint8 reason; ++} BWL_POST_PACKED_STRUCT disc_log_link_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct log_link_cancel_evt_parms { ++ uint8 status; ++ uint8 plh; ++ uint8 tx_fs_ID; ++} BWL_POST_PACKED_STRUCT log_link_cancel_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct flow_spec_mod_evt_parms { ++ uint8 status; ++ uint16 llh; ++} BWL_POST_PACKED_STRUCT flow_spec_mod_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct phy_link_evt_parms { ++ uint8 status; ++ uint8 plh; ++} BWL_POST_PACKED_STRUCT phy_link_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct dis_phy_link_evt_parms { ++ uint8 status; ++ uint8 plh; ++ uint8 reason; ++} BWL_POST_PACKED_STRUCT dis_phy_link_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct read_ls_to_evt_parms { ++ uint8 status; ++ hci_handle_t handle; ++ uint16 timeout; ++} BWL_POST_PACKED_STRUCT read_ls_to_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct read_lla_ca_to_evt_parms { ++ uint8 status; ++ uint16 timeout; ++} BWL_POST_PACKED_STRUCT read_lla_ca_to_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct read_data_block_size_evt_parms { ++ uint8 status; ++ uint16 ACL_pkt_len; ++ uint16 data_block_len; ++ uint16 data_block_num; ++} BWL_POST_PACKED_STRUCT read_data_block_size_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct data_blocks { ++ uint16 handle; ++ uint16 pkts; ++ uint16 blocks; ++} BWL_POST_PACKED_STRUCT data_blocks_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct num_completed_data_blocks_evt_parms { ++ uint16 num_blocks; ++ uint8 num_handles; ++ data_blocks_t completed[1]; ++} BWL_POST_PACKED_STRUCT num_completed_data_blocks_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct befto_evt_parms { ++ uint8 status; ++ uint32 befto; ++} BWL_POST_PACKED_STRUCT befto_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct srm_evt_parms { ++ uint8 status; ++ uint8 plh; ++ uint8 srm; ++} BWL_POST_PACKED_STRUCT srm_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct contact_counter_evt_parms { ++ uint8 status; ++ uint8 llh[2]; ++ uint16 counter; ++} BWL_POST_PACKED_STRUCT contact_counter_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct contact_counter_reset_evt_parms { ++ uint8 status; ++ uint8 llh[2]; ++} BWL_POST_PACKED_STRUCT contact_counter_reset_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct read_linkq_evt_parms { ++ uint8 status; ++ hci_handle_t handle; ++ uint8 link_quality; ++} BWL_POST_PACKED_STRUCT read_linkq_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct ld_evt_parms { ++ uint8 status; ++ uint8 ld_aware; ++ uint8 ld[2]; ++ uint8 ld_opts; ++ uint8 l_opts; ++} BWL_POST_PACKED_STRUCT ld_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct eflush_complete_evt_parms { ++ uint16 handle; ++} BWL_POST_PACKED_STRUCT eflush_complete_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct vendor_specific_evt_parms { ++ uint8 len; ++ uint8 parms[1]; ++} BWL_POST_PACKED_STRUCT vendor_specific_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct local_version_info_evt_parms { ++ uint8 status; ++ uint8 hci_version; ++ uint16 hci_revision; ++ uint8 pal_version; ++ uint16 mfg_name; ++ uint16 pal_subversion; ++} BWL_POST_PACKED_STRUCT local_version_info_evt_parms_t; ++ ++#define MAX_SUPPORTED_CMD_BYTE 64 ++typedef BWL_PRE_PACKED_STRUCT struct local_supported_cmd_evt_parms { ++ uint8 status; ++ uint8 cmd[MAX_SUPPORTED_CMD_BYTE]; ++} BWL_POST_PACKED_STRUCT local_supported_cmd_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct status_change_evt_parms { ++ uint8 status; ++ uint8 amp_status; ++} BWL_POST_PACKED_STRUCT status_change_evt_parms_t; ++ ++/* AMP HCI error codes */ ++#define HCI_SUCCESS 0x00 ++#define HCI_ERR_ILLEGAL_COMMAND 0x01 ++#define HCI_ERR_NO_CONNECTION 0x02 ++#define HCI_ERR_MEMORY_FULL 0x07 ++#define HCI_ERR_CONNECTION_TIMEOUT 0x08 ++#define HCI_ERR_MAX_NUM_OF_CONNECTIONS 0x09 ++#define HCI_ERR_CONNECTION_EXISTS 0x0B ++#define HCI_ERR_CONNECTION_DISALLOWED 0x0C ++#define HCI_ERR_CONNECTION_ACCEPT_TIMEOUT 0x10 ++#define HCI_ERR_UNSUPPORTED_VALUE 0x11 ++#define HCI_ERR_ILLEGAL_PARAMETER_FMT 0x12 ++#define HCI_ERR_CONN_TERM_BY_LOCAL_HOST 0x16 ++#define HCI_ERR_UNSPECIFIED 0x1F ++#define HCI_ERR_UNIT_KEY_USED 0x26 ++#define HCI_ERR_QOS_REJECTED 0x2D ++#define HCI_ERR_PARAM_OUT_OF_RANGE 0x30 ++#define HCI_ERR_NO_SUITABLE_CHANNEL 0x39 ++#define HCI_ERR_CHANNEL_MOVE 0xFF ++ ++/* AMP HCI ACL Data packet format */ ++typedef BWL_PRE_PACKED_STRUCT struct amp_hci_ACL_data { ++ uint16 handle; /* 12-bit connection handle + 2-bit PB and 2-bit BC flags */ ++ uint16 dlen; /* data total length */ ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT amp_hci_ACL_data_t; ++ ++#define HCI_ACL_DATA_PREAMBLE_SIZE OFFSETOF(amp_hci_ACL_data_t, data) ++ ++#define HCI_ACL_DATA_BC_FLAGS (0x0 << 14) ++#define HCI_ACL_DATA_PB_FLAGS (0x3 << 12) ++ ++#define HCI_ACL_DATA_HANDLE(handle) ((handle) & 0x0fff) ++#define HCI_ACL_DATA_FLAGS(handle) ((handle) >> 12) ++ ++/* AMP Activity Report packet formats */ ++typedef BWL_PRE_PACKED_STRUCT struct amp_hci_activity_report { ++ uint8 ScheduleKnown; ++ uint8 NumReports; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT amp_hci_activity_report_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct amp_hci_activity_report_triple { ++ uint32 StartTime; ++ uint32 Duration; ++ uint32 Periodicity; ++} BWL_POST_PACKED_STRUCT amp_hci_activity_report_triple_t; ++ ++#define HCI_AR_SCHEDULE_KNOWN 0x01 ++ ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* _bt_amp_hci_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/proto/eapol.h b/drivers/net/wireless/ap6211/include/proto/eapol.h +new file mode 100755 +index 0000000..8936d16 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/proto/eapol.h +@@ -0,0 +1,193 @@ ++/* ++ * 802.1x EAPOL definitions ++ * ++ * See ++ * IEEE Std 802.1X-2001 ++ * IEEE 802.1X RADIUS Usage Guidelines ++ * ++ * Copyright (C) 2002 Broadcom Corporation ++ * ++ * $Id: eapol.h 241182 2011-02-17 21:50:03Z $ ++ */ ++ ++#ifndef _eapol_h_ ++#define _eapol_h_ ++ ++#ifndef _TYPEDEFS_H_ ++#include ++#endif ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++#include ++ ++/* EAPOL for 802.3/Ethernet */ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ struct ether_header eth; /* 802.3/Ethernet header */ ++ unsigned char version; /* EAPOL protocol version */ ++ unsigned char type; /* EAPOL type */ ++ unsigned short length; /* Length of body */ ++ unsigned char body[1]; /* Body (optional) */ ++} BWL_POST_PACKED_STRUCT eapol_header_t; ++ ++#define EAPOL_HEADER_LEN 18 ++ ++typedef struct { ++ unsigned char version; /* EAPOL protocol version */ ++ unsigned char type; /* EAPOL type */ ++ unsigned short length; /* Length of body */ ++} eapol_hdr_t; ++ ++#define EAPOL_HDR_LEN 4 ++ ++/* EAPOL version */ ++#define WPA2_EAPOL_VERSION 2 ++#define WPA_EAPOL_VERSION 1 ++#define LEAP_EAPOL_VERSION 1 ++#define SES_EAPOL_VERSION 1 ++ ++/* EAPOL types */ ++#define EAP_PACKET 0 ++#define EAPOL_START 1 ++#define EAPOL_LOGOFF 2 ++#define EAPOL_KEY 3 ++#define EAPOL_ASF 4 ++ ++/* EAPOL-Key types */ ++#define EAPOL_RC4_KEY 1 ++#define EAPOL_WPA2_KEY 2 /* 802.11i/WPA2 */ ++#define EAPOL_WPA_KEY 254 /* WPA */ ++ ++/* RC4 EAPOL-Key header field sizes */ ++#define EAPOL_KEY_REPLAY_LEN 8 ++#define EAPOL_KEY_IV_LEN 16 ++#define EAPOL_KEY_SIG_LEN 16 ++ ++/* RC4 EAPOL-Key */ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ unsigned char type; /* Key Descriptor Type */ ++ unsigned short length; /* Key Length (unaligned) */ ++ unsigned char replay[EAPOL_KEY_REPLAY_LEN]; /* Replay Counter */ ++ unsigned char iv[EAPOL_KEY_IV_LEN]; /* Key IV */ ++ unsigned char index; /* Key Flags & Index */ ++ unsigned char signature[EAPOL_KEY_SIG_LEN]; /* Key Signature */ ++ unsigned char key[1]; /* Key (optional) */ ++} BWL_POST_PACKED_STRUCT eapol_key_header_t; ++ ++#define EAPOL_KEY_HEADER_LEN 44 ++ ++/* RC4 EAPOL-Key flags */ ++#define EAPOL_KEY_FLAGS_MASK 0x80 ++#define EAPOL_KEY_BROADCAST 0 ++#define EAPOL_KEY_UNICAST 0x80 ++ ++/* RC4 EAPOL-Key index */ ++#define EAPOL_KEY_INDEX_MASK 0x7f ++ ++/* WPA/802.11i/WPA2 EAPOL-Key header field sizes */ ++#define EAPOL_WPA_KEY_REPLAY_LEN 8 ++#define EAPOL_WPA_KEY_NONCE_LEN 32 ++#define EAPOL_WPA_KEY_IV_LEN 16 ++#define EAPOL_WPA_KEY_RSC_LEN 8 ++#define EAPOL_WPA_KEY_ID_LEN 8 ++#define EAPOL_WPA_KEY_MIC_LEN 16 ++#define EAPOL_WPA_KEY_DATA_LEN (EAPOL_WPA_MAX_KEY_SIZE + AKW_BLOCK_LEN) ++#define EAPOL_WPA_MAX_KEY_SIZE 32 ++ ++/* WPA EAPOL-Key */ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ unsigned char type; /* Key Descriptor Type */ ++ unsigned short key_info; /* Key Information (unaligned) */ ++ unsigned short key_len; /* Key Length (unaligned) */ ++ unsigned char replay[EAPOL_WPA_KEY_REPLAY_LEN]; /* Replay Counter */ ++ unsigned char nonce[EAPOL_WPA_KEY_NONCE_LEN]; /* Nonce */ ++ unsigned char iv[EAPOL_WPA_KEY_IV_LEN]; /* Key IV */ ++ unsigned char rsc[EAPOL_WPA_KEY_RSC_LEN]; /* Key RSC */ ++ unsigned char id[EAPOL_WPA_KEY_ID_LEN]; /* WPA:Key ID, 802.11i/WPA2: Reserved */ ++ unsigned char mic[EAPOL_WPA_KEY_MIC_LEN]; /* Key MIC */ ++ unsigned short data_len; /* Key Data Length */ ++ unsigned char data[EAPOL_WPA_KEY_DATA_LEN]; /* Key data */ ++} BWL_POST_PACKED_STRUCT eapol_wpa_key_header_t; ++ ++#define EAPOL_WPA_KEY_LEN 95 ++ ++/* WPA/802.11i/WPA2 KEY KEY_INFO bits */ ++#define WPA_KEY_DESC_V1 0x01 ++#define WPA_KEY_DESC_V2 0x02 ++#define WPA_KEY_DESC_V3 0x03 ++#define WPA_KEY_PAIRWISE 0x08 ++#define WPA_KEY_INSTALL 0x40 ++#define WPA_KEY_ACK 0x80 ++#define WPA_KEY_MIC 0x100 ++#define WPA_KEY_SECURE 0x200 ++#define WPA_KEY_ERROR 0x400 ++#define WPA_KEY_REQ 0x800 ++ ++#define WPA_KEY_DESC_V2_OR_V3 WPA_KEY_DESC_V2 ++ ++/* WPA-only KEY KEY_INFO bits */ ++#define WPA_KEY_INDEX_0 0x00 ++#define WPA_KEY_INDEX_1 0x10 ++#define WPA_KEY_INDEX_2 0x20 ++#define WPA_KEY_INDEX_3 0x30 ++#define WPA_KEY_INDEX_MASK 0x30 ++#define WPA_KEY_INDEX_SHIFT 0x04 ++ ++/* 802.11i/WPA2-only KEY KEY_INFO bits */ ++#define WPA_KEY_ENCRYPTED_DATA 0x1000 ++ ++/* Key Data encapsulation */ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint8 type; ++ uint8 length; ++ uint8 oui[3]; ++ uint8 subtype; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT eapol_wpa2_encap_data_t; ++ ++#define EAPOL_WPA2_ENCAP_DATA_HDR_LEN 6 ++ ++#define WPA2_KEY_DATA_SUBTYPE_GTK 1 ++#define WPA2_KEY_DATA_SUBTYPE_STAKEY 2 ++#define WPA2_KEY_DATA_SUBTYPE_MAC 3 ++#define WPA2_KEY_DATA_SUBTYPE_PMKID 4 ++#define WPA2_KEY_DATA_SUBTYPE_IGTK 9 ++ ++/* GTK encapsulation */ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint8 flags; ++ uint8 reserved; ++ uint8 gtk[EAPOL_WPA_MAX_KEY_SIZE]; ++} BWL_POST_PACKED_STRUCT eapol_wpa2_key_gtk_encap_t; ++ ++#define EAPOL_WPA2_KEY_GTK_ENCAP_HDR_LEN 2 ++ ++#define WPA2_GTK_INDEX_MASK 0x03 ++#define WPA2_GTK_INDEX_SHIFT 0x00 ++ ++#define WPA2_GTK_TRANSMIT 0x04 ++ ++/* IGTK encapsulation */ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint16 key_id; ++ uint8 ipn[6]; ++ uint8 key[EAPOL_WPA_MAX_KEY_SIZE]; ++} BWL_POST_PACKED_STRUCT eapol_wpa2_key_igtk_encap_t; ++ ++#define EAPOL_WPA2_KEY_IGTK_ENCAP_HDR_LEN 8 ++ ++/* STAKey encapsulation */ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint8 reserved[2]; ++ uint8 mac[ETHER_ADDR_LEN]; ++ uint8 stakey[EAPOL_WPA_MAX_KEY_SIZE]; ++} BWL_POST_PACKED_STRUCT eapol_wpa2_key_stakey_encap_t; ++ ++#define WPA2_KEY_DATA_PAD 0xdd ++ ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* _eapol_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/proto/ethernet.h b/drivers/net/wireless/ap6211/include/proto/ethernet.h +new file mode 100755 +index 0000000..a6ce6e1 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/proto/ethernet.h +@@ -0,0 +1,190 @@ ++/* ++ * From FreeBSD 2.2.7: Fundamental constants relating to ethernet. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: ethernet.h 309193 2012-01-19 00:03:57Z $ ++ */ ++ ++#ifndef _NET_ETHERNET_H_ /* use native BSD ethernet.h when available */ ++#define _NET_ETHERNET_H_ ++ ++#ifndef _TYPEDEFS_H_ ++#include "typedefs.h" ++#endif ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++ ++/* ++ * The number of bytes in an ethernet (MAC) address. ++ */ ++#define ETHER_ADDR_LEN 6 ++ ++/* ++ * The number of bytes in the type field. ++ */ ++#define ETHER_TYPE_LEN 2 ++ ++/* ++ * The number of bytes in the trailing CRC field. ++ */ ++#define ETHER_CRC_LEN 4 ++ ++/* ++ * The length of the combined header. ++ */ ++#define ETHER_HDR_LEN (ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN) ++ ++/* ++ * The minimum packet length. ++ */ ++#define ETHER_MIN_LEN 64 ++ ++/* ++ * The minimum packet user data length. ++ */ ++#define ETHER_MIN_DATA 46 ++ ++/* ++ * The maximum packet length. ++ */ ++#define ETHER_MAX_LEN 1518 ++ ++/* ++ * The maximum packet user data length. ++ */ ++#define ETHER_MAX_DATA 1500 ++ ++/* ether types */ ++#define ETHER_TYPE_MIN 0x0600 /* Anything less than MIN is a length */ ++#define ETHER_TYPE_IP 0x0800 /* IP */ ++#define ETHER_TYPE_ARP 0x0806 /* ARP */ ++#define ETHER_TYPE_8021Q 0x8100 /* 802.1Q */ ++#define ETHER_TYPE_IPV6 0x86dd /* IPv6 */ ++#define ETHER_TYPE_BRCM 0x886c /* Broadcom Corp. */ ++#define ETHER_TYPE_802_1X 0x888e /* 802.1x */ ++#define ETHER_TYPE_802_1X_PREAUTH 0x88c7 /* 802.1x preauthentication */ ++#define ETHER_TYPE_WAI 0x88b4 /* WAI */ ++#define ETHER_TYPE_89_0D 0x890d /* 89-0d frame for TDLS */ ++ ++#define ETHER_TYPE_IPV6 0x86dd /* IPV6 */ ++ ++/* Broadcom subtype follows ethertype; First 2 bytes are reserved; Next 2 are subtype; */ ++#define ETHER_BRCM_SUBTYPE_LEN 4 /* Broadcom 4 byte subtype */ ++ ++/* ether header */ ++#define ETHER_DEST_OFFSET (0 * ETHER_ADDR_LEN) /* dest address offset */ ++#define ETHER_SRC_OFFSET (1 * ETHER_ADDR_LEN) /* src address offset */ ++#define ETHER_TYPE_OFFSET (2 * ETHER_ADDR_LEN) /* ether type offset */ ++ ++/* ++ * A macro to validate a length with ++ */ ++#define ETHER_IS_VALID_LEN(foo) \ ++ ((foo) >= ETHER_MIN_LEN && (foo) <= ETHER_MAX_LEN) ++ ++#define ETHER_FILL_MCAST_ADDR_FROM_IP(ea, mgrp_ip) { \ ++ ((uint8 *)ea)[0] = 0x01; \ ++ ((uint8 *)ea)[1] = 0x00; \ ++ ((uint8 *)ea)[2] = 0x5e; \ ++ ((uint8 *)ea)[3] = ((mgrp_ip) >> 16) & 0x7f; \ ++ ((uint8 *)ea)[4] = ((mgrp_ip) >> 8) & 0xff; \ ++ ((uint8 *)ea)[5] = ((mgrp_ip) >> 0) & 0xff; \ ++} ++ ++#ifndef __INCif_etherh /* Quick and ugly hack for VxWorks */ ++/* ++ * Structure of a 10Mb/s Ethernet header. ++ */ ++BWL_PRE_PACKED_STRUCT struct ether_header { ++ uint8 ether_dhost[ETHER_ADDR_LEN]; ++ uint8 ether_shost[ETHER_ADDR_LEN]; ++ uint16 ether_type; ++} BWL_POST_PACKED_STRUCT; ++ ++/* ++ * Structure of a 48-bit Ethernet address. ++ */ ++BWL_PRE_PACKED_STRUCT struct ether_addr { ++ uint8 octet[ETHER_ADDR_LEN]; ++} BWL_POST_PACKED_STRUCT; ++#endif /* !__INCif_etherh Quick and ugly hack for VxWorks */ ++ ++/* ++ * Takes a pointer, set, test, clear, toggle locally admininistered ++ * address bit in the 48-bit Ethernet address. ++ */ ++#define ETHER_SET_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] | 2)) ++#define ETHER_IS_LOCALADDR(ea) (((uint8 *)(ea))[0] & 2) ++#define ETHER_CLR_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] & 0xfd)) ++#define ETHER_TOGGLE_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] ^ 2)) ++ ++/* Takes a pointer, marks unicast address bit in the MAC address */ ++#define ETHER_SET_UNICAST(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] & ~1)) ++ ++/* ++ * Takes a pointer, returns true if a 48-bit multicast address ++ * (including broadcast, since it is all ones) ++ */ ++#define ETHER_ISMULTI(ea) (((const uint8 *)(ea))[0] & 1) ++ ++ ++/* compare two ethernet addresses - assumes the pointers can be referenced as shorts */ ++#define ether_cmp(a, b) (!(((short*)(a))[0] == ((short*)(b))[0]) | \ ++ !(((short*)(a))[1] == ((short*)(b))[1]) | \ ++ !(((short*)(a))[2] == ((short*)(b))[2])) ++ ++/* copy an ethernet address - assumes the pointers can be referenced as shorts */ ++#define ether_copy(s, d) { \ ++ ((short*)(d))[0] = ((const short*)(s))[0]; \ ++ ((short*)(d))[1] = ((const short*)(s))[1]; \ ++ ((short*)(d))[2] = ((const short*)(s))[2]; } ++ ++ ++static const struct ether_addr ether_bcast = {{255, 255, 255, 255, 255, 255}}; ++static const struct ether_addr ether_null = {{0, 0, 0, 0, 0, 0}}; ++ ++#define ETHER_ISBCAST(ea) ((((uint8 *)(ea))[0] & \ ++ ((uint8 *)(ea))[1] & \ ++ ((uint8 *)(ea))[2] & \ ++ ((uint8 *)(ea))[3] & \ ++ ((uint8 *)(ea))[4] & \ ++ ((uint8 *)(ea))[5]) == 0xff) ++#define ETHER_ISNULLADDR(ea) ((((uint8 *)(ea))[0] | \ ++ ((uint8 *)(ea))[1] | \ ++ ((uint8 *)(ea))[2] | \ ++ ((uint8 *)(ea))[3] | \ ++ ((uint8 *)(ea))[4] | \ ++ ((uint8 *)(ea))[5]) == 0) ++ ++#define ETHER_MOVE_HDR(d, s) \ ++do { \ ++ struct ether_header t; \ ++ t = *(struct ether_header *)(s); \ ++ *(struct ether_header *)(d) = t; \ ++} while (0) ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* _NET_ETHERNET_H_ */ +diff --git a/drivers/net/wireless/ap6211/include/proto/p2p.h b/drivers/net/wireless/ap6211/include/proto/p2p.h +new file mode 100755 +index 0000000..6716e2a +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/proto/p2p.h +@@ -0,0 +1,579 @@ ++/* ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * Fundamental types and constants relating to WFA P2P (aka WiFi Direct) ++ * ++ * $Id: p2p.h 356417 2012-09-12 16:41:24Z $ ++ */ ++ ++#ifndef _P2P_H_ ++#define _P2P_H_ ++ ++#ifndef _TYPEDEFS_H_ ++#include ++#endif ++#include ++#include ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++ ++/* WiFi P2P OUI values */ ++#define P2P_OUI WFA_OUI /* WiFi P2P OUI */ ++#define P2P_VER WFA_OUI_TYPE_P2P /* P2P version: 9=WiFi P2P v1.0 */ ++ ++#define P2P_IE_ID 0xdd /* P2P IE element ID */ ++ ++/* WiFi P2P IE */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_ie { ++ uint8 id; /* IE ID: 0xDD */ ++ uint8 len; /* IE length */ ++ uint8 OUI[3]; /* WiFi P2P specific OUI: P2P_OUI */ ++ uint8 oui_type; /* Identifies P2P version: P2P_VER */ ++ uint8 subelts[1]; /* variable length subelements */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_ie wifi_p2p_ie_t; ++ ++#define P2P_IE_FIXED_LEN 6 ++ ++#define P2P_ATTR_ID_OFF 0 ++#define P2P_ATTR_LEN_OFF 1 ++#define P2P_ATTR_DATA_OFF 3 ++ ++#define P2P_ATTR_ID_LEN 1 /* ID filed length */ ++#define P2P_ATTR_LEN_LEN 2 /* length field length */ ++#define P2P_ATTR_HDR_LEN 3 /* ID + 2-byte length field spec 1.02 */ ++ ++/* P2P IE Subelement IDs from WiFi P2P Technical Spec 1.00 */ ++#define P2P_SEID_STATUS 0 /* Status */ ++#define P2P_SEID_MINOR_RC 1 /* Minor Reason Code */ ++#define P2P_SEID_P2P_INFO 2 /* P2P Capability (capabilities info) */ ++#define P2P_SEID_DEV_ID 3 /* P2P Device ID */ ++#define P2P_SEID_INTENT 4 /* Group Owner Intent */ ++#define P2P_SEID_CFG_TIMEOUT 5 /* Configuration Timeout */ ++#define P2P_SEID_CHANNEL 6 /* Channel */ ++#define P2P_SEID_GRP_BSSID 7 /* P2P Group BSSID */ ++#define P2P_SEID_XT_TIMING 8 /* Extended Listen Timing */ ++#define P2P_SEID_INTINTADDR 9 /* Intended P2P Interface Address */ ++#define P2P_SEID_P2P_MGBTY 10 /* P2P Manageability */ ++#define P2P_SEID_CHAN_LIST 11 /* Channel List */ ++#define P2P_SEID_ABSENCE 12 /* Notice of Absence */ ++#define P2P_SEID_DEV_INFO 13 /* Device Info */ ++#define P2P_SEID_GROUP_INFO 14 /* Group Info */ ++#define P2P_SEID_GROUP_ID 15 /* Group ID */ ++#define P2P_SEID_P2P_IF 16 /* P2P Interface */ ++#define P2P_SEID_OP_CHANNEL 17 /* Operating Channel */ ++#define P2P_SEID_INVITE_FLAGS 18 /* Invitation Flags */ ++#define P2P_SEID_VNDR 221 /* Vendor-specific subelement */ ++ ++#define P2P_SE_VS_ID_SERVICES 0x1b /* BRCM proprietary subel: L2 Services */ ++ ++ ++/* WiFi P2P IE subelement: P2P Capability (capabilities info) */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_info_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_P2P_INFO */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 dev; /* Device Capability Bitmap */ ++ uint8 group; /* Group Capability Bitmap */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_info_se_s wifi_p2p_info_se_t; ++ ++/* P2P Capability subelement's Device Capability Bitmap bit values */ ++#define P2P_CAPSE_DEV_SERVICE_DIS 0x1 /* Service Discovery */ ++#define P2P_CAPSE_DEV_CLIENT_DIS 0x2 /* Client Discoverability */ ++#define P2P_CAPSE_DEV_CONCURRENT 0x4 /* Concurrent Operation */ ++#define P2P_CAPSE_DEV_INFRA_MAN 0x8 /* P2P Infrastructure Managed */ ++#define P2P_CAPSE_DEV_LIMIT 0x10 /* P2P Device Limit */ ++#define P2P_CAPSE_INVITE_PROC 0x20 /* P2P Invitation Procedure */ ++ ++/* P2P Capability subelement's Group Capability Bitmap bit values */ ++#define P2P_CAPSE_GRP_OWNER 0x1 /* P2P Group Owner */ ++#define P2P_CAPSE_PERSIST_GRP 0x2 /* Persistent P2P Group */ ++#define P2P_CAPSE_GRP_LIMIT 0x4 /* P2P Group Limit */ ++#define P2P_CAPSE_GRP_INTRA_BSS 0x8 /* Intra-BSS Distribution */ ++#define P2P_CAPSE_GRP_X_CONNECT 0x10 /* Cross Connection */ ++#define P2P_CAPSE_GRP_PERSISTENT 0x20 /* Persistent Reconnect */ ++#define P2P_CAPSE_GRP_FORMATION 0x40 /* Group Formation */ ++ ++ ++/* WiFi P2P IE subelement: Group Owner Intent */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_intent_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_INTENT */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 intent; /* Intent Value 0...15 (0=legacy 15=master only) */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_intent_se_s wifi_p2p_intent_se_t; ++ ++/* WiFi P2P IE subelement: Configuration Timeout */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_cfg_tmo_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_CFG_TIMEOUT */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 go_tmo; /* GO config timeout in units of 10 ms */ ++ uint8 client_tmo; /* Client config timeout in units of 10 ms */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_cfg_tmo_se_s wifi_p2p_cfg_tmo_se_t; ++ ++/* WiFi P2P IE subelement: Listen Channel */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_listen_channel_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_CHANNEL */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 country[3]; /* Country String */ ++ uint8 op_class; /* Operating Class */ ++ uint8 channel; /* Channel */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_listen_channel_se_s wifi_p2p_listen_channel_se_t; ++ ++/* WiFi P2P IE subelement: P2P Group BSSID */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_grp_bssid_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_GRP_BSSID */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 mac[6]; /* P2P group bssid */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_grp_bssid_se_s wifi_p2p_grp_bssid_se_t; ++ ++/* WiFi P2P IE subelement: P2P Group ID */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_grp_id_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_GROUP_ID */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 mac[6]; /* P2P device address */ ++ uint8 ssid[1]; /* ssid. device id. variable length */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_grp_id_se_s wifi_p2p_grp_id_se_t; ++ ++/* WiFi P2P IE subelement: P2P Interface */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_intf_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_P2P_IF */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 mac[6]; /* P2P device address */ ++ uint8 ifaddrs; /* P2P Interface Address count */ ++ uint8 ifaddr[1][6]; /* P2P Interface Address list */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_intf_se_s wifi_p2p_intf_se_t; ++ ++/* WiFi P2P IE subelement: Status */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_status_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_STATUS */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 status; /* Status Code: P2P_STATSE_* */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_status_se_s wifi_p2p_status_se_t; ++ ++/* Status subelement Status Code definitions */ ++#define P2P_STATSE_SUCCESS 0 ++ /* Success */ ++#define P2P_STATSE_FAIL_INFO_CURR_UNAVAIL 1 ++ /* Failed, information currently unavailable */ ++#define P2P_STATSE_PASSED_UP P2P_STATSE_FAIL_INFO_CURR_UNAVAIL ++ /* Old name for above in P2P spec 1.08 and older */ ++#define P2P_STATSE_FAIL_INCOMPAT_PARAMS 2 ++ /* Failed, incompatible parameters */ ++#define P2P_STATSE_FAIL_LIMIT_REACHED 3 ++ /* Failed, limit reached */ ++#define P2P_STATSE_FAIL_INVALID_PARAMS 4 ++ /* Failed, invalid parameters */ ++#define P2P_STATSE_FAIL_UNABLE_TO_ACCOM 5 ++ /* Failed, unable to accomodate request */ ++#define P2P_STATSE_FAIL_PROTO_ERROR 6 ++ /* Failed, previous protocol error or disruptive behaviour */ ++#define P2P_STATSE_FAIL_NO_COMMON_CHAN 7 ++ /* Failed, no common channels */ ++#define P2P_STATSE_FAIL_UNKNOWN_GROUP 8 ++ /* Failed, unknown P2P Group */ ++#define P2P_STATSE_FAIL_INTENT 9 ++ /* Failed, both peers indicated Intent 15 in GO Negotiation */ ++#define P2P_STATSE_FAIL_INCOMPAT_PROVIS 10 ++ /* Failed, incompatible provisioning method */ ++#define P2P_STATSE_FAIL_USER_REJECT 11 ++ /* Failed, rejected by user */ ++ ++/* WiFi P2P IE attribute: Extended Listen Timing */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_ext_se_s { ++ uint8 eltId; /* ID: P2P_SEID_EXT_TIMING */ ++ uint8 len[2]; /* length not including eltId, len fields */ ++ uint8 avail[2]; /* availibility period */ ++ uint8 interval[2]; /* availibility interval */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_ext_se_s wifi_p2p_ext_se_t; ++ ++#define P2P_EXT_MIN 10 /* minimum 10ms */ ++ ++/* WiFi P2P IE subelement: Intended P2P Interface Address */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_intintad_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_INTINTADDR */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 mac[6]; /* intended P2P interface MAC address */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_intintad_se_s wifi_p2p_intintad_se_t; ++ ++/* WiFi P2P IE subelement: Channel */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_channel_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_STATUS */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 band; /* Regulatory Class (band) */ ++ uint8 channel; /* Channel */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_channel_se_s wifi_p2p_channel_se_t; ++ ++ ++/* Channel Entry structure within the Channel List SE */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_chanlist_entry_s { ++ uint8 band; /* Regulatory Class (band) */ ++ uint8 num_channels; /* # of channels in the channel list */ ++ uint8 channels[WL_NUMCHANNELS]; /* Channel List */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_chanlist_entry_s wifi_p2p_chanlist_entry_t; ++#define WIFI_P2P_CHANLIST_SE_MAX_ENTRIES 2 ++ ++/* WiFi P2P IE subelement: Channel List */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_chanlist_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_CHAN_LIST */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 country[3]; /* Country String */ ++ uint8 num_entries; /* # of channel entries */ ++ wifi_p2p_chanlist_entry_t entries[WIFI_P2P_CHANLIST_SE_MAX_ENTRIES]; ++ /* Channel Entry List */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_chanlist_se_s wifi_p2p_chanlist_se_t; ++ ++/* WiFi Primary Device Type structure */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_pri_devtype_s { ++ uint16 cat_id; /* Category ID */ ++ uint8 OUI[3]; /* WFA OUI: 0x0050F2 */ ++ uint8 oui_type; /* WPS_OUI_TYPE */ ++ uint16 sub_cat_id; /* Sub Category ID */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_pri_devtype_s wifi_p2p_pri_devtype_t; ++ ++/* WiFi P2P IE's Device Info subelement */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_devinfo_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_DEVINFO */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 mac[6]; /* P2P Device MAC address */ ++ uint16 wps_cfg_meths; /* Config Methods: reg_prototlv.h WPS_CONFMET_* */ ++ uint8 pri_devtype[8]; /* Primary Device Type */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_devinfo_se_s wifi_p2p_devinfo_se_t; ++ ++#define P2P_DEV_TYPE_LEN 8 ++ ++/* WiFi P2P IE's Group Info subelement Client Info Descriptor */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_cid_fixed_s { ++ uint8 len; ++ uint8 devaddr[ETHER_ADDR_LEN]; /* P2P Device Address */ ++ uint8 ifaddr[ETHER_ADDR_LEN]; /* P2P Interface Address */ ++ uint8 devcap; /* Device Capability */ ++ uint8 cfg_meths[2]; /* Config Methods: reg_prototlv.h WPS_CONFMET_* */ ++ uint8 pridt[P2P_DEV_TYPE_LEN]; /* Primary Device Type */ ++ uint8 secdts; /* Number of Secondary Device Types */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_cid_fixed_s wifi_p2p_cid_fixed_t; ++ ++/* WiFi P2P IE's Device ID subelement */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_devid_se_s { ++ uint8 eltId; ++ uint8 len[2]; ++ struct ether_addr addr; /* P2P Device MAC address */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_devid_se_s wifi_p2p_devid_se_t; ++ ++/* WiFi P2P IE subelement: P2P Manageability */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_mgbt_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_P2P_MGBTY */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 mg_bitmap; /* manageability bitmap */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_mgbt_se_s wifi_p2p_mgbt_se_t; ++/* mg_bitmap field bit values */ ++#define P2P_MGBTSE_P2PDEVMGMT_FLAG 0x1 /* AP supports Managed P2P Device */ ++ ++/* WiFi P2P IE subelement: Group Info */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_grpinfo_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_GROUP_INFO */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_grpinfo_se_s wifi_p2p_grpinfo_se_t; ++ ++/* WiFi IE subelement: Operating Channel */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_op_channel_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_OP_CHANNEL */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 country[3]; /* Country String */ ++ uint8 op_class; /* Operating Class */ ++ uint8 channel; /* Channel */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_op_channel_se_s wifi_p2p_op_channel_se_t; ++ ++/* WiFi IE subelement: INVITATION FLAGS */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_invite_flags_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_INVITE_FLAGS */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 flags; /* Flags */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_invite_flags_se_s wifi_p2p_invite_flags_se_t; ++ ++/* WiFi P2P Action Frame */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_action_frame { ++ uint8 category; /* P2P_AF_CATEGORY */ ++ uint8 OUI[3]; /* OUI - P2P_OUI */ ++ uint8 type; /* OUI Type - P2P_VER */ ++ uint8 subtype; /* OUI Subtype - P2P_AF_* */ ++ uint8 dialog_token; /* nonzero, identifies req/resp tranaction */ ++ uint8 elts[1]; /* Variable length information elements. Max size = ++ * ACTION_FRAME_SIZE - sizeof(this structure) - 1 ++ */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_action_frame wifi_p2p_action_frame_t; ++#define P2P_AF_CATEGORY 0x7f ++ ++#define P2P_AF_FIXED_LEN 7 ++ ++/* WiFi P2P Action Frame OUI Subtypes */ ++#define P2P_AF_NOTICE_OF_ABSENCE 0 /* Notice of Absence */ ++#define P2P_AF_PRESENCE_REQ 1 /* P2P Presence Request */ ++#define P2P_AF_PRESENCE_RSP 2 /* P2P Presence Response */ ++#define P2P_AF_GO_DISC_REQ 3 /* GO Discoverability Request */ ++ ++ ++/* WiFi P2P Public Action Frame */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_pub_act_frame { ++ uint8 category; /* P2P_PUB_AF_CATEGORY */ ++ uint8 action; /* P2P_PUB_AF_ACTION */ ++ uint8 oui[3]; /* P2P_OUI */ ++ uint8 oui_type; /* OUI type - P2P_VER */ ++ uint8 subtype; /* OUI subtype - P2P_TYPE_* */ ++ uint8 dialog_token; /* nonzero, identifies req/rsp transaction */ ++ uint8 elts[1]; /* Variable length information elements. Max size = ++ * ACTION_FRAME_SIZE - sizeof(this structure) - 1 ++ */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_pub_act_frame wifi_p2p_pub_act_frame_t; ++#define P2P_PUB_AF_FIXED_LEN 8 ++#define P2P_PUB_AF_CATEGORY 0x04 ++#define P2P_PUB_AF_ACTION 0x09 ++ ++/* WiFi P2P Public Action Frame OUI Subtypes */ ++#define P2P_PAF_GON_REQ 0 /* Group Owner Negotiation Req */ ++#define P2P_PAF_GON_RSP 1 /* Group Owner Negotiation Rsp */ ++#define P2P_PAF_GON_CONF 2 /* Group Owner Negotiation Confirm */ ++#define P2P_PAF_INVITE_REQ 3 /* P2P Invitation Request */ ++#define P2P_PAF_INVITE_RSP 4 /* P2P Invitation Response */ ++#define P2P_PAF_DEVDIS_REQ 5 /* Device Discoverability Request */ ++#define P2P_PAF_DEVDIS_RSP 6 /* Device Discoverability Response */ ++#define P2P_PAF_PROVDIS_REQ 7 /* Provision Discovery Request */ ++#define P2P_PAF_PROVDIS_RSP 8 /* Provision Discovery Response */ ++#define P2P_PAF_SUBTYPE_INVALID 255 /* Invalid Subtype */ ++ ++/* TODO: Stop using these obsolete aliases for P2P_PAF_GON_* */ ++#define P2P_TYPE_MNREQ P2P_PAF_GON_REQ ++#define P2P_TYPE_MNRSP P2P_PAF_GON_RSP ++#define P2P_TYPE_MNCONF P2P_PAF_GON_CONF ++ ++/* WiFi P2P IE subelement: Notice of Absence */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_noa_desc { ++ uint8 cnt_type; /* Count/Type */ ++ uint32 duration; /* Duration */ ++ uint32 interval; /* Interval */ ++ uint32 start; /* Start Time */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_noa_desc wifi_p2p_noa_desc_t; ++ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_noa_se { ++ uint8 eltId; /* Subelement ID */ ++ uint8 len[2]; /* Length */ ++ uint8 index; /* Index */ ++ uint8 ops_ctw_parms; /* CTWindow and OppPS Parameters */ ++ wifi_p2p_noa_desc_t desc[1]; /* Notice of Absence Descriptor(s) */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_noa_se wifi_p2p_noa_se_t; ++ ++#define P2P_NOA_SE_FIXED_LEN 5 ++ ++/* cnt_type field values */ ++#define P2P_NOA_DESC_CNT_RESERVED 0 /* reserved and should not be used */ ++#define P2P_NOA_DESC_CNT_REPEAT 255 /* continuous schedule */ ++#define P2P_NOA_DESC_TYPE_PREFERRED 1 /* preferred values */ ++#define P2P_NOA_DESC_TYPE_ACCEPTABLE 2 /* acceptable limits */ ++ ++/* ctw_ops_parms field values */ ++#define P2P_NOA_CTW_MASK 0x7f ++#define P2P_NOA_OPS_MASK 0x80 ++#define P2P_NOA_OPS_SHIFT 7 ++ ++#define P2P_CTW_MIN 10 /* minimum 10TU */ ++ ++/* ++ * P2P Service Discovery related ++ */ ++#define P2PSD_ACTION_CATEGORY 0x04 ++ /* Public action frame */ ++#define P2PSD_ACTION_ID_GAS_IREQ 0x0a ++ /* Action value for GAS Initial Request AF */ ++#define P2PSD_ACTION_ID_GAS_IRESP 0x0b ++ /* Action value for GAS Initial Response AF */ ++#define P2PSD_ACTION_ID_GAS_CREQ 0x0c ++ /* Action value for GAS Comback Request AF */ ++#define P2PSD_ACTION_ID_GAS_CRESP 0x0d ++ /* Action value for GAS Comback Response AF */ ++#define P2PSD_AD_EID 0x6c ++ /* Advertisement Protocol IE ID */ ++#define P2PSD_ADP_TUPLE_QLMT_PAMEBI 0x00 ++ /* Query Response Length Limit 7 bits plus PAME-BI 1 bit */ ++#define P2PSD_ADP_PROTO_ID 0x00 ++ /* Advertisement Protocol ID. Always 0 for P2P SD */ ++#define P2PSD_GAS_OUI P2P_OUI ++ /* WFA OUI */ ++#define P2PSD_GAS_OUI_SUBTYPE P2P_VER ++ /* OUI Subtype for GAS IE */ ++#define P2PSD_GAS_NQP_INFOID 0xDDDD ++ /* NQP Query Info ID: 56797 */ ++#define P2PSD_GAS_COMEBACKDEALY 0x00 ++ /* Not used in the Native GAS protocol */ ++ ++/* Service Protocol Type */ ++typedef enum p2psd_svc_protype { ++ SVC_RPOTYPE_ALL = 0, ++ SVC_RPOTYPE_BONJOUR = 1, ++ SVC_RPOTYPE_UPNP = 2, ++ SVC_RPOTYPE_WSD = 3, ++ SVC_RPOTYPE_VENDOR = 255 ++} p2psd_svc_protype_t; ++ ++/* Service Discovery response status code */ ++typedef enum { ++ P2PSD_RESP_STATUS_SUCCESS = 0, ++ P2PSD_RESP_STATUS_PROTYPE_NA = 1, ++ P2PSD_RESP_STATUS_DATA_NA = 2, ++ P2PSD_RESP_STATUS_BAD_REQUEST = 3 ++} p2psd_resp_status_t; ++ ++/* Advertisement Protocol IE tuple field */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2psd_adp_tpl { ++ uint8 llm_pamebi; /* Query Response Length Limit bit 0-6, set to 0 plus ++ * Pre-Associated Message Exchange BSSID Independent bit 7, set to 0 ++ */ ++ uint8 adp_id; /* Advertisement Protocol ID: 0 for NQP Native Query Protocol */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2psd_adp_tpl wifi_p2psd_adp_tpl_t; ++ ++/* Advertisement Protocol IE */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2psd_adp_ie { ++ uint8 id; /* IE ID: 0x6c - 108 */ ++ uint8 len; /* IE length */ ++ wifi_p2psd_adp_tpl_t adp_tpl; /* Advertisement Protocol Tuple field. Only one ++ * tuple is defined for P2P Service Discovery ++ */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2psd_adp_ie wifi_p2psd_adp_ie_t; ++ ++/* NQP Vendor-specific Content */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2psd_nqp_query_vsc { ++ uint8 oui_subtype; /* OUI Subtype: 0x09 */ ++ uint16 svc_updi; /* Service Update Indicator */ ++ uint8 svc_tlvs[1]; /* wifi_p2psd_qreq_tlv_t type for service request, ++ * wifi_p2psd_qresp_tlv_t type for service response ++ */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2psd_nqp_query_vsc wifi_p2psd_nqp_query_vsc_t; ++ ++/* Service Request TLV */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qreq_tlv { ++ uint16 len; /* Length: 5 plus size of Query Data */ ++ uint8 svc_prot; /* Service Protocol Type */ ++ uint8 svc_tscid; /* Service Transaction ID */ ++ uint8 query_data[1]; /* Query Data, passed in from above Layer 2 */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2psd_qreq_tlv wifi_p2psd_qreq_tlv_t; ++ ++/* Query Request Frame, defined in generic format, instead of NQP specific */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qreq_frame { ++ uint16 info_id; /* Info ID: 0xDDDD */ ++ uint16 len; /* Length of service request TLV, 5 plus the size of request data */ ++ uint8 oui[3]; /* WFA OUI: 0x0050F2 */ ++ uint8 qreq_vsc[1]; /* Vendor-specific Content: wifi_p2psd_nqp_query_vsc_t type for NQP */ ++ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2psd_qreq_frame wifi_p2psd_qreq_frame_t; ++ ++/* GAS Initial Request AF body, "elts" in wifi_p2p_pub_act_frame */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_ireq_frame { ++ wifi_p2psd_adp_ie_t adp_ie; /* Advertisement Protocol IE */ ++ uint16 qreq_len; /* Query Request Length */ ++ uint8 qreq_frm[1]; /* Query Request Frame wifi_p2psd_qreq_frame_t */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2psd_gas_ireq_frame wifi_p2psd_gas_ireq_frame_t; ++ ++/* Service Response TLV */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qresp_tlv { ++ uint16 len; /* Length: 5 plus size of Query Data */ ++ uint8 svc_prot; /* Service Protocol Type */ ++ uint8 svc_tscid; /* Service Transaction ID */ ++ uint8 status; /* Value defined in Table 57 of P2P spec. */ ++ uint8 query_data[1]; /* Response Data, passed in from above Layer 2 */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2psd_qresp_tlv wifi_p2psd_qresp_tlv_t; ++ ++/* Query Response Frame, defined in generic format, instead of NQP specific */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qresp_frame { ++ uint16 info_id; /* Info ID: 0xDDDD */ ++ uint16 len; /* Lenth of service response TLV, 6 plus the size of resp data */ ++ uint8 oui[3]; /* WFA OUI: 0x0050F2 */ ++ uint8 qresp_vsc[1]; /* Vendor-specific Content: wifi_p2psd_qresp_tlv_t type for NQP */ ++ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2psd_qresp_frame wifi_p2psd_qresp_frame_t; ++ ++/* GAS Initial Response AF body, "elts" in wifi_p2p_pub_act_frame */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_iresp_frame { ++ uint16 status; /* Value defined in Table 7-23 of IEEE P802.11u */ ++ uint16 cb_delay; /* GAS Comeback Delay */ ++ wifi_p2psd_adp_ie_t adp_ie; /* Advertisement Protocol IE */ ++ uint16 qresp_len; /* Query Response Length */ ++ uint8 qresp_frm[1]; /* Query Response Frame wifi_p2psd_qresp_frame_t */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2psd_gas_iresp_frame wifi_p2psd_gas_iresp_frame_t; ++ ++/* GAS Comeback Response AF body, "elts" in wifi_p2p_pub_act_frame */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_cresp_frame { ++ uint16 status; /* Value defined in Table 7-23 of IEEE P802.11u */ ++ uint8 fragment_id; /* Fragmentation ID */ ++ uint16 cb_delay; /* GAS Comeback Delay */ ++ wifi_p2psd_adp_ie_t adp_ie; /* Advertisement Protocol IE */ ++ uint16 qresp_len; /* Query Response Length */ ++ uint8 qresp_frm[1]; /* Query Response Frame wifi_p2psd_qresp_frame_t */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2psd_gas_cresp_frame wifi_p2psd_gas_cresp_frame_t; ++ ++/* Wi-Fi GAS Public Action Frame */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_pub_act_frame { ++ uint8 category; /* 0x04 Public Action Frame */ ++ uint8 action; /* 0x6c Advertisement Protocol */ ++ uint8 dialog_token; /* nonzero, identifies req/rsp transaction */ ++ uint8 query_data[1]; /* Query Data. wifi_p2psd_gas_ireq_frame_t ++ * or wifi_p2psd_gas_iresp_frame_t format ++ */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2psd_gas_pub_act_frame wifi_p2psd_gas_pub_act_frame_t; ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* _P2P_H_ */ +diff --git a/drivers/net/wireless/ap6211/include/proto/sdspi.h b/drivers/net/wireless/ap6211/include/proto/sdspi.h +new file mode 100755 +index 0000000..a4900ed +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/proto/sdspi.h +@@ -0,0 +1,75 @@ ++/* ++ * SD-SPI Protocol Standard ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: sdspi.h 241182 2011-02-17 21:50:03Z $ ++ */ ++#ifndef _SD_SPI_H ++#define _SD_SPI_H ++ ++#define SPI_START_M BITFIELD_MASK(1) /* Bit [31] - Start Bit */ ++#define SPI_START_S 31 ++#define SPI_DIR_M BITFIELD_MASK(1) /* Bit [30] - Direction */ ++#define SPI_DIR_S 30 ++#define SPI_CMD_INDEX_M BITFIELD_MASK(6) /* Bits [29:24] - Command number */ ++#define SPI_CMD_INDEX_S 24 ++#define SPI_RW_M BITFIELD_MASK(1) /* Bit [23] - Read=0, Write=1 */ ++#define SPI_RW_S 23 ++#define SPI_FUNC_M BITFIELD_MASK(3) /* Bits [22:20] - Function Number */ ++#define SPI_FUNC_S 20 ++#define SPI_RAW_M BITFIELD_MASK(1) /* Bit [19] - Read After Wr */ ++#define SPI_RAW_S 19 ++#define SPI_STUFF_M BITFIELD_MASK(1) /* Bit [18] - Stuff bit */ ++#define SPI_STUFF_S 18 ++#define SPI_BLKMODE_M BITFIELD_MASK(1) /* Bit [19] - Blockmode 1=blk */ ++#define SPI_BLKMODE_S 19 ++#define SPI_OPCODE_M BITFIELD_MASK(1) /* Bit [18] - OP Code */ ++#define SPI_OPCODE_S 18 ++#define SPI_ADDR_M BITFIELD_MASK(17) /* Bits [17:1] - Address */ ++#define SPI_ADDR_S 1 ++#define SPI_STUFF0_M BITFIELD_MASK(1) /* Bit [0] - Stuff bit */ ++#define SPI_STUFF0_S 0 ++ ++#define SPI_RSP_START_M BITFIELD_MASK(1) /* Bit [7] - Start Bit (always 0) */ ++#define SPI_RSP_START_S 7 ++#define SPI_RSP_PARAM_ERR_M BITFIELD_MASK(1) /* Bit [6] - Parameter Error */ ++#define SPI_RSP_PARAM_ERR_S 6 ++#define SPI_RSP_RFU5_M BITFIELD_MASK(1) /* Bit [5] - RFU (Always 0) */ ++#define SPI_RSP_RFU5_S 5 ++#define SPI_RSP_FUNC_ERR_M BITFIELD_MASK(1) /* Bit [4] - Function number error */ ++#define SPI_RSP_FUNC_ERR_S 4 ++#define SPI_RSP_CRC_ERR_M BITFIELD_MASK(1) /* Bit [3] - COM CRC Error */ ++#define SPI_RSP_CRC_ERR_S 3 ++#define SPI_RSP_ILL_CMD_M BITFIELD_MASK(1) /* Bit [2] - Illegal Command error */ ++#define SPI_RSP_ILL_CMD_S 2 ++#define SPI_RSP_RFU1_M BITFIELD_MASK(1) /* Bit [1] - RFU (Always 0) */ ++#define SPI_RSP_RFU1_S 1 ++#define SPI_RSP_IDLE_M BITFIELD_MASK(1) /* Bit [0] - In idle state */ ++#define SPI_RSP_IDLE_S 0 ++ ++/* SD-SPI Protocol Definitions */ ++#define SDSPI_COMMAND_LEN 6 /* Number of bytes in an SD command */ ++#define SDSPI_START_BLOCK 0xFE /* SD Start Block Token */ ++#define SDSPI_IDLE_PAD 0xFF /* SD-SPI idle value for MOSI */ ++#define SDSPI_START_BIT_MASK 0x80 ++ ++#endif /* _SD_SPI_H */ +diff --git a/drivers/net/wireless/ap6211/include/proto/vlan.h b/drivers/net/wireless/ap6211/include/proto/vlan.h +new file mode 100755 +index 0000000..88502bf +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/proto/vlan.h +@@ -0,0 +1,69 @@ ++/* ++ * 802.1Q VLAN protocol definitions ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: vlan.h 241182 2011-02-17 21:50:03Z $ ++ */ ++ ++#ifndef _vlan_h_ ++#define _vlan_h_ ++ ++#ifndef _TYPEDEFS_H_ ++#include ++#endif ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++#define VLAN_VID_MASK 0xfff /* low 12 bits are vlan id */ ++#define VLAN_CFI_SHIFT 12 /* canonical format indicator bit */ ++#define VLAN_PRI_SHIFT 13 /* user priority */ ++ ++#define VLAN_PRI_MASK 7 /* 3 bits of priority */ ++ ++#define VLAN_TAG_LEN 4 ++#define VLAN_TAG_OFFSET (2 * ETHER_ADDR_LEN) /* offset in Ethernet II packet only */ ++ ++#define VLAN_TPID 0x8100 /* VLAN ethertype/Tag Protocol ID */ ++ ++struct ethervlan_header { ++ uint8 ether_dhost[ETHER_ADDR_LEN]; ++ uint8 ether_shost[ETHER_ADDR_LEN]; ++ uint16 vlan_type; /* 0x8100 */ ++ uint16 vlan_tag; /* priority, cfi and vid */ ++ uint16 ether_type; ++}; ++ ++#define ETHERVLAN_HDR_LEN (ETHER_HDR_LEN + VLAN_TAG_LEN) ++ ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#define ETHERVLAN_MOVE_HDR(d, s) \ ++do { \ ++ struct ethervlan_header t; \ ++ t = *(struct ethervlan_header *)(s); \ ++ *(struct ethervlan_header *)(d) = t; \ ++} while (0) ++ ++#endif /* _vlan_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/proto/wpa.h b/drivers/net/wireless/ap6211/include/proto/wpa.h +new file mode 100755 +index 0000000..23ab8d6 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/proto/wpa.h +@@ -0,0 +1,206 @@ ++/* ++ * Fundamental types and constants relating to WPA ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: wpa.h 261155 2011-05-23 23:51:32Z $ ++ */ ++ ++#ifndef _proto_wpa_h_ ++#define _proto_wpa_h_ ++ ++#include ++#include ++ ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++/* Reason Codes */ ++ ++/* 13 through 23 taken from IEEE Std 802.11i-2004 */ ++#define DOT11_RC_INVALID_WPA_IE 13 /* Invalid info. element */ ++#define DOT11_RC_MIC_FAILURE 14 /* Michael failure */ ++#define DOT11_RC_4WH_TIMEOUT 15 /* 4-way handshake timeout */ ++#define DOT11_RC_GTK_UPDATE_TIMEOUT 16 /* Group key update timeout */ ++#define DOT11_RC_WPA_IE_MISMATCH 17 /* WPA IE in 4-way handshake differs from ++ * (re-)assoc. request/probe response ++ */ ++#define DOT11_RC_INVALID_MC_CIPHER 18 /* Invalid multicast cipher */ ++#define DOT11_RC_INVALID_UC_CIPHER 19 /* Invalid unicast cipher */ ++#define DOT11_RC_INVALID_AKMP 20 /* Invalid authenticated key management protocol */ ++#define DOT11_RC_BAD_WPA_VERSION 21 /* Unsupported WPA version */ ++#define DOT11_RC_INVALID_WPA_CAP 22 /* Invalid WPA IE capabilities */ ++#define DOT11_RC_8021X_AUTH_FAIL 23 /* 802.1X authentication failure */ ++ ++#define WPA2_PMKID_LEN 16 ++ ++/* WPA IE fixed portion */ ++typedef BWL_PRE_PACKED_STRUCT struct ++{ ++ uint8 tag; /* TAG */ ++ uint8 length; /* TAG length */ ++ uint8 oui[3]; /* IE OUI */ ++ uint8 oui_type; /* OUI type */ ++ BWL_PRE_PACKED_STRUCT struct { ++ uint8 low; ++ uint8 high; ++ } BWL_POST_PACKED_STRUCT version; /* IE version */ ++} BWL_POST_PACKED_STRUCT wpa_ie_fixed_t; ++#define WPA_IE_OUITYPE_LEN 4 ++#define WPA_IE_FIXED_LEN 8 ++#define WPA_IE_TAG_FIXED_LEN 6 ++ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint8 tag; /* TAG */ ++ uint8 length; /* TAG length */ ++ BWL_PRE_PACKED_STRUCT struct { ++ uint8 low; ++ uint8 high; ++ } BWL_POST_PACKED_STRUCT version; /* IE version */ ++} BWL_POST_PACKED_STRUCT wpa_rsn_ie_fixed_t; ++#define WPA_RSN_IE_FIXED_LEN 4 ++#define WPA_RSN_IE_TAG_FIXED_LEN 2 ++typedef uint8 wpa_pmkid_t[WPA2_PMKID_LEN]; ++ ++/* WPA suite/multicast suite */ ++typedef BWL_PRE_PACKED_STRUCT struct ++{ ++ uint8 oui[3]; ++ uint8 type; ++} BWL_POST_PACKED_STRUCT wpa_suite_t, wpa_suite_mcast_t; ++#define WPA_SUITE_LEN 4 ++ ++/* WPA unicast suite list/key management suite list */ ++typedef BWL_PRE_PACKED_STRUCT struct ++{ ++ BWL_PRE_PACKED_STRUCT struct { ++ uint8 low; ++ uint8 high; ++ } BWL_POST_PACKED_STRUCT count; ++ wpa_suite_t list[1]; ++} BWL_POST_PACKED_STRUCT wpa_suite_ucast_t, wpa_suite_auth_key_mgmt_t; ++#define WPA_IE_SUITE_COUNT_LEN 2 ++typedef BWL_PRE_PACKED_STRUCT struct ++{ ++ BWL_PRE_PACKED_STRUCT struct { ++ uint8 low; ++ uint8 high; ++ } BWL_POST_PACKED_STRUCT count; ++ wpa_pmkid_t list[1]; ++} BWL_POST_PACKED_STRUCT wpa_pmkid_list_t; ++ ++/* WPA cipher suites */ ++#define WPA_CIPHER_NONE 0 /* None */ ++#define WPA_CIPHER_WEP_40 1 /* WEP (40-bit) */ ++#define WPA_CIPHER_TKIP 2 /* TKIP: default for WPA */ ++#define WPA_CIPHER_AES_OCB 3 /* AES (OCB) */ ++#define WPA_CIPHER_AES_CCM 4 /* AES (CCM) */ ++#define WPA_CIPHER_WEP_104 5 /* WEP (104-bit) */ ++#define WPA_CIPHER_BIP 6 /* WEP (104-bit) */ ++#define WPA_CIPHER_TPK 7 /* Group addressed traffic not allowed */ ++#ifdef BCMWAPI_WPI ++#define WAPI_CIPHER_NONE WPA_CIPHER_NONE ++#define WAPI_CIPHER_SMS4 11 ++ ++#define WAPI_CSE_WPI_SMS4 1 ++#endif /* BCMWAPI_WPI */ ++ ++ ++#define IS_WPA_CIPHER(cipher) ((cipher) == WPA_CIPHER_NONE || \ ++ (cipher) == WPA_CIPHER_WEP_40 || \ ++ (cipher) == WPA_CIPHER_WEP_104 || \ ++ (cipher) == WPA_CIPHER_TKIP || \ ++ (cipher) == WPA_CIPHER_AES_OCB || \ ++ (cipher) == WPA_CIPHER_AES_CCM || \ ++ (cipher) == WPA_CIPHER_TPK) ++ ++#ifdef BCMWAPI_WAI ++#define IS_WAPI_CIPHER(cipher) ((cipher) == WAPI_CIPHER_NONE || \ ++ (cipher) == WAPI_CSE_WPI_SMS4) ++ ++/* convert WAPI_CSE_WPI_XXX to WAPI_CIPHER_XXX */ ++#define WAPI_CSE_WPI_2_CIPHER(cse) ((cse) == WAPI_CSE_WPI_SMS4 ? \ ++ WAPI_CIPHER_SMS4 : WAPI_CIPHER_NONE) ++ ++#define WAPI_CIPHER_2_CSE_WPI(cipher) ((cipher) == WAPI_CIPHER_SMS4 ? \ ++ WAPI_CSE_WPI_SMS4 : WAPI_CIPHER_NONE) ++#endif /* BCMWAPI_WAI */ ++ ++ ++/* WPA TKIP countermeasures parameters */ ++#define WPA_TKIP_CM_DETECT 60 /* multiple MIC failure window (seconds) */ ++#define WPA_TKIP_CM_BLOCK 60 /* countermeasures active window (seconds) */ ++ ++/* RSN IE defines */ ++#define RSN_CAP_LEN 2 /* Length of RSN capabilities field (2 octets) */ ++ ++/* RSN Capabilities defined in 802.11i */ ++#define RSN_CAP_PREAUTH 0x0001 ++#define RSN_CAP_NOPAIRWISE 0x0002 ++#define RSN_CAP_PTK_REPLAY_CNTR_MASK 0x000C ++#define RSN_CAP_PTK_REPLAY_CNTR_SHIFT 2 ++#define RSN_CAP_GTK_REPLAY_CNTR_MASK 0x0030 ++#define RSN_CAP_GTK_REPLAY_CNTR_SHIFT 4 ++#define RSN_CAP_1_REPLAY_CNTR 0 ++#define RSN_CAP_2_REPLAY_CNTRS 1 ++#define RSN_CAP_4_REPLAY_CNTRS 2 ++#define RSN_CAP_16_REPLAY_CNTRS 3 ++#ifdef MFP ++#define RSN_CAP_MFPR 0x0040 ++#define RSN_CAP_MFPC 0x0080 ++#endif ++ ++/* WPA capabilities defined in 802.11i */ ++#define WPA_CAP_4_REPLAY_CNTRS RSN_CAP_4_REPLAY_CNTRS ++#define WPA_CAP_16_REPLAY_CNTRS RSN_CAP_16_REPLAY_CNTRS ++#define WPA_CAP_REPLAY_CNTR_SHIFT RSN_CAP_PTK_REPLAY_CNTR_SHIFT ++#define WPA_CAP_REPLAY_CNTR_MASK RSN_CAP_PTK_REPLAY_CNTR_MASK ++ ++/* WPA capabilities defined in 802.11zD9.0 */ ++#define WPA_CAP_PEER_KEY_ENABLE (0x1 << 1) /* bit 9 */ ++ ++/* WPA Specific defines */ ++#define WPA_CAP_LEN RSN_CAP_LEN /* Length of RSN capabilities in RSN IE (2 octets) */ ++#define WPA_PMKID_CNT_LEN 2 /* Length of RSN PMKID count (2 octests) */ ++ ++#define WPA_CAP_WPA2_PREAUTH RSN_CAP_PREAUTH ++ ++#ifdef BCMWAPI_WAI ++#define WAPI_CAP_PREAUTH RSN_CAP_PREAUTH ++ ++/* Other WAI definition */ ++#define WAPI_WAI_REQUEST 0x00F1 ++#define WAPI_UNICAST_REKEY 0x00F2 ++#define WAPI_STA_AGING 0x00F3 ++#define WAPI_MUTIL_REKEY 0x00F4 ++#define WAPI_STA_STATS 0x00F5 ++ ++#define WAPI_USK_REKEY_COUNT 0x4000000 /* 0xA00000 */ ++#define WAPI_MSK_REKEY_COUNT 0x4000000 /* 0xA00000 */ ++#endif /* BCMWAPI_WAI */ ++#define WPA2_PMKID_COUNT_LEN 2 ++ ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* _proto_wpa_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/sbchipc.h b/drivers/net/wireless/ap6211/include/sbchipc.h +new file mode 100755 +index 0000000..c694291 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/sbchipc.h +@@ -0,0 +1,2405 @@ ++/* ++ * SiliconBackplane Chipcommon core hardware definitions. ++ * ++ * The chipcommon core provides chip identification, SB control, ++ * JTAG, 0/1/2 UARTs, clock frequency control, a watchdog interrupt timer, ++ * GPIO interface, extbus, and support for serial and parallel flashes. ++ * ++ * $Id: sbchipc.h 347614 2012-07-27 10:24:51Z $ ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ */ ++ ++#ifndef _SBCHIPC_H ++#define _SBCHIPC_H ++ ++#ifndef _LANGUAGE_ASSEMBLY ++ ++/* cpp contortions to concatenate w/arg prescan */ ++#ifndef PAD ++#define _PADLINE(line) pad ## line ++#define _XSTR(line) _PADLINE(line) ++#define PAD _XSTR(__LINE__) ++#endif /* PAD */ ++ ++typedef struct eci_prerev35 { ++ uint32 eci_output; ++ uint32 eci_control; ++ uint32 eci_inputlo; ++ uint32 eci_inputmi; ++ uint32 eci_inputhi; ++ uint32 eci_inputintpolaritylo; ++ uint32 eci_inputintpolaritymi; ++ uint32 eci_inputintpolarityhi; ++ uint32 eci_intmasklo; ++ uint32 eci_intmaskmi; ++ uint32 eci_intmaskhi; ++ uint32 eci_eventlo; ++ uint32 eci_eventmi; ++ uint32 eci_eventhi; ++ uint32 eci_eventmasklo; ++ uint32 eci_eventmaskmi; ++ uint32 eci_eventmaskhi; ++ uint32 PAD[3]; ++} eci_prerev35_t; ++ ++typedef struct eci_rev35 { ++ uint32 eci_outputlo; ++ uint32 eci_outputhi; ++ uint32 eci_controllo; ++ uint32 eci_controlhi; ++ uint32 eci_inputlo; ++ uint32 eci_inputhi; ++ uint32 eci_inputintpolaritylo; ++ uint32 eci_inputintpolarityhi; ++ uint32 eci_intmasklo; ++ uint32 eci_intmaskhi; ++ uint32 eci_eventlo; ++ uint32 eci_eventhi; ++ uint32 eci_eventmasklo; ++ uint32 eci_eventmaskhi; ++ uint32 eci_auxtx; ++ uint32 eci_auxrx; ++ uint32 eci_datatag; ++ uint32 eci_uartescvalue; ++ uint32 eci_autobaudctr; ++ uint32 eci_uartfifolevel; ++} eci_rev35_t; ++ ++typedef struct flash_config { ++ uint32 PAD[19]; ++ /* Flash struct configuration registers (0x18c) for BCM4706 (corerev = 31) */ ++ uint32 flashstrconfig; ++} flash_config_t; ++ ++typedef volatile struct { ++ uint32 chipid; /* 0x0 */ ++ uint32 capabilities; ++ uint32 corecontrol; /* corerev >= 1 */ ++ uint32 bist; ++ ++ /* OTP */ ++ uint32 otpstatus; /* 0x10, corerev >= 10 */ ++ uint32 otpcontrol; ++ uint32 otpprog; ++ uint32 otplayout; /* corerev >= 23 */ ++ ++ /* Interrupt control */ ++ uint32 intstatus; /* 0x20 */ ++ uint32 intmask; ++ ++ /* Chip specific regs */ ++ uint32 chipcontrol; /* 0x28, rev >= 11 */ ++ uint32 chipstatus; /* 0x2c, rev >= 11 */ ++ ++ /* Jtag Master */ ++ uint32 jtagcmd; /* 0x30, rev >= 10 */ ++ uint32 jtagir; ++ uint32 jtagdr; ++ uint32 jtagctrl; ++ ++ /* serial flash interface registers */ ++ uint32 flashcontrol; /* 0x40 */ ++ uint32 flashaddress; ++ uint32 flashdata; ++ uint32 otplayoutextension; /* rev >= 35 */ ++ ++ /* Silicon backplane configuration broadcast control */ ++ uint32 broadcastaddress; /* 0x50 */ ++ uint32 broadcastdata; ++ ++ /* gpio - cleared only by power-on-reset */ ++ uint32 gpiopullup; /* 0x58, corerev >= 20 */ ++ uint32 gpiopulldown; /* 0x5c, corerev >= 20 */ ++ uint32 gpioin; /* 0x60 */ ++ uint32 gpioout; /* 0x64 */ ++ uint32 gpioouten; /* 0x68 */ ++ uint32 gpiocontrol; /* 0x6C */ ++ uint32 gpiointpolarity; /* 0x70 */ ++ uint32 gpiointmask; /* 0x74 */ ++ ++ /* GPIO events corerev >= 11 */ ++ uint32 gpioevent; ++ uint32 gpioeventintmask; ++ ++ /* Watchdog timer */ ++ uint32 watchdog; /* 0x80 */ ++ ++ /* GPIO events corerev >= 11 */ ++ uint32 gpioeventintpolarity; ++ ++ /* GPIO based LED powersave registers corerev >= 16 */ ++ uint32 gpiotimerval; /* 0x88 */ ++ uint32 gpiotimeroutmask; ++ ++ /* clock control */ ++ uint32 clockcontrol_n; /* 0x90 */ ++ uint32 clockcontrol_sb; /* aka m0 */ ++ uint32 clockcontrol_pci; /* aka m1 */ ++ uint32 clockcontrol_m2; /* mii/uart/mipsref */ ++ uint32 clockcontrol_m3; /* cpu */ ++ uint32 clkdiv; /* corerev >= 3 */ ++ uint32 gpiodebugsel; /* corerev >= 28 */ ++ uint32 capabilities_ext; /* 0xac */ ++ ++ /* pll delay registers (corerev >= 4) */ ++ uint32 pll_on_delay; /* 0xb0 */ ++ uint32 fref_sel_delay; ++ uint32 slow_clk_ctl; /* 5 < corerev < 10 */ ++ uint32 PAD; ++ ++ /* Instaclock registers (corerev >= 10) */ ++ uint32 system_clk_ctl; /* 0xc0 */ ++ uint32 clkstatestretch; ++ uint32 PAD[2]; ++ ++ /* Indirect backplane access (corerev >= 22) */ ++ uint32 bp_addrlow; /* 0xd0 */ ++ uint32 bp_addrhigh; ++ uint32 bp_data; ++ uint32 PAD; ++ uint32 bp_indaccess; ++ /* SPI registers, corerev >= 37 */ ++ uint32 gsioctrl; ++ uint32 gsioaddress; ++ uint32 gsiodata; ++ ++ /* More clock dividers (corerev >= 32) */ ++ uint32 clkdiv2; ++ /* FAB ID (corerev >= 40) */ ++ uint32 otpcontrol1; ++ uint32 fabid; /* 0xf8 */ ++ ++ /* In AI chips, pointer to erom */ ++ uint32 eromptr; /* 0xfc */ ++ ++ /* ExtBus control registers (corerev >= 3) */ ++ uint32 pcmcia_config; /* 0x100 */ ++ uint32 pcmcia_memwait; ++ uint32 pcmcia_attrwait; ++ uint32 pcmcia_iowait; ++ uint32 ide_config; ++ uint32 ide_memwait; ++ uint32 ide_attrwait; ++ uint32 ide_iowait; ++ uint32 prog_config; ++ uint32 prog_waitcount; ++ uint32 flash_config; ++ uint32 flash_waitcount; ++ uint32 SECI_config; /* 0x130 SECI configuration */ ++ uint32 SECI_status; ++ uint32 SECI_statusmask; ++ uint32 SECI_rxnibchanged; ++ ++ uint32 PAD[20]; ++ ++ /* SROM interface (corerev >= 32) */ ++ uint32 sromcontrol; /* 0x190 */ ++ uint32 sromaddress; ++ uint32 sromdata; ++ uint32 PAD[1]; /* 0x19C */ ++ /* NAND flash registers for BCM4706 (corerev = 31) */ ++ uint32 nflashctrl; /* 0x1a0 */ ++ uint32 nflashconf; ++ uint32 nflashcoladdr; ++ uint32 nflashrowaddr; ++ uint32 nflashdata; ++ uint32 nflashwaitcnt0; /* 0x1b4 */ ++ uint32 PAD[2]; ++ ++ uint32 seci_uart_data; /* 0x1C0 */ ++ uint32 seci_uart_bauddiv; ++ uint32 seci_uart_fcr; ++ uint32 seci_uart_lcr; ++ uint32 seci_uart_mcr; ++ uint32 seci_uart_lsr; ++ uint32 seci_uart_msr; ++ uint32 seci_uart_baudadj; ++ /* Clock control and hardware workarounds (corerev >= 20) */ ++ uint32 clk_ctl_st; /* 0x1e0 */ ++ uint32 hw_war; ++ uint32 PAD[70]; ++ ++ /* UARTs */ ++ uint8 uart0data; /* 0x300 */ ++ uint8 uart0imr; ++ uint8 uart0fcr; ++ uint8 uart0lcr; ++ uint8 uart0mcr; ++ uint8 uart0lsr; ++ uint8 uart0msr; ++ uint8 uart0scratch; ++ uint8 PAD[248]; /* corerev >= 1 */ ++ ++ uint8 uart1data; /* 0x400 */ ++ uint8 uart1imr; ++ uint8 uart1fcr; ++ uint8 uart1lcr; ++ uint8 uart1mcr; ++ uint8 uart1lsr; ++ uint8 uart1msr; ++ uint8 uart1scratch; ++ uint32 PAD[126]; ++ ++ /* PMU registers (corerev >= 20) */ ++ /* Note: all timers driven by ILP clock are updated asynchronously to HT/ALP. ++ * The CPU must read them twice, compare, and retry if different. ++ */ ++ uint32 pmucontrol; /* 0x600 */ ++ uint32 pmucapabilities; ++ uint32 pmustatus; ++ uint32 res_state; ++ uint32 res_pending; ++ uint32 pmutimer; ++ uint32 min_res_mask; ++ uint32 max_res_mask; ++ uint32 res_table_sel; ++ uint32 res_dep_mask; ++ uint32 res_updn_timer; ++ uint32 res_timer; ++ uint32 clkstretch; ++ uint32 pmuwatchdog; ++ uint32 gpiosel; /* 0x638, rev >= 1 */ ++ uint32 gpioenable; /* 0x63c, rev >= 1 */ ++ uint32 res_req_timer_sel; ++ uint32 res_req_timer; ++ uint32 res_req_mask; ++ uint32 PAD; ++ uint32 chipcontrol_addr; /* 0x650 */ ++ uint32 chipcontrol_data; /* 0x654 */ ++ uint32 regcontrol_addr; ++ uint32 regcontrol_data; ++ uint32 pllcontrol_addr; ++ uint32 pllcontrol_data; ++ uint32 pmustrapopt; /* 0x668, corerev >= 28 */ ++ uint32 pmu_xtalfreq; /* 0x66C, pmurev >= 10 */ ++ uint32 retention_ctl; /* 0x670 */ ++ uint32 PAD[3]; ++ uint32 retention_grpidx; /* 0x680 */ ++ uint32 retention_grpctl; /* 0x684 */ ++ uint32 PAD[94]; ++ uint16 sromotp[512]; /* 0x800 */ ++#ifdef NFLASH_SUPPORT ++ /* Nand flash MLC controller registers (corerev >= 38) */ ++ uint32 nand_revision; /* 0xC00 */ ++ uint32 nand_cmd_start; ++ uint32 nand_cmd_addr_x; ++ uint32 nand_cmd_addr; ++ uint32 nand_cmd_end_addr; ++ uint32 nand_cs_nand_select; ++ uint32 nand_cs_nand_xor; ++ uint32 PAD; ++ uint32 nand_spare_rd0; ++ uint32 nand_spare_rd4; ++ uint32 nand_spare_rd8; ++ uint32 nand_spare_rd12; ++ uint32 nand_spare_wr0; ++ uint32 nand_spare_wr4; ++ uint32 nand_spare_wr8; ++ uint32 nand_spare_wr12; ++ uint32 nand_acc_control; ++ uint32 PAD; ++ uint32 nand_config; ++ uint32 PAD; ++ uint32 nand_timing_1; ++ uint32 nand_timing_2; ++ uint32 nand_semaphore; ++ uint32 PAD; ++ uint32 nand_devid; ++ uint32 nand_devid_x; ++ uint32 nand_block_lock_status; ++ uint32 nand_intfc_status; ++ uint32 nand_ecc_corr_addr_x; ++ uint32 nand_ecc_corr_addr; ++ uint32 nand_ecc_unc_addr_x; ++ uint32 nand_ecc_unc_addr; ++ uint32 nand_read_error_count; ++ uint32 nand_corr_stat_threshold; ++ uint32 PAD[2]; ++ uint32 nand_read_addr_x; ++ uint32 nand_read_addr; ++ uint32 nand_page_program_addr_x; ++ uint32 nand_page_program_addr; ++ uint32 nand_copy_back_addr_x; ++ uint32 nand_copy_back_addr; ++ uint32 nand_block_erase_addr_x; ++ uint32 nand_block_erase_addr; ++ uint32 nand_inv_read_addr_x; ++ uint32 nand_inv_read_addr; ++ uint32 PAD[2]; ++ uint32 nand_blk_wr_protect; ++ uint32 PAD[3]; ++ uint32 nand_acc_control_cs1; ++ uint32 nand_config_cs1; ++ uint32 nand_timing_1_cs1; ++ uint32 nand_timing_2_cs1; ++ uint32 PAD[20]; ++ uint32 nand_spare_rd16; ++ uint32 nand_spare_rd20; ++ uint32 nand_spare_rd24; ++ uint32 nand_spare_rd28; ++ uint32 nand_cache_addr; ++ uint32 nand_cache_data; ++ uint32 nand_ctrl_config; ++ uint32 nand_ctrl_status; ++#endif /* NFLASH_SUPPORT */ ++ uint32 gci_corecaps0; /* GCI starting at 0xC00 */ ++ uint32 gci_corecaps1; ++ uint32 gci_corecaps2; ++ uint32 gci_corectrl; ++ uint32 gci_corestat; /* 0xC10 */ ++ uint32 PAD[11]; ++ uint32 gci_indirect_addr; /* 0xC40 */ ++ uint32 PAD[111]; ++ uint32 gci_chipctrl; /* 0xE00 */ ++} chipcregs_t; ++ ++#endif /* _LANGUAGE_ASSEMBLY */ ++ ++ ++#define CC_CHIPID 0 ++#define CC_CAPABILITIES 4 ++#define CC_CHIPST 0x2c ++#define CC_EROMPTR 0xfc ++ ++#define CC_OTPST 0x10 ++#define CC_JTAGCMD 0x30 ++#define CC_JTAGIR 0x34 ++#define CC_JTAGDR 0x38 ++#define CC_JTAGCTRL 0x3c ++#define CC_GPIOPU 0x58 ++#define CC_GPIOPD 0x5c ++#define CC_GPIOIN 0x60 ++#define CC_GPIOOUT 0x64 ++#define CC_GPIOOUTEN 0x68 ++#define CC_GPIOCTRL 0x6c ++#define CC_GPIOPOL 0x70 ++#define CC_GPIOINTM 0x74 ++#define CC_WATCHDOG 0x80 ++#define CC_CLKC_N 0x90 ++#define CC_CLKC_M0 0x94 ++#define CC_CLKC_M1 0x98 ++#define CC_CLKC_M2 0x9c ++#define CC_CLKC_M3 0xa0 ++#define CC_CLKDIV 0xa4 ++#define CC_SYS_CLK_CTL 0xc0 ++#define CC_CLK_CTL_ST SI_CLK_CTL_ST ++#define PMU_CTL 0x600 ++#define PMU_CAP 0x604 ++#define PMU_ST 0x608 ++#define PMU_RES_STATE 0x60c ++#define PMU_TIMER 0x614 ++#define PMU_MIN_RES_MASK 0x618 ++#define PMU_MAX_RES_MASK 0x61c ++#define CC_CHIPCTL_ADDR 0x650 ++#define CC_CHIPCTL_DATA 0x654 ++#define PMU_REG_CONTROL_ADDR 0x658 ++#define PMU_REG_CONTROL_DATA 0x65C ++#define PMU_PLL_CONTROL_ADDR 0x660 ++#define PMU_PLL_CONTROL_DATA 0x664 ++#define CC_SROM_OTP 0x800 /* SROM/OTP address space */ ++#define CC_GCI_INDIRECT_ADDR_REG 0xC40 ++#define CC_GCI_CHIP_CTRL_REG 0xE00 ++#define CC_GCI_CC_OFFSET_2 2 ++#define CC_GCI_CC_OFFSET_5 5 ++ ++#ifdef NFLASH_SUPPORT ++/* NAND flash support */ ++#define CC_NAND_REVISION 0xC00 ++#define CC_NAND_CMD_START 0xC04 ++#define CC_NAND_CMD_ADDR 0xC0C ++#define CC_NAND_SPARE_RD_0 0xC20 ++#define CC_NAND_SPARE_RD_4 0xC24 ++#define CC_NAND_SPARE_RD_8 0xC28 ++#define CC_NAND_SPARE_RD_C 0xC2C ++#define CC_NAND_CONFIG 0xC48 ++#define CC_NAND_DEVID 0xC60 ++#define CC_NAND_DEVID_EXT 0xC64 ++#define CC_NAND_INTFC_STATUS 0xC6C ++#endif /* NFLASH_SUPPORT */ ++ ++/* chipid */ ++#define CID_ID_MASK 0x0000ffff /* Chip Id mask */ ++#define CID_REV_MASK 0x000f0000 /* Chip Revision mask */ ++#define CID_REV_SHIFT 16 /* Chip Revision shift */ ++#define CID_PKG_MASK 0x00f00000 /* Package Option mask */ ++#define CID_PKG_SHIFT 20 /* Package Option shift */ ++#define CID_CC_MASK 0x0f000000 /* CoreCount (corerev >= 4) */ ++#define CID_CC_SHIFT 24 ++#define CID_TYPE_MASK 0xf0000000 /* Chip Type */ ++#define CID_TYPE_SHIFT 28 ++ ++/* capabilities */ ++#define CC_CAP_UARTS_MASK 0x00000003 /* Number of UARTs */ ++#define CC_CAP_MIPSEB 0x00000004 /* MIPS is in big-endian mode */ ++#define CC_CAP_UCLKSEL 0x00000018 /* UARTs clock select */ ++#define CC_CAP_UINTCLK 0x00000008 /* UARTs are driven by internal divided clock */ ++#define CC_CAP_UARTGPIO 0x00000020 /* UARTs own GPIOs 15:12 */ ++#define CC_CAP_EXTBUS_MASK 0x000000c0 /* External bus mask */ ++#define CC_CAP_EXTBUS_NONE 0x00000000 /* No ExtBus present */ ++#define CC_CAP_EXTBUS_FULL 0x00000040 /* ExtBus: PCMCIA, IDE & Prog */ ++#define CC_CAP_EXTBUS_PROG 0x00000080 /* ExtBus: ProgIf only */ ++#define CC_CAP_FLASH_MASK 0x00000700 /* Type of flash */ ++#define CC_CAP_PLL_MASK 0x00038000 /* Type of PLL */ ++#define CC_CAP_PWR_CTL 0x00040000 /* Power control */ ++#define CC_CAP_OTPSIZE 0x00380000 /* OTP Size (0 = none) */ ++#define CC_CAP_OTPSIZE_SHIFT 19 /* OTP Size shift */ ++#define CC_CAP_OTPSIZE_BASE 5 /* OTP Size base */ ++#define CC_CAP_JTAGP 0x00400000 /* JTAG Master Present */ ++#define CC_CAP_ROM 0x00800000 /* Internal boot rom active */ ++#define CC_CAP_BKPLN64 0x08000000 /* 64-bit backplane */ ++#define CC_CAP_PMU 0x10000000 /* PMU Present, rev >= 20 */ ++#define CC_CAP_ECI 0x20000000 /* ECI Present, rev >= 21 */ ++#define CC_CAP_SROM 0x40000000 /* Srom Present, rev >= 32 */ ++#define CC_CAP_NFLASH 0x80000000 /* Nand flash present, rev >= 35 */ ++ ++#define CC_CAP2_SECI 0x00000001 /* SECI Present, rev >= 36 */ ++#define CC_CAP2_GSIO 0x00000002 /* GSIO (spi/i2c) present, rev >= 37 */ ++ ++/* capabilities extension */ ++#define CC_CAP_EXT_SECI_PRESENT 0x00000001 /* SECI present */ ++ ++/* PLL type */ ++#define PLL_NONE 0x00000000 ++#define PLL_TYPE1 0x00010000 /* 48MHz base, 3 dividers */ ++#define PLL_TYPE2 0x00020000 /* 48MHz, 4 dividers */ ++#define PLL_TYPE3 0x00030000 /* 25MHz, 2 dividers */ ++#define PLL_TYPE4 0x00008000 /* 48MHz, 4 dividers */ ++#define PLL_TYPE5 0x00018000 /* 25MHz, 4 dividers */ ++#define PLL_TYPE6 0x00028000 /* 100/200 or 120/240 only */ ++#define PLL_TYPE7 0x00038000 /* 25MHz, 4 dividers */ ++ ++/* ILP clock */ ++#define ILP_CLOCK 32000 ++ ++/* ALP clock on pre-PMU chips */ ++#define ALP_CLOCK 20000000 ++ ++/* HT clock */ ++#define HT_CLOCK 80000000 ++ ++/* corecontrol */ ++#define CC_UARTCLKO 0x00000001 /* Drive UART with internal clock */ ++#define CC_SE 0x00000002 /* sync clk out enable (corerev >= 3) */ ++#define CC_ASYNCGPIO 0x00000004 /* 1=generate GPIO interrupt without backplane clock */ ++#define CC_UARTCLKEN 0x00000008 /* enable UART Clock (corerev > = 21 */ ++ ++/* 4321 chipcontrol */ ++#define CHIPCTRL_4321A0_DEFAULT 0x3a4 ++#define CHIPCTRL_4321A1_DEFAULT 0x0a4 ++#define CHIPCTRL_4321_PLL_DOWN 0x800000 /* serdes PLL down override */ ++ ++/* Fields in the otpstatus register in rev >= 21 */ ++#define OTPS_OL_MASK 0x000000ff ++#define OTPS_OL_MFG 0x00000001 /* manuf row is locked */ ++#define OTPS_OL_OR1 0x00000002 /* otp redundancy row 1 is locked */ ++#define OTPS_OL_OR2 0x00000004 /* otp redundancy row 2 is locked */ ++#define OTPS_OL_GU 0x00000008 /* general use region is locked */ ++#define OTPS_GUP_MASK 0x00000f00 ++#define OTPS_GUP_SHIFT 8 ++#define OTPS_GUP_HW 0x00000100 /* h/w subregion is programmed */ ++#define OTPS_GUP_SW 0x00000200 /* s/w subregion is programmed */ ++#define OTPS_GUP_CI 0x00000400 /* chipid/pkgopt subregion is programmed */ ++#define OTPS_GUP_FUSE 0x00000800 /* fuse subregion is programmed */ ++#define OTPS_READY 0x00001000 ++#define OTPS_RV(x) (1 << (16 + (x))) /* redundancy entry valid */ ++#define OTPS_RV_MASK 0x0fff0000 ++#define OTPS_PROGOK 0x40000000 ++ ++/* Fields in the otpcontrol register in rev >= 21 */ ++#define OTPC_PROGSEL 0x00000001 ++#define OTPC_PCOUNT_MASK 0x0000000e ++#define OTPC_PCOUNT_SHIFT 1 ++#define OTPC_VSEL_MASK 0x000000f0 ++#define OTPC_VSEL_SHIFT 4 ++#define OTPC_TMM_MASK 0x00000700 ++#define OTPC_TMM_SHIFT 8 ++#define OTPC_ODM 0x00000800 ++#define OTPC_PROGEN 0x80000000 ++ ++/* Fields in the 40nm otpcontrol register in rev >= 40 */ ++#define OTPC_40NM_PROGSEL_SHIFT 0 ++#define OTPC_40NM_PCOUNT_SHIFT 1 ++#define OTPC_40NM_PCOUNT_WR 0xA ++#define OTPC_40NM_PCOUNT_V1X 0xB ++#define OTPC_40NM_REGCSEL_SHIFT 5 ++#define OTPC_40NM_REGCSEL_DEF 0x4 ++#define OTPC_40NM_PROGIN_SHIFT 8 ++#define OTPC_40NM_R2X_SHIFT 10 ++#define OTPC_40NM_ODM_SHIFT 11 ++#define OTPC_40NM_DF_SHIFT 15 ++#define OTPC_40NM_VSEL_SHIFT 16 ++#define OTPC_40NM_VSEL_WR 0xA ++#define OTPC_40NM_VSEL_V1X 0xA ++#define OTPC_40NM_VSEL_R1X 0x5 ++#define OTPC_40NM_COFAIL_SHIFT 30 ++ ++#define OTPC1_CPCSEL_SHIFT 0 ++#define OTPC1_CPCSEL_DEF 6 ++#define OTPC1_TM_SHIFT 8 ++#define OTPC1_TM_WR 0x84 ++#define OTPC1_TM_V1X 0x84 ++#define OTPC1_TM_R1X 0x4 ++ ++/* Fields in otpprog in rev >= 21 and HND OTP */ ++#define OTPP_COL_MASK 0x000000ff ++#define OTPP_COL_SHIFT 0 ++#define OTPP_ROW_MASK 0x0000ff00 ++#define OTPP_ROW_SHIFT 8 ++#define OTPP_OC_MASK 0x0f000000 ++#define OTPP_OC_SHIFT 24 ++#define OTPP_READERR 0x10000000 ++#define OTPP_VALUE_MASK 0x20000000 ++#define OTPP_VALUE_SHIFT 29 ++#define OTPP_START_BUSY 0x80000000 ++#define OTPP_READ 0x40000000 /* HND OTP */ ++ ++/* Fields in otplayout register */ ++#define OTPL_HWRGN_OFF_MASK 0x00000FFF ++#define OTPL_HWRGN_OFF_SHIFT 0 ++#define OTPL_WRAP_REVID_MASK 0x00F80000 ++#define OTPL_WRAP_REVID_SHIFT 19 ++#define OTPL_WRAP_TYPE_MASK 0x00070000 ++#define OTPL_WRAP_TYPE_SHIFT 16 ++#define OTPL_WRAP_TYPE_65NM 0 ++#define OTPL_WRAP_TYPE_40NM 1 ++ ++/* otplayout reg corerev >= 36 */ ++#define OTP_CISFORMAT_NEW 0x80000000 ++ ++/* Opcodes for OTPP_OC field */ ++#define OTPPOC_READ 0 ++#define OTPPOC_BIT_PROG 1 ++#define OTPPOC_VERIFY 3 ++#define OTPPOC_INIT 4 ++#define OTPPOC_SET 5 ++#define OTPPOC_RESET 6 ++#define OTPPOC_OCST 7 ++#define OTPPOC_ROW_LOCK 8 ++#define OTPPOC_PRESCN_TEST 9 ++ ++/* Opcodes for OTPP_OC field (40NM) */ ++#define OTPPOC_READ_40NM 0 ++#define OTPPOC_PROG_ENABLE_40NM 1 ++#define OTPPOC_PROG_DISABLE_40NM 2 ++#define OTPPOC_VERIFY_40NM 3 ++#define OTPPOC_WORD_VERIFY_1_40NM 4 ++#define OTPPOC_ROW_LOCK_40NM 5 ++#define OTPPOC_STBY_40NM 6 ++#define OTPPOC_WAKEUP_40NM 7 ++#define OTPPOC_WORD_VERIFY_0_40NM 8 ++#define OTPPOC_PRESCN_TEST_40NM 9 ++#define OTPPOC_BIT_PROG_40NM 10 ++#define OTPPOC_WORDPROG_40NM 11 ++#define OTPPOC_BURNIN_40NM 12 ++#define OTPPOC_AUTORELOAD_40NM 13 ++#define OTPPOC_OVST_READ_40NM 14 ++#define OTPPOC_OVST_PROG_40NM 15 ++ ++/* Fields in otplayoutextension */ ++#define OTPLAYOUTEXT_FUSE_MASK 0x3FF ++ ++ ++/* Jtagm characteristics that appeared at a given corerev */ ++#define JTAGM_CREV_OLD 10 /* Old command set, 16bit max IR */ ++#define JTAGM_CREV_IRP 22 /* Able to do pause-ir */ ++#define JTAGM_CREV_RTI 28 /* Able to do return-to-idle */ ++ ++/* jtagcmd */ ++#define JCMD_START 0x80000000 ++#define JCMD_BUSY 0x80000000 ++#define JCMD_STATE_MASK 0x60000000 ++#define JCMD_STATE_TLR 0x00000000 /* Test-logic-reset */ ++#define JCMD_STATE_PIR 0x20000000 /* Pause IR */ ++#define JCMD_STATE_PDR 0x40000000 /* Pause DR */ ++#define JCMD_STATE_RTI 0x60000000 /* Run-test-idle */ ++#define JCMD0_ACC_MASK 0x0000f000 ++#define JCMD0_ACC_IRDR 0x00000000 ++#define JCMD0_ACC_DR 0x00001000 ++#define JCMD0_ACC_IR 0x00002000 ++#define JCMD0_ACC_RESET 0x00003000 ++#define JCMD0_ACC_IRPDR 0x00004000 ++#define JCMD0_ACC_PDR 0x00005000 ++#define JCMD0_IRW_MASK 0x00000f00 ++#define JCMD_ACC_MASK 0x000f0000 /* Changes for corerev 11 */ ++#define JCMD_ACC_IRDR 0x00000000 ++#define JCMD_ACC_DR 0x00010000 ++#define JCMD_ACC_IR 0x00020000 ++#define JCMD_ACC_RESET 0x00030000 ++#define JCMD_ACC_IRPDR 0x00040000 ++#define JCMD_ACC_PDR 0x00050000 ++#define JCMD_ACC_PIR 0x00060000 ++#define JCMD_ACC_IRDR_I 0x00070000 /* rev 28: return to run-test-idle */ ++#define JCMD_ACC_DR_I 0x00080000 /* rev 28: return to run-test-idle */ ++#define JCMD_IRW_MASK 0x00001f00 ++#define JCMD_IRW_SHIFT 8 ++#define JCMD_DRW_MASK 0x0000003f ++ ++/* jtagctrl */ ++#define JCTRL_FORCE_CLK 4 /* Force clock */ ++#define JCTRL_EXT_EN 2 /* Enable external targets */ ++#define JCTRL_EN 1 /* Enable Jtag master */ ++ ++/* Fields in clkdiv */ ++#define CLKD_SFLASH 0x0f000000 ++#define CLKD_SFLASH_SHIFT 24 ++#define CLKD_OTP 0x000f0000 ++#define CLKD_OTP_SHIFT 16 ++#define CLKD_JTAG 0x00000f00 ++#define CLKD_JTAG_SHIFT 8 ++#define CLKD_UART 0x000000ff ++ ++#define CLKD2_SROM 0x00000003 ++ ++/* intstatus/intmask */ ++#define CI_GPIO 0x00000001 /* gpio intr */ ++#define CI_EI 0x00000002 /* extif intr (corerev >= 3) */ ++#define CI_TEMP 0x00000004 /* temp. ctrl intr (corerev >= 15) */ ++#define CI_SIRQ 0x00000008 /* serial IRQ intr (corerev >= 15) */ ++#define CI_ECI 0x00000010 /* eci intr (corerev >= 21) */ ++#define CI_PMU 0x00000020 /* pmu intr (corerev >= 21) */ ++#define CI_UART 0x00000040 /* uart intr (corerev >= 21) */ ++#define CI_WDRESET 0x80000000 /* watchdog reset occurred */ ++ ++/* slow_clk_ctl */ ++#define SCC_SS_MASK 0x00000007 /* slow clock source mask */ ++#define SCC_SS_LPO 0x00000000 /* source of slow clock is LPO */ ++#define SCC_SS_XTAL 0x00000001 /* source of slow clock is crystal */ ++#define SCC_SS_PCI 0x00000002 /* source of slow clock is PCI */ ++#define SCC_LF 0x00000200 /* LPOFreqSel, 1: 160Khz, 0: 32KHz */ ++#define SCC_LP 0x00000400 /* LPOPowerDown, 1: LPO is disabled, ++ * 0: LPO is enabled ++ */ ++#define SCC_FS 0x00000800 /* ForceSlowClk, 1: sb/cores running on slow clock, ++ * 0: power logic control ++ */ ++#define SCC_IP 0x00001000 /* IgnorePllOffReq, 1/0: power logic ignores/honors ++ * PLL clock disable requests from core ++ */ ++#define SCC_XC 0x00002000 /* XtalControlEn, 1/0: power logic does/doesn't ++ * disable crystal when appropriate ++ */ ++#define SCC_XP 0x00004000 /* XtalPU (RO), 1/0: crystal running/disabled */ ++#define SCC_CD_MASK 0xffff0000 /* ClockDivider (SlowClk = 1/(4+divisor)) */ ++#define SCC_CD_SHIFT 16 ++ ++/* system_clk_ctl */ ++#define SYCC_IE 0x00000001 /* ILPen: Enable Idle Low Power */ ++#define SYCC_AE 0x00000002 /* ALPen: Enable Active Low Power */ ++#define SYCC_FP 0x00000004 /* ForcePLLOn */ ++#define SYCC_AR 0x00000008 /* Force ALP (or HT if ALPen is not set */ ++#define SYCC_HR 0x00000010 /* Force HT */ ++#define SYCC_CD_MASK 0xffff0000 /* ClkDiv (ILP = 1/(4 * (divisor + 1)) */ ++#define SYCC_CD_SHIFT 16 ++ ++/* Indirect backplane access */ ++#define BPIA_BYTEEN 0x0000000f ++#define BPIA_SZ1 0x00000001 ++#define BPIA_SZ2 0x00000003 ++#define BPIA_SZ4 0x00000007 ++#define BPIA_SZ8 0x0000000f ++#define BPIA_WRITE 0x00000100 ++#define BPIA_START 0x00000200 ++#define BPIA_BUSY 0x00000200 ++#define BPIA_ERROR 0x00000400 ++ ++/* pcmcia/prog/flash_config */ ++#define CF_EN 0x00000001 /* enable */ ++#define CF_EM_MASK 0x0000000e /* mode */ ++#define CF_EM_SHIFT 1 ++#define CF_EM_FLASH 0 /* flash/asynchronous mode */ ++#define CF_EM_SYNC 2 /* synchronous mode */ ++#define CF_EM_PCMCIA 4 /* pcmcia mode */ ++#define CF_DS 0x00000010 /* destsize: 0=8bit, 1=16bit */ ++#define CF_BS 0x00000020 /* byteswap */ ++#define CF_CD_MASK 0x000000c0 /* clock divider */ ++#define CF_CD_SHIFT 6 ++#define CF_CD_DIV2 0x00000000 /* backplane/2 */ ++#define CF_CD_DIV3 0x00000040 /* backplane/3 */ ++#define CF_CD_DIV4 0x00000080 /* backplane/4 */ ++#define CF_CE 0x00000100 /* clock enable */ ++#define CF_SB 0x00000200 /* size/bytestrobe (synch only) */ ++ ++/* pcmcia_memwait */ ++#define PM_W0_MASK 0x0000003f /* waitcount0 */ ++#define PM_W1_MASK 0x00001f00 /* waitcount1 */ ++#define PM_W1_SHIFT 8 ++#define PM_W2_MASK 0x001f0000 /* waitcount2 */ ++#define PM_W2_SHIFT 16 ++#define PM_W3_MASK 0x1f000000 /* waitcount3 */ ++#define PM_W3_SHIFT 24 ++ ++/* pcmcia_attrwait */ ++#define PA_W0_MASK 0x0000003f /* waitcount0 */ ++#define PA_W1_MASK 0x00001f00 /* waitcount1 */ ++#define PA_W1_SHIFT 8 ++#define PA_W2_MASK 0x001f0000 /* waitcount2 */ ++#define PA_W2_SHIFT 16 ++#define PA_W3_MASK 0x1f000000 /* waitcount3 */ ++#define PA_W3_SHIFT 24 ++ ++/* pcmcia_iowait */ ++#define PI_W0_MASK 0x0000003f /* waitcount0 */ ++#define PI_W1_MASK 0x00001f00 /* waitcount1 */ ++#define PI_W1_SHIFT 8 ++#define PI_W2_MASK 0x001f0000 /* waitcount2 */ ++#define PI_W2_SHIFT 16 ++#define PI_W3_MASK 0x1f000000 /* waitcount3 */ ++#define PI_W3_SHIFT 24 ++ ++/* prog_waitcount */ ++#define PW_W0_MASK 0x0000001f /* waitcount0 */ ++#define PW_W1_MASK 0x00001f00 /* waitcount1 */ ++#define PW_W1_SHIFT 8 ++#define PW_W2_MASK 0x001f0000 /* waitcount2 */ ++#define PW_W2_SHIFT 16 ++#define PW_W3_MASK 0x1f000000 /* waitcount3 */ ++#define PW_W3_SHIFT 24 ++ ++#define PW_W0 0x0000000c ++#define PW_W1 0x00000a00 ++#define PW_W2 0x00020000 ++#define PW_W3 0x01000000 ++ ++/* flash_waitcount */ ++#define FW_W0_MASK 0x0000003f /* waitcount0 */ ++#define FW_W1_MASK 0x00001f00 /* waitcount1 */ ++#define FW_W1_SHIFT 8 ++#define FW_W2_MASK 0x001f0000 /* waitcount2 */ ++#define FW_W2_SHIFT 16 ++#define FW_W3_MASK 0x1f000000 /* waitcount3 */ ++#define FW_W3_SHIFT 24 ++ ++/* When Srom support present, fields in sromcontrol */ ++#define SRC_START 0x80000000 ++#define SRC_BUSY 0x80000000 ++#define SRC_OPCODE 0x60000000 ++#define SRC_OP_READ 0x00000000 ++#define SRC_OP_WRITE 0x20000000 ++#define SRC_OP_WRDIS 0x40000000 ++#define SRC_OP_WREN 0x60000000 ++#define SRC_OTPSEL 0x00000010 ++#define SRC_LOCK 0x00000008 ++#define SRC_SIZE_MASK 0x00000006 ++#define SRC_SIZE_1K 0x00000000 ++#define SRC_SIZE_4K 0x00000002 ++#define SRC_SIZE_16K 0x00000004 ++#define SRC_SIZE_SHIFT 1 ++#define SRC_PRESENT 0x00000001 ++ ++/* Fields in pmucontrol */ ++#define PCTL_ILP_DIV_MASK 0xffff0000 ++#define PCTL_ILP_DIV_SHIFT 16 ++#define PCTL_PLL_PLLCTL_UPD 0x00000400 /* rev 2 */ ++#define PCTL_NOILP_ON_WAIT 0x00000200 /* rev 1 */ ++#define PCTL_HT_REQ_EN 0x00000100 ++#define PCTL_ALP_REQ_EN 0x00000080 ++#define PCTL_XTALFREQ_MASK 0x0000007c ++#define PCTL_XTALFREQ_SHIFT 2 ++#define PCTL_ILP_DIV_EN 0x00000002 ++#define PCTL_LPO_SEL 0x00000001 ++ ++/* Fields in clkstretch */ ++#define CSTRETCH_HT 0xffff0000 ++#define CSTRETCH_ALP 0x0000ffff ++ ++/* gpiotimerval */ ++#define GPIO_ONTIME_SHIFT 16 ++ ++/* clockcontrol_n */ ++#define CN_N1_MASK 0x3f /* n1 control */ ++#define CN_N2_MASK 0x3f00 /* n2 control */ ++#define CN_N2_SHIFT 8 ++#define CN_PLLC_MASK 0xf0000 /* pll control */ ++#define CN_PLLC_SHIFT 16 ++ ++/* clockcontrol_sb/pci/uart */ ++#define CC_M1_MASK 0x3f /* m1 control */ ++#define CC_M2_MASK 0x3f00 /* m2 control */ ++#define CC_M2_SHIFT 8 ++#define CC_M3_MASK 0x3f0000 /* m3 control */ ++#define CC_M3_SHIFT 16 ++#define CC_MC_MASK 0x1f000000 /* mux control */ ++#define CC_MC_SHIFT 24 ++ ++/* N3M Clock control magic field values */ ++#define CC_F6_2 0x02 /* A factor of 2 in */ ++#define CC_F6_3 0x03 /* 6-bit fields like */ ++#define CC_F6_4 0x05 /* N1, M1 or M3 */ ++#define CC_F6_5 0x09 ++#define CC_F6_6 0x11 ++#define CC_F6_7 0x21 ++ ++#define CC_F5_BIAS 5 /* 5-bit fields get this added */ ++ ++#define CC_MC_BYPASS 0x08 ++#define CC_MC_M1 0x04 ++#define CC_MC_M1M2 0x02 ++#define CC_MC_M1M2M3 0x01 ++#define CC_MC_M1M3 0x11 ++ ++/* Type 2 Clock control magic field values */ ++#define CC_T2_BIAS 2 /* n1, n2, m1 & m3 bias */ ++#define CC_T2M2_BIAS 3 /* m2 bias */ ++ ++#define CC_T2MC_M1BYP 1 ++#define CC_T2MC_M2BYP 2 ++#define CC_T2MC_M3BYP 4 ++ ++/* Type 6 Clock control magic field values */ ++#define CC_T6_MMASK 1 /* bits of interest in m */ ++#define CC_T6_M0 120000000 /* sb clock for m = 0 */ ++#define CC_T6_M1 100000000 /* sb clock for m = 1 */ ++#define SB2MIPS_T6(sb) (2 * (sb)) ++ ++/* Common clock base */ ++#define CC_CLOCK_BASE1 24000000 /* Half the clock freq */ ++#define CC_CLOCK_BASE2 12500000 /* Alternate crystal on some PLLs */ ++ ++/* Clock control values for 200MHz in 5350 */ ++#define CLKC_5350_N 0x0311 ++#define CLKC_5350_M 0x04020009 ++ ++/* Flash types in the chipcommon capabilities register */ ++#define FLASH_NONE 0x000 /* No flash */ ++#define SFLASH_ST 0x100 /* ST serial flash */ ++#define SFLASH_AT 0x200 /* Atmel serial flash */ ++#define NFLASH 0x300 ++#define PFLASH 0x700 /* Parallel flash */ ++ ++/* Bits in the ExtBus config registers */ ++#define CC_CFG_EN 0x0001 /* Enable */ ++#define CC_CFG_EM_MASK 0x000e /* Extif Mode */ ++#define CC_CFG_EM_ASYNC 0x0000 /* Async/Parallel flash */ ++#define CC_CFG_EM_SYNC 0x0002 /* Synchronous */ ++#define CC_CFG_EM_PCMCIA 0x0004 /* PCMCIA */ ++#define CC_CFG_EM_IDE 0x0006 /* IDE */ ++#define CC_CFG_DS 0x0010 /* Data size, 0=8bit, 1=16bit */ ++#define CC_CFG_CD_MASK 0x00e0 /* Sync: Clock divisor, rev >= 20 */ ++#define CC_CFG_CE 0x0100 /* Sync: Clock enable, rev >= 20 */ ++#define CC_CFG_SB 0x0200 /* Sync: Size/Bytestrobe, rev >= 20 */ ++#define CC_CFG_IS 0x0400 /* Extif Sync Clk Select, rev >= 20 */ ++ ++/* ExtBus address space */ ++#define CC_EB_BASE 0x1a000000 /* Chipc ExtBus base address */ ++#define CC_EB_PCMCIA_MEM 0x1a000000 /* PCMCIA 0 memory base address */ ++#define CC_EB_PCMCIA_IO 0x1a200000 /* PCMCIA 0 I/O base address */ ++#define CC_EB_PCMCIA_CFG 0x1a400000 /* PCMCIA 0 config base address */ ++#define CC_EB_IDE 0x1a800000 /* IDE memory base */ ++#define CC_EB_PCMCIA1_MEM 0x1a800000 /* PCMCIA 1 memory base address */ ++#define CC_EB_PCMCIA1_IO 0x1aa00000 /* PCMCIA 1 I/O base address */ ++#define CC_EB_PCMCIA1_CFG 0x1ac00000 /* PCMCIA 1 config base address */ ++#define CC_EB_PROGIF 0x1b000000 /* ProgIF Async/Sync base address */ ++ ++ ++/* Start/busy bit in flashcontrol */ ++#define SFLASH_OPCODE 0x000000ff ++#define SFLASH_ACTION 0x00000700 ++#define SFLASH_CS_ACTIVE 0x00001000 /* Chip Select Active, rev >= 20 */ ++#define SFLASH_START 0x80000000 ++#define SFLASH_BUSY SFLASH_START ++ ++/* flashcontrol action codes */ ++#define SFLASH_ACT_OPONLY 0x0000 /* Issue opcode only */ ++#define SFLASH_ACT_OP1D 0x0100 /* opcode + 1 data byte */ ++#define SFLASH_ACT_OP3A 0x0200 /* opcode + 3 addr bytes */ ++#define SFLASH_ACT_OP3A1D 0x0300 /* opcode + 3 addr & 1 data bytes */ ++#define SFLASH_ACT_OP3A4D 0x0400 /* opcode + 3 addr & 4 data bytes */ ++#define SFLASH_ACT_OP3A4X4D 0x0500 /* opcode + 3 addr, 4 don't care & 4 data bytes */ ++#define SFLASH_ACT_OP3A1X4D 0x0700 /* opcode + 3 addr, 1 don't care & 4 data bytes */ ++ ++/* flashcontrol action+opcodes for ST flashes */ ++#define SFLASH_ST_WREN 0x0006 /* Write Enable */ ++#define SFLASH_ST_WRDIS 0x0004 /* Write Disable */ ++#define SFLASH_ST_RDSR 0x0105 /* Read Status Register */ ++#define SFLASH_ST_WRSR 0x0101 /* Write Status Register */ ++#define SFLASH_ST_READ 0x0303 /* Read Data Bytes */ ++#define SFLASH_ST_PP 0x0302 /* Page Program */ ++#define SFLASH_ST_SE 0x02d8 /* Sector Erase */ ++#define SFLASH_ST_BE 0x00c7 /* Bulk Erase */ ++#define SFLASH_ST_DP 0x00b9 /* Deep Power-down */ ++#define SFLASH_ST_RES 0x03ab /* Read Electronic Signature */ ++#define SFLASH_ST_CSA 0x1000 /* Keep chip select asserted */ ++#define SFLASH_ST_SSE 0x0220 /* Sub-sector Erase */ ++ ++#define SFLASH_MXIC_RDID 0x0390 /* Read Manufacture ID */ ++#define SFLASH_MXIC_MFID 0xc2 /* MXIC Manufacture ID */ ++ ++/* Status register bits for ST flashes */ ++#define SFLASH_ST_WIP 0x01 /* Write In Progress */ ++#define SFLASH_ST_WEL 0x02 /* Write Enable Latch */ ++#define SFLASH_ST_BP_MASK 0x1c /* Block Protect */ ++#define SFLASH_ST_BP_SHIFT 2 ++#define SFLASH_ST_SRWD 0x80 /* Status Register Write Disable */ ++ ++/* flashcontrol action+opcodes for Atmel flashes */ ++#define SFLASH_AT_READ 0x07e8 ++#define SFLASH_AT_PAGE_READ 0x07d2 ++#define SFLASH_AT_BUF1_READ ++#define SFLASH_AT_BUF2_READ ++#define SFLASH_AT_STATUS 0x01d7 ++#define SFLASH_AT_BUF1_WRITE 0x0384 ++#define SFLASH_AT_BUF2_WRITE 0x0387 ++#define SFLASH_AT_BUF1_ERASE_PROGRAM 0x0283 ++#define SFLASH_AT_BUF2_ERASE_PROGRAM 0x0286 ++#define SFLASH_AT_BUF1_PROGRAM 0x0288 ++#define SFLASH_AT_BUF2_PROGRAM 0x0289 ++#define SFLASH_AT_PAGE_ERASE 0x0281 ++#define SFLASH_AT_BLOCK_ERASE 0x0250 ++#define SFLASH_AT_BUF1_WRITE_ERASE_PROGRAM 0x0382 ++#define SFLASH_AT_BUF2_WRITE_ERASE_PROGRAM 0x0385 ++#define SFLASH_AT_BUF1_LOAD 0x0253 ++#define SFLASH_AT_BUF2_LOAD 0x0255 ++#define SFLASH_AT_BUF1_COMPARE 0x0260 ++#define SFLASH_AT_BUF2_COMPARE 0x0261 ++#define SFLASH_AT_BUF1_REPROGRAM 0x0258 ++#define SFLASH_AT_BUF2_REPROGRAM 0x0259 ++ ++/* Status register bits for Atmel flashes */ ++#define SFLASH_AT_READY 0x80 ++#define SFLASH_AT_MISMATCH 0x40 ++#define SFLASH_AT_ID_MASK 0x38 ++#define SFLASH_AT_ID_SHIFT 3 ++ ++/* SPI register bits, corerev >= 37 */ ++#define GSIO_START 0x80000000 ++#define GSIO_BUSY GSIO_START ++ ++/* ++ * These are the UART port assignments, expressed as offsets from the base ++ * register. These assignments should hold for any serial port based on ++ * a 8250, 16450, or 16550(A). ++ */ ++ ++#define UART_RX 0 /* In: Receive buffer (DLAB=0) */ ++#define UART_TX 0 /* Out: Transmit buffer (DLAB=0) */ ++#define UART_DLL 0 /* Out: Divisor Latch Low (DLAB=1) */ ++#define UART_IER 1 /* In/Out: Interrupt Enable Register (DLAB=0) */ ++#define UART_DLM 1 /* Out: Divisor Latch High (DLAB=1) */ ++#define UART_IIR 2 /* In: Interrupt Identity Register */ ++#define UART_FCR 2 /* Out: FIFO Control Register */ ++#define UART_LCR 3 /* Out: Line Control Register */ ++#define UART_MCR 4 /* Out: Modem Control Register */ ++#define UART_LSR 5 /* In: Line Status Register */ ++#define UART_MSR 6 /* In: Modem Status Register */ ++#define UART_SCR 7 /* I/O: Scratch Register */ ++#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */ ++#define UART_LCR_WLEN8 0x03 /* Word length: 8 bits */ ++#define UART_MCR_OUT2 0x08 /* MCR GPIO out 2 */ ++#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */ ++#define UART_LSR_RX_FIFO 0x80 /* Receive FIFO error */ ++#define UART_LSR_TDHR 0x40 /* Data-hold-register empty */ ++#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */ ++#define UART_LSR_BREAK 0x10 /* Break interrupt */ ++#define UART_LSR_FRAMING 0x08 /* Framing error */ ++#define UART_LSR_PARITY 0x04 /* Parity error */ ++#define UART_LSR_OVERRUN 0x02 /* Overrun error */ ++#define UART_LSR_RXRDY 0x01 /* Receiver ready */ ++#define UART_FCR_FIFO_ENABLE 1 /* FIFO control register bit controlling FIFO enable/disable */ ++ ++/* Interrupt Identity Register (IIR) bits */ ++#define UART_IIR_FIFO_MASK 0xc0 /* IIR FIFO disable/enabled mask */ ++#define UART_IIR_INT_MASK 0xf /* IIR interrupt ID source */ ++#define UART_IIR_MDM_CHG 0x0 /* Modem status changed */ ++#define UART_IIR_NOINT 0x1 /* No interrupt pending */ ++#define UART_IIR_THRE 0x2 /* THR empty */ ++#define UART_IIR_RCVD_DATA 0x4 /* Received data available */ ++#define UART_IIR_RCVR_STATUS 0x6 /* Receiver status */ ++#define UART_IIR_CHAR_TIME 0xc /* Character time */ ++ ++/* Interrupt Enable Register (IER) bits */ ++#define UART_IER_EDSSI 8 /* enable modem status interrupt */ ++#define UART_IER_ELSI 4 /* enable receiver line status interrupt */ ++#define UART_IER_ETBEI 2 /* enable transmitter holding register empty interrupt */ ++#define UART_IER_ERBFI 1 /* enable data available interrupt */ ++ ++/* pmustatus */ ++#define PST_EXTLPOAVAIL 0x0100 ++#define PST_WDRESET 0x0080 ++#define PST_INTPEND 0x0040 ++#define PST_SBCLKST 0x0030 ++#define PST_SBCLKST_ILP 0x0010 ++#define PST_SBCLKST_ALP 0x0020 ++#define PST_SBCLKST_HT 0x0030 ++#define PST_ALPAVAIL 0x0008 ++#define PST_HTAVAIL 0x0004 ++#define PST_RESINIT 0x0003 ++ ++/* pmucapabilities */ ++#define PCAP_REV_MASK 0x000000ff ++#define PCAP_RC_MASK 0x00001f00 ++#define PCAP_RC_SHIFT 8 ++#define PCAP_TC_MASK 0x0001e000 ++#define PCAP_TC_SHIFT 13 ++#define PCAP_PC_MASK 0x001e0000 ++#define PCAP_PC_SHIFT 17 ++#define PCAP_VC_MASK 0x01e00000 ++#define PCAP_VC_SHIFT 21 ++#define PCAP_CC_MASK 0x1e000000 ++#define PCAP_CC_SHIFT 25 ++#define PCAP5_PC_MASK 0x003e0000 /* PMU corerev >= 5 */ ++#define PCAP5_PC_SHIFT 17 ++#define PCAP5_VC_MASK 0x07c00000 ++#define PCAP5_VC_SHIFT 22 ++#define PCAP5_CC_MASK 0xf8000000 ++#define PCAP5_CC_SHIFT 27 ++ ++/* PMU Resource Request Timer registers */ ++/* This is based on PmuRev0 */ ++#define PRRT_TIME_MASK 0x03ff ++#define PRRT_INTEN 0x0400 ++#define PRRT_REQ_ACTIVE 0x0800 ++#define PRRT_ALP_REQ 0x1000 ++#define PRRT_HT_REQ 0x2000 ++#define PRRT_HQ_REQ 0x4000 ++ ++/* PMU resource bit position */ ++#define PMURES_BIT(bit) (1 << (bit)) ++ ++/* PMU resource number limit */ ++#define PMURES_MAX_RESNUM 30 ++ ++/* PMU chip control0 register */ ++#define PMU_CHIPCTL0 0 ++ ++/* clock req types */ ++#define PMU_CC1_CLKREQ_TYPE_SHIFT 19 ++#define PMU_CC1_CLKREQ_TYPE_MASK (1 << PMU_CC1_CLKREQ_TYPE_SHIFT) ++ ++#define CLKREQ_TYPE_CONFIG_OPENDRAIN 0 ++#define CLKREQ_TYPE_CONFIG_PUSHPULL 1 ++ ++/* PMU chip control1 register */ ++#define PMU_CHIPCTL1 1 ++#define PMU_CC1_RXC_DLL_BYPASS 0x00010000 ++ ++#define PMU_CC1_IF_TYPE_MASK 0x00000030 ++#define PMU_CC1_IF_TYPE_RMII 0x00000000 ++#define PMU_CC1_IF_TYPE_MII 0x00000010 ++#define PMU_CC1_IF_TYPE_RGMII 0x00000020 ++ ++#define PMU_CC1_SW_TYPE_MASK 0x000000c0 ++#define PMU_CC1_SW_TYPE_EPHY 0x00000000 ++#define PMU_CC1_SW_TYPE_EPHYMII 0x00000040 ++#define PMU_CC1_SW_TYPE_EPHYRMII 0x00000080 ++#define PMU_CC1_SW_TYPE_RGMII 0x000000c0 ++ ++/* PMU chip control2 register */ ++#define PMU_CHIPCTL2 2 ++ ++/* PMU chip control3 register */ ++#define PMU_CHIPCTL3 3 ++ ++#define PMU_CC3_ENABLE_SDIO_WAKEUP_SHIFT 19 ++#define PMU_CC3_ENABLE_RF_SHIFT 22 ++#define PMU_CC3_RF_DISABLE_IVALUE_SHIFT 23 ++ ++ ++/* PMU corerev and chip specific PLL controls. ++ * PMU_PLL_XX where is PMU corerev and is an arbitrary number ++ * to differentiate different PLLs controlled by the same PMU rev. ++ */ ++/* pllcontrol registers */ ++/* PDIV, div_phy, div_arm, div_adc, dith_sel, ioff, kpd_scale, lsb_sel, mash_sel, lf_c & lf_r */ ++#define PMU0_PLL0_PLLCTL0 0 ++#define PMU0_PLL0_PC0_PDIV_MASK 1 ++#define PMU0_PLL0_PC0_PDIV_FREQ 25000 ++#define PMU0_PLL0_PC0_DIV_ARM_MASK 0x00000038 ++#define PMU0_PLL0_PC0_DIV_ARM_SHIFT 3 ++#define PMU0_PLL0_PC0_DIV_ARM_BASE 8 ++ ++/* PC0_DIV_ARM for PLLOUT_ARM */ ++#define PMU0_PLL0_PC0_DIV_ARM_110MHZ 0 ++#define PMU0_PLL0_PC0_DIV_ARM_97_7MHZ 1 ++#define PMU0_PLL0_PC0_DIV_ARM_88MHZ 2 ++#define PMU0_PLL0_PC0_DIV_ARM_80MHZ 3 /* Default */ ++#define PMU0_PLL0_PC0_DIV_ARM_73_3MHZ 4 ++#define PMU0_PLL0_PC0_DIV_ARM_67_7MHZ 5 ++#define PMU0_PLL0_PC0_DIV_ARM_62_9MHZ 6 ++#define PMU0_PLL0_PC0_DIV_ARM_58_6MHZ 7 ++ ++/* Wildcard base, stop_mod, en_lf_tp, en_cal & lf_r2 */ ++#define PMU0_PLL0_PLLCTL1 1 ++#define PMU0_PLL0_PC1_WILD_INT_MASK 0xf0000000 ++#define PMU0_PLL0_PC1_WILD_INT_SHIFT 28 ++#define PMU0_PLL0_PC1_WILD_FRAC_MASK 0x0fffff00 ++#define PMU0_PLL0_PC1_WILD_FRAC_SHIFT 8 ++#define PMU0_PLL0_PC1_STOP_MOD 0x00000040 ++ ++/* Wildcard base, vco_calvar, vco_swc, vco_var_selref, vso_ical & vco_sel_avdd */ ++#define PMU0_PLL0_PLLCTL2 2 ++#define PMU0_PLL0_PC2_WILD_INT_MASK 0xf ++#define PMU0_PLL0_PC2_WILD_INT_SHIFT 4 ++ ++/* pllcontrol registers */ ++/* ndiv_pwrdn, pwrdn_ch, refcomp_pwrdn, dly_ch, p1div, p2div, _bypass_sdmod */ ++#define PMU1_PLL0_PLLCTL0 0 ++#define PMU1_PLL0_PC0_P1DIV_MASK 0x00f00000 ++#define PMU1_PLL0_PC0_P1DIV_SHIFT 20 ++#define PMU1_PLL0_PC0_P2DIV_MASK 0x0f000000 ++#define PMU1_PLL0_PC0_P2DIV_SHIFT 24 ++ ++/* mdiv */ ++#define PMU1_PLL0_PLLCTL1 1 ++#define PMU1_PLL0_PC1_M1DIV_MASK 0x000000ff ++#define PMU1_PLL0_PC1_M1DIV_SHIFT 0 ++#define PMU1_PLL0_PC1_M2DIV_MASK 0x0000ff00 ++#define PMU1_PLL0_PC1_M2DIV_SHIFT 8 ++#define PMU1_PLL0_PC1_M3DIV_MASK 0x00ff0000 ++#define PMU1_PLL0_PC1_M3DIV_SHIFT 16 ++#define PMU1_PLL0_PC1_M4DIV_MASK 0xff000000 ++#define PMU1_PLL0_PC1_M4DIV_SHIFT 24 ++#define PMU1_PLL0_PC1_M4DIV_BY_9 9 ++#define PMU1_PLL0_PC1_M4DIV_BY_18 0x12 ++#define PMU1_PLL0_PC1_M4DIV_BY_36 0x24 ++ ++#define DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT 8 ++#define DOT11MAC_880MHZ_CLK_DIVISOR_MASK (0xFF << DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT) ++#define DOT11MAC_880MHZ_CLK_DIVISOR_VAL (0xE << DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT) ++ ++/* mdiv, ndiv_dither_mfb, ndiv_mode, ndiv_int */ ++#define PMU1_PLL0_PLLCTL2 2 ++#define PMU1_PLL0_PC2_M5DIV_MASK 0x000000ff ++#define PMU1_PLL0_PC2_M5DIV_SHIFT 0 ++#define PMU1_PLL0_PC2_M5DIV_BY_12 0xc ++#define PMU1_PLL0_PC2_M5DIV_BY_18 0x12 ++#define PMU1_PLL0_PC2_M5DIV_BY_36 0x24 ++#define PMU1_PLL0_PC2_M6DIV_MASK 0x0000ff00 ++#define PMU1_PLL0_PC2_M6DIV_SHIFT 8 ++#define PMU1_PLL0_PC2_M6DIV_BY_18 0x12 ++#define PMU1_PLL0_PC2_M6DIV_BY_36 0x24 ++#define PMU1_PLL0_PC2_NDIV_MODE_MASK 0x000e0000 ++#define PMU1_PLL0_PC2_NDIV_MODE_SHIFT 17 ++#define PMU1_PLL0_PC2_NDIV_MODE_MASH 1 ++#define PMU1_PLL0_PC2_NDIV_MODE_MFB 2 /* recommended for 4319 */ ++#define PMU1_PLL0_PC2_NDIV_INT_MASK 0x1ff00000 ++#define PMU1_PLL0_PC2_NDIV_INT_SHIFT 20 ++ ++/* ndiv_frac */ ++#define PMU1_PLL0_PLLCTL3 3 ++#define PMU1_PLL0_PC3_NDIV_FRAC_MASK 0x00ffffff ++#define PMU1_PLL0_PC3_NDIV_FRAC_SHIFT 0 ++ ++/* pll_ctrl */ ++#define PMU1_PLL0_PLLCTL4 4 ++ ++/* pll_ctrl, vco_rng, clkdrive_ch */ ++#define PMU1_PLL0_PLLCTL5 5 ++#define PMU1_PLL0_PC5_CLK_DRV_MASK 0xffffff00 ++#define PMU1_PLL0_PC5_CLK_DRV_SHIFT 8 ++ ++/* PMU rev 2 control words */ ++#define PMU2_PHY_PLL_PLLCTL 4 ++#define PMU2_SI_PLL_PLLCTL 10 ++ ++/* PMU rev 2 */ ++/* pllcontrol registers */ ++/* ndiv_pwrdn, pwrdn_ch, refcomp_pwrdn, dly_ch, p1div, p2div, _bypass_sdmod */ ++#define PMU2_PLL_PLLCTL0 0 ++#define PMU2_PLL_PC0_P1DIV_MASK 0x00f00000 ++#define PMU2_PLL_PC0_P1DIV_SHIFT 20 ++#define PMU2_PLL_PC0_P2DIV_MASK 0x0f000000 ++#define PMU2_PLL_PC0_P2DIV_SHIFT 24 ++ ++/* mdiv */ ++#define PMU2_PLL_PLLCTL1 1 ++#define PMU2_PLL_PC1_M1DIV_MASK 0x000000ff ++#define PMU2_PLL_PC1_M1DIV_SHIFT 0 ++#define PMU2_PLL_PC1_M2DIV_MASK 0x0000ff00 ++#define PMU2_PLL_PC1_M2DIV_SHIFT 8 ++#define PMU2_PLL_PC1_M3DIV_MASK 0x00ff0000 ++#define PMU2_PLL_PC1_M3DIV_SHIFT 16 ++#define PMU2_PLL_PC1_M4DIV_MASK 0xff000000 ++#define PMU2_PLL_PC1_M4DIV_SHIFT 24 ++ ++/* mdiv, ndiv_dither_mfb, ndiv_mode, ndiv_int */ ++#define PMU2_PLL_PLLCTL2 2 ++#define PMU2_PLL_PC2_M5DIV_MASK 0x000000ff ++#define PMU2_PLL_PC2_M5DIV_SHIFT 0 ++#define PMU2_PLL_PC2_M6DIV_MASK 0x0000ff00 ++#define PMU2_PLL_PC2_M6DIV_SHIFT 8 ++#define PMU2_PLL_PC2_NDIV_MODE_MASK 0x000e0000 ++#define PMU2_PLL_PC2_NDIV_MODE_SHIFT 17 ++#define PMU2_PLL_PC2_NDIV_INT_MASK 0x1ff00000 ++#define PMU2_PLL_PC2_NDIV_INT_SHIFT 20 ++ ++/* ndiv_frac */ ++#define PMU2_PLL_PLLCTL3 3 ++#define PMU2_PLL_PC3_NDIV_FRAC_MASK 0x00ffffff ++#define PMU2_PLL_PC3_NDIV_FRAC_SHIFT 0 ++ ++/* pll_ctrl */ ++#define PMU2_PLL_PLLCTL4 4 ++ ++/* pll_ctrl, vco_rng, clkdrive_ch */ ++#define PMU2_PLL_PLLCTL5 5 ++#define PMU2_PLL_PC5_CLKDRIVE_CH1_MASK 0x00000f00 ++#define PMU2_PLL_PC5_CLKDRIVE_CH1_SHIFT 8 ++#define PMU2_PLL_PC5_CLKDRIVE_CH2_MASK 0x0000f000 ++#define PMU2_PLL_PC5_CLKDRIVE_CH2_SHIFT 12 ++#define PMU2_PLL_PC5_CLKDRIVE_CH3_MASK 0x000f0000 ++#define PMU2_PLL_PC5_CLKDRIVE_CH3_SHIFT 16 ++#define PMU2_PLL_PC5_CLKDRIVE_CH4_MASK 0x00f00000 ++#define PMU2_PLL_PC5_CLKDRIVE_CH4_SHIFT 20 ++#define PMU2_PLL_PC5_CLKDRIVE_CH5_MASK 0x0f000000 ++#define PMU2_PLL_PC5_CLKDRIVE_CH5_SHIFT 24 ++#define PMU2_PLL_PC5_CLKDRIVE_CH6_MASK 0xf0000000 ++#define PMU2_PLL_PC5_CLKDRIVE_CH6_SHIFT 28 ++ ++/* PMU rev 5 (& 6) */ ++#define PMU5_PLL_P1P2_OFF 0 ++#define PMU5_PLL_P1_MASK 0x0f000000 ++#define PMU5_PLL_P1_SHIFT 24 ++#define PMU5_PLL_P2_MASK 0x00f00000 ++#define PMU5_PLL_P2_SHIFT 20 ++#define PMU5_PLL_M14_OFF 1 ++#define PMU5_PLL_MDIV_MASK 0x000000ff ++#define PMU5_PLL_MDIV_WIDTH 8 ++#define PMU5_PLL_NM5_OFF 2 ++#define PMU5_PLL_NDIV_MASK 0xfff00000 ++#define PMU5_PLL_NDIV_SHIFT 20 ++#define PMU5_PLL_NDIV_MODE_MASK 0x000e0000 ++#define PMU5_PLL_NDIV_MODE_SHIFT 17 ++#define PMU5_PLL_FMAB_OFF 3 ++#define PMU5_PLL_MRAT_MASK 0xf0000000 ++#define PMU5_PLL_MRAT_SHIFT 28 ++#define PMU5_PLL_ABRAT_MASK 0x08000000 ++#define PMU5_PLL_ABRAT_SHIFT 27 ++#define PMU5_PLL_FDIV_MASK 0x07ffffff ++#define PMU5_PLL_PLLCTL_OFF 4 ++#define PMU5_PLL_PCHI_OFF 5 ++#define PMU5_PLL_PCHI_MASK 0x0000003f ++ ++/* pmu XtalFreqRatio */ ++#define PMU_XTALFREQ_REG_ILPCTR_MASK 0x00001FFF ++#define PMU_XTALFREQ_REG_MEASURE_MASK 0x80000000 ++#define PMU_XTALFREQ_REG_MEASURE_SHIFT 31 ++ ++/* Divider allocation in 4716/47162/5356/5357 */ ++#define PMU5_MAINPLL_CPU 1 ++#define PMU5_MAINPLL_MEM 2 ++#define PMU5_MAINPLL_SI 3 ++ ++/* 4706 PMU */ ++#define PMU4706_MAINPLL_PLL0 0 ++#define PMU6_4706_PROCPLL_OFF 4 /* The CPU PLL */ ++#define PMU6_4706_PROC_P2DIV_MASK 0x000f0000 ++#define PMU6_4706_PROC_P2DIV_SHIFT 16 ++#define PMU6_4706_PROC_P1DIV_MASK 0x0000f000 ++#define PMU6_4706_PROC_P1DIV_SHIFT 12 ++#define PMU6_4706_PROC_NDIV_INT_MASK 0x00000ff8 ++#define PMU6_4706_PROC_NDIV_INT_SHIFT 3 ++#define PMU6_4706_PROC_NDIV_MODE_MASK 0x00000007 ++#define PMU6_4706_PROC_NDIV_MODE_SHIFT 0 ++ ++#define PMU7_PLL_PLLCTL7 7 ++#define PMU7_PLL_CTL7_M4DIV_MASK 0xff000000 ++#define PMU7_PLL_CTL7_M4DIV_SHIFT 24 ++#define PMU7_PLL_CTL7_M4DIV_BY_6 6 ++#define PMU7_PLL_CTL7_M4DIV_BY_12 0xc ++#define PMU7_PLL_CTL7_M4DIV_BY_24 0x18 ++#define PMU7_PLL_PLLCTL8 8 ++#define PMU7_PLL_CTL8_M5DIV_MASK 0x000000ff ++#define PMU7_PLL_CTL8_M5DIV_SHIFT 0 ++#define PMU7_PLL_CTL8_M5DIV_BY_8 8 ++#define PMU7_PLL_CTL8_M5DIV_BY_12 0xc ++#define PMU7_PLL_CTL8_M5DIV_BY_24 0x18 ++#define PMU7_PLL_CTL8_M6DIV_MASK 0x0000ff00 ++#define PMU7_PLL_CTL8_M6DIV_SHIFT 8 ++#define PMU7_PLL_CTL8_M6DIV_BY_12 0xc ++#define PMU7_PLL_CTL8_M6DIV_BY_24 0x18 ++#define PMU7_PLL_PLLCTL11 11 ++#define PMU7_PLL_PLLCTL11_MASK 0xffffff00 ++#define PMU7_PLL_PLLCTL11_VAL 0x22222200 ++ ++/* PMU rev 15 */ ++#define PMU15_PLL_PLLCTL0 0 ++#define PMU15_PLL_PC0_CLKSEL_MASK 0x00000003 ++#define PMU15_PLL_PC0_CLKSEL_SHIFT 0 ++#define PMU15_PLL_PC0_FREQTGT_MASK 0x003FFFFC ++#define PMU15_PLL_PC0_FREQTGT_SHIFT 2 ++#define PMU15_PLL_PC0_PRESCALE_MASK 0x00C00000 ++#define PMU15_PLL_PC0_PRESCALE_SHIFT 22 ++#define PMU15_PLL_PC0_KPCTRL_MASK 0x07000000 ++#define PMU15_PLL_PC0_KPCTRL_SHIFT 24 ++#define PMU15_PLL_PC0_FCNTCTRL_MASK 0x38000000 ++#define PMU15_PLL_PC0_FCNTCTRL_SHIFT 27 ++#define PMU15_PLL_PC0_FDCMODE_MASK 0x40000000 ++#define PMU15_PLL_PC0_FDCMODE_SHIFT 30 ++#define PMU15_PLL_PC0_CTRLBIAS_MASK 0x80000000 ++#define PMU15_PLL_PC0_CTRLBIAS_SHIFT 31 ++ ++#define PMU15_PLL_PLLCTL1 1 ++#define PMU15_PLL_PC1_BIAS_CTLM_MASK 0x00000060 ++#define PMU15_PLL_PC1_BIAS_CTLM_SHIFT 5 ++#define PMU15_PLL_PC1_BIAS_CTLM_RST_MASK 0x00000040 ++#define PMU15_PLL_PC1_BIAS_CTLM_RST_SHIFT 6 ++#define PMU15_PLL_PC1_BIAS_SS_DIVR_MASK 0x0001FF80 ++#define PMU15_PLL_PC1_BIAS_SS_DIVR_SHIFT 7 ++#define PMU15_PLL_PC1_BIAS_SS_RSTVAL_MASK 0x03FE0000 ++#define PMU15_PLL_PC1_BIAS_SS_RSTVAL_SHIFT 17 ++#define PMU15_PLL_PC1_BIAS_INTG_BW_MASK 0x0C000000 ++#define PMU15_PLL_PC1_BIAS_INTG_BW_SHIFT 26 ++#define PMU15_PLL_PC1_BIAS_INTG_BYP_MASK 0x10000000 ++#define PMU15_PLL_PC1_BIAS_INTG_BYP_SHIFT 28 ++#define PMU15_PLL_PC1_OPENLP_EN_MASK 0x40000000 ++#define PMU15_PLL_PC1_OPENLP_EN_SHIFT 30 ++ ++#define PMU15_PLL_PLLCTL2 2 ++#define PMU15_PLL_PC2_CTEN_MASK 0x00000001 ++#define PMU15_PLL_PC2_CTEN_SHIFT 0 ++ ++#define PMU15_PLL_PLLCTL3 3 ++#define PMU15_PLL_PC3_DITHER_EN_MASK 0x00000001 ++#define PMU15_PLL_PC3_DITHER_EN_SHIFT 0 ++#define PMU15_PLL_PC3_DCOCTLSP_MASK 0xFE000000 ++#define PMU15_PLL_PC3_DCOCTLSP_SHIFT 25 ++#define PMU15_PLL_PC3_DCOCTLSP_DIV2EN_MASK 0x01 ++#define PMU15_PLL_PC3_DCOCTLSP_DIV2EN_SHIFT 0 ++#define PMU15_PLL_PC3_DCOCTLSP_CH0EN_MASK 0x02 ++#define PMU15_PLL_PC3_DCOCTLSP_CH0EN_SHIFT 1 ++#define PMU15_PLL_PC3_DCOCTLSP_CH1EN_MASK 0x04 ++#define PMU15_PLL_PC3_DCOCTLSP_CH1EN_SHIFT 2 ++#define PMU15_PLL_PC3_DCOCTLSP_CH0SEL_MASK 0x18 ++#define PMU15_PLL_PC3_DCOCTLSP_CH0SEL_SHIFT 3 ++#define PMU15_PLL_PC3_DCOCTLSP_CH1SEL_MASK 0x60 ++#define PMU15_PLL_PC3_DCOCTLSP_CH1SEL_SHIFT 5 ++#define PMU15_PLL_PC3_DCOCTLSP_CHSEL_OUTP_DIV1 0 ++#define PMU15_PLL_PC3_DCOCTLSP_CHSEL_OUTP_DIV2 1 ++#define PMU15_PLL_PC3_DCOCTLSP_CHSEL_OUTP_DIV3 2 ++#define PMU15_PLL_PC3_DCOCTLSP_CHSEL_OUTP_DIV5 3 ++ ++#define PMU15_PLL_PLLCTL4 4 ++#define PMU15_PLL_PC4_FLLCLK1_DIV_MASK 0x00000007 ++#define PMU15_PLL_PC4_FLLCLK1_DIV_SHIFT 0 ++#define PMU15_PLL_PC4_FLLCLK2_DIV_MASK 0x00000038 ++#define PMU15_PLL_PC4_FLLCLK2_DIV_SHIFT 3 ++#define PMU15_PLL_PC4_FLLCLK3_DIV_MASK 0x000001C0 ++#define PMU15_PLL_PC4_FLLCLK3_DIV_SHIFT 6 ++#define PMU15_PLL_PC4_DBGMODE_MASK 0x00000E00 ++#define PMU15_PLL_PC4_DBGMODE_SHIFT 9 ++#define PMU15_PLL_PC4_FLL480_CTLSP_LK_MASK 0x00001000 ++#define PMU15_PLL_PC4_FLL480_CTLSP_LK_SHIFT 12 ++#define PMU15_PLL_PC4_FLL480_CTLSP_MASK 0x000FE000 ++#define PMU15_PLL_PC4_FLL480_CTLSP_SHIFT 13 ++#define PMU15_PLL_PC4_DINPOL_MASK 0x00100000 ++#define PMU15_PLL_PC4_DINPOL_SHIFT 20 ++#define PMU15_PLL_PC4_CLKOUT_PD_MASK 0x00200000 ++#define PMU15_PLL_PC4_CLKOUT_PD_SHIFT 21 ++#define PMU15_PLL_PC4_CLKDIV2_PD_MASK 0x00400000 ++#define PMU15_PLL_PC4_CLKDIV2_PD_SHIFT 22 ++#define PMU15_PLL_PC4_CLKDIV4_PD_MASK 0x00800000 ++#define PMU15_PLL_PC4_CLKDIV4_PD_SHIFT 23 ++#define PMU15_PLL_PC4_CLKDIV8_PD_MASK 0x01000000 ++#define PMU15_PLL_PC4_CLKDIV8_PD_SHIFT 24 ++#define PMU15_PLL_PC4_CLKDIV16_PD_MASK 0x02000000 ++#define PMU15_PLL_PC4_CLKDIV16_PD_SHIFT 25 ++#define PMU15_PLL_PC4_TEST_EN_MASK 0x04000000 ++#define PMU15_PLL_PC4_TEST_EN_SHIFT 26 ++ ++#define PMU15_PLL_PLLCTL5 5 ++#define PMU15_PLL_PC5_FREQTGT_MASK 0x000FFFFF ++#define PMU15_PLL_PC5_FREQTGT_SHIFT 0 ++#define PMU15_PLL_PC5_DCOCTLSP_MASK 0x07F00000 ++#define PMU15_PLL_PC5_DCOCTLSP_SHIFT 20 ++#define PMU15_PLL_PC5_PRESCALE_MASK 0x18000000 ++#define PMU15_PLL_PC5_PRESCALE_SHIFT 27 ++ ++#define PMU15_PLL_PLLCTL6 6 ++#define PMU15_PLL_PC6_FREQTGT_MASK 0x000FFFFF ++#define PMU15_PLL_PC6_FREQTGT_SHIFT 0 ++#define PMU15_PLL_PC6_DCOCTLSP_MASK 0x07F00000 ++#define PMU15_PLL_PC6_DCOCTLSP_SHIFT 20 ++#define PMU15_PLL_PC6_PRESCALE_MASK 0x18000000 ++#define PMU15_PLL_PC6_PRESCALE_SHIFT 27 ++ ++#define PMU15_FREQTGT_480_DEFAULT 0x19AB1 ++#define PMU15_FREQTGT_492_DEFAULT 0x1A4F5 ++#define PMU15_ARM_96MHZ 96000000 /* 96 Mhz */ ++#define PMU15_ARM_98MHZ 98400000 /* 98.4 Mhz */ ++#define PMU15_ARM_97MHZ 97000000 /* 97 Mhz */ ++ ++ ++#define PMU17_PLLCTL2_NDIVTYPE_MASK 0x00000070 ++#define PMU17_PLLCTL2_NDIVTYPE_SHIFT 4 ++ ++#define PMU17_PLLCTL2_NDIV_MODE_INT 0 ++#define PMU17_PLLCTL2_NDIV_MODE_INT1B8 1 ++#define PMU17_PLLCTL2_NDIV_MODE_MASH111 2 ++#define PMU17_PLLCTL2_NDIV_MODE_MASH111B8 3 ++ ++#define PMU17_PLLCTL0_BBPLL_PWRDWN 0 ++#define PMU17_PLLCTL0_BBPLL_DRST 3 ++#define PMU17_PLLCTL0_BBPLL_DISBL_CLK 8 ++ ++/* PLL usage in 4716/47162 */ ++#define PMU4716_MAINPLL_PLL0 12 ++ ++/* PLL usage in 5356/5357 */ ++#define PMU5356_MAINPLL_PLL0 0 ++#define PMU5357_MAINPLL_PLL0 0 ++ ++/* 4716/47162 resources */ ++#define RES4716_PROC_PLL_ON 0x00000040 ++#define RES4716_PROC_HT_AVAIL 0x00000080 ++ ++/* 4716/4717/4718 Chip specific ChipControl register bits */ ++#define CCTRL_471X_I2S_PINS_ENABLE 0x0080 /* I2S pins off by default, shared w/ pflash */ ++ ++/* 5357 Chip specific ChipControl register bits */ ++/* 2nd - 32-bit reg */ ++#define CCTRL_5357_I2S_PINS_ENABLE 0x00040000 /* I2S pins enable */ ++#define CCTRL_5357_I2CSPI_PINS_ENABLE 0x00080000 /* I2C/SPI pins enable */ ++ ++/* 5354 resources */ ++#define RES5354_EXT_SWITCHER_PWM 0 /* 0x00001 */ ++#define RES5354_BB_SWITCHER_PWM 1 /* 0x00002 */ ++#define RES5354_BB_SWITCHER_BURST 2 /* 0x00004 */ ++#define RES5354_BB_EXT_SWITCHER_BURST 3 /* 0x00008 */ ++#define RES5354_ILP_REQUEST 4 /* 0x00010 */ ++#define RES5354_RADIO_SWITCHER_PWM 5 /* 0x00020 */ ++#define RES5354_RADIO_SWITCHER_BURST 6 /* 0x00040 */ ++#define RES5354_ROM_SWITCH 7 /* 0x00080 */ ++#define RES5354_PA_REF_LDO 8 /* 0x00100 */ ++#define RES5354_RADIO_LDO 9 /* 0x00200 */ ++#define RES5354_AFE_LDO 10 /* 0x00400 */ ++#define RES5354_PLL_LDO 11 /* 0x00800 */ ++#define RES5354_BG_FILTBYP 12 /* 0x01000 */ ++#define RES5354_TX_FILTBYP 13 /* 0x02000 */ ++#define RES5354_RX_FILTBYP 14 /* 0x04000 */ ++#define RES5354_XTAL_PU 15 /* 0x08000 */ ++#define RES5354_XTAL_EN 16 /* 0x10000 */ ++#define RES5354_BB_PLL_FILTBYP 17 /* 0x20000 */ ++#define RES5354_RF_PLL_FILTBYP 18 /* 0x40000 */ ++#define RES5354_BB_PLL_PU 19 /* 0x80000 */ ++ ++/* 5357 Chip specific ChipControl register bits */ ++#define CCTRL5357_EXTPA (1<<14) /* extPA in ChipControl 1, bit 14 */ ++#define CCTRL5357_ANT_MUX_2o3 (1<<15) /* 2o3 in ChipControl 1, bit 15 */ ++#define CCTRL5357_NFLASH (1<<16) /* Nandflash in ChipControl 1, bit 16 */ ++ ++/* 43217 Chip specific ChipControl register bits */ ++#define CCTRL43217_EXTPA_C0 (1<<13) /* core0 extPA in ChipControl 1, bit 13 */ ++#define CCTRL43217_EXTPA_C1 (1<<8) /* core1 extPA in ChipControl 1, bit 8 */ ++ ++/* 4328 resources */ ++#define RES4328_EXT_SWITCHER_PWM 0 /* 0x00001 */ ++#define RES4328_BB_SWITCHER_PWM 1 /* 0x00002 */ ++#define RES4328_BB_SWITCHER_BURST 2 /* 0x00004 */ ++#define RES4328_BB_EXT_SWITCHER_BURST 3 /* 0x00008 */ ++#define RES4328_ILP_REQUEST 4 /* 0x00010 */ ++#define RES4328_RADIO_SWITCHER_PWM 5 /* 0x00020 */ ++#define RES4328_RADIO_SWITCHER_BURST 6 /* 0x00040 */ ++#define RES4328_ROM_SWITCH 7 /* 0x00080 */ ++#define RES4328_PA_REF_LDO 8 /* 0x00100 */ ++#define RES4328_RADIO_LDO 9 /* 0x00200 */ ++#define RES4328_AFE_LDO 10 /* 0x00400 */ ++#define RES4328_PLL_LDO 11 /* 0x00800 */ ++#define RES4328_BG_FILTBYP 12 /* 0x01000 */ ++#define RES4328_TX_FILTBYP 13 /* 0x02000 */ ++#define RES4328_RX_FILTBYP 14 /* 0x04000 */ ++#define RES4328_XTAL_PU 15 /* 0x08000 */ ++#define RES4328_XTAL_EN 16 /* 0x10000 */ ++#define RES4328_BB_PLL_FILTBYP 17 /* 0x20000 */ ++#define RES4328_RF_PLL_FILTBYP 18 /* 0x40000 */ ++#define RES4328_BB_PLL_PU 19 /* 0x80000 */ ++ ++/* 4325 A0/A1 resources */ ++#define RES4325_BUCK_BOOST_BURST 0 /* 0x00000001 */ ++#define RES4325_CBUCK_BURST 1 /* 0x00000002 */ ++#define RES4325_CBUCK_PWM 2 /* 0x00000004 */ ++#define RES4325_CLDO_CBUCK_BURST 3 /* 0x00000008 */ ++#define RES4325_CLDO_CBUCK_PWM 4 /* 0x00000010 */ ++#define RES4325_BUCK_BOOST_PWM 5 /* 0x00000020 */ ++#define RES4325_ILP_REQUEST 6 /* 0x00000040 */ ++#define RES4325_ABUCK_BURST 7 /* 0x00000080 */ ++#define RES4325_ABUCK_PWM 8 /* 0x00000100 */ ++#define RES4325_LNLDO1_PU 9 /* 0x00000200 */ ++#define RES4325_OTP_PU 10 /* 0x00000400 */ ++#define RES4325_LNLDO3_PU 11 /* 0x00000800 */ ++#define RES4325_LNLDO4_PU 12 /* 0x00001000 */ ++#define RES4325_XTAL_PU 13 /* 0x00002000 */ ++#define RES4325_ALP_AVAIL 14 /* 0x00004000 */ ++#define RES4325_RX_PWRSW_PU 15 /* 0x00008000 */ ++#define RES4325_TX_PWRSW_PU 16 /* 0x00010000 */ ++#define RES4325_RFPLL_PWRSW_PU 17 /* 0x00020000 */ ++#define RES4325_LOGEN_PWRSW_PU 18 /* 0x00040000 */ ++#define RES4325_AFE_PWRSW_PU 19 /* 0x00080000 */ ++#define RES4325_BBPLL_PWRSW_PU 20 /* 0x00100000 */ ++#define RES4325_HT_AVAIL 21 /* 0x00200000 */ ++ ++/* 4325 B0/C0 resources */ ++#define RES4325B0_CBUCK_LPOM 1 /* 0x00000002 */ ++#define RES4325B0_CBUCK_BURST 2 /* 0x00000004 */ ++#define RES4325B0_CBUCK_PWM 3 /* 0x00000008 */ ++#define RES4325B0_CLDO_PU 4 /* 0x00000010 */ ++ ++/* 4325 C1 resources */ ++#define RES4325C1_LNLDO2_PU 12 /* 0x00001000 */ ++ ++/* 4325 chip-specific ChipStatus register bits */ ++#define CST4325_SPROM_OTP_SEL_MASK 0x00000003 ++#define CST4325_DEFCIS_SEL 0 /* OTP is powered up, use def. CIS, no SPROM */ ++#define CST4325_SPROM_SEL 1 /* OTP is powered up, SPROM is present */ ++#define CST4325_OTP_SEL 2 /* OTP is powered up, no SPROM */ ++#define CST4325_OTP_PWRDN 3 /* OTP is powered down, SPROM is present */ ++#define CST4325_SDIO_USB_MODE_MASK 0x00000004 ++#define CST4325_SDIO_USB_MODE_SHIFT 2 ++#define CST4325_RCAL_VALID_MASK 0x00000008 ++#define CST4325_RCAL_VALID_SHIFT 3 ++#define CST4325_RCAL_VALUE_MASK 0x000001f0 ++#define CST4325_RCAL_VALUE_SHIFT 4 ++#define CST4325_PMUTOP_2B_MASK 0x00000200 /* 1 for 2b, 0 for to 2a */ ++#define CST4325_PMUTOP_2B_SHIFT 9 ++ ++#define RES4329_RESERVED0 0 /* 0x00000001 */ ++#define RES4329_CBUCK_LPOM 1 /* 0x00000002 */ ++#define RES4329_CBUCK_BURST 2 /* 0x00000004 */ ++#define RES4329_CBUCK_PWM 3 /* 0x00000008 */ ++#define RES4329_CLDO_PU 4 /* 0x00000010 */ ++#define RES4329_PALDO_PU 5 /* 0x00000020 */ ++#define RES4329_ILP_REQUEST 6 /* 0x00000040 */ ++#define RES4329_RESERVED7 7 /* 0x00000080 */ ++#define RES4329_RESERVED8 8 /* 0x00000100 */ ++#define RES4329_LNLDO1_PU 9 /* 0x00000200 */ ++#define RES4329_OTP_PU 10 /* 0x00000400 */ ++#define RES4329_RESERVED11 11 /* 0x00000800 */ ++#define RES4329_LNLDO2_PU 12 /* 0x00001000 */ ++#define RES4329_XTAL_PU 13 /* 0x00002000 */ ++#define RES4329_ALP_AVAIL 14 /* 0x00004000 */ ++#define RES4329_RX_PWRSW_PU 15 /* 0x00008000 */ ++#define RES4329_TX_PWRSW_PU 16 /* 0x00010000 */ ++#define RES4329_RFPLL_PWRSW_PU 17 /* 0x00020000 */ ++#define RES4329_LOGEN_PWRSW_PU 18 /* 0x00040000 */ ++#define RES4329_AFE_PWRSW_PU 19 /* 0x00080000 */ ++#define RES4329_BBPLL_PWRSW_PU 20 /* 0x00100000 */ ++#define RES4329_HT_AVAIL 21 /* 0x00200000 */ ++ ++#define CST4329_SPROM_OTP_SEL_MASK 0x00000003 ++#define CST4329_DEFCIS_SEL 0 /* OTP is powered up, use def. CIS, no SPROM */ ++#define CST4329_SPROM_SEL 1 /* OTP is powered up, SPROM is present */ ++#define CST4329_OTP_SEL 2 /* OTP is powered up, no SPROM */ ++#define CST4329_OTP_PWRDN 3 /* OTP is powered down, SPROM is present */ ++#define CST4329_SPI_SDIO_MODE_MASK 0x00000004 ++#define CST4329_SPI_SDIO_MODE_SHIFT 2 ++ ++/* 4312 chip-specific ChipStatus register bits */ ++#define CST4312_SPROM_OTP_SEL_MASK 0x00000003 ++#define CST4312_DEFCIS_SEL 0 /* OTP is powered up, use def. CIS, no SPROM */ ++#define CST4312_SPROM_SEL 1 /* OTP is powered up, SPROM is present */ ++#define CST4312_OTP_SEL 2 /* OTP is powered up, no SPROM */ ++#define CST4312_OTP_BAD 3 /* OTP is broken, SPROM is present */ ++ ++/* 4312 resources (all PMU chips with little memory constraint) */ ++#define RES4312_SWITCHER_BURST 0 /* 0x00000001 */ ++#define RES4312_SWITCHER_PWM 1 /* 0x00000002 */ ++#define RES4312_PA_REF_LDO 2 /* 0x00000004 */ ++#define RES4312_CORE_LDO_BURST 3 /* 0x00000008 */ ++#define RES4312_CORE_LDO_PWM 4 /* 0x00000010 */ ++#define RES4312_RADIO_LDO 5 /* 0x00000020 */ ++#define RES4312_ILP_REQUEST 6 /* 0x00000040 */ ++#define RES4312_BG_FILTBYP 7 /* 0x00000080 */ ++#define RES4312_TX_FILTBYP 8 /* 0x00000100 */ ++#define RES4312_RX_FILTBYP 9 /* 0x00000200 */ ++#define RES4312_XTAL_PU 10 /* 0x00000400 */ ++#define RES4312_ALP_AVAIL 11 /* 0x00000800 */ ++#define RES4312_BB_PLL_FILTBYP 12 /* 0x00001000 */ ++#define RES4312_RF_PLL_FILTBYP 13 /* 0x00002000 */ ++#define RES4312_HT_AVAIL 14 /* 0x00004000 */ ++ ++/* 4322 resources */ ++#define RES4322_RF_LDO 0 ++#define RES4322_ILP_REQUEST 1 ++#define RES4322_XTAL_PU 2 ++#define RES4322_ALP_AVAIL 3 ++#define RES4322_SI_PLL_ON 4 ++#define RES4322_HT_SI_AVAIL 5 ++#define RES4322_PHY_PLL_ON 6 ++#define RES4322_HT_PHY_AVAIL 7 ++#define RES4322_OTP_PU 8 ++ ++/* 4322 chip-specific ChipStatus register bits */ ++#define CST4322_XTAL_FREQ_20_40MHZ 0x00000020 ++#define CST4322_SPROM_OTP_SEL_MASK 0x000000c0 ++#define CST4322_SPROM_OTP_SEL_SHIFT 6 ++#define CST4322_NO_SPROM_OTP 0 /* no OTP, no SPROM */ ++#define CST4322_SPROM_PRESENT 1 /* SPROM is present */ ++#define CST4322_OTP_PRESENT 2 /* OTP is present */ ++#define CST4322_PCI_OR_USB 0x00000100 ++#define CST4322_BOOT_MASK 0x00000600 ++#define CST4322_BOOT_SHIFT 9 ++#define CST4322_BOOT_FROM_SRAM 0 /* boot from SRAM, ARM in reset */ ++#define CST4322_BOOT_FROM_ROM 1 /* boot from ROM */ ++#define CST4322_BOOT_FROM_FLASH 2 /* boot from FLASH */ ++#define CST4322_BOOT_FROM_INVALID 3 ++#define CST4322_ILP_DIV_EN 0x00000800 ++#define CST4322_FLASH_TYPE_MASK 0x00001000 ++#define CST4322_FLASH_TYPE_SHIFT 12 ++#define CST4322_FLASH_TYPE_SHIFT_ST 0 /* ST serial FLASH */ ++#define CST4322_FLASH_TYPE_SHIFT_ATMEL 1 /* ATMEL flash */ ++#define CST4322_ARM_TAP_SEL 0x00002000 ++#define CST4322_RES_INIT_MODE_MASK 0x0000c000 ++#define CST4322_RES_INIT_MODE_SHIFT 14 ++#define CST4322_RES_INIT_MODE_ILPAVAIL 0 /* resinitmode: ILP available */ ++#define CST4322_RES_INIT_MODE_ILPREQ 1 /* resinitmode: ILP request */ ++#define CST4322_RES_INIT_MODE_ALPAVAIL 2 /* resinitmode: ALP available */ ++#define CST4322_RES_INIT_MODE_HTAVAIL 3 /* resinitmode: HT available */ ++#define CST4322_PCIPLLCLK_GATING 0x00010000 ++#define CST4322_CLK_SWITCH_PCI_TO_ALP 0x00020000 ++#define CST4322_PCI_CARDBUS_MODE 0x00040000 ++ ++/* 43224 chip-specific ChipControl register bits */ ++#define CCTRL43224_GPIO_TOGGLE 0x8000 /* gpio[3:0] pins as btcoex or s/w gpio */ ++#define CCTRL_43224A0_12MA_LED_DRIVE 0x00F000F0 /* 12 mA drive strength */ ++#define CCTRL_43224B0_12MA_LED_DRIVE 0xF0 /* 12 mA drive strength for later 43224s */ ++ ++/* 43236 resources */ ++#define RES43236_REGULATOR 0 ++#define RES43236_ILP_REQUEST 1 ++#define RES43236_XTAL_PU 2 ++#define RES43236_ALP_AVAIL 3 ++#define RES43236_SI_PLL_ON 4 ++#define RES43236_HT_SI_AVAIL 5 ++ ++/* 43236 chip-specific ChipControl register bits */ ++#define CCTRL43236_BT_COEXIST (1<<0) /* 0 disable */ ++#define CCTRL43236_SECI (1<<1) /* 0 SECI is disabled (JATG functional) */ ++#define CCTRL43236_EXT_LNA (1<<2) /* 0 disable */ ++#define CCTRL43236_ANT_MUX_2o3 (1<<3) /* 2o3 mux, chipcontrol bit 3 */ ++#define CCTRL43236_GSIO (1<<4) /* 0 disable */ ++ ++/* 43236 Chip specific ChipStatus register bits */ ++#define CST43236_SFLASH_MASK 0x00000040 ++#define CST43236_OTP_SEL_MASK 0x00000080 ++#define CST43236_OTP_SEL_SHIFT 7 ++#define CST43236_HSIC_MASK 0x00000100 /* USB/HSIC */ ++#define CST43236_BP_CLK 0x00000200 /* 120/96Mbps */ ++#define CST43236_BOOT_MASK 0x00001800 ++#define CST43236_BOOT_SHIFT 11 ++#define CST43236_BOOT_FROM_SRAM 0 /* boot from SRAM, ARM in reset */ ++#define CST43236_BOOT_FROM_ROM 1 /* boot from ROM */ ++#define CST43236_BOOT_FROM_FLASH 2 /* boot from FLASH */ ++#define CST43236_BOOT_FROM_INVALID 3 ++ ++/* 43237 resources */ ++#define RES43237_REGULATOR 0 ++#define RES43237_ILP_REQUEST 1 ++#define RES43237_XTAL_PU 2 ++#define RES43237_ALP_AVAIL 3 ++#define RES43237_SI_PLL_ON 4 ++#define RES43237_HT_SI_AVAIL 5 ++ ++/* 43237 chip-specific ChipControl register bits */ ++#define CCTRL43237_BT_COEXIST (1<<0) /* 0 disable */ ++#define CCTRL43237_SECI (1<<1) /* 0 SECI is disabled (JATG functional) */ ++#define CCTRL43237_EXT_LNA (1<<2) /* 0 disable */ ++#define CCTRL43237_ANT_MUX_2o3 (1<<3) /* 2o3 mux, chipcontrol bit 3 */ ++#define CCTRL43237_GSIO (1<<4) /* 0 disable */ ++ ++/* 43237 Chip specific ChipStatus register bits */ ++#define CST43237_SFLASH_MASK 0x00000040 ++#define CST43237_OTP_SEL_MASK 0x00000080 ++#define CST43237_OTP_SEL_SHIFT 7 ++#define CST43237_HSIC_MASK 0x00000100 /* USB/HSIC */ ++#define CST43237_BP_CLK 0x00000200 /* 120/96Mbps */ ++#define CST43237_BOOT_MASK 0x00001800 ++#define CST43237_BOOT_SHIFT 11 ++#define CST43237_BOOT_FROM_SRAM 0 /* boot from SRAM, ARM in reset */ ++#define CST43237_BOOT_FROM_ROM 1 /* boot from ROM */ ++#define CST43237_BOOT_FROM_FLASH 2 /* boot from FLASH */ ++#define CST43237_BOOT_FROM_INVALID 3 ++ ++/* 43239 resources */ ++#define RES43239_OTP_PU 9 ++#define RES43239_MACPHY_CLKAVAIL 23 ++#define RES43239_HT_AVAIL 24 ++ ++/* 43239 Chip specific ChipStatus register bits */ ++#define CST43239_SPROM_MASK 0x00000002 ++#define CST43239_SFLASH_MASK 0x00000004 ++#define CST43239_RES_INIT_MODE_SHIFT 7 ++#define CST43239_RES_INIT_MODE_MASK 0x000001f0 ++#define CST43239_CHIPMODE_SDIOD(cs) ((cs) & (1 << 15)) /* SDIO || gSPI */ ++#define CST43239_CHIPMODE_USB20D(cs) (~(cs) & (1 << 15)) /* USB || USBDA */ ++#define CST43239_CHIPMODE_SDIO(cs) (((cs) & (1 << 0)) == 0) /* SDIO */ ++#define CST43239_CHIPMODE_GSPI(cs) (((cs) & (1 << 0)) == (1 << 0)) /* gSPI */ ++ ++/* 4324 resources */ ++#define RES4324_OTP_PU 10 ++#define RES4324_HT_AVAIL 29 ++#define RES4324_MACPHY_CLKAVAIL 30 ++ ++/* 4324 Chip specific ChipStatus register bits */ ++#define CST4324_SPROM_MASK 0x00000080 ++#define CST4324_SFLASH_MASK 0x00400000 ++#define CST4324_RES_INIT_MODE_SHIFT 10 ++#define CST4324_RES_INIT_MODE_MASK 0x00000c00 ++#define CST4324_CHIPMODE_MASK 0x7 ++#define CST4324_CHIPMODE_SDIOD(cs) ((~(cs)) & (1 << 2)) /* SDIO || gSPI */ ++#define CST4324_CHIPMODE_USB20D(cs) (((cs) & CST4324_CHIPMODE_MASK) == 0x6) /* USB || USBDA */ ++ ++/* 4331 resources */ ++#define RES4331_REGULATOR 0 ++#define RES4331_ILP_REQUEST 1 ++#define RES4331_XTAL_PU 2 ++#define RES4331_ALP_AVAIL 3 ++#define RES4331_SI_PLL_ON 4 ++#define RES4331_HT_SI_AVAIL 5 ++ ++/* 4331 chip-specific ChipControl register bits */ ++#define CCTRL4331_BT_COEXIST (1<<0) /* 0 disable */ ++#define CCTRL4331_SECI (1<<1) /* 0 SECI is disabled (JATG functional) */ ++#define CCTRL4331_EXT_LNA_G (1<<2) /* 0 disable */ ++#define CCTRL4331_SPROM_GPIO13_15 (1<<3) /* sprom/gpio13-15 mux */ ++#define CCTRL4331_EXTPA_EN (1<<4) /* 0 ext pa disable, 1 ext pa enabled */ ++#define CCTRL4331_GPIOCLK_ON_SPROMCS (1<<5) /* set drive out GPIO_CLK on sprom_cs pin */ ++#define CCTRL4331_PCIE_MDIO_ON_SPROMCS (1<<6) /* use sprom_cs pin as PCIE mdio interface */ ++#define CCTRL4331_EXTPA_ON_GPIO2_5 (1<<7) /* aband extpa will be at gpio2/5 and sprom_dout */ ++#define CCTRL4331_OVR_PIPEAUXCLKEN (1<<8) /* override core control on pipe_AuxClkEnable */ ++#define CCTRL4331_OVR_PIPEAUXPWRDOWN (1<<9) /* override core control on pipe_AuxPowerDown */ ++#define CCTRL4331_PCIE_AUXCLKEN (1<<10) /* pcie_auxclkenable */ ++#define CCTRL4331_PCIE_PIPE_PLLDOWN (1<<11) /* pcie_pipe_pllpowerdown */ ++#define CCTRL4331_EXTPA_EN2 (1<<12) /* 0 ext pa disable, 1 ext pa enabled */ ++#define CCTRL4331_EXT_LNA_A (1<<13) /* 0 disable */ ++#define CCTRL4331_BT_SHD0_ON_GPIO4 (1<<16) /* enable bt_shd0 at gpio4 */ ++#define CCTRL4331_BT_SHD1_ON_GPIO5 (1<<17) /* enable bt_shd1 at gpio5 */ ++#define CCTRL4331_EXTPA_ANA_EN (1<<24) /* 0 ext pa disable, 1 ext pa enabled */ ++ ++/* 4331 Chip specific ChipStatus register bits */ ++#define CST4331_XTAL_FREQ 0x00000001 /* crystal frequency 20/40Mhz */ ++#define CST4331_SPROM_OTP_SEL_MASK 0x00000006 ++#define CST4331_SPROM_OTP_SEL_SHIFT 1 ++#define CST4331_SPROM_PRESENT 0x00000002 ++#define CST4331_OTP_PRESENT 0x00000004 ++#define CST4331_LDO_RF 0x00000008 ++#define CST4331_LDO_PAR 0x00000010 ++ ++/* 4315 resource */ ++#define RES4315_CBUCK_LPOM 1 /* 0x00000002 */ ++#define RES4315_CBUCK_BURST 2 /* 0x00000004 */ ++#define RES4315_CBUCK_PWM 3 /* 0x00000008 */ ++#define RES4315_CLDO_PU 4 /* 0x00000010 */ ++#define RES4315_PALDO_PU 5 /* 0x00000020 */ ++#define RES4315_ILP_REQUEST 6 /* 0x00000040 */ ++#define RES4315_LNLDO1_PU 9 /* 0x00000200 */ ++#define RES4315_OTP_PU 10 /* 0x00000400 */ ++#define RES4315_LNLDO2_PU 12 /* 0x00001000 */ ++#define RES4315_XTAL_PU 13 /* 0x00002000 */ ++#define RES4315_ALP_AVAIL 14 /* 0x00004000 */ ++#define RES4315_RX_PWRSW_PU 15 /* 0x00008000 */ ++#define RES4315_TX_PWRSW_PU 16 /* 0x00010000 */ ++#define RES4315_RFPLL_PWRSW_PU 17 /* 0x00020000 */ ++#define RES4315_LOGEN_PWRSW_PU 18 /* 0x00040000 */ ++#define RES4315_AFE_PWRSW_PU 19 /* 0x00080000 */ ++#define RES4315_BBPLL_PWRSW_PU 20 /* 0x00100000 */ ++#define RES4315_HT_AVAIL 21 /* 0x00200000 */ ++ ++/* 4315 chip-specific ChipStatus register bits */ ++#define CST4315_SPROM_OTP_SEL_MASK 0x00000003 /* gpio [7:6], SDIO CIS selection */ ++#define CST4315_DEFCIS_SEL 0x00000000 /* use default CIS, OTP is powered up */ ++#define CST4315_SPROM_SEL 0x00000001 /* use SPROM, OTP is powered up */ ++#define CST4315_OTP_SEL 0x00000002 /* use OTP, OTP is powered up */ ++#define CST4315_OTP_PWRDN 0x00000003 /* use SPROM, OTP is powered down */ ++#define CST4315_SDIO_MODE 0x00000004 /* gpio [8], sdio/usb mode */ ++#define CST4315_RCAL_VALID 0x00000008 ++#define CST4315_RCAL_VALUE_MASK 0x000001f0 ++#define CST4315_RCAL_VALUE_SHIFT 4 ++#define CST4315_PALDO_EXTPNP 0x00000200 /* PALDO is configured with external PNP */ ++#define CST4315_CBUCK_MODE_MASK 0x00000c00 ++#define CST4315_CBUCK_MODE_BURST 0x00000400 ++#define CST4315_CBUCK_MODE_LPBURST 0x00000c00 ++ ++/* 4319 resources */ ++#define RES4319_CBUCK_LPOM 1 /* 0x00000002 */ ++#define RES4319_CBUCK_BURST 2 /* 0x00000004 */ ++#define RES4319_CBUCK_PWM 3 /* 0x00000008 */ ++#define RES4319_CLDO_PU 4 /* 0x00000010 */ ++#define RES4319_PALDO_PU 5 /* 0x00000020 */ ++#define RES4319_ILP_REQUEST 6 /* 0x00000040 */ ++#define RES4319_LNLDO1_PU 9 /* 0x00000200 */ ++#define RES4319_OTP_PU 10 /* 0x00000400 */ ++#define RES4319_LNLDO2_PU 12 /* 0x00001000 */ ++#define RES4319_XTAL_PU 13 /* 0x00002000 */ ++#define RES4319_ALP_AVAIL 14 /* 0x00004000 */ ++#define RES4319_RX_PWRSW_PU 15 /* 0x00008000 */ ++#define RES4319_TX_PWRSW_PU 16 /* 0x00010000 */ ++#define RES4319_RFPLL_PWRSW_PU 17 /* 0x00020000 */ ++#define RES4319_LOGEN_PWRSW_PU 18 /* 0x00040000 */ ++#define RES4319_AFE_PWRSW_PU 19 /* 0x00080000 */ ++#define RES4319_BBPLL_PWRSW_PU 20 /* 0x00100000 */ ++#define RES4319_HT_AVAIL 21 /* 0x00200000 */ ++ ++/* 4319 chip-specific ChipStatus register bits */ ++#define CST4319_SPI_CPULESSUSB 0x00000001 ++#define CST4319_SPI_CLK_POL 0x00000002 ++#define CST4319_SPI_CLK_PH 0x00000008 ++#define CST4319_SPROM_OTP_SEL_MASK 0x000000c0 /* gpio [7:6], SDIO CIS selection */ ++#define CST4319_SPROM_OTP_SEL_SHIFT 6 ++#define CST4319_DEFCIS_SEL 0x00000000 /* use default CIS, OTP is powered up */ ++#define CST4319_SPROM_SEL 0x00000040 /* use SPROM, OTP is powered up */ ++#define CST4319_OTP_SEL 0x00000080 /* use OTP, OTP is powered up */ ++#define CST4319_OTP_PWRDN 0x000000c0 /* use SPROM, OTP is powered down */ ++#define CST4319_SDIO_USB_MODE 0x00000100 /* gpio [8], sdio/usb mode */ ++#define CST4319_REMAP_SEL_MASK 0x00000600 ++#define CST4319_ILPDIV_EN 0x00000800 ++#define CST4319_XTAL_PD_POL 0x00001000 ++#define CST4319_LPO_SEL 0x00002000 ++#define CST4319_RES_INIT_MODE 0x0000c000 ++#define CST4319_PALDO_EXTPNP 0x00010000 /* PALDO is configured with external PNP */ ++#define CST4319_CBUCK_MODE_MASK 0x00060000 ++#define CST4319_CBUCK_MODE_BURST 0x00020000 ++#define CST4319_CBUCK_MODE_LPBURST 0x00060000 ++#define CST4319_RCAL_VALID 0x01000000 ++#define CST4319_RCAL_VALUE_MASK 0x3e000000 ++#define CST4319_RCAL_VALUE_SHIFT 25 ++ ++#define PMU1_PLL0_CHIPCTL0 0 ++#define PMU1_PLL0_CHIPCTL1 1 ++#define PMU1_PLL0_CHIPCTL2 2 ++#define CCTL_4319USB_XTAL_SEL_MASK 0x00180000 ++#define CCTL_4319USB_XTAL_SEL_SHIFT 19 ++#define CCTL_4319USB_48MHZ_PLL_SEL 1 ++#define CCTL_4319USB_24MHZ_PLL_SEL 2 ++ ++/* PMU resources for 4336 */ ++#define RES4336_CBUCK_LPOM 0 ++#define RES4336_CBUCK_BURST 1 ++#define RES4336_CBUCK_LP_PWM 2 ++#define RES4336_CBUCK_PWM 3 ++#define RES4336_CLDO_PU 4 ++#define RES4336_DIS_INT_RESET_PD 5 ++#define RES4336_ILP_REQUEST 6 ++#define RES4336_LNLDO_PU 7 ++#define RES4336_LDO3P3_PU 8 ++#define RES4336_OTP_PU 9 ++#define RES4336_XTAL_PU 10 ++#define RES4336_ALP_AVAIL 11 ++#define RES4336_RADIO_PU 12 ++#define RES4336_BG_PU 13 ++#define RES4336_VREG1p4_PU_PU 14 ++#define RES4336_AFE_PWRSW_PU 15 ++#define RES4336_RX_PWRSW_PU 16 ++#define RES4336_TX_PWRSW_PU 17 ++#define RES4336_BB_PWRSW_PU 18 ++#define RES4336_SYNTH_PWRSW_PU 19 ++#define RES4336_MISC_PWRSW_PU 20 ++#define RES4336_LOGEN_PWRSW_PU 21 ++#define RES4336_BBPLL_PWRSW_PU 22 ++#define RES4336_MACPHY_CLKAVAIL 23 ++#define RES4336_HT_AVAIL 24 ++#define RES4336_RSVD 25 ++ ++/* 4336 chip-specific ChipStatus register bits */ ++#define CST4336_SPI_MODE_MASK 0x00000001 ++#define CST4336_SPROM_PRESENT 0x00000002 ++#define CST4336_OTP_PRESENT 0x00000004 ++#define CST4336_ARMREMAP_0 0x00000008 ++#define CST4336_ILPDIV_EN_MASK 0x00000010 ++#define CST4336_ILPDIV_EN_SHIFT 4 ++#define CST4336_XTAL_PD_POL_MASK 0x00000020 ++#define CST4336_XTAL_PD_POL_SHIFT 5 ++#define CST4336_LPO_SEL_MASK 0x00000040 ++#define CST4336_LPO_SEL_SHIFT 6 ++#define CST4336_RES_INIT_MODE_MASK 0x00000180 ++#define CST4336_RES_INIT_MODE_SHIFT 7 ++#define CST4336_CBUCK_MODE_MASK 0x00000600 ++#define CST4336_CBUCK_MODE_SHIFT 9 ++ ++/* 4336 Chip specific PMU ChipControl register bits */ ++#define PCTL_4336_SERIAL_ENAB (1 << 24) ++ ++/* 4330 resources */ ++#define RES4330_CBUCK_LPOM 0 ++#define RES4330_CBUCK_BURST 1 ++#define RES4330_CBUCK_LP_PWM 2 ++#define RES4330_CBUCK_PWM 3 ++#define RES4330_CLDO_PU 4 ++#define RES4330_DIS_INT_RESET_PD 5 ++#define RES4330_ILP_REQUEST 6 ++#define RES4330_LNLDO_PU 7 ++#define RES4330_LDO3P3_PU 8 ++#define RES4330_OTP_PU 9 ++#define RES4330_XTAL_PU 10 ++#define RES4330_ALP_AVAIL 11 ++#define RES4330_RADIO_PU 12 ++#define RES4330_BG_PU 13 ++#define RES4330_VREG1p4_PU_PU 14 ++#define RES4330_AFE_PWRSW_PU 15 ++#define RES4330_RX_PWRSW_PU 16 ++#define RES4330_TX_PWRSW_PU 17 ++#define RES4330_BB_PWRSW_PU 18 ++#define RES4330_SYNTH_PWRSW_PU 19 ++#define RES4330_MISC_PWRSW_PU 20 ++#define RES4330_LOGEN_PWRSW_PU 21 ++#define RES4330_BBPLL_PWRSW_PU 22 ++#define RES4330_MACPHY_CLKAVAIL 23 ++#define RES4330_HT_AVAIL 24 ++#define RES4330_5gRX_PWRSW_PU 25 ++#define RES4330_5gTX_PWRSW_PU 26 ++#define RES4330_5g_LOGEN_PWRSW_PU 27 ++ ++/* 4330 chip-specific ChipStatus register bits */ ++#define CST4330_CHIPMODE_SDIOD(cs) (((cs) & 0x7) < 6) /* SDIO || gSPI */ ++#define CST4330_CHIPMODE_USB20D(cs) (((cs) & 0x7) >= 6) /* USB || USBDA */ ++#define CST4330_CHIPMODE_SDIO(cs) (((cs) & 0x4) == 0) /* SDIO */ ++#define CST4330_CHIPMODE_GSPI(cs) (((cs) & 0x6) == 4) /* gSPI */ ++#define CST4330_CHIPMODE_USB(cs) (((cs) & 0x7) == 6) /* USB packet-oriented */ ++#define CST4330_CHIPMODE_USBDA(cs) (((cs) & 0x7) == 7) /* USB Direct Access */ ++#define CST4330_OTP_PRESENT 0x00000010 ++#define CST4330_LPO_AUTODET_EN 0x00000020 ++#define CST4330_ARMREMAP_0 0x00000040 ++#define CST4330_SPROM_PRESENT 0x00000080 /* takes priority over OTP if both set */ ++#define CST4330_ILPDIV_EN 0x00000100 ++#define CST4330_LPO_SEL 0x00000200 ++#define CST4330_RES_INIT_MODE_SHIFT 10 ++#define CST4330_RES_INIT_MODE_MASK 0x00000c00 ++#define CST4330_CBUCK_MODE_SHIFT 12 ++#define CST4330_CBUCK_MODE_MASK 0x00003000 ++#define CST4330_CBUCK_POWER_OK 0x00004000 ++#define CST4330_BB_PLL_LOCKED 0x00008000 ++#define SOCDEVRAM_BP_ADDR 0x1E000000 ++#define SOCDEVRAM_ARM_ADDR 0x00800000 ++ ++/* 4330 Chip specific PMU ChipControl register bits */ ++#define PCTL_4330_SERIAL_ENAB (1 << 24) ++ ++/* 4330 Chip specific ChipControl register bits */ ++#define CCTRL_4330_GPIO_SEL 0x00000001 /* 1=select GPIOs to be muxed out */ ++#define CCTRL_4330_ERCX_SEL 0x00000002 /* 1=select ERCX BT coex to be muxed out */ ++#define CCTRL_4330_SDIO_HOST_WAKE 0x00000004 /* SDIO: 1=configure GPIO0 for host wake */ ++#define CCTRL_4330_JTAG_DISABLE 0x00000008 /* 1=disable JTAG interface on mux'd pins */ ++ ++#define PMU_VREG0_ADDR 0 ++#define PMU_VREG0_DISABLE_PULLD_BT_SHIFT 2 ++#define PMU_VREG0_DISABLE_PULLD_WL_SHIFT 3 ++ ++/* 4334 resources */ ++#define RES4334_LPLDO_PU 0 ++#define RES4334_RESET_PULLDN_DIS 1 ++#define RES4334_PMU_BG_PU 2 ++#define RES4334_HSIC_LDO_PU 3 ++#define RES4334_CBUCK_LPOM_PU 4 ++#define RES4334_CBUCK_PFM_PU 5 ++#define RES4334_CLDO_PU 6 ++#define RES4334_LPLDO2_LVM 7 ++#define RES4334_LNLDO_PU 8 ++#define RES4334_LDO3P3_PU 9 ++#define RES4334_OTP_PU 10 ++#define RES4334_XTAL_PU 11 ++#define RES4334_WL_PWRSW_PU 12 ++#define RES4334_LQ_AVAIL 13 ++#define RES4334_LOGIC_RET 14 ++#define RES4334_MEM_SLEEP 15 ++#define RES4334_MACPHY_RET 16 ++#define RES4334_WL_CORE_READY 17 ++#define RES4334_ILP_REQ 18 ++#define RES4334_ALP_AVAIL 19 ++#define RES4334_MISC_PWRSW_PU 20 ++#define RES4334_SYNTH_PWRSW_PU 21 ++#define RES4334_RX_PWRSW_PU 22 ++#define RES4334_RADIO_PU 23 ++#define RES4334_WL_PMU_PU 24 ++#define RES4334_VCO_LDO_PU 25 ++#define RES4334_AFE_LDO_PU 26 ++#define RES4334_RX_LDO_PU 27 ++#define RES4334_TX_LDO_PU 28 ++#define RES4334_HT_AVAIL 29 ++#define RES4334_MACPHY_CLK_AVAIL 30 ++ ++/* 4334 chip-specific ChipStatus register bits */ ++#define CST4334_CHIPMODE_MASK 7 ++#define CST4334_SDIO_MODE 0x00000000 ++#define CST4334_SPI_MODE 0x00000004 ++#define CST4334_HSIC_MODE 0x00000006 ++#define CST4334_BLUSB_MODE 0x00000007 ++#define CST4334_CHIPMODE_HSIC(cs) (((cs) & CST4334_CHIPMODE_MASK) == CST4334_HSIC_MODE) ++#define CST4334_OTP_PRESENT 0x00000010 ++#define CST4334_LPO_AUTODET_EN 0x00000020 ++#define CST4334_ARMREMAP_0 0x00000040 ++#define CST4334_SPROM_PRESENT 0x00000080 ++#define CST4334_ILPDIV_EN_MASK 0x00000100 ++#define CST4334_ILPDIV_EN_SHIFT 8 ++#define CST4334_LPO_SEL_MASK 0x00000200 ++#define CST4334_LPO_SEL_SHIFT 9 ++#define CST4334_RES_INIT_MODE_MASK 0x00000C00 ++#define CST4334_RES_INIT_MODE_SHIFT 10 ++ ++/* 4334 Chip specific PMU ChipControl register bits */ ++#define PCTL_4334_GPIO3_ENAB (1 << 3) ++ ++/* 4334 Chip control */ ++#define CCTRL4334_HSIC_LDO_PU (1 << 23) ++ ++/* 4324 Chip specific ChipControl1 register bits */ ++#define CCTRL1_4324_GPIO_SEL (1 << 0) /* 1=select GPIOs to be muxed out */ ++#define CCTRL1_4324_SDIO_HOST_WAKE (1 << 2) /* SDIO: 1=configure GPIO0 for host wake */ ++ ++ ++/* 4313 resources */ ++#define RES4313_BB_PU_RSRC 0 ++#define RES4313_ILP_REQ_RSRC 1 ++#define RES4313_XTAL_PU_RSRC 2 ++#define RES4313_ALP_AVAIL_RSRC 3 ++#define RES4313_RADIO_PU_RSRC 4 ++#define RES4313_BG_PU_RSRC 5 ++#define RES4313_VREG1P4_PU_RSRC 6 ++#define RES4313_AFE_PWRSW_RSRC 7 ++#define RES4313_RX_PWRSW_RSRC 8 ++#define RES4313_TX_PWRSW_RSRC 9 ++#define RES4313_BB_PWRSW_RSRC 10 ++#define RES4313_SYNTH_PWRSW_RSRC 11 ++#define RES4313_MISC_PWRSW_RSRC 12 ++#define RES4313_BB_PLL_PWRSW_RSRC 13 ++#define RES4313_HT_AVAIL_RSRC 14 ++#define RES4313_MACPHY_CLK_AVAIL_RSRC 15 ++ ++/* 4313 chip-specific ChipStatus register bits */ ++#define CST4313_SPROM_PRESENT 1 ++#define CST4313_OTP_PRESENT 2 ++#define CST4313_SPROM_OTP_SEL_MASK 0x00000002 ++#define CST4313_SPROM_OTP_SEL_SHIFT 0 ++ ++/* 4313 Chip specific ChipControl register bits */ ++#define CCTRL_4313_12MA_LED_DRIVE 0x00000007 /* 12 mA drive strengh for later 4313 */ ++ ++/* PMU respources for 4314 */ ++#define RES4314_LPLDO_PU 0 ++#define RES4314_PMU_SLEEP_DIS 1 ++#define RES4314_PMU_BG_PU 2 ++#define RES4314_CBUCK_LPOM_PU 3 ++#define RES4314_CBUCK_PFM_PU 4 ++#define RES4314_CLDO_PU 5 ++#define RES4314_LPLDO2_LVM 6 ++#define RES4314_WL_PMU_PU 7 ++#define RES4314_LNLDO_PU 8 ++#define RES4314_LDO3P3_PU 9 ++#define RES4314_OTP_PU 10 ++#define RES4314_XTAL_PU 11 ++#define RES4314_WL_PWRSW_PU 12 ++#define RES4314_LQ_AVAIL 13 ++#define RES4314_LOGIC_RET 14 ++#define RES4314_MEM_SLEEP 15 ++#define RES4314_MACPHY_RET 16 ++#define RES4314_WL_CORE_READY 17 ++#define RES4314_ILP_REQ 18 ++#define RES4314_ALP_AVAIL 19 ++#define RES4314_MISC_PWRSW_PU 20 ++#define RES4314_SYNTH_PWRSW_PU 21 ++#define RES4314_RX_PWRSW_PU 22 ++#define RES4314_RADIO_PU 23 ++#define RES4314_VCO_LDO_PU 24 ++#define RES4314_AFE_LDO_PU 25 ++#define RES4314_RX_LDO_PU 26 ++#define RES4314_TX_LDO_PU 27 ++#define RES4314_HT_AVAIL 28 ++#define RES4314_MACPHY_CLK_AVAIL 29 ++ ++/* 4314 chip-specific ChipStatus register bits */ ++#define CST4314_OTP_ENABLED 0x00200000 ++ ++/* 43228 resources */ ++#define RES43228_NOT_USED 0 ++#define RES43228_ILP_REQUEST 1 ++#define RES43228_XTAL_PU 2 ++#define RES43228_ALP_AVAIL 3 ++#define RES43228_PLL_EN 4 ++#define RES43228_HT_PHY_AVAIL 5 ++ ++/* 43228 chipstatus reg bits */ ++#define CST43228_ILP_DIV_EN 0x1 ++#define CST43228_OTP_PRESENT 0x2 ++#define CST43228_SERDES_REFCLK_PADSEL 0x4 ++#define CST43228_SDIO_MODE 0x8 ++#define CST43228_SDIO_OTP_PRESENT 0x10 ++#define CST43228_SDIO_RESET 0x20 ++ ++/* 4706 chipstatus reg bits */ ++#define CST4706_PKG_OPTION (1<<0) /* 0: full-featured package 1: low-cost package */ ++#define CST4706_SFLASH_PRESENT (1<<1) /* 0: parallel, 1: serial flash is present */ ++#define CST4706_SFLASH_TYPE (1<<2) /* 0: 8b-p/ST-s flash, 1: 16b-p/Atmal-s flash */ ++#define CST4706_MIPS_BENDIAN (1<<3) /* 0: little, 1: big endian */ ++#define CST4706_PCIE1_DISABLE (1<<5) /* PCIE1 enable strap pin */ ++ ++/* 4706 flashstrconfig reg bits */ ++#define FLSTRCF4706_MASK 0x000000ff ++#define FLSTRCF4706_SF1 0x00000001 /* 2nd serial flash present */ ++#define FLSTRCF4706_PF1 0x00000002 /* 2nd parallel flash present */ ++#define FLSTRCF4706_SF1_TYPE 0x00000004 /* 2nd serial flash type : 0 : ST, 1 : Atmel */ ++#define FLSTRCF4706_NF1 0x00000008 /* 2nd NAND flash present */ ++#define FLSTRCF4706_1ST_MADDR_SEG_MASK 0x000000f0 /* Valid value mask */ ++#define FLSTRCF4706_1ST_MADDR_SEG_4MB 0x00000010 /* 4MB */ ++#define FLSTRCF4706_1ST_MADDR_SEG_8MB 0x00000020 /* 8MB */ ++#define FLSTRCF4706_1ST_MADDR_SEG_16MB 0x00000030 /* 16MB */ ++#define FLSTRCF4706_1ST_MADDR_SEG_32MB 0x00000040 /* 32MB */ ++#define FLSTRCF4706_1ST_MADDR_SEG_64MB 0x00000050 /* 64MB */ ++#define FLSTRCF4706_1ST_MADDR_SEG_128MB 0x00000060 /* 128MB */ ++#define FLSTRCF4706_1ST_MADDR_SEG_256MB 0x00000070 /* 256MB */ ++ ++/* 4360 Chip specific ChipControl register bits */ ++#define CCTRL4360_SECI_MODE (1 << 2) ++#define CCTRL4360_BTSWCTRL_MODE (1 << 3) ++#define CCTRL4360_EXTRA_FEMCTRL_MODE (1 << 8) ++#define CCTRL4360_BT_LGCY_MODE (1 << 9) ++#define CCTRL4360_CORE2FEMCTRL4_ON (1 << 21) ++ ++/* 4360 PMU resources and chip status bits */ ++#define RES4360_REGULATOR 0 ++#define RES4360_ILP_AVAIL 1 ++#define RES4360_ILP_REQ 2 ++#define RES4360_XTAL_LDO_PU 3 ++#define RES4360_XTAL_PU 4 ++#define RES4360_ALP_AVAIL 5 ++#define RES4360_BBPLLPWRSW_PU 6 ++#define RES4360_HT_AVAIL 7 ++#define RES4360_OTP_PU 8 ++ ++#define CST4360_XTAL_40MZ 0x00000001 ++#define CST4360_SFLASH 0x00000002 ++#define CST4360_SPROM_PRESENT 0x00000004 ++#define CST4360_SFLASH_TYPE 0x00000004 ++#define CST4360_OTP_ENABLED 0x00000008 ++#define CST4360_REMAP_ROM 0x00000010 ++#define CST4360_RSRC_INIT_MODE_MASK 0x00000060 ++#define CST4360_RSRC_INIT_MODE_SHIFT 5 ++#define CST4360_ILP_DIVEN 0x00000080 ++#define CST4360_MODE_USB 0x00000100 ++#define CST4360_SPROM_SIZE_MASK 0x00000600 ++#define CST4360_SPROM_SIZE_SHIFT 9 ++#define CST4360_BBPLL_LOCK 0x00000800 ++#define CST4360_AVBBPLL_LOCK 0x00001000 ++#define CST4360_USBBBPLL_LOCK 0x00002000 ++ ++#define CCTRL_4360_UART_SEL 0x2 ++ ++/* 4335 resources */ ++#define RES4335_LPLDO_PO 0 ++#define RES4335_PMU_BG_PU 1 ++#define RES4335_PMU_SLEEP 2 ++#define RES4335_RSVD_3 3 ++#define RES4335_CBUCK_LPOM_PU 4 ++#define RES4335_CBUCK_PFM_PU 5 ++#define RES4335_RSVD_6 6 ++#define RES4335_RSVD_7 7 ++#define RES4335_LNLDO_PU 8 ++#define RES4335_XTALLDO_PU 9 ++#define RES4335_LDO3P3_PU 10 ++#define RES4335_OTP_PU 11 ++#define RES4335_XTAL_PU 12 ++#define RES4335_SR_CLK_START 13 ++#define RES4335_LQ_AVAIL 14 ++#define RES4335_LQ_START 15 ++#define RES4335_RSVD_16 16 ++#define RES4335_WL_CORE_RDY 17 ++#define RES4335_ILP_REQ 18 ++#define RES4335_ALP_AVAIL 19 ++#define RES4335_MINI_PMU 20 ++#define RES4335_RADIO_PU 21 ++#define RES4335_SR_CLK_STABLE 22 ++#define RES4335_SR_SAVE_RESTORE 23 ++#define RES4335_SR_PHY_PWRSW 24 ++#define RES4335_SR_VDDM_PWRSW 25 ++#define RES4335_SR_SUBCORE_PWRSW 26 ++#define RES4335_SR_SLEEP 27 ++#define RES4335_HT_START 28 ++#define RES4335_HT_AVAIL 29 ++#define RES4335_MACPHY_CLKAVAIL 30 ++ ++/* 4335 Chip specific ChipStatus register bits */ ++#define CST4335_SPROM_MASK 0x00000020 ++#define CST4335_SFLASH_MASK 0x00000040 ++#define CST4335_RES_INIT_MODE_SHIFT 7 ++#define CST4335_RES_INIT_MODE_MASK 0x00000180 ++#define CST4335_CHIPMODE_MASK 0xF ++#define CST4335_CHIPMODE_SDIOD(cs) (((cs) & (1 << 0)) != 0) /* SDIO */ ++#define CST4335_CHIPMODE_GSPI(cs) (((cs) & (1 << 1)) != 0) /* gSPI */ ++#define CST4335_CHIPMODE_USB20D(cs) (((cs) & (1 << 2)) != 0) /* USB || USBDA */ ++#define CST4335_CHIPMODE_PCIE(cs) (((cs) & (1 << 3)) != 0) /* PCIE */ ++ ++/* 4335 Chip specific ChipControl1 register bits */ ++#define CCTRL1_4335_GPIO_SEL (1 << 0) /* 1=select GPIOs to be muxed out */ ++#define CCTRL1_4335_SDIO_HOST_WAKE (1 << 2) /* SDIO: 1=configure GPIO0 for host wake */ ++ ++ ++#define CR4_RAM_BASE (0x180000) ++ ++/* 4335 resources--END */ ++ ++/* GCI chipcontrol register indices */ ++#define CC_GCI_CHIPCTRL_00 (0) ++#define CC_GCI_CHIPCTRL_01 (1) ++#define CC_GCI_CHIPCTRL_02 (2) ++#define CC_GCI_CHIPCTRL_03 (3) ++#define CC_GCI_CHIPCTRL_04 (4) ++#define CC_GCI_CHIPCTRL_05 (5) ++#define CC_GCI_CHIPCTRL_06 (6) ++#define CC_GCI_CHIPCTRL_07 (7) ++#define CC_GCI_CHIPCTRL_08 (8) ++ ++#define CC_GCI_NUMCHIPCTRLREGS(cap1) ((cap1 & 0xF00) >> 8) ++ ++/* 4335 pins ++* note: only the values set as default/used are added here. ++*/ ++#define CC4335_PIN_GPIO_00 (0) ++#define CC4335_PIN_GPIO_01 (1) ++#define CC4335_PIN_GPIO_02 (2) ++#define CC4335_PIN_GPIO_03 (3) ++#define CC4335_PIN_GPIO_04 (4) ++#define CC4335_PIN_GPIO_05 (5) ++#define CC4335_PIN_GPIO_06 (6) ++#define CC4335_PIN_GPIO_07 (7) ++#define CC4335_PIN_GPIO_08 (8) ++#define CC4335_PIN_GPIO_09 (9) ++#define CC4335_PIN_GPIO_10 (10) ++#define CC4335_PIN_GPIO_11 (11) ++#define CC4335_PIN_GPIO_12 (12) ++#define CC4335_PIN_GPIO_13 (13) ++#define CC4335_PIN_GPIO_14 (14) ++#define CC4335_PIN_GPIO_15 (15) ++#define CC4335_PIN_SDIO_CLK (16) ++#define CC4335_PIN_SDIO_CMD (17) ++#define CC4335_PIN_SDIO_DATA0 (18) ++#define CC4335_PIN_SDIO_DATA1 (19) ++#define CC4335_PIN_SDIO_DATA2 (20) ++#define CC4335_PIN_SDIO_DATA3 (21) ++#define CC4335_PIN_RF_SW_CTRL_0 (22) ++#define CC4335_PIN_RF_SW_CTRL_1 (23) ++#define CC4335_PIN_RF_SW_CTRL_2 (24) ++#define CC4335_PIN_RF_SW_CTRL_3 (25) ++#define CC4335_PIN_RF_SW_CTRL_4 (26) ++#define CC4335_PIN_RF_SW_CTRL_5 (27) ++#define CC4335_PIN_RF_SW_CTRL_6 (28) ++#define CC4335_PIN_RF_SW_CTRL_7 (29) ++#define CC4335_PIN_RF_SW_CTRL_8 (30) ++#define CC4335_PIN_RF_SW_CTRL_9 (31) ++ ++/* 4335 GCI function sel values ++*/ ++#define CC4335_FNSEL_HWDEF (0) ++#define CC4335_FNSEL_SAMEASPIN (1) ++#define CC4335_FNSEL_GPIO0 (2) ++#define CC4335_FNSEL_GPIO1 (3) ++#define CC4335_FNSEL_GCI0 (4) ++#define CC4335_FNSEL_GCI1 (5) ++#define CC4335_FNSEL_UART (6) ++#define CC4335_FNSEL_SFLASH (7) ++#define CC4335_FNSEL_SPROM (8) ++#define CC4335_FNSEL_MISC0 (9) ++#define CC4335_FNSEL_MISC1 (10) ++#define CC4335_FNSEL_MISC2 (11) ++#define CC4335_FNSEL_IND (12) ++#define CC4335_FNSEL_PDN (13) ++#define CC4335_FNSEL_PUP (14) ++#define CC4335_FNSEL_TRI (15) ++ ++/* find the 4 bit mask given the bit position */ ++#define GCIMASK(pos) (((uint32)0xF) << pos) ++ ++/* get the value which can be used to directly OR with chipcontrol reg */ ++#define GCIPOSVAL(val, pos) ((((uint32)val) << pos) & GCIMASK(pos)) ++ ++/* 4335 MUX options. each nibble belongs to a setting. Non-zero value specifies a logic ++* for now only UART for bootloader. ++*/ ++#define MUXENAB4335_UART_MASK (0x0000000f) ++ ++ ++/* defines to detect active host interface in use */ ++#define CHIP_HOSTIF_USB(sih) (si_chip_hostif(sih) & CST4360_MODE_USB) ++ ++/* ++* Maximum delay for the PMU state transition in us. ++* This is an upper bound intended for spinwaits etc. ++*/ ++#define PMU_MAX_TRANSITION_DLY 15000 ++ ++/* PMU resource up transition time in ILP cycles */ ++#define PMURES_UP_TRANSITION 2 ++ ++ ++/* SECI configuration */ ++#define SECI_MODE_UART 0x0 ++#define SECI_MODE_SECI 0x1 ++#define SECI_MODE_LEGACY_3WIRE_BT 0x2 ++#define SECI_MODE_LEGACY_3WIRE_WLAN 0x3 ++#define SECI_MODE_HALF_SECI 0x4 ++ ++#define SECI_RESET (1 << 0) ++#define SECI_RESET_BAR_UART (1 << 1) ++#define SECI_ENAB_SECI_ECI (1 << 2) ++#define SECI_ENAB_SECIOUT_DIS (1 << 3) ++#define SECI_MODE_MASK 0x7 ++#define SECI_MODE_SHIFT 4 /* (bits 5, 6, 7) */ ++#define SECI_UPD_SECI (1 << 7) ++ ++#define SECI_SIGNOFF_0 0xDB ++#define SECI_SIGNOFF_1 0 ++ ++/* seci clk_ctl_st bits */ ++#define CLKCTL_STS_SECI_CLK_REQ (1 << 8) ++#define CLKCTL_STS_SECI_CLK_AVAIL (1 << 24) ++ ++#define SECI_UART_MSR_CTS_STATE (1 << 0) ++#define SECI_UART_MSR_RTS_STATE (1 << 1) ++#define SECI_UART_SECI_IN_STATE (1 << 2) ++#define SECI_UART_SECI_IN2_STATE (1 << 3) ++ ++/* SECI UART LCR/MCR register bits */ ++#define SECI_UART_LCR_STOP_BITS (1 << 0) /* 0 - 1bit, 1 - 2bits */ ++#define SECI_UART_LCR_PARITY_EN (1 << 1) ++#define SECI_UART_LCR_PARITY (1 << 2) /* 0 - odd, 1 - even */ ++#define SECI_UART_LCR_RX_EN (1 << 3) ++#define SECI_UART_LCR_LBRK_CTRL (1 << 4) /* 1 => SECI_OUT held low */ ++#define SECI_UART_LCR_TXO_EN (1 << 5) ++#define SECI_UART_LCR_RTSO_EN (1 << 6) ++#define SECI_UART_LCR_SLIPMODE_EN (1 << 7) ++#define SECI_UART_LCR_RXCRC_CHK (1 << 8) ++#define SECI_UART_LCR_TXCRC_INV (1 << 9) ++#define SECI_UART_LCR_TXCRC_LSBF (1 << 10) ++#define SECI_UART_LCR_TXCRC_EN (1 << 11) ++ ++#define SECI_UART_MCR_TX_EN (1 << 0) ++#define SECI_UART_MCR_PRTS (1 << 1) ++#define SECI_UART_MCR_SWFLCTRL_EN (1 << 2) ++#define SECI_UART_MCR_HIGHRATE_EN (1 << 3) ++#define SECI_UART_MCR_LOOPBK_EN (1 << 4) ++#define SECI_UART_MCR_AUTO_RTS (1 << 5) ++#define SECI_UART_MCR_AUTO_TX_DIS (1 << 6) ++#define SECI_UART_MCR_BAUD_ADJ_EN (1 << 7) ++#define SECI_UART_MCR_XONOFF_RPT (1 << 9) ++ ++/* WLAN channel numbers - used from wifi.h */ ++ ++/* WLAN BW */ ++#define ECI_BW_20 0x0 ++#define ECI_BW_25 0x1 ++#define ECI_BW_30 0x2 ++#define ECI_BW_35 0x3 ++#define ECI_BW_40 0x4 ++#define ECI_BW_45 0x5 ++#define ECI_BW_50 0x6 ++#define ECI_BW_ALL 0x7 ++ ++/* WLAN - number of antenna */ ++#define WLAN_NUM_ANT1 TXANT_0 ++#define WLAN_NUM_ANT2 TXANT_1 ++ ++#endif /* _SBCHIPC_H */ +diff --git a/drivers/net/wireless/ap6211/include/sbconfig.h b/drivers/net/wireless/ap6211/include/sbconfig.h +new file mode 100755 +index 0000000..73ddadd +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/sbconfig.h +@@ -0,0 +1,282 @@ ++/* ++ * Broadcom SiliconBackplane hardware register definitions. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: sbconfig.h 241182 2011-02-17 21:50:03Z $ ++ */ ++ ++#ifndef _SBCONFIG_H ++#define _SBCONFIG_H ++ ++/* cpp contortions to concatenate w/arg prescan */ ++#ifndef PAD ++#define _PADLINE(line) pad ## line ++#define _XSTR(line) _PADLINE(line) ++#define PAD _XSTR(__LINE__) ++#endif ++ ++/* enumeration in SB is based on the premise that cores are contiguos in the ++ * enumeration space. ++ */ ++#define SB_BUS_SIZE 0x10000 /* Each bus gets 64Kbytes for cores */ ++#define SB_BUS_BASE(b) (SI_ENUM_BASE + (b) * SB_BUS_SIZE) ++#define SB_BUS_MAXCORES (SB_BUS_SIZE / SI_CORE_SIZE) /* Max cores per bus */ ++ ++/* ++ * Sonics Configuration Space Registers. ++ */ ++#define SBCONFIGOFF 0xf00 /* core sbconfig regs are top 256bytes of regs */ ++#define SBCONFIGSIZE 256 /* sizeof (sbconfig_t) */ ++ ++#define SBIPSFLAG 0x08 ++#define SBTPSFLAG 0x18 ++#define SBTMERRLOGA 0x48 /* sonics >= 2.3 */ ++#define SBTMERRLOG 0x50 /* sonics >= 2.3 */ ++#define SBADMATCH3 0x60 ++#define SBADMATCH2 0x68 ++#define SBADMATCH1 0x70 ++#define SBIMSTATE 0x90 ++#define SBINTVEC 0x94 ++#define SBTMSTATELOW 0x98 ++#define SBTMSTATEHIGH 0x9c ++#define SBBWA0 0xa0 ++#define SBIMCONFIGLOW 0xa8 ++#define SBIMCONFIGHIGH 0xac ++#define SBADMATCH0 0xb0 ++#define SBTMCONFIGLOW 0xb8 ++#define SBTMCONFIGHIGH 0xbc ++#define SBBCONFIG 0xc0 ++#define SBBSTATE 0xc8 ++#define SBACTCNFG 0xd8 ++#define SBFLAGST 0xe8 ++#define SBIDLOW 0xf8 ++#define SBIDHIGH 0xfc ++ ++/* All the previous registers are above SBCONFIGOFF, but with Sonics 2.3, we have ++ * a few registers *below* that line. I think it would be very confusing to try ++ * and change the value of SBCONFIGOFF, so I'm definig them as absolute offsets here, ++ */ ++ ++#define SBIMERRLOGA 0xea8 ++#define SBIMERRLOG 0xeb0 ++#define SBTMPORTCONNID0 0xed8 ++#define SBTMPORTLOCK0 0xef8 ++ ++#ifndef _LANGUAGE_ASSEMBLY ++ ++typedef volatile struct _sbconfig { ++ uint32 PAD[2]; ++ uint32 sbipsflag; /* initiator port ocp slave flag */ ++ uint32 PAD[3]; ++ uint32 sbtpsflag; /* target port ocp slave flag */ ++ uint32 PAD[11]; ++ uint32 sbtmerrloga; /* (sonics >= 2.3) */ ++ uint32 PAD; ++ uint32 sbtmerrlog; /* (sonics >= 2.3) */ ++ uint32 PAD[3]; ++ uint32 sbadmatch3; /* address match3 */ ++ uint32 PAD; ++ uint32 sbadmatch2; /* address match2 */ ++ uint32 PAD; ++ uint32 sbadmatch1; /* address match1 */ ++ uint32 PAD[7]; ++ uint32 sbimstate; /* initiator agent state */ ++ uint32 sbintvec; /* interrupt mask */ ++ uint32 sbtmstatelow; /* target state */ ++ uint32 sbtmstatehigh; /* target state */ ++ uint32 sbbwa0; /* bandwidth allocation table0 */ ++ uint32 PAD; ++ uint32 sbimconfiglow; /* initiator configuration */ ++ uint32 sbimconfighigh; /* initiator configuration */ ++ uint32 sbadmatch0; /* address match0 */ ++ uint32 PAD; ++ uint32 sbtmconfiglow; /* target configuration */ ++ uint32 sbtmconfighigh; /* target configuration */ ++ uint32 sbbconfig; /* broadcast configuration */ ++ uint32 PAD; ++ uint32 sbbstate; /* broadcast state */ ++ uint32 PAD[3]; ++ uint32 sbactcnfg; /* activate configuration */ ++ uint32 PAD[3]; ++ uint32 sbflagst; /* current sbflags */ ++ uint32 PAD[3]; ++ uint32 sbidlow; /* identification */ ++ uint32 sbidhigh; /* identification */ ++} sbconfig_t; ++ ++#endif /* _LANGUAGE_ASSEMBLY */ ++ ++/* sbipsflag */ ++#define SBIPS_INT1_MASK 0x3f /* which sbflags get routed to mips interrupt 1 */ ++#define SBIPS_INT1_SHIFT 0 ++#define SBIPS_INT2_MASK 0x3f00 /* which sbflags get routed to mips interrupt 2 */ ++#define SBIPS_INT2_SHIFT 8 ++#define SBIPS_INT3_MASK 0x3f0000 /* which sbflags get routed to mips interrupt 3 */ ++#define SBIPS_INT3_SHIFT 16 ++#define SBIPS_INT4_MASK 0x3f000000 /* which sbflags get routed to mips interrupt 4 */ ++#define SBIPS_INT4_SHIFT 24 ++ ++/* sbtpsflag */ ++#define SBTPS_NUM0_MASK 0x3f /* interrupt sbFlag # generated by this core */ ++#define SBTPS_F0EN0 0x40 /* interrupt is always sent on the backplane */ ++ ++/* sbtmerrlog */ ++#define SBTMEL_CM 0x00000007 /* command */ ++#define SBTMEL_CI 0x0000ff00 /* connection id */ ++#define SBTMEL_EC 0x0f000000 /* error code */ ++#define SBTMEL_ME 0x80000000 /* multiple error */ ++ ++/* sbimstate */ ++#define SBIM_PC 0xf /* pipecount */ ++#define SBIM_AP_MASK 0x30 /* arbitration policy */ ++#define SBIM_AP_BOTH 0x00 /* use both timeslaces and token */ ++#define SBIM_AP_TS 0x10 /* use timesliaces only */ ++#define SBIM_AP_TK 0x20 /* use token only */ ++#define SBIM_AP_RSV 0x30 /* reserved */ ++#define SBIM_IBE 0x20000 /* inbanderror */ ++#define SBIM_TO 0x40000 /* timeout */ ++#define SBIM_BY 0x01800000 /* busy (sonics >= 2.3) */ ++#define SBIM_RJ 0x02000000 /* reject (sonics >= 2.3) */ ++ ++/* sbtmstatelow */ ++#define SBTML_RESET 0x0001 /* reset */ ++#define SBTML_REJ_MASK 0x0006 /* reject field */ ++#define SBTML_REJ 0x0002 /* reject */ ++#define SBTML_TMPREJ 0x0004 /* temporary reject, for error recovery */ ++ ++#define SBTML_SICF_SHIFT 16 /* Shift to locate the SI control flags in sbtml */ ++ ++/* sbtmstatehigh */ ++#define SBTMH_SERR 0x0001 /* serror */ ++#define SBTMH_INT 0x0002 /* interrupt */ ++#define SBTMH_BUSY 0x0004 /* busy */ ++#define SBTMH_TO 0x0020 /* timeout (sonics >= 2.3) */ ++ ++#define SBTMH_SISF_SHIFT 16 /* Shift to locate the SI status flags in sbtmh */ ++ ++/* sbbwa0 */ ++#define SBBWA_TAB0_MASK 0xffff /* lookup table 0 */ ++#define SBBWA_TAB1_MASK 0xffff /* lookup table 1 */ ++#define SBBWA_TAB1_SHIFT 16 ++ ++/* sbimconfiglow */ ++#define SBIMCL_STO_MASK 0x7 /* service timeout */ ++#define SBIMCL_RTO_MASK 0x70 /* request timeout */ ++#define SBIMCL_RTO_SHIFT 4 ++#define SBIMCL_CID_MASK 0xff0000 /* connection id */ ++#define SBIMCL_CID_SHIFT 16 ++ ++/* sbimconfighigh */ ++#define SBIMCH_IEM_MASK 0xc /* inband error mode */ ++#define SBIMCH_TEM_MASK 0x30 /* timeout error mode */ ++#define SBIMCH_TEM_SHIFT 4 ++#define SBIMCH_BEM_MASK 0xc0 /* bus error mode */ ++#define SBIMCH_BEM_SHIFT 6 ++ ++/* sbadmatch0 */ ++#define SBAM_TYPE_MASK 0x3 /* address type */ ++#define SBAM_AD64 0x4 /* reserved */ ++#define SBAM_ADINT0_MASK 0xf8 /* type0 size */ ++#define SBAM_ADINT0_SHIFT 3 ++#define SBAM_ADINT1_MASK 0x1f8 /* type1 size */ ++#define SBAM_ADINT1_SHIFT 3 ++#define SBAM_ADINT2_MASK 0x1f8 /* type2 size */ ++#define SBAM_ADINT2_SHIFT 3 ++#define SBAM_ADEN 0x400 /* enable */ ++#define SBAM_ADNEG 0x800 /* negative decode */ ++#define SBAM_BASE0_MASK 0xffffff00 /* type0 base address */ ++#define SBAM_BASE0_SHIFT 8 ++#define SBAM_BASE1_MASK 0xfffff000 /* type1 base address for the core */ ++#define SBAM_BASE1_SHIFT 12 ++#define SBAM_BASE2_MASK 0xffff0000 /* type2 base address for the core */ ++#define SBAM_BASE2_SHIFT 16 ++ ++/* sbtmconfiglow */ ++#define SBTMCL_CD_MASK 0xff /* clock divide */ ++#define SBTMCL_CO_MASK 0xf800 /* clock offset */ ++#define SBTMCL_CO_SHIFT 11 ++#define SBTMCL_IF_MASK 0xfc0000 /* interrupt flags */ ++#define SBTMCL_IF_SHIFT 18 ++#define SBTMCL_IM_MASK 0x3000000 /* interrupt mode */ ++#define SBTMCL_IM_SHIFT 24 ++ ++/* sbtmconfighigh */ ++#define SBTMCH_BM_MASK 0x3 /* busy mode */ ++#define SBTMCH_RM_MASK 0x3 /* retry mode */ ++#define SBTMCH_RM_SHIFT 2 ++#define SBTMCH_SM_MASK 0x30 /* stop mode */ ++#define SBTMCH_SM_SHIFT 4 ++#define SBTMCH_EM_MASK 0x300 /* sb error mode */ ++#define SBTMCH_EM_SHIFT 8 ++#define SBTMCH_IM_MASK 0xc00 /* int mode */ ++#define SBTMCH_IM_SHIFT 10 ++ ++/* sbbconfig */ ++#define SBBC_LAT_MASK 0x3 /* sb latency */ ++#define SBBC_MAX0_MASK 0xf0000 /* maxccntr0 */ ++#define SBBC_MAX0_SHIFT 16 ++#define SBBC_MAX1_MASK 0xf00000 /* maxccntr1 */ ++#define SBBC_MAX1_SHIFT 20 ++ ++/* sbbstate */ ++#define SBBS_SRD 0x1 /* st reg disable */ ++#define SBBS_HRD 0x2 /* hold reg disable */ ++ ++/* sbidlow */ ++#define SBIDL_CS_MASK 0x3 /* config space */ ++#define SBIDL_AR_MASK 0x38 /* # address ranges supported */ ++#define SBIDL_AR_SHIFT 3 ++#define SBIDL_SYNCH 0x40 /* sync */ ++#define SBIDL_INIT 0x80 /* initiator */ ++#define SBIDL_MINLAT_MASK 0xf00 /* minimum backplane latency */ ++#define SBIDL_MINLAT_SHIFT 8 ++#define SBIDL_MAXLAT 0xf000 /* maximum backplane latency */ ++#define SBIDL_MAXLAT_SHIFT 12 ++#define SBIDL_FIRST 0x10000 /* this initiator is first */ ++#define SBIDL_CW_MASK 0xc0000 /* cycle counter width */ ++#define SBIDL_CW_SHIFT 18 ++#define SBIDL_TP_MASK 0xf00000 /* target ports */ ++#define SBIDL_TP_SHIFT 20 ++#define SBIDL_IP_MASK 0xf000000 /* initiator ports */ ++#define SBIDL_IP_SHIFT 24 ++#define SBIDL_RV_MASK 0xf0000000 /* sonics backplane revision code */ ++#define SBIDL_RV_SHIFT 28 ++#define SBIDL_RV_2_2 0x00000000 /* version 2.2 or earlier */ ++#define SBIDL_RV_2_3 0x10000000 /* version 2.3 */ ++ ++/* sbidhigh */ ++#define SBIDH_RC_MASK 0x000f /* revision code */ ++#define SBIDH_RCE_MASK 0x7000 /* revision code extension field */ ++#define SBIDH_RCE_SHIFT 8 ++#define SBCOREREV(sbidh) \ ++ ((((sbidh) & SBIDH_RCE_MASK) >> SBIDH_RCE_SHIFT) | ((sbidh) & SBIDH_RC_MASK)) ++#define SBIDH_CC_MASK 0x8ff0 /* core code */ ++#define SBIDH_CC_SHIFT 4 ++#define SBIDH_VC_MASK 0xffff0000 /* vendor code */ ++#define SBIDH_VC_SHIFT 16 ++ ++#define SB_COMMIT 0xfd8 /* update buffered registers value */ ++ ++/* vendor codes */ ++#define SB_VEND_BCM 0x4243 /* Broadcom's SB vendor code */ ++ ++#endif /* _SBCONFIG_H */ +diff --git a/drivers/net/wireless/ap6211/include/sbhnddma.h b/drivers/net/wireless/ap6211/include/sbhnddma.h +new file mode 100755 +index 0000000..40ebd8a +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/sbhnddma.h +@@ -0,0 +1,384 @@ ++/* ++ * Generic Broadcom Home Networking Division (HND) DMA engine HW interface ++ * This supports the following chips: BCM42xx, 44xx, 47xx . ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: sbhnddma.h 309193 2012-01-19 00:03:57Z $ ++ */ ++ ++#ifndef _sbhnddma_h_ ++#define _sbhnddma_h_ ++ ++/* DMA structure: ++ * support two DMA engines: 32 bits address or 64 bit addressing ++ * basic DMA register set is per channel(transmit or receive) ++ * a pair of channels is defined for convenience ++ */ ++ ++ ++/* 32 bits addressing */ ++ ++/* dma registers per channel(xmt or rcv) */ ++typedef volatile struct { ++ uint32 control; /* enable, et al */ ++ uint32 addr; /* descriptor ring base address (4K aligned) */ ++ uint32 ptr; /* last descriptor posted to chip */ ++ uint32 status; /* current active descriptor, et al */ ++} dma32regs_t; ++ ++typedef volatile struct { ++ dma32regs_t xmt; /* dma tx channel */ ++ dma32regs_t rcv; /* dma rx channel */ ++} dma32regp_t; ++ ++typedef volatile struct { /* diag access */ ++ uint32 fifoaddr; /* diag address */ ++ uint32 fifodatalow; /* low 32bits of data */ ++ uint32 fifodatahigh; /* high 32bits of data */ ++ uint32 pad; /* reserved */ ++} dma32diag_t; ++ ++/* ++ * DMA Descriptor ++ * Descriptors are only read by the hardware, never written back. ++ */ ++typedef volatile struct { ++ uint32 ctrl; /* misc control bits & bufcount */ ++ uint32 addr; /* data buffer address */ ++} dma32dd_t; ++ ++/* ++ * Each descriptor ring must be 4096byte aligned, and fit within a single 4096byte page. ++ */ ++#define D32RINGALIGN_BITS 12 ++#define D32MAXRINGSZ (1 << D32RINGALIGN_BITS) ++#define D32RINGALIGN (1 << D32RINGALIGN_BITS) ++ ++#define D32MAXDD (D32MAXRINGSZ / sizeof (dma32dd_t)) ++ ++/* transmit channel control */ ++#define XC_XE ((uint32)1 << 0) /* transmit enable */ ++#define XC_SE ((uint32)1 << 1) /* transmit suspend request */ ++#define XC_LE ((uint32)1 << 2) /* loopback enable */ ++#define XC_FL ((uint32)1 << 4) /* flush request */ ++#define XC_MR_MASK 0x000000C0 /* Multiple outstanding reads */ ++#define XC_MR_SHIFT 6 ++#define XC_PD ((uint32)1 << 11) /* parity check disable */ ++#define XC_AE ((uint32)3 << 16) /* address extension bits */ ++#define XC_AE_SHIFT 16 ++#define XC_BL_MASK 0x001C0000 /* BurstLen bits */ ++#define XC_BL_SHIFT 18 ++#define XC_PC_MASK 0x00E00000 /* Prefetch control */ ++#define XC_PC_SHIFT 21 ++#define XC_PT_MASK 0x03000000 /* Prefetch threshold */ ++#define XC_PT_SHIFT 24 ++ ++/* Multiple outstanding reads */ ++#define DMA_MR_1 0 ++#define DMA_MR_2 1 ++/* 2, 3: reserved */ ++ ++/* DMA Burst Length in bytes */ ++#define DMA_BL_16 0 ++#define DMA_BL_32 1 ++#define DMA_BL_64 2 ++#define DMA_BL_128 3 ++#define DMA_BL_256 4 ++#define DMA_BL_512 5 ++#define DMA_BL_1024 6 ++ ++/* Prefetch control */ ++#define DMA_PC_0 0 ++#define DMA_PC_4 1 ++#define DMA_PC_8 2 ++#define DMA_PC_16 3 ++/* others: reserved */ ++ ++/* Prefetch threshold */ ++#define DMA_PT_1 0 ++#define DMA_PT_2 1 ++#define DMA_PT_4 2 ++#define DMA_PT_8 3 ++ ++/* transmit descriptor table pointer */ ++#define XP_LD_MASK 0xfff /* last valid descriptor */ ++ ++/* transmit channel status */ ++#define XS_CD_MASK 0x0fff /* current descriptor pointer */ ++#define XS_XS_MASK 0xf000 /* transmit state */ ++#define XS_XS_SHIFT 12 ++#define XS_XS_DISABLED 0x0000 /* disabled */ ++#define XS_XS_ACTIVE 0x1000 /* active */ ++#define XS_XS_IDLE 0x2000 /* idle wait */ ++#define XS_XS_STOPPED 0x3000 /* stopped */ ++#define XS_XS_SUSP 0x4000 /* suspend pending */ ++#define XS_XE_MASK 0xf0000 /* transmit errors */ ++#define XS_XE_SHIFT 16 ++#define XS_XE_NOERR 0x00000 /* no error */ ++#define XS_XE_DPE 0x10000 /* descriptor protocol error */ ++#define XS_XE_DFU 0x20000 /* data fifo underrun */ ++#define XS_XE_BEBR 0x30000 /* bus error on buffer read */ ++#define XS_XE_BEDA 0x40000 /* bus error on descriptor access */ ++#define XS_AD_MASK 0xfff00000 /* active descriptor */ ++#define XS_AD_SHIFT 20 ++ ++/* receive channel control */ ++#define RC_RE ((uint32)1 << 0) /* receive enable */ ++#define RC_RO_MASK 0xfe /* receive frame offset */ ++#define RC_RO_SHIFT 1 ++#define RC_FM ((uint32)1 << 8) /* direct fifo receive (pio) mode */ ++#define RC_SH ((uint32)1 << 9) /* separate rx header descriptor enable */ ++#define RC_OC ((uint32)1 << 10) /* overflow continue */ ++#define RC_PD ((uint32)1 << 11) /* parity check disable */ ++#define RC_AE ((uint32)3 << 16) /* address extension bits */ ++#define RC_AE_SHIFT 16 ++#define RC_BL_MASK 0x001C0000 /* BurstLen bits */ ++#define RC_BL_SHIFT 18 ++#define RC_PC_MASK 0x00E00000 /* Prefetch control */ ++#define RC_PC_SHIFT 21 ++#define RC_PT_MASK 0x03000000 /* Prefetch threshold */ ++#define RC_PT_SHIFT 24 ++ ++/* receive descriptor table pointer */ ++#define RP_LD_MASK 0xfff /* last valid descriptor */ ++ ++/* receive channel status */ ++#define RS_CD_MASK 0x0fff /* current descriptor pointer */ ++#define RS_RS_MASK 0xf000 /* receive state */ ++#define RS_RS_SHIFT 12 ++#define RS_RS_DISABLED 0x0000 /* disabled */ ++#define RS_RS_ACTIVE 0x1000 /* active */ ++#define RS_RS_IDLE 0x2000 /* idle wait */ ++#define RS_RS_STOPPED 0x3000 /* reserved */ ++#define RS_RE_MASK 0xf0000 /* receive errors */ ++#define RS_RE_SHIFT 16 ++#define RS_RE_NOERR 0x00000 /* no error */ ++#define RS_RE_DPE 0x10000 /* descriptor protocol error */ ++#define RS_RE_DFO 0x20000 /* data fifo overflow */ ++#define RS_RE_BEBW 0x30000 /* bus error on buffer write */ ++#define RS_RE_BEDA 0x40000 /* bus error on descriptor access */ ++#define RS_AD_MASK 0xfff00000 /* active descriptor */ ++#define RS_AD_SHIFT 20 ++ ++/* fifoaddr */ ++#define FA_OFF_MASK 0xffff /* offset */ ++#define FA_SEL_MASK 0xf0000 /* select */ ++#define FA_SEL_SHIFT 16 ++#define FA_SEL_XDD 0x00000 /* transmit dma data */ ++#define FA_SEL_XDP 0x10000 /* transmit dma pointers */ ++#define FA_SEL_RDD 0x40000 /* receive dma data */ ++#define FA_SEL_RDP 0x50000 /* receive dma pointers */ ++#define FA_SEL_XFD 0x80000 /* transmit fifo data */ ++#define FA_SEL_XFP 0x90000 /* transmit fifo pointers */ ++#define FA_SEL_RFD 0xc0000 /* receive fifo data */ ++#define FA_SEL_RFP 0xd0000 /* receive fifo pointers */ ++#define FA_SEL_RSD 0xe0000 /* receive frame status data */ ++#define FA_SEL_RSP 0xf0000 /* receive frame status pointers */ ++ ++/* descriptor control flags */ ++#define CTRL_BC_MASK 0x00001fff /* buffer byte count, real data len must <= 4KB */ ++#define CTRL_AE ((uint32)3 << 16) /* address extension bits */ ++#define CTRL_AE_SHIFT 16 ++#define CTRL_PARITY ((uint32)3 << 18) /* parity bit */ ++#define CTRL_EOT ((uint32)1 << 28) /* end of descriptor table */ ++#define CTRL_IOC ((uint32)1 << 29) /* interrupt on completion */ ++#define CTRL_EOF ((uint32)1 << 30) /* end of frame */ ++#define CTRL_SOF ((uint32)1 << 31) /* start of frame */ ++ ++/* control flags in the range [27:20] are core-specific and not defined here */ ++#define CTRL_CORE_MASK 0x0ff00000 ++ ++/* 64 bits addressing */ ++ ++/* dma registers per channel(xmt or rcv) */ ++typedef volatile struct { ++ uint32 control; /* enable, et al */ ++ uint32 ptr; /* last descriptor posted to chip */ ++ uint32 addrlow; /* descriptor ring base address low 32-bits (8K aligned) */ ++ uint32 addrhigh; /* descriptor ring base address bits 63:32 (8K aligned) */ ++ uint32 status0; /* current descriptor, xmt state */ ++ uint32 status1; /* active descriptor, xmt error */ ++} dma64regs_t; ++ ++typedef volatile struct { ++ dma64regs_t tx; /* dma64 tx channel */ ++ dma64regs_t rx; /* dma64 rx channel */ ++} dma64regp_t; ++ ++typedef volatile struct { /* diag access */ ++ uint32 fifoaddr; /* diag address */ ++ uint32 fifodatalow; /* low 32bits of data */ ++ uint32 fifodatahigh; /* high 32bits of data */ ++ uint32 pad; /* reserved */ ++} dma64diag_t; ++ ++/* ++ * DMA Descriptor ++ * Descriptors are only read by the hardware, never written back. ++ */ ++typedef volatile struct { ++ uint32 ctrl1; /* misc control bits */ ++ uint32 ctrl2; /* buffer count and address extension */ ++ uint32 addrlow; /* memory address of the date buffer, bits 31:0 */ ++ uint32 addrhigh; /* memory address of the date buffer, bits 63:32 */ ++} dma64dd_t; ++ ++/* ++ * Each descriptor ring must be 8kB aligned, and fit within a contiguous 8kB physical addresss. ++ */ ++#define D64RINGALIGN_BITS 13 ++#define D64MAXRINGSZ (1 << D64RINGALIGN_BITS) ++#define D64RINGALIGN (1 << D64RINGALIGN_BITS) ++ ++#define D64MAXDD (D64MAXRINGSZ / sizeof (dma64dd_t)) ++ ++/* transmit channel control */ ++#define D64_XC_XE 0x00000001 /* transmit enable */ ++#define D64_XC_SE 0x00000002 /* transmit suspend request */ ++#define D64_XC_LE 0x00000004 /* loopback enable */ ++#define D64_XC_FL 0x00000010 /* flush request */ ++#define D64_XC_MR_MASK 0x000000C0 /* Multiple outstanding reads */ ++#define D64_XC_MR_SHIFT 6 ++#define D64_XC_PD 0x00000800 /* parity check disable */ ++#define D64_XC_AE 0x00030000 /* address extension bits */ ++#define D64_XC_AE_SHIFT 16 ++#define D64_XC_BL_MASK 0x001C0000 /* BurstLen bits */ ++#define D64_XC_BL_SHIFT 18 ++#define D64_XC_PC_MASK 0x00E00000 /* Prefetch control */ ++#define D64_XC_PC_SHIFT 21 ++#define D64_XC_PT_MASK 0x03000000 /* Prefetch threshold */ ++#define D64_XC_PT_SHIFT 24 ++ ++/* transmit descriptor table pointer */ ++#define D64_XP_LD_MASK 0x00001fff /* last valid descriptor */ ++ ++/* transmit channel status */ ++#define D64_XS0_CD_MASK 0x00001fff /* current descriptor pointer */ ++#define D64_XS0_XS_MASK 0xf0000000 /* transmit state */ ++#define D64_XS0_XS_SHIFT 28 ++#define D64_XS0_XS_DISABLED 0x00000000 /* disabled */ ++#define D64_XS0_XS_ACTIVE 0x10000000 /* active */ ++#define D64_XS0_XS_IDLE 0x20000000 /* idle wait */ ++#define D64_XS0_XS_STOPPED 0x30000000 /* stopped */ ++#define D64_XS0_XS_SUSP 0x40000000 /* suspend pending */ ++ ++#define D64_XS1_AD_MASK 0x00001fff /* active descriptor */ ++#define D64_XS1_XE_MASK 0xf0000000 /* transmit errors */ ++#define D64_XS1_XE_SHIFT 28 ++#define D64_XS1_XE_NOERR 0x00000000 /* no error */ ++#define D64_XS1_XE_DPE 0x10000000 /* descriptor protocol error */ ++#define D64_XS1_XE_DFU 0x20000000 /* data fifo underrun */ ++#define D64_XS1_XE_DTE 0x30000000 /* data transfer error */ ++#define D64_XS1_XE_DESRE 0x40000000 /* descriptor read error */ ++#define D64_XS1_XE_COREE 0x50000000 /* core error */ ++ ++/* receive channel control */ ++#define D64_RC_RE 0x00000001 /* receive enable */ ++#define D64_RC_RO_MASK 0x000000fe /* receive frame offset */ ++#define D64_RC_RO_SHIFT 1 ++#define D64_RC_FM 0x00000100 /* direct fifo receive (pio) mode */ ++#define D64_RC_SH 0x00000200 /* separate rx header descriptor enable */ ++#define D64_RC_OC 0x00000400 /* overflow continue */ ++#define D64_RC_PD 0x00000800 /* parity check disable */ ++#define D64_RC_AE 0x00030000 /* address extension bits */ ++#define D64_RC_AE_SHIFT 16 ++#define D64_RC_BL_MASK 0x001C0000 /* BurstLen bits */ ++#define D64_RC_BL_SHIFT 18 ++#define D64_RC_PC_MASK 0x00E00000 /* Prefetch control */ ++#define D64_RC_PC_SHIFT 21 ++#define D64_RC_PT_MASK 0x03000000 /* Prefetch threshold */ ++#define D64_RC_PT_SHIFT 24 ++ ++/* flags for dma controller */ ++#define DMA_CTRL_PEN (1 << 0) /* partity enable */ ++#define DMA_CTRL_ROC (1 << 1) /* rx overflow continue */ ++#define DMA_CTRL_RXMULTI (1 << 2) /* allow rx scatter to multiple descriptors */ ++#define DMA_CTRL_UNFRAMED (1 << 3) /* Unframed Rx/Tx data */ ++#define DMA_CTRL_USB_BOUNDRY4KB_WAR (1 << 4) ++#define DMA_CTRL_DMA_AVOIDANCE_WAR (1 << 5) /* DMA avoidance WAR for 4331 */ ++ ++/* receive descriptor table pointer */ ++#define D64_RP_LD_MASK 0x00001fff /* last valid descriptor */ ++ ++/* receive channel status */ ++#define D64_RS0_CD_MASK 0x00001fff /* current descriptor pointer */ ++#define D64_RS0_RS_MASK 0xf0000000 /* receive state */ ++#define D64_RS0_RS_SHIFT 28 ++#define D64_RS0_RS_DISABLED 0x00000000 /* disabled */ ++#define D64_RS0_RS_ACTIVE 0x10000000 /* active */ ++#define D64_RS0_RS_IDLE 0x20000000 /* idle wait */ ++#define D64_RS0_RS_STOPPED 0x30000000 /* stopped */ ++#define D64_RS0_RS_SUSP 0x40000000 /* suspend pending */ ++ ++#define D64_RS1_AD_MASK 0x0001ffff /* active descriptor */ ++#define D64_RS1_RE_MASK 0xf0000000 /* receive errors */ ++#define D64_RS1_RE_SHIFT 28 ++#define D64_RS1_RE_NOERR 0x00000000 /* no error */ ++#define D64_RS1_RE_DPO 0x10000000 /* descriptor protocol error */ ++#define D64_RS1_RE_DFU 0x20000000 /* data fifo overflow */ ++#define D64_RS1_RE_DTE 0x30000000 /* data transfer error */ ++#define D64_RS1_RE_DESRE 0x40000000 /* descriptor read error */ ++#define D64_RS1_RE_COREE 0x50000000 /* core error */ ++ ++/* fifoaddr */ ++#define D64_FA_OFF_MASK 0xffff /* offset */ ++#define D64_FA_SEL_MASK 0xf0000 /* select */ ++#define D64_FA_SEL_SHIFT 16 ++#define D64_FA_SEL_XDD 0x00000 /* transmit dma data */ ++#define D64_FA_SEL_XDP 0x10000 /* transmit dma pointers */ ++#define D64_FA_SEL_RDD 0x40000 /* receive dma data */ ++#define D64_FA_SEL_RDP 0x50000 /* receive dma pointers */ ++#define D64_FA_SEL_XFD 0x80000 /* transmit fifo data */ ++#define D64_FA_SEL_XFP 0x90000 /* transmit fifo pointers */ ++#define D64_FA_SEL_RFD 0xc0000 /* receive fifo data */ ++#define D64_FA_SEL_RFP 0xd0000 /* receive fifo pointers */ ++#define D64_FA_SEL_RSD 0xe0000 /* receive frame status data */ ++#define D64_FA_SEL_RSP 0xf0000 /* receive frame status pointers */ ++ ++/* descriptor control flags 1 */ ++#define D64_CTRL_COREFLAGS 0x0ff00000 /* core specific flags */ ++#define D64_CTRL1_EOT ((uint32)1 << 28) /* end of descriptor table */ ++#define D64_CTRL1_IOC ((uint32)1 << 29) /* interrupt on completion */ ++#define D64_CTRL1_EOF ((uint32)1 << 30) /* end of frame */ ++#define D64_CTRL1_SOF ((uint32)1 << 31) /* start of frame */ ++ ++/* descriptor control flags 2 */ ++#define D64_CTRL2_BC_MASK 0x00007fff /* buffer byte count. real data len must <= 16KB */ ++#define D64_CTRL2_AE 0x00030000 /* address extension bits */ ++#define D64_CTRL2_AE_SHIFT 16 ++#define D64_CTRL2_PARITY 0x00040000 /* parity bit */ ++ ++/* control flags in the range [27:20] are core-specific and not defined here */ ++#define D64_CTRL_CORE_MASK 0x0ff00000 ++ ++#define D64_RX_FRM_STS_LEN 0x0000ffff /* frame length mask */ ++#define D64_RX_FRM_STS_OVFL 0x00800000 /* RxOverFlow */ ++#define D64_RX_FRM_STS_DSCRCNT 0x0f000000 /* no. of descriptors used - 1, d11corerev >= 22 */ ++#define D64_RX_FRM_STS_DATATYPE 0xf0000000 /* core-dependent data type */ ++ ++/* receive frame status */ ++typedef volatile struct { ++ uint16 len; ++ uint16 flags; ++} dma_rxh_t; ++ ++#endif /* _sbhnddma_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/sbpcmcia.h b/drivers/net/wireless/ap6211/include/sbpcmcia.h +new file mode 100755 +index 0000000..c4e9d46 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/sbpcmcia.h +@@ -0,0 +1,113 @@ ++/* ++ * BCM43XX Sonics SiliconBackplane PCMCIA core hardware definitions. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: sbpcmcia.h 326494 2012-04-09 13:29:57Z $ ++ */ ++ ++#ifndef _SBPCMCIA_H ++#define _SBPCMCIA_H ++ ++/* All the addresses that are offsets in attribute space are divided ++ * by two to account for the fact that odd bytes are invalid in ++ * attribute space and our read/write routines make the space appear ++ * as if they didn't exist. Still we want to show the original numbers ++ * as documented in the hnd_pcmcia core manual. ++ */ ++ ++/* PCMCIA Function Configuration Registers */ ++#define PCMCIA_FCR (0x700 / 2) ++ ++#define FCR0_OFF 0 ++#define FCR1_OFF (0x40 / 2) ++#define FCR2_OFF (0x80 / 2) ++#define FCR3_OFF (0xc0 / 2) ++ ++#define PCMCIA_FCR0 (0x700 / 2) ++#define PCMCIA_FCR1 (0x740 / 2) ++#define PCMCIA_FCR2 (0x780 / 2) ++#define PCMCIA_FCR3 (0x7c0 / 2) ++ ++/* Standard PCMCIA FCR registers */ ++ ++#define PCMCIA_COR 0 ++ ++#define COR_RST 0x80 ++#define COR_LEV 0x40 ++#define COR_IRQEN 0x04 ++#define COR_BLREN 0x01 ++#define COR_FUNEN 0x01 ++ ++ ++#define PCICIA_FCSR (2 / 2) ++#define PCICIA_PRR (4 / 2) ++#define PCICIA_SCR (6 / 2) ++#define PCICIA_ESR (8 / 2) ++ ++ ++#define PCM_MEMOFF 0x0000 ++#define F0_MEMOFF 0x1000 ++#define F1_MEMOFF 0x2000 ++#define F2_MEMOFF 0x3000 ++#define F3_MEMOFF 0x4000 ++ ++/* Memory base in the function fcr's */ ++#define MEM_ADDR0 (0x728 / 2) ++#define MEM_ADDR1 (0x72a / 2) ++#define MEM_ADDR2 (0x72c / 2) ++ ++/* PCMCIA base plus Srom access in fcr0: */ ++#define PCMCIA_ADDR0 (0x072e / 2) ++#define PCMCIA_ADDR1 (0x0730 / 2) ++#define PCMCIA_ADDR2 (0x0732 / 2) ++ ++#define MEM_SEG (0x0734 / 2) ++#define SROM_CS (0x0736 / 2) ++#define SROM_DATAL (0x0738 / 2) ++#define SROM_DATAH (0x073a / 2) ++#define SROM_ADDRL (0x073c / 2) ++#define SROM_ADDRH (0x073e / 2) ++#define SROM_INFO2 (0x0772 / 2) /* Corerev >= 2 && <= 5 */ ++#define SROM_INFO (0x07be / 2) /* Corerev >= 6 */ ++ ++/* Values for srom_cs: */ ++#define SROM_IDLE 0 ++#define SROM_WRITE 1 ++#define SROM_READ 2 ++#define SROM_WEN 4 ++#define SROM_WDS 7 ++#define SROM_DONE 8 ++ ++/* Fields in srom_info: */ ++#define SRI_SZ_MASK 0x03 ++#define SRI_BLANK 0x04 ++#define SRI_OTP 0x80 ++ ++ ++/* sbtmstatelow */ ++#define SBTML_INT_ACK 0x40000 /* ack the sb interrupt */ ++#define SBTML_INT_EN 0x20000 /* enable sb interrupt */ ++ ++/* sbtmstatehigh */ ++#define SBTMH_INT_STATUS 0x40000 /* sb interrupt status */ ++ ++#endif /* _SBPCMCIA_H */ +diff --git a/drivers/net/wireless/ap6211/include/sbsdio.h b/drivers/net/wireless/ap6211/include/sbsdio.h +new file mode 100755 +index 0000000..8d0139d +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/sbsdio.h +@@ -0,0 +1,188 @@ ++/* ++ * SDIO device core hardware definitions. ++ * sdio is a portion of the pcmcia core in core rev 3 - rev 8 ++ * ++ * SDIO core support 1bit, 4 bit SDIO mode as well as SPI mode. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: sbsdio.h 361940 2012-10-10 08:32:12Z $ ++ */ ++ ++#ifndef _SBSDIO_H ++#define _SBSDIO_H ++ ++#define SBSDIO_NUM_FUNCTION 3 /* as of sdiod rev 0, supports 3 functions */ ++ ++/* function 1 miscellaneous registers */ ++#define SBSDIO_SPROM_CS 0x10000 /* sprom command and status */ ++#define SBSDIO_SPROM_INFO 0x10001 /* sprom info register */ ++#define SBSDIO_SPROM_DATA_LOW 0x10002 /* sprom indirect access data byte 0 */ ++#define SBSDIO_SPROM_DATA_HIGH 0x10003 /* sprom indirect access data byte 1 */ ++#define SBSDIO_SPROM_ADDR_LOW 0x10004 /* sprom indirect access addr byte 0 */ ++#define SBSDIO_SPROM_ADDR_HIGH 0x10005 /* sprom indirect access addr byte 0 */ ++#define SBSDIO_CHIP_CTRL_DATA 0x10006 /* xtal_pu (gpio) output */ ++#define SBSDIO_CHIP_CTRL_EN 0x10007 /* xtal_pu (gpio) enable */ ++#define SBSDIO_WATERMARK 0x10008 /* rev < 7, watermark for sdio device */ ++#define SBSDIO_DEVICE_CTL 0x10009 /* control busy signal generation */ ++ ++/* registers introduced in rev 8, some content (mask/bits) defs in sbsdpcmdev.h */ ++#define SBSDIO_FUNC1_SBADDRLOW 0x1000A /* SB Address Window Low (b15) */ ++#define SBSDIO_FUNC1_SBADDRMID 0x1000B /* SB Address Window Mid (b23:b16) */ ++#define SBSDIO_FUNC1_SBADDRHIGH 0x1000C /* SB Address Window High (b31:b24) */ ++#define SBSDIO_FUNC1_FRAMECTRL 0x1000D /* Frame Control (frame term/abort) */ ++#define SBSDIO_FUNC1_CHIPCLKCSR 0x1000E /* ChipClockCSR (ALP/HT ctl/status) */ ++#define SBSDIO_FUNC1_SDIOPULLUP 0x1000F /* SdioPullUp (on cmd, d0-d2) */ ++#define SBSDIO_FUNC1_WFRAMEBCLO 0x10019 /* Write Frame Byte Count Low */ ++#define SBSDIO_FUNC1_WFRAMEBCHI 0x1001A /* Write Frame Byte Count High */ ++#define SBSDIO_FUNC1_RFRAMEBCLO 0x1001B /* Read Frame Byte Count Low */ ++#define SBSDIO_FUNC1_RFRAMEBCHI 0x1001C /* Read Frame Byte Count High */ ++#define SBSDIO_FUNC1_MESBUSYCTRL 0x1001D /* MesBusyCtl at 0x1001D (rev 11) */ ++ ++#define SBSDIO_FUNC1_MISC_REG_START 0x10000 /* f1 misc register start */ ++#define SBSDIO_FUNC1_MISC_REG_LIMIT 0x1001C /* f1 misc register end */ ++ ++/* Sdio Core Rev 12 */ ++#define SBSDIO_FUNC1_WAKEUPCTRL 0x1001E ++#define SBSDIO_FUNC1_WCTRL_ALPWAIT_MASK 0x1 ++#define SBSDIO_FUNC1_WCTRL_ALPWAIT_SHIFT 0 ++#define SBSDIO_FUNC1_WCTRL_HTWAIT_MASK 0x2 ++#define SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT 1 ++#define SBSDIO_FUNC1_SLEEPCSR 0x1001F ++#define SBSDIO_FUNC1_SLEEPCSR_KSO_MASK 0x1 ++#define SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT 0 ++#define SBSDIO_FUNC1_SLEEPCSR_KSO_EN 1 ++#define SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK 0x2 ++#define SBSDIO_FUNC1_SLEEPCSR_DEVON_SHIFT 1 ++ ++/* SBSDIO_SPROM_CS */ ++#define SBSDIO_SPROM_IDLE 0 ++#define SBSDIO_SPROM_WRITE 1 ++#define SBSDIO_SPROM_READ 2 ++#define SBSDIO_SPROM_WEN 4 ++#define SBSDIO_SPROM_WDS 7 ++#define SBSDIO_SPROM_DONE 8 ++ ++/* SBSDIO_SPROM_INFO */ ++#define SROM_SZ_MASK 0x03 /* SROM size, 1: 4k, 2: 16k */ ++#define SROM_BLANK 0x04 /* depreciated in corerev 6 */ ++#define SROM_OTP 0x80 /* OTP present */ ++ ++/* SBSDIO_CHIP_CTRL */ ++#define SBSDIO_CHIP_CTRL_XTAL 0x01 /* or'd with onchip xtal_pu, ++ * 1: power on oscillator ++ * (for 4318 only) ++ */ ++/* SBSDIO_WATERMARK */ ++#define SBSDIO_WATERMARK_MASK 0x7f /* number of words - 1 for sd device ++ * to wait before sending data to host ++ */ ++ ++/* SBSDIO_MESBUSYCTRL */ ++/* When RX FIFO has less entries than this & MBE is set ++ * => busy signal is asserted between data blocks. ++*/ ++#define SBSDIO_MESBUSYCTRL_MASK 0x7f ++ ++/* SBSDIO_DEVICE_CTL */ ++#define SBSDIO_DEVCTL_SETBUSY 0x01 /* 1: device will assert busy signal when ++ * receiving CMD53 ++ */ ++#define SBSDIO_DEVCTL_SPI_INTR_SYNC 0x02 /* 1: assertion of sdio interrupt is ++ * synchronous to the sdio clock ++ */ ++#define SBSDIO_DEVCTL_CA_INT_ONLY 0x04 /* 1: mask all interrupts to host ++ * except the chipActive (rev 8) ++ */ ++#define SBSDIO_DEVCTL_PADS_ISO 0x08 /* 1: isolate internal sdio signals, put ++ * external pads in tri-state; requires ++ * sdio bus power cycle to clear (rev 9) ++ */ ++#define SBSDIO_DEVCTL_SB_RST_CTL 0x30 /* Force SD->SB reset mapping (rev 11) */ ++#define SBSDIO_DEVCTL_RST_CORECTL 0x00 /* Determined by CoreControl bit */ ++#define SBSDIO_DEVCTL_RST_BPRESET 0x10 /* Force backplane reset */ ++#define SBSDIO_DEVCTL_RST_NOBPRESET 0x20 /* Force no backplane reset */ ++#define SBSDIO_DEVCTL_EN_F2_BLK_WATERMARK 0x10 /* Enable function 2 tx for each block */ ++ ++ ++/* SBSDIO_FUNC1_CHIPCLKCSR */ ++#define SBSDIO_FORCE_ALP 0x01 /* Force ALP request to backplane */ ++#define SBSDIO_FORCE_HT 0x02 /* Force HT request to backplane */ ++#define SBSDIO_FORCE_ILP 0x04 /* Force ILP request to backplane */ ++#define SBSDIO_ALP_AVAIL_REQ 0x08 /* Make ALP ready (power up xtal) */ ++#define SBSDIO_HT_AVAIL_REQ 0x10 /* Make HT ready (power up PLL) */ ++#define SBSDIO_FORCE_HW_CLKREQ_OFF 0x20 /* Squelch clock requests from HW */ ++#define SBSDIO_ALP_AVAIL 0x40 /* Status: ALP is ready */ ++#define SBSDIO_HT_AVAIL 0x80 /* Status: HT is ready */ ++/* In rev8, actual avail bits followed original docs */ ++#define SBSDIO_Rev8_HT_AVAIL 0x40 ++#define SBSDIO_Rev8_ALP_AVAIL 0x80 ++#define SBSDIO_CSR_MASK 0x1F ++ ++#define SBSDIO_AVBITS (SBSDIO_HT_AVAIL | SBSDIO_ALP_AVAIL) ++#define SBSDIO_ALPAV(regval) ((regval) & SBSDIO_AVBITS) ++#define SBSDIO_HTAV(regval) (((regval) & SBSDIO_AVBITS) == SBSDIO_AVBITS) ++#define SBSDIO_ALPONLY(regval) (SBSDIO_ALPAV(regval) && !SBSDIO_HTAV(regval)) ++#define SBSDIO_CLKAV(regval, alponly) (SBSDIO_ALPAV(regval) && \ ++ (alponly ? 1 : SBSDIO_HTAV(regval))) ++ ++/* SBSDIO_FUNC1_SDIOPULLUP */ ++#define SBSDIO_PULLUP_D0 0x01 /* Enable D0/MISO pullup */ ++#define SBSDIO_PULLUP_D1 0x02 /* Enable D1/INT# pullup */ ++#define SBSDIO_PULLUP_D2 0x04 /* Enable D2 pullup */ ++#define SBSDIO_PULLUP_CMD 0x08 /* Enable CMD/MOSI pullup */ ++#define SBSDIO_PULLUP_ALL 0x0f /* All valid bits */ ++ ++/* function 1 OCP space */ ++#define SBSDIO_SB_OFT_ADDR_MASK 0x07FFF /* sb offset addr is <= 15 bits, 32k */ ++#define SBSDIO_SB_OFT_ADDR_LIMIT 0x08000 ++#define SBSDIO_SB_ACCESS_2_4B_FLAG 0x08000 /* with b15, maps to 32-bit SB access */ ++ ++/* some duplication with sbsdpcmdev.h here */ ++/* valid bits in SBSDIO_FUNC1_SBADDRxxx regs */ ++#define SBSDIO_SBADDRLOW_MASK 0x80 /* Valid bits in SBADDRLOW */ ++#define SBSDIO_SBADDRMID_MASK 0xff /* Valid bits in SBADDRMID */ ++#define SBSDIO_SBADDRHIGH_MASK 0xffU /* Valid bits in SBADDRHIGH */ ++#define SBSDIO_SBWINDOW_MASK 0xffff8000 /* Address bits from SBADDR regs */ ++ ++/* direct(mapped) cis space */ ++#define SBSDIO_CIS_BASE_COMMON 0x1000 /* MAPPED common CIS address */ ++#define SBSDIO_CIS_SIZE_LIMIT 0x200 /* maximum bytes in one CIS */ ++#define SBSDIO_OTP_CIS_SIZE_LIMIT 0x078 /* maximum bytes OTP CIS */ ++ ++#define SBSDIO_CIS_OFT_ADDR_MASK 0x1FFFF /* cis offset addr is < 17 bits */ ++ ++#define SBSDIO_CIS_MANFID_TUPLE_LEN 6 /* manfid tuple length, include tuple, ++ * link bytes ++ */ ++ ++/* indirect cis access (in sprom) */ ++#define SBSDIO_SPROM_CIS_OFFSET 0x8 /* 8 control bytes first, CIS starts from ++ * 8th byte ++ */ ++ ++#define SBSDIO_BYTEMODE_DATALEN_MAX 64 /* sdio byte mode: maximum length of one ++ * data comamnd ++ */ ++ ++#define SBSDIO_CORE_ADDR_MASK 0x1FFFF /* sdio core function one address mask */ ++ ++#endif /* _SBSDIO_H */ +diff --git a/drivers/net/wireless/ap6211/include/sbsdpcmdev.h b/drivers/net/wireless/ap6211/include/sbsdpcmdev.h +new file mode 100755 +index 0000000..10c7401 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/sbsdpcmdev.h +@@ -0,0 +1,295 @@ ++/* ++ * Broadcom SiliconBackplane SDIO/PCMCIA hardware-specific ++ * device core support ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: sbsdpcmdev.h 347614 2012-07-27 10:24:51Z $ ++ */ ++ ++#ifndef _sbsdpcmdev_h_ ++#define _sbsdpcmdev_h_ ++ ++/* cpp contortions to concatenate w/arg prescan */ ++#ifndef PAD ++#define _PADLINE(line) pad ## line ++#define _XSTR(line) _PADLINE(line) ++#define PAD _XSTR(__LINE__) ++#endif /* PAD */ ++ ++ ++typedef volatile struct { ++ dma64regs_t xmt; /* dma tx */ ++ uint32 PAD[2]; ++ dma64regs_t rcv; /* dma rx */ ++ uint32 PAD[2]; ++} dma64p_t; ++ ++/* dma64 sdiod corerev >= 1 */ ++typedef volatile struct { ++ dma64p_t dma64regs[2]; ++ dma64diag_t dmafifo; /* DMA Diagnostic Regs, 0x280-0x28c */ ++ uint32 PAD[92]; ++} sdiodma64_t; ++ ++/* dma32 sdiod corerev == 0 */ ++typedef volatile struct { ++ dma32regp_t dma32regs[2]; /* dma tx & rx, 0x200-0x23c */ ++ dma32diag_t dmafifo; /* DMA Diagnostic Regs, 0x240-0x24c */ ++ uint32 PAD[108]; ++} sdiodma32_t; ++ ++/* dma32 regs for pcmcia core */ ++typedef volatile struct { ++ dma32regp_t dmaregs; /* DMA Regs, 0x200-0x21c, rev8 */ ++ dma32diag_t dmafifo; /* DMA Diagnostic Regs, 0x220-0x22c */ ++ uint32 PAD[116]; ++} pcmdma32_t; ++ ++/* core registers */ ++typedef volatile struct { ++ uint32 corecontrol; /* CoreControl, 0x000, rev8 */ ++ uint32 corestatus; /* CoreStatus, 0x004, rev8 */ ++ uint32 PAD[1]; ++ uint32 biststatus; /* BistStatus, 0x00c, rev8 */ ++ ++ /* PCMCIA access */ ++ uint16 pcmciamesportaladdr; /* PcmciaMesPortalAddr, 0x010, rev8 */ ++ uint16 PAD[1]; ++ uint16 pcmciamesportalmask; /* PcmciaMesPortalMask, 0x014, rev8 */ ++ uint16 PAD[1]; ++ uint16 pcmciawrframebc; /* PcmciaWrFrameBC, 0x018, rev8 */ ++ uint16 PAD[1]; ++ uint16 pcmciaunderflowtimer; /* PcmciaUnderflowTimer, 0x01c, rev8 */ ++ uint16 PAD[1]; ++ ++ /* interrupt */ ++ uint32 intstatus; /* IntStatus, 0x020, rev8 */ ++ uint32 hostintmask; /* IntHostMask, 0x024, rev8 */ ++ uint32 intmask; /* IntSbMask, 0x028, rev8 */ ++ uint32 sbintstatus; /* SBIntStatus, 0x02c, rev8 */ ++ uint32 sbintmask; /* SBIntMask, 0x030, rev8 */ ++ uint32 funcintmask; /* SDIO Function Interrupt Mask, SDIO rev4 */ ++ uint32 PAD[2]; ++ uint32 tosbmailbox; /* ToSBMailbox, 0x040, rev8 */ ++ uint32 tohostmailbox; /* ToHostMailbox, 0x044, rev8 */ ++ uint32 tosbmailboxdata; /* ToSbMailboxData, 0x048, rev8 */ ++ uint32 tohostmailboxdata; /* ToHostMailboxData, 0x04c, rev8 */ ++ ++ /* synchronized access to registers in SDIO clock domain */ ++ uint32 sdioaccess; /* SdioAccess, 0x050, rev8 */ ++ uint32 PAD[3]; ++ ++ /* PCMCIA frame control */ ++ uint8 pcmciaframectrl; /* pcmciaFrameCtrl, 0x060, rev8 */ ++ uint8 PAD[3]; ++ uint8 pcmciawatermark; /* pcmciaWaterMark, 0x064, rev8 */ ++ uint8 PAD[155]; ++ ++ /* interrupt batching control */ ++ uint32 intrcvlazy; /* IntRcvLazy, 0x100, rev8 */ ++ uint32 PAD[3]; ++ ++ /* counters */ ++ uint32 cmd52rd; /* Cmd52RdCount, 0x110, rev8, SDIO: cmd52 reads */ ++ uint32 cmd52wr; /* Cmd52WrCount, 0x114, rev8, SDIO: cmd52 writes */ ++ uint32 cmd53rd; /* Cmd53RdCount, 0x118, rev8, SDIO: cmd53 reads */ ++ uint32 cmd53wr; /* Cmd53WrCount, 0x11c, rev8, SDIO: cmd53 writes */ ++ uint32 abort; /* AbortCount, 0x120, rev8, SDIO: aborts */ ++ uint32 datacrcerror; /* DataCrcErrorCount, 0x124, rev8, SDIO: frames w/bad CRC */ ++ uint32 rdoutofsync; /* RdOutOfSyncCount, 0x128, rev8, SDIO/PCMCIA: Rd Frm OOS */ ++ uint32 wroutofsync; /* RdOutOfSyncCount, 0x12c, rev8, SDIO/PCMCIA: Wr Frm OOS */ ++ uint32 writebusy; /* WriteBusyCount, 0x130, rev8, SDIO: dev asserted "busy" */ ++ uint32 readwait; /* ReadWaitCount, 0x134, rev8, SDIO: read: no data avail */ ++ uint32 readterm; /* ReadTermCount, 0x138, rev8, SDIO: rd frm terminates */ ++ uint32 writeterm; /* WriteTermCount, 0x13c, rev8, SDIO: wr frm terminates */ ++ uint32 PAD[40]; ++ uint32 clockctlstatus; /* ClockCtlStatus, 0x1e0, rev8 */ ++ uint32 PAD[7]; ++ ++ /* DMA engines */ ++ volatile union { ++ pcmdma32_t pcm32; ++ sdiodma32_t sdiod32; ++ sdiodma64_t sdiod64; ++ } dma; ++ ++ /* SDIO/PCMCIA CIS region */ ++ char cis[512]; /* 512 byte CIS, 0x400-0x5ff, rev6 */ ++ ++ /* PCMCIA function control registers */ ++ char pcmciafcr[256]; /* PCMCIA FCR, 0x600-6ff, rev6 */ ++ uint16 PAD[55]; ++ ++ /* PCMCIA backplane access */ ++ uint16 backplanecsr; /* BackplaneCSR, 0x76E, rev6 */ ++ uint16 backplaneaddr0; /* BackplaneAddr0, 0x770, rev6 */ ++ uint16 backplaneaddr1; /* BackplaneAddr1, 0x772, rev6 */ ++ uint16 backplaneaddr2; /* BackplaneAddr2, 0x774, rev6 */ ++ uint16 backplaneaddr3; /* BackplaneAddr3, 0x776, rev6 */ ++ uint16 backplanedata0; /* BackplaneData0, 0x778, rev6 */ ++ uint16 backplanedata1; /* BackplaneData1, 0x77a, rev6 */ ++ uint16 backplanedata2; /* BackplaneData2, 0x77c, rev6 */ ++ uint16 backplanedata3; /* BackplaneData3, 0x77e, rev6 */ ++ uint16 PAD[31]; ++ ++ /* sprom "size" & "blank" info */ ++ uint16 spromstatus; /* SPROMStatus, 0x7BE, rev2 */ ++ uint32 PAD[464]; ++ ++ /* Sonics SiliconBackplane registers */ ++ sbconfig_t sbconfig; /* SbConfig Regs, 0xf00-0xfff, rev8 */ ++} sdpcmd_regs_t; ++ ++/* corecontrol */ ++#define CC_CISRDY (1 << 0) /* CIS Ready */ ++#define CC_BPRESEN (1 << 1) /* CCCR RES signal causes backplane reset */ ++#define CC_F2RDY (1 << 2) /* set CCCR IOR2 bit */ ++#define CC_CLRPADSISO (1 << 3) /* clear SDIO pads isolation bit (rev 11) */ ++#define CC_XMTDATAAVAIL_MODE (1 << 4) /* data avail generates an interrupt */ ++#define CC_XMTDATAAVAIL_CTRL (1 << 5) /* data avail interrupt ctrl */ ++ ++/* corestatus */ ++#define CS_PCMCIAMODE (1 << 0) /* Device Mode; 0=SDIO, 1=PCMCIA */ ++#define CS_SMARTDEV (1 << 1) /* 1=smartDev enabled */ ++#define CS_F2ENABLED (1 << 2) /* 1=host has enabled the device */ ++ ++#define PCMCIA_MES_PA_MASK 0x7fff /* PCMCIA Message Portal Address Mask */ ++#define PCMCIA_MES_PM_MASK 0x7fff /* PCMCIA Message Portal Mask Mask */ ++#define PCMCIA_WFBC_MASK 0xffff /* PCMCIA Write Frame Byte Count Mask */ ++#define PCMCIA_UT_MASK 0x07ff /* PCMCIA Underflow Timer Mask */ ++ ++/* intstatus */ ++#define I_SMB_SW0 (1 << 0) /* To SB Mail S/W interrupt 0 */ ++#define I_SMB_SW1 (1 << 1) /* To SB Mail S/W interrupt 1 */ ++#define I_SMB_SW2 (1 << 2) /* To SB Mail S/W interrupt 2 */ ++#define I_SMB_SW3 (1 << 3) /* To SB Mail S/W interrupt 3 */ ++#define I_SMB_SW_MASK 0x0000000f /* To SB Mail S/W interrupts mask */ ++#define I_SMB_SW_SHIFT 0 /* To SB Mail S/W interrupts shift */ ++#define I_HMB_SW0 (1 << 4) /* To Host Mail S/W interrupt 0 */ ++#define I_HMB_SW1 (1 << 5) /* To Host Mail S/W interrupt 1 */ ++#define I_HMB_SW2 (1 << 6) /* To Host Mail S/W interrupt 2 */ ++#define I_HMB_SW3 (1 << 7) /* To Host Mail S/W interrupt 3 */ ++#define I_HMB_SW_MASK 0x000000f0 /* To Host Mail S/W interrupts mask */ ++#define I_HMB_SW_SHIFT 4 /* To Host Mail S/W interrupts shift */ ++#define I_WR_OOSYNC (1 << 8) /* Write Frame Out Of Sync */ ++#define I_RD_OOSYNC (1 << 9) /* Read Frame Out Of Sync */ ++#define I_PC (1 << 10) /* descriptor error */ ++#define I_PD (1 << 11) /* data error */ ++#define I_DE (1 << 12) /* Descriptor protocol Error */ ++#define I_RU (1 << 13) /* Receive descriptor Underflow */ ++#define I_RO (1 << 14) /* Receive fifo Overflow */ ++#define I_XU (1 << 15) /* Transmit fifo Underflow */ ++#define I_RI (1 << 16) /* Receive Interrupt */ ++#define I_BUSPWR (1 << 17) /* SDIO Bus Power Change (rev 9) */ ++#define I_XMTDATA_AVAIL (1 << 23) /* bits in fifo */ ++#define I_XI (1 << 24) /* Transmit Interrupt */ ++#define I_RF_TERM (1 << 25) /* Read Frame Terminate */ ++#define I_WF_TERM (1 << 26) /* Write Frame Terminate */ ++#define I_PCMCIA_XU (1 << 27) /* PCMCIA Transmit FIFO Underflow */ ++#define I_SBINT (1 << 28) /* sbintstatus Interrupt */ ++#define I_CHIPACTIVE (1 << 29) /* chip transitioned from doze to active state */ ++#define I_SRESET (1 << 30) /* CCCR RES interrupt */ ++#define I_IOE2 (1U << 31) /* CCCR IOE2 Bit Changed */ ++#define I_ERRORS (I_PC | I_PD | I_DE | I_RU | I_RO | I_XU) /* DMA Errors */ ++#define I_DMA (I_RI | I_XI | I_ERRORS) ++ ++/* sbintstatus */ ++#define I_SB_SERR (1 << 8) /* Backplane SError (write) */ ++#define I_SB_RESPERR (1 << 9) /* Backplane Response Error (read) */ ++#define I_SB_SPROMERR (1 << 10) /* Error accessing the sprom */ ++ ++/* sdioaccess */ ++#define SDA_DATA_MASK 0x000000ff /* Read/Write Data Mask */ ++#define SDA_ADDR_MASK 0x000fff00 /* Read/Write Address Mask */ ++#define SDA_ADDR_SHIFT 8 /* Read/Write Address Shift */ ++#define SDA_WRITE 0x01000000 /* Write bit */ ++#define SDA_READ 0x00000000 /* Write bit cleared for Read */ ++#define SDA_BUSY 0x80000000 /* Busy bit */ ++ ++/* sdioaccess-accessible register address spaces */ ++#define SDA_CCCR_SPACE 0x000 /* sdioAccess CCCR register space */ ++#define SDA_F1_FBR_SPACE 0x100 /* sdioAccess F1 FBR register space */ ++#define SDA_F2_FBR_SPACE 0x200 /* sdioAccess F2 FBR register space */ ++#define SDA_F1_REG_SPACE 0x300 /* sdioAccess F1 core-specific register space */ ++ ++/* SDA_F1_REG_SPACE sdioaccess-accessible F1 reg space register offsets */ ++#define SDA_CHIPCONTROLDATA 0x006 /* ChipControlData */ ++#define SDA_CHIPCONTROLENAB 0x007 /* ChipControlEnable */ ++#define SDA_F2WATERMARK 0x008 /* Function 2 Watermark */ ++#define SDA_DEVICECONTROL 0x009 /* DeviceControl */ ++#define SDA_SBADDRLOW 0x00a /* SbAddrLow */ ++#define SDA_SBADDRMID 0x00b /* SbAddrMid */ ++#define SDA_SBADDRHIGH 0x00c /* SbAddrHigh */ ++#define SDA_FRAMECTRL 0x00d /* FrameCtrl */ ++#define SDA_CHIPCLOCKCSR 0x00e /* ChipClockCSR */ ++#define SDA_SDIOPULLUP 0x00f /* SdioPullUp */ ++#define SDA_SDIOWRFRAMEBCLOW 0x019 /* SdioWrFrameBCLow */ ++#define SDA_SDIOWRFRAMEBCHIGH 0x01a /* SdioWrFrameBCHigh */ ++#define SDA_SDIORDFRAMEBCLOW 0x01b /* SdioRdFrameBCLow */ ++#define SDA_SDIORDFRAMEBCHIGH 0x01c /* SdioRdFrameBCHigh */ ++ ++/* SDA_F2WATERMARK */ ++#define SDA_F2WATERMARK_MASK 0x7f /* F2Watermark Mask */ ++ ++/* SDA_SBADDRLOW */ ++#define SDA_SBADDRLOW_MASK 0x80 /* SbAddrLow Mask */ ++ ++/* SDA_SBADDRMID */ ++#define SDA_SBADDRMID_MASK 0xff /* SbAddrMid Mask */ ++ ++/* SDA_SBADDRHIGH */ ++#define SDA_SBADDRHIGH_MASK 0xff /* SbAddrHigh Mask */ ++ ++/* SDA_FRAMECTRL */ ++#define SFC_RF_TERM (1 << 0) /* Read Frame Terminate */ ++#define SFC_WF_TERM (1 << 1) /* Write Frame Terminate */ ++#define SFC_CRC4WOOS (1 << 2) /* HW reports CRC error for write out of sync */ ++#define SFC_ABORTALL (1 << 3) /* Abort cancels all in-progress frames */ ++ ++/* pcmciaframectrl */ ++#define PFC_RF_TERM (1 << 0) /* Read Frame Terminate */ ++#define PFC_WF_TERM (1 << 1) /* Write Frame Terminate */ ++ ++/* intrcvlazy */ ++#define IRL_TO_MASK 0x00ffffff /* timeout */ ++#define IRL_FC_MASK 0xff000000 /* frame count */ ++#define IRL_FC_SHIFT 24 /* frame count */ ++ ++/* rx header */ ++typedef volatile struct { ++ uint16 len; ++ uint16 flags; ++} sdpcmd_rxh_t; ++ ++/* rx header flags */ ++#define RXF_CRC 0x0001 /* CRC error detected */ ++#define RXF_WOOS 0x0002 /* write frame out of sync */ ++#define RXF_WF_TERM 0x0004 /* write frame terminated */ ++#define RXF_ABORT 0x0008 /* write frame aborted */ ++#define RXF_DISCARD (RXF_CRC | RXF_WOOS | RXF_WF_TERM | RXF_ABORT) /* bad frame */ ++ ++/* HW frame tag */ ++#define SDPCM_FRAMETAG_LEN 4 /* HW frametag: 2 bytes len, 2 bytes check val */ ++ ++#define SDPCM_HWEXT_LEN 8 ++ ++#endif /* _sbsdpcmdev_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/sbsocram.h b/drivers/net/wireless/ap6211/include/sbsocram.h +new file mode 100755 +index 0000000..6455f2b +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/sbsocram.h +@@ -0,0 +1,199 @@ ++/* ++ * BCM47XX Sonics SiliconBackplane embedded ram core ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: sbsocram.h 271781 2011-07-13 20:00:06Z $ ++ */ ++ ++#ifndef _SBSOCRAM_H ++#define _SBSOCRAM_H ++ ++#ifndef _LANGUAGE_ASSEMBLY ++ ++/* cpp contortions to concatenate w/arg prescan */ ++#ifndef PAD ++#define _PADLINE(line) pad ## line ++#define _XSTR(line) _PADLINE(line) ++#define PAD _XSTR(__LINE__) ++#endif /* PAD */ ++ ++/* Memcsocram core registers */ ++typedef volatile struct sbsocramregs { ++ uint32 coreinfo; ++ uint32 bwalloc; ++ uint32 extracoreinfo; ++ uint32 biststat; ++ uint32 bankidx; ++ uint32 standbyctrl; ++ ++ uint32 errlogstatus; /* rev 6 */ ++ uint32 errlogaddr; /* rev 6 */ ++ /* used for patching rev 3 & 5 */ ++ uint32 cambankidx; ++ uint32 cambankstandbyctrl; ++ uint32 cambankpatchctrl; ++ uint32 cambankpatchtblbaseaddr; ++ uint32 cambankcmdreg; ++ uint32 cambankdatareg; ++ uint32 cambankmaskreg; ++ uint32 PAD[1]; ++ uint32 bankinfo; /* corev 8 */ ++ uint32 PAD[15]; ++ uint32 extmemconfig; ++ uint32 extmemparitycsr; ++ uint32 extmemparityerrdata; ++ uint32 extmemparityerrcnt; ++ uint32 extmemwrctrlandsize; ++ uint32 PAD[84]; ++ uint32 workaround; ++ uint32 pwrctl; /* corerev >= 2 */ ++ uint32 PAD[133]; ++ uint32 sr_control; /* corerev >= 15 */ ++ uint32 sr_status; /* corerev >= 15 */ ++ uint32 sr_address; /* corerev >= 15 */ ++ uint32 sr_data; /* corerev >= 15 */ ++} sbsocramregs_t; ++ ++#endif /* _LANGUAGE_ASSEMBLY */ ++ ++/* Register offsets */ ++#define SR_COREINFO 0x00 ++#define SR_BWALLOC 0x04 ++#define SR_BISTSTAT 0x0c ++#define SR_BANKINDEX 0x10 ++#define SR_BANKSTBYCTL 0x14 ++#define SR_PWRCTL 0x1e8 ++ ++/* Coreinfo register */ ++#define SRCI_PT_MASK 0x00070000 /* corerev >= 6; port type[18:16] */ ++#define SRCI_PT_SHIFT 16 ++/* port types : SRCI_PT__ */ ++#define SRCI_PT_OCP_OCP 0 ++#define SRCI_PT_AXI_OCP 1 ++#define SRCI_PT_ARM7AHB_OCP 2 ++#define SRCI_PT_CM3AHB_OCP 3 ++#define SRCI_PT_AXI_AXI 4 ++#define SRCI_PT_AHB_AXI 5 ++/* corerev >= 3 */ ++#define SRCI_LSS_MASK 0x00f00000 ++#define SRCI_LSS_SHIFT 20 ++#define SRCI_LRS_MASK 0x0f000000 ++#define SRCI_LRS_SHIFT 24 ++ ++/* In corerev 0, the memory size is 2 to the power of the ++ * base plus 16 plus to the contents of the memsize field plus 1. ++ */ ++#define SRCI_MS0_MASK 0xf ++#define SR_MS0_BASE 16 ++ ++/* ++ * In corerev 1 the bank size is 2 ^ the bank size field plus 14, ++ * the memory size is number of banks times bank size. ++ * The same applies to rom size. ++ */ ++#define SRCI_ROMNB_MASK 0xf000 ++#define SRCI_ROMNB_SHIFT 12 ++#define SRCI_ROMBSZ_MASK 0xf00 ++#define SRCI_ROMBSZ_SHIFT 8 ++#define SRCI_SRNB_MASK 0xf0 ++#define SRCI_SRNB_SHIFT 4 ++#define SRCI_SRBSZ_MASK 0xf ++#define SRCI_SRBSZ_SHIFT 0 ++ ++#define SR_BSZ_BASE 14 ++ ++/* Standby control register */ ++#define SRSC_SBYOVR_MASK 0x80000000 ++#define SRSC_SBYOVR_SHIFT 31 ++#define SRSC_SBYOVRVAL_MASK 0x60000000 ++#define SRSC_SBYOVRVAL_SHIFT 29 ++#define SRSC_SBYEN_MASK 0x01000000 /* rev >= 3 */ ++#define SRSC_SBYEN_SHIFT 24 ++ ++/* Power control register */ ++#define SRPC_PMU_STBYDIS_MASK 0x00000010 /* rev >= 3 */ ++#define SRPC_PMU_STBYDIS_SHIFT 4 ++#define SRPC_STBYOVRVAL_MASK 0x00000008 ++#define SRPC_STBYOVRVAL_SHIFT 3 ++#define SRPC_STBYOVR_MASK 0x00000007 ++#define SRPC_STBYOVR_SHIFT 0 ++ ++/* Extra core capability register */ ++#define SRECC_NUM_BANKS_MASK 0x000000F0 ++#define SRECC_NUM_BANKS_SHIFT 4 ++#define SRECC_BANKSIZE_MASK 0x0000000F ++#define SRECC_BANKSIZE_SHIFT 0 ++ ++#define SRECC_BANKSIZE(value) (1 << (value)) ++ ++/* CAM bank patch control */ ++#define SRCBPC_PATCHENABLE 0x80000000 ++ ++#define SRP_ADDRESS 0x0001FFFC ++#define SRP_VALID 0x8000 ++ ++/* CAM bank command reg */ ++#define SRCMD_WRITE 0x00020000 ++#define SRCMD_READ 0x00010000 ++#define SRCMD_DONE 0x80000000 ++ ++#define SRCMD_DONE_DLY 1000 ++ ++/* bankidx and bankinfo reg defines corerev >= 8 */ ++#define SOCRAM_BANKINFO_SZMASK 0x7f ++#define SOCRAM_BANKIDX_ROM_MASK 0x100 ++ ++#define SOCRAM_BANKIDX_MEMTYPE_SHIFT 8 ++/* socram bankinfo memtype */ ++#define SOCRAM_MEMTYPE_RAM 0 ++#define SOCRAM_MEMTYPE_R0M 1 ++#define SOCRAM_MEMTYPE_DEVRAM 2 ++ ++#define SOCRAM_BANKINFO_REG 0x40 ++#define SOCRAM_BANKIDX_REG 0x10 ++#define SOCRAM_BANKINFO_STDBY_MASK 0x400 ++#define SOCRAM_BANKINFO_STDBY_TIMER 0x800 ++ ++/* bankinfo rev >= 10 */ ++#define SOCRAM_BANKINFO_DEVRAMSEL_SHIFT 13 ++#define SOCRAM_BANKINFO_DEVRAMSEL_MASK 0x2000 ++#define SOCRAM_BANKINFO_DEVRAMPRO_SHIFT 14 ++#define SOCRAM_BANKINFO_DEVRAMPRO_MASK 0x4000 ++#define SOCRAM_BANKINFO_SLPSUPP_SHIFT 15 ++#define SOCRAM_BANKINFO_SLPSUPP_MASK 0x8000 ++#define SOCRAM_BANKINFO_RETNTRAM_SHIFT 16 ++#define SOCRAM_BANKINFO_RETNTRAM_MASK 0x00010000 ++#define SOCRAM_BANKINFO_PDASZ_SHIFT 17 ++#define SOCRAM_BANKINFO_PDASZ_MASK 0x003E0000 ++#define SOCRAM_BANKINFO_DEVRAMREMAP_SHIFT 24 ++#define SOCRAM_BANKINFO_DEVRAMREMAP_MASK 0x01000000 ++ ++/* extracoreinfo register */ ++#define SOCRAM_DEVRAMBANK_MASK 0xF000 ++#define SOCRAM_DEVRAMBANK_SHIFT 12 ++ ++/* bank info to calculate bank size */ ++#define SOCRAM_BANKINFO_SZBASE 8192 ++#define SOCRAM_BANKSIZE_SHIFT 13 /* SOCRAM_BANKINFO_SZBASE */ ++ ++ ++#endif /* _SBSOCRAM_H */ +diff --git a/drivers/net/wireless/ap6211/include/sdio.h b/drivers/net/wireless/ap6211/include/sdio.h +new file mode 100755 +index 0000000..b8eee1f +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/sdio.h +@@ -0,0 +1,617 @@ ++/* ++ * SDIO spec header file ++ * Protocol and standard (common) device definitions ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: sdio.h 308973 2012-01-18 04:19:34Z $ ++ */ ++ ++#ifndef _SDIO_H ++#define _SDIO_H ++ ++ ++/* CCCR structure for function 0 */ ++typedef volatile struct { ++ uint8 cccr_sdio_rev; /* RO, cccr and sdio revision */ ++ uint8 sd_rev; /* RO, sd spec revision */ ++ uint8 io_en; /* I/O enable */ ++ uint8 io_rdy; /* I/O ready reg */ ++ uint8 intr_ctl; /* Master and per function interrupt enable control */ ++ uint8 intr_status; /* RO, interrupt pending status */ ++ uint8 io_abort; /* read/write abort or reset all functions */ ++ uint8 bus_inter; /* bus interface control */ ++ uint8 capability; /* RO, card capability */ ++ ++ uint8 cis_base_low; /* 0x9 RO, common CIS base address, LSB */ ++ uint8 cis_base_mid; ++ uint8 cis_base_high; /* 0xB RO, common CIS base address, MSB */ ++ ++ /* suspend/resume registers */ ++ uint8 bus_suspend; /* 0xC */ ++ uint8 func_select; /* 0xD */ ++ uint8 exec_flag; /* 0xE */ ++ uint8 ready_flag; /* 0xF */ ++ ++ uint8 fn0_blk_size[2]; /* 0x10(LSB), 0x11(MSB) */ ++ ++ uint8 power_control; /* 0x12 (SDIO version 1.10) */ ++ ++ uint8 speed_control; /* 0x13 */ ++} sdio_regs_t; ++ ++/* SDIO Device CCCR offsets */ ++#define SDIOD_CCCR_REV 0x00 ++#define SDIOD_CCCR_SDREV 0x01 ++#define SDIOD_CCCR_IOEN 0x02 ++#define SDIOD_CCCR_IORDY 0x03 ++#define SDIOD_CCCR_INTEN 0x04 ++#define SDIOD_CCCR_INTPEND 0x05 ++#define SDIOD_CCCR_IOABORT 0x06 ++#define SDIOD_CCCR_BICTRL 0x07 ++#define SDIOD_CCCR_CAPABLITIES 0x08 ++#define SDIOD_CCCR_CISPTR_0 0x09 ++#define SDIOD_CCCR_CISPTR_1 0x0A ++#define SDIOD_CCCR_CISPTR_2 0x0B ++#define SDIOD_CCCR_BUSSUSP 0x0C ++#define SDIOD_CCCR_FUNCSEL 0x0D ++#define SDIOD_CCCR_EXECFLAGS 0x0E ++#define SDIOD_CCCR_RDYFLAGS 0x0F ++#define SDIOD_CCCR_BLKSIZE_0 0x10 ++#define SDIOD_CCCR_BLKSIZE_1 0x11 ++#define SDIOD_CCCR_POWER_CONTROL 0x12 ++#define SDIOD_CCCR_SPEED_CONTROL 0x13 ++#define SDIOD_CCCR_UHSI_SUPPORT 0x14 ++#define SDIOD_CCCR_DRIVER_STRENGTH 0x15 ++#define SDIOD_CCCR_INTR_EXTN 0x16 ++ ++/* Broadcom extensions (corerev >= 1) */ ++#define SDIOD_CCCR_BRCM_CARDCAP 0xf0 ++#define SDIOD_CCCR_BRCM_CARDCAP_CMD14_SUPPORT 0x02 ++#define SDIOD_CCCR_BRCM_CARDCAP_CMD14_EXT 0x04 ++#define SDIOD_CCCR_BRCM_CARDCAP_CMD_NODEC 0x08 ++#define SDIOD_CCCR_BRCM_CARDCTL 0xf1 ++#define SDIOD_CCCR_BRCM_SEPINT 0xf2 ++ ++/* cccr_sdio_rev */ ++#define SDIO_REV_SDIOID_MASK 0xf0 /* SDIO spec revision number */ ++#define SDIO_REV_CCCRID_MASK 0x0f /* CCCR format version number */ ++ ++/* sd_rev */ ++#define SD_REV_PHY_MASK 0x0f /* SD format version number */ ++ ++/* io_en */ ++#define SDIO_FUNC_ENABLE_1 0x02 /* function 1 I/O enable */ ++#define SDIO_FUNC_ENABLE_2 0x04 /* function 2 I/O enable */ ++ ++/* io_rdys */ ++#define SDIO_FUNC_READY_1 0x02 /* function 1 I/O ready */ ++#define SDIO_FUNC_READY_2 0x04 /* function 2 I/O ready */ ++ ++/* intr_ctl */ ++#define INTR_CTL_MASTER_EN 0x1 /* interrupt enable master */ ++#define INTR_CTL_FUNC1_EN 0x2 /* interrupt enable for function 1 */ ++#define INTR_CTL_FUNC2_EN 0x4 /* interrupt enable for function 2 */ ++ ++/* intr_status */ ++#define INTR_STATUS_FUNC1 0x2 /* interrupt pending for function 1 */ ++#define INTR_STATUS_FUNC2 0x4 /* interrupt pending for function 2 */ ++ ++/* io_abort */ ++#define IO_ABORT_RESET_ALL 0x08 /* I/O card reset */ ++#define IO_ABORT_FUNC_MASK 0x07 /* abort selction: function x */ ++ ++/* bus_inter */ ++#define BUS_CARD_DETECT_DIS 0x80 /* Card Detect disable */ ++#define BUS_SPI_CONT_INTR_CAP 0x40 /* support continuous SPI interrupt */ ++#define BUS_SPI_CONT_INTR_EN 0x20 /* continuous SPI interrupt enable */ ++#define BUS_SD_DATA_WIDTH_MASK 0x03 /* bus width mask */ ++#define BUS_SD_DATA_WIDTH_4BIT 0x02 /* bus width 4-bit mode */ ++#define BUS_SD_DATA_WIDTH_1BIT 0x00 /* bus width 1-bit mode */ ++ ++/* capability */ ++#define SDIO_CAP_4BLS 0x80 /* 4-bit support for low speed card */ ++#define SDIO_CAP_LSC 0x40 /* low speed card */ ++#define SDIO_CAP_E4MI 0x20 /* enable interrupt between block of data in 4-bit mode */ ++#define SDIO_CAP_S4MI 0x10 /* support interrupt between block of data in 4-bit mode */ ++#define SDIO_CAP_SBS 0x08 /* support suspend/resume */ ++#define SDIO_CAP_SRW 0x04 /* support read wait */ ++#define SDIO_CAP_SMB 0x02 /* support multi-block transfer */ ++#define SDIO_CAP_SDC 0x01 /* Support Direct commands during multi-byte transfer */ ++ ++/* power_control */ ++#define SDIO_POWER_SMPC 0x01 /* supports master power control (RO) */ ++#define SDIO_POWER_EMPC 0x02 /* enable master power control (allow > 200mA) (RW) */ ++ ++/* speed_control (control device entry into high-speed clocking mode) */ ++#define SDIO_SPEED_SHS 0x01 /* supports high-speed [clocking] mode (RO) */ ++#define SDIO_SPEED_EHS 0x02 /* enable high-speed [clocking] mode (RW) */ ++ ++/* for setting bus speed in card: 0x13h */ ++#define SDIO_BUS_SPEED_UHSISEL_M BITFIELD_MASK(3) ++#define SDIO_BUS_SPEED_UHSISEL_S 1 ++ ++/* for getting bus speed cap in card: 0x14h */ ++#define SDIO_BUS_SPEED_UHSICAP_M BITFIELD_MASK(3) ++#define SDIO_BUS_SPEED_UHSICAP_S 0 ++ ++/* for getting driver type CAP in card: 0x15h */ ++#define SDIO_BUS_DRVR_TYPE_CAP_M BITFIELD_MASK(3) ++#define SDIO_BUS_DRVR_TYPE_CAP_S 0 ++ ++/* for setting driver type selection in card: 0x15h */ ++#define SDIO_BUS_DRVR_TYPE_SEL_M BITFIELD_MASK(2) ++#define SDIO_BUS_DRVR_TYPE_SEL_S 4 ++ ++/* for getting async int support in card: 0x16h */ ++#define SDIO_BUS_ASYNCINT_CAP_M BITFIELD_MASK(1) ++#define SDIO_BUS_ASYNCINT_CAP_S 0 ++ ++/* for setting async int selection in card: 0x16h */ ++#define SDIO_BUS_ASYNCINT_SEL_M BITFIELD_MASK(1) ++#define SDIO_BUS_ASYNCINT_SEL_S 1 ++ ++/* brcm sepint */ ++#define SDIO_SEPINT_MASK 0x01 /* route sdpcmdev intr onto separate pad (chip-specific) */ ++#define SDIO_SEPINT_OE 0x02 /* 1 asserts output enable for above pad */ ++#define SDIO_SEPINT_ACT_HI 0x04 /* use active high interrupt level instead of active low */ ++ ++/* FBR structure for function 1-7, FBR addresses and register offsets */ ++typedef volatile struct { ++ uint8 devctr; /* device interface, CSA control */ ++ uint8 ext_dev; /* extended standard I/O device type code */ ++ uint8 pwr_sel; /* power selection support */ ++ uint8 PAD[6]; /* reserved */ ++ ++ uint8 cis_low; /* CIS LSB */ ++ uint8 cis_mid; ++ uint8 cis_high; /* CIS MSB */ ++ uint8 csa_low; /* code storage area, LSB */ ++ uint8 csa_mid; ++ uint8 csa_high; /* code storage area, MSB */ ++ uint8 csa_dat_win; /* data access window to function */ ++ ++ uint8 fnx_blk_size[2]; /* block size, little endian */ ++} sdio_fbr_t; ++ ++/* Maximum number of I/O funcs */ ++#define SDIOD_MAX_FUNCS 8 ++#define SDIOD_MAX_IOFUNCS 7 ++ ++/* SDIO Device FBR Start Address */ ++#define SDIOD_FBR_STARTADDR 0x100 ++ ++/* SDIO Device FBR Size */ ++#define SDIOD_FBR_SIZE 0x100 ++ ++/* Macro to calculate FBR register base */ ++#define SDIOD_FBR_BASE(n) ((n) * 0x100) ++ ++/* Function register offsets */ ++#define SDIOD_FBR_DEVCTR 0x00 /* basic info for function */ ++#define SDIOD_FBR_EXT_DEV 0x01 /* extended I/O device code */ ++#define SDIOD_FBR_PWR_SEL 0x02 /* power selection bits */ ++ ++/* SDIO Function CIS ptr offset */ ++#define SDIOD_FBR_CISPTR_0 0x09 ++#define SDIOD_FBR_CISPTR_1 0x0A ++#define SDIOD_FBR_CISPTR_2 0x0B ++ ++/* Code Storage Area pointer */ ++#define SDIOD_FBR_CSA_ADDR_0 0x0C ++#define SDIOD_FBR_CSA_ADDR_1 0x0D ++#define SDIOD_FBR_CSA_ADDR_2 0x0E ++#define SDIOD_FBR_CSA_DATA 0x0F ++ ++/* SDIO Function I/O Block Size */ ++#define SDIOD_FBR_BLKSIZE_0 0x10 ++#define SDIOD_FBR_BLKSIZE_1 0x11 ++ ++/* devctr */ ++#define SDIOD_FBR_DEVCTR_DIC 0x0f /* device interface code */ ++#define SDIOD_FBR_DECVTR_CSA 0x40 /* CSA support flag */ ++#define SDIOD_FBR_DEVCTR_CSA_EN 0x80 /* CSA enabled */ ++/* interface codes */ ++#define SDIOD_DIC_NONE 0 /* SDIO standard interface is not supported */ ++#define SDIOD_DIC_UART 1 ++#define SDIOD_DIC_BLUETOOTH_A 2 ++#define SDIOD_DIC_BLUETOOTH_B 3 ++#define SDIOD_DIC_GPS 4 ++#define SDIOD_DIC_CAMERA 5 ++#define SDIOD_DIC_PHS 6 ++#define SDIOD_DIC_WLAN 7 ++#define SDIOD_DIC_EXT 0xf /* extended device interface, read ext_dev register */ ++ ++/* pwr_sel */ ++#define SDIOD_PWR_SEL_SPS 0x01 /* supports power selection */ ++#define SDIOD_PWR_SEL_EPS 0x02 /* enable power selection (low-current mode) */ ++ ++/* misc defines */ ++#define SDIO_FUNC_0 0 ++#define SDIO_FUNC_1 1 ++#define SDIO_FUNC_2 2 ++#define SDIO_FUNC_3 3 ++#define SDIO_FUNC_4 4 ++#define SDIO_FUNC_5 5 ++#define SDIO_FUNC_6 6 ++#define SDIO_FUNC_7 7 ++ ++#define SD_CARD_TYPE_UNKNOWN 0 /* bad type or unrecognized */ ++#define SD_CARD_TYPE_IO 1 /* IO only card */ ++#define SD_CARD_TYPE_MEMORY 2 /* memory only card */ ++#define SD_CARD_TYPE_COMBO 3 /* IO and memory combo card */ ++ ++#define SDIO_MAX_BLOCK_SIZE 2048 /* maximum block size for block mode operation */ ++#define SDIO_MIN_BLOCK_SIZE 1 /* minimum block size for block mode operation */ ++ ++/* Card registers: status bit position */ ++#define CARDREG_STATUS_BIT_OUTOFRANGE 31 ++#define CARDREG_STATUS_BIT_COMCRCERROR 23 ++#define CARDREG_STATUS_BIT_ILLEGALCOMMAND 22 ++#define CARDREG_STATUS_BIT_ERROR 19 ++#define CARDREG_STATUS_BIT_IOCURRENTSTATE3 12 ++#define CARDREG_STATUS_BIT_IOCURRENTSTATE2 11 ++#define CARDREG_STATUS_BIT_IOCURRENTSTATE1 10 ++#define CARDREG_STATUS_BIT_IOCURRENTSTATE0 9 ++#define CARDREG_STATUS_BIT_FUN_NUM_ERROR 4 ++ ++ ++ ++#define SD_CMD_GO_IDLE_STATE 0 /* mandatory for SDIO */ ++#define SD_CMD_SEND_OPCOND 1 ++#define SD_CMD_MMC_SET_RCA 3 ++#define SD_CMD_IO_SEND_OP_COND 5 /* mandatory for SDIO */ ++#define SD_CMD_SELECT_DESELECT_CARD 7 ++#define SD_CMD_SEND_CSD 9 ++#define SD_CMD_SEND_CID 10 ++#define SD_CMD_STOP_TRANSMISSION 12 ++#define SD_CMD_SEND_STATUS 13 ++#define SD_CMD_GO_INACTIVE_STATE 15 ++#define SD_CMD_SET_BLOCKLEN 16 ++#define SD_CMD_READ_SINGLE_BLOCK 17 ++#define SD_CMD_READ_MULTIPLE_BLOCK 18 ++#define SD_CMD_WRITE_BLOCK 24 ++#define SD_CMD_WRITE_MULTIPLE_BLOCK 25 ++#define SD_CMD_PROGRAM_CSD 27 ++#define SD_CMD_SET_WRITE_PROT 28 ++#define SD_CMD_CLR_WRITE_PROT 29 ++#define SD_CMD_SEND_WRITE_PROT 30 ++#define SD_CMD_ERASE_WR_BLK_START 32 ++#define SD_CMD_ERASE_WR_BLK_END 33 ++#define SD_CMD_ERASE 38 ++#define SD_CMD_LOCK_UNLOCK 42 ++#define SD_CMD_IO_RW_DIRECT 52 /* mandatory for SDIO */ ++#define SD_CMD_IO_RW_EXTENDED 53 /* mandatory for SDIO */ ++#define SD_CMD_APP_CMD 55 ++#define SD_CMD_GEN_CMD 56 ++#define SD_CMD_READ_OCR 58 ++#define SD_CMD_CRC_ON_OFF 59 /* mandatory for SDIO */ ++#define SD_ACMD_SD_STATUS 13 ++#define SD_ACMD_SEND_NUM_WR_BLOCKS 22 ++#define SD_ACMD_SET_WR_BLOCK_ERASE_CNT 23 ++#define SD_ACMD_SD_SEND_OP_COND 41 ++#define SD_ACMD_SET_CLR_CARD_DETECT 42 ++#define SD_ACMD_SEND_SCR 51 ++ ++/* argument for SD_CMD_IO_RW_DIRECT and SD_CMD_IO_RW_EXTENDED */ ++#define SD_IO_OP_READ 0 /* Read_Write: Read */ ++#define SD_IO_OP_WRITE 1 /* Read_Write: Write */ ++#define SD_IO_RW_NORMAL 0 /* no RAW */ ++#define SD_IO_RW_RAW 1 /* RAW */ ++#define SD_IO_BYTE_MODE 0 /* Byte Mode */ ++#define SD_IO_BLOCK_MODE 1 /* BlockMode */ ++#define SD_IO_FIXED_ADDRESS 0 /* fix Address */ ++#define SD_IO_INCREMENT_ADDRESS 1 /* IncrementAddress */ ++ ++/* build SD_CMD_IO_RW_DIRECT Argument */ ++#define SDIO_IO_RW_DIRECT_ARG(rw, raw, func, addr, data) \ ++ ((((rw) & 1) << 31) | (((func) & 0x7) << 28) | (((raw) & 1) << 27) | \ ++ (((addr) & 0x1FFFF) << 9) | ((data) & 0xFF)) ++ ++/* build SD_CMD_IO_RW_EXTENDED Argument */ ++#define SDIO_IO_RW_EXTENDED_ARG(rw, blk, func, addr, inc_addr, count) \ ++ ((((rw) & 1) << 31) | (((func) & 0x7) << 28) | (((blk) & 1) << 27) | \ ++ (((inc_addr) & 1) << 26) | (((addr) & 0x1FFFF) << 9) | ((count) & 0x1FF)) ++ ++/* SDIO response parameters */ ++#define SD_RSP_NO_NONE 0 ++#define SD_RSP_NO_1 1 ++#define SD_RSP_NO_2 2 ++#define SD_RSP_NO_3 3 ++#define SD_RSP_NO_4 4 ++#define SD_RSP_NO_5 5 ++#define SD_RSP_NO_6 6 ++ ++ /* Modified R6 response (to CMD3) */ ++#define SD_RSP_MR6_COM_CRC_ERROR 0x8000 ++#define SD_RSP_MR6_ILLEGAL_COMMAND 0x4000 ++#define SD_RSP_MR6_ERROR 0x2000 ++ ++ /* Modified R1 in R4 Response (to CMD5) */ ++#define SD_RSP_MR1_SBIT 0x80 ++#define SD_RSP_MR1_PARAMETER_ERROR 0x40 ++#define SD_RSP_MR1_RFU5 0x20 ++#define SD_RSP_MR1_FUNC_NUM_ERROR 0x10 ++#define SD_RSP_MR1_COM_CRC_ERROR 0x08 ++#define SD_RSP_MR1_ILLEGAL_COMMAND 0x04 ++#define SD_RSP_MR1_RFU1 0x02 ++#define SD_RSP_MR1_IDLE_STATE 0x01 ++ ++ /* R5 response (to CMD52 and CMD53) */ ++#define SD_RSP_R5_COM_CRC_ERROR 0x80 ++#define SD_RSP_R5_ILLEGAL_COMMAND 0x40 ++#define SD_RSP_R5_IO_CURRENTSTATE1 0x20 ++#define SD_RSP_R5_IO_CURRENTSTATE0 0x10 ++#define SD_RSP_R5_ERROR 0x08 ++#define SD_RSP_R5_RFU 0x04 ++#define SD_RSP_R5_FUNC_NUM_ERROR 0x02 ++#define SD_RSP_R5_OUT_OF_RANGE 0x01 ++ ++#define SD_RSP_R5_ERRBITS 0xCB ++ ++ ++/* ------------------------------------------------ ++ * SDIO Commands and responses ++ * ++ * I/O only commands are: ++ * CMD0, CMD3, CMD5, CMD7, CMD14, CMD15, CMD52, CMD53 ++ * ------------------------------------------------ ++ */ ++ ++/* SDIO Commands */ ++#define SDIOH_CMD_0 0 ++#define SDIOH_CMD_3 3 ++#define SDIOH_CMD_5 5 ++#define SDIOH_CMD_7 7 ++#define SDIOH_CMD_11 11 ++#define SDIOH_CMD_14 14 ++#define SDIOH_CMD_15 15 ++#define SDIOH_CMD_19 19 ++#define SDIOH_CMD_52 52 ++#define SDIOH_CMD_53 53 ++#define SDIOH_CMD_59 59 ++ ++/* SDIO Command Responses */ ++#define SDIOH_RSP_NONE 0 ++#define SDIOH_RSP_R1 1 ++#define SDIOH_RSP_R2 2 ++#define SDIOH_RSP_R3 3 ++#define SDIOH_RSP_R4 4 ++#define SDIOH_RSP_R5 5 ++#define SDIOH_RSP_R6 6 ++ ++/* ++ * SDIO Response Error flags ++ */ ++#define SDIOH_RSP5_ERROR_FLAGS 0xCB ++ ++/* ------------------------------------------------ ++ * SDIO Command structures. I/O only commands are: ++ * ++ * CMD0, CMD3, CMD5, CMD7, CMD15, CMD52, CMD53 ++ * ------------------------------------------------ ++ */ ++ ++#define CMD5_OCR_M BITFIELD_MASK(24) ++#define CMD5_OCR_S 0 ++ ++#define CMD5_S18R_M BITFIELD_MASK(1) ++#define CMD5_S18R_S 24 ++ ++#define CMD7_RCA_M BITFIELD_MASK(16) ++#define CMD7_RCA_S 16 ++ ++#define CMD14_RCA_M BITFIELD_MASK(16) ++#define CMD14_RCA_S 16 ++#define CMD14_SLEEP_M BITFIELD_MASK(1) ++#define CMD14_SLEEP_S 15 ++ ++#define CMD_15_RCA_M BITFIELD_MASK(16) ++#define CMD_15_RCA_S 16 ++ ++#define CMD52_DATA_M BITFIELD_MASK(8) /* Bits [7:0] - Write Data/Stuff bits of CMD52 ++ */ ++#define CMD52_DATA_S 0 ++#define CMD52_REG_ADDR_M BITFIELD_MASK(17) /* Bits [25:9] - register address */ ++#define CMD52_REG_ADDR_S 9 ++#define CMD52_RAW_M BITFIELD_MASK(1) /* Bit 27 - Read after Write flag */ ++#define CMD52_RAW_S 27 ++#define CMD52_FUNCTION_M BITFIELD_MASK(3) /* Bits [30:28] - Function number */ ++#define CMD52_FUNCTION_S 28 ++#define CMD52_RW_FLAG_M BITFIELD_MASK(1) /* Bit 31 - R/W flag */ ++#define CMD52_RW_FLAG_S 31 ++ ++ ++#define CMD53_BYTE_BLK_CNT_M BITFIELD_MASK(9) /* Bits [8:0] - Byte/Block Count of CMD53 */ ++#define CMD53_BYTE_BLK_CNT_S 0 ++#define CMD53_REG_ADDR_M BITFIELD_MASK(17) /* Bits [25:9] - register address */ ++#define CMD53_REG_ADDR_S 9 ++#define CMD53_OP_CODE_M BITFIELD_MASK(1) /* Bit 26 - R/W Operation Code */ ++#define CMD53_OP_CODE_S 26 ++#define CMD53_BLK_MODE_M BITFIELD_MASK(1) /* Bit 27 - Block Mode */ ++#define CMD53_BLK_MODE_S 27 ++#define CMD53_FUNCTION_M BITFIELD_MASK(3) /* Bits [30:28] - Function number */ ++#define CMD53_FUNCTION_S 28 ++#define CMD53_RW_FLAG_M BITFIELD_MASK(1) /* Bit 31 - R/W flag */ ++#define CMD53_RW_FLAG_S 31 ++ ++/* ------------------------------------------------------ ++ * SDIO Command Response structures for SD1 and SD4 modes ++ * ----------------------------------------------------- ++ */ ++#define RSP4_IO_OCR_M BITFIELD_MASK(24) /* Bits [23:0] - Card's OCR Bits [23:0] */ ++#define RSP4_IO_OCR_S 0 ++ ++#define RSP4_S18A_M BITFIELD_MASK(1) /* Bits [23:0] - Card's OCR Bits [23:0] */ ++#define RSP4_S18A_S 24 ++ ++#define RSP4_STUFF_M BITFIELD_MASK(3) /* Bits [26:24] - Stuff bits */ ++#define RSP4_STUFF_S 24 ++#define RSP4_MEM_PRESENT_M BITFIELD_MASK(1) /* Bit 27 - Memory present */ ++#define RSP4_MEM_PRESENT_S 27 ++#define RSP4_NUM_FUNCS_M BITFIELD_MASK(3) /* Bits [30:28] - Number of I/O funcs */ ++#define RSP4_NUM_FUNCS_S 28 ++#define RSP4_CARD_READY_M BITFIELD_MASK(1) /* Bit 31 - SDIO card ready */ ++#define RSP4_CARD_READY_S 31 ++ ++#define RSP6_STATUS_M BITFIELD_MASK(16) /* Bits [15:0] - Card status bits [19,22,23,12:0] ++ */ ++#define RSP6_STATUS_S 0 ++#define RSP6_IO_RCA_M BITFIELD_MASK(16) /* Bits [31:16] - RCA bits[31-16] */ ++#define RSP6_IO_RCA_S 16 ++ ++#define RSP1_AKE_SEQ_ERROR_M BITFIELD_MASK(1) /* Bit 3 - Authentication seq error */ ++#define RSP1_AKE_SEQ_ERROR_S 3 ++#define RSP1_APP_CMD_M BITFIELD_MASK(1) /* Bit 5 - Card expects ACMD */ ++#define RSP1_APP_CMD_S 5 ++#define RSP1_READY_FOR_DATA_M BITFIELD_MASK(1) /* Bit 8 - Ready for data (buff empty) */ ++#define RSP1_READY_FOR_DATA_S 8 ++#define RSP1_CURR_STATE_M BITFIELD_MASK(4) /* Bits [12:9] - State of card ++ * when Cmd was received ++ */ ++#define RSP1_CURR_STATE_S 9 ++#define RSP1_EARSE_RESET_M BITFIELD_MASK(1) /* Bit 13 - Erase seq cleared */ ++#define RSP1_EARSE_RESET_S 13 ++#define RSP1_CARD_ECC_DISABLE_M BITFIELD_MASK(1) /* Bit 14 - Card ECC disabled */ ++#define RSP1_CARD_ECC_DISABLE_S 14 ++#define RSP1_WP_ERASE_SKIP_M BITFIELD_MASK(1) /* Bit 15 - Partial blocks erased due to W/P */ ++#define RSP1_WP_ERASE_SKIP_S 15 ++#define RSP1_CID_CSD_OVERW_M BITFIELD_MASK(1) /* Bit 16 - Illegal write to CID or R/O bits ++ * of CSD ++ */ ++#define RSP1_CID_CSD_OVERW_S 16 ++#define RSP1_ERROR_M BITFIELD_MASK(1) /* Bit 19 - General/Unknown error */ ++#define RSP1_ERROR_S 19 ++#define RSP1_CC_ERROR_M BITFIELD_MASK(1) /* Bit 20 - Internal Card Control error */ ++#define RSP1_CC_ERROR_S 20 ++#define RSP1_CARD_ECC_FAILED_M BITFIELD_MASK(1) /* Bit 21 - Card internal ECC failed ++ * to correct data ++ */ ++#define RSP1_CARD_ECC_FAILED_S 21 ++#define RSP1_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 22 - Cmd not legal for the card state */ ++#define RSP1_ILLEGAL_CMD_S 22 ++#define RSP1_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 23 - CRC check of previous command failed ++ */ ++#define RSP1_COM_CRC_ERROR_S 23 ++#define RSP1_LOCK_UNLOCK_FAIL_M BITFIELD_MASK(1) /* Bit 24 - Card lock-unlock Cmd Seq error */ ++#define RSP1_LOCK_UNLOCK_FAIL_S 24 ++#define RSP1_CARD_LOCKED_M BITFIELD_MASK(1) /* Bit 25 - Card locked by the host */ ++#define RSP1_CARD_LOCKED_S 25 ++#define RSP1_WP_VIOLATION_M BITFIELD_MASK(1) /* Bit 26 - Attempt to program ++ * write-protected blocks ++ */ ++#define RSP1_WP_VIOLATION_S 26 ++#define RSP1_ERASE_PARAM_M BITFIELD_MASK(1) /* Bit 27 - Invalid erase blocks */ ++#define RSP1_ERASE_PARAM_S 27 ++#define RSP1_ERASE_SEQ_ERR_M BITFIELD_MASK(1) /* Bit 28 - Erase Cmd seq error */ ++#define RSP1_ERASE_SEQ_ERR_S 28 ++#define RSP1_BLK_LEN_ERR_M BITFIELD_MASK(1) /* Bit 29 - Block length error */ ++#define RSP1_BLK_LEN_ERR_S 29 ++#define RSP1_ADDR_ERR_M BITFIELD_MASK(1) /* Bit 30 - Misaligned address */ ++#define RSP1_ADDR_ERR_S 30 ++#define RSP1_OUT_OF_RANGE_M BITFIELD_MASK(1) /* Bit 31 - Cmd arg was out of range */ ++#define RSP1_OUT_OF_RANGE_S 31 ++ ++ ++#define RSP5_DATA_M BITFIELD_MASK(8) /* Bits [0:7] - data */ ++#define RSP5_DATA_S 0 ++#define RSP5_FLAGS_M BITFIELD_MASK(8) /* Bit [15:8] - Rsp flags */ ++#define RSP5_FLAGS_S 8 ++#define RSP5_STUFF_M BITFIELD_MASK(16) /* Bits [31:16] - Stuff bits */ ++#define RSP5_STUFF_S 16 ++ ++/* ---------------------------------------------- ++ * SDIO Command Response structures for SPI mode ++ * ---------------------------------------------- ++ */ ++#define SPIRSP4_IO_OCR_M BITFIELD_MASK(16) /* Bits [15:0] - Card's OCR Bits [23:8] */ ++#define SPIRSP4_IO_OCR_S 0 ++#define SPIRSP4_STUFF_M BITFIELD_MASK(3) /* Bits [18:16] - Stuff bits */ ++#define SPIRSP4_STUFF_S 16 ++#define SPIRSP4_MEM_PRESENT_M BITFIELD_MASK(1) /* Bit 19 - Memory present */ ++#define SPIRSP4_MEM_PRESENT_S 19 ++#define SPIRSP4_NUM_FUNCS_M BITFIELD_MASK(3) /* Bits [22:20] - Number of I/O funcs */ ++#define SPIRSP4_NUM_FUNCS_S 20 ++#define SPIRSP4_CARD_READY_M BITFIELD_MASK(1) /* Bit 23 - SDIO card ready */ ++#define SPIRSP4_CARD_READY_S 23 ++#define SPIRSP4_IDLE_STATE_M BITFIELD_MASK(1) /* Bit 24 - idle state */ ++#define SPIRSP4_IDLE_STATE_S 24 ++#define SPIRSP4_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 26 - Illegal Cmd error */ ++#define SPIRSP4_ILLEGAL_CMD_S 26 ++#define SPIRSP4_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 27 - COM CRC error */ ++#define SPIRSP4_COM_CRC_ERROR_S 27 ++#define SPIRSP4_FUNC_NUM_ERROR_M BITFIELD_MASK(1) /* Bit 28 - Function number error ++ */ ++#define SPIRSP4_FUNC_NUM_ERROR_S 28 ++#define SPIRSP4_PARAM_ERROR_M BITFIELD_MASK(1) /* Bit 30 - Parameter Error Bit */ ++#define SPIRSP4_PARAM_ERROR_S 30 ++#define SPIRSP4_START_BIT_M BITFIELD_MASK(1) /* Bit 31 - Start Bit */ ++#define SPIRSP4_START_BIT_S 31 ++ ++#define SPIRSP5_DATA_M BITFIELD_MASK(8) /* Bits [23:16] - R/W Data */ ++#define SPIRSP5_DATA_S 16 ++#define SPIRSP5_IDLE_STATE_M BITFIELD_MASK(1) /* Bit 24 - Idle state */ ++#define SPIRSP5_IDLE_STATE_S 24 ++#define SPIRSP5_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 26 - Illegal Cmd error */ ++#define SPIRSP5_ILLEGAL_CMD_S 26 ++#define SPIRSP5_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 27 - COM CRC error */ ++#define SPIRSP5_COM_CRC_ERROR_S 27 ++#define SPIRSP5_FUNC_NUM_ERROR_M BITFIELD_MASK(1) /* Bit 28 - Function number error ++ */ ++#define SPIRSP5_FUNC_NUM_ERROR_S 28 ++#define SPIRSP5_PARAM_ERROR_M BITFIELD_MASK(1) /* Bit 30 - Parameter Error Bit */ ++#define SPIRSP5_PARAM_ERROR_S 30 ++#define SPIRSP5_START_BIT_M BITFIELD_MASK(1) /* Bit 31 - Start Bit */ ++#define SPIRSP5_START_BIT_S 31 ++ ++/* RSP6 card status format; Pg 68 Physical Layer spec v 1.10 */ ++#define RSP6STAT_AKE_SEQ_ERROR_M BITFIELD_MASK(1) /* Bit 3 - Authentication seq error ++ */ ++#define RSP6STAT_AKE_SEQ_ERROR_S 3 ++#define RSP6STAT_APP_CMD_M BITFIELD_MASK(1) /* Bit 5 - Card expects ACMD */ ++#define RSP6STAT_APP_CMD_S 5 ++#define RSP6STAT_READY_FOR_DATA_M BITFIELD_MASK(1) /* Bit 8 - Ready for data ++ * (buff empty) ++ */ ++#define RSP6STAT_READY_FOR_DATA_S 8 ++#define RSP6STAT_CURR_STATE_M BITFIELD_MASK(4) /* Bits [12:9] - Card state at ++ * Cmd reception ++ */ ++#define RSP6STAT_CURR_STATE_S 9 ++#define RSP6STAT_ERROR_M BITFIELD_MASK(1) /* Bit 13 - General/Unknown error Bit 19 ++ */ ++#define RSP6STAT_ERROR_S 13 ++#define RSP6STAT_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 14 - Illegal cmd for ++ * card state Bit 22 ++ */ ++#define RSP6STAT_ILLEGAL_CMD_S 14 ++#define RSP6STAT_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 15 - CRC previous command ++ * failed Bit 23 ++ */ ++#define RSP6STAT_COM_CRC_ERROR_S 15 ++ ++#define SDIOH_XFER_TYPE_READ SD_IO_OP_READ ++#define SDIOH_XFER_TYPE_WRITE SD_IO_OP_WRITE ++ ++/* command issue options */ ++#define CMD_OPTION_DEFAULT 0 ++#define CMD_OPTION_TUNING 1 ++#endif /* _SDIO_H */ +diff --git a/drivers/net/wireless/ap6211/include/sdioh.h b/drivers/net/wireless/ap6211/include/sdioh.h +new file mode 100755 +index 0000000..5517a71 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/sdioh.h +@@ -0,0 +1,445 @@ ++/* ++ * SDIO Host Controller Spec header file ++ * Register map and definitions for the Standard Host Controller ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: sdioh.h 347633 2012-07-27 11:02:02Z $ ++ */ ++ ++#ifndef _SDIOH_H ++#define _SDIOH_H ++ ++#define SD_SysAddr 0x000 ++#define SD_BlockSize 0x004 ++#define SD_BlockCount 0x006 ++#define SD_Arg0 0x008 ++#define SD_Arg1 0x00A ++#define SD_TransferMode 0x00C ++#define SD_Command 0x00E ++#define SD_Response0 0x010 ++#define SD_Response1 0x012 ++#define SD_Response2 0x014 ++#define SD_Response3 0x016 ++#define SD_Response4 0x018 ++#define SD_Response5 0x01A ++#define SD_Response6 0x01C ++#define SD_Response7 0x01E ++#define SD_BufferDataPort0 0x020 ++#define SD_BufferDataPort1 0x022 ++#define SD_PresentState 0x024 ++#define SD_HostCntrl 0x028 ++#define SD_PwrCntrl 0x029 ++#define SD_BlockGapCntrl 0x02A ++#define SD_WakeupCntrl 0x02B ++#define SD_ClockCntrl 0x02C ++#define SD_TimeoutCntrl 0x02E ++#define SD_SoftwareReset 0x02F ++#define SD_IntrStatus 0x030 ++#define SD_ErrorIntrStatus 0x032 ++#define SD_IntrStatusEnable 0x034 ++#define SD_ErrorIntrStatusEnable 0x036 ++#define SD_IntrSignalEnable 0x038 ++#define SD_ErrorIntrSignalEnable 0x03A ++#define SD_CMD12ErrorStatus 0x03C ++#define SD_Capabilities 0x040 ++#define SD_Capabilities3 0x044 ++#define SD_MaxCurCap 0x048 ++#define SD_MaxCurCap_Reserved 0x04C ++#define SD_ADMA_ErrStatus 0x054 ++#define SD_ADMA_SysAddr 0x58 ++#define SD_SlotInterruptStatus 0x0FC ++#define SD_HostControllerVersion 0x0FE ++#define SD_GPIO_Reg 0x100 ++#define SD_GPIO_OE 0x104 ++#define SD_GPIO_Enable 0x108 ++ ++/* SD specific registers in PCI config space */ ++#define SD_SlotInfo 0x40 ++ ++/* HC 3.0 specific registers and offsets */ ++#define SD3_HostCntrl2 0x03E ++/* preset regsstart and count */ ++#define SD3_PresetValStart 0x060 ++#define SD3_PresetValCount 8 ++/* preset-indiv regs */ ++#define SD3_PresetVal_init 0x060 ++#define SD3_PresetVal_default 0x062 ++#define SD3_PresetVal_HS 0x064 ++#define SD3_PresetVal_SDR12 0x066 ++#define SD3_PresetVal_SDR25 0x068 ++#define SD3_PresetVal_SDR50 0x06a ++#define SD3_PresetVal_SDR104 0x06c ++#define SD3_PresetVal_DDR50 0x06e ++/* SDIO3.0 Revx specific Registers */ ++#define SD3_Tuning_Info_Register 0x0EC ++#define SD3_WL_BT_reset_register 0x0F0 ++ ++ ++/* preset value indices */ ++#define SD3_PRESETVAL_INITIAL_IX 0 ++#define SD3_PRESETVAL_DESPEED_IX 1 ++#define SD3_PRESETVAL_HISPEED_IX 2 ++#define SD3_PRESETVAL_SDR12_IX 3 ++#define SD3_PRESETVAL_SDR25_IX 4 ++#define SD3_PRESETVAL_SDR50_IX 5 ++#define SD3_PRESETVAL_SDR104_IX 6 ++#define SD3_PRESETVAL_DDR50_IX 7 ++ ++/* SD_Capabilities reg (0x040) */ ++#define CAP_TO_CLKFREQ_M BITFIELD_MASK(6) ++#define CAP_TO_CLKFREQ_S 0 ++#define CAP_TO_CLKUNIT_M BITFIELD_MASK(1) ++#define CAP_TO_CLKUNIT_S 7 ++/* Note: for sdio-2.0 case, this mask has to be 6 bits, but msb 2 ++ bits are reserved. going ahead with 8 bits, as it is req for 3.0 ++*/ ++#define CAP_BASECLK_M BITFIELD_MASK(8) ++#define CAP_BASECLK_S 8 ++#define CAP_MAXBLOCK_M BITFIELD_MASK(2) ++#define CAP_MAXBLOCK_S 16 ++#define CAP_ADMA2_M BITFIELD_MASK(1) ++#define CAP_ADMA2_S 19 ++#define CAP_ADMA1_M BITFIELD_MASK(1) ++#define CAP_ADMA1_S 20 ++#define CAP_HIGHSPEED_M BITFIELD_MASK(1) ++#define CAP_HIGHSPEED_S 21 ++#define CAP_DMA_M BITFIELD_MASK(1) ++#define CAP_DMA_S 22 ++#define CAP_SUSPEND_M BITFIELD_MASK(1) ++#define CAP_SUSPEND_S 23 ++#define CAP_VOLT_3_3_M BITFIELD_MASK(1) ++#define CAP_VOLT_3_3_S 24 ++#define CAP_VOLT_3_0_M BITFIELD_MASK(1) ++#define CAP_VOLT_3_0_S 25 ++#define CAP_VOLT_1_8_M BITFIELD_MASK(1) ++#define CAP_VOLT_1_8_S 26 ++#define CAP_64BIT_HOST_M BITFIELD_MASK(1) ++#define CAP_64BIT_HOST_S 28 ++ ++#define SDIO_OCR_READ_FAIL (2) ++ ++ ++#define CAP_ASYNCINT_SUP_M BITFIELD_MASK(1) ++#define CAP_ASYNCINT_SUP_S 29 ++ ++#define CAP_SLOTTYPE_M BITFIELD_MASK(2) ++#define CAP_SLOTTYPE_S 30 ++ ++#define CAP3_MSBits_OFFSET (32) ++/* note: following are caps MSB32 bits. ++ So the bits start from 0, instead of 32. that is why ++ CAP3_MSBits_OFFSET is subtracted. ++*/ ++#define CAP3_SDR50_SUP_M BITFIELD_MASK(1) ++#define CAP3_SDR50_SUP_S (32 - CAP3_MSBits_OFFSET) ++ ++#define CAP3_SDR104_SUP_M BITFIELD_MASK(1) ++#define CAP3_SDR104_SUP_S (33 - CAP3_MSBits_OFFSET) ++ ++#define CAP3_DDR50_SUP_M BITFIELD_MASK(1) ++#define CAP3_DDR50_SUP_S (34 - CAP3_MSBits_OFFSET) ++ ++/* for knowing the clk caps in a single read */ ++#define CAP3_30CLKCAP_M BITFIELD_MASK(3) ++#define CAP3_30CLKCAP_S (32 - CAP3_MSBits_OFFSET) ++ ++#define CAP3_DRIVTYPE_A_M BITFIELD_MASK(1) ++#define CAP3_DRIVTYPE_A_S (36 - CAP3_MSBits_OFFSET) ++ ++#define CAP3_DRIVTYPE_C_M BITFIELD_MASK(1) ++#define CAP3_DRIVTYPE_C_S (37 - CAP3_MSBits_OFFSET) ++ ++#define CAP3_DRIVTYPE_D_M BITFIELD_MASK(1) ++#define CAP3_DRIVTYPE_D_S (38 - CAP3_MSBits_OFFSET) ++ ++#define CAP3_RETUNING_TC_M BITFIELD_MASK(4) ++#define CAP3_RETUNING_TC_S (40 - CAP3_MSBits_OFFSET) ++ ++#define CAP3_TUNING_SDR50_M BITFIELD_MASK(1) ++#define CAP3_TUNING_SDR50_S (45 - CAP3_MSBits_OFFSET) ++ ++#define CAP3_RETUNING_MODES_M BITFIELD_MASK(2) ++#define CAP3_RETUNING_MODES_S (46 - CAP3_MSBits_OFFSET) ++ ++#define CAP3_CLK_MULT_M BITFIELD_MASK(8) ++#define CAP3_CLK_MULT_S (48 - CAP3_MSBits_OFFSET) ++ ++#define PRESET_DRIVR_SELECT_M BITFIELD_MASK(2) ++#define PRESET_DRIVR_SELECT_S 14 ++ ++#define PRESET_CLK_DIV_M BITFIELD_MASK(10) ++#define PRESET_CLK_DIV_S 0 ++ ++/* SD_MaxCurCap reg (0x048) */ ++#define CAP_CURR_3_3_M BITFIELD_MASK(8) ++#define CAP_CURR_3_3_S 0 ++#define CAP_CURR_3_0_M BITFIELD_MASK(8) ++#define CAP_CURR_3_0_S 8 ++#define CAP_CURR_1_8_M BITFIELD_MASK(8) ++#define CAP_CURR_1_8_S 16 ++ ++/* SD_SysAddr: Offset 0x0000, Size 4 bytes */ ++ ++/* SD_BlockSize: Offset 0x004, Size 2 bytes */ ++#define BLKSZ_BLKSZ_M BITFIELD_MASK(12) ++#define BLKSZ_BLKSZ_S 0 ++#define BLKSZ_BNDRY_M BITFIELD_MASK(3) ++#define BLKSZ_BNDRY_S 12 ++ ++/* SD_BlockCount: Offset 0x006, size 2 bytes */ ++ ++/* SD_Arg0: Offset 0x008, size = 4 bytes */ ++/* SD_TransferMode Offset 0x00C, size = 2 bytes */ ++#define XFER_DMA_ENABLE_M BITFIELD_MASK(1) ++#define XFER_DMA_ENABLE_S 0 ++#define XFER_BLK_COUNT_EN_M BITFIELD_MASK(1) ++#define XFER_BLK_COUNT_EN_S 1 ++#define XFER_CMD_12_EN_M BITFIELD_MASK(1) ++#define XFER_CMD_12_EN_S 2 ++#define XFER_DATA_DIRECTION_M BITFIELD_MASK(1) ++#define XFER_DATA_DIRECTION_S 4 ++#define XFER_MULTI_BLOCK_M BITFIELD_MASK(1) ++#define XFER_MULTI_BLOCK_S 5 ++ ++/* SD_Command: Offset 0x00E, size = 2 bytes */ ++/* resp_type field */ ++#define RESP_TYPE_NONE 0 ++#define RESP_TYPE_136 1 ++#define RESP_TYPE_48 2 ++#define RESP_TYPE_48_BUSY 3 ++/* type field */ ++#define CMD_TYPE_NORMAL 0 ++#define CMD_TYPE_SUSPEND 1 ++#define CMD_TYPE_RESUME 2 ++#define CMD_TYPE_ABORT 3 ++ ++#define CMD_RESP_TYPE_M BITFIELD_MASK(2) /* Bits [0-1] - Response type */ ++#define CMD_RESP_TYPE_S 0 ++#define CMD_CRC_EN_M BITFIELD_MASK(1) /* Bit 3 - CRC enable */ ++#define CMD_CRC_EN_S 3 ++#define CMD_INDEX_EN_M BITFIELD_MASK(1) /* Bit 4 - Enable index checking */ ++#define CMD_INDEX_EN_S 4 ++#define CMD_DATA_EN_M BITFIELD_MASK(1) /* Bit 5 - Using DAT line */ ++#define CMD_DATA_EN_S 5 ++#define CMD_TYPE_M BITFIELD_MASK(2) /* Bit [6-7] - Normal, abort, resume, etc ++ */ ++#define CMD_TYPE_S 6 ++#define CMD_INDEX_M BITFIELD_MASK(6) /* Bits [8-13] - Command number */ ++#define CMD_INDEX_S 8 ++ ++/* SD_BufferDataPort0 : Offset 0x020, size = 2 or 4 bytes */ ++/* SD_BufferDataPort1 : Offset 0x022, size = 2 bytes */ ++/* SD_PresentState : Offset 0x024, size = 4 bytes */ ++#define PRES_CMD_INHIBIT_M BITFIELD_MASK(1) /* Bit 0 May use CMD */ ++#define PRES_CMD_INHIBIT_S 0 ++#define PRES_DAT_INHIBIT_M BITFIELD_MASK(1) /* Bit 1 May use DAT */ ++#define PRES_DAT_INHIBIT_S 1 ++#define PRES_DAT_BUSY_M BITFIELD_MASK(1) /* Bit 2 DAT is busy */ ++#define PRES_DAT_BUSY_S 2 ++#define PRES_PRESENT_RSVD_M BITFIELD_MASK(5) /* Bit [3-7] rsvd */ ++#define PRES_PRESENT_RSVD_S 3 ++#define PRES_WRITE_ACTIVE_M BITFIELD_MASK(1) /* Bit 8 Write is active */ ++#define PRES_WRITE_ACTIVE_S 8 ++#define PRES_READ_ACTIVE_M BITFIELD_MASK(1) /* Bit 9 Read is active */ ++#define PRES_READ_ACTIVE_S 9 ++#define PRES_WRITE_DATA_RDY_M BITFIELD_MASK(1) /* Bit 10 Write buf is avail */ ++#define PRES_WRITE_DATA_RDY_S 10 ++#define PRES_READ_DATA_RDY_M BITFIELD_MASK(1) /* Bit 11 Read buf data avail */ ++#define PRES_READ_DATA_RDY_S 11 ++#define PRES_CARD_PRESENT_M BITFIELD_MASK(1) /* Bit 16 Card present - debounced */ ++#define PRES_CARD_PRESENT_S 16 ++#define PRES_CARD_STABLE_M BITFIELD_MASK(1) /* Bit 17 Debugging */ ++#define PRES_CARD_STABLE_S 17 ++#define PRES_CARD_PRESENT_RAW_M BITFIELD_MASK(1) /* Bit 18 Not debounced */ ++#define PRES_CARD_PRESENT_RAW_S 18 ++#define PRES_WRITE_ENABLED_M BITFIELD_MASK(1) /* Bit 19 Write protected? */ ++#define PRES_WRITE_ENABLED_S 19 ++#define PRES_DAT_SIGNAL_M BITFIELD_MASK(4) /* Bit [20-23] Debugging */ ++#define PRES_DAT_SIGNAL_S 20 ++#define PRES_CMD_SIGNAL_M BITFIELD_MASK(1) /* Bit 24 Debugging */ ++#define PRES_CMD_SIGNAL_S 24 ++ ++/* SD_HostCntrl: Offset 0x028, size = 1 bytes */ ++#define HOST_LED_M BITFIELD_MASK(1) /* Bit 0 LED On/Off */ ++#define HOST_LED_S 0 ++#define HOST_DATA_WIDTH_M BITFIELD_MASK(1) /* Bit 1 4 bit enable */ ++#define HOST_DATA_WIDTH_S 1 ++#define HOST_HI_SPEED_EN_M BITFIELD_MASK(1) /* Bit 2 High speed vs low speed */ ++#define HOST_DMA_SEL_S 3 ++#define HOST_DMA_SEL_M BITFIELD_MASK(2) /* Bit 4:3 DMA Select */ ++#define HOST_HI_SPEED_EN_S 2 ++ ++/* Host Control2: */ ++#define HOSTCtrl2_PRESVAL_EN_M BITFIELD_MASK(1) /* 1 bit */ ++#define HOSTCtrl2_PRESVAL_EN_S 15 /* bit# */ ++ ++#define HOSTCtrl2_ASYINT_EN_M BITFIELD_MASK(1) /* 1 bit */ ++#define HOSTCtrl2_ASYINT_EN_S 14 /* bit# */ ++ ++#define HOSTCtrl2_SAMPCLK_SEL_M BITFIELD_MASK(1) /* 1 bit */ ++#define HOSTCtrl2_SAMPCLK_SEL_S 7 /* bit# */ ++ ++#define HOSTCtrl2_EXEC_TUNING_M BITFIELD_MASK(1) /* 1 bit */ ++#define HOSTCtrl2_EXEC_TUNING_S 6 /* bit# */ ++ ++#define HOSTCtrl2_DRIVSTRENGTH_SEL_M BITFIELD_MASK(2) /* 2 bit */ ++#define HOSTCtrl2_DRIVSTRENGTH_SEL_S 4 /* bit# */ ++ ++#define HOSTCtrl2_1_8SIG_EN_M BITFIELD_MASK(1) /* 1 bit */ ++#define HOSTCtrl2_1_8SIG_EN_S 3 /* bit# */ ++ ++#define HOSTCtrl2_UHSMODE_SEL_M BITFIELD_MASK(3) /* 3 bit */ ++#define HOSTCtrl2_UHSMODE_SEL_S 0 /* bit# */ ++ ++#define HOST_CONTR_VER_2 (1) ++#define HOST_CONTR_VER_3 (2) ++ ++/* misc defines */ ++#define SD1_MODE 0x1 /* SD Host Cntrlr Spec */ ++#define SD4_MODE 0x2 /* SD Host Cntrlr Spec */ ++ ++/* SD_PwrCntrl: Offset 0x029, size = 1 bytes */ ++#define PWR_BUS_EN_M BITFIELD_MASK(1) /* Bit 0 Power the bus */ ++#define PWR_BUS_EN_S 0 ++#define PWR_VOLTS_M BITFIELD_MASK(3) /* Bit [1-3] Voltage Select */ ++#define PWR_VOLTS_S 1 ++ ++/* SD_SoftwareReset: Offset 0x02F, size = 1 byte */ ++#define SW_RESET_ALL_M BITFIELD_MASK(1) /* Bit 0 Reset All */ ++#define SW_RESET_ALL_S 0 ++#define SW_RESET_CMD_M BITFIELD_MASK(1) /* Bit 1 CMD Line Reset */ ++#define SW_RESET_CMD_S 1 ++#define SW_RESET_DAT_M BITFIELD_MASK(1) /* Bit 2 DAT Line Reset */ ++#define SW_RESET_DAT_S 2 ++ ++/* SD_IntrStatus: Offset 0x030, size = 2 bytes */ ++/* Defs also serve SD_IntrStatusEnable and SD_IntrSignalEnable */ ++#define INTSTAT_CMD_COMPLETE_M BITFIELD_MASK(1) /* Bit 0 */ ++#define INTSTAT_CMD_COMPLETE_S 0 ++#define INTSTAT_XFER_COMPLETE_M BITFIELD_MASK(1) ++#define INTSTAT_XFER_COMPLETE_S 1 ++#define INTSTAT_BLOCK_GAP_EVENT_M BITFIELD_MASK(1) ++#define INTSTAT_BLOCK_GAP_EVENT_S 2 ++#define INTSTAT_DMA_INT_M BITFIELD_MASK(1) ++#define INTSTAT_DMA_INT_S 3 ++#define INTSTAT_BUF_WRITE_READY_M BITFIELD_MASK(1) ++#define INTSTAT_BUF_WRITE_READY_S 4 ++#define INTSTAT_BUF_READ_READY_M BITFIELD_MASK(1) ++#define INTSTAT_BUF_READ_READY_S 5 ++#define INTSTAT_CARD_INSERTION_M BITFIELD_MASK(1) ++#define INTSTAT_CARD_INSERTION_S 6 ++#define INTSTAT_CARD_REMOVAL_M BITFIELD_MASK(1) ++#define INTSTAT_CARD_REMOVAL_S 7 ++#define INTSTAT_CARD_INT_M BITFIELD_MASK(1) ++#define INTSTAT_CARD_INT_S 8 ++#define INTSTAT_RETUNING_INT_M BITFIELD_MASK(1) /* Bit 12 */ ++#define INTSTAT_RETUNING_INT_S 12 ++#define INTSTAT_ERROR_INT_M BITFIELD_MASK(1) /* Bit 15 */ ++#define INTSTAT_ERROR_INT_S 15 ++ ++/* SD_ErrorIntrStatus: Offset 0x032, size = 2 bytes */ ++/* Defs also serve SD_ErrorIntrStatusEnable and SD_ErrorIntrSignalEnable */ ++#define ERRINT_CMD_TIMEOUT_M BITFIELD_MASK(1) ++#define ERRINT_CMD_TIMEOUT_S 0 ++#define ERRINT_CMD_CRC_M BITFIELD_MASK(1) ++#define ERRINT_CMD_CRC_S 1 ++#define ERRINT_CMD_ENDBIT_M BITFIELD_MASK(1) ++#define ERRINT_CMD_ENDBIT_S 2 ++#define ERRINT_CMD_INDEX_M BITFIELD_MASK(1) ++#define ERRINT_CMD_INDEX_S 3 ++#define ERRINT_DATA_TIMEOUT_M BITFIELD_MASK(1) ++#define ERRINT_DATA_TIMEOUT_S 4 ++#define ERRINT_DATA_CRC_M BITFIELD_MASK(1) ++#define ERRINT_DATA_CRC_S 5 ++#define ERRINT_DATA_ENDBIT_M BITFIELD_MASK(1) ++#define ERRINT_DATA_ENDBIT_S 6 ++#define ERRINT_CURRENT_LIMIT_M BITFIELD_MASK(1) ++#define ERRINT_CURRENT_LIMIT_S 7 ++#define ERRINT_AUTO_CMD12_M BITFIELD_MASK(1) ++#define ERRINT_AUTO_CMD12_S 8 ++#define ERRINT_VENDOR_M BITFIELD_MASK(4) ++#define ERRINT_VENDOR_S 12 ++#define ERRINT_ADMA_M BITFIELD_MASK(1) ++#define ERRINT_ADMA_S 9 ++ ++/* Also provide definitions in "normal" form to allow combined masks */ ++#define ERRINT_CMD_TIMEOUT_BIT 0x0001 ++#define ERRINT_CMD_CRC_BIT 0x0002 ++#define ERRINT_CMD_ENDBIT_BIT 0x0004 ++#define ERRINT_CMD_INDEX_BIT 0x0008 ++#define ERRINT_DATA_TIMEOUT_BIT 0x0010 ++#define ERRINT_DATA_CRC_BIT 0x0020 ++#define ERRINT_DATA_ENDBIT_BIT 0x0040 ++#define ERRINT_CURRENT_LIMIT_BIT 0x0080 ++#define ERRINT_AUTO_CMD12_BIT 0x0100 ++#define ERRINT_ADMA_BIT 0x0200 ++ ++/* Masks to select CMD vs. DATA errors */ ++#define ERRINT_CMD_ERRS (ERRINT_CMD_TIMEOUT_BIT | ERRINT_CMD_CRC_BIT |\ ++ ERRINT_CMD_ENDBIT_BIT | ERRINT_CMD_INDEX_BIT) ++#define ERRINT_DATA_ERRS (ERRINT_DATA_TIMEOUT_BIT | ERRINT_DATA_CRC_BIT |\ ++ ERRINT_DATA_ENDBIT_BIT | ERRINT_ADMA_BIT) ++#define ERRINT_TRANSFER_ERRS (ERRINT_CMD_ERRS | ERRINT_DATA_ERRS) ++ ++/* SD_WakeupCntr_BlockGapCntrl : Offset 0x02A , size = bytes */ ++/* SD_ClockCntrl : Offset 0x02C , size = bytes */ ++/* SD_SoftwareReset_TimeoutCntrl : Offset 0x02E , size = bytes */ ++/* SD_IntrStatus : Offset 0x030 , size = bytes */ ++/* SD_ErrorIntrStatus : Offset 0x032 , size = bytes */ ++/* SD_IntrStatusEnable : Offset 0x034 , size = bytes */ ++/* SD_ErrorIntrStatusEnable : Offset 0x036 , size = bytes */ ++/* SD_IntrSignalEnable : Offset 0x038 , size = bytes */ ++/* SD_ErrorIntrSignalEnable : Offset 0x03A , size = bytes */ ++/* SD_CMD12ErrorStatus : Offset 0x03C , size = bytes */ ++/* SD_Capabilities : Offset 0x040 , size = bytes */ ++/* SD_MaxCurCap : Offset 0x048 , size = bytes */ ++/* SD_MaxCurCap_Reserved: Offset 0x04C , size = bytes */ ++/* SD_SlotInterruptStatus: Offset 0x0FC , size = bytes */ ++/* SD_HostControllerVersion : Offset 0x0FE , size = bytes */ ++ ++/* SDIO Host Control Register DMA Mode Definitions */ ++#define SDIOH_SDMA_MODE 0 ++#define SDIOH_ADMA1_MODE 1 ++#define SDIOH_ADMA2_MODE 2 ++#define SDIOH_ADMA2_64_MODE 3 ++ ++#define ADMA2_ATTRIBUTE_VALID (1 << 0) /* ADMA Descriptor line valid */ ++#define ADMA2_ATTRIBUTE_END (1 << 1) /* End of Descriptor */ ++#define ADMA2_ATTRIBUTE_INT (1 << 2) /* Interrupt when line is done */ ++#define ADMA2_ATTRIBUTE_ACT_NOP (0 << 4) /* Skip current line, go to next. */ ++#define ADMA2_ATTRIBUTE_ACT_RSV (1 << 4) /* Same as NOP */ ++#define ADMA1_ATTRIBUTE_ACT_SET (1 << 4) /* ADMA1 Only - set transfer length */ ++#define ADMA2_ATTRIBUTE_ACT_TRAN (2 << 4) /* Transfer Data of one descriptor line. */ ++#define ADMA2_ATTRIBUTE_ACT_LINK (3 << 4) /* Link Descriptor */ ++ ++/* ADMA2 Descriptor Table Entry for 32-bit Address */ ++typedef struct adma2_dscr_32b { ++ uint32 len_attr; ++ uint32 phys_addr; ++} adma2_dscr_32b_t; ++ ++/* ADMA1 Descriptor Table Entry */ ++typedef struct adma1_dscr { ++ uint32 phys_addr_attr; ++} adma1_dscr_t; ++ ++#endif /* _SDIOH_H */ +diff --git a/drivers/net/wireless/ap6211/include/sdiovar.h b/drivers/net/wireless/ap6211/include/sdiovar.h +new file mode 100755 +index 0000000..83f82de +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/sdiovar.h +@@ -0,0 +1,58 @@ ++/* ++ * Structure used by apps whose drivers access SDIO drivers. ++ * Pulled out separately so dhdu and wlu can both use it. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: sdiovar.h 241182 2011-02-17 21:50:03Z $ ++ */ ++ ++#ifndef _sdiovar_h_ ++#define _sdiovar_h_ ++ ++#include ++ ++/* require default structure packing */ ++#define BWL_DEFAULT_PACKING ++#include ++ ++typedef struct sdreg { ++ int func; ++ int offset; ++ int value; ++} sdreg_t; ++ ++/* Common msglevel constants */ ++#define SDH_ERROR_VAL 0x0001 /* Error */ ++#define SDH_TRACE_VAL 0x0002 /* Trace */ ++#define SDH_INFO_VAL 0x0004 /* Info */ ++#define SDH_DEBUG_VAL 0x0008 /* Debug */ ++#define SDH_DATA_VAL 0x0010 /* Data */ ++#define SDH_CTRL_VAL 0x0020 /* Control Regs */ ++#define SDH_LOG_VAL 0x0040 /* Enable bcmlog */ ++#define SDH_DMA_VAL 0x0080 /* DMA */ ++ ++#define NUM_PREV_TRANSACTIONS 16 ++ ++ ++#include ++ ++#endif /* _sdiovar_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/siutils.h b/drivers/net/wireless/ap6211/include/siutils.h +new file mode 100755 +index 0000000..acc72ee +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/siutils.h +@@ -0,0 +1,347 @@ ++/* ++ * Misc utility routines for accessing the SOC Interconnects ++ * of Broadcom HNBU chips. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: siutils.h 347614 2012-07-27 10:24:51Z $ ++ */ ++ ++#ifndef _siutils_h_ ++#define _siutils_h_ ++ ++/* ++ * Data structure to export all chip specific common variables ++ * public (read-only) portion of siutils handle returned by si_attach()/si_kattach() ++ */ ++struct si_pub { ++ uint socitype; /* SOCI_SB, SOCI_AI */ ++ ++ uint bustype; /* SI_BUS, PCI_BUS */ ++ uint buscoretype; /* PCI_CORE_ID, PCIE_CORE_ID, PCMCIA_CORE_ID */ ++ uint buscorerev; /* buscore rev */ ++ uint buscoreidx; /* buscore index */ ++ int ccrev; /* chip common core rev */ ++ uint32 cccaps; /* chip common capabilities */ ++ uint32 cccaps_ext; /* chip common capabilities extension */ ++ int pmurev; /* pmu core rev */ ++ uint32 pmucaps; /* pmu capabilities */ ++ uint boardtype; /* board type */ ++ uint boardrev; /* board rev */ ++ uint boardvendor; /* board vendor */ ++ uint boardflags; /* board flags */ ++ uint boardflags2; /* board flags2 */ ++ uint chip; /* chip number */ ++ uint chiprev; /* chip revision */ ++ uint chippkg; /* chip package option */ ++ uint32 chipst; /* chip status */ ++ bool issim; /* chip is in simulation or emulation */ ++ uint socirev; /* SOC interconnect rev */ ++ bool pci_pr32414; ++ ++}; ++ ++/* for HIGH_ONLY driver, the si_t must be writable to allow states sync from BMAC to HIGH driver ++ * for monolithic driver, it is readonly to prevent accident change ++ */ ++typedef const struct si_pub si_t; ++ ++ ++/* ++ * Many of the routines below take an 'sih' handle as their first arg. ++ * Allocate this by calling si_attach(). Free it by calling si_detach(). ++ * At any one time, the sih is logically focused on one particular si core ++ * (the "current core"). ++ * Use si_setcore() or si_setcoreidx() to change the association to another core. ++ */ ++#define SI_OSH NULL /* Use for si_kattach when no osh is available */ ++ ++#define BADIDX (SI_MAXCORES + 1) ++ ++/* clkctl xtal what flags */ ++#define XTAL 0x1 /* primary crystal oscillator (2050) */ ++#define PLL 0x2 /* main chip pll */ ++ ++/* clkctl clk mode */ ++#define CLK_FAST 0 /* force fast (pll) clock */ ++#define CLK_DYNAMIC 2 /* enable dynamic clock control */ ++ ++/* GPIO usage priorities */ ++#define GPIO_DRV_PRIORITY 0 /* Driver */ ++#define GPIO_APP_PRIORITY 1 /* Application */ ++#define GPIO_HI_PRIORITY 2 /* Highest priority. Ignore GPIO reservation */ ++ ++/* GPIO pull up/down */ ++#define GPIO_PULLUP 0 ++#define GPIO_PULLDN 1 ++ ++/* GPIO event regtype */ ++#define GPIO_REGEVT 0 /* GPIO register event */ ++#define GPIO_REGEVT_INTMSK 1 /* GPIO register event int mask */ ++#define GPIO_REGEVT_INTPOL 2 /* GPIO register event int polarity */ ++ ++/* device path */ ++#define SI_DEVPATH_BUFSZ 16 /* min buffer size in bytes */ ++ ++/* SI routine enumeration: to be used by update function with multiple hooks */ ++#define SI_DOATTACH 1 ++#define SI_PCIDOWN 2 ++#define SI_PCIUP 3 ++ ++#define ISSIM_ENAB(sih) 0 ++ ++/* PMU clock/power control */ ++#if defined(BCMPMUCTL) ++#define PMUCTL_ENAB(sih) (BCMPMUCTL) ++#else ++#define PMUCTL_ENAB(sih) ((sih)->cccaps & CC_CAP_PMU) ++#endif ++ ++/* chipcommon clock/power control (exclusive with PMU's) */ ++#if defined(BCMPMUCTL) && BCMPMUCTL ++#define CCCTL_ENAB(sih) (0) ++#define CCPLL_ENAB(sih) (0) ++#else ++#define CCCTL_ENAB(sih) ((sih)->cccaps & CC_CAP_PWR_CTL) ++#define CCPLL_ENAB(sih) ((sih)->cccaps & CC_CAP_PLL_MASK) ++#endif ++ ++typedef void (*gpio_handler_t)(uint32 stat, void *arg); ++/* External BT Coex enable mask */ ++#define CC_BTCOEX_EN_MASK 0x01 ++/* External PA enable mask */ ++#define GPIO_CTRL_EPA_EN_MASK 0x40 ++/* WL/BT control enable mask */ ++#define GPIO_CTRL_5_6_EN_MASK 0x60 ++#define GPIO_CTRL_7_6_EN_MASK 0xC0 ++#define GPIO_OUT_7_EN_MASK 0x80 ++ ++ ++/* CR4 specific defines used by the host driver */ ++#define SI_CR4_CAP (0x04) ++#define SI_CR4_BANKIDX (0x40) ++#define SI_CR4_BANKINFO (0x44) ++ ++#define ARMCR4_TCBBNB_MASK 0xf0 ++#define ARMCR4_TCBBNB_SHIFT 4 ++#define ARMCR4_TCBANB_MASK 0xf ++#define ARMCR4_TCBANB_SHIFT 0 ++ ++#define SICF_CPUHALT (0x0020) ++#define ARMCR4_BSZ_MASK 0x3f ++#define ARMCR4_BSZ_MULT 8192 ++ ++ ++/* === exported functions === */ ++extern si_t *si_attach(uint pcidev, osl_t *osh, void *regs, uint bustype, ++ void *sdh, char **vars, uint *varsz); ++extern si_t *si_kattach(osl_t *osh); ++extern void si_detach(si_t *sih); ++extern bool si_pci_war16165(si_t *sih); ++ ++extern uint si_corelist(si_t *sih, uint coreid[]); ++extern uint si_coreid(si_t *sih); ++extern uint si_flag(si_t *sih); ++extern uint si_intflag(si_t *sih); ++extern uint si_coreidx(si_t *sih); ++extern uint si_coreunit(si_t *sih); ++extern uint si_corevendor(si_t *sih); ++extern uint si_corerev(si_t *sih); ++extern void *si_osh(si_t *sih); ++extern void si_setosh(si_t *sih, osl_t *osh); ++extern uint si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); ++extern void *si_coreregs(si_t *sih); ++extern uint si_wrapperreg(si_t *sih, uint32 offset, uint32 mask, uint32 val); ++extern uint32 si_core_cflags(si_t *sih, uint32 mask, uint32 val); ++extern void si_core_cflags_wo(si_t *sih, uint32 mask, uint32 val); ++extern uint32 si_core_sflags(si_t *sih, uint32 mask, uint32 val); ++extern bool si_iscoreup(si_t *sih); ++extern uint si_findcoreidx(si_t *sih, uint coreid, uint coreunit); ++extern void *si_setcoreidx(si_t *sih, uint coreidx); ++extern void *si_setcore(si_t *sih, uint coreid, uint coreunit); ++extern void *si_switch_core(si_t *sih, uint coreid, uint *origidx, uint *intr_val); ++extern void si_restore_core(si_t *sih, uint coreid, uint intr_val); ++extern int si_numaddrspaces(si_t *sih); ++extern uint32 si_addrspace(si_t *sih, uint asidx); ++extern uint32 si_addrspacesize(si_t *sih, uint asidx); ++extern void si_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size); ++extern int si_corebist(si_t *sih); ++extern void si_core_reset(si_t *sih, uint32 bits, uint32 resetbits); ++extern void si_core_disable(si_t *sih, uint32 bits); ++extern uint32 si_clock_rate(uint32 pll_type, uint32 n, uint32 m); ++extern bool si_read_pmu_autopll(si_t *sih); ++extern uint32 si_clock(si_t *sih); ++extern uint32 si_alp_clock(si_t *sih); ++extern uint32 si_ilp_clock(si_t *sih); ++extern void si_pci_setup(si_t *sih, uint coremask); ++extern void si_pcmcia_init(si_t *sih); ++extern void si_setint(si_t *sih, int siflag); ++extern bool si_backplane64(si_t *sih); ++extern void si_register_intr_callback(si_t *sih, void *intrsoff_fn, void *intrsrestore_fn, ++ void *intrsenabled_fn, void *intr_arg); ++extern void si_deregister_intr_callback(si_t *sih); ++extern void si_clkctl_init(si_t *sih); ++extern uint16 si_clkctl_fast_pwrup_delay(si_t *sih); ++extern bool si_clkctl_cc(si_t *sih, uint mode); ++extern int si_clkctl_xtal(si_t *sih, uint what, bool on); ++extern uint32 si_gpiotimerval(si_t *sih, uint32 mask, uint32 val); ++extern void si_btcgpiowar(si_t *sih); ++extern bool si_deviceremoved(si_t *sih); ++extern uint32 si_socram_size(si_t *sih); ++extern uint32 si_socdevram_size(si_t *sih); ++extern uint32 si_socram_srmem_size(si_t *sih); ++extern void si_socdevram(si_t *sih, bool set, uint8 *ennable, uint8 *protect, uint8 *remap); ++extern bool si_socdevram_pkg(si_t *sih); ++extern bool si_socdevram_remap_isenb(si_t *sih); ++extern uint32 si_socdevram_remap_size(si_t *sih); ++ ++extern void si_watchdog(si_t *sih, uint ticks); ++extern void si_watchdog_ms(si_t *sih, uint32 ms); ++extern uint32 si_watchdog_msticks(void); ++extern void *si_gpiosetcore(si_t *sih); ++extern uint32 si_gpiocontrol(si_t *sih, uint32 mask, uint32 val, uint8 priority); ++extern uint32 si_gpioouten(si_t *sih, uint32 mask, uint32 val, uint8 priority); ++extern uint32 si_gpioout(si_t *sih, uint32 mask, uint32 val, uint8 priority); ++extern uint32 si_gpioin(si_t *sih); ++extern uint32 si_gpiointpolarity(si_t *sih, uint32 mask, uint32 val, uint8 priority); ++extern uint32 si_gpiointmask(si_t *sih, uint32 mask, uint32 val, uint8 priority); ++extern uint32 si_gpioled(si_t *sih, uint32 mask, uint32 val); ++extern uint32 si_gpioreserve(si_t *sih, uint32 gpio_num, uint8 priority); ++extern uint32 si_gpiorelease(si_t *sih, uint32 gpio_num, uint8 priority); ++extern uint32 si_gpiopull(si_t *sih, bool updown, uint32 mask, uint32 val); ++extern uint32 si_gpioevent(si_t *sih, uint regtype, uint32 mask, uint32 val); ++extern uint32 si_gpio_int_enable(si_t *sih, bool enable); ++ ++/* GPIO event handlers */ ++extern void *si_gpio_handler_register(si_t *sih, uint32 e, bool lev, gpio_handler_t cb, void *arg); ++extern void si_gpio_handler_unregister(si_t *sih, void* gpioh); ++extern void si_gpio_handler_process(si_t *sih); ++ ++/* Wake-on-wireless-LAN (WOWL) */ ++extern bool si_pci_pmecap(si_t *sih); ++struct osl_info; ++extern bool si_pci_fastpmecap(struct osl_info *osh); ++extern bool si_pci_pmestat(si_t *sih); ++extern void si_pci_pmeclr(si_t *sih); ++extern void si_pci_pmeen(si_t *sih); ++extern void si_pci_pmestatclr(si_t *sih); ++extern uint si_pcie_readreg(void *sih, uint addrtype, uint offset); ++ ++extern void si_sdio_init(si_t *sih); ++ ++extern uint16 si_d11_devid(si_t *sih); ++extern int si_corepciid(si_t *sih, uint func, uint16 *pcivendor, uint16 *pcidevice, ++ uint8 *pciclass, uint8 *pcisubclass, uint8 *pciprogif, uint8 *pciheader); ++ ++#define si_eci(sih) 0 ++static INLINE void * si_eci_init(si_t *sih) {return NULL;} ++#define si_eci_notify_bt(sih, type, val) (0) ++#define si_seci(sih) 0 ++#define si_seci_upd(sih, a) do {} while (0) ++static INLINE void * si_seci_init(si_t *sih, uint8 use_seci) {return NULL;} ++#define si_seci_down(sih) do {} while (0) ++ ++/* OTP status */ ++extern bool si_is_otp_disabled(si_t *sih); ++extern bool si_is_otp_powered(si_t *sih); ++extern void si_otp_power(si_t *sih, bool on); ++ ++/* SPROM availability */ ++extern bool si_is_sprom_available(si_t *sih); ++extern bool si_is_sprom_enabled(si_t *sih); ++extern void si_sprom_enable(si_t *sih, bool enable); ++ ++/* OTP/SROM CIS stuff */ ++extern int si_cis_source(si_t *sih); ++#define CIS_DEFAULT 0 ++#define CIS_SROM 1 ++#define CIS_OTP 2 ++ ++/* Fab-id information */ ++#define DEFAULT_FAB 0x0 /* Original/first fab used for this chip */ ++#define CSM_FAB7 0x1 /* CSM Fab7 chip */ ++#define TSMC_FAB12 0x2 /* TSMC Fab12/Fab14 chip */ ++#define SMIC_FAB4 0x3 /* SMIC Fab4 chip */ ++extern int si_otp_fabid(si_t *sih, uint16 *fabid, bool rw); ++extern uint16 si_fabid(si_t *sih); ++ ++/* ++ * Build device path. Path size must be >= SI_DEVPATH_BUFSZ. ++ * The returned path is NULL terminated and has trailing '/'. ++ * Return 0 on success, nonzero otherwise. ++ */ ++extern int si_devpath(si_t *sih, char *path, int size); ++/* Read variable with prepending the devpath to the name */ ++extern char *si_getdevpathvar(si_t *sih, const char *name); ++extern int si_getdevpathintvar(si_t *sih, const char *name); ++extern char *si_coded_devpathvar(si_t *sih, char *varname, int var_len, const char *name); ++ ++ ++extern uint8 si_pcieclkreq(si_t *sih, uint32 mask, uint32 val); ++extern uint32 si_pcielcreg(si_t *sih, uint32 mask, uint32 val); ++extern void si_war42780_clkreq(si_t *sih, bool clkreq); ++extern void si_pci_down(si_t *sih); ++extern void si_pci_up(si_t *sih); ++extern void si_pci_sleep(si_t *sih); ++extern void si_pcie_war_ovr_update(si_t *sih, uint8 aspm); ++extern void si_pcie_power_save_enable(si_t *sih, bool enable); ++extern void si_pcie_extendL1timer(si_t *sih, bool extend); ++extern int si_pci_fixcfg(si_t *sih); ++extern void si_chippkg_set(si_t *sih, uint); ++ ++extern void si_chipcontrl_btshd0_4331(si_t *sih, bool on); ++extern void si_chipcontrl_restore(si_t *sih, uint32 val); ++extern uint32 si_chipcontrl_read(si_t *sih); ++extern void si_chipcontrl_epa4331(si_t *sih, bool on); ++extern void si_chipcontrl_epa4331_wowl(si_t *sih, bool enter_wowl); ++extern void si_chipcontrl_srom4360(si_t *sih, bool on); ++/* Enable BT-COEX & Ex-PA for 4313 */ ++extern void si_epa_4313war(si_t *sih); ++extern void si_btc_enable_chipcontrol(si_t *sih); ++/* BT/WL selection for 4313 bt combo >= P250 boards */ ++extern void si_btcombo_p250_4313_war(si_t *sih); ++extern void si_btcombo_43228_war(si_t *sih); ++extern void si_clk_pmu_htavail_set(si_t *sih, bool set_clear); ++extern uint si_pll_reset(si_t *sih); ++/* === debug routines === */ ++ ++extern bool si_taclear(si_t *sih, bool details); ++ ++ ++ ++extern uint32 si_pciereg(si_t *sih, uint32 offset, uint32 mask, uint32 val, uint type); ++extern uint32 si_pcieserdesreg(si_t *sih, uint32 mdioslave, uint32 offset, uint32 mask, uint32 val); ++extern void si_pcie_set_request_size(si_t *sih, uint16 size); ++extern uint16 si_pcie_get_request_size(si_t *sih); ++extern uint16 si_pcie_get_ssid(si_t *sih); ++extern uint32 si_pcie_get_bar0(si_t *sih); ++extern int si_pcie_configspace_cache(si_t *sih); ++extern int si_pcie_configspace_restore(si_t *sih); ++extern int si_pcie_configspace_get(si_t *sih, uint8 *buf, uint size); ++ ++char *si_getnvramflvar(si_t *sih, const char *name); ++ ++ ++extern uint32 si_tcm_size(si_t *sih); ++ ++extern int si_set_sromctl(si_t *sih, uint32 value); ++extern uint32 si_get_sromctl(si_t *sih); ++#endif /* _siutils_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/trxhdr.h b/drivers/net/wireless/ap6211/include/trxhdr.h +new file mode 100755 +index 0000000..bf92a56 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/trxhdr.h +@@ -0,0 +1,53 @@ ++/* ++ * TRX image file header format. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: trxhdr.h 260898 2011-05-20 23:11:12Z $ ++ */ ++ ++#ifndef _TRX_HDR_H ++#define _TRX_HDR_H ++ ++#include ++ ++#define TRX_MAGIC 0x30524448 /* "HDR0" */ ++#define TRX_VERSION 1 /* Version 1 */ ++#define TRX_MAX_LEN 0x3B0000 /* Max length */ ++#define TRX_NO_HEADER 1 /* Do not write TRX header */ ++#define TRX_GZ_FILES 0x2 /* Contains up to TRX_MAX_OFFSET individual gzip files */ ++#define TRX_EMBED_UCODE 0x8 /* Trx contains embedded ucode image */ ++#define TRX_ROMSIM_IMAGE 0x10 /* Trx contains ROM simulation image */ ++#define TRX_UNCOMP_IMAGE 0x20 /* Trx contains uncompressed rtecdc.bin image */ ++#define TRX_MAX_OFFSET 3 /* Max number of individual files */ ++ ++struct trx_header { ++ uint32 magic; /* "HDR0" */ ++ uint32 len; /* Length of file including header */ ++ uint32 crc32; /* 32-bit CRC from flag_version to end of file */ ++ uint32 flag_version; /* 0:15 flags, 16:31 version */ ++ uint32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */ ++}; ++ ++/* Compatibility */ ++typedef struct trx_header TRXHDR, *PTRXHDR; ++ ++#endif /* _TRX_HDR_H */ +diff --git a/drivers/net/wireless/ap6211/include/typedefs.h b/drivers/net/wireless/ap6211/include/typedefs.h +new file mode 100755 +index 0000000..fe1d162 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/typedefs.h +@@ -0,0 +1,343 @@ ++/* ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * $Id: typedefs.h 286783 2011-09-29 06:18:57Z $ ++ */ ++ ++#ifndef _TYPEDEFS_H_ ++#define _TYPEDEFS_H_ ++ ++#ifdef SITE_TYPEDEFS ++ ++/* ++ * Define SITE_TYPEDEFS in the compile to include a site-specific ++ * typedef file "site_typedefs.h". ++ * ++ * If SITE_TYPEDEFS is not defined, then the code section below makes ++ * inferences about the compile environment based on defined symbols and ++ * possibly compiler pragmas. ++ * ++ * Following these two sections is the Default Typedefs section. ++ * This section is only processed if USE_TYPEDEF_DEFAULTS is ++ * defined. This section has a default set of typedefs and a few ++ * preprocessor symbols (TRUE, FALSE, NULL, ...). ++ */ ++ ++#include "site_typedefs.h" ++ ++#else ++ ++/* ++ * Infer the compile environment based on preprocessor symbols and pragmas. ++ * Override type definitions as needed, and include configuration-dependent ++ * header files to define types. ++ */ ++ ++#ifdef __cplusplus ++ ++#define TYPEDEF_BOOL ++#ifndef FALSE ++#define FALSE false ++#endif ++#ifndef TRUE ++#define TRUE true ++#endif ++ ++#else /* ! __cplusplus */ ++ ++ ++#endif /* ! __cplusplus */ ++ ++#if defined(__x86_64__) ++#define TYPEDEF_UINTPTR ++typedef unsigned long long int uintptr; ++#endif ++ ++ ++ ++ ++ ++#if defined(_NEED_SIZE_T_) ++typedef long unsigned int size_t; ++#endif ++ ++ ++ ++ ++#if defined(__sparc__) ++#define TYPEDEF_ULONG ++#endif ++ ++ ++/* ++ * If this is either a Linux hybrid build or the per-port code of a hybrid build ++ * then use the Linux header files to get some of the typedefs. Otherwise, define ++ * them entirely in this file. We can't always define the types because we get ++ * a duplicate typedef error; there is no way to "undefine" a typedef. ++ * We know when it's per-port code because each file defines LINUX_PORT at the top. ++ */ ++#if !defined(LINUX_HYBRID) || defined(LINUX_PORT) ++#define TYPEDEF_UINT ++#ifndef TARGETENV_android ++#define TYPEDEF_USHORT ++#define TYPEDEF_ULONG ++#endif /* TARGETENV_android */ ++#ifdef __KERNEL__ ++#include ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)) ++#define TYPEDEF_BOOL ++#endif /* >= 2.6.19 */ ++/* special detection for 2.6.18-128.7.1.0.1.el5 */ ++#if (LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 18)) ++#include ++#ifdef noinline_for_stack ++#define TYPEDEF_BOOL ++#endif ++#endif /* == 2.6.18 */ ++#endif /* __KERNEL__ */ ++#endif /* !defined(LINUX_HYBRID) || defined(LINUX_PORT) */ ++ ++ ++ ++ ++/* Do not support the (u)int64 types with strict ansi for GNU C */ ++#if defined(__GNUC__) && defined(__STRICT_ANSI__) ++#define TYPEDEF_INT64 ++#define TYPEDEF_UINT64 ++#endif ++ ++/* ICL accepts unsigned 64 bit type only, and complains in ANSI mode ++ * for signed or unsigned ++ */ ++#if defined(__ICL) ++ ++#define TYPEDEF_INT64 ++ ++#if defined(__STDC__) ++#define TYPEDEF_UINT64 ++#endif ++ ++#endif /* __ICL */ ++ ++#if !defined(__DJGPP__) ++ ++/* pick up ushort & uint from standard types.h */ ++#if defined(__KERNEL__) ++ ++/* See note above */ ++#if !defined(LINUX_HYBRID) || defined(LINUX_PORT) ++#include /* sys/types.h and linux/types.h are oil and water */ ++#endif /* !defined(LINUX_HYBRID) || defined(LINUX_PORT) */ ++ ++#else ++ ++ ++#include ++ ++#endif /* linux && __KERNEL__ */ ++ ++#endif ++ ++ ++ ++/* use the default typedefs in the next section of this file */ ++#define USE_TYPEDEF_DEFAULTS ++ ++#endif /* SITE_TYPEDEFS */ ++ ++ ++/* ++ * Default Typedefs ++ */ ++ ++#ifdef USE_TYPEDEF_DEFAULTS ++#undef USE_TYPEDEF_DEFAULTS ++ ++#ifndef TYPEDEF_BOOL ++typedef /* @abstract@ */ unsigned char bool; ++#endif ++ ++/* define uchar, ushort, uint, ulong */ ++ ++#ifndef TYPEDEF_UCHAR ++typedef unsigned char uchar; ++#endif ++ ++#ifndef TYPEDEF_USHORT ++typedef unsigned short ushort; ++#endif ++ ++#ifndef TYPEDEF_UINT ++typedef unsigned int uint; ++#endif ++ ++#ifndef TYPEDEF_ULONG ++typedef unsigned long ulong; ++#endif ++ ++/* define [u]int8/16/32/64, uintptr */ ++ ++#ifndef TYPEDEF_UINT8 ++typedef unsigned char uint8; ++#endif ++ ++#ifndef TYPEDEF_UINT16 ++typedef unsigned short uint16; ++#endif ++ ++#ifndef TYPEDEF_UINT32 ++typedef unsigned int uint32; ++#endif ++ ++#ifndef TYPEDEF_UINT64 ++typedef unsigned long long uint64; ++#endif ++ ++#ifndef TYPEDEF_UINTPTR ++typedef unsigned int uintptr; ++#endif ++ ++#ifndef TYPEDEF_INT8 ++typedef signed char int8; ++#endif ++ ++#ifndef TYPEDEF_INT16 ++typedef signed short int16; ++#endif ++ ++#ifndef TYPEDEF_INT32 ++typedef signed int int32; ++#endif ++ ++#ifndef TYPEDEF_INT64 ++typedef signed long long int64; ++#endif ++ ++/* define float32/64, float_t */ ++ ++#ifndef TYPEDEF_FLOAT32 ++typedef float float32; ++#endif ++ ++#ifndef TYPEDEF_FLOAT64 ++typedef double float64; ++#endif ++ ++/* ++ * abstracted floating point type allows for compile time selection of ++ * single or double precision arithmetic. Compiling with -DFLOAT32 ++ * selects single precision; the default is double precision. ++ */ ++ ++#ifndef TYPEDEF_FLOAT_T ++ ++#if defined(FLOAT32) ++typedef float32 float_t; ++#else /* default to double precision floating point */ ++typedef float64 float_t; ++#endif ++ ++#endif /* TYPEDEF_FLOAT_T */ ++ ++/* define macro values */ ++ ++#ifndef FALSE ++#define FALSE 0 ++#endif ++ ++#ifndef TRUE ++#define TRUE 1 /* TRUE */ ++#endif ++ ++#ifndef NULL ++#define NULL 0 ++#endif ++ ++#ifndef OFF ++#define OFF 0 ++#endif ++ ++#ifndef ON ++#define ON 1 /* ON = 1 */ ++#endif ++ ++#define AUTO (-1) /* Auto = -1 */ ++ ++/* define PTRSZ, INLINE */ ++ ++#ifndef PTRSZ ++#define PTRSZ sizeof(char*) ++#endif ++ ++ ++/* Detect compiler type. */ ++#if defined(__GNUC__) || defined(__lint) ++ #define BWL_COMPILER_GNU ++#elif defined(__CC_ARM) && __CC_ARM ++ #define BWL_COMPILER_ARMCC ++#else ++ #error "Unknown compiler!" ++#endif ++ ++ ++#ifndef INLINE ++ #if defined(BWL_COMPILER_MICROSOFT) ++ #define INLINE __inline ++ #elif defined(BWL_COMPILER_GNU) ++ #define INLINE __inline__ ++ #elif defined(BWL_COMPILER_ARMCC) ++ #define INLINE __inline ++ #else ++ #define INLINE ++ #endif ++#endif /* INLINE */ ++ ++#undef TYPEDEF_BOOL ++#undef TYPEDEF_UCHAR ++#undef TYPEDEF_USHORT ++#undef TYPEDEF_UINT ++#undef TYPEDEF_ULONG ++#undef TYPEDEF_UINT8 ++#undef TYPEDEF_UINT16 ++#undef TYPEDEF_UINT32 ++#undef TYPEDEF_UINT64 ++#undef TYPEDEF_UINTPTR ++#undef TYPEDEF_INT8 ++#undef TYPEDEF_INT16 ++#undef TYPEDEF_INT32 ++#undef TYPEDEF_INT64 ++#undef TYPEDEF_FLOAT32 ++#undef TYPEDEF_FLOAT64 ++#undef TYPEDEF_FLOAT_T ++ ++#endif /* USE_TYPEDEF_DEFAULTS */ ++ ++/* Suppress unused parameter warning */ ++#define UNUSED_PARAMETER(x) (void)(x) ++ ++/* Avoid warning for discarded const or volatile qualifier in special cases (-Wcast-qual) */ ++#define DISCARD_QUAL(ptr, type) ((type *)(uintptr)(ptr)) ++ ++/* ++ * Including the bcmdefs.h here, to make sure everyone including typedefs.h ++ * gets this automatically ++*/ ++#include ++#endif /* _TYPEDEFS_H_ */ +diff --git a/drivers/net/wireless/ap6211/include/wlfc_proto.h b/drivers/net/wireless/ap6211/include/wlfc_proto.h +new file mode 100755 +index 0000000..98d2fa9 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/wlfc_proto.h +@@ -0,0 +1,217 @@ ++/* ++* Copyright (C) 1999-2012, Broadcom Corporation ++* ++* Unless you and Broadcom execute a separate written software license ++* agreement governing use of this software, this software is licensed to you ++* under the terms of the GNU General Public License version 2 (the "GPL"), ++* available at http://www.broadcom.com/licenses/GPLv2.php, with the ++* following added to such license: ++* ++* As a special exception, the copyright holders of this software give you ++* permission to link this software with independent modules, and to copy and ++* distribute the resulting executable under terms of your choice, provided that ++* you also meet, for each linked independent module, the terms and conditions of ++* the license of that module. An independent module is a module which is not ++* derived from this software. The special exception does not apply to any ++* modifications of the software. ++* ++* Notwithstanding the above, under no circumstances may you combine this ++* software in any way with any other Broadcom software provided under a license ++* other than the GPL, without Broadcom's express prior written consent. ++* $Id: wlfc_proto.h 361006 2012-10-05 07:45:51Z $ ++* ++*/ ++#ifndef __wlfc_proto_definitions_h__ ++#define __wlfc_proto_definitions_h__ ++ ++ /* Use TLV to convey WLFC information. ++ --------------------------------------------------------------------------- ++ | Type | Len | value | Description ++ --------------------------------------------------------------------------- ++ | 1 | 1 | (handle) | MAC OPEN ++ --------------------------------------------------------------------------- ++ | 2 | 1 | (handle) | MAC CLOSE ++ --------------------------------------------------------------------------- ++ | 3 | 2 | (count, handle, prec_bmp)| Set the credit depth for a MAC dstn ++ --------------------------------------------------------------------------- ++ | 4 | 4 | see pkttag comments | TXSTATUS ++ --------------------------------------------------------------------------- ++ | 5 | 4 | see pkttag comments | PKKTTAG [host->firmware] ++ --------------------------------------------------------------------------- ++ | 6 | 8 | (handle, ifid, MAC) | MAC ADD ++ --------------------------------------------------------------------------- ++ | 7 | 8 | (handle, ifid, MAC) | MAC DEL ++ --------------------------------------------------------------------------- ++ | 8 | 1 | (rssi) | RSSI - RSSI value for the packet. ++ --------------------------------------------------------------------------- ++ | 9 | 1 | (interface ID) | Interface OPEN ++ --------------------------------------------------------------------------- ++ | 10 | 1 | (interface ID) | Interface CLOSE ++ --------------------------------------------------------------------------- ++ | 11 | 8 | fifo credit returns map | FIFO credits back to the host ++ | | | | ++ | | | | -------------------------------------- ++ | | | | | ac0 | ac1 | ac2 | ac3 | bcmc | atim | ++ | | | | -------------------------------------- ++ | | | | ++ --------------------------------------------------------------------------- ++ | 12 | 2 | MAC handle, | Host provides a bitmap of pending ++ | | | AC[0-3] traffic bitmap | unicast traffic for MAC-handle dstn. ++ | | | | [host->firmware] ++ --------------------------------------------------------------------------- ++ | 13 | 3 | (count, handle, prec_bmp)| One time request for packet to a specific ++ | | | | MAC destination. ++ --------------------------------------------------------------------------- ++ | 15 | 1 | interface ID | NIC period start ++ --------------------------------------------------------------------------- ++ | 16 | 1 | interface ID | NIC period end ++ --------------------------------------------------------------------------- ++ | 17 | 3 | (ifid, txs) | Action frame tx status ++ --------------------------------------------------------------------------- ++ | 255 | N/A | N/A | FILLER - This is a special type ++ | | | | that has no length or value. ++ | | | | Typically used for padding. ++ --------------------------------------------------------------------------- ++ */ ++ ++#define WLFC_CTL_TYPE_MAC_OPEN 1 ++#define WLFC_CTL_TYPE_MAC_CLOSE 2 ++#define WLFC_CTL_TYPE_MAC_REQUEST_CREDIT 3 ++#define WLFC_CTL_TYPE_TXSTATUS 4 ++#define WLFC_CTL_TYPE_PKTTAG 5 ++ ++#define WLFC_CTL_TYPE_MACDESC_ADD 6 ++#define WLFC_CTL_TYPE_MACDESC_DEL 7 ++#define WLFC_CTL_TYPE_RSSI 8 ++ ++#define WLFC_CTL_TYPE_INTERFACE_OPEN 9 ++#define WLFC_CTL_TYPE_INTERFACE_CLOSE 10 ++ ++#define WLFC_CTL_TYPE_FIFO_CREDITBACK 11 ++ ++#define WLFC_CTL_TYPE_PENDING_TRAFFIC_BMP 12 ++#define WLFC_CTL_TYPE_MAC_REQUEST_PACKET 13 ++#define WLFC_CTL_TYPE_HOST_REORDER_RXPKTS 14 ++ ++#define WLFC_CTL_TYPE_NIC_PRD_START 15 ++#define WLFC_CTL_TYPE_NIC_PRD_END 16 ++#define WLFC_CTL_TYPE_AF_TXS 17 ++#define WLFC_CTL_TYPE_TRANS_ID 18 ++#define WLFC_CTL_TYPE_COMP_TXSTATUS 19 ++ ++#define WLFC_CTL_TYPE_FILLER 255 ++ ++#define WLFC_CTL_VALUE_LEN_MACDESC 8 /* handle, interface, MAC */ ++ ++#define WLFC_CTL_VALUE_LEN_MAC 1 /* MAC-handle */ ++#define WLFC_CTL_VALUE_LEN_RSSI 1 ++ ++#define WLFC_CTL_VALUE_LEN_INTERFACE 1 ++#define WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP 2 ++ ++#define WLFC_CTL_VALUE_LEN_TXSTATUS 4 ++#define WLFC_CTL_VALUE_LEN_PKTTAG 4 ++ ++/* enough space to host all 4 ACs, bc/mc and atim fifo credit */ ++#define WLFC_CTL_VALUE_LEN_FIFO_CREDITBACK 6 ++ ++#define WLFC_CTL_VALUE_LEN_REQUEST_CREDIT 3 /* credit, MAC-handle, prec_bitmap */ ++#define WLFC_CTL_VALUE_LEN_REQUEST_PACKET 3 /* credit, MAC-handle, prec_bitmap */ ++ ++#define WLFC_CTL_VALUE_LEN_NIC_PRD_START 1 ++#define WLFC_CTL_VALUE_LEN_NIC_PRD_END 1 ++#define WLFC_CTL_VALUE_LEN_AF_TXS 3 ++ ++ ++#define WLFC_PKTID_GEN_MASK 0x80000000 ++#define WLFC_PKTID_GEN_SHIFT 31 ++ ++#define WLFC_PKTID_GEN(x) (((x) & WLFC_PKTID_GEN_MASK) >> WLFC_PKTID_GEN_SHIFT) ++#define WLFC_PKTID_SETGEN(x, gen) (x) = ((x) & ~WLFC_PKTID_GEN_MASK) | \ ++ (((gen) << WLFC_PKTID_GEN_SHIFT) & WLFC_PKTID_GEN_MASK) ++ ++#define WLFC_PKTFLAG_PKTFROMHOST 0x01 ++#define WLFC_PKTFLAG_PKT_REQUESTED 0x02 ++ ++#define WL_TXSTATUS_FLAGS_MASK 0xf /* allow 4 bits only */ ++#define WL_TXSTATUS_FLAGS_SHIFT 27 ++ ++#define WL_TXSTATUS_SET_FLAGS(x, flags) ((x) = \ ++ ((x) & ~(WL_TXSTATUS_FLAGS_MASK << WL_TXSTATUS_FLAGS_SHIFT)) | \ ++ (((flags) & WL_TXSTATUS_FLAGS_MASK) << WL_TXSTATUS_FLAGS_SHIFT)) ++#define WL_TXSTATUS_GET_FLAGS(x) (((x) >> WL_TXSTATUS_FLAGS_SHIFT) & \ ++ WL_TXSTATUS_FLAGS_MASK) ++ ++#define WL_TXSTATUS_FIFO_MASK 0x7 /* allow 3 bits for FIFO ID */ ++#define WL_TXSTATUS_FIFO_SHIFT 24 ++ ++#define WL_TXSTATUS_SET_FIFO(x, flags) ((x) = \ ++ ((x) & ~(WL_TXSTATUS_FIFO_MASK << WL_TXSTATUS_FIFO_SHIFT)) | \ ++ (((flags) & WL_TXSTATUS_FIFO_MASK) << WL_TXSTATUS_FIFO_SHIFT)) ++#define WL_TXSTATUS_GET_FIFO(x) (((x) >> WL_TXSTATUS_FIFO_SHIFT) & WL_TXSTATUS_FIFO_MASK) ++ ++#define WL_TXSTATUS_PKTID_MASK 0xffffff /* allow 24 bits */ ++#define WL_TXSTATUS_SET_PKTID(x, num) ((x) = \ ++ ((x) & ~WL_TXSTATUS_PKTID_MASK) | (num)) ++#define WL_TXSTATUS_GET_PKTID(x) ((x) & WL_TXSTATUS_PKTID_MASK) ++ ++/* 32 STA should be enough??, 6 bits; Must be power of 2 */ ++#define WLFC_MAC_DESC_TABLE_SIZE 32 ++#define WLFC_MAX_IFNUM 16 ++#define WLFC_MAC_DESC_ID_INVALID 0xff ++ ++/* b[7:5] -reuse guard, b[4:0] -value */ ++#define WLFC_MAC_DESC_GET_LOOKUP_INDEX(x) ((x) & 0x1f) ++ ++#define WLFC_PKTFLAG_SET_PKTREQUESTED(x) (x) |= \ ++ (WLFC_PKTFLAG_PKT_REQUESTED << WL_TXSTATUS_FLAGS_SHIFT) ++ ++#define WLFC_PKTFLAG_CLR_PKTREQUESTED(x) (x) &= \ ++ ~(WLFC_PKTFLAG_PKT_REQUESTED << WL_TXSTATUS_FLAGS_SHIFT) ++ ++#define WL_TXSTATUS_GENERATION_MASK 1 ++#define WL_TXSTATUS_GENERATION_SHIFT 31 ++ ++#define WLFC_PKTFLAG_SET_GENERATION(x, gen) ((x) = \ ++ ((x) & ~(WL_TXSTATUS_GENERATION_MASK << WL_TXSTATUS_GENERATION_SHIFT)) | \ ++ (((gen) & WL_TXSTATUS_GENERATION_MASK) << WL_TXSTATUS_GENERATION_SHIFT)) ++ ++#define WLFC_PKTFLAG_GENERATION(x) (((x) >> WL_TXSTATUS_GENERATION_SHIFT) & \ ++ WL_TXSTATUS_GENERATION_MASK) ++ ++#define WLFC_MAX_PENDING_DATALEN 120 ++ ++/* host is free to discard the packet */ ++#define WLFC_CTL_PKTFLAG_DISCARD 0 ++/* D11 suppressed a packet */ ++#define WLFC_CTL_PKTFLAG_D11SUPPRESS 1 ++/* WL firmware suppressed a packet because MAC is ++ already in PSMode (short time window) ++*/ ++#define WLFC_CTL_PKTFLAG_WLSUPPRESS 2 ++/* Firmware tossed this packet */ ++#define WLFC_CTL_PKTFLAG_TOSSED_BYWLC 3 ++ ++#define WLFC_D11_STATUS_INTERPRET(txs) \ ++ (((txs)->status.suppr_ind != 0) ? WLFC_CTL_PKTFLAG_D11SUPPRESS : WLFC_CTL_PKTFLAG_DISCARD) ++ ++/* AMPDU host reorder packet flags */ ++#define WLHOST_REORDERDATA_MAXFLOWS 256 ++#define WLHOST_REORDERDATA_LEN 10 ++#define WLHOST_REORDERDATA_TOTLEN (WLHOST_REORDERDATA_LEN + 1 + 1) /* +tag +len */ ++ ++#define WLHOST_REORDERDATA_FLOWID_OFFSET 0 ++#define WLHOST_REORDERDATA_MAXIDX_OFFSET 2 ++#define WLHOST_REORDERDATA_FLAGS_OFFSET 4 ++#define WLHOST_REORDERDATA_CURIDX_OFFSET 6 ++#define WLHOST_REORDERDATA_EXPIDX_OFFSET 8 ++ ++#define WLHOST_REORDERDATA_DEL_FLOW 0x01 ++#define WLHOST_REORDERDATA_FLUSH_ALL 0x02 ++#define WLHOST_REORDERDATA_CURIDX_VALID 0x04 ++#define WLHOST_REORDERDATA_EXPIDX_VALID 0x08 ++#define WLHOST_REORDERDATA_NEW_HOLE 0x10 ++/* transaction id data len byte 0: rsvd, byte 1: seqnumber, byte 2-5 will be used for timestampe */ ++#define WLFC_CTL_TRANS_ID_LEN 6 ++ ++#endif /* __wlfc_proto_definitions_h__ */ +diff --git a/drivers/net/wireless/ap6211/include/wlioctl.h b/drivers/net/wireless/ap6211/include/wlioctl.h +new file mode 100755 +index 0000000..a3e7003 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/wlioctl.h +@@ -0,0 +1,5079 @@ ++/* ++ * Custom OID/ioctl definitions for ++ * Broadcom 802.11abg Networking Device Driver ++ * ++ * Definitions subject to change without notice. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: wlioctl.h 366141 2012-11-01 01:55:06Z $ ++ */ ++ ++#ifndef _wlioctl_h_ ++#define _wlioctl_h_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++#include ++#include ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++/* LINUX_POSTMOGRIFY_REMOVAL: undefined during compile phase, so its ++ * a no-op for most cases. For hybrid and other open source releases, ++ * its defined during a second pass and mogrified out for distribution. ++ */ ++ ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++ ++#ifndef INTF_NAME_SIZ ++#define INTF_NAME_SIZ 16 ++#endif ++ ++/* Used to send ioctls over the transport pipe */ ++typedef struct remote_ioctl { ++ cdc_ioctl_t msg; ++ uint data_len; ++ char intf_name[INTF_NAME_SIZ]; ++} rem_ioctl_t; ++#define REMOTE_SIZE sizeof(rem_ioctl_t) ++ ++#define ACTION_FRAME_SIZE 1800 ++ ++typedef struct wl_action_frame { ++ struct ether_addr da; ++ uint16 len; ++ uint32 packetId; ++ uint8 data[ACTION_FRAME_SIZE]; ++} wl_action_frame_t; ++ ++#define WL_WIFI_ACTION_FRAME_SIZE sizeof(struct wl_action_frame) ++ ++typedef struct ssid_info ++{ ++ uint8 ssid_len; /* the length of SSID */ ++ uint8 ssid[32]; /* SSID string */ ++} ssid_info_t; ++ ++typedef struct wl_af_params { ++ uint32 channel; ++ int32 dwell_time; ++ struct ether_addr BSSID; ++ wl_action_frame_t action_frame; ++} wl_af_params_t; ++ ++#define WL_WIFI_AF_PARAMS_SIZE sizeof(struct wl_af_params) ++ ++#define MFP_TEST_FLAG_NORMAL 0 ++#define MFP_TEST_FLAG_ANY_KEY 1 ++typedef struct wl_sa_query { ++ uint32 flag; ++ uint8 action; ++ uint16 id; ++ struct ether_addr da; ++} wl_sa_query_t; ++ ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++/* require default structure packing */ ++#define BWL_DEFAULT_PACKING ++#include ++ ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++/* Legacy structure to help keep backward compatible wl tool and tray app */ ++ ++#define LEGACY_WL_BSS_INFO_VERSION 107 /* older version of wl_bss_info struct */ ++ ++typedef struct wl_bss_info_107 { ++ uint32 version; /* version field */ ++ uint32 length; /* byte length of data in this record, ++ * starting at version and including IEs ++ */ ++ struct ether_addr BSSID; ++ uint16 beacon_period; /* units are Kusec */ ++ uint16 capability; /* Capability information */ ++ uint8 SSID_len; ++ uint8 SSID[32]; ++ struct { ++ uint count; /* # rates in this set */ ++ uint8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */ ++ } rateset; /* supported rates */ ++ uint8 channel; /* Channel no. */ ++ uint16 atim_window; /* units are Kusec */ ++ uint8 dtim_period; /* DTIM period */ ++ int16 RSSI; /* receive signal strength (in dBm) */ ++ int8 phy_noise; /* noise (in dBm) */ ++ uint32 ie_length; /* byte length of Information Elements */ ++ /* variable length Information Elements */ ++} wl_bss_info_107_t; ++ ++/* ++ * Per-BSS information structure. ++ */ ++ ++#define LEGACY2_WL_BSS_INFO_VERSION 108 /* old version of wl_bss_info struct */ ++ ++/* BSS info structure ++ * Applications MUST CHECK ie_offset field and length field to access IEs and ++ * next bss_info structure in a vector (in wl_scan_results_t) ++ */ ++typedef struct wl_bss_info_108 { ++ uint32 version; /* version field */ ++ uint32 length; /* byte length of data in this record, ++ * starting at version and including IEs ++ */ ++ struct ether_addr BSSID; ++ uint16 beacon_period; /* units are Kusec */ ++ uint16 capability; /* Capability information */ ++ uint8 SSID_len; ++ uint8 SSID[32]; ++ struct { ++ uint count; /* # rates in this set */ ++ uint8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */ ++ } rateset; /* supported rates */ ++ chanspec_t chanspec; /* chanspec for bss */ ++ uint16 atim_window; /* units are Kusec */ ++ uint8 dtim_period; /* DTIM period */ ++ int16 RSSI; /* receive signal strength (in dBm) */ ++ int8 phy_noise; /* noise (in dBm) */ ++ ++ uint8 n_cap; /* BSS is 802.11N Capable */ ++ uint32 nbss_cap; /* 802.11N BSS Capabilities (based on HT_CAP_*) */ ++ uint8 ctl_ch; /* 802.11N BSS control channel number */ ++ uint32 reserved32[1]; /* Reserved for expansion of BSS properties */ ++ uint8 flags; /* flags */ ++ uint8 reserved[3]; /* Reserved for expansion of BSS properties */ ++ uint8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */ ++ ++ uint16 ie_offset; /* offset at which IEs start, from beginning */ ++ uint32 ie_length; /* byte length of Information Elements */ ++ /* Add new fields here */ ++ /* variable length Information Elements */ ++} wl_bss_info_108_t; ++ ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++#define WL_BSS_INFO_VERSION 109 /* current version of wl_bss_info struct */ ++ ++/* BSS info structure ++ * Applications MUST CHECK ie_offset field and length field to access IEs and ++ * next bss_info structure in a vector (in wl_scan_results_t) ++ */ ++typedef struct wl_bss_info { ++ uint32 version; /* version field */ ++ uint32 length; /* byte length of data in this record, ++ * starting at version and including IEs ++ */ ++ struct ether_addr BSSID; ++ uint16 beacon_period; /* units are Kusec */ ++ uint16 capability; /* Capability information */ ++ uint8 SSID_len; ++ uint8 SSID[32]; ++ struct { ++ uint count; /* # rates in this set */ ++ uint8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */ ++ } rateset; /* supported rates */ ++ chanspec_t chanspec; /* chanspec for bss */ ++ uint16 atim_window; /* units are Kusec */ ++ uint8 dtim_period; /* DTIM period */ ++ int16 RSSI; /* receive signal strength (in dBm) */ ++ int8 phy_noise; /* noise (in dBm) */ ++ ++ uint8 n_cap; /* BSS is 802.11N Capable */ ++ uint32 nbss_cap; /* 802.11N+AC BSS Capabilities */ ++ uint8 ctl_ch; /* 802.11N BSS control channel number */ ++ uint8 padding1[3]; /* explicit struct alignment padding */ ++ uint16 vht_rxmcsmap; /* VHT rx mcs map */ ++ uint16 vht_txmcsmap; /* VHT tx mcs map */ ++ uint8 flags; /* flags */ ++ uint8 vht_cap; /* BSS is vht capable */ ++ uint8 reserved[2]; /* Reserved for expansion of BSS properties */ ++ uint8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */ ++ ++ uint16 ie_offset; /* offset at which IEs start, from beginning */ ++ uint32 ie_length; /* byte length of Information Elements */ ++ int16 SNR; /* average SNR of during frame reception */ ++ /* Add new fields here */ ++ /* variable length Information Elements */ ++} wl_bss_info_t; ++ ++/* bss_info_cap_t flags */ ++#define WL_BSS_FLAGS_FROM_BEACON 0x01 /* bss_info derived from beacon */ ++#define WL_BSS_FLAGS_FROM_CACHE 0x02 /* bss_info collected from cache */ ++#define WL_BSS_FLAGS_RSSI_ONCHANNEL 0x04 /* rssi info was received on channel (vs offchannel) */ ++ ++/* bssinfo flag for nbss_cap */ ++#define VHT_BI_SGI_80MHZ 0x00000100 ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++ ++typedef struct wl_bsscfg { ++ uint32 wsec; ++ uint32 WPA_auth; ++ uint32 wsec_index; ++ uint32 associated; ++ uint32 BSS; ++ uint32 phytest_on; ++ struct ether_addr prev_BSSID; ++ struct ether_addr BSSID; ++ uint32 targetbss_wpa2_flags; ++ uint32 assoc_type; ++ uint32 assoc_state; ++} wl_bsscfg_t; ++ ++typedef struct wl_bss_config { ++ uint32 atim_window; ++ uint32 beacon_period; ++ uint32 chanspec; ++} wl_bss_config_t; ++ ++#define DLOAD_HANDLER_VER 1 /* Downloader version */ ++#define DLOAD_FLAG_VER_MASK 0xf000 /* Downloader version mask */ ++#define DLOAD_FLAG_VER_SHIFT 12 /* Downloader version shift */ ++ ++#define DL_CRC_NOT_INUSE 0x0001 ++ ++/* generic download types & flags */ ++enum { ++ DL_TYPE_UCODE = 1, ++ DL_TYPE_CLM = 2 ++}; ++ ++/* ucode type values */ ++enum { ++ UCODE_FW, ++ INIT_VALS, ++ BS_INIT_VALS ++}; ++ ++struct wl_dload_data { ++ uint16 flag; ++ uint16 dload_type; ++ uint32 len; ++ uint32 crc; ++ uint8 data[1]; ++}; ++typedef struct wl_dload_data wl_dload_data_t; ++ ++struct wl_ucode_info { ++ uint32 ucode_type; ++ uint32 num_chunks; ++ uint32 chunk_len; ++ uint32 chunk_num; ++ uint8 data_chunk[1]; ++}; ++typedef struct wl_ucode_info wl_ucode_info_t; ++ ++struct wl_clm_dload_info { ++ uint32 ds_id; ++ uint32 clm_total_len; ++ uint32 num_chunks; ++ uint32 chunk_len; ++ uint32 chunk_offset; ++ uint8 data_chunk[1]; ++}; ++typedef struct wl_clm_dload_info wl_clm_dload_info_t; ++ ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++typedef struct wlc_ssid { ++ uint32 SSID_len; ++ uchar SSID[32]; ++} wlc_ssid_t; ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++ ++#define MAX_PREFERRED_AP_NUM 5 ++typedef struct wlc_fastssidinfo { ++ uint32 SSID_channel[MAX_PREFERRED_AP_NUM]; ++ wlc_ssid_t SSID_info[MAX_PREFERRED_AP_NUM]; ++} wlc_fastssidinfo_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct wnm_url { ++ uint8 len; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT wnm_url_t; ++ ++typedef struct chan_scandata { ++ uint8 txpower; ++ uint8 pad; ++ chanspec_t channel; /* Channel num, bw, ctrl_sb and band */ ++ uint32 channel_mintime; ++ uint32 channel_maxtime; ++} chan_scandata_t; ++ ++typedef enum wl_scan_type { ++ EXTDSCAN_FOREGROUND_SCAN, ++ EXTDSCAN_BACKGROUND_SCAN, ++ EXTDSCAN_FORCEDBACKGROUND_SCAN ++} wl_scan_type_t; ++ ++#define WLC_EXTDSCAN_MAX_SSID 5 ++ ++typedef struct wl_extdscan_params { ++ int8 nprobes; /* 0, passive, otherwise active */ ++ int8 split_scan; /* split scan */ ++ int8 band; /* band */ ++ int8 pad; ++ wlc_ssid_t ssid[WLC_EXTDSCAN_MAX_SSID]; /* ssid list */ ++ uint32 tx_rate; /* in 500ksec units */ ++ wl_scan_type_t scan_type; /* enum */ ++ int32 channel_num; ++ chan_scandata_t channel_list[1]; /* list of chandata structs */ ++} wl_extdscan_params_t; ++ ++#define WL_EXTDSCAN_PARAMS_FIXED_SIZE (sizeof(wl_extdscan_params_t) - sizeof(chan_scandata_t)) ++ ++#define WL_BSSTYPE_INFRA 1 ++#define WL_BSSTYPE_INDEP 0 ++#define WL_BSSTYPE_ANY 2 ++ ++/* Bitmask for scan_type */ ++#define WL_SCANFLAGS_PASSIVE 0x01 /* force passive scan */ ++#define WL_SCANFLAGS_RESERVED 0x02 /* Reserved */ ++#define WL_SCANFLAGS_PROHIBITED 0x04 /* allow scanning prohibited channels */ ++ ++#define WL_SCAN_PARAMS_SSID_MAX 10 ++ ++typedef struct wl_scan_params { ++ wlc_ssid_t ssid; /* default: {0, ""} */ ++ struct ether_addr bssid; /* default: bcast */ ++ int8 bss_type; /* default: any, ++ * DOT11_BSSTYPE_ANY/INFRASTRUCTURE/INDEPENDENT ++ */ ++ uint8 scan_type; /* flags, 0 use default */ ++ int32 nprobes; /* -1 use default, number of probes per channel */ ++ int32 active_time; /* -1 use default, dwell time per channel for ++ * active scanning ++ */ ++ int32 passive_time; /* -1 use default, dwell time per channel ++ * for passive scanning ++ */ ++ int32 home_time; /* -1 use default, dwell time for the home channel ++ * between channel scans ++ */ ++ int32 channel_num; /* count of channels and ssids that follow ++ * ++ * low half is count of channels in channel_list, 0 ++ * means default (use all available channels) ++ * ++ * high half is entries in wlc_ssid_t array that ++ * follows channel_list, aligned for int32 (4 bytes) ++ * meaning an odd channel count implies a 2-byte pad ++ * between end of channel_list and first ssid ++ * ++ * if ssid count is zero, single ssid in the fixed ++ * parameter portion is assumed, otherwise ssid in ++ * the fixed portion is ignored ++ */ ++ uint16 channel_list[1]; /* list of chanspecs */ ++} wl_scan_params_t; ++ ++/* size of wl_scan_params not including variable length array */ ++#define WL_SCAN_PARAMS_FIXED_SIZE 64 ++ ++/* masks for channel and ssid count */ ++#define WL_SCAN_PARAMS_COUNT_MASK 0x0000ffff ++#define WL_SCAN_PARAMS_NSSID_SHIFT 16 ++ ++#define WL_SCAN_ACTION_START 1 ++#define WL_SCAN_ACTION_CONTINUE 2 ++#define WL_SCAN_ACTION_ABORT 3 ++ ++#define ISCAN_REQ_VERSION 1 ++ ++/* incremental scan struct */ ++typedef struct wl_iscan_params { ++ uint32 version; ++ uint16 action; ++ uint16 scan_duration; ++ wl_scan_params_t params; ++} wl_iscan_params_t; ++ ++/* 3 fields + size of wl_scan_params, not including variable length array */ ++#define WL_ISCAN_PARAMS_FIXED_SIZE (OFFSETOF(wl_iscan_params_t, params) + sizeof(wlc_ssid_t)) ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++typedef struct wl_scan_results { ++ uint32 buflen; ++ uint32 version; ++ uint32 count; ++ wl_bss_info_t bss_info[1]; ++} wl_scan_results_t; ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++/* size of wl_scan_results not including variable length array */ ++#define WL_SCAN_RESULTS_FIXED_SIZE (sizeof(wl_scan_results_t) - sizeof(wl_bss_info_t)) ++ ++/* wl_iscan_results status values */ ++#define WL_SCAN_RESULTS_SUCCESS 0 ++#define WL_SCAN_RESULTS_PARTIAL 1 ++#define WL_SCAN_RESULTS_PENDING 2 ++#define WL_SCAN_RESULTS_ABORTED 3 ++#define WL_SCAN_RESULTS_NO_MEM 4 ++ ++/* Used in EXT_STA */ ++#define DNGL_RXCTXT_SIZE 45 ++ ++ ++#define ESCAN_REQ_VERSION 1 ++ ++typedef struct wl_escan_params { ++ uint32 version; ++ uint16 action; ++ uint16 sync_id; ++ wl_scan_params_t params; ++} wl_escan_params_t; ++ ++#define WL_ESCAN_PARAMS_FIXED_SIZE (OFFSETOF(wl_escan_params_t, params) + sizeof(wlc_ssid_t)) ++ ++typedef struct wl_escan_result { ++ uint32 buflen; ++ uint32 version; ++ uint16 sync_id; ++ uint16 bss_count; ++ wl_bss_info_t bss_info[1]; ++} wl_escan_result_t; ++ ++#define WL_ESCAN_RESULTS_FIXED_SIZE (sizeof(wl_escan_result_t) - sizeof(wl_bss_info_t)) ++ ++/* incremental scan results struct */ ++typedef struct wl_iscan_results { ++ uint32 status; ++ wl_scan_results_t results; ++} wl_iscan_results_t; ++ ++/* size of wl_iscan_results not including variable length array */ ++#define WL_ISCAN_RESULTS_FIXED_SIZE \ ++ (WL_SCAN_RESULTS_FIXED_SIZE + OFFSETOF(wl_iscan_results_t, results)) ++ ++typedef struct wl_probe_params { ++ wlc_ssid_t ssid; ++ struct ether_addr bssid; ++ struct ether_addr mac; ++} wl_probe_params_t; ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++#define WL_MAXRATES_IN_SET 16 /* max # of rates in a rateset */ ++typedef struct wl_rateset { ++ uint32 count; /* # rates in this set */ ++ uint8 rates[WL_MAXRATES_IN_SET]; /* rates in 500kbps units w/hi bit set if basic */ ++} wl_rateset_t; ++ ++typedef struct wl_rateset_args { ++ uint32 count; /* # rates in this set */ ++ uint8 rates[WL_MAXRATES_IN_SET]; /* rates in 500kbps units w/hi bit set if basic */ ++ uint8 mcs[MCSSET_LEN]; /* supported mcs index bit map */ ++} wl_rateset_args_t; ++ ++/* uint32 list */ ++typedef struct wl_uint32_list { ++ /* in - # of elements, out - # of entries */ ++ uint32 count; ++ /* variable length uint32 list */ ++ uint32 element[1]; ++} wl_uint32_list_t; ++ ++/* used for association with a specific BSSID and chanspec list */ ++typedef struct wl_assoc_params { ++ struct ether_addr bssid; /* 00:00:00:00:00:00: broadcast scan */ ++ uint16 bssid_cnt; /* 0: use chanspec_num, and the single bssid, ++ * otherwise count of chanspecs in chanspec_list ++ * AND paired bssids following chanspec_list ++ */ ++ int32 chanspec_num; /* 0: all available channels, ++ * otherwise count of chanspecs in chanspec_list ++ */ ++ chanspec_t chanspec_list[1]; /* list of chanspecs */ ++} wl_assoc_params_t; ++#define WL_ASSOC_PARAMS_FIXED_SIZE OFFSETOF(wl_assoc_params_t, chanspec_list) ++ ++/* used for reassociation/roam to a specific BSSID and channel */ ++typedef wl_assoc_params_t wl_reassoc_params_t; ++#define WL_REASSOC_PARAMS_FIXED_SIZE WL_ASSOC_PARAMS_FIXED_SIZE ++ ++/* used for association to a specific BSSID and channel */ ++typedef wl_assoc_params_t wl_join_assoc_params_t; ++#define WL_JOIN_ASSOC_PARAMS_FIXED_SIZE WL_ASSOC_PARAMS_FIXED_SIZE ++ ++/* used for join with or without a specific bssid and channel list */ ++typedef struct wl_join_params { ++ wlc_ssid_t ssid; ++ wl_assoc_params_t params; /* optional field, but it must include the fixed portion ++ * of the wl_assoc_params_t struct when it does present. ++ */ ++} wl_join_params_t; ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++#define WL_JOIN_PARAMS_FIXED_SIZE (OFFSETOF(wl_join_params_t, params) + \ ++ WL_ASSOC_PARAMS_FIXED_SIZE) ++/* scan params for extended join */ ++typedef struct wl_join_scan_params { ++ uint8 scan_type; /* 0 use default, active or passive scan */ ++ int32 nprobes; /* -1 use default, number of probes per channel */ ++ int32 active_time; /* -1 use default, dwell time per channel for ++ * active scanning ++ */ ++ int32 passive_time; /* -1 use default, dwell time per channel ++ * for passive scanning ++ */ ++ int32 home_time; /* -1 use default, dwell time for the home channel ++ * between channel scans ++ */ ++} wl_join_scan_params_t; ++ ++/* extended join params */ ++typedef struct wl_extjoin_params { ++ wlc_ssid_t ssid; /* {0, ""}: wildcard scan */ ++ wl_join_scan_params_t scan; ++ wl_join_assoc_params_t assoc; /* optional field, but it must include the fixed portion ++ * of the wl_join_assoc_params_t struct when it does ++ * present. ++ */ ++} wl_extjoin_params_t; ++#define WL_EXTJOIN_PARAMS_FIXED_SIZE (OFFSETOF(wl_extjoin_params_t, assoc) + \ ++ WL_JOIN_ASSOC_PARAMS_FIXED_SIZE) ++ ++/* All builds use the new 11ac ratespec/chanspec */ ++#undef D11AC_IOTYPES ++#define D11AC_IOTYPES ++ ++#ifndef D11AC_IOTYPES ++ ++/* defines used by the nrate iovar */ ++#define NRATE_MCS_INUSE 0x00000080 /* MSC in use,indicates b0-6 holds an mcs */ ++#define NRATE_RATE_MASK 0x0000007f /* rate/mcs value */ ++#define NRATE_STF_MASK 0x0000ff00 /* stf mode mask: siso, cdd, stbc, sdm */ ++#define NRATE_STF_SHIFT 8 /* stf mode shift */ ++#define NRATE_OVERRIDE 0x80000000 /* bit indicates override both rate & mode */ ++#define NRATE_OVERRIDE_MCS_ONLY 0x40000000 /* bit indicate to override mcs only */ ++#define NRATE_SGI_MASK 0x00800000 /* sgi mode */ ++#define NRATE_SGI_SHIFT 23 /* sgi mode */ ++#define NRATE_LDPC_CODING 0x00400000 /* bit indicates adv coding in use */ ++#define NRATE_LDPC_SHIFT 22 /* ldpc shift */ ++ ++#define NRATE_STF_SISO 0 /* stf mode SISO */ ++#define NRATE_STF_CDD 1 /* stf mode CDD */ ++#define NRATE_STF_STBC 2 /* stf mode STBC */ ++#define NRATE_STF_SDM 3 /* stf mode SDM */ ++ ++#else /* D11AC_IOTYPES */ ++ ++/* WL_RSPEC defines for rate information */ ++#define WL_RSPEC_RATE_MASK 0x000000FF /* rate or HT MCS value */ ++#define WL_RSPEC_VHT_MCS_MASK 0x0000000F /* VHT MCS value */ ++#define WL_RSPEC_VHT_NSS_MASK 0x000000F0 /* VHT Nss value */ ++#define WL_RSPEC_VHT_NSS_SHIFT 4 /* VHT Nss value shift */ ++#define WL_RSPEC_TXEXP_MASK 0x00000300 ++#define WL_RSPEC_TXEXP_SHIFT 8 ++#define WL_RSPEC_BW_MASK 0x00070000 /* bandwidth mask */ ++#define WL_RSPEC_BW_SHIFT 16 /* bandwidth shift */ ++#define WL_RSPEC_STBC 0x00100000 /* STBC encoding, Nsts = 2 x Nss */ ++#define WL_RSPEC_LDPC 0x00400000 /* bit indicates adv coding in use */ ++#define WL_RSPEC_SGI 0x00800000 /* Short GI mode */ ++#define WL_RSPEC_ENCODING_MASK 0x03000000 /* Encoding of Rate/MCS field */ ++#define WL_RSPEC_OVERRIDE_RATE 0x40000000 /* bit indicate to override mcs only */ ++#define WL_RSPEC_OVERRIDE_MODE 0x80000000 /* bit indicates override both rate & mode */ ++ ++/* WL_RSPEC_ENCODING field defs */ ++#define WL_RSPEC_ENCODE_RATE 0x00000000 /* Legacy rate is stored in RSPEC_RATE_MASK */ ++#define WL_RSPEC_ENCODE_HT 0x01000000 /* HT MCS is stored in RSPEC_RATE_MASK */ ++#define WL_RSPEC_ENCODE_VHT 0x02000000 /* VHT MCS and Nss is stored in RSPEC_RATE_MASK */ ++ ++/* WL_RSPEC_BW field defs */ ++#define WL_RSPEC_BW_UNSPECIFIED 0 ++#define WL_RSPEC_BW_20MHZ 0x00010000 ++#define WL_RSPEC_BW_40MHZ 0x00020000 ++#define WL_RSPEC_BW_80MHZ 0x00030000 ++#define WL_RSPEC_BW_160MHZ 0x00040000 ++ ++/* Legacy defines for the nrate iovar */ ++#define OLD_NRATE_MCS_INUSE 0x00000080 /* MSC in use,indicates b0-6 holds an mcs */ ++#define OLD_NRATE_RATE_MASK 0x0000007f /* rate/mcs value */ ++#define OLD_NRATE_STF_MASK 0x0000ff00 /* stf mode mask: siso, cdd, stbc, sdm */ ++#define OLD_NRATE_STF_SHIFT 8 /* stf mode shift */ ++#define OLD_NRATE_OVERRIDE 0x80000000 /* bit indicates override both rate & mode */ ++#define OLD_NRATE_OVERRIDE_MCS_ONLY 0x40000000 /* bit indicate to override mcs only */ ++#define OLD_NRATE_SGI 0x00800000 /* sgi mode */ ++#define OLD_NRATE_LDPC_CODING 0x00400000 /* bit indicates adv coding in use */ ++ ++#define OLD_NRATE_STF_SISO 0 /* stf mode SISO */ ++#define OLD_NRATE_STF_CDD 1 /* stf mode CDD */ ++#define OLD_NRATE_STF_STBC 2 /* stf mode STBC */ ++#define OLD_NRATE_STF_SDM 3 /* stf mode SDM */ ++ ++#endif /* D11AC_IOTYPES */ ++ ++#define ANTENNA_NUM_1 1 /* total number of antennas to be used */ ++#define ANTENNA_NUM_2 2 ++#define ANTENNA_NUM_3 3 ++#define ANTENNA_NUM_4 4 ++ ++#define ANT_SELCFG_AUTO 0x80 /* bit indicates antenna sel AUTO */ ++#define ANT_SELCFG_MASK 0x33 /* antenna configuration mask */ ++#define ANT_SELCFG_MAX 4 /* max number of antenna configurations */ ++#define ANT_SELCFG_TX_UNICAST 0 /* unicast tx antenna configuration */ ++#define ANT_SELCFG_RX_UNICAST 1 /* unicast rx antenna configuration */ ++#define ANT_SELCFG_TX_DEF 2 /* default tx antenna configuration */ ++#define ANT_SELCFG_RX_DEF 3 /* default rx antenna configuration */ ++ ++#define MAX_STREAMS_SUPPORTED 4 /* max number of streams supported */ ++ ++typedef struct { ++ uint8 ant_config[ANT_SELCFG_MAX]; /* antenna configuration */ ++ uint8 num_antcfg; /* number of available antenna configurations */ ++} wlc_antselcfg_t; ++ ++#define HIGHEST_SINGLE_STREAM_MCS 7 /* MCS values greater than this enable multiple streams */ ++ ++#define MAX_CCA_CHANNELS 38 /* Max number of 20 Mhz wide channels */ ++#define MAX_CCA_SECS 60 /* CCA keeps this many seconds history */ ++ ++#define IBSS_MED 15 /* Mediom in-bss congestion percentage */ ++#define IBSS_HI 25 /* Hi in-bss congestion percentage */ ++#define OBSS_MED 12 ++#define OBSS_HI 25 ++#define INTERFER_MED 5 ++#define INTERFER_HI 10 ++ ++#define CCA_FLAG_2G_ONLY 0x01 /* Return a channel from 2.4 Ghz band */ ++#define CCA_FLAG_5G_ONLY 0x02 /* Return a channel from 2.4 Ghz band */ ++#define CCA_FLAG_IGNORE_DURATION 0x04 /* Ignore dwell time for each channel */ ++#define CCA_FLAGS_PREFER_1_6_11 0x10 ++#define CCA_FLAG_IGNORE_INTERFER 0x20 /* do not exlude channel based on interfer level */ ++ ++#define CCA_ERRNO_BAND 1 /* After filtering for band pref, no choices left */ ++#define CCA_ERRNO_DURATION 2 /* After filtering for duration, no choices left */ ++#define CCA_ERRNO_PREF_CHAN 3 /* After filtering for chan pref, no choices left */ ++#define CCA_ERRNO_INTERFER 4 /* After filtering for interference, no choices left */ ++#define CCA_ERRNO_TOO_FEW 5 /* Only 1 channel was input */ ++ ++typedef struct { ++ uint32 duration; /* millisecs spent sampling this channel */ ++ uint32 congest_ibss; /* millisecs in our bss (presumably this traffic will */ ++ /* move if cur bss moves channels) */ ++ uint32 congest_obss; /* traffic not in our bss */ ++ uint32 interference; /* millisecs detecting a non 802.11 interferer. */ ++ uint32 timestamp; /* second timestamp */ ++} cca_congest_t; ++ ++typedef struct { ++ chanspec_t chanspec; /* Which channel? */ ++ uint8 num_secs; /* How many secs worth of data */ ++ cca_congest_t secs[1]; /* Data */ ++} cca_congest_channel_req_t; ++ ++/* interference source detection and identification mode */ ++#define ITFR_MODE_DISABLE 0 /* disable feature */ ++#define ITFR_MODE_MANUAL_ENABLE 1 /* enable manual detection */ ++#define ITFR_MODE_AUTO_ENABLE 2 /* enable auto detection */ ++ ++/* interference sources */ ++enum interference_source { ++ ITFR_NONE = 0, /* interference */ ++ ITFR_PHONE, /* wireless phone */ ++ ITFR_VIDEO_CAMERA, /* wireless video camera */ ++ ITFR_MICROWAVE_OVEN, /* microwave oven */ ++ ITFR_BABY_MONITOR, /* wireless baby monitor */ ++ ITFR_BLUETOOTH, /* bluetooth */ ++ ITFR_VIDEO_CAMERA_OR_BABY_MONITOR, /* wireless camera or baby monitor */ ++ ITFR_BLUETOOTH_OR_BABY_MONITOR, /* bluetooth or baby monitor */ ++ ITFR_VIDEO_CAMERA_OR_PHONE, /* video camera or phone */ ++ ITFR_UNIDENTIFIED /* interference from unidentified source */ ++}; ++ ++/* structure for interference source report */ ++typedef struct { ++ uint32 flags; /* flags. bit definitions below */ ++ uint32 source; /* last detected interference source */ ++ uint32 timestamp; /* second timestamp on interferenced flag change */ ++} interference_source_rep_t; ++ ++/* bit definitions for flags in interference source report */ ++#define ITFR_INTERFERENCED 1 /* interference detected */ ++#define ITFR_HOME_CHANNEL 2 /* home channel has interference */ ++#define ITFR_NOISY_ENVIRONMENT 4 /* noisy environemnt so feature stopped */ ++ ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++#define WLC_CNTRY_BUF_SZ 4 /* Country string is 3 bytes + NUL */ ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++ ++typedef struct wl_country { ++ char country_abbrev[WLC_CNTRY_BUF_SZ]; /* nul-terminated country code used in ++ * the Country IE ++ */ ++ int32 rev; /* revision specifier for ccode ++ * on set, -1 indicates unspecified. ++ * on get, rev >= 0 ++ */ ++ char ccode[WLC_CNTRY_BUF_SZ]; /* nul-terminated built-in country code. ++ * variable length, but fixed size in ++ * struct allows simple allocation for ++ * expected country strings <= 3 chars. ++ */ ++} wl_country_t; ++ ++typedef struct wl_channels_in_country { ++ uint32 buflen; ++ uint32 band; ++ char country_abbrev[WLC_CNTRY_BUF_SZ]; ++ uint32 count; ++ uint32 channel[1]; ++} wl_channels_in_country_t; ++ ++typedef struct wl_country_list { ++ uint32 buflen; ++ uint32 band_set; ++ uint32 band; ++ uint32 count; ++ char country_abbrev[1]; ++} wl_country_list_t; ++ ++#define WL_NUM_RPI_BINS 8 ++#define WL_RM_TYPE_BASIC 1 ++#define WL_RM_TYPE_CCA 2 ++#define WL_RM_TYPE_RPI 3 ++ ++#define WL_RM_FLAG_PARALLEL (1<<0) ++ ++#define WL_RM_FLAG_LATE (1<<1) ++#define WL_RM_FLAG_INCAPABLE (1<<2) ++#define WL_RM_FLAG_REFUSED (1<<3) ++ ++typedef struct wl_rm_req_elt { ++ int8 type; ++ int8 flags; ++ chanspec_t chanspec; ++ uint32 token; /* token for this measurement */ ++ uint32 tsf_h; /* TSF high 32-bits of Measurement start time */ ++ uint32 tsf_l; /* TSF low 32-bits */ ++ uint32 dur; /* TUs */ ++} wl_rm_req_elt_t; ++ ++typedef struct wl_rm_req { ++ uint32 token; /* overall measurement set token */ ++ uint32 count; /* number of measurement requests */ ++ void *cb; /* completion callback function: may be NULL */ ++ void *cb_arg; /* arg to completion callback function */ ++ wl_rm_req_elt_t req[1]; /* variable length block of requests */ ++} wl_rm_req_t; ++#define WL_RM_REQ_FIXED_LEN OFFSETOF(wl_rm_req_t, req) ++ ++typedef struct wl_rm_rep_elt { ++ int8 type; ++ int8 flags; ++ chanspec_t chanspec; ++ uint32 token; /* token for this measurement */ ++ uint32 tsf_h; /* TSF high 32-bits of Measurement start time */ ++ uint32 tsf_l; /* TSF low 32-bits */ ++ uint32 dur; /* TUs */ ++ uint32 len; /* byte length of data block */ ++ uint8 data[1]; /* variable length data block */ ++} wl_rm_rep_elt_t; ++#define WL_RM_REP_ELT_FIXED_LEN 24 /* length excluding data block */ ++ ++#define WL_RPI_REP_BIN_NUM 8 ++typedef struct wl_rm_rpi_rep { ++ uint8 rpi[WL_RPI_REP_BIN_NUM]; ++ int8 rpi_max[WL_RPI_REP_BIN_NUM]; ++} wl_rm_rpi_rep_t; ++ ++typedef struct wl_rm_rep { ++ uint32 token; /* overall measurement set token */ ++ uint32 len; /* length of measurement report block */ ++ wl_rm_rep_elt_t rep[1]; /* variable length block of reports */ ++} wl_rm_rep_t; ++#define WL_RM_REP_FIXED_LEN 8 ++ ++ ++typedef enum sup_auth_status { ++ /* Basic supplicant authentication states */ ++ WLC_SUP_DISCONNECTED = 0, ++ WLC_SUP_CONNECTING, ++ WLC_SUP_IDREQUIRED, ++ WLC_SUP_AUTHENTICATING, ++ WLC_SUP_AUTHENTICATED, ++ WLC_SUP_KEYXCHANGE, ++ WLC_SUP_KEYED, ++ WLC_SUP_TIMEOUT, ++ WLC_SUP_LAST_BASIC_STATE, ++ ++ /* Extended supplicant authentication states */ ++ /* Waiting to receive handshake msg M1 */ ++ WLC_SUP_KEYXCHANGE_WAIT_M1 = WLC_SUP_AUTHENTICATED, ++ /* Preparing to send handshake msg M2 */ ++ WLC_SUP_KEYXCHANGE_PREP_M2 = WLC_SUP_KEYXCHANGE, ++ /* Waiting to receive handshake msg M3 */ ++ WLC_SUP_KEYXCHANGE_WAIT_M3 = WLC_SUP_LAST_BASIC_STATE, ++ WLC_SUP_KEYXCHANGE_PREP_M4, /* Preparing to send handshake msg M4 */ ++ WLC_SUP_KEYXCHANGE_WAIT_G1, /* Waiting to receive handshake msg G1 */ ++ WLC_SUP_KEYXCHANGE_PREP_G2 /* Preparing to send handshake msg G2 */ ++} sup_auth_status_t; ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++/* Enumerate crypto algorithms */ ++#define CRYPTO_ALGO_OFF 0 ++#define CRYPTO_ALGO_WEP1 1 ++#define CRYPTO_ALGO_TKIP 2 ++#define CRYPTO_ALGO_WEP128 3 ++#define CRYPTO_ALGO_AES_CCM 4 ++#define CRYPTO_ALGO_AES_OCB_MSDU 5 ++#define CRYPTO_ALGO_AES_OCB_MPDU 6 ++#if !defined(BCMEXTCCX) ++#define CRYPTO_ALGO_NALG 7 ++#else ++#define CRYPTO_ALGO_CKIP 7 ++#define CRYPTO_ALGO_CKIP_MMH 8 ++#define CRYPTO_ALGO_WEP_MMH 9 ++#define CRYPTO_ALGO_NALG 10 ++#endif ++#ifdef BCMWAPI_WPI ++#define CRYPTO_ALGO_SMS4 11 ++#endif /* BCMWAPI_WPI */ ++#define CRYPTO_ALGO_PMK 12 /* for 802.1x supp to set PMK before 4-way */ ++ ++#define WSEC_GEN_MIC_ERROR 0x0001 ++#define WSEC_GEN_REPLAY 0x0002 ++#define WSEC_GEN_ICV_ERROR 0x0004 ++#define WSEC_GEN_MFP_ACT_ERROR 0x0008 ++#define WSEC_GEN_MFP_DISASSOC_ERROR 0x0010 ++#define WSEC_GEN_MFP_DEAUTH_ERROR 0x0020 ++ ++#define WL_SOFT_KEY (1 << 0) /* Indicates this key is using soft encrypt */ ++#define WL_PRIMARY_KEY (1 << 1) /* Indicates this key is the primary (ie tx) key */ ++#if defined(BCMEXTCCX) ++#define WL_CKIP_KP (1 << 4) /* CMIC */ ++#define WL_CKIP_MMH (1 << 5) /* CKIP */ ++#else ++#define WL_KF_RES_4 (1 << 4) /* Reserved for backward compat */ ++#define WL_KF_RES_5 (1 << 5) /* Reserved for backward compat */ ++#endif ++#define WL_IBSS_PEER_GROUP_KEY (1 << 6) /* Indicates a group key for a IBSS PEER */ ++ ++typedef struct wl_wsec_key { ++ uint32 index; /* key index */ ++ uint32 len; /* key length */ ++ uint8 data[DOT11_MAX_KEY_SIZE]; /* key data */ ++ uint32 pad_1[18]; ++ uint32 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */ ++ uint32 flags; /* misc flags */ ++ uint32 pad_2[2]; ++ int pad_3; ++ int iv_initialized; /* has IV been initialized already? */ ++ int pad_4; ++ /* Rx IV */ ++ struct { ++ uint32 hi; /* upper 32 bits of IV */ ++ uint16 lo; /* lower 16 bits of IV */ ++ } rxiv; ++ uint32 pad_5[2]; ++ struct ether_addr ea; /* per station */ ++} wl_wsec_key_t; ++ ++#define WSEC_MIN_PSK_LEN 8 ++#define WSEC_MAX_PSK_LEN 64 ++ ++/* Flag for key material needing passhash'ing */ ++#define WSEC_PASSPHRASE (1<<0) ++ ++/* receptacle for WLC_SET_WSEC_PMK parameter */ ++typedef struct { ++ ushort key_len; /* octets in key material */ ++ ushort flags; /* key handling qualification */ ++ uint8 key[WSEC_MAX_PSK_LEN]; /* PMK material */ ++} wsec_pmk_t; ++ ++/* wireless security bitvec */ ++#define WEP_ENABLED 0x0001 ++#define TKIP_ENABLED 0x0002 ++#define AES_ENABLED 0x0004 ++#define WSEC_SWFLAG 0x0008 ++#define SES_OW_ENABLED 0x0040 /* to go into transition mode without setting wep */ ++ ++/* wsec macros for operating on the above definitions */ ++#define WSEC_WEP_ENABLED(wsec) ((wsec) & WEP_ENABLED) ++#define WSEC_TKIP_ENABLED(wsec) ((wsec) & TKIP_ENABLED) ++#define WSEC_AES_ENABLED(wsec) ((wsec) & AES_ENABLED) ++ ++#define WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED)) ++#define WSEC_SES_OW_ENABLED(wsec) ((wsec) & SES_OW_ENABLED) ++#ifdef BCMWAPI_WPI ++#define SMS4_ENABLED 0x0100 ++#endif /* BCMWAPI_WPI */ ++ ++#ifdef MFP ++#define MFP_CAPABLE 0x0200 ++#define MFP_REQUIRED 0x0400 ++#define MFP_SHA256 0x0800 /* a special configuration for STA for WIFI test tool */ ++#endif /* MFP */ ++ ++/* WPA authentication mode bitvec */ ++#define WPA_AUTH_DISABLED 0x0000 /* Legacy (i.e., non-WPA) */ ++#define WPA_AUTH_NONE 0x0001 /* none (IBSS) */ ++#define WPA_AUTH_UNSPECIFIED 0x0002 /* over 802.1x */ ++#define WPA_AUTH_PSK 0x0004 /* Pre-shared key */ ++#if defined(BCMEXTCCX) ++#define WPA_AUTH_CCKM 0x0008 /* CCKM */ ++#define WPA2_AUTH_CCKM 0x0010 /* CCKM2 */ ++#endif ++/* #define WPA_AUTH_8021X 0x0020 */ /* 802.1x, reserved */ ++#define WPA2_AUTH_UNSPECIFIED 0x0040 /* over 802.1x */ ++#define WPA2_AUTH_PSK 0x0080 /* Pre-shared key */ ++#define BRCM_AUTH_PSK 0x0100 /* BRCM specific PSK */ ++#define BRCM_AUTH_DPT 0x0200 /* DPT PSK without group keys */ ++#ifdef BCMWAPI_WAI ++#define WPA_AUTH_WAPI 0x0400 ++#define WAPI_AUTH_NONE WPA_AUTH_NONE /* none (IBSS) */ ++#define WAPI_AUTH_UNSPECIFIED 0x0400 /* over AS */ ++#define WAPI_AUTH_PSK 0x0800 /* Pre-shared key */ ++#endif /* BCMWAPI_WAI */ ++#define WPA2_AUTH_MFP 0x1000 /* MFP (11w) in contrast to CCX */ ++#define WPA2_AUTH_TPK 0x2000 /* TDLS Peer Key */ ++#define WPA2_AUTH_FT 0x4000 /* Fast Transition. */ ++#define WPA_AUTH_PFN_ANY 0xffffffff /* for PFN, match only ssid */ ++ ++/* pmkid */ ++#define MAXPMKID 16 ++ ++typedef struct _pmkid { ++ struct ether_addr BSSID; ++ uint8 PMKID[WPA2_PMKID_LEN]; ++} pmkid_t; ++ ++typedef struct _pmkid_list { ++ uint32 npmkid; ++ pmkid_t pmkid[1]; ++} pmkid_list_t; ++ ++typedef struct _pmkid_cand { ++ struct ether_addr BSSID; ++ uint8 preauth; ++} pmkid_cand_t; ++ ++typedef struct _pmkid_cand_list { ++ uint32 npmkid_cand; ++ pmkid_cand_t pmkid_cand[1]; ++} pmkid_cand_list_t; ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++typedef struct wl_assoc_info { ++ uint32 req_len; ++ uint32 resp_len; ++ uint32 flags; ++ struct dot11_assoc_req req; ++ struct ether_addr reassoc_bssid; /* used in reassoc's */ ++ struct dot11_assoc_resp resp; ++} wl_assoc_info_t; ++ ++/* flags */ ++#define WLC_ASSOC_REQ_IS_REASSOC 0x01 /* assoc req was actually a reassoc */ ++ ++typedef struct wl_led_info { ++ uint32 index; /* led index */ ++ uint32 behavior; ++ uint8 activehi; ++} wl_led_info_t; ++ ++ ++/* srom read/write struct passed through ioctl */ ++typedef struct { ++ uint byteoff; /* byte offset */ ++ uint nbytes; /* number of bytes */ ++ uint16 buf[1]; ++} srom_rw_t; ++ ++/* similar cis (srom or otp) struct [iovar: may not be aligned] */ ++typedef struct { ++ uint32 source; /* cis source */ ++ uint32 byteoff; /* byte offset */ ++ uint32 nbytes; /* number of bytes */ ++ /* data follows here */ ++} cis_rw_t; ++ ++#define WLC_CIS_DEFAULT 0 /* built-in default */ ++#define WLC_CIS_SROM 1 /* source is sprom */ ++#define WLC_CIS_OTP 2 /* source is otp */ ++ ++/* R_REG and W_REG struct passed through ioctl */ ++typedef struct { ++ uint32 byteoff; /* byte offset of the field in d11regs_t */ ++ uint32 val; /* read/write value of the field */ ++ uint32 size; /* sizeof the field */ ++ uint band; /* band (optional) */ ++} rw_reg_t; ++ ++/* Structure used by GET/SET_ATTEN ioctls - it controls power in b/g-band */ ++/* PCL - Power Control Loop */ ++/* current gain setting is replaced by user input */ ++#define WL_ATTEN_APP_INPUT_PCL_OFF 0 /* turn off PCL, apply supplied input */ ++#define WL_ATTEN_PCL_ON 1 /* turn on PCL */ ++/* current gain setting is maintained */ ++#define WL_ATTEN_PCL_OFF 2 /* turn off PCL. */ ++ ++typedef struct { ++ uint16 auto_ctrl; /* WL_ATTEN_XX */ ++ uint16 bb; /* Baseband attenuation */ ++ uint16 radio; /* Radio attenuation */ ++ uint16 txctl1; /* Radio TX_CTL1 value */ ++} atten_t; ++ ++/* Per-AC retry parameters */ ++struct wme_tx_params_s { ++ uint8 short_retry; ++ uint8 short_fallback; ++ uint8 long_retry; ++ uint8 long_fallback; ++ uint16 max_rate; /* In units of 512 Kbps */ ++}; ++ ++typedef struct wme_tx_params_s wme_tx_params_t; ++ ++#define WL_WME_TX_PARAMS_IO_BYTES (sizeof(wme_tx_params_t) * AC_COUNT) ++ ++/* defines used by poweridx iovar - it controls power in a-band */ ++/* current gain setting is maintained */ ++#define WL_PWRIDX_PCL_OFF -2 /* turn off PCL. */ ++#define WL_PWRIDX_PCL_ON -1 /* turn on PCL */ ++#define WL_PWRIDX_LOWER_LIMIT -2 /* lower limit */ ++#define WL_PWRIDX_UPPER_LIMIT 63 /* upper limit */ ++/* value >= 0 causes ++ * - input to be set to that value ++ * - PCL to be off ++ */ ++ ++/* Used to get specific link/ac parameters */ ++typedef struct { ++ int ac; ++ uint8 val; ++ struct ether_addr ea; ++} link_val_t; ++ ++#define BCM_MAC_STATUS_INDICATION (0x40010200L) ++ ++typedef struct { ++ uint16 ver; /* version of this struct */ ++ uint16 len; /* length in bytes of this structure */ ++ uint16 cap; /* sta's advertised capabilities */ ++ uint32 flags; /* flags defined below */ ++ uint32 idle; /* time since data pkt rx'd from sta */ ++ struct ether_addr ea; /* Station address */ ++ wl_rateset_t rateset; /* rateset in use */ ++ uint32 in; /* seconds elapsed since associated */ ++ uint32 listen_interval_inms; /* Min Listen interval in ms for this STA */ ++ uint32 tx_pkts; /* # of packets transmitted */ ++ uint32 tx_failures; /* # of packets failed */ ++ uint32 rx_ucast_pkts; /* # of unicast packets received */ ++ uint32 rx_mcast_pkts; /* # of multicast packets received */ ++ uint32 tx_rate; /* Rate of last successful tx frame */ ++ uint32 rx_rate; /* Rate of last successful rx frame */ ++ uint32 rx_decrypt_succeeds; /* # of packet decrypted successfully */ ++ uint32 rx_decrypt_failures; /* # of packet decrypted unsuccessfully */ ++} sta_info_t; ++ ++#define WL_OLD_STAINFO_SIZE OFFSETOF(sta_info_t, tx_pkts) ++ ++#define WL_STA_VER 3 ++ ++/* Flags for sta_info_t indicating properties of STA */ ++#define WL_STA_BRCM 0x1 /* Running a Broadcom driver */ ++#define WL_STA_WME 0x2 /* WMM association */ ++#define WL_STA_UNUSED 0x4 ++#define WL_STA_AUTHE 0x8 /* Authenticated */ ++#define WL_STA_ASSOC 0x10 /* Associated */ ++#define WL_STA_AUTHO 0x20 /* Authorized */ ++#define WL_STA_WDS 0x40 /* Wireless Distribution System */ ++#define WL_STA_WDS_LINKUP 0x80 /* WDS traffic/probes flowing properly */ ++#define WL_STA_PS 0x100 /* STA is in power save mode from AP's viewpoint */ ++#define WL_STA_APSD_BE 0x200 /* APSD delv/trigger for AC_BE is default enabled */ ++#define WL_STA_APSD_BK 0x400 /* APSD delv/trigger for AC_BK is default enabled */ ++#define WL_STA_APSD_VI 0x800 /* APSD delv/trigger for AC_VI is default enabled */ ++#define WL_STA_APSD_VO 0x1000 /* APSD delv/trigger for AC_VO is default enabled */ ++#define WL_STA_N_CAP 0x2000 /* STA 802.11n capable */ ++#define WL_STA_SCBSTATS 0x4000 /* Per STA debug stats */ ++ ++#define WL_WDS_LINKUP WL_STA_WDS_LINKUP /* deprecated */ ++ ++/* Values for TX Filter override mode */ ++#define WLC_TXFILTER_OVERRIDE_DISABLED 0 ++#define WLC_TXFILTER_OVERRIDE_ENABLED 1 ++ ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++/* Used to get specific STA parameters */ ++typedef struct { ++ uint32 val; ++ struct ether_addr ea; ++} scb_val_t; ++ ++/* Used by iovar versions of some ioctls, i.e. WLC_SCB_AUTHORIZE et al */ ++typedef struct { ++ uint32 code; ++ scb_val_t ioctl_args; ++} authops_t; ++ ++/* channel encoding */ ++typedef struct channel_info { ++ int hw_channel; ++ int target_channel; ++ int scan_channel; ++} channel_info_t; ++ ++/* For ioctls that take a list of MAC addresses */ ++struct maclist { ++ uint count; /* number of MAC addresses */ ++ struct ether_addr ea[1]; /* variable length array of MAC addresses */ ++}; ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++/* get pkt count struct passed through ioctl */ ++typedef struct get_pktcnt { ++ uint rx_good_pkt; ++ uint rx_bad_pkt; ++ uint tx_good_pkt; ++ uint tx_bad_pkt; ++ uint rx_ocast_good_pkt; /* unicast packets destined for others */ ++} get_pktcnt_t; ++ ++/* NINTENDO2 */ ++#define LQ_IDX_MIN 0 ++#define LQ_IDX_MAX 1 ++#define LQ_IDX_AVG 2 ++#define LQ_IDX_SUM 2 ++#define LQ_IDX_LAST 3 ++#define LQ_STOP_MONITOR 0 ++#define LQ_START_MONITOR 1 ++ ++/* Get averages RSSI, Rx PHY rate and SNR values */ ++typedef struct { ++ int rssi[LQ_IDX_LAST]; /* Array to keep min, max, avg rssi */ ++ int snr[LQ_IDX_LAST]; /* Array to keep min, max, avg snr */ ++ int isvalid; /* Flag indicating whether above data is valid */ ++} wl_lq_t; /* Link Quality */ ++ ++typedef enum wl_wakeup_reason_type { ++ LCD_ON = 1, ++ LCD_OFF, ++ DRC1_WAKE, ++ DRC2_WAKE, ++ REASON_LAST ++} wl_wr_type_t; ++ ++typedef struct { ++/* Unique filter id */ ++ uint32 id; ++ ++/* stores the reason for the last wake up */ ++ uint8 reason; ++} wl_wr_t; ++ ++/* Get MAC specific rate histogram command */ ++typedef struct { ++ struct ether_addr ea; /* MAC Address */ ++ uint8 ac_cat; /* Access Category */ ++ uint8 num_pkts; /* Number of packet entries to be averaged */ ++} wl_mac_ratehisto_cmd_t; /* MAC Specific Rate Histogram command */ ++ ++/* Get MAC rate histogram response */ ++typedef struct { ++ uint32 rate[WLC_MAXRATE + 1]; /* Rates */ ++ uint32 mcs[WL_RATESET_SZ_HT_MCS * WL_TX_CHAINS_MAX]; /* MCS counts */ ++ uint32 vht[WL_RATESET_SZ_VHT_MCS][WL_TX_CHAINS_MAX]; /* VHT counts */ ++ uint32 tsf_timer[2][2]; /* Start and End time for 8bytes value */ ++} wl_mac_ratehisto_res_t; /* MAC Specific Rate Histogram Response */ ++ ++/* Values for TX Filter override mode */ ++#define WLC_TXFILTER_OVERRIDE_DISABLED 0 ++#define WLC_TXFILTER_OVERRIDE_ENABLED 1 ++ ++#define WL_IOCTL_ACTION_GET 0x0 ++#define WL_IOCTL_ACTION_SET 0x1 ++#define WL_IOCTL_ACTION_OVL_IDX_MASK 0x1e ++#define WL_IOCTL_ACTION_OVL_RSV 0x20 ++#define WL_IOCTL_ACTION_OVL 0x40 ++#define WL_IOCTL_ACTION_MASK 0x7e ++#define WL_IOCTL_ACTION_OVL_SHIFT 1 ++ ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++/* Linux network driver ioctl encoding */ ++typedef struct wl_ioctl { ++ uint cmd; /* common ioctl definition */ ++ void *buf; /* pointer to user buffer */ ++ uint len; /* length of user buffer */ ++ uint8 set; /* 1=set IOCTL; 0=query IOCTL */ ++ uint used; /* bytes read or written (optional) */ ++ uint needed; /* bytes needed (optional) */ ++} wl_ioctl_t; ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++ ++/* reference to wl_ioctl_t struct used by usermode driver */ ++#define ioctl_subtype set /* subtype param */ ++#define ioctl_pid used /* pid param */ ++#define ioctl_status needed /* status param */ ++ ++/* ++ * Structure for passing hardware and software ++ * revision info up from the driver. ++ */ ++typedef struct wlc_rev_info { ++ uint vendorid; /* PCI vendor id */ ++ uint deviceid; /* device id of chip */ ++ uint radiorev; /* radio revision */ ++ uint chiprev; /* chip revision */ ++ uint corerev; /* core revision */ ++ uint boardid; /* board identifier (usu. PCI sub-device id) */ ++ uint boardvendor; /* board vendor (usu. PCI sub-vendor id) */ ++ uint boardrev; /* board revision */ ++ uint driverrev; /* driver version */ ++ uint ucoderev; /* microcode version */ ++ uint bus; /* bus type */ ++ uint chipnum; /* chip number */ ++ uint phytype; /* phy type */ ++ uint phyrev; /* phy revision */ ++ uint anarev; /* anacore rev */ ++ uint chippkg; /* chip package info */ ++} wlc_rev_info_t; ++ ++#define WL_REV_INFO_LEGACY_LENGTH 48 ++ ++#define WL_BRAND_MAX 10 ++typedef struct wl_instance_info { ++ uint instance; ++ char brand[WL_BRAND_MAX]; ++} wl_instance_info_t; ++ ++/* structure to change size of tx fifo */ ++typedef struct wl_txfifo_sz { ++ uint16 magic; ++ uint16 fifo; ++ uint16 size; ++} wl_txfifo_sz_t; ++/* magic pattern used for mismatch driver and wl */ ++#define WL_TXFIFO_SZ_MAGIC 0xa5a5 ++ ++/* Transfer info about an IOVar from the driver */ ++/* Max supported IOV name size in bytes, + 1 for nul termination */ ++#define WLC_IOV_NAME_LEN 30 ++typedef struct wlc_iov_trx_s { ++ uint8 module; ++ uint8 type; ++ char name[WLC_IOV_NAME_LEN]; ++} wlc_iov_trx_t; ++ ++/* check this magic number */ ++#define WLC_IOCTL_MAGIC 0x14e46c77 ++ ++/* bump this number if you change the ioctl interface */ ++#ifdef D11AC_IOTYPES ++#define WLC_IOCTL_VERSION 2 ++#define WLC_IOCTL_VERSION_LEGACY_IOTYPES 1 ++#else ++#define WLC_IOCTL_VERSION 1 ++#endif /* D11AC_IOTYPES */ ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++#define WLC_IOCTL_MAXLEN 8192 /* max length ioctl buffer required */ ++#define WLC_IOCTL_SMLEN 256 /* "small" length ioctl buffer required */ ++#define WLC_IOCTL_MEDLEN 1536 /* "med" length ioctl buffer required */ ++#if defined(LCNCONF) || defined(LCN40CONF) ++#define WLC_SAMPLECOLLECT_MAXLEN 8192 /* Max Sample Collect buffer */ ++#else ++#define WLC_SAMPLECOLLECT_MAXLEN 10240 /* Max Sample Collect buffer for two cores */ ++#endif ++ ++/* common ioctl definitions */ ++#define WLC_GET_MAGIC 0 ++#define WLC_GET_VERSION 1 ++#define WLC_UP 2 ++#define WLC_DOWN 3 ++#define WLC_GET_LOOP 4 ++#define WLC_SET_LOOP 5 ++#define WLC_DUMP 6 ++#define WLC_GET_MSGLEVEL 7 ++#define WLC_SET_MSGLEVEL 8 ++#define WLC_GET_PROMISC 9 ++#define WLC_SET_PROMISC 10 ++/* #define WLC_OVERLAY_IOCTL 11 */ /* not supported */ ++#define WLC_GET_RATE 12 ++#define WLC_GET_MAX_RATE 13 ++#define WLC_GET_INSTANCE 14 ++/* #define WLC_GET_FRAG 15 */ /* no longer supported */ ++/* #define WLC_SET_FRAG 16 */ /* no longer supported */ ++/* #define WLC_GET_RTS 17 */ /* no longer supported */ ++/* #define WLC_SET_RTS 18 */ /* no longer supported */ ++#define WLC_GET_INFRA 19 ++#define WLC_SET_INFRA 20 ++#define WLC_GET_AUTH 21 ++#define WLC_SET_AUTH 22 ++#define WLC_GET_BSSID 23 ++#define WLC_SET_BSSID 24 ++#define WLC_GET_SSID 25 ++#define WLC_SET_SSID 26 ++#define WLC_RESTART 27 ++#define WLC_TERMINATED 28 ++/* #define WLC_DUMP_SCB 28 */ /* no longer supported */ ++#define WLC_GET_CHANNEL 29 ++#define WLC_SET_CHANNEL 30 ++#define WLC_GET_SRL 31 ++#define WLC_SET_SRL 32 ++#define WLC_GET_LRL 33 ++#define WLC_SET_LRL 34 ++#define WLC_GET_PLCPHDR 35 ++#define WLC_SET_PLCPHDR 36 ++#define WLC_GET_RADIO 37 ++#define WLC_SET_RADIO 38 ++#define WLC_GET_PHYTYPE 39 ++#define WLC_DUMP_RATE 40 ++#define WLC_SET_RATE_PARAMS 41 ++#define WLC_GET_FIXRATE 42 ++#define WLC_SET_FIXRATE 43 ++/* #define WLC_GET_WEP 42 */ /* no longer supported */ ++/* #define WLC_SET_WEP 43 */ /* no longer supported */ ++#define WLC_GET_KEY 44 ++#define WLC_SET_KEY 45 ++#define WLC_GET_REGULATORY 46 ++#define WLC_SET_REGULATORY 47 ++#define WLC_GET_PASSIVE_SCAN 48 ++#define WLC_SET_PASSIVE_SCAN 49 ++#define WLC_SCAN 50 ++#define WLC_SCAN_RESULTS 51 ++#define WLC_DISASSOC 52 ++#define WLC_REASSOC 53 ++#define WLC_GET_ROAM_TRIGGER 54 ++#define WLC_SET_ROAM_TRIGGER 55 ++#define WLC_GET_ROAM_DELTA 56 ++#define WLC_SET_ROAM_DELTA 57 ++#define WLC_GET_ROAM_SCAN_PERIOD 58 ++#define WLC_SET_ROAM_SCAN_PERIOD 59 ++#define WLC_EVM 60 /* diag */ ++#define WLC_GET_TXANT 61 ++#define WLC_SET_TXANT 62 ++#define WLC_GET_ANTDIV 63 ++#define WLC_SET_ANTDIV 64 ++/* #define WLC_GET_TXPWR 65 */ /* no longer supported */ ++/* #define WLC_SET_TXPWR 66 */ /* no longer supported */ ++#define WLC_GET_CLOSED 67 ++#define WLC_SET_CLOSED 68 ++#define WLC_GET_MACLIST 69 ++#define WLC_SET_MACLIST 70 ++#define WLC_GET_RATESET 71 ++#define WLC_SET_RATESET 72 ++/* #define WLC_GET_LOCALE 73 */ /* no longer supported */ ++#define WLC_LONGTRAIN 74 ++#define WLC_GET_BCNPRD 75 ++#define WLC_SET_BCNPRD 76 ++#define WLC_GET_DTIMPRD 77 ++#define WLC_SET_DTIMPRD 78 ++#define WLC_GET_SROM 79 ++#define WLC_SET_SROM 80 ++#define WLC_GET_WEP_RESTRICT 81 ++#define WLC_SET_WEP_RESTRICT 82 ++#define WLC_GET_COUNTRY 83 ++#define WLC_SET_COUNTRY 84 ++#define WLC_GET_PM 85 ++#define WLC_SET_PM 86 ++#define WLC_GET_WAKE 87 ++#define WLC_SET_WAKE 88 ++/* #define WLC_GET_D11CNTS 89 */ /* -> "counters" iovar */ ++#define WLC_GET_FORCELINK 90 /* ndis only */ ++#define WLC_SET_FORCELINK 91 /* ndis only */ ++#define WLC_FREQ_ACCURACY 92 /* diag */ ++#define WLC_CARRIER_SUPPRESS 93 /* diag */ ++#define WLC_GET_PHYREG 94 ++#define WLC_SET_PHYREG 95 ++#define WLC_GET_RADIOREG 96 ++#define WLC_SET_RADIOREG 97 ++#define WLC_GET_REVINFO 98 ++#define WLC_GET_UCANTDIV 99 ++#define WLC_SET_UCANTDIV 100 ++#define WLC_R_REG 101 ++#define WLC_W_REG 102 ++/* #define WLC_DIAG_LOOPBACK 103 old tray diag */ ++/* #define WLC_RESET_D11CNTS 104 */ /* -> "reset_d11cnts" iovar */ ++#define WLC_GET_MACMODE 105 ++#define WLC_SET_MACMODE 106 ++#define WLC_GET_MONITOR 107 ++#define WLC_SET_MONITOR 108 ++#define WLC_GET_GMODE 109 ++#define WLC_SET_GMODE 110 ++#define WLC_GET_LEGACY_ERP 111 ++#define WLC_SET_LEGACY_ERP 112 ++#define WLC_GET_RX_ANT 113 ++#define WLC_GET_CURR_RATESET 114 /* current rateset */ ++#define WLC_GET_SCANSUPPRESS 115 ++#define WLC_SET_SCANSUPPRESS 116 ++#define WLC_GET_AP 117 ++#define WLC_SET_AP 118 ++#define WLC_GET_EAP_RESTRICT 119 ++#define WLC_SET_EAP_RESTRICT 120 ++#define WLC_SCB_AUTHORIZE 121 ++#define WLC_SCB_DEAUTHORIZE 122 ++#define WLC_GET_WDSLIST 123 ++#define WLC_SET_WDSLIST 124 ++#define WLC_GET_ATIM 125 ++#define WLC_SET_ATIM 126 ++#define WLC_GET_RSSI 127 ++#define WLC_GET_PHYANTDIV 128 ++#define WLC_SET_PHYANTDIV 129 ++#define WLC_AP_RX_ONLY 130 ++#define WLC_GET_TX_PATH_PWR 131 ++#define WLC_SET_TX_PATH_PWR 132 ++#define WLC_GET_WSEC 133 ++#define WLC_SET_WSEC 134 ++#define WLC_GET_PHY_NOISE 135 ++#define WLC_GET_BSS_INFO 136 ++#define WLC_GET_PKTCNTS 137 ++#define WLC_GET_LAZYWDS 138 ++#define WLC_SET_LAZYWDS 139 ++#define WLC_GET_BANDLIST 140 ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++#define WLC_GET_BAND 141 ++#define WLC_SET_BAND 142 ++#define WLC_SCB_DEAUTHENTICATE 143 ++#define WLC_GET_SHORTSLOT 144 ++#define WLC_GET_SHORTSLOT_OVERRIDE 145 ++#define WLC_SET_SHORTSLOT_OVERRIDE 146 ++#define WLC_GET_SHORTSLOT_RESTRICT 147 ++#define WLC_SET_SHORTSLOT_RESTRICT 148 ++#define WLC_GET_GMODE_PROTECTION 149 ++#define WLC_GET_GMODE_PROTECTION_OVERRIDE 150 ++#define WLC_SET_GMODE_PROTECTION_OVERRIDE 151 ++#define WLC_UPGRADE 152 ++/* #define WLC_GET_MRATE 153 */ /* no longer supported */ ++/* #define WLC_SET_MRATE 154 */ /* no longer supported */ ++#define WLC_GET_IGNORE_BCNS 155 ++#define WLC_SET_IGNORE_BCNS 156 ++#define WLC_GET_SCB_TIMEOUT 157 ++#define WLC_SET_SCB_TIMEOUT 158 ++#define WLC_GET_ASSOCLIST 159 ++#define WLC_GET_CLK 160 ++#define WLC_SET_CLK 161 ++#define WLC_GET_UP 162 ++#define WLC_OUT 163 ++#define WLC_GET_WPA_AUTH 164 ++#define WLC_SET_WPA_AUTH 165 ++#define WLC_GET_UCFLAGS 166 ++#define WLC_SET_UCFLAGS 167 ++#define WLC_GET_PWRIDX 168 ++#define WLC_SET_PWRIDX 169 ++#define WLC_GET_TSSI 170 ++#define WLC_GET_SUP_RATESET_OVERRIDE 171 ++#define WLC_SET_SUP_RATESET_OVERRIDE 172 ++/* #define WLC_SET_FAST_TIMER 173 */ /* no longer supported */ ++/* #define WLC_GET_FAST_TIMER 174 */ /* no longer supported */ ++/* #define WLC_SET_SLOW_TIMER 175 */ /* no longer supported */ ++/* #define WLC_GET_SLOW_TIMER 176 */ /* no longer supported */ ++/* #define WLC_DUMP_PHYREGS 177 */ /* no longer supported */ ++#define WLC_GET_PROTECTION_CONTROL 178 ++#define WLC_SET_PROTECTION_CONTROL 179 ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++#define WLC_GET_PHYLIST 180 ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++#define WLC_ENCRYPT_STRENGTH 181 /* ndis only */ ++#define WLC_DECRYPT_STATUS 182 /* ndis only */ ++#define WLC_GET_KEY_SEQ 183 ++#define WLC_GET_SCAN_CHANNEL_TIME 184 ++#define WLC_SET_SCAN_CHANNEL_TIME 185 ++#define WLC_GET_SCAN_UNASSOC_TIME 186 ++#define WLC_SET_SCAN_UNASSOC_TIME 187 ++#define WLC_GET_SCAN_HOME_TIME 188 ++#define WLC_SET_SCAN_HOME_TIME 189 ++#define WLC_GET_SCAN_NPROBES 190 ++#define WLC_SET_SCAN_NPROBES 191 ++#define WLC_GET_PRB_RESP_TIMEOUT 192 ++#define WLC_SET_PRB_RESP_TIMEOUT 193 ++#define WLC_GET_ATTEN 194 ++#define WLC_SET_ATTEN 195 ++#define WLC_GET_SHMEM 196 /* diag */ ++#define WLC_SET_SHMEM 197 /* diag */ ++/* #define WLC_GET_GMODE_PROTECTION_CTS 198 */ /* no longer supported */ ++/* #define WLC_SET_GMODE_PROTECTION_CTS 199 */ /* no longer supported */ ++#define WLC_SET_WSEC_TEST 200 ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++#define WLC_SCB_DEAUTHENTICATE_FOR_REASON 201 ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++#define WLC_TKIP_COUNTERMEASURES 202 ++#define WLC_GET_PIOMODE 203 ++#define WLC_SET_PIOMODE 204 ++#define WLC_SET_ASSOC_PREFER 205 ++#define WLC_GET_ASSOC_PREFER 206 ++#define WLC_SET_ROAM_PREFER 207 ++#define WLC_GET_ROAM_PREFER 208 ++#define WLC_SET_LED 209 ++#define WLC_GET_LED 210 ++#define WLC_GET_INTERFERENCE_MODE 211 ++#define WLC_SET_INTERFERENCE_MODE 212 ++#define WLC_GET_CHANNEL_QA 213 ++#define WLC_START_CHANNEL_QA 214 ++#define WLC_GET_CHANNEL_SEL 215 ++#define WLC_START_CHANNEL_SEL 216 ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++#define WLC_GET_VALID_CHANNELS 217 ++#define WLC_GET_FAKEFRAG 218 ++#define WLC_SET_FAKEFRAG 219 ++#define WLC_GET_PWROUT_PERCENTAGE 220 ++#define WLC_SET_PWROUT_PERCENTAGE 221 ++#define WLC_SET_BAD_FRAME_PREEMPT 222 ++#define WLC_GET_BAD_FRAME_PREEMPT 223 ++#define WLC_SET_LEAP_LIST 224 ++#define WLC_GET_LEAP_LIST 225 ++#define WLC_GET_CWMIN 226 ++#define WLC_SET_CWMIN 227 ++#define WLC_GET_CWMAX 228 ++#define WLC_SET_CWMAX 229 ++#define WLC_GET_WET 230 ++#define WLC_SET_WET 231 ++#define WLC_GET_PUB 232 ++/* #define WLC_SET_GLACIAL_TIMER 233 */ /* no longer supported */ ++/* #define WLC_GET_GLACIAL_TIMER 234 */ /* no longer supported */ ++#define WLC_GET_KEY_PRIMARY 235 ++#define WLC_SET_KEY_PRIMARY 236 ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++ ++/* #define WLC_DUMP_RADIOREGS 237 */ /* no longer supported */ ++#define WLC_GET_ACI_ARGS 238 ++#define WLC_SET_ACI_ARGS 239 ++#define WLC_UNSET_CALLBACK 240 ++#define WLC_SET_CALLBACK 241 ++#define WLC_GET_RADAR 242 ++#define WLC_SET_RADAR 243 ++#define WLC_SET_SPECT_MANAGMENT 244 ++#define WLC_GET_SPECT_MANAGMENT 245 ++#define WLC_WDS_GET_REMOTE_HWADDR 246 /* handled in wl_linux.c/wl_vx.c */ ++#define WLC_WDS_GET_WPA_SUP 247 ++#define WLC_SET_CS_SCAN_TIMER 248 ++#define WLC_GET_CS_SCAN_TIMER 249 ++#define WLC_MEASURE_REQUEST 250 ++#define WLC_INIT 251 ++#define WLC_SEND_QUIET 252 ++#define WLC_KEEPALIVE 253 ++#define WLC_SEND_PWR_CONSTRAINT 254 ++#define WLC_UPGRADE_STATUS 255 ++#define WLC_CURRENT_PWR 256 ++#define WLC_GET_SCAN_PASSIVE_TIME 257 ++#define WLC_SET_SCAN_PASSIVE_TIME 258 ++#define WLC_LEGACY_LINK_BEHAVIOR 259 ++#define WLC_GET_CHANNELS_IN_COUNTRY 260 ++#define WLC_GET_COUNTRY_LIST 261 ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++#define WLC_GET_VAR 262 /* get value of named variable */ ++#define WLC_SET_VAR 263 /* set named variable to value */ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++#define WLC_NVRAM_GET 264 /* deprecated */ ++#define WLC_NVRAM_SET 265 ++#define WLC_NVRAM_DUMP 266 ++#define WLC_REBOOT 267 ++#define WLC_SET_WSEC_PMK 268 ++#define WLC_GET_AUTH_MODE 269 ++#define WLC_SET_AUTH_MODE 270 ++#define WLC_GET_WAKEENTRY 271 ++#define WLC_SET_WAKEENTRY 272 ++#define WLC_NDCONFIG_ITEM 273 /* currently handled in wl_oid.c */ ++#define WLC_NVOTPW 274 ++#define WLC_OTPW 275 ++#define WLC_IOV_BLOCK_GET 276 ++#define WLC_IOV_MODULES_GET 277 ++#define WLC_SOFT_RESET 278 ++#define WLC_GET_ALLOW_MODE 279 ++#define WLC_SET_ALLOW_MODE 280 ++#define WLC_GET_DESIRED_BSSID 281 ++#define WLC_SET_DESIRED_BSSID 282 ++#define WLC_DISASSOC_MYAP 283 ++#define WLC_GET_NBANDS 284 /* for Dongle EXT_STA support */ ++#define WLC_GET_BANDSTATES 285 /* for Dongle EXT_STA support */ ++#define WLC_GET_WLC_BSS_INFO 286 /* for Dongle EXT_STA support */ ++#define WLC_GET_ASSOC_INFO 287 /* for Dongle EXT_STA support */ ++#define WLC_GET_OID_PHY 288 /* for Dongle EXT_STA support */ ++#define WLC_SET_OID_PHY 289 /* for Dongle EXT_STA support */ ++#define WLC_SET_ASSOC_TIME 290 /* for Dongle EXT_STA support */ ++#define WLC_GET_DESIRED_SSID 291 /* for Dongle EXT_STA support */ ++#define WLC_GET_CHANSPEC 292 /* for Dongle EXT_STA support */ ++#define WLC_GET_ASSOC_STATE 293 /* for Dongle EXT_STA support */ ++#define WLC_SET_PHY_STATE 294 /* for Dongle EXT_STA support */ ++#define WLC_GET_SCAN_PENDING 295 /* for Dongle EXT_STA support */ ++#define WLC_GET_SCANREQ_PENDING 296 /* for Dongle EXT_STA support */ ++#define WLC_GET_PREV_ROAM_REASON 297 /* for Dongle EXT_STA support */ ++#define WLC_SET_PREV_ROAM_REASON 298 /* for Dongle EXT_STA support */ ++#define WLC_GET_BANDSTATES_PI 299 /* for Dongle EXT_STA support */ ++#define WLC_GET_PHY_STATE 300 /* for Dongle EXT_STA support */ ++#define WLC_GET_BSS_WPA_RSN 301 /* for Dongle EXT_STA support */ ++#define WLC_GET_BSS_WPA2_RSN 302 /* for Dongle EXT_STA support */ ++#define WLC_GET_BSS_BCN_TS 303 /* for Dongle EXT_STA support */ ++#define WLC_GET_INT_DISASSOC 304 /* for Dongle EXT_STA support */ ++#define WLC_SET_NUM_PEERS 305 /* for Dongle EXT_STA support */ ++#define WLC_GET_NUM_BSS 306 /* for Dongle EXT_STA support */ ++#define WLC_PHY_SAMPLE_COLLECT 307 /* phy sample collect mode */ ++/* #define WLC_UM_PRIV 308 */ /* Deprecated: usermode driver */ ++#define WLC_GET_CMD 309 ++/* #define WLC_LAST 310 */ /* Never used - can be reused */ ++#define WLC_SET_INTERFERENCE_OVERRIDE_MODE 311 /* set inter mode override */ ++#define WLC_GET_INTERFERENCE_OVERRIDE_MODE 312 /* get inter mode override */ ++/* #define WLC_GET_WAI_RESTRICT 313 */ /* for WAPI, deprecated use iovar instead */ ++/* #define WLC_SET_WAI_RESTRICT 314 */ /* for WAPI, deprecated use iovar instead */ ++/* #define WLC_SET_WAI_REKEY 315 */ /* for WAPI, deprecated use iovar instead */ ++#define WLC_SET_NAT_CONFIG 316 /* for configuring NAT filter driver */ ++#define WLC_GET_NAT_STATE 317 ++#define WLC_LAST 318 ++ ++#ifndef EPICTRL_COOKIE ++#define EPICTRL_COOKIE 0xABADCEDE ++#endif ++ ++/* vx wlc ioctl's offset */ ++#define CMN_IOCTL_OFF 0x180 ++ ++/* ++ * custom OID support ++ * ++ * 0xFF - implementation specific OID ++ * 0xE4 - first byte of Broadcom PCI vendor ID ++ * 0x14 - second byte of Broadcom PCI vendor ID ++ * 0xXX - the custom OID number ++ */ ++ ++/* begin 0x1f values beyond the start of the ET driver range. */ ++#define WL_OID_BASE 0xFFE41420 ++ ++/* NDIS overrides */ ++#define OID_WL_GETINSTANCE (WL_OID_BASE + WLC_GET_INSTANCE) ++#define OID_WL_GET_FORCELINK (WL_OID_BASE + WLC_GET_FORCELINK) ++#define OID_WL_SET_FORCELINK (WL_OID_BASE + WLC_SET_FORCELINK) ++#define OID_WL_ENCRYPT_STRENGTH (WL_OID_BASE + WLC_ENCRYPT_STRENGTH) ++#define OID_WL_DECRYPT_STATUS (WL_OID_BASE + WLC_DECRYPT_STATUS) ++#define OID_LEGACY_LINK_BEHAVIOR (WL_OID_BASE + WLC_LEGACY_LINK_BEHAVIOR) ++#define OID_WL_NDCONFIG_ITEM (WL_OID_BASE + WLC_NDCONFIG_ITEM) ++ ++/* EXT_STA Dongle suuport */ ++#define OID_STA_CHANSPEC (WL_OID_BASE + WLC_GET_CHANSPEC) ++#define OID_STA_NBANDS (WL_OID_BASE + WLC_GET_NBANDS) ++#define OID_STA_GET_PHY (WL_OID_BASE + WLC_GET_OID_PHY) ++#define OID_STA_SET_PHY (WL_OID_BASE + WLC_SET_OID_PHY) ++#define OID_STA_ASSOC_TIME (WL_OID_BASE + WLC_SET_ASSOC_TIME) ++#define OID_STA_DESIRED_SSID (WL_OID_BASE + WLC_GET_DESIRED_SSID) ++#define OID_STA_SET_PHY_STATE (WL_OID_BASE + WLC_SET_PHY_STATE) ++#define OID_STA_SCAN_PENDING (WL_OID_BASE + WLC_GET_SCAN_PENDING) ++#define OID_STA_SCANREQ_PENDING (WL_OID_BASE + WLC_GET_SCANREQ_PENDING) ++#define OID_STA_GET_ROAM_REASON (WL_OID_BASE + WLC_GET_PREV_ROAM_REASON) ++#define OID_STA_SET_ROAM_REASON (WL_OID_BASE + WLC_SET_PREV_ROAM_REASON) ++#define OID_STA_GET_PHY_STATE (WL_OID_BASE + WLC_GET_PHY_STATE) ++#define OID_STA_INT_DISASSOC (WL_OID_BASE + WLC_GET_INT_DISASSOC) ++#define OID_STA_SET_NUM_PEERS (WL_OID_BASE + WLC_SET_NUM_PEERS) ++#define OID_STA_GET_NUM_BSS (WL_OID_BASE + WLC_GET_NUM_BSS) ++ ++/* NAT filter driver support */ ++#define OID_NAT_SET_CONFIG (WL_OID_BASE + WLC_SET_NAT_CONFIG) ++#define OID_NAT_GET_STATE (WL_OID_BASE + WLC_GET_NAT_STATE) ++ ++#define WL_DECRYPT_STATUS_SUCCESS 1 ++#define WL_DECRYPT_STATUS_FAILURE 2 ++#define WL_DECRYPT_STATUS_UNKNOWN 3 ++ ++/* allows user-mode app to poll the status of USB image upgrade */ ++#define WLC_UPGRADE_SUCCESS 0 ++#define WLC_UPGRADE_PENDING 1 ++ ++#ifdef CONFIG_USBRNDIS_RETAIL ++/* struct passed in for WLC_NDCONFIG_ITEM */ ++typedef struct { ++ char *name; ++ void *param; ++} ndconfig_item_t; ++#endif ++ ++ ++/* WLC_GET_AUTH, WLC_SET_AUTH values */ ++#define WL_AUTH_OPEN_SYSTEM 0 /* d11 open authentication */ ++#define WL_AUTH_SHARED_KEY 1 /* d11 shared authentication */ ++#ifdef BCM4330_CHIP ++#define WL_AUTH_OPEN_SHARED 2 /* try open, then shared if open failed w/rc 13 */ ++#else ++/* BCM4334(Phoenex branch) value changed to 3 */ ++#define WL_AUTH_OPEN_SHARED 3 /* try open, then shared if open failed w/rc 13 */ ++#endif ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++/* Bit masks for radio disabled status - returned by WL_GET_RADIO */ ++#define WL_RADIO_SW_DISABLE (1<<0) ++#define WL_RADIO_HW_DISABLE (1<<1) ++#define WL_RADIO_MPC_DISABLE (1<<2) ++#define WL_RADIO_COUNTRY_DISABLE (1<<3) /* some countries don't support any channel */ ++ ++#define WL_SPURAVOID_OFF 0 ++#define WL_SPURAVOID_ON1 1 ++#define WL_SPURAVOID_ON2 2 ++ ++/* Override bit for WLC_SET_TXPWR. if set, ignore other level limits */ ++#define WL_TXPWR_OVERRIDE (1U<<31) ++#define WL_TXPWR_NEG (1U<<30) ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++#define WL_PHY_PAVARS_LEN 32 /* Phy type, Band range, chain, a1[0], b0[0], b1[0] ... */ ++ ++#define WL_PHY_PAVAR_VER 1 /* pavars version */ ++ ++typedef struct wl_po { ++ uint16 phy_type; /* Phy type */ ++ uint16 band; ++ uint16 cckpo; ++ uint32 ofdmpo; ++ uint16 mcspo[8]; ++} wl_po_t; ++ ++/* a large TX Power as an init value to factor out of MIN() calculations, ++ * keep low enough to fit in an int8, units are .25 dBm ++ */ ++#define WLC_TXPWR_MAX (127) /* ~32 dBm = 1,500 mW */ ++ ++/* "diag" iovar argument and error code */ ++#define WL_DIAG_INTERRUPT 1 /* d11 loopback interrupt test */ ++#define WL_DIAG_LOOPBACK 2 /* d11 loopback data test */ ++#define WL_DIAG_MEMORY 3 /* d11 memory test */ ++#define WL_DIAG_LED 4 /* LED test */ ++#define WL_DIAG_REG 5 /* d11/phy register test */ ++#define WL_DIAG_SROM 6 /* srom read/crc test */ ++#define WL_DIAG_DMA 7 /* DMA test */ ++#define WL_DIAG_LOOPBACK_EXT 8 /* enhenced d11 loopback data test */ ++ ++#define WL_DIAGERR_SUCCESS 0 ++#define WL_DIAGERR_FAIL_TO_RUN 1 /* unable to run requested diag */ ++#define WL_DIAGERR_NOT_SUPPORTED 2 /* diag requested is not supported */ ++#define WL_DIAGERR_INTERRUPT_FAIL 3 /* loopback interrupt test failed */ ++#define WL_DIAGERR_LOOPBACK_FAIL 4 /* loopback data test failed */ ++#define WL_DIAGERR_SROM_FAIL 5 /* srom read failed */ ++#define WL_DIAGERR_SROM_BADCRC 6 /* srom crc failed */ ++#define WL_DIAGERR_REG_FAIL 7 /* d11/phy register test failed */ ++#define WL_DIAGERR_MEMORY_FAIL 8 /* d11 memory test failed */ ++#define WL_DIAGERR_NOMEM 9 /* diag test failed due to no memory */ ++#define WL_DIAGERR_DMA_FAIL 10 /* DMA test failed */ ++ ++#define WL_DIAGERR_MEMORY_TIMEOUT 11 /* d11 memory test didn't finish in time */ ++#define WL_DIAGERR_MEMORY_BADPATTERN 12 /* d11 memory test result in bad pattern */ ++ ++/* band types */ ++#define WLC_BAND_AUTO 0 /* auto-select */ ++#define WLC_BAND_5G 1 /* 5 Ghz */ ++#define WLC_BAND_2G 2 /* 2.4 Ghz */ ++#define WLC_BAND_ALL 3 /* all bands */ ++ ++/* band range returned by band_range iovar */ ++#define WL_CHAN_FREQ_RANGE_2G 0 ++#define WL_CHAN_FREQ_RANGE_5GL 1 ++#define WL_CHAN_FREQ_RANGE_5GM 2 ++#define WL_CHAN_FREQ_RANGE_5GH 3 ++ ++#define WL_CHAN_FREQ_RANGE_5G_BAND0 1 ++#define WL_CHAN_FREQ_RANGE_5G_BAND1 2 ++#define WL_CHAN_FREQ_RANGE_5G_BAND2 3 ++#define WL_CHAN_FREQ_RANGE_5G_BAND3 4 ++ ++#define WL_CHAN_FREQ_RANGE_5G_4BAND 5 ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++/* phy types (returned by WLC_GET_PHYTPE) */ ++#define WLC_PHY_TYPE_A 0 ++#define WLC_PHY_TYPE_B 1 ++#define WLC_PHY_TYPE_G 2 ++#define WLC_PHY_TYPE_N 4 ++#define WLC_PHY_TYPE_LP 5 ++#define WLC_PHY_TYPE_SSN 6 ++#define WLC_PHY_TYPE_HT 7 ++#define WLC_PHY_TYPE_LCN 8 ++#define WLC_PHY_TYPE_LCN40 10 ++#define WLC_PHY_TYPE_AC 11 ++#define WLC_PHY_TYPE_NULL 0xf ++ ++/* Values for PM */ ++#define PM_OFF 0 ++#define PM_MAX 1 ++#define PM_FAST 2 ++#define PM_FORCE_OFF 3 /* use this bit to force PM off even bt is active */ ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++/* MAC list modes */ ++#define WLC_MACMODE_DISABLED 0 /* MAC list disabled */ ++#define WLC_MACMODE_DENY 1 /* Deny specified (i.e. allow unspecified) */ ++#define WLC_MACMODE_ALLOW 2 /* Allow specified (i.e. deny unspecified) */ ++ ++/* ++ * 54g modes (basic bits may still be overridden) ++ * ++ * GMODE_LEGACY_B Rateset: 1b, 2b, 5.5, 11 ++ * Preamble: Long ++ * Shortslot: Off ++ * GMODE_AUTO Rateset: 1b, 2b, 5.5b, 11b, 18, 24, 36, 54 ++ * Extended Rateset: 6, 9, 12, 48 ++ * Preamble: Long ++ * Shortslot: Auto ++ * GMODE_ONLY Rateset: 1b, 2b, 5.5b, 11b, 18, 24b, 36, 54 ++ * Extended Rateset: 6b, 9, 12b, 48 ++ * Preamble: Short required ++ * Shortslot: Auto ++ * GMODE_B_DEFERRED Rateset: 1b, 2b, 5.5b, 11b, 18, 24, 36, 54 ++ * Extended Rateset: 6, 9, 12, 48 ++ * Preamble: Long ++ * Shortslot: On ++ * GMODE_PERFORMANCE Rateset: 1b, 2b, 5.5b, 6b, 9, 11b, 12b, 18, 24b, 36, 48, 54 ++ * Preamble: Short required ++ * Shortslot: On and required ++ * GMODE_LRS Rateset: 1b, 2b, 5.5b, 11b ++ * Extended Rateset: 6, 9, 12, 18, 24, 36, 48, 54 ++ * Preamble: Long ++ * Shortslot: Auto ++ */ ++#define GMODE_LEGACY_B 0 ++#define GMODE_AUTO 1 ++#define GMODE_ONLY 2 ++#define GMODE_B_DEFERRED 3 ++#define GMODE_PERFORMANCE 4 ++#define GMODE_LRS 5 ++#define GMODE_MAX 6 ++ ++/* values for PLCPHdr_override */ ++#define WLC_PLCP_AUTO -1 ++#define WLC_PLCP_SHORT 0 ++#define WLC_PLCP_LONG 1 ++ ++/* values for g_protection_override and n_protection_override */ ++#define WLC_PROTECTION_AUTO -1 ++#define WLC_PROTECTION_OFF 0 ++#define WLC_PROTECTION_ON 1 ++#define WLC_PROTECTION_MMHDR_ONLY 2 ++#define WLC_PROTECTION_CTS_ONLY 3 ++ ++/* values for g_protection_control and n_protection_control */ ++#define WLC_PROTECTION_CTL_OFF 0 ++#define WLC_PROTECTION_CTL_LOCAL 1 ++#define WLC_PROTECTION_CTL_OVERLAP 2 ++ ++/* values for n_protection */ ++#define WLC_N_PROTECTION_OFF 0 ++#define WLC_N_PROTECTION_OPTIONAL 1 ++#define WLC_N_PROTECTION_20IN40 2 ++#define WLC_N_PROTECTION_MIXEDMODE 3 ++ ++/* values for n_preamble_type */ ++#define WLC_N_PREAMBLE_MIXEDMODE 0 ++#define WLC_N_PREAMBLE_GF 1 ++#define WLC_N_PREAMBLE_GF_BRCM 2 ++ ++/* values for band specific 40MHz capabilities (deprecated) */ ++#define WLC_N_BW_20ALL 0 ++#define WLC_N_BW_40ALL 1 ++#define WLC_N_BW_20IN2G_40IN5G 2 ++ ++#define WLC_BW_20MHZ_BIT (1<<0) ++#define WLC_BW_40MHZ_BIT (1<<1) ++#define WLC_BW_80MHZ_BIT (1<<2) ++ ++/* Bandwidth capabilities */ ++#define WLC_BW_CAP_20MHZ (WLC_BW_20MHZ_BIT) ++#define WLC_BW_CAP_40MHZ (WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT) ++#define WLC_BW_CAP_80MHZ (WLC_BW_80MHZ_BIT|WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT) ++#define WLC_BW_CAP_UNRESTRICTED 0xFF ++ ++#define WL_BW_CAP_20MHZ(bw_cap) (((bw_cap) & WLC_BW_20MHZ_BIT) ? TRUE : FALSE) ++#define WL_BW_CAP_40MHZ(bw_cap) (((bw_cap) & WLC_BW_40MHZ_BIT) ? TRUE : FALSE) ++#define WL_BW_CAP_80MHZ(bw_cap) (((bw_cap) & WLC_BW_80MHZ_BIT) ? TRUE : FALSE) ++ ++/* values to force tx/rx chain */ ++#define WLC_N_TXRX_CHAIN0 0 ++#define WLC_N_TXRX_CHAIN1 1 ++ ++/* bitflags for SGI support (sgi_rx iovar) */ ++#define WLC_N_SGI_20 0x01 ++#define WLC_N_SGI_40 0x02 ++#define WLC_VHT_SGI_80 0x04 ++ ++/* when sgi_tx==WLC_SGI_ALL, bypass rate selection, enable sgi for all mcs */ ++#define WLC_SGI_ALL 0x02 ++ ++#define LISTEN_INTERVAL 10 ++/* interference mitigation options */ ++#define INTERFERE_OVRRIDE_OFF -1 /* interference override off */ ++#define INTERFERE_NONE 0 /* off */ ++#define NON_WLAN 1 /* foreign/non 802.11 interference, no auto detect */ ++#define WLAN_MANUAL 2 /* ACI: no auto detection */ ++#define WLAN_AUTO 3 /* ACI: auto detect */ ++#define WLAN_AUTO_W_NOISE 4 /* ACI: auto - detect and non 802.11 interference */ ++#define AUTO_ACTIVE (1 << 7) /* Auto is currently active */ ++ ++/* AP environment */ ++#define AP_ENV_DETECT_NOT_USED 0 /* We aren't using AP environment detection */ ++#define AP_ENV_DENSE 1 /* "Corporate" or other AP dense environment */ ++#define AP_ENV_SPARSE 2 /* "Home" or other sparse environment */ ++#define AP_ENV_INDETERMINATE 3 /* AP environment hasn't been identified */ ++ ++typedef struct wl_aci_args { ++ int enter_aci_thresh; /* Trigger level to start detecting ACI */ ++ int exit_aci_thresh; /* Trigger level to exit ACI mode */ ++ int usec_spin; /* microsecs to delay between rssi samples */ ++ int glitch_delay; /* interval between ACI scans when glitch count is consistently high */ ++ uint16 nphy_adcpwr_enter_thresh; /* ADC power to enter ACI mitigation mode */ ++ uint16 nphy_adcpwr_exit_thresh; /* ADC power to exit ACI mitigation mode */ ++ uint16 nphy_repeat_ctr; /* Number of tries per channel to compute power */ ++ uint16 nphy_num_samples; /* Number of samples to compute power on one channel */ ++ uint16 nphy_undetect_window_sz; /* num of undetects to exit ACI Mitigation mode */ ++ uint16 nphy_b_energy_lo_aci; /* low ACI power energy threshold for bphy */ ++ uint16 nphy_b_energy_md_aci; /* mid ACI power energy threshold for bphy */ ++ uint16 nphy_b_energy_hi_aci; /* high ACI power energy threshold for bphy */ ++ uint16 nphy_noise_noassoc_glitch_th_up; /* wl interference 4 */ ++ uint16 nphy_noise_noassoc_glitch_th_dn; ++ uint16 nphy_noise_assoc_glitch_th_up; ++ uint16 nphy_noise_assoc_glitch_th_dn; ++ uint16 nphy_noise_assoc_aci_glitch_th_up; ++ uint16 nphy_noise_assoc_aci_glitch_th_dn; ++ uint16 nphy_noise_assoc_enter_th; ++ uint16 nphy_noise_noassoc_enter_th; ++ uint16 nphy_noise_assoc_rx_glitch_badplcp_enter_th; ++ uint16 nphy_noise_noassoc_crsidx_incr; ++ uint16 nphy_noise_assoc_crsidx_incr; ++ uint16 nphy_noise_crsidx_decr; ++} wl_aci_args_t; ++ ++#define TRIGGER_NOW 0 ++#define TRIGGER_CRS 0x01 ++#define TRIGGER_CRSDEASSERT 0x02 ++#define TRIGGER_GOODFCS 0x04 ++#define TRIGGER_BADFCS 0x08 ++#define TRIGGER_BADPLCP 0x10 ++#define TRIGGER_CRSGLITCH 0x20 ++#define WL_ACI_ARGS_LEGACY_LENGTH 16 /* bytes of pre NPHY aci args */ ++#define WL_SAMPLECOLLECT_T_VERSION 2 /* version of wl_samplecollect_args_t struct */ ++typedef struct wl_samplecollect_args { ++ /* version 0 fields */ ++ uint8 coll_us; ++ int cores; ++ /* add'l version 1 fields */ ++ uint16 version; /* see definition of WL_SAMPLECOLLECT_T_VERSION */ ++ uint16 length; /* length of entire structure */ ++ int8 trigger; ++ uint16 timeout; ++ uint16 mode; ++ uint32 pre_dur; ++ uint32 post_dur; ++ uint8 gpio_sel; ++ bool downsamp; ++ bool be_deaf; ++ bool agc; /* loop from init gain and going down */ ++ bool filter; /* override high pass corners to lowest */ ++ /* add'l version 2 fields */ ++ uint8 trigger_state; ++ uint8 module_sel1; ++ uint8 module_sel2; ++ uint16 nsamps; ++} wl_samplecollect_args_t; ++ ++#define WL_SAMPLEDATA_HEADER_TYPE 1 ++#define WL_SAMPLEDATA_HEADER_SIZE 80 /* sample collect header size (bytes) */ ++#define WL_SAMPLEDATA_TYPE 2 ++#define WL_SAMPLEDATA_SEQ 0xff /* sequence # */ ++#define WL_SAMPLEDATA_MORE_DATA 0x100 /* more data mask */ ++#define WL_SAMPLEDATA_T_VERSION 1 /* version of wl_samplecollect_args_t struct */ ++/* version for unpacked sample data, int16 {(I,Q),Core(0..N)} */ ++#define WL_SAMPLEDATA_T_VERSION_SPEC_AN 2 ++ ++typedef struct wl_sampledata { ++ uint16 version; /* structure version */ ++ uint16 size; /* size of structure */ ++ uint16 tag; /* Header/Data */ ++ uint16 length; /* data length */ ++ uint32 flag; /* bit def */ ++} wl_sampledata_t; ++ ++/* wl_radar_args_t */ ++typedef struct { ++ int npulses; /* required number of pulses at n * t_int */ ++ int ncontig; /* required number of pulses at t_int */ ++ int min_pw; /* minimum pulse width (20 MHz clocks) */ ++ int max_pw; /* maximum pulse width (20 MHz clocks) */ ++ uint16 thresh0; /* Radar detection, thresh 0 */ ++ uint16 thresh1; /* Radar detection, thresh 1 */ ++ uint16 blank; /* Radar detection, blank control */ ++ uint16 fmdemodcfg; /* Radar detection, fmdemod config */ ++ int npulses_lp; /* Radar detection, minimum long pulses */ ++ int min_pw_lp; /* Minimum pulsewidth for long pulses */ ++ int max_pw_lp; /* Maximum pulsewidth for long pulses */ ++ int min_fm_lp; /* Minimum fm for long pulses */ ++ int max_span_lp; /* Maximum deltat for long pulses */ ++ int min_deltat; /* Minimum spacing between pulses */ ++ int max_deltat; /* Maximum spacing between pulses */ ++ uint16 autocorr; /* Radar detection, autocorr on or off */ ++ uint16 st_level_time; /* Radar detection, start_timing level */ ++ uint16 t2_min; /* minimum clocks needed to remain in state 2 */ ++ uint32 version; /* version */ ++ uint32 fra_pulse_err; /* sample error margin for detecting French radar pulsed */ ++ int npulses_fra; /* Radar detection, minimum French pulses set */ ++ int npulses_stg2; /* Radar detection, minimum staggered-2 pulses set */ ++ int npulses_stg3; /* Radar detection, minimum staggered-3 pulses set */ ++ uint16 percal_mask; /* defines which period cal is masked from radar detection */ ++ int quant; /* quantization resolution to pulse positions */ ++ uint32 min_burst_intv_lp; /* minimum burst to burst interval for bin3 radar */ ++ uint32 max_burst_intv_lp; /* maximum burst to burst interval for bin3 radar */ ++ int nskip_rst_lp; /* number of skipped pulses before resetting lp buffer */ ++ int max_pw_tol; /* maximum tollerance allowed in detected pulse width for radar detection */ ++ uint16 feature_mask; /* 16-bit mask to specify enabled features */ ++} wl_radar_args_t; ++ ++#define WL_RADAR_ARGS_VERSION 2 ++ ++typedef struct { ++ uint32 version; /* version */ ++ uint16 thresh0_20_lo; /* Radar detection, thresh 0 (range 5250-5350MHz) for BW 20MHz */ ++ uint16 thresh1_20_lo; /* Radar detection, thresh 1 (range 5250-5350MHz) for BW 20MHz */ ++ uint16 thresh0_40_lo; /* Radar detection, thresh 0 (range 5250-5350MHz) for BW 40MHz */ ++ uint16 thresh1_40_lo; /* Radar detection, thresh 1 (range 5250-5350MHz) for BW 40MHz */ ++ uint16 thresh0_80_lo; /* Radar detection, thresh 0 (range 5250-5350MHz) for BW 80MHz */ ++ uint16 thresh1_80_lo; /* Radar detection, thresh 1 (range 5250-5350MHz) for BW 80MHz */ ++ uint16 thresh0_160_lo; /* Radar detection, thresh 0 (range 5250-5350MHz) for BW 160MHz */ ++ uint16 thresh1_160_lo; /* Radar detection, thresh 1 (range 5250-5350MHz) for BW 160MHz */ ++ uint16 thresh0_20_hi; /* Radar detection, thresh 0 (range 5470-5725MHz) for BW 20MHz */ ++ uint16 thresh1_20_hi; /* Radar detection, thresh 1 (range 5470-5725MHz) for BW 20MHz */ ++ uint16 thresh0_40_hi; /* Radar detection, thresh 0 (range 5470-5725MHz) for BW 40MHz */ ++ uint16 thresh1_40_hi; /* Radar detection, thresh 1 (range 5470-5725MHz) for BW 40MHz */ ++ uint16 thresh0_80_hi; /* Radar detection, thresh 0 (range 5470-5725MHz) for BW 80MHz */ ++ uint16 thresh1_80_hi; /* Radar detection, thresh 1 (range 5470-5725MHz) for BW 80MHz */ ++ uint16 thresh0_160_hi; /* Radar detection, thresh 0 (range 5470-5725MHz) for BW 160MHz */ ++ uint16 thresh1_160_hi; /* Radar detection, thresh 1 (range 5470-5725MHz) for BW 160MHz */ ++} wl_radar_thr_t; ++ ++#define WL_RADAR_THR_VERSION 2 ++#define WL_THRESHOLD_LO_BAND 70 /* range from 5250MHz - 5350MHz */ ++ ++/* radar iovar SET defines */ ++#define WL_RADAR_DETECTOR_OFF 0 /* radar detector off */ ++#define WL_RADAR_DETECTOR_ON 1 /* radar detector on */ ++#define WL_RADAR_SIMULATED 2 /* force radar detector to declare ++ * detection once ++ */ ++#define WL_RSSI_ANT_VERSION 1 /* current version of wl_rssi_ant_t */ ++#define WL_ANT_RX_MAX 2 /* max 2 receive antennas */ ++#define WL_ANT_HT_RX_MAX 3 /* max 3 receive antennas/cores */ ++#define WL_ANT_IDX_1 0 /* antenna index 1 */ ++#define WL_ANT_IDX_2 1 /* antenna index 2 */ ++ ++#ifndef WL_RSSI_ANT_MAX ++#define WL_RSSI_ANT_MAX 4 /* max possible rx antennas */ ++#elif WL_RSSI_ANT_MAX != 4 ++#error "WL_RSSI_ANT_MAX does not match" ++#endif ++ ++/* RSSI per antenna */ ++typedef struct { ++ uint32 version; /* version field */ ++ uint32 count; /* number of valid antenna rssi */ ++ int8 rssi_ant[WL_RSSI_ANT_MAX]; /* rssi per antenna */ ++} wl_rssi_ant_t; ++ ++/* dfs_status iovar-related defines */ ++ ++/* cac - channel availability check, ++ * ism - in-service monitoring ++ * csa - channel switching announcement ++ */ ++ ++/* cac state values */ ++#define WL_DFS_CACSTATE_IDLE 0 /* state for operating in non-radar channel */ ++#define WL_DFS_CACSTATE_PREISM_CAC 1 /* CAC in progress */ ++#define WL_DFS_CACSTATE_ISM 2 /* ISM in progress */ ++#define WL_DFS_CACSTATE_CSA 3 /* csa */ ++#define WL_DFS_CACSTATE_POSTISM_CAC 4 /* ISM CAC */ ++#define WL_DFS_CACSTATE_PREISM_OOC 5 /* PREISM OOC */ ++#define WL_DFS_CACSTATE_POSTISM_OOC 6 /* POSTISM OOC */ ++#define WL_DFS_CACSTATES 7 /* this many states exist */ ++ ++/* data structure used in 'dfs_status' wl interface, which is used to query dfs status */ ++typedef struct { ++ uint state; /* noted by WL_DFS_CACSTATE_XX. */ ++ uint duration; /* time spent in ms in state. */ ++ /* as dfs enters ISM state, it removes the operational channel from quiet channel ++ * list and notes the channel in channel_cleared. set to 0 if no channel is cleared ++ */ ++ chanspec_t chanspec_cleared; ++ /* chanspec cleared used to be a uint, add another to uint16 to maintain size */ ++ uint16 pad; ++} wl_dfs_status_t; ++ ++#define NUM_PWRCTRL_RATES 12 ++ ++typedef struct { ++ uint8 txpwr_band_max[NUM_PWRCTRL_RATES]; /* User set target */ ++ uint8 txpwr_limit[NUM_PWRCTRL_RATES]; /* reg and local power limit */ ++ uint8 txpwr_local_max; /* local max according to the AP */ ++ uint8 txpwr_local_constraint; /* local constraint according to the AP */ ++ uint8 txpwr_chan_reg_max; /* Regulatory max for this channel */ ++ uint8 txpwr_target[2][NUM_PWRCTRL_RATES]; /* Latest target for 2.4 and 5 Ghz */ ++ uint8 txpwr_est_Pout[2]; /* Latest estimate for 2.4 and 5 Ghz */ ++ uint8 txpwr_opo[NUM_PWRCTRL_RATES]; /* On G phy, OFDM power offset */ ++ uint8 txpwr_bphy_cck_max[NUM_PWRCTRL_RATES]; /* Max CCK power for this band (SROM) */ ++ uint8 txpwr_bphy_ofdm_max; /* Max OFDM power for this band (SROM) */ ++ uint8 txpwr_aphy_max[NUM_PWRCTRL_RATES]; /* Max power for A band (SROM) */ ++ int8 txpwr_antgain[2]; /* Ant gain for each band - from SROM */ ++ uint8 txpwr_est_Pout_gofdm; /* Pwr estimate for 2.4 OFDM */ ++} tx_power_legacy_t; ++ ++#define WL_TX_POWER_RATES_LEGACY 45 ++#define WL_TX_POWER_MCS20_FIRST 12 ++#define WL_TX_POWER_MCS20_NUM 16 ++#define WL_TX_POWER_MCS40_FIRST 28 ++#define WL_TX_POWER_MCS40_NUM 17 ++ ++typedef struct { ++ uint32 flags; ++ chanspec_t chanspec; /* txpwr report for this channel */ ++ chanspec_t local_chanspec; /* channel on which we are associated */ ++ uint8 local_max; /* local max according to the AP */ ++ uint8 local_constraint; /* local constraint according to the AP */ ++ int8 antgain[2]; /* Ant gain for each band - from SROM */ ++ uint8 rf_cores; /* count of RF Cores being reported */ ++ uint8 est_Pout[4]; /* Latest tx power out estimate per RF ++ * chain without adjustment ++ */ ++ uint8 est_Pout_cck; /* Latest CCK tx power out estimate */ ++ uint8 user_limit[WL_TX_POWER_RATES_LEGACY]; /* User limit */ ++ uint8 reg_limit[WL_TX_POWER_RATES_LEGACY]; /* Regulatory power limit */ ++ uint8 board_limit[WL_TX_POWER_RATES_LEGACY]; /* Max power board can support (SROM) */ ++ uint8 target[WL_TX_POWER_RATES_LEGACY]; /* Latest target power */ ++} tx_power_legacy2_t; ++ ++/* TX Power index defines */ ++#define WL_NUM_RATES_CCK 4 /* 1, 2, 5.5, 11 Mbps */ ++#define WL_NUM_RATES_OFDM 8 /* 6, 9, 12, 18, 24, 36, 48, 54 Mbps SISO/CDD */ ++#define WL_NUM_RATES_MCS_1STREAM 8 /* MCS 0-7 1-stream rates - SISO/CDD/STBC/MCS */ ++#define WL_NUM_RATES_EXTRA_VHT 2 /* Additional VHT 11AC rates */ ++#define WL_NUM_RATES_VHT 10 ++#define WL_NUM_RATES_MCS32 1 ++ ++#define WLC_NUM_RATES_CCK WL_NUM_RATES_CCK ++#define WLC_NUM_RATES_OFDM WL_NUM_RATES_OFDM ++#define WLC_NUM_RATES_MCS_1_STREAM WL_NUM_RATES_MCS_1STREAM ++#define WLC_NUM_RATES_MCS_2_STREAM WL_NUM_RATES_MCS_1STREAM ++#define WLC_NUM_RATES_MCS32 WL_NUM_RATES_MCS32 ++#define WL_TX_POWER_CCK_NUM WL_NUM_RATES_CCK ++#define WL_TX_POWER_OFDM_NUM WL_NUM_RATES_OFDM ++#define WL_TX_POWER_MCS_1_STREAM_NUM WL_NUM_RATES_MCS_1STREAM ++#define WL_TX_POWER_MCS_2_STREAM_NUM WL_NUM_RATES_MCS_1STREAM ++#define WL_TX_POWER_MCS_32_NUM WL_NUM_RATES_MCS32 ++ ++#define WL_NUM_2x2_ELEMENTS 4 ++#define WL_NUM_3x3_ELEMENTS 6 ++ ++typedef struct txppr { ++ /* start of 20MHz tx power limits */ ++ uint8 b20_1x1dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b20_1x1ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM transmission */ ++ uint8 b20_1x1mcs0[WL_NUM_RATES_MCS_1STREAM]; /* SISO MCS 0-7 */ ++ ++ uint8 b20_1x2dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b20_1x2cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ ++ uint8 b20_1x2cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* CDD MCS 0-7 */ ++ uint8 b20_2x2stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ ++ uint8 b20_2x2sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* MCS 8-15 */ ++ ++ uint8 b20_1x3dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b20_1x3cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ ++ uint8 b20_1x3cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* 1 Nsts to 3 Tx Chain */ ++ uint8 b20_2x3stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ ++ uint8 b20_2x3sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* 2 Nsts to 3 Tx Chain */ ++ uint8 b20_3x3sdm_mcs16[WL_NUM_RATES_MCS_1STREAM]; /* 3 Nsts to 3 Tx Chain */ ++ ++ uint8 b20_1x1vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1 */ ++ uint8 b20_1x2cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD1 */ ++ uint8 b20_2x2stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC */ ++ uint8 b20_2x2sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2 */ ++ uint8 b20_1x3cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD2 */ ++ uint8 b20_2x3stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC_SPEXP1 */ ++ uint8 b20_2x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2_SPEXP1 */ ++ uint8 b20_3x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS3 */ ++ ++ /* start of 40MHz tx power limits */ ++ uint8 b40_dummy1x1dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b40_1x1ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM transmission */ ++ uint8 b40_1x1mcs0[WL_NUM_RATES_MCS_1STREAM]; /* SISO MCS 0-7 */ ++ ++ uint8 b40_dummy1x2dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b40_1x2cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ ++ uint8 b40_1x2cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* CDD MCS 0-7 */ ++ uint8 b40_2x2stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ ++ uint8 b40_2x2sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* MCS 8-15 */ ++ ++ uint8 b40_dummy1x3dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b40_1x3cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ ++ uint8 b40_1x3cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* 1 Nsts to 3 Tx Chain */ ++ uint8 b40_2x3stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ ++ uint8 b40_2x3sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* 2 Nsts to 3 Tx Chain */ ++ uint8 b40_3x3sdm_mcs16[WL_NUM_RATES_MCS_1STREAM]; /* 3 Nsts to 3 Tx Chain */ ++ ++ uint8 b40_1x1vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1 */ ++ uint8 b40_1x2cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD1 */ ++ uint8 b40_2x2stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC */ ++ uint8 b40_2x2sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2 */ ++ uint8 b40_1x3cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD2 */ ++ uint8 b40_2x3stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC_SPEXP1 */ ++ uint8 b40_2x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2_SPEXP1 */ ++ uint8 b40_3x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS3 */ ++ ++ /* start of 20in40MHz tx power limits */ ++ uint8 b20in40_1x1dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b20in40_1x1ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM transmission */ ++ uint8 b20in40_1x1mcs0[WL_NUM_RATES_MCS_1STREAM]; /* SISO MCS 0-7 */ ++ ++ uint8 b20in40_1x2dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b20in40_1x2cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ ++ uint8 b20in40_1x2cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* CDD MCS 0-7 */ ++ uint8 b20in40_2x2stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ ++ uint8 b20in40_2x2sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* MCS 8-15 */ ++ ++ uint8 b20in40_1x3dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b20in40_1x3cdd_ofdm[WL_NUM_RATES_OFDM]; /* 20 in 40 MHz Legacy OFDM CDD */ ++ uint8 b20in40_1x3cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* 1 Nsts to 3 Tx Chain */ ++ uint8 b20in40_2x3stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ ++ uint8 b20in40_2x3sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* 2 Nsts to 3 Tx Chain */ ++ uint8 b20in40_3x3sdm_mcs16[WL_NUM_RATES_MCS_1STREAM]; /* 3 Nsts to 3 Tx Chain */ ++ ++ uint8 b20in40_1x1vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1 */ ++ uint8 b20in40_1x2cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD1 */ ++ uint8 b20in40_2x2stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC */ ++ uint8 b20in40_2x2sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2 */ ++ uint8 b20in40_1x3cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD2 */ ++ uint8 b20in40_2x3stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC_SPEXP1 */ ++ uint8 b20in40_2x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2_SPEXP1 */ ++ uint8 b20in40_3x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS3 */ ++ ++ /* start of 80MHz tx power limits */ ++ uint8 b80_dummy1x1dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b80_1x1ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM transmission */ ++ uint8 b80_1x1mcs0[WL_NUM_RATES_MCS_1STREAM]; /* SISO MCS 0-7 */ ++ ++ uint8 b80_dummy1x2dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b80_1x2cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ ++ uint8 b80_1x2cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* CDD MCS 0-7 */ ++ uint8 b80_2x2stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ ++ uint8 b80_2x2sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* MCS 8-15 */ ++ ++ uint8 b80_dummy1x3dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b80_1x3cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ ++ uint8 b80_1x3cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* 1 Nsts to 3 Tx Chain */ ++ uint8 b80_2x3stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ ++ uint8 b80_2x3sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* 2 Nsts to 3 Tx Chain */ ++ uint8 b80_3x3sdm_mcs16[WL_NUM_RATES_MCS_1STREAM]; /* 3 Nsts to 3 Tx Chain */ ++ ++ uint8 b80_1x1vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1 */ ++ uint8 b80_1x2cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD1 */ ++ uint8 b80_2x2stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC */ ++ uint8 b80_2x2sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2 */ ++ uint8 b80_1x3cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD2 */ ++ uint8 b80_2x3stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC_SPEXP1 */ ++ uint8 b80_2x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2_SPEXP1 */ ++ uint8 b80_3x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS3 */ ++ ++ /* start of 20in80MHz tx power limits */ ++ uint8 b20in80_1x1dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b20in80_1x1ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM transmission */ ++ uint8 b20in80_1x1mcs0[WL_NUM_RATES_MCS_1STREAM]; /* SISO MCS 0-7 */ ++ ++ uint8 b20in80_1x2dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b20in80_1x2cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ ++ uint8 b20in80_1x2cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* CDD MCS 0-7 */ ++ uint8 b20in80_2x2stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ ++ uint8 b20in80_2x2sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* MCS 8-15 */ ++ ++ uint8 b20in80_1x3dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b20in80_1x3cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ ++ uint8 b20in80_1x3cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* 1 Nsts to 3 Tx Chain */ ++ uint8 b20in80_2x3stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ ++ uint8 b20in80_2x3sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* 2 Nsts to 3 Tx Chain */ ++ uint8 b20in80_3x3sdm_mcs16[WL_NUM_RATES_MCS_1STREAM]; /* 3 Nsts to 3 Tx Chain */ ++ ++ uint8 b20in80_1x1vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1 */ ++ uint8 b20in80_1x2cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD1 */ ++ uint8 b20in80_2x2stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC */ ++ uint8 b20in80_2x2sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2 */ ++ uint8 b20in80_1x3cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD2 */ ++ uint8 b20in80_2x3stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC_SPEXP1 */ ++ uint8 b20in80_2x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2_SPEXP1 */ ++ uint8 b20in80_3x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS3 */ ++ ++ /* start of 40in80MHz tx power limits */ ++ uint8 b40in80_dummy1x1dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b40in80_1x1ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM transmission */ ++ uint8 b40in80_1x1mcs0[WL_NUM_RATES_MCS_1STREAM]; /* SISO MCS 0-7 */ ++ ++ uint8 b40in80_dummy1x2dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b40in80_1x2cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ ++ uint8 b40in80_1x2cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* CDD MCS 0-7 */ ++ uint8 b40in80_2x2stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ ++ uint8 b40in80_2x2sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* MCS 8-15 */ ++ ++ uint8 b40in80_dummy1x3dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b40in80_1x3cdd_ofdm[WL_NUM_RATES_OFDM]; /* MHz Legacy OFDM CDD */ ++ uint8 b40in80_1x3cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* 1 Nsts to 3 Tx Chain */ ++ uint8 b40in80_2x3stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ ++ uint8 b40in80_2x3sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* 2 Nsts to 3 Tx Chain */ ++ uint8 b40in80_3x3sdm_mcs16[WL_NUM_RATES_MCS_1STREAM]; /* 3 Nsts to 3 Tx Chain */ ++ ++ uint8 b40in80_1x1vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1 */ ++ uint8 b40in80_1x2cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD1 */ ++ uint8 b40in80_2x2stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC */ ++ uint8 b40in80_2x2sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2 */ ++ uint8 b40in80_1x3cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD2 */ ++ uint8 b40in80_2x3stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC_SPEXP1 */ ++ uint8 b40in80_2x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2_SPEXP1 */ ++ uint8 b40in80_3x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS3 */ ++ ++ uint8 mcs32; /* C_CHECK - THIS NEEDS TO BE REMOVED THROUGHOUT THE CODE */ ++} txppr_t; ++ ++/* 20MHz */ ++#define WL_TX_POWER_CCK_FIRST OFFSETOF(txppr_t, b20_1x1dsss) ++#define WL_TX_POWER_OFDM20_FIRST OFFSETOF(txppr_t, b20_1x1ofdm) ++#define WL_TX_POWER_MCS20_SISO_FIRST OFFSETOF(txppr_t, b20_1x1mcs0) ++#define WL_TX_POWER_20_S1x1_FIRST OFFSETOF(txppr_t, b20_1x1mcs0) ++ ++#define WL_TX_POWER_CCK_CDD_S1x2_FIRST OFFSETOF(txppr_t, b20_1x2dsss) ++#define WL_TX_POWER_OFDM20_CDD_FIRST OFFSETOF(txppr_t, b20_1x2cdd_ofdm) ++#define WL_TX_POWER_MCS20_CDD_FIRST OFFSETOF(txppr_t, b20_1x2cdd_mcs0) ++#define WL_TX_POWER_20_S1x2_FIRST OFFSETOF(txppr_t, b20_1x2cdd_mcs0) ++#define WL_TX_POWER_MCS20_STBC_FIRST OFFSETOF(txppr_t, b20_2x2stbc_mcs0) ++#define WL_TX_POWER_MCS20_SDM_FIRST OFFSETOF(txppr_t, b20_2x2sdm_mcs8) ++#define WL_TX_POWER_20_S2x2_FIRST OFFSETOF(txppr_t, b20_2x2sdm_mcs8) ++ ++#define WL_TX_POWER_CCK_CDD_S1x3_FIRST OFFSETOF(txppr_t, b20_1x3dsss) ++#define WL_TX_POWER_OFDM20_CDD_S1x3_FIRST OFFSETOF(txppr_t, b20_1x3cdd_ofdm) ++#define WL_TX_POWER_20_S1x3_FIRST OFFSETOF(txppr_t, b20_1x3cdd_mcs0) ++#define WL_TX_POWER_20_STBC_S2x3_FIRST OFFSETOF(txppr_t, b20_2x3stbc_mcs0) ++#define WL_TX_POWER_20_S2x3_FIRST OFFSETOF(txppr_t, b20_2x3sdm_mcs8) ++#define WL_TX_POWER_20_S3x3_FIRST OFFSETOF(txppr_t, b20_3x3sdm_mcs16) ++ ++#define WL_TX_POWER_20_S1X1_VHT OFFSETOF(txppr_t, b20_1x1vht) ++#define WL_TX_POWER_20_S1X2_CDD_VHT OFFSETOF(txppr_t, b20_1x2cdd_vht) ++#define WL_TX_POWER_20_S2X2_STBC_VHT OFFSETOF(txppr_t, b20_2x2stbc_vht) ++#define WL_TX_POWER_20_S2X2_VHT OFFSETOF(txppr_t, b20_2x2sdm_vht) ++#define WL_TX_POWER_20_S1X3_CDD_VHT OFFSETOF(txppr_t, b20_1x3cdd_vht) ++#define WL_TX_POWER_20_S2X3_STBC_VHT OFFSETOF(txppr_t, b20_2x3stbc_vht) ++#define WL_TX_POWER_20_S2X3_VHT OFFSETOF(txppr_t, b20_2x3sdm_vht) ++#define WL_TX_POWER_20_S3X3_VHT OFFSETOF(txppr_t, b20_3x3sdm_vht) ++ ++/* 40MHz */ ++#define WL_TX_POWER_40_DUMMY_CCK_FIRST OFFSETOF(txppr_t, b40_dummy1x1dsss) ++#define WL_TX_POWER_OFDM40_FIRST OFFSETOF(txppr_t, b40_1x1ofdm) ++#define WL_TX_POWER_MCS40_SISO_FIRST OFFSETOF(txppr_t, b40_1x1mcs0) ++#define WL_TX_POWER_40_S1x1_FIRST OFFSETOF(txppr_t, b40_1x1mcs0) ++ ++#define WL_TX_POWER_40_DUMMY_CCK_CDD_S1x2_FIRST OFFSETOF(txppr_t, b40_dummy1x2dsss) ++#define WL_TX_POWER_OFDM40_CDD_FIRST OFFSETOF(txppr_t, b40_1x2cdd_ofdm) ++#define WL_TX_POWER_MCS40_CDD_FIRST OFFSETOF(txppr_t, b40_1x2cdd_mcs0) ++#define WL_TX_POWER_40_S1x2_FIRST OFFSETOF(txppr_t, b40_1x2cdd_mcs0) ++#define WL_TX_POWER_MCS40_STBC_FIRST OFFSETOF(txppr_t, b40_2x2stbc_mcs0) ++#define WL_TX_POWER_MCS40_SDM_FIRST OFFSETOF(txppr_t, b40_2x2sdm_mcs8) ++#define WL_TX_POWER_40_S2x2_FIRST OFFSETOF(txppr_t, b40_2x2sdm_mcs8) ++ ++#define WL_TX_POWER_40_DUMMY_CCK_CDD_S1x3_FIRST OFFSETOF(txppr_t, b40_dummy1x3dsss) ++#define WL_TX_POWER_OFDM40_CDD_S1x3_FIRST OFFSETOF(txppr_t, b40_1x3cdd_ofdm) ++#define WL_TX_POWER_40_S1x3_FIRST OFFSETOF(txppr_t, b40_1x3cdd_mcs0) ++#define WL_TX_POWER_40_STBC_S2x3_FIRST OFFSETOF(txppr_t, b40_2x3stbc_mcs0) ++#define WL_TX_POWER_40_S2x3_FIRST OFFSETOF(txppr_t, b40_2x3sdm_mcs8) ++#define WL_TX_POWER_40_S3x3_FIRST OFFSETOF(txppr_t, b40_3x3sdm_mcs16) ++ ++#define WL_TX_POWER_40_S1X1_VHT OFFSETOF(txppr_t, b40_1x1vht) ++#define WL_TX_POWER_40_S1X2_CDD_VHT OFFSETOF(txppr_t, b40_1x2cdd_vht) ++#define WL_TX_POWER_40_S2X2_STBC_VHT OFFSETOF(txppr_t, b40_2x2stbc_vht) ++#define WL_TX_POWER_40_S2X2_VHT OFFSETOF(txppr_t, b40_2x2sdm_vht) ++#define WL_TX_POWER_40_S1X3_CDD_VHT OFFSETOF(txppr_t, b40_1x3cdd_vht) ++#define WL_TX_POWER_40_S2X3_STBC_VHT OFFSETOF(txppr_t, b40_2x3stbc_vht) ++#define WL_TX_POWER_40_S2X3_VHT OFFSETOF(txppr_t, b40_2x3sdm_vht) ++#define WL_TX_POWER_40_S3X3_VHT OFFSETOF(txppr_t, b40_3x3sdm_vht) ++ ++/* 20 in 40MHz */ ++#define WL_TX_POWER_20UL_CCK_FIRST OFFSETOF(txppr_t, b20in40_1x1dsss) ++#define WL_TX_POWER_20UL_OFDM_FIRST OFFSETOF(txppr_t, b20in40_1x1ofdm) ++#define WL_TX_POWER_20UL_S1x1_FIRST OFFSETOF(txppr_t, b20in40_1x1mcs0) ++ ++#define WL_TX_POWER_CCK_20U_CDD_S1x2_FIRST OFFSETOF(txppr_t, b20in40_1x2dsss) ++#define WL_TX_POWER_20UL_OFDM_CDD_FIRST OFFSETOF(txppr_t, b20in40_1x2cdd_ofdm) ++#define WL_TX_POWER_20UL_S1x2_FIRST OFFSETOF(txppr_t, b20in40_1x2cdd_mcs0) ++#define WL_TX_POWER_20UL_STBC_S2x2_FIRST OFFSETOF(txppr_t, b20in40_2x2stbc_mcs0) ++#define WL_TX_POWER_20UL_S2x2_FIRST OFFSETOF(txppr_t, b20in40_2x2sdm_mcs8) ++ ++#define WL_TX_POWER_CCK_20U_CDD_S1x3_FIRST OFFSETOF(txppr_t, b20in40_1x3dsss) ++#define WL_TX_POWER_20UL_OFDM_CDD_S1x3_FIRST OFFSETOF(txppr_t, b20in40_1x3cdd_ofdm) ++#define WL_TX_POWER_20UL_S1x3_FIRST OFFSETOF(txppr_t, b20in40_1x3cdd_mcs0) ++#define WL_TX_POWER_20UL_STBC_S2x3_FIRST OFFSETOF(txppr_t, b20in40_2x3stbc_mcs0) ++#define WL_TX_POWER_20UL_S2x3_FIRST OFFSETOF(txppr_t, b20in40_2x3sdm_mcs8) ++#define WL_TX_POWER_20UL_S3x3_FIRST OFFSETOF(txppr_t, b20in40_3x3sdm_mcs16) ++ ++#define WL_TX_POWER_20UL_S1X1_VHT OFFSETOF(txppr_t, b20in40_1x1vht) ++#define WL_TX_POWER_20UL_S1X2_CDD_VHT OFFSETOF(txppr_t, b20in40_1x2cdd_vht) ++#define WL_TX_POWER_20UL_S2X2_STBC_VHT OFFSETOF(txppr_t, b20in40_2x2stbc_vht) ++#define WL_TX_POWER_20UL_S2X2_VHT OFFSETOF(txppr_t, b20in40_2x2sdm_vht) ++#define WL_TX_POWER_20UL_S1X3_CDD_VHT OFFSETOF(txppr_t, b20in40_1x3cdd_vht) ++#define WL_TX_POWER_20UL_S2X3_STBC_VHT OFFSETOF(txppr_t, b20in40_2x3stbc_vht) ++#define WL_TX_POWER_20UL_S2X3_VHT OFFSETOF(txppr_t, b20in40_2x3sdm_vht) ++#define WL_TX_POWER_20UL_S3X3_VHT OFFSETOF(txppr_t, b20in40_3x3sdm_vht) ++ ++/* 80MHz */ ++#define WL_TX_POWER_80_DUMMY_CCK_FIRST OFFSETOF(txppr_t, b80_dummy1x1dsss) ++#define WL_TX_POWER_OFDM80_FIRST OFFSETOF(txppr_t, b80_1x1ofdm) ++#define WL_TX_POWER_MCS80_SISO_FIRST OFFSETOF(txppr_t, b80_1x1mcs0) ++#define WL_TX_POWER_80_S1x1_FIRST OFFSETOF(txppr_t, b80_1x1mcs0) ++ ++#define WL_TX_POWER_80_DUMMY_CCK_CDD_S1x2_FIRST OFFSETOF(txppr_t, b80_dummy1x2dsss) ++#define WL_TX_POWER_OFDM80_CDD_FIRST OFFSETOF(txppr_t, b80_1x2cdd_ofdm) ++#define WL_TX_POWER_MCS80_CDD_FIRST OFFSETOF(txppr_t, b80_1x2cdd_mcs0) ++#define WL_TX_POWER_80_S1x2_FIRST OFFSETOF(txppr_t, b80_1x2cdd_mcs0) ++#define WL_TX_POWER_MCS80_STBC_FIRST OFFSETOF(txppr_t, b80_2x2stbc_mcs0) ++#define WL_TX_POWER_MCS80_SDM_FIRST OFFSETOF(txppr_t, b80_2x2sdm_mcs8) ++#define WL_TX_POWER_80_S2x2_FIRST OFFSETOF(txppr_t, b80_2x2sdm_mcs8) ++ ++#define WL_TX_POWER_80_DUMMY_CCK_CDD_S1x3_FIRST OFFSETOF(txppr_t, b80_dummy1x3dsss) ++#define WL_TX_POWER_OFDM80_CDD_S1x3_FIRST OFFSETOF(txppr_t, b80_1x3cdd_ofdm) ++#define WL_TX_POWER_80_S1x3_FIRST OFFSETOF(txppr_t, b80_1x3cdd_mcs0) ++#define WL_TX_POWER_80_STBC_S2x3_FIRST OFFSETOF(txppr_t, b80_2x3stbc_mcs0) ++#define WL_TX_POWER_80_S2x3_FIRST OFFSETOF(txppr_t, b80_2x3sdm_mcs8) ++#define WL_TX_POWER_80_S3x3_FIRST OFFSETOF(txppr_t, b80_3x3sdm_mcs16) ++ ++#define WL_TX_POWER_80_S1X1_VHT OFFSETOF(txppr_t, b80_1x1vht) ++#define WL_TX_POWER_80_S1X2_CDD_VHT OFFSETOF(txppr_t, b80_1x2cdd_vht) ++#define WL_TX_POWER_80_S2X2_STBC_VHT OFFSETOF(txppr_t, b80_2x2stbc_vht) ++#define WL_TX_POWER_80_S2X2_VHT OFFSETOF(txppr_t, b80_2x2sdm_vht) ++#define WL_TX_POWER_80_S1X3_CDD_VHT OFFSETOF(txppr_t, b80_1x3cdd_vht) ++#define WL_TX_POWER_80_S2X3_STBC_VHT OFFSETOF(txppr_t, b80_2x3stbc_vht) ++#define WL_TX_POWER_80_S2X3_VHT OFFSETOF(txppr_t, b80_2x3sdm_vht) ++#define WL_TX_POWER_80_S3X3_VHT OFFSETOF(txppr_t, b80_3x3sdm_vht) ++ ++/* 20 in 80MHz */ ++#define WL_TX_POWER_20UUL_CCK_FIRST OFFSETOF(txppr_t, b20in80_1x1dsss) ++#define WL_TX_POWER_20UUL_OFDM_FIRST OFFSETOF(txppr_t, b20in80_1x1ofdm) ++#define WL_TX_POWER_20UUL_S1x1_FIRST OFFSETOF(txppr_t, b20in80_1x1mcs0) ++ ++#define WL_TX_POWER_CCK_20UU_CDD_S1x2_FIRST OFFSETOF(txppr_t, b20in80_1x2dsss) ++#define WL_TX_POWER_20UUL_OFDM_CDD_FIRST OFFSETOF(txppr_t, b20in80_1x2cdd_ofdm) ++#define WL_TX_POWER_20UUL_S1x2_FIRST OFFSETOF(txppr_t, b20in80_1x2cdd_mcs0) ++#define WL_TX_POWER_20UUL_STBC_S2x2_FIRST OFFSETOF(txppr_t, b20in80_2x2stbc_mcs0) ++#define WL_TX_POWER_20UUL_S2x2_FIRST OFFSETOF(txppr_t, b20in80_2x2sdm_mcs8) ++ ++#define WL_TX_POWER_CCK_20UU_CDD_S1x3_FIRST OFFSETOF(txppr_t, b20in80_1x3dsss) ++#define WL_TX_POWER_20UUL_OFDM_CDD_S1x3_FIRST OFFSETOF(txppr_t, b20in80_1x3cdd_ofdm) ++#define WL_TX_POWER_20UUL_S1x3_FIRST OFFSETOF(txppr_t, b20in80_1x3cdd_mcs0) ++#define WL_TX_POWER_20UUL_STBC_S2x3_FIRST OFFSETOF(txppr_t, b20in80_2x3stbc_mcs0) ++#define WL_TX_POWER_20UUL_S2x3_FIRST OFFSETOF(txppr_t, b20in80_2x3sdm_mcs8) ++#define WL_TX_POWER_20UUL_S3x3_FIRST OFFSETOF(txppr_t, b20in80_3x3sdm_mcs16) ++ ++#define WL_TX_POWER_20UUL_S1X1_VHT OFFSETOF(txppr_t, b20in80_1x1vht) ++#define WL_TX_POWER_20UUL_S1X2_CDD_VHT OFFSETOF(txppr_t, b20in80_1x2cdd_vht) ++#define WL_TX_POWER_20UUL_S2X2_STBC_VHT OFFSETOF(txppr_t, b20in80_2x2stbc_vht) ++#define WL_TX_POWER_20UUL_S2X2_VHT OFFSETOF(txppr_t, b20in80_2x2sdm_vht) ++#define WL_TX_POWER_20UUL_S1X3_CDD_VHT OFFSETOF(txppr_t, b20in80_1x3cdd_vht) ++#define WL_TX_POWER_20UUL_S2X3_STBC_VHT OFFSETOF(txppr_t, b20in80_2x3stbc_vht) ++#define WL_TX_POWER_20UUL_S2X3_VHT OFFSETOF(txppr_t, b20in80_2x3sdm_vht) ++#define WL_TX_POWER_20UUL_S3X3_VHT OFFSETOF(txppr_t, b20in80_3x3sdm_vht) ++ ++/* 40 in 80MHz */ ++#define WL_TX_POWER_40UUL_DUMMY_CCK_FIRST OFFSETOF(txppr_t, b40in80_dummy1x1dsss) ++#define WL_TX_POWER_40UUL_OFDM_FIRST OFFSETOF(txppr_t, b40in80_1x1ofdm) ++#define WL_TX_POWER_40UUL_S1x1_FIRST OFFSETOF(txppr_t, b40in80_1x1mcs0) ++ ++#define WL_TX_POWER_CCK_40UU_DUMMY_CDD_S1x2_FIRST OFFSETOF(txppr_t, b40in80_dummy1x2dsss) ++#define WL_TX_POWER_40UUL_OFDM_CDD_FIRST OFFSETOF(txppr_t, b40in80_1x2cdd_ofdm) ++#define WL_TX_POWER_40UUL_S1x2_FIRST OFFSETOF(txppr_t, b40in80_1x2cdd_mcs0) ++#define WL_TX_POWER_40UUL_STBC_S2x2_FIRST OFFSETOF(txppr_t, b40in80_2x2stbc_mcs0) ++#define WL_TX_POWER_40UUL_S2x2_FIRST OFFSETOF(txppr_t, b40in80_2x2sdm_mcs8) ++ ++#define WL_TX_POWER_CCK_40UU_DUMMY_CDD_S1x3_FIRST OFFSETOF(txppr_t, b40in80_dummy1x3dsss) ++#define WL_TX_POWER_40UUL_OFDM_CDD_S1x3_FIRST OFFSETOF(txppr_t, b40in80_1x3cdd_ofdm) ++#define WL_TX_POWER_40UUL_S1x3_FIRST OFFSETOF(txppr_t, b40in80_1x3cdd_mcs0) ++#define WL_TX_POWER_40UUL_STBC_S2x3_FIRST OFFSETOF(txppr_t, b40in80_2x3stbc_mcs0) ++#define WL_TX_POWER_40UUL_S2x3_FIRST OFFSETOF(txppr_t, b40in80_2x3sdm_mcs8) ++#define WL_TX_POWER_40UUL_S3x3_FIRST OFFSETOF(txppr_t, b40in80_3x3sdm_mcs16) ++ ++#define WL_TX_POWER_40UUL_S1X1_VHT OFFSETOF(txppr_t, b40in80_1x1vht) ++#define WL_TX_POWER_40UUL_S1X2_CDD_VHT OFFSETOF(txppr_t, b40in80_1x2cdd_vht) ++#define WL_TX_POWER_40UUL_S2X2_STBC_VHT OFFSETOF(txppr_t, b40in80_2x2stbc_vht) ++#define WL_TX_POWER_40UUL_S2X2_VHT OFFSETOF(txppr_t, b40in80_2x2sdm_vht) ++#define WL_TX_POWER_40UUL_S1X3_CDD_VHT OFFSETOF(txppr_t, b40in80_1x3cdd_vht) ++#define WL_TX_POWER_40UUL_S2X3_STBC_VHT OFFSETOF(txppr_t, b40in80_2x3stbc_vht) ++#define WL_TX_POWER_40UUL_S2X3_VHT OFFSETOF(txppr_t, b40in80_2x3sdm_vht) ++#define WL_TX_POWER_40UUL_S3X3_VHT OFFSETOF(txppr_t, b40in80_3x3sdm_vht) ++ ++#define WL_TX_POWER_MCS_32 OFFSETOF(txppr_t, mcs32) /* C_CHECK remove later */ ++ ++#define WL_TX_POWER_RATES sizeof(struct txppr) ++ ++/* sslpnphy specifics */ ++#define WL_TX_POWER_MCS20_SISO_FIRST_SSN WL_TX_POWER_MCS20_SISO_FIRST ++#define WL_TX_POWER_MCS40_SISO_FIRST_SSN WL_TX_POWER_MCS40_SISO_FIRST ++ ++/* tx_power_t.flags bits */ ++#define WL_TX_POWER_F_ENABLED 1 ++#define WL_TX_POWER_F_HW 2 ++#define WL_TX_POWER_F_MIMO 4 ++#define WL_TX_POWER_F_SISO 8 ++#define WL_TX_POWER_F_HT 0x10 ++ ++typedef struct { ++ uint16 ver; /* version of this struct */ ++ uint16 len; /* length in bytes of this structure */ ++ uint32 flags; ++ chanspec_t chanspec; /* txpwr report for this channel */ ++ chanspec_t local_chanspec; /* channel on which we are associated */ ++ uint8 ppr[WL_TX_POWER_RATES]; /* Latest target power */ ++} wl_txppr_t; ++ ++#define WL_TXPPR_VERSION 0 ++#define WL_TXPPR_LENGTH (sizeof(wl_txppr_t)) ++#define TX_POWER_T_VERSION 43 ++ ++/* Defines used with channel_bandwidth for curpower */ ++#define WL_BW_20MHZ 0 ++#define WL_BW_40MHZ 1 ++#define WL_BW_80MHZ 2 ++ ++/* tx_power_t.flags bits */ ++#ifdef PPR_API ++#define WL_TX_POWER2_F_ENABLED 1 ++#define WL_TX_POWER2_F_HW 2 ++#define WL_TX_POWER2_F_MIMO 4 ++#define WL_TX_POWER2_F_SISO 8 ++#define WL_TX_POWER2_F_HT 0x10 ++#else ++#define WL_TX_POWER_F_ENABLED 1 ++#define WL_TX_POWER_F_HW 2 ++#define WL_TX_POWER_F_MIMO 4 ++#define WL_TX_POWER_F_SISO 8 ++#define WL_TX_POWER_F_HT 0x10 ++#endif ++typedef struct { ++ uint32 flags; ++ chanspec_t chanspec; /* txpwr report for this channel */ ++ chanspec_t local_chanspec; /* channel on which we are associated */ ++ uint8 local_max; /* local max according to the AP */ ++ uint8 local_constraint; /* local constraint according to the AP */ ++ int8 antgain[2]; /* Ant gain for each band - from SROM */ ++ uint8 rf_cores; /* count of RF Cores being reported */ ++ uint8 est_Pout[4]; /* Latest tx power out estimate per RF chain */ ++ uint8 est_Pout_act[4]; /* Latest tx power out estimate per RF chain ++ * without adjustment ++ */ ++ uint8 est_Pout_cck; /* Latest CCK tx power out estimate */ ++ uint8 tx_power_max[4]; /* Maximum target power among all rates */ ++ uint tx_power_max_rate_ind[4]; /* Index of the rate with the max target power */ ++ uint8 user_limit[WL_TX_POWER_RATES]; /* User limit */ ++ int8 board_limit[WL_TX_POWER_RATES]; /* Max power board can support (SROM) */ ++ int8 target[WL_TX_POWER_RATES]; /* Latest target power */ ++ int8 clm_limits[WL_NUMRATES]; /* regulatory limits - 20, 40 or 80MHz */ ++ int8 clm_limits_subchan1[WL_NUMRATES]; /* regulatory limits - 20in40 or 40in80 */ ++ int8 clm_limits_subchan2[WL_NUMRATES]; /* regulatory limits - 20in80MHz */ ++ int8 sar; /* SAR limit for display by wl executable */ ++ int8 channel_bandwidth; /* 20, 40 or 80 MHz bandwidth? */ ++ uint8 version; /* Version of the data format wlu <--> driver */ ++ uint8 display_core; /* Displayed curpower core */ ++#ifdef PPR_API ++} tx_power_new_t; ++#else ++} tx_power_t; ++#endif ++ ++typedef struct tx_inst_power { ++ uint8 txpwr_est_Pout[2]; /* Latest estimate for 2.4 and 5 Ghz */ ++ uint8 txpwr_est_Pout_gofdm; /* Pwr estimate for 2.4 OFDM */ ++} tx_inst_power_t; ++ ++ ++typedef struct { ++ uint32 flags; ++ chanspec_t chanspec; /* txpwr report for this channel */ ++ chanspec_t local_chanspec; /* channel on which we are associated */ ++ uint8 local_max; /* local max according to the AP */ ++ uint8 local_constraint; /* local constraint according to the AP */ ++ int8 antgain[2]; /* Ant gain for each band - from SROM */ ++ uint8 rf_cores; /* count of RF Cores being reported */ ++ uint8 est_Pout[4]; /* Latest tx power out estimate per RF chain */ ++ uint8 est_Pout_act[4]; /* Latest tx power out estimate per RF chain ++ * without adjustment ++ */ ++ uint8 est_Pout_cck; /* Latest CCK tx power out estimate */ ++ uint8 tx_power_max[4]; /* Maximum target power among all rates */ ++ uint tx_power_max_rate_ind[4]; /* Index of the rate with the max target power */ ++ txppr_t user_limit; /* User limit */ ++ txppr_t reg_limit; /* Regulatory power limit */ ++ txppr_t board_limit; /* Max power board can support (SROM) */ ++ txppr_t target; /* Latest target power */ ++} wl_txpwr_t; ++ ++#define WL_NUM_TXCHAIN_MAX 4 ++typedef struct wl_txchain_pwr_offsets { ++ int8 offset[WL_NUM_TXCHAIN_MAX]; /* quarter dBm signed offset for each chain */ ++} wl_txchain_pwr_offsets_t; ++ ++/* 802.11h measurement types */ ++#define WLC_MEASURE_TPC 1 ++#define WLC_MEASURE_CHANNEL_BASIC 2 ++#define WLC_MEASURE_CHANNEL_CCA 3 ++#define WLC_MEASURE_CHANNEL_RPI 4 ++ ++/* regulatory enforcement levels */ ++#define SPECT_MNGMT_OFF 0 /* both 11h and 11d disabled */ ++#define SPECT_MNGMT_LOOSE_11H 1 /* allow non-11h APs in scan lists */ ++#define SPECT_MNGMT_STRICT_11H 2 /* prune out non-11h APs from scan list */ ++#define SPECT_MNGMT_STRICT_11D 3 /* switch to 802.11D mode */ ++/* SPECT_MNGMT_LOOSE_11H_D - same as SPECT_MNGMT_LOOSE with the exception that Country IE ++ * adoption is done regardless of capability spectrum_management ++ */ ++#define SPECT_MNGMT_LOOSE_11H_D 4 /* operation defined above */ ++ ++#define WL_CHAN_VALID_HW (1 << 0) /* valid with current HW */ ++#define WL_CHAN_VALID_SW (1 << 1) /* valid with current country setting */ ++#define WL_CHAN_BAND_5G (1 << 2) /* 5GHz-band channel */ ++#define WL_CHAN_RADAR (1 << 3) /* radar sensitive channel */ ++#define WL_CHAN_INACTIVE (1 << 4) /* temporarily inactive due to radar */ ++#define WL_CHAN_PASSIVE (1 << 5) /* channel is in passive mode */ ++#define WL_CHAN_RESTRICTED (1 << 6) /* restricted use channel */ ++ ++/* BTC mode used by "btc_mode" iovar */ ++#define WL_BTC_DISABLE 0 /* disable BT coexistence */ ++#define WL_BTC_FULLTDM 1 /* full TDM COEX */ ++#define WL_BTC_ENABLE 1 /* full TDM COEX to maintain backward compatiblity */ ++#define WL_BTC_PREMPT 2 /* full TDM COEX with preemption */ ++#define WL_BTC_LITE 3 /* light weight coex for large isolation platform */ ++#define WL_BTC_PARALLEL 4 /* BT and WLAN run in parallel with separate antenna */ ++#define WL_BTC_HYBRID 5 /* hybrid coex, only ack is allowed to transmit in BT slot */ ++#define WL_BTC_DEFAULT 8 /* set the default mode for the device */ ++#define WL_INF_BTC_DISABLE 0 ++#define WL_INF_BTC_ENABLE 1 ++#define WL_INF_BTC_AUTO 3 ++ ++/* BTC wire used by "btc_wire" iovar */ ++#define WL_BTC_DEFWIRE 0 /* use default wire setting */ ++#define WL_BTC_2WIRE 2 /* use 2-wire BTC */ ++#define WL_BTC_3WIRE 3 /* use 3-wire BTC */ ++#define WL_BTC_4WIRE 4 /* use 4-wire BTC */ ++ ++/* BTC flags: BTC configuration that can be set by host */ ++#define WL_BTC_FLAG_PREMPT (1 << 0) ++#define WL_BTC_FLAG_BT_DEF (1 << 1) ++#define WL_BTC_FLAG_ACTIVE_PROT (1 << 2) ++#define WL_BTC_FLAG_SIM_RSP (1 << 3) ++#define WL_BTC_FLAG_PS_PROTECT (1 << 4) ++#define WL_BTC_FLAG_SIM_TX_LP (1 << 5) ++#define WL_BTC_FLAG_ECI (1 << 6) ++#define WL_BTC_FLAG_LIGHT (1 << 7) ++#define WL_BTC_FLAG_PARALLEL (1 << 8) ++ ++/* Message levels */ ++#define WL_ERROR_VAL 0x00000001 ++#define WL_TRACE_VAL 0x00000002 ++#define WL_PRHDRS_VAL 0x00000004 ++#define WL_PRPKT_VAL 0x00000008 ++#define WL_INFORM_VAL 0x00000010 ++#define WL_TMP_VAL 0x00000020 ++#define WL_OID_VAL 0x00000040 ++#define WL_RATE_VAL 0x00000080 ++#define WL_ASSOC_VAL 0x00000100 ++#define WL_PRUSR_VAL 0x00000200 ++#define WL_PS_VAL 0x00000400 ++#define WL_TXPWR_VAL 0x00000800 /* retired in TOT on 6/10/2009 */ ++#define WL_PORT_VAL 0x00001000 ++#define WL_DUAL_VAL 0x00002000 ++#define WL_WSEC_VAL 0x00004000 ++#define WL_WSEC_DUMP_VAL 0x00008000 ++#define WL_LOG_VAL 0x00010000 ++#define WL_NRSSI_VAL 0x00020000 /* retired in TOT on 6/10/2009 */ ++#define WL_LOFT_VAL 0x00040000 /* retired in TOT on 6/10/2009 */ ++#define WL_REGULATORY_VAL 0x00080000 ++#define WL_PHYCAL_VAL 0x00100000 /* retired in TOT on 6/10/2009 */ ++#define WL_RADAR_VAL 0x00200000 /* retired in TOT on 6/10/2009 */ ++#define WL_MPC_VAL 0x00400000 ++#define WL_APSTA_VAL 0x00800000 ++#define WL_DFS_VAL 0x01000000 ++#define WL_BA_VAL 0x02000000 /* retired in TOT on 6/14/2010 */ ++#define WL_ACI_VAL 0x04000000 ++#define WL_MBSS_VAL 0x04000000 ++#define WL_CAC_VAL 0x08000000 ++#define WL_AMSDU_VAL 0x10000000 ++#define WL_AMPDU_VAL 0x20000000 ++#define WL_FFPLD_VAL 0x40000000 ++ ++/* wl_msg_level is full. For new bits take the next one and AND with ++ * wl_msg_level2 in wl_dbg.h ++ */ ++#define WL_DPT_VAL 0x00000001 ++#define WL_SCAN_VAL 0x00000002 ++#define WL_WOWL_VAL 0x00000004 ++#define WL_COEX_VAL 0x00000008 ++#define WL_RTDC_VAL 0x00000010 ++#define WL_PROTO_VAL 0x00000020 ++#define WL_BTA_VAL 0x00000040 ++#define WL_CHANINT_VAL 0x00000080 ++#define WL_THERMAL_VAL 0x00000100 /* retired in TOT on 6/10/2009 */ ++#define WL_P2P_VAL 0x00000200 ++#define WL_ITFR_VAL 0x00000400 ++#define WL_MCHAN_VAL 0x00000800 ++#define WL_TDLS_VAL 0x00001000 ++#define WL_MCNX_VAL 0x00002000 ++#define WL_PROT_VAL 0x00004000 ++#define WL_PSTA_VAL 0x00008000 ++#define WL_TBTT_VAL 0x00010000 ++#define WL_NIC_VAL 0x00020000 ++#define WL_PWRSEL_VAL 0x00040000 ++/* use top-bit for WL_TIME_STAMP_VAL because this is a modifier ++ * rather than a message-type of its own ++ */ ++#define WL_TIMESTAMP_VAL 0x80000000 ++ ++/* max # of leds supported by GPIO (gpio pin# == led index#) */ ++#define WL_LED_NUMGPIO 32 /* gpio 0-31 */ ++ ++/* led per-pin behaviors */ ++#define WL_LED_OFF 0 /* always off */ ++#define WL_LED_ON 1 /* always on */ ++#define WL_LED_ACTIVITY 2 /* activity */ ++#define WL_LED_RADIO 3 /* radio enabled */ ++#define WL_LED_ARADIO 4 /* 5 Ghz radio enabled */ ++#define WL_LED_BRADIO 5 /* 2.4Ghz radio enabled */ ++#define WL_LED_BGMODE 6 /* on if gmode, off if bmode */ ++#define WL_LED_WI1 7 ++#define WL_LED_WI2 8 ++#define WL_LED_WI3 9 ++#define WL_LED_ASSOC 10 /* associated state indicator */ ++#define WL_LED_INACTIVE 11 /* null behavior (clears default behavior) */ ++#define WL_LED_ASSOCACT 12 /* on when associated; blink fast for activity */ ++#define WL_LED_WI4 13 ++#define WL_LED_WI5 14 ++#define WL_LED_BLINKSLOW 15 /* blink slow */ ++#define WL_LED_BLINKMED 16 /* blink med */ ++#define WL_LED_BLINKFAST 17 /* blink fast */ ++#define WL_LED_BLINKCUSTOM 18 /* blink custom */ ++#define WL_LED_BLINKPERIODIC 19 /* blink periodic (custom 1000ms / off 400ms) */ ++#define WL_LED_ASSOC_WITH_SEC 20 /* when connected with security */ ++ /* keep on for 300 sec */ ++#define WL_LED_START_OFF 21 /* off upon boot, could be turned on later */ ++#define WL_LED_NUMBEHAVIOR 22 ++ ++/* led behavior numeric value format */ ++#define WL_LED_BEH_MASK 0x7f /* behavior mask */ ++#define WL_LED_AL_MASK 0x80 /* activelow (polarity) bit */ ++ ++/* maximum channels returned by the get valid channels iovar */ ++#define WL_NUMCHANNELS 64 ++ ++/* max number of chanspecs (used by the iovar to calc. buf space) */ ++#define WL_NUMCHANSPECS 110 ++ ++/* WDS link local endpoint WPA role */ ++#define WL_WDS_WPA_ROLE_AUTH 0 /* authenticator */ ++#define WL_WDS_WPA_ROLE_SUP 1 /* supplicant */ ++#define WL_WDS_WPA_ROLE_AUTO 255 /* auto, based on mac addr value */ ++ ++/* number of bytes needed to define a 128-bit mask for MAC event reporting */ ++#define WL_EVENTING_MASK_LEN 16 ++ ++/* ++ * Join preference iovar value is an array of tuples. Each tuple has a one-byte type, ++ * a one-byte length, and a variable length value. RSSI type tuple must be present ++ * in the array. ++ * ++ * Types are defined in "join preference types" section. ++ * ++ * Length is the value size in octets. It is reserved for WL_JOIN_PREF_WPA type tuple ++ * and must be set to zero. ++ * ++ * Values are defined below. ++ * ++ * 1. RSSI - 2 octets ++ * offset 0: reserved ++ * offset 1: reserved ++ * ++ * 2. WPA - 2 + 12 * n octets (n is # tuples defined below) ++ * offset 0: reserved ++ * offset 1: # of tuples ++ * offset 2: tuple 1 ++ * offset 14: tuple 2 ++ * ... ++ * offset 2 + 12 * (n - 1) octets: tuple n ++ * ++ * struct wpa_cfg_tuple { ++ * uint8 akm[DOT11_OUI_LEN+1]; akm suite ++ * uint8 ucipher[DOT11_OUI_LEN+1]; unicast cipher suite ++ * uint8 mcipher[DOT11_OUI_LEN+1]; multicast cipher suite ++ * }; ++ * ++ * multicast cipher suite can be specified as a specific cipher suite or WL_WPA_ACP_MCS_ANY. ++ * ++ * 3. BAND - 2 octets ++ * offset 0: reserved ++ * offset 1: see "band preference" and "band types" ++ * ++ * 4. BAND RSSI - 2 octets ++ * offset 0: band types ++ * offset 1: +ve RSSI boost balue in dB ++ */ ++ ++/* join preference types */ ++#define WL_JOIN_PREF_RSSI 1 /* by RSSI */ ++#define WL_JOIN_PREF_WPA 2 /* by akm and ciphers */ ++#define WL_JOIN_PREF_BAND 3 /* by 802.11 band */ ++#define WL_JOIN_PREF_RSSI_DELTA 4 /* by 802.11 band only if RSSI delta condition matches */ ++#define WL_JOIN_PREF_TRANS_PREF 5 /* defined by requesting AP */ ++ ++/* band preference */ ++#define WLJP_BAND_ASSOC_PREF 255 /* use what WLC_SET_ASSOC_PREFER ioctl specifies */ ++ ++/* any multicast cipher suite */ ++#define WL_WPA_ACP_MCS_ANY "\x00\x00\x00\x00" ++ ++struct tsinfo_arg { ++ uint8 octets[3]; ++}; ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++#define NFIFO 6 /* # tx/rx fifopairs */ ++ ++#define WL_CNT_T_VERSION 8 /* current version of wl_cnt_t struct */ ++ ++typedef struct { ++ uint16 version; /* see definition of WL_CNT_T_VERSION */ ++ uint16 length; /* length of entire structure */ ++ ++ /* transmit stat counters */ ++ uint32 txframe; /* tx data frames */ ++ uint32 txbyte; /* tx data bytes */ ++ uint32 txretrans; /* tx mac retransmits */ ++ uint32 txerror; /* tx data errors (derived: sum of others) */ ++ uint32 txctl; /* tx management frames */ ++ uint32 txprshort; /* tx short preamble frames */ ++ uint32 txserr; /* tx status errors */ ++ uint32 txnobuf; /* tx out of buffers errors */ ++ uint32 txnoassoc; /* tx discard because we're not associated */ ++ uint32 txrunt; /* tx runt frames */ ++ uint32 txchit; /* tx header cache hit (fastpath) */ ++ uint32 txcmiss; /* tx header cache miss (slowpath) */ ++ ++ /* transmit chip error counters */ ++ uint32 txuflo; /* tx fifo underflows */ ++ uint32 txphyerr; /* tx phy errors (indicated in tx status) */ ++ uint32 txphycrs; ++ ++ /* receive stat counters */ ++ uint32 rxframe; /* rx data frames */ ++ uint32 rxbyte; /* rx data bytes */ ++ uint32 rxerror; /* rx data errors (derived: sum of others) */ ++ uint32 rxctl; /* rx management frames */ ++ uint32 rxnobuf; /* rx out of buffers errors */ ++ uint32 rxnondata; /* rx non data frames in the data channel errors */ ++ uint32 rxbadds; /* rx bad DS errors */ ++ uint32 rxbadcm; /* rx bad control or management frames */ ++ uint32 rxfragerr; /* rx fragmentation errors */ ++ uint32 rxrunt; /* rx runt frames */ ++ uint32 rxgiant; /* rx giant frames */ ++ uint32 rxnoscb; /* rx no scb error */ ++ uint32 rxbadproto; /* rx invalid frames */ ++ uint32 rxbadsrcmac; /* rx frames with Invalid Src Mac */ ++ uint32 rxbadda; /* rx frames tossed for invalid da */ ++ uint32 rxfilter; /* rx frames filtered out */ ++ ++ /* receive chip error counters */ ++ uint32 rxoflo; /* rx fifo overflow errors */ ++ uint32 rxuflo[NFIFO]; /* rx dma descriptor underflow errors */ ++ ++ uint32 d11cnt_txrts_off; /* d11cnt txrts value when reset d11cnt */ ++ uint32 d11cnt_rxcrc_off; /* d11cnt rxcrc value when reset d11cnt */ ++ uint32 d11cnt_txnocts_off; /* d11cnt txnocts value when reset d11cnt */ ++ ++ /* misc counters */ ++ uint32 dmade; /* tx/rx dma descriptor errors */ ++ uint32 dmada; /* tx/rx dma data errors */ ++ uint32 dmape; /* tx/rx dma descriptor protocol errors */ ++ uint32 reset; /* reset count */ ++ uint32 tbtt; /* cnts the TBTT int's */ ++ uint32 txdmawar; ++ uint32 pkt_callback_reg_fail; /* callbacks register failure */ ++ ++ /* MAC counters: 32-bit version of d11.h's macstat_t */ ++ uint32 txallfrm; /* total number of frames sent, incl. Data, ACK, RTS, CTS, ++ * Control Management (includes retransmissions) ++ */ ++ uint32 txrtsfrm; /* number of RTS sent out by the MAC */ ++ uint32 txctsfrm; /* number of CTS sent out by the MAC */ ++ uint32 txackfrm; /* number of ACK frames sent out */ ++ uint32 txdnlfrm; /* Not used */ ++ uint32 txbcnfrm; /* beacons transmitted */ ++ uint32 txfunfl[8]; /* per-fifo tx underflows */ ++ uint32 txtplunfl; /* Template underflows (mac was too slow to transmit ACK/CTS ++ * or BCN) ++ */ ++ uint32 txphyerror; /* Transmit phy error, type of error is reported in tx-status for ++ * driver enqueued frames ++ */ ++ uint32 rxfrmtoolong; /* Received frame longer than legal limit (2346 bytes) */ ++ uint32 rxfrmtooshrt; /* Received frame did not contain enough bytes for its frame type */ ++ uint32 rxinvmachdr; /* Either the protocol version != 0 or frame type not ++ * data/control/management ++ */ ++ uint32 rxbadfcs; /* number of frames for which the CRC check failed in the MAC */ ++ uint32 rxbadplcp; /* parity check of the PLCP header failed */ ++ uint32 rxcrsglitch; /* PHY was able to correlate the preamble but not the header */ ++ uint32 rxstrt; /* Number of received frames with a good PLCP ++ * (i.e. passing parity check) ++ */ ++ uint32 rxdfrmucastmbss; /* Number of received DATA frames with good FCS and matching RA */ ++ uint32 rxmfrmucastmbss; /* number of received mgmt frames with good FCS and matching RA */ ++ uint32 rxcfrmucast; /* number of received CNTRL frames with good FCS and matching RA */ ++ uint32 rxrtsucast; /* number of unicast RTS addressed to the MAC (good FCS) */ ++ uint32 rxctsucast; /* number of unicast CTS addressed to the MAC (good FCS) */ ++ uint32 rxackucast; /* number of ucast ACKS received (good FCS) */ ++ uint32 rxdfrmocast; /* number of received DATA frames (good FCS and not matching RA) */ ++ uint32 rxmfrmocast; /* number of received MGMT frames (good FCS and not matching RA) */ ++ uint32 rxcfrmocast; /* number of received CNTRL frame (good FCS and not matching RA) */ ++ uint32 rxrtsocast; /* number of received RTS not addressed to the MAC */ ++ uint32 rxctsocast; /* number of received CTS not addressed to the MAC */ ++ uint32 rxdfrmmcast; /* number of RX Data multicast frames received by the MAC */ ++ uint32 rxmfrmmcast; /* number of RX Management multicast frames received by the MAC */ ++ uint32 rxcfrmmcast; /* number of RX Control multicast frames received by the MAC ++ * (unlikely to see these) ++ */ ++ uint32 rxbeaconmbss; /* beacons received from member of BSS */ ++ uint32 rxdfrmucastobss; /* number of unicast frames addressed to the MAC from ++ * other BSS (WDS FRAME) ++ */ ++ uint32 rxbeaconobss; /* beacons received from other BSS */ ++ uint32 rxrsptmout; /* Number of response timeouts for transmitted frames ++ * expecting a response ++ */ ++ uint32 bcntxcancl; /* transmit beacons canceled due to receipt of beacon (IBSS) */ ++ uint32 rxf0ovfl; /* Number of receive fifo 0 overflows */ ++ uint32 rxf1ovfl; /* Number of receive fifo 1 overflows (obsolete) */ ++ uint32 rxf2ovfl; /* Number of receive fifo 2 overflows (obsolete) */ ++ uint32 txsfovfl; /* Number of transmit status fifo overflows (obsolete) */ ++ uint32 pmqovfl; /* Number of PMQ overflows */ ++ uint32 rxcgprqfrm; /* Number of received Probe requests that made it into ++ * the PRQ fifo ++ */ ++ uint32 rxcgprsqovfl; /* Rx Probe Request Que overflow in the AP */ ++ uint32 txcgprsfail; /* Tx Probe Response Fail. AP sent probe response but did ++ * not get ACK ++ */ ++ uint32 txcgprssuc; /* Tx Probe Response Success (ACK was received) */ ++ uint32 prs_timeout; /* Number of probe requests that were dropped from the PRQ ++ * fifo because a probe response could not be sent out within ++ * the time limit defined in M_PRS_MAXTIME ++ */ ++ uint32 rxnack; /* obsolete */ ++ uint32 frmscons; /* obsolete */ ++ uint32 txnack; /* obsolete */ ++ uint32 txglitch_nack; /* obsolete */ ++ uint32 txburst; /* obsolete */ ++ ++ /* 802.11 MIB counters, pp. 614 of 802.11 reaff doc. */ ++ uint32 txfrag; /* dot11TransmittedFragmentCount */ ++ uint32 txmulti; /* dot11MulticastTransmittedFrameCount */ ++ uint32 txfail; /* dot11FailedCount */ ++ uint32 txretry; /* dot11RetryCount */ ++ uint32 txretrie; /* dot11MultipleRetryCount */ ++ uint32 rxdup; /* dot11FrameduplicateCount */ ++ uint32 txrts; /* dot11RTSSuccessCount */ ++ uint32 txnocts; /* dot11RTSFailureCount */ ++ uint32 txnoack; /* dot11ACKFailureCount */ ++ uint32 rxfrag; /* dot11ReceivedFragmentCount */ ++ uint32 rxmulti; /* dot11MulticastReceivedFrameCount */ ++ uint32 rxcrc; /* dot11FCSErrorCount */ ++ uint32 txfrmsnt; /* dot11TransmittedFrameCount (bogus MIB?) */ ++ uint32 rxundec; /* dot11WEPUndecryptableCount */ ++ ++ /* WPA2 counters (see rxundec for DecryptFailureCount) */ ++ uint32 tkipmicfaill; /* TKIPLocalMICFailures */ ++ uint32 tkipcntrmsr; /* TKIPCounterMeasuresInvoked */ ++ uint32 tkipreplay; /* TKIPReplays */ ++ uint32 ccmpfmterr; /* CCMPFormatErrors */ ++ uint32 ccmpreplay; /* CCMPReplays */ ++ uint32 ccmpundec; /* CCMPDecryptErrors */ ++ uint32 fourwayfail; /* FourWayHandshakeFailures */ ++ uint32 wepundec; /* dot11WEPUndecryptableCount */ ++ uint32 wepicverr; /* dot11WEPICVErrorCount */ ++ uint32 decsuccess; /* DecryptSuccessCount */ ++ uint32 tkipicverr; /* TKIPICVErrorCount */ ++ uint32 wepexcluded; /* dot11WEPExcludedCount */ ++ ++ uint32 txchanrej; /* Tx frames suppressed due to channel rejection */ ++ uint32 psmwds; /* Count PSM watchdogs */ ++ uint32 phywatchdog; /* Count Phy watchdogs (triggered by ucode) */ ++ ++ /* MBSS counters, AP only */ ++ uint32 prq_entries_handled; /* PRQ entries read in */ ++ uint32 prq_undirected_entries; /* which were bcast bss & ssid */ ++ uint32 prq_bad_entries; /* which could not be translated to info */ ++ uint32 atim_suppress_count; /* TX suppressions on ATIM fifo */ ++ uint32 bcn_template_not_ready; /* Template marked in use on send bcn ... */ ++ uint32 bcn_template_not_ready_done; /* ...but "DMA done" interrupt rcvd */ ++ uint32 late_tbtt_dpc; /* TBTT DPC did not happen in time */ ++ ++ /* per-rate receive stat counters */ ++ uint32 rx1mbps; /* packets rx at 1Mbps */ ++ uint32 rx2mbps; /* packets rx at 2Mbps */ ++ uint32 rx5mbps5; /* packets rx at 5.5Mbps */ ++ uint32 rx6mbps; /* packets rx at 6Mbps */ ++ uint32 rx9mbps; /* packets rx at 9Mbps */ ++ uint32 rx11mbps; /* packets rx at 11Mbps */ ++ uint32 rx12mbps; /* packets rx at 12Mbps */ ++ uint32 rx18mbps; /* packets rx at 18Mbps */ ++ uint32 rx24mbps; /* packets rx at 24Mbps */ ++ uint32 rx36mbps; /* packets rx at 36Mbps */ ++ uint32 rx48mbps; /* packets rx at 48Mbps */ ++ uint32 rx54mbps; /* packets rx at 54Mbps */ ++ uint32 rx108mbps; /* packets rx at 108mbps */ ++ uint32 rx162mbps; /* packets rx at 162mbps */ ++ uint32 rx216mbps; /* packets rx at 216 mbps */ ++ uint32 rx270mbps; /* packets rx at 270 mbps */ ++ uint32 rx324mbps; /* packets rx at 324 mbps */ ++ uint32 rx378mbps; /* packets rx at 378 mbps */ ++ uint32 rx432mbps; /* packets rx at 432 mbps */ ++ uint32 rx486mbps; /* packets rx at 486 mbps */ ++ uint32 rx540mbps; /* packets rx at 540 mbps */ ++ ++ /* pkteng rx frame stats */ ++ uint32 pktengrxducast; /* unicast frames rxed by the pkteng code */ ++ uint32 pktengrxdmcast; /* multicast frames rxed by the pkteng code */ ++ ++ uint32 rfdisable; /* count of radio disables */ ++ uint32 bphy_rxcrsglitch; /* PHY count of bphy glitches */ ++ ++ uint32 txexptime; /* Tx frames suppressed due to timer expiration */ ++ ++ uint32 txmpdu_sgi; /* count for sgi transmit */ ++ uint32 rxmpdu_sgi; /* count for sgi received */ ++ uint32 txmpdu_stbc; /* count for stbc transmit */ ++ uint32 rxmpdu_stbc; /* count for stbc received */ ++ ++ uint32 rxundec_mcst; /* dot11WEPUndecryptableCount */ ++ ++ /* WPA2 counters (see rxundec for DecryptFailureCount) */ ++ uint32 tkipmicfaill_mcst; /* TKIPLocalMICFailures */ ++ uint32 tkipcntrmsr_mcst; /* TKIPCounterMeasuresInvoked */ ++ uint32 tkipreplay_mcst; /* TKIPReplays */ ++ uint32 ccmpfmterr_mcst; /* CCMPFormatErrors */ ++ uint32 ccmpreplay_mcst; /* CCMPReplays */ ++ uint32 ccmpundec_mcst; /* CCMPDecryptErrors */ ++ uint32 fourwayfail_mcst; /* FourWayHandshakeFailures */ ++ uint32 wepundec_mcst; /* dot11WEPUndecryptableCount */ ++ uint32 wepicverr_mcst; /* dot11WEPICVErrorCount */ ++ uint32 decsuccess_mcst; /* DecryptSuccessCount */ ++ uint32 tkipicverr_mcst; /* TKIPICVErrorCount */ ++ uint32 wepexcluded_mcst; /* dot11WEPExcludedCount */ ++ ++ uint32 dma_hang; /* count for dma hang */ ++ uint32 reinit; /* count for reinit */ ++ ++ uint32 pstatxucast; /* count of ucast frames xmitted on all psta assoc */ ++ uint32 pstatxnoassoc; /* count of txnoassoc frames xmitted on all psta assoc */ ++ uint32 pstarxucast; /* count of ucast frames received on all psta assoc */ ++ uint32 pstarxbcmc; /* count of bcmc frames received on all psta */ ++ uint32 pstatxbcmc; /* count of bcmc frames transmitted on all psta */ ++ ++ uint32 cso_passthrough; /* hw cso required but passthrough */ ++} wl_cnt_t; ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++typedef struct { ++ uint16 version; /* see definition of WL_CNT_T_VERSION */ ++ uint16 length; /* length of entire structure */ ++ ++ /* transmit stat counters */ ++ uint32 txframe; /* tx data frames */ ++ uint32 txbyte; /* tx data bytes */ ++ uint32 txretrans; /* tx mac retransmits */ ++ uint32 txerror; /* tx data errors (derived: sum of others) */ ++ uint32 txctl; /* tx management frames */ ++ uint32 txprshort; /* tx short preamble frames */ ++ uint32 txserr; /* tx status errors */ ++ uint32 txnobuf; /* tx out of buffers errors */ ++ uint32 txnoassoc; /* tx discard because we're not associated */ ++ uint32 txrunt; /* tx runt frames */ ++ uint32 txchit; /* tx header cache hit (fastpath) */ ++ uint32 txcmiss; /* tx header cache miss (slowpath) */ ++ ++ /* transmit chip error counters */ ++ uint32 txuflo; /* tx fifo underflows */ ++ uint32 txphyerr; /* tx phy errors (indicated in tx status) */ ++ uint32 txphycrs; ++ ++ /* receive stat counters */ ++ uint32 rxframe; /* rx data frames */ ++ uint32 rxbyte; /* rx data bytes */ ++ uint32 rxerror; /* rx data errors (derived: sum of others) */ ++ uint32 rxctl; /* rx management frames */ ++ uint32 rxnobuf; /* rx out of buffers errors */ ++ uint32 rxnondata; /* rx non data frames in the data channel errors */ ++ uint32 rxbadds; /* rx bad DS errors */ ++ uint32 rxbadcm; /* rx bad control or management frames */ ++ uint32 rxfragerr; /* rx fragmentation errors */ ++ uint32 rxrunt; /* rx runt frames */ ++ uint32 rxgiant; /* rx giant frames */ ++ uint32 rxnoscb; /* rx no scb error */ ++ uint32 rxbadproto; /* rx invalid frames */ ++ uint32 rxbadsrcmac; /* rx frames with Invalid Src Mac */ ++ uint32 rxbadda; /* rx frames tossed for invalid da */ ++ uint32 rxfilter; /* rx frames filtered out */ ++ ++ /* receive chip error counters */ ++ uint32 rxoflo; /* rx fifo overflow errors */ ++ uint32 rxuflo[NFIFO]; /* rx dma descriptor underflow errors */ ++ ++ uint32 d11cnt_txrts_off; /* d11cnt txrts value when reset d11cnt */ ++ uint32 d11cnt_rxcrc_off; /* d11cnt rxcrc value when reset d11cnt */ ++ uint32 d11cnt_txnocts_off; /* d11cnt txnocts value when reset d11cnt */ ++ ++ /* misc counters */ ++ uint32 dmade; /* tx/rx dma descriptor errors */ ++ uint32 dmada; /* tx/rx dma data errors */ ++ uint32 dmape; /* tx/rx dma descriptor protocol errors */ ++ uint32 reset; /* reset count */ ++ uint32 tbtt; /* cnts the TBTT int's */ ++ uint32 txdmawar; ++ uint32 pkt_callback_reg_fail; /* callbacks register failure */ ++ ++ /* MAC counters: 32-bit version of d11.h's macstat_t */ ++ uint32 txallfrm; /* total number of frames sent, incl. Data, ACK, RTS, CTS, ++ * Control Management (includes retransmissions) ++ */ ++ uint32 txrtsfrm; /* number of RTS sent out by the MAC */ ++ uint32 txctsfrm; /* number of CTS sent out by the MAC */ ++ uint32 txackfrm; /* number of ACK frames sent out */ ++ uint32 txdnlfrm; /* Not used */ ++ uint32 txbcnfrm; /* beacons transmitted */ ++ uint32 txfunfl[8]; /* per-fifo tx underflows */ ++ uint32 txtplunfl; /* Template underflows (mac was too slow to transmit ACK/CTS ++ * or BCN) ++ */ ++ uint32 txphyerror; /* Transmit phy error, type of error is reported in tx-status for ++ * driver enqueued frames ++ */ ++ uint32 rxfrmtoolong; /* Received frame longer than legal limit (2346 bytes) */ ++ uint32 rxfrmtooshrt; /* Received frame did not contain enough bytes for its frame type */ ++ uint32 rxinvmachdr; /* Either the protocol version != 0 or frame type not ++ * data/control/management ++ */ ++ uint32 rxbadfcs; /* number of frames for which the CRC check failed in the MAC */ ++ uint32 rxbadplcp; /* parity check of the PLCP header failed */ ++ uint32 rxcrsglitch; /* PHY was able to correlate the preamble but not the header */ ++ uint32 rxstrt; /* Number of received frames with a good PLCP ++ * (i.e. passing parity check) ++ */ ++ uint32 rxdfrmucastmbss; /* Number of received DATA frames with good FCS and matching RA */ ++ uint32 rxmfrmucastmbss; /* number of received mgmt frames with good FCS and matching RA */ ++ uint32 rxcfrmucast; /* number of received CNTRL frames with good FCS and matching RA */ ++ uint32 rxrtsucast; /* number of unicast RTS addressed to the MAC (good FCS) */ ++ uint32 rxctsucast; /* number of unicast CTS addressed to the MAC (good FCS) */ ++ uint32 rxackucast; /* number of ucast ACKS received (good FCS) */ ++ uint32 rxdfrmocast; /* number of received DATA frames (good FCS and not matching RA) */ ++ uint32 rxmfrmocast; /* number of received MGMT frames (good FCS and not matching RA) */ ++ uint32 rxcfrmocast; /* number of received CNTRL frame (good FCS and not matching RA) */ ++ uint32 rxrtsocast; /* number of received RTS not addressed to the MAC */ ++ uint32 rxctsocast; /* number of received CTS not addressed to the MAC */ ++ uint32 rxdfrmmcast; /* number of RX Data multicast frames received by the MAC */ ++ uint32 rxmfrmmcast; /* number of RX Management multicast frames received by the MAC */ ++ uint32 rxcfrmmcast; /* number of RX Control multicast frames received by the MAC ++ * (unlikely to see these) ++ */ ++ uint32 rxbeaconmbss; /* beacons received from member of BSS */ ++ uint32 rxdfrmucastobss; /* number of unicast frames addressed to the MAC from ++ * other BSS (WDS FRAME) ++ */ ++ uint32 rxbeaconobss; /* beacons received from other BSS */ ++ uint32 rxrsptmout; /* Number of response timeouts for transmitted frames ++ * expecting a response ++ */ ++ uint32 bcntxcancl; /* transmit beacons canceled due to receipt of beacon (IBSS) */ ++ uint32 rxf0ovfl; /* Number of receive fifo 0 overflows */ ++ uint32 rxf1ovfl; /* Number of receive fifo 1 overflows (obsolete) */ ++ uint32 rxf2ovfl; /* Number of receive fifo 2 overflows (obsolete) */ ++ uint32 txsfovfl; /* Number of transmit status fifo overflows (obsolete) */ ++ uint32 pmqovfl; /* Number of PMQ overflows */ ++ uint32 rxcgprqfrm; /* Number of received Probe requests that made it into ++ * the PRQ fifo ++ */ ++ uint32 rxcgprsqovfl; /* Rx Probe Request Que overflow in the AP */ ++ uint32 txcgprsfail; /* Tx Probe Response Fail. AP sent probe response but did ++ * not get ACK ++ */ ++ uint32 txcgprssuc; /* Tx Probe Response Success (ACK was received) */ ++ uint32 prs_timeout; /* Number of probe requests that were dropped from the PRQ ++ * fifo because a probe response could not be sent out within ++ * the time limit defined in M_PRS_MAXTIME ++ */ ++ uint32 rxnack; ++ uint32 frmscons; ++ uint32 txnack; ++ uint32 txglitch_nack; /* obsolete */ ++ uint32 txburst; /* obsolete */ ++ ++ /* 802.11 MIB counters, pp. 614 of 802.11 reaff doc. */ ++ uint32 txfrag; /* dot11TransmittedFragmentCount */ ++ uint32 txmulti; /* dot11MulticastTransmittedFrameCount */ ++ uint32 txfail; /* dot11FailedCount */ ++ uint32 txretry; /* dot11RetryCount */ ++ uint32 txretrie; /* dot11MultipleRetryCount */ ++ uint32 rxdup; /* dot11FrameduplicateCount */ ++ uint32 txrts; /* dot11RTSSuccessCount */ ++ uint32 txnocts; /* dot11RTSFailureCount */ ++ uint32 txnoack; /* dot11ACKFailureCount */ ++ uint32 rxfrag; /* dot11ReceivedFragmentCount */ ++ uint32 rxmulti; /* dot11MulticastReceivedFrameCount */ ++ uint32 rxcrc; /* dot11FCSErrorCount */ ++ uint32 txfrmsnt; /* dot11TransmittedFrameCount (bogus MIB?) */ ++ uint32 rxundec; /* dot11WEPUndecryptableCount */ ++ ++ /* WPA2 counters (see rxundec for DecryptFailureCount) */ ++ uint32 tkipmicfaill; /* TKIPLocalMICFailures */ ++ uint32 tkipcntrmsr; /* TKIPCounterMeasuresInvoked */ ++ uint32 tkipreplay; /* TKIPReplays */ ++ uint32 ccmpfmterr; /* CCMPFormatErrors */ ++ uint32 ccmpreplay; /* CCMPReplays */ ++ uint32 ccmpundec; /* CCMPDecryptErrors */ ++ uint32 fourwayfail; /* FourWayHandshakeFailures */ ++ uint32 wepundec; /* dot11WEPUndecryptableCount */ ++ uint32 wepicverr; /* dot11WEPICVErrorCount */ ++ uint32 decsuccess; /* DecryptSuccessCount */ ++ uint32 tkipicverr; /* TKIPICVErrorCount */ ++ uint32 wepexcluded; /* dot11WEPExcludedCount */ ++ ++ uint32 rxundec_mcst; /* dot11WEPUndecryptableCount */ ++ ++ /* WPA2 counters (see rxundec for DecryptFailureCount) */ ++ uint32 tkipmicfaill_mcst; /* TKIPLocalMICFailures */ ++ uint32 tkipcntrmsr_mcst; /* TKIPCounterMeasuresInvoked */ ++ uint32 tkipreplay_mcst; /* TKIPReplays */ ++ uint32 ccmpfmterr_mcst; /* CCMPFormatErrors */ ++ uint32 ccmpreplay_mcst; /* CCMPReplays */ ++ uint32 ccmpundec_mcst; /* CCMPDecryptErrors */ ++ uint32 fourwayfail_mcst; /* FourWayHandshakeFailures */ ++ uint32 wepundec_mcst; /* dot11WEPUndecryptableCount */ ++ uint32 wepicverr_mcst; /* dot11WEPICVErrorCount */ ++ uint32 decsuccess_mcst; /* DecryptSuccessCount */ ++ uint32 tkipicverr_mcst; /* TKIPICVErrorCount */ ++ uint32 wepexcluded_mcst; /* dot11WEPExcludedCount */ ++ ++ uint32 txchanrej; /* Tx frames suppressed due to channel rejection */ ++ uint32 txexptime; /* Tx frames suppressed due to timer expiration */ ++ uint32 psmwds; /* Count PSM watchdogs */ ++ uint32 phywatchdog; /* Count Phy watchdogs (triggered by ucode) */ ++ ++ /* MBSS counters, AP only */ ++ uint32 prq_entries_handled; /* PRQ entries read in */ ++ uint32 prq_undirected_entries; /* which were bcast bss & ssid */ ++ uint32 prq_bad_entries; /* which could not be translated to info */ ++ uint32 atim_suppress_count; /* TX suppressions on ATIM fifo */ ++ uint32 bcn_template_not_ready; /* Template marked in use on send bcn ... */ ++ uint32 bcn_template_not_ready_done; /* ...but "DMA done" interrupt rcvd */ ++ uint32 late_tbtt_dpc; /* TBTT DPC did not happen in time */ ++ ++ /* per-rate receive stat counters */ ++ uint32 rx1mbps; /* packets rx at 1Mbps */ ++ uint32 rx2mbps; /* packets rx at 2Mbps */ ++ uint32 rx5mbps5; /* packets rx at 5.5Mbps */ ++ uint32 rx6mbps; /* packets rx at 6Mbps */ ++ uint32 rx9mbps; /* packets rx at 9Mbps */ ++ uint32 rx11mbps; /* packets rx at 11Mbps */ ++ uint32 rx12mbps; /* packets rx at 12Mbps */ ++ uint32 rx18mbps; /* packets rx at 18Mbps */ ++ uint32 rx24mbps; /* packets rx at 24Mbps */ ++ uint32 rx36mbps; /* packets rx at 36Mbps */ ++ uint32 rx48mbps; /* packets rx at 48Mbps */ ++ uint32 rx54mbps; /* packets rx at 54Mbps */ ++ uint32 rx108mbps; /* packets rx at 108mbps */ ++ uint32 rx162mbps; /* packets rx at 162mbps */ ++ uint32 rx216mbps; /* packets rx at 216 mbps */ ++ uint32 rx270mbps; /* packets rx at 270 mbps */ ++ uint32 rx324mbps; /* packets rx at 324 mbps */ ++ uint32 rx378mbps; /* packets rx at 378 mbps */ ++ uint32 rx432mbps; /* packets rx at 432 mbps */ ++ uint32 rx486mbps; /* packets rx at 486 mbps */ ++ uint32 rx540mbps; /* packets rx at 540 mbps */ ++ ++ /* pkteng rx frame stats */ ++ uint32 pktengrxducast; /* unicast frames rxed by the pkteng code */ ++ uint32 pktengrxdmcast; /* multicast frames rxed by the pkteng code */ ++ ++ uint32 rfdisable; /* count of radio disables */ ++ uint32 bphy_rxcrsglitch; /* PHY count of bphy glitches */ ++ ++ uint32 txmpdu_sgi; /* count for sgi transmit */ ++ uint32 rxmpdu_sgi; /* count for sgi received */ ++ uint32 txmpdu_stbc; /* count for stbc transmit */ ++ uint32 rxmpdu_stbc; /* count for stbc received */ ++} wl_cnt_ver_six_t; ++ ++#define WL_DELTA_STATS_T_VERSION 1 /* current version of wl_delta_stats_t struct */ ++ ++typedef struct { ++ uint16 version; /* see definition of WL_DELTA_STATS_T_VERSION */ ++ uint16 length; /* length of entire structure */ ++ ++ /* transmit stat counters */ ++ uint32 txframe; /* tx data frames */ ++ uint32 txbyte; /* tx data bytes */ ++ uint32 txretrans; /* tx mac retransmits */ ++ uint32 txfail; /* tx failures */ ++ ++ /* receive stat counters */ ++ uint32 rxframe; /* rx data frames */ ++ uint32 rxbyte; /* rx data bytes */ ++ ++ /* per-rate receive stat counters */ ++ uint32 rx1mbps; /* packets rx at 1Mbps */ ++ uint32 rx2mbps; /* packets rx at 2Mbps */ ++ uint32 rx5mbps5; /* packets rx at 5.5Mbps */ ++ uint32 rx6mbps; /* packets rx at 6Mbps */ ++ uint32 rx9mbps; /* packets rx at 9Mbps */ ++ uint32 rx11mbps; /* packets rx at 11Mbps */ ++ uint32 rx12mbps; /* packets rx at 12Mbps */ ++ uint32 rx18mbps; /* packets rx at 18Mbps */ ++ uint32 rx24mbps; /* packets rx at 24Mbps */ ++ uint32 rx36mbps; /* packets rx at 36Mbps */ ++ uint32 rx48mbps; /* packets rx at 48Mbps */ ++ uint32 rx54mbps; /* packets rx at 54Mbps */ ++ uint32 rx108mbps; /* packets rx at 108mbps */ ++ uint32 rx162mbps; /* packets rx at 162mbps */ ++ uint32 rx216mbps; /* packets rx at 216 mbps */ ++ uint32 rx270mbps; /* packets rx at 270 mbps */ ++ uint32 rx324mbps; /* packets rx at 324 mbps */ ++ uint32 rx378mbps; /* packets rx at 378 mbps */ ++ uint32 rx432mbps; /* packets rx at 432 mbps */ ++ uint32 rx486mbps; /* packets rx at 486 mbps */ ++ uint32 rx540mbps; /* packets rx at 540 mbps */ ++} wl_delta_stats_t; ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++#define WL_WME_CNT_VERSION 1 /* current version of wl_wme_cnt_t */ ++ ++typedef struct { ++ uint32 packets; ++ uint32 bytes; ++} wl_traffic_stats_t; ++ ++typedef struct { ++ uint16 version; /* see definition of WL_WME_CNT_VERSION */ ++ uint16 length; /* length of entire structure */ ++ ++ wl_traffic_stats_t tx[AC_COUNT]; /* Packets transmitted */ ++ wl_traffic_stats_t tx_failed[AC_COUNT]; /* Packets dropped or failed to transmit */ ++ wl_traffic_stats_t rx[AC_COUNT]; /* Packets received */ ++ wl_traffic_stats_t rx_failed[AC_COUNT]; /* Packets failed to receive */ ++ ++ wl_traffic_stats_t forward[AC_COUNT]; /* Packets forwarded by AP */ ++ ++ wl_traffic_stats_t tx_expired[AC_COUNT]; /* packets dropped due to lifetime expiry */ ++ ++} wl_wme_cnt_t; ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++struct wl_msglevel2 { ++ uint32 low; ++ uint32 high; ++}; ++ ++typedef struct wl_mkeep_alive_pkt { ++ uint16 version; /* Version for mkeep_alive */ ++ uint16 length; /* length of fixed parameters in the structure */ ++ uint32 period_msec; ++ uint16 len_bytes; ++ uint8 keep_alive_id; /* 0 - 3 for N = 4 */ ++ uint8 data[1]; ++} wl_mkeep_alive_pkt_t; ++ ++#define WL_MKEEP_ALIVE_VERSION 1 ++#define WL_MKEEP_ALIVE_FIXED_LEN OFFSETOF(wl_mkeep_alive_pkt_t, data) ++#define WL_MKEEP_ALIVE_PRECISION 500 ++ ++#ifdef WLBA ++ ++#define WLC_BA_CNT_VERSION 1 /* current version of wlc_ba_cnt_t */ ++ ++/* block ack related stats */ ++typedef struct wlc_ba_cnt { ++ uint16 version; /* WLC_BA_CNT_VERSION */ ++ uint16 length; /* length of entire structure */ ++ ++ /* transmit stat counters */ ++ uint32 txpdu; /* pdus sent */ ++ uint32 txsdu; /* sdus sent */ ++ uint32 txfc; /* tx side flow controlled packets */ ++ uint32 txfci; /* tx side flow control initiated */ ++ uint32 txretrans; /* retransmitted pdus */ ++ uint32 txbatimer; /* ba resend due to timer */ ++ uint32 txdrop; /* dropped packets */ ++ uint32 txaddbareq; /* addba req sent */ ++ uint32 txaddbaresp; /* addba resp sent */ ++ uint32 txdelba; /* delba sent */ ++ uint32 txba; /* ba sent */ ++ uint32 txbar; /* bar sent */ ++ uint32 txpad[4]; /* future */ ++ ++ /* receive side counters */ ++ uint32 rxpdu; /* pdus recd */ ++ uint32 rxqed; /* pdus buffered before sending up */ ++ uint32 rxdup; /* duplicate pdus */ ++ uint32 rxnobuf; /* pdus discarded due to no buf */ ++ uint32 rxaddbareq; /* addba req recd */ ++ uint32 rxaddbaresp; /* addba resp recd */ ++ uint32 rxdelba; /* delba recd */ ++ uint32 rxba; /* ba recd */ ++ uint32 rxbar; /* bar recd */ ++ uint32 rxinvba; /* invalid ba recd */ ++ uint32 rxbaholes; /* ba recd with holes */ ++ uint32 rxunexp; /* unexpected packets */ ++ uint32 rxpad[4]; /* future */ ++} wlc_ba_cnt_t; ++#endif /* WLBA */ ++ ++/* structure for per-tid ampdu control */ ++struct ampdu_tid_control { ++ uint8 tid; /* tid */ ++ uint8 enable; /* enable/disable */ ++}; ++ ++/* structure for identifying ea/tid for sending addba/delba */ ++struct ampdu_ea_tid { ++ struct ether_addr ea; /* Station address */ ++ uint8 tid; /* tid */ ++}; ++/* structure for identifying retry/tid for retry_limit_tid/rr_retry_limit_tid */ ++struct ampdu_retry_tid { ++ uint8 tid; /* tid */ ++ uint8 retry; /* retry value */ ++}; ++ ++/* Different discovery modes for dpt */ ++#define DPT_DISCOVERY_MANUAL 0x01 /* manual discovery mode */ ++#define DPT_DISCOVERY_AUTO 0x02 /* auto discovery mode */ ++#define DPT_DISCOVERY_SCAN 0x04 /* scan-based discovery mode */ ++ ++/* different path selection values */ ++#define DPT_PATHSEL_AUTO 0 /* auto mode for path selection */ ++#define DPT_PATHSEL_DIRECT 1 /* always use direct DPT path */ ++#define DPT_PATHSEL_APPATH 2 /* always use AP path */ ++ ++/* different ops for deny list */ ++#define DPT_DENY_LIST_ADD 1 /* add to dpt deny list */ ++#define DPT_DENY_LIST_REMOVE 2 /* remove from dpt deny list */ ++ ++/* different ops for manual end point */ ++#define DPT_MANUAL_EP_CREATE 1 /* create manual dpt endpoint */ ++#define DPT_MANUAL_EP_MODIFY 2 /* modify manual dpt endpoint */ ++#define DPT_MANUAL_EP_DELETE 3 /* delete manual dpt endpoint */ ++ ++/* structure for dpt iovars */ ++typedef struct dpt_iovar { ++ struct ether_addr ea; /* Station address */ ++ uint8 mode; /* mode: depends on iovar */ ++ uint32 pad; /* future */ ++} dpt_iovar_t; ++ ++/* flags to indicate DPT status */ ++#define DPT_STATUS_ACTIVE 0x01 /* link active (though may be suspended) */ ++#define DPT_STATUS_AES 0x02 /* link secured through AES encryption */ ++#define DPT_STATUS_FAILED 0x04 /* DPT link failed */ ++ ++#define DPT_FNAME_LEN 48 /* Max length of friendly name */ ++ ++typedef struct dpt_status { ++ uint8 status; /* flags to indicate status */ ++ uint8 fnlen; /* length of friendly name */ ++ uchar name[DPT_FNAME_LEN]; /* friendly name */ ++ uint32 rssi; /* RSSI of the link */ ++ sta_info_t sta; /* sta info */ ++} dpt_status_t; ++ ++/* structure for dpt list */ ++typedef struct dpt_list { ++ uint32 num; /* number of entries in struct */ ++ dpt_status_t status[1]; /* per station info */ ++} dpt_list_t; ++ ++/* structure for dpt friendly name */ ++typedef struct dpt_fname { ++ uint8 len; /* length of friendly name */ ++ uchar name[DPT_FNAME_LEN]; /* friendly name */ ++} dpt_fname_t; ++ ++#define BDD_FNAME_LEN 32 /* Max length of friendly name */ ++typedef struct bdd_fname { ++ uint8 len; /* length of friendly name */ ++ uchar name[BDD_FNAME_LEN]; /* friendly name */ ++} bdd_fname_t; ++ ++/* structure for addts arguments */ ++/* For ioctls that take a list of TSPEC */ ++struct tslist { ++ int count; /* number of tspecs */ ++ struct tsinfo_arg tsinfo[1]; /* variable length array of tsinfo */ ++}; ++ ++#ifdef WLTDLS ++/* different ops for manual end point */ ++#define TDLS_MANUAL_EP_CREATE 1 /* create manual dpt endpoint */ ++#define TDLS_MANUAL_EP_MODIFY 2 /* modify manual dpt endpoint */ ++#define TDLS_MANUAL_EP_DELETE 3 /* delete manual dpt endpoint */ ++#define TDLS_MANUAL_EP_PM 4 /* put dpt endpoint in PM mode */ ++#define TDLS_MANUAL_EP_WAKE 5 /* wake up dpt endpoint from PM */ ++#define TDLS_MANUAL_EP_DISCOVERY 6 /* discover if endpoint is TDLS capable */ ++#define TDLS_MANUAL_EP_CHSW 7 /* channel switch */ ++ ++/* structure for tdls iovars */ ++typedef struct tdls_iovar { ++ struct ether_addr ea; /* Station address */ ++ uint8 mode; /* mode: depends on iovar */ ++ chanspec_t chanspec; ++ uint32 pad; /* future */ ++} tdls_iovar_t; ++ ++/* modes */ ++#define TDLS_WFD_IE_TX 0 ++#define TDLS_WFD_IE_RX 1 ++#define TDLS_WFD_IE_SIZE 255 ++/* structure for tdls wfd ie */ ++typedef struct tdls_wfd_ie_iovar { ++ struct ether_addr ea; /* Station address */ ++ uint8 mode; ++ uint8 length; ++ uint8 data[TDLS_WFD_IE_SIZE]; ++} tdls_wfd_ie_iovar_t; ++#endif /* WLTDLS */ ++ ++/* structure for addts/delts arguments */ ++typedef struct tspec_arg { ++ uint16 version; /* see definition of TSPEC_ARG_VERSION */ ++ uint16 length; /* length of entire structure */ ++ uint flag; /* bit field */ ++ /* TSPEC Arguments */ ++ struct tsinfo_arg tsinfo; /* TS Info bit field */ ++ uint16 nom_msdu_size; /* (Nominal or fixed) MSDU Size (bytes) */ ++ uint16 max_msdu_size; /* Maximum MSDU Size (bytes) */ ++ uint min_srv_interval; /* Minimum Service Interval (us) */ ++ uint max_srv_interval; /* Maximum Service Interval (us) */ ++ uint inactivity_interval; /* Inactivity Interval (us) */ ++ uint suspension_interval; /* Suspension Interval (us) */ ++ uint srv_start_time; /* Service Start Time (us) */ ++ uint min_data_rate; /* Minimum Data Rate (bps) */ ++ uint mean_data_rate; /* Mean Data Rate (bps) */ ++ uint peak_data_rate; /* Peak Data Rate (bps) */ ++ uint max_burst_size; /* Maximum Burst Size (bytes) */ ++ uint delay_bound; /* Delay Bound (us) */ ++ uint min_phy_rate; /* Minimum PHY Rate (bps) */ ++ uint16 surplus_bw; /* Surplus Bandwidth Allowance (range 1.0 to 8.0) */ ++ uint16 medium_time; /* Medium Time (32 us/s periods) */ ++ uint8 dialog_token; /* dialog token */ ++} tspec_arg_t; ++ ++/* tspec arg for desired station */ ++typedef struct tspec_per_sta_arg { ++ struct ether_addr ea; ++ struct tspec_arg ts; ++} tspec_per_sta_arg_t; ++ ++/* structure for max bandwidth for each access category */ ++typedef struct wme_max_bandwidth { ++ uint32 ac[AC_COUNT]; /* max bandwidth for each access category */ ++} wme_max_bandwidth_t; ++ ++#define WL_WME_MBW_PARAMS_IO_BYTES (sizeof(wme_max_bandwidth_t)) ++ ++/* current version of wl_tspec_arg_t struct */ ++#define TSPEC_ARG_VERSION 2 /* current version of wl_tspec_arg_t struct */ ++#define TSPEC_ARG_LENGTH 55 /* argument length from tsinfo to medium_time */ ++#define TSPEC_DEFAULT_DIALOG_TOKEN 42 /* default dialog token */ ++#define TSPEC_DEFAULT_SBW_FACTOR 0x3000 /* default surplus bw */ ++ ++ ++#define WL_WOWL_KEEPALIVE_MAX_PACKET_SIZE 80 ++#define WLC_WOWL_MAX_KEEPALIVE 2 ++ ++/* define for flag */ ++#define TSPEC_PENDING 0 /* TSPEC pending */ ++#define TSPEC_ACCEPTED 1 /* TSPEC accepted */ ++#define TSPEC_REJECTED 2 /* TSPEC rejected */ ++#define TSPEC_UNKNOWN 3 /* TSPEC unknown */ ++#define TSPEC_STATUS_MASK 7 /* TSPEC status mask */ ++ ++ ++/* Software feature flag defines used by wlfeatureflag */ ++#ifdef WLAFTERBURNER ++#define WL_SWFL_ABBFL 0x0001 /* Allow Afterburner on systems w/o hardware BFL */ ++#define WL_SWFL_ABENCORE 0x0002 /* Allow AB on non-4318E chips */ ++#endif /* WLAFTERBURNER */ ++#define WL_SWFL_NOHWRADIO 0x0004 ++#define WL_SWFL_FLOWCONTROL 0x0008 /* Enable backpressure to OS stack */ ++#define WL_SWFL_WLBSSSORT 0x0010 /* Per-port supports sorting of BSS */ ++ ++#define WL_LIFETIME_MAX 0xFFFF /* Max value in ms */ ++ ++/* Packet lifetime configuration per ac */ ++typedef struct wl_lifetime { ++ uint32 ac; /* access class */ ++ uint32 lifetime; /* Packet lifetime value in ms */ ++} wl_lifetime_t; ++ ++/* Channel Switch Announcement param */ ++typedef struct wl_chan_switch { ++ uint8 mode; /* value 0 or 1 */ ++ uint8 count; /* count # of beacons before switching */ ++ chanspec_t chspec; /* chanspec */ ++ uint8 reg; /* regulatory class */ ++} wl_chan_switch_t; ++ ++/* Roaming trigger definitions for WLC_SET_ROAM_TRIGGER. ++ * ++ * (-100 < value < 0) value is used directly as a roaming trigger in dBm ++ * (0 <= value) value specifies a logical roaming trigger level from ++ * the list below ++ * ++ * WLC_GET_ROAM_TRIGGER always returns roaming trigger value in dBm, never ++ * the logical roam trigger value. ++ */ ++#define WLC_ROAM_TRIGGER_DEFAULT 0 /* default roaming trigger */ ++#define WLC_ROAM_TRIGGER_BANDWIDTH 1 /* optimize for bandwidth roaming trigger */ ++#define WLC_ROAM_TRIGGER_DISTANCE 2 /* optimize for distance roaming trigger */ ++#define WLC_ROAM_TRIGGER_AUTO 3 /* auto-detect environment */ ++#define WLC_ROAM_TRIGGER_MAX_VALUE 3 /* max. valid value */ ++ ++#define WLC_ROAM_NEVER_ROAM_TRIGGER (-100) /* Avoid Roaming by setting a large value */ ++ ++/* Preferred Network Offload (PNO, formerly PFN) defines */ ++#define WPA_AUTH_PFN_ANY 0xffffffff /* for PFN, match only ssid */ ++ ++enum { ++ PFN_LIST_ORDER, ++ PFN_RSSI ++}; ++ ++enum { ++ DISABLE, ++ ENABLE ++}; ++ ++enum { ++ OFF_ADAPT, ++ SMART_ADAPT, ++ STRICT_ADAPT, ++ SLOW_ADAPT ++}; ++ ++#define SORT_CRITERIA_BIT 0 ++#define AUTO_NET_SWITCH_BIT 1 ++#define ENABLE_BKGRD_SCAN_BIT 2 ++#define IMMEDIATE_SCAN_BIT 3 ++#define AUTO_CONNECT_BIT 4 ++#define ENABLE_BD_SCAN_BIT 5 ++#define ENABLE_ADAPTSCAN_BIT 6 ++#define IMMEDIATE_EVENT_BIT 8 ++#define SUPPRESS_SSID_BIT 9 ++#define ENABLE_NET_OFFLOAD_BIT 10 ++ ++#define SORT_CRITERIA_MASK 0x0001 ++#define AUTO_NET_SWITCH_MASK 0x0002 ++#define ENABLE_BKGRD_SCAN_MASK 0x0004 ++#define IMMEDIATE_SCAN_MASK 0x0008 ++#define AUTO_CONNECT_MASK 0x0010 ++ ++#define ENABLE_BD_SCAN_MASK 0x0020 ++#define ENABLE_ADAPTSCAN_MASK 0x00c0 ++#define IMMEDIATE_EVENT_MASK 0x0100 ++#define SUPPRESS_SSID_MASK 0x0200 ++#define ENABLE_NET_OFFLOAD_MASK 0x0400 ++ ++#define PFN_VERSION 2 ++#define PFN_SCANRESULT_VERSION 1 ++#define MAX_PFN_LIST_COUNT 16 ++ ++#define PFN_COMPLETE 1 ++#define PFN_INCOMPLETE 0 ++ ++#define DEFAULT_BESTN 2 ++#define DEFAULT_MSCAN 0 ++#define DEFAULT_REPEAT 10 ++#define DEFAULT_EXP 2 ++ ++/* PFN network info structure */ ++typedef struct wl_pfn_subnet_info { ++ struct ether_addr BSSID; ++ uint8 channel; /* channel number only */ ++ uint8 SSID_len; ++ uint8 SSID[32]; ++} wl_pfn_subnet_info_t; ++ ++typedef struct wl_pfn_net_info { ++ wl_pfn_subnet_info_t pfnsubnet; ++ int16 RSSI; /* receive signal strength (in dBm) */ ++ uint16 timestamp; /* age in seconds */ ++} wl_pfn_net_info_t; ++ ++typedef struct wl_pfn_scanresults { ++ uint32 version; ++ uint32 status; ++ uint32 count; ++ wl_pfn_net_info_t netinfo[1]; ++} wl_pfn_scanresults_t; ++ ++/* PFN data structure */ ++typedef struct wl_pfn_param { ++ int32 version; /* PNO parameters version */ ++ int32 scan_freq; /* Scan frequency */ ++ int32 lost_network_timeout; /* Timeout in sec. to declare ++ * discovered network as lost ++ */ ++ int16 flags; /* Bit field to control features ++ * of PFN such as sort criteria auto ++ * enable switch and background scan ++ */ ++ int16 rssi_margin; /* Margin to avoid jitter for choosing a ++ * PFN based on RSSI sort criteria ++ */ ++ uint8 bestn; /* number of best networks in each scan */ ++ uint8 mscan; /* number of scans recorded */ ++ uint8 repeat; /* Minimum number of scan intervals ++ *before scan frequency changes in adaptive scan ++ */ ++ uint8 exp; /* Exponent of 2 for maximum scan interval */ ++ int32 slow_freq; /* slow scan period */ ++} wl_pfn_param_t; ++ ++typedef struct wl_pfn_bssid { ++ struct ether_addr macaddr; ++ /* Bit4: suppress_lost, Bit3: suppress_found */ ++ uint16 flags; ++} wl_pfn_bssid_t; ++#define WL_PFN_SUPPRESSFOUND_MASK 0x08 ++#define WL_PFN_SUPPRESSLOST_MASK 0x10 ++ ++typedef struct wl_pfn_cfg { ++ uint32 reporttype; ++ int32 channel_num; ++ uint16 channel_list[WL_NUMCHANNELS]; ++} wl_pfn_cfg_t; ++#define WL_PFN_REPORT_ALLNET 0 ++#define WL_PFN_REPORT_SSIDNET 1 ++#define WL_PFN_REPORT_BSSIDNET 2 ++ ++typedef struct wl_pfn { ++ wlc_ssid_t ssid; /* ssid name and its length */ ++ int32 flags; /* bit2: hidden */ ++ int32 infra; /* BSS Vs IBSS */ ++ int32 auth; /* Open Vs Closed */ ++ int32 wpa_auth; /* WPA type */ ++ int32 wsec; /* wsec value */ ++} wl_pfn_t; ++#define WL_PFN_HIDDEN_BIT 2 ++#define PNO_SCAN_MAX_FW 508*1000 /* max time scan time in msec */ ++#define PNO_SCAN_MAX_FW_SEC PNO_SCAN_MAX_FW/1000 /* max time scan time in SEC */ ++#define PNO_SCAN_MIN_FW_SEC 10 /* min time scan time in SEC */ ++#define WL_PFN_HIDDEN_MASK 0x4 ++ ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++/* TCP Checksum Offload defines */ ++#define TOE_TX_CSUM_OL 0x00000001 ++#define TOE_RX_CSUM_OL 0x00000002 ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++/* TCP Checksum Offload error injection for testing */ ++#define TOE_ERRTEST_TX_CSUM 0x00000001 ++#define TOE_ERRTEST_RX_CSUM 0x00000002 ++#define TOE_ERRTEST_RX_CSUM2 0x00000004 ++ ++struct toe_ol_stats_t { ++ /* Num of tx packets that don't need to be checksummed */ ++ uint32 tx_summed; ++ ++ /* Num of tx packets where checksum is filled by offload engine */ ++ uint32 tx_iph_fill; ++ uint32 tx_tcp_fill; ++ uint32 tx_udp_fill; ++ uint32 tx_icmp_fill; ++ ++ /* Num of rx packets where toe finds out if checksum is good or bad */ ++ uint32 rx_iph_good; ++ uint32 rx_iph_bad; ++ uint32 rx_tcp_good; ++ uint32 rx_tcp_bad; ++ uint32 rx_udp_good; ++ uint32 rx_udp_bad; ++ uint32 rx_icmp_good; ++ uint32 rx_icmp_bad; ++ ++ /* Num of tx packets in which csum error is injected */ ++ uint32 tx_tcp_errinj; ++ uint32 tx_udp_errinj; ++ uint32 tx_icmp_errinj; ++ ++ /* Num of rx packets in which csum error is injected */ ++ uint32 rx_tcp_errinj; ++ uint32 rx_udp_errinj; ++ uint32 rx_icmp_errinj; ++}; ++ ++/* ARP Offload feature flags for arp_ol iovar */ ++#define ARP_OL_AGENT 0x00000001 ++#define ARP_OL_SNOOP 0x00000002 ++#define ARP_OL_HOST_AUTO_REPLY 0x00000004 ++#define ARP_OL_PEER_AUTO_REPLY 0x00000008 ++ ++/* ARP Offload error injection */ ++#define ARP_ERRTEST_REPLY_PEER 0x1 ++#define ARP_ERRTEST_REPLY_HOST 0x2 ++ ++#define ARP_MULTIHOMING_MAX 8 /* Maximum local host IP addresses */ ++#define ND_MULTIHOMING_MAX 8 /* Maximum local host IP addresses */ ++ ++/* Arp offload statistic counts */ ++struct arp_ol_stats_t { ++ uint32 host_ip_entries; /* Host IP table addresses (more than one if multihomed) */ ++ uint32 host_ip_overflow; /* Host IP table additions skipped due to overflow */ ++ ++ uint32 arp_table_entries; /* ARP table entries */ ++ uint32 arp_table_overflow; /* ARP table additions skipped due to overflow */ ++ ++ uint32 host_request; /* ARP requests from host */ ++ uint32 host_reply; /* ARP replies from host */ ++ uint32 host_service; /* ARP requests from host serviced by ARP Agent */ ++ ++ uint32 peer_request; /* ARP requests received from network */ ++ uint32 peer_request_drop; /* ARP requests from network that were dropped */ ++ uint32 peer_reply; /* ARP replies received from network */ ++ uint32 peer_reply_drop; /* ARP replies from network that were dropped */ ++ uint32 peer_service; /* ARP request from host serviced by ARP Agent */ ++}; ++ ++/* NS offload statistic counts */ ++struct nd_ol_stats_t { ++ uint32 host_ip_entries; /* Host IP table addresses (more than one if multihomed) */ ++ uint32 host_ip_overflow; /* Host IP table additions skipped due to overflow */ ++ uint32 peer_request; /* NS requests received from network */ ++ uint32 peer_request_drop; /* NS requests from network that were dropped */ ++ uint32 peer_reply_drop; /* NA replies from network that were dropped */ ++ uint32 peer_service; /* NS request from host serviced by firmware */ ++}; ++ ++/* ++ * Keep-alive packet offloading. ++ */ ++ ++/* NAT keep-alive packets format: specifies the re-transmission period, the packet ++ * length, and packet contents. ++ */ ++typedef struct wl_keep_alive_pkt { ++ uint32 period_msec; /* Retransmission period (0 to disable packet re-transmits) */ ++ uint16 len_bytes; /* Size of packet to transmit (0 to disable packet re-transmits) */ ++ uint8 data[1]; /* Variable length packet to transmit. Contents should include ++ * entire ethernet packet (enet header, IP header, UDP header, ++ * and UDP payload) in network byte order. ++ */ ++} wl_keep_alive_pkt_t; ++ ++#define WL_KEEP_ALIVE_FIXED_LEN OFFSETOF(wl_keep_alive_pkt_t, data) ++ ++/* ++ * Dongle pattern matching filter. ++ */ ++ ++/* Packet filter types. Currently, only pattern matching is supported. */ ++typedef enum wl_pkt_filter_type { ++ WL_PKT_FILTER_TYPE_PATTERN_MATCH /* Pattern matching filter */ ++} wl_pkt_filter_type_t; ++ ++#define WL_PKT_FILTER_TYPE wl_pkt_filter_type_t ++ ++/* Pattern matching filter. Specifies an offset within received packets to ++ * start matching, the pattern to match, the size of the pattern, and a bitmask ++ * that indicates which bits within the pattern should be matched. ++ */ ++typedef struct wl_pkt_filter_pattern { ++ uint32 offset; /* Offset within received packet to start pattern matching. ++ * Offset '0' is the first byte of the ethernet header. ++ */ ++ uint32 size_bytes; /* Size of the pattern. Bitmask must be the same size. */ ++ uint8 mask_and_pattern[1]; /* Variable length mask and pattern data. mask starts ++ * at offset 0. Pattern immediately follows mask. ++ */ ++} wl_pkt_filter_pattern_t; ++ ++/* IOVAR "pkt_filter_add" parameter. Used to install packet filters. */ ++typedef struct wl_pkt_filter { ++ uint32 id; /* Unique filter id, specified by app. */ ++ uint32 type; /* Filter type (WL_PKT_FILTER_TYPE_xxx). */ ++ uint32 negate_match; /* Negate the result of filter matches */ ++ union { /* Filter definitions */ ++ wl_pkt_filter_pattern_t pattern; /* Pattern matching filter */ ++ } u; ++} wl_pkt_filter_t; ++ ++#define WL_PKT_FILTER_FIXED_LEN OFFSETOF(wl_pkt_filter_t, u) ++#define WL_PKT_FILTER_PATTERN_FIXED_LEN OFFSETOF(wl_pkt_filter_pattern_t, mask_and_pattern) ++ ++/* IOVAR "pkt_filter_enable" parameter. */ ++typedef struct wl_pkt_filter_enable { ++ uint32 id; /* Unique filter id */ ++ uint32 enable; /* Enable/disable bool */ ++} wl_pkt_filter_enable_t; ++ ++/* IOVAR "pkt_filter_list" parameter. Used to retrieve a list of installed filters. */ ++typedef struct wl_pkt_filter_list { ++ uint32 num; /* Number of installed packet filters */ ++ wl_pkt_filter_t filter[1]; /* Variable array of packet filters. */ ++} wl_pkt_filter_list_t; ++ ++#define WL_PKT_FILTER_LIST_FIXED_LEN OFFSETOF(wl_pkt_filter_list_t, filter) ++ ++/* IOVAR "pkt_filter_stats" parameter. Used to retrieve debug statistics. */ ++typedef struct wl_pkt_filter_stats { ++ uint32 num_pkts_matched; /* # filter matches for specified filter id */ ++ uint32 num_pkts_forwarded; /* # packets fwded from dongle to host for all filters */ ++ uint32 num_pkts_discarded; /* # packets discarded by dongle for all filters */ ++} wl_pkt_filter_stats_t; ++ ++/* Sequential Commands ioctl */ ++typedef struct wl_seq_cmd_ioctl { ++ uint32 cmd; /* common ioctl definition */ ++ uint32 len; /* length of user buffer */ ++} wl_seq_cmd_ioctl_t; ++ ++#define WL_SEQ_CMD_ALIGN_BYTES 4 ++ ++/* These are the set of get IOCTLs that should be allowed when using ++ * IOCTL sequence commands. These are issued implicitly by wl.exe each time ++ * it is invoked. We never want to buffer these, or else wl.exe will stop working. ++ */ ++#define WL_SEQ_CMDS_GET_IOCTL_FILTER(cmd) \ ++ (((cmd) == WLC_GET_MAGIC) || \ ++ ((cmd) == WLC_GET_VERSION) || \ ++ ((cmd) == WLC_GET_AP) || \ ++ ((cmd) == WLC_GET_INSTANCE)) ++ ++/* ++ * Packet engine interface ++ */ ++ ++#define WL_PKTENG_PER_TX_START 0x01 ++#define WL_PKTENG_PER_TX_STOP 0x02 ++#define WL_PKTENG_PER_RX_START 0x04 ++#define WL_PKTENG_PER_RX_WITH_ACK_START 0x05 ++#define WL_PKTENG_PER_TX_WITH_ACK_START 0x06 ++#define WL_PKTENG_PER_RX_STOP 0x08 ++#define WL_PKTENG_PER_MASK 0xff ++ ++#define WL_PKTENG_SYNCHRONOUS 0x100 /* synchronous flag */ ++ ++typedef struct wl_pkteng { ++ uint32 flags; ++ uint32 delay; /* Inter-packet delay */ ++ uint32 nframes; /* Number of frames */ ++ uint32 length; /* Packet length */ ++ uint8 seqno; /* Enable/disable sequence no. */ ++ struct ether_addr dest; /* Destination address */ ++ struct ether_addr src; /* Source address */ ++} wl_pkteng_t; ++ ++#define NUM_80211b_RATES 4 ++#define NUM_80211ag_RATES 8 ++#define NUM_80211n_RATES 32 ++#define NUM_80211_RATES (NUM_80211b_RATES+NUM_80211ag_RATES+NUM_80211n_RATES) ++typedef struct wl_pkteng_stats { ++ uint32 lostfrmcnt; /* RX PER test: no of frames lost (skip seqno) */ ++ int32 rssi; /* RSSI */ ++ int32 snr; /* signal to noise ratio */ ++ uint16 rxpktcnt[NUM_80211_RATES+1]; ++} wl_pkteng_stats_t; ++ ++ ++#define WL_WOWL_MAGIC (1 << 0) /* Wakeup on Magic packet */ ++#define WL_WOWL_NET (1 << 1) /* Wakeup on Netpattern */ ++#define WL_WOWL_DIS (1 << 2) /* Wakeup on loss-of-link due to Disassoc/Deauth */ ++#define WL_WOWL_RETR (1 << 3) /* Wakeup on retrograde TSF */ ++#define WL_WOWL_BCN (1 << 4) /* Wakeup on loss of beacon */ ++#define WL_WOWL_TST (1 << 5) /* Wakeup after test */ ++#define WL_WOWL_M1 (1 << 6) /* Wakeup after PTK refresh */ ++#define WL_WOWL_EAPID (1 << 7) /* Wakeup after receipt of EAP-Identity Req */ ++#define WL_WOWL_PME_GPIO (1 << 8) /* Wakeind via PME(0) or GPIO(1) */ ++#define WL_WOWL_NEEDTKIP1 (1 << 9) /* need tkip phase 1 key to be updated by the driver */ ++#define WL_WOWL_GTK_FAILURE (1 << 10) /* enable wakeup if GTK fails */ ++#define WL_WOWL_EXTMAGPAT (1 << 11) /* support extended magic packets */ ++#define WL_WOWL_ARPOFFLOAD (1 << 12) /* support ARP/NS/keepalive offloading */ ++#define WL_WOWL_WPA2 (1 << 13) /* read protocol version for EAPOL frames */ ++#define WL_WOWL_KEYROT (1 << 14) /* If the bit is set, use key rotaton */ ++#define WL_WOWL_BCAST (1 << 15) /* If the bit is set, frm received was bcast frame */ ++ ++#define MAGIC_PKT_MINLEN 102 /* Magic pkt min length is 6 * 0xFF + 16 * ETHER_ADDR_LEN */ ++ ++#define WOWL_PATTEN_TYPE_ARP (1 << 0) /* ARP offload Pattern */ ++#define WOWL_PATTEN_TYPE_NA (1 << 1) /* NA offload Pattern */ ++ ++typedef struct { ++ uint32 masksize; /* Size of the mask in #of bytes */ ++ uint32 offset; /* Offset to start looking for the packet in # of bytes */ ++ uint32 patternoffset; /* Offset of start of pattern in the structure */ ++ uint32 patternsize; /* Size of the pattern itself in #of bytes */ ++ uint32 id; /* id */ ++ uint32 reasonsize; /* Size of the wakeup reason code */ ++ uint32 flags; /* Flags to tell the pattern type and other properties */ ++ /* Mask follows the structure above */ ++ /* Pattern follows the mask is at 'patternoffset' from the start */ ++} wl_wowl_pattern_t; ++ ++typedef struct { ++ uint count; ++ wl_wowl_pattern_t pattern[1]; ++} wl_wowl_pattern_list_t; ++ ++typedef struct { ++ uint8 pci_wakeind; /* Whether PCI PMECSR PMEStatus bit was set */ ++ uint16 ucode_wakeind; /* What wakeup-event indication was set by ucode */ ++} wl_wowl_wakeind_t; ++ ++ ++/* per AC rate control related data structure */ ++typedef struct wl_txrate_class { ++ uint8 init_rate; ++ uint8 min_rate; ++ uint8 max_rate; ++} wl_txrate_class_t; ++ ++ ++ ++/* Overlap BSS Scan parameters default, minimum, maximum */ ++#define WLC_OBSS_SCAN_PASSIVE_DWELL_DEFAULT 20 /* unit TU */ ++#define WLC_OBSS_SCAN_PASSIVE_DWELL_MIN 5 /* unit TU */ ++#define WLC_OBSS_SCAN_PASSIVE_DWELL_MAX 1000 /* unit TU */ ++#define WLC_OBSS_SCAN_ACTIVE_DWELL_DEFAULT 10 /* unit TU */ ++#define WLC_OBSS_SCAN_ACTIVE_DWELL_MIN 10 /* unit TU */ ++#define WLC_OBSS_SCAN_ACTIVE_DWELL_MAX 1000 /* unit TU */ ++#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_DEFAULT 300 /* unit Sec */ ++#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MIN 10 /* unit Sec */ ++#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MAX 900 /* unit Sec */ ++#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_DEFAULT 5 ++#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MIN 5 ++#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MAX 100 ++#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_DEFAULT 200 /* unit TU */ ++#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MIN 200 /* unit TU */ ++#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MAX 10000 /* unit TU */ ++#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_DEFAULT 20 /* unit TU */ ++#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MIN 20 /* unit TU */ ++#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MAX 10000 /* unit TU */ ++#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_DEFAULT 25 /* unit percent */ ++#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MIN 0 /* unit percent */ ++#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MAX 100 /* unit percent */ ++ ++/* structure for Overlap BSS scan arguments */ ++typedef struct wl_obss_scan_arg { ++ int16 passive_dwell; ++ int16 active_dwell; ++ int16 bss_widthscan_interval; ++ int16 passive_total; ++ int16 active_total; ++ int16 chanwidth_transition_delay; ++ int16 activity_threshold; ++} wl_obss_scan_arg_t; ++ ++#define WL_OBSS_SCAN_PARAM_LEN sizeof(wl_obss_scan_arg_t) ++#define WL_MIN_NUM_OBSS_SCAN_ARG 7 /* minimum number of arguments required for OBSS Scan */ ++ ++#define WL_COEX_INFO_MASK 0x07 ++#define WL_COEX_INFO_REQ 0x01 ++#define WL_COEX_40MHZ_INTOLERANT 0x02 ++#define WL_COEX_WIDTH20 0x04 ++ ++#define WLC_RSSI_INVALID 0 /* invalid RSSI value */ ++ ++#define MAX_RSSI_LEVELS 8 ++ ++/* RSSI event notification configuration. */ ++typedef struct wl_rssi_event { ++ uint32 rate_limit_msec; /* # of events posted to application will be limited to ++ * one per specified period (0 to disable rate limit). ++ */ ++ uint8 num_rssi_levels; /* Number of entries in rssi_levels[] below */ ++ int8 rssi_levels[MAX_RSSI_LEVELS]; /* Variable number of RSSI levels. An event ++ * will be posted each time the RSSI of received ++ * beacons/packets crosses a level. ++ */ ++} wl_rssi_event_t; ++ ++typedef struct wl_action_obss_coex_req { ++ uint8 info; ++ uint8 num; ++ uint8 ch_list[1]; ++} wl_action_obss_coex_req_t; ++ ++ ++/* IOVar parameter block for small MAC address array with type indicator */ ++#define WL_IOV_MAC_PARAM_LEN 4 ++ ++#define WL_IOV_PKTQ_LOG_PRECS 16 ++ ++typedef struct { ++ uint32 num_addrs; ++ char addr_type[WL_IOV_MAC_PARAM_LEN]; ++ struct ether_addr ea[WL_IOV_MAC_PARAM_LEN]; ++} wl_iov_mac_params_t; ++ ++ ++/* Parameter block for PKTQ_LOG statistics */ ++typedef struct { ++ uint32 requested; /* packets requested to be stored */ ++ uint32 stored; /* packets stored */ ++ uint32 saved; /* packets saved, ++ because a lowest priority queue has given away one packet ++ */ ++ uint32 selfsaved; /* packets saved, ++ because an older packet from the same queue has been dropped ++ */ ++ uint32 full_dropped; /* packets dropped, ++ because pktq is full with higher precedence packets ++ */ ++ uint32 dropped; /* packets dropped because pktq per that precedence is full */ ++ uint32 sacrificed; /* packets dropped, ++ in order to save one from a queue of a highest priority ++ */ ++ uint32 busy; /* packets droped because of hardware/transmission error */ ++ uint32 retry; /* packets re-sent because they were not received */ ++ uint32 ps_retry; /* packets retried again prior to moving power save mode */ ++ uint32 retry_drop; /* packets finally dropped after retry limit */ ++ uint32 max_avail; /* the high-water mark of the queue capacity for packets - ++ goes to zero as queue fills ++ */ ++ uint32 max_used; /* the high-water mark of the queue utilisation for packets - ++ increases with use ('inverse' of max_avail) ++ */ ++ uint32 queue_capacity; /* the maximum capacity of the queue */ ++} pktq_log_counters_v01_t; ++ ++#define sacrified sacrificed ++ ++typedef struct { ++ uint8 num_prec[WL_IOV_MAC_PARAM_LEN]; ++ pktq_log_counters_v01_t counters[WL_IOV_MAC_PARAM_LEN][WL_IOV_PKTQ_LOG_PRECS]; ++ char headings[1]; ++} pktq_log_format_v01_t; ++ ++ ++typedef struct { ++ uint32 version; ++ wl_iov_mac_params_t params; ++ union { ++ pktq_log_format_v01_t v01; ++ } pktq_log; ++} wl_iov_pktq_log_t; ++ ++ ++/* **** EXTLOG **** */ ++#define EXTLOG_CUR_VER 0x0100 ++ ++#define MAX_ARGSTR_LEN 18 /* At least big enough for storing ETHER_ADDR_STR_LEN */ ++ ++/* log modules (bitmap) */ ++#define LOG_MODULE_COMMON 0x0001 ++#define LOG_MODULE_ASSOC 0x0002 ++#define LOG_MODULE_EVENT 0x0004 ++#define LOG_MODULE_MAX 3 /* Update when adding module */ ++ ++/* log levels */ ++#define WL_LOG_LEVEL_DISABLE 0 ++#define WL_LOG_LEVEL_ERR 1 ++#define WL_LOG_LEVEL_WARN 2 ++#define WL_LOG_LEVEL_INFO 3 ++#define WL_LOG_LEVEL_MAX WL_LOG_LEVEL_INFO /* Update when adding level */ ++ ++/* flag */ ++#define LOG_FLAG_EVENT 1 ++ ++/* log arg_type */ ++#define LOG_ARGTYPE_NULL 0 ++#define LOG_ARGTYPE_STR 1 /* %s */ ++#define LOG_ARGTYPE_INT 2 /* %d */ ++#define LOG_ARGTYPE_INT_STR 3 /* %d...%s */ ++#define LOG_ARGTYPE_STR_INT 4 /* %s...%d */ ++ ++typedef struct wlc_extlog_cfg { ++ int max_number; ++ uint16 module; /* bitmap */ ++ uint8 level; ++ uint8 flag; ++ uint16 version; ++} wlc_extlog_cfg_t; ++ ++typedef struct log_record { ++ uint32 time; ++ uint16 module; ++ uint16 id; ++ uint8 level; ++ uint8 sub_unit; ++ uint8 seq_num; ++ int32 arg; ++ char str[MAX_ARGSTR_LEN]; ++} log_record_t; ++ ++typedef struct wlc_extlog_req { ++ uint32 from_last; ++ uint32 num; ++} wlc_extlog_req_t; ++ ++typedef struct wlc_extlog_results { ++ uint16 version; ++ uint16 record_len; ++ uint32 num; ++ log_record_t logs[1]; ++} wlc_extlog_results_t; ++ ++typedef struct log_idstr { ++ uint16 id; ++ uint16 flag; ++ uint8 arg_type; ++ const char *fmt_str; ++} log_idstr_t; ++ ++#define FMTSTRF_USER 1 ++ ++/* flat ID definitions ++ * New definitions HAVE TO BE ADDED at the end of the table. Otherwise, it will ++ * affect backward compatibility with pre-existing apps ++ */ ++typedef enum { ++ FMTSTR_DRIVER_UP_ID = 0, ++ FMTSTR_DRIVER_DOWN_ID = 1, ++ FMTSTR_SUSPEND_MAC_FAIL_ID = 2, ++ FMTSTR_NO_PROGRESS_ID = 3, ++ FMTSTR_RFDISABLE_ID = 4, ++ FMTSTR_REG_PRINT_ID = 5, ++ FMTSTR_EXPTIME_ID = 6, ++ FMTSTR_JOIN_START_ID = 7, ++ FMTSTR_JOIN_COMPLETE_ID = 8, ++ FMTSTR_NO_NETWORKS_ID = 9, ++ FMTSTR_SECURITY_MISMATCH_ID = 10, ++ FMTSTR_RATE_MISMATCH_ID = 11, ++ FMTSTR_AP_PRUNED_ID = 12, ++ FMTSTR_KEY_INSERTED_ID = 13, ++ FMTSTR_DEAUTH_ID = 14, ++ FMTSTR_DISASSOC_ID = 15, ++ FMTSTR_LINK_UP_ID = 16, ++ FMTSTR_LINK_DOWN_ID = 17, ++ FMTSTR_RADIO_HW_OFF_ID = 18, ++ FMTSTR_RADIO_HW_ON_ID = 19, ++ FMTSTR_EVENT_DESC_ID = 20, ++ FMTSTR_PNP_SET_POWER_ID = 21, ++ FMTSTR_RADIO_SW_OFF_ID = 22, ++ FMTSTR_RADIO_SW_ON_ID = 23, ++ FMTSTR_PWD_MISMATCH_ID = 24, ++ FMTSTR_FATAL_ERROR_ID = 25, ++ FMTSTR_AUTH_FAIL_ID = 26, ++ FMTSTR_ASSOC_FAIL_ID = 27, ++ FMTSTR_IBSS_FAIL_ID = 28, ++ FMTSTR_EXTAP_FAIL_ID = 29, ++ FMTSTR_MAX_ID ++} log_fmtstr_id_t; ++ ++#ifdef DONGLEOVERLAYS ++typedef struct { ++ uint32 flags_idx; /* lower 8 bits: overlay index; upper 24 bits: flags */ ++ uint32 offset; /* offset into overlay region to write code */ ++ uint32 len; /* overlay code len */ ++ /* overlay code follows this struct */ ++} wl_ioctl_overlay_t; ++ ++#define OVERLAY_IDX_MASK 0x000000ff ++#define OVERLAY_IDX_SHIFT 0 ++#define OVERLAY_FLAGS_MASK 0xffffff00 ++#define OVERLAY_FLAGS_SHIFT 8 ++/* overlay written to device memory immediately after loading the base image */ ++#define OVERLAY_FLAG_POSTLOAD 0x100 ++/* defer overlay download until the device responds w/WLC_E_OVL_DOWNLOAD event */ ++#define OVERLAY_FLAG_DEFER_DL 0x200 ++/* overlay downloaded prior to the host going to sleep */ ++#define OVERLAY_FLAG_PRESLEEP 0x400 ++ ++#define OVERLAY_DOWNLOAD_CHUNKSIZE 1024 ++#endif /* DONGLEOVERLAYS */ ++ ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++/* no default structure packing */ ++#include ++ ++/* require strict packing */ ++#include ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++ ++/* Structures and constants used for "vndr_ie" IOVar interface */ ++#define VNDR_IE_CMD_LEN 4 /* length of the set command string: ++ * "add", "del" (+ NUL) ++ */ ++ ++/* 802.11 Mgmt Packet flags */ ++#define VNDR_IE_BEACON_FLAG 0x1 ++#define VNDR_IE_PRBRSP_FLAG 0x2 ++#define VNDR_IE_ASSOCRSP_FLAG 0x4 ++#define VNDR_IE_AUTHRSP_FLAG 0x8 ++#define VNDR_IE_PRBREQ_FLAG 0x10 ++#define VNDR_IE_ASSOCREQ_FLAG 0x20 ++#define VNDR_IE_IWAPID_FLAG 0x40 /* vendor IE in IW advertisement protocol ID field */ ++#define VNDR_IE_CUSTOM_FLAG 0x100 /* allow custom IE id */ ++ ++#define VNDR_IE_INFO_HDR_LEN (sizeof(uint32)) ++ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint32 pktflag; /* bitmask indicating which packet(s) contain this IE */ ++ vndr_ie_t vndr_ie_data; /* vendor IE data */ ++} BWL_POST_PACKED_STRUCT vndr_ie_info_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ int iecount; /* number of entries in the vndr_ie_list[] array */ ++ vndr_ie_info_t vndr_ie_list[1]; /* variable size list of vndr_ie_info_t structs */ ++} BWL_POST_PACKED_STRUCT vndr_ie_buf_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ char cmd[VNDR_IE_CMD_LEN]; /* vndr_ie IOVar set command : "add", "del" + NUL */ ++ vndr_ie_buf_t vndr_ie_buffer; /* buffer containing Vendor IE list information */ ++} BWL_POST_PACKED_STRUCT vndr_ie_setbuf_t; ++ ++/* tag_ID/length/value_buffer tuple */ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint8 id; ++ uint8 len; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT tlv_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint32 pktflag; /* bitmask indicating which packet(s) contain this IE */ ++ tlv_t ie_data; /* IE data */ ++} BWL_POST_PACKED_STRUCT ie_info_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ int iecount; /* number of entries in the ie_list[] array */ ++ ie_info_t ie_list[1]; /* variable size list of ie_info_t structs */ ++} BWL_POST_PACKED_STRUCT ie_buf_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ char cmd[VNDR_IE_CMD_LEN]; /* ie IOVar set command : "add" + NUL */ ++ ie_buf_t ie_buffer; /* buffer containing IE list information */ ++} BWL_POST_PACKED_STRUCT ie_setbuf_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint32 pktflag; /* bitmask indicating which packet(s) contain this IE */ ++ uint8 id; /* IE type */ ++} BWL_POST_PACKED_STRUCT ie_getbuf_t; ++ ++/* structures used to define format of wps ie data from probe requests */ ++/* passed up to applications via iovar "prbreq_wpsie" */ ++typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_hdr { ++ struct ether_addr staAddr; ++ uint16 ieLen; ++} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_hdr_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_data { ++ sta_prbreq_wps_ie_hdr_t hdr; ++ uint8 ieData[1]; ++} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_data_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_list { ++ uint32 totLen; ++ uint8 ieDataList[1]; ++} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_list_t; ++ ++ ++#ifdef WLMEDIA_TXFAILEVENT ++typedef BWL_PRE_PACKED_STRUCT struct { ++ char dest[ETHER_ADDR_LEN]; /* destination MAC */ ++ uint8 prio; /* Packet Priority */ ++ uint8 flags; /* Flags */ ++ uint32 tsf_l; /* TSF timer low */ ++ uint32 tsf_h; /* TSF timer high */ ++ uint16 rates; /* Main Rates */ ++ uint16 txstatus; /* TX Status */ ++} BWL_POST_PACKED_STRUCT txfailinfo_t; ++#endif /* WLMEDIA_TXFAILEVENT */ ++ ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++/* no strict structure packing */ ++#include ++ ++#ifdef BCMWAPI_WAI ++#define IV_LEN 16 /* XXX, same as SMS4_WPI_PN_LEN */ ++struct wapi_sta_msg_t ++{ ++ uint16 msg_type; ++ uint16 datalen; ++ uint8 vap_mac[6]; ++ uint8 reserve_data1[2]; ++ uint8 sta_mac[6]; ++ uint8 reserve_data2[2]; ++ uint8 gsn[IV_LEN]; ++ uint8 wie[256]; ++}; ++#endif /* BCMWAPI_WAI */ ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++/* Global ASSERT Logging */ ++#define ASSERTLOG_CUR_VER 0x0100 ++#define MAX_ASSRTSTR_LEN 64 ++ ++typedef struct assert_record { ++ uint32 time; ++ uint8 seq_num; ++ char str[MAX_ASSRTSTR_LEN]; ++} assert_record_t; ++ ++typedef struct assertlog_results { ++ uint16 version; ++ uint16 record_len; ++ uint32 num; ++ assert_record_t logs[1]; ++} assertlog_results_t; ++ ++#define LOGRRC_FIX_LEN 8 ++#define IOBUF_ALLOWED_NUM_OF_LOGREC(type, len) ((len - LOGRRC_FIX_LEN)/sizeof(type)) ++ ++ ++/* channel interference measurement (chanim) related defines */ ++ ++/* chanim mode */ ++#define CHANIM_DISABLE 0 /* disabled */ ++#define CHANIM_DETECT 1 /* detection only */ ++#define CHANIM_EXT 2 /* external state machine */ ++#define CHANIM_ACT 3 /* full internal state machine, detect + act */ ++#define CHANIM_MODE_MAX 4 ++ ++/* define for apcs reason code */ ++#define APCS_INIT 0 ++#define APCS_IOCTL 1 ++#define APCS_CHANIM 2 ++#define APCS_CSTIMER 3 ++#define APCS_BTA 4 ++ ++/* number of ACS record entries */ ++#define CHANIM_ACS_RECORD 10 ++ ++/* CHANIM */ ++#define CCASTATS_TXDUR 0 ++#define CCASTATS_INBSS 1 ++#define CCASTATS_OBSS 2 ++#define CCASTATS_NOCTG 3 ++#define CCASTATS_NOPKT 4 ++#define CCASTATS_DOZE 5 ++#define CCASTATS_TXOP 6 ++#define CCASTATS_GDTXDUR 7 ++#define CCASTATS_BDTXDUR 8 ++#define CCASTATS_MAX 9 ++ ++/* chanim acs record */ ++typedef struct { ++ bool valid; ++ uint8 trigger; ++ chanspec_t selected_chspc; ++ int8 bgnoise; ++ uint32 glitch_cnt; ++ uint8 ccastats; ++ uint timestamp; ++} chanim_acs_record_t; ++ ++typedef struct { ++ chanim_acs_record_t acs_record[CHANIM_ACS_RECORD]; ++ uint8 count; ++ uint timestamp; ++} wl_acs_record_t; ++ ++typedef struct chanim_stats { ++ uint32 glitchcnt; /* normalized as per second count */ ++ uint32 badplcp; /* normalized as per second count */ ++ uint8 ccastats[CCASTATS_MAX]; /* normalized as 0-255 */ ++ int8 bgnoise; /* background noise level (in dBm) */ ++ chanspec_t chanspec; ++ uint32 timestamp; ++} chanim_stats_t; ++ ++#define WL_CHANIM_STATS_VERSION 1 ++#define WL_CHANIM_COUNT_ALL 0xff ++#define WL_CHANIM_COUNT_ONE 0x1 ++ ++typedef struct { ++ uint32 buflen; ++ uint32 version; ++ uint32 count; ++ chanim_stats_t stats[1]; ++} wl_chanim_stats_t; ++ ++#define WL_CHANIM_STATS_FIXED_LEN OFFSETOF(wl_chanim_stats_t, stats) ++ ++/* Noise measurement metrics. */ ++#define NOISE_MEASURE_KNOISE 0x1 ++ ++/* scb probe parameter */ ++typedef struct { ++ uint32 scb_timeout; ++ uint32 scb_activity_time; ++ uint32 scb_max_probe; ++} wl_scb_probe_t; ++ ++/* ap tpc modes */ ++#define AP_TPC_OFF 0 ++#define AP_TPC_BSS_PWR 1 /* BSS power control */ ++#define AP_TPC_AP_PWR 2 /* AP power control */ ++#define AP_TPC_AP_BSS_PWR 3 /* Both AP and BSS power control */ ++#define AP_TPC_MAX_LINK_MARGIN 127 ++ ++/* ap tpc modes */ ++#define AP_TPC_OFF 0 ++#define AP_TPC_BSS_PWR 1 /* BSS power control */ ++#define AP_TPC_AP_PWR 2 /* AP power control */ ++#define AP_TPC_AP_BSS_PWR 3 /* Both AP and BSS power control */ ++#define AP_TPC_MAX_LINK_MARGIN 127 ++ ++/* structure/defines for selective mgmt frame (smf) stats support */ ++ ++#define SMFS_VERSION 1 ++/* selected mgmt frame (smf) stats element */ ++typedef struct wl_smfs_elem { ++ uint32 count; ++ uint16 code; /* SC or RC code */ ++} wl_smfs_elem_t; ++ ++typedef struct wl_smf_stats { ++ uint32 version; ++ uint16 length; /* reserved for future usage */ ++ uint8 type; ++ uint8 codetype; ++ uint32 ignored_cnt; ++ uint32 malformed_cnt; ++ uint32 count_total; /* count included the interested group */ ++ wl_smfs_elem_t elem[1]; ++} wl_smf_stats_t; ++ ++#define WL_SMFSTATS_FIXED_LEN OFFSETOF(wl_smf_stats_t, elem); ++ ++enum { ++ SMFS_CODETYPE_SC, ++ SMFS_CODETYPE_RC ++}; ++ ++/* reuse two number in the sc/rc space */ ++#define SMFS_CODE_MALFORMED 0xFFFE ++#define SMFS_CODE_IGNORED 0xFFFD ++ ++typedef enum smfs_type { ++ SMFS_TYPE_AUTH, ++ SMFS_TYPE_ASSOC, ++ SMFS_TYPE_REASSOC, ++ SMFS_TYPE_DISASSOC_TX, ++ SMFS_TYPE_DISASSOC_RX, ++ SMFS_TYPE_DEAUTH_TX, ++ SMFS_TYPE_DEAUTH_RX, ++ SMFS_TYPE_MAX ++} smfs_type_t; ++ ++#ifdef PHYMON ++ ++#define PHYMON_VERSION 1 ++ ++typedef struct wl_phycal_core_state { ++ /* Tx IQ/LO calibration coeffs */ ++ int16 tx_iqlocal_a; ++ int16 tx_iqlocal_b; ++ int8 tx_iqlocal_ci; ++ int8 tx_iqlocal_cq; ++ int8 tx_iqlocal_di; ++ int8 tx_iqlocal_dq; ++ int8 tx_iqlocal_ei; ++ int8 tx_iqlocal_eq; ++ int8 tx_iqlocal_fi; ++ int8 tx_iqlocal_fq; ++ ++ /* Rx IQ calibration coeffs */ ++ int16 rx_iqcal_a; ++ int16 rx_iqcal_b; ++ ++ uint8 tx_iqlocal_pwridx; /* Tx Power Index for Tx IQ/LO calibration */ ++ uint32 papd_epsilon_table[64]; /* PAPD epsilon table */ ++ int16 papd_epsilon_offset; /* PAPD epsilon offset */ ++ uint8 curr_tx_pwrindex; /* Tx power index */ ++ int8 idle_tssi; /* Idle TSSI */ ++ int8 est_tx_pwr; /* Estimated Tx Power (dB) */ ++ int8 est_rx_pwr; /* Estimated Rx Power (dB) from RSSI */ ++ uint16 rx_gaininfo; /* Rx gain applied on last Rx pkt */ ++ uint16 init_gaincode; /* initgain required for ACI */ ++ int8 estirr_tx; ++ int8 estirr_rx; ++ ++} wl_phycal_core_state_t; ++ ++typedef struct wl_phycal_state { ++ int version; ++ int8 num_phy_cores; /* number of cores */ ++ int8 curr_temperature; /* on-chip temperature sensor reading */ ++ chanspec_t chspec; /* channspec for this state */ ++ bool aci_state; /* ACI state: ON/OFF */ ++ uint16 crsminpower; /* crsminpower required for ACI */ ++ uint16 crsminpowerl; /* crsminpowerl required for ACI */ ++ uint16 crsminpoweru; /* crsminpoweru required for ACI */ ++ wl_phycal_core_state_t phycal_core[1]; ++} wl_phycal_state_t; ++ ++#define WL_PHYCAL_STAT_FIXED_LEN OFFSETOF(wl_phycal_state_t, phycal_core) ++#endif /* PHYMON */ ++ ++/* discovery state */ ++typedef struct wl_p2p_disc_st { ++ uint8 state; /* see state */ ++ chanspec_t chspec; /* valid in listen state */ ++ uint16 dwell; /* valid in listen state, in ms */ ++} wl_p2p_disc_st_t; ++ ++/* state */ ++#define WL_P2P_DISC_ST_SCAN 0 ++#define WL_P2P_DISC_ST_LISTEN 1 ++#define WL_P2P_DISC_ST_SEARCH 2 ++ ++/* scan request */ ++typedef struct wl_p2p_scan { ++ uint8 type; /* 'S' for WLC_SCAN, 'E' for "escan" */ ++ uint8 reserved[3]; ++ /* scan or escan parms... */ ++} wl_p2p_scan_t; ++ ++/* i/f request */ ++typedef struct wl_p2p_if { ++ struct ether_addr addr; ++ uint8 type; /* see i/f type */ ++ chanspec_t chspec; /* for p2p_ifadd GO */ ++} wl_p2p_if_t; ++ ++/* i/f type */ ++#define WL_P2P_IF_CLIENT 0 ++#define WL_P2P_IF_GO 1 ++#define WL_P2P_IF_DYNBCN_GO 2 ++#define WL_P2P_IF_DEV 3 ++ ++/* i/f query */ ++typedef struct wl_p2p_ifq { ++ uint bsscfgidx; ++ char ifname[BCM_MSG_IFNAME_MAX]; ++} wl_p2p_ifq_t; ++ ++/* OppPS & CTWindow */ ++typedef struct wl_p2p_ops { ++ uint8 ops; /* 0: disable 1: enable */ ++ uint8 ctw; /* >= 10 */ ++} wl_p2p_ops_t; ++ ++/* absence and presence request */ ++typedef struct wl_p2p_sched_desc { ++ uint32 start; ++ uint32 interval; ++ uint32 duration; ++ uint32 count; /* see count */ ++} wl_p2p_sched_desc_t; ++ ++/* count */ ++#define WL_P2P_SCHED_RSVD 0 ++#define WL_P2P_SCHED_REPEAT 255 /* anything > 255 will be treated as 255 */ ++ ++typedef struct wl_p2p_sched { ++ uint8 type; /* see schedule type */ ++ uint8 action; /* see schedule action */ ++ uint8 option; /* see schedule option */ ++ wl_p2p_sched_desc_t desc[1]; ++} wl_p2p_sched_t; ++#define WL_P2P_SCHED_FIXED_LEN 3 ++ ++/* schedule type */ ++#define WL_P2P_SCHED_TYPE_ABS 0 /* Scheduled Absence */ ++#define WL_P2P_SCHED_TYPE_REQ_ABS 1 /* Requested Absence */ ++ ++/* schedule action during absence periods (for WL_P2P_SCHED_ABS type) */ ++#define WL_P2P_SCHED_ACTION_NONE 0 /* no action */ ++#define WL_P2P_SCHED_ACTION_DOZE 1 /* doze */ ++/* schedule option - WL_P2P_SCHED_TYPE_REQ_ABS */ ++#define WL_P2P_SCHED_ACTION_GOOFF 2 /* turn off GO beacon/prbrsp functions */ ++/* schedule option - WL_P2P_SCHED_TYPE_XXX */ ++#define WL_P2P_SCHED_ACTION_RESET 255 /* reset */ ++ ++/* schedule option - WL_P2P_SCHED_TYPE_ABS */ ++#define WL_P2P_SCHED_OPTION_NORMAL 0 /* normal start/interval/duration/count */ ++#define WL_P2P_SCHED_OPTION_BCNPCT 1 /* percentage of beacon interval */ ++/* schedule option - WL_P2P_SCHED_TYPE_REQ_ABS */ ++#define WL_P2P_SCHED_OPTION_TSFOFS 2 /* normal start/internal/duration/count with ++ * start being an offset of the 'current' TSF ++ */ ++ ++/* feature flags */ ++#define WL_P2P_FEAT_GO_CSA (1 << 0) /* GO moves with the STA using CSA method */ ++#define WL_P2P_FEAT_GO_NOLEGACY (1 << 1) /* GO does not probe respond to non-p2p probe ++ * requests ++ */ ++#define WL_P2P_FEAT_RESTRICT_DEV_RESP (1 << 2) /* Restrict p2p dev interface from responding */ ++ ++#ifdef WLNIC ++/* nic_cnx iovar */ ++typedef struct wl_nic_cnx { ++ uint8 opcode; ++ struct ether_addr addr; ++ /* the following are valid for WL_NIC_CNX_CONN */ ++ uint8 SSID_len; ++ uint8 SSID[32]; ++ struct ether_addr abssid; ++ uint8 join_period; ++} wl_nic_cnx_t; ++ ++/* opcode */ ++#define WL_NIC_CNX_ADD 0 /* add NIC connection */ ++#define WL_NIC_CNX_DEL 1 /* delete NIC connection */ ++#define WL_NIC_CNX_IDX 2 /* query NIC connection index */ ++#define WL_NIC_CNX_CONN 3 /* join/create network */ ++#define WL_NIC_CNX_DIS 4 /* disconnect from network */ ++ ++/* nic_cfg iovar */ ++typedef struct wl_nic_cfg { ++ uint8 version; ++ uint8 beacon_mode; ++ uint16 beacon_interval; ++ uint8 diluted_beacon_period; ++ uint8 repeat_EQC; ++ uint8 scan_length; ++ uint8 scan_interval; ++ uint8 scan_probability; ++ uint8 awake_window_length; ++ int8 TSF_correction; ++ uint8 ASID; ++ uint8 channel_usage_mode; ++} wl_nic_cfg_t; ++ ++/* version */ ++#define WL_NIC_CFG_VER 1 ++ ++/* beacon_mode */ ++#define WL_NIC_BCN_NORM 0 ++#define WL_NIC_BCN_DILUTED 1 ++ ++/* channel_usage_mode */ ++#define WL_NIC_CHAN_STATIC 0 ++#define WL_NIC_CHAN_CYCLE 1 ++ ++/* nic_cfg iovar */ ++typedef struct wl_nic_frm { ++ uint8 type; ++ struct ether_addr da; ++ uint8 body[1]; ++} wl_nic_frm_t; ++ ++/* type */ ++#define WL_NIC_FRM_MYNET 1 ++#define WL_NIC_FRM_ACTION 2 ++ ++/* i/f query */ ++typedef struct wl_nic_ifq { ++ uint bsscfgidx; ++ char ifname[BCM_MSG_IFNAME_MAX]; ++} wl_nic_ifq_t; ++ ++/* data mode */ ++/* nic_dm iovar */ ++typedef struct wl_nic_dm { ++ uint8 enab; ++ chanspec_t chspec; ++} wl_nic_dm_t; ++#endif /* WLNIC */ ++ ++/* RFAWARE def */ ++#define BCM_ACTION_RFAWARE 0x77 ++#define BCM_ACTION_RFAWARE_DCS 0x01 ++ ++/* DCS reason code define */ ++#define BCM_DCS_IOVAR 0x1 ++#define BCM_DCS_UNKNOWN 0xFF ++ ++typedef struct wl_bcmdcs_data { ++ uint reason; ++ chanspec_t chspec; ++} wl_bcmdcs_data_t; ++ ++/* n-mode support capability */ ++/* 2x2 includes both 1x1 & 2x2 devices ++ * reserved #define 2 for future when we want to separate 1x1 & 2x2 and ++ * control it independently ++ */ ++#define WL_11N_2x2 1 ++#define WL_11N_3x3 3 ++#define WL_11N_4x4 4 ++ ++/* define 11n feature disable flags */ ++#define WLFEATURE_DISABLE_11N 0x00000001 ++#define WLFEATURE_DISABLE_11N_STBC_TX 0x00000002 ++#define WLFEATURE_DISABLE_11N_STBC_RX 0x00000004 ++#define WLFEATURE_DISABLE_11N_SGI_TX 0x00000008 ++#define WLFEATURE_DISABLE_11N_SGI_RX 0x00000010 ++#define WLFEATURE_DISABLE_11N_AMPDU_TX 0x00000020 ++#define WLFEATURE_DISABLE_11N_AMPDU_RX 0x00000040 ++#define WLFEATURE_DISABLE_11N_GF 0x00000080 ++ ++/* Proxy STA modes */ ++#define PSTA_MODE_DISABLED 0 ++#define PSTA_MODE_PROXY 1 ++#define PSTA_MODE_REPEATER 2 ++ ++ ++/* NAT configuration */ ++typedef struct { ++ uint32 ipaddr; /* interface ip address */ ++ uint32 ipaddr_mask; /* interface ip address mask */ ++ uint32 ipaddr_gateway; /* gateway ip address */ ++ uint8 mac_gateway[6]; /* gateway mac address */ ++ uint32 ipaddr_dns; /* DNS server ip address, valid only for public if */ ++ uint8 mac_dns[6]; /* DNS server mac address, valid only for public if */ ++ uint8 GUID[38]; /* interface GUID */ ++} nat_if_info_t; ++ ++typedef struct { ++ uint op; /* operation code */ ++ bool pub_if; /* set for public if, clear for private if */ ++ nat_if_info_t if_info; /* interface info */ ++} nat_cfg_t; ++ ++/* op code in nat_cfg */ ++#define NAT_OP_ENABLE 1 /* enable NAT on given interface */ ++#define NAT_OP_DISABLE 2 /* disable NAT on given interface */ ++#define NAT_OP_DISABLE_ALL 3 /* disable NAT on all interfaces */ ++ ++/* NAT state */ ++#define NAT_STATE_ENABLED 1 /* NAT is enabled */ ++#define NAT_STATE_DISABLED 2 /* NAT is disabled */ ++ ++typedef struct { ++ int state; /* NAT state returned */ ++} nat_state_t; ++ ++#ifdef PROP_TXSTATUS ++/* Bit definitions for tlv iovar */ ++/* ++ * enable RSSI signals: ++ * WLFC_CTL_TYPE_RSSI ++ */ ++#define WLFC_FLAGS_RSSI_SIGNALS 0x0001 ++ ++/* enable (if/mac_open, if/mac_close,, mac_add, mac_del) signals: ++ * ++ * WLFC_CTL_TYPE_MAC_OPEN ++ * WLFC_CTL_TYPE_MAC_CLOSE ++ * ++ * WLFC_CTL_TYPE_INTERFACE_OPEN ++ * WLFC_CTL_TYPE_INTERFACE_CLOSE ++ * ++ * WLFC_CTL_TYPE_MACDESC_ADD ++ * WLFC_CTL_TYPE_MACDESC_DEL ++ * ++ */ ++#define WLFC_FLAGS_XONXOFF_SIGNALS 0x0002 ++ ++/* enable (status, fifo_credit, mac_credit) signals ++ * WLFC_CTL_TYPE_MAC_REQUEST_CREDIT ++ * WLFC_CTL_TYPE_TXSTATUS ++ * WLFC_CTL_TYPE_FIFO_CREDITBACK ++ */ ++#define WLFC_FLAGS_CREDIT_STATUS_SIGNALS 0x0004 ++ ++#define WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE 0x0008 ++#define WLFC_FLAGS_PSQ_GENERATIONFSM_ENABLE 0x0010 ++#define WLFC_FLAGS_PSQ_ZERO_BUFFER_ENABLE 0x0020 ++#define WLFC_FLAGS_HOST_RXRERODER_ACTIVE 0x0040 ++#endif /* PROP_TXSTATUS */ ++ ++#define BTA_STATE_LOG_SZ 64 ++ ++/* BTAMP Statemachine states */ ++enum { ++ HCIReset = 1, ++ HCIReadLocalAMPInfo, ++ HCIReadLocalAMPASSOC, ++ HCIWriteRemoteAMPASSOC, ++ HCICreatePhysicalLink, ++ HCIAcceptPhysicalLinkRequest, ++ HCIDisconnectPhysicalLink, ++ HCICreateLogicalLink, ++ HCIAcceptLogicalLink, ++ HCIDisconnectLogicalLink, ++ HCILogicalLinkCancel, ++ HCIAmpStateChange, ++ HCIWriteLogicalLinkAcceptTimeout ++}; ++ ++typedef struct flush_txfifo { ++ uint32 txfifobmp; ++ uint32 hwtxfifoflush; ++ struct ether_addr ea; ++} flush_txfifo_t; ++ ++#define CHANNEL_5G_LOW_START 36 /* 5G low (36..48) CDD enable/disable bit mask */ ++#define CHANNEL_5G_MID_START 52 /* 5G mid (52..64) CDD enable/disable bit mask */ ++#define CHANNEL_5G_HIGH_START 100 /* 5G high (100..140) CDD enable/disable bit mask */ ++#define CHANNEL_5G_UPPER_START 149 /* 5G upper (149..161) CDD enable/disable bit mask */ ++ ++enum { ++ SPATIAL_MODE_2G_IDX = 0, ++ SPATIAL_MODE_5G_LOW_IDX, ++ SPATIAL_MODE_5G_MID_IDX, ++ SPATIAL_MODE_5G_HIGH_IDX, ++ SPATIAL_MODE_5G_UPPER_IDX, ++ SPATIAL_MODE_MAX_IDX ++}; ++ ++/* IOVAR "mempool" parameter. Used to retrieve a list of memory pool statistics. */ ++typedef struct wl_mempool_stats { ++ int num; /* Number of memory pools */ ++ bcm_mp_stats_t s[1]; /* Variable array of memory pool stats. */ ++} wl_mempool_stats_t; ++ ++ ++/* D0 Coalescing */ ++#define IPV4_ARP_FILTER 0x0001 ++#define IPV4_NETBT_FILTER 0x0002 ++#define IPV4_LLMNR_FILTER 0x0004 ++#define IPV4_SSDP_FILTER 0x0008 ++#define IPV4_WSD_FILTER 0x0010 ++#define IPV6_NETBT_FILTER 0x0200 ++#define IPV6_LLMNR_FILTER 0x0400 ++#define IPV6_SSDP_FILTER 0x0800 ++#define IPV6_WSD_FILTER 0x1000 ++ ++/* Network Offload Engine */ ++#define NWOE_OL_ENABLE 0x00000001 ++ ++typedef struct { ++ uint32 ipaddr; ++ uint32 ipaddr_netmask; ++ uint32 ipaddr_gateway; ++} nwoe_ifconfig_t; ++ ++/* ++ * Traffic management structures/defines. ++ */ ++ ++/* Traffic management bandwidth parameters */ ++#define TRF_MGMT_MAX_PRIORITIES 3 ++ ++#define TRF_MGMT_FLAG_ADD_DSCP 0x0001 /* Add DSCP to IP TOS field */ ++#define TRF_MGMT_FLAG_DISABLE_SHAPING 0x0002 /* Only support traffic clasification */ ++#define TRF_MGMT_FLAG_DISABLE_PRIORITY_TAGGING 0x0004 /* Don't override packet's priority */ ++ ++/* Traffic management priority classes */ ++typedef enum trf_mgmt_priority_class { ++ trf_mgmt_priority_low = 0, /* Maps to 802.1p BO */ ++ trf_mgmt_priority_medium = 1, /* Maps to 802.1p BE */ ++ trf_mgmt_priority_high = 2, /* Maps to 802.1p VI */ ++ trf_mgmt_priority_invalid = (trf_mgmt_priority_high + 1) ++} trf_mgmt_priority_class_t; ++ ++/* Traffic management configuration parameters */ ++typedef struct trf_mgmt_config { ++ uint32 trf_mgmt_enabled; /* 0 - disabled, 1 - enabled */ ++ uint32 flags; /* See TRF_MGMT_FLAG_xxx defines */ ++ uint32 host_ip_addr; /* My IP address to determine subnet */ ++ uint32 host_subnet_mask; /* My subnet mask */ ++ uint32 downlink_bandwidth; /* In units of kbps */ ++ uint32 uplink_bandwidth; /* In units of kbps */ ++ uint32 min_tx_bandwidth[TRF_MGMT_MAX_PRIORITIES]; /* Minimum guaranteed tx bandwidth */ ++ uint32 min_rx_bandwidth[TRF_MGMT_MAX_PRIORITIES]; /* Minimum guaranteed rx bandwidth */ ++} trf_mgmt_config_t; ++ ++/* Traffic management filter */ ++typedef struct trf_mgmt_filter { ++ struct ether_addr dst_ether_addr; /* His L2 address */ ++ uint32 dst_ip_addr; /* His IP address */ ++ uint16 dst_port; /* His L4 port */ ++ uint16 src_port; /* My L4 port */ ++ uint16 prot; /* L4 protocol (only TCP or UDP) */ ++ uint16 flags; /* TBD. For now, this must be zero. */ ++ trf_mgmt_priority_class_t priority; /* Priority for filtered packets */ ++} trf_mgmt_filter_t; ++ ++/* Traffic management filter list (variable length) */ ++typedef struct trf_mgmt_filter_list { ++ uint32 num_filters; ++ trf_mgmt_filter_t filter[1]; ++} trf_mgmt_filter_list_t; ++ ++/* Traffic management global info used for all queues */ ++typedef struct trf_mgmt_global_info { ++ uint32 maximum_bytes_per_second; ++ uint32 maximum_bytes_per_sampling_period; ++ uint32 total_bytes_consumed_per_second; ++ uint32 total_bytes_consumed_per_sampling_period; ++ uint32 total_unused_bytes_per_sampling_period; ++} trf_mgmt_global_info_t; ++ ++/* Traffic management shaping info per priority queue */ ++typedef struct trf_mgmt_shaping_info { ++ uint32 gauranteed_bandwidth_percentage; ++ uint32 guaranteed_bytes_per_second; ++ uint32 guaranteed_bytes_per_sampling_period; ++ uint32 num_bytes_produced_per_second; ++ uint32 num_bytes_consumed_per_second; ++ uint32 num_queued_packets; /* Number of packets in queue */ ++ uint32 num_queued_bytes; /* Number of bytes in queue */ ++} trf_mgmt_shaping_info_t; ++ ++/* Traffic management shaping info array */ ++typedef struct trf_mgmt_shaping_info_array { ++ trf_mgmt_global_info_t tx_global_shaping_info; ++ trf_mgmt_shaping_info_t tx_queue_shaping_info[TRF_MGMT_MAX_PRIORITIES]; ++ trf_mgmt_global_info_t rx_global_shaping_info; ++ trf_mgmt_shaping_info_t rx_queue_shaping_info[TRF_MGMT_MAX_PRIORITIES]; ++} trf_mgmt_shaping_info_array_t; ++ ++ ++/* Traffic management statistical counters */ ++typedef struct trf_mgmt_stats { ++ uint32 num_processed_packets; /* Number of packets processed */ ++ uint32 num_processed_bytes; /* Number of bytes processed */ ++ uint32 num_discarded_packets; /* Number of packets discarded from queue */ ++} trf_mgmt_stats_t; ++ ++/* Traffic management statisics array */ ++typedef struct trf_mgmt_stats_array { ++ trf_mgmt_stats_t tx_queue_stats[TRF_MGMT_MAX_PRIORITIES]; ++ trf_mgmt_stats_t rx_queue_stats[TRF_MGMT_MAX_PRIORITIES]; ++} trf_mgmt_stats_array_t; ++ ++typedef struct powersel_params { ++ /* LPC Params exposed via IOVAR */ ++ int32 tp_ratio_thresh; /* Throughput ratio threshold */ ++ uint8 rate_stab_thresh; /* Thresh for rate stability based on nupd */ ++ uint8 pwr_stab_thresh; /* Number of successes before power step down */ ++ uint8 pwr_sel_exp_time; /* Time lapse for expiry of database */ ++} powersel_params_t; ++ ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++#endif /* _wlioctl_h_ */ +diff --git a/drivers/net/wireless/ap6211/linux_osl.c b/drivers/net/wireless/ap6211/linux_osl.c +new file mode 100755 +index 0000000..d74eee3 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/linux_osl.c +@@ -0,0 +1,1138 @@ ++/* ++ * Linux OS Independent Layer ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: linux_osl.c 373382 2012-12-07 07:59:52Z $ ++ */ ++ ++#define LINUX_PORT ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include ++ ++#define PCI_CFG_RETRY 10 ++ ++#define OS_HANDLE_MAGIC 0x1234abcd /* Magic # to recognize osh */ ++#define BCM_MEM_FILENAME_LEN 24 /* Mem. filename length */ ++ ++#ifdef CONFIG_DHD_USE_STATIC_BUF ++#define DHD_SKB_HDRSIZE 336 ++#define DHD_SKB_1PAGE_BUFSIZE ((PAGE_SIZE*1)-DHD_SKB_HDRSIZE) ++#define DHD_SKB_2PAGE_BUFSIZE ((PAGE_SIZE*2)-DHD_SKB_HDRSIZE) ++#define DHD_SKB_4PAGE_BUFSIZE ((PAGE_SIZE*4)-DHD_SKB_HDRSIZE) ++ ++#define STATIC_BUF_MAX_NUM 16 ++#define STATIC_BUF_SIZE (PAGE_SIZE*2) ++#define STATIC_BUF_TOTAL_LEN (STATIC_BUF_MAX_NUM * STATIC_BUF_SIZE) ++ ++typedef struct bcm_static_buf { ++ struct semaphore static_sem; ++ unsigned char *buf_ptr; ++ unsigned char buf_use[STATIC_BUF_MAX_NUM]; ++} bcm_static_buf_t; ++ ++static bcm_static_buf_t *bcm_static_buf = 0; ++ ++#define STATIC_PKT_MAX_NUM 8 ++#if defined(ENHANCED_STATIC_BUF) ++#define STATIC_PKT_4PAGE_NUM 1 ++#define DHD_SKB_MAX_BUFSIZE DHD_SKB_4PAGE_BUFSIZE ++#else ++#define STATIC_PKT_4PAGE_NUM 0 ++#define DHD_SKB_MAX_BUFSIZE DHD_SKB_2PAGE_BUFSIZE ++#endif /* ENHANCED_STATIC_BUF */ ++ ++typedef struct bcm_static_pkt { ++ struct sk_buff *skb_4k[STATIC_PKT_MAX_NUM]; ++ struct sk_buff *skb_8k[STATIC_PKT_MAX_NUM]; ++#ifdef ENHANCED_STATIC_BUF ++ struct sk_buff *skb_16k; ++#endif ++ struct semaphore osl_pkt_sem; ++ unsigned char pkt_use[STATIC_PKT_MAX_NUM * 2 + STATIC_PKT_4PAGE_NUM]; ++} bcm_static_pkt_t; ++ ++static bcm_static_pkt_t *bcm_static_skb = 0; ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ ++typedef struct bcm_mem_link { ++ struct bcm_mem_link *prev; ++ struct bcm_mem_link *next; ++ uint size; ++ int line; ++ void *osh; ++ char file[BCM_MEM_FILENAME_LEN]; ++} bcm_mem_link_t; ++ ++struct osl_info { ++ osl_pubinfo_t pub; ++#ifdef CTFPOOL ++ ctfpool_t *ctfpool; ++#endif /* CTFPOOL */ ++ uint magic; ++ void *pdev; ++ atomic_t malloced; ++ uint failed; ++ uint bustype; ++ bcm_mem_link_t *dbgmem_list; ++ spinlock_t dbgmem_lock; ++ spinlock_t pktalloc_lock; ++}; ++ ++/* PCMCIA attribute space access macros */ ++ ++/* Global ASSERT type flag */ ++uint32 g_assert_type = FALSE; ++ ++static int16 linuxbcmerrormap[] = ++{ 0, /* 0 */ ++ -EINVAL, /* BCME_ERROR */ ++ -EINVAL, /* BCME_BADARG */ ++ -EINVAL, /* BCME_BADOPTION */ ++ -EINVAL, /* BCME_NOTUP */ ++ -EINVAL, /* BCME_NOTDOWN */ ++ -EINVAL, /* BCME_NOTAP */ ++ -EINVAL, /* BCME_NOTSTA */ ++ -EINVAL, /* BCME_BADKEYIDX */ ++ -EINVAL, /* BCME_RADIOOFF */ ++ -EINVAL, /* BCME_NOTBANDLOCKED */ ++ -EINVAL, /* BCME_NOCLK */ ++ -EINVAL, /* BCME_BADRATESET */ ++ -EINVAL, /* BCME_BADBAND */ ++ -E2BIG, /* BCME_BUFTOOSHORT */ ++ -E2BIG, /* BCME_BUFTOOLONG */ ++ -EBUSY, /* BCME_BUSY */ ++ -EINVAL, /* BCME_NOTASSOCIATED */ ++ -EINVAL, /* BCME_BADSSIDLEN */ ++ -EINVAL, /* BCME_OUTOFRANGECHAN */ ++ -EINVAL, /* BCME_BADCHAN */ ++ -EFAULT, /* BCME_BADADDR */ ++ -ENOMEM, /* BCME_NORESOURCE */ ++ -EOPNOTSUPP, /* BCME_UNSUPPORTED */ ++ -EMSGSIZE, /* BCME_BADLENGTH */ ++ -EINVAL, /* BCME_NOTREADY */ ++ -EPERM, /* BCME_EPERM */ ++ -ENOMEM, /* BCME_NOMEM */ ++ -EINVAL, /* BCME_ASSOCIATED */ ++ -ERANGE, /* BCME_RANGE */ ++ -EINVAL, /* BCME_NOTFOUND */ ++ -EINVAL, /* BCME_WME_NOT_ENABLED */ ++ -EINVAL, /* BCME_TSPEC_NOTFOUND */ ++ -EINVAL, /* BCME_ACM_NOTSUPPORTED */ ++ -EINVAL, /* BCME_NOT_WME_ASSOCIATION */ ++ -EIO, /* BCME_SDIO_ERROR */ ++ -ENODEV, /* BCME_DONGLE_DOWN */ ++ -EINVAL, /* BCME_VERSION */ ++ -EIO, /* BCME_TXFAIL */ ++ -EIO, /* BCME_RXFAIL */ ++ -ENODEV, /* BCME_NODEVICE */ ++ -EINVAL, /* BCME_NMODE_DISABLED */ ++ -ENODATA, /* BCME_NONRESIDENT */ ++ ++/* When an new error code is added to bcmutils.h, add os ++ * specific error translation here as well ++ */ ++/* check if BCME_LAST changed since the last time this function was updated */ ++#if BCME_LAST != -42 ++#error "You need to add a OS error translation in the linuxbcmerrormap \ ++ for new error code defined in bcmutils.h" ++#endif ++}; ++ ++/* translate bcmerrors into linux errors */ ++int ++osl_error(int bcmerror) ++{ ++ if (bcmerror > 0) ++ bcmerror = 0; ++ else if (bcmerror < BCME_LAST) ++ bcmerror = BCME_ERROR; ++ ++ /* Array bounds covered by ASSERT in osl_attach */ ++ return linuxbcmerrormap[-bcmerror]; ++} ++ ++extern uint8* dhd_os_prealloc(void *osh, int section, int size); ++ ++osl_t * ++osl_attach(void *pdev, uint bustype, bool pkttag) ++{ ++ osl_t *osh; ++ ++ if (!(osh = kmalloc(sizeof(osl_t), GFP_ATOMIC))) ++ return osh; ++ ++ ASSERT(osh); ++ ++ bzero(osh, sizeof(osl_t)); ++ ++ /* Check that error map has the right number of entries in it */ ++ ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(linuxbcmerrormap) - 1)); ++ ++ osh->magic = OS_HANDLE_MAGIC; ++ atomic_set(&osh->malloced, 0); ++ osh->failed = 0; ++ osh->dbgmem_list = NULL; ++ spin_lock_init(&(osh->dbgmem_lock)); ++ osh->pdev = pdev; ++ osh->pub.pkttag = pkttag; ++ osh->bustype = bustype; ++ ++ switch (bustype) { ++ case PCI_BUS: ++ case SI_BUS: ++ case PCMCIA_BUS: ++ osh->pub.mmbus = TRUE; ++ break; ++ case JTAG_BUS: ++ case SDIO_BUS: ++ case USB_BUS: ++ case SPI_BUS: ++ case RPC_BUS: ++ osh->pub.mmbus = FALSE; ++ break; ++ default: ++ ASSERT(FALSE); ++ break; ++ } ++ ++#if defined(CONFIG_DHD_USE_STATIC_BUF) ++ if (!bcm_static_buf) { ++ if (!(bcm_static_buf = (bcm_static_buf_t *)dhd_os_prealloc(osh, 3, STATIC_BUF_SIZE+ ++ STATIC_BUF_TOTAL_LEN))) { ++ AP6211_DEBUG("can not alloc static buf!\n"); ++ } ++ else ++ AP6211_DEBUG("alloc static buf at %x!\n", (unsigned int)bcm_static_buf); ++ ++ ++ sema_init(&bcm_static_buf->static_sem, 1); ++ ++ bcm_static_buf->buf_ptr = (unsigned char *)bcm_static_buf + STATIC_BUF_SIZE; ++ } ++ ++ if (!bcm_static_skb) { ++ int i; ++ void *skb_buff_ptr = 0; ++ bcm_static_skb = (bcm_static_pkt_t *)((char *)bcm_static_buf + 2048); ++ skb_buff_ptr = dhd_os_prealloc(osh, 4, 0); ++ ++ bcopy(skb_buff_ptr, bcm_static_skb, sizeof(struct sk_buff *)* ++ (STATIC_PKT_MAX_NUM * 2 + STATIC_PKT_4PAGE_NUM)); ++ for (i = 0; i < (STATIC_PKT_MAX_NUM * 2 + STATIC_PKT_4PAGE_NUM); i++) ++ bcm_static_skb->pkt_use[i] = 0; ++ ++ sema_init(&bcm_static_skb->osl_pkt_sem, 1); ++ } ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ ++ spin_lock_init(&(osh->pktalloc_lock)); ++ ++ return osh; ++} ++ ++void ++osl_detach(osl_t *osh) ++{ ++ if (osh == NULL) ++ return; ++ ++#ifdef CONFIG_DHD_USE_STATIC_BUF ++ if (bcm_static_buf) { ++ bcm_static_buf = 0; ++ } ++ if (bcm_static_skb) { ++ bcm_static_skb = 0; ++ } ++#endif ++ ++ ASSERT(osh->magic == OS_HANDLE_MAGIC); ++ kfree(osh); ++} ++ ++static struct sk_buff *osl_alloc_skb(unsigned int len) ++{ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) ++ return __dev_alloc_skb(len, GFP_ATOMIC); ++#else ++ return dev_alloc_skb(len); ++#endif ++} ++ ++#ifdef CTFPOOL ++ ++#ifdef CTFPOOL_SPINLOCK ++#define CTFPOOL_LOCK(ctfpool, flags) spin_lock_irqsave(&(ctfpool)->lock, flags) ++#define CTFPOOL_UNLOCK(ctfpool, flags) spin_unlock_irqrestore(&(ctfpool)->lock, flags) ++#else ++#define CTFPOOL_LOCK(ctfpool, flags) spin_lock_bh(&(ctfpool)->lock) ++#define CTFPOOL_UNLOCK(ctfpool, flags) spin_unlock_bh(&(ctfpool)->lock) ++#endif /* CTFPOOL_SPINLOCK */ ++/* ++ * Allocate and add an object to packet pool. ++ */ ++void * ++osl_ctfpool_add(osl_t *osh) ++{ ++ struct sk_buff *skb; ++#ifdef CTFPOOL_SPINLOCK ++ unsigned long flags; ++#endif /* CTFPOOL_SPINLOCK */ ++ ++ if ((osh == NULL) || (osh->ctfpool == NULL)) ++ return NULL; ++ ++ CTFPOOL_LOCK(osh->ctfpool, flags); ++ ASSERT(osh->ctfpool->curr_obj <= osh->ctfpool->max_obj); ++ ++ /* No need to allocate more objects */ ++ if (osh->ctfpool->curr_obj == osh->ctfpool->max_obj) { ++ CTFPOOL_UNLOCK(osh->ctfpool, flags); ++ return NULL; ++ } ++ ++ /* Allocate a new skb and add it to the ctfpool */ ++ skb = osl_alloc_skb(osh->ctfpool->obj_size); ++ if (skb == NULL) { ++ AP6211_DEBUG("%s: skb alloc of len %d failed\n", __FUNCTION__, ++ osh->ctfpool->obj_size); ++ CTFPOOL_UNLOCK(osh->ctfpool, flags); ++ return NULL; ++ } ++ ++ /* Add to ctfpool */ ++ skb->next = (struct sk_buff *)osh->ctfpool->head; ++ osh->ctfpool->head = skb; ++ osh->ctfpool->fast_frees++; ++ osh->ctfpool->curr_obj++; ++ ++ /* Hijack a skb member to store ptr to ctfpool */ ++ CTFPOOLPTR(osh, skb) = (void *)osh->ctfpool; ++ ++ /* Use bit flag to indicate skb from fast ctfpool */ ++ PKTFAST(osh, skb) = FASTBUF; ++ ++ CTFPOOL_UNLOCK(osh->ctfpool, flags); ++ ++ return skb; ++} ++ ++/* ++ * Add new objects to the pool. ++ */ ++void ++osl_ctfpool_replenish(osl_t *osh, uint thresh) ++{ ++ if ((osh == NULL) || (osh->ctfpool == NULL)) ++ return; ++ ++ /* Do nothing if no refills are required */ ++ while ((osh->ctfpool->refills > 0) && (thresh--)) { ++ osl_ctfpool_add(osh); ++ osh->ctfpool->refills--; ++ } ++} ++ ++/* ++ * Initialize the packet pool with specified number of objects. ++ */ ++int32 ++osl_ctfpool_init(osl_t *osh, uint numobj, uint size) ++{ ++ osh->ctfpool = kmalloc(sizeof(ctfpool_t), GFP_ATOMIC); ++ ASSERT(osh->ctfpool); ++ bzero(osh->ctfpool, sizeof(ctfpool_t)); ++ ++ osh->ctfpool->max_obj = numobj; ++ osh->ctfpool->obj_size = size; ++ ++ spin_lock_init(&osh->ctfpool->lock); ++ ++ while (numobj--) { ++ if (!osl_ctfpool_add(osh)) ++ return -1; ++ osh->ctfpool->fast_frees--; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Cleanup the packet pool objects. ++ */ ++void ++osl_ctfpool_cleanup(osl_t *osh) ++{ ++ struct sk_buff *skb, *nskb; ++#ifdef CTFPOOL_SPINLOCK ++ unsigned long flags; ++#endif /* CTFPOOL_SPINLOCK */ ++ ++ if ((osh == NULL) || (osh->ctfpool == NULL)) ++ return; ++ ++ CTFPOOL_LOCK(osh->ctfpool, flags); ++ ++ skb = osh->ctfpool->head; ++ ++ while (skb != NULL) { ++ nskb = skb->next; ++ dev_kfree_skb(skb); ++ skb = nskb; ++ osh->ctfpool->curr_obj--; ++ } ++ ++ ASSERT(osh->ctfpool->curr_obj == 0); ++ osh->ctfpool->head = NULL; ++ CTFPOOL_UNLOCK(osh->ctfpool, flags); ++ ++ kfree(osh->ctfpool); ++ osh->ctfpool = NULL; ++} ++ ++void ++osl_ctfpool_stats(osl_t *osh, void *b) ++{ ++ struct bcmstrbuf *bb; ++ ++ if ((osh == NULL) || (osh->ctfpool == NULL)) ++ return; ++ ++#ifdef CONFIG_DHD_USE_STATIC_BUF ++ if (bcm_static_buf) { ++ bcm_static_buf = 0; ++ } ++ if (bcm_static_skb) { ++ bcm_static_skb = 0; ++ } ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ ++ bb = b; ++ ++ ASSERT((osh != NULL) && (bb != NULL)); ++ ++ bcm_bprintf(bb, "max_obj %d obj_size %d curr_obj %d refills %d\n", ++ osh->ctfpool->max_obj, osh->ctfpool->obj_size, ++ osh->ctfpool->curr_obj, osh->ctfpool->refills); ++ bcm_bprintf(bb, "fast_allocs %d fast_frees %d slow_allocs %d\n", ++ osh->ctfpool->fast_allocs, osh->ctfpool->fast_frees, ++ osh->ctfpool->slow_allocs); ++} ++ ++static inline struct sk_buff * ++osl_pktfastget(osl_t *osh, uint len) ++{ ++ struct sk_buff *skb; ++#ifdef CTFPOOL_SPINLOCK ++ unsigned long flags; ++#endif /* CTFPOOL_SPINLOCK */ ++ ++ /* Try to do fast allocate. Return null if ctfpool is not in use ++ * or if there are no items in the ctfpool. ++ */ ++ if (osh->ctfpool == NULL) ++ return NULL; ++ ++ CTFPOOL_LOCK(osh->ctfpool, flags); ++ if (osh->ctfpool->head == NULL) { ++ ASSERT(osh->ctfpool->curr_obj == 0); ++ osh->ctfpool->slow_allocs++; ++ CTFPOOL_UNLOCK(osh->ctfpool, flags); ++ return NULL; ++ } ++ ++ ASSERT(len <= osh->ctfpool->obj_size); ++ ++ /* Get an object from ctfpool */ ++ skb = (struct sk_buff *)osh->ctfpool->head; ++ osh->ctfpool->head = (void *)skb->next; ++ ++ osh->ctfpool->fast_allocs++; ++ osh->ctfpool->curr_obj--; ++ ASSERT(CTFPOOLHEAD(osh, skb) == (struct sock *)osh->ctfpool->head); ++ CTFPOOL_UNLOCK(osh->ctfpool, flags); ++ ++ /* Init skb struct */ ++ skb->next = skb->prev = NULL; ++ skb->data = skb->head + 16; ++ skb->tail = skb->head + 16; ++ ++ skb->len = 0; ++ skb->cloned = 0; ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) ++ skb->list = NULL; ++#endif ++ atomic_set(&skb->users, 1); ++ ++ return skb; ++} ++#endif /* CTFPOOL */ ++/* Convert a driver packet to native(OS) packet ++ * In the process, packettag is zeroed out before sending up ++ * IP code depends on skb->cb to be setup correctly with various options ++ * In our case, that means it should be 0 ++ */ ++struct sk_buff * BCMFASTPATH ++osl_pkt_tonative(osl_t *osh, void *pkt) ++{ ++#ifndef WL_UMK ++ struct sk_buff *nskb; ++ unsigned long flags; ++#endif ++ ++ if (osh->pub.pkttag) ++ bzero((void*)((struct sk_buff *)pkt)->cb, OSL_PKTTAG_SZ); ++ ++#ifndef WL_UMK ++ /* Decrement the packet counter */ ++ for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next) { ++ spin_lock_irqsave(&osh->pktalloc_lock, flags); ++ osh->pub.pktalloced--; ++ spin_unlock_irqrestore(&osh->pktalloc_lock, flags); ++ } ++#endif /* WL_UMK */ ++ return (struct sk_buff *)pkt; ++} ++ ++/* Convert a native(OS) packet to driver packet. ++ * In the process, native packet is destroyed, there is no copying ++ * Also, a packettag is zeroed out ++ */ ++void * BCMFASTPATH ++osl_pkt_frmnative(osl_t *osh, void *pkt) ++{ ++#ifndef WL_UMK ++ struct sk_buff *nskb; ++ unsigned long flags; ++#endif ++ ++ if (osh->pub.pkttag) ++ bzero((void*)((struct sk_buff *)pkt)->cb, OSL_PKTTAG_SZ); ++ ++#ifndef WL_UMK ++ /* Increment the packet counter */ ++ for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next) { ++ spin_lock_irqsave(&osh->pktalloc_lock, flags); ++ osh->pub.pktalloced++; ++ spin_unlock_irqrestore(&osh->pktalloc_lock, flags); ++ } ++#endif /* WL_UMK */ ++ return (void *)pkt; ++} ++ ++/* Return a new packet. zero out pkttag */ ++void * BCMFASTPATH ++osl_pktget(osl_t *osh, uint len) ++{ ++ struct sk_buff *skb; ++ unsigned long flags; ++ ++#ifdef CTFPOOL ++ /* Allocate from local pool */ ++ skb = osl_pktfastget(osh, len); ++ if ((skb != NULL) || ((skb = osl_alloc_skb(len)) != NULL)) { ++#else /* CTFPOOL */ ++ if ((skb = osl_alloc_skb(len))) { ++#endif /* CTFPOOL */ ++ skb_put(skb, len); ++ skb->priority = 0; ++ ++ ++ spin_lock_irqsave(&osh->pktalloc_lock, flags); ++ osh->pub.pktalloced++; ++ spin_unlock_irqrestore(&osh->pktalloc_lock, flags); ++ } ++ ++ return ((void*) skb); ++} ++ ++#ifdef CTFPOOL ++static inline void ++osl_pktfastfree(osl_t *osh, struct sk_buff *skb) ++{ ++ ctfpool_t *ctfpool; ++#ifdef CTFPOOL_SPINLOCK ++ unsigned long flags; ++#endif /* CTFPOOL_SPINLOCK */ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) ++ skb->tstamp.tv.sec = 0; ++#else ++ skb->stamp.tv_sec = 0; ++#endif ++ ++ /* We only need to init the fields that we change */ ++ skb->dev = NULL; ++ skb->dst = NULL; ++ memset(skb->cb, 0, sizeof(skb->cb)); ++ skb->ip_summed = 0; ++ skb->destructor = NULL; ++ ++ ctfpool = (ctfpool_t *)CTFPOOLPTR(osh, skb); ++ ASSERT(ctfpool != NULL); ++ ++ /* Add object to the ctfpool */ ++ CTFPOOL_LOCK(ctfpool, flags); ++ skb->next = (struct sk_buff *)ctfpool->head; ++ ctfpool->head = (void *)skb; ++ ++ ctfpool->fast_frees++; ++ ctfpool->curr_obj++; ++ ++ ASSERT(ctfpool->curr_obj <= ctfpool->max_obj); ++ CTFPOOL_UNLOCK(ctfpool, flags); ++} ++#endif /* CTFPOOL */ ++ ++/* Free the driver packet. Free the tag if present */ ++void BCMFASTPATH ++osl_pktfree(osl_t *osh, void *p, bool send) ++{ ++ struct sk_buff *skb, *nskb; ++ unsigned long flags; ++ ++ skb = (struct sk_buff*) p; ++ ++ if (send && osh->pub.tx_fn) ++ osh->pub.tx_fn(osh->pub.tx_ctx, p, 0); ++ ++ PKTDBG_TRACE(osh, (void *) skb, PKTLIST_PKTFREE); ++ ++ /* perversion: we use skb->next to chain multi-skb packets */ ++ while (skb) { ++ nskb = skb->next; ++ skb->next = NULL; ++ ++ ++ ++#ifdef CTFPOOL ++ if ((PKTISFAST(osh, skb)) && (atomic_read(&skb->users) == 1)) ++ osl_pktfastfree(osh, skb); ++ else { ++#else /* CTFPOOL */ ++ { ++#endif /* CTFPOOL */ ++ ++ if (skb->destructor) ++ /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if ++ * destructor exists ++ */ ++ dev_kfree_skb_any(skb); ++ else ++ /* can free immediately (even in_irq()) if destructor ++ * does not exist ++ */ ++ dev_kfree_skb(skb); ++ } ++ spin_lock_irqsave(&osh->pktalloc_lock, flags); ++ osh->pub.pktalloced--; ++ spin_unlock_irqrestore(&osh->pktalloc_lock, flags); ++ skb = nskb; ++ } ++} ++ ++#ifdef CONFIG_DHD_USE_STATIC_BUF ++void* ++osl_pktget_static(osl_t *osh, uint len) ++{ ++ int i = 0; ++ struct sk_buff *skb; ++ ++ ++ if (len > DHD_SKB_MAX_BUFSIZE) { ++ AP6211_DEBUG("osl_pktget_static: Do we really need this big skb??" ++ " len=%d\n", len); ++ return osl_pktget(osh, len); ++ } ++ ++ down(&bcm_static_skb->osl_pkt_sem); ++ ++ if (len <= DHD_SKB_1PAGE_BUFSIZE) { ++ for (i = 0; i < STATIC_PKT_MAX_NUM; i++) { ++ if (bcm_static_skb->pkt_use[i] == 0) ++ break; ++ } ++ ++ if (i != STATIC_PKT_MAX_NUM) { ++ bcm_static_skb->pkt_use[i] = 1; ++ ++ skb = bcm_static_skb->skb_4k[i]; ++ skb->tail = skb->data + len; ++ skb->len = len; ++ ++ up(&bcm_static_skb->osl_pkt_sem); ++ return skb; ++ } ++ } ++ ++ if (len <= DHD_SKB_2PAGE_BUFSIZE) { ++ ++ for (i = 0; i < STATIC_PKT_MAX_NUM; i++) { ++ if (bcm_static_skb->pkt_use[i + STATIC_PKT_MAX_NUM] ++ == 0) ++ break; ++ } ++ ++ if (i != STATIC_PKT_MAX_NUM) { ++ bcm_static_skb->pkt_use[i + STATIC_PKT_MAX_NUM] = 1; ++ skb = bcm_static_skb->skb_8k[i]; ++ skb->tail = skb->data + len; ++ skb->len = len; ++ ++ up(&bcm_static_skb->osl_pkt_sem); ++ return skb; ++ } ++ } ++ ++#if defined(ENHANCED_STATIC_BUF) ++ if (bcm_static_skb->pkt_use[STATIC_PKT_MAX_NUM * 2] == 0) { ++ bcm_static_skb->pkt_use[STATIC_PKT_MAX_NUM * 2] = 1; ++ ++ skb = bcm_static_skb->skb_16k; ++ skb->tail = skb->data + len; ++ skb->len = len; ++ ++ up(&bcm_static_skb->osl_pkt_sem); ++ return skb; ++ } ++#endif ++ ++ up(&bcm_static_skb->osl_pkt_sem); ++ AP6211_DEBUG("osl_pktget_static: all static pkt in use!\n"); ++ return osl_pktget(osh, len); ++} ++ ++void ++osl_pktfree_static(osl_t *osh, void *p, bool send) ++{ ++ int i; ++ if (!bcm_static_skb) { ++ osl_pktfree(osh, p, send); ++ return; ++ } ++ ++ down(&bcm_static_skb->osl_pkt_sem); ++ for (i = 0; i < STATIC_PKT_MAX_NUM; i++) { ++ if (p == bcm_static_skb->skb_4k[i]) { ++ bcm_static_skb->pkt_use[i] = 0; ++ up(&bcm_static_skb->osl_pkt_sem); ++ return; ++ } ++ } ++ ++ for (i = 0; i < STATIC_PKT_MAX_NUM; i++) { ++ if (p == bcm_static_skb->skb_8k[i]) { ++ bcm_static_skb->pkt_use[i + STATIC_PKT_MAX_NUM] = 0; ++ up(&bcm_static_skb->osl_pkt_sem); ++ return; ++ } ++ } ++#ifdef ENHANCED_STATIC_BUF ++ if (p == bcm_static_skb->skb_16k) { ++ bcm_static_skb->pkt_use[STATIC_PKT_MAX_NUM*2] = 0; ++ up(&bcm_static_skb->osl_pkt_sem); ++ return; ++ } ++#endif ++ up(&bcm_static_skb->osl_pkt_sem); ++ ++ osl_pktfree(osh, p, send); ++ return; ++} ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ ++uint32 ++osl_pci_read_config(osl_t *osh, uint offset, uint size) ++{ ++ uint val = 0; ++ uint retry = PCI_CFG_RETRY; ++ ++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); ++ ++ /* only 4byte access supported */ ++ ASSERT(size == 4); ++ ++ do { ++ pci_read_config_dword(osh->pdev, offset, &val); ++ if (val != 0xffffffff) ++ break; ++ } while (retry--); ++ ++ ++ return (val); ++} ++ ++void ++osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val) ++{ ++ uint retry = PCI_CFG_RETRY; ++ ++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); ++ ++ /* only 4byte access supported */ ++ ASSERT(size == 4); ++ ++ do { ++ pci_write_config_dword(osh->pdev, offset, val); ++ if (offset != PCI_BAR0_WIN) ++ break; ++ if (osl_pci_read_config(osh, offset, size) == val) ++ break; ++ } while (retry--); ++ ++} ++ ++/* return bus # for the pci device pointed by osh->pdev */ ++uint ++osl_pci_bus(osl_t *osh) ++{ ++ ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); ++ ++ return ((struct pci_dev *)osh->pdev)->bus->number; ++} ++ ++/* return slot # for the pci device pointed by osh->pdev */ ++uint ++osl_pci_slot(osl_t *osh) ++{ ++ ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); ++ ++ return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn); ++} ++ ++/* return the pci device pointed by osh->pdev */ ++struct pci_dev * ++osl_pci_device(osl_t *osh) ++{ ++ ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); ++ ++ return osh->pdev; ++} ++ ++static void ++osl_pcmcia_attr(osl_t *osh, uint offset, char *buf, int size, bool write) ++{ ++} ++ ++void ++osl_pcmcia_read_attr(osl_t *osh, uint offset, void *buf, int size) ++{ ++ osl_pcmcia_attr(osh, offset, (char *) buf, size, FALSE); ++} ++ ++void ++osl_pcmcia_write_attr(osl_t *osh, uint offset, void *buf, int size) ++{ ++ osl_pcmcia_attr(osh, offset, (char *) buf, size, TRUE); ++} ++ ++void * ++osl_malloc(osl_t *osh, uint size) ++{ ++ void *addr; ++ ++ /* only ASSERT if osh is defined */ ++ if (osh) ++ ASSERT(osh->magic == OS_HANDLE_MAGIC); ++ ++#ifdef CONFIG_DHD_USE_STATIC_BUF ++ if (bcm_static_buf) ++ { ++ int i = 0; ++ if ((size >= PAGE_SIZE)&&(size <= STATIC_BUF_SIZE)) ++ { ++ down(&bcm_static_buf->static_sem); ++ ++ for (i = 0; i < STATIC_BUF_MAX_NUM; i++) ++ { ++ if (bcm_static_buf->buf_use[i] == 0) ++ break; ++ } ++ ++ if (i == STATIC_BUF_MAX_NUM) ++ { ++ up(&bcm_static_buf->static_sem); ++ AP6211_DEBUG("all static buff in use!\n"); ++ goto original; ++ } ++ ++ bcm_static_buf->buf_use[i] = 1; ++ up(&bcm_static_buf->static_sem); ++ ++ bzero(bcm_static_buf->buf_ptr+STATIC_BUF_SIZE*i, size); ++ if (osh) ++ atomic_add(size, &osh->malloced); ++ ++ return ((void *)(bcm_static_buf->buf_ptr+STATIC_BUF_SIZE*i)); ++ } ++ } ++original: ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ ++ if ((addr = kmalloc(size, GFP_ATOMIC)) == NULL) { ++ if (osh) ++ osh->failed++; ++ return (NULL); ++ } ++ if (osh) ++ atomic_add(size, &osh->malloced); ++ ++ return (addr); ++} ++ ++void ++osl_mfree(osl_t *osh, void *addr, uint size) ++{ ++#ifdef CONFIG_DHD_USE_STATIC_BUF ++ if (bcm_static_buf) ++ { ++ if ((addr > (void *)bcm_static_buf) && ((unsigned char *)addr ++ <= ((unsigned char *)bcm_static_buf + STATIC_BUF_TOTAL_LEN))) ++ { ++ int buf_idx = 0; ++ ++ buf_idx = ((unsigned char *)addr - bcm_static_buf->buf_ptr)/STATIC_BUF_SIZE; ++ ++ down(&bcm_static_buf->static_sem); ++ bcm_static_buf->buf_use[buf_idx] = 0; ++ up(&bcm_static_buf->static_sem); ++ ++ if (osh) { ++ ASSERT(osh->magic == OS_HANDLE_MAGIC); ++ atomic_sub(size, &osh->malloced); ++ } ++ return; ++ } ++ } ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ if (osh) { ++ ASSERT(osh->magic == OS_HANDLE_MAGIC); ++ atomic_sub(size, &osh->malloced); ++ } ++ kfree(addr); ++} ++ ++uint ++osl_malloced(osl_t *osh) ++{ ++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); ++ return (atomic_read(&osh->malloced)); ++} ++ ++uint ++osl_malloc_failed(osl_t *osh) ++{ ++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); ++ return (osh->failed); ++} ++ ++ ++uint ++osl_dma_consistent_align(void) ++{ ++ return (PAGE_SIZE); ++} ++ ++void* ++osl_dma_alloc_consistent(osl_t *osh, uint size, uint16 align_bits, uint *alloced, ulong *pap) ++{ ++ uint16 align = (1 << align_bits); ++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); ++ ++ if (!ISALIGNED(DMA_CONSISTENT_ALIGN, align)) ++ size += align; ++ *alloced = size; ++ ++ return (pci_alloc_consistent(osh->pdev, size, (dma_addr_t*)pap)); ++} ++ ++void ++osl_dma_free_consistent(osl_t *osh, void *va, uint size, ulong pa) ++{ ++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); ++ ++ pci_free_consistent(osh->pdev, size, va, (dma_addr_t)pa); ++} ++ ++uint BCMFASTPATH ++osl_dma_map(osl_t *osh, void *va, uint size, int direction) ++{ ++ int dir; ++ ++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); ++ dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE; ++ return (pci_map_single(osh->pdev, va, size, dir)); ++} ++ ++void BCMFASTPATH ++osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction) ++{ ++ int dir; ++ ++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); ++ dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE; ++ pci_unmap_single(osh->pdev, (uint32)pa, size, dir); ++} ++ ++#if defined(BCMASSERT_LOG) ++void ++osl_assert(const char *exp, const char *file, int line) ++{ ++ char tempbuf[256]; ++ const char *basename; ++ ++ basename = strrchr(file, '/'); ++ /* skip the '/' */ ++ if (basename) ++ basename++; ++ ++ if (!basename) ++ basename = file; ++ ++ snprintf(tempbuf, 64, "\"%s\": file \"%s\", line %d\n", ++ exp, basename, line); ++ ++ AP6211_DEBUG("%s", tempbuf); ++ ++ ++} ++#endif ++ ++void ++osl_delay(uint usec) ++{ ++ uint d; ++ ++ while (usec > 0) { ++ d = MIN(usec, 1000); ++ udelay(d); ++ usec -= d; ++ } ++} ++ ++ ++/* Clone a packet. ++ * The pkttag contents are NOT cloned. ++ */ ++void * ++osl_pktdup(osl_t *osh, void *skb) ++{ ++ void * p; ++ unsigned long irqflags; ++ ++ /* clear the CTFBUF flag if set and map the rest of the buffer ++ * before cloning. ++ */ ++ PKTCTFMAP(osh, skb); ++ ++ if ((p = skb_clone((struct sk_buff *)skb, GFP_ATOMIC)) == NULL) ++ return NULL; ++ ++#ifdef CTFPOOL ++ if (PKTISFAST(osh, skb)) { ++ ctfpool_t *ctfpool; ++ ++ /* if the buffer allocated from ctfpool is cloned then ++ * we can't be sure when it will be freed. since there ++ * is a chance that we will be losing a buffer ++ * from our pool, we increment the refill count for the ++ * object to be alloced later. ++ */ ++ ctfpool = (ctfpool_t *)CTFPOOLPTR(osh, skb); ++ ASSERT(ctfpool != NULL); ++ PKTCLRFAST(osh, p); ++ PKTCLRFAST(osh, skb); ++ ctfpool->refills++; ++ } ++#endif /* CTFPOOL */ ++ ++ /* skb_clone copies skb->cb.. we don't want that */ ++ if (osh->pub.pkttag) ++ bzero((void*)((struct sk_buff *)p)->cb, OSL_PKTTAG_SZ); ++ ++ /* Increment the packet counter */ ++ spin_lock_irqsave(&osh->pktalloc_lock, irqflags); ++ osh->pub.pktalloced++; ++ spin_unlock_irqrestore(&osh->pktalloc_lock, irqflags); ++ return (p); ++} ++ ++ ++/* ++ * OSLREGOPS specifies the use of osl_XXX routines to be used for register access ++ */ ++ ++/* ++ * BINOSL selects the slightly slower function-call-based binary compatible osl. ++ */ ++ ++/* Linux Kernel: File Operations: start */ ++void * ++osl_os_open_image(char *filename) ++{ ++ struct file *fp; ++ ++ fp = filp_open(filename, O_RDONLY, 0); ++ /* ++ * 2.6.11 (FC4) supports filp_open() but later revs don't? ++ * Alternative: ++ * fp = open_namei(AT_FDCWD, filename, O_RD, 0); ++ * ??? ++ */ ++ if (IS_ERR(fp)) ++ fp = NULL; ++ ++ return fp; ++} ++ ++int ++osl_os_get_image_block(char *buf, int len, void *image) ++{ ++ struct file *fp = (struct file *)image; ++ int rdlen; ++ ++ if (!image) ++ return 0; ++ ++ rdlen = kernel_read(fp, fp->f_pos, buf, len); ++ if (rdlen > 0) ++ fp->f_pos += rdlen; ++ ++ return rdlen; ++} ++ ++void ++osl_os_close_image(void *image) ++{ ++ if (image) ++ filp_close((struct file *)image, NULL); ++} ++/* Linux Kernel: File Operations: end */ +diff --git a/drivers/net/wireless/ap6211/sbutils.c b/drivers/net/wireless/ap6211/sbutils.c +new file mode 100755 +index 0000000..89f9eb3 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/sbutils.c +@@ -0,0 +1,1003 @@ ++/* ++ * Misc utility routines for accessing chip-specific features ++ * of the SiliconBackplane-based Broadcom chips. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: sbutils.c 310902 2012-01-26 19:45:33Z $ ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "siutils_priv.h" ++ ++#include ++ ++ ++/* local prototypes */ ++static uint _sb_coreidx(si_info_t *sii, uint32 sba); ++static uint _sb_scan(si_info_t *sii, uint32 sba, void *regs, uint bus, uint32 sbba, ++ uint ncores); ++static uint32 _sb_coresba(si_info_t *sii); ++static void *_sb_setcoreidx(si_info_t *sii, uint coreidx); ++ ++#define SET_SBREG(sii, r, mask, val) \ ++ W_SBREG((sii), (r), ((R_SBREG((sii), (r)) & ~(mask)) | (val))) ++#define REGS2SB(va) (sbconfig_t*) ((int8*)(va) + SBCONFIGOFF) ++ ++/* sonicsrev */ ++#define SONICS_2_2 (SBIDL_RV_2_2 >> SBIDL_RV_SHIFT) ++#define SONICS_2_3 (SBIDL_RV_2_3 >> SBIDL_RV_SHIFT) ++ ++#define R_SBREG(sii, sbr) sb_read_sbreg((sii), (sbr)) ++#define W_SBREG(sii, sbr, v) sb_write_sbreg((sii), (sbr), (v)) ++#define AND_SBREG(sii, sbr, v) W_SBREG((sii), (sbr), (R_SBREG((sii), (sbr)) & (v))) ++#define OR_SBREG(sii, sbr, v) W_SBREG((sii), (sbr), (R_SBREG((sii), (sbr)) | (v))) ++ ++static uint32 ++sb_read_sbreg(si_info_t *sii, volatile uint32 *sbr) ++{ ++ uint8 tmp; ++ uint32 val, intr_val = 0; ++ ++ ++ /* ++ * compact flash only has 11 bits address, while we needs 12 bits address. ++ * MEM_SEG will be OR'd with other 11 bits address in hardware, ++ * so we program MEM_SEG with 12th bit when necessary(access sb regsiters). ++ * For normal PCMCIA bus(CFTable_regwinsz > 2k), do nothing special ++ */ ++ if (PCMCIA(sii)) { ++ INTR_OFF(sii, intr_val); ++ tmp = 1; ++ OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); ++ sbr = (volatile uint32 *)((uintptr)sbr & ~(1 << 11)); /* mask out bit 11 */ ++ } ++ ++ val = R_REG(sii->osh, sbr); ++ ++ if (PCMCIA(sii)) { ++ tmp = 0; ++ OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); ++ INTR_RESTORE(sii, intr_val); ++ } ++ ++ return (val); ++} ++ ++static void ++sb_write_sbreg(si_info_t *sii, volatile uint32 *sbr, uint32 v) ++{ ++ uint8 tmp; ++ volatile uint32 dummy; ++ uint32 intr_val = 0; ++ ++ ++ /* ++ * compact flash only has 11 bits address, while we needs 12 bits address. ++ * MEM_SEG will be OR'd with other 11 bits address in hardware, ++ * so we program MEM_SEG with 12th bit when necessary(access sb regsiters). ++ * For normal PCMCIA bus(CFTable_regwinsz > 2k), do nothing special ++ */ ++ if (PCMCIA(sii)) { ++ INTR_OFF(sii, intr_val); ++ tmp = 1; ++ OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); ++ sbr = (volatile uint32 *)((uintptr)sbr & ~(1 << 11)); /* mask out bit 11 */ ++ } ++ ++ if (BUSTYPE(sii->pub.bustype) == PCMCIA_BUS) { ++ dummy = R_REG(sii->osh, sbr); ++ BCM_REFERENCE(dummy); ++ W_REG(sii->osh, (volatile uint16 *)sbr, (uint16)(v & 0xffff)); ++ dummy = R_REG(sii->osh, sbr); ++ BCM_REFERENCE(dummy); ++ W_REG(sii->osh, ((volatile uint16 *)sbr + 1), (uint16)((v >> 16) & 0xffff)); ++ } else ++ W_REG(sii->osh, sbr, v); ++ ++ if (PCMCIA(sii)) { ++ tmp = 0; ++ OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); ++ INTR_RESTORE(sii, intr_val); ++ } ++} ++ ++uint ++sb_coreid(si_t *sih) ++{ ++ si_info_t *sii; ++ sbconfig_t *sb; ++ ++ sii = SI_INFO(sih); ++ sb = REGS2SB(sii->curmap); ++ ++ return ((R_SBREG(sii, &sb->sbidhigh) & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT); ++} ++ ++uint ++sb_intflag(si_t *sih) ++{ ++ si_info_t *sii; ++ void *corereg; ++ sbconfig_t *sb; ++ uint origidx, intflag, intr_val = 0; ++ ++ sii = SI_INFO(sih); ++ ++ INTR_OFF(sii, intr_val); ++ origidx = si_coreidx(sih); ++ corereg = si_setcore(sih, CC_CORE_ID, 0); ++ ASSERT(corereg != NULL); ++ sb = REGS2SB(corereg); ++ intflag = R_SBREG(sii, &sb->sbflagst); ++ sb_setcoreidx(sih, origidx); ++ INTR_RESTORE(sii, intr_val); ++ ++ return intflag; ++} ++ ++uint ++sb_flag(si_t *sih) ++{ ++ si_info_t *sii; ++ sbconfig_t *sb; ++ ++ sii = SI_INFO(sih); ++ sb = REGS2SB(sii->curmap); ++ ++ return R_SBREG(sii, &sb->sbtpsflag) & SBTPS_NUM0_MASK; ++} ++ ++void ++sb_setint(si_t *sih, int siflag) ++{ ++ si_info_t *sii; ++ sbconfig_t *sb; ++ uint32 vec; ++ ++ sii = SI_INFO(sih); ++ sb = REGS2SB(sii->curmap); ++ ++ if (siflag == -1) ++ vec = 0; ++ else ++ vec = 1 << siflag; ++ W_SBREG(sii, &sb->sbintvec, vec); ++} ++ ++/* return core index of the core with address 'sba' */ ++static uint ++_sb_coreidx(si_info_t *sii, uint32 sba) ++{ ++ uint i; ++ ++ for (i = 0; i < sii->numcores; i ++) ++ if (sba == sii->coresba[i]) ++ return i; ++ return BADIDX; ++} ++ ++/* return core address of the current core */ ++static uint32 ++_sb_coresba(si_info_t *sii) ++{ ++ uint32 sbaddr; ++ ++ ++ switch (BUSTYPE(sii->pub.bustype)) { ++ case SI_BUS: { ++ sbconfig_t *sb = REGS2SB(sii->curmap); ++ sbaddr = sb_base(R_SBREG(sii, &sb->sbadmatch0)); ++ break; ++ } ++ ++ case PCI_BUS: ++ sbaddr = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32)); ++ break; ++ ++ case PCMCIA_BUS: { ++ uint8 tmp = 0; ++ OSL_PCMCIA_READ_ATTR(sii->osh, PCMCIA_ADDR0, &tmp, 1); ++ sbaddr = (uint32)tmp << 12; ++ OSL_PCMCIA_READ_ATTR(sii->osh, PCMCIA_ADDR1, &tmp, 1); ++ sbaddr |= (uint32)tmp << 16; ++ OSL_PCMCIA_READ_ATTR(sii->osh, PCMCIA_ADDR2, &tmp, 1); ++ sbaddr |= (uint32)tmp << 24; ++ break; ++ } ++ ++ case SPI_BUS: ++ case SDIO_BUS: ++ sbaddr = (uint32)(uintptr)sii->curmap; ++ break; ++ ++ ++ default: ++ sbaddr = BADCOREADDR; ++ break; ++ } ++ ++ return sbaddr; ++} ++ ++uint ++sb_corevendor(si_t *sih) ++{ ++ si_info_t *sii; ++ sbconfig_t *sb; ++ ++ sii = SI_INFO(sih); ++ sb = REGS2SB(sii->curmap); ++ ++ return ((R_SBREG(sii, &sb->sbidhigh) & SBIDH_VC_MASK) >> SBIDH_VC_SHIFT); ++} ++ ++uint ++sb_corerev(si_t *sih) ++{ ++ si_info_t *sii; ++ sbconfig_t *sb; ++ uint sbidh; ++ ++ sii = SI_INFO(sih); ++ sb = REGS2SB(sii->curmap); ++ sbidh = R_SBREG(sii, &sb->sbidhigh); ++ ++ return (SBCOREREV(sbidh)); ++} ++ ++/* set core-specific control flags */ ++void ++sb_core_cflags_wo(si_t *sih, uint32 mask, uint32 val) ++{ ++ si_info_t *sii; ++ sbconfig_t *sb; ++ uint32 w; ++ ++ sii = SI_INFO(sih); ++ sb = REGS2SB(sii->curmap); ++ ++ ASSERT((val & ~mask) == 0); ++ ++ /* mask and set */ ++ w = (R_SBREG(sii, &sb->sbtmstatelow) & ~(mask << SBTML_SICF_SHIFT)) | ++ (val << SBTML_SICF_SHIFT); ++ W_SBREG(sii, &sb->sbtmstatelow, w); ++} ++ ++/* set/clear core-specific control flags */ ++uint32 ++sb_core_cflags(si_t *sih, uint32 mask, uint32 val) ++{ ++ si_info_t *sii; ++ sbconfig_t *sb; ++ uint32 w; ++ ++ sii = SI_INFO(sih); ++ sb = REGS2SB(sii->curmap); ++ ++ ASSERT((val & ~mask) == 0); ++ ++ /* mask and set */ ++ if (mask || val) { ++ w = (R_SBREG(sii, &sb->sbtmstatelow) & ~(mask << SBTML_SICF_SHIFT)) | ++ (val << SBTML_SICF_SHIFT); ++ W_SBREG(sii, &sb->sbtmstatelow, w); ++ } ++ ++ /* return the new value ++ * for write operation, the following readback ensures the completion of write opration. ++ */ ++ return (R_SBREG(sii, &sb->sbtmstatelow) >> SBTML_SICF_SHIFT); ++} ++ ++/* set/clear core-specific status flags */ ++uint32 ++sb_core_sflags(si_t *sih, uint32 mask, uint32 val) ++{ ++ si_info_t *sii; ++ sbconfig_t *sb; ++ uint32 w; ++ ++ sii = SI_INFO(sih); ++ sb = REGS2SB(sii->curmap); ++ ++ ASSERT((val & ~mask) == 0); ++ ASSERT((mask & ~SISF_CORE_BITS) == 0); ++ ++ /* mask and set */ ++ if (mask || val) { ++ w = (R_SBREG(sii, &sb->sbtmstatehigh) & ~(mask << SBTMH_SISF_SHIFT)) | ++ (val << SBTMH_SISF_SHIFT); ++ W_SBREG(sii, &sb->sbtmstatehigh, w); ++ } ++ ++ /* return the new value */ ++ return (R_SBREG(sii, &sb->sbtmstatehigh) >> SBTMH_SISF_SHIFT); ++} ++ ++bool ++sb_iscoreup(si_t *sih) ++{ ++ si_info_t *sii; ++ sbconfig_t *sb; ++ ++ sii = SI_INFO(sih); ++ sb = REGS2SB(sii->curmap); ++ ++ return ((R_SBREG(sii, &sb->sbtmstatelow) & ++ (SBTML_RESET | SBTML_REJ_MASK | (SICF_CLOCK_EN << SBTML_SICF_SHIFT))) == ++ (SICF_CLOCK_EN << SBTML_SICF_SHIFT)); ++} ++ ++/* ++ * Switch to 'coreidx', issue a single arbitrary 32bit register mask&set operation, ++ * switch back to the original core, and return the new value. ++ * ++ * When using the silicon backplane, no fidleing with interrupts or core switches are needed. ++ * ++ * Also, when using pci/pcie, we can optimize away the core switching for pci registers ++ * and (on newer pci cores) chipcommon registers. ++ */ ++uint ++sb_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) ++{ ++ uint origidx = 0; ++ uint32 *r = NULL; ++ uint w; ++ uint intr_val = 0; ++ bool fast = FALSE; ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ ++ ASSERT(GOODIDX(coreidx)); ++ ASSERT(regoff < SI_CORE_SIZE); ++ ASSERT((val & ~mask) == 0); ++ ++ if (coreidx >= SI_MAXCORES) ++ return 0; ++ ++ if (BUSTYPE(sii->pub.bustype) == SI_BUS) { ++ /* If internal bus, we can always get at everything */ ++ fast = TRUE; ++ /* map if does not exist */ ++ if (!sii->regs[coreidx]) { ++ sii->regs[coreidx] = REG_MAP(sii->coresba[coreidx], ++ SI_CORE_SIZE); ++ ASSERT(GOODREGS(sii->regs[coreidx])); ++ } ++ r = (uint32 *)((uchar *)sii->regs[coreidx] + regoff); ++ } else if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { ++ /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ ++ ++ if ((sii->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { ++ /* Chipc registers are mapped at 12KB */ ++ ++ fast = TRUE; ++ r = (uint32 *)((char *)sii->curmap + PCI_16KB0_CCREGS_OFFSET + regoff); ++ } else if (sii->pub.buscoreidx == coreidx) { ++ /* pci registers are at either in the last 2KB of an 8KB window ++ * or, in pcie and pci rev 13 at 8KB ++ */ ++ fast = TRUE; ++ if (SI_FAST(sii)) ++ r = (uint32 *)((char *)sii->curmap + ++ PCI_16KB0_PCIREGS_OFFSET + regoff); ++ else ++ r = (uint32 *)((char *)sii->curmap + ++ ((regoff >= SBCONFIGOFF) ? ++ PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) + ++ regoff); ++ } ++ } ++ ++ if (!fast) { ++ INTR_OFF(sii, intr_val); ++ ++ /* save current core index */ ++ origidx = si_coreidx(&sii->pub); ++ ++ /* switch core */ ++ r = (uint32*) ((uchar*)sb_setcoreidx(&sii->pub, coreidx) + regoff); ++ } ++ ASSERT(r != NULL); ++ ++ /* mask and set */ ++ if (mask || val) { ++ if (regoff >= SBCONFIGOFF) { ++ w = (R_SBREG(sii, r) & ~mask) | val; ++ W_SBREG(sii, r, w); ++ } else { ++ w = (R_REG(sii->osh, r) & ~mask) | val; ++ W_REG(sii->osh, r, w); ++ } ++ } ++ ++ /* readback */ ++ if (regoff >= SBCONFIGOFF) ++ w = R_SBREG(sii, r); ++ else { ++ if ((CHIPID(sii->pub.chip) == BCM5354_CHIP_ID) && ++ (coreidx == SI_CC_IDX) && ++ (regoff == OFFSETOF(chipcregs_t, watchdog))) { ++ w = val; ++ } else ++ w = R_REG(sii->osh, r); ++ } ++ ++ if (!fast) { ++ /* restore core index */ ++ if (origidx != coreidx) ++ sb_setcoreidx(&sii->pub, origidx); ++ ++ INTR_RESTORE(sii, intr_val); ++ } ++ ++ return (w); ++} ++ ++/* Scan the enumeration space to find all cores starting from the given ++ * bus 'sbba'. Append coreid and other info to the lists in 'si'. 'sba' ++ * is the default core address at chip POR time and 'regs' is the virtual ++ * address that the default core is mapped at. 'ncores' is the number of ++ * cores expected on bus 'sbba'. It returns the total number of cores ++ * starting from bus 'sbba', inclusive. ++ */ ++#define SB_MAXBUSES 2 ++static uint ++_sb_scan(si_info_t *sii, uint32 sba, void *regs, uint bus, uint32 sbba, uint numcores) ++{ ++ uint next; ++ uint ncc = 0; ++ uint i; ++ ++ if (bus >= SB_MAXBUSES) { ++ AP6211_ERR("_sb_scan: bus 0x%08x at level %d is too deep to scan\n", sbba, bus); ++ return 0; ++ } ++ AP6211_DEBUG("_sb_scan: scan bus 0x%08x assume %u cores\n", sbba, numcores); ++ ++ /* Scan all cores on the bus starting from core 0. ++ * Core addresses must be contiguous on each bus. ++ */ ++ for (i = 0, next = sii->numcores; i < numcores && next < SB_BUS_MAXCORES; i++, next++) { ++ sii->coresba[next] = sbba + (i * SI_CORE_SIZE); ++ ++ /* keep and reuse the initial register mapping */ ++ if ((BUSTYPE(sii->pub.bustype) == SI_BUS) && (sii->coresba[next] == sba)) { ++ AP6211_DEBUG("_sb_scan: reuse mapped regs %p for core %u\n", regs, next); ++ sii->regs[next] = regs; ++ } ++ ++ /* change core to 'next' and read its coreid */ ++ sii->curmap = _sb_setcoreidx(sii, next); ++ sii->curidx = next; ++ ++ sii->coreid[next] = sb_coreid(&sii->pub); ++ ++ /* core specific processing... */ ++ /* chipc provides # cores */ ++ if (sii->coreid[next] == CC_CORE_ID) { ++ chipcregs_t *cc = (chipcregs_t *)sii->curmap; ++ uint32 ccrev = sb_corerev(&sii->pub); ++ ++ /* determine numcores - this is the total # cores in the chip */ ++ if (((ccrev == 4) || (ccrev >= 6))) ++ numcores = (R_REG(sii->osh, &cc->chipid) & CID_CC_MASK) >> ++ CID_CC_SHIFT; ++ else { ++ /* Older chips */ ++ uint chip = CHIPID(sii->pub.chip); ++ ++ if (chip == BCM4306_CHIP_ID) /* < 4306c0 */ ++ numcores = 6; ++ else if (chip == BCM4704_CHIP_ID) ++ numcores = 9; ++ else if (chip == BCM5365_CHIP_ID) ++ numcores = 7; ++ else { ++ AP6211_ERR("sb_chip2numcores: unsupported chip 0x%x\n", ++ chip); ++ ASSERT(0); ++ numcores = 1; ++ } ++ } ++ AP6211_DEBUG("_sb_scan: there are %u cores in the chip %s\n", numcores, ++ sii->pub.issim ? "QT" : ""); ++ } ++ /* scan bridged SB(s) and add results to the end of the list */ ++ else if (sii->coreid[next] == OCP_CORE_ID) { ++ sbconfig_t *sb = REGS2SB(sii->curmap); ++ uint32 nsbba = R_SBREG(sii, &sb->sbadmatch1); ++ uint nsbcc; ++ ++ sii->numcores = next + 1; ++ ++ if ((nsbba & 0xfff00000) != SI_ENUM_BASE) ++ continue; ++ nsbba &= 0xfffff000; ++ if (_sb_coreidx(sii, nsbba) != BADIDX) ++ continue; ++ ++ nsbcc = (R_SBREG(sii, &sb->sbtmstatehigh) & 0x000f0000) >> 16; ++ nsbcc = _sb_scan(sii, sba, regs, bus + 1, nsbba, nsbcc); ++ if (sbba == SI_ENUM_BASE) ++ numcores -= nsbcc; ++ ncc += nsbcc; ++ } ++ } ++ ++ AP6211_DEBUG("_sb_scan: found %u cores on bus 0x%08x\n", i, sbba); ++ ++ sii->numcores = i + ncc; ++ return sii->numcores; ++} ++ ++/* scan the sb enumerated space to identify all cores */ ++void ++sb_scan(si_t *sih, void *regs, uint devid) ++{ ++ si_info_t *sii; ++ uint32 origsba; ++ sbconfig_t *sb; ++ ++ sii = SI_INFO(sih); ++ sb = REGS2SB(sii->curmap); ++ ++ sii->pub.socirev = (R_SBREG(sii, &sb->sbidlow) & SBIDL_RV_MASK) >> SBIDL_RV_SHIFT; ++ ++ /* Save the current core info and validate it later till we know ++ * for sure what is good and what is bad. ++ */ ++ origsba = _sb_coresba(sii); ++ ++ /* scan all SB(s) starting from SI_ENUM_BASE */ ++ sii->numcores = _sb_scan(sii, origsba, regs, 0, SI_ENUM_BASE, 1); ++} ++ ++/* ++ * This function changes logical "focus" to the indicated core; ++ * must be called with interrupts off. ++ * Moreover, callers should keep interrupts off during switching out of and back to d11 core ++ */ ++void * ++sb_setcoreidx(si_t *sih, uint coreidx) ++{ ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ ++ if (coreidx >= sii->numcores) ++ return (NULL); ++ ++ /* ++ * If the user has provided an interrupt mask enabled function, ++ * then assert interrupts are disabled before switching the core. ++ */ ++ ASSERT((sii->intrsenabled_fn == NULL) || !(*(sii)->intrsenabled_fn)((sii)->intr_arg)); ++ ++ sii->curmap = _sb_setcoreidx(sii, coreidx); ++ sii->curidx = coreidx; ++ ++ return (sii->curmap); ++} ++ ++/* This function changes the logical "focus" to the indicated core. ++ * Return the current core's virtual address. ++ */ ++static void * ++_sb_setcoreidx(si_info_t *sii, uint coreidx) ++{ ++ uint32 sbaddr = sii->coresba[coreidx]; ++ void *regs; ++ ++ switch (BUSTYPE(sii->pub.bustype)) { ++ case SI_BUS: ++ /* map new one */ ++ if (!sii->regs[coreidx]) { ++ sii->regs[coreidx] = REG_MAP(sbaddr, SI_CORE_SIZE); ++ ASSERT(GOODREGS(sii->regs[coreidx])); ++ } ++ regs = sii->regs[coreidx]; ++ break; ++ ++ case PCI_BUS: ++ /* point bar0 window */ ++ OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, sbaddr); ++ regs = sii->curmap; ++ break; ++ ++ case PCMCIA_BUS: { ++ uint8 tmp = (sbaddr >> 12) & 0x0f; ++ OSL_PCMCIA_WRITE_ATTR(sii->osh, PCMCIA_ADDR0, &tmp, 1); ++ tmp = (sbaddr >> 16) & 0xff; ++ OSL_PCMCIA_WRITE_ATTR(sii->osh, PCMCIA_ADDR1, &tmp, 1); ++ tmp = (sbaddr >> 24) & 0xff; ++ OSL_PCMCIA_WRITE_ATTR(sii->osh, PCMCIA_ADDR2, &tmp, 1); ++ regs = sii->curmap; ++ break; ++ } ++ case SPI_BUS: ++ case SDIO_BUS: ++ /* map new one */ ++ if (!sii->regs[coreidx]) { ++ sii->regs[coreidx] = (void *)(uintptr)sbaddr; ++ ASSERT(GOODREGS(sii->regs[coreidx])); ++ } ++ regs = sii->regs[coreidx]; ++ break; ++ ++ ++ default: ++ ASSERT(0); ++ regs = NULL; ++ break; ++ } ++ ++ return regs; ++} ++ ++/* Return the address of sbadmatch0/1/2/3 register */ ++static volatile uint32 * ++sb_admatch(si_info_t *sii, uint asidx) ++{ ++ sbconfig_t *sb; ++ volatile uint32 *addrm; ++ ++ sb = REGS2SB(sii->curmap); ++ ++ switch (asidx) { ++ case 0: ++ addrm = &sb->sbadmatch0; ++ break; ++ ++ case 1: ++ addrm = &sb->sbadmatch1; ++ break; ++ ++ case 2: ++ addrm = &sb->sbadmatch2; ++ break; ++ ++ case 3: ++ addrm = &sb->sbadmatch3; ++ break; ++ ++ default: ++ AP6211_ERR("%s: Address space index (%d) out of range\n", __FUNCTION__, asidx); ++ return 0; ++ } ++ ++ return (addrm); ++} ++ ++/* Return the number of address spaces in current core */ ++int ++sb_numaddrspaces(si_t *sih) ++{ ++ si_info_t *sii; ++ sbconfig_t *sb; ++ ++ sii = SI_INFO(sih); ++ sb = REGS2SB(sii->curmap); ++ ++ /* + 1 because of enumeration space */ ++ return ((R_SBREG(sii, &sb->sbidlow) & SBIDL_AR_MASK) >> SBIDL_AR_SHIFT) + 1; ++} ++ ++/* Return the address of the nth address space in the current core */ ++uint32 ++sb_addrspace(si_t *sih, uint asidx) ++{ ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ ++ return (sb_base(R_SBREG(sii, sb_admatch(sii, asidx)))); ++} ++ ++/* Return the size of the nth address space in the current core */ ++uint32 ++sb_addrspacesize(si_t *sih, uint asidx) ++{ ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ ++ return (sb_size(R_SBREG(sii, sb_admatch(sii, asidx)))); ++} ++ ++ ++/* do buffered registers update */ ++void ++sb_commit(si_t *sih) ++{ ++ si_info_t *sii; ++ uint origidx; ++ uint intr_val = 0; ++ ++ sii = SI_INFO(sih); ++ ++ origidx = sii->curidx; ++ ASSERT(GOODIDX(origidx)); ++ ++ INTR_OFF(sii, intr_val); ++ ++ /* switch over to chipcommon core if there is one, else use pci */ ++ if (sii->pub.ccrev != NOREV) { ++ chipcregs_t *ccregs = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); ++ ASSERT(ccregs != NULL); ++ ++ /* do the buffer registers update */ ++ W_REG(sii->osh, &ccregs->broadcastaddress, SB_COMMIT); ++ W_REG(sii->osh, &ccregs->broadcastdata, 0x0); ++ } else ++ ASSERT(0); ++ ++ /* restore core index */ ++ sb_setcoreidx(sih, origidx); ++ INTR_RESTORE(sii, intr_val); ++} ++ ++void ++sb_core_disable(si_t *sih, uint32 bits) ++{ ++ si_info_t *sii; ++ volatile uint32 dummy; ++ sbconfig_t *sb; ++ ++ sii = SI_INFO(sih); ++ ++ ASSERT(GOODREGS(sii->curmap)); ++ sb = REGS2SB(sii->curmap); ++ ++ /* if core is already in reset, just return */ ++ if (R_SBREG(sii, &sb->sbtmstatelow) & SBTML_RESET) ++ return; ++ ++ /* if clocks are not enabled, put into reset and return */ ++ if ((R_SBREG(sii, &sb->sbtmstatelow) & (SICF_CLOCK_EN << SBTML_SICF_SHIFT)) == 0) ++ goto disable; ++ ++ /* set target reject and spin until busy is clear (preserve core-specific bits) */ ++ OR_SBREG(sii, &sb->sbtmstatelow, SBTML_REJ); ++ dummy = R_SBREG(sii, &sb->sbtmstatelow); ++ BCM_REFERENCE(dummy); ++ OSL_DELAY(1); ++ SPINWAIT((R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_BUSY), 100000); ++ if (R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_BUSY) ++ AP6211_ERR("%s: target state still busy\n", __FUNCTION__); ++ ++ if (R_SBREG(sii, &sb->sbidlow) & SBIDL_INIT) { ++ OR_SBREG(sii, &sb->sbimstate, SBIM_RJ); ++ dummy = R_SBREG(sii, &sb->sbimstate); ++ BCM_REFERENCE(dummy); ++ OSL_DELAY(1); ++ SPINWAIT((R_SBREG(sii, &sb->sbimstate) & SBIM_BY), 100000); ++ } ++ ++ /* set reset and reject while enabling the clocks */ ++ W_SBREG(sii, &sb->sbtmstatelow, ++ (((bits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) | ++ SBTML_REJ | SBTML_RESET)); ++ dummy = R_SBREG(sii, &sb->sbtmstatelow); ++ BCM_REFERENCE(dummy); ++ OSL_DELAY(10); ++ ++ /* don't forget to clear the initiator reject bit */ ++ if (R_SBREG(sii, &sb->sbidlow) & SBIDL_INIT) ++ AND_SBREG(sii, &sb->sbimstate, ~SBIM_RJ); ++ ++disable: ++ /* leave reset and reject asserted */ ++ W_SBREG(sii, &sb->sbtmstatelow, ((bits << SBTML_SICF_SHIFT) | SBTML_REJ | SBTML_RESET)); ++ OSL_DELAY(1); ++} ++ ++/* reset and re-enable a core ++ * inputs: ++ * bits - core specific bits that are set during and after reset sequence ++ * resetbits - core specific bits that are set only during reset sequence ++ */ ++void ++sb_core_reset(si_t *sih, uint32 bits, uint32 resetbits) ++{ ++ si_info_t *sii; ++ sbconfig_t *sb; ++ volatile uint32 dummy; ++ ++ sii = SI_INFO(sih); ++ ASSERT(GOODREGS(sii->curmap)); ++ sb = REGS2SB(sii->curmap); ++ ++ /* ++ * Must do the disable sequence first to work for arbitrary current core state. ++ */ ++ sb_core_disable(sih, (bits | resetbits)); ++ ++ /* ++ * Now do the initialization sequence. ++ */ ++ ++ /* set reset while enabling the clock and forcing them on throughout the core */ ++ W_SBREG(sii, &sb->sbtmstatelow, ++ (((bits | resetbits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) | ++ SBTML_RESET)); ++ dummy = R_SBREG(sii, &sb->sbtmstatelow); ++ BCM_REFERENCE(dummy); ++ OSL_DELAY(1); ++ ++ if (R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_SERR) { ++ W_SBREG(sii, &sb->sbtmstatehigh, 0); ++ } ++ if ((dummy = R_SBREG(sii, &sb->sbimstate)) & (SBIM_IBE | SBIM_TO)) { ++ AND_SBREG(sii, &sb->sbimstate, ~(SBIM_IBE | SBIM_TO)); ++ } ++ ++ /* clear reset and allow it to propagate throughout the core */ ++ W_SBREG(sii, &sb->sbtmstatelow, ++ ((bits | resetbits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT)); ++ dummy = R_SBREG(sii, &sb->sbtmstatelow); ++ BCM_REFERENCE(dummy); ++ OSL_DELAY(1); ++ ++ /* leave clock enabled */ ++ W_SBREG(sii, &sb->sbtmstatelow, ((bits | SICF_CLOCK_EN) << SBTML_SICF_SHIFT)); ++ dummy = R_SBREG(sii, &sb->sbtmstatelow); ++ BCM_REFERENCE(dummy); ++ OSL_DELAY(1); ++} ++ ++/* ++ * Set the initiator timeout for the "master core". ++ * The master core is defined to be the core in control ++ * of the chip and so it issues accesses to non-memory ++ * locations (Because of dma *any* core can access memeory). ++ * ++ * The routine uses the bus to decide who is the master: ++ * SI_BUS => mips ++ * JTAG_BUS => chipc ++ * PCI_BUS => pci or pcie ++ * PCMCIA_BUS => pcmcia ++ * SDIO_BUS => pcmcia ++ * ++ * This routine exists so callers can disable initiator ++ * timeouts so accesses to very slow devices like otp ++ * won't cause an abort. The routine allows arbitrary ++ * settings of the service and request timeouts, though. ++ * ++ * Returns the timeout state before changing it or -1 ++ * on error. ++ */ ++ ++#define TO_MASK (SBIMCL_RTO_MASK | SBIMCL_STO_MASK) ++ ++uint32 ++sb_set_initiator_to(si_t *sih, uint32 to, uint idx) ++{ ++ si_info_t *sii; ++ uint origidx; ++ uint intr_val = 0; ++ uint32 tmp, ret = 0xffffffff; ++ sbconfig_t *sb; ++ ++ sii = SI_INFO(sih); ++ ++ if ((to & ~TO_MASK) != 0) ++ return ret; ++ ++ /* Figure out the master core */ ++ if (idx == BADIDX) { ++ switch (BUSTYPE(sii->pub.bustype)) { ++ case PCI_BUS: ++ idx = sii->pub.buscoreidx; ++ break; ++ case JTAG_BUS: ++ idx = SI_CC_IDX; ++ break; ++ case PCMCIA_BUS: ++ case SDIO_BUS: ++ idx = si_findcoreidx(sih, PCMCIA_CORE_ID, 0); ++ break; ++ case SI_BUS: ++ idx = si_findcoreidx(sih, MIPS33_CORE_ID, 0); ++ break; ++ default: ++ ASSERT(0); ++ } ++ if (idx == BADIDX) ++ return ret; ++ } ++ ++ INTR_OFF(sii, intr_val); ++ origidx = si_coreidx(sih); ++ ++ sb = REGS2SB(sb_setcoreidx(sih, idx)); ++ ++ tmp = R_SBREG(sii, &sb->sbimconfiglow); ++ ret = tmp & TO_MASK; ++ W_SBREG(sii, &sb->sbimconfiglow, (tmp & ~TO_MASK) | to); ++ ++ sb_commit(sih); ++ sb_setcoreidx(sih, origidx); ++ INTR_RESTORE(sii, intr_val); ++ return ret; ++} ++ ++uint32 ++sb_base(uint32 admatch) ++{ ++ uint32 base; ++ uint type; ++ ++ type = admatch & SBAM_TYPE_MASK; ++ ASSERT(type < 3); ++ ++ base = 0; ++ ++ if (type == 0) { ++ base = admatch & SBAM_BASE0_MASK; ++ } else if (type == 1) { ++ ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ ++ base = admatch & SBAM_BASE1_MASK; ++ } else if (type == 2) { ++ ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ ++ base = admatch & SBAM_BASE2_MASK; ++ } ++ ++ return (base); ++} ++ ++uint32 ++sb_size(uint32 admatch) ++{ ++ uint32 size; ++ uint type; ++ ++ type = admatch & SBAM_TYPE_MASK; ++ ASSERT(type < 3); ++ ++ size = 0; ++ ++ if (type == 0) { ++ size = 1 << (((admatch & SBAM_ADINT0_MASK) >> SBAM_ADINT0_SHIFT) + 1); ++ } else if (type == 1) { ++ ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ ++ size = 1 << (((admatch & SBAM_ADINT1_MASK) >> SBAM_ADINT1_SHIFT) + 1); ++ } else if (type == 2) { ++ ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ ++ size = 1 << (((admatch & SBAM_ADINT2_MASK) >> SBAM_ADINT2_SHIFT) + 1); ++ } ++ ++ return (size); ++} +diff --git a/drivers/net/wireless/ap6211/siutils.c b/drivers/net/wireless/ap6211/siutils.c +new file mode 100755 +index 0000000..f917c41 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/siutils.c +@@ -0,0 +1,2472 @@ ++/* ++ * Misc utility routines for accessing chip-specific features ++ * of the SiliconBackplane-based Broadcom chips. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: siutils.c 347632 2012-07-27 11:00:35Z $ ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "siutils_priv.h" ++ ++#include ++ ++/* local prototypes */ ++static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, ++ uint bustype, void *sdh, char **vars, uint *varsz); ++static bool si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh); ++static bool si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin, ++ uint *origidx, void *regs); ++ ++ ++ ++/* global variable to indicate reservation/release of gpio's */ ++static uint32 si_gpioreservation = 0; ++ ++/* global flag to prevent shared resources from being initialized multiple times in si_attach() */ ++ ++int do_4360_pcie2_war = 0; ++ ++/* ++ * Allocate a si handle. ++ * devid - pci device id (used to determine chip#) ++ * osh - opaque OS handle ++ * regs - virtual address of initial core registers ++ * bustype - pci/pcmcia/sb/sdio/etc ++ * vars - pointer to a pointer area for "environment" variables ++ * varsz - pointer to int to return the size of the vars ++ */ ++si_t * ++si_attach(uint devid, osl_t *osh, void *regs, ++ uint bustype, void *sdh, char **vars, uint *varsz) ++{ ++ si_info_t *sii; ++ ++ /* alloc si_info_t */ ++ if ((sii = MALLOC(osh, sizeof (si_info_t))) == NULL) { ++ AP6211_ERR("si_attach: malloc failed! malloced %d bytes\n", MALLOCED(osh)); ++ return (NULL); ++ } ++ ++ if (si_doattach(sii, devid, osh, regs, bustype, sdh, vars, varsz) == NULL) { ++ MFREE(osh, sii, sizeof(si_info_t)); ++ return (NULL); ++ } ++ sii->vars = vars ? *vars : NULL; ++ sii->varsz = varsz ? *varsz : 0; ++ ++ return (si_t *)sii; ++} ++ ++/* global kernel resource */ ++static si_info_t ksii; ++ ++static uint32 wd_msticks; /* watchdog timer ticks normalized to ms */ ++ ++/* generic kernel variant of si_attach() */ ++si_t * ++si_kattach(osl_t *osh) ++{ ++ static bool ksii_attached = FALSE; ++ ++ if (!ksii_attached) { ++ void *regs = NULL; ++ regs = REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE); ++ ++ if (si_doattach(&ksii, BCM4710_DEVICE_ID, osh, regs, ++ SI_BUS, NULL, ++ osh != SI_OSH ? &ksii.vars : NULL, ++ osh != SI_OSH ? &ksii.varsz : NULL) == NULL) { ++ AP6211_ERR("si_kattach: si_doattach failed\n"); ++ REG_UNMAP(regs); ++ return NULL; ++ } ++ REG_UNMAP(regs); ++ ++ /* save ticks normalized to ms for si_watchdog_ms() */ ++ if (PMUCTL_ENAB(&ksii.pub)) { ++ /* based on 32KHz ILP clock */ ++ wd_msticks = 32; ++ } else { ++ wd_msticks = ALP_CLOCK / 1000; ++ } ++ ++ ksii_attached = TRUE; ++ AP6211_DEBUG("si_kattach done. ccrev = %d, wd_msticks = %d\n", ++ ksii.pub.ccrev, wd_msticks); ++ } ++ ++ return &ksii.pub; ++} ++ ++ ++static bool ++si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh) ++{ ++ /* need to set memseg flag for CF card first before any sb registers access */ ++ if (BUSTYPE(bustype) == PCMCIA_BUS) ++ sii->memseg = TRUE; ++ ++ ++ if (BUSTYPE(bustype) == SDIO_BUS) { ++ int err; ++ uint8 clkset; ++ ++ /* Try forcing SDIO core to do ALPAvail request only */ ++ clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ; ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err); ++ if (!err) { ++ uint8 clkval; ++ ++ /* If register supported, wait for ALPAvail and then force ALP */ ++ clkval = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, NULL); ++ if ((clkval & ~SBSDIO_AVBITS) == clkset) { ++ SPINWAIT(((clkval = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, NULL)), !SBSDIO_ALPAV(clkval)), ++ PMU_MAX_TRANSITION_DLY); ++ if (!SBSDIO_ALPAV(clkval)) { ++ AP6211_ERR("timeout on ALPAV wait, clkval 0x%02x\n", ++ clkval); ++ return FALSE; ++ } ++ clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP; ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, ++ clkset, &err); ++ OSL_DELAY(65); ++ } ++ } ++ ++ /* Also, disable the extra SDIO pull-ups */ ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL); ++ } ++ ++ ++ return TRUE; ++} ++ ++static bool ++si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin, ++ uint *origidx, void *regs) ++{ ++ bool pci, pcie, pcie_gen2 = FALSE; ++ uint i; ++ uint pciidx, pcieidx, pcirev, pcierev; ++ ++ cc = si_setcoreidx(&sii->pub, SI_CC_IDX); ++ ASSERT((uintptr)cc); ++ ++ /* get chipcommon rev */ ++ sii->pub.ccrev = (int)si_corerev(&sii->pub); ++ ++ /* get chipcommon chipstatus */ ++ if (sii->pub.ccrev >= 11) ++ sii->pub.chipst = R_REG(sii->osh, &cc->chipstatus); ++ ++ /* get chipcommon capabilites */ ++ sii->pub.cccaps = R_REG(sii->osh, &cc->capabilities); ++ /* get chipcommon extended capabilities */ ++ ++ if (sii->pub.ccrev >= 35) ++ sii->pub.cccaps_ext = R_REG(sii->osh, &cc->capabilities_ext); ++ ++ /* get pmu rev and caps */ ++ if (sii->pub.cccaps & CC_CAP_PMU) { ++ sii->pub.pmucaps = R_REG(sii->osh, &cc->pmucapabilities); ++ sii->pub.pmurev = sii->pub.pmucaps & PCAP_REV_MASK; ++ } ++ ++ AP6211_DEBUG("Chipc: rev %d, caps 0x%x, chipst 0x%x pmurev %d, pmucaps 0x%x\n", ++ sii->pub.ccrev, sii->pub.cccaps, sii->pub.chipst, sii->pub.pmurev, ++ sii->pub.pmucaps); ++ ++ /* figure out bus/orignal core idx */ ++ sii->pub.buscoretype = NODEV_CORE_ID; ++ sii->pub.buscorerev = (uint)NOREV; ++ sii->pub.buscoreidx = BADIDX; ++ ++ pci = pcie = FALSE; ++ pcirev = pcierev = (uint)NOREV; ++ pciidx = pcieidx = BADIDX; ++ ++ for (i = 0; i < sii->numcores; i++) { ++ uint cid, crev; ++ ++ si_setcoreidx(&sii->pub, i); ++ cid = si_coreid(&sii->pub); ++ crev = si_corerev(&sii->pub); ++ ++ /* Display cores found */ ++ AP6211_DEBUG("CORE[%d]: id 0x%x rev %d base 0x%x regs 0x%p\n", ++ i, cid, crev, sii->coresba[i], sii->regs[i]); ++ ++ if (BUSTYPE(bustype) == PCI_BUS) { ++ if (cid == PCI_CORE_ID) { ++ pciidx = i; ++ pcirev = crev; ++ pci = TRUE; ++ } else if ((cid == PCIE_CORE_ID) || (cid == PCIE2_CORE_ID)) { ++ pcieidx = i; ++ pcierev = crev; ++ pcie = TRUE; ++ if (cid == PCIE2_CORE_ID) ++ pcie_gen2 = TRUE; ++ } ++ } else if ((BUSTYPE(bustype) == PCMCIA_BUS) && ++ (cid == PCMCIA_CORE_ID)) { ++ sii->pub.buscorerev = crev; ++ sii->pub.buscoretype = cid; ++ sii->pub.buscoreidx = i; ++ } ++ else if (((BUSTYPE(bustype) == SDIO_BUS) || ++ (BUSTYPE(bustype) == SPI_BUS)) && ++ ((cid == PCMCIA_CORE_ID) || ++ (cid == SDIOD_CORE_ID))) { ++ sii->pub.buscorerev = crev; ++ sii->pub.buscoretype = cid; ++ sii->pub.buscoreidx = i; ++ } ++ ++ /* find the core idx before entering this func. */ ++ if ((savewin && (savewin == sii->coresba[i])) || ++ (regs == sii->regs[i])) ++ *origidx = i; ++ } ++ ++ if (pci) { ++ sii->pub.buscoretype = PCI_CORE_ID; ++ sii->pub.buscorerev = pcirev; ++ sii->pub.buscoreidx = pciidx; ++ } else if (pcie) { ++ if (pcie_gen2) ++ sii->pub.buscoretype = PCIE2_CORE_ID; ++ else ++ sii->pub.buscoretype = PCIE_CORE_ID; ++ sii->pub.buscorerev = pcierev; ++ sii->pub.buscoreidx = pcieidx; ++ } ++ ++ AP6211_DEBUG("Buscore id/type/rev %d/0x%x/%d\n", sii->pub.buscoreidx, sii->pub.buscoretype, ++ sii->pub.buscorerev); ++ ++ if (BUSTYPE(sii->pub.bustype) == SI_BUS && (CHIPID(sii->pub.chip) == BCM4712_CHIP_ID) && ++ (sii->pub.chippkg != BCM4712LARGE_PKG_ID) && (CHIPREV(sii->pub.chiprev) <= 3)) ++ OR_REG(sii->osh, &cc->slow_clk_ctl, SCC_SS_XTAL); ++ ++ ++ /* Make sure any on-chip ARM is off (in case strapping is wrong), or downloaded code was ++ * already running. ++ */ ++ if ((BUSTYPE(bustype) == SDIO_BUS) || (BUSTYPE(bustype) == SPI_BUS)) { ++ if (si_setcore(&sii->pub, ARM7S_CORE_ID, 0) || ++ si_setcore(&sii->pub, ARMCM3_CORE_ID, 0)) ++ si_core_disable(&sii->pub, 0); ++ } ++ ++ /* return to the original core */ ++ si_setcoreidx(&sii->pub, *origidx); ++ ++ return TRUE; ++} ++ ++ ++ ++ ++static si_info_t * ++si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, ++ uint bustype, void *sdh, char **vars, uint *varsz) ++{ ++ struct si_pub *sih = &sii->pub; ++ uint32 w, savewin; ++ chipcregs_t *cc; ++ char *pvars = NULL; ++ uint origidx; ++ ++ ASSERT(GOODREGS(regs)); ++ ++ bzero((uchar*)sii, sizeof(si_info_t)); ++ ++ savewin = 0; ++ ++ sih->buscoreidx = BADIDX; ++ ++ sii->curmap = regs; ++ sii->sdh = sdh; ++ sii->osh = osh; ++ ++ ++ ++ /* find Chipcommon address */ ++ if (bustype == PCI_BUS) { ++ savewin = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32)); ++ if (!GOODCOREADDR(savewin, SI_ENUM_BASE)) ++ savewin = SI_ENUM_BASE; ++ OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, SI_ENUM_BASE); ++ if (!regs) ++ return NULL; ++ cc = (chipcregs_t *)regs; ++ } else if ((bustype == SDIO_BUS) || (bustype == SPI_BUS)) { ++ cc = (chipcregs_t *)sii->curmap; ++ } else { ++ cc = (chipcregs_t *)REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE); ++ } ++ ++ sih->bustype = bustype; ++ if (bustype != BUSTYPE(bustype)) { ++ AP6211_ERR("si_doattach: bus type %d does not match configured bus type %d\n", ++ bustype, BUSTYPE(bustype)); ++ return NULL; ++ } ++ ++ /* bus/core/clk setup for register access */ ++ if (!si_buscore_prep(sii, bustype, devid, sdh)) { ++ AP6211_ERR("si_doattach: si_core_clk_prep failed %d\n", bustype); ++ return NULL; ++ } ++ ++ /* ChipID recognition. ++ * We assume we can read chipid at offset 0 from the regs arg. ++ * If we add other chiptypes (or if we need to support old sdio hosts w/o chipcommon), ++ * some way of recognizing them needs to be added here. ++ */ ++ if (!cc) { ++ AP6211_ERR("%s: chipcommon register space is null \n", __FUNCTION__); ++ return NULL; ++ } ++ w = R_REG(osh, &cc->chipid); ++ sih->socitype = (w & CID_TYPE_MASK) >> CID_TYPE_SHIFT; ++ /* Might as wll fill in chip id rev & pkg */ ++ sih->chip = w & CID_ID_MASK; ++ sih->chiprev = (w & CID_REV_MASK) >> CID_REV_SHIFT; ++ sih->chippkg = (w & CID_PKG_MASK) >> CID_PKG_SHIFT; ++ ++#if defined(HW_OOB) ++ bcmsdh_config_hw_oob_intr(sdh, sih->chip); ++#endif ++ ++ if ((CHIPID(sih->chip) == BCM4329_CHIP_ID) && (sih->chiprev == 0) && ++ (sih->chippkg != BCM4329_289PIN_PKG_ID)) { ++ sih->chippkg = BCM4329_182PIN_PKG_ID; ++ } ++ sih->issim = IS_SIM(sih->chippkg); ++ ++ /* scan for cores */ ++ if (CHIPTYPE(sii->pub.socitype) == SOCI_SB) { ++ AP6211_DEBUG("Found chip type SB (0x%08x)\n", w); ++ sb_scan(&sii->pub, regs, devid); ++ } else if (CHIPTYPE(sii->pub.socitype) == SOCI_AI) { ++ AP6211_DEBUG("Found chip type AI (0x%08x)\n", w); ++ /* pass chipc address instead of original core base */ ++ ai_scan(&sii->pub, (void *)(uintptr)cc, devid); ++ } else if (CHIPTYPE(sii->pub.socitype) == SOCI_UBUS) { ++ AP6211_DEBUG("Found chip type UBUS (0x%08x), chip id = 0x%4x\n", w, sih->chip); ++ /* pass chipc address instead of original core base */ ++ ub_scan(&sii->pub, (void *)(uintptr)cc, devid); ++ } else { ++ AP6211_ERR("Found chip of unknown type (0x%08x)\n", w); ++ return NULL; ++ } ++ /* no cores found, bail out */ ++ if (sii->numcores == 0) { ++ AP6211_ERR("si_doattach: could not find any cores\n"); ++ return NULL; ++ } ++ /* bus/core/clk setup */ ++ origidx = SI_CC_IDX; ++ if (!si_buscore_setup(sii, cc, bustype, savewin, &origidx, regs)) { ++ AP6211_ERR("si_doattach: si_buscore_setup failed\n"); ++ goto exit; ++ } ++ ++ if (CHIPID(sih->chip) == BCM4322_CHIP_ID && (((sih->chipst & CST4322_SPROM_OTP_SEL_MASK) ++ >> CST4322_SPROM_OTP_SEL_SHIFT) == (CST4322_OTP_PRESENT | ++ CST4322_SPROM_PRESENT))) { ++ AP6211_ERR("%s: Invalid setting: both SPROM and OTP strapped.\n", __FUNCTION__); ++ return NULL; ++ } ++ ++ /* assume current core is CC */ ++ if ((sii->pub.ccrev == 0x25) && ((CHIPID(sih->chip) == BCM43236_CHIP_ID || ++ CHIPID(sih->chip) == BCM43235_CHIP_ID || ++ CHIPID(sih->chip) == BCM43234_CHIP_ID || ++ CHIPID(sih->chip) == BCM43238_CHIP_ID) && ++ (CHIPREV(sii->pub.chiprev) <= 2))) { ++ ++ if ((cc->chipstatus & CST43236_BP_CLK) != 0) { ++ uint clkdiv; ++ clkdiv = R_REG(osh, &cc->clkdiv); ++ /* otp_clk_div is even number, 120/14 < 9mhz */ ++ clkdiv = (clkdiv & ~CLKD_OTP) | (14 << CLKD_OTP_SHIFT); ++ W_REG(osh, &cc->clkdiv, clkdiv); ++ AP6211_ERR("%s: set clkdiv to %x\n", __FUNCTION__, clkdiv); ++ } ++ OSL_DELAY(10); ++ } ++ ++ if (bustype == PCI_BUS) { ++ ++ } ++ ++ pvars = NULL; ++ BCM_REFERENCE(pvars); ++ ++ ++ ++ if (sii->pub.ccrev >= 20) { ++ uint32 gpiopullup = 0, gpiopulldown = 0; ++ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); ++ ASSERT(cc != NULL); ++ ++ /* 4314/43142 has pin muxing, don't clear gpio bits */ ++ if ((CHIPID(sih->chip) == BCM4314_CHIP_ID) || ++ (CHIPID(sih->chip) == BCM43142_CHIP_ID)) { ++ gpiopullup |= 0x402e0; ++ gpiopulldown |= 0x20500; ++ } ++ ++ W_REG(osh, &cc->gpiopullup, gpiopullup); ++ W_REG(osh, &cc->gpiopulldown, gpiopulldown); ++ si_setcoreidx(sih, origidx); ++ } ++ ++ ++ /* clear any previous epidiag-induced target abort */ ++ ASSERT(!si_taclear(sih, FALSE)); ++ ++ return (sii); ++ ++exit: ++ ++ return NULL; ++} ++ ++/* may be called with core in reset */ ++void ++si_detach(si_t *sih) ++{ ++ si_info_t *sii; ++ uint idx; ++ ++ ++ sii = SI_INFO(sih); ++ ++ if (sii == NULL) ++ return; ++ ++ if (BUSTYPE(sih->bustype) == SI_BUS) ++ for (idx = 0; idx < SI_MAXCORES; idx++) ++ if (sii->regs[idx]) { ++ REG_UNMAP(sii->regs[idx]); ++ sii->regs[idx] = NULL; ++ } ++ ++ ++ ++#if !defined(BCMBUSTYPE) || (BCMBUSTYPE == SI_BUS) ++ if (sii != &ksii) ++#endif /* !BCMBUSTYPE || (BCMBUSTYPE == SI_BUS) */ ++ MFREE(sii->osh, sii, sizeof(si_info_t)); ++} ++ ++void * ++si_osh(si_t *sih) ++{ ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ return sii->osh; ++} ++ ++void ++si_setosh(si_t *sih, osl_t *osh) ++{ ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ if (sii->osh != NULL) { ++ AP6211_ERR("osh is already set....\n"); ++ ASSERT(!sii->osh); ++ } ++ sii->osh = osh; ++} ++ ++/* register driver interrupt disabling and restoring callback functions */ ++void ++si_register_intr_callback(si_t *sih, void *intrsoff_fn, void *intrsrestore_fn, ++ void *intrsenabled_fn, void *intr_arg) ++{ ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ sii->intr_arg = intr_arg; ++ sii->intrsoff_fn = (si_intrsoff_t)intrsoff_fn; ++ sii->intrsrestore_fn = (si_intrsrestore_t)intrsrestore_fn; ++ sii->intrsenabled_fn = (si_intrsenabled_t)intrsenabled_fn; ++ /* save current core id. when this function called, the current core ++ * must be the core which provides driver functions(il, et, wl, etc.) ++ */ ++ sii->dev_coreid = sii->coreid[sii->curidx]; ++} ++ ++void ++si_deregister_intr_callback(si_t *sih) ++{ ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ sii->intrsoff_fn = NULL; ++} ++ ++uint ++si_intflag(si_t *sih) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_intflag(sih); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ return R_REG(sii->osh, ((uint32 *)(uintptr) ++ (sii->oob_router + OOB_STATUSA))); ++ else { ++ ASSERT(0); ++ return 0; ++ } ++} ++ ++uint ++si_flag(si_t *sih) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_flag(sih); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ return ai_flag(sih); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_flag(sih); ++ else { ++ ASSERT(0); ++ return 0; ++ } ++} ++ ++void ++si_setint(si_t *sih, int siflag) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ sb_setint(sih, siflag); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ ai_setint(sih, siflag); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ ub_setint(sih, siflag); ++ else ++ ASSERT(0); ++} ++ ++uint ++si_coreid(si_t *sih) ++{ ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ return sii->coreid[sii->curidx]; ++} ++ ++uint ++si_coreidx(si_t *sih) ++{ ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ return sii->curidx; ++} ++ ++/* return the core-type instantiation # of the current core */ ++uint ++si_coreunit(si_t *sih) ++{ ++ si_info_t *sii; ++ uint idx; ++ uint coreid; ++ uint coreunit; ++ uint i; ++ ++ sii = SI_INFO(sih); ++ coreunit = 0; ++ ++ idx = sii->curidx; ++ ++ ASSERT(GOODREGS(sii->curmap)); ++ coreid = si_coreid(sih); ++ ++ /* count the cores of our type */ ++ for (i = 0; i < idx; i++) ++ if (sii->coreid[i] == coreid) ++ coreunit++; ++ ++ return (coreunit); ++} ++ ++uint ++si_corevendor(si_t *sih) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_corevendor(sih); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ return ai_corevendor(sih); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_corevendor(sih); ++ else { ++ ASSERT(0); ++ return 0; ++ } ++} ++ ++bool ++si_backplane64(si_t *sih) ++{ ++ return ((sih->cccaps & CC_CAP_BKPLN64) != 0); ++} ++ ++uint ++si_corerev(si_t *sih) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_corerev(sih); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ return ai_corerev(sih); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_corerev(sih); ++ else { ++ ASSERT(0); ++ return 0; ++ } ++} ++ ++/* return index of coreid or BADIDX if not found */ ++uint ++si_findcoreidx(si_t *sih, uint coreid, uint coreunit) ++{ ++ si_info_t *sii; ++ uint found; ++ uint i; ++ ++ sii = SI_INFO(sih); ++ ++ found = 0; ++ ++ for (i = 0; i < sii->numcores; i++) ++ if (sii->coreid[i] == coreid) { ++ if (found == coreunit) ++ return (i); ++ found++; ++ } ++ ++ return (BADIDX); ++} ++ ++/* return list of found cores */ ++uint ++si_corelist(si_t *sih, uint coreid[]) ++{ ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ ++ bcopy((uchar*)sii->coreid, (uchar*)coreid, (sii->numcores * sizeof(uint))); ++ return (sii->numcores); ++} ++ ++/* return current register mapping */ ++void * ++si_coreregs(si_t *sih) ++{ ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ ASSERT(GOODREGS(sii->curmap)); ++ ++ return (sii->curmap); ++} ++ ++/* ++ * This function changes logical "focus" to the indicated core; ++ * must be called with interrupts off. ++ * Moreover, callers should keep interrupts off during switching out of and back to d11 core ++ */ ++void * ++si_setcore(si_t *sih, uint coreid, uint coreunit) ++{ ++ uint idx; ++ ++ idx = si_findcoreidx(sih, coreid, coreunit); ++ if (!GOODIDX(idx)) ++ return (NULL); ++ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_setcoreidx(sih, idx); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ return ai_setcoreidx(sih, idx); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_setcoreidx(sih, idx); ++ else { ++ ASSERT(0); ++ return NULL; ++ } ++} ++ ++void * ++si_setcoreidx(si_t *sih, uint coreidx) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_setcoreidx(sih, coreidx); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ return ai_setcoreidx(sih, coreidx); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_setcoreidx(sih, coreidx); ++ else { ++ ASSERT(0); ++ return NULL; ++ } ++} ++ ++/* Turn off interrupt as required by sb_setcore, before switch core */ ++void * ++si_switch_core(si_t *sih, uint coreid, uint *origidx, uint *intr_val) ++{ ++ void *cc; ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ ++ if (SI_FAST(sii)) { ++ /* Overloading the origidx variable to remember the coreid, ++ * this works because the core ids cannot be confused with ++ * core indices. ++ */ ++ *origidx = coreid; ++ if (coreid == CC_CORE_ID) ++ return (void *)CCREGS_FAST(sii); ++ else if (coreid == sih->buscoretype) ++ return (void *)PCIEREGS(sii); ++ } ++ INTR_OFF(sii, *intr_val); ++ *origidx = sii->curidx; ++ cc = si_setcore(sih, coreid, 0); ++ ASSERT(cc != NULL); ++ ++ return cc; ++} ++ ++/* restore coreidx and restore interrupt */ ++void ++si_restore_core(si_t *sih, uint coreid, uint intr_val) ++{ ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ if (SI_FAST(sii) && ((coreid == CC_CORE_ID) || (coreid == sih->buscoretype))) ++ return; ++ ++ si_setcoreidx(sih, coreid); ++ INTR_RESTORE(sii, intr_val); ++} ++ ++int ++si_numaddrspaces(si_t *sih) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_numaddrspaces(sih); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ return ai_numaddrspaces(sih); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_numaddrspaces(sih); ++ else { ++ ASSERT(0); ++ return 0; ++ } ++} ++ ++uint32 ++si_addrspace(si_t *sih, uint asidx) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_addrspace(sih, asidx); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ return ai_addrspace(sih, asidx); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_addrspace(sih, asidx); ++ else { ++ ASSERT(0); ++ return 0; ++ } ++} ++ ++uint32 ++si_addrspacesize(si_t *sih, uint asidx) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_addrspacesize(sih, asidx); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ return ai_addrspacesize(sih, asidx); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_addrspacesize(sih, asidx); ++ else { ++ ASSERT(0); ++ return 0; ++ } ++} ++ ++void ++si_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size) ++{ ++ /* Only supported for SOCI_AI */ ++ if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ ai_coreaddrspaceX(sih, asidx, addr, size); ++ else ++ *size = 0; ++} ++ ++uint32 ++si_core_cflags(si_t *sih, uint32 mask, uint32 val) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_core_cflags(sih, mask, val); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ return ai_core_cflags(sih, mask, val); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_core_cflags(sih, mask, val); ++ else { ++ ASSERT(0); ++ return 0; ++ } ++} ++ ++void ++si_core_cflags_wo(si_t *sih, uint32 mask, uint32 val) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ sb_core_cflags_wo(sih, mask, val); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ ai_core_cflags_wo(sih, mask, val); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ ub_core_cflags_wo(sih, mask, val); ++ else ++ ASSERT(0); ++} ++ ++uint32 ++si_core_sflags(si_t *sih, uint32 mask, uint32 val) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_core_sflags(sih, mask, val); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ return ai_core_sflags(sih, mask, val); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_core_sflags(sih, mask, val); ++ else { ++ ASSERT(0); ++ return 0; ++ } ++} ++ ++bool ++si_iscoreup(si_t *sih) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_iscoreup(sih); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ return ai_iscoreup(sih); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_iscoreup(sih); ++ else { ++ ASSERT(0); ++ return FALSE; ++ } ++} ++ ++uint ++si_wrapperreg(si_t *sih, uint32 offset, uint32 mask, uint32 val) ++{ ++ /* only for AI back plane chips */ ++ if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ return (ai_wrap_reg(sih, offset, mask, val)); ++ return 0; ++} ++ ++uint ++si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_corereg(sih, coreidx, regoff, mask, val); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ return ai_corereg(sih, coreidx, regoff, mask, val); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_corereg(sih, coreidx, regoff, mask, val); ++ else { ++ ASSERT(0); ++ return 0; ++ } ++} ++ ++void ++si_core_disable(si_t *sih, uint32 bits) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ sb_core_disable(sih, bits); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ ai_core_disable(sih, bits); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ ub_core_disable(sih, bits); ++} ++ ++void ++si_core_reset(si_t *sih, uint32 bits, uint32 resetbits) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ sb_core_reset(sih, bits, resetbits); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ ai_core_reset(sih, bits, resetbits); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ ub_core_reset(sih, bits, resetbits); ++} ++ ++/* Run bist on current core. Caller needs to take care of core-specific bist hazards */ ++int ++si_corebist(si_t *sih) ++{ ++ uint32 cflags; ++ int result = 0; ++ ++ /* Read core control flags */ ++ cflags = si_core_cflags(sih, 0, 0); ++ ++ /* Set bist & fgc */ ++ si_core_cflags(sih, ~0, (SICF_BIST_EN | SICF_FGC)); ++ ++ /* Wait for bist done */ ++ SPINWAIT(((si_core_sflags(sih, 0, 0) & SISF_BIST_DONE) == 0), 100000); ++ ++ if (si_core_sflags(sih, 0, 0) & SISF_BIST_ERROR) ++ result = BCME_ERROR; ++ ++ /* Reset core control flags */ ++ si_core_cflags(sih, 0xffff, cflags); ++ ++ return result; ++} ++ ++static uint32 ++factor6(uint32 x) ++{ ++ switch (x) { ++ case CC_F6_2: return 2; ++ case CC_F6_3: return 3; ++ case CC_F6_4: return 4; ++ case CC_F6_5: return 5; ++ case CC_F6_6: return 6; ++ case CC_F6_7: return 7; ++ default: return 0; ++ } ++} ++ ++/* calculate the speed the SI would run at given a set of clockcontrol values */ ++uint32 ++si_clock_rate(uint32 pll_type, uint32 n, uint32 m) ++{ ++ uint32 n1, n2, clock, m1, m2, m3, mc; ++ ++ n1 = n & CN_N1_MASK; ++ n2 = (n & CN_N2_MASK) >> CN_N2_SHIFT; ++ ++ if (pll_type == PLL_TYPE6) { ++ if (m & CC_T6_MMASK) ++ return CC_T6_M1; ++ else ++ return CC_T6_M0; ++ } else if ((pll_type == PLL_TYPE1) || ++ (pll_type == PLL_TYPE3) || ++ (pll_type == PLL_TYPE4) || ++ (pll_type == PLL_TYPE7)) { ++ n1 = factor6(n1); ++ n2 += CC_F5_BIAS; ++ } else if (pll_type == PLL_TYPE2) { ++ n1 += CC_T2_BIAS; ++ n2 += CC_T2_BIAS; ++ ASSERT((n1 >= 2) && (n1 <= 7)); ++ ASSERT((n2 >= 5) && (n2 <= 23)); ++ } else if (pll_type == PLL_TYPE5) { ++ return (100000000); ++ } else ++ ASSERT(0); ++ /* PLL types 3 and 7 use BASE2 (25Mhz) */ ++ if ((pll_type == PLL_TYPE3) || ++ (pll_type == PLL_TYPE7)) { ++ clock = CC_CLOCK_BASE2 * n1 * n2; ++ } else ++ clock = CC_CLOCK_BASE1 * n1 * n2; ++ ++ if (clock == 0) ++ return 0; ++ ++ m1 = m & CC_M1_MASK; ++ m2 = (m & CC_M2_MASK) >> CC_M2_SHIFT; ++ m3 = (m & CC_M3_MASK) >> CC_M3_SHIFT; ++ mc = (m & CC_MC_MASK) >> CC_MC_SHIFT; ++ ++ if ((pll_type == PLL_TYPE1) || ++ (pll_type == PLL_TYPE3) || ++ (pll_type == PLL_TYPE4) || ++ (pll_type == PLL_TYPE7)) { ++ m1 = factor6(m1); ++ if ((pll_type == PLL_TYPE1) || (pll_type == PLL_TYPE3)) ++ m2 += CC_F5_BIAS; ++ else ++ m2 = factor6(m2); ++ m3 = factor6(m3); ++ ++ switch (mc) { ++ case CC_MC_BYPASS: return (clock); ++ case CC_MC_M1: return (clock / m1); ++ case CC_MC_M1M2: return (clock / (m1 * m2)); ++ case CC_MC_M1M2M3: return (clock / (m1 * m2 * m3)); ++ case CC_MC_M1M3: return (clock / (m1 * m3)); ++ default: return (0); ++ } ++ } else { ++ ASSERT(pll_type == PLL_TYPE2); ++ ++ m1 += CC_T2_BIAS; ++ m2 += CC_T2M2_BIAS; ++ m3 += CC_T2_BIAS; ++ ASSERT((m1 >= 2) && (m1 <= 7)); ++ ASSERT((m2 >= 3) && (m2 <= 10)); ++ ASSERT((m3 >= 2) && (m3 <= 7)); ++ ++ if ((mc & CC_T2MC_M1BYP) == 0) ++ clock /= m1; ++ if ((mc & CC_T2MC_M2BYP) == 0) ++ clock /= m2; ++ if ((mc & CC_T2MC_M3BYP) == 0) ++ clock /= m3; ++ ++ return (clock); ++ } ++} ++ ++ ++/* set chip watchdog reset timer to fire in 'ticks' */ ++void ++si_watchdog(si_t *sih, uint ticks) ++{ ++ uint nb, maxt; ++ ++ if (PMUCTL_ENAB(sih)) { ++ ++ if ((CHIPID(sih->chip) == BCM4319_CHIP_ID) && ++ (CHIPREV(sih->chiprev) == 0) && (ticks != 0)) { ++ si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, clk_ctl_st), ~0, 0x2); ++ si_setcore(sih, USB20D_CORE_ID, 0); ++ si_core_disable(sih, 1); ++ si_setcore(sih, CC_CORE_ID, 0); ++ } ++ ++ nb = (sih->ccrev < 26) ? 16 : ((sih->ccrev >= 37) ? 32 : 24); ++ /* The mips compiler uses the sllv instruction, ++ * so we specially handle the 32-bit case. ++ */ ++ if (nb == 32) ++ maxt = 0xffffffff; ++ else ++ maxt = ((1 << nb) - 1); ++ ++ if (ticks == 1) ++ ticks = 2; ++ else if (ticks > maxt) ++ ticks = maxt; ++ ++ si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, pmuwatchdog), ~0, ticks); ++ } else { ++ maxt = (1 << 28) - 1; ++ if (ticks > maxt) ++ ticks = maxt; ++ ++ si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, watchdog), ~0, ticks); ++ } ++} ++ ++/* trigger watchdog reset after ms milliseconds */ ++void ++si_watchdog_ms(si_t *sih, uint32 ms) ++{ ++ si_watchdog(sih, wd_msticks * ms); ++} ++ ++uint32 si_watchdog_msticks(void) ++{ ++ return wd_msticks; ++} ++ ++bool ++si_taclear(si_t *sih, bool details) ++{ ++ return FALSE; ++} ++ ++ ++ ++/* return the slow clock source - LPO, XTAL, or PCI */ ++static uint ++si_slowclk_src(si_info_t *sii) ++{ ++ chipcregs_t *cc; ++ ++ ASSERT(SI_FAST(sii) || si_coreid(&sii->pub) == CC_CORE_ID); ++ ++ if (sii->pub.ccrev < 6) { ++ if ((BUSTYPE(sii->pub.bustype) == PCI_BUS) && ++ (OSL_PCI_READ_CONFIG(sii->osh, PCI_GPIO_OUT, sizeof(uint32)) & ++ PCI_CFG_GPIO_SCS)) ++ return (SCC_SS_PCI); ++ else ++ return (SCC_SS_XTAL); ++ } else if (sii->pub.ccrev < 10) { ++ cc = (chipcregs_t *)si_setcoreidx(&sii->pub, sii->curidx); ++ return (R_REG(sii->osh, &cc->slow_clk_ctl) & SCC_SS_MASK); ++ } else /* Insta-clock */ ++ return (SCC_SS_XTAL); ++} ++ ++/* return the ILP (slowclock) min or max frequency */ ++static uint ++si_slowclk_freq(si_info_t *sii, bool max_freq, chipcregs_t *cc) ++{ ++ uint32 slowclk; ++ uint div; ++ ++ ASSERT(SI_FAST(sii) || si_coreid(&sii->pub) == CC_CORE_ID); ++ ++ /* shouldn't be here unless we've established the chip has dynamic clk control */ ++ ASSERT(R_REG(sii->osh, &cc->capabilities) & CC_CAP_PWR_CTL); ++ ++ slowclk = si_slowclk_src(sii); ++ if (sii->pub.ccrev < 6) { ++ if (slowclk == SCC_SS_PCI) ++ return (max_freq ? (PCIMAXFREQ / 64) : (PCIMINFREQ / 64)); ++ else ++ return (max_freq ? (XTALMAXFREQ / 32) : (XTALMINFREQ / 32)); ++ } else if (sii->pub.ccrev < 10) { ++ div = 4 * ++ (((R_REG(sii->osh, &cc->slow_clk_ctl) & SCC_CD_MASK) >> SCC_CD_SHIFT) + 1); ++ if (slowclk == SCC_SS_LPO) ++ return (max_freq ? LPOMAXFREQ : LPOMINFREQ); ++ else if (slowclk == SCC_SS_XTAL) ++ return (max_freq ? (XTALMAXFREQ / div) : (XTALMINFREQ / div)); ++ else if (slowclk == SCC_SS_PCI) ++ return (max_freq ? (PCIMAXFREQ / div) : (PCIMINFREQ / div)); ++ else ++ ASSERT(0); ++ } else { ++ /* Chipc rev 10 is InstaClock */ ++ div = R_REG(sii->osh, &cc->system_clk_ctl) >> SYCC_CD_SHIFT; ++ div = 4 * (div + 1); ++ return (max_freq ? XTALMAXFREQ : (XTALMINFREQ / div)); ++ } ++ return (0); ++} ++ ++static void ++si_clkctl_setdelay(si_info_t *sii, void *chipcregs) ++{ ++ chipcregs_t *cc = (chipcregs_t *)chipcregs; ++ uint slowmaxfreq, pll_delay, slowclk; ++ uint pll_on_delay, fref_sel_delay; ++ ++ pll_delay = PLL_DELAY; ++ ++ /* If the slow clock is not sourced by the xtal then add the xtal_on_delay ++ * since the xtal will also be powered down by dynamic clk control logic. ++ */ ++ ++ slowclk = si_slowclk_src(sii); ++ if (slowclk != SCC_SS_XTAL) ++ pll_delay += XTAL_ON_DELAY; ++ ++ /* Starting with 4318 it is ILP that is used for the delays */ ++ slowmaxfreq = si_slowclk_freq(sii, (sii->pub.ccrev >= 10) ? FALSE : TRUE, cc); ++ ++ pll_on_delay = ((slowmaxfreq * pll_delay) + 999999) / 1000000; ++ fref_sel_delay = ((slowmaxfreq * FREF_DELAY) + 999999) / 1000000; ++ ++ W_REG(sii->osh, &cc->pll_on_delay, pll_on_delay); ++ W_REG(sii->osh, &cc->fref_sel_delay, fref_sel_delay); ++} ++ ++/* initialize power control delay registers */ ++void ++si_clkctl_init(si_t *sih) ++{ ++ si_info_t *sii; ++ uint origidx = 0; ++ chipcregs_t *cc; ++ bool fast; ++ ++ if (!CCCTL_ENAB(sih)) ++ return; ++ ++ sii = SI_INFO(sih); ++ fast = SI_FAST(sii); ++ if (!fast) { ++ origidx = sii->curidx; ++ if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL) ++ return; ++ } else if ((cc = (chipcregs_t *)CCREGS_FAST(sii)) == NULL) ++ return; ++ ASSERT(cc != NULL); ++ ++ /* set all Instaclk chip ILP to 1 MHz */ ++ if (sih->ccrev >= 10) ++ SET_REG(sii->osh, &cc->system_clk_ctl, SYCC_CD_MASK, ++ (ILP_DIV_1MHZ << SYCC_CD_SHIFT)); ++ ++ si_clkctl_setdelay(sii, (void *)(uintptr)cc); ++ ++ if (!fast) ++ si_setcoreidx(sih, origidx); ++} ++ ++ ++/* change logical "focus" to the gpio core for optimized access */ ++void * ++si_gpiosetcore(si_t *sih) ++{ ++ return (si_setcoreidx(sih, SI_CC_IDX)); ++} ++ ++/* ++ * mask & set gpiocontrol bits. ++ * If a gpiocontrol bit is set to 0, chipcommon controls the corresponding GPIO pin. ++ * If a gpiocontrol bit is set to 1, the GPIO pin is no longer a GPIO and becomes dedicated ++ * to some chip-specific purpose. ++ */ ++uint32 ++si_gpiocontrol(si_t *sih, uint32 mask, uint32 val, uint8 priority) ++{ ++ uint regoff; ++ ++ regoff = 0; ++ ++ /* gpios could be shared on router platforms ++ * ignore reservation if it's high priority (e.g., test apps) ++ */ ++ if ((priority != GPIO_HI_PRIORITY) && ++ (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { ++ mask = priority ? (si_gpioreservation & mask) : ++ ((si_gpioreservation | mask) & ~(si_gpioreservation)); ++ val &= mask; ++ } ++ ++ regoff = OFFSETOF(chipcregs_t, gpiocontrol); ++ return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); ++} ++ ++/* mask&set gpio output enable bits */ ++uint32 ++si_gpioouten(si_t *sih, uint32 mask, uint32 val, uint8 priority) ++{ ++ uint regoff; ++ ++ regoff = 0; ++ ++ /* gpios could be shared on router platforms ++ * ignore reservation if it's high priority (e.g., test apps) ++ */ ++ if ((priority != GPIO_HI_PRIORITY) && ++ (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { ++ mask = priority ? (si_gpioreservation & mask) : ++ ((si_gpioreservation | mask) & ~(si_gpioreservation)); ++ val &= mask; ++ } ++ ++ regoff = OFFSETOF(chipcregs_t, gpioouten); ++ return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); ++} ++ ++/* mask&set gpio output bits */ ++uint32 ++si_gpioout(si_t *sih, uint32 mask, uint32 val, uint8 priority) ++{ ++ uint regoff; ++ ++ regoff = 0; ++ ++ /* gpios could be shared on router platforms ++ * ignore reservation if it's high priority (e.g., test apps) ++ */ ++ if ((priority != GPIO_HI_PRIORITY) && ++ (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { ++ mask = priority ? (si_gpioreservation & mask) : ++ ((si_gpioreservation | mask) & ~(si_gpioreservation)); ++ val &= mask; ++ } ++ ++ regoff = OFFSETOF(chipcregs_t, gpioout); ++ return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); ++} ++ ++/* reserve one gpio */ ++uint32 ++si_gpioreserve(si_t *sih, uint32 gpio_bitmask, uint8 priority) ++{ ++ /* only cores on SI_BUS share GPIO's and only applcation users need to ++ * reserve/release GPIO ++ */ ++ if ((BUSTYPE(sih->bustype) != SI_BUS) || (!priority)) { ++ ASSERT((BUSTYPE(sih->bustype) == SI_BUS) && (priority)); ++ return 0xffffffff; ++ } ++ /* make sure only one bit is set */ ++ if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) { ++ ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1))); ++ return 0xffffffff; ++ } ++ ++ /* already reserved */ ++ if (si_gpioreservation & gpio_bitmask) ++ return 0xffffffff; ++ /* set reservation */ ++ si_gpioreservation |= gpio_bitmask; ++ ++ return si_gpioreservation; ++} ++ ++/* release one gpio */ ++/* ++ * releasing the gpio doesn't change the current value on the GPIO last write value ++ * persists till some one overwrites it ++ */ ++ ++uint32 ++si_gpiorelease(si_t *sih, uint32 gpio_bitmask, uint8 priority) ++{ ++ /* only cores on SI_BUS share GPIO's and only applcation users need to ++ * reserve/release GPIO ++ */ ++ if ((BUSTYPE(sih->bustype) != SI_BUS) || (!priority)) { ++ ASSERT((BUSTYPE(sih->bustype) == SI_BUS) && (priority)); ++ return 0xffffffff; ++ } ++ /* make sure only one bit is set */ ++ if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) { ++ ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1))); ++ return 0xffffffff; ++ } ++ ++ /* already released */ ++ if (!(si_gpioreservation & gpio_bitmask)) ++ return 0xffffffff; ++ ++ /* clear reservation */ ++ si_gpioreservation &= ~gpio_bitmask; ++ ++ return si_gpioreservation; ++} ++ ++/* return the current gpioin register value */ ++uint32 ++si_gpioin(si_t *sih) ++{ ++ uint regoff; ++ ++ regoff = OFFSETOF(chipcregs_t, gpioin); ++ return (si_corereg(sih, SI_CC_IDX, regoff, 0, 0)); ++} ++ ++/* mask&set gpio interrupt polarity bits */ ++uint32 ++si_gpiointpolarity(si_t *sih, uint32 mask, uint32 val, uint8 priority) ++{ ++ uint regoff; ++ ++ /* gpios could be shared on router platforms */ ++ if ((BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { ++ mask = priority ? (si_gpioreservation & mask) : ++ ((si_gpioreservation | mask) & ~(si_gpioreservation)); ++ val &= mask; ++ } ++ ++ regoff = OFFSETOF(chipcregs_t, gpiointpolarity); ++ return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); ++} ++ ++/* mask&set gpio interrupt mask bits */ ++uint32 ++si_gpiointmask(si_t *sih, uint32 mask, uint32 val, uint8 priority) ++{ ++ uint regoff; ++ ++ /* gpios could be shared on router platforms */ ++ if ((BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { ++ mask = priority ? (si_gpioreservation & mask) : ++ ((si_gpioreservation | mask) & ~(si_gpioreservation)); ++ val &= mask; ++ } ++ ++ regoff = OFFSETOF(chipcregs_t, gpiointmask); ++ return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); ++} ++ ++/* assign the gpio to an led */ ++uint32 ++si_gpioled(si_t *sih, uint32 mask, uint32 val) ++{ ++ if (sih->ccrev < 16) ++ return 0xffffffff; ++ ++ /* gpio led powersave reg */ ++ return (si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, gpiotimeroutmask), mask, val)); ++} ++ ++/* mask&set gpio timer val */ ++uint32 ++si_gpiotimerval(si_t *sih, uint32 mask, uint32 gpiotimerval) ++{ ++ if (sih->ccrev < 16) ++ return 0xffffffff; ++ ++ return (si_corereg(sih, SI_CC_IDX, ++ OFFSETOF(chipcregs_t, gpiotimerval), mask, gpiotimerval)); ++} ++ ++uint32 ++si_gpiopull(si_t *sih, bool updown, uint32 mask, uint32 val) ++{ ++ uint offs; ++ ++ if (sih->ccrev < 20) ++ return 0xffffffff; ++ ++ offs = (updown ? OFFSETOF(chipcregs_t, gpiopulldown) : OFFSETOF(chipcregs_t, gpiopullup)); ++ return (si_corereg(sih, SI_CC_IDX, offs, mask, val)); ++} ++ ++uint32 ++si_gpioevent(si_t *sih, uint regtype, uint32 mask, uint32 val) ++{ ++ uint offs; ++ ++ if (sih->ccrev < 11) ++ return 0xffffffff; ++ ++ if (regtype == GPIO_REGEVT) ++ offs = OFFSETOF(chipcregs_t, gpioevent); ++ else if (regtype == GPIO_REGEVT_INTMSK) ++ offs = OFFSETOF(chipcregs_t, gpioeventintmask); ++ else if (regtype == GPIO_REGEVT_INTPOL) ++ offs = OFFSETOF(chipcregs_t, gpioeventintpolarity); ++ else ++ return 0xffffffff; ++ ++ return (si_corereg(sih, SI_CC_IDX, offs, mask, val)); ++} ++ ++void * ++si_gpio_handler_register(si_t *sih, uint32 event, ++ bool level, gpio_handler_t cb, void *arg) ++{ ++ si_info_t *sii; ++ gpioh_item_t *gi; ++ ++ ASSERT(event); ++ ASSERT(cb != NULL); ++ ++ sii = SI_INFO(sih); ++ if (sih->ccrev < 11) ++ return NULL; ++ ++ if ((gi = MALLOC(sii->osh, sizeof(gpioh_item_t))) == NULL) ++ return NULL; ++ ++ bzero(gi, sizeof(gpioh_item_t)); ++ gi->event = event; ++ gi->handler = cb; ++ gi->arg = arg; ++ gi->level = level; ++ ++ gi->next = sii->gpioh_head; ++ sii->gpioh_head = gi; ++ ++ return (void *)(gi); ++} ++ ++void ++si_gpio_handler_unregister(si_t *sih, void *gpioh) ++{ ++ si_info_t *sii; ++ gpioh_item_t *p, *n; ++ ++ sii = SI_INFO(sih); ++ if (sih->ccrev < 11) ++ return; ++ ++ ASSERT(sii->gpioh_head != NULL); ++ if ((void*)sii->gpioh_head == gpioh) { ++ sii->gpioh_head = sii->gpioh_head->next; ++ MFREE(sii->osh, gpioh, sizeof(gpioh_item_t)); ++ return; ++ } else { ++ p = sii->gpioh_head; ++ n = p->next; ++ while (n) { ++ if ((void*)n == gpioh) { ++ p->next = n->next; ++ MFREE(sii->osh, gpioh, sizeof(gpioh_item_t)); ++ return; ++ } ++ p = n; ++ n = n->next; ++ } ++ } ++ ++ ASSERT(0); /* Not found in list */ ++} ++ ++void ++si_gpio_handler_process(si_t *sih) ++{ ++ si_info_t *sii; ++ gpioh_item_t *h; ++ uint32 level = si_gpioin(sih); ++ uint32 levelp = si_gpiointpolarity(sih, 0, 0, 0); ++ uint32 edge = si_gpioevent(sih, GPIO_REGEVT, 0, 0); ++ uint32 edgep = si_gpioevent(sih, GPIO_REGEVT_INTPOL, 0, 0); ++ ++ sii = SI_INFO(sih); ++ for (h = sii->gpioh_head; h != NULL; h = h->next) { ++ if (h->handler) { ++ uint32 status = (h->level ? level : edge) & h->event; ++ uint32 polarity = (h->level ? levelp : edgep) & h->event; ++ ++ /* polarity bitval is opposite of status bitval */ ++ if (status ^ polarity) ++ h->handler(status, h->arg); ++ } ++ } ++ ++ si_gpioevent(sih, GPIO_REGEVT, edge, edge); /* clear edge-trigger status */ ++} ++ ++uint32 ++si_gpio_int_enable(si_t *sih, bool enable) ++{ ++ uint offs; ++ ++ if (sih->ccrev < 11) ++ return 0xffffffff; ++ ++ offs = OFFSETOF(chipcregs_t, intmask); ++ return (si_corereg(sih, SI_CC_IDX, offs, CI_GPIO, (enable ? CI_GPIO : 0))); ++} ++ ++ ++/* Return the size of the specified SOCRAM bank */ ++static uint ++socram_banksize(si_info_t *sii, sbsocramregs_t *regs, uint8 idx, uint8 mem_type) ++{ ++ uint banksize, bankinfo; ++ uint bankidx = idx | (mem_type << SOCRAM_BANKIDX_MEMTYPE_SHIFT); ++ ++ ASSERT(mem_type <= SOCRAM_MEMTYPE_DEVRAM); ++ ++ W_REG(sii->osh, ®s->bankidx, bankidx); ++ bankinfo = R_REG(sii->osh, ®s->bankinfo); ++ banksize = SOCRAM_BANKINFO_SZBASE * ((bankinfo & SOCRAM_BANKINFO_SZMASK) + 1); ++ return banksize; ++} ++ ++void ++si_socdevram(si_t *sih, bool set, uint8 *enable, uint8 *protect, uint8 *remap) ++{ ++ si_info_t *sii; ++ uint origidx; ++ uint intr_val = 0; ++ sbsocramregs_t *regs; ++ bool wasup; ++ uint corerev; ++ ++ sii = SI_INFO(sih); ++ ++ /* Block ints and save current core */ ++ INTR_OFF(sii, intr_val); ++ origidx = si_coreidx(sih); ++ ++ if (!set) ++ *enable = *protect = *remap = 0; ++ ++ /* Switch to SOCRAM core */ ++ if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) ++ goto done; ++ ++ /* Get info for determining size */ ++ if (!(wasup = si_iscoreup(sih))) ++ si_core_reset(sih, 0, 0); ++ ++ corerev = si_corerev(sih); ++ if (corerev >= 10) { ++ uint32 extcinfo; ++ uint8 nb; ++ uint8 i; ++ uint32 bankidx, bankinfo; ++ ++ extcinfo = R_REG(sii->osh, ®s->extracoreinfo); ++ nb = ((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT); ++ for (i = 0; i < nb; i++) { ++ bankidx = i | (SOCRAM_MEMTYPE_DEVRAM << SOCRAM_BANKIDX_MEMTYPE_SHIFT); ++ W_REG(sii->osh, ®s->bankidx, bankidx); ++ bankinfo = R_REG(sii->osh, ®s->bankinfo); ++ if (set) { ++ bankinfo &= ~SOCRAM_BANKINFO_DEVRAMSEL_MASK; ++ bankinfo &= ~SOCRAM_BANKINFO_DEVRAMPRO_MASK; ++ bankinfo &= ~SOCRAM_BANKINFO_DEVRAMREMAP_MASK; ++ if (*enable) { ++ bankinfo |= (1 << SOCRAM_BANKINFO_DEVRAMSEL_SHIFT); ++ if (*protect) ++ bankinfo |= (1 << SOCRAM_BANKINFO_DEVRAMPRO_SHIFT); ++ if ((corerev >= 16) && *remap) ++ bankinfo |= ++ (1 << SOCRAM_BANKINFO_DEVRAMREMAP_SHIFT); ++ } ++ W_REG(sii->osh, ®s->bankinfo, bankinfo); ++ } ++ else if (i == 0) { ++ if (bankinfo & SOCRAM_BANKINFO_DEVRAMSEL_MASK) { ++ *enable = 1; ++ if (bankinfo & SOCRAM_BANKINFO_DEVRAMPRO_MASK) ++ *protect = 1; ++ if (bankinfo & SOCRAM_BANKINFO_DEVRAMREMAP_MASK) ++ *remap = 1; ++ } ++ } ++ } ++ } ++ ++ /* Return to previous state and core */ ++ if (!wasup) ++ si_core_disable(sih, 0); ++ si_setcoreidx(sih, origidx); ++ ++done: ++ INTR_RESTORE(sii, intr_val); ++} ++ ++bool ++si_socdevram_remap_isenb(si_t *sih) ++{ ++ si_info_t *sii; ++ uint origidx; ++ uint intr_val = 0; ++ sbsocramregs_t *regs; ++ bool wasup, remap = FALSE; ++ uint corerev; ++ uint32 extcinfo; ++ uint8 nb; ++ uint8 i; ++ uint32 bankidx, bankinfo; ++ ++ sii = SI_INFO(sih); ++ ++ /* Block ints and save current core */ ++ INTR_OFF(sii, intr_val); ++ origidx = si_coreidx(sih); ++ ++ /* Switch to SOCRAM core */ ++ if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) ++ goto done; ++ ++ /* Get info for determining size */ ++ if (!(wasup = si_iscoreup(sih))) ++ si_core_reset(sih, 0, 0); ++ ++ corerev = si_corerev(sih); ++ if (corerev >= 16) { ++ extcinfo = R_REG(sii->osh, ®s->extracoreinfo); ++ nb = ((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT); ++ for (i = 0; i < nb; i++) { ++ bankidx = i | (SOCRAM_MEMTYPE_DEVRAM << SOCRAM_BANKIDX_MEMTYPE_SHIFT); ++ W_REG(sii->osh, ®s->bankidx, bankidx); ++ bankinfo = R_REG(sii->osh, ®s->bankinfo); ++ if (bankinfo & SOCRAM_BANKINFO_DEVRAMREMAP_MASK) { ++ remap = TRUE; ++ break; ++ } ++ } ++ } ++ ++ /* Return to previous state and core */ ++ if (!wasup) ++ si_core_disable(sih, 0); ++ si_setcoreidx(sih, origidx); ++ ++done: ++ INTR_RESTORE(sii, intr_val); ++ return remap; ++} ++ ++bool ++si_socdevram_pkg(si_t *sih) ++{ ++ if (si_socdevram_size(sih) > 0) ++ return TRUE; ++ else ++ return FALSE; ++} ++ ++uint32 ++si_socdevram_size(si_t *sih) ++{ ++ si_info_t *sii; ++ uint origidx; ++ uint intr_val = 0; ++ uint32 memsize = 0; ++ sbsocramregs_t *regs; ++ bool wasup; ++ uint corerev; ++ ++ sii = SI_INFO(sih); ++ ++ /* Block ints and save current core */ ++ INTR_OFF(sii, intr_val); ++ origidx = si_coreidx(sih); ++ ++ /* Switch to SOCRAM core */ ++ if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) ++ goto done; ++ ++ /* Get info for determining size */ ++ if (!(wasup = si_iscoreup(sih))) ++ si_core_reset(sih, 0, 0); ++ ++ corerev = si_corerev(sih); ++ if (corerev >= 10) { ++ uint32 extcinfo; ++ uint8 nb; ++ uint8 i; ++ ++ extcinfo = R_REG(sii->osh, ®s->extracoreinfo); ++ nb = (((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT)); ++ for (i = 0; i < nb; i++) ++ memsize += socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_DEVRAM); ++ } ++ ++ /* Return to previous state and core */ ++ if (!wasup) ++ si_core_disable(sih, 0); ++ si_setcoreidx(sih, origidx); ++ ++done: ++ INTR_RESTORE(sii, intr_val); ++ ++ return memsize; ++} ++ ++uint32 ++si_socdevram_remap_size(si_t *sih) ++{ ++ si_info_t *sii; ++ uint origidx; ++ uint intr_val = 0; ++ uint32 memsize = 0, banksz; ++ sbsocramregs_t *regs; ++ bool wasup; ++ uint corerev; ++ uint32 extcinfo; ++ uint8 nb; ++ uint8 i; ++ uint32 bankidx, bankinfo; ++ ++ sii = SI_INFO(sih); ++ ++ /* Block ints and save current core */ ++ INTR_OFF(sii, intr_val); ++ origidx = si_coreidx(sih); ++ ++ /* Switch to SOCRAM core */ ++ if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) ++ goto done; ++ ++ /* Get info for determining size */ ++ if (!(wasup = si_iscoreup(sih))) ++ si_core_reset(sih, 0, 0); ++ ++ corerev = si_corerev(sih); ++ if (corerev >= 16) { ++ extcinfo = R_REG(sii->osh, ®s->extracoreinfo); ++ nb = (((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT)); ++ ++ /* ++ * FIX: A0 Issue: Max addressable is 512KB, instead 640KB ++ * Only four banks are accessible to ARM ++ */ ++ if ((corerev == 16) && (nb == 5)) ++ nb = 4; ++ ++ for (i = 0; i < nb; i++) { ++ bankidx = i | (SOCRAM_MEMTYPE_DEVRAM << SOCRAM_BANKIDX_MEMTYPE_SHIFT); ++ W_REG(sii->osh, ®s->bankidx, bankidx); ++ bankinfo = R_REG(sii->osh, ®s->bankinfo); ++ if (bankinfo & SOCRAM_BANKINFO_DEVRAMREMAP_MASK) { ++ banksz = socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_DEVRAM); ++ memsize += banksz; ++ } else { ++ /* Account only consecutive banks for now */ ++ break; ++ } ++ } ++ } ++ ++ /* Return to previous state and core */ ++ if (!wasup) ++ si_core_disable(sih, 0); ++ si_setcoreidx(sih, origidx); ++ ++done: ++ INTR_RESTORE(sii, intr_val); ++ ++ return memsize; ++} ++ ++/* Return the RAM size of the SOCRAM core */ ++uint32 ++si_socram_size(si_t *sih) ++{ ++ si_info_t *sii; ++ uint origidx; ++ uint intr_val = 0; ++ ++ sbsocramregs_t *regs; ++ bool wasup; ++ uint corerev; ++ uint32 coreinfo; ++ uint memsize = 0; ++ ++ sii = SI_INFO(sih); ++ ++ /* Block ints and save current core */ ++ INTR_OFF(sii, intr_val); ++ origidx = si_coreidx(sih); ++ ++ /* Switch to SOCRAM core */ ++ if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) ++ goto done; ++ ++ /* Get info for determining size */ ++ if (!(wasup = si_iscoreup(sih))) ++ si_core_reset(sih, 0, 0); ++ corerev = si_corerev(sih); ++ coreinfo = R_REG(sii->osh, ®s->coreinfo); ++ ++ /* Calculate size from coreinfo based on rev */ ++ if (corerev == 0) ++ memsize = 1 << (16 + (coreinfo & SRCI_MS0_MASK)); ++ else if (corerev < 3) { ++ memsize = 1 << (SR_BSZ_BASE + (coreinfo & SRCI_SRBSZ_MASK)); ++ memsize *= (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; ++ } else if ((corerev <= 7) || (corerev == 12)) { ++ uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; ++ uint bsz = (coreinfo & SRCI_SRBSZ_MASK); ++ uint lss = (coreinfo & SRCI_LSS_MASK) >> SRCI_LSS_SHIFT; ++ if (lss != 0) ++ nb --; ++ memsize = nb * (1 << (bsz + SR_BSZ_BASE)); ++ if (lss != 0) ++ memsize += (1 << ((lss - 1) + SR_BSZ_BASE)); ++ } else { ++ uint8 i; ++ uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; ++ for (i = 0; i < nb; i++) ++ memsize += socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_RAM); ++ } ++ ++ /* Return to previous state and core */ ++ if (!wasup) ++ si_core_disable(sih, 0); ++ si_setcoreidx(sih, origidx); ++ ++done: ++ INTR_RESTORE(sii, intr_val); ++ ++ return memsize; ++} ++ ++ ++/* Return the TCM-RAM size of the ARMCR4 core. */ ++uint32 ++si_tcm_size(si_t *sih) ++{ ++ si_info_t *sii; ++ uint origidx; ++ uint intr_val = 0; ++ uint8 *regs; ++ bool wasup; ++ uint32 corecap; ++ uint memsize = 0; ++ uint32 nab = 0; ++ uint32 nbb = 0; ++ uint32 totb = 0; ++ uint32 bxinfo = 0; ++ uint32 idx = 0; ++ uint32 *arm_cap_reg; ++ uint32 *arm_bidx; ++ uint32 *arm_binfo; ++ ++ sii = SI_INFO(sih); ++ ++ /* Block ints and save current core */ ++ INTR_OFF(sii, intr_val); ++ origidx = si_coreidx(sih); ++ ++ /* Switch to CR4 core */ ++ if (!(regs = si_setcore(sih, ARMCR4_CORE_ID, 0))) ++ goto done; ++ ++ /* Get info for determining size. If in reset, come out of reset, ++ * but remain in halt ++ */ ++ if (!(wasup = si_iscoreup(sih))) ++ si_core_reset(sih, SICF_CPUHALT, SICF_CPUHALT); ++ ++ arm_cap_reg = (uint32 *)(regs + SI_CR4_CAP); ++ corecap = R_REG(sii->osh, arm_cap_reg); ++ ++ nab = (corecap & ARMCR4_TCBANB_MASK) >> ARMCR4_TCBANB_SHIFT; ++ nbb = (corecap & ARMCR4_TCBBNB_MASK) >> ARMCR4_TCBBNB_SHIFT; ++ totb = nab + nbb; ++ ++ arm_bidx = (uint32 *)(regs + SI_CR4_BANKIDX); ++ arm_binfo = (uint32 *)(regs + SI_CR4_BANKINFO); ++ for (idx = 0; idx < totb; idx++) { ++ W_REG(sii->osh, arm_bidx, idx); ++ ++ bxinfo = R_REG(sii->osh, arm_binfo); ++ memsize += ((bxinfo & ARMCR4_BSZ_MASK) + 1) * ARMCR4_BSZ_MULT; ++ } ++ ++ /* Return to previous state and core */ ++ if (!wasup) ++ si_core_disable(sih, 0); ++ si_setcoreidx(sih, origidx); ++ ++done: ++ INTR_RESTORE(sii, intr_val); ++ ++ return memsize; ++} ++ ++uint32 ++si_socram_srmem_size(si_t *sih) ++{ ++ si_info_t *sii; ++ uint origidx; ++ uint intr_val = 0; ++ ++ sbsocramregs_t *regs; ++ bool wasup; ++ uint corerev; ++ uint32 coreinfo; ++ uint memsize = 0; ++ ++ if ((CHIPID(sih->chip) == BCM4334_CHIP_ID) && (CHIPREV(sih->chiprev) < 2)) { ++ return (32 * 1024); ++ } ++ ++ sii = SI_INFO(sih); ++ ++ /* Block ints and save current core */ ++ INTR_OFF(sii, intr_val); ++ origidx = si_coreidx(sih); ++ ++ /* Switch to SOCRAM core */ ++ if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) ++ goto done; ++ ++ /* Get info for determining size */ ++ if (!(wasup = si_iscoreup(sih))) ++ si_core_reset(sih, 0, 0); ++ corerev = si_corerev(sih); ++ coreinfo = R_REG(sii->osh, ®s->coreinfo); ++ ++ /* Calculate size from coreinfo based on rev */ ++ if (corerev >= 16) { ++ uint8 i; ++ uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; ++ for (i = 0; i < nb; i++) { ++ W_REG(sii->osh, ®s->bankidx, i); ++ if (R_REG(sii->osh, ®s->bankinfo) & SOCRAM_BANKINFO_RETNTRAM_MASK) ++ memsize += socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_RAM); ++ } ++ } ++ ++ /* Return to previous state and core */ ++ if (!wasup) ++ si_core_disable(sih, 0); ++ si_setcoreidx(sih, origidx); ++ ++done: ++ INTR_RESTORE(sii, intr_val); ++ ++ return memsize; ++} ++ ++ ++void ++si_btcgpiowar(si_t *sih) ++{ ++ si_info_t *sii; ++ uint origidx; ++ uint intr_val = 0; ++ chipcregs_t *cc; ++ ++ sii = SI_INFO(sih); ++ ++ /* Make sure that there is ChipCommon core present && ++ * UART_TX is strapped to 1 ++ */ ++ if (!(sih->cccaps & CC_CAP_UARTGPIO)) ++ return; ++ ++ /* si_corereg cannot be used as we have to guarantee 8-bit read/writes */ ++ INTR_OFF(sii, intr_val); ++ ++ origidx = si_coreidx(sih); ++ ++ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); ++ ASSERT(cc != NULL); ++ ++ W_REG(sii->osh, &cc->uart0mcr, R_REG(sii->osh, &cc->uart0mcr) | 0x04); ++ ++ /* restore the original index */ ++ si_setcoreidx(sih, origidx); ++ ++ INTR_RESTORE(sii, intr_val); ++} ++ ++void ++si_chipcontrl_btshd0_4331(si_t *sih, bool on) ++{ ++ si_info_t *sii; ++ chipcregs_t *cc; ++ uint origidx; ++ uint32 val; ++ uint intr_val = 0; ++ ++ sii = SI_INFO(sih); ++ ++ INTR_OFF(sii, intr_val); ++ ++ origidx = si_coreidx(sih); ++ ++ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); ++ ++ val = R_REG(sii->osh, &cc->chipcontrol); ++ ++ /* bt_shd0 controls are same for 4331 chiprevs 0 and 1, packages 12x9 and 12x12 */ ++ if (on) { ++ /* Enable bt_shd0 on gpio4: */ ++ val |= (CCTRL4331_BT_SHD0_ON_GPIO4); ++ W_REG(sii->osh, &cc->chipcontrol, val); ++ } else { ++ val &= ~(CCTRL4331_BT_SHD0_ON_GPIO4); ++ W_REG(sii->osh, &cc->chipcontrol, val); ++ } ++ ++ /* restore the original index */ ++ si_setcoreidx(sih, origidx); ++ ++ INTR_RESTORE(sii, intr_val); ++} ++ ++void ++si_chipcontrl_restore(si_t *sih, uint32 val) ++{ ++ si_info_t *sii; ++ chipcregs_t *cc; ++ uint origidx; ++ ++ sii = SI_INFO(sih); ++ origidx = si_coreidx(sih); ++ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); ++ W_REG(sii->osh, &cc->chipcontrol, val); ++ si_setcoreidx(sih, origidx); ++} ++ ++uint32 ++si_chipcontrl_read(si_t *sih) ++{ ++ si_info_t *sii; ++ chipcregs_t *cc; ++ uint origidx; ++ uint32 val; ++ ++ sii = SI_INFO(sih); ++ origidx = si_coreidx(sih); ++ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); ++ val = R_REG(sii->osh, &cc->chipcontrol); ++ si_setcoreidx(sih, origidx); ++ return val; ++} ++ ++void ++si_chipcontrl_epa4331(si_t *sih, bool on) ++{ ++ si_info_t *sii; ++ chipcregs_t *cc; ++ uint origidx; ++ uint32 val; ++ ++ sii = SI_INFO(sih); ++ origidx = si_coreidx(sih); ++ ++ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); ++ ++ val = R_REG(sii->osh, &cc->chipcontrol); ++ ++ if (on) { ++ if (sih->chippkg == 9 || sih->chippkg == 0xb) { ++ val |= (CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_ON_GPIO2_5); ++ /* Ext PA Controls for 4331 12x9 Package */ ++ W_REG(sii->osh, &cc->chipcontrol, val); ++ } else { ++ /* Ext PA Controls for 4331 12x12 Package */ ++ if (sih->chiprev > 0) { ++ W_REG(sii->osh, &cc->chipcontrol, val | ++ (CCTRL4331_EXTPA_EN) | (CCTRL4331_EXTPA_EN2)); ++ } else { ++ W_REG(sii->osh, &cc->chipcontrol, val | (CCTRL4331_EXTPA_EN)); ++ } ++ } ++ } else { ++ val &= ~(CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_EN2 | CCTRL4331_EXTPA_ON_GPIO2_5); ++ W_REG(sii->osh, &cc->chipcontrol, val); ++ } ++ ++ si_setcoreidx(sih, origidx); ++} ++ ++/* switch muxed pins, on: SROM, off: FEMCTRL */ ++void ++si_chipcontrl_srom4360(si_t *sih, bool on) ++{ ++ si_info_t *sii; ++ chipcregs_t *cc; ++ uint origidx; ++ uint32 val; ++ ++ sii = SI_INFO(sih); ++ origidx = si_coreidx(sih); ++ ++ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); ++ ++ val = R_REG(sii->osh, &cc->chipcontrol); ++ ++ if (on) { ++ val &= ~(CCTRL4360_SECI_MODE | ++ CCTRL4360_BTSWCTRL_MODE | ++ CCTRL4360_EXTRA_FEMCTRL_MODE | ++ CCTRL4360_BT_LGCY_MODE | ++ CCTRL4360_CORE2FEMCTRL4_ON); ++ ++ W_REG(sii->osh, &cc->chipcontrol, val); ++ } else { ++ } ++ ++ si_setcoreidx(sih, origidx); ++} ++ ++void ++si_chipcontrl_epa4331_wowl(si_t *sih, bool enter_wowl) ++{ ++ si_info_t *sii; ++ chipcregs_t *cc; ++ uint origidx; ++ uint32 val; ++ bool sel_chip; ++ ++ sel_chip = (CHIPID(sih->chip) == BCM4331_CHIP_ID) || ++ (CHIPID(sih->chip) == BCM43431_CHIP_ID); ++ sel_chip &= ((sih->chippkg == 9 || sih->chippkg == 0xb)); ++ ++ if (!sel_chip) ++ return; ++ ++ sii = SI_INFO(sih); ++ origidx = si_coreidx(sih); ++ ++ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); ++ ++ val = R_REG(sii->osh, &cc->chipcontrol); ++ ++ if (enter_wowl) { ++ val |= CCTRL4331_EXTPA_EN; ++ W_REG(sii->osh, &cc->chipcontrol, val); ++ } else { ++ val |= (CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_ON_GPIO2_5); ++ W_REG(sii->osh, &cc->chipcontrol, val); ++ } ++ si_setcoreidx(sih, origidx); ++} ++ ++uint ++si_pll_reset(si_t *sih) ++{ ++ uint err = 0; ++ ++ return (err); ++} ++ ++/* Enable BT-COEX & Ex-PA for 4313 */ ++void ++si_epa_4313war(si_t *sih) ++{ ++ si_info_t *sii; ++ chipcregs_t *cc; ++ uint origidx; ++ ++ sii = SI_INFO(sih); ++ origidx = si_coreidx(sih); ++ ++ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); ++ ++ /* EPA Fix */ ++ W_REG(sii->osh, &cc->gpiocontrol, ++ R_REG(sii->osh, &cc->gpiocontrol) | GPIO_CTRL_EPA_EN_MASK); ++ ++ si_setcoreidx(sih, origidx); ++} ++ ++void ++si_clk_pmu_htavail_set(si_t *sih, bool set_clear) ++{ ++} ++ ++/* WL/BT control for 4313 btcombo boards >= P250 */ ++void ++si_btcombo_p250_4313_war(si_t *sih) ++{ ++ si_info_t *sii; ++ chipcregs_t *cc; ++ uint origidx; ++ ++ sii = SI_INFO(sih); ++ origidx = si_coreidx(sih); ++ ++ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); ++ W_REG(sii->osh, &cc->gpiocontrol, ++ R_REG(sii->osh, &cc->gpiocontrol) | GPIO_CTRL_5_6_EN_MASK); ++ ++ W_REG(sii->osh, &cc->gpioouten, ++ R_REG(sii->osh, &cc->gpioouten) | GPIO_CTRL_5_6_EN_MASK); ++ ++ si_setcoreidx(sih, origidx); ++} ++void ++si_btc_enable_chipcontrol(si_t *sih) ++{ ++ si_info_t *sii; ++ chipcregs_t *cc; ++ uint origidx; ++ ++ sii = SI_INFO(sih); ++ origidx = si_coreidx(sih); ++ ++ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); ++ ++ /* BT fix */ ++ W_REG(sii->osh, &cc->chipcontrol, ++ R_REG(sii->osh, &cc->chipcontrol) | CC_BTCOEX_EN_MASK); ++ ++ si_setcoreidx(sih, origidx); ++} ++void ++si_btcombo_43228_war(si_t *sih) ++{ ++ si_info_t *sii; ++ chipcregs_t *cc; ++ uint origidx; ++ ++ sii = SI_INFO(sih); ++ origidx = si_coreidx(sih); ++ ++ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); ++ ++ W_REG(sii->osh, &cc->gpioouten, GPIO_CTRL_7_6_EN_MASK); ++ W_REG(sii->osh, &cc->gpioout, GPIO_OUT_7_EN_MASK); ++ ++ si_setcoreidx(sih, origidx); ++} ++ ++/* check if the device is removed */ ++bool ++si_deviceremoved(si_t *sih) ++{ ++ uint32 w; ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ ++ switch (BUSTYPE(sih->bustype)) { ++ case PCI_BUS: ++ ASSERT(sii->osh != NULL); ++ w = OSL_PCI_READ_CONFIG(sii->osh, PCI_CFG_VID, sizeof(uint32)); ++ if ((w & 0xFFFF) != VENDOR_BROADCOM) ++ return TRUE; ++ break; ++ } ++ return FALSE; ++} ++ ++bool ++si_is_sprom_available(si_t *sih) ++{ ++ if (sih->ccrev >= 31) { ++ si_info_t *sii; ++ uint origidx; ++ chipcregs_t *cc; ++ uint32 sromctrl; ++ ++ if ((sih->cccaps & CC_CAP_SROM) == 0) ++ return FALSE; ++ ++ sii = SI_INFO(sih); ++ origidx = sii->curidx; ++ cc = si_setcoreidx(sih, SI_CC_IDX); ++ sromctrl = R_REG(sii->osh, &cc->sromcontrol); ++ si_setcoreidx(sih, origidx); ++ return (sromctrl & SRC_PRESENT); ++ } ++ ++ switch (CHIPID(sih->chip)) { ++ case BCM4312_CHIP_ID: ++ return ((sih->chipst & CST4312_SPROM_OTP_SEL_MASK) != CST4312_OTP_SEL); ++ case BCM4325_CHIP_ID: ++ return (sih->chipst & CST4325_SPROM_SEL) != 0; ++ case BCM4322_CHIP_ID: case BCM43221_CHIP_ID: case BCM43231_CHIP_ID: ++ case BCM43222_CHIP_ID: case BCM43111_CHIP_ID: case BCM43112_CHIP_ID: ++ case BCM4342_CHIP_ID: { ++ uint32 spromotp; ++ spromotp = (sih->chipst & CST4322_SPROM_OTP_SEL_MASK) >> ++ CST4322_SPROM_OTP_SEL_SHIFT; ++ return (spromotp & CST4322_SPROM_PRESENT) != 0; ++ } ++ case BCM4329_CHIP_ID: ++ return (sih->chipst & CST4329_SPROM_SEL) != 0; ++ case BCM4315_CHIP_ID: ++ return (sih->chipst & CST4315_SPROM_SEL) != 0; ++ case BCM4319_CHIP_ID: ++ return (sih->chipst & CST4319_SPROM_SEL) != 0; ++ case BCM4336_CHIP_ID: ++ case BCM43362_CHIP_ID: ++ return (sih->chipst & CST4336_SPROM_PRESENT) != 0; ++ case BCM4330_CHIP_ID: ++ return (sih->chipst & CST4330_SPROM_PRESENT) != 0; ++ case BCM4313_CHIP_ID: ++ return (sih->chipst & CST4313_SPROM_PRESENT) != 0; ++ case BCM4331_CHIP_ID: ++ case BCM43431_CHIP_ID: ++ return (sih->chipst & CST4331_SPROM_PRESENT) != 0; ++ case BCM43239_CHIP_ID: ++ return ((sih->chipst & CST43239_SPROM_MASK) && ++ !(sih->chipst & CST43239_SFLASH_MASK)); ++ case BCM4324_CHIP_ID: ++ return ((sih->chipst & CST4324_SPROM_MASK) && ++ !(sih->chipst & CST4324_SFLASH_MASK)); ++ case BCM4335_CHIP_ID: ++ return ((sih->chipst & CST4335_SPROM_MASK) && ++ !(sih->chipst & CST4335_SFLASH_MASK)); ++ case BCM43131_CHIP_ID: ++ case BCM43217_CHIP_ID: ++ case BCM43227_CHIP_ID: ++ case BCM43228_CHIP_ID: ++ case BCM43428_CHIP_ID: ++ return (sih->chipst & CST43228_OTP_PRESENT) != CST43228_OTP_PRESENT; ++ default: ++ return TRUE; ++ } ++} ++ ++ ++uint32 si_get_sromctl(si_t *sih) ++{ ++ chipcregs_t *cc; ++ uint origidx; ++ uint32 sromctl; ++ osl_t *osh; ++ ++ osh = si_osh(sih); ++ origidx = si_coreidx(sih); ++ cc = si_setcoreidx(sih, SI_CC_IDX); ++ ASSERT((uintptr)cc); ++ ++ sromctl = R_REG(osh, &cc->sromcontrol); ++ ++ /* return to the original core */ ++ si_setcoreidx(sih, origidx); ++ return sromctl; ++} ++ ++int si_set_sromctl(si_t *sih, uint32 value) ++{ ++ chipcregs_t *cc; ++ uint origidx; ++ osl_t *osh; ++ ++ osh = si_osh(sih); ++ origidx = si_coreidx(sih); ++ cc = si_setcoreidx(sih, SI_CC_IDX); ++ ASSERT((uintptr)cc); ++ ++ /* get chipcommon rev */ ++ if (si_corerev(sih) < 32) ++ return BCME_UNSUPPORTED; ++ ++ W_REG(osh, &cc->sromcontrol, value); ++ ++ /* return to the original core */ ++ si_setcoreidx(sih, origidx); ++ return BCME_OK; ++ ++} +diff --git a/drivers/net/wireless/ap6211/siutils_priv.h b/drivers/net/wireless/ap6211/siutils_priv.h +new file mode 100755 +index 0000000..34fc3fa +--- /dev/null ++++ b/drivers/net/wireless/ap6211/siutils_priv.h +@@ -0,0 +1,236 @@ ++/* ++ * Include file private to the SOC Interconnect support files. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: siutils_priv.h 309193 2012-01-19 00:03:57Z $ ++ */ ++ ++#ifndef _siutils_priv_h_ ++#define _siutils_priv_h_ ++ ++#define IS_SIM(chippkg) ((chippkg == HDLSIM_PKG_ID) || (chippkg == HWSIM_PKG_ID)) ++ ++typedef uint32 (*si_intrsoff_t)(void *intr_arg); ++typedef void (*si_intrsrestore_t)(void *intr_arg, uint32 arg); ++typedef bool (*si_intrsenabled_t)(void *intr_arg); ++ ++typedef struct gpioh_item { ++ void *arg; ++ bool level; ++ gpio_handler_t handler; ++ uint32 event; ++ struct gpioh_item *next; ++} gpioh_item_t; ++ ++/* misc si info needed by some of the routines */ ++typedef struct si_info { ++ struct si_pub pub; /* back plane public state (must be first field) */ ++ ++ void *osh; /* osl os handle */ ++ void *sdh; /* bcmsdh handle */ ++ ++ uint dev_coreid; /* the core provides driver functions */ ++ void *intr_arg; /* interrupt callback function arg */ ++ si_intrsoff_t intrsoff_fn; /* turns chip interrupts off */ ++ si_intrsrestore_t intrsrestore_fn; /* restore chip interrupts */ ++ si_intrsenabled_t intrsenabled_fn; /* check if interrupts are enabled */ ++ ++ void *pch; /* PCI/E core handle */ ++ ++ gpioh_item_t *gpioh_head; /* GPIO event handlers list */ ++ ++ bool memseg; /* flag to toggle MEM_SEG register */ ++ ++ char *vars; ++ uint varsz; ++ ++ void *curmap; /* current regs va */ ++ void *regs[SI_MAXCORES]; /* other regs va */ ++ ++ uint curidx; /* current core index */ ++ uint numcores; /* # discovered cores */ ++ uint coreid[SI_MAXCORES]; /* id of each core */ ++ uint32 coresba[SI_MAXCORES]; /* backplane address of each core */ ++ void *regs2[SI_MAXCORES]; /* va of each core second register set (usbh20) */ ++ uint32 coresba2[SI_MAXCORES]; /* address of each core second register set (usbh20) */ ++ uint32 coresba_size[SI_MAXCORES]; /* backplane address space size */ ++ uint32 coresba2_size[SI_MAXCORES]; /* second address space size */ ++ ++ void *curwrap; /* current wrapper va */ ++ void *wrappers[SI_MAXCORES]; /* other cores wrapper va */ ++ uint32 wrapba[SI_MAXCORES]; /* address of controlling wrapper */ ++ ++ uint32 cia[SI_MAXCORES]; /* erom cia entry for each core */ ++ uint32 cib[SI_MAXCORES]; /* erom cia entry for each core */ ++ uint32 oob_router; /* oob router registers for axi */ ++} si_info_t; ++ ++#define SI_INFO(sih) (si_info_t *)(uintptr)sih ++ ++#define GOODCOREADDR(x, b) (((x) >= (b)) && ((x) < ((b) + SI_MAXCORES * SI_CORE_SIZE)) && \ ++ ISALIGNED((x), SI_CORE_SIZE)) ++#define GOODREGS(regs) ((regs) != NULL && ISALIGNED((uintptr)(regs), SI_CORE_SIZE)) ++#define BADCOREADDR 0 ++#define GOODIDX(idx) (((uint)idx) < SI_MAXCORES) ++#define NOREV -1 /* Invalid rev */ ++ ++#define PCI(si) ((BUSTYPE((si)->pub.bustype) == PCI_BUS) && \ ++ ((si)->pub.buscoretype == PCI_CORE_ID)) ++ ++#define PCIE_GEN1(si) ((BUSTYPE((si)->pub.bustype) == PCI_BUS) && \ ++ ((si)->pub.buscoretype == PCIE_CORE_ID)) ++ ++#define PCIE_GEN2(si) ((BUSTYPE((si)->pub.bustype) == PCI_BUS) && \ ++ ((si)->pub.buscoretype == PCIE2_CORE_ID)) ++ ++#define PCIE(si) (PCIE_GEN1(si) || PCIE_GEN2(si)) ++ ++#define PCMCIA(si) ((BUSTYPE((si)->pub.bustype) == PCMCIA_BUS) && ((si)->memseg == TRUE)) ++ ++/* Newer chips can access PCI/PCIE and CC core without requiring to change ++ * PCI BAR0 WIN ++ */ ++#define SI_FAST(si) (PCIE(si) || (PCI(si) && ((si)->pub.buscorerev >= 13))) ++ ++#define PCIEREGS(si) (((char *)((si)->curmap) + PCI_16KB0_PCIREGS_OFFSET)) ++#define CCREGS_FAST(si) (((char *)((si)->curmap) + PCI_16KB0_CCREGS_OFFSET)) ++ ++/* ++ * Macros to disable/restore function core(D11, ENET, ILINE20, etc) interrupts before/ ++ * after core switching to avoid invalid register accesss inside ISR. ++ */ ++#define INTR_OFF(si, intr_val) \ ++ if ((si)->intrsoff_fn && (si)->coreid[(si)->curidx] == (si)->dev_coreid) { \ ++ intr_val = (*(si)->intrsoff_fn)((si)->intr_arg); } ++#define INTR_RESTORE(si, intr_val) \ ++ if ((si)->intrsrestore_fn && (si)->coreid[(si)->curidx] == (si)->dev_coreid) { \ ++ (*(si)->intrsrestore_fn)((si)->intr_arg, intr_val); } ++ ++/* dynamic clock control defines */ ++#define LPOMINFREQ 25000 /* low power oscillator min */ ++#define LPOMAXFREQ 43000 /* low power oscillator max */ ++#define XTALMINFREQ 19800000 /* 20 MHz - 1% */ ++#define XTALMAXFREQ 20200000 /* 20 MHz + 1% */ ++#define PCIMINFREQ 25000000 /* 25 MHz */ ++#define PCIMAXFREQ 34000000 /* 33 MHz + fudge */ ++ ++#define ILP_DIV_5MHZ 0 /* ILP = 5 MHz */ ++#define ILP_DIV_1MHZ 4 /* ILP = 1 MHz */ ++ ++#define PCI_FORCEHT(si) \ ++ (((PCIE_GEN1(si)) && (si->pub.chip == BCM4311_CHIP_ID) && ((si->pub.chiprev <= 1))) || \ ++ ((PCI(si) || PCIE_GEN1(si)) && (si->pub.chip == BCM4321_CHIP_ID)) || \ ++ (PCIE_GEN1(si) && (si->pub.chip == BCM4716_CHIP_ID)) || \ ++ (PCIE_GEN1(si) && (si->pub.chip == BCM4748_CHIP_ID))) ++ ++/* GPIO Based LED powersave defines */ ++#define DEFAULT_GPIO_ONTIME 10 /* Default: 10% on */ ++#define DEFAULT_GPIO_OFFTIME 90 /* Default: 10% on */ ++ ++#ifndef DEFAULT_GPIOTIMERVAL ++#define DEFAULT_GPIOTIMERVAL ((DEFAULT_GPIO_ONTIME << GPIO_ONTIME_SHIFT) | DEFAULT_GPIO_OFFTIME) ++#endif ++ ++/* Silicon Backplane externs */ ++extern void sb_scan(si_t *sih, void *regs, uint devid); ++extern uint sb_coreid(si_t *sih); ++extern uint sb_intflag(si_t *sih); ++extern uint sb_flag(si_t *sih); ++extern void sb_setint(si_t *sih, int siflag); ++extern uint sb_corevendor(si_t *sih); ++extern uint sb_corerev(si_t *sih); ++extern uint sb_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); ++extern bool sb_iscoreup(si_t *sih); ++extern void *sb_setcoreidx(si_t *sih, uint coreidx); ++extern uint32 sb_core_cflags(si_t *sih, uint32 mask, uint32 val); ++extern void sb_core_cflags_wo(si_t *sih, uint32 mask, uint32 val); ++extern uint32 sb_core_sflags(si_t *sih, uint32 mask, uint32 val); ++extern void sb_commit(si_t *sih); ++extern uint32 sb_base(uint32 admatch); ++extern uint32 sb_size(uint32 admatch); ++extern void sb_core_reset(si_t *sih, uint32 bits, uint32 resetbits); ++extern void sb_core_disable(si_t *sih, uint32 bits); ++extern uint32 sb_addrspace(si_t *sih, uint asidx); ++extern uint32 sb_addrspacesize(si_t *sih, uint asidx); ++extern int sb_numaddrspaces(si_t *sih); ++ ++extern uint32 sb_set_initiator_to(si_t *sih, uint32 to, uint idx); ++ ++extern bool sb_taclear(si_t *sih, bool details); ++ ++ ++/* Wake-on-wireless-LAN (WOWL) */ ++extern bool sb_pci_pmecap(si_t *sih); ++struct osl_info; ++extern bool sb_pci_fastpmecap(struct osl_info *osh); ++extern bool sb_pci_pmeclr(si_t *sih); ++extern void sb_pci_pmeen(si_t *sih); ++extern uint sb_pcie_readreg(void *sih, uint addrtype, uint offset); ++ ++/* AMBA Interconnect exported externs */ ++extern si_t *ai_attach(uint pcidev, osl_t *osh, void *regs, uint bustype, ++ void *sdh, char **vars, uint *varsz); ++extern si_t *ai_kattach(osl_t *osh); ++extern void ai_scan(si_t *sih, void *regs, uint devid); ++ ++extern uint ai_flag(si_t *sih); ++extern void ai_setint(si_t *sih, int siflag); ++extern uint ai_coreidx(si_t *sih); ++extern uint ai_corevendor(si_t *sih); ++extern uint ai_corerev(si_t *sih); ++extern bool ai_iscoreup(si_t *sih); ++extern void *ai_setcoreidx(si_t *sih, uint coreidx); ++extern uint32 ai_core_cflags(si_t *sih, uint32 mask, uint32 val); ++extern void ai_core_cflags_wo(si_t *sih, uint32 mask, uint32 val); ++extern uint32 ai_core_sflags(si_t *sih, uint32 mask, uint32 val); ++extern uint ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); ++extern void ai_core_reset(si_t *sih, uint32 bits, uint32 resetbits); ++extern void ai_core_disable(si_t *sih, uint32 bits); ++extern int ai_numaddrspaces(si_t *sih); ++extern uint32 ai_addrspace(si_t *sih, uint asidx); ++extern uint32 ai_addrspacesize(si_t *sih, uint asidx); ++extern void ai_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size); ++extern uint ai_wrap_reg(si_t *sih, uint32 offset, uint32 mask, uint32 val); ++ ++ ++ ++#define ub_scan(a, b, c) do {} while (0) ++#define ub_flag(a) (0) ++#define ub_setint(a, b) do {} while (0) ++#define ub_coreidx(a) (0) ++#define ub_corevendor(a) (0) ++#define ub_corerev(a) (0) ++#define ub_iscoreup(a) (0) ++#define ub_setcoreidx(a, b) (0) ++#define ub_core_cflags(a, b, c) (0) ++#define ub_core_cflags_wo(a, b, c) do {} while (0) ++#define ub_core_sflags(a, b, c) (0) ++#define ub_corereg(a, b, c, d, e) (0) ++#define ub_core_reset(a, b, c) do {} while (0) ++#define ub_core_disable(a, b) do {} while (0) ++#define ub_numaddrspaces(a) (0) ++#define ub_addrspace(a, b) (0) ++#define ub_addrspacesize(a, b) (0) ++#define ub_view(a, b) do {} while (0) ++#define ub_dumpregs(a, b) do {} while (0) ++ ++#endif /* _siutils_priv_h_ */ +diff --git a/drivers/net/wireless/ap6211/uamp_api.h b/drivers/net/wireless/ap6211/uamp_api.h +new file mode 100755 +index 0000000..673dce0 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/uamp_api.h +@@ -0,0 +1,176 @@ ++/* ++ * Name: uamp_api.h ++ * ++ * Description: Universal AMP API ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: uamp_api.h 294267 2011-11-04 23:41:52Z $ ++ * ++ */ ++#ifndef UAMP_API_H ++#define UAMP_API_H ++ ++ ++#include "typedefs.h" ++ ++ ++/***************************************************************************** ++** Constant and Type Definitions ++****************************************************************************** ++*/ ++ ++#define BT_API ++ ++/* Types. */ ++typedef bool BOOLEAN; ++typedef uint8 UINT8; ++typedef uint16 UINT16; ++ ++ ++/* UAMP identifiers */ ++#define UAMP_ID_1 1 ++#define UAMP_ID_2 2 ++typedef UINT8 tUAMP_ID; ++ ++/* UAMP event ids (used by UAMP_CBACK) */ ++#define UAMP_EVT_RX_READY 0 /* Data from AMP controller is ready to be read */ ++#define UAMP_EVT_CTLR_REMOVED 1 /* Controller removed */ ++#define UAMP_EVT_CTLR_READY 2 /* Controller added/ready */ ++typedef UINT8 tUAMP_EVT; ++ ++ ++/* UAMP Channels */ ++#define UAMP_CH_HCI_CMD 0 /* HCI Command channel */ ++#define UAMP_CH_HCI_EVT 1 /* HCI Event channel */ ++#define UAMP_CH_HCI_DATA 2 /* HCI ACL Data channel */ ++typedef UINT8 tUAMP_CH; ++ ++/* tUAMP_EVT_DATA: union for event-specific data, used by UAMP_CBACK */ ++typedef union { ++ tUAMP_CH channel; /* UAMP_EVT_RX_READY: channel for which rx occured */ ++} tUAMP_EVT_DATA; ++ ++ ++/***************************************************************************** ++** ++** Function: UAMP_CBACK ++** ++** Description: Callback for events. Register callback using UAMP_Init. ++** ++** Parameters amp_id: AMP device identifier that generated the event ++** amp_evt: event id ++** p_amp_evt_data: pointer to event-specific data ++** ++****************************************************************************** ++*/ ++typedef void (*tUAMP_CBACK)(tUAMP_ID amp_id, tUAMP_EVT amp_evt, tUAMP_EVT_DATA *p_amp_evt_data); ++ ++/***************************************************************************** ++** external function declarations ++****************************************************************************** ++*/ ++#ifdef __cplusplus ++extern "C" ++{ ++#endif ++ ++/***************************************************************************** ++** ++** Function: UAMP_Init ++** ++** Description: Initialize UAMP driver ++** ++** Parameters p_cback: Callback function for UAMP event notification ++** ++****************************************************************************** ++*/ ++BT_API BOOLEAN UAMP_Init(tUAMP_CBACK p_cback); ++ ++ ++/***************************************************************************** ++** ++** Function: UAMP_Open ++** ++** Description: Open connection to local AMP device. ++** ++** Parameters app_id: Application specific AMP identifer. This value ++** will be included in AMP messages sent to the ++** BTU task, to identify source of the message ++** ++****************************************************************************** ++*/ ++BT_API BOOLEAN UAMP_Open(tUAMP_ID amp_id); ++ ++/***************************************************************************** ++** ++** Function: UAMP_Close ++** ++** Description: Close connection to local AMP device. ++** ++** Parameters app_id: Application specific AMP identifer. ++** ++****************************************************************************** ++*/ ++BT_API void UAMP_Close(tUAMP_ID amp_id); ++ ++ ++/***************************************************************************** ++** ++** Function: UAMP_Write ++** ++** Description: Send buffer to AMP device. Frees GKI buffer when done. ++** ++** ++** Parameters: app_id: AMP identifer. ++** p_buf: pointer to buffer to write ++** num_bytes: number of bytes to write ++** channel: UAMP_CH_HCI_ACL, or UAMP_CH_HCI_CMD ++** ++** Returns: number of bytes written ++** ++****************************************************************************** ++*/ ++BT_API UINT16 UAMP_Write(tUAMP_ID amp_id, UINT8 *p_buf, UINT16 num_bytes, tUAMP_CH channel); ++ ++/***************************************************************************** ++** ++** Function: UAMP_Read ++** ++** Description: Read incoming data from AMP. Call after receiving a ++** UAMP_EVT_RX_READY callback event. ++** ++** Parameters: app_id: AMP identifer. ++** p_buf: pointer to buffer for holding incoming AMP data ++** buf_size: size of p_buf ++** channel: UAMP_CH_HCI_ACL, or UAMP_CH_HCI_EVT ++** ++** Returns: number of bytes read ++** ++****************************************************************************** ++*/ ++BT_API UINT16 UAMP_Read(tUAMP_ID amp_id, UINT8 *p_buf, UINT16 buf_size, tUAMP_CH channel); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* UAMP_API_H */ +diff --git a/drivers/net/wireless/ap6211/wl_android.c b/drivers/net/wireless/ap6211/wl_android.c +new file mode 100755 +index 0000000..7e8b724 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/wl_android.c +@@ -0,0 +1,1448 @@ ++/* ++ * Linux cfg80211 driver - Android related functions ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: wl_android.c 372668 2012-12-04 14:07:12Z $ ++ */ ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef WL_CFG80211 ++#include ++#endif ++#if defined(CONFIG_WIFI_CONTROL_FUNC) ++#include ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) ++#include ++#else ++#include ++#endif ++#endif /* CONFIG_WIFI_CONTROL_FUNC */ ++ ++#include ++ ++#ifndef WL_CFG80211 ++#define htod32(i) i ++#define htod16(i) i ++#define dtoh32(i) i ++#define dtoh16(i) i ++#define htodchanspec(i) i ++#define dtohchanspec(i) i ++#endif ++ ++/* ++ * Android private command strings, PLEASE define new private commands here ++ * so they can be updated easily in the future (if needed) ++ */ ++ ++#define CMD_START "START" ++#define CMD_STOP "STOP" ++#define CMD_SCAN_ACTIVE "SCAN-ACTIVE" ++#define CMD_SCAN_PASSIVE "SCAN-PASSIVE" ++#define CMD_RSSI "RSSI" ++#define CMD_LINKSPEED "LINKSPEED" ++#define CMD_RXFILTER_START "RXFILTER-START" ++#define CMD_RXFILTER_STOP "RXFILTER-STOP" ++#define CMD_RXFILTER_ADD "RXFILTER-ADD" ++#define CMD_RXFILTER_REMOVE "RXFILTER-REMOVE" ++#define CMD_BTCOEXSCAN_START "BTCOEXSCAN-START" ++#define CMD_BTCOEXSCAN_STOP "BTCOEXSCAN-STOP" ++#define CMD_BTCOEXMODE "BTCOEXMODE" ++#define CMD_SETSUSPENDOPT "SETSUSPENDOPT" ++#define CMD_SETSUSPENDMODE "SETSUSPENDMODE" ++#define CMD_P2P_DEV_ADDR "P2P_DEV_ADDR" ++#define CMD_SETFWPATH "SETFWPATH" ++#define CMD_SETBAND "SETBAND" ++#define CMD_GETBAND "GETBAND" ++#define CMD_COUNTRY "COUNTRY" ++#define CMD_P2P_SET_NOA "P2P_SET_NOA" ++#if !defined WL_ENABLE_P2P_IF ++#define CMD_P2P_GET_NOA "P2P_GET_NOA" ++#endif ++#define CMD_P2P_SD_OFFLOAD "P2P_SD_" ++#define CMD_P2P_SET_PS "P2P_SET_PS" ++#define CMD_SET_AP_WPS_P2P_IE "SET_AP_WPS_P2P_IE" ++#define CMD_SETROAMMODE "SETROAMMODE" ++ ++ ++/* CCX Private Commands */ ++ ++#ifdef PNO_SUPPORT ++#define CMD_PNOSSIDCLR_SET "PNOSSIDCLR" ++#define CMD_PNOSETUP_SET "PNOSETUP " ++#define CMD_PNOENABLE_SET "PNOFORCE" ++#define CMD_PNODEBUG_SET "PNODEBUG" ++ ++#define PNO_TLV_PREFIX 'S' ++#define PNO_TLV_VERSION '1' ++#define PNO_TLV_SUBVERSION '2' ++#define PNO_TLV_RESERVED '0' ++#define PNO_TLV_TYPE_SSID_IE 'S' ++#define PNO_TLV_TYPE_TIME 'T' ++#define PNO_TLV_FREQ_REPEAT 'R' ++#define PNO_TLV_FREQ_EXPO_MAX 'M' ++ ++typedef struct cmd_tlv { ++ char prefix; ++ char version; ++ char subver; ++ char reserved; ++} cmd_tlv_t; ++#endif /* PNO_SUPPORT */ ++ ++#define CMD_OKC_SET_PMK "SET_PMK" ++#define CMD_OKC_ENABLE "OKC_ENABLE" ++ ++ ++typedef struct android_wifi_priv_cmd { ++ char *buf; ++ int used_len; ++ int total_len; ++} android_wifi_priv_cmd; ++ ++/** ++ * Extern function declarations (TODO: move them to dhd_linux.h) ++ */ ++void dhd_customer_gpio_wlan_ctrl(int onoff); ++int dhd_dev_reset(struct net_device *dev, uint8 flag); ++int dhd_dev_init_ioctl(struct net_device *dev); ++#ifdef WL_CFG80211 ++int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr); ++int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command); ++#else ++int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr) ++{ return 0; } ++int wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len) ++{ return 0; } ++int wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len) ++{ return 0; } ++int wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len) ++{ return 0; } ++#endif /* WL_CFG80211 */ ++ ++extern int dhd_os_check_wakelock(void *dhdp); ++extern int dhd_os_check_if_up(void *dhdp); ++extern void *bcmsdh_get_drvdata(void); ++#if defined(PROP_TXSTATUS) && !defined(PROP_TXSTATUS_VSDB) ++extern int dhd_wlfc_init(dhd_pub_t *dhd); ++extern void dhd_wlfc_deinit(dhd_pub_t *dhd); ++#endif ++ ++extern bool ap_fw_loaded; ++extern char iface_name[IFNAMSIZ]; ++ ++#define WIFI_TURNOFF_DELAY 0 ++/** ++ * Local (static) functions and variables ++ */ ++ ++/* Initialize g_wifi_on to 1 so dhd_bus_start will be called for the first ++ * time (only) in dhd_open, subsequential wifi on will be handled by ++ * wl_android_wifi_on ++ */ ++static int g_wifi_on = TRUE; ++ ++/** ++ * Local (static) function definitions ++ */ ++static int wl_android_get_link_speed(struct net_device *net, char *command, int total_len) ++{ ++ int link_speed; ++ int bytes_written; ++ int error; ++ ++ error = wldev_get_link_speed(net, &link_speed); ++ if (error) ++ return -1; ++ ++ /* Convert Kbps to Android Mbps */ ++ link_speed = link_speed / 1000; ++ bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed); ++ AP6211_DEBUG("%s: command result is %s\n", __FUNCTION__, command); ++ return bytes_written; ++} ++ ++static int wl_android_get_rssi(struct net_device *net, char *command, int total_len) ++{ ++ wlc_ssid_t ssid = {0}; ++ int rssi; ++ int bytes_written = 0; ++ int error; ++ ++ error = wldev_get_rssi(net, &rssi); ++ if (error) ++ return -1; ++#if defined(RSSIOFFSET) ++ rssi = wl_update_rssi_offset(rssi); ++#endif ++ ++ error = wldev_get_ssid(net, &ssid); ++ if (error) ++ return -1; ++ if ((ssid.SSID_len == 0) || (ssid.SSID_len > DOT11_MAX_SSID_LEN)) { ++ AP6211_ERR("%s: wldev_get_ssid failed\n", __FUNCTION__); ++ } else { ++ memcpy(command, ssid.SSID, ssid.SSID_len); ++ bytes_written = ssid.SSID_len; ++ } ++ bytes_written += snprintf(&command[bytes_written], total_len, " rssi %d", rssi); ++ AP6211_DEBUG("%s: command result is %s (%d)\n", __FUNCTION__, command, bytes_written); ++ return bytes_written; ++} ++ ++static int wl_android_set_suspendopt(struct net_device *dev, char *command, int total_len) ++{ ++ int suspend_flag; ++ int ret_now; ++ int ret = 0; ++ ++ suspend_flag = *(command + strlen(CMD_SETSUSPENDOPT) + 1) - '0'; ++ ++ if (suspend_flag != 0) ++ suspend_flag = 1; ++ ret_now = net_os_set_suspend_disable(dev, suspend_flag); ++ ++ if (ret_now != suspend_flag) { ++ if (!(ret = net_os_set_suspend(dev, ret_now, 1))) ++ AP6211_DEBUG("%s: Suspend Flag %d -> %d\n", ++ __FUNCTION__, ret_now, suspend_flag); ++ else ++ AP6211_ERR("%s: failed %d\n", __FUNCTION__, ret); ++ } ++ return ret; ++} ++ ++static int wl_android_set_suspendmode(struct net_device *dev, char *command, int total_len) ++{ ++ int ret = 0; ++ ++#if !defined(CONFIG_HAS_EARLYSUSPEND) || !defined(DHD_USE_EARLYSUSPEND) ++ int suspend_flag; ++ ++ suspend_flag = *(command + strlen(CMD_SETSUSPENDMODE) + 1) - '0'; ++ ++ if (suspend_flag != 0) ++ suspend_flag = 1; ++ ++ if (!(ret = net_os_set_suspend(dev, suspend_flag, 0))) ++ AP6211_DEBUG("%s: Suspend Mode %d\n",__FUNCTION__,suspend_flag); ++ else ++ AP6211_ERR("%s: failed %d\n",__FUNCTION__,ret); ++#endif ++ return ret; ++} ++ ++static int wl_android_get_band(struct net_device *dev, char *command, int total_len) ++{ ++ uint band; ++ int bytes_written; ++ int error; ++ ++ error = wldev_get_band(dev, &band); ++ if (error) ++ return -1; ++ bytes_written = snprintf(command, total_len, "Band %d", band); ++ return bytes_written; ++} ++ ++#if defined(PNO_SUPPORT) && !defined(WL_SCHED_SCAN) ++static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len) ++{ ++ wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT]; ++ int res = -1; ++ int nssid = 0; ++ cmd_tlv_t *cmd_tlv_temp; ++ char *str_ptr; ++ int tlv_size_left; ++ int pno_time = 0; ++ int pno_repeat = 0; ++ int pno_freq_expo_max = 0; ++ ++#ifdef PNO_SET_DEBUG ++ int i; ++ char pno_in_example[] = { ++ 'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ', ++ 'S', '1', '2', '0', ++ 'S', ++ 0x05, ++ 'd', 'l', 'i', 'n', 'k', ++ 'S', ++ 0x04, ++ 'G', 'O', 'O', 'G', ++ 'T', ++ '0', 'B', ++ 'R', ++ '2', ++ 'M', ++ '2', ++ 0x00 ++ }; ++#endif /* PNO_SET_DEBUG */ ++ ++ AP6211_DEBUG("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len); ++ ++ if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) { ++ AP6211_ERR("%s argument=%d less min size\n", __FUNCTION__, total_len); ++ goto exit_proc; ++ } ++ ++ ++#ifdef PNO_SET_DEBUG ++ memcpy(command, pno_in_example, sizeof(pno_in_example)); ++ for (i = 0; i < sizeof(pno_in_example); i++) ++ AP6211_DUMP("%02X ", command[i]); ++ AP6211_DUMP("\n"); ++ total_len = sizeof(pno_in_example); ++#endif ++ ++ str_ptr = command + strlen(CMD_PNOSETUP_SET); ++ tlv_size_left = total_len - strlen(CMD_PNOSETUP_SET); ++ ++ cmd_tlv_temp = (cmd_tlv_t *)str_ptr; ++ memset(ssids_local, 0, sizeof(ssids_local)); ++ ++ if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) && ++ (cmd_tlv_temp->version == PNO_TLV_VERSION) && ++ (cmd_tlv_temp->subver == PNO_TLV_SUBVERSION)) { ++ ++ str_ptr += sizeof(cmd_tlv_t); ++ tlv_size_left -= sizeof(cmd_tlv_t); ++ ++ if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local, ++ MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) { ++ AP6211_ERR("SSID is not presented or corrupted ret=%d\n", nssid); ++ goto exit_proc; ++ } else { ++ if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) { ++ AP6211_ERR("%s scan duration corrupted field size %d\n", ++ __FUNCTION__, tlv_size_left); ++ goto exit_proc; ++ } ++ str_ptr++; ++ pno_time = simple_strtoul(str_ptr, &str_ptr, 16); ++ AP6211_DEBUG("%s: pno_time=%d\n", __FUNCTION__, pno_time); ++ ++ if (str_ptr[0] != 0) { ++ if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) { ++ AP6211_ERR("%s pno repeat : corrupted field\n", ++ __FUNCTION__); ++ goto exit_proc; ++ } ++ str_ptr++; ++ pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16); ++ AP6211_DEBUG("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat); ++ if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) { ++ AP6211_ERR("%s FREQ_EXPO_MAX corrupted field size\n", ++ __FUNCTION__); ++ goto exit_proc; ++ } ++ str_ptr++; ++ pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16); ++ AP6211_DEBUG("%s: pno_freq_expo_max=%d\n", ++ __FUNCTION__, pno_freq_expo_max); ++ } ++ } ++ } else { ++ AP6211_ERR("%s get wrong TLV command\n", __FUNCTION__); ++ goto exit_proc; ++ } ++ ++ res = dhd_dev_pno_set(dev, ssids_local, nssid, pno_time, pno_repeat, pno_freq_expo_max); ++ ++exit_proc: ++ return res; ++} ++#endif /* PNO_SUPPORT && !WL_SCHED_SCAN */ ++ ++static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, int total_len) ++{ ++ int ret; ++ int bytes_written = 0; ++ ++ ret = wl_cfg80211_get_p2p_dev_addr(ndev, (struct ether_addr*)command); ++ if (ret) ++ return 0; ++ bytes_written = sizeof(struct ether_addr); ++ return bytes_written; ++} ++ ++/** ++ * Global function definitions (declared in wl_android.h) ++ */ ++ ++int wl_android_wifi_on(struct net_device *dev) ++{ ++ int ret = 0; ++ int retry = POWERUP_MAX_RETRY; ++ ++ AP6211_DEBUG("%s in\n", __FUNCTION__); ++ if (!dev) { ++ AP6211_ERR("%s: dev is null\n", __FUNCTION__); ++ return -EINVAL; ++ } ++ ++ dhd_net_if_lock(dev); ++ if (!g_wifi_on) { ++ do { ++ dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON); ++ ret = sdioh_start(NULL, 0); ++ if (ret == 0) ++ break; ++ AP6211_ERR("failed to power up wifi chip, retry again (%d left) **\n\n", ++ retry+1); ++ dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF); ++ } while (retry-- >= 0); ++ if (ret != 0) { ++ AP6211_ERR("failed to power up wifi chip, max retry reached **\n\n"); ++ goto exit; ++ } ++ ret = dhd_dev_reset(dev, FALSE); ++ if (ret) ++ goto err; ++ sdioh_start(NULL, 1); ++ if (!ret) { ++ if (dhd_dev_init_ioctl(dev) < 0) { ++ ret = -EFAULT; ++ goto err; ++ } ++ } ++#if defined(PROP_TXSTATUS) && !defined(PROP_TXSTATUS_VSDB) ++ dhd_wlfc_init(bcmsdh_get_drvdata()); ++#endif ++ g_wifi_on = TRUE; ++ } ++ ++exit: ++ dhd_net_if_unlock(dev); ++ AP6211_DEBUG("%s: Success\n", __FUNCTION__); ++ return ret; ++err: ++ dhd_dev_reset(dev, TRUE); ++ sdioh_stop(NULL); ++ dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF); ++ dhd_net_if_unlock(dev); ++ AP6211_DEBUG("%s: Failed\n", __FUNCTION__); ++ ++ return ret; ++} ++ ++int wl_android_wifi_off(struct net_device *dev) ++{ ++ int ret = 0; ++ ++ AP6211_DEBUG("%s in\n", __FUNCTION__); ++ if (!dev) { ++ AP6211_DEBUG("%s: dev is null\n", __FUNCTION__); ++ return -EINVAL; ++ } ++ ++ dhd_net_if_lock(dev); ++ if (g_wifi_on) { ++#if defined(PROP_TXSTATUS) && !defined(PROP_TXSTATUS_VSDB) ++ dhd_wlfc_deinit(bcmsdh_get_drvdata()); ++#endif ++ ret = dhd_dev_reset(dev, TRUE); ++ sdioh_stop(NULL); ++ dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF); ++ g_wifi_on = FALSE; ++ } ++ dhd_net_if_unlock(dev); ++ ++ return ret; ++} ++ ++static int wl_android_set_fwpath(struct net_device *net, char *command, int total_len) ++{ ++ if ((strlen(command) - strlen(CMD_SETFWPATH)) > MOD_PARAM_PATHLEN) ++ return -1; ++ bcm_strncpy_s(fw_path, sizeof(fw_path), ++ command + strlen(CMD_SETFWPATH) + 1, MOD_PARAM_PATHLEN - 1); ++ if (strstr(fw_path, "apsta") != NULL) { ++ AP6211_DEBUG("GOT APSTA FIRMWARE\n"); ++ ap_fw_loaded = TRUE; ++ } else { ++ AP6211_DEBUG("GOT STA FIRMWARE\n"); ++ ap_fw_loaded = FALSE; ++ } ++ return 0; ++} ++ ++static int ++wl_android_set_pmk(struct net_device *dev, char *command, int total_len) ++{ ++ uchar pmk[33]; ++ int error = 0; ++ char smbuf[WLC_IOCTL_SMLEN]; ++#ifdef OKC_DEBUG ++ int i = 0; ++#endif ++ ++ bzero(pmk, sizeof(pmk)); ++ memcpy((char *)pmk, command + strlen("SET_PMK "), 32); ++ error = wldev_iovar_setbuf(dev, "okc_info_pmk", pmk, 32, smbuf, sizeof(smbuf), NULL); ++ if (error) { ++ AP6211_ERR("Failed to set PMK for OKC, error = %d\n", error); ++ } ++#ifdef OKC_DEBUG ++ AP6211_ERR("PMK is "); ++ for (i = 0; i < 32; i++) ++ AP6211_ERR("%02X ", pmk[i]); ++ ++ AP6211_ERR("\n"); ++#endif ++ return error; ++} ++ ++static int ++wl_android_okc_enable(struct net_device *dev, char *command, int total_len) ++{ ++ int error = 0; ++ char okc_enable = 0; ++ ++ okc_enable = command[strlen(CMD_OKC_ENABLE) + 1] - '0'; ++ error = wldev_iovar_setint(dev, "okc_enable", okc_enable); ++ if (error) { ++ AP6211_ERR("Failed to %s OKC, error = %d\n", ++ okc_enable ? "enable" : "disable", error); ++ } ++ ++ return error; ++} ++ ++int wl_android_set_roam_mode(struct net_device *dev, char *command, int total_len) ++{ ++ int error = 0; ++ int mode = 0; ++ ++ if (sscanf(command, "%*s %d", &mode) != 1) { ++ AP6211_ERR("%s: Failed to get Parameter\n", __FUNCTION__); ++ return -1; ++ } ++ ++ error = wldev_iovar_setint(dev, "roam_off", mode); ++ if (error) { ++ AP6211_ERR("%s: Failed to set roaming Mode %d, error = %d\n", ++ __FUNCTION__, mode, error); ++ return -1; ++ } ++ else ++ AP6211_ERR("%s: succeeded to set roaming Mode %d, error = %d\n", ++ __FUNCTION__, mode, error); ++ return 0; ++} ++ ++int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) ++{ ++#define PRIVATE_COMMAND_MAX_LEN 8192 ++ int ret = 0; ++ char *command = NULL; ++ int bytes_written = 0; ++ android_wifi_priv_cmd priv_cmd; ++ ++ net_os_wake_lock(net); ++ ++ if (!ifr->ifr_data) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) { ++ ret = -EFAULT; ++ goto exit; ++ } ++ if (priv_cmd.total_len > PRIVATE_COMMAND_MAX_LEN) ++ { ++ AP6211_ERR("%s: too long priavte command\n", __FUNCTION__); ++ ret = -EINVAL; ++ } ++ command = kmalloc(priv_cmd.total_len, GFP_KERNEL); ++ if (!command) ++ { ++ AP6211_ERR("%s: failed to allocate memory\n", __FUNCTION__); ++ ret = -ENOMEM; ++ goto exit; ++ } ++ if (copy_from_user(command, priv_cmd.buf, priv_cmd.total_len)) { ++ ret = -EFAULT; ++ goto exit; ++ } ++ ++ AP6211_DEBUG("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__, command, ifr->ifr_name); ++ ++ if (strnicmp(command, CMD_START, strlen(CMD_START)) == 0) { ++ AP6211_DEBUG("%s, Received regular START command\n", __FUNCTION__); ++ bytes_written = wl_android_wifi_on(net); ++ } ++ else if (strnicmp(command, CMD_SETFWPATH, strlen(CMD_SETFWPATH)) == 0) { ++ bytes_written = wl_android_set_fwpath(net, command, priv_cmd.total_len); ++ } ++ ++ if (!g_wifi_on) { ++ AP6211_ERR("%s: Ignore private cmd \"%s\" - iface %s is down\n", ++ __FUNCTION__, command, ifr->ifr_name); ++ ret = 0; ++ goto exit; ++ } ++ ++ if (strnicmp(command, CMD_STOP, strlen(CMD_STOP)) == 0) { ++ bytes_written = wl_android_wifi_off(net); ++ } ++ else if (strnicmp(command, CMD_SCAN_ACTIVE, strlen(CMD_SCAN_ACTIVE)) == 0) { ++ /* TBD: SCAN-ACTIVE */ ++ } ++ else if (strnicmp(command, CMD_SCAN_PASSIVE, strlen(CMD_SCAN_PASSIVE)) == 0) { ++ /* TBD: SCAN-PASSIVE */ ++ } ++ else if (strnicmp(command, CMD_RSSI, strlen(CMD_RSSI)) == 0) { ++ bytes_written = wl_android_get_rssi(net, command, priv_cmd.total_len); ++ } ++ else if (strnicmp(command, CMD_LINKSPEED, strlen(CMD_LINKSPEED)) == 0) { ++ bytes_written = wl_android_get_link_speed(net, command, priv_cmd.total_len); ++ } ++#ifdef PKT_FILTER_SUPPORT ++ else if (strnicmp(command, CMD_RXFILTER_START, strlen(CMD_RXFILTER_START)) == 0) { ++ bytes_written = net_os_enable_packet_filter(net, 1); ++ } ++ else if (strnicmp(command, CMD_RXFILTER_STOP, strlen(CMD_RXFILTER_STOP)) == 0) { ++ bytes_written = net_os_enable_packet_filter(net, 0); ++ } ++ else if (strnicmp(command, CMD_RXFILTER_ADD, strlen(CMD_RXFILTER_ADD)) == 0) { ++ int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0'; ++ bytes_written = net_os_rxfilter_add_remove(net, TRUE, filter_num); ++ } ++ else if (strnicmp(command, CMD_RXFILTER_REMOVE, strlen(CMD_RXFILTER_REMOVE)) == 0) { ++ int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0'; ++ bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num); ++ } ++#endif /* PKT_FILTER_SUPPORT */ ++ else if (strnicmp(command, CMD_BTCOEXSCAN_START, strlen(CMD_BTCOEXSCAN_START)) == 0) { ++ /* TBD: BTCOEXSCAN-START */ ++ } ++ else if (strnicmp(command, CMD_BTCOEXSCAN_STOP, strlen(CMD_BTCOEXSCAN_STOP)) == 0) { ++ /* TBD: BTCOEXSCAN-STOP */ ++ } ++ else if (strnicmp(command, CMD_BTCOEXMODE, strlen(CMD_BTCOEXMODE)) == 0) { ++#ifdef WL_CFG80211 ++ bytes_written = wl_cfg80211_set_btcoex_dhcp(net, command); ++#else ++#ifdef PKT_FILTER_SUPPORT ++ uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0'; ++ ++ if (mode == 1) ++ net_os_enable_packet_filter(net, 0); /* DHCP starts */ ++ else ++ net_os_enable_packet_filter(net, 1); /* DHCP ends */ ++#endif /* PKT_FILTER_SUPPORT */ ++#endif /* WL_CFG80211 */ ++ } ++ else if (strnicmp(command, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) { ++ bytes_written = wl_android_set_suspendopt(net, command, priv_cmd.total_len); ++ } ++ else if (strnicmp(command, CMD_SETSUSPENDMODE, strlen(CMD_SETSUSPENDMODE)) == 0) { ++ bytes_written = wl_android_set_suspendmode(net, command, priv_cmd.total_len); ++ } ++ else if (strnicmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) { ++ uint band = *(command + strlen(CMD_SETBAND) + 1) - '0'; ++#ifdef WL_HOST_BAND_MGMT ++ if (wl_cfg80211_set_band(net, band) < 0) { ++ bytes_written = -1; ++ goto exit; ++ } ++ if (band == WLC_BAND_AUTO) ++ bytes_written = wldev_set_band(net, band); ++#else ++ bytes_written = wldev_set_band(net, band); ++#endif /* WL_HOST_BAND_MGMT */ ++ } ++ else if (strnicmp(command, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) { ++ bytes_written = wl_android_get_band(net, command, priv_cmd.total_len); ++ } ++#ifdef WL_CFG80211 ++ /* CUSTOMER_SET_COUNTRY feature is define for only GGSM model */ ++ else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) { ++ char *country_code = command + strlen(CMD_COUNTRY) + 1; ++ bytes_written = wldev_set_country(net, country_code); ++ } ++#endif /* WL_CFG80211 */ ++#if defined(PNO_SUPPORT) && !defined(WL_SCHED_SCAN) ++ else if (strnicmp(command, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) { ++ bytes_written = dhd_dev_pno_reset(net); ++ } ++ else if (strnicmp(command, CMD_PNOSETUP_SET, strlen(CMD_PNOSETUP_SET)) == 0) { ++ bytes_written = wl_android_set_pno_setup(net, command, priv_cmd.total_len); ++ } ++ else if (strnicmp(command, CMD_PNOENABLE_SET, strlen(CMD_PNOENABLE_SET)) == 0) { ++ uint pfn_enabled = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0'; ++ bytes_written = dhd_dev_pno_enable(net, pfn_enabled); ++ } ++#endif /* PNO_SUPPORT && !WL_SCHED_SCAN */ ++ else if (strnicmp(command, CMD_P2P_DEV_ADDR, strlen(CMD_P2P_DEV_ADDR)) == 0) { ++ bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd.total_len); ++ } ++ else if (strnicmp(command, CMD_P2P_SET_NOA, strlen(CMD_P2P_SET_NOA)) == 0) { ++ int skip = strlen(CMD_P2P_SET_NOA) + 1; ++ bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip, ++ priv_cmd.total_len - skip); ++ } ++#if !defined WL_ENABLE_P2P_IF ++ else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) { ++ bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len); ++ } ++#endif /* WL_ENABLE_P2P_IF */ ++ else if (strnicmp(command, CMD_P2P_SET_PS, strlen(CMD_P2P_SET_PS)) == 0) { ++ int skip = strlen(CMD_P2P_SET_PS) + 1; ++ bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip, ++ priv_cmd.total_len - skip); ++ } ++#ifdef WL_CFG80211 ++ else if (strnicmp(command, CMD_SET_AP_WPS_P2P_IE, ++ strlen(CMD_SET_AP_WPS_P2P_IE)) == 0) { ++ int skip = strlen(CMD_SET_AP_WPS_P2P_IE) + 3; ++ bytes_written = wl_cfg80211_set_wps_p2p_ie(net, command + skip, ++ priv_cmd.total_len - skip, *(command + skip - 2) - '0'); ++ } ++#endif /* WL_CFG80211 */ ++ else if (strnicmp(command, CMD_OKC_SET_PMK, strlen(CMD_OKC_SET_PMK)) == 0) ++ bytes_written = wl_android_set_pmk(net, command, priv_cmd.total_len); ++ else if (strnicmp(command, CMD_OKC_ENABLE, strlen(CMD_OKC_ENABLE)) == 0) ++ bytes_written = wl_android_okc_enable(net, command, priv_cmd.total_len); ++ else if (strnicmp(command, CMD_SETROAMMODE, strlen(CMD_SETROAMMODE)) == 0) ++ bytes_written = wl_android_set_roam_mode(net, command, priv_cmd.total_len); ++ else { ++ AP6211_ERR("Unknown PRIVATE command %s - ignored\n", command); ++ snprintf(command, 3, "OK"); ++ bytes_written = strlen("OK"); ++ } ++ ++ if (bytes_written >= 0) { ++ if ((bytes_written == 0) && (priv_cmd.total_len > 0)) ++ command[0] = '\0'; ++ if (bytes_written >= priv_cmd.total_len) { ++ AP6211_ERR("%s: bytes_written = %d\n", __FUNCTION__, bytes_written); ++ bytes_written = priv_cmd.total_len; ++ } else { ++ bytes_written++; ++ } ++ priv_cmd.used_len = bytes_written; ++ if (copy_to_user(priv_cmd.buf, command, bytes_written)) { ++ AP6211_ERR("%s: failed to copy data to user buffer\n", __FUNCTION__); ++ ret = -EFAULT; ++ } ++ } ++ else { ++ ret = bytes_written; ++ } ++ ++exit: ++ net_os_wake_unlock(net); ++ if (command) { ++ kfree(command); ++ } ++ ++ return ret; ++} ++ ++int wl_android_init(void) ++{ ++ int ret = 0; ++ ++ dhd_msg_level |= DHD_ERROR_VAL; ++#ifdef ENABLE_INSMOD_NO_FW_LOAD ++ dhd_download_fw_on_driverload = FALSE; ++#endif /* ENABLE_INSMOD_NO_FW_LOAD */ ++ if (!iface_name[0]) { ++ memset(iface_name, 0, IFNAMSIZ); ++ bcm_strncpy_s(iface_name, IFNAMSIZ, "wlan", IFNAMSIZ); ++ } ++ return ret; ++} ++ ++int wl_android_exit(void) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++void wl_android_post_init(void) ++{ ++ if (!dhd_download_fw_on_driverload) { ++ /* Call customer gpio to turn off power with WL_REG_ON signal */ ++ dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF); ++ g_wifi_on = 0; ++ } ++} ++ ++#if defined(RSSIAVG) ++void ++wl_free_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl) ++{ ++ wl_rssi_cache_t *node, *cur, **rssi_head; ++ int i=0; ++ ++ rssi_head = &rssi_cache_ctrl->m_cache_head; ++ node = *rssi_head; ++ ++ for (;node;) { ++ AP6211_DEBUG("%s: Free %d with BSSID %pM\n", ++ __FUNCTION__, i, &node->BSSID); ++ cur = node; ++ node = cur->next; ++ kfree(cur); ++ i++; ++ } ++ *rssi_head = NULL; ++} ++ ++void ++wl_delete_dirty_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl) ++{ ++ wl_rssi_cache_t *node, *prev, **rssi_head; ++ int i = -1, tmp = 0; ++#if defined(BSSCACHE) ++ int max = BSSCACHE_LEN; ++#else ++ int max = RSSICACHE_LEN; ++#endif ++ ++ rssi_head = &rssi_cache_ctrl->m_cache_head; ++ node = *rssi_head; ++ prev = node; ++ for (;node;) { ++ i++; ++ if (node->dirty >= max || node->dirty >= RSSICACHE_LEN) { ++ if (node == *rssi_head) { ++ tmp = 1; ++ *rssi_head = node->next; ++ } else { ++ tmp = 0; ++ prev->next = node->next; ++ } ++ AP6211_DEBUG("%s: Del %d with BSSID %pM\n", ++ __FUNCTION__, i, &node->BSSID); ++ kfree(node); ++ if (tmp == 1) { ++ node = *rssi_head; ++ prev = node; ++ } else { ++ node = prev->next; ++ } ++ continue; ++ } ++ prev = node; ++ node = node->next; ++ } ++} ++ ++void ++wl_reset_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl) ++{ ++ wl_rssi_cache_t *node, **rssi_head; ++ ++ rssi_head = &rssi_cache_ctrl->m_cache_head; ++ ++ /* reset dirty */ ++ node = *rssi_head; ++ for (;node;) { ++ node->dirty += 1; ++ node = node->next; ++ } ++} ++ ++void ++wl_update_connected_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, struct net_device *net) ++{ ++ wl_rssi_cache_t *node, *prev, **rssi_head; ++ int j, k=0; ++ int rssi, error; ++ struct ether_addr bssid; ++ ++ error = wldev_ioctl(net, WLC_GET_BSSID, &bssid, sizeof(bssid), false); ++ if (error) ++ return; ++ error = wldev_get_rssi(net, &rssi); ++ if (error) ++ return; ++ ++ /* update RSSI */ ++ rssi_head = &rssi_cache_ctrl->m_cache_head; ++ node = *rssi_head; ++ for (;node;) { ++ if (!memcmp(&node->BSSID, &bssid, ETHER_ADDR_LEN)) { ++ AP6211_DEBUG("%s: Update %d with BSSID %pM, RSSI=%d\n", ++ __FUNCTION__, k, &bssid, rssi); ++ for(j=0; jRSSI[j] = node->RSSI[j+1]; ++ node->RSSI[j] = rssi; ++ node->dirty = 0; ++ break; ++ } ++ prev = node; ++ node = node->next; ++ k++; ++ } ++} ++ ++void ++wl_update_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, wl_scan_results_t *ss_list) ++{ ++ wl_rssi_cache_t *node, *prev, *leaf, **rssi_head; ++ wl_bss_info_t *bi = NULL; ++ int i, j, k; ++ ++ if (!ss_list->count) ++ return; ++ ++ rssi_head = &rssi_cache_ctrl->m_cache_head; ++ ++ /* update RSSI */ ++ for (i = 0; i < ss_list->count; i++) { ++ node = *rssi_head; ++ prev = NULL; ++ k = 0; ++ bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info; ++ for (;node;) { ++ if (!memcmp(&node->BSSID, &bi->BSSID, ETHER_ADDR_LEN)) { ++ AP6211_DEBUG("%s: Update %d with BSSID %pM, RSSI=%d, SSID \"%s\"\n", ++ __FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID); ++ for(j=0; jRSSI[j] = node->RSSI[j+1]; ++ node->RSSI[j] = dtoh16(bi->RSSI); ++ node->dirty = 0; ++ break; ++ } ++ prev = node; ++ node = node->next; ++ k++; ++ } ++ ++ if (node) ++ continue; ++ ++ leaf = kmalloc(sizeof(wl_rssi_cache_t), GFP_KERNEL); ++ if (!leaf) { ++ AP6211_ERR("%s: Memory alloc failure %d\n", ++ __FUNCTION__, sizeof(wl_rssi_cache_t)); ++ return; ++ } ++ AP6211_DEBUG("%s: Add %d with cached BSSID %pM, RSSI=%d, SSID \"%s\" in the leaf\n", ++ __FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID); ++ ++ leaf->next = NULL; ++ leaf->dirty = 0; ++ memcpy(&leaf->BSSID, &bi->BSSID, ETHER_ADDR_LEN); ++ for (j=0; jRSSI[j] = dtoh16(bi->RSSI); ++ ++ if (!prev) ++ *rssi_head = leaf; ++ else ++ prev->next = leaf; ++ } ++} ++ ++int16 ++wl_get_avg_rssi(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, void *addr) ++{ ++ wl_rssi_cache_t *node, **rssi_head; ++ int j, rssi_sum, rssi=-200; ++ ++ rssi_head = &rssi_cache_ctrl->m_cache_head; ++ ++ /* reset dirty */ ++ node = *rssi_head; ++ for (;node;) { ++ if (!memcmp(&node->BSSID, addr, ETHER_ADDR_LEN)) { ++ rssi_sum = 0; ++ rssi = 0; ++ for (j=0; jRSSI[RSSIAVG_LEN-j-1]; ++ rssi = rssi_sum / j; ++ break; ++ } ++ node = node->next; ++ } ++ if (rssi >= -2) ++ rssi = -2; ++ if (rssi == -200) { ++ AP6211_ERR("%s: BSSID %pM does not in RSSI cache\n", ++ __FUNCTION__, addr); ++ } ++ return (int16)rssi; ++} ++#endif ++ ++#if defined(RSSIOFFSET) ++int ++wl_update_rssi_offset(int rssi) ++{ ++ uint chip, chiprev; ++ ++ chip = dhd_bus_chip_id(bcmsdh_get_drvdata()); ++ chiprev = dhd_bus_chiprev_id(bcmsdh_get_drvdata()); ++ if (chip == BCM4330_CHIP_ID && chiprev == BCM4330B2_CHIP_REV) { ++#if defined(RSSIOFFSET_NEW) ++ int j; ++ for (j=0; j= -2) ++ rssi = -2; ++ return rssi; ++} ++#endif ++ ++#if defined(BSSCACHE) ++#define WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN 32 ++ ++void ++wl_free_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl) ++{ ++ wl_bss_cache_t *node, *cur, **bss_head; ++ int i=0; ++ ++ AP6211_DEBUG("%s called\n", __FUNCTION__); ++ ++ bss_head = &bss_cache_ctrl->m_cache_head; ++ node = *bss_head; ++ ++ for (;node;) { ++ AP6211_DEBUG("%s: Free %d with BSSID %pM\n", ++ __FUNCTION__, i, &node->results.bss_info->BSSID); ++ cur = node; ++ node = cur->next; ++ kfree(cur); ++ i++; ++ } ++ *bss_head = NULL; ++} ++ ++void ++wl_delete_dirty_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl) ++{ ++ wl_bss_cache_t *node, *prev, **bss_head; ++ int i = -1, tmp = 0; ++ ++ bss_head = &bss_cache_ctrl->m_cache_head; ++ node = *bss_head; ++ prev = node; ++ for (;node;) { ++ i++; ++ if (node->dirty >= BSSCACHE_LEN) { ++ if (node == *bss_head) { ++ tmp = 1; ++ *bss_head = node->next; ++ } else { ++ tmp = 0; ++ prev->next = node->next; ++ } ++ AP6211_DEBUG("%s: Del %d with BSSID %pM, RSSI=%d, SSID \"%s\"\n", ++ __FUNCTION__, i, &node->results.bss_info->BSSID, ++ dtoh16(node->results.bss_info->RSSI), node->results.bss_info->SSID); ++ kfree(node); ++ if (tmp == 1) { ++ node = *bss_head; ++ prev = node; ++ } else { ++ node = prev->next; ++ } ++ continue; ++ } ++ prev = node; ++ node = node->next; ++ } ++} ++ ++void ++wl_reset_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl) ++{ ++ wl_bss_cache_t *node, **bss_head; ++ ++ bss_head = &bss_cache_ctrl->m_cache_head; ++ ++ /* reset dirty */ ++ node = *bss_head; ++ for (;node;) { ++ node->dirty += 1; ++ node = node->next; ++ } ++} ++ ++void ++wl_update_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl, wl_scan_results_t *ss_list) ++{ ++ wl_bss_cache_t *node, *prev, *leaf, *tmp, **bss_head; ++ wl_bss_info_t *bi = NULL; ++ int i, k=0; ++ ++ if (!ss_list->count) ++ return; ++ ++ bss_head = &bss_cache_ctrl->m_cache_head; ++ ++ for (i=0; i < ss_list->count; i++) { ++ node = *bss_head; ++ prev = NULL; ++ bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info; ++ ++ for (;node;) { ++ if (!memcmp(&node->results.bss_info->BSSID, &bi->BSSID, ETHER_ADDR_LEN)) { ++ tmp = node; ++ leaf = kmalloc(dtoh32(bi->length) + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN, GFP_KERNEL); ++ if (!leaf) { ++ AP6211_ERR("%s: Memory alloc failure %d and keep old BSS info\n", ++ __FUNCTION__, dtoh32(bi->length) + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN); ++ break; ++ } ++ ++ memcpy(leaf->results.bss_info, bi, dtoh32(bi->length)); ++ leaf->next = node->next; ++ leaf->dirty = 0; ++ leaf->results.count = 1; ++ leaf->results.version = ss_list->version; ++ AP6211_DEBUG("%s: Update %d with BSSID %pM, RSSI=%d, SSID \"%s\"\n", ++ __FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID); ++ if (!prev) ++ *bss_head = leaf; ++ else ++ prev->next = leaf; ++ node = leaf; ++ prev = node; ++ ++ kfree(tmp); ++ k++; ++ break; ++ } ++ prev = node; ++ node = node->next; ++ } ++ ++ if (node) ++ continue; ++ ++ leaf = kmalloc(dtoh32(bi->length) + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN, GFP_KERNEL); ++ if (!leaf) { ++ AP6211_ERR("%s: Memory alloc failure %d\n", __FUNCTION__, ++ dtoh32(bi->length) + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN); ++ return; ++ } ++ AP6211_DEBUG("%s: Add %d with cached BSSID %pM, RSSI=%d, SSID \"%s\" in the leaf\n", ++ __FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID); ++ ++ memcpy(leaf->results.bss_info, bi, dtoh32(bi->length)); ++ leaf->next = NULL; ++ leaf->dirty = 0; ++ leaf->results.count = 1; ++ leaf->results.version = ss_list->version; ++ k++; ++ ++ if (!prev) ++ *bss_head = leaf; ++ else ++ prev->next = leaf; ++ } ++} ++ ++void ++wl_run_bss_cache_timer(wl_bss_cache_ctrl_t *bss_cache_ctrl, int kick_off) ++{ ++ struct timer_list **timer; ++ ++ timer = &bss_cache_ctrl->m_timer; ++ ++ if (*timer) { ++ if (kick_off) { ++ (*timer)->expires = jiffies + BSSCACHE_TIME * HZ / 1000; ++ add_timer(*timer); ++ AP6211_DEBUG("%s: timer starts\n", __FUNCTION__); ++ } else { ++ del_timer_sync(*timer); ++ AP6211_DEBUG("%s: timer stops\n", __FUNCTION__); ++ } ++ } ++} ++ ++void ++wl_set_bss_cache_timer_flag(ulong data) ++{ ++ wl_bss_cache_ctrl_t *bss_cache_ctrl = (wl_bss_cache_ctrl_t *)data; ++ ++ bss_cache_ctrl->m_timer_expired = 1; ++ AP6211_DEBUG("%s called\n", __FUNCTION__); ++} ++ ++void ++wl_release_bss_cache_ctrl(wl_bss_cache_ctrl_t *bss_cache_ctrl) ++{ ++ AP6211_DEBUG("%s:\n", __FUNCTION__); ++ wl_free_bss_cache(bss_cache_ctrl); ++ wl_run_bss_cache_timer(bss_cache_ctrl, 0); ++ if (bss_cache_ctrl->m_timer) { ++ kfree(bss_cache_ctrl->m_timer); ++ } ++} ++ ++void ++wl_init_bss_cache_ctrl(wl_bss_cache_ctrl_t *bss_cache_ctrl) ++{ ++ AP6211_DEBUG("%s:\n", __FUNCTION__); ++ bss_cache_ctrl->m_timer_expired = 0; ++ ++ bss_cache_ctrl->m_timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL); ++ if (!bss_cache_ctrl->m_timer) { ++ AP6211_ERR("%s: Memory alloc failure\n", __FUNCTION__ ); ++ return; ++ } ++ init_timer(bss_cache_ctrl->m_timer); ++ bss_cache_ctrl->m_timer->function = (void *)wl_set_bss_cache_timer_flag; ++ bss_cache_ctrl->m_timer->data = (ulong)bss_cache_ctrl; ++} ++#endif ++ ++/** ++ * Functions for Android WiFi card detection ++ */ ++#if defined(CONFIG_WIFI_CONTROL_FUNC) ++ ++static int g_wifidev_registered = 0; ++static struct semaphore wifi_control_sem; ++static struct wifi_platform_data *wifi_control_data = NULL; ++static struct resource *wifi_irqres = NULL; ++ ++static int wifi_add_dev(void); ++static void wifi_del_dev(void); ++ ++int wl_android_wifictrl_func_add(void) ++{ ++ int ret = 0; ++ sema_init(&wifi_control_sem, 0); ++ ++ ret = wifi_add_dev(); ++ if (ret) { ++ AP6211_ERR("%s: platform_driver_register failed\n", __FUNCTION__); ++ return ret; ++ } ++ g_wifidev_registered = 1; ++ ++ /* Waiting callback after platform_driver_register is done or exit with error */ ++ if (down_timeout(&wifi_control_sem, msecs_to_jiffies(1000)) != 0) { ++ ret = -EINVAL; ++ AP6211_ERR("%s: platform_driver_register timeout\n", __FUNCTION__); ++ } ++ ++ return ret; ++} ++ ++void wl_android_wifictrl_func_del(void) ++{ ++ if (g_wifidev_registered) ++ { ++ wifi_del_dev(); ++ g_wifidev_registered = 0; ++ } ++} ++ ++void* wl_android_prealloc(int section, unsigned long size) ++{ ++ void *alloc_ptr = NULL; ++ if (wifi_control_data && wifi_control_data->mem_prealloc) { ++ alloc_ptr = wifi_control_data->mem_prealloc(section, size); ++ if (alloc_ptr) { ++ AP6211_DEBUG("success alloc section %d\n", section); ++ if (size != 0L) ++ bzero(alloc_ptr, size); ++ return alloc_ptr; ++ } ++ } ++ ++ AP6211_ERR("can't alloc section %d\n", section); ++ return NULL; ++} ++ ++int wifi_get_irq_number(unsigned long *irq_flags_ptr) ++{ ++ if (wifi_irqres) { ++ *irq_flags_ptr = wifi_irqres->flags & IRQF_TRIGGER_MASK; ++ return (int)wifi_irqres->start; ++ } ++#ifdef CUSTOM_OOB_GPIO_NUM ++ return CUSTOM_OOB_GPIO_NUM; ++#else ++ return -1; ++#endif ++} ++ ++int wifi_set_power(int on, unsigned long msec) ++{ ++ AP6211_ERR("%s = %d\n", __FUNCTION__, on); ++ if (wifi_control_data && wifi_control_data->set_power) { ++ wifi_control_data->set_power(on); ++ } ++ if (msec) ++ msleep(msec); ++ return 0; ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) ++int wifi_get_mac_addr(unsigned char *buf) ++{ ++ AP6211_ERR("%s\n", __FUNCTION__); ++ if (!buf) ++ return -EINVAL; ++ if (wifi_control_data && wifi_control_data->get_mac_addr) { ++ return wifi_control_data->get_mac_addr(buf); ++ } ++ return -EOPNOTSUPP; ++} ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) ++void *wifi_get_country_code(char *ccode) ++{ ++ AP6211_DEBUG("%s\n", __FUNCTION__); ++ if (!ccode) ++ return NULL; ++ if (wifi_control_data && wifi_control_data->get_country_code) { ++ return wifi_control_data->get_country_code(ccode); ++ } ++ return NULL; ++} ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) */ ++ ++static int wifi_set_carddetect(int on) ++{ ++ AP6211_ERR("%s = %d\n", __FUNCTION__, on); ++ if (wifi_control_data && wifi_control_data->set_carddetect) { ++ wifi_control_data->set_carddetect(on); ++ } ++ return 0; ++} ++ ++static int wifi_probe(struct platform_device *pdev) ++{ ++ struct wifi_platform_data *wifi_ctrl = ++ (struct wifi_platform_data *)(pdev->dev.platform_data); ++ ++ wifi_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcmdhd_wlan_irq"); ++ if (wifi_irqres == NULL) ++ wifi_irqres = platform_get_resource_byname(pdev, ++ IORESOURCE_IRQ, "bcm4329_wlan_irq"); ++ wifi_control_data = wifi_ctrl; ++ wifi_set_power(1, 0); /* Power On */ ++ wifi_set_carddetect(1); /* CardDetect (0->1) */ ++ ++ up(&wifi_control_sem); ++ return 0; ++} ++ ++static int wifi_remove(struct platform_device *pdev) ++{ ++ struct wifi_platform_data *wifi_ctrl = ++ (struct wifi_platform_data *)(pdev->dev.platform_data); ++ ++ AP6211_ERR("## %s\n", __FUNCTION__); ++ wifi_control_data = wifi_ctrl; ++ ++ wifi_set_power(0, WIFI_TURNOFF_DELAY); /* Power Off */ ++ wifi_set_carddetect(0); /* CardDetect (1->0) */ ++ ++ up(&wifi_control_sem); ++ return 0; ++} ++ ++static int wifi_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ AP6211_DEBUG("##> %s\n", __FUNCTION__); ++#if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI) ++ if (dhd_os_check_wakelock(bcmsdh_get_drvdata())) ++ return -EBUSY; ++#endif /* defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI) */ ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) && 1 ++ bcmsdh_oob_intr_set(0); ++#endif /* (OOB_INTR_ONLY) */ ++ return 0; ++} ++ ++static int wifi_resume(struct platform_device *pdev) ++{ ++ AP6211_DEBUG("##> %s\n", __FUNCTION__); ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) && 1 ++ if (dhd_os_check_if_up(bcmsdh_get_drvdata())) ++ bcmsdh_oob_intr_set(1); ++#endif /* (OOB_INTR_ONLY) */ ++ return 0; ++} ++ ++static struct platform_driver wifi_device = { ++ .probe = wifi_probe, ++ .remove = wifi_remove, ++ .suspend = wifi_suspend, ++ .resume = wifi_resume, ++ .driver = { ++ .name = "bcmdhd_wlan", ++ } ++}; ++ ++static struct platform_driver wifi_device_legacy = { ++ .probe = wifi_probe, ++ .remove = wifi_remove, ++ .suspend = wifi_suspend, ++ .resume = wifi_resume, ++ .driver = { ++ .name = "bcm4329_wlan", ++ } ++}; ++ ++static int wifi_add_dev(void) ++{ ++ int ret = 0; ++ AP6211_DEBUG("## Calling platform_driver_register\n"); ++ ret = platform_driver_register(&wifi_device); ++ if (ret) ++ return ret; ++ ++ ret = platform_driver_register(&wifi_device_legacy); ++ return ret; ++} ++ ++static void wifi_del_dev(void) ++{ ++ AP6211_DEBUG("## Unregister platform_driver_register\n"); ++ platform_driver_unregister(&wifi_device); ++ platform_driver_unregister(&wifi_device_legacy); ++} ++#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */ +diff --git a/drivers/net/wireless/ap6211/wl_android.h b/drivers/net/wireless/ap6211/wl_android.h +new file mode 100755 +index 0000000..d933e06 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/wl_android.h +@@ -0,0 +1,124 @@ ++/* ++ * Linux cfg80211 driver - Android related functions ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: wl_android.h 367273 2012-11-07 09:58:55Z $ ++ */ ++ ++#include ++#include ++#include ++ ++/* If any feature uses the Generic Netlink Interface, put it here to enable WL_GENL ++ * automatically ++ */ ++ ++/** ++ * Android platform dependent functions, feel free to add Android specific functions here ++ * (save the macros in dhd). Please do NOT declare functions that are NOT exposed to dhd ++ * or cfg, define them as static in wl_android.c ++ */ ++ ++/** ++ * wl_android_init will be called from module init function (dhd_module_init now), similarly ++ * wl_android_exit will be called from module exit function (dhd_module_cleanup now) ++ */ ++int wl_android_init(void); ++int wl_android_exit(void); ++void wl_android_post_init(void); ++int wl_android_wifi_on(struct net_device *dev); ++int wl_android_wifi_off(struct net_device *dev); ++int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd); ++ ++#define BSSCACHE ++#define RSSIAVG ++#define RSSIOFFSET ++//#define RSSIOFFSET_NEW ++ ++#if defined(RSSIAVG) ++#define RSSIAVG_LEN 8 ++#define RSSICACHE_LEN 8 ++ ++typedef struct wl_rssi_cache { ++ struct wl_rssi_cache *next; ++ int dirty; ++ struct ether_addr BSSID; ++ int16 RSSI[RSSIAVG_LEN]; ++} wl_rssi_cache_t; ++ ++typedef struct wl_rssi_cache_ctrl { ++ wl_rssi_cache_t *m_cache_head; ++} wl_rssi_cache_ctrl_t; ++ ++void wl_free_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl); ++void wl_delete_dirty_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl); ++void wl_reset_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl); ++void wl_update_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, wl_scan_results_t *ss_list); ++void wl_update_connected_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, struct net_device *net); ++int16 wl_get_avg_rssi(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, void *addr); ++#endif ++ ++#if defined(RSSIOFFSET) ++#define RSSI_OFFSET 5 ++#define RSSI_MAX -80 ++#define RSSI_MIN -94 ++#define RSSI_INT ((RSSI_MAX-RSSI_MIN)/RSSI_OFFSET) ++#define BCM4330_CHIP_ID 0x4330 ++#define BCM4330B2_CHIP_REV 4 ++int wl_update_rssi_offset(int rssi); ++#endif ++ ++#if defined(BSSCACHE) ++#define BSSCACHE_LEN 8 ++#define BSSCACHE_TIME 15000 ++ ++typedef struct wl_bss_cache { ++ struct wl_bss_cache *next; ++ int dirty; ++ wl_scan_results_t results; ++} wl_bss_cache_t; ++ ++typedef struct wl_bss_cache_ctrl { ++ wl_bss_cache_t *m_cache_head; ++ struct timer_list *m_timer; ++ int m_timer_expired; ++} wl_bss_cache_ctrl_t; ++ ++void wl_free_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl); ++void wl_delete_dirty_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl); ++void wl_reset_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl); ++void wl_update_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl, wl_scan_results_t *ss_list); ++void wl_run_bss_cache_timer(wl_bss_cache_ctrl_t *bss_cache_ctrl, int kick_off); ++void wl_release_bss_cache_ctrl(wl_bss_cache_ctrl_t *bss_cache_ctrl); ++void wl_init_bss_cache_ctrl(wl_bss_cache_ctrl_t *bss_cache_ctrl); ++#endif ++ ++#if defined(CONFIG_WIFI_CONTROL_FUNC) ++int wl_android_wifictrl_func_add(void); ++void wl_android_wifictrl_func_del(void); ++void* wl_android_prealloc(int section, unsigned long size); ++ ++int wifi_get_irq_number(unsigned long *irq_flags_ptr); ++int wifi_set_power(int on, unsigned long msec); ++int wifi_get_mac_addr(unsigned char *buf); ++void *wifi_get_country_code(char *ccode); ++#endif /* CONFIG_WIFI_CONTROL_FUNC */ +diff --git a/drivers/net/wireless/ap6211/wl_cfg80211.c b/drivers/net/wireless/ap6211/wl_cfg80211.c +new file mode 100755 +index 0000000..1ebce14 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/wl_cfg80211.c +@@ -0,0 +1,10129 @@ ++/* ++ * Linux cfg80211 driver ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: wl_cfg80211.c 374275 2012-12-12 11:44:18Z $ ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#ifdef PROP_TXSTATUS ++#include ++#endif ++#ifdef BCMWAPI_WPI ++/* these items should evetually go into wireless.h of the linux system headfile dir */ ++#ifndef IW_ENCODE_ALG_SM4 ++#define IW_ENCODE_ALG_SM4 0x20 ++#endif ++ ++#ifndef IW_AUTH_WAPI_ENABLED ++#define IW_AUTH_WAPI_ENABLED 0x20 ++#endif ++ ++#ifndef IW_AUTH_WAPI_VERSION_1 ++#define IW_AUTH_WAPI_VERSION_1 0x00000008 ++#endif ++ ++#ifndef IW_AUTH_CIPHER_SMS4 ++#define IW_AUTH_CIPHER_SMS4 0x00000020 ++#endif ++ ++#ifndef IW_AUTH_KEY_MGMT_WAPI_PSK ++#define IW_AUTH_KEY_MGMT_WAPI_PSK 4 ++#endif ++ ++#ifndef IW_AUTH_KEY_MGMT_WAPI_CERT ++#define IW_AUTH_KEY_MGMT_WAPI_CERT 8 ++#endif ++#endif /* BCMWAPI_WPI */ ++ ++#ifdef BCMWAPI_WPI ++#define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | SMS4_ENABLED)) ++#else /* BCMWAPI_WPI */ ++#define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED)) ++#endif /* BCMWAPI_WPI */ ++#ifdef WL11U ++#ifndef WL_ENABLE_P2P_IF ++#error "You should enable WL_ENABLE_P2P_IF and Only supported in JB" ++#endif ++#endif /* WL11U */ ++ ++#define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED)) ++ ++static struct device *cfg80211_parent_dev = NULL; ++struct wl_priv *wlcfg_drv_priv = NULL; ++u32 wl_dbg_level = WL_DBG_ERR; ++ ++#define MAX_WAIT_TIME 1500 ++ ++#ifdef VSDB ++/* sleep time to keep STA's connecting or connection for continuous af tx or finding a peer */ ++#define DEFAULT_SLEEP_TIME_VSDB 200 ++#define OFF_CHAN_TIME_THRESHOLD_MS 200 ++ ++/* if sta is connected or connecting, sleep for a while before retry af tx or finding a peer */ ++#define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(wl) \ ++ do { \ ++ if (wl_get_drv_status(wl, CONNECTED, wl_to_prmry_ndev(wl)) || \ ++ wl_get_drv_status(wl, CONNECTING, wl_to_prmry_ndev(wl))) { \ ++ msleep(DEFAULT_SLEEP_TIME_VSDB); \ ++ } \ ++ } while (0) ++#else /* VSDB */ ++/* if not VSDB, do nothing */ ++#define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(wl) ++#endif /* VSDB */ ++ ++#ifdef WL_CFG80211_SYNC_GON ++#define WL_DRV_STATUS_SENDING_AF_FRM_EXT(wl) \ ++ (wl_get_drv_status_all(wl, SENDING_ACT_FRM) || \ ++ wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM_LISTEN)) ++#else ++#define WL_DRV_STATUS_SENDING_AF_FRM_EXT(wl) wl_get_drv_status_all(wl, SENDING_ACT_FRM) ++#endif /* WL_CFG80211_SYNC_GON */ ++ ++#define WL_CHANSPEC_CTL_SB_NONE WL_CHANSPEC_CTL_SB_LLL ++ ++ ++#define DNGL_FUNC(func, parameters) func parameters; ++#define COEX_DHCP ++ ++#define WLAN_EID_SSID 0 ++#define CH_MIN_5G_CHANNEL 34 ++#define CH_MIN_2G_CHANNEL 1 ++ ++/* This is to override regulatory domains defined in cfg80211 module (reg.c) ++ * By default world regulatory domain defined in reg.c puts the flags NL80211_RRF_PASSIVE_SCAN ++ * and NL80211_RRF_NO_IBSS for 5GHz channels (for 36..48 and 149..165). ++ * With respect to these flags, wpa_supplicant doesn't start p2p operations on 5GHz channels. ++ * All the chnages in world regulatory domain are to be done here. ++ */ ++static const struct ieee80211_regdomain brcm_regdom = { ++ .n_reg_rules = 4, ++ .alpha2 = "99", ++ .reg_rules = { ++ /* IEEE 802.11b/g, channels 1..11 */ ++ REG_RULE(2412-10, 2472+10, 40, 6, 20, 0), ++ /* If any */ ++ /* IEEE 802.11 channel 14 - Only JP enables ++ * this and for 802.11b only ++ */ ++ REG_RULE(2484-10, 2484+10, 20, 6, 20, 0), ++ /* IEEE 802.11a, channel 36..64 */ ++ REG_RULE(5150-10, 5350+10, 40, 6, 20, 0), ++ /* IEEE 802.11a, channel 100..165 */ ++ REG_RULE(5470-10, 5850+10, 40, 6, 20, 0), } ++}; ++ ++ ++/* Data Element Definitions */ ++#define WPS_ID_CONFIG_METHODS 0x1008 ++#define WPS_ID_REQ_TYPE 0x103A ++#define WPS_ID_DEVICE_NAME 0x1011 ++#define WPS_ID_VERSION 0x104A ++#define WPS_ID_DEVICE_PWD_ID 0x1012 ++#define WPS_ID_REQ_DEV_TYPE 0x106A ++#define WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS 0x1053 ++#define WPS_ID_PRIM_DEV_TYPE 0x1054 ++ ++/* Device Password ID */ ++#define DEV_PW_DEFAULT 0x0000 ++#define DEV_PW_USER_SPECIFIED 0x0001, ++#define DEV_PW_MACHINE_SPECIFIED 0x0002 ++#define DEV_PW_REKEY 0x0003 ++#define DEV_PW_PUSHBUTTON 0x0004 ++#define DEV_PW_REGISTRAR_SPECIFIED 0x0005 ++ ++/* Config Methods */ ++#define WPS_CONFIG_USBA 0x0001 ++#define WPS_CONFIG_ETHERNET 0x0002 ++#define WPS_CONFIG_LABEL 0x0004 ++#define WPS_CONFIG_DISPLAY 0x0008 ++#define WPS_CONFIG_EXT_NFC_TOKEN 0x0010 ++#define WPS_CONFIG_INT_NFC_TOKEN 0x0020 ++#define WPS_CONFIG_NFC_INTERFACE 0x0040 ++#define WPS_CONFIG_PUSHBUTTON 0x0080 ++#define WPS_CONFIG_KEYPAD 0x0100 ++#define WPS_CONFIG_VIRT_PUSHBUTTON 0x0280 ++#define WPS_CONFIG_PHY_PUSHBUTTON 0x0480 ++#define WPS_CONFIG_VIRT_DISPLAY 0x2008 ++#define WPS_CONFIG_PHY_DISPLAY 0x4008 ++ ++#define PM_BLOCK 1 ++#define PM_ENABLE 0 ++/* ++ * cfg80211_ops api/callback list ++ */ ++static s32 wl_frame_get_mgmt(u16 fc, const struct ether_addr *da, ++ const struct ether_addr *sa, const struct ether_addr *bssid, ++ u8 **pheader, u32 *body_len, u8 *pbody); ++static s32 __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, ++ struct cfg80211_scan_request *request, ++ struct cfg80211_ssid *this_ssid); ++static s32 wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, ++ struct cfg80211_scan_request *request); ++static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed); ++static s32 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, ++ struct cfg80211_ibss_params *params); ++static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, ++ struct net_device *dev); ++static s32 wl_cfg80211_get_station(struct wiphy *wiphy, ++ struct net_device *dev, u8 *mac, ++ struct station_info *sinfo); ++static s32 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, ++ struct net_device *dev, bool enabled, ++ s32 timeout); ++static int wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, ++ struct cfg80211_connect_params *sme); ++static s32 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, ++ u16 reason_code); ++static s32 wl_cfg80211_set_tx_power(struct wiphy *wiphy, ++ enum nl80211_tx_power_setting type, ++ s32 dbm); ++static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm); ++static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy, ++ struct net_device *dev, ++ u8 key_idx, bool unicast, bool multicast); ++static s32 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, ++ u8 key_idx, bool pairwise, const u8 *mac_addr, ++ struct key_params *params); ++static s32 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, ++ u8 key_idx, bool pairwise, const u8 *mac_addr); ++static s32 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, ++ u8 key_idx, bool pairwise, const u8 *mac_addr, ++ void *cookie, void (*callback) (void *cookie, ++ struct key_params *params)); ++static s32 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, ++ struct net_device *dev, u8 key_idx); ++static s32 wl_cfg80211_resume(struct wiphy *wiphy); ++#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ ++ 2, 0)) ++static s32 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, ++ struct net_device *dev, u64 cookie); ++static s32 wl_cfg80211_del_station(struct wiphy *wiphy, ++ struct net_device *ndev, u8* mac_addr); ++#endif ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39) ++static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow); ++#else ++static s32 wl_cfg80211_suspend(struct wiphy *wiphy); ++#endif ++static s32 wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev, ++ struct cfg80211_pmksa *pmksa); ++static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, ++ struct cfg80211_pmksa *pmksa); ++static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy, ++ struct net_device *dev); ++static s32 wl_notify_escan_complete(struct wl_priv *wl, ++ struct net_device *ndev, bool aborted, bool fw_abort); ++/* ++ * event & event Q handlers for cfg80211 interfaces ++ */ ++static s32 wl_create_event_handler(struct wl_priv *wl); ++static void wl_destroy_event_handler(struct wl_priv *wl); ++static s32 wl_event_handler(void *data); ++static void wl_init_eq(struct wl_priv *wl); ++static void wl_flush_eq(struct wl_priv *wl); ++static unsigned long wl_lock_eq(struct wl_priv *wl); ++static void wl_unlock_eq(struct wl_priv *wl, unsigned long flags); ++static void wl_init_eq_lock(struct wl_priv *wl); ++static void wl_init_event_handler(struct wl_priv *wl); ++static struct wl_event_q *wl_deq_event(struct wl_priv *wl); ++static s32 wl_enq_event(struct wl_priv *wl, struct net_device *ndev, u32 type, ++ const wl_event_msg_t *msg, void *data); ++static void wl_put_event(struct wl_event_q *e); ++static void wl_wakeup_event(struct wl_priv *wl); ++static s32 wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data); ++static s32 wl_notify_connect_status(struct wl_priv *wl, ++ struct net_device *ndev, ++ const wl_event_msg_t *e, void *data); ++static s32 wl_notify_roaming_status(struct wl_priv *wl, ++ struct net_device *ndev, ++ const wl_event_msg_t *e, void *data); ++static s32 wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data); ++static s32 wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data, bool completed); ++static s32 wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data); ++static s32 wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data); ++#ifdef WL_SCHED_SCAN ++static s32 ++wl_notify_sched_scan_results(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data); ++#endif /* WL_SCHED_SCAN */ ++#ifdef PNO_SUPPORT ++static s32 wl_notify_pfn_status(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data); ++#endif /* PNO_SUPPORT */ ++static s32 wl_notifier_change_state(struct wl_priv *wl, struct net_info *_net_info, ++ enum wl_status state, bool set); ++/* ++ * register/deregister parent device ++ */ ++static void wl_cfg80211_clear_parent_dev(void); ++ ++/* ++ * ioctl utilites ++ */ ++ ++/* ++ * cfg80211 set_wiphy_params utilities ++ */ ++static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold); ++static s32 wl_set_rts(struct net_device *dev, u32 frag_threshold); ++static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l); ++ ++/* ++ * wl profile utilities ++ */ ++static s32 wl_update_prof(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data, s32 item); ++static void *wl_read_prof(struct wl_priv *wl, struct net_device *ndev, s32 item); ++static void wl_init_prof(struct wl_priv *wl, struct net_device *ndev); ++ ++/* ++ * cfg80211 connect utilites ++ */ ++static s32 wl_set_wpa_version(struct net_device *dev, ++ struct cfg80211_connect_params *sme); ++static s32 wl_set_auth_type(struct net_device *dev, ++ struct cfg80211_connect_params *sme); ++static s32 wl_set_set_cipher(struct net_device *dev, ++ struct cfg80211_connect_params *sme); ++static s32 wl_set_key_mgmt(struct net_device *dev, ++ struct cfg80211_connect_params *sme); ++static s32 wl_set_set_sharedkey(struct net_device *dev, ++ struct cfg80211_connect_params *sme); ++#ifdef BCMWAPI_WPI ++static s32 wl_set_set_wapi_ie(struct net_device *dev, ++ struct cfg80211_connect_params *sme); ++#endif ++static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev); ++static void wl_ch_to_chanspec(int ch, ++ struct wl_join_params *join_params, size_t *join_params_size); ++ ++/* ++ * information element utilities ++ */ ++static void wl_rst_ie(struct wl_priv *wl); ++static __used s32 wl_add_ie(struct wl_priv *wl, u8 t, u8 l, u8 *v); ++static s32 wl_mrg_ie(struct wl_priv *wl, u8 *ie_stream, u16 ie_size); ++static s32 wl_cp_ie(struct wl_priv *wl, u8 *dst, u16 dst_size); ++static u32 wl_get_ielen(struct wl_priv *wl); ++ ++#ifdef WL11U ++bcm_tlv_t * ++wl_cfg80211_find_interworking_ie(u8 *parse, u32 len); ++static s32 ++wl_cfg80211_add_iw_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, s32 pktflag, ++ uint8 ie_id, uint8 *data, uint8 data_len); ++#endif /* WL11U */ ++ ++static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *dev); ++static void wl_free_wdev(struct wl_priv *wl); ++static int ++wl_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request); ++ ++static s32 wl_inform_bss(struct wl_priv *wl); ++static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi, u8 is_roam_done); ++static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev, u8 is_roam_done); ++static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy); ++s32 wl_cfg80211_channel_to_freq(u32 channel); ++ ++#if defined(DHCP_SCAN_SUPPRESS) ++static void wl_cfg80211_work_handler(struct work_struct *work); ++static void wl_cfg80211_scan_supp_timerfunc(ulong data); ++#endif /* DHCP_SCAN_SUPPRESS */ ++ ++static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, ++ u8 key_idx, const u8 *mac_addr, ++ struct key_params *params); ++/* ++ * key indianess swap utilities ++ */ ++static void swap_key_from_BE(struct wl_wsec_key *key); ++static void swap_key_to_BE(struct wl_wsec_key *key); ++ ++/* ++ * wl_priv memory init/deinit utilities ++ */ ++static s32 wl_init_priv_mem(struct wl_priv *wl); ++static void wl_deinit_priv_mem(struct wl_priv *wl); ++ ++static void wl_delay(u32 ms); ++ ++/* ++ * ibss mode utilities ++ */ ++static bool wl_is_ibssmode(struct wl_priv *wl, struct net_device *ndev); ++static __used bool wl_is_ibssstarter(struct wl_priv *wl); ++ ++/* ++ * link up/down , default configuration utilities ++ */ ++static s32 __wl_cfg80211_up(struct wl_priv *wl); ++static s32 __wl_cfg80211_down(struct wl_priv *wl); ++static bool wl_is_linkdown(struct wl_priv *wl, const wl_event_msg_t *e); ++static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e, struct net_device *ndev); ++static bool wl_is_nonetwork(struct wl_priv *wl, const wl_event_msg_t *e); ++static void wl_link_up(struct wl_priv *wl); ++static void wl_link_down(struct wl_priv *wl); ++static s32 wl_config_ifmode(struct wl_priv *wl, struct net_device *ndev, s32 iftype); ++static void wl_init_conf(struct wl_conf *conf); ++ ++/* ++ * iscan handler ++ */ ++static void wl_iscan_timer(unsigned long data); ++static void wl_term_iscan(struct wl_priv *wl); ++static s32 wl_init_scan(struct wl_priv *wl); ++static s32 wl_iscan_thread(void *data); ++static s32 wl_run_iscan(struct wl_iscan_ctrl *iscan, struct cfg80211_scan_request *request, ++ u16 action); ++static s32 wl_do_iscan(struct wl_priv *wl, struct cfg80211_scan_request *request); ++static s32 wl_wakeup_iscan(struct wl_iscan_ctrl *iscan); ++static s32 wl_invoke_iscan(struct wl_priv *wl); ++static s32 wl_get_iscan_results(struct wl_iscan_ctrl *iscan, u32 *status, ++ struct wl_scan_results **bss_list); ++static void wl_notify_iscan_complete(struct wl_iscan_ctrl *iscan, bool aborted); ++static void wl_init_iscan_handler(struct wl_iscan_ctrl *iscan); ++static s32 wl_iscan_done(struct wl_priv *wl); ++static s32 wl_iscan_pending(struct wl_priv *wl); ++static s32 wl_iscan_inprogress(struct wl_priv *wl); ++static s32 wl_iscan_aborted(struct wl_priv *wl); ++ ++/* ++ * find most significant bit set ++ */ ++static __used u32 wl_find_msb(u16 bit16); ++ ++/* ++ * rfkill support ++ */ ++static int wl_setup_rfkill(struct wl_priv *wl, bool setup); ++static int wl_rfkill_set(void *data, bool blocked); ++ ++static wl_scan_params_t *wl_cfg80211_scan_alloc_params(int channel, ++ int nprobes, int *out_params_size); ++static void get_primary_mac(struct wl_priv *wl, struct ether_addr *mac); ++ ++/* ++ * Some external functions, TODO: move them to dhd_linux.h ++ */ ++int dhd_add_monitor(char *name, struct net_device **new_ndev); ++int dhd_del_monitor(struct net_device *ndev); ++int dhd_monitor_init(void *dhd_pub); ++int dhd_monitor_uninit(void); ++int dhd_start_xmit(struct sk_buff *skb, struct net_device *net); ++ ++ ++ ++#define CHECK_SYS_UP(wlpriv) \ ++do { \ ++ struct net_device *ndev = wl_to_prmry_ndev(wlpriv); \ ++ if (unlikely(!wl_get_drv_status(wlpriv, READY, ndev))) { \ ++ AP6211_DEBUG("device is not ready\n"); \ ++ return -EIO; \ ++ } \ ++} while (0) ++ ++ ++#define IS_WPA_AKM(akm) ((akm) == RSN_AKM_NONE || \ ++ (akm) == RSN_AKM_UNSPECIFIED || \ ++ (akm) == RSN_AKM_PSK) ++ ++ ++extern int dhd_wait_pend8021x(struct net_device *dev); ++#ifdef PROP_TXSTATUS_VSDB ++extern int disable_proptx; ++extern int dhd_wlfc_init(dhd_pub_t *dhd); ++extern void dhd_wlfc_deinit(dhd_pub_t *dhd); ++#endif /* PROP_TXSTATUS_VSDB */ ++ ++#if (WL_DBG_LEVEL > 0) ++#define WL_DBG_ESTR_MAX 50 ++static s8 wl_dbg_estr[][WL_DBG_ESTR_MAX] = { ++ "SET_SSID", "JOIN", "START", "AUTH", "AUTH_IND", ++ "DEAUTH", "DEAUTH_IND", "ASSOC", "ASSOC_IND", "REASSOC", ++ "REASSOC_IND", "DISASSOC", "DISASSOC_IND", "QUIET_START", "QUIET_END", ++ "BEACON_RX", "LINK", "MIC_ERROR", "NDIS_LINK", "ROAM", ++ "TXFAIL", "PMKID_CACHE", "RETROGRADE_TSF", "PRUNE", "AUTOAUTH", ++ "EAPOL_MSG", "SCAN_COMPLETE", "ADDTS_IND", "DELTS_IND", "BCNSENT_IND", ++ "BCNRX_MSG", "BCNLOST_MSG", "ROAM_PREP", "PFN_NET_FOUND", ++ "PFN_NET_LOST", ++ "RESET_COMPLETE", "JOIN_START", "ROAM_START", "ASSOC_START", ++ "IBSS_ASSOC", ++ "RADIO", "PSM_WATCHDOG", "WLC_E_CCX_ASSOC_START", "WLC_E_CCX_ASSOC_ABORT", ++ "PROBREQ_MSG", ++ "SCAN_CONFIRM_IND", "PSK_SUP", "COUNTRY_CODE_CHANGED", ++ "EXCEEDED_MEDIUM_TIME", "ICV_ERROR", ++ "UNICAST_DECODE_ERROR", "MULTICAST_DECODE_ERROR", "TRACE", ++ "WLC_E_BTA_HCI_EVENT", "IF", "WLC_E_P2P_DISC_LISTEN_COMPLETE", ++ "RSSI", "PFN_SCAN_COMPLETE", "WLC_E_EXTLOG_MSG", ++ "ACTION_FRAME", "ACTION_FRAME_COMPLETE", "WLC_E_PRE_ASSOC_IND", ++ "WLC_E_PRE_REASSOC_IND", "WLC_E_CHANNEL_ADOPTED", "WLC_E_AP_STARTED", ++ "WLC_E_DFS_AP_STOP", "WLC_E_DFS_AP_RESUME", "WLC_E_WAI_STA_EVENT", ++ "WLC_E_WAI_MSG", "WLC_E_ESCAN_RESULT", "WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE", ++ "WLC_E_PROBRESP_MSG", "WLC_E_P2P_PROBREQ_MSG", "WLC_E_DCS_REQUEST", "WLC_E_FIFO_CREDIT_MAP", ++ "WLC_E_ACTION_FRAME_RX", "WLC_E_WAKE_EVENT", "WLC_E_RM_COMPLETE" ++}; ++#endif /* WL_DBG_LEVEL */ ++ ++#define CHAN2G(_channel, _freq, _flags) { \ ++ .band = IEEE80211_BAND_2GHZ, \ ++ .center_freq = (_freq), \ ++ .hw_value = (_channel), \ ++ .flags = (_flags), \ ++ .max_antenna_gain = 0, \ ++ .max_power = 30, \ ++} ++ ++#define CHAN5G(_channel, _flags) { \ ++ .band = IEEE80211_BAND_5GHZ, \ ++ .center_freq = 5000 + (5 * (_channel)), \ ++ .hw_value = (_channel), \ ++ .flags = (_flags), \ ++ .max_antenna_gain = 0, \ ++ .max_power = 30, \ ++} ++ ++#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2) ++#define RATETAB_ENT(_rateid, _flags) \ ++ { \ ++ .bitrate = RATE_TO_BASE100KBPS(_rateid), \ ++ .hw_value = (_rateid), \ ++ .flags = (_flags), \ ++ } ++ ++static struct ieee80211_rate __wl_rates[] = { ++ RATETAB_ENT(WLC_RATE_1M, 0), ++ RATETAB_ENT(WLC_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE), ++ RATETAB_ENT(WLC_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE), ++ RATETAB_ENT(WLC_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE), ++ RATETAB_ENT(WLC_RATE_6M, 0), ++ RATETAB_ENT(WLC_RATE_9M, 0), ++ RATETAB_ENT(WLC_RATE_12M, 0), ++ RATETAB_ENT(WLC_RATE_18M, 0), ++ RATETAB_ENT(WLC_RATE_24M, 0), ++ RATETAB_ENT(WLC_RATE_36M, 0), ++ RATETAB_ENT(WLC_RATE_48M, 0), ++ RATETAB_ENT(WLC_RATE_54M, 0) ++}; ++ ++#define wl_a_rates (__wl_rates + 4) ++#define wl_a_rates_size 8 ++#define wl_g_rates (__wl_rates + 0) ++#define wl_g_rates_size 12 ++ ++static struct ieee80211_channel __wl_2ghz_channels[] = { ++ CHAN2G(1, 2412, 0), ++ CHAN2G(2, 2417, 0), ++ CHAN2G(3, 2422, 0), ++ CHAN2G(4, 2427, 0), ++ CHAN2G(5, 2432, 0), ++ CHAN2G(6, 2437, 0), ++ CHAN2G(7, 2442, 0), ++ CHAN2G(8, 2447, 0), ++ CHAN2G(9, 2452, 0), ++ CHAN2G(10, 2457, 0), ++ CHAN2G(11, 2462, 0), ++ CHAN2G(12, 2467, 0), ++ CHAN2G(13, 2472, 0), ++ CHAN2G(14, 2484, 0) ++}; ++ ++static struct ieee80211_channel __wl_5ghz_a_channels[] = { ++ CHAN5G(34, 0), CHAN5G(36, 0), ++ CHAN5G(38, 0), CHAN5G(40, 0), ++ CHAN5G(42, 0), CHAN5G(44, 0), ++ CHAN5G(46, 0), CHAN5G(48, 0), ++ CHAN5G(52, 0), CHAN5G(56, 0), ++ CHAN5G(60, 0), CHAN5G(64, 0), ++ CHAN5G(100, 0), CHAN5G(104, 0), ++ CHAN5G(108, 0), CHAN5G(112, 0), ++ CHAN5G(116, 0), CHAN5G(120, 0), ++ CHAN5G(124, 0), CHAN5G(128, 0), ++ CHAN5G(132, 0), CHAN5G(136, 0), ++ CHAN5G(140, 0), CHAN5G(149, 0), ++ CHAN5G(153, 0), CHAN5G(157, 0), ++ CHAN5G(161, 0), CHAN5G(165, 0) ++}; ++ ++static struct ieee80211_supported_band __wl_band_2ghz = { ++ .band = IEEE80211_BAND_2GHZ, ++ .channels = __wl_2ghz_channels, ++ .n_channels = ARRAY_SIZE(__wl_2ghz_channels), ++ .bitrates = wl_g_rates, ++ .n_bitrates = wl_g_rates_size ++}; ++ ++static struct ieee80211_supported_band __wl_band_5ghz_a = { ++ .band = IEEE80211_BAND_5GHZ, ++ .channels = __wl_5ghz_a_channels, ++ .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels), ++ .bitrates = wl_a_rates, ++ .n_bitrates = wl_a_rates_size ++}; ++ ++static const u32 __wl_cipher_suites[] = { ++ WLAN_CIPHER_SUITE_WEP40, ++ WLAN_CIPHER_SUITE_WEP104, ++ WLAN_CIPHER_SUITE_TKIP, ++ WLAN_CIPHER_SUITE_CCMP, ++ WLAN_CIPHER_SUITE_AES_CMAC, ++#ifdef BCMWAPI_WPI ++ WLAN_CIPHER_SUITE_SMS4 ++#endif ++}; ++ ++ ++/* IOCtl version read from targeted driver */ ++static int ioctl_version; ++ ++/* Return a new chanspec given a legacy chanspec ++ * Returns INVCHANSPEC on error ++ */ ++static chanspec_t ++wl_chspec_from_legacy(chanspec_t legacy_chspec) ++{ ++ chanspec_t chspec; ++ ++ /* get the channel number */ ++ chspec = LCHSPEC_CHANNEL(legacy_chspec); ++ ++ /* convert the band */ ++ if (LCHSPEC_IS2G(legacy_chspec)) { ++ chspec |= WL_CHANSPEC_BAND_2G; ++ } else { ++ chspec |= WL_CHANSPEC_BAND_5G; ++ } ++ ++ /* convert the bw and sideband */ ++ if (LCHSPEC_IS20(legacy_chspec)) { ++ chspec |= WL_CHANSPEC_BW_20; ++ } else { ++ chspec |= WL_CHANSPEC_BW_40; ++ if (LCHSPEC_CTL_SB(legacy_chspec) == WL_LCHANSPEC_CTL_SB_LOWER) { ++ chspec |= WL_CHANSPEC_CTL_SB_L; ++ } else { ++ chspec |= WL_CHANSPEC_CTL_SB_U; ++ } ++ } ++ ++ if (wf_chspec_malformed(chspec)) { ++ AP6211_ERR("wl_chspec_from_legacy: output chanspec (0x%04X) malformed\n", ++ chspec); ++ return INVCHANSPEC; ++ } ++ ++ return chspec; ++} ++ ++/* Return a legacy chanspec given a new chanspec ++ * Returns INVCHANSPEC on error ++ */ ++static chanspec_t ++wl_chspec_to_legacy(chanspec_t chspec) ++{ ++ chanspec_t lchspec; ++ ++ if (wf_chspec_malformed(chspec)) { ++ AP6211_ERR("wl_chspec_to_legacy: input chanspec (0x%04X) malformed\n", ++ chspec); ++ return INVCHANSPEC; ++ } ++ ++ /* get the channel number */ ++ lchspec = CHSPEC_CHANNEL(chspec); ++ ++ /* convert the band */ ++ if (CHSPEC_IS2G(chspec)) { ++ lchspec |= WL_LCHANSPEC_BAND_2G; ++ } else { ++ lchspec |= WL_LCHANSPEC_BAND_5G; ++ } ++ ++ /* convert the bw and sideband */ ++ if (CHSPEC_IS20(chspec)) { ++ lchspec |= WL_LCHANSPEC_BW_20; ++ lchspec |= WL_LCHANSPEC_CTL_SB_NONE; ++ } else if (CHSPEC_IS40(chspec)) { ++ lchspec |= WL_LCHANSPEC_BW_40; ++ if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_L) { ++ lchspec |= WL_LCHANSPEC_CTL_SB_LOWER; ++ } else { ++ lchspec |= WL_LCHANSPEC_CTL_SB_UPPER; ++ } ++ } else { ++ /* cannot express the bandwidth */ ++ char chanbuf[CHANSPEC_STR_LEN]; ++ AP6211_ERR( ++ "wl_chspec_to_legacy: unable to convert chanspec %s (0x%04X) " ++ "to pre-11ac format\n", ++ wf_chspec_ntoa(chspec, chanbuf), chspec); ++ return INVCHANSPEC; ++ } ++ ++ return lchspec; ++} ++ ++/* given a chanspec value, do the endian and chanspec version conversion to ++ * a chanspec_t value ++ * Returns INVCHANSPEC on error ++ */ ++static chanspec_t ++wl_chspec_host_to_driver(chanspec_t chanspec) ++{ ++ if (ioctl_version == 1) { ++ chanspec = wl_chspec_to_legacy(chanspec); ++ if (chanspec == INVCHANSPEC) { ++ return chanspec; ++ } ++ } ++ chanspec = htodchanspec(chanspec); ++ ++ return chanspec; ++} ++ ++/* given a channel value, do the endian and chanspec version conversion to ++ * a chanspec_t value ++ * Returns INVCHANSPEC on error ++ */ ++chanspec_t ++wl_ch_host_to_driver(u16 channel) ++{ ++ ++ chanspec_t chanspec; ++ ++ chanspec = channel & WL_CHANSPEC_CHAN_MASK; ++ ++ if (channel <= CH_MAX_2G_CHANNEL) ++ chanspec |= WL_CHANSPEC_BAND_2G; ++ else ++ chanspec |= WL_CHANSPEC_BAND_5G; ++ ++ chanspec |= WL_CHANSPEC_BW_20; ++ chanspec |= WL_CHANSPEC_CTL_SB_NONE; ++ ++ return wl_chspec_host_to_driver(chanspec); ++} ++ ++/* given a chanspec value from the driver, do the endian and chanspec version conversion to ++ * a chanspec_t value ++ * Returns INVCHANSPEC on error ++ */ ++static chanspec_t ++wl_chspec_driver_to_host(chanspec_t chanspec) ++{ ++ chanspec = dtohchanspec(chanspec); ++ if (ioctl_version == 1) { ++ chanspec = wl_chspec_from_legacy(chanspec); ++ } ++ ++ return chanspec; ++} ++ ++/* There isn't a lot of sense in it, but you can transmit anything you like */ ++static const struct ieee80211_txrx_stypes ++wl_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { ++ [NL80211_IFTYPE_ADHOC] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) ++ }, ++ [NL80211_IFTYPE_STATION] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | ++ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) ++ }, ++ [NL80211_IFTYPE_AP] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | ++ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | ++ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ++ BIT(IEEE80211_STYPE_DISASSOC >> 4) | ++ BIT(IEEE80211_STYPE_AUTH >> 4) | ++ BIT(IEEE80211_STYPE_DEAUTH >> 4) | ++ BIT(IEEE80211_STYPE_ACTION >> 4) ++ }, ++ [NL80211_IFTYPE_AP_VLAN] = { ++ /* copy AP */ ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | ++ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | ++ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ++ BIT(IEEE80211_STYPE_DISASSOC >> 4) | ++ BIT(IEEE80211_STYPE_AUTH >> 4) | ++ BIT(IEEE80211_STYPE_DEAUTH >> 4) | ++ BIT(IEEE80211_STYPE_ACTION >> 4) ++ }, ++ [NL80211_IFTYPE_P2P_CLIENT] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | ++ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) ++ }, ++ [NL80211_IFTYPE_P2P_GO] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | ++ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | ++ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ++ BIT(IEEE80211_STYPE_DISASSOC >> 4) | ++ BIT(IEEE80211_STYPE_AUTH >> 4) | ++ BIT(IEEE80211_STYPE_DEAUTH >> 4) | ++ BIT(IEEE80211_STYPE_ACTION >> 4) ++ } ++}; ++ ++static void swap_key_from_BE(struct wl_wsec_key *key) ++{ ++ key->index = htod32(key->index); ++ key->len = htod32(key->len); ++ key->algo = htod32(key->algo); ++ key->flags = htod32(key->flags); ++ key->rxiv.hi = htod32(key->rxiv.hi); ++ key->rxiv.lo = htod16(key->rxiv.lo); ++ key->iv_initialized = htod32(key->iv_initialized); ++} ++ ++static void swap_key_to_BE(struct wl_wsec_key *key) ++{ ++ key->index = dtoh32(key->index); ++ key->len = dtoh32(key->len); ++ key->algo = dtoh32(key->algo); ++ key->flags = dtoh32(key->flags); ++ key->rxiv.hi = dtoh32(key->rxiv.hi); ++ key->rxiv.lo = dtoh16(key->rxiv.lo); ++ key->iv_initialized = dtoh32(key->iv_initialized); ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) ++/* For debug: Dump the contents of the encoded wps ie buffe */ ++static void ++wl_validate_wps_ie(char *wps_ie, s32 wps_ie_len, bool *pbc) ++{ ++ #define WPS_IE_FIXED_LEN 6 ++ u16 len; ++ u8 *subel = NULL; ++ u16 subelt_id; ++ u16 subelt_len; ++ u16 val; ++ u8 *valptr = (uint8*) &val; ++ if (wps_ie == NULL || wps_ie_len < WPS_IE_FIXED_LEN) { ++ AP6211_ERR("invalid argument : NULL\n")); ++ return; ++ } ++ len = (u16)wps_ie[TLV_LEN_OFF]; ++ ++ if (len > wps_ie_len) { ++ AP6211_ERR("invalid length len %d, wps ie len %d\n", len, wps_ie_len); ++ return; ++ } ++ AP6211_DEBUG("wps_ie len=%d\n", len); ++ len -= 4; /* for the WPS IE's OUI, oui_type fields */ ++ subel = wps_ie + WPS_IE_FIXED_LEN; ++ while (len >= 4) { /* must have attr id, attr len fields */ ++ valptr[0] = *subel++; ++ valptr[1] = *subel++; ++ subelt_id = HTON16(val); ++ ++ valptr[0] = *subel++; ++ valptr[1] = *subel++; ++ subelt_len = HTON16(val); ++ ++ len -= 4; /* for the attr id, attr len fields */ ++ len -= subelt_len; /* for the remaining fields in this attribute */ ++ AP6211_DEBUG(" subel=%p, subelt_id=0x%x subelt_len=%u\n", ++ subel, subelt_id, subelt_len); ++ ++ if (subelt_id == WPS_ID_VERSION) { ++ AP6211_DEBUG(" attr WPS_ID_VERSION: %u\n", *subel); ++ } else if (subelt_id == WPS_ID_REQ_TYPE) { ++ AP6211_DEBUG(" attr WPS_ID_REQ_TYPE: %u\n", *subel); ++ } else if (subelt_id == WPS_ID_CONFIG_METHODS) { ++ valptr[0] = *subel; ++ valptr[1] = *(subel + 1); ++ AP6211_DEBUG(" attr WPS_ID_CONFIG_METHODS: %x\n", HTON16(val)); ++ } else if (subelt_id == WPS_ID_DEVICE_NAME) { ++ char devname[100]; ++ memcpy(devname, subel, subelt_len); ++ devname[subelt_len] = '\0'; ++ AP6211_DEBUG(" attr WPS_ID_DEVICE_NAME: %s (len %u)\n", ++ devname, subelt_len); ++ } else if (subelt_id == WPS_ID_DEVICE_PWD_ID) { ++ valptr[0] = *subel; ++ valptr[1] = *(subel + 1); ++ AP6211_DEBUG(" attr WPS_ID_DEVICE_PWD_ID: %u\n", HTON16(val)); ++ *pbc = (HTON16(val) == DEV_PW_PUSHBUTTON) ? true : false; ++ } else if (subelt_id == WPS_ID_PRIM_DEV_TYPE) { ++ valptr[0] = *subel; ++ valptr[1] = *(subel + 1); ++ AP6211_DEBUG(" attr WPS_ID_PRIM_DEV_TYPE: cat=%u \n", HTON16(val)); ++ valptr[0] = *(subel + 6); ++ valptr[1] = *(subel + 7); ++ AP6211_DEBUG(" attr WPS_ID_PRIM_DEV_TYPE: subcat=%u\n", HTON16(val)); ++ } else if (subelt_id == WPS_ID_REQ_DEV_TYPE) { ++ valptr[0] = *subel; ++ valptr[1] = *(subel + 1); ++ AP6211_DEBUG(" attr WPS_ID_REQ_DEV_TYPE: cat=%u\n", HTON16(val)); ++ valptr[0] = *(subel + 6); ++ valptr[1] = *(subel + 7); ++ AP6211_DEBUG(" attr WPS_ID_REQ_DEV_TYPE: subcat=%u\n", HTON16(val)); ++ } else if (subelt_id == WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS) { ++ valptr[0] = *subel; ++ valptr[1] = *(subel + 1); ++ AP6211_DEBUG(" attr WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS" ++ ": cat=%u\n", HTON16(val)); ++ } else { ++ AP6211_DEBUG(" unknown attr 0x%x\n", subelt_id); ++ } ++ ++ subel += subelt_len; ++ } ++} ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) */ ++ ++static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy) ++{ ++ chanspec_t chspec; ++ int err = 0; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ struct net_device *dev = wl_to_prmry_ndev(wl); ++ struct ether_addr bssid; ++ struct wl_bss_info *bss = NULL; ++ ++ if ((err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), false))) { ++ /* STA interface is not associated. So start the new interface on a temp ++ * channel . Later proper channel will be applied by the above framework ++ * via set_channel (cfg80211 API). ++ */ ++ AP6211_DEBUG("Not associated. Return a temp channel. \n"); ++ return wl_ch_host_to_driver(WL_P2P_TEMP_CHAN); ++ } ++ ++ ++ *(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX); ++ if ((err = wldev_ioctl(dev, WLC_GET_BSS_INFO, wl->extra_buf, ++ WL_EXTRA_BUF_MAX, false))) { ++ AP6211_ERR("Failed to get associated bss info, use temp channel \n"); ++ chspec = wl_ch_host_to_driver(WL_P2P_TEMP_CHAN); ++ } ++ else { ++ bss = (struct wl_bss_info *) (wl->extra_buf + 4); ++ chspec = bss->chanspec; ++ AP6211_DEBUG("Valid BSS Found. chanspec:%d \n", chspec); ++ } ++ return chspec; ++} ++ ++static struct net_device* wl_cfg80211_add_monitor_if(char *name) ++{ ++#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF) ++ AP6211_DEBUG("wl_cfg80211_add_monitor_if: No more support monitor interface\n"); ++ return ERR_PTR(-EOPNOTSUPP); ++#else ++ struct net_device* ndev = NULL; ++ ++ dhd_add_monitor(name, &ndev); ++ AP6211_DEBUG("wl_cfg80211_add_monitor_if net device returned: 0x%p\n", ndev); ++ return ndev; ++#endif /* defined(WLP2P) && defined(WL_ENABLE_P2P_IF) */ ++} ++ ++static struct net_device * ++wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, ++ enum nl80211_iftype type, u32 *flags, ++ struct vif_params *params) ++{ ++ s32 err; ++ s32 timeout = -1; ++ s32 wlif_type = -1; ++ s32 mode = 0; ++ s32 val = 0; ++ s32 dhd_mode = 0; ++ chanspec_t chspec; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ struct net_device *_ndev; ++ struct ether_addr primary_mac; ++ int (*net_attach)(void *dhdp, int ifidx); ++ bool rollback_lock = false; ++#ifdef PROP_TXSTATUS_VSDB ++ s32 up = 1; ++ dhd_pub_t *dhd; ++#endif /* PROP_TXSTATUS_VSDB */ ++ ++ if (!wl) ++ return ERR_PTR(-EINVAL); ++ ++#ifdef PROP_TXSTATUS_VSDB ++ dhd = (dhd_pub_t *)(wl->pub); ++#endif /* PROP_TXSTATUS_VSDB */ ++ ++ ++ /* Use primary I/F for sending cmds down to firmware */ ++ _ndev = wl_to_prmry_ndev(wl); ++ ++ AP6211_DEBUG("if name: %s, type: %d\n", name, type); ++ switch (type) { ++ case NL80211_IFTYPE_ADHOC: ++ case NL80211_IFTYPE_AP_VLAN: ++ case NL80211_IFTYPE_WDS: ++ case NL80211_IFTYPE_MESH_POINT: ++ AP6211_ERR("Unsupported interface type\n"); ++ mode = WL_MODE_IBSS; ++ return NULL; ++ case NL80211_IFTYPE_MONITOR: ++ return wl_cfg80211_add_monitor_if(name); ++ case NL80211_IFTYPE_P2P_CLIENT: ++ case NL80211_IFTYPE_STATION: ++ wlif_type = WL_P2P_IF_CLIENT; ++ mode = WL_MODE_BSS; ++ break; ++ case NL80211_IFTYPE_P2P_GO: ++ case NL80211_IFTYPE_AP: ++ wlif_type = WL_P2P_IF_GO; ++ mode = WL_MODE_AP; ++ break; ++ default: ++ AP6211_ERR("Unsupported interface type\n"); ++ return NULL; ++ break; ++ } ++ ++ if (!name) { ++ AP6211_ERR("name is NULL\n"); ++ return NULL; ++ } ++ if (wl->p2p_supported && (wlif_type != -1)) { ++ if (wl_get_p2p_status(wl, IF_DELETING)) { ++ /* wait till IF_DEL is complete ++ * release the lock for the unregister to proceed ++ */ ++ if (rtnl_is_locked()) { ++ rtnl_unlock(); ++ rollback_lock = true; ++ } ++ AP6211_DEBUG("%s: Released the lock and wait till IF_DEL is complete\n", ++ __func__); ++ timeout = wait_event_interruptible_timeout(wl->netif_change_event, ++ (wl_get_p2p_status(wl, IF_DELETING) == false), ++ msecs_to_jiffies(MAX_WAIT_TIME)); ++ ++ /* put back the rtnl_lock again */ ++ if (rollback_lock) { ++ rtnl_lock(); ++ rollback_lock = false; ++ } ++ if (timeout > 0) { ++ AP6211_ERR("IF DEL is Success\n"); ++ ++ } else { ++ AP6211_ERR("timeount < 0, return -EAGAIN\n"); ++ return ERR_PTR(-EAGAIN); ++ } ++ /* It should be now be safe to put this check here since we are sure ++ * by now netdev_notifier (unregister) would have been called ++ */ ++ if (wl->iface_cnt == IFACE_MAX_CNT) ++ return ERR_PTR(-ENOMEM); ++ } ++ ++#ifdef PROP_TXSTATUS_VSDB ++ if (!dhd) ++ return ERR_PTR(-ENODEV); ++#endif /* PROP_TXSTATUS_VSDB */ ++ if (!wl->p2p) ++ return ERR_PTR(-ENODEV); ++ ++ if (wl->p2p && !wl->p2p->on && strstr(name, WL_P2P_INTERFACE_PREFIX)) { ++ p2p_on(wl) = true; ++ wl_cfgp2p_set_firm_p2p(wl); ++ wl_cfgp2p_init_discovery(wl); ++ get_primary_mac(wl, &primary_mac); ++ wl_cfgp2p_generate_bss_mac(&primary_mac, ++ &wl->p2p->dev_addr, &wl->p2p->int_addr); ++ } ++ ++ memset(wl->p2p->vir_ifname, 0, IFNAMSIZ); ++ strncpy(wl->p2p->vir_ifname, name, IFNAMSIZ - 1); ++ ++ wl_notify_escan_complete(wl, _ndev, true, true); ++#ifdef PROP_TXSTATUS_VSDB ++ if (!wl->wlfc_on && !disable_proptx) { ++ dhd->wlfc_enabled = true; ++ dhd_wlfc_init(dhd); ++ err = wldev_ioctl(_ndev, WLC_UP, &up, sizeof(s32), true); ++ if (err < 0) ++ AP6211_ERR("WLC_UP return err:%d\n", err); ++ wl->wlfc_on = true; ++ } ++#endif /* PROP_TXSTATUS_VSDB */ ++ ++ /* In concurrency case, STA may be already associated in a particular channel. ++ * so retrieve the current channel of primary interface and then start the virtual ++ * interface on that. ++ */ ++ chspec = wl_cfg80211_get_shared_freq(wiphy); ++ ++ /* For P2P mode, use P2P-specific driver features to create the ++ * bss: "wl p2p_ifadd" ++ */ ++ wl_set_p2p_status(wl, IF_ADD); ++ if (wlif_type == WL_P2P_IF_GO) ++ wldev_iovar_setint(_ndev, "mpc", 0); ++ err = wl_cfgp2p_ifadd(wl, &wl->p2p->int_addr, htod32(wlif_type), chspec); ++ ++ if (unlikely(err)) { ++ AP6211_ERR(" virtual iface add failed (%d) \n", err); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ timeout = wait_event_interruptible_timeout(wl->netif_change_event, ++ (wl_get_p2p_status(wl, IF_ADD) == false), ++ msecs_to_jiffies(MAX_WAIT_TIME)); ++ if (timeout > 0 && (!wl_get_p2p_status(wl, IF_ADD))) { ++ ++ struct wireless_dev *vwdev; ++ vwdev = kzalloc(sizeof(*vwdev), GFP_KERNEL); ++ if (unlikely(!vwdev)) { ++ AP6211_ERR("Could not allocate wireless device\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ vwdev->wiphy = wl->wdev->wiphy; ++ AP6211_DEBUG(" virtual interface(%s) is created memalloc done \n", ++ wl->p2p->vir_ifname); ++ vwdev->iftype = type; ++ _ndev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION); ++ _ndev->ieee80211_ptr = vwdev; ++ SET_NETDEV_DEV(_ndev, wiphy_dev(vwdev->wiphy)); ++ vwdev->netdev = _ndev; ++ wl_set_drv_status(wl, READY, _ndev); ++ wl->p2p->vif_created = true; ++ wl_set_mode_by_netdev(wl, _ndev, mode); ++ net_attach = wl_to_p2p_bss_private(wl, P2PAPI_BSSCFG_CONNECTION); ++ if (rtnl_is_locked()) { ++ rtnl_unlock(); ++ rollback_lock = true; ++ } ++ if (net_attach && !net_attach(wl->pub, _ndev->ifindex)) { ++ wl_alloc_netinfo(wl, _ndev, vwdev, mode, PM_ENABLE); ++ val = 1; ++ /* Disable firmware roaming for P2P interface */ ++ wldev_iovar_setint(_ndev, "roam_off", val); ++ AP6211_ERR(" virtual interface(%s) is " ++ "created net attach done\n", wl->p2p->vir_ifname); ++ if (mode == WL_MODE_AP) ++ wl_set_drv_status(wl, CONNECTED, _ndev); ++ if (type == NL80211_IFTYPE_P2P_CLIENT) ++ dhd_mode = DHD_FLAG_P2P_GC_MODE; ++ else if (type == NL80211_IFTYPE_P2P_GO) ++ dhd_mode = DHD_FLAG_P2P_GO_MODE; ++ DNGL_FUNC(dhd_cfg80211_set_p2p_info, (wl, dhd_mode)); ++ } else { ++ /* put back the rtnl_lock again */ ++ if (rollback_lock) ++ rtnl_lock(); ++ goto fail; ++ } ++ /* put back the rtnl_lock again */ ++ if (rollback_lock) ++ rtnl_lock(); ++ return _ndev; ++ ++ } else { ++ wl_clr_p2p_status(wl, IF_ADD); ++ AP6211_ERR(" virtual interface(%s) is not created \n", wl->p2p->vir_ifname); ++ memset(wl->p2p->vir_ifname, '\0', IFNAMSIZ); ++ wl->p2p->vif_created = false; ++#ifdef PROP_TXSTATUS_VSDB ++ if (dhd->wlfc_enabled && wl->wlfc_on) { ++ dhd->wlfc_enabled = false; ++ dhd_wlfc_deinit(dhd); ++ wl->wlfc_on = false; ++ } ++#endif /* PROP_TXSTATUS_VSDB */ ++ } ++ } ++fail: ++ if (wlif_type == WL_P2P_IF_GO) ++ wldev_iovar_setint(_ndev, "mpc", 1); ++ return ERR_PTR(-ENODEV); ++} ++ ++static s32 ++wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev) ++{ ++ struct ether_addr p2p_mac; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ s32 timeout = -1; ++ s32 ret = 0; ++ AP6211_DEBUG("Enter\n"); ++ ++ if (wl->p2p_net == dev) { ++ /* Since there is no ifidx corresponding to p2p0, cmds to ++ * firmware should be routed through primary I/F ++ */ ++ dev = wl_to_prmry_ndev(wl); ++ } ++ ++ if (wl->p2p_supported) { ++ memcpy(p2p_mac.octet, wl->p2p->int_addr.octet, ETHER_ADDR_LEN); ++ ++ /* Clear GO_NEG_PHASE bit to take care of GO-NEG-FAIL cases ++ */ ++ AP6211_DEBUG("P2P: GO_NEG_PHASE status cleared "); ++ wl_clr_p2p_status(wl, GO_NEG_PHASE); ++ if (wl->p2p->vif_created) { ++ if (wl_get_drv_status(wl, SCANNING, dev)) { ++ wl_notify_escan_complete(wl, dev, true, true); ++ } ++ wldev_iovar_setint(dev, "mpc", 1); ++ ++ /* for GC */ ++ if (wl_get_drv_status(wl, DISCONNECTING, dev) && ++ (wl_get_mode_by_netdev(wl, dev) != WL_MODE_AP)) { ++ AP6211_ERR("Wait for Link Down event for GC !\n"); ++ wait_for_completion_timeout ++ (&wl->iface_disable, msecs_to_jiffies(500)); ++ } ++ wl_set_p2p_status(wl, IF_DELETING); ++ DNGL_FUNC(dhd_cfg80211_clean_p2p_info, (wl)); ++ ++ /* for GO */ ++ if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_AP) { ++ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, false); ++ /* disable interface before bsscfg free */ ++ ret = wl_cfgp2p_ifdisable(wl, &p2p_mac); ++ /* if fw doesn't support "ifdis", ++ do not wait for link down of ap mode ++ */ ++ if (ret == 0) { ++ AP6211_ERR("Wait for Link Down event for GO !!!\n"); ++ wait_for_completion_timeout(&wl->iface_disable, ++ msecs_to_jiffies(500)); ++ } else { ++ msleep(300); ++ } ++ } ++ wl_cfgp2p_clear_management_ie(wl, wl_cfgp2p_find_idx(wl, dev)); ++ /* delete interface after link down */ ++ ret = wl_cfgp2p_ifdel(wl, &p2p_mac); ++ /* Firmware could not delete the interface so we will not get WLC_E_IF ++ * event for cleaning the dhd virtual nw interace ++ * So lets do it here. Failures from fw will ensure the application to do ++ * ifconfig down and up sequnce, which will reload the fw ++ * however we should cleanup the linux network virtual interfaces ++ */ ++ /* Request framework to RESET and clean up */ ++ if (ret) { ++ struct net_device *ndev = wl_to_prmry_ndev(wl); ++ AP6211_ERR("Firmware returned an error (%d) from p2p_ifdel" ++ "HANG Notification sent to %s\n", ret, ndev->name); ++ net_os_send_hang_message(ndev); ++ } ++ /* Wait for IF_DEL operation to be finished in firmware */ ++ timeout = wait_event_interruptible_timeout(wl->netif_change_event, ++ (wl->p2p->vif_created == false), ++ msecs_to_jiffies(MAX_WAIT_TIME)); ++ if (timeout > 0 && (wl->p2p->vif_created == false)) { ++ AP6211_DEBUG("IFDEL operation done\n"); ++ } else { ++ AP6211_ERR("IFDEL didn't complete properly\n"); ++ } ++ ret = dhd_del_monitor(dev); ++ } ++ } ++ return ret; ++} ++ ++static s32 ++wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, ++ enum nl80211_iftype type, u32 *flags, ++ struct vif_params *params) ++{ ++ s32 ap = 0; ++ s32 infra = 0; ++ s32 wlif_type; ++ s32 mode = 0; ++ chanspec_t chspec; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); ++ AP6211_DEBUG("Enter type %d\n", type); ++ switch (type) { ++ case NL80211_IFTYPE_MONITOR: ++ case NL80211_IFTYPE_WDS: ++ case NL80211_IFTYPE_MESH_POINT: ++ ap = 1; ++ AP6211_ERR("type (%d) : currently we do not support this type\n", ++ type); ++ break; ++ case NL80211_IFTYPE_ADHOC: ++ mode = WL_MODE_IBSS; ++ break; ++ case NL80211_IFTYPE_STATION: ++ case NL80211_IFTYPE_P2P_CLIENT: ++ mode = WL_MODE_BSS; ++ infra = 1; ++ break; ++ case NL80211_IFTYPE_AP: ++ case NL80211_IFTYPE_AP_VLAN: ++ case NL80211_IFTYPE_P2P_GO: ++ mode = WL_MODE_AP; ++ ap = 1; ++ break; ++ default: ++ return -EINVAL; ++ } ++ if (!dhd) ++ return -EINVAL; ++ if (ap) { ++ wl_set_mode_by_netdev(wl, ndev, mode); ++ if (wl->p2p_supported && wl->p2p->vif_created) { ++ AP6211_DEBUG("p2p_vif_created (%d) p2p_on (%d)\n", wl->p2p->vif_created, ++ p2p_on(wl)); ++ wldev_iovar_setint(ndev, "mpc", 0); ++ wl_notify_escan_complete(wl, ndev, true, true); ++ ++ /* In concurrency case, STA may be already associated in a particular ++ * channel. so retrieve the current channel of primary interface and ++ * then start the virtual interface on that. ++ */ ++ chspec = wl_cfg80211_get_shared_freq(wiphy); ++ ++ wlif_type = WL_P2P_IF_GO; ++ AP6211_ERR("%s : ap (%d), infra (%d), iftype: (%d)\n", ++ ndev->name, ap, infra, type); ++ wl_set_p2p_status(wl, IF_CHANGING); ++ wl_clr_p2p_status(wl, IF_CHANGED); ++ wl_cfgp2p_ifchange(wl, &wl->p2p->int_addr, htod32(wlif_type), chspec); ++ wait_event_interruptible_timeout(wl->netif_change_event, ++ (wl_get_p2p_status(wl, IF_CHANGED) == true), ++ msecs_to_jiffies(MAX_WAIT_TIME)); ++ wl_set_mode_by_netdev(wl, ndev, mode); ++ dhd->op_mode &= ~DHD_FLAG_P2P_GC_MODE; ++ dhd->op_mode |= DHD_FLAG_P2P_GO_MODE; ++ wl_clr_p2p_status(wl, IF_CHANGING); ++ wl_clr_p2p_status(wl, IF_CHANGED); ++ if (mode == WL_MODE_AP) ++ wl_set_drv_status(wl, CONNECTED, ndev); ++ } else if (ndev == wl_to_prmry_ndev(wl) && ++ !wl_get_drv_status(wl, AP_CREATED, ndev)) { ++ wl_set_drv_status(wl, AP_CREATING, ndev); ++ if (!wl->ap_info && ++ !(wl->ap_info = kzalloc(sizeof(struct ap_info), GFP_KERNEL))) { ++ AP6211_ERR("struct ap_saved_ie allocation failed\n"); ++ return -ENOMEM; ++ } ++ } else { ++ AP6211_ERR("Cannot change the interface for GO or SOFTAP\n"); ++ return -EINVAL; ++ } ++ } else { ++ AP6211_DEBUG("Change_virtual_iface for transition from GO/AP to client/STA"); ++ } ++ ++ ndev->ieee80211_ptr->iftype = type; ++ return 0; ++} ++ ++s32 ++wl_cfg80211_notify_ifadd(struct net_device *ndev, s32 idx, s32 bssidx, ++ void* _net_attach) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ s32 ret = BCME_OK; ++ AP6211_DEBUG("Enter"); ++ if (!ndev) { ++ AP6211_ERR("net is NULL\n"); ++ return 0; ++ } ++ if (wl->p2p_supported && wl_get_p2p_status(wl, IF_ADD)) { ++ AP6211_DEBUG("IF_ADD event called from dongle, old interface name: %s," ++ "new name: %s\n", ndev->name, wl->p2p->vir_ifname); ++ /* Assign the net device to CONNECT BSSCFG */ ++ strncpy(ndev->name, wl->p2p->vir_ifname, IFNAMSIZ - 1); ++ wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION) = ndev; ++ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION) = bssidx; ++ wl_to_p2p_bss_private(wl, P2PAPI_BSSCFG_CONNECTION) = _net_attach; ++ ndev->ifindex = idx; ++ wl_clr_p2p_status(wl, IF_ADD); ++ ++ wake_up_interruptible(&wl->netif_change_event); ++ } else { ++ ret = BCME_NOTREADY; ++ } ++ return ret; ++} ++ ++s32 ++wl_cfg80211_notify_ifdel(void) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ ++ AP6211_DEBUG("Enter \n"); ++ wl_clr_p2p_status(wl, IF_DELETING); ++ wake_up_interruptible(&wl->netif_change_event); ++ return 0; ++} ++ ++s32 ++wl_cfg80211_ifdel_ops(struct net_device *ndev) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ bool rollback_lock = false; ++ s32 index = 0; ++#ifdef PROP_TXSTATUS_VSDB ++ dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); ++#endif /* PROP_TXSTATUS_VSDB */ ++ if (!ndev || (strlen(ndev->name) == 0)) { ++ AP6211_ERR("net is NULL\n"); ++ return 0; ++ } ++ ++ if (p2p_is_on(wl) && wl->p2p->vif_created && ++ wl_get_p2p_status(wl, IF_DELETING)) { ++ if (wl->scan_request && ++ (wl->escan_info.ndev == ndev)) { ++ /* Abort any pending scan requests */ ++ wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; ++ if (!rtnl_is_locked()) { ++ rtnl_lock(); ++ rollback_lock = true; ++ } ++ AP6211_DEBUG("ESCAN COMPLETED\n"); ++ wl_notify_escan_complete(wl, ndev, true, false); ++ if (rollback_lock) ++ rtnl_unlock(); ++ } ++ AP6211_ERR("IF_DEL event called from dongle, net %x, vif name: %s\n", ++ (unsigned int)ndev, wl->p2p->vir_ifname); ++ ++ memset(wl->p2p->vir_ifname, '\0', IFNAMSIZ); ++ index = wl_cfgp2p_find_idx(wl, ndev); ++ wl_to_p2p_bss_ndev(wl, index) = NULL; ++ wl_to_p2p_bss_bssidx(wl, index) = WL_INVALID; ++ wl->p2p->vif_created = false; ++ ++ AP6211_DEBUG("index : %d\n", index); ++#ifdef PROP_TXSTATUS_VSDB ++ if (dhd->wlfc_enabled && wl->wlfc_on) { ++ dhd->wlfc_enabled = false; ++ dhd_wlfc_deinit(dhd); ++ wl->wlfc_on = false; ++ } ++#endif /* PROP_TXSTATUS_VSDB */ ++ wl_clr_drv_status(wl, CONNECTED, ndev); ++ } ++ /* Wake up any waiting thread */ ++ wake_up_interruptible(&wl->netif_change_event); ++ ++ return 0; ++} ++ ++s32 ++wl_cfg80211_is_progress_ifadd(void) ++{ ++ s32 is_progress = 0; ++ struct wl_priv *wl = wlcfg_drv_priv; ++ if (wl_get_p2p_status(wl, IF_ADD)) ++ is_progress = 1; ++ return is_progress; ++} ++ ++s32 ++wl_cfg80211_is_progress_ifchange(void) ++{ ++ s32 is_progress = 0; ++ struct wl_priv *wl = wlcfg_drv_priv; ++ if (wl_get_p2p_status(wl, IF_CHANGING)) ++ is_progress = 1; ++ return is_progress; ++} ++ ++ ++s32 ++wl_cfg80211_notify_ifchange(void) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ if (wl_get_p2p_status(wl, IF_CHANGING)) { ++ wl_set_p2p_status(wl, IF_CHANGED); ++ wake_up_interruptible(&wl->netif_change_event); ++ } ++ return 0; ++} ++ ++/* Find listen channel */ ++static s32 wl_find_listen_channel(struct wl_priv *wl, ++ u8 *ie, u32 ie_len) ++{ ++ wifi_p2p_ie_t *p2p_ie; ++ u8 *end, *pos; ++ s32 listen_channel; ++ ++ p2p_ie = wl_cfgp2p_find_p2pie(ie, ie_len); ++ ++ if (p2p_ie == NULL) ++ return 0; ++ ++ pos = p2p_ie->subelts; ++ end = p2p_ie->subelts + (p2p_ie->len - 4); ++ ++ AP6211_DEBUG(" found p2p ie ! lenth %d \n", ++ p2p_ie->len); ++ ++ while (pos < end) { ++ uint16 attr_len; ++ if (pos + 2 >= end) { ++ AP6211_DEBUG(" -- Invalid P2P attribute"); ++ return 0; ++ } ++ attr_len = ((uint16) (((pos + 1)[1] << 8) | (pos + 1)[0])); ++ ++ if (pos + 3 + attr_len > end) { ++ AP6211_DEBUG("P2P: Attribute underflow " ++ "(len=%u left=%d)", ++ attr_len, (int) (end - pos - 3)); ++ return 0; ++ } ++ ++ /* if Listen Channel att id is 6 and the vailue is valid, ++ * return the listen channel ++ */ ++ if (pos[0] == 6) { ++ /* listen channel subel length format ++ * 1(id) + 2(len) + 3(country) + 1(op. class) + 1(chan num) ++ */ ++ listen_channel = pos[1 + 2 + 3 + 1]; ++ ++ if (listen_channel == SOCIAL_CHAN_1 || ++ listen_channel == SOCIAL_CHAN_2 || ++ listen_channel == SOCIAL_CHAN_3) { ++ AP6211_DEBUG(" Found my Listen Channel %d \n", listen_channel); ++ return listen_channel; ++ } ++ } ++ pos += 3 + attr_len; ++ } ++ return 0; ++} ++ ++static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_request *request) ++{ ++ u32 n_ssids; ++ u32 n_channels; ++ u16 channel; ++ chanspec_t chanspec; ++ s32 i = 0, j = 0, offset; ++ char *ptr; ++ wlc_ssid_t ssid; ++ struct wl_priv *wl = wlcfg_drv_priv; ++ ++ memcpy(¶ms->bssid, ðer_bcast, ETHER_ADDR_LEN); ++ params->bss_type = DOT11_BSSTYPE_ANY; ++ params->scan_type = 0; ++ params->nprobes = -1; ++ params->active_time = -1; ++ params->passive_time = -1; ++ params->home_time = -1; ++ params->channel_num = 0; ++ memset(¶ms->ssid, 0, sizeof(wlc_ssid_t)); ++ ++ AP6211_DEBUG("Preparing Scan request\n"); ++ AP6211_DEBUG("nprobes=%d\n", params->nprobes); ++ AP6211_DEBUG("active_time=%d\n", params->active_time); ++ AP6211_DEBUG("passive_time=%d\n", params->passive_time); ++ AP6211_DEBUG("home_time=%d\n", params->home_time); ++ AP6211_DEBUG("scan_type=%d\n", params->scan_type); ++ ++ params->nprobes = htod32(params->nprobes); ++ params->active_time = htod32(params->active_time); ++ params->passive_time = htod32(params->passive_time); ++ params->home_time = htod32(params->home_time); ++ ++ /* if request is null just exit so it will be all channel broadcast scan */ ++ if (!request) ++ return; ++ ++ n_ssids = request->n_ssids; ++ n_channels = request->n_channels; ++ ++ /* Copy channel array if applicable */ ++ AP6211_DEBUG("### List of channelspecs to scan ###\n"); ++ if (n_channels > 0) { ++ for (i = 0; i < n_channels; i++) { ++ chanspec = 0; ++ channel = ieee80211_frequency_to_channel(request->channels[i]->center_freq); ++ /* SKIP DFS channels for Secondary interface */ ++ if ((wl->escan_info.ndev != wl_to_prmry_ndev(wl)) && ++ (request->channels[i]->flags & ++ (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_PASSIVE_SCAN))) ++ continue; ++ ++ if (request->channels[i]->band == IEEE80211_BAND_2GHZ) { ++#ifdef WL_HOST_BAND_MGMT ++ if (wl->curr_band == WLC_BAND_5G) { ++ AP6211_DEBUG("In 5G only mode, omit 2G channel:%d\n", channel); ++ continue; ++ } ++#endif /* WL_HOST_BAND_MGMT */ ++ chanspec |= WL_CHANSPEC_BAND_2G; ++ } else { ++#ifdef WL_HOST_BAND_MGMT ++ if (wl->curr_band == WLC_BAND_2G) { ++ AP6211_DEBUG("In 2G only mode, omit 5G channel:%d\n", channel); ++ continue; ++ } ++#endif /* WL_HOST_BAND_MGMT */ ++ chanspec |= WL_CHANSPEC_BAND_5G; ++ } ++ ++ chanspec |= WL_CHANSPEC_BW_20; ++ chanspec |= WL_CHANSPEC_CTL_SB_NONE; ++ ++ params->channel_list[j] = channel; ++ params->channel_list[j] &= WL_CHANSPEC_CHAN_MASK; ++ params->channel_list[j] |= chanspec; ++ AP6211_DEBUG("Chan : %d, Channel spec: %x \n", ++ channel, params->channel_list[j]); ++ params->channel_list[j] = wl_chspec_host_to_driver(params->channel_list[j]); ++ j++; ++ } ++ } else { ++ AP6211_DEBUG("Scanning all channels\n"); ++ } ++ n_channels = j; ++ /* Copy ssid array if applicable */ ++ AP6211_DEBUG("### List of SSIDs to scan ###\n"); ++ if (n_ssids > 0) { ++ offset = offsetof(wl_scan_params_t, channel_list) + n_channels * sizeof(u16); ++ offset = roundup(offset, sizeof(u32)); ++ ptr = (char*)params + offset; ++ for (i = 0; i < n_ssids; i++) { ++ memset(&ssid, 0, sizeof(wlc_ssid_t)); ++ ssid.SSID_len = request->ssids[i].ssid_len; ++ memcpy(ssid.SSID, request->ssids[i].ssid, ssid.SSID_len); ++ if (!ssid.SSID_len) ++ AP6211_DEBUG("%d: Broadcast scan\n", i); ++ else ++ AP6211_DEBUG("%d: scan for %s size =%d\n", i, ++ ssid.SSID, ssid.SSID_len); ++ memcpy(ptr, &ssid, sizeof(wlc_ssid_t)); ++ ptr += sizeof(wlc_ssid_t); ++ } ++ } else { ++ AP6211_DEBUG("Broadcast scan\n"); ++ } ++ /* Adding mask to channel numbers */ ++ params->channel_num = ++ htod32((n_ssids << WL_SCAN_PARAMS_NSSID_SHIFT) | ++ (n_channels & WL_SCAN_PARAMS_COUNT_MASK)); ++ ++ if (n_channels == 1 && wl_get_drv_status_all(wl, CONNECTED)) { ++ params->active_time = WL_SCAN_CONNECT_DWELL_TIME_MS; ++ } ++} ++ ++static s32 ++wl_run_iscan(struct wl_iscan_ctrl *iscan, struct cfg80211_scan_request *request, u16 action) ++{ ++ u32 n_channels; ++ u32 n_ssids; ++ s32 params_size = ++ (WL_SCAN_PARAMS_FIXED_SIZE + offsetof(wl_iscan_params_t, params)); ++ struct wl_iscan_params *params = NULL; ++ s32 err = 0; ++ ++ if (request != NULL) { ++ n_channels = request->n_channels; ++ n_ssids = request->n_ssids; ++ /* Allocate space for populating ssids in wl_iscan_params struct */ ++ if (n_channels % 2) ++ /* If n_channels is odd, add a padd of u16 */ ++ params_size += sizeof(u16) * (n_channels + 1); ++ else ++ params_size += sizeof(u16) * n_channels; ++ ++ /* Allocate space for populating ssids in wl_iscan_params struct */ ++ params_size += sizeof(struct wlc_ssid) * n_ssids; ++ } ++ params = (struct wl_iscan_params *)kzalloc(params_size, GFP_KERNEL); ++ if (!params) { ++ err = -ENOMEM; ++ goto done; ++ } ++ wl_scan_prep(¶ms->params, request); ++ ++ params->version = htod32(ISCAN_REQ_VERSION); ++ params->action = htod16(action); ++ params->scan_duration = htod16(0); ++ ++ if (params_size + sizeof("iscan") >= WLC_IOCTL_MEDLEN) { ++ AP6211_ERR("ioctl buffer length is not sufficient\n"); ++ err = -ENOMEM; ++ goto done; ++ } ++ err = wldev_iovar_setbuf(iscan->dev, "iscan", params, params_size, ++ iscan->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); ++ if (unlikely(err)) { ++ if (err == -EBUSY) { ++ AP6211_ERR("system busy : iscan canceled\n"); ++ } else { ++ AP6211_ERR("error (%d)\n", err); ++ } ++ } ++ ++done: ++ if (params) ++ kfree(params); ++ return err; ++} ++ ++static s32 wl_do_iscan(struct wl_priv *wl, struct cfg80211_scan_request *request) ++{ ++ struct wl_iscan_ctrl *iscan = wl_to_iscan(wl); ++ struct net_device *ndev = wl_to_prmry_ndev(wl); ++ s32 passive_scan; ++ s32 err = 0; ++ ++ iscan->state = WL_ISCAN_STATE_SCANING; ++ ++ passive_scan = wl->active_scan ? 0 : 1; ++ err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN, ++ &passive_scan, sizeof(passive_scan), true); ++ if (unlikely(err)) { ++ AP6211_DEBUG("error (%d)\n", err); ++ return err; ++ } ++ wl->iscan_kickstart = true; ++ wl_run_iscan(iscan, request, WL_SCAN_ACTION_START); ++ mod_timer(&iscan->timer, jiffies + msecs_to_jiffies(iscan->timer_ms)); ++ iscan->timer_on = 1; ++ ++ return err; ++} ++ ++static s32 ++wl_get_valid_channels(struct net_device *ndev, u8 *valid_chan_list, s32 size) ++{ ++ wl_uint32_list_t *list; ++ s32 err = BCME_OK; ++ if (valid_chan_list == NULL || size <= 0) ++ return -ENOMEM; ++ ++ memset(valid_chan_list, 0, size); ++ list = (wl_uint32_list_t *)(void *) valid_chan_list; ++ list->count = htod32(WL_NUMCHANNELS); ++ err = wldev_ioctl(ndev, WLC_GET_VALID_CHANNELS, valid_chan_list, size, false); ++ if (err != 0) { ++ AP6211_ERR("get channels failed with %d\n", err); ++ } ++ ++ return err; ++} ++ ++static s32 ++wl_run_escan(struct wl_priv *wl, struct net_device *ndev, ++ struct cfg80211_scan_request *request, uint16 action) ++{ ++ s32 err = BCME_OK; ++ u32 n_channels; ++ u32 n_ssids; ++ s32 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params)); ++ wl_escan_params_t *params = NULL; ++ u8 chan_buf[sizeof(u32)*(WL_NUMCHANNELS + 1)]; ++ u32 num_chans = 0; ++ s32 channel; ++ s32 n_valid_chan; ++ s32 search_state = WL_P2P_DISC_ST_SCAN; ++ u32 i, j, n_nodfs = 0; ++ u16 *default_chan_list = NULL; ++ wl_uint32_list_t *list; ++ struct net_device *dev = NULL; ++ ++ AP6211_DEBUG("Enter \n"); ++ ++ if (!wl) { ++ err = -EINVAL; ++ goto exit; ++ } ++ if (!wl->p2p_supported || !p2p_scan(wl)) { ++ /* LEGACY SCAN TRIGGER */ ++ AP6211_DEBUG(" LEGACY E-SCAN START\n"); ++ ++ /* if scan request is not empty parse scan request paramters */ ++ if (request != NULL) { ++ n_channels = request->n_channels; ++ n_ssids = request->n_ssids; ++ /* Allocate space for populating ssids in wl_iscan_params struct */ ++ if (n_channels % 2) ++ /* If n_channels is odd, add a padd of u16 */ ++ params_size += sizeof(u16) * (n_channels + 1); ++ else ++ params_size += sizeof(u16) * n_channels; ++ ++ /* Allocate space for populating ssids in wl_iscan_params struct */ ++ params_size += sizeof(struct wlc_ssid) * n_ssids; ++ } ++ params = (wl_escan_params_t *) kzalloc(params_size, GFP_KERNEL); ++ if (params == NULL) { ++ err = -ENOMEM; ++ goto exit; ++ } ++ ++ wl_scan_prep(¶ms->params, request); ++ ++ params->version = htod32(ESCAN_REQ_VERSION); ++ params->action = htod16(action); ++ params->sync_id = htod16(0x1234); ++ if (params_size + sizeof("escan") >= WLC_IOCTL_MEDLEN) { ++ AP6211_ERR("ioctl buffer length not sufficient\n"); ++ kfree(params); ++ err = -ENOMEM; ++ goto exit; ++ } ++ err = wldev_iovar_setbuf(ndev, "escan", params, params_size, ++ wl->escan_ioctl_buf, WLC_IOCTL_MEDLEN, NULL); ++ if (unlikely(err)) { ++ if (err == BCME_EPERM) ++ /* Scan Not permitted at this point of time */ ++ AP6211_DEBUG(" Escan not permitted at this time (%d)\n", err); ++ else ++ AP6211_ERR(" Escan set error (%d)\n", err); ++ } ++ kfree(params); ++ } ++ else if (p2p_is_on(wl) && p2p_scan(wl)) { ++ /* P2P SCAN TRIGGER */ ++ s32 _freq = 0; ++ n_nodfs = 0; ++ if (request && request->n_channels) { ++ num_chans = request->n_channels; ++ AP6211_DEBUG(" chann number : %d\n", num_chans); ++ default_chan_list = kzalloc(num_chans * sizeof(*default_chan_list), ++ GFP_KERNEL); ++ if (default_chan_list == NULL) { ++ AP6211_ERR("channel list allocation failed \n"); ++ err = -ENOMEM; ++ goto exit; ++ } ++ if (!wl_get_valid_channels(ndev, chan_buf, sizeof(chan_buf))) { ++ list = (wl_uint32_list_t *) chan_buf; ++ n_valid_chan = dtoh32(list->count); ++ for (i = 0; i < num_chans; i++) ++ { ++#ifdef WL_HOST_BAND_MGMT ++ int channel_band = 0; ++#endif /* WL_HOST_BAND_MGMT */ ++ _freq = request->channels[i]->center_freq; ++ channel = ieee80211_frequency_to_channel(_freq); ++#ifdef WL_HOST_BAND_MGMT ++ channel_band = (channel > CH_MAX_2G_CHANNEL) ? ++ WLC_BAND_5G : WLC_BAND_2G; ++ if ((wl->curr_band != WLC_BAND_AUTO) && ++ (wl->curr_band != channel_band) && ++ !IS_P2P_SOCIAL_CHANNEL(channel)) ++ continue; ++#endif /* WL_HOST_BAND_MGMT */ ++ ++ /* ignore DFS channels */ ++ if (request->channels[i]->flags & ++ (IEEE80211_CHAN_RADAR ++ | IEEE80211_CHAN_PASSIVE_SCAN)) ++ continue; ++ ++ for (j = 0; j < n_valid_chan; j++) { ++ /* allows only supported channel on ++ * current reguatory ++ */ ++ if (channel == (dtoh32(list->element[j]))) ++ default_chan_list[n_nodfs++] = ++ channel; ++ } ++ ++ } ++ } ++ if (num_chans == 3 && ( ++ (default_chan_list[0] == SOCIAL_CHAN_1) && ++ (default_chan_list[1] == SOCIAL_CHAN_2) && ++ (default_chan_list[2] == SOCIAL_CHAN_3))) { ++ /* SOCIAL CHANNELS 1, 6, 11 */ ++ search_state = WL_P2P_DISC_ST_SEARCH; ++ AP6211_DEBUG("P2P SEARCH PHASE START \n"); ++ } else if ((dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION)) && ++ (wl_get_mode_by_netdev(wl, dev) == WL_MODE_AP)) { ++ /* If you are already a GO, then do SEARCH only */ ++ AP6211_DEBUG("Already a GO. Do SEARCH Only"); ++ search_state = WL_P2P_DISC_ST_SEARCH; ++ num_chans = n_nodfs; ++ ++ } else { ++ AP6211_DEBUG("P2P SCAN STATE START \n"); ++ num_chans = n_nodfs; ++ } ++ ++ } ++ err = wl_cfgp2p_escan(wl, ndev, wl->active_scan, num_chans, default_chan_list, ++ search_state, action, ++ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); ++ kfree(default_chan_list); ++ } ++exit: ++ if (unlikely(err)) { ++ /* Don't print Error incase of Scan suppress */ ++ if ((err == BCME_EPERM) && wl->scan_suppressed) ++ AP6211_DEBUG("Escan failed: Scan Suppressed \n"); ++ else ++ AP6211_ERR("error (%d)\n", err); ++ } ++ return err; ++} ++ ++ ++static s32 ++wl_do_escan(struct wl_priv *wl, struct wiphy *wiphy, struct net_device *ndev, ++ struct cfg80211_scan_request *request) ++{ ++ s32 err = BCME_OK; ++ s32 passive_scan; ++ wl_scan_results_t *results; ++ AP6211_DEBUG("Enter \n"); ++ mutex_lock(&wl->usr_sync); ++ results = (wl_scan_results_t *) wl->escan_info.escan_buf; ++ results->version = 0; ++ results->count = 0; ++ results->buflen = WL_SCAN_RESULTS_FIXED_SIZE; ++ ++ wl->escan_info.ndev = ndev; ++ wl->escan_info.wiphy = wiphy; ++ wl->escan_info.escan_state = WL_ESCAN_STATE_SCANING; ++ passive_scan = wl->active_scan ? 0 : 1; ++ err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN, ++ &passive_scan, sizeof(passive_scan), true); ++ if (unlikely(err)) { ++ AP6211_ERR("error (%d)\n", err); ++ goto exit; ++ } ++ ++ err = wl_run_escan(wl, ndev, request, WL_SCAN_ACTION_START); ++exit: ++ mutex_unlock(&wl->usr_sync); ++ return err; ++} ++ ++static s32 ++__wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, ++ struct cfg80211_scan_request *request, ++ struct cfg80211_ssid *this_ssid) ++{ ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ struct cfg80211_ssid *ssids; ++ struct wl_scan_req *sr = wl_to_sr(wl); ++ struct ether_addr primary_mac; ++ s32 passive_scan; ++ bool iscan_req; ++ bool escan_req = false; ++ bool p2p_ssid; ++#ifdef WL11U ++ bcm_tlv_t *interworking_ie; ++ u32 ie_len; ++#endif ++ s32 err = 0; ++ s32 bssidx = -1; ++ s32 i; ++ ++ unsigned long flags; ++ static s32 busy_count = 0; ++ ++ /* If scan req comes for p2p0, send it over primary I/F ++ * Scan results will be delivered corresponding to cfg80211_scan_request ++ */ ++ if (ndev == wl->p2p_net) { ++ ndev = wl_to_prmry_ndev(wl); ++ } ++ ++ if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(wl)) { ++ AP6211_ERR("Sending Action Frames. Try it again.\n"); ++ return -EAGAIN; ++ } ++ ++ AP6211_DEBUG("Enter wiphy (%p)\n", wiphy); ++ if (wl_get_drv_status_all(wl, SCANNING)) { ++ if (wl->scan_request == NULL) { ++ wl_clr_drv_status_all(wl, SCANNING); ++ AP6211_DEBUG("<<<<<<<<<<>>>>>>>>>>\n"); ++ } else { ++ AP6211_ERR("Scanning already\n"); ++ return -EAGAIN; ++ } ++ } ++ if (wl_get_drv_status(wl, SCAN_ABORTING, ndev)) { ++ AP6211_ERR("Scanning being aborted\n"); ++ return -EAGAIN; ++ } ++ if (request && request->n_ssids > WL_SCAN_PARAMS_SSID_MAX) { ++ AP6211_ERR("request null or n_ssids > WL_SCAN_PARAMS_SSID_MAX\n"); ++ return -EOPNOTSUPP; ++ } ++#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST ++ if (wl_get_drv_status_all(wl, REMAINING_ON_CHANNEL)) { ++ AP6211_DEBUG("Remain_on_channel bit is set, somehow it didn't get cleared\n"); ++ wl_notify_escan_complete(wl, ndev, true, true); ++ } ++#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ ++ ++ /* Arm scan timeout timer */ ++ mod_timer(&wl->scan_timeout, jiffies + msecs_to_jiffies(WL_SCAN_TIMER_INTERVAL_MS)); ++ iscan_req = false; ++ if (request) { /* scan bss */ ++ ssids = request->ssids; ++ if (wl->iscan_on && (!ssids || !ssids->ssid_len || request->n_ssids != 1)) { ++ iscan_req = true; ++ } else if (wl->escan_on) { ++ escan_req = true; ++ p2p_ssid = false; ++ for (i = 0; i < request->n_ssids; i++) { ++ if (ssids[i].ssid_len && ++ IS_P2P_SSID(ssids[i].ssid, ssids[i].ssid_len)) { ++ p2p_ssid = true; ++ break; ++ } ++ } ++ if (p2p_ssid) { ++ if (wl->p2p_supported) { ++ /* p2p scan trigger */ ++ if (p2p_on(wl) == false) { ++ /* p2p on at the first time */ ++ p2p_on(wl) = true; ++ wl_cfgp2p_set_firm_p2p(wl); ++ get_primary_mac(wl, &primary_mac); ++ wl_cfgp2p_generate_bss_mac(&primary_mac, ++ &wl->p2p->dev_addr, &wl->p2p->int_addr); ++ } ++ wl_clr_p2p_status(wl, GO_NEG_PHASE); ++ AP6211_DEBUG("P2P: GO_NEG_PHASE status cleared \n"); ++ p2p_scan(wl) = true; ++ } ++ } else { ++ /* legacy scan trigger ++ * So, we have to disable p2p discovery if p2p discovery is on ++ */ ++ if (wl->p2p_supported) { ++ p2p_scan(wl) = false; ++ /* If Netdevice is not equals to primary and p2p is on ++ * , we will do p2p scan using P2PAPI_BSSCFG_DEVICE. ++ */ ++ ++ if (p2p_scan(wl) == false) { ++ if (wl_get_p2p_status(wl, DISCOVERY_ON)) { ++ err = wl_cfgp2p_discover_enable_search(wl, ++ false); ++ if (unlikely(err)) { ++ goto scan_out; ++ } ++ ++ } ++ } ++ } ++ if (!wl->p2p_supported || !p2p_scan(wl)) { ++ bssidx = wl_cfgp2p_find_idx(wl, ndev); ++ ++#ifdef WL11U ++ if ((interworking_ie = wl_cfg80211_find_interworking_ie( ++ (u8 *)request->ie, request->ie_len)) != NULL) { ++ ie_len = interworking_ie->len; ++ ++ err = wl_cfg80211_add_iw_ie(wl, ndev, bssidx, ++ VNDR_IE_CUSTOM_FLAG, interworking_ie->id, ++ interworking_ie->data, interworking_ie->len); ++ ++ if (unlikely(err)) { ++ goto scan_out; ++ } ++ } else if (wl->iw_ie_len != 0) { ++ /* we have to clear IW IE and disable gratuitous APR */ ++ wl_cfg80211_add_iw_ie(wl, ndev, bssidx, ++ VNDR_IE_CUSTOM_FLAG, ++ DOT11_MNG_INTERWORKING_ID, ++ 0, 0); ++ ++ wldev_iovar_setint_bsscfg(ndev, "grat_arp", 0, ++ bssidx); ++ /* we don't care about error */ ++ } ++#endif /* WL11U */ ++ err = wl_cfgp2p_set_management_ie(wl, ndev, bssidx, ++ VNDR_IE_PRBREQ_FLAG, (u8 *)request->ie, ++ request->ie_len); ++ ++ if (unlikely(err)) { ++ goto scan_out; ++ } ++ ++ } ++ } ++ } ++ } else { /* scan in ibss */ ++ /* we don't do iscan in ibss */ ++ ssids = this_ssid; ++ } ++ wl->scan_request = request; ++ wl_set_drv_status(wl, SCANNING, ndev); ++ if (iscan_req) { ++ err = wl_do_iscan(wl, request); ++ if (likely(!err)) ++ goto scan_success; ++ else ++ goto scan_out; ++ } else if (escan_req) { ++ if (wl->p2p_supported) { ++ if (p2p_on(wl) && p2p_scan(wl)) { ++ ++ /* find my listen channel */ ++ wl->afx_hdl->my_listen_chan = ++ wl_find_listen_channel(wl, (u8 *)request->ie, ++ request->ie_len); ++ err = wl_cfgp2p_enable_discovery(wl, ndev, ++ request->ie, request->ie_len); ++ ++ if (unlikely(err)) { ++ goto scan_out; ++ } ++ } ++ } ++ err = wl_do_escan(wl, wiphy, ndev, request); ++ if (likely(!err)) ++ goto scan_success; ++ else ++ goto scan_out; ++ ++ ++ } else { ++ memset(&sr->ssid, 0, sizeof(sr->ssid)); ++ sr->ssid.SSID_len = ++ min_t(u8, sizeof(sr->ssid.SSID), ssids->ssid_len); ++ if (sr->ssid.SSID_len) { ++ memcpy(sr->ssid.SSID, ssids->ssid, sr->ssid.SSID_len); ++ sr->ssid.SSID_len = htod32(sr->ssid.SSID_len); ++ AP6211_DEBUG("Specific scan ssid=\"%s\" len=%d\n", ++ sr->ssid.SSID, sr->ssid.SSID_len); ++ } else { ++ AP6211_DEBUG("Broadcast scan\n"); ++ } ++ AP6211_DEBUG("sr->ssid.SSID_len (%d)\n", sr->ssid.SSID_len); ++ passive_scan = wl->active_scan ? 0 : 1; ++ err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN, ++ &passive_scan, sizeof(passive_scan), true); ++ if (unlikely(err)) { ++ AP6211_DEBUG("WLC_SET_PASSIVE_SCAN error (%d)\n", err); ++ goto scan_out; ++ } ++ err = wldev_ioctl(ndev, WLC_SCAN, &sr->ssid, ++ sizeof(sr->ssid), false); ++ if (err) { ++ if (err == -EBUSY) { ++ AP6211_ERR("system busy : scan for \"%s\" " ++ "canceled\n", sr->ssid.SSID); ++ } else { ++ AP6211_ERR("WLC_SCAN error (%d)\n", err); ++ } ++ goto scan_out; ++ } ++ } ++ ++scan_success: ++ ++ busy_count = 0; ++ ++ return 0; ++ ++scan_out: ++ ++ if (err == BCME_BUSY || err == BCME_NOTREADY) { ++ AP6211_ERR("Scan err = (%d), busy?%d", err, -EBUSY); ++ err = -EBUSY; ++ } ++ ++#define SCAN_EBUSY_RETRY_LIMIT 10 ++ if (err == -EBUSY) { ++ if (busy_count++ > SCAN_EBUSY_RETRY_LIMIT) { ++ struct ether_addr bssid; ++ s32 ret = 0; ++ busy_count = 0; ++ AP6211_ERR("Unusual continuous EBUSY error, %d %d %d %d %d %d %d %d %d\n", ++ wl_get_drv_status(wl, SCANNING, ndev), ++ wl_get_drv_status(wl, SCAN_ABORTING, ndev), ++ wl_get_drv_status(wl, CONNECTING, ndev), ++ wl_get_drv_status(wl, CONNECTED, ndev), ++ wl_get_drv_status(wl, DISCONNECTING, ndev), ++ wl_get_drv_status(wl, AP_CREATING, ndev), ++ wl_get_drv_status(wl, AP_CREATED, ndev), ++ wl_get_drv_status(wl, SENDING_ACT_FRM, ndev), ++ wl_get_drv_status(wl, SENDING_ACT_FRM, ndev)); ++ ++ bzero(&bssid, sizeof(bssid)); ++ if ((ret = wldev_ioctl(ndev, WLC_GET_BSSID, ++ &bssid, ETHER_ADDR_LEN, false)) == 0) ++ AP6211_ERR("FW is connected with " MACDBG "/n", ++ MAC2STRDBG(bssid.octet)); ++ else ++ AP6211_ERR("GET BSSID failed with %d\n", ret); ++ ++ wl_cfg80211_disconnect(wiphy, ndev, DOT11_RC_DISASSOC_LEAVING); ++ } ++ } else { ++ busy_count = 0; ++ } ++ wl_clr_drv_status(wl, SCANNING, ndev); ++ if (timer_pending(&wl->scan_timeout)) ++ del_timer_sync(&wl->scan_timeout); ++ spin_lock_irqsave(&wl->cfgdrv_lock, flags); ++ wl->scan_request = NULL; ++ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); ++ return err; ++} ++ ++static s32 ++wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, ++ struct cfg80211_scan_request *request) ++{ ++ s32 err = 0; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ ++ AP6211_DEBUG("Enter \n"); ++ CHECK_SYS_UP(wl); ++ ++ err = __wl_cfg80211_scan(wiphy, ndev, request, NULL); ++ if (unlikely(err)) { ++ if ((err == BCME_EPERM) && wl->scan_suppressed) ++ AP6211_DEBUG("scan not permitted at this time (%d)\n", err); ++ else ++ AP6211_ERR("scan error (%d)\n", err); ++ return err; ++ } ++ ++ return err; ++} ++ ++static s32 wl_set_rts(struct net_device *dev, u32 rts_threshold) ++{ ++ s32 err = 0; ++ ++ err = wldev_iovar_setint(dev, "rtsthresh", rts_threshold); ++ if (unlikely(err)) { ++ AP6211_ERR("Error (%d)\n", err); ++ return err; ++ } ++ return err; ++} ++ ++static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold) ++{ ++ s32 err = 0; ++ ++ err = wldev_iovar_setint_bsscfg(dev, "fragthresh", frag_threshold, 0); ++ if (unlikely(err)) { ++ AP6211_ERR("Error (%d)\n", err); ++ return err; ++ } ++ return err; ++} ++ ++static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l) ++{ ++ s32 err = 0; ++ u32 cmd = (l ? WLC_SET_LRL : WLC_SET_SRL); ++ ++ retry = htod32(retry); ++ err = wldev_ioctl(dev, cmd, &retry, sizeof(retry), true); ++ if (unlikely(err)) { ++ AP6211_ERR("cmd (%d) , error (%d)\n", cmd, err); ++ return err; ++ } ++ return err; ++} ++ ++static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) ++{ ++ struct wl_priv *wl = (struct wl_priv *)wiphy_priv(wiphy); ++ struct net_device *ndev = wl_to_prmry_ndev(wl); ++ s32 err = 0; ++ ++ CHECK_SYS_UP(wl); ++ AP6211_DEBUG("Enter\n"); ++ if (changed & WIPHY_PARAM_RTS_THRESHOLD && ++ (wl->conf->rts_threshold != wiphy->rts_threshold)) { ++ wl->conf->rts_threshold = wiphy->rts_threshold; ++ err = wl_set_rts(ndev, wl->conf->rts_threshold); ++ if (!err) ++ return err; ++ } ++ if (changed & WIPHY_PARAM_FRAG_THRESHOLD && ++ (wl->conf->frag_threshold != wiphy->frag_threshold)) { ++ wl->conf->frag_threshold = wiphy->frag_threshold; ++ err = wl_set_frag(ndev, wl->conf->frag_threshold); ++ if (!err) ++ return err; ++ } ++ if (changed & WIPHY_PARAM_RETRY_LONG && ++ (wl->conf->retry_long != wiphy->retry_long)) { ++ wl->conf->retry_long = wiphy->retry_long; ++ err = wl_set_retry(ndev, wl->conf->retry_long, true); ++ if (!err) ++ return err; ++ } ++ if (changed & WIPHY_PARAM_RETRY_SHORT && ++ (wl->conf->retry_short != wiphy->retry_short)) { ++ wl->conf->retry_short = wiphy->retry_short; ++ err = wl_set_retry(ndev, wl->conf->retry_short, false); ++ if (!err) { ++ return err; ++ } ++ } ++ ++ return err; ++} ++ ++static s32 ++wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, ++ struct cfg80211_ibss_params *params) ++{ ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ struct cfg80211_bss *bss; ++ struct ieee80211_channel *chan; ++ struct wl_join_params join_params; ++ struct cfg80211_ssid ssid; ++ s32 scan_retry = 0; ++ s32 err = 0; ++ bool rollback_lock = false; ++ ++ AP6211_DEBUG("In\n"); ++ CHECK_SYS_UP(wl); ++ if (params->bssid) { ++ AP6211_ERR("Invalid bssid\n"); ++ return -EOPNOTSUPP; ++ } ++ bss = cfg80211_get_ibss(wiphy, NULL, params->ssid, params->ssid_len); ++ if (!bss) { ++ memcpy(ssid.ssid, params->ssid, params->ssid_len); ++ ssid.ssid_len = params->ssid_len; ++ do { ++ if (unlikely ++ (__wl_cfg80211_scan(wiphy, dev, NULL, &ssid) == ++ -EBUSY)) { ++ wl_delay(150); ++ } else { ++ break; ++ } ++ } while (++scan_retry < WL_SCAN_RETRY_MAX); ++ /* to allow scan_inform to propagate to cfg80211 plane */ ++ if (rtnl_is_locked()) { ++ rtnl_unlock(); ++ rollback_lock = true; ++ } ++ ++ /* wait 4 secons till scan done.... */ ++ schedule_timeout_interruptible(msecs_to_jiffies(4000)); ++ if (rollback_lock) ++ rtnl_lock(); ++ bss = cfg80211_get_ibss(wiphy, NULL, ++ params->ssid, params->ssid_len); ++ } ++ if (bss) { ++ wl->ibss_starter = false; ++ AP6211_DEBUG("Found IBSS\n"); ++ } else { ++ wl->ibss_starter = true; ++ } ++ chan = params->channel; ++ if (chan) ++ wl->channel = ieee80211_frequency_to_channel(chan->center_freq); ++ /* ++ * Join with specific BSSID and cached SSID ++ * If SSID is zero join based on BSSID only ++ */ ++ memset(&join_params, 0, sizeof(join_params)); ++ memcpy((void *)join_params.ssid.SSID, (void *)params->ssid, ++ params->ssid_len); ++ join_params.ssid.SSID_len = htod32(params->ssid_len); ++ if (params->bssid) ++ memcpy(&join_params.params.bssid, params->bssid, ++ ETHER_ADDR_LEN); ++ else ++ memset(&join_params.params.bssid, 0, ETHER_ADDR_LEN); ++ ++ err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, ++ sizeof(join_params), true); ++ if (unlikely(err)) { ++ AP6211_ERR("Error (%d)\n", err); ++ return err; ++ } ++ return err; ++} ++ ++static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) ++{ ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ s32 err = 0; ++ ++ CHECK_SYS_UP(wl); ++ wl_link_down(wl); ++ ++ return err; ++} ++ ++static s32 ++wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ struct wl_security *sec; ++ s32 val = 0; ++ s32 err = 0; ++ s32 bssidx = wl_cfgp2p_find_idx(wl, dev); ++ ++ if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) ++ val = WPA_AUTH_PSK | ++ WPA_AUTH_UNSPECIFIED; ++ else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) ++ val = WPA2_AUTH_PSK| ++ WPA2_AUTH_UNSPECIFIED; ++ else ++ val = WPA_AUTH_DISABLED; ++ ++ if (is_wps_conn(sme)) ++ val = WPA_AUTH_DISABLED; ++ ++#ifdef BCMWAPI_WPI ++ if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) { ++ AP6211_DEBUG(" * wl_set_wpa_version, set wpa_auth" ++ " to WPA_AUTH_WAPI 0x400"); ++ val = WAPI_AUTH_PSK; /* | WAPI_AUTH_UNSPECIFIED; */ ++ } ++#endif ++ AP6211_DEBUG("setting wpa_auth to 0x%0x\n", val); ++ err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx); ++ if (unlikely(err)) { ++ AP6211_ERR("set wpa_auth failed (%d)\n", err); ++ return err; ++ } ++ sec = wl_read_prof(wl, dev, WL_PROF_SEC); ++ sec->wpa_versions = sme->crypto.wpa_versions; ++ return err; ++} ++ ++#ifdef BCMWAPI_WPI ++static s32 ++wl_set_set_wapi_ie(struct net_device *dev, struct cfg80211_connect_params *sme) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ s32 err = 0; ++ s32 bssidx = wl_cfgp2p_find_idx(wl, dev); ++ ++ AP6211_DEBUG(" %s \n", __FUNCTION__); ++ ++ if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) { ++ err = wldev_iovar_setbuf_bsscfg(dev, "wapiie", sme->ie, ++ sme->ie_len, wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); ++ if (unlikely(err)) { ++ AP6211_ERR("===> set_wapi_ie Error (%d)\n", err); ++ return err; ++ } ++ } else ++ AP6211_DEBUG(" * skip \n"); ++ return err; ++} ++#endif /* BCMWAPI_WPI */ ++ ++static s32 ++wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ struct wl_security *sec; ++ s32 val = 0; ++ s32 err = 0; ++ s32 bssidx = wl_cfgp2p_find_idx(wl, dev); ++ switch (sme->auth_type) { ++ case NL80211_AUTHTYPE_OPEN_SYSTEM: ++ val = WL_AUTH_OPEN_SYSTEM; ++ AP6211_DEBUG("open system\n"); ++ break; ++ case NL80211_AUTHTYPE_SHARED_KEY: ++ val = WL_AUTH_SHARED_KEY; ++ AP6211_DEBUG("shared key\n"); ++ break; ++ case NL80211_AUTHTYPE_AUTOMATIC: ++ val = WL_AUTH_OPEN_SHARED; ++ AP6211_DEBUG("automatic\n"); ++ break; ++ default: ++ val = WL_AUTH_OPEN_SHARED; ++ AP6211_ERR("invalid auth type (%d)\n", sme->auth_type); ++ break; ++ } ++ ++ err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx); ++ if (unlikely(err)) { ++ AP6211_ERR("set auth failed (%d)\n", err); ++ return err; ++ } ++ sec = wl_read_prof(wl, dev, WL_PROF_SEC); ++ sec->auth_type = sme->auth_type; ++ return err; ++} ++ ++static s32 ++wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ struct wl_security *sec; ++ s32 pval = 0; ++ s32 gval = 0; ++ s32 err = 0; ++#ifdef BCMWAPI_WPI ++ s32 val = 0; ++#endif ++ s32 bssidx = wl_cfgp2p_find_idx(wl, dev); ++ ++ if (sme->crypto.n_ciphers_pairwise) { ++ switch (sme->crypto.ciphers_pairwise[0]) { ++ case WLAN_CIPHER_SUITE_WEP40: ++ case WLAN_CIPHER_SUITE_WEP104: ++ pval = WEP_ENABLED; ++ break; ++ case WLAN_CIPHER_SUITE_TKIP: ++ pval = TKIP_ENABLED; ++ break; ++ case WLAN_CIPHER_SUITE_CCMP: ++ pval = AES_ENABLED; ++ break; ++ case WLAN_CIPHER_SUITE_AES_CMAC: ++ pval = AES_ENABLED; ++ break; ++#ifdef BCMWAPI_WPI ++ case WLAN_CIPHER_SUITE_SMS4: ++ val = SMS4_ENABLED; ++ pval = SMS4_ENABLED; ++ break; ++#endif ++ default: ++ AP6211_ERR("invalid cipher pairwise (%d)\n", ++ sme->crypto.ciphers_pairwise[0]); ++ return -EINVAL; ++ } ++ } ++ if (sme->crypto.cipher_group) { ++ switch (sme->crypto.cipher_group) { ++ case WLAN_CIPHER_SUITE_WEP40: ++ case WLAN_CIPHER_SUITE_WEP104: ++ gval = WEP_ENABLED; ++ break; ++ case WLAN_CIPHER_SUITE_TKIP: ++ gval = TKIP_ENABLED; ++ break; ++ case WLAN_CIPHER_SUITE_CCMP: ++ gval = AES_ENABLED; ++ break; ++ case WLAN_CIPHER_SUITE_AES_CMAC: ++ gval = AES_ENABLED; ++ break; ++#ifdef BCMWAPI_WPI ++ case WLAN_CIPHER_SUITE_SMS4: ++ val = SMS4_ENABLED; ++ gval = SMS4_ENABLED; ++ break; ++#endif ++ default: ++ AP6211_ERR("invalid cipher group (%d)\n", ++ sme->crypto.cipher_group); ++ return -EINVAL; ++ } ++ } ++ ++ AP6211_DEBUG("pval (%d) gval (%d)\n", pval, gval); ++ ++ if (is_wps_conn(sme)) { ++ if (sme->privacy) ++ err = wldev_iovar_setint_bsscfg(dev, "wsec", 4, bssidx); ++#ifdef BCMWAPI_WPI ++ else if (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_SMS4) { ++ AP6211_DEBUG(" NO, is_wps_conn, WAPI set to SMS4_ENABLED"); ++ err = wldev_iovar_setint_bsscfg(dev, "wsec", val, bssidx); ++ } ++#endif ++ else ++ /* WPS-2.0 allows no security */ ++ err = wldev_iovar_setint_bsscfg(dev, "wsec", 0, bssidx); ++ } else { ++ AP6211_DEBUG(" NO, is_wps_conn, Set pval | gval to WSEC"); ++ err = wldev_iovar_setint_bsscfg(dev, "wsec", ++ pval | gval, bssidx); ++ } ++ if (unlikely(err)) { ++ AP6211_ERR("error (%d)\n", err); ++ return err; ++ } ++ ++ sec = wl_read_prof(wl, dev, WL_PROF_SEC); ++ sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0]; ++ sec->cipher_group = sme->crypto.cipher_group; ++ ++ return err; ++} ++ ++static s32 ++wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ struct wl_security *sec; ++ s32 val = 0; ++ s32 err = 0; ++ s32 bssidx = wl_cfgp2p_find_idx(wl, dev); ++ ++ if (sme->crypto.n_akm_suites) { ++ err = wldev_iovar_getint(dev, "wpa_auth", &val); ++ if (unlikely(err)) { ++ AP6211_ERR("could not get wpa_auth (%d)\n", err); ++ return err; ++ } ++ if (val & (WPA_AUTH_PSK | ++ WPA_AUTH_UNSPECIFIED)) { ++ switch (sme->crypto.akm_suites[0]) { ++ case WLAN_AKM_SUITE_8021X: ++ val = WPA_AUTH_UNSPECIFIED; ++ break; ++ case WLAN_AKM_SUITE_PSK: ++ val = WPA_AUTH_PSK; ++ break; ++ default: ++ AP6211_ERR("invalid cipher group (%d)\n", ++ sme->crypto.cipher_group); ++ return -EINVAL; ++ } ++ } else if (val & (WPA2_AUTH_PSK | ++ WPA2_AUTH_UNSPECIFIED)) { ++ switch (sme->crypto.akm_suites[0]) { ++ case WLAN_AKM_SUITE_8021X: ++ val = WPA2_AUTH_UNSPECIFIED; ++ break; ++ case WLAN_AKM_SUITE_PSK: ++ val = WPA2_AUTH_PSK; ++ break; ++ default: ++ AP6211_ERR("invalid cipher group (%d)\n", ++ sme->crypto.cipher_group); ++ return -EINVAL; ++ } ++ } ++#ifdef BCMWAPI_WPI ++ else if (val & (WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED)) { ++ switch (sme->crypto.akm_suites[0]) { ++ case WLAN_AKM_SUITE_WAPI_CERT: ++ val = WAPI_AUTH_UNSPECIFIED; ++ break; ++ case WLAN_AKM_SUITE_WAPI_PSK: ++ val = WAPI_AUTH_PSK; ++ break; ++ default: ++ AP6211_ERR("invalid cipher group (%d)\n", ++ sme->crypto.cipher_group); ++ return -EINVAL; ++ } ++ } ++#endif ++ AP6211_DEBUG("setting wpa_auth to %d\n", val); ++ ++ err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx); ++ if (unlikely(err)) { ++ AP6211_ERR("could not set wpa_auth (%d)\n", err); ++ return err; ++ } ++ } ++ sec = wl_read_prof(wl, dev, WL_PROF_SEC); ++ sec->wpa_auth = sme->crypto.akm_suites[0]; ++ ++ return err; ++} ++ ++static s32 ++wl_set_set_sharedkey(struct net_device *dev, ++ struct cfg80211_connect_params *sme) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ struct wl_security *sec; ++ struct wl_wsec_key key; ++ s32 val; ++ s32 err = 0; ++ s32 bssidx = wl_cfgp2p_find_idx(wl, dev); ++ ++ AP6211_DEBUG("key len (%d)\n", sme->key_len); ++ if (sme->key_len) { ++ sec = wl_read_prof(wl, dev, WL_PROF_SEC); ++ AP6211_DEBUG("wpa_versions 0x%x cipher_pairwise 0x%x\n", ++ sec->wpa_versions, sec->cipher_pairwise); ++ if (!(sec->wpa_versions & (NL80211_WPA_VERSION_1 | ++ NL80211_WPA_VERSION_2 ++#ifdef BCMWAPI_WPI ++ | NL80211_WAPI_VERSION_1 ++#endif ++ )) && ++ (sec->cipher_pairwise & (WLAN_CIPHER_SUITE_WEP40 | ++ WLAN_CIPHER_SUITE_WEP104 ++#ifdef BCMWAPI_WPI ++ | WLAN_CIPHER_SUITE_SMS4 ++#endif ++ ))) ++ { ++ memset(&key, 0, sizeof(key)); ++ key.len = (u32) sme->key_len; ++ key.index = (u32) sme->key_idx; ++ if (unlikely(key.len > sizeof(key.data))) { ++ AP6211_ERR("Too long key length (%u)\n", key.len); ++ return -EINVAL; ++ } ++ memcpy(key.data, sme->key, key.len); ++ key.flags = WL_PRIMARY_KEY; ++ switch (sec->cipher_pairwise) { ++ case WLAN_CIPHER_SUITE_WEP40: ++ key.algo = CRYPTO_ALGO_WEP1; ++ break; ++ case WLAN_CIPHER_SUITE_WEP104: ++ key.algo = CRYPTO_ALGO_WEP128; ++ break; ++#ifdef BCMWAPI_WPI ++ case WLAN_CIPHER_SUITE_SMS4: ++ key.algo = CRYPTO_ALGO_SMS4; ++ break; ++#endif ++ default: ++ AP6211_ERR("Invalid algorithm (%d)\n", ++ sme->crypto.ciphers_pairwise[0]); ++ return -EINVAL; ++ } ++ /* Set the new key/index */ ++ AP6211_DEBUG("key length (%d) key index (%d) algo (%d)\n", ++ key.len, key.index, key.algo); ++ AP6211_DEBUG("key \"%s\"\n", key.data); ++ swap_key_from_BE(&key); ++ err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ++ wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); ++ if (unlikely(err)) { ++ AP6211_ERR("WLC_SET_KEY error (%d)\n", err); ++ return err; ++ } ++ if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) { ++ AP6211_DEBUG("set auth_type to shared key\n"); ++ val = WL_AUTH_SHARED_KEY; /* shared key */ ++ err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx); ++ if (unlikely(err)) { ++ AP6211_ERR("set auth failed (%d)\n", err); ++ return err; ++ } ++ } ++ } ++ } ++ return err; ++} ++ ++#ifdef ESCAN_RESULT_PATCH ++static u8 connect_req_bssid[6]; ++static u8 broad_bssid[6]; ++#endif ++ ++ ++static s32 ++wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, ++ struct cfg80211_connect_params *sme) ++{ ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ struct ieee80211_channel *chan = sme->channel; ++ wl_extjoin_params_t *ext_join_params; ++ struct wl_join_params join_params; ++ size_t join_params_size; ++ s32 err = 0; ++ wpa_ie_fixed_t *wpa_ie; ++ bcm_tlv_t *wpa2_ie; ++ u8* wpaie = 0; ++ u32 wpaie_len = 0; ++ u32 chan_cnt = 0; ++ struct ether_addr bssid; ++ int ret; ++ ++ AP6211_DEBUG("In\n"); ++ ++ if (unlikely(!sme->ssid)) { ++ AP6211_ERR("Invalid ssid\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ CHECK_SYS_UP(wl); ++ ++ /* ++ * Cancel ongoing scan to sync up with sme state machine of cfg80211. ++ */ ++#if !defined(ESCAN_RESULT_PATCH) ++ if (wl->scan_request) { ++ wl_notify_escan_complete(wl, dev, true, true); ++ } ++#endif ++#ifdef ESCAN_RESULT_PATCH ++ if (sme->bssid) { ++ memcpy(connect_req_bssid, sme->bssid, ETHER_ADDR_LEN); ++ } ++ else { ++ bzero(connect_req_bssid, ETHER_ADDR_LEN); ++ } ++ bzero(broad_bssid, ETHER_ADDR_LEN); ++#endif ++ ++ bzero(&bssid, sizeof(bssid)); ++ if (!wl_get_drv_status(wl, CONNECTED, dev)&& ++ (ret = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false)) == 0) { ++ if (!ETHER_ISNULLADDR(&bssid)) { ++ scb_val_t scbval; ++ wl_set_drv_status(wl, DISCONNECTING, dev); ++ scbval.val = DOT11_RC_DISASSOC_LEAVING; ++ memcpy(&scbval.ea, &bssid, ETHER_ADDR_LEN); ++ scbval.val = htod32(scbval.val); ++ ++ AP6211_DEBUG("drv status CONNECTED is not set, but connected in FW!" MACDBG "\n", ++ MAC2STRDBG(bssid.octet)); ++ err = wldev_ioctl(dev, WLC_DISASSOC, &scbval, ++ sizeof(scb_val_t), true); ++ if (unlikely(err)) { ++ wl_clr_drv_status(wl, DISCONNECTING, dev); ++ AP6211_ERR("error (%d)\n", err); ++ return err; ++ } ++ while (wl_get_drv_status(wl, DISCONNECTING, dev)) { ++ AP6211_ERR("Waiting for disconnection terminated.\n"); ++ msleep(20); ++ } ++ } else ++ AP6211_DEBUG("Currently not associated!\n"); ++ } ++ ++ /* Clean BSSID */ ++ bzero(&bssid, sizeof(bssid)); ++ if (!wl_get_drv_status(wl, DISCONNECTING, dev)) ++ wl_update_prof(wl, dev, NULL, (void *)&bssid, WL_PROF_BSSID); ++ ++ if (p2p_is_on(wl) && (dev != wl_to_prmry_ndev(wl))) { ++ /* we only allow to connect using virtual interface in case of P2P */ ++ wl_cfgp2p_set_management_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev), ++ VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len); ++ } else if (dev == wl_to_prmry_ndev(wl)) { ++ /* find the RSN_IE */ ++ if ((wpa2_ie = bcm_parse_tlvs((u8 *)sme->ie, sme->ie_len, ++ DOT11_MNG_RSN_ID)) != NULL) { ++ AP6211_DEBUG(" WPA2 IE is found\n"); ++ } ++ /* find the WPA_IE */ ++ if ((wpa_ie = wl_cfgp2p_find_wpaie((u8 *)sme->ie, ++ sme->ie_len)) != NULL) { ++ AP6211_DEBUG(" WPA IE is found\n"); ++ } ++ if (wpa_ie != NULL || wpa2_ie != NULL) { ++ wpaie = (wpa_ie != NULL) ? (u8 *)wpa_ie : (u8 *)wpa2_ie; ++ wpaie_len = (wpa_ie != NULL) ? wpa_ie->length : wpa2_ie->len; ++ wpaie_len += WPA_RSN_IE_TAG_FIXED_LEN; ++ wldev_iovar_setbuf(dev, "wpaie", wpaie, wpaie_len, ++ wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); ++ } else { ++ wldev_iovar_setbuf(dev, "wpaie", NULL, 0, ++ wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); ++ } ++ ++ err = wl_cfgp2p_set_management_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev), ++ VNDR_IE_ASSOCREQ_FLAG, (u8 *)sme->ie, sme->ie_len); ++ if (unlikely(err)) { ++ return err; ++ } ++ } ++ ++ if (chan) { ++ wl->channel = ieee80211_frequency_to_channel(chan->center_freq); ++ chan_cnt = 1; ++ AP6211_DEBUG("channel (%d), center_req (%d), %d channels\n", wl->channel, ++ chan->center_freq, chan_cnt); ++ } else ++ wl->channel = 0; ++ ++#ifdef BCMWAPI_WPI ++ AP6211_DEBUG("1. enable wapi auth\n"); ++ if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) { ++ AP6211_DEBUG("2. set wapi ie \n"); ++ err = wl_set_set_wapi_ie(dev, sme); ++ if (unlikely(err)) ++ return err; ++ } else ++ AP6211_DEBUG("2. Not wapi ie \n"); ++#endif ++ AP6211_DEBUG("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len); ++ AP6211_DEBUG("3. set wapi version \n"); ++ err = wl_set_wpa_version(dev, sme); ++ if (unlikely(err)) { ++ AP6211_ERR("Invalid wpa_version\n"); ++ return err; ++ } ++#ifdef BCMWAPI_WPI ++ if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) ++ AP6211_DEBUG("4. WAPI Dont Set wl_set_auth_type\n"); ++ else { ++ AP6211_DEBUG("4. wl_set_auth_type\n"); ++#endif ++ err = wl_set_auth_type(dev, sme); ++ if (unlikely(err)) { ++ AP6211_ERR("Invalid auth type\n"); ++ return err; ++ } ++#ifdef BCMWAPI_WPI ++ ++ } ++#endif ++ ++ err = wl_set_set_cipher(dev, sme); ++ if (unlikely(err)) { ++ AP6211_ERR("Invalid ciper\n"); ++ return err; ++ } ++ ++ err = wl_set_key_mgmt(dev, sme); ++ if (unlikely(err)) { ++ AP6211_ERR("Invalid key mgmt\n"); ++ return err; ++ } ++ ++ err = wl_set_set_sharedkey(dev, sme); ++ if (unlikely(err)) { ++ AP6211_ERR("Invalid shared key\n"); ++ return err; ++ } ++ ++ /* ++ * Join with specific BSSID and cached SSID ++ * If SSID is zero join based on BSSID only ++ */ ++ join_params_size = WL_EXTJOIN_PARAMS_FIXED_SIZE + ++ chan_cnt * sizeof(chanspec_t); ++ ext_join_params = (wl_extjoin_params_t*)kzalloc(join_params_size, GFP_KERNEL); ++ if (ext_join_params == NULL) { ++ err = -ENOMEM; ++ wl_clr_drv_status(wl, CONNECTING, dev); ++ goto exit; ++ } ++ ext_join_params->ssid.SSID_len = min(sizeof(ext_join_params->ssid.SSID), sme->ssid_len); ++ memcpy(&ext_join_params->ssid.SSID, sme->ssid, ext_join_params->ssid.SSID_len); ++ wl_update_prof(wl, dev, NULL, &ext_join_params->ssid, WL_PROF_SSID); ++ ext_join_params->ssid.SSID_len = htod32(ext_join_params->ssid.SSID_len); ++ /* increate dwell time to receive probe response or detect Beacon ++ * from target AP at a noisy air only during connect command ++ */ ++ ext_join_params->scan.active_time = WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS; ++ ext_join_params->scan.passive_time = WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS; ++ /* Set up join scan parameters */ ++ ext_join_params->scan.scan_type = -1; ++ ext_join_params->scan.nprobes ++ = (ext_join_params->scan.active_time/WL_SCAN_JOIN_PROBE_INTERVAL_MS); ++ ext_join_params->scan.home_time = -1; ++ ++ if (sme->bssid) ++ memcpy(&ext_join_params->assoc.bssid, sme->bssid, ETH_ALEN); ++ else ++ memcpy(&ext_join_params->assoc.bssid, ðer_bcast, ETH_ALEN); ++ ext_join_params->assoc.chanspec_num = chan_cnt; ++ if (chan_cnt) { ++ u16 channel, band, bw, ctl_sb; ++ chanspec_t chspec; ++ channel = wl->channel; ++ band = (channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G ++ : WL_CHANSPEC_BAND_5G; ++ bw = WL_CHANSPEC_BW_20; ++ ctl_sb = WL_CHANSPEC_CTL_SB_NONE; ++ chspec = (channel | band | bw | ctl_sb); ++ ext_join_params->assoc.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK; ++ ext_join_params->assoc.chanspec_list[0] |= chspec; ++ ext_join_params->assoc.chanspec_list[0] = ++ wl_chspec_host_to_driver(ext_join_params->assoc.chanspec_list[0]); ++ } ++ ext_join_params->assoc.chanspec_num = htod32(ext_join_params->assoc.chanspec_num); ++ if (ext_join_params->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) { ++ AP6211_DEBUG("ssid \"%s\", len (%d)\n", ext_join_params->ssid.SSID, ++ ext_join_params->ssid.SSID_len); ++ } ++ wl_set_drv_status(wl, CONNECTING, dev); ++ err = wldev_iovar_setbuf_bsscfg(dev, "join", ext_join_params, join_params_size, ++ wl->ioctl_buf, WLC_IOCTL_MAXLEN, wl_cfgp2p_find_idx(wl, dev), &wl->ioctl_buf_sync); ++ kfree(ext_join_params); ++ if (err) { ++ wl_clr_drv_status(wl, CONNECTING, dev); ++ if (err == BCME_UNSUPPORTED) { ++ AP6211_DEBUG("join iovar is not supported\n"); ++ goto set_ssid; ++ } else ++ AP6211_ERR("error (%d)\n", err); ++ } else ++ goto exit; ++ ++set_ssid: ++ memset(&join_params, 0, sizeof(join_params)); ++ join_params_size = sizeof(join_params.ssid); ++ ++ join_params.ssid.SSID_len = min(sizeof(join_params.ssid.SSID), sme->ssid_len); ++ memcpy(&join_params.ssid.SSID, sme->ssid, join_params.ssid.SSID_len); ++ join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len); ++ wl_update_prof(wl, dev, NULL, &join_params.ssid, WL_PROF_SSID); ++ if (sme->bssid) ++ memcpy(&join_params.params.bssid, sme->bssid, ETH_ALEN); ++ else ++ memcpy(&join_params.params.bssid, ðer_bcast, ETH_ALEN); ++ ++ wl_ch_to_chanspec(wl->channel, &join_params, &join_params_size); ++ AP6211_DEBUG("join_param_size %d\n", join_params_size); ++ ++ if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) { ++ AP6211_DEBUG("ssid \"%s\", len (%d)\n", join_params.ssid.SSID, ++ join_params.ssid.SSID_len); ++ } ++ wl_set_drv_status(wl, CONNECTING, dev); ++ err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size, true); ++ if (err) { ++ AP6211_ERR("error (%d)\n", err); ++ wl_clr_drv_status(wl, CONNECTING, dev); ++ } ++exit: ++ return err; ++} ++ ++static s32 ++wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, ++ u16 reason_code) ++{ ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ scb_val_t scbval; ++ bool act = false; ++ s32 err = 0; ++ u8 *curbssid; ++ AP6211_ERR("Reason %d\n", reason_code); ++ CHECK_SYS_UP(wl); ++ act = *(bool *) wl_read_prof(wl, dev, WL_PROF_ACT); ++ curbssid = wl_read_prof(wl, dev, WL_PROF_BSSID); ++ if (act) { ++ /* ++ * Cancel ongoing scan to sync up with sme state machine of cfg80211. ++ */ ++#if !defined(ESCAN_RESULT_PATCH) ++ /* Let scan aborted by F/W */ ++ if (wl->scan_request) { ++ wl_notify_escan_complete(wl, dev, true, true); ++ } ++#endif /* ESCAN_RESULT_PATCH */ ++ wl_set_drv_status(wl, DISCONNECTING, dev); ++ scbval.val = reason_code; ++ memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); ++ scbval.val = htod32(scbval.val); ++ err = wldev_ioctl(dev, WLC_DISASSOC, &scbval, ++ sizeof(scb_val_t), true); ++ if (unlikely(err)) { ++ wl_clr_drv_status(wl, DISCONNECTING, dev); ++ AP6211_ERR("error (%d)\n", err); ++ return err; ++ } ++ } ++ ++ return err; ++} ++ ++static s32 ++wl_cfg80211_set_tx_power(struct wiphy *wiphy, ++ enum nl80211_tx_power_setting type, s32 dbm) ++{ ++ ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ struct net_device *ndev = wl_to_prmry_ndev(wl); ++ u16 txpwrmw; ++ s32 err = 0; ++ s32 disable = 0; ++ ++ CHECK_SYS_UP(wl); ++ switch (type) { ++ case NL80211_TX_POWER_AUTOMATIC: ++ break; ++ case NL80211_TX_POWER_LIMITED: ++ if (dbm < 0) { ++ AP6211_ERR("TX_POWER_LIMITTED - dbm is negative\n"); ++ return -EINVAL; ++ } ++ break; ++ case NL80211_TX_POWER_FIXED: ++ if (dbm < 0) { ++ AP6211_ERR("TX_POWER_FIXED - dbm is negative..\n"); ++ return -EINVAL; ++ } ++ break; ++ } ++ /* Make sure radio is off or on as far as software is concerned */ ++ disable = WL_RADIO_SW_DISABLE << 16; ++ disable = htod32(disable); ++ err = wldev_ioctl(ndev, WLC_SET_RADIO, &disable, sizeof(disable), true); ++ if (unlikely(err)) { ++ AP6211_ERR("WLC_SET_RADIO error (%d)\n", err); ++ return err; ++ } ++ ++ if (dbm > 0xffff) ++ txpwrmw = 0xffff; ++ else ++ txpwrmw = (u16) dbm; ++ err = wldev_iovar_setint(ndev, "qtxpower", ++ (s32) (bcm_mw_to_qdbm(txpwrmw))); ++ if (unlikely(err)) { ++ AP6211_ERR("qtxpower error (%d)\n", err); ++ return err; ++ } ++ wl->conf->tx_power = dbm; ++ ++ return err; ++} ++ ++static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm) ++{ ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ struct net_device *ndev = wl_to_prmry_ndev(wl); ++ s32 txpwrdbm; ++ u8 result; ++ s32 err = 0; ++ ++ CHECK_SYS_UP(wl); ++ err = wldev_iovar_getint(ndev, "qtxpower", &txpwrdbm); ++ if (unlikely(err)) { ++ AP6211_ERR("error (%d)\n", err); ++ return err; ++ } ++ result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE); ++ *dbm = (s32) bcm_qdbm_to_mw(result); ++ ++ return err; ++} ++ ++static s32 ++wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev, ++ u8 key_idx, bool unicast, bool multicast) ++{ ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ u32 index; ++ s32 wsec; ++ s32 err = 0; ++ s32 bssidx = wl_cfgp2p_find_idx(wl, dev); ++ ++ AP6211_DEBUG("key index (%d)\n", key_idx); ++ CHECK_SYS_UP(wl); ++ err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx); ++ if (unlikely(err)) { ++ AP6211_ERR("WLC_GET_WSEC error (%d)\n", err); ++ return err; ++ } ++ if (wsec & WEP_ENABLED) { ++ /* Just select a new current key */ ++ index = (u32) key_idx; ++ index = htod32(index); ++ err = wldev_ioctl(dev, WLC_SET_KEY_PRIMARY, &index, ++ sizeof(index), true); ++ if (unlikely(err)) { ++ AP6211_ERR("error (%d)\n", err); ++ } ++ } ++ return err; ++} ++ ++static s32 ++wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, ++ u8 key_idx, const u8 *mac_addr, struct key_params *params) ++{ ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ struct wl_wsec_key key; ++ s32 err = 0; ++ s32 bssidx = wl_cfgp2p_find_idx(wl, dev); ++ s32 mode = wl_get_mode_by_netdev(wl, dev); ++ memset(&key, 0, sizeof(key)); ++ key.index = (u32) key_idx; ++ ++ if (!ETHER_ISMULTI(mac_addr)) ++ memcpy((char *)&key.ea, (void *)mac_addr, ETHER_ADDR_LEN); ++ key.len = (u32) params->key_len; ++ ++ /* check for key index change */ ++ if (key.len == 0) { ++ /* key delete */ ++ swap_key_from_BE(&key); ++ err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ++ wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); ++ if (unlikely(err)) { ++ AP6211_ERR("key delete error (%d)\n", err); ++ return err; ++ } ++ } else { ++ if (key.len > sizeof(key.data)) { ++ AP6211_ERR("Invalid key length (%d)\n", key.len); ++ return -EINVAL; ++ } ++ AP6211_DEBUG("Setting the key index %d\n", key.index); ++ memcpy(key.data, params->key, key.len); ++ ++ if ((mode == WL_MODE_BSS) && ++ (params->cipher == WLAN_CIPHER_SUITE_TKIP)) { ++ u8 keybuf[8]; ++ memcpy(keybuf, &key.data[24], sizeof(keybuf)); ++ memcpy(&key.data[24], &key.data[16], sizeof(keybuf)); ++ memcpy(&key.data[16], keybuf, sizeof(keybuf)); ++ } ++ ++ /* if IW_ENCODE_EXT_RX_SEQ_VALID set */ ++ if (params->seq && params->seq_len == 6) { ++ /* rx iv */ ++ u8 *ivptr; ++ ivptr = (u8 *) params->seq; ++ key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) | ++ (ivptr[3] << 8) | ivptr[2]; ++ key.rxiv.lo = (ivptr[1] << 8) | ivptr[0]; ++ key.iv_initialized = true; ++ } ++ ++ switch (params->cipher) { ++ case WLAN_CIPHER_SUITE_WEP40: ++ key.algo = CRYPTO_ALGO_WEP1; ++ AP6211_DEBUG("WLAN_CIPHER_SUITE_WEP40\n"); ++ break; ++ case WLAN_CIPHER_SUITE_WEP104: ++ key.algo = CRYPTO_ALGO_WEP128; ++ AP6211_DEBUG("WLAN_CIPHER_SUITE_WEP104\n"); ++ break; ++ case WLAN_CIPHER_SUITE_TKIP: ++ key.algo = CRYPTO_ALGO_TKIP; ++ AP6211_DEBUG("WLAN_CIPHER_SUITE_TKIP\n"); ++ break; ++ case WLAN_CIPHER_SUITE_AES_CMAC: ++ key.algo = CRYPTO_ALGO_AES_CCM; ++ AP6211_DEBUG("WLAN_CIPHER_SUITE_AES_CMAC\n"); ++ break; ++ case WLAN_CIPHER_SUITE_CCMP: ++ key.algo = CRYPTO_ALGO_AES_CCM; ++ AP6211_DEBUG("WLAN_CIPHER_SUITE_CCMP\n"); ++ break; ++#ifdef BCMWAPI_WPI ++ case WLAN_CIPHER_SUITE_SMS4: ++ key.algo = CRYPTO_ALGO_SMS4; ++ AP6211_DEBUG("WLAN_CIPHER_SUITE_SMS4\n"); ++ break; ++#endif ++ default: ++ AP6211_ERR("Invalid cipher (0x%x)\n", params->cipher); ++ return -EINVAL; ++ } ++ swap_key_from_BE(&key); ++ /* need to guarantee EAPOL 4/4 send out before set key */ ++ dhd_wait_pend8021x(dev); ++ err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ++ wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); ++ if (unlikely(err)) { ++ AP6211_ERR("WLC_SET_KEY error (%d)\n", err); ++ return err; ++ } ++ } ++ return err; ++} ++ ++static s32 ++wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, ++ u8 key_idx, bool pairwise, const u8 *mac_addr, ++ struct key_params *params) ++{ ++ struct wl_wsec_key key; ++ s32 val = 0; ++ s32 wsec = 0; ++ s32 err = 0; ++ u8 keybuf[8]; ++ s32 bssidx = 0; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ s32 mode = wl_get_mode_by_netdev(wl, dev); ++ AP6211_DEBUG("key index (%d)\n", key_idx); ++ CHECK_SYS_UP(wl); ++ ++ bssidx = wl_cfgp2p_find_idx(wl, dev); ++ ++ if (mac_addr) { ++ wl_add_keyext(wiphy, dev, key_idx, mac_addr, params); ++ goto exit; ++ } ++ memset(&key, 0, sizeof(key)); ++ ++ key.len = (u32) params->key_len; ++ key.index = (u32) key_idx; ++ ++ if (unlikely(key.len > sizeof(key.data))) { ++ AP6211_ERR("Too long key length (%u)\n", key.len); ++ return -EINVAL; ++ } ++ memcpy(key.data, params->key, key.len); ++ ++ key.flags = WL_PRIMARY_KEY; ++ switch (params->cipher) { ++ case WLAN_CIPHER_SUITE_WEP40: ++ key.algo = CRYPTO_ALGO_WEP1; ++ val = WEP_ENABLED; ++ AP6211_DEBUG("WLAN_CIPHER_SUITE_WEP40\n"); ++ break; ++ case WLAN_CIPHER_SUITE_WEP104: ++ key.algo = CRYPTO_ALGO_WEP128; ++ val = WEP_ENABLED; ++ AP6211_DEBUG("WLAN_CIPHER_SUITE_WEP104\n"); ++ break; ++ case WLAN_CIPHER_SUITE_TKIP: ++ key.algo = CRYPTO_ALGO_TKIP; ++ val = TKIP_ENABLED; ++ /* wpa_supplicant switches the third and fourth quarters of the TKIP key */ ++ if (mode == WL_MODE_BSS) { ++ bcopy(&key.data[24], keybuf, sizeof(keybuf)); ++ bcopy(&key.data[16], &key.data[24], sizeof(keybuf)); ++ bcopy(keybuf, &key.data[16], sizeof(keybuf)); ++ } ++ AP6211_DEBUG("WLAN_CIPHER_SUITE_TKIP\n"); ++ break; ++ case WLAN_CIPHER_SUITE_AES_CMAC: ++ key.algo = CRYPTO_ALGO_AES_CCM; ++ val = AES_ENABLED; ++ AP6211_DEBUG("WLAN_CIPHER_SUITE_AES_CMAC\n"); ++ break; ++ case WLAN_CIPHER_SUITE_CCMP: ++ key.algo = CRYPTO_ALGO_AES_CCM; ++ val = AES_ENABLED; ++ AP6211_DEBUG("WLAN_CIPHER_SUITE_CCMP\n"); ++ break; ++#ifdef BCMWAPI_WPI ++ case WLAN_CIPHER_SUITE_SMS4: ++ key.algo = CRYPTO_ALGO_SMS4; ++ val = SMS4_ENABLED; ++ AP6211_DEBUG(" * wl_cfg80211_add_key, set key " ++ " to WLAN_CIPHER_SUITE_SMS4\n"); ++ break; ++#endif /* BCMWAPI_WPI */ ++ default: ++ AP6211_ERR("Invalid cipher (0x%x)\n", params->cipher); ++ return -EINVAL; ++ } ++ ++ /* Set the new key/index */ ++ swap_key_from_BE(&key); ++ err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), wl->ioctl_buf, ++ WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); ++ if (unlikely(err)) { ++ AP6211_ERR("WLC_SET_KEY error (%d)\n", err); ++ return err; ++ } ++ ++exit: ++ err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx); ++ if (unlikely(err)) { ++ AP6211_ERR("get wsec error (%d)\n", err); ++ return err; ++ } ++ ++ wsec |= val; ++ err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx); ++ if (unlikely(err)) { ++ AP6211_ERR("set wsec error (%d)\n", err); ++ return err; ++ } ++ ++ return err; ++} ++ ++static s32 ++wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, ++ u8 key_idx, bool pairwise, const u8 *mac_addr) ++{ ++ struct wl_wsec_key key; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ s32 err = 0; ++ s32 bssidx = wl_cfgp2p_find_idx(wl, dev); ++ ++ AP6211_DEBUG("Enter\n"); ++#ifndef IEEE80211W ++ if ((key_idx >= DOT11_MAX_DEFAULT_KEYS) && (key_idx < DOT11_MAX_DEFAULT_KEYS+2)) ++ return -EINVAL; ++#endif ++ CHECK_SYS_UP(wl); ++ memset(&key, 0, sizeof(key)); ++ ++ key.flags = WL_PRIMARY_KEY; ++ key.algo = CRYPTO_ALGO_OFF; ++ key.index = (u32) key_idx; ++ ++ AP6211_DEBUG("key index (%d)\n", key_idx); ++ /* Set the new key/index */ ++ swap_key_from_BE(&key); ++ err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), wl->ioctl_buf, ++ WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); ++ if (unlikely(err)) { ++ if (err == -EINVAL) { ++ if (key.index >= DOT11_MAX_DEFAULT_KEYS) { ++ /* we ignore this key index in this case */ ++ AP6211_DEBUG("invalid key index (%d)\n", key_idx); ++ } ++ } else { ++ AP6211_ERR("WLC_SET_KEY error (%d)\n", err); ++ } ++ return err; ++ } ++ return err; ++} ++ ++static s32 ++wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, ++ u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie, ++ void (*callback) (void *cookie, struct key_params * params)) ++{ ++ struct key_params params; ++ struct wl_wsec_key key; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ struct wl_security *sec; ++ s32 wsec; ++ s32 err = 0; ++ s32 bssidx = wl_cfgp2p_find_idx(wl, dev); ++ ++ AP6211_DEBUG("key index (%d)\n", key_idx); ++ CHECK_SYS_UP(wl); ++ memset(&key, 0, sizeof(key)); ++ key.index = key_idx; ++ swap_key_to_BE(&key); ++ memset(¶ms, 0, sizeof(params)); ++ params.key_len = (u8) min_t(u8, DOT11_MAX_KEY_SIZE, key.len); ++ memcpy(params.key, key.data, params.key_len); ++ ++ wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx); ++ if (unlikely(err)) { ++ AP6211_ERR("WLC_GET_WSEC error (%d)\n", err); ++ return err; ++ } ++ switch (wsec & ~SES_OW_ENABLED) { ++ case WEP_ENABLED: ++ sec = wl_read_prof(wl, dev, WL_PROF_SEC); ++ if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) { ++ params.cipher = WLAN_CIPHER_SUITE_WEP40; ++ AP6211_DEBUG("WLAN_CIPHER_SUITE_WEP40\n"); ++ } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) { ++ params.cipher = WLAN_CIPHER_SUITE_WEP104; ++ AP6211_DEBUG("WLAN_CIPHER_SUITE_WEP104\n"); ++ } ++ break; ++ case TKIP_ENABLED: ++ params.cipher = WLAN_CIPHER_SUITE_TKIP; ++ AP6211_DEBUG("WLAN_CIPHER_SUITE_TKIP\n"); ++ break; ++ case AES_ENABLED: ++ params.cipher = WLAN_CIPHER_SUITE_AES_CMAC; ++ AP6211_DEBUG("WLAN_CIPHER_SUITE_AES_CMAC\n"); ++ break; ++#ifdef BCMWAPI_WPI ++ case WLAN_CIPHER_SUITE_SMS4: ++ key.algo = CRYPTO_ALGO_SMS4; ++ AP6211_DEBUG(" * wl_cfg80211_add_key, set key" ++ "to WLAN_CIPHER_SUITE_SMS4\n"); ++ break; ++#endif ++ default: ++ AP6211_ERR("Invalid algo (0x%x)\n", wsec); ++ return -EINVAL; ++ } ++ ++ callback(cookie, ¶ms); ++ return err; ++} ++ ++static s32 ++wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, ++ struct net_device *dev, u8 key_idx) ++{ ++ AP6211_DEBUG("Not supported\n"); ++ return -EOPNOTSUPP; ++} ++ ++static s32 ++wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, ++ u8 *mac, struct station_info *sinfo) ++{ ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ scb_val_t scb_val; ++ s32 rssi; ++ s32 rate; ++ s32 err = 0; ++ sta_info_t *sta; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) ++ s8 eabuf[ETHER_ADDR_STR_LEN]; ++#endif ++ dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); ++ CHECK_SYS_UP(wl); ++ if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_AP) { ++ err = wldev_iovar_getbuf(dev, "sta_info", (struct ether_addr *)mac, ++ ETHER_ADDR_LEN, wl->ioctl_buf, WLC_IOCTL_SMLEN, &wl->ioctl_buf_sync); ++ if (err < 0) { ++ AP6211_ERR("GET STA INFO failed, %d\n", err); ++ return err; ++ } ++ sinfo->filled = STATION_INFO_INACTIVE_TIME; ++ sta = (sta_info_t *)wl->ioctl_buf; ++ sta->len = dtoh16(sta->len); ++ sta->cap = dtoh16(sta->cap); ++ sta->flags = dtoh32(sta->flags); ++ sta->idle = dtoh32(sta->idle); ++ sta->in = dtoh32(sta->in); ++ sinfo->inactive_time = sta->idle * 1000; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) ++ if (sta->flags & WL_STA_ASSOC) { ++ sinfo->filled |= STATION_INFO_CONNECTED_TIME; ++ sinfo->connected_time = sta->in; ++ } ++ AP6211_DEBUG("STA %s : idle time : %d sec, connected time :%d ms\n", ++ bcm_ether_ntoa((const struct ether_addr *)mac, eabuf), sinfo->inactive_time, ++ sta->idle * 1000); ++#endif ++ } else if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_BSS) { ++ get_pktcnt_t pktcnt; ++ u8 *curmacp = wl_read_prof(wl, dev, WL_PROF_BSSID); ++ if (!wl_get_drv_status(wl, CONNECTED, dev) || ++ (dhd_is_associated(dhd, NULL, &err) == FALSE)) { ++ AP6211_ERR("NOT assoc\n"); ++ if (err == -ERESTARTSYS) ++ return err; ++ err = -ENODEV; ++ return err; ++ } ++ if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) { ++ AP6211_ERR("Wrong Mac address: "MACDBG" != "MACDBG"\n", ++ MAC2STRDBG(mac), MAC2STRDBG(curmacp)); ++ } ++ ++ /* Report the current tx rate */ ++ err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), false); ++ if (err) { ++ AP6211_ERR("Could not get rate (%d)\n", err); ++ } else { ++ rate = dtoh32(rate); ++ sinfo->filled |= STATION_INFO_TX_BITRATE; ++ sinfo->txrate.legacy = rate * 5; ++ AP6211_DEBUG("Rate %d Mbps\n", (rate / 2)); ++ } ++ ++ memset(&scb_val, 0, sizeof(scb_val)); ++ scb_val.val = 0; ++ err = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val, ++ sizeof(scb_val_t), false); ++ if (err) { ++ AP6211_ERR("Could not get rssi (%d)\n", err); ++ goto get_station_err; ++ } ++ rssi = dtoh32(scb_val.val); ++#if defined(RSSIOFFSET) ++ rssi = wl_update_rssi_offset(rssi); ++#endif ++ sinfo->filled |= STATION_INFO_SIGNAL; ++ sinfo->signal = rssi; ++ AP6211_DEBUG("RSSI %d dBm\n", rssi); ++ err = wldev_ioctl(dev, WLC_GET_PKTCNTS, &pktcnt, ++ sizeof(pktcnt), false); ++ if (!err) { ++ sinfo->filled |= (STATION_INFO_RX_PACKETS | ++ STATION_INFO_RX_DROP_MISC | ++ STATION_INFO_TX_PACKETS | ++ STATION_INFO_TX_FAILED); ++ sinfo->rx_packets = pktcnt.rx_good_pkt; ++ sinfo->rx_dropped_misc = pktcnt.rx_bad_pkt; ++ sinfo->tx_packets = pktcnt.tx_good_pkt; ++ sinfo->tx_failed = pktcnt.tx_bad_pkt; ++ } ++get_station_err: ++ if (err && (err != -ERESTARTSYS)) { ++ /* Disconnect due to zero BSSID or error to get RSSI */ ++ AP6211_ERR("force cfg80211_disconnected\n"); ++ wl_clr_drv_status(wl, CONNECTED, dev); ++ cfg80211_disconnected(dev, 0, NULL, 0, GFP_KERNEL); ++ wl_link_down(wl); ++ } ++ } ++ ++ return err; ++} ++ ++/* Function to update sta power save mode for Kernel wifi stack */ ++int wl_cfg80211_update_power_mode(struct net_device *dev) ++{ ++ int pm = -1; ++ int err; ++ ++ err = wldev_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm), false); ++ if (err || (pm == -1)) { ++ AP6211_ERR("error (%d)\n", err); ++ } else { ++ pm = (pm == PM_OFF) ? false : true; ++ AP6211_DEBUG("%s: %d\n", __func__, pm); ++ if (dev->ieee80211_ptr) ++ dev->ieee80211_ptr->ps = pm; ++ } ++ return err; ++} ++ ++static s32 ++wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, ++ bool enabled, s32 timeout) ++{ ++ s32 pm; ++ s32 err = 0; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ struct net_info *_net_info = wl_get_netinfo_by_netdev(wl, dev); ++#if !defined(SUPPORT_PM2_ONLY) ++ dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); ++#endif /* (OEM_ANDROID) */ ++ CHECK_SYS_UP(wl); ++ ++ if (wl->p2p_net == dev || _net_info == NULL) { ++ return err; ++ } ++ AP6211_DEBUG("%s: Enter power save enabled %d\n", dev->name, enabled); ++ ++#if !defined(SUPPORT_PM2_ONLY) ++ /* android has special hooks to change pm when kernel suspended */ ++ pm = enabled ? ((dhd->in_suspend) ? PM_MAX : PM_FAST) : PM_OFF; ++#else ++ pm = enabled ? PM_FAST : PM_OFF; ++#endif /* SUPPORT_PM2_ONLY */ ++ ++ if (_net_info->pm_block || wl->vsdb_mode) { ++ /* Do not enable the power save if it is p2p interface or vsdb mode is set */ ++ AP6211_DEBUG("%s:Do not enable the power save for pm_block %d or vsdb_mode %d\n", ++ dev->name, _net_info->pm_block, wl->vsdb_mode); ++ pm = PM_OFF; ++ } ++ pm = htod32(pm); ++ AP6211_DEBUG("%s:power save %s\n", dev->name, (pm ? "enabled" : "disabled")); ++ err = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), true); ++ if (unlikely(err)) { ++ if (err == -ENODEV) ++ AP6211_DEBUG("net_device is not ready yet\n"); ++ else ++ AP6211_ERR("error (%d)\n", err); ++ return err; ++ } ++ return err; ++} ++ ++static __used u32 wl_find_msb(u16 bit16) ++{ ++ u32 ret = 0; ++ ++ if (bit16 & 0xff00) { ++ ret += 8; ++ bit16 >>= 8; ++ } ++ ++ if (bit16 & 0xf0) { ++ ret += 4; ++ bit16 >>= 4; ++ } ++ ++ if (bit16 & 0xc) { ++ ret += 2; ++ bit16 >>= 2; ++ } ++ ++ if (bit16 & 2) ++ ret += bit16 & 2; ++ else if (bit16) ++ ret += bit16; ++ ++ return ret; ++} ++ ++static s32 wl_cfg80211_resume(struct wiphy *wiphy) ++{ ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ struct net_device *ndev = wl_to_prmry_ndev(wl); ++ s32 err = 0; ++ ++ if (unlikely(!wl_get_drv_status(wl, READY, ndev))) { ++ AP6211_DEBUG("device is not ready\n"); ++ return 0; ++ } ++ ++ wl_invoke_iscan(wl); ++ ++ return err; ++} ++ ++static s32 ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39) ++wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow) ++#else ++wl_cfg80211_suspend(struct wiphy *wiphy) ++#endif ++{ ++#ifdef DHD_CLEAR_ON_SUSPEND ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ struct net_info *iter, *next; ++ struct net_device *ndev = wl_to_prmry_ndev(wl); ++ unsigned long flags; ++ if (unlikely(!wl_get_drv_status(wl, READY, ndev))) { ++ AP6211_DEBUG("device is not ready : status (%d)\n", ++ (int)wl->status); ++ return 0; ++ } ++ for_each_ndev(wl, iter, next) ++ wl_set_drv_status(wl, SCAN_ABORTING, iter->ndev); ++ wl_term_iscan(wl); ++ spin_lock_irqsave(&wl->cfgdrv_lock, flags); ++ if (wl->scan_request) { ++ cfg80211_scan_done(wl->scan_request, true); ++ wl->scan_request = NULL; ++ } ++ for_each_ndev(wl, iter, next) { ++ wl_clr_drv_status(wl, SCANNING, iter->ndev); ++ wl_clr_drv_status(wl, SCAN_ABORTING, iter->ndev); ++ } ++ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); ++ for_each_ndev(wl, iter, next) { ++ if (wl_get_drv_status(wl, CONNECTING, iter->ndev)) { ++ wl_bss_connect_done(wl, iter->ndev, NULL, NULL, false); ++ } ++ } ++#endif /* DHD_CLEAR_ON_SUSPEND */ ++ return 0; ++} ++ ++static s32 ++wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list, ++ s32 err) ++{ ++ int i, j; ++ struct wl_priv *wl = wlcfg_drv_priv; ++ struct net_device *primary_dev = wl_to_prmry_ndev(wl); ++ ++ if (!pmk_list) { ++ AP6211_DEBUG("pmk_list is NULL\n"); ++ return -EINVAL; ++ } ++ /* pmk list is supported only for STA interface i.e. primary interface ++ * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init ++ */ ++ if (primary_dev != dev) { ++ AP6211_DEBUG("Not supporting Flushing pmklist on virtual" ++ " interfaces than primary interface\n"); ++ return err; ++ } ++ ++ AP6211_DEBUG("No of elements %d\n", pmk_list->pmkids.npmkid); ++ for (i = 0; i < pmk_list->pmkids.npmkid; i++) { ++ AP6211_DEBUG("PMKID[%d]: %pM =\n", i, ++ &pmk_list->pmkids.pmkid[i].BSSID); ++ for (j = 0; j < WPA2_PMKID_LEN; j++) { ++ AP6211_DEBUG("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j]); ++ } ++ } ++ if (likely(!err)) { ++ err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmk_list, ++ sizeof(*pmk_list), wl->ioctl_buf, WLC_IOCTL_MAXLEN, NULL); ++ } ++ ++ return err; ++} ++ ++static s32 ++wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev, ++ struct cfg80211_pmksa *pmksa) ++{ ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ s32 err = 0; ++ int i; ++ ++ CHECK_SYS_UP(wl); ++ for (i = 0; i < wl->pmk_list->pmkids.npmkid; i++) ++ if (!memcmp(pmksa->bssid, &wl->pmk_list->pmkids.pmkid[i].BSSID, ++ ETHER_ADDR_LEN)) ++ break; ++ if (i < WL_NUM_PMKIDS_MAX) { ++ memcpy(&wl->pmk_list->pmkids.pmkid[i].BSSID, pmksa->bssid, ++ ETHER_ADDR_LEN); ++ memcpy(&wl->pmk_list->pmkids.pmkid[i].PMKID, pmksa->pmkid, ++ WPA2_PMKID_LEN); ++ if (i == wl->pmk_list->pmkids.npmkid) ++ wl->pmk_list->pmkids.npmkid++; ++ } else { ++ err = -EINVAL; ++ } ++ AP6211_DEBUG("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n", ++ &wl->pmk_list->pmkids.pmkid[wl->pmk_list->pmkids.npmkid - 1].BSSID); ++ for (i = 0; i < WPA2_PMKID_LEN; i++) { ++ AP6211_DEBUG("%02x\n", ++ wl->pmk_list->pmkids.pmkid[wl->pmk_list->pmkids.npmkid - 1]. ++ PMKID[i]); ++ } ++ ++ err = wl_update_pmklist(dev, wl->pmk_list, err); ++ ++ return err; ++} ++ ++static s32 ++wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, ++ struct cfg80211_pmksa *pmksa) ++{ ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ struct _pmkid_list pmkid; ++ s32 err = 0; ++ int i; ++ ++ CHECK_SYS_UP(wl); ++ memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETHER_ADDR_LEN); ++ memcpy(pmkid.pmkid[0].PMKID, pmksa->pmkid, WPA2_PMKID_LEN); ++ ++ AP6211_DEBUG("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n", ++ &pmkid.pmkid[0].BSSID); ++ for (i = 0; i < WPA2_PMKID_LEN; i++) { ++ AP6211_DEBUG("%02x\n", pmkid.pmkid[0].PMKID[i]); ++ } ++ ++ for (i = 0; i < wl->pmk_list->pmkids.npmkid; i++) ++ if (!memcmp ++ (pmksa->bssid, &wl->pmk_list->pmkids.pmkid[i].BSSID, ++ ETHER_ADDR_LEN)) ++ break; ++ ++ if ((wl->pmk_list->pmkids.npmkid > 0) && ++ (i < wl->pmk_list->pmkids.npmkid)) { ++ memset(&wl->pmk_list->pmkids.pmkid[i], 0, sizeof(pmkid_t)); ++ for (; i < (wl->pmk_list->pmkids.npmkid - 1); i++) { ++ memcpy(&wl->pmk_list->pmkids.pmkid[i].BSSID, ++ &wl->pmk_list->pmkids.pmkid[i + 1].BSSID, ++ ETHER_ADDR_LEN); ++ memcpy(&wl->pmk_list->pmkids.pmkid[i].PMKID, ++ &wl->pmk_list->pmkids.pmkid[i + 1].PMKID, ++ WPA2_PMKID_LEN); ++ } ++ wl->pmk_list->pmkids.npmkid--; ++ } else { ++ err = -EINVAL; ++ } ++ ++ err = wl_update_pmklist(dev, wl->pmk_list, err); ++ ++ return err; ++ ++} ++ ++static s32 ++wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev) ++{ ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ s32 err = 0; ++ CHECK_SYS_UP(wl); ++ memset(wl->pmk_list, 0, sizeof(*wl->pmk_list)); ++ err = wl_update_pmklist(dev, wl->pmk_list, err); ++ return err; ++ ++} ++ ++static wl_scan_params_t * ++wl_cfg80211_scan_alloc_params(int channel, int nprobes, int *out_params_size) ++{ ++ wl_scan_params_t *params; ++ int params_size; ++ int num_chans; ++ ++ *out_params_size = 0; ++ ++ /* Our scan params only need space for 1 channel and 0 ssids */ ++ params_size = WL_SCAN_PARAMS_FIXED_SIZE + 1 * sizeof(uint16); ++ params = (wl_scan_params_t*) kzalloc(params_size, GFP_KERNEL); ++ if (params == NULL) { ++ AP6211_ERR("%s: mem alloc failed (%d bytes)\n", __func__, params_size); ++ return params; ++ } ++ memset(params, 0, params_size); ++ params->nprobes = nprobes; ++ ++ num_chans = (channel == 0) ? 0 : 1; ++ ++ memcpy(¶ms->bssid, ðer_bcast, ETHER_ADDR_LEN); ++ params->bss_type = DOT11_BSSTYPE_ANY; ++ params->scan_type = DOT11_SCANTYPE_ACTIVE; ++ params->nprobes = htod32(1); ++ params->active_time = htod32(-1); ++ params->passive_time = htod32(-1); ++ params->home_time = htod32(10); ++ if (channel == -1) ++ params->channel_list[0] = htodchanspec(channel); ++ else ++ params->channel_list[0] = wl_ch_host_to_driver(channel); ++ ++ /* Our scan params have 1 channel and 0 ssids */ ++ params->channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) | ++ (num_chans & WL_SCAN_PARAMS_COUNT_MASK)); ++ ++ *out_params_size = params_size; /* rtn size to the caller */ ++ return params; ++} ++ ++static s32 ++wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, ++ struct ieee80211_channel * channel, ++ enum nl80211_channel_type channel_type, ++ unsigned int duration, u64 *cookie) ++{ ++ s32 target_channel; ++ u32 id; ++ struct ether_addr primary_mac; ++ struct net_device *ndev = NULL; ++ ++ s32 err = BCME_OK; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ ++ AP6211_DEBUG("Enter, ifindex: %d, channel: %d, duration ms (%d) SCANNING ?? %s \n", ++ dev->ifindex, ieee80211_frequency_to_channel(channel->center_freq), ++ duration, (wl_get_drv_status(wl, SCANNING, ndev)) ? "YES":"NO"); ++ ++ if (wl->p2p_net == dev) { ++ ndev = wl_to_prmry_ndev(wl); ++ } else { ++ ndev = dev; ++ } ++ ++ if (!wl->p2p) { ++ AP6211_ERR("wl->p2p is not initialized\n"); ++ err = BCME_ERROR; ++ goto exit; ++ } ++ ++#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST ++ if (wl_get_drv_status(wl, SCANNING, ndev)) { ++ wl_notify_escan_complete(wl, ndev, true, true); ++ } ++#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ ++ ++ target_channel = ieee80211_frequency_to_channel(channel->center_freq); ++ memcpy(&wl->remain_on_chan, channel, sizeof(struct ieee80211_channel)); ++ wl->remain_on_chan_type = channel_type; ++ id = ++wl->last_roc_id; ++ if (id == 0) ++ id = ++wl->last_roc_id; ++ *cookie = id; ++ ++#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST ++ if (wl_get_drv_status(wl, SCANNING, ndev)) { ++ struct timer_list *_timer; ++ AP6211_DEBUG("scan is running. go to fake listen state\n"); ++ ++ wl_set_drv_status(wl, FAKE_REMAINING_ON_CHANNEL, ndev); ++ ++ if (timer_pending(&wl->p2p->listen_timer)) { ++ AP6211_DEBUG("cancel current listen timer \n"); ++ del_timer_sync(&wl->p2p->listen_timer); ++ } ++ ++ _timer = &wl->p2p->listen_timer; ++ wl_clr_p2p_status(wl, LISTEN_EXPIRED); ++ ++ INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration, 0); ++ ++ err = BCME_OK; ++ goto exit; ++ } ++#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ ++ ++#ifdef WL_CFG80211_SYNC_GON ++ if (wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM_LISTEN)) { ++ /* do not enter listen mode again if we are in listen mode already for next af. ++ * remain on channel completion will be returned by waiting next af completion. ++ */ ++#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST ++ wl_set_drv_status(wl, FAKE_REMAINING_ON_CHANNEL, ndev); ++#else ++ wl_set_drv_status(wl, REMAINING_ON_CHANNEL, ndev); ++#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ ++ goto exit; ++ } ++#endif /* WL_CFG80211_SYNC_GON */ ++ if (wl->p2p && !wl->p2p->on) { ++ /* In case of p2p_listen command, supplicant send remain_on_channel ++ * without turning on P2P ++ */ ++ get_primary_mac(wl, &primary_mac); ++ wl_cfgp2p_generate_bss_mac(&primary_mac, &wl->p2p->dev_addr, &wl->p2p->int_addr); ++ p2p_on(wl) = true; ++ } ++ ++ if (p2p_is_on(wl)) { ++ err = wl_cfgp2p_enable_discovery(wl, ndev, NULL, 0); ++ if (unlikely(err)) { ++ goto exit; ++ } ++#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST ++ wl_set_drv_status(wl, REMAINING_ON_CHANNEL, ndev); ++#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ ++ err = wl_cfgp2p_discover_listen(wl, target_channel, duration); ++ ++#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST ++ if (err == BCME_OK) { ++ wl_set_drv_status(wl, REMAINING_ON_CHANNEL, ndev); ++ } else { ++ /* if failed, firmware may be internal scanning state. ++ * so other scan request shall not abort it ++ */ ++ wl_set_drv_status(wl, FAKE_REMAINING_ON_CHANNEL, ndev); ++ } ++#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ ++ /* WAR: set err = ok to prevent cookie mismatch in wpa_supplicant ++ * and expire timer will send a completion to the upper layer ++ */ ++ err = BCME_OK; ++ } ++ ++exit: ++ if (err == BCME_OK) { ++ AP6211_DEBUG("Success\n"); ++ cfg80211_ready_on_channel(dev, *cookie, channel, ++ channel_type, duration, GFP_KERNEL); ++ } else { ++ AP6211_ERR("Fail to Set (err=%d cookie:%llu)\n", err, *cookie); ++ } ++ return err; ++} ++ ++static s32 ++wl_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, ++ u64 cookie) ++{ ++ s32 err = 0; ++ AP6211_DEBUG(" enter ) netdev_ifidx: %d \n", dev->ifindex); ++ return err; ++} ++ ++static void ++wl_cfg80211_afx_handler(struct work_struct *work) ++{ ++ struct afx_hdl *afx_instance; ++ struct wl_priv *wl = wlcfg_drv_priv; ++ s32 ret = BCME_OK; ++ ++ afx_instance = container_of(work, struct afx_hdl, work); ++ if (afx_instance != NULL && wl->afx_hdl->is_active) { ++ if (wl->afx_hdl->is_listen && wl->afx_hdl->my_listen_chan) { ++ ret = wl_cfgp2p_discover_listen(wl, wl->afx_hdl->my_listen_chan, ++ (100 * (1 + (random32() % 3)))); /* 100ms ~ 300ms */ ++ } else { ++ ret = wl_cfgp2p_act_frm_search(wl, wl->afx_hdl->dev, ++ wl->afx_hdl->bssidx, wl->afx_hdl->peer_listen_chan); ++ } ++ if (unlikely(ret != BCME_OK)) { ++ AP6211_ERR("ERROR occurred! returned value is (%d)\n", ret); ++ if (wl_get_drv_status_all(wl, FINDING_COMMON_CHANNEL)) ++ complete(&wl->act_frm_scan); ++ } ++ } ++} ++ ++static s32 ++wl_cfg80211_af_searching_channel(struct wl_priv *wl, struct net_device *dev) ++{ ++ u32 max_retry = WL_CHANNEL_SYNC_RETRY; ++ ++ if (dev == NULL) ++ return -1; ++ ++ AP6211_DEBUG(" enter ) \n"); ++ ++ wl_set_drv_status(wl, FINDING_COMMON_CHANNEL, dev); ++ wl->afx_hdl->is_active = TRUE; ++ ++ /* Loop to wait until we find a peer's channel or the ++ * pending action frame tx is cancelled. ++ */ ++ while ((wl->afx_hdl->retry < max_retry) && ++ (wl->afx_hdl->peer_chan == WL_INVALID)) { ++ wl->afx_hdl->is_listen = FALSE; ++ wl_set_drv_status(wl, SCANNING, dev); ++ AP6211_DEBUG("Scheduling the action frame for sending.. retry %d\n", ++ wl->afx_hdl->retry); ++ /* search peer on peer's listen channel */ ++ schedule_work(&wl->afx_hdl->work); ++ wait_for_completion_timeout(&wl->act_frm_scan, ++ msecs_to_jiffies(MAX_WAIT_TIME)); ++ ++ if ((wl->afx_hdl->peer_chan != WL_INVALID) || ++ !(wl_get_drv_status(wl, FINDING_COMMON_CHANNEL, dev))) ++ break; ++ ++ if (wl->afx_hdl->my_listen_chan) { ++ AP6211_DEBUG("Scheduling Listen peer in my listen channel = %d\n", ++ wl->afx_hdl->my_listen_chan); ++ /* listen on my listen channel */ ++ wl->afx_hdl->is_listen = TRUE; ++ schedule_work(&wl->afx_hdl->work); ++ wait_for_completion_timeout(&wl->act_frm_scan, ++ msecs_to_jiffies(MAX_WAIT_TIME)); ++ } ++ if (!wl_get_drv_status(wl, FINDING_COMMON_CHANNEL, dev)) ++ break; ++ wl->afx_hdl->retry++; ++ ++ WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(wl); ++ } ++ ++ wl->afx_hdl->is_active = FALSE; ++ ++ wl_clr_drv_status(wl, SCANNING, dev); ++ wl_clr_drv_status(wl, FINDING_COMMON_CHANNEL, dev); ++ ++ return (wl->afx_hdl->peer_chan); ++} ++ ++struct p2p_config_af_params { ++ s32 max_tx_retry; /* max tx retry count if tx no ack */ ++ /* To make sure to send successfully action frame, we have to turn off mpc ++ * 0: off, 1: on, (-1): do nothing ++ */ ++ s32 mpc_onoff; ++#ifdef WL_CFG80211_SYNC_GON ++ bool extra_listen; ++#endif ++ bool search_channel; /* 1: search peer's channel to send af */ ++}; ++ ++static s32 ++wl_cfg80211_config_p2p_pub_af_tx(struct wiphy *wiphy, ++ wl_action_frame_t *action_frame, wl_af_params_t *af_params, ++ struct p2p_config_af_params *config_af_params) ++{ ++ s32 err = BCME_OK; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ wifi_p2p_pub_act_frame_t *act_frm = ++ (wifi_p2p_pub_act_frame_t *) (action_frame->data); ++ ++ /* initialize default value */ ++#ifdef WL_CFG80211_SYNC_GON ++ config_af_params->extra_listen = true; ++#endif ++ config_af_params->search_channel = false; ++ config_af_params->max_tx_retry = WL_AF_TX_MAX_RETRY; ++ config_af_params->mpc_onoff = -1; ++ ++ switch (act_frm->subtype) { ++ case P2P_PAF_GON_REQ: { ++ AP6211_DEBUG("P2P: GO_NEG_PHASE status set \n"); ++ wl_set_p2p_status(wl, GO_NEG_PHASE); ++ ++ config_af_params->mpc_onoff = 0; ++ config_af_params->search_channel = true; ++ wl->next_af_subtype = act_frm->subtype + 1; ++ ++ /* increase dwell time to wait for RESP frame */ ++ af_params->dwell_time = WL_MED_DWELL_TIME; ++ ++ break; ++ } ++ case P2P_PAF_GON_RSP: { ++ wl->next_af_subtype = act_frm->subtype + 1; ++ /* increase dwell time to wait for CONF frame */ ++ af_params->dwell_time = WL_MED_DWELL_TIME; ++ break; ++ } ++ case P2P_PAF_GON_CONF: { ++ /* If we reached till GO Neg confirmation reset the filter */ ++ AP6211_DEBUG("P2P: GO_NEG_PHASE status cleared \n"); ++ wl_clr_p2p_status(wl, GO_NEG_PHASE); ++ ++ /* turn on mpc again if go nego is done */ ++ config_af_params->mpc_onoff = 1; ++ ++ /* minimize dwell time */ ++ af_params->dwell_time = WL_MIN_DWELL_TIME; ++ ++#ifdef WL_CFG80211_SYNC_GON ++ config_af_params->extra_listen = false; ++#endif /* WL_CFG80211_SYNC_GON */ ++ break; ++ } ++ case P2P_PAF_INVITE_REQ: { ++ config_af_params->search_channel = true; ++ wl->next_af_subtype = act_frm->subtype + 1; ++ ++ /* increase dwell time */ ++ af_params->dwell_time = WL_MED_DWELL_TIME; ++ break; ++ } ++ case P2P_PAF_INVITE_RSP: ++ /* minimize dwell time */ ++ af_params->dwell_time = WL_MIN_DWELL_TIME; ++#ifdef WL_CFG80211_SYNC_GON ++ config_af_params->extra_listen = false; ++#endif /* WL_CFG80211_SYNC_GON */ ++ break; ++ case P2P_PAF_DEVDIS_REQ: { ++ config_af_params->search_channel = true; ++ ++ wl->next_af_subtype = act_frm->subtype + 1; ++ /* maximize dwell time to wait for RESP frame */ ++ af_params->dwell_time = WL_LONG_DWELL_TIME; ++ break; ++ } ++ case P2P_PAF_DEVDIS_RSP: ++ /* minimize dwell time */ ++ af_params->dwell_time = WL_MIN_DWELL_TIME; ++#ifdef WL_CFG80211_SYNC_GON ++ config_af_params->extra_listen = false; ++#endif /* WL_CFG80211_SYNC_GON */ ++ break; ++ case P2P_PAF_PROVDIS_REQ: { ++ if (IS_PROV_DISC_WITHOUT_GROUP_ID(&act_frm->elts[0], ++ action_frame->len)) { ++ config_af_params->search_channel = true; ++ } ++ ++ config_af_params->mpc_onoff = 0; ++ wl->next_af_subtype = act_frm->subtype + 1; ++ /* increase dwell time to wait for RESP frame */ ++ af_params->dwell_time = WL_MED_DWELL_TIME; ++ break; ++ } ++ case P2P_PAF_PROVDIS_RSP: { ++ wl->next_af_subtype = P2P_PAF_GON_REQ; ++ /* increase dwell time to MED level */ ++ af_params->dwell_time = WL_MED_DWELL_TIME; ++#ifdef WL_CFG80211_SYNC_GON ++ config_af_params->extra_listen = false; ++#endif /* WL_CFG80211_SYNC_GON */ ++ break; ++ } ++ default: ++ AP6211_DEBUG("Unknown p2p pub act frame subtype: %d\n", ++ act_frm->subtype); ++ err = BCME_BADARG; ++ } ++ return err; ++} ++ ++ ++static bool ++wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev, ++ struct net_device *ndev, wl_af_params_t *af_params, ++ wl_action_frame_t *action_frame, u16 action_frame_len, s32 bssidx) ++{ ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ bool ack = false; ++ u8 category, action; ++ s32 tx_retry; ++ struct p2p_config_af_params config_af_params; ++#ifdef VSDB ++ ulong off_chan_started_jiffies = 0; ++#endif ++ dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); ++ ++ wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len); ++ ++ category = action_frame->data[DOT11_ACTION_CAT_OFF]; ++ action = action_frame->data[DOT11_ACTION_ACT_OFF]; ++ ++ /* initialize variables */ ++ tx_retry = 0; ++ wl->next_af_subtype = P2P_PAF_SUBTYPE_INVALID; ++ config_af_params.max_tx_retry = WL_AF_TX_MAX_RETRY; ++ config_af_params.mpc_onoff = -1; ++ config_af_params.search_channel = false; ++#ifdef WL_CFG80211_SYNC_GON ++ config_af_params.extra_listen = false; ++#endif ++ ++ /* config parameters */ ++ /* Public Action Frame Process - DOT11_ACTION_CAT_PUBLIC */ ++ if (category == DOT11_ACTION_CAT_PUBLIC) { ++ if ((action == P2P_PUB_AF_ACTION) && ++ (action_frame_len >= sizeof(wifi_p2p_pub_act_frame_t))) { ++ /* p2p public action frame process */ ++ if (BCME_OK != wl_cfg80211_config_p2p_pub_af_tx(wiphy, ++ action_frame, af_params, &config_af_params)) { ++ AP6211_DEBUG("Unknown subtype.\n"); ++ } ++ ++ } else if (action_frame_len >= sizeof(wifi_p2psd_gas_pub_act_frame_t)) { ++ /* service discovery process */ ++ if (action == P2PSD_ACTION_ID_GAS_IREQ || ++ action == P2PSD_ACTION_ID_GAS_CREQ) { ++ /* configure service discovery query frame */ ++ ++ config_af_params.search_channel = true; ++ ++ /* save next af suptype to cancel remained dwell time */ ++ wl->next_af_subtype = action + 1; ++ ++ af_params->dwell_time = WL_MED_DWELL_TIME; ++ } else if (action == P2PSD_ACTION_ID_GAS_IRESP || ++ action == P2PSD_ACTION_ID_GAS_CRESP) { ++ /* configure service discovery response frame */ ++ af_params->dwell_time = WL_MIN_DWELL_TIME; ++ } else { ++ AP6211_DEBUG("Unknown action type: %d\n", action); ++ } ++ } else { ++ AP6211_DEBUG("Unknown Frame: category 0x%x, action 0x%x, length %d\n", ++ category, action, action_frame_len); ++ } ++ } else if (category == P2P_AF_CATEGORY) { ++ /* do not configure anything. it will be sent with a default configuration */ ++ } else { ++ AP6211_DEBUG("Unknown Frame: category 0x%x, action 0x%x\n", ++ category, action); ++ if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { ++ wl_clr_drv_status(wl, SENDING_ACT_FRM, dev); ++ return false; ++ } ++ } ++ ++ /* To make sure to send successfully action frame, we have to turn off mpc */ ++ if (config_af_params.mpc_onoff == 0) { ++ wldev_iovar_setint(dev, "mpc", 0); ++ } ++ ++ /* validate channel and p2p ies */ ++ if (config_af_params.search_channel && IS_P2P_SOCIAL(af_params->channel) && ++ wl_to_p2p_bss_saved_ie(wl, P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len) { ++ config_af_params.search_channel = true; ++ } else { ++ config_af_params.search_channel = false; ++ } ++ ++#ifdef WL11U ++ if (ndev == wl_to_prmry_ndev(wl)) ++ config_af_params.search_channel = false; ++#endif /* WL11U */ ++ ++#ifdef VSDB ++ /* if connecting on primary iface, sleep for a while before sending af tx for VSDB */ ++ if (wl_get_drv_status(wl, CONNECTING, wl_to_prmry_ndev(wl))) { ++ msleep(50); ++ } ++#endif ++ ++ /* if scan is ongoing, abort current scan. */ ++ if (wl_get_drv_status_all(wl, SCANNING)) { ++ wl_notify_escan_complete(wl, ndev, true, true); ++ } ++ ++ /* set status and destination address before sending af */ ++ if (wl->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) { ++ /* set this status to cancel the remained dwell time in rx process */ ++ wl_set_drv_status(wl, WAITING_NEXT_ACT_FRM, dev); ++ } ++ wl_set_drv_status(wl, SENDING_ACT_FRM, dev); ++ memcpy(wl->afx_hdl->tx_dst_addr.octet, ++ af_params->action_frame.da.octet, ++ sizeof(wl->afx_hdl->tx_dst_addr.octet)); ++ ++ /* save af_params for rx process */ ++ wl->afx_hdl->pending_tx_act_frm = af_params; ++ ++ /* search peer's channel */ ++ if (config_af_params.search_channel) { ++ /* initialize afx_hdl */ ++ wl->afx_hdl->bssidx = wl_cfgp2p_find_idx(wl, dev); ++ wl->afx_hdl->dev = dev; ++ wl->afx_hdl->retry = 0; ++ wl->afx_hdl->peer_chan = WL_INVALID; ++ ++ if (wl_cfg80211_af_searching_channel(wl, dev) == WL_INVALID) { ++ AP6211_ERR("couldn't find peer's channel.\n"); ++ goto exit; ++ } ++ ++ /* Suspend P2P discovery's search-listen to prevent it from ++ * starting a scan or changing the channel. ++ */ ++ wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev); ++/* Do not abort scan for VSDB. Scan will be aborted in firmware if necessary */ ++#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST ++ wl_notify_escan_complete(wl, dev, true, true); ++#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ ++ wl_cfgp2p_discover_enable_search(wl, false); ++ ++ /* update channel */ ++ af_params->channel = wl->afx_hdl->peer_chan; ++ } ++ ++#ifdef VSDB ++ off_chan_started_jiffies = jiffies; ++#endif /* VSDB */ ++ ++ /* Now send a tx action frame */ ++ ack = wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx) ? false : true; ++ ++ /* if failed, retry it. tx_retry_max value is configure by .... */ ++ while ((ack == false) && (tx_retry++ < config_af_params.max_tx_retry)) { ++#ifdef VSDB ++ if (af_params->channel) { ++ if (jiffies_to_msecs(jiffies - off_chan_started_jiffies) > ++ OFF_CHAN_TIME_THRESHOLD_MS) { ++ WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(wl); ++ off_chan_started_jiffies = jiffies; ++ } ++ } ++#endif /* VSDB */ ++ ack = wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx) ? ++ false : true; ++ } ++ if (ack == false) { ++ AP6211_ERR("Failed to send Action Frame(retry %d)\n", tx_retry); ++ } ++exit: ++ /* Clear SENDING_ACT_FRM after all sending af is done */ ++ wl_clr_drv_status(wl, SENDING_ACT_FRM, dev); ++ ++#ifdef WL_CFG80211_SYNC_GON ++ /* WAR: sometimes dongle does not keep the dwell time of 'actframe'. ++ * if we coundn't get the next action response frame and dongle does not keep ++ * the dwell time, go to listen state again to get next action response frame. ++ */ ++ if (ack && config_af_params.extra_listen && ++ wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM) && ++ wl->af_sent_channel == wl->afx_hdl->my_listen_chan) { ++ s32 extar_listen_time; ++ ++ extar_listen_time = af_params->dwell_time - ++ jiffies_to_msecs(jiffies - wl->af_tx_sent_jiffies); ++ ++ if (extar_listen_time > 50) { ++ wl_set_drv_status(wl, WAITING_NEXT_ACT_FRM_LISTEN, dev); ++ AP6211_DEBUG("Wait more time! actual af time:%d," ++ "calculated extar listen:%d\n", ++ af_params->dwell_time, extar_listen_time); ++ if (wl_cfgp2p_discover_listen(wl, wl->af_sent_channel, ++ extar_listen_time + 100) == BCME_OK) { ++ wait_for_completion_timeout(&wl->wait_next_af, ++ msecs_to_jiffies(extar_listen_time + 100 + 300)); ++ } ++ wl_clr_drv_status(wl, WAITING_NEXT_ACT_FRM_LISTEN, dev); ++ } ++ } ++#endif /* WL_CFG80211_SYNC_GON */ ++ wl_clr_drv_status(wl, WAITING_NEXT_ACT_FRM, dev); ++ ++ if (wl->afx_hdl->pending_tx_act_frm) ++ wl->afx_hdl->pending_tx_act_frm = NULL; ++ ++ AP6211_DEBUG("-- sending Action Frame is %s, listen chan: %d\n", ++ (ack) ? "Succeeded!!":"Failed!!", wl->afx_hdl->my_listen_chan); ++ ++ ++ /* if all done, turn mpc on again */ ++ if (config_af_params.mpc_onoff == 1) { ++ wldev_iovar_setint(dev, "mpc", 1); ++ } ++ ++ return ack; ++} ++ ++static s32 ++wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, ++ struct ieee80211_channel *channel, bool offchan, ++ enum nl80211_channel_type channel_type, ++ bool channel_type_valid, unsigned int wait, ++ const u8* buf, size_t len, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) ++ bool no_cck, ++#endif ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0) ++ bool dont_wait_for_ack, ++#endif ++ u64 *cookie) ++{ ++ wl_action_frame_t *action_frame; ++ wl_af_params_t *af_params; ++ scb_val_t scb_val; ++ const struct ieee80211_mgmt *mgmt; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ struct net_device *dev = NULL; ++ s32 err = BCME_OK; ++ s32 bssidx = 0; ++ u32 id; ++ bool ack = false; ++ s8 eabuf[ETHER_ADDR_STR_LEN]; ++ ++ AP6211_DEBUG("Enter \n"); ++ ++ if (ndev == wl->p2p_net) { ++ dev = wl_to_prmry_ndev(wl); ++ } else { ++ /* If TX req is for any valid ifidx. Use as is */ ++ dev = ndev; ++ } ++ ++ /* find bssidx based on ndev */ ++ bssidx = wl_cfgp2p_find_idx(wl, dev); ++ if (bssidx == -1) { ++ ++ AP6211_ERR("Can not find the bssidx for dev( %p )\n", dev); ++ return -ENODEV; ++ } ++ if (p2p_is_on(wl)) { ++ /* Suspend P2P discovery search-listen to prevent it from changing the ++ * channel. ++ */ ++ if ((err = wl_cfgp2p_discover_enable_search(wl, false)) < 0) { ++ AP6211_ERR("Can not disable discovery mode\n"); ++ return -EFAULT; ++ } ++ } ++ *cookie = 0; ++ id = wl->send_action_id++; ++ if (id == 0) ++ id = wl->send_action_id++; ++ *cookie = id; ++ mgmt = (const struct ieee80211_mgmt *)buf; ++ if (ieee80211_is_mgmt(mgmt->frame_control)) { ++ if (ieee80211_is_probe_resp(mgmt->frame_control)) { ++ s32 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN; ++ s32 ie_len = len - ie_offset; ++ if (dev == wl_to_prmry_ndev(wl)) ++ bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); ++ wl_cfgp2p_set_management_ie(wl, dev, bssidx, ++ VNDR_IE_PRBRSP_FLAG, (u8 *)(buf + ie_offset), ie_len); ++ cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL); ++ goto exit; ++ } else if (ieee80211_is_disassoc(mgmt->frame_control) || ++ ieee80211_is_deauth(mgmt->frame_control)) { ++ memcpy(scb_val.ea.octet, mgmt->da, ETH_ALEN); ++ scb_val.val = mgmt->u.disassoc.reason_code; ++ err = wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val, ++ sizeof(scb_val_t), true); ++ if (err < 0) ++ AP6211_ERR("WLC_SCB_DEAUTHENTICATE_FOR_REASON error %d\n", err); ++ AP6211_DEBUG("Disconnect STA : %s scb_val.val %d\n", ++ bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf), ++ scb_val.val); ++ wl_delay(400); ++ cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL); ++ goto exit; ++ ++ } else if (ieee80211_is_action(mgmt->frame_control)) { ++ /* Abort the dwell time of any previous off-channel ++ * action frame that may be still in effect. Sending ++ * off-channel action frames relies on the driver's ++ * scan engine. If a previous off-channel action frame ++ * tx is still in progress (including the dwell time), ++ * then this new action frame will not be sent out. ++ */ ++/* Do not abort scan for VSDB. Scan will be aborted in firmware if necessary. ++ * And previous off-channel action frame must be ended before new af tx. ++ */ ++#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST ++ wl_notify_escan_complete(wl, dev, true, true); ++#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ ++ } ++ ++ } else { ++ AP6211_ERR("Driver only allows MGMT packet type\n"); ++ goto exit; ++ } ++ ++ af_params = (wl_af_params_t *) kzalloc(WL_WIFI_AF_PARAMS_SIZE, GFP_KERNEL); ++ ++ if (af_params == NULL) ++ { ++ AP6211_ERR("unable to allocate frame\n"); ++ return -ENOMEM; ++ } ++ ++ action_frame = &af_params->action_frame; ++ ++ /* Add the packet Id */ ++ action_frame->packetId = *cookie; ++ AP6211_DEBUG("action frame %d\n", action_frame->packetId); ++ /* Add BSSID */ ++ memcpy(&action_frame->da, &mgmt->da[0], ETHER_ADDR_LEN); ++ memcpy(&af_params->BSSID, &mgmt->bssid[0], ETHER_ADDR_LEN); ++ ++ /* Add the length exepted for 802.11 header */ ++ action_frame->len = len - DOT11_MGMT_HDR_LEN; ++ AP6211_DEBUG("action_frame->len: %d\n", action_frame->len); ++ ++ /* Add the channel */ ++ af_params->channel = ++ ieee80211_frequency_to_channel(channel->center_freq); ++ ++ /* Save listen_chan for searching common channel */ ++ wl->afx_hdl->peer_listen_chan = af_params->channel; ++ AP6211_DEBUG("channel from upper layer %d\n", wl->afx_hdl->peer_listen_chan); ++ ++ /* Add the default dwell time ++ * Dwell time to stay off-channel to wait for a response action frame ++ * after transmitting an GO Negotiation action frame ++ */ ++ af_params->dwell_time = WL_DWELL_TIME; ++ ++ memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len); ++ ++ ack = wl_cfg80211_send_action_frame(wiphy, dev, ndev, af_params, ++ action_frame, action_frame->len, bssidx); ++ ++ cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, ack, GFP_KERNEL); ++ ++ kfree(af_params); ++exit: ++ return err; ++} ++ ++ ++static void ++wl_cfg80211_mgmt_frame_register(struct wiphy *wiphy, struct net_device *dev, ++ u16 frame_type, bool reg) ++{ ++ ++ AP6211_DEBUG("%s: frame_type: %x, reg: %d\n", __func__, frame_type, reg); ++ ++ if (frame_type != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ)) ++ return; ++ ++ return; ++} ++ ++ ++static s32 ++wl_cfg80211_change_bss(struct wiphy *wiphy, ++ struct net_device *dev, ++ struct bss_parameters *params) ++{ ++ if (params->use_cts_prot >= 0) { ++ } ++ ++ if (params->use_short_preamble >= 0) { ++ } ++ ++ if (params->use_short_slot_time >= 0) { ++ } ++ ++ if (params->basic_rates) { ++ } ++ ++ if (params->ap_isolate >= 0) { ++ } ++ ++ if (params->ht_opmode >= 0) { ++ } ++ ++ return 0; ++} ++ ++static s32 ++wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, ++ struct ieee80211_channel *chan, ++ enum nl80211_channel_type channel_type) ++{ ++ s32 _chan; ++ chanspec_t chspec = 0; ++ chanspec_t fw_chspec = 0; ++ u32 bw = WL_CHANSPEC_BW_20; ++ ++ s32 err = BCME_OK; ++ s32 bw_cap = 0; ++ struct { ++ u32 band; ++ u32 bw_cap; ++ } param = {0, 0}; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ ++ if (wl->p2p_net == dev) { ++ dev = wl_to_prmry_ndev(wl); ++ } ++ _chan = ieee80211_frequency_to_channel(chan->center_freq); ++ AP6211_ERR("netdev_ifidx(%d), chan_type(%d) target channel(%d) \n", ++ dev->ifindex, channel_type, _chan); ++ ++ ++ if (chan->band == IEEE80211_BAND_5GHZ) { ++ param.band = WLC_BAND_5G; ++ err = wldev_iovar_getbuf(dev, "bw_cap", ¶m, sizeof(param), ++ wl->ioctl_buf, WLC_IOCTL_SMLEN, &wl->ioctl_buf_sync); ++ if (err) { ++ if (err != BCME_UNSUPPORTED) { ++ AP6211_ERR("bw_cap failed, %d\n", err); ++ return err; ++ } else { ++ err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap); ++ if (err) { ++ AP6211_ERR("error get mimo_bw_cap (%d)\n", err); ++ } ++ if (bw_cap != WLC_N_BW_20ALL) ++ bw = WL_CHANSPEC_BW_40; ++ } ++ } else { ++ if (WL_BW_CAP_80MHZ(wl->ioctl_buf[0])) ++ bw = WL_CHANSPEC_BW_80; ++ else if (WL_BW_CAP_40MHZ(wl->ioctl_buf[0])) ++ bw = WL_CHANSPEC_BW_40; ++ else ++ bw = WL_CHANSPEC_BW_20; ++ ++ } ++ ++ } else if (chan->band == IEEE80211_BAND_2GHZ) ++ bw = WL_CHANSPEC_BW_20; ++set_channel: ++ chspec = wf_channel2chspec(_chan, bw); ++ if (wf_chspec_valid(chspec)) { ++ fw_chspec = wl_chspec_host_to_driver(chspec); ++ if (fw_chspec != INVCHANSPEC) { ++ if ((err = wldev_iovar_setint(dev, "chanspec", ++ fw_chspec)) == BCME_BADCHAN) { ++ if (bw == WL_CHANSPEC_BW_80) ++ goto change_bw; ++ err = wldev_ioctl(dev, WLC_SET_CHANNEL, ++ &_chan, sizeof(_chan), true); ++ if (err < 0) { ++ AP6211_ERR("WLC_SET_CHANNEL error %d" ++ "chip may not be supporting this channel\n", err); ++ } ++ } else if (err) { ++ AP6211_ERR("failed to set chanspec error %d\n", err); ++ } ++ } else { ++ AP6211_ERR("failed to convert host chanspec to fw chanspec\n"); ++ err = BCME_ERROR; ++ } ++ } else { ++change_bw: ++ if (bw == WL_CHANSPEC_BW_80) ++ bw = WL_CHANSPEC_BW_40; ++ else if (bw == WL_CHANSPEC_BW_40) ++ bw = WL_CHANSPEC_BW_20; ++ else ++ bw = 0; ++ if (bw) ++ goto set_channel; ++ AP6211_ERR("Invalid chanspec 0x%x\n", chspec); ++ err = BCME_ERROR; ++ } ++ return err; ++} ++ ++static s32 ++wl_validate_opensecurity(struct net_device *dev, s32 bssidx) ++{ ++ s32 err = BCME_OK; ++ ++ /* set auth */ ++ err = wldev_iovar_setint_bsscfg(dev, "auth", 0, bssidx); ++ if (err < 0) { ++ AP6211_ERR("auth error %d\n", err); ++ return BCME_ERROR; ++ } ++ /* set wsec */ ++ err = wldev_iovar_setint_bsscfg(dev, "wsec", 0, bssidx); ++ if (err < 0) { ++ AP6211_ERR("wsec error %d\n", err); ++ return BCME_ERROR; ++ } ++ /* set upper-layer auth */ ++ err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", WPA_AUTH_NONE, bssidx); ++ if (err < 0) { ++ AP6211_ERR("wpa_auth error %d\n", err); ++ return BCME_ERROR; ++ } ++ ++ return 0; ++} ++ ++static s32 ++wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx) ++{ ++ s32 len = 0; ++ s32 err = BCME_OK; ++ u16 auth = 0; /* d11 open authentication */ ++ u32 wsec; ++ u32 pval = 0; ++ u32 gval = 0; ++ u32 wpa_auth = 0; ++ wpa_suite_mcast_t *mcast; ++ wpa_suite_ucast_t *ucast; ++ wpa_suite_auth_key_mgmt_t *mgmt; ++ ++ u16 suite_count; ++ u8 rsn_cap[2]; ++ u32 wme_bss_disable; ++ ++ if (wpa2ie == NULL) ++ goto exit; ++ ++ AP6211_DEBUG("Enter \n"); ++ len = wpa2ie->len; ++ /* check the mcast cipher */ ++ mcast = (wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN]; ++ switch (mcast->type) { ++ case WPA_CIPHER_NONE: ++ gval = 0; ++ break; ++ case WPA_CIPHER_WEP_40: ++ case WPA_CIPHER_WEP_104: ++ gval = WEP_ENABLED; ++ break; ++ case WPA_CIPHER_TKIP: ++ gval = TKIP_ENABLED; ++ break; ++ case WPA_CIPHER_AES_CCM: ++ gval = AES_ENABLED; ++ break; ++#ifdef BCMWAPI_WPI ++ case WAPI_CIPHER_SMS4: ++ gval = SMS4_ENABLED; ++ break; ++#endif ++ default: ++ AP6211_ERR("No Security Info\n"); ++ break; ++ } ++ if ((len -= WPA_SUITE_LEN) <= 0) ++ return BCME_BADLEN; ++ ++ /* check the unicast cipher */ ++ ucast = (wpa_suite_ucast_t *)&mcast[1]; ++ suite_count = ltoh16_ua(&ucast->count); ++ switch (ucast->list[0].type) { ++ case WPA_CIPHER_NONE: ++ pval = 0; ++ break; ++ case WPA_CIPHER_WEP_40: ++ case WPA_CIPHER_WEP_104: ++ pval = WEP_ENABLED; ++ break; ++ case WPA_CIPHER_TKIP: ++ pval = TKIP_ENABLED; ++ break; ++ case WPA_CIPHER_AES_CCM: ++ pval = AES_ENABLED; ++ break; ++#ifdef BCMWAPI_WPI ++ case WAPI_CIPHER_SMS4: ++ pval = SMS4_ENABLED; ++ break; ++#endif ++ default: ++ AP6211_ERR("No Security Info\n"); ++ } ++ if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) <= 0) ++ return BCME_BADLEN; ++ ++ /* FOR WPS , set SEC_OW_ENABLED */ ++ wsec = (pval | gval | SES_OW_ENABLED); ++ /* check the AKM */ ++ mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count]; ++ suite_count = ltoh16_ua(&mgmt->count); ++ switch (mgmt->list[0].type) { ++ case RSN_AKM_NONE: ++ wpa_auth = WPA_AUTH_NONE; ++ break; ++ case RSN_AKM_UNSPECIFIED: ++ wpa_auth = WPA2_AUTH_UNSPECIFIED; ++ break; ++ case RSN_AKM_PSK: ++ wpa_auth = WPA2_AUTH_PSK; ++ break; ++ default: ++ AP6211_ERR("No Key Mgmt Info\n"); ++ } ++ ++ if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) { ++ rsn_cap[0] = *(u8 *)&mgmt->list[suite_count]; ++ rsn_cap[1] = *((u8 *)&mgmt->list[suite_count] + 1); ++ ++ if (rsn_cap[0] & (RSN_CAP_16_REPLAY_CNTRS << RSN_CAP_PTK_REPLAY_CNTR_SHIFT)) { ++ wme_bss_disable = 0; ++ } else { ++ wme_bss_disable = 1; ++ } ++ ++ /* set wme_bss_disable to sync RSN Capabilities */ ++ err = wldev_iovar_setint_bsscfg(dev, "wme_bss_disable", wme_bss_disable, bssidx); ++ if (err < 0) { ++ AP6211_ERR("wme_bss_disable error %d\n", err); ++ return BCME_ERROR; ++ } ++ } else { ++ AP6211_DEBUG("There is no RSN Capabilities. remained len %d\n", len); ++ } ++ ++ /* set auth */ ++ err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx); ++ if (err < 0) { ++ AP6211_ERR("auth error %d\n", err); ++ return BCME_ERROR; ++ } ++ /* set wsec */ ++ err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx); ++ if (err < 0) { ++ AP6211_ERR("wsec error %d\n", err); ++ return BCME_ERROR; ++ } ++ /* set upper-layer auth */ ++ err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx); ++ if (err < 0) { ++ AP6211_ERR("wpa_auth error %d\n", err); ++ return BCME_ERROR; ++ } ++exit: ++ return 0; ++} ++ ++static s32 ++wl_validate_wpaie(struct net_device *dev, wpa_ie_fixed_t *wpaie, s32 bssidx) ++{ ++ wpa_suite_mcast_t *mcast; ++ wpa_suite_ucast_t *ucast; ++ wpa_suite_auth_key_mgmt_t *mgmt; ++ u16 auth = 0; /* d11 open authentication */ ++ u16 count; ++ s32 err = BCME_OK; ++ s32 len = 0; ++ u32 i; ++ u32 wsec; ++ u32 pval = 0; ++ u32 gval = 0; ++ u32 wpa_auth = 0; ++ u32 tmp = 0; ++ ++ if (wpaie == NULL) ++ goto exit; ++ AP6211_DEBUG("Enter \n"); ++ len = wpaie->length; /* value length */ ++ len -= WPA_IE_TAG_FIXED_LEN; ++ /* check for multicast cipher suite */ ++ if (len < WPA_SUITE_LEN) { ++ AP6211_DEBUG("no multicast cipher suite\n"); ++ goto exit; ++ } ++ ++ /* pick up multicast cipher */ ++ mcast = (wpa_suite_mcast_t *)&wpaie[1]; ++ len -= WPA_SUITE_LEN; ++ if (!bcmp(mcast->oui, WPA_OUI, WPA_OUI_LEN)) { ++ if (IS_WPA_CIPHER(mcast->type)) { ++ tmp = 0; ++ switch (mcast->type) { ++ case WPA_CIPHER_NONE: ++ tmp = 0; ++ break; ++ case WPA_CIPHER_WEP_40: ++ case WPA_CIPHER_WEP_104: ++ tmp = WEP_ENABLED; ++ break; ++ case WPA_CIPHER_TKIP: ++ tmp = TKIP_ENABLED; ++ break; ++ case WPA_CIPHER_AES_CCM: ++ tmp = AES_ENABLED; ++ break; ++ default: ++ AP6211_ERR("No Security Info\n"); ++ } ++ gval |= tmp; ++ } ++ } ++ /* Check for unicast suite(s) */ ++ if (len < WPA_IE_SUITE_COUNT_LEN) { ++ AP6211_DEBUG("no unicast suite\n"); ++ goto exit; ++ } ++ /* walk thru unicast cipher list and pick up what we recognize */ ++ ucast = (wpa_suite_ucast_t *)&mcast[1]; ++ count = ltoh16_ua(&ucast->count); ++ len -= WPA_IE_SUITE_COUNT_LEN; ++ for (i = 0; i < count && len >= WPA_SUITE_LEN; ++ i++, len -= WPA_SUITE_LEN) { ++ if (!bcmp(ucast->list[i].oui, WPA_OUI, WPA_OUI_LEN)) { ++ if (IS_WPA_CIPHER(ucast->list[i].type)) { ++ tmp = 0; ++ switch (ucast->list[i].type) { ++ case WPA_CIPHER_NONE: ++ tmp = 0; ++ break; ++ case WPA_CIPHER_WEP_40: ++ case WPA_CIPHER_WEP_104: ++ tmp = WEP_ENABLED; ++ break; ++ case WPA_CIPHER_TKIP: ++ tmp = TKIP_ENABLED; ++ break; ++ case WPA_CIPHER_AES_CCM: ++ tmp = AES_ENABLED; ++ break; ++ default: ++ AP6211_ERR("No Security Info\n"); ++ } ++ pval |= tmp; ++ } ++ } ++ } ++ len -= (count - i) * WPA_SUITE_LEN; ++ /* Check for auth key management suite(s) */ ++ if (len < WPA_IE_SUITE_COUNT_LEN) { ++ AP6211_DEBUG(" no auth key mgmt suite\n"); ++ goto exit; ++ } ++ /* walk thru auth management suite list and pick up what we recognize */ ++ mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[count]; ++ count = ltoh16_ua(&mgmt->count); ++ len -= WPA_IE_SUITE_COUNT_LEN; ++ for (i = 0; i < count && len >= WPA_SUITE_LEN; ++ i++, len -= WPA_SUITE_LEN) { ++ if (!bcmp(mgmt->list[i].oui, WPA_OUI, WPA_OUI_LEN)) { ++ if (IS_WPA_AKM(mgmt->list[i].type)) { ++ tmp = 0; ++ switch (mgmt->list[i].type) { ++ case RSN_AKM_NONE: ++ tmp = WPA_AUTH_NONE; ++ break; ++ case RSN_AKM_UNSPECIFIED: ++ tmp = WPA_AUTH_UNSPECIFIED; ++ break; ++ case RSN_AKM_PSK: ++ tmp = WPA_AUTH_PSK; ++ break; ++ default: ++ AP6211_ERR("No Key Mgmt Info\n"); ++ } ++ wpa_auth |= tmp; ++ } ++ } ++ ++ } ++ /* FOR WPS , set SEC_OW_ENABLED */ ++ wsec = (pval | gval | SES_OW_ENABLED); ++ /* set auth */ ++ err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx); ++ if (err < 0) { ++ AP6211_ERR("auth error %d\n", err); ++ return BCME_ERROR; ++ } ++ /* set wsec */ ++ err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx); ++ if (err < 0) { ++ AP6211_ERR("wsec error %d\n", err); ++ return BCME_ERROR; ++ } ++ /* set upper-layer auth */ ++ err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx); ++ if (err < 0) { ++ AP6211_ERR("wpa_auth error %d\n", err); ++ return BCME_ERROR; ++ } ++exit: ++ return 0; ++} ++ ++static s32 ++wl_cfg80211_bcn_validate_sec( ++ struct net_device *dev, ++ struct parsed_ies *ies, ++ u32 dev_role, ++ s32 bssidx) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ ++ if (dev_role == NL80211_IFTYPE_P2P_GO && (ies->wpa2_ie)) { ++ /* For P2P GO, the sec type is WPA2-PSK */ ++ AP6211_DEBUG("P2P GO: validating wpa2_ie"); ++ if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0) ++ return BCME_ERROR; ++ ++ } else if (dev_role == NL80211_IFTYPE_AP) { ++ ++ AP6211_DEBUG("SoftAP: validating security"); ++ /* If wpa2_ie or wpa_ie is present validate it */ ++ if ((ies->wpa2_ie || ies->wpa_ie) && ++ ((wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 || ++ wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0))) { ++ wl->ap_info->security_mode = false; ++ return BCME_ERROR; ++ } ++ ++ wl->ap_info->security_mode = true; ++ if (wl->ap_info->rsn_ie) { ++ kfree(wl->ap_info->rsn_ie); ++ wl->ap_info->rsn_ie = NULL; ++ } ++ if (wl->ap_info->wpa_ie) { ++ kfree(wl->ap_info->wpa_ie); ++ wl->ap_info->wpa_ie = NULL; ++ } ++ if (wl->ap_info->wps_ie) { ++ kfree(wl->ap_info->wps_ie); ++ wl->ap_info->wps_ie = NULL; ++ } ++ if (ies->wpa_ie != NULL) { ++ /* WPAIE */ ++ wl->ap_info->rsn_ie = NULL; ++ wl->ap_info->wpa_ie = kmemdup(ies->wpa_ie, ++ ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN, ++ GFP_KERNEL); ++ } else if (ies->wpa2_ie != NULL) { ++ /* RSNIE */ ++ wl->ap_info->wpa_ie = NULL; ++ wl->ap_info->rsn_ie = kmemdup(ies->wpa2_ie, ++ ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN, ++ GFP_KERNEL); ++ } ++ ++ if (!ies->wpa2_ie && !ies->wpa_ie) { ++ wl_validate_opensecurity(dev, bssidx); ++ wl->ap_info->security_mode = false; ++ } ++ ++ if (ies->wps_ie) { ++ wl->ap_info->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL); ++ } ++ } ++ ++ return 0; ++ ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) ++static s32 wl_cfg80211_bcn_set_params( ++ struct cfg80211_ap_settings *info, ++ struct net_device *dev, ++ u32 dev_role, s32 bssidx) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ s32 err = BCME_OK; ++ ++ AP6211_DEBUG("interval (%d) \ndtim_period (%d) \n", ++ info->beacon_interval, info->dtim_period); ++ ++ if (info->beacon_interval) { ++ if ((err = wldev_ioctl(dev, WLC_SET_BCNPRD, ++ &info->beacon_interval, sizeof(s32), true)) < 0) { ++ AP6211_ERR("Beacon Interval Set Error, %d\n", err); ++ return err; ++ } ++ } ++ ++ if (info->dtim_period) { ++ if ((err = wldev_ioctl(dev, WLC_SET_DTIMPRD, ++ &info->dtim_period, sizeof(s32), true)) < 0) { ++ AP6211_ERR("DTIM Interval Set Error, %d\n", err); ++ return err; ++ } ++ } ++ ++ if ((info->ssid) && (info->ssid_len > 0) && ++ (info->ssid_len <= 32)) { ++ AP6211_DEBUG("SSID (%s) len:%d \n", info->ssid, info->ssid_len); ++ if (dev_role == NL80211_IFTYPE_AP) { ++ /* Store the hostapd SSID */ ++ memset(wl->hostapd_ssid.SSID, 0x00, 32); ++ memcpy(wl->hostapd_ssid.SSID, info->ssid, info->ssid_len); ++ wl->hostapd_ssid.SSID_len = info->ssid_len; ++ } else { ++ /* P2P GO */ ++ memset(wl->p2p->ssid.SSID, 0x00, 32); ++ memcpy(wl->p2p->ssid.SSID, info->ssid, info->ssid_len); ++ wl->p2p->ssid.SSID_len = info->ssid_len; ++ } ++ } ++ ++ if (info->hidden_ssid) { ++ if ((err = wldev_iovar_setint(dev, "closednet", 1)) < 0) ++ AP6211_ERR("failed to set hidden : %d\n", err); ++ AP6211_DEBUG("hidden_ssid_enum_val: %d \n", info->hidden_ssid); ++ } ++ ++ return err; ++} ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */ ++ ++static s32 ++wl_cfg80211_parse_ies(u8 *ptr, u32 len, struct parsed_ies *ies) ++{ ++ s32 err = BCME_OK; ++ ++ memset(ies, 0, sizeof(struct parsed_ies)); ++ ++ /* find the WPSIE */ ++ if ((ies->wps_ie = wl_cfgp2p_find_wpsie(ptr, len)) != NULL) { ++ AP6211_DEBUG("WPSIE in beacon \n"); ++ ies->wps_ie_len = ies->wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN; ++ } else { ++ AP6211_ERR("No WPSIE in beacon \n"); ++ } ++ ++ /* find the RSN_IE */ ++ if ((ies->wpa2_ie = bcm_parse_tlvs(ptr, len, ++ DOT11_MNG_RSN_ID)) != NULL) { ++ AP6211_DEBUG(" WPA2 IE found\n"); ++ ies->wpa2_ie_len = ies->wpa2_ie->len; ++ } ++ ++ /* find the WPA_IE */ ++ if ((ies->wpa_ie = wl_cfgp2p_find_wpaie(ptr, len)) != NULL) { ++ AP6211_DEBUG(" WPA found\n"); ++ ies->wpa_ie_len = ies->wpa_ie->length; ++ } ++ ++ return err; ++ ++} ++ ++static s32 ++wl_cfg80211_bcn_bringup_ap( ++ struct net_device *dev, ++ struct parsed_ies *ies, ++ u32 dev_role, s32 bssidx) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ struct wl_join_params join_params; ++ bool is_bssup = false; ++ s32 infra = 1; ++ s32 join_params_size = 0; ++ s32 ap = 1; ++ s32 err = BCME_OK; ++ ++ AP6211_DEBUG("Enter dev_role: %d\n", dev_role); ++ ++ /* Common code for SoftAP and P2P GO */ ++ wldev_iovar_setint(dev, "mpc", 0); ++ ++ if (dev_role == NL80211_IFTYPE_P2P_GO) { ++ is_bssup = wl_cfgp2p_bss_isup(dev, bssidx); ++ if (!is_bssup && (ies->wpa2_ie != NULL)) { ++ ++ err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true); ++ if (err < 0) { ++ AP6211_ERR("SET INFRA error %d\n", err); ++ goto exit; ++ } ++ ++ err = wldev_iovar_setbuf_bsscfg(dev, "ssid", &wl->p2p->ssid, ++ sizeof(wl->p2p->ssid), wl->ioctl_buf, WLC_IOCTL_MAXLEN, ++ bssidx, &wl->ioctl_buf_sync); ++ if (err < 0) { ++ AP6211_ERR("GO SSID setting error %d\n", err); ++ goto exit; ++ } ++ ++ if ((err = wl_cfgp2p_bss(wl, dev, bssidx, 1)) < 0) { ++ AP6211_ERR("GO Bring up error %d\n", err); ++ goto exit; ++ } ++ } else ++ AP6211_DEBUG("Bss is already up\n"); ++ } else if ((dev_role == NL80211_IFTYPE_AP) && ++ (wl_get_drv_status(wl, AP_CREATING, dev))) { ++ /* Device role SoftAP */ ++ err = wldev_ioctl(dev, WLC_DOWN, &ap, sizeof(s32), true); ++ if (err < 0) { ++ AP6211_ERR("WLC_DOWN error %d\n", err); ++ goto exit; ++ } ++ err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true); ++ if (err < 0) { ++ AP6211_ERR("SET INFRA error %d\n", err); ++ goto exit; ++ } ++ if ((err = wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32), true)) < 0) { ++ AP6211_ERR("setting AP mode failed %d \n", err); ++ goto exit; ++ } ++ ++ err = wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), true); ++ if (unlikely(err)) { ++ AP6211_ERR("WLC_UP error (%d)\n", err); ++ goto exit; ++ } ++ ++ memset(&join_params, 0, sizeof(join_params)); ++ /* join parameters starts with ssid */ ++ join_params_size = sizeof(join_params.ssid); ++ memcpy(join_params.ssid.SSID, wl->hostapd_ssid.SSID, ++ wl->hostapd_ssid.SSID_len); ++ join_params.ssid.SSID_len = htod32(wl->hostapd_ssid.SSID_len); ++ ++ /* create softap */ ++ if ((err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, ++ join_params_size, true)) == 0) { ++ AP6211_DEBUG("SoftAP set SSID (%s) success\n", join_params.ssid.SSID); ++ wl_clr_drv_status(wl, AP_CREATING, dev); ++ wl_set_drv_status(wl, AP_CREATED, dev); ++ } ++ } ++ ++ ++exit: ++ return err; ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) ++s32 ++wl_cfg80211_parse_set_ies( ++ struct net_device *dev, ++ struct cfg80211_beacon_data *info, ++ struct parsed_ies *ies, ++ u32 dev_role, ++ s32 bssidx) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ struct parsed_ies prb_ies; ++ s32 err = BCME_OK; ++ ++ memset(ies, 0, sizeof(struct parsed_ies)); ++ memset(&prb_ies, 0, sizeof(struct parsed_ies)); ++ ++ /* Parse Beacon IEs */ ++ if (wl_cfg80211_parse_ies((u8 *)info->tail, ++ info->tail_len, ies) < 0) { ++ AP6211_ERR("Beacon get IEs failed \n"); ++ err = -EINVAL; ++ goto fail; ++ } ++ ++ /* Set Beacon IEs to FW */ ++ if ((err = wl_cfgp2p_set_management_ie(wl, dev, bssidx, ++ VNDR_IE_BEACON_FLAG, (u8 *)info->tail, ++ info->tail_len)) < 0) { ++ AP6211_ERR("Set Beacon IE Failed \n"); ++ } else { ++ AP6211_DEBUG("Applied Vndr IEs for Beacon \n"); ++ } ++ ++ /* Parse Probe Response IEs */ ++ if (wl_cfg80211_parse_ies((u8 *)info->proberesp_ies, ++ info->proberesp_ies_len, &prb_ies) < 0) { ++ AP6211_ERR("PRB RESP get IEs failed \n"); ++ err = -EINVAL; ++ goto fail; ++ } ++ ++ /* Set Probe Response IEs to FW */ ++ if ((err = wl_cfgp2p_set_management_ie(wl, dev, bssidx, ++ VNDR_IE_PRBRSP_FLAG, (u8 *)info->proberesp_ies, ++ info->proberesp_ies_len)) < 0) { ++ AP6211_ERR("Set Probe Resp IE Failed \n"); ++ } else { ++ AP6211_DEBUG("Applied Vndr IEs for Probe Resp \n"); ++ } ++ ++fail: ++ ++ return err; ++} ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */ ++ ++static s32 wl_cfg80211_hostapd_sec( ++ struct net_device *dev, ++ struct parsed_ies *ies, ++ s32 bssidx) ++{ ++ bool update_bss = 0; ++ struct wl_priv *wl = wlcfg_drv_priv; ++ ++ ++ if (ies->wps_ie) { ++ if (wl->ap_info->wps_ie && ++ memcmp(wl->ap_info->wps_ie, ies->wps_ie, ies->wps_ie_len)) { ++ AP6211_DEBUG(" WPS IE is changed\n"); ++ kfree(wl->ap_info->wps_ie); ++ wl->ap_info->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL); ++ } else if (wl->ap_info->wps_ie == NULL) { ++ AP6211_DEBUG(" WPS IE is added\n"); ++ wl->ap_info->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL); ++ } ++ if ((ies->wpa_ie != NULL || ies->wpa2_ie != NULL)) { ++ if (!wl->ap_info->security_mode) { ++ /* change from open mode to security mode */ ++ update_bss = true; ++ if (ies->wpa_ie != NULL) { ++ wl->ap_info->wpa_ie = kmemdup(ies->wpa_ie, ++ ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN, ++ GFP_KERNEL); ++ } else { ++ wl->ap_info->rsn_ie = kmemdup(ies->wpa2_ie, ++ ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN, ++ GFP_KERNEL); ++ } ++ } else if (wl->ap_info->wpa_ie) { ++ /* change from WPA2 mode to WPA mode */ ++ if (ies->wpa_ie != NULL) { ++ update_bss = true; ++ kfree(wl->ap_info->rsn_ie); ++ wl->ap_info->rsn_ie = NULL; ++ wl->ap_info->wpa_ie = kmemdup(ies->wpa_ie, ++ ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN, ++ GFP_KERNEL); ++ } else if (memcmp(wl->ap_info->rsn_ie, ++ ies->wpa2_ie, ies->wpa2_ie->len ++ + WPA_RSN_IE_TAG_FIXED_LEN)) { ++ update_bss = true; ++ kfree(wl->ap_info->rsn_ie); ++ wl->ap_info->rsn_ie = kmemdup(ies->wpa2_ie, ++ ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN, ++ GFP_KERNEL); ++ wl->ap_info->wpa_ie = NULL; ++ } ++ } ++ if (update_bss) { ++ wl->ap_info->security_mode = true; ++ wl_cfgp2p_bss(wl, dev, bssidx, 0); ++ if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 || ++ wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0) { ++ return BCME_ERROR; ++ } ++ wl_cfgp2p_bss(wl, dev, bssidx, 1); ++ } ++ } ++ } else { ++ AP6211_ERR("No WPSIE in beacon \n"); ++ } ++ return 0; ++} ++ ++#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ ++ 2, 0)) ++static s32 ++wl_cfg80211_del_station( ++ struct wiphy *wiphy, ++ struct net_device *ndev, ++ u8* mac_addr) ++{ ++ struct net_device *dev; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ scb_val_t scb_val; ++ s8 eabuf[ETHER_ADDR_STR_LEN]; ++ ++ AP6211_DEBUG("Entry\n"); ++ if (mac_addr == NULL) { ++ AP6211_DEBUG("mac_addr is NULL ignore it\n"); ++ return 0; ++ } ++ ++ if (ndev == wl->p2p_net) { ++ dev = wl_to_prmry_ndev(wl); ++ } else { ++ dev = ndev; ++ } ++ ++ if (p2p_is_on(wl)) { ++ /* Suspend P2P discovery search-listen to prevent it from changing the ++ * channel. ++ */ ++ if ((wl_cfgp2p_discover_enable_search(wl, false)) < 0) { ++ AP6211_ERR("Can not disable discovery mode\n"); ++ return -EFAULT; ++ } ++ } ++ ++ memcpy(scb_val.ea.octet, mac_addr, ETHER_ADDR_LEN); ++ scb_val.val = DOT11_RC_DEAUTH_LEAVING; ++ if (wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val, ++ sizeof(scb_val_t), true)) ++ AP6211_ERR("WLC_SCB_DEAUTHENTICATE_FOR_REASON failed\n"); ++ AP6211_DEBUG("Disconnect STA : %s scb_val.val %d\n", ++ bcm_ether_ntoa((const struct ether_addr *)mac_addr, eabuf), ++ scb_val.val); ++ wl_delay(400); ++ return 0; ++} ++#endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) ++static s32 ++wl_cfg80211_start_ap( ++ struct wiphy *wiphy, ++ struct net_device *dev, ++ struct cfg80211_ap_settings *info) ++{ ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ s32 err = BCME_OK; ++ struct parsed_ies ies; ++ s32 bssidx = 0; ++ u32 dev_role = 0; ++ ++ AP6211_DEBUG("Enter \n"); ++ if (dev == wl_to_prmry_ndev(wl)) { ++ AP6211_DEBUG("Start AP req on primary iface: Softap\n"); ++ dev_role = NL80211_IFTYPE_AP; ++ } else if (dev == wl->p2p_net) { ++ /* Group Add request on p2p0 */ ++ AP6211_DEBUG("Start AP req on P2P iface: GO\n"); ++ dev = wl_to_prmry_ndev(wl); ++ dev_role = NL80211_IFTYPE_P2P_GO; ++ } ++ ++ bssidx = wl_cfgp2p_find_idx(wl, dev); ++ if (p2p_is_on(wl) && ++ (bssidx == wl_to_p2p_bss_bssidx(wl, ++ P2PAPI_BSSCFG_CONNECTION))) { ++ dev_role = NL80211_IFTYPE_P2P_GO; ++ AP6211_DEBUG("Start AP req on P2P connection iface\n"); ++ } ++ ++ if ((err = wl_cfg80211_bcn_set_params(info, dev, ++ dev_role, bssidx)) < 0) { ++ AP6211_ERR("Beacon params set failed \n"); ++ goto fail; ++ } ++ ++ /* Set IEs to FW */ ++ if ((err = wl_cfg80211_parse_set_ies(dev, &info->beacon, ++ &ies, dev_role, bssidx) < 0)) { ++ AP6211_ERR("Set IEs failed \n"); ++ goto fail; ++ } ++ ++ if ((wl_cfg80211_bcn_validate_sec(dev, &ies, ++ dev_role, bssidx)) < 0) ++ { ++ AP6211_ERR("Beacon set security failed \n"); ++ goto fail; ++ } ++ ++ if ((err = wl_cfg80211_bcn_bringup_ap(dev, &ies, ++ dev_role, bssidx)) < 0) { ++ AP6211_ERR("Beacon bring up AP/GO failed \n"); ++ goto fail; ++ } ++ ++ AP6211_DEBUG("** AP/GO Created **\n"); ++ ++fail: ++ if (err) { ++ AP6211_ERR("ADD/SET beacon failed\n"); ++ wldev_iovar_setint(dev, "mpc", 1); ++ } ++ ++ return err; ++} ++ ++static s32 ++wl_cfg80211_stop_ap( ++ struct wiphy *wiphy, ++ struct net_device *dev) ++{ ++ int err = 0; ++ u32 dev_role = 0; ++ int infra = 0; ++ int ap = 0; ++ s32 bssidx = 0; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ ++ AP6211_DEBUG("Enter \n"); ++ if (dev == wl_to_prmry_ndev(wl)) { ++ dev_role = NL80211_IFTYPE_AP; ++ } else if (dev == wl->p2p_net) { ++ /* Group Add request on p2p0 */ ++ dev = wl_to_prmry_ndev(wl); ++ dev_role = NL80211_IFTYPE_P2P_GO; ++ } ++ bssidx = wl_cfgp2p_find_idx(wl, dev); ++ if (p2p_is_on(wl) && ++ (bssidx == wl_to_p2p_bss_bssidx(wl, ++ P2PAPI_BSSCFG_CONNECTION))) { ++ dev_role = NL80211_IFTYPE_P2P_GO; ++ } ++ ++ if (dev_role == NL80211_IFTYPE_AP) { ++ /* SoftAp on primary Interface. ++ * Shut down AP and turn on MPC ++ */ ++ err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true); ++ if (err < 0) { ++ AP6211_ERR("SET INFRA error %d\n", err); ++ err = -ENOTSUPP; ++ goto exit; ++ } ++ if ((err = wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32), true)) < 0) { ++ AP6211_ERR("setting AP mode failed %d \n", err); ++ err = -ENOTSUPP; ++ goto exit; ++ } ++ ++ err = wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), true); ++ if (unlikely(err)) { ++ AP6211_ERR("WLC_UP error (%d)\n", err); ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ wl_clr_drv_status(wl, AP_CREATED, dev); ++ /* Turn on the MPC */ ++ wldev_iovar_setint(dev, "mpc", 1); ++ } else { ++ AP6211_DEBUG("Stopping P2P GO \n"); ++ } ++ ++exit: ++ return err; ++} ++ ++static s32 ++wl_cfg80211_change_beacon( ++ struct wiphy *wiphy, ++ struct net_device *dev, ++ struct cfg80211_beacon_data *info) ++{ ++ s32 err = BCME_OK; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ struct parsed_ies ies; ++ u32 dev_role = 0; ++ s32 bssidx = 0; ++ ++ AP6211_DEBUG("Enter \n"); ++ ++ if (dev == wl_to_prmry_ndev(wl)) { ++ dev_role = NL80211_IFTYPE_AP; ++ } else if (dev == wl->p2p_net) { ++ /* Group Add request on p2p0 */ ++ dev = wl_to_prmry_ndev(wl); ++ dev_role = NL80211_IFTYPE_P2P_GO; ++ } ++ ++ bssidx = wl_cfgp2p_find_idx(wl, dev); ++ if (p2p_is_on(wl) && ++ (bssidx == wl_to_p2p_bss_bssidx(wl, ++ P2PAPI_BSSCFG_CONNECTION))) { ++ dev_role = NL80211_IFTYPE_P2P_GO; ++ } ++ ++ /* Set IEs to FW */ ++ if ((err = wl_cfg80211_parse_set_ies(dev, info, ++ &ies, dev_role, bssidx) < 0)) { ++ AP6211_ERR("Set IEs failed \n"); ++ goto fail; ++ } ++ ++ if (dev_role == NL80211_IFTYPE_AP) { ++ if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) { ++ AP6211_ERR("Hostapd update sec failed \n"); ++ err = -EINVAL; ++ goto fail; ++ } ++ } ++ ++fail: ++ return err; ++} ++#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) */ ++static s32 ++wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, ++ struct beacon_parameters *info) ++{ ++ s32 err = BCME_OK; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ s32 ie_offset = 0; ++ s32 bssidx = 0; ++ u32 dev_role = NL80211_IFTYPE_AP; ++ struct parsed_ies ies; ++ bcm_tlv_t *ssid_ie; ++ bool pbc = 0; ++ ++ AP6211_DEBUG("interval (%d) dtim_period (%d) head_len (%d) tail_len (%d)\n", ++ info->interval, info->dtim_period, info->head_len, info->tail_len); ++ ++ if (dev == wl_to_prmry_ndev(wl)) { ++ dev_role = NL80211_IFTYPE_AP; ++ } else if (dev == wl->p2p_net) { ++ /* Group Add request on p2p0 */ ++ dev = wl_to_prmry_ndev(wl); ++ dev_role = NL80211_IFTYPE_P2P_GO; ++ } ++ ++ bssidx = wl_cfgp2p_find_idx(wl, dev); ++ if (p2p_is_on(wl) && ++ (bssidx == wl_to_p2p_bss_bssidx(wl, ++ P2PAPI_BSSCFG_CONNECTION))) { ++ dev_role = NL80211_IFTYPE_P2P_GO; ++ } ++ ++ ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN; ++ /* find the SSID */ ++ if ((ssid_ie = bcm_parse_tlvs((u8 *)&info->head[ie_offset], ++ info->head_len - ie_offset, ++ DOT11_MNG_SSID_ID)) != NULL) { ++ if (dev_role == NL80211_IFTYPE_AP) { ++ /* Store the hostapd SSID */ ++ memset(&wl->hostapd_ssid.SSID[0], 0x00, 32); ++ memcpy(&wl->hostapd_ssid.SSID[0], ssid_ie->data, ssid_ie->len); ++ wl->hostapd_ssid.SSID_len = ssid_ie->len; ++ } else { ++ /* P2P GO */ ++ memset(&wl->p2p->ssid.SSID[0], 0x00, 32); ++ memcpy(wl->p2p->ssid.SSID, ssid_ie->data, ssid_ie->len); ++ wl->p2p->ssid.SSID_len = ssid_ie->len; ++ } ++ } ++ ++ if (wl_cfg80211_parse_ies((u8 *)info->tail, ++ info->tail_len, &ies) < 0) { ++ AP6211_ERR("Beacon get IEs failed \n"); ++ err = -EINVAL; ++ goto fail; ++ } ++ ++ if (wl_cfgp2p_set_management_ie(wl, dev, bssidx, ++ VNDR_IE_BEACON_FLAG, (u8 *)info->tail, ++ info->tail_len) < 0) { ++ AP6211_ERR("Beacon set IEs failed \n"); ++ goto fail; ++ } else { ++ AP6211_DEBUG("Applied Vndr IEs for Beacon \n"); ++ } ++ if (!wl_cfgp2p_bss_isup(dev, bssidx) && ++ (wl_cfg80211_bcn_validate_sec(dev, &ies, dev_role, bssidx) < 0)) ++ { ++ AP6211_ERR("Beacon set security failed \n"); ++ goto fail; ++ } ++ ++ /* Set BI and DTIM period */ ++ if (info->interval) { ++ if ((err = wldev_ioctl(dev, WLC_SET_BCNPRD, ++ &info->interval, sizeof(s32), true)) < 0) { ++ AP6211_ERR("Beacon Interval Set Error, %d\n", err); ++ return err; ++ } ++ } ++ if (info->dtim_period) { ++ if ((err = wldev_ioctl(dev, WLC_SET_DTIMPRD, ++ &info->dtim_period, sizeof(s32), true)) < 0) { ++ AP6211_ERR("DTIM Interval Set Error, %d\n", err); ++ return err; ++ } ++ } ++ ++ if (wl_cfg80211_bcn_bringup_ap(dev, &ies, dev_role, bssidx) < 0) { ++ AP6211_ERR("Beacon bring up AP/GO failed \n"); ++ goto fail; ++ } ++ ++ if (wl_get_drv_status(wl, AP_CREATED, dev)) { ++ /* Soft AP already running. Update changed params */ ++ if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) { ++ AP6211_ERR("Hostapd update sec failed \n"); ++ err = -EINVAL; ++ goto fail; ++ } ++ } ++ ++ /* Enable Probe Req filter */ ++ if (((dev_role == NL80211_IFTYPE_P2P_GO) || ++ (dev_role == NL80211_IFTYPE_AP)) && (ies.wps_ie != NULL)) { ++ wl_validate_wps_ie((char *) ies.wps_ie, ies.wps_ie_len, &pbc); ++ if (pbc) ++ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true); ++ } ++ ++ AP6211_DEBUG("** ADD/SET beacon done **\n"); ++ ++fail: ++ if (err) { ++ AP6211_ERR("ADD/SET beacon failed\n"); ++ wldev_iovar_setint(dev, "mpc", 1); ++ } ++ return err; ++ ++} ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) */ ++ ++#ifdef WL_SCHED_SCAN ++#define PNO_TIME 30 ++#define PNO_REPEAT 4 ++#define PNO_FREQ_EXPO_MAX 2 ++int wl_cfg80211_sched_scan_start(struct wiphy *wiphy, ++ struct net_device *dev, ++ struct cfg80211_sched_scan_request *request) ++{ ++ ushort pno_time = PNO_TIME; ++ int pno_repeat = PNO_REPEAT; ++ int pno_freq_expo_max = PNO_FREQ_EXPO_MAX; ++ wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT]; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ struct cfg80211_ssid *ssid = NULL; ++ int ssid_count = 0; ++ int i; ++ int ret = 0; ++ ++ AP6211_DEBUG("Enter \n"); ++ AP6211_DEBUG(">>> SCHED SCAN START\n"); ++ AP6211_DEBUG("Enter n_match_sets:%d n_ssids:%d \n", ++ request->n_match_sets, request->n_ssids); ++ AP6211_DEBUG("ssids:%d pno_time:%d pno_repeat:%d pno_freq:%d \n", ++ request->n_ssids, pno_time, pno_repeat, pno_freq_expo_max); ++ ++ ++ if (!request || !request->n_ssids || !request->n_match_sets) { ++ AP6211_ERR("Invalid sched scan req!! n_ssids:%d \n", request->n_ssids); ++ return -EINVAL; ++ } ++ ++ memset(&ssids_local, 0, sizeof(ssids_local)); ++ ++ if (request->n_match_sets > 0) { ++ for (i = 0; i < request->n_match_sets; i++) { ++ ssid = &request->match_sets[i].ssid; ++ memcpy(ssids_local[i].SSID, ssid->ssid, ssid->ssid_len); ++ ssids_local[i].SSID_len = ssid->ssid_len; ++ AP6211_DEBUG(">>> PNO filter set for ssid (%s) \n", ssid->ssid); ++ ssid_count++; ++ } ++ } ++ ++ if (request->n_ssids > 0) { ++ for (i = 0; i < request->n_ssids; i++) { ++ /* Active scan req for ssids */ ++ AP6211_DEBUG(">>> Active scan req for ssid (%s) \n", request->ssids[i].ssid); ++ ++ /* match_set ssids is a supert set of n_ssid list, so we need ++ * not add these set seperately ++ */ ++ } ++ } ++ ++ if (ssid_count) { ++ if ((ret = dhd_dev_pno_set(dev, ssids_local, request->n_match_sets, ++ pno_time, pno_repeat, pno_freq_expo_max)) < 0) { ++ AP6211_ERR("PNO setup failed!! ret=%d \n", ret); ++ return -EINVAL; ++ } ++ ++ /* Enable the PNO */ ++ if (dhd_dev_pno_enable(dev, 1) < 0) { ++ AP6211_ERR("PNO enable failed!! ret=%d \n", ret); ++ return -EINVAL; ++ } ++ wl->sched_scan_req = request; ++ } else { ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++int wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev) ++{ ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ ++ AP6211_DEBUG("Enter \n"); ++ AP6211_DEBUG(">>> SCHED SCAN STOP\n"); ++ ++ if (dhd_dev_pno_enable(dev, 0) < 0) ++ AP6211_ERR("PNO disable failed"); ++ ++ if (dhd_dev_pno_reset(dev) < 0) ++ AP6211_ERR("PNO reset failed"); ++ ++ if (wl->scan_request && wl->sched_scan_running) { ++ AP6211_DEBUG(">>> Sched scan running. Aborting it..\n"); ++ wl_notify_escan_complete(wl, dev, true, true); ++ } ++ ++ wl->sched_scan_req = NULL; ++ wl->sched_scan_running = FALSE; ++ ++ return 0; ++} ++#endif /* WL_SCHED_SCAN */ ++ ++static struct cfg80211_ops wl_cfg80211_ops = { ++ .add_virtual_intf = wl_cfg80211_add_virtual_iface, ++ .del_virtual_intf = wl_cfg80211_del_virtual_iface, ++ .change_virtual_intf = wl_cfg80211_change_virtual_iface, ++ .scan = wl_cfg80211_scan, ++ .set_wiphy_params = wl_cfg80211_set_wiphy_params, ++ .join_ibss = wl_cfg80211_join_ibss, ++ .leave_ibss = wl_cfg80211_leave_ibss, ++ .get_station = wl_cfg80211_get_station, ++ .set_tx_power = wl_cfg80211_set_tx_power, ++ .get_tx_power = wl_cfg80211_get_tx_power, ++ .add_key = wl_cfg80211_add_key, ++ .del_key = wl_cfg80211_del_key, ++ .get_key = wl_cfg80211_get_key, ++ .set_default_key = wl_cfg80211_config_default_key, ++ .set_default_mgmt_key = wl_cfg80211_config_default_mgmt_key, ++ .set_power_mgmt = wl_cfg80211_set_power_mgmt, ++ .connect = wl_cfg80211_connect, ++ .disconnect = wl_cfg80211_disconnect, ++ .suspend = wl_cfg80211_suspend, ++ .resume = wl_cfg80211_resume, ++ .set_pmksa = wl_cfg80211_set_pmksa, ++ .del_pmksa = wl_cfg80211_del_pmksa, ++ .flush_pmksa = wl_cfg80211_flush_pmksa, ++ .remain_on_channel = wl_cfg80211_remain_on_channel, ++ .cancel_remain_on_channel = wl_cfg80211_cancel_remain_on_channel, ++ .mgmt_tx = wl_cfg80211_mgmt_tx, ++ .mgmt_frame_register = wl_cfg80211_mgmt_frame_register, ++ .change_bss = wl_cfg80211_change_bss, ++ .set_channel = wl_cfg80211_set_channel, ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) ++ .set_beacon = wl_cfg80211_add_set_beacon, ++ .add_beacon = wl_cfg80211_add_set_beacon, ++#else ++ .change_beacon = wl_cfg80211_change_beacon, ++ .start_ap = wl_cfg80211_start_ap, ++ .stop_ap = wl_cfg80211_stop_ap, ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) */ ++#ifdef WL_SCHED_SCAN ++ .sched_scan_start = wl_cfg80211_sched_scan_start, ++ .sched_scan_stop = wl_cfg80211_sched_scan_stop, ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) */ ++#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ ++ 2, 0)) ++ .del_station = wl_cfg80211_del_station, ++ .mgmt_tx_cancel_wait = wl_cfg80211_mgmt_tx_cancel_wait, ++#endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VERSION >= (3,2,0) */ ++}; ++ ++s32 wl_mode_to_nl80211_iftype(s32 mode) ++{ ++ s32 err = 0; ++ ++ switch (mode) { ++ case WL_MODE_BSS: ++ return NL80211_IFTYPE_STATION; ++ case WL_MODE_IBSS: ++ return NL80211_IFTYPE_ADHOC; ++ case WL_MODE_AP: ++ return NL80211_IFTYPE_AP; ++ default: ++ return NL80211_IFTYPE_UNSPECIFIED; ++ } ++ ++ return err; ++} ++ ++static int ++wl_cfg80211_reg_notifier( ++ struct wiphy *wiphy, ++ struct regulatory_request *request) ++{ ++ struct wl_priv *wl = (struct wl_priv *)wiphy_priv(wiphy); ++ wl_country_t cspec = {{0}, 0, {0} }; ++ int ret = 0; ++ ++ if (!request || !wl) { ++ AP6211_ERR("Invalid arg\n"); ++ return -EINVAL; ++ } ++ ++ AP6211_DEBUG("ccode: %c%c Initiator: %d\n", ++ request->alpha2[0], request->alpha2[1], request->initiator); ++ ++ /* We support only REGDOM_SET_BY_USER as of now */ ++ if (request->initiator != NL80211_REGDOM_SET_BY_USER) { ++ AP6211_ERR("reg_notifier for intiator:%d not supported \n", ++ request->initiator); ++ return -ENOTSUPP; ++ } ++ ++ if (request->alpha2[0] == '0' && request->alpha2[1] == '0') { ++ /* world domain */ ++ AP6211_ERR("World domain. Setting XY/4 \n"); ++ strncpy(cspec.country_abbrev, "XY", strlen("XY")); ++ cspec.rev = 4; ++ } else { ++ memcpy(cspec.country_abbrev, request->alpha2, 2); ++ cspec.country_abbrev[3] = '\0'; ++ cspec.rev = -1; /* Unspecified */ ++ } ++ ++ if ((ret = wldev_iovar_setbuf(wl_to_prmry_ndev(wl), "country", (char *)&cspec, ++ sizeof(cspec), wl->ioctl_buf, WLC_IOCTL_SMLEN, NULL)) < 0) { ++ AP6211_ERR("set country Failed :%d\n", ret); ++ goto exit; ++ } ++ ++ if ((ret = wl_update_wiphybands(wl, false)) < 0) { ++ AP6211_ERR("wl_update_wiphybands failed\n"); ++ goto exit; ++ } ++ ++ AP6211_DEBUG("%s: set country '%s/%d' done\n", ++ __FUNCTION__, cspec.country_abbrev, cspec.rev); ++ ++exit: ++ return ret; ++} ++ ++static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev) ++{ ++ s32 err = 0; ++ wdev->wiphy = ++ wiphy_new(&wl_cfg80211_ops, sizeof(struct wl_priv)); ++ if (unlikely(!wdev->wiphy)) { ++ AP6211_ERR("Couldn not allocate wiphy device\n"); ++ err = -ENOMEM; ++ return err; ++ } ++ set_wiphy_dev(wdev->wiphy, sdiofunc_dev); ++ wdev->wiphy->max_scan_ie_len = WL_SCAN_IE_LEN_MAX; ++ /* Report how many SSIDs Driver can support per Scan request */ ++ wdev->wiphy->max_scan_ssids = WL_SCAN_PARAMS_SSID_MAX; ++ wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; ++#ifdef WL_SCHED_SCAN ++ wdev->wiphy->max_sched_scan_ssids = MAX_PFN_LIST_COUNT; ++ wdev->wiphy->max_match_sets = MAX_PFN_LIST_COUNT; ++ wdev->wiphy->max_sched_scan_ie_len = WL_SCAN_IE_LEN_MAX; ++ wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; ++#endif /* WL_SCHED_SCAN */ ++ wdev->wiphy->interface_modes = ++ BIT(NL80211_IFTYPE_STATION) ++#if !(defined(WLP2P) && defined(WL_ENABLE_P2P_IF)) ++ | BIT(NL80211_IFTYPE_MONITOR) ++#endif ++ | BIT(NL80211_IFTYPE_AP); ++ ++ wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; ++ ++ wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; ++ wdev->wiphy->cipher_suites = __wl_cipher_suites; ++ wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); ++ wdev->wiphy->max_remain_on_channel_duration = 5000; ++ wdev->wiphy->mgmt_stypes = wl_cfg80211_default_mgmt_stypes; ++#ifndef WL_POWERSAVE_DISABLED ++ wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; ++#else ++ wdev->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; ++#endif /* !WL_POWERSAVE_DISABLED */ ++ wdev->wiphy->flags |= WIPHY_FLAG_NETNS_OK | ++ WIPHY_FLAG_4ADDR_AP | ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39) ++ WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS | ++#endif ++ WIPHY_FLAG_4ADDR_STATION; ++ /* If driver advertises FW_ROAM, the supplicant wouldn't ++ * send the BSSID & Freq in the connect command allowing the ++ * the driver to choose the AP to connect to. But unless we ++ * support ROAM_CACHE in firware this will delay the ASSOC as ++ * as the FW need to do a full scan before attempting to connect ++ * So that feature will just increase assoc. The better approach ++ * to let Supplicant to provide channel info and FW letter may roam ++ * if needed so DON'T advertise that featur eto Supplicant. ++ */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) ++ /* wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; */ ++#endif ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0) ++ wdev->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | ++ WIPHY_FLAG_OFFCHAN_TX; ++#endif ++#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ ++ 4, 0)) ++ /* From 3.4 kernel ownards AP_SME flag can be advertised ++ * to remove the patch from supplicant ++ */ ++ wdev->wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME; ++#endif ++ ++ wdev->wiphy->reg_notifier = wl_cfg80211_reg_notifier; ++ ++ AP6211_DEBUG("Registering custom regulatory)\n"); ++ wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; ++ wiphy_apply_custom_regulatory(wdev->wiphy, &brcm_regdom); ++ /* Now we can register wiphy with cfg80211 module */ ++ err = wiphy_register(wdev->wiphy); ++ if (unlikely(err < 0)) { ++ AP6211_ERR("Couldn not register wiphy device (%d)\n", err); ++ wiphy_free(wdev->wiphy); ++ } ++ return err; ++} ++ ++static void wl_free_wdev(struct wl_priv *wl) ++{ ++ struct wireless_dev *wdev = wl->wdev; ++ struct wiphy *wiphy; ++ if (!wdev) { ++ AP6211_ERR("wdev is invalid\n"); ++ return; ++ } ++ wiphy = wdev->wiphy; ++ wiphy_unregister(wdev->wiphy); ++ wdev->wiphy->dev.parent = NULL; ++ ++ wl_delete_all_netinfo(wl); ++ wiphy_free(wiphy); ++ /* PLEASE do NOT call any function after wiphy_free, the driver's private structure "wl", ++ * which is the private part of wiphy, has been freed in wiphy_free !!!!!!!!!!! ++ */ ++} ++ ++#if defined(RSSIAVG) ++static wl_rssi_cache_ctrl_t g_rssi_cache_ctrl; ++#endif ++#if defined(BSSCACHE) ++static wl_bss_cache_ctrl_t g_bss_cache_ctrl; ++#endif ++ ++static s32 wl_inform_bss(struct wl_priv *wl) ++{ ++ struct wl_scan_results *bss_list; ++ struct wl_bss_info *bi = NULL; /* must be initialized */ ++ s32 err = 0; ++ s32 i; ++#if defined(RSSIAVG) ++ struct net_device *ndev = wl_to_prmry_ndev(wl); ++#endif ++#if defined(BSSCACHE) ++ wl_bss_cache_t *node; ++#endif ++ ++ bss_list = wl->bss_list; ++#if defined(BSSCACHE) ++ if (g_bss_cache_ctrl.m_timer_expired || (p2p_is_on(wl) && p2p_scan(wl))) { ++#if defined(RSSIAVG) ++ wl_free_rssi_cache(&g_rssi_cache_ctrl); ++#endif ++ wl_free_bss_cache(&g_bss_cache_ctrl); ++ g_bss_cache_ctrl.m_timer_expired ^= 1; ++ } ++ wl_update_bss_cache(&g_bss_cache_ctrl, bss_list); ++ wl_delete_dirty_bss_cache(&g_bss_cache_ctrl); ++ wl_reset_bss_cache(&g_bss_cache_ctrl); ++#endif ++ ++#if defined(RSSIAVG) ++#if defined(BSSCACHE) ++ node = g_bss_cache_ctrl.m_cache_head; ++ for (;node;) { ++ wl_update_rssi_cache(&g_rssi_cache_ctrl, &node->results); ++ node = node->next; ++ } ++#else ++ wl_update_rssi_cache(&g_rssi_cache_ctrl, bss_list); ++#endif ++ if (!in_atomic()) ++ wl_update_connected_rssi_cache(&g_rssi_cache_ctrl, ndev); ++ wl_delete_dirty_rssi_cache(&g_rssi_cache_ctrl); ++ wl_reset_rssi_cache(&g_rssi_cache_ctrl); ++#endif ++ ++ AP6211_DEBUG("scanned AP count (%d)\n", bss_list->count); ++ ++#if defined(BSSCACHE) ++ node = g_bss_cache_ctrl.m_cache_head; ++ for (i=0; node && iresults.bss_info; ++ err = wl_inform_single_bss(wl, bi, 0); ++ if (unlikely(err)) ++ break; ++ node = node->next; ++ } ++ wl_run_bss_cache_timer(&g_bss_cache_ctrl, 0); ++ wl_run_bss_cache_timer(&g_bss_cache_ctrl, 1); ++#else ++ bi = next_bss(bss_list, bi); ++ for_each_bss(bss_list, bi, i) { ++ err = wl_inform_single_bss(wl, bi, 0); ++ if (unlikely(err)) ++ break; ++ } ++#endif ++ return err; ++} ++ ++static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi, u8 is_roam_done) ++{ ++ struct wiphy *wiphy = wl_to_wiphy(wl); ++ struct ieee80211_mgmt *mgmt; ++ struct ieee80211_channel *channel; ++ struct ieee80211_supported_band *band; ++ struct wl_cfg80211_bss_info *notif_bss_info; ++ struct wl_scan_req *sr = wl_to_sr(wl); ++ struct beacon_proberesp *beacon_proberesp; ++ struct cfg80211_bss *cbss = NULL; ++ s32 mgmt_type; ++ s32 signal; ++ u32 freq; ++ s32 err = 0; ++ gfp_t aflags; ++ u8 *ie_offset = NULL; ++ ++ if (unlikely(dtoh32(bi->length) > WL_BSS_INFO_MAX)) { ++ AP6211_DEBUG("Beacon is larger than buffer. Discarding\n"); ++ return err; ++ } ++ aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL; ++ notif_bss_info = kzalloc(sizeof(*notif_bss_info) + sizeof(*mgmt) ++ - sizeof(u8) + WL_BSS_INFO_MAX, aflags); ++ if (unlikely(!notif_bss_info)) { ++ AP6211_ERR("notif_bss_info alloc failed\n"); ++ return -ENOMEM; ++ } ++ mgmt = (struct ieee80211_mgmt *)notif_bss_info->frame_buf; ++ notif_bss_info->channel = ++ bi->ctl_ch ? bi->ctl_ch : CHSPEC_CHANNEL(wl_chspec_driver_to_host(bi->chanspec)); ++ ++ if (notif_bss_info->channel <= CH_MAX_2G_CHANNEL) ++ band = wiphy->bands[IEEE80211_BAND_2GHZ]; ++ else ++ band = wiphy->bands[IEEE80211_BAND_5GHZ]; ++ if (!band) { ++ AP6211_ERR("No valid band"); ++ kfree(notif_bss_info); ++ return -EINVAL; ++ } ++ notif_bss_info->rssi = dtoh16(bi->RSSI); ++#if defined(RSSIAVG) ++ notif_bss_info->rssi = wl_get_avg_rssi(&g_rssi_cache_ctrl, &bi->BSSID); ++#endif ++#if defined(RSSIOFFSET) ++ notif_bss_info->rssi = wl_update_rssi_offset(notif_bss_info->rssi); ++#endif ++ memcpy(mgmt->bssid, &bi->BSSID, ETHER_ADDR_LEN); ++ mgmt_type = wl->active_scan ? ++ IEEE80211_STYPE_PROBE_RESP : IEEE80211_STYPE_BEACON; ++ if (!memcmp(bi->SSID, sr->ssid.SSID, bi->SSID_len)) { ++ mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | mgmt_type); ++ } ++ beacon_proberesp = wl->active_scan ? ++ (struct beacon_proberesp *)&mgmt->u.probe_resp : ++ (struct beacon_proberesp *)&mgmt->u.beacon; ++ beacon_proberesp->timestamp = 0; ++ beacon_proberesp->beacon_int = cpu_to_le16(bi->beacon_period); ++ beacon_proberesp->capab_info = cpu_to_le16(bi->capability); ++ wl_rst_ie(wl); ++ ++ ie_offset = ((u8 *) bi) + bi->ie_offset; ++ ++ if (is_roam_done && ((int)(*(ie_offset)) == WLAN_EID_SSID && ++ ((int)(*(ie_offset+1)) == 0 || (int)(*(ie_offset+2)) == 0))) { ++ u8 *ie_new_offset = NULL; ++ uint8 ie_new_length; ++ ++ AP6211_ERR("WAR trace: Changing the SSID Info, from beacon %d\n", ++ bi->flags & WL_BSS_FLAGS_FROM_BEACON); ++ ++ ie_new_offset = (u8 *)kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); ++ if (ie_new_offset) { ++ *(ie_new_offset) = WLAN_EID_SSID; ++ *(ie_new_offset+1) = bi->SSID_len; ++ memcpy(ie_new_offset+2, bi->SSID, bi->SSID_len); ++ ie_new_length = bi->ie_length - *(ie_offset+1) + bi->SSID_len; ++ ++ /* Copy the remaining IE apart from SSID IE from bi */ ++ memcpy(ie_new_offset+2 + bi->SSID_len, ++ ie_offset+2 + *(ie_offset+1), ++ bi->ie_length - 2 - *(ie_offset+1)); ++ wl_mrg_ie(wl, ie_new_offset, ie_new_length); ++ kfree(ie_new_offset); ++ } else { ++ wl_mrg_ie(wl, ((u8 *) bi) + bi->ie_offset, bi->ie_length); ++ } ++ } else { ++ wl_mrg_ie(wl, ((u8 *) bi) + bi->ie_offset, bi->ie_length); ++ } ++ ++ wl_cp_ie(wl, beacon_proberesp->variable, WL_BSS_INFO_MAX - ++ offsetof(struct wl_cfg80211_bss_info, frame_buf)); ++ notif_bss_info->frame_len = offsetof(struct ieee80211_mgmt, ++ u.beacon.variable) + wl_get_ielen(wl); ++#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) ++ freq = ieee80211_channel_to_frequency(notif_bss_info->channel); ++ (void)band->band; ++#else ++ freq = ieee80211_channel_to_frequency(notif_bss_info->channel, band->band); ++#endif ++ if (freq == 0) { ++ AP6211_ERR("Invalid channel, fail to chcnage channel to freq\n"); ++ kfree(notif_bss_info); ++ return -EINVAL; ++ } ++ channel = ieee80211_get_channel(wiphy, freq); ++ if (unlikely(!channel)) { ++ AP6211_ERR("ieee80211_get_channel error\n"); ++ kfree(notif_bss_info); ++ return -EINVAL; ++ } ++ AP6211_DEBUG("BSSID %pM, channel %d, rssi %d, capability 0x04%x, mgmt_type %d, " ++ "frame_len %d, SSID \"%s\"\n", &bi->BSSID, notif_bss_info->channel, ++ notif_bss_info->rssi, mgmt->u.beacon.capab_info, mgmt_type, ++ notif_bss_info->frame_len, bi->SSID); ++ ++ signal = notif_bss_info->rssi * 100; ++ if (!mgmt->u.probe_resp.timestamp) { ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) ++ struct timespec ts; ++ get_monotonic_boottime(&ts); ++ mgmt->u.probe_resp.timestamp = ((u64)ts.tv_sec*1000000) ++ + ts.tv_nsec / 1000; ++#else ++ struct timeval tv; ++ do_gettimeofday(&tv); ++ mgmt->u.probe_resp.timestamp = ((u64)tv.tv_sec*1000000) ++ + tv.tv_usec; ++#endif ++ } ++ ++ cbss = cfg80211_inform_bss_frame(wiphy, channel, mgmt, ++ le16_to_cpu(notif_bss_info->frame_len), signal, aflags); ++ if (unlikely(!cbss)) { ++ AP6211_ERR("cfg80211_inform_bss_frame error\n"); ++ kfree(notif_bss_info); ++ return -EINVAL; ++ } ++ ++ cfg80211_put_bss(cbss); ++ kfree(notif_bss_info); ++ return err; ++} ++ ++static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e, struct net_device *ndev) ++{ ++ u32 event = ntoh32(e->event_type); ++ u32 status = ntoh32(e->status); ++ u16 flags = ntoh16(e->flags); ++ ++ AP6211_DEBUG("event %d, status %d flags %x\n", event, status, flags); ++ if (event == WLC_E_SET_SSID) { ++ if (status == WLC_E_STATUS_SUCCESS) { ++ if (!wl_is_ibssmode(wl, ndev)) ++ return true; ++ } ++ } else if (event == WLC_E_LINK) { ++ if (flags & WLC_EVENT_MSG_LINK) ++ return true; ++ } ++ ++ AP6211_DEBUG("wl_is_linkup false\n"); ++ return false; ++} ++ ++static bool wl_is_linkdown(struct wl_priv *wl, const wl_event_msg_t *e) ++{ ++ u32 event = ntoh32(e->event_type); ++ u16 flags = ntoh16(e->flags); ++ ++ if (event == WLC_E_DEAUTH_IND || ++ event == WLC_E_DISASSOC_IND || ++ event == WLC_E_DISASSOC || ++ event == WLC_E_DEAUTH) { ++#if (WL_DBG_LEVEL > 0) ++ AP6211_ERR("Link down Reason : WLC_E_%s\n", wl_dbg_estr[event]); ++#endif /* (WL_DBG_LEVEL > 0) */ ++ return true; ++ } else if (event == WLC_E_LINK) { ++ if (!(flags & WLC_EVENT_MSG_LINK)) { ++#if (WL_DBG_LEVEL > 0) ++ AP6211_ERR("Link down Reason : WLC_E_%s\n", wl_dbg_estr[event]); ++#endif /* (WL_DBG_LEVEL > 0) */ ++ return true; ++ } ++ } ++ ++ return false; ++} ++ ++static bool wl_is_nonetwork(struct wl_priv *wl, const wl_event_msg_t *e) ++{ ++ u32 event = ntoh32(e->event_type); ++ u32 status = ntoh32(e->status); ++ ++ if (event == WLC_E_LINK && status == WLC_E_STATUS_NO_NETWORKS) ++ return true; ++ if (event == WLC_E_SET_SSID && status != WLC_E_STATUS_SUCCESS) ++ return true; ++ ++ return false; ++} ++ ++/* The mainline kernel >= 3.2.0 has support for indicating new/del station ++ * to AP/P2P GO via events. If this change is backported to kernel for which ++ * this driver is being built, then define WL_CFG80211_STA_EVENT. You ++ * should use this new/del sta event mechanism for BRCM supplicant >= 22. ++ */ ++static s32 ++wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data) ++{ ++ s32 err = 0; ++ u32 event = ntoh32(e->event_type); ++ u32 reason = ntoh32(e->reason); ++ u32 len = ntoh32(e->datalen); ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT) ++ bool isfree = false; ++ u8 *mgmt_frame; ++ u8 bsscfgidx = e->bsscfgidx; ++ s32 freq; ++ s32 channel; ++ u8 *body = NULL; ++ u16 fc = 0; ++ ++ struct ieee80211_supported_band *band; ++ struct ether_addr da; ++ struct ether_addr bssid; ++ struct wiphy *wiphy = wl_to_wiphy(wl); ++ channel_info_t ci; ++#else ++ struct station_info sinfo; ++#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !WL_CFG80211_STA_EVENT */ ++ ++ AP6211_DEBUG("event %d status %d reason %d\n", event, ntoh32(e->status), reason); ++ /* if link down, bsscfg is disabled. */ ++ if (event == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS && ++ wl_get_p2p_status(wl, IF_DELETING) && (ndev != wl_to_prmry_ndev(wl))) { ++ wl_add_remove_eventmsg(ndev, WLC_E_PROBREQ_MSG, false); ++ AP6211_DEBUG("AP mode link down !! \n"); ++ complete(&wl->iface_disable); ++ return 0; ++ } ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT) ++ AP6211_DEBUG("Enter \n"); ++ if (!len && (event == WLC_E_DEAUTH)) { ++ len = 2; /* reason code field */ ++ data = &reason; ++ } ++ if (len) { ++ body = kzalloc(len, GFP_KERNEL); ++ ++ if (body == NULL) { ++ AP6211_ERR("wl_notify_connect_status: Failed to allocate body\n"); ++ return WL_INVALID; ++ } ++ } ++ memset(&bssid, 0, ETHER_ADDR_LEN); ++ AP6211_DEBUG("Enter event %d ndev %p\n", event, ndev); ++ if (wl_get_mode_by_netdev(wl, ndev) == WL_INVALID) { ++ kfree(body); ++ return WL_INVALID; ++ } ++ if (len) ++ memcpy(body, data, len); ++ ++ wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr", ++ NULL, 0, wl->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &wl->ioctl_buf_sync); ++ memcpy(da.octet, wl->ioctl_buf, ETHER_ADDR_LEN); ++ err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); ++ switch (event) { ++ case WLC_E_ASSOC_IND: ++ fc = FC_ASSOC_REQ; ++ break; ++ case WLC_E_REASSOC_IND: ++ fc = FC_REASSOC_REQ; ++ break; ++ case WLC_E_DISASSOC_IND: ++ fc = FC_DISASSOC; ++ break; ++ case WLC_E_DEAUTH_IND: ++ fc = FC_DISASSOC; ++ break; ++ case WLC_E_DEAUTH: ++ fc = FC_DISASSOC; ++ break; ++ default: ++ fc = 0; ++ goto exit; ++ } ++ if ((err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci), false))) { ++ kfree(body); ++ return err; ++ } ++ ++ channel = dtoh32(ci.hw_channel); ++ if (channel <= CH_MAX_2G_CHANNEL) ++ band = wiphy->bands[IEEE80211_BAND_2GHZ]; ++ else ++ band = wiphy->bands[IEEE80211_BAND_5GHZ]; ++ if (!band) { ++ AP6211_ERR("No valid band"); ++ if (body) ++ kfree(body); ++ return -EINVAL; ++ } ++#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) ++ freq = ieee80211_channel_to_frequency(channel); ++ (void)band->band; ++#else ++ freq = ieee80211_channel_to_frequency(channel, band->band); ++#endif ++ ++ err = wl_frame_get_mgmt(fc, &da, &e->addr, &bssid, ++ &mgmt_frame, &len, body); ++ if (err < 0) ++ goto exit; ++ isfree = true; ++ ++ if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) { ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) ++ cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC); ++#else ++ cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */ ++ } else if (event == WLC_E_DISASSOC_IND) { ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) ++ cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC); ++#else ++ cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */ ++ } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) { ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) ++ cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC); ++#else ++ cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */ ++ } ++ ++exit: ++ if (isfree) ++ kfree(mgmt_frame); ++ if (body) ++ kfree(body); ++ return err; ++#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0) && !WL_CFG80211_STA_EVENT */ ++ sinfo.filled = 0; ++ if (((event == WLC_E_ASSOC_IND) || (event == WLC_E_REASSOC_IND)) && ++ reason == DOT11_SC_SUCCESS) { ++ sinfo.filled = STATION_INFO_ASSOC_REQ_IES; ++ if (!data) { ++ AP6211_ERR("No IEs present in ASSOC/REASSOC_IND"); ++ return -EINVAL; ++ } ++ sinfo.assoc_req_ies = data; ++ sinfo.assoc_req_ies_len = len; ++ cfg80211_new_sta(ndev, e->addr.octet, &sinfo, GFP_ATOMIC); ++ } else if (event == WLC_E_DISASSOC_IND) { ++ cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC); ++ } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) { ++ cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC); ++ } ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0) && !WL_CFG80211_STA_EVENT */ ++ return err; ++} ++ ++static s32 ++wl_get_auth_assoc_status(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e) ++{ ++ u32 reason = ntoh32(e->reason); ++ u32 event = ntoh32(e->event_type); ++ struct wl_security *sec = wl_read_prof(wl, ndev, WL_PROF_SEC); ++ AP6211_DEBUG("event type : %d, reason : %d\n", event, reason); ++ if (sec) { ++ switch (event) { ++ case WLC_E_ASSOC: ++ case WLC_E_AUTH: ++ sec->auth_assoc_res_status = reason; ++ default: ++ break; ++ } ++ } else ++ AP6211_ERR("sec is NULL\n"); ++ return 0; ++} ++ ++static s32 ++wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data) ++{ ++ bool act; ++ s32 err = 0; ++ u32 event = ntoh32(e->event_type); ++ ++ if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_AP) { ++ wl_notify_connect_status_ap(wl, ndev, e, data); ++ } else { ++ AP6211_DEBUG("wl_notify_connect_status : event %d status : %d ndev %p\n", ++ ntoh32(e->event_type), ntoh32(e->status), ndev); ++ if (event == WLC_E_ASSOC || event == WLC_E_AUTH) { ++ wl_get_auth_assoc_status(wl, ndev, e); ++ return err; ++ } ++ if (wl_is_linkup(wl, e, ndev)) { ++ wl_link_up(wl); ++ act = true; ++ if (wl_is_ibssmode(wl, ndev)) { ++ AP6211_DEBUG("cfg80211_ibss_joined\n"); ++ cfg80211_ibss_joined(ndev, (s8 *)&e->addr, ++ GFP_KERNEL); ++ AP6211_DEBUG("joined in IBSS network\n"); ++ } else { ++ if (!wl_get_drv_status(wl, DISCONNECTING, ndev)) { ++ AP6211_DEBUG("wl_bss_connect_done succeeded with " MACDBG "\n", ++ MAC2STRDBG((u8*)(&e->addr))); ++ wl_bss_connect_done(wl, ndev, e, data, true); ++ AP6211_DEBUG("joined in BSS network \"%s\"\n", ++ ((struct wlc_ssid *) ++ wl_read_prof(wl, ndev, WL_PROF_SSID))->SSID); ++ } ++ } ++ wl_update_prof(wl, ndev, e, &act, WL_PROF_ACT); ++ wl_update_prof(wl, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID); ++ ++ } else if (wl_is_linkdown(wl, e)) { ++ if (wl->scan_request) { ++ if (wl->escan_on) { ++ wl_notify_escan_complete(wl, ndev, true, true); ++ } else { ++ del_timer_sync(&wl->scan_timeout); ++ wl_iscan_aborted(wl); ++ } ++ } ++ if (wl_get_drv_status(wl, CONNECTED, ndev)) { ++ scb_val_t scbval; ++ u8 *curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); ++ s32 reason = 0; ++ if (event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) ++ reason = ntoh32(e->reason); ++ /* WLAN_REASON_UNSPECIFIED is used for hang up event in Android */ ++ reason = (reason == WLAN_REASON_UNSPECIFIED)? 0 : reason; ++ ++ AP6211_DEBUG("link down if %s may call cfg80211_disconnected. " ++ "event : %d, reason=%d from " MACDBG "\n", ++ ndev->name, event, ntoh32(e->reason), ++ MAC2STRDBG((u8*)(&e->addr))); ++ if (memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) != 0) { ++ AP6211_ERR("BSSID of event is not the connected BSSID" ++ "(ignore it) cur: " MACDBG " event: " MACDBG"\n", ++ MAC2STRDBG(curbssid), MAC2STRDBG((u8*)(&e->addr))); ++ return 0; ++ } ++ wl_clr_drv_status(wl, CONNECTED, ndev); ++ if (! wl_get_drv_status(wl, DISCONNECTING, ndev)) { ++ /* To make sure disconnect, explictly send dissassoc ++ * for BSSID 00:00:00:00:00:00 issue ++ */ ++ scbval.val = WLAN_REASON_DEAUTH_LEAVING; ++ ++ memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); ++ scbval.val = htod32(scbval.val); ++ err = wldev_ioctl(ndev, WLC_DISASSOC, &scbval, ++ sizeof(scb_val_t), true); ++ if (err < 0) { ++ AP6211_ERR("WLC_DISASSOC error %d\n", err); ++ err = 0; ++ } ++ cfg80211_disconnected(ndev, reason, NULL, 0, GFP_KERNEL); ++ wl_link_down(wl); ++ wl_init_prof(wl, ndev); ++ } ++ } ++ else if (wl_get_drv_status(wl, CONNECTING, ndev)) { ++ AP6211_DEBUG("link down, during connecting\n"); ++#ifdef ESCAN_RESULT_PATCH ++ if ((memcmp(connect_req_bssid, broad_bssid, ETHER_ADDR_LEN) == 0) || ++ (memcmp(&e->addr, broad_bssid, ETHER_ADDR_LEN) == 0) || ++ (memcmp(&e->addr, connect_req_bssid, ETHER_ADDR_LEN) == 0)) ++ /* In case this event comes while associating another AP */ ++#endif /* ESCAN_RESULT_PATCH */ ++ wl_bss_connect_done(wl, ndev, e, data, false); ++ } ++ wl_clr_drv_status(wl, DISCONNECTING, ndev); ++ ++ /* if link down, bsscfg is diabled */ ++ if (ndev != wl_to_prmry_ndev(wl)) ++ complete(&wl->iface_disable); ++ ++ } else if (wl_is_nonetwork(wl, e)) { ++ AP6211_DEBUG("connect failed event=%d e->status %d e->reason %d \n", ++ event, (int)ntoh32(e->status), (int)ntoh32(e->reason)); ++ /* Clean up any pending scan request */ ++ if (wl->scan_request) { ++ if (wl->escan_on) { ++ wl_notify_escan_complete(wl, ndev, true, true); ++ } else { ++ del_timer_sync(&wl->scan_timeout); ++ wl_iscan_aborted(wl); ++ } ++ } ++ if (wl_get_drv_status(wl, CONNECTING, ndev)) ++ wl_bss_connect_done(wl, ndev, e, data, false); ++ } else { ++ AP6211_DEBUG("%s nothing\n", __FUNCTION__); ++ } ++ } ++ return err; ++} ++ ++static s32 ++wl_notify_roaming_status(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data) ++{ ++ bool act; ++ s32 err = 0; ++ u32 event = be32_to_cpu(e->event_type); ++ u32 status = be32_to_cpu(e->status); ++ AP6211_DEBUG("Enter \n"); ++ if (event == WLC_E_ROAM && status == WLC_E_STATUS_SUCCESS) { ++ if (wl_get_drv_status(wl, CONNECTED, ndev)) ++ wl_bss_roaming_done(wl, ndev, e, data); ++ else ++ wl_bss_connect_done(wl, ndev, e, data, true); ++ act = true; ++ wl_update_prof(wl, ndev, e, &act, WL_PROF_ACT); ++ wl_update_prof(wl, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID); ++ } ++ return err; ++} ++ ++static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev) ++{ ++ wl_assoc_info_t assoc_info; ++ struct wl_connect_info *conn_info = wl_to_conn(wl); ++ s32 err = 0; ++ ++ AP6211_DEBUG("Enter \n"); ++ err = wldev_iovar_getbuf(ndev, "assoc_info", NULL, 0, wl->extra_buf, ++ WL_ASSOC_INFO_MAX, NULL); ++ if (unlikely(err)) { ++ AP6211_ERR("could not get assoc info (%d)\n", err); ++ return err; ++ } ++ memcpy(&assoc_info, wl->extra_buf, sizeof(wl_assoc_info_t)); ++ assoc_info.req_len = htod32(assoc_info.req_len); ++ assoc_info.resp_len = htod32(assoc_info.resp_len); ++ assoc_info.flags = htod32(assoc_info.flags); ++ if (conn_info->req_ie_len) { ++ conn_info->req_ie_len = 0; ++ bzero(conn_info->req_ie, sizeof(conn_info->req_ie)); ++ } ++ if (conn_info->resp_ie_len) { ++ conn_info->resp_ie_len = 0; ++ bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie)); ++ } ++ if (assoc_info.req_len) { ++ err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, wl->extra_buf, ++ WL_ASSOC_INFO_MAX, NULL); ++ if (unlikely(err)) { ++ AP6211_ERR("could not get assoc req (%d)\n", err); ++ return err; ++ } ++ conn_info->req_ie_len = assoc_info.req_len - sizeof(struct dot11_assoc_req); ++ if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) { ++ conn_info->req_ie_len -= ETHER_ADDR_LEN; ++ } ++ if (conn_info->req_ie_len <= MAX_REQ_LINE) ++ memcpy(conn_info->req_ie, wl->extra_buf, conn_info->req_ie_len); ++ else { ++ AP6211_ERR("%s IE size %d above max %d size \n", ++ __FUNCTION__, conn_info->req_ie_len, MAX_REQ_LINE); ++ return err; ++ } ++ } else { ++ conn_info->req_ie_len = 0; ++ } ++ if (assoc_info.resp_len) { ++ err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, wl->extra_buf, ++ WL_ASSOC_INFO_MAX, NULL); ++ if (unlikely(err)) { ++ AP6211_ERR("could not get assoc resp (%d)\n", err); ++ return err; ++ } ++ conn_info->resp_ie_len = assoc_info.resp_len -sizeof(struct dot11_assoc_resp); ++ if (conn_info->resp_ie_len <= MAX_REQ_LINE) ++ memcpy(conn_info->resp_ie, wl->extra_buf, conn_info->resp_ie_len); ++ else { ++ AP6211_ERR("%s IE size %d above max %d size \n", ++ __FUNCTION__, conn_info->resp_ie_len, MAX_REQ_LINE); ++ return err; ++ } ++ } else { ++ conn_info->resp_ie_len = 0; ++ } ++ AP6211_DEBUG("req len (%d) resp len (%d)\n", conn_info->req_ie_len, ++ conn_info->resp_ie_len); ++ ++ return err; ++} ++ ++static void wl_ch_to_chanspec(int ch, struct wl_join_params *join_params, ++ size_t *join_params_size) ++{ ++ chanspec_t chanspec = 0; ++ if (ch != 0) { ++ join_params->params.chanspec_num = 1; ++ join_params->params.chanspec_list[0] = ch; ++ ++ if (join_params->params.chanspec_list[0] <= CH_MAX_2G_CHANNEL) ++ chanspec |= WL_CHANSPEC_BAND_2G; ++ else ++ chanspec |= WL_CHANSPEC_BAND_5G; ++ ++ chanspec |= WL_CHANSPEC_BW_20; ++ chanspec |= WL_CHANSPEC_CTL_SB_NONE; ++ ++ *join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE + ++ join_params->params.chanspec_num * sizeof(chanspec_t); ++ ++ join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK; ++ join_params->params.chanspec_list[0] |= chanspec; ++ join_params->params.chanspec_list[0] = ++ wl_chspec_host_to_driver(join_params->params.chanspec_list[0]); ++ ++ join_params->params.chanspec_num = ++ htod32(join_params->params.chanspec_num); ++ AP6211_DEBUG("join_params->params.chanspec_list[0]= %X, %d channels\n", ++ join_params->params.chanspec_list[0], ++ join_params->params.chanspec_num); ++ } ++} ++ ++static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev, u8 is_roam_done) ++{ ++ struct cfg80211_bss *bss; ++ struct wl_bss_info *bi; ++ struct wlc_ssid *ssid; ++ struct bcm_tlv *tim; ++ s32 beacon_interval; ++ s32 dtim_period; ++ size_t ie_len; ++ u8 *ie; ++ u8 *ssidie; ++ u8 *curbssid; ++ s32 err = 0; ++ struct wiphy *wiphy; ++ ++ wiphy = wl_to_wiphy(wl); ++ ++ if (wl_is_ibssmode(wl, ndev)) ++ return err; ++ ++ ssid = (struct wlc_ssid *)wl_read_prof(wl, ndev, WL_PROF_SSID); ++ curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); ++ bss = cfg80211_get_bss(wiphy, NULL, curbssid, ++ ssid->SSID, ssid->SSID_len, WLAN_CAPABILITY_ESS, ++ WLAN_CAPABILITY_ESS); ++ ++ mutex_lock(&wl->usr_sync); ++ if (!bss) { ++ AP6211_DEBUG("Could not find the AP\n"); ++ *(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX); ++ err = wldev_ioctl(ndev, WLC_GET_BSS_INFO, ++ wl->extra_buf, WL_EXTRA_BUF_MAX, false); ++ if (unlikely(err)) { ++ AP6211_ERR("Could not get bss info %d\n", err); ++ goto update_bss_info_out; ++ } ++ bi = (struct wl_bss_info *)(wl->extra_buf + 4); ++ if (memcmp(bi->BSSID.octet, curbssid, ETHER_ADDR_LEN)) { ++ err = -EIO; ++ goto update_bss_info_out; ++ } ++ ++ ie = ((u8 *)bi) + bi->ie_offset; ++ ie_len = bi->ie_length; ++ ssidie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ie, ie_len); ++ if (ssidie && ssidie[1] == bi->SSID_len && !ssidie[2] && bi->SSID[0]) ++ memcpy(ssidie + 2, bi->SSID, bi->SSID_len); ++ ++ err = wl_inform_single_bss(wl, bi, is_roam_done); ++ if (unlikely(err)) ++ goto update_bss_info_out; ++ ++ ie = ((u8 *)bi) + bi->ie_offset; ++ ie_len = bi->ie_length; ++ beacon_interval = cpu_to_le16(bi->beacon_period); ++ } else { ++ AP6211_DEBUG("Found the AP in the list - BSSID %pM\n", bss->bssid); ++ ie = bss->information_elements; ++ ie_len = bss->len_information_elements; ++ beacon_interval = bss->beacon_interval; ++ cfg80211_put_bss(bss); ++ } ++ ++ tim = bcm_parse_tlvs(ie, ie_len, WLAN_EID_TIM); ++ if (tim) { ++ dtim_period = tim->data[1]; ++ } else { ++ /* ++ * active scan was done so we could not get dtim ++ * information out of probe response. ++ * so we speficially query dtim information. ++ */ ++ err = wldev_ioctl(ndev, WLC_GET_DTIMPRD, ++ &dtim_period, sizeof(dtim_period), false); ++ if (unlikely(err)) { ++ AP6211_ERR("WLC_GET_DTIMPRD error (%d)\n", err); ++ goto update_bss_info_out; ++ } ++ } ++ ++ wl_update_prof(wl, ndev, NULL, &beacon_interval, WL_PROF_BEACONINT); ++ wl_update_prof(wl, ndev, NULL, &dtim_period, WL_PROF_DTIMPERIOD); ++ ++update_bss_info_out: ++ mutex_unlock(&wl->usr_sync); ++ return err; ++} ++ ++static s32 ++wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data) ++{ ++ struct wl_connect_info *conn_info = wl_to_conn(wl); ++ s32 err = 0; ++ u8 *curbssid; ++ ++ wl_get_assoc_ies(wl, ndev); ++ wl_update_prof(wl, ndev, NULL, (void *)(e->addr.octet), WL_PROF_BSSID); ++ curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); ++ wl_update_bss_info(wl, ndev, 1); ++ wl_update_pmklist(ndev, wl->pmk_list, err); ++ AP6211_DEBUG("wl_bss_roaming_done succeeded to " MACDBG "\n", ++ MAC2STRDBG((u8*)(&e->addr))); ++ ++ cfg80211_roamed(ndev, ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0) ++ NULL, /* struct cfg80211_bss *bss */ ++#elif LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39) ++ NULL, ++#endif ++ curbssid, ++ conn_info->req_ie, conn_info->req_ie_len, ++ conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL); ++ AP6211_DEBUG("Report roaming result\n"); ++ ++ wl_set_drv_status(wl, CONNECTED, ndev); ++ ++ return err; ++} ++ ++static s32 ++wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data, bool completed) ++{ ++ struct wl_connect_info *conn_info = wl_to_conn(wl); ++ struct wl_security *sec = wl_read_prof(wl, ndev, WL_PROF_SEC); ++ s32 err = 0; ++ u8 *curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); ++ if (!sec) { ++ AP6211_ERR("sec is NULL\n"); ++ return -ENODEV; ++ } ++ AP6211_DEBUG(" enter\n"); ++#ifdef ESCAN_RESULT_PATCH ++ if (wl_get_drv_status(wl, CONNECTED, ndev)) { ++ if (memcmp(curbssid, connect_req_bssid, ETHER_ADDR_LEN) == 0) { ++ AP6211_DEBUG(" Connected event of connected device e=%d s=%d, ignore it\n", ++ ntoh32(e->event_type), ntoh32(e->status)); ++ return err; ++ } ++ } ++ if (memcmp(curbssid, broad_bssid, ETHER_ADDR_LEN) == 0 && ++ memcmp(broad_bssid, connect_req_bssid, ETHER_ADDR_LEN) != 0) { ++ AP6211_DEBUG("copy bssid\n"); ++ memcpy(curbssid, connect_req_bssid, ETHER_ADDR_LEN); ++ } ++ ++#else ++ if (wl->scan_request) { ++ wl_notify_escan_complete(wl, ndev, true, true); ++ } ++#endif /* ESCAN_RESULT_PATCH */ ++ if (wl_get_drv_status(wl, CONNECTING, ndev)) { ++ wl_clr_drv_status(wl, CONNECTING, ndev); ++ if (completed) { ++ wl_get_assoc_ies(wl, ndev); ++ wl_update_prof(wl, ndev, NULL, (void *)(e->addr.octet), WL_PROF_BSSID); ++ curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); ++ wl_update_bss_info(wl, ndev, 0); ++ wl_update_pmklist(ndev, wl->pmk_list, err); ++ wl_set_drv_status(wl, CONNECTED, ndev); ++ } ++ cfg80211_connect_result(ndev, ++ curbssid, ++ conn_info->req_ie, ++ conn_info->req_ie_len, ++ conn_info->resp_ie, ++ conn_info->resp_ie_len, ++ completed ? WLAN_STATUS_SUCCESS : ++ (sec->auth_assoc_res_status) ? ++ sec->auth_assoc_res_status : ++ WLAN_STATUS_UNSPECIFIED_FAILURE, ++ GFP_KERNEL); ++ if (completed) ++ AP6211_DEBUG("Report connect result - connection succeeded\n"); ++ else ++ AP6211_ERR("Report connect result - connection failed\n"); ++ } ++ return err; ++} ++ ++static s32 ++wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data) ++{ ++ u16 flags = ntoh16(e->flags); ++ enum nl80211_key_type key_type; ++ ++ mutex_lock(&wl->usr_sync); ++ if (flags & WLC_EVENT_MSG_GROUP) ++ key_type = NL80211_KEYTYPE_GROUP; ++ else ++ key_type = NL80211_KEYTYPE_PAIRWISE; ++ ++ cfg80211_michael_mic_failure(ndev, (u8 *)&e->addr, key_type, -1, ++ NULL, GFP_KERNEL); ++ mutex_unlock(&wl->usr_sync); ++ ++ return 0; ++} ++ ++#ifdef PNO_SUPPORT ++static s32 ++wl_notify_pfn_status(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data) ++{ ++ AP6211_ERR(">>> PNO Event\n"); ++ ++#ifndef WL_SCHED_SCAN ++ mutex_lock(&wl->usr_sync); ++ /* TODO: Use cfg80211_sched_scan_results(wiphy); */ ++ cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL); ++ mutex_unlock(&wl->usr_sync); ++#else ++ /* If cfg80211 scheduled scan is supported, report the pno results via sched ++ * scan results ++ */ ++ wl_notify_sched_scan_results(wl, ndev, e, data); ++#endif /* WL_SCHED_SCAN */ ++ return 0; ++} ++#endif /* PNO_SUPPORT */ ++ ++static s32 ++wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data) ++{ ++ struct channel_info channel_inform; ++ struct wl_scan_results *bss_list; ++ u32 len = WL_SCAN_BUF_MAX; ++ s32 err = 0; ++ unsigned long flags; ++ ++ AP6211_DEBUG("Enter \n"); ++ if (!wl_get_drv_status(wl, SCANNING, ndev)) { ++ AP6211_ERR("scan is not ready \n"); ++ return err; ++ } ++ if (wl->iscan_on && wl->iscan_kickstart) ++ return wl_wakeup_iscan(wl_to_iscan(wl)); ++ ++ mutex_lock(&wl->usr_sync); ++ wl_clr_drv_status(wl, SCANNING, ndev); ++ err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &channel_inform, ++ sizeof(channel_inform), false); ++ if (unlikely(err)) { ++ AP6211_ERR("scan busy (%d)\n", err); ++ goto scan_done_out; ++ } ++ channel_inform.scan_channel = dtoh32(channel_inform.scan_channel); ++ if (unlikely(channel_inform.scan_channel)) { ++ ++ AP6211_DEBUG("channel_inform.scan_channel (%d)\n", ++ channel_inform.scan_channel); ++ } ++ wl->bss_list = wl->scan_results; ++ bss_list = wl->bss_list; ++ memset(bss_list, 0, len); ++ bss_list->buflen = htod32(len); ++ err = wldev_ioctl(ndev, WLC_SCAN_RESULTS, bss_list, len, false); ++ if (unlikely(err) && unlikely(!wl->scan_suppressed)) { ++ AP6211_ERR("%s Scan_results error (%d)\n", ndev->name, err); ++ err = -EINVAL; ++ goto scan_done_out; ++ } ++ bss_list->buflen = dtoh32(bss_list->buflen); ++ bss_list->version = dtoh32(bss_list->version); ++ bss_list->count = dtoh32(bss_list->count); ++ ++ err = wl_inform_bss(wl); ++ ++scan_done_out: ++ del_timer_sync(&wl->scan_timeout); ++ spin_lock_irqsave(&wl->cfgdrv_lock, flags); ++ if (wl->scan_request) { ++ cfg80211_scan_done(wl->scan_request, false); ++ wl->scan_request = NULL; ++ } ++ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); ++ AP6211_DEBUG("cfg80211_scan_done\n"); ++ mutex_unlock(&wl->usr_sync); ++ return err; ++} ++static s32 ++wl_frame_get_mgmt(u16 fc, const struct ether_addr *da, ++ const struct ether_addr *sa, const struct ether_addr *bssid, ++ u8 **pheader, u32 *body_len, u8 *pbody) ++{ ++ struct dot11_management_header *hdr; ++ u32 totlen = 0; ++ s32 err = 0; ++ u8 *offset; ++ u32 prebody_len = *body_len; ++ switch (fc) { ++ case FC_ASSOC_REQ: ++ /* capability , listen interval */ ++ totlen = DOT11_ASSOC_REQ_FIXED_LEN; ++ *body_len += DOT11_ASSOC_REQ_FIXED_LEN; ++ break; ++ ++ case FC_REASSOC_REQ: ++ /* capability, listen inteval, ap address */ ++ totlen = DOT11_REASSOC_REQ_FIXED_LEN; ++ *body_len += DOT11_REASSOC_REQ_FIXED_LEN; ++ break; ++ } ++ totlen += DOT11_MGMT_HDR_LEN + prebody_len; ++ *pheader = kzalloc(totlen, GFP_KERNEL); ++ if (*pheader == NULL) { ++ AP6211_ERR("memory alloc failed \n"); ++ return -ENOMEM; ++ } ++ hdr = (struct dot11_management_header *) (*pheader); ++ hdr->fc = htol16(fc); ++ hdr->durid = 0; ++ hdr->seq = 0; ++ offset = (u8*)(hdr + 1) + (totlen - DOT11_MGMT_HDR_LEN - prebody_len); ++ bcopy((const char*)da, (u8*)&hdr->da, ETHER_ADDR_LEN); ++ bcopy((const char*)sa, (u8*)&hdr->sa, ETHER_ADDR_LEN); ++ bcopy((const char*)bssid, (u8*)&hdr->bssid, ETHER_ADDR_LEN); ++ if ((pbody != NULL) && prebody_len) ++ bcopy((const char*)pbody, offset, prebody_len); ++ *body_len = totlen; ++ return err; ++} ++ ++ ++void ++wl_stop_wait_next_action_frame(struct wl_priv *wl, struct net_device *ndev) ++{ ++ if (wl_get_drv_status_all(wl, SENDING_ACT_FRM) && ++ (wl_get_p2p_status(wl, ACTION_TX_COMPLETED) || ++ wl_get_p2p_status(wl, ACTION_TX_NOACK))) { ++ AP6211_DEBUG("*** Wake UP ** abort actframe iovar\n"); ++ /* if channel is not zero, "actfame" uses off channel scan. ++ * So abort scan for off channel completion. ++ */ ++ if (wl->af_sent_channel) ++ /* wl_cfg80211_scan_abort(wl, ndev); */ ++ wl_notify_escan_complete(wl, ++ (ndev == wl->p2p_net) ? wl_to_prmry_ndev(wl) : ndev, true, true); ++ } ++#ifdef WL_CFG80211_SYNC_GON ++ else if (wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM_LISTEN)) { ++ AP6211_DEBUG("*** Wake UP ** abort listen for next af frame\n"); ++ /* So abort scan to cancel listen */ ++ wl_notify_escan_complete(wl, ++ (ndev == wl->p2p_net) ? wl_to_prmry_ndev(wl) : ndev, true, true); ++ } ++#endif /* WL_CFG80211_SYNC_GON */ ++} ++ ++static s32 ++wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data) ++{ ++ struct ieee80211_supported_band *band; ++ struct wiphy *wiphy = wl_to_wiphy(wl); ++ struct ether_addr da; ++ struct ether_addr bssid; ++ bool isfree = false; ++ s32 err = 0; ++ s32 freq; ++ struct net_device *dev = NULL; ++ wifi_p2p_pub_act_frame_t *act_frm = NULL; ++ wifi_p2p_action_frame_t *p2p_act_frm = NULL; ++ wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL; ++ wl_event_rx_frame_data_t *rxframe = ++ (wl_event_rx_frame_data_t*)data; ++ u32 event = ntoh32(e->event_type); ++ u8 *mgmt_frame; ++ u8 bsscfgidx = e->bsscfgidx; ++ u32 mgmt_frame_len = ntoh32(e->datalen) - sizeof(wl_event_rx_frame_data_t); ++ u16 channel = ((ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK)); ++ ++ memset(&bssid, 0, ETHER_ADDR_LEN); ++ ++ if (wl->p2p_net == ndev) { ++ dev = wl_to_prmry_ndev(wl); ++ } else { ++ dev = ndev; ++ } ++ ++ if (channel <= CH_MAX_2G_CHANNEL) ++ band = wiphy->bands[IEEE80211_BAND_2GHZ]; ++ else ++ band = wiphy->bands[IEEE80211_BAND_5GHZ]; ++ if (!band) { ++ AP6211_ERR("No valid band"); ++ return -EINVAL; ++ } ++#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) ++ freq = ieee80211_channel_to_frequency(channel); ++ (void)band->band; ++#else ++ freq = ieee80211_channel_to_frequency(channel, band->band); ++#endif ++ if (event == WLC_E_ACTION_FRAME_RX) { ++ wldev_iovar_getbuf_bsscfg(dev, "cur_etheraddr", ++ NULL, 0, wl->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &wl->ioctl_buf_sync); ++ ++ err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); ++ if (err < 0) ++ AP6211_ERR("WLC_GET_BSSID error %d\n", err); ++ memcpy(da.octet, wl->ioctl_buf, ETHER_ADDR_LEN); ++ err = wl_frame_get_mgmt(FC_ACTION, &da, &e->addr, &bssid, ++ &mgmt_frame, &mgmt_frame_len, ++ (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1)); ++ if (err < 0) { ++ AP6211_ERR("%s: Error in receiving action frame len %d channel %d freq %d\n", ++ __func__, mgmt_frame_len, channel, freq); ++ goto exit; ++ } ++ isfree = true; ++ if (wl_cfgp2p_is_pub_action(&mgmt_frame[DOT11_MGMT_HDR_LEN], ++ mgmt_frame_len - DOT11_MGMT_HDR_LEN)) { ++ act_frm = (wifi_p2p_pub_act_frame_t *) ++ (&mgmt_frame[DOT11_MGMT_HDR_LEN]); ++ } else if (wl_cfgp2p_is_p2p_action(&mgmt_frame[DOT11_MGMT_HDR_LEN], ++ mgmt_frame_len - DOT11_MGMT_HDR_LEN)) { ++ p2p_act_frm = (wifi_p2p_action_frame_t *) ++ (&mgmt_frame[DOT11_MGMT_HDR_LEN]); ++ (void) p2p_act_frm; ++ } else if (wl_cfgp2p_is_gas_action(&mgmt_frame[DOT11_MGMT_HDR_LEN], ++ mgmt_frame_len - DOT11_MGMT_HDR_LEN)) { ++ sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *) ++ (&mgmt_frame[DOT11_MGMT_HDR_LEN]); ++ if (sd_act_frm && wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM)) { ++ if (wl->next_af_subtype == sd_act_frm->action) { ++ AP6211_DEBUG("We got a right next frame of SD!(%d)\n", ++ sd_act_frm->action); ++ wl_clr_drv_status(wl, WAITING_NEXT_ACT_FRM, ++ (ndev == wl->p2p_net) ? ++ wl_to_prmry_ndev(wl) : ndev); ++ ++ /* Stop waiting for next AF. */ ++ wl_stop_wait_next_action_frame(wl, ndev); ++ } ++ } ++ (void) sd_act_frm; ++ } else { ++ /* ++ * if we got normal action frame and ndev is p2p0, ++ * we have to change ndev from p2p0 to wlan0 ++ */ ++ if (wl->p2p_net == ndev) ++ ndev = wl_to_prmry_ndev(wl); ++ } ++ ++ if (act_frm) { ++ ++ if (wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM)) { ++ if (wl->next_af_subtype == act_frm->subtype) { ++ AP6211_DEBUG("We got a right next frame!(%d)\n", ++ act_frm->subtype); ++ wl_clr_drv_status(wl, WAITING_NEXT_ACT_FRM, ++ (ndev == wl->p2p_net) ? ++ wl_to_prmry_ndev(wl) : ndev); ++ ++ /* Stop waiting for next AF. */ ++ wl_stop_wait_next_action_frame(wl, ndev); ++ } ++ } ++ } ++ ++ wl_cfgp2p_print_actframe(false, &mgmt_frame[DOT11_MGMT_HDR_LEN], ++ mgmt_frame_len - DOT11_MGMT_HDR_LEN); ++ /* ++ * After complete GO Negotiation, roll back to mpc mode ++ */ ++ if (act_frm && ((act_frm->subtype == P2P_PAF_GON_CONF) || ++ (act_frm->subtype == P2P_PAF_PROVDIS_RSP))) { ++ wldev_iovar_setint(dev, "mpc", 1); ++ } ++ if (act_frm && (act_frm->subtype == P2P_PAF_GON_CONF)) { ++ AP6211_DEBUG("P2P: GO_NEG_PHASE status cleared \n"); ++ wl_clr_p2p_status(wl, GO_NEG_PHASE); ++ } ++ } else { ++ mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1); ++ ++ /* wpa supplicant use probe request event for restarting another GON Req. ++ * but it makes GON Req repetition. ++ * so if src addr of prb req is same as my target device, ++ * do not send probe request event during sending action frame. ++ */ ++ if (event == WLC_E_P2P_PROBREQ_MSG) { ++ AP6211_DEBUG(" Event %s\n", (event == WLC_E_P2P_PROBREQ_MSG) ? ++ "WLC_E_P2P_PROBREQ_MSG":"WLC_E_PROBREQ_MSG"); ++ ++ ++ /* Filter any P2P probe reqs arriving during the ++ * GO-NEG Phase ++ */ ++ if (wl->p2p && ++ wl_get_p2p_status(wl, GO_NEG_PHASE)) { ++ AP6211_DEBUG("Filtering P2P probe_req while " ++ "being in GO-Neg state\n"); ++ return 0; ++ } ++ } ++ } ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) ++ cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC); ++#else ++ cfg80211_rx_mgmt(ndev, freq, mgmt_frame, mgmt_frame_len, GFP_ATOMIC); ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */ ++ ++ AP6211_DEBUG("%s: mgmt_frame_len (%d) , e->datalen (%d), channel (%d), freq (%d)\n", __func__, ++ mgmt_frame_len, ntoh32(e->datalen), channel, freq); ++exit: ++ if (isfree) ++ kfree(mgmt_frame); ++ return 0; ++} ++ ++#ifdef WL_SCHED_SCAN ++/* If target scan is not reliable, set the below define to "1" to do a ++ * full escan ++ */ ++#define FULL_ESCAN_ON_PFN_NET_FOUND 0 ++static s32 ++wl_notify_sched_scan_results(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data) ++{ ++ wl_pfn_net_info_t *netinfo, *pnetinfo; ++ struct cfg80211_scan_request request; ++ struct wiphy *wiphy = wl_to_wiphy(wl); ++ int err = 0; ++ struct cfg80211_ssid ssid[MAX_PFN_LIST_COUNT]; ++ struct ieee80211_channel *channel = NULL; ++ int channel_req = 0; ++ int band = 0; ++ struct wl_pfn_scanresults *pfn_result = (struct wl_pfn_scanresults *)data; ++ ++ AP6211_DEBUG("Enter\n"); ++ ++ if (e->event_type == WLC_E_PFN_NET_LOST) { ++ AP6211_DEBUG("PFN NET LOST event. Do Nothing \n"); ++ return 0; ++ } ++ AP6211_DEBUG(">>> PFN NET FOUND event. count:%d \n", pfn_result->count); ++ if (pfn_result->count > 0) { ++ int i; ++ ++ memset(&request, 0x00, sizeof(struct cfg80211_scan_request)); ++ memset(&ssid, 0x00, sizeof(ssid)); ++ request.wiphy = wiphy; ++ ++ pnetinfo = (wl_pfn_net_info_t *)(data + sizeof(wl_pfn_scanresults_t) ++ - sizeof(wl_pfn_net_info_t)); ++ channel = (struct ieee80211_channel *)kzalloc( ++ (sizeof(struct ieee80211_channel) * MAX_PFN_LIST_COUNT), ++ GFP_KERNEL); ++ if (!channel) { ++ AP6211_ERR("No memory"); ++ err = -ENOMEM; ++ goto out_err; ++ } ++ ++ for (i = 0; i < pfn_result->count; i++) { ++ netinfo = &pnetinfo[i]; ++ if (!netinfo) { ++ AP6211_ERR("Invalid netinfo ptr. index:%d", i); ++ err = -EINVAL; ++ goto out_err; ++ } ++ AP6211_DEBUG(">>> SSID:%s Channel:%d \n", ++ netinfo->pfnsubnet.SSID, netinfo->pfnsubnet.channel); ++ /* PFN result doesn't have all the info which are required by the supplicant ++ * (For e.g IEs) Do a target Escan so that sched scan results are reported ++ * via wl_inform_single_bss in the required format. Escan does require the ++ * scan request in the form of cfg80211_scan_request. For timebeing, create ++ * cfg80211_scan_request one out of the received PNO event. ++ */ ++ memcpy(ssid[i].ssid, netinfo->pfnsubnet.SSID, ++ netinfo->pfnsubnet.SSID_len); ++ ssid[i].ssid_len = netinfo->pfnsubnet.SSID_len; ++ request.n_ssids++; ++ ++ channel_req = netinfo->pfnsubnet.channel; ++ band = (channel_req <= CH_MAX_2G_CHANNEL) ? NL80211_BAND_2GHZ ++ : NL80211_BAND_5GHZ; ++ channel[i].center_freq = ieee80211_channel_to_frequency(channel_req, band); ++ channel[i].band = band; ++ channel[i].flags |= IEEE80211_CHAN_NO_HT40; ++ request.channels[i] = &channel[i]; ++ request.n_channels++; ++ } ++ ++ /* assign parsed ssid array */ ++ if (request.n_ssids) ++ request.ssids = &ssid[0]; ++ ++ if (wl_get_drv_status_all(wl, SCANNING)) { ++ /* Abort any on-going scan */ ++ wl_notify_escan_complete(wl, ndev, true, true); ++ } ++ ++ if (wl_get_p2p_status(wl, DISCOVERY_ON)) { ++ AP6211_DEBUG(">>> P2P discovery was ON. Disabling it\n"); ++ err = wl_cfgp2p_discover_enable_search(wl, false); ++ if (unlikely(err)) { ++ wl_clr_drv_status(wl, SCANNING, ndev); ++ goto out_err; ++ } ++ } ++ ++ wl_set_drv_status(wl, SCANNING, ndev); ++#if FULL_ESCAN_ON_PFN_NET_FOUND ++ AP6211_DEBUG(">>> Doing Full ESCAN on PNO event\n"); ++ err = wl_do_escan(wl, wiphy, ndev, NULL); ++#else ++ AP6211_DEBUG(">>> Doing targeted ESCAN on PNO event\n"); ++ err = wl_do_escan(wl, wiphy, ndev, &request); ++#endif ++ if (err) { ++ wl_clr_drv_status(wl, SCANNING, ndev); ++ goto out_err; ++ } ++ wl->sched_scan_running = TRUE; ++ } ++ else { ++ AP6211_ERR("FALSE PNO Event. (pfn_count == 0) \n"); ++ } ++out_err: ++ if (channel) ++ kfree(channel); ++ return err; ++} ++#endif /* WL_SCHED_SCAN */ ++ ++static void wl_init_conf(struct wl_conf *conf) ++{ ++ AP6211_DEBUG("Enter \n"); ++ conf->frag_threshold = (u32)-1; ++ conf->rts_threshold = (u32)-1; ++ conf->retry_short = (u32)-1; ++ conf->retry_long = (u32)-1; ++ conf->tx_power = -1; ++} ++ ++static void wl_init_prof(struct wl_priv *wl, struct net_device *ndev) ++{ ++ unsigned long flags; ++ struct wl_profile *profile = wl_get_profile_by_netdev(wl, ndev); ++ ++ spin_lock_irqsave(&wl->cfgdrv_lock, flags); ++ memset(profile, 0, sizeof(struct wl_profile)); ++ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); ++} ++ ++static void wl_init_event_handler(struct wl_priv *wl) ++{ ++ memset(wl->evt_handler, 0, sizeof(wl->evt_handler)); ++ ++ wl->evt_handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status; ++ wl->evt_handler[WLC_E_AUTH] = wl_notify_connect_status; ++ wl->evt_handler[WLC_E_ASSOC] = wl_notify_connect_status; ++ wl->evt_handler[WLC_E_LINK] = wl_notify_connect_status; ++ wl->evt_handler[WLC_E_DEAUTH_IND] = wl_notify_connect_status; ++ wl->evt_handler[WLC_E_DEAUTH] = wl_notify_connect_status; ++ wl->evt_handler[WLC_E_DISASSOC_IND] = wl_notify_connect_status; ++ wl->evt_handler[WLC_E_ASSOC_IND] = wl_notify_connect_status; ++ wl->evt_handler[WLC_E_REASSOC_IND] = wl_notify_connect_status; ++ wl->evt_handler[WLC_E_ROAM] = wl_notify_roaming_status; ++ wl->evt_handler[WLC_E_MIC_ERROR] = wl_notify_mic_status; ++ wl->evt_handler[WLC_E_SET_SSID] = wl_notify_connect_status; ++ wl->evt_handler[WLC_E_ACTION_FRAME_RX] = wl_notify_rx_mgmt_frame; ++ wl->evt_handler[WLC_E_PROBREQ_MSG] = wl_notify_rx_mgmt_frame; ++ wl->evt_handler[WLC_E_P2P_PROBREQ_MSG] = wl_notify_rx_mgmt_frame; ++ wl->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] = wl_cfgp2p_listen_complete; ++ wl->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete; ++ wl->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete; ++#ifdef PNO_SUPPORT ++ wl->evt_handler[WLC_E_PFN_NET_FOUND] = wl_notify_pfn_status; ++#endif /* PNO_SUPPORT */ ++} ++ ++static s32 wl_init_priv_mem(struct wl_priv *wl) ++{ ++ AP6211_DEBUG("Enter \n"); ++ wl->scan_results = (void *)kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL); ++ if (unlikely(!wl->scan_results)) { ++ AP6211_ERR("Scan results alloc failed\n"); ++ goto init_priv_mem_out; ++ } ++ wl->conf = (void *)kzalloc(sizeof(*wl->conf), GFP_KERNEL); ++ if (unlikely(!wl->conf)) { ++ AP6211_ERR("wl_conf alloc failed\n"); ++ goto init_priv_mem_out; ++ } ++ wl->scan_req_int = ++ (void *)kzalloc(sizeof(*wl->scan_req_int), GFP_KERNEL); ++ if (unlikely(!wl->scan_req_int)) { ++ AP6211_ERR("Scan req alloc failed\n"); ++ goto init_priv_mem_out; ++ } ++ wl->ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL); ++ if (unlikely(!wl->ioctl_buf)) { ++ AP6211_ERR("Ioctl buf alloc failed\n"); ++ goto init_priv_mem_out; ++ } ++ wl->escan_ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL); ++ if (unlikely(!wl->escan_ioctl_buf)) { ++ AP6211_ERR("Ioctl buf alloc failed\n"); ++ goto init_priv_mem_out; ++ } ++ wl->extra_buf = (void *)kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); ++ if (unlikely(!wl->extra_buf)) { ++ AP6211_ERR("Extra buf alloc failed\n"); ++ goto init_priv_mem_out; ++ } ++ wl->iscan = (void *)kzalloc(sizeof(*wl->iscan), GFP_KERNEL); ++ if (unlikely(!wl->iscan)) { ++ AP6211_ERR("Iscan buf alloc failed\n"); ++ goto init_priv_mem_out; ++ } ++ wl->pmk_list = (void *)kzalloc(sizeof(*wl->pmk_list), GFP_KERNEL); ++ if (unlikely(!wl->pmk_list)) { ++ AP6211_ERR("pmk list alloc failed\n"); ++ goto init_priv_mem_out; ++ } ++ wl->sta_info = (void *)kzalloc(sizeof(*wl->sta_info), GFP_KERNEL); ++ if (unlikely(!wl->sta_info)) { ++ AP6211_ERR("sta info alloc failed\n"); ++ goto init_priv_mem_out; ++ } ++ ++#if defined(STATIC_WL_PRIV_STRUCT) ++ wl->conn_info = (void *)kzalloc(sizeof(*wl->conn_info), GFP_KERNEL); ++ if (unlikely(!wl->conn_info)) { ++ AP6211_ERR("wl->conn_info alloc failed\n"); ++ goto init_priv_mem_out; ++ } ++ wl->ie = (void *)kzalloc(sizeof(*wl->ie), GFP_KERNEL); ++ if (unlikely(!wl->ie)) { ++ AP6211_ERR("wl->ie alloc failed\n"); ++ goto init_priv_mem_out; ++ } ++ wl->escan_info.escan_buf = dhd_os_prealloc(NULL, DHD_PREALLOC_WIPHY_ESCAN0, 0); ++ bzero(wl->escan_info.escan_buf, ESCAN_BUF_SIZE); ++#endif /* STATIC_WL_PRIV_STRUCT */ ++ wl->afx_hdl = (void *)kzalloc(sizeof(*wl->afx_hdl), GFP_KERNEL); ++ if (unlikely(!wl->afx_hdl)) { ++ AP6211_ERR("afx hdl alloc failed\n"); ++ goto init_priv_mem_out; ++ } else { ++ init_completion(&wl->act_frm_scan); ++ init_completion(&wl->wait_next_af); ++ ++ INIT_WORK(&wl->afx_hdl->work, wl_cfg80211_afx_handler); ++ } ++ return 0; ++ ++init_priv_mem_out: ++ wl_deinit_priv_mem(wl); ++ ++ return -ENOMEM; ++} ++ ++static void wl_deinit_priv_mem(struct wl_priv *wl) ++{ ++ kfree(wl->scan_results); ++ wl->scan_results = NULL; ++ kfree(wl->conf); ++ wl->conf = NULL; ++ kfree(wl->scan_req_int); ++ wl->scan_req_int = NULL; ++ kfree(wl->ioctl_buf); ++ wl->ioctl_buf = NULL; ++ kfree(wl->escan_ioctl_buf); ++ wl->escan_ioctl_buf = NULL; ++ kfree(wl->extra_buf); ++ wl->extra_buf = NULL; ++ kfree(wl->iscan); ++ wl->iscan = NULL; ++ kfree(wl->pmk_list); ++ wl->pmk_list = NULL; ++ kfree(wl->sta_info); ++ wl->sta_info = NULL; ++#if defined(STATIC_WL_PRIV_STRUCT) ++ kfree(wl->conn_info); ++ wl->conn_info = NULL; ++ kfree(wl->ie); ++ wl->ie = NULL; ++ wl->escan_info.escan_buf = NULL; ++#endif /* STATIC_WL_PRIV_STRUCT */ ++ if (wl->afx_hdl) { ++ cancel_work_sync(&wl->afx_hdl->work); ++ kfree(wl->afx_hdl); ++ wl->afx_hdl = NULL; ++ } ++ ++ if (wl->ap_info) { ++ kfree(wl->ap_info->wpa_ie); ++ kfree(wl->ap_info->rsn_ie); ++ kfree(wl->ap_info->wps_ie); ++ kfree(wl->ap_info); ++ wl->ap_info = NULL; ++ } ++} ++ ++static s32 wl_create_event_handler(struct wl_priv *wl) ++{ ++ int ret = 0; ++ AP6211_DEBUG("Enter \n"); ++ ++ /* Do not use DHD in cfg driver */ ++ wl->event_tsk.thr_pid = -1; ++ ++#ifdef USE_KTHREAD_API ++ PROC_START2(wl_event_handler, wl, &wl->event_tsk, 0, "wl_event_handler"); ++#else ++ PROC_START(wl_event_handler, wl, &wl->event_tsk, 0); ++#endif ++ if (wl->event_tsk.thr_pid < 0) ++ ret = -ENOMEM; ++ return ret; ++} ++ ++static void wl_destroy_event_handler(struct wl_priv *wl) ++{ ++ if (wl->event_tsk.thr_pid >= 0) ++ PROC_STOP(&wl->event_tsk); ++} ++ ++static void wl_term_iscan(struct wl_priv *wl) ++{ ++ struct wl_iscan_ctrl *iscan = wl_to_iscan(wl); ++ AP6211_DEBUG("In\n"); ++ if (wl->iscan_on && iscan->tsk) { ++ iscan->state = WL_ISCAN_STATE_IDLE; ++ AP6211_DEBUG("SIGTERM\n"); ++ send_sig(SIGTERM, iscan->tsk, 1); ++ AP6211_DEBUG("kthread_stop\n"); ++ kthread_stop(iscan->tsk); ++ iscan->tsk = NULL; ++ } ++} ++ ++static void wl_notify_iscan_complete(struct wl_iscan_ctrl *iscan, bool aborted) ++{ ++ struct wl_priv *wl = iscan_to_wl(iscan); ++ struct net_device *ndev = wl_to_prmry_ndev(wl); ++ unsigned long flags; ++ ++ AP6211_DEBUG("Enter \n"); ++ if (!wl_get_drv_status(wl, SCANNING, ndev)) { ++ wl_clr_drv_status(wl, SCANNING, ndev); ++ AP6211_ERR("Scan complete while device not scanning\n"); ++ return; ++ } ++ spin_lock_irqsave(&wl->cfgdrv_lock, flags); ++ wl_clr_drv_status(wl, SCANNING, ndev); ++ if (likely(wl->scan_request)) { ++ cfg80211_scan_done(wl->scan_request, aborted); ++ wl->scan_request = NULL; ++ } ++ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); ++ wl->iscan_kickstart = false; ++} ++ ++static s32 wl_wakeup_iscan(struct wl_iscan_ctrl *iscan) ++{ ++ if (likely(iscan->state != WL_ISCAN_STATE_IDLE)) { ++ AP6211_DEBUG("wake up iscan\n"); ++ up(&iscan->sync); ++ return 0; ++ } ++ ++ return -EIO; ++} ++ ++static s32 ++wl_get_iscan_results(struct wl_iscan_ctrl *iscan, u32 *status, ++ struct wl_scan_results **bss_list) ++{ ++ struct wl_iscan_results list; ++ struct wl_scan_results *results; ++ struct wl_iscan_results *list_buf; ++ s32 err = 0; ++ ++ AP6211_DEBUG("Enter \n"); ++ memset(iscan->scan_buf, 0, WL_ISCAN_BUF_MAX); ++ list_buf = (struct wl_iscan_results *)iscan->scan_buf; ++ results = &list_buf->results; ++ results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE; ++ results->version = 0; ++ results->count = 0; ++ ++ memset(&list, 0, sizeof(list)); ++ list.results.buflen = htod32(WL_ISCAN_BUF_MAX); ++ err = wldev_iovar_getbuf(iscan->dev, "iscanresults", &list, ++ WL_ISCAN_RESULTS_FIXED_SIZE, iscan->scan_buf, ++ WL_ISCAN_BUF_MAX, NULL); ++ if (unlikely(err)) { ++ AP6211_ERR("error (%d)\n", err); ++ return err; ++ } ++ results->buflen = dtoh32(results->buflen); ++ results->version = dtoh32(results->version); ++ results->count = dtoh32(results->count); ++ AP6211_DEBUG("results->count = %d\n", results->count); ++ AP6211_DEBUG("results->buflen = %d\n", results->buflen); ++ *status = dtoh32(list_buf->status); ++ *bss_list = results; ++ ++ return err; ++} ++ ++static s32 wl_iscan_done(struct wl_priv *wl) ++{ ++ struct wl_iscan_ctrl *iscan = wl->iscan; ++ s32 err = 0; ++ ++ iscan->state = WL_ISCAN_STATE_IDLE; ++ mutex_lock(&wl->usr_sync); ++ wl_inform_bss(wl); ++ wl_notify_iscan_complete(iscan, false); ++ mutex_unlock(&wl->usr_sync); ++ ++ return err; ++} ++ ++static s32 wl_iscan_pending(struct wl_priv *wl) ++{ ++ struct wl_iscan_ctrl *iscan = wl->iscan; ++ s32 err = 0; ++ ++ /* Reschedule the timer */ ++ mod_timer(&iscan->timer, jiffies + msecs_to_jiffies(iscan->timer_ms)); ++ iscan->timer_on = 1; ++ ++ return err; ++} ++ ++static s32 wl_iscan_inprogress(struct wl_priv *wl) ++{ ++ struct wl_iscan_ctrl *iscan = wl->iscan; ++ s32 err = 0; ++ ++ mutex_lock(&wl->usr_sync); ++ wl_inform_bss(wl); ++ wl_run_iscan(iscan, NULL, WL_SCAN_ACTION_CONTINUE); ++ mutex_unlock(&wl->usr_sync); ++ /* Reschedule the timer */ ++ mod_timer(&iscan->timer, jiffies + msecs_to_jiffies(iscan->timer_ms)); ++ iscan->timer_on = 1; ++ ++ return err; ++} ++ ++static s32 wl_iscan_aborted(struct wl_priv *wl) ++{ ++ struct wl_iscan_ctrl *iscan = wl->iscan; ++ s32 err = 0; ++ ++ iscan->state = WL_ISCAN_STATE_IDLE; ++ mutex_lock(&wl->usr_sync); ++ wl_notify_iscan_complete(iscan, true); ++ mutex_unlock(&wl->usr_sync); ++ ++ return err; ++} ++ ++static s32 wl_iscan_thread(void *data) ++{ ++ struct wl_iscan_ctrl *iscan = (struct wl_iscan_ctrl *)data; ++ struct wl_priv *wl = iscan_to_wl(iscan); ++ u32 status; ++ int err = 0; ++ ++ allow_signal(SIGTERM); ++ status = WL_SCAN_RESULTS_PARTIAL; ++ while (likely(!down_interruptible(&iscan->sync))) { ++ if (kthread_should_stop()) ++ break; ++ if (iscan->timer_on) { ++ del_timer_sync(&iscan->timer); ++ iscan->timer_on = 0; ++ } ++ mutex_lock(&wl->usr_sync); ++ err = wl_get_iscan_results(iscan, &status, &wl->bss_list); ++ if (unlikely(err)) { ++ status = WL_SCAN_RESULTS_ABORTED; ++ AP6211_ERR("Abort iscan\n"); ++ } ++ mutex_unlock(&wl->usr_sync); ++ iscan->iscan_handler[status] (wl); ++ } ++ if (iscan->timer_on) { ++ del_timer_sync(&iscan->timer); ++ iscan->timer_on = 0; ++ } ++ AP6211_DEBUG("%s was terminated\n", __func__); ++ ++ return 0; ++} ++ ++static void wl_scan_timeout(unsigned long data) ++{ ++ wl_event_msg_t msg; ++ struct wl_priv *wl = (struct wl_priv *)data; ++ ++ if (!(wl->scan_request)) { ++ AP6211_ERR("timer expired but no scan request\n"); ++ return; ++ } ++ bzero(&msg, sizeof(wl_event_msg_t)); ++ AP6211_ERR("timer expired\n"); ++ if (wl->escan_on) { ++ msg.event_type = hton32(WLC_E_ESCAN_RESULT); ++ msg.status = hton32(WLC_E_STATUS_TIMEOUT); ++ msg.reason = 0xFFFFFFFF; ++ wl_cfg80211_event(wl_to_prmry_ndev(wl), &msg, NULL); ++ } else { ++ AP6211_ERR("SCAN Timeout(ISCAN)\n"); ++ wl_notify_iscan_complete(wl_to_iscan(wl), true); ++ } ++} ++static void wl_iscan_timer(unsigned long data) ++{ ++ struct wl_iscan_ctrl *iscan = (struct wl_iscan_ctrl *)data; ++ ++ if (iscan) { ++ iscan->timer_on = 0; ++ AP6211_DEBUG("timer expired\n"); ++ wl_wakeup_iscan(iscan); ++ } ++} ++ ++static s32 wl_invoke_iscan(struct wl_priv *wl) ++{ ++ struct wl_iscan_ctrl *iscan = wl_to_iscan(wl); ++ int err = 0; ++ ++ if (wl->iscan_on && !iscan->tsk) { ++ iscan->state = WL_ISCAN_STATE_IDLE; ++ sema_init(&iscan->sync, 0); ++ iscan->tsk = kthread_run(wl_iscan_thread, iscan, "wl_iscan"); ++ if (IS_ERR(iscan->tsk)) { ++ AP6211_ERR("Could not create iscan thread\n"); ++ iscan->tsk = NULL; ++ return -ENOMEM; ++ } ++ } ++ ++ return err; ++} ++ ++static void wl_init_iscan_handler(struct wl_iscan_ctrl *iscan) ++{ ++ memset(iscan->iscan_handler, 0, sizeof(iscan->iscan_handler)); ++ iscan->iscan_handler[WL_SCAN_RESULTS_SUCCESS] = wl_iscan_done; ++ iscan->iscan_handler[WL_SCAN_RESULTS_PARTIAL] = wl_iscan_inprogress; ++ iscan->iscan_handler[WL_SCAN_RESULTS_PENDING] = wl_iscan_pending; ++ iscan->iscan_handler[WL_SCAN_RESULTS_ABORTED] = wl_iscan_aborted; ++ iscan->iscan_handler[WL_SCAN_RESULTS_NO_MEM] = wl_iscan_aborted; ++} ++ ++static s32 ++wl_cfg80211_netdev_notifier_call(struct notifier_block * nb, ++ unsigned long state, ++ void *ndev) ++{ ++ struct net_device *dev = ndev; ++ struct wireless_dev *wdev = dev->ieee80211_ptr; ++ struct wl_priv *wl = wlcfg_drv_priv; ++ int refcnt = 0; ++ ++ AP6211_DEBUG("Enter \n"); ++ if (!wdev || !wl || dev == wl_to_prmry_ndev(wl)) ++ return NOTIFY_DONE; ++ switch (state) { ++ case NETDEV_DOWN: ++ while (work_pending(&wdev->cleanup_work) && refcnt < 100) { ++ if (refcnt%5 == 0) ++ AP6211_ERR("%s : [NETDEV_DOWN] work_pending (%d th)\n", ++ __FUNCTION__, refcnt); ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(100); ++ set_current_state(TASK_RUNNING); ++ refcnt++; ++ } ++ break; ++ ++ case NETDEV_UNREGISTER: ++ /* after calling list_del_rcu(&wdev->list) */ ++ wl_dealloc_netinfo(wl, ndev); ++ break; ++ case NETDEV_GOING_DOWN: ++ /* At NETDEV_DOWN state, wdev_cleanup_work work will be called. ++ * In front of door, the function checks ++ * whether current scan is working or not. ++ * If the scanning is still working, wdev_cleanup_work call WARN_ON and ++ * make the scan done forcibly. ++ */ ++ if (wl_get_drv_status(wl, SCANNING, dev)) { ++ if (wl->escan_on) { ++ wl_notify_escan_complete(wl, dev, true, true); ++ } ++ } ++ break; ++ } ++ return NOTIFY_DONE; ++} ++static struct notifier_block wl_cfg80211_netdev_notifier = { ++ .notifier_call = wl_cfg80211_netdev_notifier_call, ++}; ++ ++static s32 wl_notify_escan_complete(struct wl_priv *wl, ++ struct net_device *ndev, ++ bool aborted, bool fw_abort) ++{ ++ wl_scan_params_t *params = NULL; ++ s32 params_size = 0; ++ s32 err = BCME_OK; ++ unsigned long flags; ++ struct net_device *dev; ++ ++ AP6211_DEBUG("Enter \n"); ++ ++ if (wl->escan_info.ndev != ndev) ++ { ++ AP6211_ERR("ndev is different %p %p\n", wl->escan_info.ndev, ndev); ++ return err; ++ } ++ ++ if (wl->scan_request) { ++ if (wl->scan_request->dev == wl->p2p_net) ++ dev = wl_to_prmry_ndev(wl); ++ else ++ dev = wl->scan_request->dev; ++ } ++ else { ++ AP6211_DEBUG("wl->scan_request is NULL may be internal scan." ++ "doing scan_abort for ndev %p primary %p p2p_net %p", ++ ndev, wl_to_prmry_ndev(wl), wl->p2p_net); ++ dev = ndev; ++ } ++ if (fw_abort && !in_atomic()) { ++ /* Our scan params only need space for 1 channel and 0 ssids */ ++ params = wl_cfg80211_scan_alloc_params(-1, 0, ¶ms_size); ++ if (params == NULL) { ++ AP6211_ERR("scan params allocation failed \n"); ++ err = -ENOMEM; ++ } else { ++ /* Do a scan abort to stop the driver's scan engine */ ++ err = wldev_ioctl(dev, WLC_SCAN, params, params_size, true); ++ if (err < 0) { ++ AP6211_ERR("scan abort failed \n"); ++ } ++ } ++ } ++ if (timer_pending(&wl->scan_timeout)) ++ del_timer_sync(&wl->scan_timeout); ++#if defined(ESCAN_RESULT_PATCH) ++ if (likely(wl->scan_request)) { ++ wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf; ++ wl_inform_bss(wl); ++ } ++#endif /* ESCAN_RESULT_PATCH */ ++ spin_lock_irqsave(&wl->cfgdrv_lock, flags); ++#ifdef WL_SCHED_SCAN ++ if (wl->sched_scan_req && !wl->scan_request) { ++ AP6211_DEBUG(">>> REPORTING SCHED SCAN RESULTS \n"); ++ if (aborted) ++ cfg80211_sched_scan_stopped(wl->sched_scan_req->wiphy); ++ else ++ cfg80211_sched_scan_results(wl->sched_scan_req->wiphy); ++ wl->sched_scan_running = FALSE; ++ wl->sched_scan_req = NULL; ++ } ++#endif /* WL_SCHED_SCAN */ ++ if (likely(wl->scan_request)) { ++ cfg80211_scan_done(wl->scan_request, aborted); ++ wl->scan_request = NULL; ++ } ++ if (p2p_is_on(wl)) ++ wl_clr_p2p_status(wl, SCANNING); ++ wl_clr_drv_status(wl, SCANNING, dev); ++ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); ++ if (params) ++ kfree(params); ++ ++ return err; ++} ++ ++static s32 wl_escan_handler(struct wl_priv *wl, ++ struct net_device *ndev, ++ const wl_event_msg_t *e, void *data) ++{ ++ s32 err = BCME_OK; ++ s32 status = ntoh32(e->status); ++ wl_bss_info_t *bi; ++ wl_escan_result_t *escan_result; ++ wl_bss_info_t *bss = NULL; ++ wl_scan_results_t *list; ++ wifi_p2p_ie_t * p2p_ie; ++ u32 bi_length; ++ u32 i; ++ u8 *p2p_dev_addr = NULL; ++ ++ AP6211_DEBUG(" enter event type : %d, status : %d \n", ++ ntoh32(e->event_type), ntoh32(e->status)); ++ ++ mutex_lock(&wl->usr_sync); ++ /* P2P SCAN is coming from primary interface */ ++ if (wl_get_p2p_status(wl, SCANNING)) { ++ if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) ++ ndev = wl->afx_hdl->dev; ++ else ++ ndev = wl->escan_info.ndev; ++ ++ } ++ if (!ndev || !wl->escan_on || ++ (!wl_get_drv_status(wl, SCANNING, ndev) && ++ !wl->sched_scan_running)) { ++ AP6211_ERR("escan is not ready ndev %p wl->escan_on %d drv_status 0x%x\n", ++ ndev, wl->escan_on, wl_get_drv_status(wl, SCANNING, ndev)); ++ goto exit; ++ } ++ if (status == WLC_E_STATUS_PARTIAL) { ++ AP6211_DEBUG("WLC_E_STATUS_PARTIAL \n"); ++ escan_result = (wl_escan_result_t *) data; ++ if (!escan_result) { ++ AP6211_ERR("Invalid escan result (NULL pointer)\n"); ++ goto exit; ++ } ++ if (dtoh16(escan_result->bss_count) != 1) { ++ AP6211_ERR("Invalid bss_count %d: ignoring\n", escan_result->bss_count); ++ goto exit; ++ } ++ bi = escan_result->bss_info; ++ if (!bi) { ++ AP6211_ERR("Invalid escan bss info (NULL pointer)\n"); ++ goto exit; ++ } ++ bi_length = dtoh32(bi->length); ++ if (bi_length != (dtoh32(escan_result->buflen) - WL_ESCAN_RESULTS_FIXED_SIZE)) { ++ AP6211_ERR("Invalid bss_info length %d: ignoring\n", bi_length); ++ goto exit; ++ } ++ ++ if (!(wl_to_wiphy(wl)->interface_modes & BIT(NL80211_IFTYPE_ADHOC))) { ++ if (dtoh16(bi->capability) & DOT11_CAP_IBSS) { ++ AP6211_DEBUG("Ignoring IBSS result\n"); ++ goto exit; ++ } ++ } ++ ++ if (wl_get_drv_status_all(wl, FINDING_COMMON_CHANNEL)) { ++ p2p_dev_addr = wl_cfgp2p_retreive_p2p_dev_addr(bi, bi_length); ++ if (p2p_dev_addr && !memcmp(p2p_dev_addr, ++ wl->afx_hdl->tx_dst_addr.octet, ETHER_ADDR_LEN)) { ++ s32 channel = CHSPEC_CHANNEL( ++ wl_chspec_driver_to_host(bi->chanspec)); ++ AP6211_DEBUG("ACTION FRAME SCAN : Peer " MACDBG " found, channel : %d\n", ++ MAC2STRDBG(wl->afx_hdl->tx_dst_addr.octet), channel); ++ wl_clr_p2p_status(wl, SCANNING); ++ wl->afx_hdl->peer_chan = channel; ++ complete(&wl->act_frm_scan); ++ goto exit; ++ } ++ ++ } else { ++ int cur_len = WL_SCAN_RESULTS_FIXED_SIZE; ++ list = (wl_scan_results_t *)wl->escan_info.escan_buf; ++#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF) ++ if (wl->p2p_net && wl->scan_request && ++ wl->scan_request->dev == wl->p2p_net) ++#else ++ if (p2p_is_on(wl) && p2p_scan(wl)) ++#endif ++ { ++#ifdef WL_HOST_BAND_MGMT ++ s32 channel = 0; ++ s32 channel_band = 0; ++#endif /* WL_HOST_BAND_MGMT */ ++ /* p2p scan && allow only probe response */ ++ if (bi->flags & WL_BSS_FLAGS_FROM_BEACON) ++ goto exit; ++ if ((p2p_ie = wl_cfgp2p_find_p2pie(((u8 *) bi) + bi->ie_offset, ++ bi->ie_length)) == NULL) { ++ AP6211_ERR("Couldn't find P2PIE in probe" ++ " response/beacon\n"); ++ goto exit; ++ } ++#ifdef WL_HOST_BAND_MGMT ++ channel = CHSPEC_CHANNEL(wl_chspec_driver_to_host(bi->chanspec)); ++ channel_band = (channel > CH_MAX_2G_CHANNEL) ? ++ WLC_BAND_5G : WLC_BAND_2G; ++ ++ ++ if ((wl->curr_band == WLC_BAND_5G) && ++ (channel_band == WLC_BAND_2G)) { ++ /* Avoid sending the GO results in band conflict */ ++ if (wl_cfgp2p_retreive_p2pattrib(p2p_ie, ++ P2P_SEID_GROUP_ID) != NULL) ++ goto exit; ++ } ++#endif /* WL_HOST_BAND_MGMT */ ++ } ++ for (i = 0; i < list->count; i++) { ++ bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length)) ++ : list->bss_info; ++ ++ if (!bcmp(&bi->BSSID, &bss->BSSID, ETHER_ADDR_LEN) && ++ (CHSPEC_BAND(wl_chspec_driver_to_host(bi->chanspec)) ++ == CHSPEC_BAND(wl_chspec_driver_to_host(bss->chanspec))) && ++ bi->SSID_len == bss->SSID_len && ++ !bcmp(bi->SSID, bss->SSID, bi->SSID_len)) { ++ ++ /* do not allow beacon data to update ++ *the data recd from a probe response ++ */ ++ if (!(bss->flags & WL_BSS_FLAGS_FROM_BEACON) && ++ (bi->flags & WL_BSS_FLAGS_FROM_BEACON)) ++ goto exit; ++ ++ AP6211_DEBUG("%s("MACDBG"), i=%d prev: RSSI %d" ++ " flags 0x%x, new: RSSI %d flags 0x%x\n", ++ bss->SSID, MAC2STRDBG(bi->BSSID.octet), i, ++ bss->RSSI, bss->flags, bi->RSSI, bi->flags); ++ ++ if ((bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) == ++ (bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL)) { ++ /* preserve max RSSI if the measurements are ++ * both on-channel or both off-channel ++ */ ++ AP6211_DEBUG("%s("MACDBG"), same onchan" ++ ", RSSI: prev %d new %d\n", ++ bss->SSID, MAC2STRDBG(bi->BSSID.octet), ++ bss->RSSI, bi->RSSI); ++ bi->RSSI = MAX(bss->RSSI, bi->RSSI); ++ } else if ((bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) && ++ (bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) == 0) { ++ /* preserve the on-channel rssi measurement ++ * if the new measurement is off channel ++ */ ++ AP6211_DEBUG("%s("MACDBG"), prev onchan" ++ ", RSSI: prev %d new %d\n", ++ bss->SSID, MAC2STRDBG(bi->BSSID.octet), ++ bss->RSSI, bi->RSSI); ++ bi->RSSI = bss->RSSI; ++ bi->flags |= WL_BSS_FLAGS_RSSI_ONCHANNEL; ++ } ++ if (dtoh32(bss->length) != bi_length) { ++ u32 prev_len = dtoh32(bss->length); ++ ++ AP6211_DEBUG("bss info replacement" ++ " is occured(bcast:%d->probresp%d)\n", ++ bss->ie_length, bi->ie_length); ++ AP6211_DEBUG("%s("MACDBG"), replacement!(%d -> %d)\n", ++ bss->SSID, MAC2STRDBG(bi->BSSID.octet), ++ prev_len, bi_length); ++ ++ if (list->buflen - prev_len + bi_length ++ > ESCAN_BUF_SIZE) { ++ AP6211_ERR("Buffer is too small: keep the" ++ " previous result of this AP\n"); ++ /* Only update RSSI */ ++ bss->RSSI = bi->RSSI; ++ bss->flags |= (bi->flags ++ & WL_BSS_FLAGS_RSSI_ONCHANNEL); ++ goto exit; ++ } ++ ++ if (i < list->count - 1) { ++ /* memory copy required by this case only */ ++ memmove((u8 *)bss + bi_length, ++ (u8 *)bss + prev_len, ++ list->buflen - cur_len - prev_len); ++ } ++ list->buflen -= prev_len; ++ list->buflen += bi_length; ++ } ++ list->version = dtoh32(bi->version); ++ memcpy((u8 *)bss, (u8 *)bi, bi_length); ++ goto exit; ++ } ++ cur_len += dtoh32(bss->length); ++ } ++ if (bi_length > ESCAN_BUF_SIZE - list->buflen) { ++ AP6211_ERR("Buffer is too small: ignoring\n"); ++ goto exit; ++ } ++ if (strlen(bi->SSID) == 0) { // terence: fix for hidden SSID ++ AP6211_DEBUG("Skip hidden SSID %pM\n", &bi->BSSID); ++ goto exit; ++ } ++ memcpy(&(wl->escan_info.escan_buf[list->buflen]), bi, bi_length); ++ list->version = dtoh32(bi->version); ++ list->buflen += bi_length; ++ list->count++; ++ } ++ ++ } ++ else if (status == WLC_E_STATUS_SUCCESS) { ++ wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; ++ if (wl_get_drv_status_all(wl, FINDING_COMMON_CHANNEL)) { ++ AP6211_DEBUG("ACTION FRAME SCAN DONE\n"); ++ wl_clr_p2p_status(wl, SCANNING); ++ wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev); ++ if (wl->afx_hdl->peer_chan == WL_INVALID) ++ complete(&wl->act_frm_scan); ++ } else if ((likely(wl->scan_request)) || (wl->sched_scan_running)) { ++ AP6211_DEBUG("ESCAN COMPLETED\n"); ++ wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf; ++ wl_inform_bss(wl); ++ wl_notify_escan_complete(wl, ndev, false, false); ++ } ++ } ++ else if (status == WLC_E_STATUS_ABORT) { ++ wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; ++ if (wl_get_drv_status_all(wl, FINDING_COMMON_CHANNEL)) { ++ AP6211_DEBUG("ACTION FRAME SCAN DONE\n"); ++ wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev); ++ wl_clr_p2p_status(wl, SCANNING); ++ if (wl->afx_hdl->peer_chan == WL_INVALID) ++ complete(&wl->act_frm_scan); ++ } else if ((likely(wl->scan_request)) || (wl->sched_scan_running)) { ++ AP6211_DEBUG("ESCAN ABORTED\n"); ++ wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf; ++ wl_inform_bss(wl); ++ wl_notify_escan_complete(wl, ndev, true, false); ++ } ++ } ++ else if (status == WLC_E_STATUS_NEWSCAN) ++ { ++ escan_result = (wl_escan_result_t *) data; ++ AP6211_ERR("WLC_E_STATUS_NEWSCAN : scan_request[%p]\n", wl->scan_request); ++ AP6211_ERR("sync_id[%d], bss_count[%d]\n", escan_result->sync_id, ++ escan_result->bss_count); ++ } else if (status == WLC_E_STATUS_TIMEOUT) { ++ AP6211_ERR("WLC_E_STATUS_TIMEOUT : scan_request[%p]\n", wl->scan_request); ++ AP6211_ERR("escan_on[%d], reason[0x%x]\n", wl->escan_on, e->reason); ++ if (e->reason == 0xFFFFFFFF) { ++ wl_notify_escan_complete(wl, wl->escan_info.ndev, true, true); ++ } ++ } else { ++ AP6211_ERR("unexpected Escan Event %d : abort\n", status); ++ wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; ++ if (wl_get_drv_status_all(wl, FINDING_COMMON_CHANNEL)) { ++ AP6211_DEBUG("ACTION FRAME SCAN DONE\n"); ++ wl_clr_p2p_status(wl, SCANNING); ++ wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev); ++ if (wl->afx_hdl->peer_chan == WL_INVALID) ++ complete(&wl->act_frm_scan); ++ } else if ((likely(wl->scan_request)) || (wl->sched_scan_running)) { ++ wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf; ++ wl_inform_bss(wl); ++ wl_notify_escan_complete(wl, ndev, true, false); ++ } ++ } ++exit: ++ mutex_unlock(&wl->usr_sync); ++ return err; ++} ++static void wl_cfg80211_concurrent_roam(struct wl_priv *wl, int enable) ++{ ++ u32 connected_cnt = wl_get_drv_status_all(wl, CONNECTED); ++ struct net_info *iter, *next; ++ int err; ++ ++ if (!wl->roamoff_on_concurrent) ++ return; ++ if (enable && connected_cnt > 1) { ++ for_each_ndev(wl, iter, next) { ++ /* Save the current roam setting */ ++ if ((err = wldev_iovar_getint(iter->ndev, "roam_off", ++ (s32 *)&iter->roam_off)) != BCME_OK) { ++ AP6211_ERR("%s:Failed to get current roam setting err %d\n", ++ iter->ndev->name, err); ++ continue; ++ } ++ if ((err = wldev_iovar_setint(iter->ndev, "roam_off", 1)) != BCME_OK) { ++ AP6211_ERR(" %s:failed to set roam_off : %d\n", ++ iter->ndev->name, err); ++ } ++ } ++ } ++ else if (!enable) { ++ for_each_ndev(wl, iter, next) { ++ if (iter->roam_off != WL_INVALID) { ++ if ((err = wldev_iovar_setint(iter->ndev, "roam_off", ++ iter->roam_off)) == BCME_OK) ++ iter->roam_off = WL_INVALID; ++ else { ++ AP6211_ERR(" %s:failed to set roam_off : %d\n", ++ iter->ndev->name, err); ++ } ++ } ++ } ++ } ++ return; ++} ++ ++static void wl_cfg80211_determine_vsdb_mode(struct wl_priv *wl) ++{ ++ struct net_info *iter, *next; ++ u32 chan = 0; ++ u32 chanspec = 0; ++ u32 prev_chan = 0; ++ u32 connected_cnt = wl_get_drv_status_all(wl, CONNECTED); ++ wl->vsdb_mode = false; ++ ++ if (connected_cnt <= 1) { ++ return; ++ } ++ for_each_ndev(wl, iter, next) { ++ chanspec = 0; ++ chan = 0; ++ if (wl_get_drv_status(wl, CONNECTED, iter->ndev)) { ++ if (wldev_iovar_getint(iter->ndev, "chanspec", ++ (s32 *)&chanspec) == BCME_OK) { ++ chan = CHSPEC_CHANNEL(chanspec); ++ if (CHSPEC_IS40(chanspec)) { ++ if (CHSPEC_SB_UPPER(chanspec)) ++ chan += CH_10MHZ_APART; ++ else ++ chan -= CH_10MHZ_APART; ++ } ++ wl_update_prof(wl, iter->ndev, NULL, ++ &chan, WL_PROF_CHAN); ++ } ++ if (!prev_chan && chan) ++ prev_chan = chan; ++ else if (prev_chan && (prev_chan != chan)) ++ wl->vsdb_mode = true; ++ } ++ } ++ return; ++} ++static s32 wl_notifier_change_state(struct wl_priv *wl, struct net_info *_net_info, ++ enum wl_status state, bool set) ++{ ++ s32 pm = PM_FAST; ++ s32 err = BCME_OK; ++ u32 chan = 0; ++ struct net_info *iter, *next; ++ struct net_device *primary_dev = wl_to_prmry_ndev(wl); ++ AP6211_DEBUG("Enter state %d set %d _net_info->pm_restore %d iface %s\n", ++ state, set, _net_info->pm_restore, _net_info->ndev->name); ++ ++ if (state != WL_STATUS_CONNECTED) ++ return 0; ++ ++ if (set) { ++ wl_cfg80211_concurrent_roam(wl, 1); ++ ++ if (wl_get_mode_by_netdev(wl, _net_info->ndev) == WL_MODE_AP) { ++ pm = PM_OFF; ++ AP6211_DEBUG("%s:AP power save %s\n", _net_info->ndev->name, ++ pm ? "enabled" : "disabled"); ++ if ((err = wldev_ioctl(_net_info->ndev, WLC_SET_PM, ++ &pm, sizeof(pm), true)) != 0) { ++ if (err == -ENODEV) ++ AP6211_DEBUG("%s:net_device is not ready\n", ++ _net_info->ndev->name); ++ else ++ AP6211_ERR("%s:error (%d)\n", _net_info->ndev->name, err); ++ } ++ if (wl_add_remove_eventmsg(primary_dev, WLC_E_P2P_PROBREQ_MSG, false)) ++ AP6211_ERR(" failed to unset WLC_E_P2P_PROPREQ_MSG\n"); ++ return 0; ++ } ++ wl_cfg80211_determine_vsdb_mode(wl); ++ pm = PM_OFF; ++ for_each_ndev(wl, iter, next) { ++ if ((!wl->vsdb_mode) && (iter->ndev != _net_info->ndev)) { ++ /* Do not touch the other interfaces power save ++ * if we are not in vsdb mode ++ */ ++ continue; ++ } ++ /* Save the current power mode */ ++ iter->pm_restore = true; ++ err = wldev_ioctl(iter->ndev, WLC_GET_PM, &iter->pm, ++ sizeof(iter->pm), false); ++ AP6211_DEBUG("%s:power save %s\n", iter->ndev->name, ++ iter->pm ? "enabled" : "disabled"); ++ if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM, &pm, ++ sizeof(pm), true)) != 0) { ++ if (err == -ENODEV) ++ AP6211_DEBUG("%s:netdev not ready\n", iter->ndev->name); ++ else ++ AP6211_ERR("%s:error (%d)\n", iter->ndev->name, err); ++ iter->ndev->ieee80211_ptr->ps = pm ? true: false; ++ } ++ } ++ } ++ else { /* clear */ ++ chan = 0; ++ /* clear chan information when the net device is disconnected */ ++ wl_update_prof(wl, _net_info->ndev, NULL, &chan, WL_PROF_CHAN); ++ wl_cfg80211_determine_vsdb_mode(wl); ++ for_each_ndev(wl, iter, next) { ++ if (iter->pm_restore) { ++ AP6211_DEBUG("%s:restoring power save %s\n", ++ iter->ndev->name, (iter->pm ? "enabled" : "disabled")); ++ err = wldev_ioctl(iter->ndev, ++ WLC_SET_PM, &iter->pm, sizeof(iter->pm), true); ++ if (unlikely(err)) { ++ if (err == -ENODEV) ++ AP6211_DEBUG("%s:netdev not ready\n", iter->ndev->name); ++ else ++ AP6211_ERR("%s:error(%d)\n", iter->ndev->name, err); ++ break; ++ } ++ iter->pm_restore = 0; ++ } ++ } ++ wl_cfg80211_concurrent_roam(wl, 0); ++ } ++ return err; ++} ++ ++static s32 wl_init_scan(struct wl_priv *wl) ++{ ++ struct wl_iscan_ctrl *iscan = wl_to_iscan(wl); ++ int err = 0; ++ ++ if (wl->iscan_on) { ++ iscan->dev = wl_to_prmry_ndev(wl); ++ iscan->state = WL_ISCAN_STATE_IDLE; ++ wl_init_iscan_handler(iscan); ++ iscan->timer_ms = WL_ISCAN_TIMER_INTERVAL_MS; ++ init_timer(&iscan->timer); ++ iscan->timer.data = (unsigned long) iscan; ++ iscan->timer.function = wl_iscan_timer; ++ sema_init(&iscan->sync, 0); ++ iscan->tsk = kthread_run(wl_iscan_thread, iscan, "wl_iscan"); ++ if (IS_ERR(iscan->tsk)) { ++ AP6211_ERR("Could not create iscan thread\n"); ++ iscan->tsk = NULL; ++ return -ENOMEM; ++ } ++ iscan->data = wl; ++ } else if (wl->escan_on) { ++ wl->evt_handler[WLC_E_ESCAN_RESULT] = wl_escan_handler; ++ wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; ++ } ++ /* Init scan_timeout timer */ ++ init_timer(&wl->scan_timeout); ++ wl->scan_timeout.data = (unsigned long) wl; ++ wl->scan_timeout.function = wl_scan_timeout; ++ ++ return err; ++} ++ ++static s32 wl_init_priv(struct wl_priv *wl) ++{ ++ struct wiphy *wiphy = wl_to_wiphy(wl); ++ struct net_device *ndev = wl_to_prmry_ndev(wl); ++ s32 err = 0; ++ ++ wl->scan_request = NULL; ++ wl->pwr_save = !!(wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT); ++ wl->iscan_on = false; ++ wl->escan_on = true; ++ wl->roam_on = false; ++ wl->iscan_kickstart = false; ++ wl->active_scan = true; ++ wl->rf_blocked = false; ++ wl->vsdb_mode = false; ++ wl->wlfc_on = false; ++ wl->roamoff_on_concurrent = true; ++ /* register interested state */ ++ set_bit(WL_STATUS_CONNECTED, &wl->interrested_state); ++ spin_lock_init(&wl->cfgdrv_lock); ++ mutex_init(&wl->ioctl_buf_sync); ++ init_waitqueue_head(&wl->netif_change_event); ++ init_completion(&wl->send_af_done); ++ init_completion(&wl->iface_disable); ++ wl_init_eq(wl); ++ err = wl_init_priv_mem(wl); ++ if (err) ++ return err; ++ if (wl_create_event_handler(wl)) ++ return -ENOMEM; ++ wl_init_event_handler(wl); ++ mutex_init(&wl->usr_sync); ++ mutex_init(&wl->event_sync); ++ err = wl_init_scan(wl); ++ if (err) ++ return err; ++ wl_init_conf(wl->conf); ++ wl_init_prof(wl, ndev); ++ wl_link_down(wl); ++ DNGL_FUNC(dhd_cfg80211_init, (wl)); ++ ++ return err; ++} ++ ++static void wl_deinit_priv(struct wl_priv *wl) ++{ ++ DNGL_FUNC(dhd_cfg80211_deinit, (wl)); ++ wl_destroy_event_handler(wl); ++ wl_flush_eq(wl); ++ wl_link_down(wl); ++ del_timer_sync(&wl->scan_timeout); ++ wl_term_iscan(wl); ++ wl_deinit_priv_mem(wl); ++ unregister_netdevice_notifier(&wl_cfg80211_netdev_notifier); ++} ++ ++#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF) ++static s32 wl_cfg80211_attach_p2p(void) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ ++ AP6211_DEBUG("Enter \n"); ++ ++ if (wl_cfgp2p_register_ndev(wl) < 0) { ++ AP6211_ERR("%s: P2P attach failed. \n", __func__); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++static s32 wl_cfg80211_detach_p2p(void) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ struct wireless_dev *wdev = wl->p2p_wdev; ++ ++ AP6211_DEBUG("Enter \n"); ++ if (!wdev || !wl) { ++ AP6211_ERR("Invalid Ptr\n"); ++ return -EINVAL; ++ } ++ ++ wl_cfgp2p_unregister_ndev(wl); ++ ++ wl->p2p_wdev = NULL; ++ wl->p2p_net = NULL; ++ AP6211_DEBUG("Freeing 0x%08x \n", (unsigned int)wdev); ++ kfree(wdev); ++ ++ return 0; ++} ++#endif /* defined(WLP2P) && defined(WL_ENABLE_P2P_IF) */ ++ ++s32 wl_cfg80211_attach_post(struct net_device *ndev) ++{ ++ struct wl_priv * wl = NULL; ++ s32 err = 0; ++ AP6211_DEBUG("In\n"); ++ if (unlikely(!ndev)) { ++ AP6211_ERR("ndev is invaild\n"); ++ return -ENODEV; ++ } ++ wl = wlcfg_drv_priv; ++ if (unlikely(!wl)) { ++ AP6211_ERR("wl is invaild\n"); ++ return -EINVAL; ++ } ++ if (!wl_get_drv_status(wl, READY, ndev)) { ++ if (wl->wdev && ++ wl_cfgp2p_supported(wl, ndev)) { ++#if !defined(WL_ENABLE_P2P_IF) ++ wl->wdev->wiphy->interface_modes |= ++ (BIT(NL80211_IFTYPE_P2P_CLIENT)| ++ BIT(NL80211_IFTYPE_P2P_GO)); ++#endif ++ if ((err = wl_cfgp2p_init_priv(wl)) != 0) ++ goto fail; ++ ++#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF) ++ if (wl->p2p_net) { ++ /* Update MAC addr for p2p0 interface here. */ ++ memcpy(wl->p2p_net->dev_addr, ndev->dev_addr, ETH_ALEN); ++ wl->p2p_net->dev_addr[0] |= 0x02; ++ AP6211_ERR("%s: p2p_dev_addr="MACDBG "\n", ++ wl->p2p_net->name, ++ MAC2STRDBG(wl->p2p_net->dev_addr)); ++ } else { ++ AP6211_ERR("p2p_net not yet populated." ++ " Couldn't update the MAC Address for p2p0 \n"); ++ return -ENODEV; ++ } ++#endif /* defined(WLP2P) && (WL_ENABLE_P2P_IF) */ ++ ++ wl->p2p_supported = true; ++ } ++ } ++ wl_set_drv_status(wl, READY, ndev); ++fail: ++ return err; ++} ++ ++s32 wl_cfg80211_attach(struct net_device *ndev, void *data) ++{ ++ struct wireless_dev *wdev; ++ struct wl_priv *wl; ++ s32 err = 0; ++ struct device *dev; ++ ++ AP6211_DEBUG("In\n"); ++ if (!ndev) { ++ AP6211_ERR("ndev is invaild\n"); ++ return -ENODEV; ++ } ++ AP6211_DEBUG("func %p\n", wl_cfg80211_get_parent_dev()); ++ dev = wl_cfg80211_get_parent_dev(); ++ ++ wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); ++ if (unlikely(!wdev)) { ++ AP6211_ERR("Could not allocate wireless device\n"); ++ return -ENOMEM; ++ } ++ err = wl_setup_wiphy(wdev, dev); ++ if (unlikely(err)) { ++ kfree(wdev); ++ return -ENOMEM; ++ } ++ wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS); ++ wl = (struct wl_priv *)wiphy_priv(wdev->wiphy); ++ wl->wdev = wdev; ++ wl->pub = data; ++ INIT_LIST_HEAD(&wl->net_list); ++ ndev->ieee80211_ptr = wdev; ++ SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); ++ wdev->netdev = ndev; ++ wl->state_notifier = wl_notifier_change_state; ++ err = wl_alloc_netinfo(wl, ndev, wdev, WL_MODE_BSS, PM_ENABLE); ++ if (err) { ++ AP6211_ERR("Failed to alloc net_info (%d)\n", err); ++ goto cfg80211_attach_out; ++ } ++ err = wl_init_priv(wl); ++ if (err) { ++ AP6211_ERR("Failed to init iwm_priv (%d)\n", err); ++ goto cfg80211_attach_out; ++ } ++ ++ err = wl_setup_rfkill(wl, TRUE); ++ if (err) { ++ AP6211_ERR("Failed to setup rfkill %d\n", err); ++ goto cfg80211_attach_out; ++ } ++ err = register_netdevice_notifier(&wl_cfg80211_netdev_notifier); ++ if (err) { ++ AP6211_ERR("Failed to register notifierl %d\n", err); ++ goto cfg80211_attach_out; ++ } ++#if defined(COEX_DHCP) ++ if (wl_cfg80211_btcoex_init(wl)) ++ goto cfg80211_attach_out; ++#endif ++#if defined(BSSCACHE) ++ wl_init_bss_cache_ctrl(&g_bss_cache_ctrl); ++#endif ++ ++ wlcfg_drv_priv = wl; ++ ++#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF) ++ err = wl_cfg80211_attach_p2p(); ++ if (err) ++ goto cfg80211_attach_out; ++#endif ++ ++ return err; ++ ++cfg80211_attach_out: ++ err = wl_setup_rfkill(wl, FALSE); ++ wl_free_wdev(wl); ++ return err; ++} ++ ++void wl_cfg80211_detach(void *para) ++{ ++ struct wl_priv *wl; ++ ++ (void)para; ++ wl = wlcfg_drv_priv; ++ ++ AP6211_DEBUG("In\n"); ++ ++#if defined(COEX_DHCP) ++ wl_cfg80211_btcoex_deinit(wl); ++#endif ++ ++ wl_setup_rfkill(wl, FALSE); ++ if (wl->p2p_supported) { ++ if (timer_pending(&wl->p2p->listen_timer)) ++ del_timer_sync(&wl->p2p->listen_timer); ++ wl_cfgp2p_deinit_priv(wl); ++ } ++ ++#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF) ++ wl_cfg80211_detach_p2p(); ++#endif ++ wl_deinit_priv(wl); ++ wlcfg_drv_priv = NULL; ++ wl_cfg80211_clear_parent_dev(); ++ wl_free_wdev(wl); ++#if defined(RSSIAVG) ++ wl_free_rssi_cache(&g_rssi_cache_ctrl); ++#endif ++#if defined(BSSCACHE) ++ wl_release_bss_cache_ctrl(&g_bss_cache_ctrl); ++#endif ++ /* PLEASE do NOT call any function after wl_free_wdev, the driver's private structure "wl", ++ * which is the private part of wiphy, has been freed in wl_free_wdev !!!!!!!!!!! ++ */ ++} ++ ++static void wl_wakeup_event(struct wl_priv *wl) ++{ ++ if (wl->event_tsk.thr_pid >= 0) { ++ DHD_OS_WAKE_LOCK(wl->pub); ++ up(&wl->event_tsk.sema); ++ } ++} ++ ++static int wl_is_p2p_event(struct wl_event_q *e) ++{ ++ switch (e->etype) { ++ /* We have to seperate out the P2P events received ++ * on primary interface so that it can be send up ++ * via p2p0 interface. ++ */ ++ case WLC_E_P2P_PROBREQ_MSG: ++ case WLC_E_P2P_DISC_LISTEN_COMPLETE: ++ case WLC_E_ACTION_FRAME_RX: ++ case WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE: ++ case WLC_E_ACTION_FRAME_COMPLETE: ++ ++ if (e->emsg.ifidx != 0) { ++ AP6211_DEBUG("P2P Event on Virtual I/F (ifidx:%d) \n", ++ e->emsg.ifidx); ++ /* We are only bothered about the P2P events received ++ * on primary interface. For rest of them return false ++ * so that it is sent over the interface corresponding ++ * to the ifidx. ++ */ ++ return FALSE; ++ } else { ++ AP6211_DEBUG("P2P Event on Primary I/F (ifidx:%d)." ++ " Sent it to p2p0 \n", e->emsg.ifidx); ++ return TRUE; ++ } ++ break; ++ ++ default: ++ AP6211_DEBUG("NON-P2P Event %d on ifidx (ifidx:%d) \n", ++ e->etype, e->emsg.ifidx); ++ return FALSE; ++ } ++} ++ ++static s32 wl_event_handler(void *data) ++{ ++ struct net_device *netdev; ++ struct wl_priv *wl = NULL; ++ struct wl_event_q *e; ++ tsk_ctl_t *tsk = (tsk_ctl_t *)data; ++ ++ wl = (struct wl_priv *)tsk->parent; ++#ifndef USE_KTHREAD_API ++ DAEMONIZE("dhd_cfg80211_event"); ++ complete(&tsk->completed); ++#else ++ AP6211_ERR("tsk Enter, tsk = 0x%08x\n", (unsigned int)tsk); ++#endif ++ ++ while (down_interruptible (&tsk->sema) == 0) { ++ SMP_RD_BARRIER_DEPENDS(); ++ if (tsk->terminated) ++ break; ++ while ((e = wl_deq_event(wl))) { ++ AP6211_DEBUG("event type (%d), if idx: %d\n", e->etype, e->emsg.ifidx); ++ /* All P2P device address related events comes on primary interface since ++ * there is no corresponding bsscfg for P2P interface. Map it to p2p0 ++ * interface. ++ */ ++ if ((wl_is_p2p_event(e) == TRUE) && (wl->p2p_net)) { ++ netdev = wl->p2p_net; ++ } else { ++ netdev = dhd_idx2net((struct dhd_pub *)(wl->pub), e->emsg.ifidx); ++ } ++ if (!netdev) ++ netdev = wl_to_prmry_ndev(wl); ++ if (e->etype < WLC_E_LAST && wl->evt_handler[e->etype]) { ++ wl->evt_handler[e->etype] (wl, netdev, &e->emsg, e->edata); ++ } else { ++ AP6211_DEBUG("Unknown Event (%d): ignoring\n", e->etype); ++ } ++ wl_put_event(e); ++ } ++ DHD_OS_WAKE_UNLOCK(wl->pub); ++ } ++ AP6211_ERR("%s was terminated\n", __func__); ++ complete_and_exit(&tsk->completed, 0); ++ return 0; ++} ++ ++void ++wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data) ++{ ++ u32 event_type = ntoh32(e->event_type); ++ struct wl_priv *wl = wlcfg_drv_priv; ++ ++#if (WL_DBG_LEVEL > 0) ++ s8 *estr = (event_type <= sizeof(wl_dbg_estr) / WL_DBG_ESTR_MAX - 1) ? ++ wl_dbg_estr[event_type] : (s8 *) "Unknown"; ++ AP6211_DEBUG("event_type (%d):" "WLC_E_" "%s\n", event_type, estr); ++#endif /* (WL_DBG_LEVEL > 0) */ ++ ++ if (event_type == WLC_E_PFN_NET_FOUND) { ++ AP6211_DEBUG(" PNOEVENT: PNO_NET_FOUND\n"); ++ } ++ else if (event_type == WLC_E_PFN_NET_LOST) { ++ AP6211_DEBUG(" PNOEVENT: PNO_NET_LOST\n"); ++ } ++ ++ if (likely(!wl_enq_event(wl, ndev, event_type, e, data))) ++ wl_wakeup_event(wl); ++} ++ ++static void wl_init_eq(struct wl_priv *wl) ++{ ++ wl_init_eq_lock(wl); ++ INIT_LIST_HEAD(&wl->eq_list); ++} ++ ++static void wl_flush_eq(struct wl_priv *wl) ++{ ++ struct wl_event_q *e; ++ unsigned long flags; ++ ++ flags = wl_lock_eq(wl); ++ while (!list_empty(&wl->eq_list)) { ++ e = list_first_entry(&wl->eq_list, struct wl_event_q, eq_list); ++ list_del(&e->eq_list); ++ kfree(e); ++ } ++ wl_unlock_eq(wl, flags); ++} ++ ++/* ++* retrieve first queued event from head ++*/ ++ ++static struct wl_event_q *wl_deq_event(struct wl_priv *wl) ++{ ++ struct wl_event_q *e = NULL; ++ unsigned long flags; ++ ++ flags = wl_lock_eq(wl); ++ if (likely(!list_empty(&wl->eq_list))) { ++ e = list_first_entry(&wl->eq_list, struct wl_event_q, eq_list); ++ list_del(&e->eq_list); ++ } ++ wl_unlock_eq(wl, flags); ++ ++ return e; ++} ++ ++/* ++ * push event to tail of the queue ++ */ ++ ++static s32 ++wl_enq_event(struct wl_priv *wl, struct net_device *ndev, u32 event, const wl_event_msg_t *msg, ++ void *data) ++{ ++ struct wl_event_q *e; ++ s32 err = 0; ++ uint32 evtq_size; ++ uint32 data_len; ++ unsigned long flags; ++ gfp_t aflags; ++ ++ data_len = 0; ++ if (data) ++ data_len = ntoh32(msg->datalen); ++ evtq_size = sizeof(struct wl_event_q) + data_len; ++ aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL; ++ e = kzalloc(evtq_size, aflags); ++ if (unlikely(!e)) { ++ AP6211_ERR("event alloc failed\n"); ++ return -ENOMEM; ++ } ++ e->etype = event; ++ memcpy(&e->emsg, msg, sizeof(wl_event_msg_t)); ++ if (data) ++ memcpy(e->edata, data, data_len); ++ flags = wl_lock_eq(wl); ++ list_add_tail(&e->eq_list, &wl->eq_list); ++ wl_unlock_eq(wl, flags); ++ ++ return err; ++} ++ ++static void wl_put_event(struct wl_event_q *e) ++{ ++ kfree(e); ++} ++ ++static s32 wl_config_ifmode(struct wl_priv *wl, struct net_device *ndev, s32 iftype) ++{ ++ s32 infra = 0; ++ s32 err = 0; ++ s32 mode = 0; ++ switch (iftype) { ++ case NL80211_IFTYPE_MONITOR: ++ case NL80211_IFTYPE_WDS: ++ AP6211_ERR("type (%d) : currently we do not support this mode\n", ++ iftype); ++ err = -EINVAL; ++ return err; ++ case NL80211_IFTYPE_ADHOC: ++ mode = WL_MODE_IBSS; ++ break; ++ case NL80211_IFTYPE_STATION: ++ case NL80211_IFTYPE_P2P_CLIENT: ++ mode = WL_MODE_BSS; ++ infra = 1; ++ break; ++ case NL80211_IFTYPE_AP: ++ case NL80211_IFTYPE_P2P_GO: ++ mode = WL_MODE_AP; ++ infra = 1; ++ break; ++ default: ++ err = -EINVAL; ++ AP6211_ERR("invalid type (%d)\n", iftype); ++ return err; ++ } ++ infra = htod32(infra); ++ err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra), true); ++ if (unlikely(err)) { ++ AP6211_ERR("WLC_SET_INFRA error (%d)\n", err); ++ return err; ++ } ++ ++ wl_set_mode_by_netdev(wl, ndev, mode); ++ ++ return 0; ++} ++ ++void wl_cfg80211_add_to_eventbuffer(struct wl_eventmsg_buf *ev, u16 event, bool set) ++{ ++ if (!ev || (event > WLC_E_LAST)) ++ return; ++ ++ if (ev->num < MAX_EVENT_BUF_NUM) { ++ ev->event[ev->num].type = event; ++ ev->event[ev->num].set = set; ++ ev->num++; ++ } else { ++ AP6211_ERR("evenbuffer doesn't support > %u events. Update" ++ " the define MAX_EVENT_BUF_NUM \n", MAX_EVENT_BUF_NUM); ++ ASSERT(0); ++ } ++} ++ ++s32 wl_cfg80211_apply_eventbuffer( ++ struct net_device *ndev, ++ struct wl_priv *wl, ++ wl_eventmsg_buf_t *ev) ++{ ++ char eventmask[WL_EVENTING_MASK_LEN]; ++ int i, ret = 0; ++ s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; ++ ++ if (!ev || (!ev->num)) ++ return -EINVAL; ++ ++ mutex_lock(&wl->event_sync); ++ ++ /* Read event_msgs mask */ ++ bcm_mkiovar("event_msgs", NULL, 0, iovbuf, ++ sizeof(iovbuf)); ++ ret = wldev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf), false); ++ if (unlikely(ret)) { ++ AP6211_ERR("Get event_msgs error (%d)\n", ret); ++ goto exit; ++ } ++ memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN); ++ ++ /* apply the set bits */ ++ for (i = 0; i < ev->num; i++) { ++ if (ev->event[i].set) ++ setbit(eventmask, ev->event[i].type); ++ else ++ clrbit(eventmask, ev->event[i].type); ++ } ++ ++ /* Write updated Event mask */ ++ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, ++ sizeof(iovbuf)); ++ ret = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); ++ if (unlikely(ret)) { ++ AP6211_ERR("Set event_msgs error (%d)\n", ret); ++ } ++ ++exit: ++ mutex_unlock(&wl->event_sync); ++ return ret; ++} ++ ++s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add) ++{ ++ s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; ++ s8 eventmask[WL_EVENTING_MASK_LEN]; ++ s32 err = 0; ++ struct wl_priv *wl = wlcfg_drv_priv; ++ ++ if (!ndev || !wl) ++ return -ENODEV; ++ ++ mutex_lock(&wl->event_sync); ++ ++ /* Setup event_msgs */ ++ bcm_mkiovar("event_msgs", NULL, 0, iovbuf, ++ sizeof(iovbuf)); ++ err = wldev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf), false); ++ if (unlikely(err)) { ++ AP6211_ERR("Get event_msgs error (%d)\n", err); ++ goto eventmsg_out; ++ } ++ memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN); ++ if (add) { ++ setbit(eventmask, event); ++ } else { ++ clrbit(eventmask, event); ++ } ++ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, ++ sizeof(iovbuf)); ++ err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); ++ if (unlikely(err)) { ++ AP6211_ERR("Set event_msgs error (%d)\n", err); ++ goto eventmsg_out; ++ } ++ ++eventmsg_out: ++ mutex_unlock(&wl->event_sync); ++ return err; ++} ++ ++static int wl_construct_reginfo(struct wl_priv *wl, s32 bw_cap) ++{ ++ struct net_device *dev = wl_to_prmry_ndev(wl); ++ struct ieee80211_channel *band_chan_arr = NULL; ++ wl_uint32_list_t *list; ++ u32 i, j, index, n_2g, n_5g, band, channel, array_size; ++ u32 *n_cnt = NULL; ++ chanspec_t c = 0; ++ s32 err = BCME_OK; ++ bool update; ++ bool ht40_allowed; ++ u8 *pbuf = NULL; ++ ++#define LOCAL_BUF_LEN 1024 ++ pbuf = kzalloc(LOCAL_BUF_LEN, GFP_KERNEL); ++ ++ if (pbuf == NULL) { ++ AP6211_ERR("failed to allocate local buf\n"); ++ return -ENOMEM; ++ } ++ list = (wl_uint32_list_t *)(void *) pbuf; ++ list->count = htod32(WL_NUMCHANSPECS); ++ ++ ++ err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL, ++ 0, pbuf, LOCAL_BUF_LEN, 0, &wl->ioctl_buf_sync); ++ if (err != 0) { ++ AP6211_ERR("get chanspecs failed with %d\n", err); ++ kfree(pbuf); ++ return err; ++ } ++#undef LOCAL_BUF_LEN ++ ++ list = (wl_uint32_list_t *)(void *)pbuf; ++ band = array_size = n_2g = n_5g = 0; ++ for (i = 0; i < dtoh32(list->count); i++) { ++ index = 0; ++ update = false; ++ ht40_allowed = false; ++ c = (chanspec_t)dtoh32(list->element[i]); ++ c = wl_chspec_driver_to_host(c); ++ channel = CHSPEC_CHANNEL(c); ++ if (CHSPEC_IS40(c)) { ++ if (CHSPEC_SB_UPPER(c)) ++ channel += CH_10MHZ_APART; ++ else ++ channel -= CH_10MHZ_APART; ++ } else if (CHSPEC_IS80(c)) { ++ AP6211_DEBUG("HT80 center channel : %d\n", channel); ++ continue; ++ } ++ if (CHSPEC_IS2G(c) && (channel >= CH_MIN_2G_CHANNEL) && ++ (channel <= CH_MAX_2G_CHANNEL)) { ++ band_chan_arr = __wl_2ghz_channels; ++ array_size = ARRAYSIZE(__wl_2ghz_channels); ++ n_cnt = &n_2g; ++ band = IEEE80211_BAND_2GHZ; ++ ht40_allowed = (bw_cap == WLC_N_BW_40ALL)? true : false; ++ } else if (CHSPEC_IS5G(c) && channel >= CH_MIN_5G_CHANNEL) { ++ band_chan_arr = __wl_5ghz_a_channels; ++ array_size = ARRAYSIZE(__wl_5ghz_a_channels); ++ n_cnt = &n_5g; ++ band = IEEE80211_BAND_5GHZ; ++ ht40_allowed = (bw_cap == WLC_N_BW_20ALL)? false : true; ++ } else { ++ AP6211_ERR("Invalid channel Sepc. 0x%x.\n", c); ++ continue; ++ } ++ if (!ht40_allowed && CHSPEC_IS40(c)) ++ continue; ++ for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) { ++ if (band_chan_arr[j].hw_value == channel) { ++ update = true; ++ break; ++ } ++ } ++ if (update) ++ index = j; ++ else ++ index = *n_cnt; ++ if (index < array_size) { ++#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) ++ band_chan_arr[index].center_freq = ++ ieee80211_channel_to_frequency(channel); ++#else ++ band_chan_arr[index].center_freq = ++ ieee80211_channel_to_frequency(channel, band); ++#endif ++ band_chan_arr[index].hw_value = channel; ++ ++ if (CHSPEC_IS40(c) && ht40_allowed) { ++ /* assuming the order is HT20, HT40 Upper, ++ HT40 lower from chanspecs ++ */ ++ u32 ht40_flag = band_chan_arr[index].flags & IEEE80211_CHAN_NO_HT40; ++ if (CHSPEC_SB_UPPER(c)) { ++ if (ht40_flag == IEEE80211_CHAN_NO_HT40) ++ band_chan_arr[index].flags &= ++ ~IEEE80211_CHAN_NO_HT40; ++ band_chan_arr[index].flags |= IEEE80211_CHAN_NO_HT40PLUS; ++ } else { ++ /* It should be one of ++ IEEE80211_CHAN_NO_HT40 or IEEE80211_CHAN_NO_HT40PLUS ++ */ ++ band_chan_arr[index].flags &= ~IEEE80211_CHAN_NO_HT40; ++ if (ht40_flag == IEEE80211_CHAN_NO_HT40) ++ band_chan_arr[index].flags |= ++ IEEE80211_CHAN_NO_HT40MINUS; ++ } ++ } else { ++ band_chan_arr[index].flags = IEEE80211_CHAN_NO_HT40; ++ if (band == IEEE80211_BAND_2GHZ) ++ channel |= WL_CHANSPEC_BAND_2G; ++ else ++ channel |= WL_CHANSPEC_BAND_5G; ++ channel |= WL_CHANSPEC_BW_20; ++ channel = wl_chspec_host_to_driver(channel); ++ err = wldev_iovar_getint(dev, "per_chan_info", &channel); ++ if (!err) { ++ if (channel & WL_CHAN_RADAR) ++ band_chan_arr[index].flags |= ++ (IEEE80211_CHAN_RADAR | ++ IEEE80211_CHAN_NO_IBSS); ++ if (channel & WL_CHAN_PASSIVE) ++ band_chan_arr[index].flags |= ++ IEEE80211_CHAN_PASSIVE_SCAN; ++ } ++ } ++ if (!update) ++ (*n_cnt)++; ++ } ++ ++ } ++ __wl_band_2ghz.n_channels = n_2g; ++ __wl_band_5ghz_a.n_channels = n_5g; ++ kfree(pbuf); ++ return err; ++} ++ ++s32 wl_update_wiphybands(struct wl_priv *wl, bool notify) ++{ ++ struct wiphy *wiphy; ++ struct net_device *dev; ++ u32 bandlist[3]; ++ u32 nband = 0; ++ u32 i = 0; ++ s32 err = 0; ++ s32 index = 0; ++ s32 nmode = 0; ++ bool rollback_lock = false; ++ s32 bw_cap = 0; ++ s32 cur_band = -1; ++ struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS] = {NULL, }; ++ ++ if (wl == NULL) { ++ wl = wlcfg_drv_priv; ++ mutex_lock(&wl->usr_sync); ++ rollback_lock = true; ++ } ++ dev = wl_to_prmry_ndev(wl); ++ ++ memset(bandlist, 0, sizeof(bandlist)); ++ err = wldev_ioctl(dev, WLC_GET_BANDLIST, bandlist, ++ sizeof(bandlist), false); ++ if (unlikely(err)) { ++ AP6211_ERR("error read bandlist (%d)\n", err); ++ goto end_bands; ++ } ++ ++ wiphy = wl_to_wiphy(wl); ++ ++ err = wldev_ioctl(dev, WLC_GET_BAND, &cur_band, ++ sizeof(s32), false); ++ if (unlikely(err)) { ++ AP6211_ERR("error (%d)\n", err); ++ goto end_bands; ++ } ++ ++ err = wldev_iovar_getint(dev, "nmode", &nmode); ++ if (unlikely(err)) { ++ AP6211_ERR("error reading nmode (%d)\n", err); ++ } else { ++ /* For nmodeonly check bw cap */ ++ err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap); ++ if (unlikely(err)) { ++ AP6211_ERR("error get mimo_bw_cap (%d)\n", err); ++ } ++ } ++ ++ err = wl_construct_reginfo(wl, bw_cap); ++ if (err) { ++ AP6211_ERR("wl_construct_reginfo() fails err=%d\n", err); ++ if (err != BCME_UNSUPPORTED) ++ goto end_bands; ++ err = 0; ++ } ++ ++ nband = bandlist[0]; ++ ++ for (i = 1; i <= nband && i < ARRAYSIZE(bandlist); i++) { ++ index = -1; ++ if (bandlist[i] == WLC_BAND_5G && __wl_band_5ghz_a.n_channels > 0) { ++ bands[IEEE80211_BAND_5GHZ] = ++ &__wl_band_5ghz_a; ++ index = IEEE80211_BAND_5GHZ; ++ if (bw_cap == WLC_N_BW_40ALL || bw_cap == WLC_N_BW_20IN2G_40IN5G) ++ bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; ++ } ++ else if (bandlist[i] == WLC_BAND_2G && __wl_band_2ghz.n_channels > 0) { ++ bands[IEEE80211_BAND_2GHZ] = ++ &__wl_band_2ghz; ++ index = IEEE80211_BAND_2GHZ; ++ if (bw_cap == WLC_N_BW_40ALL) ++ bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; ++ } ++ ++ if ((index >= 0) && nmode) { ++ bands[index]->ht_cap.cap |= ++ (IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_DSSSCCK40); ++ bands[index]->ht_cap.ht_supported = TRUE; ++ bands[index]->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; ++ bands[index]->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16; ++ /* An HT shall support all EQM rates for one spatial stream */ ++ bands[index]->ht_cap.mcs.rx_mask[0] = 0xff; ++ } ++ ++ } ++ ++ wiphy->bands[IEEE80211_BAND_2GHZ] = bands[IEEE80211_BAND_2GHZ]; ++ wiphy->bands[IEEE80211_BAND_5GHZ] = bands[IEEE80211_BAND_5GHZ]; ++ ++ if (notify) ++ wiphy_apply_custom_regulatory(wiphy, &brcm_regdom); ++ ++end_bands: ++ if (rollback_lock) ++ mutex_unlock(&wl->usr_sync); ++ return err; ++} ++ ++static s32 __wl_cfg80211_up(struct wl_priv *wl) ++{ ++ s32 err = 0; ++ struct net_device *ndev = wl_to_prmry_ndev(wl); ++ struct wireless_dev *wdev = ndev->ieee80211_ptr; ++ ++ AP6211_DEBUG("In\n"); ++ ++ err = dhd_config_dongle(wl, false); ++ if (unlikely(err)) ++ return err; ++ ++ err = wl_config_ifmode(wl, ndev, wdev->iftype); ++ if (unlikely(err && err != -EINPROGRESS)) { ++ AP6211_ERR("wl_config_ifmode failed\n"); ++ } ++ err = wl_update_wiphybands(wl, true); ++ if (unlikely(err)) { ++ AP6211_ERR("wl_update_wiphybands failed\n"); ++ } ++ ++ err = dhd_monitor_init(wl->pub); ++ err = wl_invoke_iscan(wl); ++ ++#ifdef WL_HOST_BAND_MGMT ++ /* By default the curr_band is initialized to BAND_AUTO */ ++ if (wl_cfg80211_set_band(ndev, WLC_BAND_AUTO) < 0) { ++ AP6211_ERR("roam_band set failed\n"); ++ err = -1; ++ } ++#endif /* WL_HOST_BAND_MGMT */ ++ ++#if defined(DHCP_SCAN_SUPPRESS) ++ /* wlan scan_supp timer and work thread info */ ++ init_timer(&wl->scan_supp_timer); ++ wl->scan_supp_timer.data = (ulong)wl; ++ wl->scan_supp_timer.function = wl_cfg80211_scan_supp_timerfunc; ++ INIT_WORK(&wl->wlan_work, wl_cfg80211_work_handler); ++#endif /* DHCP_SCAN_SUPPRESS */ ++ ++ wl_set_drv_status(wl, READY, ndev); ++ return err; ++} ++ ++static s32 __wl_cfg80211_down(struct wl_priv *wl) ++{ ++ s32 err = 0; ++ unsigned long flags; ++ struct net_info *iter, *next; ++ struct net_device *ndev = wl_to_prmry_ndev(wl); ++ struct net_device *p2p_net = wl->p2p_net; ++ u32 bssidx = wl_cfgp2p_find_idx(wl, ndev); ++ AP6211_DEBUG("In\n"); ++ ++#if defined(DHCP_SCAN_SUPPRESS) ++ /* Force clear of scan_suppress */ ++ if (wl->scan_suppressed) ++ wl_cfg80211_scan_suppress(ndev, 0); ++ if (timer_pending(&wl->scan_supp_timer)) ++ del_timer_sync(&wl->scan_supp_timer); ++ cancel_work_sync(&wl->wlan_work); ++#endif /* DHCP_SCAN_SUPPRESS */ ++ ++ /* If BSS is operational (e.g SoftAp), bring it down */ ++ if (wl_cfgp2p_bss_isup(ndev, bssidx)) { ++ if (wl_cfgp2p_bss(wl, ndev, bssidx, 0) < 0) ++ AP6211_ERR("BSS down failed \n"); ++ } ++ ++ /* Check if cfg80211 interface is already down */ ++ if (!wl_get_drv_status(wl, READY, ndev)) ++ return err; /* it is even not ready */ ++ ++ for_each_ndev(wl, iter, next) ++ wl_set_drv_status(wl, SCAN_ABORTING, iter->ndev); ++ ++ wl_term_iscan(wl); ++ spin_lock_irqsave(&wl->cfgdrv_lock, flags); ++ if (wl->scan_request) { ++ cfg80211_scan_done(wl->scan_request, true); ++ wl->scan_request = NULL; ++ } ++ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); ++ ++ for_each_ndev(wl, iter, next) { ++ wl_clr_drv_status(wl, READY, iter->ndev); ++ wl_clr_drv_status(wl, SCANNING, iter->ndev); ++ wl_clr_drv_status(wl, SCAN_ABORTING, iter->ndev); ++ wl_clr_drv_status(wl, CONNECTING, iter->ndev); ++ wl_clr_drv_status(wl, CONNECTED, iter->ndev); ++ wl_clr_drv_status(wl, DISCONNECTING, iter->ndev); ++ wl_clr_drv_status(wl, AP_CREATED, iter->ndev); ++ wl_clr_drv_status(wl, AP_CREATING, iter->ndev); ++ } ++ wl_to_prmry_ndev(wl)->ieee80211_ptr->iftype = ++ NL80211_IFTYPE_STATION; ++ if (p2p_net) ++ dev_close(p2p_net); ++ DNGL_FUNC(dhd_cfg80211_down, (wl)); ++ wl_flush_eq(wl); ++ wl_link_down(wl); ++ if (wl->p2p_supported) ++ wl_cfgp2p_down(wl); ++ dhd_monitor_uninit(); ++ ++ return err; ++} ++ ++s32 wl_cfg80211_up(void *para) ++{ ++ struct wl_priv *wl; ++ s32 err = 0; ++ int val = 1; ++ dhd_pub_t *dhd; ++ ++ (void)para; ++ AP6211_DEBUG("In\n"); ++ wl = wlcfg_drv_priv; ++ ++ if ((err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_VERSION, &val, ++ sizeof(int), false) < 0)) { ++ AP6211_ERR("WLC_GET_VERSION failed, err=%d\n", err); ++ return err; ++ } ++ val = dtoh32(val); ++ if (val != WLC_IOCTL_VERSION && val != 1) { ++ AP6211_ERR("Version mismatch, please upgrade. Got %d, expected %d or 1\n", ++ val, WLC_IOCTL_VERSION); ++ return BCME_VERSION; ++ } ++ ioctl_version = val; ++ AP6211_DEBUG("WLC_GET_VERSION=%d\n", ioctl_version); ++ ++ mutex_lock(&wl->usr_sync); ++ dhd = (dhd_pub_t *)(wl->pub); ++ if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) { ++ err = wl_cfg80211_attach_post(wl_to_prmry_ndev(wl)); ++ if (unlikely(err)) ++ return err; ++ } ++ err = __wl_cfg80211_up(wl); ++ if (unlikely(err)) ++ AP6211_ERR("__wl_cfg80211_up failed\n"); ++ mutex_unlock(&wl->usr_sync); ++ return err; ++} ++ ++/* Private Event to Supplicant with indication that chip hangs */ ++int wl_cfg80211_hang(struct net_device *dev, u16 reason) ++{ ++ struct wl_priv *wl; ++ wl = wlcfg_drv_priv; ++ ++ AP6211_ERR("In : chip crash eventing\n"); ++ cfg80211_disconnected(dev, reason, NULL, 0, GFP_KERNEL); ++#if defined(RSSIAVG) ++ wl_free_rssi_cache(&g_rssi_cache_ctrl); ++#endif ++#if defined(BSSCACHE) ++ wl_free_bss_cache(&g_bss_cache_ctrl); ++ wl_run_bss_cache_timer(&g_bss_cache_ctrl, 0); ++#endif ++ if (wl != NULL) { ++ wl_link_down(wl); ++ } ++ return 0; ++} ++ ++s32 wl_cfg80211_down(void *para) ++{ ++ struct wl_priv *wl; ++ s32 err = 0; ++ ++ (void)para; ++ AP6211_DEBUG("In\n"); ++ wl = wlcfg_drv_priv; ++ mutex_lock(&wl->usr_sync); ++#if defined(RSSIAVG) ++ wl_free_rssi_cache(&g_rssi_cache_ctrl); ++#endif ++#if defined(BSSCACHE) ++ wl_free_bss_cache(&g_bss_cache_ctrl); ++ wl_run_bss_cache_timer(&g_bss_cache_ctrl, 0); ++#endif ++ err = __wl_cfg80211_down(wl); ++ mutex_unlock(&wl->usr_sync); ++ ++ return err; ++} ++ ++static void *wl_read_prof(struct wl_priv *wl, struct net_device *ndev, s32 item) ++{ ++ unsigned long flags; ++ void *rptr = NULL; ++ struct wl_profile *profile = wl_get_profile_by_netdev(wl, ndev); ++ ++ if (!profile) ++ return NULL; ++ spin_lock_irqsave(&wl->cfgdrv_lock, flags); ++ switch (item) { ++ case WL_PROF_SEC: ++ rptr = &profile->sec; ++ break; ++ case WL_PROF_ACT: ++ rptr = &profile->active; ++ break; ++ case WL_PROF_BSSID: ++ rptr = profile->bssid; ++ break; ++ case WL_PROF_SSID: ++ rptr = &profile->ssid; ++ break; ++ case WL_PROF_CHAN: ++ rptr = &profile->channel; ++ break; ++ } ++ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); ++ if (!rptr) ++ AP6211_ERR("invalid item (%d)\n", item); ++ return rptr; ++} ++ ++static s32 ++wl_update_prof(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data, s32 item) ++{ ++ s32 err = 0; ++ struct wlc_ssid *ssid; ++ unsigned long flags; ++ struct wl_profile *profile = wl_get_profile_by_netdev(wl, ndev); ++ ++ if (!profile) ++ return WL_INVALID; ++ spin_lock_irqsave(&wl->cfgdrv_lock, flags); ++ switch (item) { ++ case WL_PROF_SSID: ++ ssid = (wlc_ssid_t *) data; ++ memset(profile->ssid.SSID, 0, ++ sizeof(profile->ssid.SSID)); ++ memcpy(profile->ssid.SSID, ssid->SSID, ssid->SSID_len); ++ profile->ssid.SSID_len = ssid->SSID_len; ++ break; ++ case WL_PROF_BSSID: ++ if (data) ++ memcpy(profile->bssid, data, ETHER_ADDR_LEN); ++ else ++ memset(profile->bssid, 0, ETHER_ADDR_LEN); ++ break; ++ case WL_PROF_SEC: ++ memcpy(&profile->sec, data, sizeof(profile->sec)); ++ break; ++ case WL_PROF_ACT: ++ profile->active = *(bool *)data; ++ break; ++ case WL_PROF_BEACONINT: ++ profile->beacon_interval = *(u16 *)data; ++ break; ++ case WL_PROF_DTIMPERIOD: ++ profile->dtim_period = *(u8 *)data; ++ break; ++ case WL_PROF_CHAN: ++ profile->channel = *(u32*)data; ++ default: ++ err = -EOPNOTSUPP; ++ break; ++ } ++ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); ++ ++ if (err == EOPNOTSUPP) ++ AP6211_ERR("unsupported item (%d)\n", item); ++ ++ return err; ++} ++ ++void wl_cfg80211_dbg_level(u32 level) ++{ ++ /* ++ * prohibit to change debug level ++ * by insmod parameter. ++ * eventually debug level will be configured ++ * in compile time by using CONFIG_XXX ++ */ ++ /* wl_dbg_level = level; */ ++} ++ ++static bool wl_is_ibssmode(struct wl_priv *wl, struct net_device *ndev) ++{ ++ return wl_get_mode_by_netdev(wl, ndev) == WL_MODE_IBSS; ++} ++ ++static __used bool wl_is_ibssstarter(struct wl_priv *wl) ++{ ++ return wl->ibss_starter; ++} ++ ++static void wl_rst_ie(struct wl_priv *wl) ++{ ++ struct wl_ie *ie = wl_to_ie(wl); ++ ++ ie->offset = 0; ++} ++ ++static __used s32 wl_add_ie(struct wl_priv *wl, u8 t, u8 l, u8 *v) ++{ ++ struct wl_ie *ie = wl_to_ie(wl); ++ s32 err = 0; ++ ++ if (unlikely(ie->offset + l + 2 > WL_TLV_INFO_MAX)) { ++ AP6211_ERR("ei crosses buffer boundary\n"); ++ return -ENOSPC; ++ } ++ ie->buf[ie->offset] = t; ++ ie->buf[ie->offset + 1] = l; ++ memcpy(&ie->buf[ie->offset + 2], v, l); ++ ie->offset += l + 2; ++ ++ return err; ++} ++ ++static s32 wl_mrg_ie(struct wl_priv *wl, u8 *ie_stream, u16 ie_size) ++{ ++ struct wl_ie *ie = wl_to_ie(wl); ++ s32 err = 0; ++ ++ if (unlikely(ie->offset + ie_size > WL_TLV_INFO_MAX)) { ++ AP6211_ERR("ei_stream crosses buffer boundary\n"); ++ return -ENOSPC; ++ } ++ memcpy(&ie->buf[ie->offset], ie_stream, ie_size); ++ ie->offset += ie_size; ++ ++ return err; ++} ++ ++static s32 wl_cp_ie(struct wl_priv *wl, u8 *dst, u16 dst_size) ++{ ++ struct wl_ie *ie = wl_to_ie(wl); ++ s32 err = 0; ++ ++ if (unlikely(ie->offset > dst_size)) { ++ AP6211_ERR("dst_size is not enough\n"); ++ return -ENOSPC; ++ } ++ memcpy(dst, &ie->buf[0], ie->offset); ++ ++ return err; ++} ++ ++static u32 wl_get_ielen(struct wl_priv *wl) ++{ ++ struct wl_ie *ie = wl_to_ie(wl); ++ ++ return ie->offset; ++} ++ ++static void wl_link_up(struct wl_priv *wl) ++{ ++ wl->link_up = true; ++} ++ ++static void wl_link_down(struct wl_priv *wl) ++{ ++ struct wl_connect_info *conn_info = wl_to_conn(wl); ++ ++ AP6211_DEBUG("In\n"); ++ wl->link_up = false; ++ conn_info->req_ie_len = 0; ++ conn_info->resp_ie_len = 0; ++} ++ ++static unsigned long wl_lock_eq(struct wl_priv *wl) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&wl->eq_lock, flags); ++ return flags; ++} ++ ++static void wl_unlock_eq(struct wl_priv *wl, unsigned long flags) ++{ ++ spin_unlock_irqrestore(&wl->eq_lock, flags); ++} ++ ++static void wl_init_eq_lock(struct wl_priv *wl) ++{ ++ spin_lock_init(&wl->eq_lock); ++} ++ ++static void wl_delay(u32 ms) ++{ ++ if (in_atomic() || (ms < jiffies_to_msecs(1))) { ++ mdelay(ms); ++ } else { ++ msleep(ms); ++ } ++} ++ ++s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ struct ether_addr p2pif_addr; ++ struct ether_addr primary_mac; ++ if (!wl->p2p) ++ return -1; ++ if (!p2p_is_on(wl)) { ++ get_primary_mac(wl, &primary_mac); ++ wl_cfgp2p_generate_bss_mac(&primary_mac, p2pdev_addr, &p2pif_addr); ++ } else { ++ memcpy(p2pdev_addr->octet, ++ wl->p2p->dev_addr.octet, ETHER_ADDR_LEN); ++ } ++ ++ ++ return 0; ++} ++s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len) ++{ ++ struct wl_priv *wl; ++ ++ wl = wlcfg_drv_priv; ++ ++ return wl_cfgp2p_set_p2p_noa(wl, net, buf, len); ++} ++ ++s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len) ++{ ++ struct wl_priv *wl; ++ wl = wlcfg_drv_priv; ++ ++ return wl_cfgp2p_get_p2p_noa(wl, net, buf, len); ++} ++ ++s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len) ++{ ++ struct wl_priv *wl; ++ wl = wlcfg_drv_priv; ++ ++ return wl_cfgp2p_set_p2p_ps(wl, net, buf, len); ++} ++ ++s32 wl_cfg80211_channel_to_freq(u32 channel) ++{ ++ int freq = 0; ++ ++#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) ++ freq = ieee80211_channel_to_frequency(channel); ++#else ++ { ++ u16 band = 0; ++ if (channel <= CH_MAX_2G_CHANNEL) ++ band = IEEE80211_BAND_2GHZ; ++ else ++ band = IEEE80211_BAND_5GHZ; ++ freq = ieee80211_channel_to_frequency(channel, band); ++ } ++#endif ++ return freq; ++} ++ ++s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len, ++ enum wl_management_type type) ++{ ++ struct wl_priv *wl; ++ struct net_device *ndev = NULL; ++ struct ether_addr primary_mac; ++ s32 ret = 0; ++ s32 bssidx = 0; ++ s32 pktflag = 0; ++ wl = wlcfg_drv_priv; ++ ++ if (wl_get_drv_status(wl, AP_CREATING, net) || ++ wl_get_drv_status(wl, AP_CREATED, net)) { ++ ndev = net; ++ bssidx = 0; ++ } else if (wl->p2p) { ++ if (net == wl->p2p_net) { ++ net = wl_to_prmry_ndev(wl); ++ } ++ if (!wl->p2p->on) { ++ get_primary_mac(wl, &primary_mac); ++ wl_cfgp2p_generate_bss_mac(&primary_mac, &wl->p2p->dev_addr, ++ &wl->p2p->int_addr); ++ /* In case of p2p_listen command, supplicant send remain_on_channel ++ * without turning on P2P ++ */ ++ ++ p2p_on(wl) = true; ++ ret = wl_cfgp2p_enable_discovery(wl, net, NULL, 0); ++ ++ if (unlikely(ret)) { ++ goto exit; ++ } ++ } ++ if (net != wl_to_prmry_ndev(wl)) { ++ if (wl_get_mode_by_netdev(wl, net) == WL_MODE_AP) { ++ ndev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION); ++ bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION); ++ } ++ } else { ++ ndev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY); ++ bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); ++ } ++ } ++ if (ndev != NULL) { ++ switch (type) { ++ case WL_BEACON: ++ pktflag = VNDR_IE_BEACON_FLAG; ++ break; ++ case WL_PROBE_RESP: ++ pktflag = VNDR_IE_PRBRSP_FLAG; ++ break; ++ case WL_ASSOC_RESP: ++ pktflag = VNDR_IE_ASSOCRSP_FLAG; ++ break; ++ } ++ if (pktflag) ++ ret = wl_cfgp2p_set_management_ie(wl, ndev, bssidx, pktflag, buf, len); ++ } ++exit: ++ return ret; ++} ++ ++static const struct rfkill_ops wl_rfkill_ops = { ++ .set_block = wl_rfkill_set ++}; ++ ++static int wl_rfkill_set(void *data, bool blocked) ++{ ++ struct wl_priv *wl = (struct wl_priv *)data; ++ ++ AP6211_DEBUG("Enter \n"); ++ AP6211_DEBUG("RF %s\n", blocked ? "blocked" : "unblocked"); ++ ++ if (!wl) ++ return -EINVAL; ++ ++ wl->rf_blocked = blocked; ++ ++ return 0; ++} ++ ++static int wl_setup_rfkill(struct wl_priv *wl, bool setup) ++{ ++ s32 err = 0; ++ ++ AP6211_DEBUG("Enter \n"); ++ if (!wl) ++ return -EINVAL; ++ if (setup) { ++ wl->rfkill = rfkill_alloc("brcmfmac-wifi", ++ wl_cfg80211_get_parent_dev(), ++ RFKILL_TYPE_WLAN, &wl_rfkill_ops, (void *)wl); ++ ++ if (!wl->rfkill) { ++ err = -ENOMEM; ++ goto err_out; ++ } ++ ++ err = rfkill_register(wl->rfkill); ++ ++ if (err) ++ rfkill_destroy(wl->rfkill); ++ } else { ++ if (!wl->rfkill) { ++ err = -ENOMEM; ++ goto err_out; ++ } ++ ++ rfkill_unregister(wl->rfkill); ++ rfkill_destroy(wl->rfkill); ++ } ++ ++err_out: ++ return err; ++} ++ ++struct device *wl_cfg80211_get_parent_dev(void) ++{ ++ return cfg80211_parent_dev; ++} ++ ++void wl_cfg80211_set_parent_dev(void *dev) ++{ ++ cfg80211_parent_dev = dev; ++} ++ ++static void wl_cfg80211_clear_parent_dev(void) ++{ ++ cfg80211_parent_dev = NULL; ++} ++ ++static void get_primary_mac(struct wl_priv *wl, struct ether_addr *mac) ++{ ++ wldev_iovar_getbuf_bsscfg(wl_to_prmry_ndev(wl), "cur_etheraddr", NULL, ++ 0, wl->ioctl_buf, WLC_IOCTL_SMLEN, 0, &wl->ioctl_buf_sync); ++ memcpy(mac->octet, wl->ioctl_buf, ETHER_ADDR_LEN); ++} ++ ++int wl_cfg80211_do_driver_init(struct net_device *net) ++{ ++ struct wl_priv *wl = *(struct wl_priv **)netdev_priv(net); ++ ++ if (!wl || !wl->wdev) ++ return -EINVAL; ++ ++ if (dhd_do_driver_init(wl->wdev->netdev) < 0) ++ return -1; ++ ++ return 0; ++} ++ ++void wl_cfg80211_enable_trace(u32 level) ++{ ++ wl_dbg_level = level; ++ AP6211_DEBUG("%s: wl_dbg_level = 0x%x\n", __FUNCTION__, wl_dbg_level); ++} ++ ++#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ ++ 2, 0)) ++static s32 ++wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, ++ struct net_device *dev, u64 cookie) ++{ ++ /* CFG80211 checks for tx_cancel_wait callback when ATTR_DURATION ++ * is passed with CMD_FRAME. This callback is supposed to cancel ++ * the OFFCHANNEL Wait. Since we are already taking care of that ++ * with the tx_mgmt logic, do nothing here. ++ */ ++ ++ return 0; ++} ++#endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL >= 3.2.0 */ ++ ++#ifdef WL11U ++bcm_tlv_t * ++wl_cfg80211_find_interworking_ie(u8 *parse, u32 len) ++{ ++ bcm_tlv_t *ie; ++ ++ while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_INTERWORKING_ID))) { ++ return (bcm_tlv_t *)ie; ++ } ++ return NULL; ++} ++ ++static s32 ++wl_cfg80211_add_iw_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, s32 pktflag, ++ uint8 ie_id, uint8 *data, uint8 data_len) ++{ ++ s32 err = BCME_OK; ++ s32 buf_len; ++ s32 iecount; ++ ie_setbuf_t *ie_setbuf; ++ ++ if (ie_id != DOT11_MNG_INTERWORKING_ID) ++ return BCME_UNSUPPORTED; ++ ++ /* Validate the pktflag parameter */ ++ if ((pktflag & ~(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG | ++ VNDR_IE_ASSOCRSP_FLAG | VNDR_IE_AUTHRSP_FLAG | ++ VNDR_IE_PRBREQ_FLAG | VNDR_IE_ASSOCREQ_FLAG| ++ VNDR_IE_CUSTOM_FLAG))) { ++ AP6211_ERR("cfg80211 Add IE: Invalid packet flag 0x%x\n", pktflag); ++ return -1; ++ } ++ ++ /* use VNDR_IE_CUSTOM_FLAG flags for none vendor IE . currently fixed value */ ++ pktflag = htod32(pktflag); ++ ++ buf_len = sizeof(ie_setbuf_t) + data_len - 1; ++ ie_setbuf = (ie_setbuf_t *) kzalloc(buf_len, GFP_KERNEL); ++ ++ if (!ie_setbuf) { ++ AP6211_ERR("Error allocating buffer for IE\n"); ++ return -ENOMEM; ++ } ++ ++ if (wl->iw_ie_len == data_len && !memcmp(wl->iw_ie, data, data_len)) { ++ AP6211_ERR("Previous IW IE is equals to current IE\n"); ++ return err; ++ } ++ ++ strncpy(ie_setbuf->cmd, "add", VNDR_IE_CMD_LEN - 1); ++ ie_setbuf->cmd[VNDR_IE_CMD_LEN - 1] = '\0'; ++ ++ /* Buffer contains only 1 IE */ ++ iecount = htod32(1); ++ memcpy((void *)&ie_setbuf->ie_buffer.iecount, &iecount, sizeof(int)); ++ memcpy((void *)&ie_setbuf->ie_buffer.ie_list[0].pktflag, &pktflag, sizeof(uint32)); ++ ++ /* Now, add the IE to the buffer */ ++ ie_setbuf->ie_buffer.ie_list[0].ie_data.id = ie_id; ++ ++ /* if already set with previous values, delete it first */ ++ if (wl->iw_ie_len != 0) { ++ AP6211_DEBUG("Different IW_IE was already set. clear first\n"); ++ ++ ie_setbuf->ie_buffer.ie_list[0].ie_data.len = 0; ++ ++ err = wldev_iovar_setbuf_bsscfg(ndev, "ie", ie_setbuf, buf_len, ++ wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); ++ ++ if (err != BCME_OK) ++ return err; ++ } ++ ++ ie_setbuf->ie_buffer.ie_list[0].ie_data.len = data_len; ++ memcpy((uchar *)&ie_setbuf->ie_buffer.ie_list[0].ie_data.data[0], data, data_len); ++ ++ err = wldev_iovar_setbuf_bsscfg(ndev, "ie", ie_setbuf, buf_len, ++ wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); ++ ++ if (err == BCME_OK) { ++ memcpy(wl->iw_ie, data, data_len); ++ wl->iw_ie_len = data_len; ++ wl->wl11u = TRUE; ++ ++ err = wldev_iovar_setint_bsscfg(ndev, "grat_arp", 1, bssidx); ++ } ++ ++ kfree(ie_setbuf); ++ return err; ++} ++#endif /* WL11U */ ++ ++#ifdef WL_HOST_BAND_MGMT ++s32 ++wl_cfg80211_set_band(struct net_device *ndev, int band) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ int ret = 0; ++ char ioctl_buf[50]; ++ ++ if ((band < WLC_BAND_AUTO) || (band > WLC_BAND_2G)) { ++ AP6211_ERR("Invalid band\n"); ++ return -EINVAL; ++ } ++ ++ if ((ret = wldev_iovar_setbuf(ndev, "roam_band", &band, ++ sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) { ++ AP6211_ERR("seting roam_band failed code=%d\n", ret); ++ return ret; ++ } ++ ++ AP6211_DEBUG("Setting band to %d\n", band); ++ wl->curr_band = band; ++ ++ return 0; ++} ++#endif /* WL_HOST_BAND_MGMT */ ++ ++#if defined(DHCP_SCAN_SUPPRESS) ++static void wl_cfg80211_scan_supp_timerfunc(ulong data) ++{ ++ struct wl_priv *wl = (struct wl_priv *)data; ++ ++ AP6211_DEBUG("Enter \n"); ++ schedule_work(&wl->wlan_work); ++} ++ ++static void wl_cfg80211_work_handler(struct work_struct *work) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ ++ wl = container_of(work, struct wl_priv, wlan_work); ++ ++ if (!wl) { ++ AP6211_ERR("wl_priv ptr NULL\n"); ++ return; ++ } ++ ++ if (wl->scan_suppressed) { ++ /* There is pending scan_suppress. Clean it */ ++ AP6211_ERR("Clean up from timer after %d msec\n", WL_SCAN_SUPPRESS_TIMEOUT); ++ wl_cfg80211_scan_suppress(wl_to_prmry_ndev(wl), 0); ++ } ++} ++ ++int wl_cfg80211_scan_suppress(struct net_device *dev, int suppress) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ int ret = 0; ++ ++ if (!dev || !wl || ((suppress != 0) && (suppress != 1))) ++ return -EINVAL; ++ ++ if (suppress == wl->scan_suppressed) { ++ AP6211_DEBUG("No change in scan_suppress state. Ignoring cmd..\n"); ++ return 0; ++ } ++ ++ if (timer_pending(&wl->scan_supp_timer)) ++ del_timer_sync(&wl->scan_supp_timer); ++ ++ if ((ret = wldev_ioctl(dev, WLC_SET_SCANSUPPRESS, ++ &suppress, sizeof(int), true)) < 0) { ++ AP6211_ERR("Scan suppress setting failed ret:%d \n", ret); ++ } else { ++ AP6211_DEBUG("Scan suppress %s \n", suppress ? "Enabled" : "Disabled"); ++ wl->scan_suppressed = suppress; ++ } ++ ++ /* If scan_suppress is set, Start a timer to monitor it (just incase) */ ++ if (wl->scan_suppressed) { ++ if (ret) { ++ AP6211_ERR("Retry scan_suppress reset at a later time \n"); ++ mod_timer(&wl->scan_supp_timer, ++ jiffies + msecs_to_jiffies(WL_SCAN_SUPPRESS_RETRY)); ++ } else { ++ AP6211_DEBUG("Start wlan_timer to clear of scan_suppress \n"); ++ mod_timer(&wl->scan_supp_timer, ++ jiffies + msecs_to_jiffies(WL_SCAN_SUPPRESS_TIMEOUT)); ++ } ++ } ++ ++ return ret; ++} ++#endif /* DHCP_SCAN_SUPPRESS */ +diff --git a/drivers/net/wireless/ap6211/wl_cfg80211.h b/drivers/net/wireless/ap6211/wl_cfg80211.h +new file mode 100755 +index 0000000..01dd136 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/wl_cfg80211.h +@@ -0,0 +1,791 @@ ++/* ++ * Linux cfg80211 driver ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: wl_cfg80211.h 374275 2012-12-12 11:44:18Z $ ++ */ ++ ++#ifndef _wl_cfg80211_h_ ++#define _wl_cfg80211_h_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++struct wl_conf; ++struct wl_iface; ++struct wl_priv; ++struct wl_security; ++struct wl_ibss; ++ ++ ++#define htod32(i) i ++#define htod16(i) i ++#define dtoh32(i) i ++#define dtoh16(i) i ++#define htodchanspec(i) i ++#define dtohchanspec(i) i ++ ++#define WL_DBG_NONE 0 ++#define WL_DBG_P2P_ACTION (1 << 5) ++#define WL_DBG_TRACE (1 << 4) ++#define WL_DBG_SCAN (1 << 3) ++#define WL_DBG_DBG (1 << 2) ++#define WL_DBG_INFO (1 << 1) ++#define WL_DBG_ERR (1 << 0) ++ ++/* 0 invalidates all debug messages. default is 1 */ ++#define WL_DBG_LEVEL 0xFF ++ ++#define WL_SCAN_RETRY_MAX 3 ++#define WL_NUM_PMKIDS_MAX MAXPMKID ++#define WL_SCAN_BUF_MAX (1024 * 8) ++#define WL_TLV_INFO_MAX 1500 ++#define WL_SCAN_IE_LEN_MAX 2048 ++#define WL_BSS_INFO_MAX 2048 ++#define WL_ASSOC_INFO_MAX 512 ++#define WL_IOCTL_LEN_MAX 1024 ++#define WL_EXTRA_BUF_MAX 2048 ++#define WL_ISCAN_BUF_MAX 2048 ++#define WL_ISCAN_TIMER_INTERVAL_MS 3000 ++#define WL_SCAN_ERSULTS_LAST (WL_SCAN_RESULTS_NO_MEM+1) ++#define WL_AP_MAX 256 ++#define WL_FILE_NAME_MAX 256 ++#define WL_DWELL_TIME 200 ++#define WL_MED_DWELL_TIME 400 ++#define WL_MIN_DWELL_TIME 100 ++#define WL_LONG_DWELL_TIME 1000 ++#define IFACE_MAX_CNT 2 ++#define WL_SCAN_CONNECT_DWELL_TIME_MS 200 ++#define WL_SCAN_JOIN_PROBE_INTERVAL_MS 20 ++#define WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320 ++#define WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400 ++#define WL_AF_TX_MAX_RETRY 5 ++ ++#define WL_SCAN_TIMER_INTERVAL_MS 8000 /* Scan timeout */ ++#define WL_CHANNEL_SYNC_RETRY 5 ++#define WL_INVALID -1 ++ ++/* Bring down SCB Timeout to 20secs from 60secs default */ ++#ifndef WL_SCB_TIMEOUT ++#define WL_SCB_TIMEOUT 20 ++#endif ++ ++/* SCAN_SUPPRESS timer values in ms */ ++#define WL_SCAN_SUPPRESS_TIMEOUT 31000 /* default Framwork DHCP timeout is 30 sec */ ++#define WL_SCAN_SUPPRESS_RETRY 3000 ++ ++/* driver status */ ++enum wl_status { ++ WL_STATUS_READY = 0, ++ WL_STATUS_SCANNING, ++ WL_STATUS_SCAN_ABORTING, ++ WL_STATUS_CONNECTING, ++ WL_STATUS_CONNECTED, ++ WL_STATUS_DISCONNECTING, ++ WL_STATUS_AP_CREATING, ++ WL_STATUS_AP_CREATED, ++ /* whole sending action frame procedure: ++ * includes a) 'finding common channel' for public action request frame ++ * and b) 'sending af via 'actframe' iovar' ++ */ ++ WL_STATUS_SENDING_ACT_FRM, ++ /* find a peer to go to a common channel before sending public action req frame */ ++ WL_STATUS_FINDING_COMMON_CHANNEL, ++ /* waiting for next af to sync time of supplicant. ++ * it includes SENDING_ACT_FRM and WAITING_NEXT_ACT_FRM_LISTEN ++ */ ++ WL_STATUS_WAITING_NEXT_ACT_FRM, ++#ifdef WL_CFG80211_SYNC_GON ++ /* go to listen state to wait for next af after SENDING_ACT_FRM */ ++ WL_STATUS_WAITING_NEXT_ACT_FRM_LISTEN, ++#endif /* WL_CFG80211_SYNC_GON */ ++ /* it will be set when upper layer requests listen and succeed in setting listen mode. ++ * if set, other scan request can abort current listen state ++ */ ++ WL_STATUS_REMAINING_ON_CHANNEL, ++#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST ++ /* it's fake listen state to keep current scan state. ++ * it will be set when upper layer requests listen but scan is running. then just run ++ * a expire timer without actual listen state. ++ * if set, other scan request does not need to abort scan. ++ */ ++ WL_STATUS_FAKE_REMAINING_ON_CHANNEL ++#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ ++}; ++ ++/* wi-fi mode */ ++enum wl_mode { ++ WL_MODE_BSS, ++ WL_MODE_IBSS, ++ WL_MODE_AP ++}; ++ ++/* driver profile list */ ++enum wl_prof_list { ++ WL_PROF_MODE, ++ WL_PROF_SSID, ++ WL_PROF_SEC, ++ WL_PROF_IBSS, ++ WL_PROF_BAND, ++ WL_PROF_CHAN, ++ WL_PROF_BSSID, ++ WL_PROF_ACT, ++ WL_PROF_BEACONINT, ++ WL_PROF_DTIMPERIOD ++}; ++ ++/* driver iscan state */ ++enum wl_iscan_state { ++ WL_ISCAN_STATE_IDLE, ++ WL_ISCAN_STATE_SCANING ++}; ++ ++/* donlge escan state */ ++enum wl_escan_state { ++ WL_ESCAN_STATE_IDLE, ++ WL_ESCAN_STATE_SCANING ++}; ++/* fw downloading status */ ++enum wl_fw_status { ++ WL_FW_LOADING_DONE, ++ WL_NVRAM_LOADING_DONE ++}; ++ ++enum wl_management_type { ++ WL_BEACON = 0x1, ++ WL_PROBE_RESP = 0x2, ++ WL_ASSOC_RESP = 0x4 ++}; ++/* beacon / probe_response */ ++struct beacon_proberesp { ++ __le64 timestamp; ++ __le16 beacon_int; ++ __le16 capab_info; ++ u8 variable[0]; ++} __attribute__ ((packed)); ++ ++/* driver configuration */ ++struct wl_conf { ++ u32 frag_threshold; ++ u32 rts_threshold; ++ u32 retry_short; ++ u32 retry_long; ++ s32 tx_power; ++ struct ieee80211_channel channel; ++}; ++ ++typedef s32(*EVENT_HANDLER) (struct wl_priv *wl, ++ struct net_device *ndev, const wl_event_msg_t *e, void *data); ++ ++/* bss inform structure for cfg80211 interface */ ++struct wl_cfg80211_bss_info { ++ u16 band; ++ u16 channel; ++ s16 rssi; ++ u16 frame_len; ++ u8 frame_buf[1]; ++}; ++ ++/* basic structure of scan request */ ++struct wl_scan_req { ++ struct wlc_ssid ssid; ++}; ++ ++/* basic structure of information element */ ++struct wl_ie { ++ u16 offset; ++ u8 buf[WL_TLV_INFO_MAX]; ++}; ++ ++/* event queue for cfg80211 main event */ ++struct wl_event_q { ++ struct list_head eq_list; ++ u32 etype; ++ wl_event_msg_t emsg; ++ s8 edata[1]; ++}; ++ ++/* security information with currently associated ap */ ++struct wl_security { ++ u32 wpa_versions; ++ u32 auth_type; ++ u32 cipher_pairwise; ++ u32 cipher_group; ++ u32 wpa_auth; ++ u32 auth_assoc_res_status; ++}; ++ ++/* ibss information for currently joined ibss network */ ++struct wl_ibss { ++ u8 beacon_interval; /* in millisecond */ ++ u8 atim; /* in millisecond */ ++ s8 join_only; ++ u8 band; ++ u8 channel; ++}; ++ ++/* wl driver profile */ ++struct wl_profile { ++ u32 mode; ++ s32 band; ++ u32 channel; ++ struct wlc_ssid ssid; ++ struct wl_security sec; ++ struct wl_ibss ibss; ++ u8 bssid[ETHER_ADDR_LEN]; ++ u16 beacon_interval; ++ u8 dtim_period; ++ bool active; ++}; ++ ++struct net_info { ++ struct net_device *ndev; ++ struct wireless_dev *wdev; ++ struct wl_profile profile; ++ s32 mode; ++ s32 roam_off; ++ unsigned long sme_state; ++ bool pm_restore; ++ bool pm_block; ++ s32 pm; ++ struct list_head list; /* list of all net_info structure */ ++}; ++typedef s32(*ISCAN_HANDLER) (struct wl_priv *wl); ++ ++/* iscan controller */ ++struct wl_iscan_ctrl { ++ struct net_device *dev; ++ struct timer_list timer; ++ u32 timer_ms; ++ u32 timer_on; ++ s32 state; ++ struct task_struct *tsk; ++ struct semaphore sync; ++ ISCAN_HANDLER iscan_handler[WL_SCAN_ERSULTS_LAST]; ++ void *data; ++ s8 ioctl_buf[WLC_IOCTL_SMLEN]; ++ s8 scan_buf[WL_ISCAN_BUF_MAX]; ++}; ++ ++/* association inform */ ++#define MAX_REQ_LINE 1024 ++struct wl_connect_info { ++ u8 req_ie[MAX_REQ_LINE]; ++ s32 req_ie_len; ++ u8 resp_ie[MAX_REQ_LINE]; ++ s32 resp_ie_len; ++}; ++ ++/* firmware /nvram downloading controller */ ++struct wl_fw_ctrl { ++ const struct firmware *fw_entry; ++ unsigned long status; ++ u32 ptr; ++ s8 fw_name[WL_FILE_NAME_MAX]; ++ s8 nvram_name[WL_FILE_NAME_MAX]; ++}; ++ ++/* assoc ie length */ ++struct wl_assoc_ielen { ++ u32 req_len; ++ u32 resp_len; ++}; ++ ++/* wpa2 pmk list */ ++struct wl_pmk_list { ++ pmkid_list_t pmkids; ++ pmkid_t foo[MAXPMKID - 1]; ++}; ++ ++ ++#define ESCAN_BUF_SIZE (64 * 1024) ++ ++struct escan_info { ++ u32 escan_state; ++#if defined(STATIC_WL_PRIV_STRUCT) ++#ifndef CONFIG_DHD_USE_STATIC_BUF ++#error STATIC_WL_PRIV_STRUCT should be used with CONFIG_DHD_USE_STATIC_BUF ++#endif ++ u8 *escan_buf; ++#else ++ u8 escan_buf[ESCAN_BUF_SIZE]; ++#endif /* STATIC_WL_PRIV_STRUCT */ ++ struct wiphy *wiphy; ++ struct net_device *ndev; ++}; ++ ++struct ap_info { ++/* Structure to hold WPS, WPA IEs for a AP */ ++ u8 probe_res_ie[VNDR_IES_MAX_BUF_LEN]; ++ u8 beacon_ie[VNDR_IES_MAX_BUF_LEN]; ++ u32 probe_res_ie_len; ++ u32 beacon_ie_len; ++ u8 *wpa_ie; ++ u8 *rsn_ie; ++ u8 *wps_ie; ++ bool security_mode; ++}; ++struct btcoex_info { ++ struct timer_list timer; ++ u32 timer_ms; ++ u32 timer_on; ++ u32 ts_dhcp_start; /* ms ts ecord time stats */ ++ u32 ts_dhcp_ok; /* ms ts ecord time stats */ ++ bool dhcp_done; /* flag, indicates that host done with ++ * dhcp before t1/t2 expiration ++ */ ++ s32 bt_state; ++ struct work_struct work; ++ struct net_device *dev; ++}; ++ ++struct sta_info { ++ /* Structure to hold WPS IE for a STA */ ++ u8 probe_req_ie[VNDR_IES_BUF_LEN]; ++ u8 assoc_req_ie[VNDR_IES_BUF_LEN]; ++ u32 probe_req_ie_len; ++ u32 assoc_req_ie_len; ++}; ++ ++struct afx_hdl { ++ wl_af_params_t *pending_tx_act_frm; ++ struct ether_addr tx_dst_addr; ++ struct net_device *dev; ++ struct work_struct work; ++ u32 bssidx; ++ u32 retry; ++ s32 peer_chan; ++ s32 peer_listen_chan; /* search channel: configured by upper layer */ ++ s32 my_listen_chan; /* listen chanel: extract it from prb req or gon req */ ++ bool is_listen; ++ bool ack_recv; ++ bool is_active; ++}; ++ ++struct parsed_ies { ++ wpa_ie_fixed_t *wps_ie; ++ u32 wps_ie_len; ++ wpa_ie_fixed_t *wpa_ie; ++ u32 wpa_ie_len; ++ bcm_tlv_t *wpa2_ie; ++ u32 wpa2_ie_len; ++}; ++ ++ ++#ifdef WL11U ++/* Max length of Interworking element */ ++#define IW_IES_MAX_BUF_LEN 9 ++#endif ++ ++#define MAX_EVENT_BUF_NUM 16 ++typedef struct wl_eventmsg_buf { ++ u16 num; ++ struct { ++ u16 type; ++ bool set; ++ } event [MAX_EVENT_BUF_NUM]; ++} wl_eventmsg_buf_t; ++ ++/* private data of cfg80211 interface */ ++struct wl_priv { ++ struct wireless_dev *wdev; /* representing wl cfg80211 device */ ++ ++ struct wireless_dev *p2p_wdev; /* representing wl cfg80211 device for P2P */ ++ struct net_device *p2p_net; /* reference to p2p0 interface */ ++ ++ struct wl_conf *conf; ++ struct cfg80211_scan_request *scan_request; /* scan request object */ ++ EVENT_HANDLER evt_handler[WLC_E_LAST]; ++ struct list_head eq_list; /* used for event queue */ ++ struct list_head net_list; /* used for struct net_info */ ++ spinlock_t eq_lock; /* for event queue synchronization */ ++ spinlock_t cfgdrv_lock; /* to protect scan status (and others if needed) */ ++ struct completion act_frm_scan; ++ struct completion iface_disable; ++ struct completion wait_next_af; ++ struct mutex usr_sync; /* maily for up/down synchronization */ ++ struct wl_scan_results *bss_list; ++ struct wl_scan_results *scan_results; ++ ++ /* scan request object for internal purpose */ ++ struct wl_scan_req *scan_req_int; ++ /* information element object for internal purpose */ ++#if defined(STATIC_WL_PRIV_STRUCT) ++ struct wl_ie *ie; ++#else ++ struct wl_ie ie; ++#endif ++ struct wl_iscan_ctrl *iscan; /* iscan controller */ ++ ++ /* association information container */ ++#if defined(STATIC_WL_PRIV_STRUCT) ++ struct wl_connect_info *conn_info; ++#else ++ struct wl_connect_info conn_info; ++#endif ++ ++ struct wl_pmk_list *pmk_list; /* wpa2 pmk list */ ++ tsk_ctl_t event_tsk; /* task of main event handler thread */ ++ void *pub; ++ u32 iface_cnt; ++ u32 channel; /* current channel */ ++ u32 af_sent_channel; /* channel action frame is sent */ ++ /* next af subtype to cancel the remained dwell time in rx process */ ++ u8 next_af_subtype; ++#ifdef WL_CFG80211_SYNC_GON ++ ulong af_tx_sent_jiffies; ++#endif /* WL_CFG80211_SYNC_GON */ ++ bool iscan_on; /* iscan on/off switch */ ++ bool iscan_kickstart; /* indicate iscan already started */ ++ bool escan_on; /* escan on/off switch */ ++ struct escan_info escan_info; /* escan information */ ++ bool active_scan; /* current scan mode */ ++ bool ibss_starter; /* indicates this sta is ibss starter */ ++ bool link_up; /* link/connection up flag */ ++ ++ /* indicate whether chip to support power save mode */ ++ bool pwr_save; ++ bool roam_on; /* on/off switch for self-roaming */ ++ bool scan_tried; /* indicates if first scan attempted */ ++ bool wlfc_on; ++ bool vsdb_mode; ++ bool roamoff_on_concurrent; ++ u8 *ioctl_buf; /* ioctl buffer */ ++ struct mutex ioctl_buf_sync; ++ u8 *escan_ioctl_buf; ++ u8 *extra_buf; /* maily to grab assoc information */ ++ struct dentry *debugfsdir; ++ struct rfkill *rfkill; ++ bool rf_blocked; ++ struct ieee80211_channel remain_on_chan; ++ enum nl80211_channel_type remain_on_chan_type; ++ u64 send_action_id; ++ u64 last_roc_id; ++ wait_queue_head_t netif_change_event; ++ struct completion send_af_done; ++ struct afx_hdl *afx_hdl; ++ struct ap_info *ap_info; ++ struct sta_info *sta_info; ++ struct p2p_info *p2p; ++ bool p2p_supported; ++ struct btcoex_info *btcoex_info; ++ struct timer_list scan_timeout; /* Timer for catch scan event timeout */ ++ s32(*state_notifier) (struct wl_priv *wl, ++ struct net_info *_net_info, enum wl_status state, bool set); ++ unsigned long interrested_state; ++ wlc_ssid_t hostapd_ssid; ++#ifdef WL11U ++ bool wl11u; ++ u8 iw_ie[IW_IES_MAX_BUF_LEN]; ++ u32 iw_ie_len; ++#endif /* WL11U */ ++ bool sched_scan_running; /* scheduled scan req status */ ++#ifdef WL_SCHED_SCAN ++ struct cfg80211_sched_scan_request *sched_scan_req; /* scheduled scan req */ ++#endif /* WL_SCHED_SCAN */ ++#ifdef WL_HOST_BAND_MGMT ++ u8 curr_band; ++#endif /* WL_HOST_BAND_MGMT */ ++ bool scan_suppressed; ++ struct timer_list scan_supp_timer; ++ struct work_struct wlan_work; ++ struct mutex event_sync; /* maily for up/down synchronization */ ++}; ++ ++ ++static inline struct wl_bss_info *next_bss(struct wl_scan_results *list, struct wl_bss_info *bss) ++{ ++ return bss = bss ? ++ (struct wl_bss_info *)((uintptr) bss + dtoh32(bss->length)) : list->bss_info; ++} ++static inline s32 ++wl_alloc_netinfo(struct wl_priv *wl, struct net_device *ndev, ++ struct wireless_dev * wdev, s32 mode, bool pm_block) ++{ ++ struct net_info *_net_info; ++ s32 err = 0; ++ if (wl->iface_cnt == IFACE_MAX_CNT) ++ return -ENOMEM; ++ _net_info = kzalloc(sizeof(struct net_info), GFP_KERNEL); ++ if (!_net_info) ++ err = -ENOMEM; ++ else { ++ _net_info->mode = mode; ++ _net_info->ndev = ndev; ++ _net_info->wdev = wdev; ++ _net_info->pm_restore = 0; ++ _net_info->pm = 0; ++ _net_info->pm_block = pm_block; ++ _net_info->roam_off = WL_INVALID; ++ wl->iface_cnt++; ++ list_add(&_net_info->list, &wl->net_list); ++ } ++ return err; ++} ++static inline void ++wl_dealloc_netinfo(struct wl_priv *wl, struct net_device *ndev) ++{ ++ struct net_info *_net_info, *next; ++ ++ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { ++ if (ndev && (_net_info->ndev == ndev)) { ++ list_del(&_net_info->list); ++ wl->iface_cnt--; ++ if (_net_info->wdev) { ++ kfree(_net_info->wdev); ++ ndev->ieee80211_ptr = NULL; ++ } ++ kfree(_net_info); ++ } ++ } ++ ++} ++static inline void ++wl_delete_all_netinfo(struct wl_priv *wl) ++{ ++ struct net_info *_net_info, *next; ++ ++ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { ++ list_del(&_net_info->list); ++ if (_net_info->wdev) ++ kfree(_net_info->wdev); ++ kfree(_net_info); ++ } ++ wl->iface_cnt = 0; ++} ++static inline u32 ++wl_get_status_all(struct wl_priv *wl, s32 status) ++ ++{ ++ struct net_info *_net_info, *next; ++ u32 cnt = 0; ++ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { ++ if (_net_info->ndev && ++ test_bit(status, &_net_info->sme_state)) ++ cnt++; ++ } ++ return cnt; ++} ++static inline void ++wl_set_status_all(struct wl_priv *wl, s32 status, u32 op) ++{ ++ struct net_info *_net_info, *next; ++ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { ++ switch (op) { ++ case 1: ++ return; /* set all status is not allowed */ ++ case 2: ++ clear_bit(status, &_net_info->sme_state); ++ if (wl->state_notifier && ++ test_bit(status, &(wl->interrested_state))) ++ wl->state_notifier(wl, _net_info, status, false); ++ break; ++ case 4: ++ return; /* change all status is not allowed */ ++ default: ++ return; /* unknown operation */ ++ } ++ } ++} ++static inline void ++wl_set_status_by_netdev(struct wl_priv *wl, s32 status, ++ struct net_device *ndev, u32 op) ++{ ++ ++ struct net_info *_net_info, *next; ++ ++ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { ++ if (ndev && (_net_info->ndev == ndev)) { ++ switch (op) { ++ case 1: ++ set_bit(status, &_net_info->sme_state); ++ if (wl->state_notifier && ++ test_bit(status, &(wl->interrested_state))) ++ wl->state_notifier(wl, _net_info, status, true); ++ break; ++ case 2: ++ clear_bit(status, &_net_info->sme_state); ++ if (wl->state_notifier && ++ test_bit(status, &(wl->interrested_state))) ++ wl->state_notifier(wl, _net_info, status, false); ++ break; ++ case 4: ++ change_bit(status, &_net_info->sme_state); ++ break; ++ } ++ } ++ ++ } ++ ++} ++ ++static inline u32 ++wl_get_status_by_netdev(struct wl_priv *wl, s32 status, ++ struct net_device *ndev) ++{ ++ struct net_info *_net_info, *next; ++ ++ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { ++ if (ndev && (_net_info->ndev == ndev)) ++ return test_bit(status, &_net_info->sme_state); ++ } ++ return 0; ++} ++ ++static inline s32 ++wl_get_mode_by_netdev(struct wl_priv *wl, struct net_device *ndev) ++{ ++ struct net_info *_net_info, *next; ++ ++ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { ++ if (ndev && (_net_info->ndev == ndev)) ++ return _net_info->mode; ++ } ++ return -1; ++} ++ ++ ++static inline void ++wl_set_mode_by_netdev(struct wl_priv *wl, struct net_device *ndev, ++ s32 mode) ++{ ++ struct net_info *_net_info, *next; ++ ++ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { ++ if (ndev && (_net_info->ndev == ndev)) ++ _net_info->mode = mode; ++ } ++} ++static inline struct wl_profile * ++wl_get_profile_by_netdev(struct wl_priv *wl, struct net_device *ndev) ++{ ++ struct net_info *_net_info, *next; ++ ++ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { ++ if (ndev && (_net_info->ndev == ndev)) ++ return &_net_info->profile; ++ } ++ return NULL; ++} ++static inline struct net_info * ++wl_get_netinfo_by_netdev(struct wl_priv *wl, struct net_device *ndev) ++{ ++ struct net_info *_net_info, *next; ++ ++ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { ++ if (ndev && (_net_info->ndev == ndev)) ++ return _net_info; ++ } ++ return NULL; ++} ++#define wl_to_wiphy(w) (w->wdev->wiphy) ++#define wl_to_prmry_ndev(w) (w->wdev->netdev) ++#define ndev_to_wl(n) (wdev_to_wl(n->ieee80211_ptr)) ++#define wl_to_sr(w) (w->scan_req_int) ++#if defined(STATIC_WL_PRIV_STRUCT) ++#define wl_to_ie(w) (w->ie) ++#define wl_to_conn(w) (w->conn_info) ++#else ++#define wl_to_ie(w) (&w->ie) ++#define wl_to_conn(w) (&w->conn_info) ++#endif ++#define iscan_to_wl(i) ((struct wl_priv *)(i->data)) ++#define wl_to_iscan(w) (w->iscan) ++#define wiphy_from_scan(w) (w->escan_info.wiphy) ++#define wl_get_drv_status_all(wl, stat) \ ++ (wl_get_status_all(wl, WL_STATUS_ ## stat)) ++#define wl_get_drv_status(wl, stat, ndev) \ ++ (wl_get_status_by_netdev(wl, WL_STATUS_ ## stat, ndev)) ++#define wl_set_drv_status(wl, stat, ndev) \ ++ (wl_set_status_by_netdev(wl, WL_STATUS_ ## stat, ndev, 1)) ++#define wl_clr_drv_status(wl, stat, ndev) \ ++ (wl_set_status_by_netdev(wl, WL_STATUS_ ## stat, ndev, 2)) ++#define wl_clr_drv_status_all(wl, stat) \ ++ (wl_set_status_all(wl, WL_STATUS_ ## stat, 2)) ++#define wl_chg_drv_status(wl, stat, ndev) \ ++ (wl_set_status_by_netdev(wl, WL_STATUS_ ## stat, ndev, 4)) ++ ++#define for_each_bss(list, bss, __i) \ ++ for (__i = 0; __i < list->count && __i < WL_AP_MAX; __i++, bss = next_bss(list, bss)) ++ ++#define for_each_ndev(wl, iter, next) \ ++ list_for_each_entry_safe(iter, next, &wl->net_list, list) ++ ++ ++/* In case of WPS from wpa_supplicant, pairwise siute and group suite is 0. ++ * In addtion to that, wpa_version is WPA_VERSION_1 ++ */ ++#define is_wps_conn(_sme) \ ++ ((wl_cfgp2p_find_wpsie((u8 *)_sme->ie, _sme->ie_len) != NULL) && \ ++ (!_sme->crypto.n_ciphers_pairwise) && \ ++ (!_sme->crypto.cipher_group)) ++extern s32 wl_cfg80211_attach(struct net_device *ndev, void *data); ++extern s32 wl_cfg80211_attach_post(struct net_device *ndev); ++extern void wl_cfg80211_detach(void *para); ++ ++extern void wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t *e, ++ void *data); ++void wl_cfg80211_set_parent_dev(void *dev); ++struct device *wl_cfg80211_get_parent_dev(void); ++ ++extern s32 wl_cfg80211_up(void *para); ++extern s32 wl_cfg80211_down(void *para); ++extern s32 wl_cfg80211_notify_ifadd(struct net_device *ndev, s32 idx, s32 bssidx, ++ void* _net_attach); ++extern s32 wl_cfg80211_ifdel_ops(struct net_device *net); ++extern s32 wl_cfg80211_notify_ifdel(void); ++extern s32 wl_cfg80211_is_progress_ifadd(void); ++extern s32 wl_cfg80211_is_progress_ifchange(void); ++extern s32 wl_cfg80211_is_progress_ifadd(void); ++extern s32 wl_cfg80211_notify_ifchange(void); ++extern void wl_cfg80211_dbg_level(u32 level); ++extern s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr); ++extern s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len); ++extern s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len); ++extern s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len, ++ enum wl_management_type type); ++extern s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len); ++extern int wl_cfg80211_hang(struct net_device *dev, u16 reason); ++extern s32 wl_mode_to_nl80211_iftype(s32 mode); ++int wl_cfg80211_do_driver_init(struct net_device *net); ++void wl_cfg80211_enable_trace(u32 level); ++extern s32 wl_update_wiphybands(struct wl_priv *wl, bool notify); ++extern s32 wl_cfg80211_if_is_group_owner(void); ++extern chanspec_t wl_ch_host_to_driver(u16 channel); ++extern s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add); ++extern void wl_stop_wait_next_action_frame(struct wl_priv *wl, struct net_device *ndev); ++extern s32 wl_cfg80211_set_band(struct net_device *ndev, int band); ++extern int wl_cfg80211_update_power_mode(struct net_device *dev); ++#if defined(DHCP_SCAN_SUPPRESS) ++extern int wl_cfg80211_scan_suppress(struct net_device *dev, int suppress); ++#endif /* OEM_ANDROID */ ++extern void wl_cfg80211_add_to_eventbuffer(wl_eventmsg_buf_t *ev, u16 event, bool set); ++extern s32 wl_cfg80211_apply_eventbuffer(struct net_device *ndev, ++ struct wl_priv *wl, wl_eventmsg_buf_t *ev); ++#endif /* _wl_cfg80211_h_ */ +diff --git a/drivers/net/wireless/ap6211/wl_cfgp2p.c b/drivers/net/wireless/ap6211/wl_cfgp2p.c +new file mode 100755 +index 0000000..eb7df08 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/wl_cfgp2p.c +@@ -0,0 +1,2393 @@ ++/* ++ * Linux cfgp2p driver ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: wl_cfgp2p.c 372668 2012-12-04 14:07:12Z $ ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++static s8 scanparambuf[WLC_IOCTL_SMLEN]; ++static s8 g_mgmt_ie_buf[2048]; ++static bool ++wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type); ++ ++static u32 ++wl_cfgp2p_vndr_ie(struct wl_priv *wl, u8 *iebuf, s32 bssidx, s32 pktflag, ++ s8 *oui, s32 ie_id, s8 *data, s32 datalen, const s8* add_del_cmd); ++ ++static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev); ++static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd); ++static int wl_cfgp2p_if_open(struct net_device *net); ++static int wl_cfgp2p_if_stop(struct net_device *net); ++static s32 wl_cfgp2p_cancel_listen(struct wl_priv *wl, struct net_device *ndev, ++ bool notify); ++ ++static const struct net_device_ops wl_cfgp2p_if_ops = { ++ .ndo_open = wl_cfgp2p_if_open, ++ .ndo_stop = wl_cfgp2p_if_stop, ++ .ndo_do_ioctl = wl_cfgp2p_do_ioctl, ++ .ndo_start_xmit = wl_cfgp2p_start_xmit, ++}; ++ ++bool wl_cfgp2p_is_pub_action(void *frame, u32 frame_len) ++{ ++ wifi_p2p_pub_act_frame_t *pact_frm; ++ ++ if (frame == NULL) ++ return false; ++ pact_frm = (wifi_p2p_pub_act_frame_t *)frame; ++ if (frame_len < sizeof(wifi_p2p_pub_act_frame_t) -1) ++ return false; ++ ++ if (pact_frm->category == P2P_PUB_AF_CATEGORY && ++ pact_frm->action == P2P_PUB_AF_ACTION && ++ pact_frm->oui_type == P2P_VER && ++ memcmp(pact_frm->oui, P2P_OUI, sizeof(pact_frm->oui)) == 0) { ++ return true; ++ } ++ ++ return false; ++} ++ ++bool wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len) ++{ ++ wifi_p2p_action_frame_t *act_frm; ++ ++ if (frame == NULL) ++ return false; ++ act_frm = (wifi_p2p_action_frame_t *)frame; ++ if (frame_len < sizeof(wifi_p2p_action_frame_t) -1) ++ return false; ++ ++ if (act_frm->category == P2P_AF_CATEGORY && ++ act_frm->type == P2P_VER && ++ memcmp(act_frm->OUI, P2P_OUI, DOT11_OUI_LEN) == 0) { ++ return true; ++ } ++ ++ return false; ++} ++ ++/* ++* Currently Action frame just pass to P2P interface regardless real dst. ++* but GAS Action can be used for Hotspot2.0 as well ++* Need to distingush that it's for P2P or HS20 ++*/ ++#ifdef WL11U ++#define GAS_RESP_LEN 2 ++#define DOUBLE_TLV_BODY_OFF 4 ++#define GAS_RESP_OFFSET 4 ++#define GAS_CRESP_OFFSET 5 ++ ++bool wl_cfgp2p_find_gas_subtype(u8 subtype, u8* data, u32 len) ++{ ++ bcm_tlv_t *ie = (bcm_tlv_t *)data; ++ u8 *frame = NULL; ++ u16 id, flen; ++ ++ /* Skipped first ANQP Element, if frame has anqp elemnt */ ++ ie = bcm_parse_tlvs(ie, (int)len, DOT11_MNG_ADVERTISEMENT_ID); ++ ++ if (ie == NULL) ++ return false; ++ ++ frame = (uint8 *)ie + ie->len + TLV_HDR_LEN + GAS_RESP_LEN; ++ id = ((u16) (((frame)[1] << 8) | (frame)[0])); ++ flen = ((u16) (((frame)[3] << 8) | (frame)[2])); ++ ++ /* If the contents match the OUI and the type */ ++ if (flen >= WFA_OUI_LEN + 1 && ++ id == P2PSD_GAS_NQP_INFOID && ++ !bcmp(&frame[DOUBLE_TLV_BODY_OFF], (const uint8*)WFA_OUI, WFA_OUI_LEN) && ++ subtype == frame[DOUBLE_TLV_BODY_OFF+WFA_OUI_LEN]) { ++ return true; ++ } ++ ++ return false; ++} ++#endif /* WL11U */ ++ ++bool wl_cfgp2p_is_gas_action(void *frame, u32 frame_len) ++{ ++ ++ wifi_p2psd_gas_pub_act_frame_t *sd_act_frm; ++ ++ if (frame == NULL) ++ return false; ++ ++ sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame; ++ if (frame_len < sizeof(wifi_p2psd_gas_pub_act_frame_t) - 1) ++ return false; ++ if (sd_act_frm->category != P2PSD_ACTION_CATEGORY) ++ return false; ++ ++#ifdef WL11U ++ if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP) ++ return wl_cfgp2p_find_gas_subtype(P2PSD_GAS_OUI_SUBTYPE, ++ (u8 *)sd_act_frm->query_data + GAS_RESP_OFFSET, ++ frame_len); ++ ++ else if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_CRESP) ++ return wl_cfgp2p_find_gas_subtype(P2PSD_GAS_OUI_SUBTYPE, ++ (u8 *)sd_act_frm->query_data + GAS_CRESP_OFFSET, ++ frame_len); ++ else if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ || ++ sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ) ++ return true; ++ else ++ return false; ++#else ++ if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ || ++ sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP || ++ sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ || ++ sd_act_frm->action == P2PSD_ACTION_ID_GAS_CRESP) ++ return true; ++ else ++ return false; ++#endif /* WLC11U */ ++} ++void wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len) ++{ ++ wifi_p2p_pub_act_frame_t *pact_frm; ++ wifi_p2p_action_frame_t *act_frm; ++ wifi_p2psd_gas_pub_act_frame_t *sd_act_frm; ++ if (!frame || frame_len <= 2) ++ return; ++ ++ if (wl_cfgp2p_is_pub_action(frame, frame_len)) { ++ pact_frm = (wifi_p2p_pub_act_frame_t *)frame; ++ switch (pact_frm->subtype) { ++ case P2P_PAF_GON_REQ: ++ AP6211_DEBUG("%s P2P Group Owner Negotiation Req Frame\n", ++ (tx)? "TX": "RX"); ++ break; ++ case P2P_PAF_GON_RSP: ++ AP6211_DEBUG("%s P2P Group Owner Negotiation Rsp Frame\n", ++ (tx)? "TX": "RX"); ++ break; ++ case P2P_PAF_GON_CONF: ++ AP6211_DEBUG("%s P2P Group Owner Negotiation Confirm Frame\n", ++ (tx)? "TX": "RX"); ++ break; ++ case P2P_PAF_INVITE_REQ: ++ AP6211_DEBUG("%s P2P Invitation Request Frame\n", ++ (tx)? "TX": "RX"); ++ break; ++ case P2P_PAF_INVITE_RSP: ++ AP6211_DEBUG("%s P2P Invitation Response Frame\n", ++ (tx)? "TX": "RX"); ++ break; ++ case P2P_PAF_DEVDIS_REQ: ++ AP6211_DEBUG("%s P2P Device Discoverability Request Frame\n", ++ (tx)? "TX": "RX"); ++ break; ++ case P2P_PAF_DEVDIS_RSP: ++ AP6211_DEBUG("%s P2P Device Discoverability Response Frame\n", ++ (tx)? "TX": "RX"); ++ break; ++ case P2P_PAF_PROVDIS_REQ: ++ AP6211_DEBUG("%s P2P Provision Discovery Request Frame\n", ++ (tx)? "TX": "RX"); ++ break; ++ case P2P_PAF_PROVDIS_RSP: ++ AP6211_DEBUG("%s P2P Provision Discovery Response Frame\n", ++ (tx)? "TX": "RX"); ++ break; ++ default: ++ AP6211_DEBUG("%s Unknown P2P Public Action Frame\n", ++ (tx)? "TX": "RX"); ++ ++ } ++ ++ } else if (wl_cfgp2p_is_p2p_action(frame, frame_len)) { ++ act_frm = (wifi_p2p_action_frame_t *)frame; ++ switch (act_frm->subtype) { ++ case P2P_AF_NOTICE_OF_ABSENCE: ++ AP6211_DEBUG("%s P2P Notice of Absence Frame\n", ++ (tx)? "TX": "RX"); ++ break; ++ case P2P_AF_PRESENCE_REQ: ++ AP6211_DEBUG("%s P2P Presence Request Frame\n", ++ (tx)? "TX": "RX"); ++ break; ++ case P2P_AF_PRESENCE_RSP: ++ AP6211_DEBUG("%s P2P Presence Response Frame\n", ++ (tx)? "TX": "RX"); ++ break; ++ case P2P_AF_GO_DISC_REQ: ++ AP6211_DEBUG("%s P2P Discoverability Request Frame\n", ++ (tx)? "TX": "RX"); ++ break; ++ default: ++ AP6211_DEBUG("%s Unknown P2P Action Frame\n", ++ (tx)? "TX": "RX"); ++ } ++ ++ } else if (wl_cfgp2p_is_gas_action(frame, frame_len)) { ++ sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame; ++ switch (sd_act_frm->action) { ++ case P2PSD_ACTION_ID_GAS_IREQ: ++ AP6211_DEBUG("%s P2P GAS Initial Request\n", ++ (tx)? "TX" : "RX"); ++ break; ++ case P2PSD_ACTION_ID_GAS_IRESP: ++ AP6211_DEBUG("%s P2P GAS Initial Response\n", ++ (tx)? "TX" : "RX"); ++ break; ++ case P2PSD_ACTION_ID_GAS_CREQ: ++ AP6211_DEBUG("%s P2P GAS Comback Request\n", ++ (tx)? "TX" : "RX"); ++ break; ++ case P2PSD_ACTION_ID_GAS_CRESP: ++ AP6211_DEBUG("%s P2P GAS Comback Response\n", ++ (tx)? "TX" : "RX"); ++ break; ++ default: ++ AP6211_DEBUG("%s Unknown P2P GAS Frame\n", ++ (tx)? "TX" : "RX"); ++ } ++ ++ ++ } ++} ++ ++/* ++ * Initialize variables related to P2P ++ * ++ */ ++s32 ++wl_cfgp2p_init_priv(struct wl_priv *wl) ++{ ++ if (!(wl->p2p = kzalloc(sizeof(struct p2p_info), GFP_KERNEL))) { ++ AP6211_ERR("struct p2p_info allocation failed\n"); ++ return -ENOMEM; ++ } ++#define INIT_IE(IE_TYPE, BSS_TYPE) \ ++ do { \ ++ memset(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie, 0, \ ++ sizeof(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie)); \ ++ wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie_len = 0; \ ++ } while (0); ++ ++ INIT_IE(probe_req, P2PAPI_BSSCFG_PRIMARY); ++ INIT_IE(probe_res, P2PAPI_BSSCFG_PRIMARY); ++ INIT_IE(assoc_req, P2PAPI_BSSCFG_PRIMARY); ++ INIT_IE(assoc_res, P2PAPI_BSSCFG_PRIMARY); ++ INIT_IE(beacon, P2PAPI_BSSCFG_PRIMARY); ++ INIT_IE(probe_req, P2PAPI_BSSCFG_DEVICE); ++ INIT_IE(probe_res, P2PAPI_BSSCFG_DEVICE); ++ INIT_IE(assoc_req, P2PAPI_BSSCFG_DEVICE); ++ INIT_IE(assoc_res, P2PAPI_BSSCFG_DEVICE); ++ INIT_IE(beacon, P2PAPI_BSSCFG_DEVICE); ++ INIT_IE(probe_req, P2PAPI_BSSCFG_CONNECTION); ++ INIT_IE(probe_res, P2PAPI_BSSCFG_CONNECTION); ++ INIT_IE(assoc_req, P2PAPI_BSSCFG_CONNECTION); ++ INIT_IE(assoc_res, P2PAPI_BSSCFG_CONNECTION); ++ INIT_IE(beacon, P2PAPI_BSSCFG_CONNECTION); ++#undef INIT_IE ++ wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY) = wl_to_prmry_ndev(wl); ++ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_PRIMARY) = 0; ++ wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE) = NULL; ++ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = 0; ++ wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION) = NULL; ++ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION) = 0; ++ return BCME_OK; ++ ++} ++/* ++ * Deinitialize variables related to P2P ++ * ++ */ ++void ++wl_cfgp2p_deinit_priv(struct wl_priv *wl) ++{ ++ AP6211_DEBUG("In\n"); ++ if (wl->p2p) { ++ kfree(wl->p2p); ++ wl->p2p = NULL; ++ } ++ wl->p2p_supported = 0; ++} ++/* ++ * Set P2P functions into firmware ++ */ ++s32 ++wl_cfgp2p_set_firm_p2p(struct wl_priv *wl) ++{ ++ struct net_device *ndev = wl_to_prmry_ndev(wl); ++ struct ether_addr null_eth_addr = { { 0, 0, 0, 0, 0, 0 } }; ++ s32 ret = BCME_OK; ++ s32 val = 0; ++ /* Do we have to check whether APSTA is enabled or not ? */ ++ wldev_iovar_getint(ndev, "apsta", &val); ++ if (val == 0) { ++ val = 1; ++ ret = wldev_ioctl(ndev, WLC_DOWN, &val, sizeof(s32), true); ++ if (ret < 0) { ++ AP6211_ERR("WLC_DOWN error %d\n", ret); ++ return ret; ++ } ++ wldev_iovar_setint(ndev, "apsta", val); ++ ret = wldev_ioctl(ndev, WLC_UP, &val, sizeof(s32), true); ++ if (ret < 0) { ++ AP6211_ERR("WLC_UP error %d\n", ret); ++ return ret; ++ } ++ } ++ ++ /* In case of COB type, firmware has default mac address ++ * After Initializing firmware, we have to set current mac address to ++ * firmware for P2P device address ++ */ ++ ret = wldev_iovar_setbuf_bsscfg(ndev, "p2p_da_override", &null_eth_addr, ++ sizeof(null_eth_addr), wl->ioctl_buf, WLC_IOCTL_MAXLEN, 0, &wl->ioctl_buf_sync); ++ if (ret && ret != BCME_UNSUPPORTED) { ++ AP6211_ERR("failed to update device address ret %d\n", ret); ++ } ++ return ret; ++} ++ ++/* Create a new P2P BSS. ++ * Parameters: ++ * @mac : MAC address of the BSS to create ++ * @if_type : interface type: WL_P2P_IF_GO or WL_P2P_IF_CLIENT ++ * @chspec : chspec to use if creating a GO BSS. ++ * Returns 0 if success. ++ */ ++s32 ++wl_cfgp2p_ifadd(struct wl_priv *wl, struct ether_addr *mac, u8 if_type, ++ chanspec_t chspec) ++{ ++ wl_p2p_if_t ifreq; ++ s32 err; ++ u32 scb_timeout = WL_SCB_TIMEOUT; ++ struct net_device *ndev = wl_to_prmry_ndev(wl); ++ ++ ifreq.type = if_type; ++ ifreq.chspec = chspec; ++ memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet)); ++ ++ AP6211_DEBUG("---wl p2p_ifadd "MACDBG" %s %u\n", ++ MAC2STRDBG(ifreq.addr.octet), ++ (if_type == WL_P2P_IF_GO) ? "go" : "client", ++ (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT); ++ ++ err = wldev_iovar_setbuf(ndev, "p2p_ifadd", &ifreq, sizeof(ifreq), ++ wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); ++ ++ if (unlikely(err < 0)) ++ AP6211_DEBUG("'wl p2p_ifadd' error %d\n", err); ++ else if (if_type == WL_P2P_IF_GO) { ++ err = wldev_ioctl(ndev, WLC_SET_SCB_TIMEOUT, &scb_timeout, sizeof(u32), true); ++ if (unlikely(err < 0)) ++ AP6211_DEBUG("'wl scb_timeout' error %d\n", err); ++ } ++ return err; ++} ++ ++/* Disable a P2P BSS. ++ * Parameters: ++ * @mac : MAC address of the BSS to create ++ * Returns 0 if success. ++ */ ++s32 ++wl_cfgp2p_ifdisable(struct wl_priv *wl, struct ether_addr *mac) ++{ ++ s32 ret; ++ struct net_device *netdev = wl_to_prmry_ndev(wl); ++ ++ AP6211_DEBUG("------primary idx %d : wl p2p_ifdis "MACDBG"\n", ++ netdev->ifindex, MAC2STRDBG(mac->octet)); ++ ret = wldev_iovar_setbuf(netdev, "p2p_ifdis", mac, sizeof(*mac), ++ wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); ++ if (unlikely(ret < 0)) { ++ AP6211_DEBUG("'wl p2p_ifdis' error %d\n", ret); ++ } ++ return ret; ++} ++ ++/* Delete a P2P BSS. ++ * Parameters: ++ * @mac : MAC address of the BSS to create ++ * Returns 0 if success. ++ */ ++s32 ++wl_cfgp2p_ifdel(struct wl_priv *wl, struct ether_addr *mac) ++{ ++ s32 ret; ++ struct net_device *netdev = wl_to_prmry_ndev(wl); ++ ++ AP6211_DEBUG("------primary idx %d : wl p2p_ifdel "MACDBG"\n", ++ netdev->ifindex, MAC2STRDBG(mac->octet)); ++ ret = wldev_iovar_setbuf(netdev, "p2p_ifdel", mac, sizeof(*mac), ++ wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); ++ if (unlikely(ret < 0)) { ++ AP6211_DEBUG("'wl p2p_ifdel' error %d\n", ret); ++ } ++ return ret; ++} ++ ++/* Change a P2P Role. ++ * Parameters: ++ * @mac : MAC address of the BSS to change a role ++ * Returns 0 if success. ++ */ ++s32 ++wl_cfgp2p_ifchange(struct wl_priv *wl, struct ether_addr *mac, u8 if_type, ++ chanspec_t chspec) ++{ ++ wl_p2p_if_t ifreq; ++ s32 err; ++ u32 scb_timeout = WL_SCB_TIMEOUT; ++ ++ struct net_device *netdev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION); ++ ++ ifreq.type = if_type; ++ ifreq.chspec = chspec; ++ memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet)); ++ ++ AP6211_DEBUG("---wl p2p_ifchange "MACDBG" %s %u" ++ " chanspec 0x%04x\n", MAC2STRDBG(ifreq.addr.octet), ++ (if_type == WL_P2P_IF_GO) ? "go" : "client", ++ (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT, ++ ifreq.chspec); ++ ++ err = wldev_iovar_setbuf(netdev, "p2p_ifupd", &ifreq, sizeof(ifreq), ++ wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); ++ ++ if (unlikely(err < 0)) { ++ AP6211_DEBUG("'wl p2p_ifupd' error %d\n", err); ++ } else if (if_type == WL_P2P_IF_GO) { ++ err = wldev_ioctl(netdev, WLC_SET_SCB_TIMEOUT, &scb_timeout, sizeof(u32), true); ++ if (unlikely(err < 0)) ++ AP6211_DEBUG("'wl scb_timeout' error %d\n", err); ++ } ++ return err; ++} ++ ++ ++/* Get the index of a created P2P BSS. ++ * Parameters: ++ * @mac : MAC address of the created BSS ++ * @index : output: index of created BSS ++ * Returns 0 if success. ++ */ ++s32 ++wl_cfgp2p_ifidx(struct wl_priv *wl, struct ether_addr *mac, s32 *index) ++{ ++ s32 ret; ++ u8 getbuf[64]; ++ struct net_device *dev = wl_to_prmry_ndev(wl); ++ ++ AP6211_DEBUG("---wl p2p_if "MACDBG"\n", MAC2STRDBG(mac->octet)); ++ ++ ret = wldev_iovar_getbuf_bsscfg(dev, "p2p_if", mac, sizeof(*mac), getbuf, ++ sizeof(getbuf), wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_PRIMARY), NULL); ++ ++ if (ret == 0) { ++ memcpy(index, getbuf, sizeof(s32)); ++ AP6211_DEBUG("---wl p2p_if ==> %d\n", *index); ++ } ++ ++ return ret; ++} ++ ++static s32 ++wl_cfgp2p_set_discovery(struct wl_priv *wl, s32 on) ++{ ++ s32 ret = BCME_OK; ++ struct net_device *ndev = wl_to_prmry_ndev(wl); ++ AP6211_DEBUG("enter\n"); ++ ++ ret = wldev_iovar_setint(ndev, "p2p_disc", on); ++ ++ if (unlikely(ret < 0)) { ++ AP6211_ERR("p2p_disc %d error %d\n", on, ret); ++ } ++ ++ return ret; ++} ++ ++/* Set the WL driver's P2P mode. ++ * Parameters : ++ * @mode : is one of WL_P2P_DISC_ST_{SCAN,LISTEN,SEARCH}. ++ * @channel : the channel to listen ++ * @listen_ms : the time (milli seconds) to wait ++ * @bssidx : bss index for BSSCFG ++ * Returns 0 if success ++ */ ++ ++s32 ++wl_cfgp2p_set_p2p_mode(struct wl_priv *wl, u8 mode, u32 channel, u16 listen_ms, int bssidx) ++{ ++ wl_p2p_disc_st_t discovery_mode; ++ s32 ret; ++ struct net_device *dev; ++ AP6211_DEBUG("enter\n"); ++ ++ if (unlikely(bssidx == WL_INVALID || bssidx >= P2PAPI_BSSCFG_MAX)) { ++ AP6211_ERR(" %d index out of range\n", bssidx); ++ return -1; ++ } ++ ++ dev = wl_to_p2p_bss_ndev(wl, bssidx); ++ if (unlikely(dev == NULL)) { ++ AP6211_ERR("bssidx %d is not assigned\n", bssidx); ++ return BCME_NOTFOUND; ++ } ++ ++ /* Put the WL driver into P2P Listen Mode to respond to P2P probe reqs */ ++ discovery_mode.state = mode; ++ discovery_mode.chspec = wl_ch_host_to_driver(channel); ++ discovery_mode.dwell = listen_ms; ++ ret = wldev_iovar_setbuf_bsscfg(dev, "p2p_state", &discovery_mode, ++ sizeof(discovery_mode), wl->ioctl_buf, WLC_IOCTL_MAXLEN, ++ bssidx, &wl->ioctl_buf_sync); ++ ++ return ret; ++} ++ ++/* Get the index of the P2P Discovery BSS */ ++static s32 ++wl_cfgp2p_get_disc_idx(struct wl_priv *wl, s32 *index) ++{ ++ s32 ret; ++ struct net_device *dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY); ++ ++ ret = wldev_iovar_getint(dev, "p2p_dev", index); ++ AP6211_DEBUG("p2p_dev bsscfg_idx=%d ret=%d\n", *index, ret); ++ ++ if (unlikely(ret < 0)) { ++ AP6211_ERR("'p2p_dev' error %d\n", ret); ++ return ret; ++ } ++ return ret; ++} ++ ++s32 ++wl_cfgp2p_init_discovery(struct wl_priv *wl) ++{ ++ ++ s32 index = 0; ++ s32 ret = BCME_OK; ++ ++ AP6211_DEBUG("enter\n"); ++ ++ if (wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) != 0) { ++ AP6211_ERR("do nothing, already initialized\n"); ++ return ret; ++ } ++ ++ ret = wl_cfgp2p_set_discovery(wl, 1); ++ if (ret < 0) { ++ AP6211_ERR("set discover error\n"); ++ return ret; ++ } ++ /* Enable P2P Discovery in the WL Driver */ ++ ret = wl_cfgp2p_get_disc_idx(wl, &index); ++ ++ if (ret < 0) { ++ return ret; ++ } ++ wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE) = ++ wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY); ++ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = index; ++ ++ /* Set the initial discovery state to SCAN */ ++ ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0, ++ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); ++ ++ if (unlikely(ret != 0)) { ++ AP6211_ERR("unable to set WL_P2P_DISC_ST_SCAN\n"); ++ wl_cfgp2p_set_discovery(wl, 0); ++ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = 0; ++ wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE) = NULL; ++ return 0; ++ } ++ return ret; ++} ++ ++/* Deinitialize P2P Discovery ++ * Parameters : ++ * @wl : wl_private data ++ * Returns 0 if succes ++ */ ++static s32 ++wl_cfgp2p_deinit_discovery(struct wl_priv *wl) ++{ ++ s32 ret = BCME_OK; ++ AP6211_DEBUG("enter\n"); ++ ++ if (wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) == 0) { ++ AP6211_ERR("do nothing, not initialized\n"); ++ return -1; ++ } ++ /* Set the discovery state to SCAN */ ++ ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0, ++ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); ++ /* Disable P2P discovery in the WL driver (deletes the discovery BSSCFG) */ ++ ret = wl_cfgp2p_set_discovery(wl, 0); ++ ++ /* Clear our saved WPS and P2P IEs for the discovery BSS. The driver ++ * deleted these IEs when wl_cfgp2p_set_discovery() deleted the discovery ++ * BSS. ++ */ ++ ++ /* Clear the saved bsscfg index of the discovery BSSCFG to indicate we ++ * have no discovery BSS. ++ */ ++ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = WL_INVALID; ++ wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE) = NULL; ++ ++ return ret; ++ ++} ++/* Enable P2P Discovery ++ * Parameters: ++ * @wl : wl_private data ++ * @ie : probe request ie (WPS IE + P2P IE) ++ * @ie_len : probe request ie length ++ * Returns 0 if success. ++ */ ++s32 ++wl_cfgp2p_enable_discovery(struct wl_priv *wl, struct net_device *dev, ++ const u8 *ie, u32 ie_len) ++{ ++ s32 ret = BCME_OK; ++ s32 bssidx = (wl_to_prmry_ndev(wl) == dev) ? ++ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) : wl_cfgp2p_find_idx(wl, dev); ++ if (wl_get_p2p_status(wl, DISCOVERY_ON)) { ++ AP6211_DEBUG(" DISCOVERY is already initialized, we have nothing to do\n"); ++ goto set_ie; ++ } ++ ++ wl_set_p2p_status(wl, DISCOVERY_ON); ++ ++ AP6211_DEBUG("enter\n"); ++ ++ ret = wl_cfgp2p_init_discovery(wl); ++ if (unlikely(ret < 0)) { ++ AP6211_ERR(" init discovery error %d\n", ret); ++ goto exit; ++ } ++ /* Set wsec to any non-zero value in the discovery bsscfg to ensure our ++ * P2P probe responses have the privacy bit set in the 802.11 WPA IE. ++ * Some peer devices may not initiate WPS with us if this bit is not set. ++ */ ++ ret = wldev_iovar_setint_bsscfg(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE), ++ "wsec", AES_ENABLED, wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); ++ if (unlikely(ret < 0)) { ++ AP6211_ERR(" wsec error %d\n", ret); ++ } ++set_ie: ++ if (ie_len) { ++ ret = wl_cfgp2p_set_management_ie(wl, dev, ++ bssidx, ++ VNDR_IE_PRBREQ_FLAG, ie, ie_len); ++ ++ if (unlikely(ret < 0)) { ++ AP6211_ERR("set probreq ie occurs error %d\n", ret); ++ goto exit; ++ } ++ } ++exit: ++ return ret; ++} ++ ++/* Disable P2P Discovery ++ * Parameters: ++ * @wl : wl_private_data ++ * Returns 0 if success. ++ */ ++s32 ++wl_cfgp2p_disable_discovery(struct wl_priv *wl) ++{ ++ s32 ret = BCME_OK; ++ AP6211_DEBUG(" enter\n"); ++ wl_clr_p2p_status(wl, DISCOVERY_ON); ++ ++ if (wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) == 0) { ++ AP6211_ERR(" do nothing, not initialized\n"); ++ goto exit; ++ } ++ ++ ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0, ++ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); ++ ++ if (unlikely(ret < 0)) { ++ ++ AP6211_ERR("unable to set WL_P2P_DISC_ST_SCAN\n"); ++ } ++ /* Do a scan abort to stop the driver's scan engine in case it is still ++ * waiting out an action frame tx dwell time. ++ */ ++ wl_clr_p2p_status(wl, DISCOVERY_ON); ++ ret = wl_cfgp2p_deinit_discovery(wl); ++ ++exit: ++ return ret; ++} ++ ++s32 ++wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active, ++ u32 num_chans, u16 *channels, ++ s32 search_state, u16 action, u32 bssidx) ++{ ++ s32 ret = BCME_OK; ++ s32 memsize; ++ s32 eparams_size; ++ u32 i; ++ s8 *memblk; ++ wl_p2p_scan_t *p2p_params; ++ wl_escan_params_t *eparams; ++ wlc_ssid_t ssid; ++ /* Scan parameters */ ++#define P2PAPI_SCAN_NPROBES 1 ++#define P2PAPI_SCAN_DWELL_TIME_MS 80 ++#define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 40 ++#define P2PAPI_SCAN_HOME_TIME_MS 60 ++#define P2PAPI_SCAN_NPROBS_TIME_MS 30 ++#define P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS 100 ++ ++ struct net_device *pri_dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY); ++ /* Allocate scan params which need space for 3 channels and 0 ssids */ ++ eparams_size = (WL_SCAN_PARAMS_FIXED_SIZE + ++ OFFSETOF(wl_escan_params_t, params)) + ++ num_chans * sizeof(eparams->params.channel_list[0]); ++ ++ memsize = sizeof(wl_p2p_scan_t) + eparams_size; ++ memblk = scanparambuf; ++ if (memsize > sizeof(scanparambuf)) { ++ AP6211_ERR(" scanpar buf too small (%u > %u)\n", ++ memsize, sizeof(scanparambuf)); ++ return -1; ++ } ++ memset(memblk, 0, memsize); ++ memset(wl->ioctl_buf, 0, WLC_IOCTL_MAXLEN); ++ if (search_state == WL_P2P_DISC_ST_SEARCH) { ++ /* ++ * If we in SEARCH STATE, we don't need to set SSID explictly ++ * because dongle use P2P WILDCARD internally by default ++ */ ++ wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SEARCH, 0, 0, bssidx); ++ ssid.SSID_len = htod32(0); ++ ++ } else if (search_state == WL_P2P_DISC_ST_SCAN) { ++ /* SCAN STATE 802.11 SCAN ++ * WFD Supplicant has p2p_find command with (type=progressive, type= full) ++ * So if P2P_find command with type=progressive, ++ * we have to set ssid to P2P WILDCARD because ++ * we just do broadcast scan unless setting SSID ++ */ ++ strncpy(ssid.SSID, WL_P2P_WILDCARD_SSID, sizeof(ssid.SSID) - 1); ++ ssid.SSID[sizeof(ssid.SSID) - 1] = 0; ++ ssid.SSID_len = htod32(WL_P2P_WILDCARD_SSID_LEN); ++ wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0, bssidx); ++ } ++ else { ++ AP6211_ERR(" invalid search state %d\n", search_state); ++ return -1; ++ } ++ ++ ++ /* Fill in the P2P scan structure at the start of the iovar param block */ ++ p2p_params = (wl_p2p_scan_t*) memblk; ++ p2p_params->type = 'E'; ++ /* Fill in the Scan structure that follows the P2P scan structure */ ++ eparams = (wl_escan_params_t*) (p2p_params + 1); ++ eparams->params.bss_type = DOT11_BSSTYPE_ANY; ++ if (active) ++ eparams->params.scan_type = DOT11_SCANTYPE_ACTIVE; ++ else ++ eparams->params.scan_type = DOT11_SCANTYPE_PASSIVE; ++ ++ memcpy(&eparams->params.bssid, ðer_bcast, ETHER_ADDR_LEN); ++ if (ssid.SSID_len) ++ memcpy(&eparams->params.ssid, &ssid, sizeof(wlc_ssid_t)); ++ ++ eparams->params.home_time = htod32(P2PAPI_SCAN_HOME_TIME_MS); ++ ++ /* SOCIAL_CHAN_CNT + 1 takes care of the Progressive scan supported by ++ * the supplicant ++ */ ++ if ((num_chans == SOCIAL_CHAN_CNT) || (num_chans == SOCIAL_CHAN_CNT + 1)) ++ eparams->params.active_time = htod32(P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS); ++ else if (num_chans == AF_PEER_SEARCH_CNT) ++ eparams->params.active_time = htod32(P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS); ++ else if (wl_get_drv_status_all(wl, CONNECTED)) ++ eparams->params.active_time = -1; ++ else ++ eparams->params.active_time = htod32(P2PAPI_SCAN_DWELL_TIME_MS); ++ eparams->params.nprobes = htod32((eparams->params.active_time / ++ P2PAPI_SCAN_NPROBS_TIME_MS)); ++ ++ /* Override scan params to find a peer for a connection */ ++ if (num_chans == 1) { ++ eparams->params.active_time = htod32(WL_SCAN_CONNECT_DWELL_TIME_MS); ++ eparams->params.nprobes = htod32(eparams->params.active_time / ++ WL_SCAN_JOIN_PROBE_INTERVAL_MS); ++ } ++ ++ if (eparams->params.nprobes <= 0) ++ eparams->params.nprobes = 1; ++ AP6211_DEBUG("nprobes # %d, active_time %d\n", ++ eparams->params.nprobes, eparams->params.active_time); ++ eparams->params.passive_time = htod32(-1); ++ eparams->params.channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) | ++ (num_chans & WL_SCAN_PARAMS_COUNT_MASK)); ++ ++ for (i = 0; i < num_chans; i++) { ++ eparams->params.channel_list[i] = wl_ch_host_to_driver(channels[i]); ++ } ++ eparams->version = htod32(ESCAN_REQ_VERSION); ++ eparams->action = htod16(action); ++ eparams->sync_id = htod16(0x1234); ++ AP6211_DEBUG("SCAN CHANNELS : "); ++ ++ for (i = 0; i < num_chans; i++) { ++ if (i == 0) AP6211_DEBUG("%d", channels[i]); ++ else AP6211_DEBUG(",%d", channels[i]); ++ } ++ ++ AP6211_DEBUG("\n"); ++ ++ ret = wldev_iovar_setbuf_bsscfg(pri_dev, "p2p_scan", ++ memblk, memsize, wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); ++ if (ret == BCME_OK) ++ wl_set_p2p_status(wl, SCANNING); ++ return ret; ++} ++ ++/* search function to reach at common channel to send action frame ++ * Parameters: ++ * @wl : wl_private data ++ * @ndev : net device for bssidx ++ * @bssidx : bssidx for BSS ++ * Returns 0 if success. ++ */ ++s32 ++wl_cfgp2p_act_frm_search(struct wl_priv *wl, struct net_device *ndev, ++ s32 bssidx, s32 channel) ++{ ++ s32 ret = 0; ++ u32 chan_cnt = 0; ++ u16 *default_chan_list = NULL; ++ if (!p2p_is_on(wl) || ndev == NULL || bssidx == WL_INVALID) ++ return -BCME_ERROR; ++ AP6211_DEBUG(" Enter\n"); ++ if (bssidx == P2PAPI_BSSCFG_PRIMARY) ++ bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); ++ if (channel) ++ chan_cnt = AF_PEER_SEARCH_CNT; ++ else ++ chan_cnt = SOCIAL_CHAN_CNT; ++ default_chan_list = kzalloc(chan_cnt * sizeof(*default_chan_list), GFP_KERNEL); ++ if (default_chan_list == NULL) { ++ AP6211_ERR("channel list allocation failed \n"); ++ ret = -ENOMEM; ++ goto exit; ++ } ++ if (channel) { ++ u32 i; ++ /* insert same channel to the chan_list */ ++ for (i = 0; i < chan_cnt; i++) { ++ default_chan_list[i] = channel; ++ } ++ } else { ++ default_chan_list[0] = SOCIAL_CHAN_1; ++ default_chan_list[1] = SOCIAL_CHAN_2; ++ default_chan_list[2] = SOCIAL_CHAN_3; ++ } ++ ret = wl_cfgp2p_escan(wl, ndev, true, chan_cnt, ++ default_chan_list, WL_P2P_DISC_ST_SEARCH, ++ WL_SCAN_ACTION_START, bssidx); ++ kfree(default_chan_list); ++exit: ++ return ret; ++} ++ ++/* Check whether pointed-to IE looks like WPA. */ ++#define wl_cfgp2p_is_wpa_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ ++ (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPA_OUI_TYPE) ++/* Check whether pointed-to IE looks like WPS. */ ++#define wl_cfgp2p_is_wps_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ ++ (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPS_OUI_TYPE) ++/* Check whether the given IE looks like WFA P2P IE. */ ++#define wl_cfgp2p_is_p2p_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ ++ (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_P2P) ++/* Check whether the given IE looks like WFA WFDisplay IE. */ ++#define WFA_OUI_TYPE_WFD 0x0a /* WiFi Display OUI TYPE */ ++#define wl_cfgp2p_is_wfd_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ ++ (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_WFD) ++ ++static s32 ++wl_cfgp2p_parse_vndr_ies(u8 *parse, u32 len, ++ struct parsed_vndr_ies *vndr_ies) ++{ ++ s32 err = BCME_OK; ++ vndr_ie_t *vndrie; ++ bcm_tlv_t *ie; ++ struct parsed_vndr_ie_info *parsed_info; ++ u32 count = 0; ++ s32 remained_len; ++ ++ remained_len = (s32)len; ++ memset(vndr_ies, 0, sizeof(*vndr_ies)); ++ ++ AP6211_DEBUG("---> len %d\n", len); ++ ie = (bcm_tlv_t *) parse; ++ if (!bcm_valid_tlv(ie, remained_len)) ++ ie = NULL; ++ while (ie) { ++ if (count >= MAX_VNDR_IE_NUMBER) ++ break; ++ if (ie->id == DOT11_MNG_VS_ID) { ++ vndrie = (vndr_ie_t *) ie; ++ /* len should be bigger than OUI length + one data length at least */ ++ if (vndrie->len < (VNDR_IE_MIN_LEN + 1)) { ++ AP6211_ERR("%s: invalid vndr ie. length is too small %d\n", ++ __FUNCTION__, vndrie->len); ++ goto end; ++ } ++ /* if wpa or wme ie, do not add ie */ ++ if (!bcmp(vndrie->oui, (u8*)WPA_OUI, WPA_OUI_LEN) && ++ ((vndrie->data[0] == WPA_OUI_TYPE) || ++ (vndrie->data[0] == WME_OUI_TYPE))) { ++ AP6211_DEBUG("Found WPA/WME oui. Do not add it\n"); ++ goto end; ++ } ++ ++ parsed_info = &vndr_ies->ie_info[count++]; ++ ++ /* save vndr ie information */ ++ parsed_info->ie_ptr = (char *)vndrie; ++ parsed_info->ie_len = (vndrie->len + TLV_HDR_LEN); ++ memcpy(&parsed_info->vndrie, vndrie, sizeof(vndr_ie_t)); ++ ++ vndr_ies->count = count; ++ ++ AP6211_DEBUG("\t ** OUI %02x %02x %02x, type 0x%02x \n", ++ parsed_info->vndrie.oui[0], parsed_info->vndrie.oui[1], ++ parsed_info->vndrie.oui[2], parsed_info->vndrie.data[0]); ++ } ++end: ++ ie = bcm_next_tlv(ie, &remained_len); ++ } ++ return err; ++} ++ ++ ++/* Delete and Set a management vndr ie to firmware ++ * Parameters: ++ * @wl : wl_private data ++ * @ndev : net device for bssidx ++ * @bssidx : bssidx for BSS ++ * @pktflag : packet flag for IE (VNDR_IE_PRBREQ_FLAG,VNDR_IE_PRBRSP_FLAG, VNDR_IE_ASSOCRSP_FLAG, ++ * VNDR_IE_ASSOCREQ_FLAG) ++ * @ie : VNDR IE (such as P2P IE , WPS IE) ++ * @ie_len : VNDR IE Length ++ * Returns 0 if success. ++ */ ++ ++s32 ++wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, ++ s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len) ++{ ++ s32 ret = BCME_OK; ++ u8 *curr_ie_buf = NULL; ++ u8 *mgmt_ie_buf = NULL; ++ u32 mgmt_ie_buf_len = 0; ++ u32 *mgmt_ie_len = 0; ++ u32 del_add_ie_buf_len = 0; ++ u32 total_ie_buf_len = 0; ++ u32 parsed_ie_buf_len = 0; ++ struct parsed_vndr_ies old_vndr_ies; ++ struct parsed_vndr_ies new_vndr_ies; ++ s32 i; ++ u8 *ptr; ++ s32 remained_buf_len; ++ ++#define IE_TYPE(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie) ++#define IE_TYPE_LEN(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie_len) ++ memset(g_mgmt_ie_buf, 0, sizeof(g_mgmt_ie_buf)); ++ curr_ie_buf = g_mgmt_ie_buf; ++ AP6211_DEBUG(" bssidx %d, pktflag : 0x%02X\n", bssidx, pktflag); ++ if (wl->p2p != NULL) { ++ switch (pktflag) { ++ case VNDR_IE_PRBREQ_FLAG : ++ mgmt_ie_buf = IE_TYPE(probe_req, bssidx); ++ mgmt_ie_len = &IE_TYPE_LEN(probe_req, bssidx); ++ mgmt_ie_buf_len = sizeof(IE_TYPE(probe_req, bssidx)); ++ break; ++ case VNDR_IE_PRBRSP_FLAG : ++ mgmt_ie_buf = IE_TYPE(probe_res, bssidx); ++ mgmt_ie_len = &IE_TYPE_LEN(probe_res, bssidx); ++ mgmt_ie_buf_len = sizeof(IE_TYPE(probe_res, bssidx)); ++ break; ++ case VNDR_IE_ASSOCREQ_FLAG : ++ mgmt_ie_buf = IE_TYPE(assoc_req, bssidx); ++ mgmt_ie_len = &IE_TYPE_LEN(assoc_req, bssidx); ++ mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_req, bssidx)); ++ break; ++ case VNDR_IE_ASSOCRSP_FLAG : ++ mgmt_ie_buf = IE_TYPE(assoc_res, bssidx); ++ mgmt_ie_len = &IE_TYPE_LEN(assoc_res, bssidx); ++ mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_res, bssidx)); ++ break; ++ case VNDR_IE_BEACON_FLAG : ++ mgmt_ie_buf = IE_TYPE(beacon, bssidx); ++ mgmt_ie_len = &IE_TYPE_LEN(beacon, bssidx); ++ mgmt_ie_buf_len = sizeof(IE_TYPE(beacon, bssidx)); ++ break; ++ default: ++ mgmt_ie_buf = NULL; ++ mgmt_ie_len = NULL; ++ AP6211_ERR("not suitable type\n"); ++ return -1; ++ } ++ } else if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_AP) { ++ switch (pktflag) { ++ case VNDR_IE_PRBRSP_FLAG : ++ mgmt_ie_buf = wl->ap_info->probe_res_ie; ++ mgmt_ie_len = &wl->ap_info->probe_res_ie_len; ++ mgmt_ie_buf_len = sizeof(wl->ap_info->probe_res_ie); ++ break; ++ case VNDR_IE_BEACON_FLAG : ++ mgmt_ie_buf = wl->ap_info->beacon_ie; ++ mgmt_ie_len = &wl->ap_info->beacon_ie_len; ++ mgmt_ie_buf_len = sizeof(wl->ap_info->beacon_ie); ++ break; ++ default: ++ mgmt_ie_buf = NULL; ++ mgmt_ie_len = NULL; ++ AP6211_ERR("not suitable type\n"); ++ return -1; ++ } ++ bssidx = 0; ++ } else if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_BSS) { ++ switch (pktflag) { ++ case VNDR_IE_PRBREQ_FLAG : ++ mgmt_ie_buf = wl->sta_info->probe_req_ie; ++ mgmt_ie_len = &wl->sta_info->probe_req_ie_len; ++ mgmt_ie_buf_len = sizeof(wl->sta_info->probe_req_ie); ++ break; ++ case VNDR_IE_ASSOCREQ_FLAG : ++ mgmt_ie_buf = wl->sta_info->assoc_req_ie; ++ mgmt_ie_len = &wl->sta_info->assoc_req_ie_len; ++ mgmt_ie_buf_len = sizeof(wl->sta_info->assoc_req_ie); ++ break; ++ default: ++ mgmt_ie_buf = NULL; ++ mgmt_ie_len = NULL; ++ AP6211_ERR("not suitable type\n"); ++ return -1; ++ } ++ bssidx = 0; ++ } else { ++ AP6211_ERR("not suitable type\n"); ++ return -1; ++ } ++ ++ if (vndr_ie_len > mgmt_ie_buf_len) { ++ AP6211_ERR("extra IE size too big\n"); ++ ret = -ENOMEM; ++ } else { ++ /* parse and save new vndr_ie in curr_ie_buff before comparing it */ ++ if (vndr_ie && vndr_ie_len && curr_ie_buf) { ++ ptr = curr_ie_buf; ++ ++ wl_cfgp2p_parse_vndr_ies((u8*)vndr_ie, ++ vndr_ie_len, &new_vndr_ies); ++ ++ for (i = 0; i < new_vndr_ies.count; i++) { ++ struct parsed_vndr_ie_info *vndrie_info = ++ &new_vndr_ies.ie_info[i]; ++ ++ memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr, ++ vndrie_info->ie_len); ++ parsed_ie_buf_len += vndrie_info->ie_len; ++ } ++ } ++ ++ if (mgmt_ie_buf != NULL) { ++ if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) && ++ (memcmp(mgmt_ie_buf, curr_ie_buf, parsed_ie_buf_len) == 0)) { ++ AP6211_DEBUG("Previous mgmt IE is equals to current IE"); ++ goto exit; ++ } ++ ++ /* parse old vndr_ie */ ++ wl_cfgp2p_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, ++ &old_vndr_ies); ++ ++ /* make a command to delete old ie */ ++ for (i = 0; i < old_vndr_ies.count; i++) { ++ struct parsed_vndr_ie_info *vndrie_info = ++ &old_vndr_ies.ie_info[i]; ++ ++ AP6211_DEBUG("DELETED ID : %d, Len: %d , OUI:%02x:%02x:%02x\n", ++ vndrie_info->vndrie.id, vndrie_info->vndrie.len, ++ vndrie_info->vndrie.oui[0], vndrie_info->vndrie.oui[1], ++ vndrie_info->vndrie.oui[2]); ++ ++ del_add_ie_buf_len = wl_cfgp2p_vndr_ie(wl, curr_ie_buf, ++ bssidx, pktflag, vndrie_info->vndrie.oui, ++ vndrie_info->vndrie.id, ++ vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN, ++ vndrie_info->ie_len - VNDR_IE_FIXED_LEN, ++ "del"); ++ ++ curr_ie_buf += del_add_ie_buf_len; ++ total_ie_buf_len += del_add_ie_buf_len; ++ } ++ } ++ ++ *mgmt_ie_len = 0; ++ /* Add if there is any extra IE */ ++ if (mgmt_ie_buf && parsed_ie_buf_len) { ++ ptr = mgmt_ie_buf; ++ ++ remained_buf_len = mgmt_ie_buf_len; ++ ++ /* make a command to add new ie */ ++ for (i = 0; i < new_vndr_ies.count; i++) { ++ struct parsed_vndr_ie_info *vndrie_info = ++ &new_vndr_ies.ie_info[i]; ++ ++ AP6211_DEBUG("ADDED ID : %d, Len: %d(%d), OUI:%02x:%02x:%02x\n", ++ vndrie_info->vndrie.id, vndrie_info->vndrie.len, ++ vndrie_info->ie_len - 2, ++ vndrie_info->vndrie.oui[0], vndrie_info->vndrie.oui[1], ++ vndrie_info->vndrie.oui[2]); ++ ++ del_add_ie_buf_len = wl_cfgp2p_vndr_ie(wl, curr_ie_buf, ++ bssidx, pktflag, vndrie_info->vndrie.oui, ++ vndrie_info->vndrie.id, ++ vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN, ++ vndrie_info->ie_len - VNDR_IE_FIXED_LEN, ++ "add"); ++ ++ /* verify remained buf size before copy data */ ++ if (remained_buf_len >= vndrie_info->ie_len) { ++ remained_buf_len -= vndrie_info->ie_len; ++ } else { ++ AP6211_ERR("no space in mgmt_ie_buf: pktflag = %d, " ++ "found vndr ies # = %d(cur %d), remained len %d, " ++ "cur mgmt_ie_len %d, new ie len = %d\n", ++ pktflag, new_vndr_ies.count, i, remained_buf_len, ++ *mgmt_ie_len, vndrie_info->ie_len); ++ break; ++ } ++ ++ /* save the parsed IE in wl struct */ ++ memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr, ++ vndrie_info->ie_len); ++ *mgmt_ie_len += vndrie_info->ie_len; ++ ++ curr_ie_buf += del_add_ie_buf_len; ++ total_ie_buf_len += del_add_ie_buf_len; ++ } ++ } ++ if (total_ie_buf_len) { ++ ret = wldev_iovar_setbuf_bsscfg(ndev, "vndr_ie", g_mgmt_ie_buf, ++ total_ie_buf_len, wl->ioctl_buf, WLC_IOCTL_MAXLEN, ++ bssidx, &wl->ioctl_buf_sync); ++ if (ret) ++ AP6211_ERR("vndr ie set error : %d\n", ret); ++ } ++ } ++#undef IE_TYPE ++#undef IE_TYPE_LEN ++exit: ++ return ret; ++} ++ ++/* Clear the manament IE buffer of BSSCFG ++ * Parameters: ++ * @wl : wl_private data ++ * @bssidx : bssidx for BSS ++ * ++ * Returns 0 if success. ++ */ ++s32 ++wl_cfgp2p_clear_management_ie(struct wl_priv *wl, s32 bssidx) ++{ ++ s32 vndrie_flag[] = {VNDR_IE_BEACON_FLAG, VNDR_IE_PRBRSP_FLAG, VNDR_IE_ASSOCRSP_FLAG, ++ VNDR_IE_PRBREQ_FLAG, VNDR_IE_ASSOCREQ_FLAG}; ++ s32 index = -1; ++ struct net_device *ndev = wl_cfgp2p_find_ndev(wl, bssidx); ++#define INIT_IE(IE_TYPE, BSS_TYPE) \ ++ do { \ ++ memset(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie, 0, \ ++ sizeof(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie)); \ ++ wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie_len = 0; \ ++ } while (0); ++ ++ if (bssidx < 0 || ndev == NULL) { ++ AP6211_ERR("invalid %s\n", (bssidx < 0) ? "bssidx" : "ndev"); ++ return BCME_BADARG; ++ } ++ for (index = 0; index < ARRAYSIZE(vndrie_flag); index++) { ++ /* clean up vndr ies in dongle */ ++ wl_cfgp2p_set_management_ie(wl, ndev, bssidx, vndrie_flag[index], NULL, 0); ++ } ++ INIT_IE(probe_req, bssidx); ++ INIT_IE(probe_res, bssidx); ++ INIT_IE(assoc_req, bssidx); ++ INIT_IE(assoc_res, bssidx); ++ INIT_IE(beacon, bssidx); ++ return BCME_OK; ++} ++ ++ ++/* Is any of the tlvs the expected entry? If ++ * not update the tlvs buffer pointer/length. ++ */ ++static bool ++wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type) ++{ ++ /* If the contents match the OUI and the type */ ++ if (ie[TLV_LEN_OFF] >= oui_len + 1 && ++ !bcmp(&ie[TLV_BODY_OFF], oui, oui_len) && ++ type == ie[TLV_BODY_OFF + oui_len]) { ++ return TRUE; ++ } ++ ++ if (tlvs == NULL) ++ return FALSE; ++ /* point to the next ie */ ++ ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN; ++ /* calculate the length of the rest of the buffer */ ++ *tlvs_len -= (int)(ie - *tlvs); ++ /* update the pointer to the start of the buffer */ ++ *tlvs = ie; ++ ++ return FALSE; ++} ++ ++wpa_ie_fixed_t * ++wl_cfgp2p_find_wpaie(u8 *parse, u32 len) ++{ ++ bcm_tlv_t *ie; ++ ++ while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_VS_ID))) { ++ if (wl_cfgp2p_is_wpa_ie((u8*)ie, &parse, &len)) { ++ return (wpa_ie_fixed_t *)ie; ++ } ++ } ++ return NULL; ++} ++ ++wpa_ie_fixed_t * ++wl_cfgp2p_find_wpsie(u8 *parse, u32 len) ++{ ++ bcm_tlv_t *ie; ++ ++ while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_VS_ID))) { ++ if (wl_cfgp2p_is_wps_ie((u8*)ie, &parse, &len)) { ++ return (wpa_ie_fixed_t *)ie; ++ } ++ } ++ return NULL; ++} ++ ++wifi_p2p_ie_t * ++wl_cfgp2p_find_p2pie(u8 *parse, u32 len) ++{ ++ bcm_tlv_t *ie; ++ ++ while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) { ++ if (wl_cfgp2p_is_p2p_ie((uint8*)ie, &parse, &len)) { ++ return (wifi_p2p_ie_t *)ie; ++ } ++ } ++ return NULL; ++} ++ ++wifi_wfd_ie_t * ++wl_cfgp2p_find_wfdie(u8 *parse, u32 len) ++{ ++ bcm_tlv_t *ie; ++ ++ while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) { ++ if (wl_cfgp2p_is_wfd_ie((uint8*)ie, &parse, &len)) { ++ return (wifi_wfd_ie_t *)ie; ++ } ++ } ++ return NULL; ++} ++static u32 ++wl_cfgp2p_vndr_ie(struct wl_priv *wl, u8 *iebuf, s32 bssidx, s32 pktflag, ++ s8 *oui, s32 ie_id, s8 *data, s32 datalen, const s8* add_del_cmd) ++{ ++ vndr_ie_setbuf_t hdr; /* aligned temporary vndr_ie buffer header */ ++ s32 iecount; ++ u32 data_offset; ++ ++ /* Validate the pktflag parameter */ ++ if ((pktflag & ~(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG | ++ VNDR_IE_ASSOCRSP_FLAG | VNDR_IE_AUTHRSP_FLAG | ++ VNDR_IE_PRBREQ_FLAG | VNDR_IE_ASSOCREQ_FLAG))) { ++ AP6211_ERR("p2pwl_vndr_ie: Invalid packet flag 0x%x\n", pktflag); ++ return -1; ++ } ++ ++ /* Copy the vndr_ie SET command ("add"/"del") to the buffer */ ++ strncpy(hdr.cmd, add_del_cmd, VNDR_IE_CMD_LEN - 1); ++ hdr.cmd[VNDR_IE_CMD_LEN - 1] = '\0'; ++ ++ /* Set the IE count - the buffer contains only 1 IE */ ++ iecount = htod32(1); ++ memcpy((void *)&hdr.vndr_ie_buffer.iecount, &iecount, sizeof(s32)); ++ ++ /* Copy packet flags that indicate which packets will contain this IE */ ++ pktflag = htod32(pktflag); ++ memcpy((void *)&hdr.vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag, ++ sizeof(u32)); ++ ++ /* Add the IE ID to the buffer */ ++ hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = ie_id; ++ ++ /* Add the IE length to the buffer */ ++ hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = ++ (uint8) VNDR_IE_MIN_LEN + datalen; ++ ++ /* Add the IE OUI to the buffer */ ++ hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[0] = oui[0]; ++ hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[1] = oui[1]; ++ hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[2] = oui[2]; ++ ++ /* Copy the aligned temporary vndr_ie buffer header to the IE buffer */ ++ memcpy(iebuf, &hdr, sizeof(hdr) - 1); ++ ++ /* Copy the IE data to the IE buffer */ ++ data_offset = ++ (u8*)&hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data[0] - ++ (u8*)&hdr; ++ memcpy(iebuf + data_offset, data, datalen); ++ return data_offset + datalen; ++ ++} ++ ++/* ++ * Search the bssidx based on dev argument ++ * Parameters: ++ * @wl : wl_private data ++ * @ndev : net device to search bssidx ++ * Returns bssidx for ndev ++ */ ++s32 ++wl_cfgp2p_find_idx(struct wl_priv *wl, struct net_device *ndev) ++{ ++ u32 i; ++ s32 index = -1; ++ ++ if (ndev == NULL) { ++ AP6211_ERR(" ndev is NULL\n"); ++ goto exit; ++ } ++ if (!wl->p2p_supported) { ++ return P2PAPI_BSSCFG_PRIMARY; ++ } ++ for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) { ++ if (ndev == wl_to_p2p_bss_ndev(wl, i)) { ++ index = wl_to_p2p_bss_bssidx(wl, i); ++ break; ++ } ++ } ++ if (index == -1) ++ return P2PAPI_BSSCFG_PRIMARY; ++exit: ++ return index; ++} ++ ++struct net_device * ++wl_cfgp2p_find_ndev(struct wl_priv *wl, s32 bssidx) ++{ ++ u32 i; ++ struct net_device *ndev = NULL; ++ if (bssidx < 0) { ++ AP6211_ERR(" bsscfg idx is invalid\n"); ++ goto exit; ++ } ++ ++ for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) { ++ if (bssidx == wl_to_p2p_bss_bssidx(wl, i)) { ++ ndev = wl_to_p2p_bss_ndev(wl, i); ++ break; ++ } ++ } ++ ++exit: ++ return ndev; ++} ++ ++/* ++ * Callback function for WLC_E_P2P_DISC_LISTEN_COMPLETE ++ */ ++s32 ++wl_cfgp2p_listen_complete(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data) ++{ ++ s32 ret = BCME_OK; ++ struct net_device *netdev; ++ if (!wl || !wl->p2p) ++ return BCME_ERROR; ++ if (wl->p2p_net == ndev) { ++ netdev = wl_to_prmry_ndev(wl); ++ } else { ++ netdev = ndev; ++ } ++ AP6211_DEBUG(" Enter\n"); ++ if (wl_get_p2p_status(wl, LISTEN_EXPIRED) == 0) { ++ wl_set_p2p_status(wl, LISTEN_EXPIRED); ++ if (timer_pending(&wl->p2p->listen_timer)) { ++ del_timer_sync(&wl->p2p->listen_timer); ++ } ++ ++ if (wl->afx_hdl->is_listen == TRUE && ++ wl_get_drv_status_all(wl, FINDING_COMMON_CHANNEL)) { ++ AP6211_DEBUG("Listen DONE for action frame\n"); ++ complete(&wl->act_frm_scan); ++ } ++#ifdef WL_CFG80211_SYNC_GON ++ else if (wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM_LISTEN)) { ++ wl_clr_drv_status(wl, WAITING_NEXT_ACT_FRM_LISTEN, netdev); ++ AP6211_DEBUG("Listen DONE and wake up wait_next_af !!(%d)\n", ++ jiffies_to_msecs(jiffies - wl->af_tx_sent_jiffies)); ++ ++ if (wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM)) ++ wl_clr_drv_status(wl, WAITING_NEXT_ACT_FRM, netdev); ++ ++ complete(&wl->wait_next_af); ++ } ++#endif /* WL_CFG80211_SYNC_GON */ ++ ++#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST ++ if (wl_get_drv_status_all(wl, REMAINING_ON_CHANNEL)) { ++#else ++ if (wl_get_drv_status_all(wl, REMAINING_ON_CHANNEL) || ++ wl_get_drv_status_all(wl, FAKE_REMAINING_ON_CHANNEL)) { ++#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ ++ AP6211_DEBUG("Listen DONE for ramain on channel expired\n"); ++ wl_clr_drv_status(wl, REMAINING_ON_CHANNEL, netdev); ++#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST ++ wl_clr_drv_status(wl, FAKE_REMAINING_ON_CHANNEL, netdev); ++#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ ++ if (ndev && (ndev->ieee80211_ptr != NULL)) { ++ cfg80211_remain_on_channel_expired(ndev, wl->last_roc_id, ++ &wl->remain_on_chan, wl->remain_on_chan_type, GFP_KERNEL); ++ } ++ } ++ if (wl_add_remove_eventmsg(wl_to_prmry_ndev(wl), ++ WLC_E_P2P_PROBREQ_MSG, false) != BCME_OK) { ++ AP6211_ERR(" failed to unset WLC_E_P2P_PROPREQ_MSG\n"); ++ } ++ } else ++ wl_clr_p2p_status(wl, LISTEN_EXPIRED); ++ ++ return ret; ++ ++} ++ ++/* ++ * Timer expire callback function for LISTEN ++ * We can't report cfg80211_remain_on_channel_expired from Timer ISR context, ++ * so lets do it from thread context. ++ */ ++void ++wl_cfgp2p_listen_expired(unsigned long data) ++{ ++ wl_event_msg_t msg; ++ struct wl_priv *wl = (struct wl_priv *) data; ++ AP6211_DEBUG(" Enter\n"); ++ bzero(&msg, sizeof(wl_event_msg_t)); ++ msg.event_type = hton32(WLC_E_P2P_DISC_LISTEN_COMPLETE); ++ wl_cfg80211_event(wl->p2p_net ? wl->p2p_net : ++ wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE), &msg, NULL); ++} ++/* ++ * Routine for cancelling the P2P LISTEN ++ */ ++static s32 ++wl_cfgp2p_cancel_listen(struct wl_priv *wl, struct net_device *ndev, ++ bool notify) ++{ ++ AP6211_DEBUG("Enter \n"); ++ /* Irrespective of whether timer is running or not, reset ++ * the LISTEN state. ++ */ ++ if (timer_pending(&wl->p2p->listen_timer)) { ++ del_timer_sync(&wl->p2p->listen_timer); ++ if (notify) ++ if (ndev && ndev->ieee80211_ptr) { ++ cfg80211_remain_on_channel_expired(ndev, wl->last_roc_id, ++ &wl->remain_on_chan, wl->remain_on_chan_type, ++ GFP_KERNEL); ++ } ++ } ++ return 0; ++} ++/* ++ * Do a P2P Listen on the given channel for the given duration. ++ * A listen consists of sitting idle and responding to P2P probe requests ++ * with a P2P probe response. ++ * ++ * This fn assumes dongle p2p device discovery is already enabled. ++ * Parameters : ++ * @wl : wl_private data ++ * @channel : channel to listen ++ * @duration_ms : the time (milli seconds) to wait ++ */ ++s32 ++wl_cfgp2p_discover_listen(struct wl_priv *wl, s32 channel, u32 duration_ms) ++{ ++#define EXTRA_DELAY_TIME 100 ++ s32 ret = BCME_OK; ++ struct timer_list *_timer; ++ s32 extra_delay; ++ struct net_device *netdev = wl_to_prmry_ndev(wl); ++ ++ AP6211_DEBUG(" Enter Listen Channel : %d, Duration : %d\n", channel, duration_ms); ++ if (unlikely(wl_get_p2p_status(wl, DISCOVERY_ON) == 0)) { ++ ++ AP6211_ERR(" Discovery is not set, so we have noting to do\n"); ++ ++ ret = BCME_NOTREADY; ++ goto exit; ++ } ++ if (timer_pending(&wl->p2p->listen_timer)) { ++ AP6211_DEBUG("previous LISTEN is not completed yet\n"); ++ goto exit; ++ ++ } ++#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST ++ else ++ wl_clr_p2p_status(wl, LISTEN_EXPIRED); ++#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ ++ if (wl_add_remove_eventmsg(netdev, WLC_E_P2P_PROBREQ_MSG, true) != BCME_OK) { ++ AP6211_ERR(" failed to set WLC_E_P2P_PROPREQ_MSG\n"); ++ } ++ ++ ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_LISTEN, channel, (u16) duration_ms, ++ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); ++ _timer = &wl->p2p->listen_timer; ++ ++ /* We will wait to receive WLC_E_P2P_DISC_LISTEN_COMPLETE from dongle , ++ * otherwise we will wait up to duration_ms + 100ms + duration / 10 ++ */ ++ if (ret == BCME_OK) { ++ extra_delay = EXTRA_DELAY_TIME + (duration_ms / 10); ++ } else { ++ /* if failed to set listen, it doesn't need to wait whole duration. */ ++ duration_ms = 100 + duration_ms / 20; ++ extra_delay = 0; ++ } ++ ++ INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration_ms, extra_delay); ++#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST ++ wl_clr_p2p_status(wl, LISTEN_EXPIRED); ++#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ ++ ++#undef EXTRA_DELAY_TIME ++exit: ++ return ret; ++} ++ ++ ++s32 ++wl_cfgp2p_discover_enable_search(struct wl_priv *wl, u8 enable) ++{ ++ s32 ret = BCME_OK; ++ AP6211_DEBUG(" Enter\n"); ++ if (!wl_get_p2p_status(wl, DISCOVERY_ON)) { ++ ++ AP6211_DEBUG(" do nothing, discovery is off\n"); ++ return ret; ++ } ++ if (wl_get_p2p_status(wl, SEARCH_ENABLED) == enable) { ++ AP6211_DEBUG("already : %d\n", enable); ++ return ret; ++ } ++ ++ wl_chg_p2p_status(wl, SEARCH_ENABLED); ++ /* When disabling Search, reset the WL driver's p2p discovery state to ++ * WL_P2P_DISC_ST_SCAN. ++ */ ++ if (!enable) { ++ wl_clr_p2p_status(wl, SCANNING); ++ ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0, ++ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); ++ } ++ ++ return ret; ++} ++ ++/* ++ * Callback function for WLC_E_ACTION_FRAME_COMPLETE, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE ++ */ ++s32 ++wl_cfgp2p_action_tx_complete(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data) ++{ ++ s32 ret = BCME_OK; ++ u32 event_type = ntoh32(e->event_type); ++ u32 status = ntoh32(e->status); ++ AP6211_DEBUG(" Enter\n"); ++ if (event_type == WLC_E_ACTION_FRAME_COMPLETE) { ++ ++ AP6211_DEBUG(" WLC_E_ACTION_FRAME_COMPLETE is received : %d\n", status); ++ if (status == WLC_E_STATUS_SUCCESS) { ++ wl_set_p2p_status(wl, ACTION_TX_COMPLETED); ++ AP6211_DEBUG("WLC_E_ACTION_FRAME_COMPLETE : ACK\n"); ++ } ++ else { ++ wl_set_p2p_status(wl, ACTION_TX_NOACK); ++ AP6211_DEBUG("WLC_E_ACTION_FRAME_COMPLETE : NO ACK\n"); ++ wl_stop_wait_next_action_frame(wl, ndev); ++ } ++ } else { ++ AP6211_DEBUG(" WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE is received," ++ "status : %d\n", status); ++ ++ if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) ++ complete(&wl->send_af_done); ++ } ++ return ret; ++} ++/* Send an action frame immediately without doing channel synchronization. ++ * ++ * This function does not wait for a completion event before returning. ++ * The WLC_E_ACTION_FRAME_COMPLETE event will be received when the action ++ * frame is transmitted. ++ * The WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE event will be received when an ++ * 802.11 ack has been received for the sent action frame. ++ */ ++s32 ++wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev, ++ wl_af_params_t *af_params, s32 bssidx) ++{ ++ s32 ret = BCME_OK; ++ s32 timeout = 0; ++ wl_eventmsg_buf_t buf; ++ ++ ++ AP6211_DEBUG("\n"); ++ AP6211_DEBUG("channel : %u , dwell time : %u\n", ++ af_params->channel, af_params->dwell_time); ++ ++ wl_clr_p2p_status(wl, ACTION_TX_COMPLETED); ++ wl_clr_p2p_status(wl, ACTION_TX_NOACK); ++ ++ bzero(&buf, sizeof(wl_eventmsg_buf_t)); ++ wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE, true); ++ wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_COMPLETE, true); ++ if ((ret = wl_cfg80211_apply_eventbuffer(wl_to_prmry_ndev(wl), wl, &buf)) < 0) ++ return ret; ++ ++#define MAX_WAIT_TIME 2000 ++ if (bssidx == P2PAPI_BSSCFG_PRIMARY) ++ bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); ++ ++ wl->af_sent_channel = af_params->channel; ++#ifdef WL_CFG80211_SYNC_GON ++ wl->af_tx_sent_jiffies = jiffies; ++#endif /* WL_CFG80211_SYNC_GON */ ++ ++ ret = wldev_iovar_setbuf_bsscfg(dev, "actframe", af_params, sizeof(*af_params), ++ wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); ++ ++ if (ret < 0) { ++ AP6211_ERR(" sending action frame is failed\n"); ++ goto exit; ++ } ++ ++ timeout = wait_for_completion_timeout(&wl->send_af_done, msecs_to_jiffies(MAX_WAIT_TIME)); ++ ++ if (timeout > 0 && wl_get_p2p_status(wl, ACTION_TX_COMPLETED)) { ++ AP6211_DEBUG("tx action frame operation is completed\n"); ++ ret = BCME_OK; ++ } else { ++ ret = BCME_ERROR; ++ AP6211_DEBUG("tx action frame operation is failed\n"); ++ } ++ /* clear status bit for action tx */ ++ wl_clr_p2p_status(wl, ACTION_TX_COMPLETED); ++ wl_clr_p2p_status(wl, ACTION_TX_NOACK); ++ ++exit: ++ AP6211_DEBUG(" via act frame iovar : status = %d\n", ret); ++ ++ bzero(&buf, sizeof(wl_eventmsg_buf_t)); ++ wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE, false); ++ wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_COMPLETE, false); ++ if ((ret = wl_cfg80211_apply_eventbuffer(wl_to_prmry_ndev(wl), wl, &buf)) < 0) ++ AP6211_ERR("TX frame events revert back failed \n"); ++ ++#undef MAX_WAIT_TIME ++ return ret; ++} ++ ++/* Generate our P2P Device Address and P2P Interface Address from our primary ++ * MAC address. ++ */ ++void ++wl_cfgp2p_generate_bss_mac(struct ether_addr *primary_addr, ++ struct ether_addr *out_dev_addr, struct ether_addr *out_int_addr) ++{ ++ memset(out_dev_addr, 0, sizeof(*out_dev_addr)); ++ memset(out_int_addr, 0, sizeof(*out_int_addr)); ++ ++ /* Generate the P2P Device Address. This consists of the device's ++ * primary MAC address with the locally administered bit set. ++ */ ++ memcpy(out_dev_addr, primary_addr, sizeof(*out_dev_addr)); ++ out_dev_addr->octet[0] |= 0x02; ++ ++ /* Generate the P2P Interface Address. If the discovery and connection ++ * BSSCFGs need to simultaneously co-exist, then this address must be ++ * different from the P2P Device Address. ++ */ ++ memcpy(out_int_addr, out_dev_addr, sizeof(*out_int_addr)); ++ out_int_addr->octet[4] ^= 0x80; ++ ++} ++ ++/* P2P IF Address change to Virtual Interface MAC Address */ ++void ++wl_cfg80211_change_ifaddr(u8* buf, struct ether_addr *p2p_int_addr, u8 element_id) ++{ ++ wifi_p2p_ie_t *ie = (wifi_p2p_ie_t*) buf; ++ u16 len = ie->len; ++ u8 *subel; ++ u8 subelt_id; ++ u16 subelt_len; ++ AP6211_DEBUG(" Enter\n"); ++ ++ /* Point subel to the P2P IE's subelt field. ++ * Subtract the preceding fields (id, len, OUI, oui_type) from the length. ++ */ ++ subel = ie->subelts; ++ len -= 4; /* exclude OUI + OUI_TYPE */ ++ ++ while (len >= 3) { ++ /* attribute id */ ++ subelt_id = *subel; ++ subel += 1; ++ len -= 1; ++ ++ /* 2-byte little endian */ ++ subelt_len = *subel++; ++ subelt_len |= *subel++ << 8; ++ ++ len -= 2; ++ len -= subelt_len; /* for the remaining subelt fields */ ++ ++ if (subelt_id == element_id) { ++ if (subelt_id == P2P_SEID_INTINTADDR) { ++ memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN); ++ AP6211_DEBUG("Intended P2P Interface Address ATTR FOUND\n"); ++ } else if (subelt_id == P2P_SEID_DEV_ID) { ++ memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN); ++ AP6211_DEBUG("Device ID ATTR FOUND\n"); ++ } else if (subelt_id == P2P_SEID_DEV_INFO) { ++ memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN); ++ AP6211_DEBUG("Device INFO ATTR FOUND\n"); ++ } else if (subelt_id == P2P_SEID_GROUP_ID) { ++ memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN); ++ AP6211_DEBUG("GROUP ID ATTR FOUND\n"); ++ } return; ++ } else { ++ AP6211_DEBUG("OTHER id : %d\n", subelt_id); ++ } ++ subel += subelt_len; ++ } ++} ++/* ++ * Check if a BSS is up. ++ * This is a common implementation called by most OSL implementations of ++ * p2posl_bss_isup(). DO NOT call this function directly from the ++ * common code -- call p2posl_bss_isup() instead to allow the OSL to ++ * override the common implementation if necessary. ++ */ ++bool ++wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx) ++{ ++ s32 result, val; ++ bool isup = false; ++ s8 getbuf[64]; ++ ++ /* Check if the BSS is up */ ++ *(int*)getbuf = -1; ++ result = wldev_iovar_getbuf_bsscfg(ndev, "bss", &bsscfg_idx, ++ sizeof(bsscfg_idx), getbuf, sizeof(getbuf), 0, NULL); ++ if (result != 0) { ++ AP6211_ERR("'wl bss -C %d' failed: %d\n", bsscfg_idx, result); ++ AP6211_ERR("NOTE: this ioctl error is normal " ++ "when the BSS has not been created yet.\n"); ++ } else { ++ val = *(int*)getbuf; ++ val = dtoh32(val); ++ AP6211_DEBUG("---wl bss -C %d ==> %d\n", bsscfg_idx, val); ++ isup = (val ? TRUE : FALSE); ++ } ++ return isup; ++} ++ ++ ++/* Bring up or down a BSS */ ++s32 ++wl_cfgp2p_bss(struct wl_priv *wl, struct net_device *ndev, s32 bsscfg_idx, s32 up) ++{ ++ s32 ret = BCME_OK; ++ s32 val = up ? 1 : 0; ++ ++ struct { ++ s32 cfg; ++ s32 val; ++ } bss_setbuf; ++ ++ bss_setbuf.cfg = htod32(bsscfg_idx); ++ bss_setbuf.val = htod32(val); ++ AP6211_DEBUG("---wl bss -C %d %s\n", bsscfg_idx, up ? "up" : "down"); ++ ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf), ++ wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); ++ ++ if (ret != 0) { ++ AP6211_ERR("'bss %d' failed with %d\n", up, ret); ++ } ++ ++ return ret; ++} ++ ++/* Check if 'p2p' is supported in the driver */ ++s32 ++wl_cfgp2p_supported(struct wl_priv *wl, struct net_device *ndev) ++{ ++ s32 ret = BCME_OK; ++ s32 p2p_supported = 0; ++ ret = wldev_iovar_getint(ndev, "p2p", ++ &p2p_supported); ++ if (ret < 0) { ++ AP6211_ERR("wl p2p error %d\n", ret); ++ return 0; ++ } ++ if (p2p_supported == 1) { ++ AP6211_DEBUG("p2p is supported\n"); ++ } else { ++ AP6211_DEBUG("p2p is unsupported\n"); ++ p2p_supported = 0; ++ } ++ return p2p_supported; ++} ++ ++/* Cleanup P2P resources */ ++s32 ++wl_cfgp2p_down(struct wl_priv *wl) ++{ ++ s32 i = 0, index = -1; ++ wl_cfgp2p_cancel_listen(wl, ++ wl->p2p_net ? wl->p2p_net : wl_to_prmry_ndev(wl), TRUE); ++ for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) { ++ index = wl_to_p2p_bss_bssidx(wl, i); ++ if (index != WL_INVALID) ++ wl_cfgp2p_clear_management_ie(wl, index); ++ } ++ wl_cfgp2p_deinit_priv(wl); ++ return 0; ++} ++ ++s32 ++wl_cfgp2p_set_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int len) ++{ ++ s32 ret = -1; ++ int count, start, duration; ++ wl_p2p_sched_t dongle_noa; ++ ++ AP6211_DEBUG(" Enter\n"); ++ ++ memset(&dongle_noa, 0, sizeof(dongle_noa)); ++ ++ if (wl->p2p && wl->p2p->vif_created) { ++ ++ wl->p2p->noa.desc[0].start = 0; ++ ++ sscanf(buf, "%10d %10d %10d", &count, &start, &duration); ++ AP6211_DEBUG("set_p2p_noa count %d start %d duration %d\n", ++ count, start, duration); ++ if (count != -1) ++ wl->p2p->noa.desc[0].count = count; ++ ++ /* supplicant gives interval as start */ ++ if (start != -1) ++ wl->p2p->noa.desc[0].interval = start; ++ ++ if (duration != -1) ++ wl->p2p->noa.desc[0].duration = duration; ++ ++ if (wl->p2p->noa.desc[0].count != 255) { ++ wl->p2p->noa.desc[0].start = 200; ++ dongle_noa.type = WL_P2P_SCHED_TYPE_REQ_ABS; ++ dongle_noa.action = WL_P2P_SCHED_ACTION_GOOFF; ++ dongle_noa.option = WL_P2P_SCHED_OPTION_TSFOFS; ++ } ++ else { ++ /* Continuous NoA interval. */ ++ dongle_noa.action = WL_P2P_SCHED_ACTION_NONE; ++ dongle_noa.type = WL_P2P_SCHED_TYPE_ABS; ++ if ((wl->p2p->noa.desc[0].interval == 102) || ++ (wl->p2p->noa.desc[0].interval == 100)) { ++ wl->p2p->noa.desc[0].start = 100 - ++ wl->p2p->noa.desc[0].duration; ++ dongle_noa.option = WL_P2P_SCHED_OPTION_BCNPCT; ++ } ++ else { ++ dongle_noa.option = WL_P2P_SCHED_OPTION_NORMAL; ++ } ++ } ++ /* Put the noa descriptor in dongle format for dongle */ ++ dongle_noa.desc[0].count = htod32(wl->p2p->noa.desc[0].count); ++ if (dongle_noa.option == WL_P2P_SCHED_OPTION_BCNPCT) { ++ dongle_noa.desc[0].start = htod32(wl->p2p->noa.desc[0].start); ++ dongle_noa.desc[0].duration = htod32(wl->p2p->noa.desc[0].duration); ++ } ++ else { ++ dongle_noa.desc[0].start = htod32(wl->p2p->noa.desc[0].start*1000); ++ dongle_noa.desc[0].duration = htod32(wl->p2p->noa.desc[0].duration*1000); ++ } ++ dongle_noa.desc[0].interval = htod32(wl->p2p->noa.desc[0].interval*1000); ++ ++ ret = wldev_iovar_setbuf(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION), ++ "p2p_noa", &dongle_noa, sizeof(dongle_noa), wl->ioctl_buf, WLC_IOCTL_MAXLEN, ++ &wl->ioctl_buf_sync); ++ ++ if (ret < 0) { ++ AP6211_ERR("fw set p2p_noa failed %d\n", ret); ++ } ++ } ++ else { ++ AP6211_ERR("ERROR: set_noa in non-p2p mode\n"); ++ } ++ return ret; ++} ++s32 ++wl_cfgp2p_get_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int buf_len) ++{ ++ ++ wifi_p2p_noa_desc_t *noa_desc; ++ int len = 0, i; ++ char _buf[200]; ++ ++ AP6211_DEBUG(" Enter\n"); ++ buf[0] = '\0'; ++ if (wl->p2p && wl->p2p->vif_created) { ++ if (wl->p2p->noa.desc[0].count || wl->p2p->ops.ops) { ++ _buf[0] = 1; /* noa index */ ++ _buf[1] = (wl->p2p->ops.ops ? 0x80: 0) | ++ (wl->p2p->ops.ctw & 0x7f); /* ops + ctw */ ++ len += 2; ++ if (wl->p2p->noa.desc[0].count) { ++ noa_desc = (wifi_p2p_noa_desc_t*)&_buf[len]; ++ noa_desc->cnt_type = wl->p2p->noa.desc[0].count; ++ noa_desc->duration = wl->p2p->noa.desc[0].duration; ++ noa_desc->interval = wl->p2p->noa.desc[0].interval; ++ noa_desc->start = wl->p2p->noa.desc[0].start; ++ len += sizeof(wifi_p2p_noa_desc_t); ++ } ++ if (buf_len <= len * 2) { ++ AP6211_ERR("ERROR: buf_len %d in not enough for" ++ "returning noa in string format\n", buf_len); ++ return -1; ++ } ++ /* We have to convert the buffer data into ASCII strings */ ++ for (i = 0; i < len; i++) { ++ snprintf(buf, 3, "%02x", _buf[i]); ++ buf += 2; ++ } ++ buf[i*2] = '\0'; ++ } ++ } ++ else { ++ AP6211_ERR("ERROR: get_noa in non-p2p mode\n"); ++ return -1; ++ } ++ return len * 2; ++} ++s32 ++wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf, int len) ++{ ++ int ps, ctw; ++ int ret = -1; ++ s32 legacy_ps; ++ ++ AP6211_DEBUG(" Enter\n"); ++ if (wl->p2p && wl->p2p->vif_created) { ++ sscanf(buf, "%10d %10d %10d", &legacy_ps, &ps, &ctw); ++ AP6211_DEBUG(" Enter legacy_ps %d ps %d ctw %d\n", legacy_ps, ps, ctw); ++ if (ctw != -1) { ++ wl->p2p->ops.ctw = ctw; ++ ret = 0; ++ } ++ if (ps != -1) { ++ wl->p2p->ops.ops = ps; ++ ret = wldev_iovar_setbuf(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION), ++ "p2p_ops", &wl->p2p->ops, sizeof(wl->p2p->ops), ++ wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); ++ if (ret < 0) { ++ AP6211_ERR("fw set p2p_ops failed %d\n", ret); ++ } ++ } ++ ++ if ((legacy_ps != -1) && ((legacy_ps == PM_MAX) || (legacy_ps == PM_OFF))) { ++#if !defined(SUPPORT_PM2_ONLY) ++ if (legacy_ps == PM_MAX) ++ legacy_ps = PM_FAST; ++#endif /* SUPPORT_PM2_ONLY */ ++ ++ ret = wldev_ioctl(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION), ++ WLC_SET_PM, &legacy_ps, sizeof(legacy_ps), true); ++ if (unlikely(ret)) { ++ AP6211_ERR("error (%d)\n", ret); ++ } else { ++ wl_cfg80211_update_power_mode(ndev); ++ } ++ } ++ else ++ AP6211_ERR("ilegal setting\n"); ++ } ++ else { ++ AP6211_ERR("ERROR: set_p2p_ps in non-p2p mode\n"); ++ ret = -1; ++ } ++ return ret; ++} ++ ++u8 * ++wl_cfgp2p_retreive_p2pattrib(void *buf, u8 element_id) ++{ ++ wifi_p2p_ie_t *ie = NULL; ++ u16 len = 0; ++ u8 *subel; ++ u8 subelt_id; ++ u16 subelt_len; ++ ++ if (!buf) { ++ AP6211_ERR("P2P IE not present"); ++ return 0; ++ } ++ ++ ie = (wifi_p2p_ie_t*) buf; ++ len = ie->len; ++ ++ /* Point subel to the P2P IE's subelt field. ++ * Subtract the preceding fields (id, len, OUI, oui_type) from the length. ++ */ ++ subel = ie->subelts; ++ len -= 4; /* exclude OUI + OUI_TYPE */ ++ ++ while (len >= 3) { ++ /* attribute id */ ++ subelt_id = *subel; ++ subel += 1; ++ len -= 1; ++ ++ /* 2-byte little endian */ ++ subelt_len = *subel++; ++ subelt_len |= *subel++ << 8; ++ ++ len -= 2; ++ len -= subelt_len; /* for the remaining subelt fields */ ++ ++ if (subelt_id == element_id) { ++ /* This will point to start of subelement attrib after ++ * attribute id & len ++ */ ++ return subel; ++ } ++ ++ /* Go to next subelement */ ++ subel += subelt_len; ++ } ++ ++ /* Not Found */ ++ return NULL; ++} ++ ++#define P2P_GROUP_CAPAB_GO_BIT 0x01 ++u8 * ++wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_t *bi, u32 bi_length) ++{ ++ wifi_p2p_ie_t * p2p_ie = NULL; ++ u8 *capability = NULL; ++ bool p2p_go = 0; ++ u8 *ptr = NULL; ++ ++ if (!(p2p_ie = wl_cfgp2p_find_p2pie(((u8 *) bi) + bi->ie_offset, bi->ie_length))) { ++ AP6211_ERR("P2P IE not found"); ++ return NULL; ++ } ++ ++ if (!(capability = wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_P2P_INFO))) { ++ AP6211_ERR("P2P Capability attribute not found"); ++ return NULL; ++ } ++ ++ /* Check Group capability for Group Owner bit */ ++ p2p_go = capability[1] & P2P_GROUP_CAPAB_GO_BIT; ++ if (!p2p_go) { ++ return bi->BSSID.octet; ++ } ++ ++ /* In probe responses, DEVICE INFO attribute will be present */ ++ if (!(ptr = wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_DEV_INFO))) { ++ /* If DEVICE_INFO is not found, this might be a beacon frame. ++ * check for DEVICE_ID in the beacon frame. ++ */ ++ ptr = wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_DEV_ID); ++ } ++ ++ if (!ptr) ++ AP6211_ERR(" Both DEVICE_ID & DEVICE_INFO attribute not present in P2P IE "); ++ ++ return ptr; ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) ++static void ++wl_cfgp2p_ethtool_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) ++{ ++ snprintf(info->driver, sizeof(info->driver), "p2p"); ++ snprintf(info->version, sizeof(info->version), "%lu", (unsigned long)(0)); ++} ++ ++struct ethtool_ops cfgp2p_ethtool_ops = { ++ .get_drvinfo = wl_cfgp2p_ethtool_get_drvinfo ++}; ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ ++ ++s32 ++wl_cfgp2p_register_ndev(struct wl_priv *wl) ++{ ++ int ret = 0; ++ struct net_device* net = NULL; ++ struct wireless_dev *wdev = NULL; ++ uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x33, 0x22, 0x11 }; ++ ++ if (wl->p2p_net) { ++ AP6211_ERR("p2p_net defined already.\n"); ++ return -EINVAL; ++ } ++ ++ /* Allocate etherdev, including space for private structure */ ++ if (!(net = alloc_etherdev(sizeof(struct wl_priv *)))) { ++ AP6211_ERR("%s: OOM - alloc_etherdev\n", __FUNCTION__); ++ return -ENODEV; ++ } ++ ++ wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); ++ if (unlikely(!wdev)) { ++ AP6211_ERR("Could not allocate wireless device\n"); ++ free_netdev(net); ++ return -ENOMEM; ++ } ++ ++ strncpy(net->name, "p2p%d", sizeof(net->name) - 1); ++ net->name[IFNAMSIZ - 1] = '\0'; ++ ++ /* Copy the reference to wl_priv */ ++ memcpy((void *)netdev_priv(net), &wl, sizeof(struct wl_priv *)); ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) ++ ASSERT(!net->open); ++ net->do_ioctl = wl_cfgp2p_do_ioctl; ++ net->hard_start_xmit = wl_cfgp2p_start_xmit; ++ net->open = wl_cfgp2p_if_open; ++ net->stop = wl_cfgp2p_if_stop; ++#else ++ ASSERT(!net->netdev_ops); ++ net->netdev_ops = &wl_cfgp2p_if_ops; ++#endif ++ ++ /* Register with a dummy MAC addr */ ++ memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN); ++ ++ wdev->wiphy = wl->wdev->wiphy; ++ ++ wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS); ++ ++ net->ieee80211_ptr = wdev; ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) ++ net->ethtool_ops = &cfgp2p_ethtool_ops; ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ ++ ++ SET_NETDEV_DEV(net, wiphy_dev(wdev->wiphy)); ++ ++ /* Associate p2p0 network interface with new wdev */ ++ wdev->netdev = net; ++ ++ ret = register_netdev(net); ++ if (ret) { ++ AP6211_ERR(" register_netdevice failed (%d)\n", ret); ++ free_netdev(net); ++ kfree(wdev); ++ return -ENODEV; ++ } ++ ++ /* store p2p net ptr for further reference. Note that iflist won't have this ++ * entry as there corresponding firmware interface is a "Hidden" interface. ++ */ ++ wl->p2p_wdev = wdev; ++ wl->p2p_net = net; ++ ++ AP6211_DEBUG("%s: P2P Interface Registered\n", net->name); ++ ++ return ret; ++} ++ ++s32 ++wl_cfgp2p_unregister_ndev(struct wl_priv *wl) ++{ ++ ++ if (!wl || !wl->p2p_net) { ++ AP6211_ERR("Invalid Ptr\n"); ++ return -EINVAL; ++ } ++ ++ unregister_netdev(wl->p2p_net); ++ free_netdev(wl->p2p_net); ++ ++ return 0; ++} ++static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev) ++{ ++ if (skb) ++ { ++ AP6211_DEBUG("(%s) is not used for data operations.Droping the packet.\n", ++ ndev->name); ++ dev_kfree_skb_any(skb); ++ } ++ ++ return 0; ++} ++ ++static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd) ++{ ++ int ret = 0; ++ struct wl_priv *wl = *(struct wl_priv **)netdev_priv(net); ++ struct net_device *ndev = wl_to_prmry_ndev(wl); ++ ++ /* There is no ifidx corresponding to p2p0 in our firmware. So we should ++ * not Handle any IOCTL cmds on p2p0 other than ANDROID PRIVATE CMDs. ++ * For Android PRIV CMD handling map it to primary I/F ++ */ ++ if (cmd == SIOCDEVPRIVATE+1) { ++ ret = wl_android_priv_cmd(ndev, ifr, cmd); ++ ++ } else { ++ AP6211_ERR("%s: IOCTL req 0x%x on p2p0 I/F. Ignoring. \n", ++ __FUNCTION__, cmd); ++ return -1; ++ } ++ ++ return ret; ++} ++ ++static int wl_cfgp2p_if_open(struct net_device *net) ++{ ++ extern struct wl_priv *wlcfg_drv_priv; ++ struct wireless_dev *wdev = net->ieee80211_ptr; ++ struct wl_priv *wl = NULL; ++ wl = wlcfg_drv_priv; ++ if (!wdev || !wl || !wl->p2p) ++ return -EINVAL; ++ AP6211_DEBUG("Enter\n"); ++ /* If suppose F/W download (ifconfig wlan0 up) hasn't been done by now, ++ * do it here. This will make sure that in concurrent mode, supplicant ++ * is not dependent on a particular order of interface initialization. ++ * i.e you may give wpa_supp -iwlan0 -N -ip2p0 or wpa_supp -ip2p0 -N ++ * -iwlan0. ++ */ ++ wdev->wiphy->interface_modes |= (BIT(NL80211_IFTYPE_P2P_CLIENT) ++ | BIT(NL80211_IFTYPE_P2P_GO)); ++ wl_cfg80211_do_driver_init(net); ++ ++ return 0; ++} ++ ++static int wl_cfgp2p_if_stop(struct net_device *net) ++{ ++ extern struct wl_priv *wlcfg_drv_priv; ++ struct wl_priv *wl = NULL; ++ unsigned long flags; ++ struct wireless_dev *wdev = net->ieee80211_ptr; ++ int clear_flag = 0; ++ if (!wdev) ++ return -EINVAL; ++ ++ AP6211_DEBUG("Enter\n"); ++ wl = wlcfg_drv_priv; ++ if (!wl) ++ return -EINVAL; ++ spin_lock_irqsave(&wl->cfgdrv_lock, flags); ++ if (wl->scan_request && wl->scan_request->dev == net) { ++ cfg80211_scan_done(wl->scan_request, true); ++ wl->scan_request = NULL; ++ clear_flag = 1; ++ } ++ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); ++ if (clear_flag) ++ wl_clr_drv_status(wl, SCANNING, net); ++ wdev->wiphy->interface_modes = (wdev->wiphy->interface_modes) ++ & (~(BIT(NL80211_IFTYPE_P2P_CLIENT)| ++ BIT(NL80211_IFTYPE_P2P_GO))); ++ return 0; ++} ++ ++bool wl_cfgp2p_is_ifops(const struct net_device_ops *if_ops) ++{ ++ return (if_ops == &wl_cfgp2p_if_ops); ++} +diff --git a/drivers/net/wireless/ap6211/wl_cfgp2p.h b/drivers/net/wireless/ap6211/wl_cfgp2p.h +new file mode 100755 +index 0000000..d3552d6 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/wl_cfgp2p.h +@@ -0,0 +1,311 @@ ++/* ++ * Linux cfgp2p driver ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: wl_cfgp2p.h 368091 2012-11-12 04:28:31Z $ ++ */ ++#ifndef _wl_cfgp2p_h_ ++#define _wl_cfgp2p_h_ ++#include ++#include ++ ++struct wl_priv; ++extern u32 wl_dbg_level; ++ ++typedef struct wifi_p2p_ie wifi_wfd_ie_t; ++/* Enumeration of the usages of the BSSCFGs used by the P2P Library. Do not ++ * confuse this with a bsscfg index. This value is an index into the ++ * saved_ie[] array of structures which in turn contains a bsscfg index field. ++ */ ++typedef enum { ++ P2PAPI_BSSCFG_PRIMARY, /* maps to driver's primary bsscfg */ ++ P2PAPI_BSSCFG_DEVICE, /* maps to driver's P2P device discovery bsscfg */ ++ P2PAPI_BSSCFG_CONNECTION, /* maps to driver's P2P connection bsscfg */ ++ P2PAPI_BSSCFG_MAX ++} p2p_bsscfg_type_t; ++ ++/* vendor ies max buffer length for probe response or beacon */ ++#define VNDR_IES_MAX_BUF_LEN 1400 ++/* normal vendor ies buffer length */ ++#define VNDR_IES_BUF_LEN 512 ++ ++/* Structure to hold all saved P2P and WPS IEs for a BSSCFG */ ++struct p2p_saved_ie { ++ u8 p2p_probe_req_ie[VNDR_IES_BUF_LEN]; ++ u8 p2p_probe_res_ie[VNDR_IES_MAX_BUF_LEN]; ++ u8 p2p_assoc_req_ie[VNDR_IES_BUF_LEN]; ++ u8 p2p_assoc_res_ie[VNDR_IES_BUF_LEN]; ++ u8 p2p_beacon_ie[VNDR_IES_MAX_BUF_LEN]; ++ u32 p2p_probe_req_ie_len; ++ u32 p2p_probe_res_ie_len; ++ u32 p2p_assoc_req_ie_len; ++ u32 p2p_assoc_res_ie_len; ++ u32 p2p_beacon_ie_len; ++}; ++ ++struct p2p_bss { ++ u32 bssidx; ++ struct net_device *dev; ++ struct p2p_saved_ie saved_ie; ++ void *private_data; ++}; ++ ++struct p2p_info { ++ bool on; /* p2p on/off switch */ ++ bool scan; ++ bool vif_created; ++ s8 vir_ifname[IFNAMSIZ]; ++ unsigned long status; ++ struct ether_addr dev_addr; ++ struct ether_addr int_addr; ++ struct p2p_bss bss_idx[P2PAPI_BSSCFG_MAX]; ++ struct timer_list listen_timer; ++ wl_p2p_sched_t noa; ++ wl_p2p_ops_t ops; ++ wlc_ssid_t ssid; ++}; ++ ++#define MAX_VNDR_IE_NUMBER 5 ++ ++struct parsed_vndr_ie_info { ++ char *ie_ptr; ++ u32 ie_len; /* total length including id & length field */ ++ vndr_ie_t vndrie; ++}; ++ ++struct parsed_vndr_ies { ++ u32 count; ++ struct parsed_vndr_ie_info ie_info[MAX_VNDR_IE_NUMBER]; ++}; ++ ++/* dongle status */ ++enum wl_cfgp2p_status { ++ WLP2P_STATUS_DISCOVERY_ON = 0, ++ WLP2P_STATUS_SEARCH_ENABLED, ++ WLP2P_STATUS_IF_ADD, ++ WLP2P_STATUS_IF_DEL, ++ WLP2P_STATUS_IF_DELETING, ++ WLP2P_STATUS_IF_CHANGING, ++ WLP2P_STATUS_IF_CHANGED, ++ WLP2P_STATUS_LISTEN_EXPIRED, ++ WLP2P_STATUS_ACTION_TX_COMPLETED, ++ WLP2P_STATUS_ACTION_TX_NOACK, ++ WLP2P_STATUS_SCANNING, ++ WLP2P_STATUS_GO_NEG_PHASE, ++ WLP2P_STATUS_DISC_IN_PROGRESS ++}; ++ ++ ++#define wl_to_p2p_bss_ndev(wl, type) ((wl)->p2p->bss_idx[type].dev) ++#define wl_to_p2p_bss_bssidx(wl, type) ((wl)->p2p->bss_idx[type].bssidx) ++#define wl_to_p2p_bss_saved_ie(wl, type) ((wl)->p2p->bss_idx[type].saved_ie) ++#define wl_to_p2p_bss_private(wl, type) ((wl)->p2p->bss_idx[type].private_data) ++#define wl_to_p2p_bss(wl, type) ((wl)->p2p->bss_idx[type]) ++#define wl_get_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : test_bit(WLP2P_STATUS_ ## stat, \ ++ &(wl)->p2p->status)) ++#define wl_set_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : set_bit(WLP2P_STATUS_ ## stat, \ ++ &(wl)->p2p->status)) ++#define wl_clr_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : clear_bit(WLP2P_STATUS_ ## stat, \ ++ &(wl)->p2p->status)) ++#define wl_chg_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0:change_bit(WLP2P_STATUS_ ## stat, \ ++ &(wl)->p2p->status)) ++#define p2p_on(wl) ((wl)->p2p->on) ++#define p2p_scan(wl) ((wl)->p2p->scan) ++#define p2p_is_on(wl) ((wl)->p2p && (wl)->p2p->on) ++ ++/* dword align allocation */ ++#define WLC_IOCTL_MAXLEN 8192 ++ ++#define INIT_TIMER(timer, func, duration, extra_delay) \ ++ do { \ ++ init_timer(timer); \ ++ timer->function = func; \ ++ timer->expires = jiffies + msecs_to_jiffies(duration + extra_delay); \ ++ timer->data = (unsigned long) wl; \ ++ add_timer(timer); \ ++ } while (0); ++extern void ++wl_cfgp2p_listen_expired(unsigned long data); ++extern bool ++wl_cfgp2p_is_pub_action(void *frame, u32 frame_len); ++extern bool ++wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len); ++extern bool ++wl_cfgp2p_is_gas_action(void *frame, u32 frame_len); ++extern void ++wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len); ++extern s32 ++wl_cfgp2p_init_priv(struct wl_priv *wl); ++extern void ++wl_cfgp2p_deinit_priv(struct wl_priv *wl); ++extern s32 ++wl_cfgp2p_set_firm_p2p(struct wl_priv *wl); ++extern s32 ++wl_cfgp2p_set_p2p_mode(struct wl_priv *wl, u8 mode, ++ u32 channel, u16 listen_ms, int bssidx); ++extern s32 ++wl_cfgp2p_ifadd(struct wl_priv *wl, struct ether_addr *mac, u8 if_type, ++ chanspec_t chspec); ++extern s32 ++wl_cfgp2p_ifdisable(struct wl_priv *wl, struct ether_addr *mac); ++extern s32 ++wl_cfgp2p_ifdel(struct wl_priv *wl, struct ether_addr *mac); ++extern s32 ++wl_cfgp2p_ifchange(struct wl_priv *wl, struct ether_addr *mac, u8 if_type, chanspec_t chspec); ++ ++extern s32 ++wl_cfgp2p_ifidx(struct wl_priv *wl, struct ether_addr *mac, s32 *index); ++ ++extern s32 ++wl_cfgp2p_init_discovery(struct wl_priv *wl); ++extern s32 ++wl_cfgp2p_enable_discovery(struct wl_priv *wl, struct net_device *dev, const u8 *ie, u32 ie_len); ++extern s32 ++wl_cfgp2p_disable_discovery(struct wl_priv *wl); ++extern s32 ++wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active, u32 num_chans, ++ u16 *channels, ++ s32 search_state, u16 action, u32 bssidx); ++ ++extern s32 ++wl_cfgp2p_act_frm_search(struct wl_priv *wl, struct net_device *ndev, ++ s32 bssidx, s32 channel); ++ ++extern wpa_ie_fixed_t * ++wl_cfgp2p_find_wpaie(u8 *parse, u32 len); ++ ++extern wpa_ie_fixed_t * ++wl_cfgp2p_find_wpsie(u8 *parse, u32 len); ++ ++extern wifi_p2p_ie_t * ++wl_cfgp2p_find_p2pie(u8 *parse, u32 len); ++ ++extern wifi_wfd_ie_t * ++wl_cfgp2p_find_wfdie(u8 *parse, u32 len); ++extern s32 ++wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, ++ s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len); ++extern s32 ++wl_cfgp2p_clear_management_ie(struct wl_priv *wl, s32 bssidx); ++ ++extern s32 ++wl_cfgp2p_find_idx(struct wl_priv *wl, struct net_device *ndev); ++extern struct net_device * ++wl_cfgp2p_find_ndev(struct wl_priv *wl, s32 bssidx); ++ ++ ++extern s32 ++wl_cfgp2p_listen_complete(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data); ++extern s32 ++wl_cfgp2p_discover_listen(struct wl_priv *wl, s32 channel, u32 duration_ms); ++ ++extern s32 ++wl_cfgp2p_discover_enable_search(struct wl_priv *wl, u8 enable); ++ ++extern s32 ++wl_cfgp2p_action_tx_complete(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data); ++extern s32 ++wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev, ++ wl_af_params_t *af_params, s32 bssidx); ++ ++extern void ++wl_cfgp2p_generate_bss_mac(struct ether_addr *primary_addr, struct ether_addr *out_dev_addr, ++ struct ether_addr *out_int_addr); ++ ++extern void ++wl_cfg80211_change_ifaddr(u8* buf, struct ether_addr *p2p_int_addr, u8 element_id); ++extern bool ++wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx); ++ ++extern s32 ++wl_cfgp2p_bss(struct wl_priv *wl, struct net_device *ndev, s32 bsscfg_idx, s32 up); ++ ++ ++extern s32 ++wl_cfgp2p_supported(struct wl_priv *wl, struct net_device *ndev); ++ ++extern s32 ++wl_cfgp2p_down(struct wl_priv *wl); ++ ++extern s32 ++wl_cfgp2p_set_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int len); ++ ++extern s32 ++wl_cfgp2p_get_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int len); ++ ++extern s32 ++wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf, int len); ++ ++extern u8 * ++wl_cfgp2p_retreive_p2pattrib(void *buf, u8 element_id); ++ ++extern u8 * ++wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_t *bi, u32 bi_length); ++ ++extern s32 ++wl_cfgp2p_register_ndev(struct wl_priv *wl); ++ ++extern s32 ++wl_cfgp2p_unregister_ndev(struct wl_priv *wl); ++ ++extern bool ++wl_cfgp2p_is_ifops(const struct net_device_ops *if_ops); ++ ++/* WiFi Direct */ ++#define SOCIAL_CHAN_1 1 ++#define SOCIAL_CHAN_2 6 ++#define SOCIAL_CHAN_3 11 ++#define IS_P2P_SOCIAL_CHANNEL(channel) ((channel == SOCIAL_CHAN_1) || \ ++ (channel == SOCIAL_CHAN_2) || \ ++ (channel == SOCIAL_CHAN_3)) ++#define SOCIAL_CHAN_CNT 3 ++#define AF_PEER_SEARCH_CNT 2 ++#define WL_P2P_WILDCARD_SSID "DIRECT-" ++#define WL_P2P_WILDCARD_SSID_LEN 7 ++#define WL_P2P_INTERFACE_PREFIX "p2p" ++#define WL_P2P_TEMP_CHAN 11 ++ ++/* If the provision discovery is for JOIN operations, ++ * then we need not do an internal scan to find GO. ++ */ ++#define IS_PROV_DISC_WITHOUT_GROUP_ID(p2p_ie, len) \ ++ (wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_GROUP_ID) == NULL) ++ ++#define IS_GAS_REQ(frame, len) (wl_cfgp2p_is_gas_action(frame, len) && \ ++ ((frame->action == P2PSD_ACTION_ID_GAS_IREQ) || \ ++ (frame->action == P2PSD_ACTION_ID_GAS_CREQ))) ++#define IS_P2P_PUB_ACT_REQ(frame, p2p_ie, len) \ ++ (wl_cfgp2p_is_pub_action(frame, len) && \ ++ ((frame->subtype == P2P_PAF_GON_REQ) || \ ++ (frame->subtype == P2P_PAF_INVITE_REQ) || \ ++ ((frame->subtype == P2P_PAF_PROVDIS_REQ) && \ ++ IS_PROV_DISC_WITHOUT_GROUP_ID(p2p_ie, len)))) ++#define IS_P2P_PUB_ACT_RSP_SUBTYPE(subtype) ((subtype == P2P_PAF_GON_RSP) || \ ++ ((subtype == P2P_PAF_GON_CONF) || \ ++ (subtype == P2P_PAF_INVITE_RSP) || \ ++ (subtype == P2P_PAF_PROVDIS_RSP))) ++#define IS_P2P_SOCIAL(ch) ((ch == SOCIAL_CHAN_1) || (ch == SOCIAL_CHAN_2) || (ch == SOCIAL_CHAN_3)) ++#define IS_P2P_SSID(ssid, len) (!memcmp(ssid, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN) && \ ++ (len == WL_P2P_WILDCARD_SSID_LEN)) ++#endif /* _wl_cfgp2p_h_ */ +diff --git a/drivers/net/wireless/ap6211/wl_iw.c b/drivers/net/wireless/ap6211/wl_iw.c +new file mode 100755 +index 0000000..8e067f4 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/wl_iw.c +@@ -0,0 +1,3622 @@ ++/* ++ * Linux Wireless Extensions support ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: wl_iw.c 352251 2012-08-22 06:08:38Z $ ++ */ ++ ++#if defined(USE_IW) ++#define LINUX_PORT ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++ ++typedef const struct si_pub si_t; ++#include ++ ++ ++#include ++ ++#include ++ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++#include ++#endif ++#if defined(SOFTAP) ++struct net_device *ap_net_dev = NULL; ++tsk_ctl_t ap_eth_ctl; /* apsta AP netdev waiter thread */ ++#endif /* SOFTAP */ ++ ++extern bool wl_iw_conn_status_str(uint32 event_type, uint32 status, ++ uint32 reason, char* stringBuf, uint buflen); ++ ++uint iw_msg_level = WL_ERROR_VAL; ++ ++#define MAX_WLIW_IOCTL_LEN 1024 ++ ++/* IOCTL swapping mode for Big Endian host with Little Endian dongle. Default to off */ ++#define htod32(i) i ++#define htod16(i) i ++#define dtoh32(i) i ++#define dtoh16(i) i ++#define htodchanspec(i) i ++#define dtohchanspec(i) i ++ ++extern struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev); ++extern int dhd_wait_pend8021x(struct net_device *dev); ++ ++#if WIRELESS_EXT < 19 ++#define IW_IOCTL_IDX(cmd) ((cmd) - SIOCIWFIRST) ++#define IW_EVENT_IDX(cmd) ((cmd) - IWEVFIRST) ++#endif /* WIRELESS_EXT < 19 */ ++ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) ++#define DAEMONIZE(a) daemonize(a); \ ++ allow_signal(SIGKILL); \ ++ allow_signal(SIGTERM); ++#else /* Linux 2.4 (w/o preemption patch) */ ++#define RAISE_RX_SOFTIRQ() \ ++ cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ) ++#define DAEMONIZE(a) daemonize(); \ ++ do { if (a) \ ++ strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a) + 1))); \ ++ } while (0); ++#endif /* LINUX_VERSION_CODE */ ++ ++#define ISCAN_STATE_IDLE 0 ++#define ISCAN_STATE_SCANING 1 ++ ++/* the buf lengh can be WLC_IOCTL_MAXLEN (8K) to reduce iteration */ ++#define WLC_IW_ISCAN_MAXLEN 2048 ++typedef struct iscan_buf { ++ struct iscan_buf * next; ++ char iscan_buf[WLC_IW_ISCAN_MAXLEN]; ++} iscan_buf_t; ++ ++typedef struct iscan_info { ++ struct net_device *dev; ++ struct timer_list timer; ++ uint32 timer_ms; ++ uint32 timer_on; ++ int iscan_state; ++ iscan_buf_t * list_hdr; ++ iscan_buf_t * list_cur; ++ ++ /* Thread to work on iscan */ ++ long sysioc_pid; ++ struct semaphore sysioc_sem; ++ struct completion sysioc_exited; ++ ++ ++ char ioctlbuf[WLC_IOCTL_SMLEN]; ++} iscan_info_t; ++iscan_info_t *g_iscan = NULL; ++static void wl_iw_timerfunc(ulong data); ++static void wl_iw_set_event_mask(struct net_device *dev); ++static int wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action); ++ ++/* priv_link becomes netdev->priv and is the link between netdev and wlif struct */ ++typedef struct priv_link { ++ wl_iw_t *wliw; ++} priv_link_t; ++ ++/* dev to priv_link */ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)) ++#define WL_DEV_LINK(dev) (priv_link_t*)(dev->priv) ++#else ++#define WL_DEV_LINK(dev) (priv_link_t*)netdev_priv(dev) ++#endif ++ ++/* dev to wl_iw_t */ ++#define IW_DEV_IF(dev) ((wl_iw_t*)(WL_DEV_LINK(dev))->wliw) ++ ++static void swap_key_from_BE( ++ wl_wsec_key_t *key ++) ++{ ++ key->index = htod32(key->index); ++ key->len = htod32(key->len); ++ key->algo = htod32(key->algo); ++ key->flags = htod32(key->flags); ++ key->rxiv.hi = htod32(key->rxiv.hi); ++ key->rxiv.lo = htod16(key->rxiv.lo); ++ key->iv_initialized = htod32(key->iv_initialized); ++} ++ ++static void swap_key_to_BE( ++ wl_wsec_key_t *key ++) ++{ ++ key->index = dtoh32(key->index); ++ key->len = dtoh32(key->len); ++ key->algo = dtoh32(key->algo); ++ key->flags = dtoh32(key->flags); ++ key->rxiv.hi = dtoh32(key->rxiv.hi); ++ key->rxiv.lo = dtoh16(key->rxiv.lo); ++ key->iv_initialized = dtoh32(key->iv_initialized); ++} ++ ++static int ++dev_wlc_ioctl( ++ struct net_device *dev, ++ int cmd, ++ void *arg, ++ int len ++) ++{ ++ struct ifreq ifr; ++ wl_ioctl_t ioc; ++ mm_segment_t fs; ++ int ret; ++ ++ memset(&ioc, 0, sizeof(ioc)); ++ ioc.cmd = cmd; ++ ioc.buf = arg; ++ ioc.len = len; ++ ++ strcpy(ifr.ifr_name, dev->name); ++ ifr.ifr_data = (caddr_t) &ioc; ++ ++#ifndef LINUX_HYBRID ++ /* Causes an extraneous 'up'. If specific ioctls are failing due ++ to device down, then we can investigate those ioctls. ++ */ ++ dev_open(dev); ++#endif ++ ++ fs = get_fs(); ++ set_fs(get_ds()); ++#if defined(WL_USE_NETDEV_OPS) ++ ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE); ++#else ++ ret = dev->do_ioctl(dev, &ifr, SIOCDEVPRIVATE); ++#endif ++ set_fs(fs); ++ ++ return ret; ++} ++ ++/* ++set named driver variable to int value and return error indication ++calling example: dev_wlc_intvar_set(dev, "arate", rate) ++*/ ++ ++static int ++dev_wlc_intvar_set( ++ struct net_device *dev, ++ char *name, ++ int val) ++{ ++ char buf[WLC_IOCTL_SMLEN]; ++ uint len; ++ ++ val = htod32(val); ++ len = bcm_mkiovar(name, (char *)(&val), sizeof(val), buf, sizeof(buf)); ++ ASSERT(len); ++ ++ return (dev_wlc_ioctl(dev, WLC_SET_VAR, buf, len)); ++} ++ ++static int ++dev_iw_iovar_setbuf( ++ struct net_device *dev, ++ char *iovar, ++ void *param, ++ int paramlen, ++ void *bufptr, ++ int buflen) ++{ ++ int iolen; ++ ++ iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen); ++ ASSERT(iolen); ++ BCM_REFERENCE(iolen); ++ ++ return (dev_wlc_ioctl(dev, WLC_SET_VAR, bufptr, iolen)); ++} ++ ++static int ++dev_iw_iovar_getbuf( ++ struct net_device *dev, ++ char *iovar, ++ void *param, ++ int paramlen, ++ void *bufptr, ++ int buflen) ++{ ++ int iolen; ++ ++ iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen); ++ ASSERT(iolen); ++ BCM_REFERENCE(iolen); ++ ++ return (dev_wlc_ioctl(dev, WLC_GET_VAR, bufptr, buflen)); ++} ++ ++#if WIRELESS_EXT > 17 ++static int ++dev_wlc_bufvar_set( ++ struct net_device *dev, ++ char *name, ++ char *buf, int len) ++{ ++ char *ioctlbuf; ++ uint buflen; ++ int error; ++ ++ ioctlbuf = kmalloc(MAX_WLIW_IOCTL_LEN, GFP_KERNEL); ++ if (!ioctlbuf) ++ return -ENOMEM; ++ ++ buflen = bcm_mkiovar(name, buf, len, ioctlbuf, MAX_WLIW_IOCTL_LEN); ++ ASSERT(buflen); ++ error = dev_wlc_ioctl(dev, WLC_SET_VAR, ioctlbuf, buflen); ++ ++ kfree(ioctlbuf); ++ return error; ++} ++#endif /* WIRELESS_EXT > 17 */ ++ ++/* ++get named driver variable to int value and return error indication ++calling example: dev_wlc_bufvar_get(dev, "arate", &rate) ++*/ ++ ++static int ++dev_wlc_bufvar_get( ++ struct net_device *dev, ++ char *name, ++ char *buf, int buflen) ++{ ++ char *ioctlbuf; ++ int error; ++ ++ uint len; ++ ++ ioctlbuf = kmalloc(MAX_WLIW_IOCTL_LEN, GFP_KERNEL); ++ if (!ioctlbuf) ++ return -ENOMEM; ++ len = bcm_mkiovar(name, NULL, 0, ioctlbuf, MAX_WLIW_IOCTL_LEN); ++ ASSERT(len); ++ BCM_REFERENCE(len); ++ error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)ioctlbuf, MAX_WLIW_IOCTL_LEN); ++ if (!error) ++ bcopy(ioctlbuf, buf, buflen); ++ ++ kfree(ioctlbuf); ++ return (error); ++} ++ ++/* ++get named driver variable to int value and return error indication ++calling example: dev_wlc_intvar_get(dev, "arate", &rate) ++*/ ++ ++static int ++dev_wlc_intvar_get( ++ struct net_device *dev, ++ char *name, ++ int *retval) ++{ ++ union { ++ char buf[WLC_IOCTL_SMLEN]; ++ int val; ++ } var; ++ int error; ++ ++ uint len; ++ uint data_null; ++ ++ len = bcm_mkiovar(name, (char *)(&data_null), 0, (char *)(&var), sizeof(var.buf)); ++ ASSERT(len); ++ error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)&var, len); ++ ++ *retval = dtoh32(var.val); ++ ++ return (error); ++} ++ ++/* Maintain backward compatibility */ ++#if WIRELESS_EXT < 13 ++struct iw_request_info ++{ ++ __u16 cmd; /* Wireless Extension command */ ++ __u16 flags; /* More to come ;-) */ ++}; ++ ++typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info, ++ void *wrqu, char *extra); ++#endif /* WIRELESS_EXT < 13 */ ++ ++#if WIRELESS_EXT > 12 ++static int ++wl_iw_set_leddc( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, ++ char *extra ++) ++{ ++ int dc = *(int *)extra; ++ int error; ++ ++ error = dev_wlc_intvar_set(dev, "leddc", dc); ++ return error; ++} ++ ++static int ++wl_iw_set_vlanmode( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, ++ char *extra ++) ++{ ++ int mode = *(int *)extra; ++ int error; ++ ++ mode = htod32(mode); ++ error = dev_wlc_intvar_set(dev, "vlan_mode", mode); ++ return error; ++} ++ ++static int ++wl_iw_set_pm( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, ++ char *extra ++) ++{ ++ int pm = *(int *)extra; ++ int error; ++ ++ pm = htod32(pm); ++ error = dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm)); ++ return error; ++} ++#endif /* WIRELESS_EXT > 12 */ ++ ++int ++wl_iw_send_priv_event( ++ struct net_device *dev, ++ char *flag ++) ++{ ++ union iwreq_data wrqu; ++ char extra[IW_CUSTOM_MAX + 1]; ++ int cmd; ++ ++ cmd = IWEVCUSTOM; ++ memset(&wrqu, 0, sizeof(wrqu)); ++ if (strlen(flag) > sizeof(extra)) ++ return -1; ++ ++ strcpy(extra, flag); ++ wrqu.data.length = strlen(extra); ++ wireless_send_event(dev, cmd, &wrqu, extra); ++ AP6211_DEBUG("Send IWEVCUSTOM Event as %s\n", extra); ++ ++ return 0; ++} ++ ++static int ++wl_iw_config_commit( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ void *zwrq, ++ char *extra ++) ++{ ++ wlc_ssid_t ssid; ++ int error; ++ struct sockaddr bssid; ++ ++ AP6211_DEBUG("%s: SIOCSIWCOMMIT\n", dev->name); ++ ++ if ((error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid)))) ++ return error; ++ ++ ssid.SSID_len = dtoh32(ssid.SSID_len); ++ ++ if (!ssid.SSID_len) ++ return 0; ++ ++ bzero(&bssid, sizeof(struct sockaddr)); ++ if ((error = dev_wlc_ioctl(dev, WLC_REASSOC, &bssid, ETHER_ADDR_LEN))) { ++ AP6211_ERR("%s: WLC_REASSOC failed (%d)\n", __FUNCTION__, error); ++ return error; ++ } ++ ++ return 0; ++} ++ ++static int ++wl_iw_get_name( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *cwrq, ++ char *extra ++) ++{ ++ int phytype, err; ++ uint band[3]; ++ char cap[5]; ++ ++ AP6211_DEBUG("%s: SIOCGIWNAME\n", dev->name); ++ ++ cap[0] = 0; ++ if ((err = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &phytype, sizeof(phytype))) < 0) ++ goto done; ++ if ((err = dev_wlc_ioctl(dev, WLC_GET_BANDLIST, band, sizeof(band))) < 0) ++ goto done; ++ ++ band[0] = dtoh32(band[0]); ++ switch (phytype) { ++ case WLC_PHY_TYPE_A: ++ strcpy(cap, "a"); ++ break; ++ case WLC_PHY_TYPE_B: ++ strcpy(cap, "b"); ++ break; ++ case WLC_PHY_TYPE_LP: ++ case WLC_PHY_TYPE_G: ++ if (band[0] >= 2) ++ strcpy(cap, "abg"); ++ else ++ strcpy(cap, "bg"); ++ break; ++ case WLC_PHY_TYPE_N: ++ if (band[0] >= 2) ++ strcpy(cap, "abgn"); ++ else ++ strcpy(cap, "bgn"); ++ break; ++ } ++done: ++ snprintf(cwrq->name, IFNAMSIZ, "IEEE 802.11%s", cap); ++ return 0; ++} ++ ++static int ++wl_iw_set_freq( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_freq *fwrq, ++ char *extra ++) ++{ ++ int error, chan; ++ uint sf = 0; ++ ++ AP6211_DEBUG("%s: SIOCSIWFREQ\n", dev->name); ++ ++ /* Setting by channel number */ ++ if (fwrq->e == 0 && fwrq->m < MAXCHANNEL) { ++ chan = fwrq->m; ++ } ++ ++ /* Setting by frequency */ ++ else { ++ /* Convert to MHz as best we can */ ++ if (fwrq->e >= 6) { ++ fwrq->e -= 6; ++ while (fwrq->e--) ++ fwrq->m *= 10; ++ } else if (fwrq->e < 6) { ++ while (fwrq->e++ < 6) ++ fwrq->m /= 10; ++ } ++ /* handle 4.9GHz frequencies as Japan 4 GHz based channelization */ ++ if (fwrq->m > 4000 && fwrq->m < 5000) ++ sf = WF_CHAN_FACTOR_4_G; /* start factor for 4 GHz */ ++ ++ chan = wf_mhz2channel(fwrq->m, sf); ++ } ++ chan = htod32(chan); ++ if ((error = dev_wlc_ioctl(dev, WLC_SET_CHANNEL, &chan, sizeof(chan)))) ++ return error; ++ ++ /* -EINPROGRESS: Call commit handler */ ++ return -EINPROGRESS; ++} ++ ++static int ++wl_iw_get_freq( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_freq *fwrq, ++ char *extra ++) ++{ ++ channel_info_t ci; ++ int error; ++ ++ AP6211_DEBUG("%s: SIOCGIWFREQ\n", dev->name); ++ ++ if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci)))) ++ return error; ++ ++ /* Return radio channel in channel form */ ++ fwrq->m = dtoh32(ci.hw_channel); ++ fwrq->e = dtoh32(0); ++ return 0; ++} ++ ++static int ++wl_iw_set_mode( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ __u32 *uwrq, ++ char *extra ++) ++{ ++ int infra = 0, ap = 0, error = 0; ++ ++ AP6211_DEBUG("%s: SIOCSIWMODE\n", dev->name); ++ ++ switch (*uwrq) { ++ case IW_MODE_MASTER: ++ infra = ap = 1; ++ break; ++ case IW_MODE_ADHOC: ++ case IW_MODE_AUTO: ++ break; ++ case IW_MODE_INFRA: ++ infra = 1; ++ break; ++ default: ++ return -EINVAL; ++ } ++ infra = htod32(infra); ++ ap = htod32(ap); ++ ++ if ((error = dev_wlc_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(infra))) || ++ (error = dev_wlc_ioctl(dev, WLC_SET_AP, &ap, sizeof(ap)))) ++ return error; ++ ++ /* -EINPROGRESS: Call commit handler */ ++ return -EINPROGRESS; ++} ++ ++static int ++wl_iw_get_mode( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ __u32 *uwrq, ++ char *extra ++) ++{ ++ int error, infra = 0, ap = 0; ++ ++ AP6211_DEBUG("%s: SIOCGIWMODE\n", dev->name); ++ ++ if ((error = dev_wlc_ioctl(dev, WLC_GET_INFRA, &infra, sizeof(infra))) || ++ (error = dev_wlc_ioctl(dev, WLC_GET_AP, &ap, sizeof(ap)))) ++ return error; ++ ++ infra = dtoh32(infra); ++ ap = dtoh32(ap); ++ *uwrq = infra ? ap ? IW_MODE_MASTER : IW_MODE_INFRA : IW_MODE_ADHOC; ++ ++ return 0; ++} ++ ++static int ++wl_iw_get_range( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *dwrq, ++ char *extra ++) ++{ ++ struct iw_range *range = (struct iw_range *) extra; ++ static int channels[MAXCHANNEL+1]; ++ wl_uint32_list_t *list = (wl_uint32_list_t *) channels; ++ wl_rateset_t rateset; ++ int error, i, k; ++ uint sf, ch; ++ ++ int phytype; ++ int bw_cap = 0, sgi_tx = 0, nmode = 0; ++ channel_info_t ci; ++ uint8 nrate_list2copy = 0; ++ uint16 nrate_list[4][8] = { {13, 26, 39, 52, 78, 104, 117, 130}, ++ {14, 29, 43, 58, 87, 116, 130, 144}, ++ {27, 54, 81, 108, 162, 216, 243, 270}, ++ {30, 60, 90, 120, 180, 240, 270, 300}}; ++ ++ AP6211_DEBUG("%s: SIOCGIWRANGE\n", dev->name); ++ ++ if (!extra) ++ return -EINVAL; ++ ++ dwrq->length = sizeof(struct iw_range); ++ memset(range, 0, sizeof(*range)); ++ ++ /* We don't use nwids */ ++ range->min_nwid = range->max_nwid = 0; ++ ++ /* Set available channels/frequencies */ ++ list->count = htod32(MAXCHANNEL); ++ if ((error = dev_wlc_ioctl(dev, WLC_GET_VALID_CHANNELS, channels, sizeof(channels)))) ++ return error; ++ for (i = 0; i < dtoh32(list->count) && i < IW_MAX_FREQUENCIES; i++) { ++ range->freq[i].i = dtoh32(list->element[i]); ++ ++ ch = dtoh32(list->element[i]); ++ if (ch <= CH_MAX_2G_CHANNEL) ++ sf = WF_CHAN_FACTOR_2_4_G; ++ else ++ sf = WF_CHAN_FACTOR_5_G; ++ ++ range->freq[i].m = wf_channel2mhz(ch, sf); ++ range->freq[i].e = 6; ++ } ++ range->num_frequency = range->num_channels = i; ++ ++ /* Link quality (use NDIS cutoffs) */ ++ range->max_qual.qual = 5; ++ /* Signal level (use RSSI) */ ++ range->max_qual.level = 0x100 - 200; /* -200 dBm */ ++ /* Noise level (use noise) */ ++ range->max_qual.noise = 0x100 - 200; /* -200 dBm */ ++ /* Signal level threshold range (?) */ ++ range->sensitivity = 65535; ++ ++#if WIRELESS_EXT > 11 ++ /* Link quality (use NDIS cutoffs) */ ++ range->avg_qual.qual = 3; ++ /* Signal level (use RSSI) */ ++ range->avg_qual.level = 0x100 + WL_IW_RSSI_GOOD; ++ /* Noise level (use noise) */ ++ range->avg_qual.noise = 0x100 - 75; /* -75 dBm */ ++#endif /* WIRELESS_EXT > 11 */ ++ ++ /* Set available bitrates */ ++ if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset)))) ++ return error; ++ rateset.count = dtoh32(rateset.count); ++ range->num_bitrates = rateset.count; ++ for (i = 0; i < rateset.count && i < IW_MAX_BITRATES; i++) ++ range->bitrate[i] = (rateset.rates[i] & 0x7f) * 500000; /* convert to bps */ ++ dev_wlc_intvar_get(dev, "nmode", &nmode); ++ if ((error = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &phytype, sizeof(phytype)))) ++ return error; ++ ++ if (nmode == 1 && ((phytype == WLC_PHY_TYPE_SSN) || (phytype == WLC_PHY_TYPE_LCN) || ++ (phytype == WLC_PHY_TYPE_LCN40))) { ++ dev_wlc_intvar_get(dev, "mimo_bw_cap", &bw_cap); ++ dev_wlc_intvar_get(dev, "sgi_tx", &sgi_tx); ++ dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(channel_info_t)); ++ ci.hw_channel = dtoh32(ci.hw_channel); ++ ++ if (bw_cap == 0 || ++ (bw_cap == 2 && ci.hw_channel <= 14)) { ++ if (sgi_tx == 0) ++ nrate_list2copy = 0; ++ else ++ nrate_list2copy = 1; ++ } ++ if (bw_cap == 1 || ++ (bw_cap == 2 && ci.hw_channel >= 36)) { ++ if (sgi_tx == 0) ++ nrate_list2copy = 2; ++ else ++ nrate_list2copy = 3; ++ } ++ range->num_bitrates += 8; ++ for (k = 0; i < range->num_bitrates; k++, i++) { ++ /* convert to bps */ ++ range->bitrate[i] = (nrate_list[nrate_list2copy][k]) * 500000; ++ } ++ } ++ ++ /* Set an indication of the max TCP throughput ++ * in bit/s that we can expect using this interface. ++ * May be use for QoS stuff... Jean II ++ */ ++ if ((error = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &i, sizeof(i)))) ++ return error; ++ i = dtoh32(i); ++ if (i == WLC_PHY_TYPE_A) ++ range->throughput = 24000000; /* 24 Mbits/s */ ++ else ++ range->throughput = 1500000; /* 1.5 Mbits/s */ ++ ++ /* RTS and fragmentation thresholds */ ++ range->min_rts = 0; ++ range->max_rts = 2347; ++ range->min_frag = 256; ++ range->max_frag = 2346; ++ ++ range->max_encoding_tokens = DOT11_MAX_DEFAULT_KEYS; ++ range->num_encoding_sizes = 4; ++ range->encoding_size[0] = WEP1_KEY_SIZE; ++ range->encoding_size[1] = WEP128_KEY_SIZE; ++#if WIRELESS_EXT > 17 ++ range->encoding_size[2] = TKIP_KEY_SIZE; ++#else ++ range->encoding_size[2] = 0; ++#endif ++ range->encoding_size[3] = AES_KEY_SIZE; ++ ++ /* Do not support power micro-management */ ++ range->min_pmp = 0; ++ range->max_pmp = 0; ++ range->min_pmt = 0; ++ range->max_pmt = 0; ++ range->pmp_flags = 0; ++ range->pm_capa = 0; ++ ++ /* Transmit Power - values are in mW */ ++ range->num_txpower = 2; ++ range->txpower[0] = 1; ++ range->txpower[1] = 255; ++ range->txpower_capa = IW_TXPOW_MWATT; ++ ++#if WIRELESS_EXT > 10 ++ range->we_version_compiled = WIRELESS_EXT; ++ range->we_version_source = 19; ++ ++ /* Only support retry limits */ ++ range->retry_capa = IW_RETRY_LIMIT; ++ range->retry_flags = IW_RETRY_LIMIT; ++ range->r_time_flags = 0; ++ /* SRL and LRL limits */ ++ range->min_retry = 1; ++ range->max_retry = 255; ++ /* Retry lifetime limits unsupported */ ++ range->min_r_time = 0; ++ range->max_r_time = 0; ++#endif /* WIRELESS_EXT > 10 */ ++ ++#if WIRELESS_EXT > 17 ++ range->enc_capa = IW_ENC_CAPA_WPA; ++ range->enc_capa |= IW_ENC_CAPA_CIPHER_TKIP; ++ range->enc_capa |= IW_ENC_CAPA_CIPHER_CCMP; ++ range->enc_capa |= IW_ENC_CAPA_WPA2; ++#if (defined(BCMSUP_PSK) && defined(WLFBT)) ++ /* Tell the host (e.g. wpa_supplicant) to let us do the handshake */ ++ range->enc_capa |= IW_ENC_CAPA_4WAY_HANDSHAKE; ++#endif /* (defined (BCMSUP_PSK) && defined(WLFBT)) */ ++ ++ /* Event capability (kernel) */ ++ IW_EVENT_CAPA_SET_KERNEL(range->event_capa); ++ /* Event capability (driver) */ ++ IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); ++ IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); ++ IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP); ++ IW_EVENT_CAPA_SET(range->event_capa, IWEVMICHAELMICFAILURE); ++ IW_EVENT_CAPA_SET(range->event_capa, IWEVASSOCREQIE); ++ IW_EVENT_CAPA_SET(range->event_capa, IWEVASSOCRESPIE); ++ IW_EVENT_CAPA_SET(range->event_capa, IWEVPMKIDCAND); ++ ++#if WIRELESS_EXT >= 22 && defined(IW_SCAN_CAPA_ESSID) ++ /* FC7 wireless.h defines EXT 22 but doesn't define scan_capa bits */ ++ range->scan_capa = IW_SCAN_CAPA_ESSID; ++#endif ++#endif /* WIRELESS_EXT > 17 */ ++ ++ return 0; ++} ++ ++static int ++rssi_to_qual(int rssi) ++{ ++ if (rssi <= WL_IW_RSSI_NO_SIGNAL) ++ return 0; ++ else if (rssi <= WL_IW_RSSI_VERY_LOW) ++ return 1; ++ else if (rssi <= WL_IW_RSSI_LOW) ++ return 2; ++ else if (rssi <= WL_IW_RSSI_GOOD) ++ return 3; ++ else if (rssi <= WL_IW_RSSI_VERY_GOOD) ++ return 4; ++ else ++ return 5; ++} ++ ++static int ++wl_iw_set_spy( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *dwrq, ++ char *extra ++) ++{ ++ wl_iw_t *iw = IW_DEV_IF(dev); ++ struct sockaddr *addr = (struct sockaddr *) extra; ++ int i; ++ ++ AP6211_DEBUG("%s: SIOCSIWSPY\n", dev->name); ++ ++ if (!extra) ++ return -EINVAL; ++ ++ iw->spy_num = MIN(ARRAYSIZE(iw->spy_addr), dwrq->length); ++ for (i = 0; i < iw->spy_num; i++) ++ memcpy(&iw->spy_addr[i], addr[i].sa_data, ETHER_ADDR_LEN); ++ memset(iw->spy_qual, 0, sizeof(iw->spy_qual)); ++ ++ return 0; ++} ++ ++static int ++wl_iw_get_spy( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *dwrq, ++ char *extra ++) ++{ ++ wl_iw_t *iw = IW_DEV_IF(dev); ++ struct sockaddr *addr = (struct sockaddr *) extra; ++ struct iw_quality *qual = (struct iw_quality *) &addr[iw->spy_num]; ++ int i; ++ ++ AP6211_DEBUG("%s: SIOCGIWSPY\n", dev->name); ++ ++ if (!extra) ++ return -EINVAL; ++ ++ dwrq->length = iw->spy_num; ++ for (i = 0; i < iw->spy_num; i++) { ++ memcpy(addr[i].sa_data, &iw->spy_addr[i], ETHER_ADDR_LEN); ++ addr[i].sa_family = AF_UNIX; ++ memcpy(&qual[i], &iw->spy_qual[i], sizeof(struct iw_quality)); ++ iw->spy_qual[i].updated = 0; ++ } ++ ++ return 0; ++} ++ ++static int ++wl_iw_set_wap( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct sockaddr *awrq, ++ char *extra ++) ++{ ++ int error = -EINVAL; ++ ++ AP6211_DEBUG("%s: SIOCSIWAP\n", dev->name); ++ ++ if (awrq->sa_family != ARPHRD_ETHER) { ++ AP6211_ERR("%s: Invalid Header...sa_family\n", __FUNCTION__); ++ return -EINVAL; ++ } ++ ++ /* Ignore "auto" or "off" */ ++ if (ETHER_ISBCAST(awrq->sa_data) || ETHER_ISNULLADDR(awrq->sa_data)) { ++ scb_val_t scbval; ++ bzero(&scbval, sizeof(scb_val_t)); ++ if ((error = dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)))) { ++ AP6211_ERR("%s: WLC_DISASSOC failed (%d).\n", __FUNCTION__, error); ++ } ++ return 0; ++ } ++ /* WL_ASSOC(("Assoc to %s\n", bcm_ether_ntoa((struct ether_addr *)&(awrq->sa_data), ++ * eabuf))); ++ */ ++ /* Reassociate to the specified AP */ ++ if ((error = dev_wlc_ioctl(dev, WLC_REASSOC, awrq->sa_data, ETHER_ADDR_LEN))) { ++ AP6211_ERR("%s: WLC_REASSOC failed (%d).\n", __FUNCTION__, error); ++ return error; ++ } ++ ++ return 0; ++} ++ ++static int ++wl_iw_get_wap( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct sockaddr *awrq, ++ char *extra ++) ++{ ++ AP6211_DEBUG("%s: SIOCGIWAP\n", dev->name); ++ ++ awrq->sa_family = ARPHRD_ETHER; ++ memset(awrq->sa_data, 0, ETHER_ADDR_LEN); ++ ++ /* Ignore error (may be down or disassociated) */ ++ (void) dev_wlc_ioctl(dev, WLC_GET_BSSID, awrq->sa_data, ETHER_ADDR_LEN); ++ ++ return 0; ++} ++ ++#if WIRELESS_EXT > 17 ++static int ++wl_iw_mlme( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct sockaddr *awrq, ++ char *extra ++) ++{ ++ struct iw_mlme *mlme; ++ scb_val_t scbval; ++ int error = -EINVAL; ++ ++ AP6211_DEBUG("%s: SIOCSIWMLME\n", dev->name); ++ ++ mlme = (struct iw_mlme *)extra; ++ if (mlme == NULL) { ++ AP6211_ERR("Invalid ioctl data.\n"); ++ return error; ++ } ++ ++ scbval.val = mlme->reason_code; ++ bcopy(&mlme->addr.sa_data, &scbval.ea, ETHER_ADDR_LEN); ++ ++ if (mlme->cmd == IW_MLME_DISASSOC) { ++ scbval.val = htod32(scbval.val); ++ error = dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)); ++ } ++ else if (mlme->cmd == IW_MLME_DEAUTH) { ++ scbval.val = htod32(scbval.val); ++ error = dev_wlc_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval, ++ sizeof(scb_val_t)); ++ } ++ else { ++ AP6211_ERR("%s: Invalid ioctl data.\n", __FUNCTION__); ++ return error; ++ } ++ ++ return error; ++} ++#endif /* WIRELESS_EXT > 17 */ ++ ++static int ++wl_iw_get_aplist( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *dwrq, ++ char *extra ++) ++{ ++ wl_scan_results_t *list; ++ struct sockaddr *addr = (struct sockaddr *) extra; ++ struct iw_quality qual[IW_MAX_AP]; ++ wl_bss_info_t *bi = NULL; ++ int error, i; ++ uint buflen = dwrq->length; ++ ++ AP6211_DEBUG("%s: SIOCGIWAPLIST\n", dev->name); ++ ++ if (!extra) ++ return -EINVAL; ++ ++ /* Get scan results (too large to put on the stack) */ ++ list = kmalloc(buflen, GFP_KERNEL); ++ if (!list) ++ return -ENOMEM; ++ memset(list, 0, buflen); ++ list->buflen = htod32(buflen); ++ if ((error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, buflen))) { ++ AP6211_ERR("%d: Scan results error %d\n", __LINE__, error); ++ kfree(list); ++ return error; ++ } ++ list->buflen = dtoh32(list->buflen); ++ list->version = dtoh32(list->version); ++ list->count = dtoh32(list->count); ++ ASSERT(list->version == WL_BSS_INFO_VERSION); ++ ++ for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) { ++ bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; ++ ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + ++ buflen)); ++ ++ /* Infrastructure only */ ++ if (!(dtoh16(bi->capability) & DOT11_CAP_ESS)) ++ continue; ++ ++ /* BSSID */ ++ memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETHER_ADDR_LEN); ++ addr[dwrq->length].sa_family = ARPHRD_ETHER; ++ qual[dwrq->length].qual = rssi_to_qual(dtoh16(bi->RSSI)); ++ qual[dwrq->length].level = 0x100 + dtoh16(bi->RSSI); ++ qual[dwrq->length].noise = 0x100 + bi->phy_noise; ++ ++ /* Updated qual, level, and noise */ ++#if WIRELESS_EXT > 18 ++ qual[dwrq->length].updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; ++#else ++ qual[dwrq->length].updated = 7; ++#endif /* WIRELESS_EXT > 18 */ ++ ++ dwrq->length++; ++ } ++ ++ kfree(list); ++ ++ if (dwrq->length) { ++ memcpy(&addr[dwrq->length], qual, sizeof(struct iw_quality) * dwrq->length); ++ /* Provided qual */ ++ dwrq->flags = 1; ++ } ++ ++ return 0; ++} ++ ++static int ++wl_iw_iscan_get_aplist( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *dwrq, ++ char *extra ++) ++{ ++ wl_scan_results_t *list; ++ iscan_buf_t * buf; ++ iscan_info_t *iscan = g_iscan; ++ ++ struct sockaddr *addr = (struct sockaddr *) extra; ++ struct iw_quality qual[IW_MAX_AP]; ++ wl_bss_info_t *bi = NULL; ++ int i; ++ ++ AP6211_DEBUG("%s: SIOCGIWAPLIST\n", dev->name); ++ ++ if (!extra) ++ return -EINVAL; ++ ++ if ((!iscan) || (iscan->sysioc_pid < 0)) { ++ return wl_iw_get_aplist(dev, info, dwrq, extra); ++ } ++ ++ buf = iscan->list_hdr; ++ /* Get scan results (too large to put on the stack) */ ++ while (buf) { ++ list = &((wl_iscan_results_t*)buf->iscan_buf)->results; ++ ASSERT(list->version == WL_BSS_INFO_VERSION); ++ ++ bi = NULL; ++ for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) { ++ bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; ++ ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + ++ WLC_IW_ISCAN_MAXLEN)); ++ ++ /* Infrastructure only */ ++ if (!(dtoh16(bi->capability) & DOT11_CAP_ESS)) ++ continue; ++ ++ /* BSSID */ ++ memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETHER_ADDR_LEN); ++ addr[dwrq->length].sa_family = ARPHRD_ETHER; ++ qual[dwrq->length].qual = rssi_to_qual(dtoh16(bi->RSSI)); ++ qual[dwrq->length].level = 0x100 + dtoh16(bi->RSSI); ++ qual[dwrq->length].noise = 0x100 + bi->phy_noise; ++ ++ /* Updated qual, level, and noise */ ++#if WIRELESS_EXT > 18 ++ qual[dwrq->length].updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; ++#else ++ qual[dwrq->length].updated = 7; ++#endif /* WIRELESS_EXT > 18 */ ++ ++ dwrq->length++; ++ } ++ buf = buf->next; ++ } ++ if (dwrq->length) { ++ memcpy(&addr[dwrq->length], qual, sizeof(struct iw_quality) * dwrq->length); ++ /* Provided qual */ ++ dwrq->flags = 1; ++ } ++ ++ return 0; ++} ++ ++#if WIRELESS_EXT > 13 ++static int ++wl_iw_set_scan( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, ++ char *extra ++) ++{ ++ wlc_ssid_t ssid; ++ ++ AP6211_DEBUG("%s: SIOCSIWSCAN\n", dev->name); ++ ++ /* default Broadcast scan */ ++ memset(&ssid, 0, sizeof(ssid)); ++ ++#if WIRELESS_EXT > 17 ++ /* check for given essid */ ++ if (wrqu->data.length == sizeof(struct iw_scan_req)) { ++ if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { ++ struct iw_scan_req *req = (struct iw_scan_req *)extra; ++ ssid.SSID_len = MIN(sizeof(ssid.SSID), req->essid_len); ++ memcpy(ssid.SSID, req->essid, ssid.SSID_len); ++ ssid.SSID_len = htod32(ssid.SSID_len); ++ } ++ } ++#endif ++ /* Ignore error (most likely scan in progress) */ ++ (void) dev_wlc_ioctl(dev, WLC_SCAN, &ssid, sizeof(ssid)); ++ ++ return 0; ++} ++ ++static int ++wl_iw_iscan_set_scan( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, ++ char *extra ++) ++{ ++ wlc_ssid_t ssid; ++ iscan_info_t *iscan = g_iscan; ++ ++ AP6211_DEBUG("%s: SIOCSIWSCAN\n", dev->name); ++ ++ /* use backup if our thread is not successful */ ++ if ((!iscan) || (iscan->sysioc_pid < 0)) { ++ return wl_iw_set_scan(dev, info, wrqu, extra); ++ } ++ if (iscan->iscan_state == ISCAN_STATE_SCANING) { ++ return 0; ++ } ++ ++ /* default Broadcast scan */ ++ memset(&ssid, 0, sizeof(ssid)); ++ ++#if WIRELESS_EXT > 17 ++ /* check for given essid */ ++ if (wrqu->data.length == sizeof(struct iw_scan_req)) { ++ if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { ++ struct iw_scan_req *req = (struct iw_scan_req *)extra; ++ ssid.SSID_len = MIN(sizeof(ssid.SSID), req->essid_len); ++ memcpy(ssid.SSID, req->essid, ssid.SSID_len); ++ ssid.SSID_len = htod32(ssid.SSID_len); ++ } ++ } ++#endif ++ ++ iscan->list_cur = iscan->list_hdr; ++ iscan->iscan_state = ISCAN_STATE_SCANING; ++ ++ ++ wl_iw_set_event_mask(dev); ++ wl_iw_iscan(iscan, &ssid, WL_SCAN_ACTION_START); ++ ++ iscan->timer.expires = jiffies + msecs_to_jiffies(iscan->timer_ms); ++ add_timer(&iscan->timer); ++ iscan->timer_on = 1; ++ ++ return 0; ++} ++ ++#if WIRELESS_EXT > 17 ++static bool ++ie_is_wpa_ie(uint8 **wpaie, uint8 **tlvs, int *tlvs_len) ++{ ++/* Is this body of this tlvs entry a WPA entry? If */ ++/* not update the tlvs buffer pointer/length */ ++ uint8 *ie = *wpaie; ++ ++ /* If the contents match the WPA_OUI and type=1 */ ++ if ((ie[1] >= 6) && ++ !bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x01"), 4)) { ++ return TRUE; ++ } ++ ++ /* point to the next ie */ ++ ie += ie[1] + 2; ++ /* calculate the length of the rest of the buffer */ ++ *tlvs_len -= (int)(ie - *tlvs); ++ /* update the pointer to the start of the buffer */ ++ *tlvs = ie; ++ return FALSE; ++} ++ ++static bool ++ie_is_wps_ie(uint8 **wpsie, uint8 **tlvs, int *tlvs_len) ++{ ++/* Is this body of this tlvs entry a WPS entry? If */ ++/* not update the tlvs buffer pointer/length */ ++ uint8 *ie = *wpsie; ++ ++ /* If the contents match the WPA_OUI and type=4 */ ++ if ((ie[1] >= 4) && ++ !bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x04"), 4)) { ++ return TRUE; ++ } ++ ++ /* point to the next ie */ ++ ie += ie[1] + 2; ++ /* calculate the length of the rest of the buffer */ ++ *tlvs_len -= (int)(ie - *tlvs); ++ /* update the pointer to the start of the buffer */ ++ *tlvs = ie; ++ return FALSE; ++} ++#endif /* WIRELESS_EXT > 17 */ ++ ++ ++static int ++wl_iw_handle_scanresults_ies(char **event_p, char *end, ++ struct iw_request_info *info, wl_bss_info_t *bi) ++{ ++#if WIRELESS_EXT > 17 ++ struct iw_event iwe; ++ char *event; ++ ++ event = *event_p; ++ if (bi->ie_length) { ++ /* look for wpa/rsn ies in the ie list... */ ++ bcm_tlv_t *ie; ++ uint8 *ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t); ++ int ptr_len = bi->ie_length; ++ ++ if ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_RSN_ID))) { ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.length = ie->len + 2; ++ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie); ++ } ++ ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t); ++ ++#if defined(WLFBT) ++ if ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_MDIE_ID))) { ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.length = ie->len + 2; ++ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie); ++ } ++ ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t); ++#endif /* WLFBT */ ++ ++ while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) { ++ /* look for WPS IE */ ++ if (ie_is_wps_ie(((uint8 **)&ie), &ptr, &ptr_len)) { ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.length = ie->len + 2; ++ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie); ++ break; ++ } ++ } ++ ++ ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t); ++ ptr_len = bi->ie_length; ++ while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) { ++ if (ie_is_wpa_ie(((uint8 **)&ie), &ptr, &ptr_len)) { ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.length = ie->len + 2; ++ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie); ++ break; ++ } ++ } ++ ++ *event_p = event; ++ } ++ ++#endif /* WIRELESS_EXT > 17 */ ++ return 0; ++} ++static int ++wl_iw_get_scan( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *dwrq, ++ char *extra ++) ++{ ++ channel_info_t ci; ++ wl_scan_results_t *list; ++ struct iw_event iwe; ++ wl_bss_info_t *bi = NULL; ++ int error, i, j; ++ char *event = extra, *end = extra + dwrq->length, *value; ++ uint buflen = dwrq->length; ++ ++ AP6211_DEBUG("%s: SIOCGIWSCAN\n", dev->name); ++ ++ if (!extra) ++ return -EINVAL; ++ ++ /* Check for scan in progress */ ++ if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci)))) ++ return error; ++ ci.scan_channel = dtoh32(ci.scan_channel); ++ if (ci.scan_channel) ++ return -EAGAIN; ++ ++ /* Get scan results (too large to put on the stack) */ ++ list = kmalloc(buflen, GFP_KERNEL); ++ if (!list) ++ return -ENOMEM; ++ memset(list, 0, buflen); ++ list->buflen = htod32(buflen); ++ if ((error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, buflen))) { ++ kfree(list); ++ return error; ++ } ++ list->buflen = dtoh32(list->buflen); ++ list->version = dtoh32(list->version); ++ list->count = dtoh32(list->count); ++ ++ ASSERT(list->version == WL_BSS_INFO_VERSION); ++ ++ for (i = 0; i < list->count && i < IW_MAX_AP; i++) { ++ bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; ++ ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + ++ buflen)); ++ ++ /* First entry must be the BSSID */ ++ iwe.cmd = SIOCGIWAP; ++ iwe.u.ap_addr.sa_family = ARPHRD_ETHER; ++ memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN); ++ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN); ++ ++ /* SSID */ ++ iwe.u.data.length = dtoh32(bi->SSID_len); ++ iwe.cmd = SIOCGIWESSID; ++ iwe.u.data.flags = 1; ++ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID); ++ ++ /* Mode */ ++ if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) { ++ iwe.cmd = SIOCGIWMODE; ++ if (dtoh16(bi->capability) & DOT11_CAP_ESS) ++ iwe.u.mode = IW_MODE_INFRA; ++ else ++ iwe.u.mode = IW_MODE_ADHOC; ++ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_UINT_LEN); ++ } ++ ++ /* Channel */ ++ iwe.cmd = SIOCGIWFREQ; ++ iwe.u.freq.m = wf_channel2mhz(CHSPEC_CHANNEL(bi->chanspec), ++ CHSPEC_CHANNEL(bi->chanspec) <= CH_MAX_2G_CHANNEL ? ++ WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G); ++ iwe.u.freq.e = 6; ++ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN); ++ ++ /* Channel quality */ ++ iwe.cmd = IWEVQUAL; ++ iwe.u.qual.qual = rssi_to_qual(dtoh16(bi->RSSI)); ++ iwe.u.qual.level = 0x100 + dtoh16(bi->RSSI); ++ iwe.u.qual.noise = 0x100 + bi->phy_noise; ++ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN); ++ ++ /* WPA, WPA2, WPS, WAPI IEs */ ++ wl_iw_handle_scanresults_ies(&event, end, info, bi); ++ ++ /* Encryption */ ++ iwe.cmd = SIOCGIWENCODE; ++ if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY) ++ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; ++ else ++ iwe.u.data.flags = IW_ENCODE_DISABLED; ++ iwe.u.data.length = 0; ++ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event); ++ ++ /* Rates */ ++ if (bi->rateset.count) { ++ value = event + IW_EV_LCP_LEN; ++ iwe.cmd = SIOCGIWRATE; ++ /* Those two flags are ignored... */ ++ iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; ++ for (j = 0; j < bi->rateset.count && j < IW_MAX_BITRATES; j++) { ++ iwe.u.bitrate.value = (bi->rateset.rates[j] & 0x7f) * 500000; ++ value = IWE_STREAM_ADD_VALUE(info, event, value, end, &iwe, ++ IW_EV_PARAM_LEN); ++ } ++ event = value; ++ } ++ } ++ ++ kfree(list); ++ ++ dwrq->length = event - extra; ++ dwrq->flags = 0; /* todo */ ++ ++ return 0; ++} ++ ++static int ++wl_iw_iscan_get_scan( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *dwrq, ++ char *extra ++) ++{ ++ wl_scan_results_t *list; ++ struct iw_event iwe; ++ wl_bss_info_t *bi = NULL; ++ int ii, j; ++ int apcnt; ++ char *event = extra, *end = extra + dwrq->length, *value; ++ iscan_info_t *iscan = g_iscan; ++ iscan_buf_t * p_buf; ++ ++ AP6211_DEBUG("%s: SIOCGIWSCAN\n", dev->name); ++ ++ if (!extra) ++ return -EINVAL; ++ ++ /* use backup if our thread is not successful */ ++ if ((!iscan) || (iscan->sysioc_pid < 0)) { ++ return wl_iw_get_scan(dev, info, dwrq, extra); ++ } ++ ++ /* Check for scan in progress */ ++ if (iscan->iscan_state == ISCAN_STATE_SCANING) ++ return -EAGAIN; ++ ++ apcnt = 0; ++ p_buf = iscan->list_hdr; ++ /* Get scan results */ ++ while (p_buf != iscan->list_cur) { ++ list = &((wl_iscan_results_t*)p_buf->iscan_buf)->results; ++ ++ if (list->version != WL_BSS_INFO_VERSION) { ++ AP6211_ERR("list->version %d != WL_BSS_INFO_VERSION\n", list->version); ++ } ++ ++ bi = NULL; ++ for (ii = 0; ii < list->count && apcnt < IW_MAX_AP; apcnt++, ii++) { ++ bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; ++ ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + ++ WLC_IW_ISCAN_MAXLEN)); ++ ++ /* overflow check cover fields before wpa IEs */ ++ if (event + ETHER_ADDR_LEN + bi->SSID_len + IW_EV_UINT_LEN + IW_EV_FREQ_LEN + ++ IW_EV_QUAL_LEN >= end) ++ return -E2BIG; ++ /* First entry must be the BSSID */ ++ iwe.cmd = SIOCGIWAP; ++ iwe.u.ap_addr.sa_family = ARPHRD_ETHER; ++ memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN); ++ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN); ++ ++ /* SSID */ ++ iwe.u.data.length = dtoh32(bi->SSID_len); ++ iwe.cmd = SIOCGIWESSID; ++ iwe.u.data.flags = 1; ++ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID); ++ ++ /* Mode */ ++ if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) { ++ iwe.cmd = SIOCGIWMODE; ++ if (dtoh16(bi->capability) & DOT11_CAP_ESS) ++ iwe.u.mode = IW_MODE_INFRA; ++ else ++ iwe.u.mode = IW_MODE_ADHOC; ++ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_UINT_LEN); ++ } ++ ++ /* Channel */ ++ iwe.cmd = SIOCGIWFREQ; ++ iwe.u.freq.m = wf_channel2mhz(CHSPEC_CHANNEL(bi->chanspec), ++ CHSPEC_CHANNEL(bi->chanspec) <= CH_MAX_2G_CHANNEL ? ++ WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G); ++ iwe.u.freq.e = 6; ++ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN); ++ ++ /* Channel quality */ ++ iwe.cmd = IWEVQUAL; ++ iwe.u.qual.qual = rssi_to_qual(dtoh16(bi->RSSI)); ++ iwe.u.qual.level = 0x100 + dtoh16(bi->RSSI); ++ iwe.u.qual.noise = 0x100 + bi->phy_noise; ++ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN); ++ ++ /* WPA, WPA2, WPS, WAPI IEs */ ++ wl_iw_handle_scanresults_ies(&event, end, info, bi); ++ ++ /* Encryption */ ++ iwe.cmd = SIOCGIWENCODE; ++ if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY) ++ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; ++ else ++ iwe.u.data.flags = IW_ENCODE_DISABLED; ++ iwe.u.data.length = 0; ++ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event); ++ ++ /* Rates */ ++ if (bi->rateset.count <= sizeof(bi->rateset.rates)) { ++ if (event + IW_MAX_BITRATES*IW_EV_PARAM_LEN >= end) ++ return -E2BIG; ++ ++ value = event + IW_EV_LCP_LEN; ++ iwe.cmd = SIOCGIWRATE; ++ /* Those two flags are ignored... */ ++ iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; ++ for (j = 0; j < bi->rateset.count && j < IW_MAX_BITRATES; j++) { ++ iwe.u.bitrate.value = (bi->rateset.rates[j] & 0x7f) * 500000; ++ value = IWE_STREAM_ADD_VALUE(info, event, value, end, &iwe, ++ IW_EV_PARAM_LEN); ++ } ++ event = value; ++ } ++ } ++ p_buf = p_buf->next; ++ } /* while (p_buf) */ ++ ++ dwrq->length = event - extra; ++ dwrq->flags = 0; /* todo */ ++ ++ return 0; ++} ++ ++#endif /* WIRELESS_EXT > 13 */ ++ ++ ++static int ++wl_iw_set_essid( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *dwrq, ++ char *extra ++) ++{ ++ wlc_ssid_t ssid; ++ int error; ++ ++ AP6211_DEBUG("%s: SIOCSIWESSID\n", dev->name); ++ ++ /* default Broadcast SSID */ ++ memset(&ssid, 0, sizeof(ssid)); ++ if (dwrq->length && extra) { ++#if WIRELESS_EXT > 20 ++ ssid.SSID_len = MIN(sizeof(ssid.SSID), dwrq->length); ++#else ++ ssid.SSID_len = MIN(sizeof(ssid.SSID), dwrq->length-1); ++#endif ++ memcpy(ssid.SSID, extra, ssid.SSID_len); ++ ssid.SSID_len = htod32(ssid.SSID_len); ++ ++ if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, &ssid, sizeof(ssid)))) ++ return error; ++ } ++ /* If essid null then it is "iwconfig essid off" command */ ++ else { ++ scb_val_t scbval; ++ bzero(&scbval, sizeof(scb_val_t)); ++ if ((error = dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)))) ++ return error; ++ } ++ return 0; ++} ++ ++static int ++wl_iw_get_essid( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *dwrq, ++ char *extra ++) ++{ ++ wlc_ssid_t ssid; ++ int error; ++ ++ AP6211_DEBUG("%s: SIOCGIWESSID\n", dev->name); ++ ++ if (!extra) ++ return -EINVAL; ++ ++ if ((error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid)))) { ++ AP6211_ERR("Error getting the SSID\n"); ++ return error; ++ } ++ ++ ssid.SSID_len = dtoh32(ssid.SSID_len); ++ ++ /* Get the current SSID */ ++ memcpy(extra, ssid.SSID, ssid.SSID_len); ++ ++ dwrq->length = ssid.SSID_len; ++ ++ dwrq->flags = 1; /* active */ ++ ++ return 0; ++} ++ ++static int ++wl_iw_set_nick( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *dwrq, ++ char *extra ++) ++{ ++ wl_iw_t *iw = IW_DEV_IF(dev); ++ AP6211_DEBUG("%s: SIOCSIWNICKN\n", dev->name); ++ ++ if (!extra) ++ return -EINVAL; ++ ++ /* Check the size of the string */ ++ if (dwrq->length > sizeof(iw->nickname)) ++ return -E2BIG; ++ ++ memcpy(iw->nickname, extra, dwrq->length); ++ iw->nickname[dwrq->length - 1] = '\0'; ++ ++ return 0; ++} ++ ++static int ++wl_iw_get_nick( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *dwrq, ++ char *extra ++) ++{ ++ wl_iw_t *iw = IW_DEV_IF(dev); ++ AP6211_DEBUG("%s: SIOCGIWNICKN\n", dev->name); ++ ++ if (!extra) ++ return -EINVAL; ++ ++ strcpy(extra, iw->nickname); ++ dwrq->length = strlen(extra) + 1; ++ ++ return 0; ++} ++ ++static int wl_iw_set_rate( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *vwrq, ++ char *extra ++) ++{ ++ wl_rateset_t rateset; ++ int error, rate, i, error_bg, error_a; ++ ++ AP6211_DEBUG("%s: SIOCSIWRATE\n", dev->name); ++ ++ /* Get current rateset */ ++ if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset)))) ++ return error; ++ ++ rateset.count = dtoh32(rateset.count); ++ ++ if (vwrq->value < 0) { ++ /* Select maximum rate */ ++ rate = rateset.rates[rateset.count - 1] & 0x7f; ++ } else if (vwrq->value < rateset.count) { ++ /* Select rate by rateset index */ ++ rate = rateset.rates[vwrq->value] & 0x7f; ++ } else { ++ /* Specified rate in bps */ ++ rate = vwrq->value / 500000; ++ } ++ ++ if (vwrq->fixed) { ++ /* ++ Set rate override, ++ Since the is a/b/g-blind, both a/bg_rate are enforced. ++ */ ++ error_bg = dev_wlc_intvar_set(dev, "bg_rate", rate); ++ error_a = dev_wlc_intvar_set(dev, "a_rate", rate); ++ ++ if (error_bg && error_a) ++ return (error_bg | error_a); ++ } else { ++ /* ++ clear rate override ++ Since the is a/b/g-blind, both a/bg_rate are enforced. ++ */ ++ /* 0 is for clearing rate override */ ++ error_bg = dev_wlc_intvar_set(dev, "bg_rate", 0); ++ /* 0 is for clearing rate override */ ++ error_a = dev_wlc_intvar_set(dev, "a_rate", 0); ++ ++ if (error_bg && error_a) ++ return (error_bg | error_a); ++ ++ /* Remove rates above selected rate */ ++ for (i = 0; i < rateset.count; i++) ++ if ((rateset.rates[i] & 0x7f) > rate) ++ break; ++ rateset.count = htod32(i); ++ ++ /* Set current rateset */ ++ if ((error = dev_wlc_ioctl(dev, WLC_SET_RATESET, &rateset, sizeof(rateset)))) ++ return error; ++ } ++ ++ return 0; ++} ++ ++static int wl_iw_get_rate( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *vwrq, ++ char *extra ++) ++{ ++ int error, rate; ++ ++ AP6211_DEBUG("%s: SIOCGIWRATE\n", dev->name); ++ ++ /* Report the current tx rate */ ++ if ((error = dev_wlc_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate)))) ++ return error; ++ rate = dtoh32(rate); ++ vwrq->value = rate * 500000; ++ ++ return 0; ++} ++ ++static int ++wl_iw_set_rts( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *vwrq, ++ char *extra ++) ++{ ++ int error, rts; ++ ++ AP6211_DEBUG("%s: SIOCSIWRTS\n", dev->name); ++ ++ if (vwrq->disabled) ++ rts = DOT11_DEFAULT_RTS_LEN; ++ else if (vwrq->value < 0 || vwrq->value > DOT11_DEFAULT_RTS_LEN) ++ return -EINVAL; ++ else ++ rts = vwrq->value; ++ ++ if ((error = dev_wlc_intvar_set(dev, "rtsthresh", rts))) ++ return error; ++ ++ return 0; ++} ++ ++static int ++wl_iw_get_rts( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *vwrq, ++ char *extra ++) ++{ ++ int error, rts; ++ ++ AP6211_DEBUG("%s: SIOCGIWRTS\n", dev->name); ++ ++ if ((error = dev_wlc_intvar_get(dev, "rtsthresh", &rts))) ++ return error; ++ ++ vwrq->value = rts; ++ vwrq->disabled = (rts >= DOT11_DEFAULT_RTS_LEN); ++ vwrq->fixed = 1; ++ ++ return 0; ++} ++ ++static int ++wl_iw_set_frag( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *vwrq, ++ char *extra ++) ++{ ++ int error, frag; ++ ++ AP6211_DEBUG("%s: SIOCSIWFRAG\n", dev->name); ++ ++ if (vwrq->disabled) ++ frag = DOT11_DEFAULT_FRAG_LEN; ++ else if (vwrq->value < 0 || vwrq->value > DOT11_DEFAULT_FRAG_LEN) ++ return -EINVAL; ++ else ++ frag = vwrq->value; ++ ++ if ((error = dev_wlc_intvar_set(dev, "fragthresh", frag))) ++ return error; ++ ++ return 0; ++} ++ ++static int ++wl_iw_get_frag( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *vwrq, ++ char *extra ++) ++{ ++ int error, fragthreshold; ++ ++ AP6211_DEBUG("%s: SIOCGIWFRAG\n", dev->name); ++ ++ if ((error = dev_wlc_intvar_get(dev, "fragthresh", &fragthreshold))) ++ return error; ++ ++ vwrq->value = fragthreshold; ++ vwrq->disabled = (fragthreshold >= DOT11_DEFAULT_FRAG_LEN); ++ vwrq->fixed = 1; ++ ++ return 0; ++} ++ ++static int ++wl_iw_set_txpow( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *vwrq, ++ char *extra ++) ++{ ++ int error, disable; ++ uint16 txpwrmw; ++ AP6211_DEBUG("%s: SIOCSIWTXPOW\n", dev->name); ++ ++ /* Make sure radio is off or on as far as software is concerned */ ++ disable = vwrq->disabled ? WL_RADIO_SW_DISABLE : 0; ++ disable += WL_RADIO_SW_DISABLE << 16; ++ ++ disable = htod32(disable); ++ if ((error = dev_wlc_ioctl(dev, WLC_SET_RADIO, &disable, sizeof(disable)))) ++ return error; ++ ++ /* If Radio is off, nothing more to do */ ++ if (disable & WL_RADIO_SW_DISABLE) ++ return 0; ++ ++ /* Only handle mW */ ++ if (!(vwrq->flags & IW_TXPOW_MWATT)) ++ return -EINVAL; ++ ++ /* Value < 0 means just "on" or "off" */ ++ if (vwrq->value < 0) ++ return 0; ++ ++ if (vwrq->value > 0xffff) txpwrmw = 0xffff; ++ else txpwrmw = (uint16)vwrq->value; ++ ++ ++ error = dev_wlc_intvar_set(dev, "qtxpower", (int)(bcm_mw_to_qdbm(txpwrmw))); ++ return error; ++} ++ ++static int ++wl_iw_get_txpow( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *vwrq, ++ char *extra ++) ++{ ++ int error, disable, txpwrdbm; ++ uint8 result; ++ ++ AP6211_DEBUG("%s: SIOCGIWTXPOW\n", dev->name); ++ ++ if ((error = dev_wlc_ioctl(dev, WLC_GET_RADIO, &disable, sizeof(disable))) || ++ (error = dev_wlc_intvar_get(dev, "qtxpower", &txpwrdbm))) ++ return error; ++ ++ disable = dtoh32(disable); ++ result = (uint8)(txpwrdbm & ~WL_TXPWR_OVERRIDE); ++ vwrq->value = (int32)bcm_qdbm_to_mw(result); ++ vwrq->fixed = 0; ++ vwrq->disabled = (disable & (WL_RADIO_SW_DISABLE | WL_RADIO_HW_DISABLE)) ? 1 : 0; ++ vwrq->flags = IW_TXPOW_MWATT; ++ ++ return 0; ++} ++ ++#if WIRELESS_EXT > 10 ++static int ++wl_iw_set_retry( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *vwrq, ++ char *extra ++) ++{ ++ int error, lrl, srl; ++ ++ AP6211_DEBUG("%s: SIOCSIWRETRY\n", dev->name); ++ ++ /* Do not handle "off" or "lifetime" */ ++ if (vwrq->disabled || (vwrq->flags & IW_RETRY_LIFETIME)) ++ return -EINVAL; ++ ++ /* Handle "[min|max] limit" */ ++ if (vwrq->flags & IW_RETRY_LIMIT) { ++ /* "max limit" or just "limit" */ ++#if WIRELESS_EXT > 20 ++ if ((vwrq->flags & IW_RETRY_LONG) ||(vwrq->flags & IW_RETRY_MAX) || ++ !((vwrq->flags & IW_RETRY_SHORT) || (vwrq->flags & IW_RETRY_MIN))) { ++#else ++ if ((vwrq->flags & IW_RETRY_MAX) || !(vwrq->flags & IW_RETRY_MIN)) { ++#endif /* WIRELESS_EXT > 20 */ ++ ++ lrl = htod32(vwrq->value); ++ if ((error = dev_wlc_ioctl(dev, WLC_SET_LRL, &lrl, sizeof(lrl)))) ++ return error; ++ } ++ /* "min limit" or just "limit" */ ++#if WIRELESS_EXT > 20 ++ if ((vwrq->flags & IW_RETRY_SHORT) ||(vwrq->flags & IW_RETRY_MIN) || ++ !((vwrq->flags & IW_RETRY_LONG) || (vwrq->flags & IW_RETRY_MAX))) { ++#else ++ if ((vwrq->flags & IW_RETRY_MIN) || !(vwrq->flags & IW_RETRY_MAX)) { ++#endif /* WIRELESS_EXT > 20 */ ++ ++ srl = htod32(vwrq->value); ++ if ((error = dev_wlc_ioctl(dev, WLC_SET_SRL, &srl, sizeof(srl)))) ++ return error; ++ } ++ } ++ ++ return 0; ++} ++ ++static int ++wl_iw_get_retry( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *vwrq, ++ char *extra ++) ++{ ++ int error, lrl, srl; ++ ++ AP6211_DEBUG("%s: SIOCGIWRETRY\n", dev->name); ++ ++ vwrq->disabled = 0; /* Can't be disabled */ ++ ++ /* Do not handle lifetime queries */ ++ if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) ++ return -EINVAL; ++ ++ /* Get retry limits */ ++ if ((error = dev_wlc_ioctl(dev, WLC_GET_LRL, &lrl, sizeof(lrl))) || ++ (error = dev_wlc_ioctl(dev, WLC_GET_SRL, &srl, sizeof(srl)))) ++ return error; ++ ++ lrl = dtoh32(lrl); ++ srl = dtoh32(srl); ++ ++ /* Note : by default, display the min retry number */ ++ if (vwrq->flags & IW_RETRY_MAX) { ++ vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; ++ vwrq->value = lrl; ++ } else { ++ vwrq->flags = IW_RETRY_LIMIT; ++ vwrq->value = srl; ++ if (srl != lrl) ++ vwrq->flags |= IW_RETRY_MIN; ++ } ++ ++ return 0; ++} ++#endif /* WIRELESS_EXT > 10 */ ++ ++static int ++wl_iw_set_encode( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *dwrq, ++ char *extra ++) ++{ ++ wl_wsec_key_t key; ++ int error, val, wsec; ++ ++ AP6211_DEBUG("%s: SIOCSIWENCODE\n", dev->name); ++ ++ memset(&key, 0, sizeof(key)); ++ ++ if ((dwrq->flags & IW_ENCODE_INDEX) == 0) { ++ /* Find the current key */ ++ for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS; key.index++) { ++ val = htod32(key.index); ++ if ((error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val, sizeof(val)))) ++ return error; ++ val = dtoh32(val); ++ if (val) ++ break; ++ } ++ /* Default to 0 */ ++ if (key.index == DOT11_MAX_DEFAULT_KEYS) ++ key.index = 0; ++ } else { ++ key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1; ++ if (key.index >= DOT11_MAX_DEFAULT_KEYS) ++ return -EINVAL; ++ } ++ ++ /* Interpret "off" to mean no encryption */ ++ wsec = (dwrq->flags & IW_ENCODE_DISABLED) ? 0 : WEP_ENABLED; ++ ++ if ((error = dev_wlc_intvar_set(dev, "wsec", wsec))) ++ return error; ++ ++ /* Old API used to pass a NULL pointer instead of IW_ENCODE_NOKEY */ ++ if (!extra || !dwrq->length || (dwrq->flags & IW_ENCODE_NOKEY)) { ++ /* Just select a new current key */ ++ val = htod32(key.index); ++ if ((error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY, &val, sizeof(val)))) ++ return error; ++ } else { ++ key.len = dwrq->length; ++ ++ if (dwrq->length > sizeof(key.data)) ++ return -EINVAL; ++ ++ memcpy(key.data, extra, dwrq->length); ++ ++ key.flags = WL_PRIMARY_KEY; ++ switch (key.len) { ++ case WEP1_KEY_SIZE: ++ key.algo = CRYPTO_ALGO_WEP1; ++ break; ++ case WEP128_KEY_SIZE: ++ key.algo = CRYPTO_ALGO_WEP128; ++ break; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) ++ case TKIP_KEY_SIZE: ++ key.algo = CRYPTO_ALGO_TKIP; ++ break; ++#endif ++ case AES_KEY_SIZE: ++ key.algo = CRYPTO_ALGO_AES_CCM; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ /* Set the new key/index */ ++ swap_key_from_BE(&key); ++ if ((error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key)))) ++ return error; ++ } ++ ++ /* Interpret "restricted" to mean shared key authentication */ ++ val = (dwrq->flags & IW_ENCODE_RESTRICTED) ? 1 : 0; ++ val = htod32(val); ++ if ((error = dev_wlc_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val)))) ++ return error; ++ ++ return 0; ++} ++ ++static int ++wl_iw_get_encode( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *dwrq, ++ char *extra ++) ++{ ++ wl_wsec_key_t key; ++ int error, val, wsec, auth; ++ ++ AP6211_DEBUG("%s: SIOCGIWENCODE\n", dev->name); ++ ++ /* assure default values of zero for things we don't touch */ ++ bzero(&key, sizeof(wl_wsec_key_t)); ++ ++ if ((dwrq->flags & IW_ENCODE_INDEX) == 0) { ++ /* Find the current key */ ++ for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS; key.index++) { ++ val = key.index; ++ if ((error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val, sizeof(val)))) ++ return error; ++ val = dtoh32(val); ++ if (val) ++ break; ++ } ++ } else ++ key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1; ++ ++ if (key.index >= DOT11_MAX_DEFAULT_KEYS) ++ key.index = 0; ++ ++ /* Get info */ ++ ++ if ((error = dev_wlc_ioctl(dev, WLC_GET_WSEC, &wsec, sizeof(wsec))) || ++ (error = dev_wlc_ioctl(dev, WLC_GET_AUTH, &auth, sizeof(auth)))) ++ return error; ++ ++ swap_key_to_BE(&key); ++ ++ wsec = dtoh32(wsec); ++ auth = dtoh32(auth); ++ /* Get key length */ ++ dwrq->length = MIN(IW_ENCODING_TOKEN_MAX, key.len); ++ ++ /* Get flags */ ++ dwrq->flags = key.index + 1; ++ if (!(wsec & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED))) { ++ /* Interpret "off" to mean no encryption */ ++ dwrq->flags |= IW_ENCODE_DISABLED; ++ } ++ if (auth) { ++ /* Interpret "restricted" to mean shared key authentication */ ++ dwrq->flags |= IW_ENCODE_RESTRICTED; ++ } ++ ++ /* Get key */ ++ if (dwrq->length && extra) ++ memcpy(extra, key.data, dwrq->length); ++ ++ return 0; ++} ++ ++static int ++wl_iw_set_power( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *vwrq, ++ char *extra ++) ++{ ++ int error, pm; ++ ++ AP6211_DEBUG("%s: SIOCSIWPOWER\n", dev->name); ++ ++ pm = vwrq->disabled ? PM_OFF : PM_MAX; ++ ++ pm = htod32(pm); ++ if ((error = dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm)))) ++ return error; ++ ++ return 0; ++} ++ ++static int ++wl_iw_get_power( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *vwrq, ++ char *extra ++) ++{ ++ int error, pm; ++ ++ AP6211_DEBUG("%s: SIOCGIWPOWER\n", dev->name); ++ ++ if ((error = dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm)))) ++ return error; ++ ++ pm = dtoh32(pm); ++ vwrq->disabled = pm ? 0 : 1; ++ vwrq->flags = IW_POWER_ALL_R; ++ ++ return 0; ++} ++ ++#if WIRELESS_EXT > 17 ++static int ++wl_iw_set_wpaie( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *iwp, ++ char *extra ++) ++{ ++ dev_wlc_bufvar_set(dev, "wpaie", extra, iwp->length); ++ ++ return 0; ++} ++ ++static int ++wl_iw_get_wpaie( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *iwp, ++ char *extra ++) ++{ ++ AP6211_DEBUG("%s: SIOCGIWGENIE\n", dev->name); ++ iwp->length = 64; ++ dev_wlc_bufvar_get(dev, "wpaie", extra, iwp->length); ++ return 0; ++} ++ ++static int ++wl_iw_set_encodeext( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *dwrq, ++ char *extra ++) ++{ ++ wl_wsec_key_t key; ++ int error; ++ struct iw_encode_ext *iwe; ++ ++ AP6211_DEBUG("%s: SIOCSIWENCODEEXT\n", dev->name); ++ ++ memset(&key, 0, sizeof(key)); ++ iwe = (struct iw_encode_ext *)extra; ++ ++ /* disable encryption completely */ ++ if (dwrq->flags & IW_ENCODE_DISABLED) { ++ ++ } ++ ++ /* get the key index */ ++ key.index = 0; ++ if (dwrq->flags & IW_ENCODE_INDEX) ++ key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1; ++ ++ key.len = iwe->key_len; ++ ++ /* Instead of bcast for ea address for default wep keys, driver needs it to be Null */ ++ if (!ETHER_ISMULTI(iwe->addr.sa_data)) ++ bcopy((void *)&iwe->addr.sa_data, (char *)&key.ea, ETHER_ADDR_LEN); ++ ++ /* check for key index change */ ++ if (key.len == 0) { ++ if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { ++ AP6211_DEBUG("Changing the the primary Key to %d\n", key.index); ++ /* change the key index .... */ ++ key.index = htod32(key.index); ++ error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY, ++ &key.index, sizeof(key.index)); ++ if (error) ++ return error; ++ } ++ /* key delete */ ++ else { ++ swap_key_from_BE(&key); ++ error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key)); ++ if (error) ++ return error; ++ } ++ } ++#if (defined(BCMSUP_PSK) && defined(WLFBT)) ++ /* This case is used to allow an external 802.1x supplicant ++ * to pass the PMK to the in-driver supplicant for use in ++ * the 4-way handshake. ++ */ ++ else if (iwe->alg == IW_ENCODE_ALG_PMK) { ++ int j; ++ wsec_pmk_t pmk; ++ char keystring[WSEC_MAX_PSK_LEN + 1]; ++ char* charptr = keystring; ++ uint len; ++ ++ /* copy the raw hex key to the appropriate format */ ++ for (j = 0; j < (WSEC_MAX_PSK_LEN / 2); j++) { ++ sprintf(charptr, "%02x", iwe->key[j]); ++ charptr += 2; ++ } ++ len = strlen(keystring); ++ pmk.key_len = htod16(len); ++ bcopy(keystring, pmk.key, len); ++ pmk.flags = htod16(WSEC_PASSPHRASE); ++ ++ error = dev_wlc_ioctl(dev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk)); ++ if (error) ++ return error; ++ } ++#endif /* (defined (BCMSUP_PSK) && defined(WLFBT)) */ ++ ++ else { ++ if (iwe->key_len > sizeof(key.data)) ++ return -EINVAL; ++ ++ AP6211_DEBUG("Setting the key index %d\n", key.index); ++ if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { ++ AP6211_DEBUG("key is a Primary Key\n"); ++ key.flags = WL_PRIMARY_KEY; ++ } ++ ++ bcopy((void *)iwe->key, key.data, iwe->key_len); ++ ++ if (iwe->alg == IW_ENCODE_ALG_TKIP) { ++ uint8 keybuf[8]; ++ bcopy(&key.data[24], keybuf, sizeof(keybuf)); ++ bcopy(&key.data[16], &key.data[24], sizeof(keybuf)); ++ bcopy(keybuf, &key.data[16], sizeof(keybuf)); ++ } ++ ++ /* rx iv */ ++ if (iwe->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { ++ uchar *ivptr; ++ ivptr = (uchar *)iwe->rx_seq; ++ key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) | ++ (ivptr[3] << 8) | ivptr[2]; ++ key.rxiv.lo = (ivptr[1] << 8) | ivptr[0]; ++ key.iv_initialized = TRUE; ++ } ++ ++ switch (iwe->alg) { ++ case IW_ENCODE_ALG_NONE: ++ key.algo = CRYPTO_ALGO_OFF; ++ break; ++ case IW_ENCODE_ALG_WEP: ++ if (iwe->key_len == WEP1_KEY_SIZE) ++ key.algo = CRYPTO_ALGO_WEP1; ++ else ++ key.algo = CRYPTO_ALGO_WEP128; ++ break; ++ case IW_ENCODE_ALG_TKIP: ++ key.algo = CRYPTO_ALGO_TKIP; ++ break; ++ case IW_ENCODE_ALG_CCMP: ++ key.algo = CRYPTO_ALGO_AES_CCM; ++ break; ++ default: ++ break; ++ } ++ swap_key_from_BE(&key); ++ ++ dhd_wait_pend8021x(dev); ++ ++ error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key)); ++ if (error) ++ return error; ++ } ++ return 0; ++} ++ ++ ++#if WIRELESS_EXT > 17 ++struct { ++ pmkid_list_t pmkids; ++ pmkid_t foo[MAXPMKID-1]; ++} pmkid_list; ++static int ++wl_iw_set_pmksa( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *vwrq, ++ char *extra ++) ++{ ++ struct iw_pmksa *iwpmksa; ++ uint i; ++ char eabuf[ETHER_ADDR_STR_LEN]; ++ pmkid_t * pmkid_array = pmkid_list.pmkids.pmkid; ++ ++ AP6211_DEBUG("%s: SIOCSIWPMKSA\n", dev->name); ++ iwpmksa = (struct iw_pmksa *)extra; ++ bzero((char *)eabuf, ETHER_ADDR_STR_LEN); ++ if (iwpmksa->cmd == IW_PMKSA_FLUSH) { ++ AP6211_DEBUG("wl_iw_set_pmksa - IW_PMKSA_FLUSH\n"); ++ bzero((char *)&pmkid_list, sizeof(pmkid_list)); ++ } ++ if (iwpmksa->cmd == IW_PMKSA_REMOVE) { ++ pmkid_list_t pmkid, *pmkidptr; ++ pmkidptr = &pmkid; ++ bcopy(&iwpmksa->bssid.sa_data[0], &pmkidptr->pmkid[0].BSSID, ETHER_ADDR_LEN); ++ bcopy(&iwpmksa->pmkid[0], &pmkidptr->pmkid[0].PMKID, WPA2_PMKID_LEN); ++ { ++ uint j; ++ AP6211_DEBUG("wl_iw_set_pmksa,IW_PMKSA_REMOVE - PMKID: %s = ", ++ bcm_ether_ntoa(&pmkidptr->pmkid[0].BSSID, ++ eabuf)); ++ for (j = 0; j < WPA2_PMKID_LEN; j++) ++ AP6211_DUMP("%02x ", pmkidptr->pmkid[0].PMKID[j]); ++ AP6211_DUMP("\n"); ++ } ++ for (i = 0; i < pmkid_list.pmkids.npmkid; i++) ++ if (!bcmp(&iwpmksa->bssid.sa_data[0], &pmkid_array[i].BSSID, ++ ETHER_ADDR_LEN)) ++ break; ++ for (; i < pmkid_list.pmkids.npmkid; i++) { ++ bcopy(&pmkid_array[i+1].BSSID, ++ &pmkid_array[i].BSSID, ++ ETHER_ADDR_LEN); ++ bcopy(&pmkid_array[i+1].PMKID, ++ &pmkid_array[i].PMKID, ++ WPA2_PMKID_LEN); ++ } ++ pmkid_list.pmkids.npmkid--; ++ } ++ if (iwpmksa->cmd == IW_PMKSA_ADD) { ++ bcopy(&iwpmksa->bssid.sa_data[0], ++ &pmkid_array[pmkid_list.pmkids.npmkid].BSSID, ++ ETHER_ADDR_LEN); ++ bcopy(&iwpmksa->pmkid[0], &pmkid_array[pmkid_list.pmkids.npmkid].PMKID, ++ WPA2_PMKID_LEN); ++ { ++ uint j; ++ uint k; ++ k = pmkid_list.pmkids.npmkid; ++ BCM_REFERENCE(k); ++ AP6211_DEBUG("wl_iw_set_pmksa,IW_PMKSA_ADD - PMKID: %s = ", ++ bcm_ether_ntoa(&pmkid_array[k].BSSID, ++ eabuf)); ++ for (j = 0; j < WPA2_PMKID_LEN; j++) ++ AP6211_DUMP("%02x ", pmkid_array[k].PMKID[j]); ++ AP6211_DUMP("\n"); ++ } ++ pmkid_list.pmkids.npmkid++; ++ } ++ AP6211_DEBUG("PRINTING pmkid LIST - No of elements %d\n", pmkid_list.pmkids.npmkid); ++ for (i = 0; i < pmkid_list.pmkids.npmkid; i++) { ++ uint j; ++ AP6211_DEBUG("PMKID[%d]: %s = ", i, ++ bcm_ether_ntoa(&pmkid_array[i].BSSID, ++ eabuf)); ++ for (j = 0; j < WPA2_PMKID_LEN; j++) ++ AP6211_DUMP("%02x ", pmkid_array[i].PMKID[j]); ++ AP6211_DEBUG("\n"); ++ } ++ AP6211_DEBUG("\n"); ++ dev_wlc_bufvar_set(dev, "pmkid_info", (char *)&pmkid_list, sizeof(pmkid_list)); ++ return 0; ++} ++#endif /* WIRELESS_EXT > 17 */ ++ ++static int ++wl_iw_get_encodeext( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *vwrq, ++ char *extra ++) ++{ ++ AP6211_DEBUG("%s: SIOCGIWENCODEEXT\n", dev->name); ++ return 0; ++} ++ ++static int ++wl_iw_set_wpaauth( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *vwrq, ++ char *extra ++) ++{ ++ int error = 0; ++ int paramid; ++ int paramval; ++ uint32 cipher_combined; ++ int val = 0; ++ wl_iw_t *iw = IW_DEV_IF(dev); ++ ++ AP6211_DEBUG("%s: SIOCSIWAUTH\n", dev->name); ++ ++ paramid = vwrq->flags & IW_AUTH_INDEX; ++ paramval = vwrq->value; ++ ++ AP6211_DEBUG("%s: SIOCSIWAUTH, paramid = 0x%0x, paramval = 0x%0x\n", ++ dev->name, paramid, paramval); ++ ++ switch (paramid) { ++ ++ case IW_AUTH_WPA_VERSION: ++ /* supported wpa version disabled or wpa or wpa2 */ ++ if (paramval & IW_AUTH_WPA_VERSION_DISABLED) ++ val = WPA_AUTH_DISABLED; ++ else if (paramval & (IW_AUTH_WPA_VERSION_WPA)) ++ val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED; ++ else if (paramval & IW_AUTH_WPA_VERSION_WPA2) ++ val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED; ++ AP6211_DEBUG("%s: %d: setting wpa_auth to 0x%0x\n", __FUNCTION__, __LINE__, val); ++ if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val))) ++ return error; ++ break; ++ ++ case IW_AUTH_CIPHER_PAIRWISE: ++ case IW_AUTH_CIPHER_GROUP: ++ ++ if (paramid == IW_AUTH_CIPHER_PAIRWISE) { ++ iw->pwsec = paramval; ++ } ++ else { ++ iw->gwsec = paramval; ++ } ++ ++ if ((error = dev_wlc_intvar_get(dev, "wsec", &val))) ++ return error; ++ ++ cipher_combined = iw->gwsec | iw->pwsec; ++ val &= ~(WEP_ENABLED | TKIP_ENABLED | AES_ENABLED); ++ if (cipher_combined & (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104)) ++ val |= WEP_ENABLED; ++ if (cipher_combined & IW_AUTH_CIPHER_TKIP) ++ val |= TKIP_ENABLED; ++ if (cipher_combined & IW_AUTH_CIPHER_CCMP) ++ val |= AES_ENABLED; ++ ++ if (iw->privacy_invoked && !val) { ++ AP6211_DEBUG("%s: %s: 'Privacy invoked' TRUE but clearing wsec, assuming " ++ "we're a WPS enrollee\n", dev->name, __FUNCTION__); ++ if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", TRUE))) { ++ AP6211_DEBUG("Failed to set iovar is_WPS_enrollee\n"); ++ return error; ++ } ++ } else if (val) { ++ if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", FALSE))) { ++ AP6211_DEBUG("Failed to clear iovar is_WPS_enrollee\n"); ++ return error; ++ } ++ } ++ ++ if ((error = dev_wlc_intvar_set(dev, "wsec", val))) ++ return error; ++#ifdef WLFBT ++ if ((paramid == IW_AUTH_CIPHER_PAIRWISE) && (val | AES_ENABLED)) { ++ if ((error = dev_wlc_intvar_set(dev, "sup_wpa", 1))) ++ return error; ++ } ++ else if (val == 0) { ++ if ((error = dev_wlc_intvar_set(dev, "sup_wpa", 0))) ++ return error; ++ } ++#endif /* WLFBT */ ++ break; ++ ++ case IW_AUTH_KEY_MGMT: ++ if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val))) ++ return error; ++ ++ if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) { ++ if (paramval & IW_AUTH_KEY_MGMT_PSK) ++ val = WPA_AUTH_PSK; ++ else ++ val = WPA_AUTH_UNSPECIFIED; ++ } ++ else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) { ++ if (paramval & IW_AUTH_KEY_MGMT_PSK) ++ val = WPA2_AUTH_PSK; ++ else ++ val = WPA2_AUTH_UNSPECIFIED; ++ } ++ AP6211_DEBUG("%s: %d: setting wpa_auth to %d\n", __FUNCTION__, __LINE__, val); ++ if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val))) ++ return error; ++ break; ++ ++ case IW_AUTH_TKIP_COUNTERMEASURES: ++ dev_wlc_bufvar_set(dev, "tkip_countermeasures", (char *)¶mval, 1); ++ break; ++ ++ case IW_AUTH_80211_AUTH_ALG: ++ /* open shared */ ++ AP6211_ERR("Setting the D11auth %d\n", paramval); ++ if (paramval & IW_AUTH_ALG_OPEN_SYSTEM) ++ val = 0; ++ else if (paramval & IW_AUTH_ALG_SHARED_KEY) ++ val = 1; ++ else ++ error = 1; ++ if (!error && (error = dev_wlc_intvar_set(dev, "auth", val))) ++ return error; ++ break; ++ ++ case IW_AUTH_WPA_ENABLED: ++ if (paramval == 0) { ++ val = 0; ++ AP6211_DEBUG("%s: %d: setting wpa_auth to %d\n", __FUNCTION__, __LINE__, val); ++ error = dev_wlc_intvar_set(dev, "wpa_auth", val); ++ return error; ++ } ++ else { ++ /* If WPA is enabled, wpa_auth is set elsewhere */ ++ } ++ break; ++ ++ case IW_AUTH_DROP_UNENCRYPTED: ++ dev_wlc_bufvar_set(dev, "wsec_restrict", (char *)¶mval, 1); ++ break; ++ ++ case IW_AUTH_RX_UNENCRYPTED_EAPOL: ++ dev_wlc_bufvar_set(dev, "rx_unencrypted_eapol", (char *)¶mval, 1); ++ break; ++ ++#if WIRELESS_EXT > 17 ++ ++ case IW_AUTH_ROAMING_CONTROL: ++ AP6211_DEBUG("%s: IW_AUTH_ROAMING_CONTROL\n", __FUNCTION__); ++ /* driver control or user space app control */ ++ break; ++ ++ case IW_AUTH_PRIVACY_INVOKED: { ++ int wsec; ++ ++ if (paramval == 0) { ++ iw->privacy_invoked = FALSE; ++ if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", FALSE))) { ++ AP6211_DEBUG("Failed to clear iovar is_WPS_enrollee\n"); ++ return error; ++ } ++ } else { ++ iw->privacy_invoked = TRUE; ++ if ((error = dev_wlc_intvar_get(dev, "wsec", &wsec))) ++ return error; ++ ++ if (!WSEC_ENABLED(wsec)) { ++ /* if privacy is true, but wsec is false, we are a WPS enrollee */ ++ if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", TRUE))) { ++ AP6211_DEBUG("Failed to set iovar is_WPS_enrollee\n"); ++ return error; ++ } ++ } else { ++ if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", FALSE))) { ++ AP6211_DEBUG("Failed to clear iovar is_WPS_enrollee\n"); ++ return error; ++ } ++ } ++ } ++ break; ++ } ++ ++ ++#endif /* WIRELESS_EXT > 17 */ ++ ++ ++ default: ++ break; ++ } ++ return 0; ++} ++#define VAL_PSK(_val) (((_val) & WPA_AUTH_PSK) || ((_val) & WPA2_AUTH_PSK)) ++ ++static int ++wl_iw_get_wpaauth( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *vwrq, ++ char *extra ++) ++{ ++ int error; ++ int paramid; ++ int paramval = 0; ++ int val; ++ wl_iw_t *iw = IW_DEV_IF(dev); ++ ++ AP6211_DEBUG("%s: SIOCGIWAUTH\n", dev->name); ++ ++ paramid = vwrq->flags & IW_AUTH_INDEX; ++ ++ switch (paramid) { ++ case IW_AUTH_WPA_VERSION: ++ /* supported wpa version disabled or wpa or wpa2 */ ++ if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val))) ++ return error; ++ if (val & (WPA_AUTH_NONE | WPA_AUTH_DISABLED)) ++ paramval = IW_AUTH_WPA_VERSION_DISABLED; ++ else if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) ++ paramval = IW_AUTH_WPA_VERSION_WPA; ++ else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) ++ paramval = IW_AUTH_WPA_VERSION_WPA2; ++ break; ++ ++ case IW_AUTH_CIPHER_PAIRWISE: ++ paramval = iw->pwsec; ++ break; ++ ++ case IW_AUTH_CIPHER_GROUP: ++ paramval = iw->gwsec; ++ break; ++ ++ case IW_AUTH_KEY_MGMT: ++ /* psk, 1x */ ++ if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val))) ++ return error; ++ if (VAL_PSK(val)) ++ paramval = IW_AUTH_KEY_MGMT_PSK; ++ else ++ paramval = IW_AUTH_KEY_MGMT_802_1X; ++ ++ break; ++ case IW_AUTH_TKIP_COUNTERMEASURES: ++ dev_wlc_bufvar_get(dev, "tkip_countermeasures", (char *)¶mval, 1); ++ break; ++ ++ case IW_AUTH_DROP_UNENCRYPTED: ++ dev_wlc_bufvar_get(dev, "wsec_restrict", (char *)¶mval, 1); ++ break; ++ ++ case IW_AUTH_RX_UNENCRYPTED_EAPOL: ++ dev_wlc_bufvar_get(dev, "rx_unencrypted_eapol", (char *)¶mval, 1); ++ break; ++ ++ case IW_AUTH_80211_AUTH_ALG: ++ /* open, shared, leap */ ++ if ((error = dev_wlc_intvar_get(dev, "auth", &val))) ++ return error; ++ if (!val) ++ paramval = IW_AUTH_ALG_OPEN_SYSTEM; ++ else ++ paramval = IW_AUTH_ALG_SHARED_KEY; ++ break; ++ case IW_AUTH_WPA_ENABLED: ++ if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val))) ++ return error; ++ if (val) ++ paramval = TRUE; ++ else ++ paramval = FALSE; ++ break; ++ ++#if WIRELESS_EXT > 17 ++ ++ case IW_AUTH_ROAMING_CONTROL: ++ AP6211_ERR("%s: IW_AUTH_ROAMING_CONTROL\n", __FUNCTION__); ++ /* driver control or user space app control */ ++ break; ++ ++ case IW_AUTH_PRIVACY_INVOKED: ++ paramval = iw->privacy_invoked; ++ break; ++ ++#endif /* WIRELESS_EXT > 17 */ ++ } ++ vwrq->value = paramval; ++ return 0; ++} ++#endif /* WIRELESS_EXT > 17 */ ++ ++static const iw_handler wl_iw_handler[] = ++{ ++ (iw_handler) wl_iw_config_commit, /* SIOCSIWCOMMIT */ ++ (iw_handler) wl_iw_get_name, /* SIOCGIWNAME */ ++ (iw_handler) NULL, /* SIOCSIWNWID */ ++ (iw_handler) NULL, /* SIOCGIWNWID */ ++ (iw_handler) wl_iw_set_freq, /* SIOCSIWFREQ */ ++ (iw_handler) wl_iw_get_freq, /* SIOCGIWFREQ */ ++ (iw_handler) wl_iw_set_mode, /* SIOCSIWMODE */ ++ (iw_handler) wl_iw_get_mode, /* SIOCGIWMODE */ ++ (iw_handler) NULL, /* SIOCSIWSENS */ ++ (iw_handler) NULL, /* SIOCGIWSENS */ ++ (iw_handler) NULL, /* SIOCSIWRANGE */ ++ (iw_handler) wl_iw_get_range, /* SIOCGIWRANGE */ ++ (iw_handler) NULL, /* SIOCSIWPRIV */ ++ (iw_handler) NULL, /* SIOCGIWPRIV */ ++ (iw_handler) NULL, /* SIOCSIWSTATS */ ++ (iw_handler) NULL, /* SIOCGIWSTATS */ ++ (iw_handler) wl_iw_set_spy, /* SIOCSIWSPY */ ++ (iw_handler) wl_iw_get_spy, /* SIOCGIWSPY */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) wl_iw_set_wap, /* SIOCSIWAP */ ++ (iw_handler) wl_iw_get_wap, /* SIOCGIWAP */ ++#if WIRELESS_EXT > 17 ++ (iw_handler) wl_iw_mlme, /* SIOCSIWMLME */ ++#else ++ (iw_handler) NULL, /* -- hole -- */ ++#endif ++ (iw_handler) wl_iw_iscan_get_aplist, /* SIOCGIWAPLIST */ ++#if WIRELESS_EXT > 13 ++ (iw_handler) wl_iw_iscan_set_scan, /* SIOCSIWSCAN */ ++ (iw_handler) wl_iw_iscan_get_scan, /* SIOCGIWSCAN */ ++#else /* WIRELESS_EXT > 13 */ ++ (iw_handler) NULL, /* SIOCSIWSCAN */ ++ (iw_handler) NULL, /* SIOCGIWSCAN */ ++#endif /* WIRELESS_EXT > 13 */ ++ (iw_handler) wl_iw_set_essid, /* SIOCSIWESSID */ ++ (iw_handler) wl_iw_get_essid, /* SIOCGIWESSID */ ++ (iw_handler) wl_iw_set_nick, /* SIOCSIWNICKN */ ++ (iw_handler) wl_iw_get_nick, /* SIOCGIWNICKN */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) wl_iw_set_rate, /* SIOCSIWRATE */ ++ (iw_handler) wl_iw_get_rate, /* SIOCGIWRATE */ ++ (iw_handler) wl_iw_set_rts, /* SIOCSIWRTS */ ++ (iw_handler) wl_iw_get_rts, /* SIOCGIWRTS */ ++ (iw_handler) wl_iw_set_frag, /* SIOCSIWFRAG */ ++ (iw_handler) wl_iw_get_frag, /* SIOCGIWFRAG */ ++ (iw_handler) wl_iw_set_txpow, /* SIOCSIWTXPOW */ ++ (iw_handler) wl_iw_get_txpow, /* SIOCGIWTXPOW */ ++#if WIRELESS_EXT > 10 ++ (iw_handler) wl_iw_set_retry, /* SIOCSIWRETRY */ ++ (iw_handler) wl_iw_get_retry, /* SIOCGIWRETRY */ ++#endif /* WIRELESS_EXT > 10 */ ++ (iw_handler) wl_iw_set_encode, /* SIOCSIWENCODE */ ++ (iw_handler) wl_iw_get_encode, /* SIOCGIWENCODE */ ++ (iw_handler) wl_iw_set_power, /* SIOCSIWPOWER */ ++ (iw_handler) wl_iw_get_power, /* SIOCGIWPOWER */ ++#if WIRELESS_EXT > 17 ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) wl_iw_set_wpaie, /* SIOCSIWGENIE */ ++ (iw_handler) wl_iw_get_wpaie, /* SIOCGIWGENIE */ ++ (iw_handler) wl_iw_set_wpaauth, /* SIOCSIWAUTH */ ++ (iw_handler) wl_iw_get_wpaauth, /* SIOCGIWAUTH */ ++ (iw_handler) wl_iw_set_encodeext, /* SIOCSIWENCODEEXT */ ++ (iw_handler) wl_iw_get_encodeext, /* SIOCGIWENCODEEXT */ ++ (iw_handler) wl_iw_set_pmksa, /* SIOCSIWPMKSA */ ++#endif /* WIRELESS_EXT > 17 */ ++}; ++ ++#if WIRELESS_EXT > 12 ++enum { ++ WL_IW_SET_LEDDC = SIOCIWFIRSTPRIV, ++ WL_IW_SET_VLANMODE, ++ WL_IW_SET_PM ++}; ++ ++static iw_handler wl_iw_priv_handler[] = { ++ wl_iw_set_leddc, ++ wl_iw_set_vlanmode, ++ wl_iw_set_pm ++}; ++ ++static struct iw_priv_args wl_iw_priv_args[] = { ++ { ++ WL_IW_SET_LEDDC, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, ++ 0, ++ "set_leddc" ++ }, ++ { ++ WL_IW_SET_VLANMODE, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, ++ 0, ++ "set_vlanmode" ++ }, ++ { ++ WL_IW_SET_PM, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, ++ 0, ++ "set_pm" ++ } ++}; ++ ++const struct iw_handler_def wl_iw_handler_def = ++{ ++ .num_standard = ARRAYSIZE(wl_iw_handler), ++ .num_private = ARRAY_SIZE(wl_iw_priv_handler), ++ .num_private_args = ARRAY_SIZE(wl_iw_priv_args), ++ .standard = (iw_handler *) wl_iw_handler, ++ .private = wl_iw_priv_handler, ++ .private_args = wl_iw_priv_args, ++#if WIRELESS_EXT >= 19 ++ get_wireless_stats: dhd_get_wireless_stats, ++#endif /* WIRELESS_EXT >= 19 */ ++ }; ++#endif /* WIRELESS_EXT > 12 */ ++ ++int ++wl_iw_ioctl( ++ struct net_device *dev, ++ struct ifreq *rq, ++ int cmd ++) ++{ ++ struct iwreq *wrq = (struct iwreq *) rq; ++ struct iw_request_info info; ++ iw_handler handler; ++ char *extra = NULL; ++ size_t token_size = 1; ++ int max_tokens = 0, ret = 0; ++ ++ if (cmd < SIOCIWFIRST || ++ IW_IOCTL_IDX(cmd) >= ARRAYSIZE(wl_iw_handler) || ++ !(handler = wl_iw_handler[IW_IOCTL_IDX(cmd)])) ++ return -EOPNOTSUPP; ++ ++ switch (cmd) { ++ ++ case SIOCSIWESSID: ++ case SIOCGIWESSID: ++ case SIOCSIWNICKN: ++ case SIOCGIWNICKN: ++ max_tokens = IW_ESSID_MAX_SIZE + 1; ++ break; ++ ++ case SIOCSIWENCODE: ++ case SIOCGIWENCODE: ++#if WIRELESS_EXT > 17 ++ case SIOCSIWENCODEEXT: ++ case SIOCGIWENCODEEXT: ++#endif ++ max_tokens = IW_ENCODING_TOKEN_MAX; ++ break; ++ ++ case SIOCGIWRANGE: ++ max_tokens = sizeof(struct iw_range); ++ break; ++ ++ case SIOCGIWAPLIST: ++ token_size = sizeof(struct sockaddr) + sizeof(struct iw_quality); ++ max_tokens = IW_MAX_AP; ++ break; ++ ++#if WIRELESS_EXT > 13 ++ case SIOCGIWSCAN: ++ if (g_iscan) ++ max_tokens = wrq->u.data.length; ++ else ++ max_tokens = IW_SCAN_MAX_DATA; ++ break; ++#endif /* WIRELESS_EXT > 13 */ ++ ++ case SIOCSIWSPY: ++ token_size = sizeof(struct sockaddr); ++ max_tokens = IW_MAX_SPY; ++ break; ++ ++ case SIOCGIWSPY: ++ token_size = sizeof(struct sockaddr) + sizeof(struct iw_quality); ++ max_tokens = IW_MAX_SPY; ++ break; ++ default: ++ break; ++ } ++ ++ if (max_tokens && wrq->u.data.pointer) { ++ if (wrq->u.data.length > max_tokens) ++ return -E2BIG; ++ ++ if (!(extra = kmalloc(max_tokens * token_size, GFP_KERNEL))) ++ return -ENOMEM; ++ ++ if (copy_from_user(extra, wrq->u.data.pointer, wrq->u.data.length * token_size)) { ++ kfree(extra); ++ return -EFAULT; ++ } ++ } ++ ++ info.cmd = cmd; ++ info.flags = 0; ++ ++ ret = handler(dev, &info, &wrq->u, extra); ++ ++ if (extra) { ++ if (copy_to_user(wrq->u.data.pointer, extra, wrq->u.data.length * token_size)) { ++ kfree(extra); ++ return -EFAULT; ++ } ++ ++ kfree(extra); ++ } ++ ++ return ret; ++} ++ ++/* Convert a connection status event into a connection status string. ++ * Returns TRUE if a matching connection status string was found. ++ */ ++bool ++wl_iw_conn_status_str(uint32 event_type, uint32 status, uint32 reason, ++ char* stringBuf, uint buflen) ++{ ++ typedef struct conn_fail_event_map_t { ++ uint32 inEvent; /* input: event type to match */ ++ uint32 inStatus; /* input: event status code to match */ ++ uint32 inReason; /* input: event reason code to match */ ++ const char* outName; /* output: failure type */ ++ const char* outCause; /* output: failure cause */ ++ } conn_fail_event_map_t; ++ ++ /* Map of WLC_E events to connection failure strings */ ++# define WL_IW_DONT_CARE 9999 ++ const conn_fail_event_map_t event_map [] = { ++ /* inEvent inStatus inReason */ ++ /* outName outCause */ ++ {WLC_E_SET_SSID, WLC_E_STATUS_SUCCESS, WL_IW_DONT_CARE, ++ "Conn", "Success"}, ++ {WLC_E_SET_SSID, WLC_E_STATUS_NO_NETWORKS, WL_IW_DONT_CARE, ++ "Conn", "NoNetworks"}, ++ {WLC_E_SET_SSID, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE, ++ "Conn", "ConfigMismatch"}, ++ {WLC_E_PRUNE, WL_IW_DONT_CARE, WLC_E_PRUNE_ENCR_MISMATCH, ++ "Conn", "EncrypMismatch"}, ++ {WLC_E_PRUNE, WL_IW_DONT_CARE, WLC_E_RSN_MISMATCH, ++ "Conn", "RsnMismatch"}, ++ {WLC_E_AUTH, WLC_E_STATUS_TIMEOUT, WL_IW_DONT_CARE, ++ "Conn", "AuthTimeout"}, ++ {WLC_E_AUTH, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE, ++ "Conn", "AuthFail"}, ++ {WLC_E_AUTH, WLC_E_STATUS_NO_ACK, WL_IW_DONT_CARE, ++ "Conn", "AuthNoAck"}, ++ {WLC_E_REASSOC, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE, ++ "Conn", "ReassocFail"}, ++ {WLC_E_REASSOC, WLC_E_STATUS_TIMEOUT, WL_IW_DONT_CARE, ++ "Conn", "ReassocTimeout"}, ++ {WLC_E_REASSOC, WLC_E_STATUS_ABORT, WL_IW_DONT_CARE, ++ "Conn", "ReassocAbort"}, ++ {WLC_E_PSK_SUP, WLC_SUP_KEYED, WL_IW_DONT_CARE, ++ "Sup", "ConnSuccess"}, ++ {WLC_E_PSK_SUP, WL_IW_DONT_CARE, WL_IW_DONT_CARE, ++ "Sup", "WpaHandshakeFail"}, ++ {WLC_E_DEAUTH_IND, WL_IW_DONT_CARE, WL_IW_DONT_CARE, ++ "Conn", "Deauth"}, ++ {WLC_E_DISASSOC_IND, WL_IW_DONT_CARE, WL_IW_DONT_CARE, ++ "Conn", "DisassocInd"}, ++ {WLC_E_DISASSOC, WL_IW_DONT_CARE, WL_IW_DONT_CARE, ++ "Conn", "Disassoc"} ++ }; ++ ++ const char* name = ""; ++ const char* cause = NULL; ++ int i; ++ ++ /* Search the event map table for a matching event */ ++ for (i = 0; i < sizeof(event_map)/sizeof(event_map[0]); i++) { ++ const conn_fail_event_map_t* row = &event_map[i]; ++ if (row->inEvent == event_type && ++ (row->inStatus == status || row->inStatus == WL_IW_DONT_CARE) && ++ (row->inReason == reason || row->inReason == WL_IW_DONT_CARE)) { ++ name = row->outName; ++ cause = row->outCause; ++ break; ++ } ++ } ++ ++ /* If found, generate a connection failure string and return TRUE */ ++ if (cause) { ++ memset(stringBuf, 0, buflen); ++ snprintf(stringBuf, buflen, "%s %s %02d %02d", ++ name, cause, status, reason); ++ AP6211_DEBUG("Connection status: %s\n", stringBuf); ++ return TRUE; ++ } else { ++ return FALSE; ++ } ++} ++ ++#if (WIRELESS_EXT > 14) ++/* Check if we have received an event that indicates connection failure ++ * If so, generate a connection failure report string. ++ * The caller supplies a buffer to hold the generated string. ++ */ ++static bool ++wl_iw_check_conn_fail(wl_event_msg_t *e, char* stringBuf, uint buflen) ++{ ++ uint32 event = ntoh32(e->event_type); ++ uint32 status = ntoh32(e->status); ++ uint32 reason = ntoh32(e->reason); ++ ++ if (wl_iw_conn_status_str(event, status, reason, stringBuf, buflen)) { ++ return TRUE; ++ } else ++ { ++ return FALSE; ++ } ++} ++#endif /* WIRELESS_EXT > 14 */ ++ ++#ifndef IW_CUSTOM_MAX ++#define IW_CUSTOM_MAX 256 /* size of extra buffer used for translation of events */ ++#endif /* IW_CUSTOM_MAX */ ++ ++void ++wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) ++{ ++#if WIRELESS_EXT > 13 ++ union iwreq_data wrqu; ++ char extra[IW_CUSTOM_MAX + 1]; ++ int cmd = 0; ++ uint32 event_type = ntoh32(e->event_type); ++ uint16 flags = ntoh16(e->flags); ++ uint32 datalen = ntoh32(e->datalen); ++ uint32 status = ntoh32(e->status); ++ ++ memset(&wrqu, 0, sizeof(wrqu)); ++ memset(extra, 0, sizeof(extra)); ++ ++ memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN); ++ wrqu.addr.sa_family = ARPHRD_ETHER; ++ ++ switch (event_type) { ++ case WLC_E_TXFAIL: ++ cmd = IWEVTXDROP; ++ break; ++#if WIRELESS_EXT > 14 ++ case WLC_E_JOIN: ++ case WLC_E_ASSOC_IND: ++ case WLC_E_REASSOC_IND: ++ cmd = IWEVREGISTERED; ++ break; ++ case WLC_E_DEAUTH_IND: ++ case WLC_E_DISASSOC_IND: ++ cmd = SIOCGIWAP; ++ wrqu.data.length = strlen(extra); ++ bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN); ++ bzero(&extra, ETHER_ADDR_LEN); ++ break; ++ ++ case WLC_E_LINK: ++ case WLC_E_NDIS_LINK: ++ cmd = SIOCGIWAP; ++ wrqu.data.length = strlen(extra); ++ if (!(flags & WLC_EVENT_MSG_LINK)) { ++ bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN); ++ bzero(&extra, ETHER_ADDR_LEN); ++ } ++ break; ++ case WLC_E_ACTION_FRAME: ++ cmd = IWEVCUSTOM; ++ if (datalen + 1 <= sizeof(extra)) { ++ wrqu.data.length = datalen + 1; ++ extra[0] = WLC_E_ACTION_FRAME; ++ memcpy(&extra[1], data, datalen); ++ AP6211_DEBUG("WLC_E_ACTION_FRAME len %d \n", wrqu.data.length); ++ } ++ break; ++ ++ case WLC_E_ACTION_FRAME_COMPLETE: ++ cmd = IWEVCUSTOM; ++ if (sizeof(status) + 1 <= sizeof(extra)) { ++ wrqu.data.length = sizeof(status) + 1; ++ extra[0] = WLC_E_ACTION_FRAME_COMPLETE; ++ memcpy(&extra[1], &status, sizeof(status)); ++ AP6211_DEBUG("wl_iw_event status %d \n", status); ++ } ++ break; ++#endif /* WIRELESS_EXT > 14 */ ++#if WIRELESS_EXT > 17 ++ case WLC_E_MIC_ERROR: { ++ struct iw_michaelmicfailure *micerrevt = (struct iw_michaelmicfailure *)&extra; ++ cmd = IWEVMICHAELMICFAILURE; ++ wrqu.data.length = sizeof(struct iw_michaelmicfailure); ++ if (flags & WLC_EVENT_MSG_GROUP) ++ micerrevt->flags |= IW_MICFAILURE_GROUP; ++ else ++ micerrevt->flags |= IW_MICFAILURE_PAIRWISE; ++ memcpy(micerrevt->src_addr.sa_data, &e->addr, ETHER_ADDR_LEN); ++ micerrevt->src_addr.sa_family = ARPHRD_ETHER; ++ ++ break; ++ } ++ ++ case WLC_E_ASSOC_REQ_IE: ++ cmd = IWEVASSOCREQIE; ++ wrqu.data.length = datalen; ++ if (datalen < sizeof(extra)) ++ memcpy(extra, data, datalen); ++ break; ++ ++ case WLC_E_ASSOC_RESP_IE: ++ cmd = IWEVASSOCRESPIE; ++ wrqu.data.length = datalen; ++ if (datalen < sizeof(extra)) ++ memcpy(extra, data, datalen); ++ break; ++ ++ case WLC_E_PMKID_CACHE: { ++ struct iw_pmkid_cand *iwpmkidcand = (struct iw_pmkid_cand *)&extra; ++ pmkid_cand_list_t *pmkcandlist; ++ pmkid_cand_t *pmkidcand; ++ int count; ++ ++ if (data == NULL) ++ break; ++ ++ cmd = IWEVPMKIDCAND; ++ pmkcandlist = data; ++ count = ntoh32_ua((uint8 *)&pmkcandlist->npmkid_cand); ++ wrqu.data.length = sizeof(struct iw_pmkid_cand); ++ pmkidcand = pmkcandlist->pmkid_cand; ++ while (count) { ++ bzero(iwpmkidcand, sizeof(struct iw_pmkid_cand)); ++ if (pmkidcand->preauth) ++ iwpmkidcand->flags |= IW_PMKID_CAND_PREAUTH; ++ bcopy(&pmkidcand->BSSID, &iwpmkidcand->bssid.sa_data, ++ ETHER_ADDR_LEN); ++ wireless_send_event(dev, cmd, &wrqu, extra); ++ pmkidcand++; ++ count--; ++ } ++ break; ++ } ++#endif /* WIRELESS_EXT > 17 */ ++ ++ case WLC_E_SCAN_COMPLETE: ++#if WIRELESS_EXT > 14 ++ cmd = SIOCGIWSCAN; ++#endif ++ AP6211_DEBUG("event WLC_E_SCAN_COMPLETE\n"); ++ if ((g_iscan) && (g_iscan->sysioc_pid >= 0) && ++ (g_iscan->iscan_state != ISCAN_STATE_IDLE)) ++ up(&g_iscan->sysioc_sem); ++ break; ++ ++ default: ++ /* Cannot translate event */ ++ break; ++ } ++ ++ if (cmd) { ++ if (cmd == SIOCGIWSCAN) ++ wireless_send_event(dev, cmd, &wrqu, NULL); ++ else ++ wireless_send_event(dev, cmd, &wrqu, extra); ++ } ++ ++#if WIRELESS_EXT > 14 ++ /* Look for WLC events that indicate a connection failure. ++ * If found, generate an IWEVCUSTOM event. ++ */ ++ memset(extra, 0, sizeof(extra)); ++ if (wl_iw_check_conn_fail(e, extra, sizeof(extra))) { ++ cmd = IWEVCUSTOM; ++ wrqu.data.length = strlen(extra); ++ wireless_send_event(dev, cmd, &wrqu, extra); ++ } ++#endif /* WIRELESS_EXT > 14 */ ++ ++#endif /* WIRELESS_EXT > 13 */ ++} ++ ++int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats) ++{ ++ int res = 0; ++ wl_cnt_t cnt; ++ int phy_noise; ++ int rssi; ++ scb_val_t scb_val; ++ ++ phy_noise = 0; ++ if ((res = dev_wlc_ioctl(dev, WLC_GET_PHY_NOISE, &phy_noise, sizeof(phy_noise)))) ++ goto done; ++ ++ phy_noise = dtoh32(phy_noise); ++ AP6211_DEBUG("wl_iw_get_wireless_stats phy noise=%d\n *****", phy_noise); ++ ++ scb_val.val = 0; ++ if ((res = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t)))) ++ goto done; ++ ++ rssi = dtoh32(scb_val.val); ++ AP6211_DEBUG("wl_iw_get_wireless_stats rssi=%d ****** \n", rssi); ++ if (rssi <= WL_IW_RSSI_NO_SIGNAL) ++ wstats->qual.qual = 0; ++ else if (rssi <= WL_IW_RSSI_VERY_LOW) ++ wstats->qual.qual = 1; ++ else if (rssi <= WL_IW_RSSI_LOW) ++ wstats->qual.qual = 2; ++ else if (rssi <= WL_IW_RSSI_GOOD) ++ wstats->qual.qual = 3; ++ else if (rssi <= WL_IW_RSSI_VERY_GOOD) ++ wstats->qual.qual = 4; ++ else ++ wstats->qual.qual = 5; ++ ++ /* Wraps to 0 if RSSI is 0 */ ++ wstats->qual.level = 0x100 + rssi; ++ wstats->qual.noise = 0x100 + phy_noise; ++#if WIRELESS_EXT > 18 ++ wstats->qual.updated |= (IW_QUAL_ALL_UPDATED | IW_QUAL_DBM); ++#else ++ wstats->qual.updated |= 7; ++#endif /* WIRELESS_EXT > 18 */ ++ ++#if WIRELESS_EXT > 11 ++ AP6211_DEBUG("wl_iw_get_wireless_stats counters=%d\n *****", (int)sizeof(wl_cnt_t)); ++ ++ memset(&cnt, 0, sizeof(wl_cnt_t)); ++ res = dev_wlc_bufvar_get(dev, "counters", (char *)&cnt, sizeof(wl_cnt_t)); ++ if (res) ++ { ++ AP6211_ERR("wl_iw_get_wireless_stats counters failed error=%d ****** \n", res); ++ goto done; ++ } ++ ++ cnt.version = dtoh16(cnt.version); ++ if (cnt.version != WL_CNT_T_VERSION) { ++ AP6211_DEBUG("\tIncorrect version of counters struct: expected %d; got %d\n", ++ WL_CNT_T_VERSION, cnt.version); ++ goto done; ++ } ++ ++ wstats->discard.nwid = 0; ++ wstats->discard.code = dtoh32(cnt.rxundec); ++ wstats->discard.fragment = dtoh32(cnt.rxfragerr); ++ wstats->discard.retries = dtoh32(cnt.txfail); ++ wstats->discard.misc = dtoh32(cnt.rxrunt) + dtoh32(cnt.rxgiant); ++ wstats->miss.beacon = 0; ++ ++ AP6211_DEBUG("wl_iw_get_wireless_stats counters txframe=%d txbyte=%d\n", ++ dtoh32(cnt.txframe), dtoh32(cnt.txbyte)); ++ AP6211_DEBUG("wl_iw_get_wireless_stats counters rxfrmtoolong=%d\n", dtoh32(cnt.rxfrmtoolong)); ++ AP6211_DEBUG("wl_iw_get_wireless_stats counters rxbadplcp=%d\n", dtoh32(cnt.rxbadplcp)); ++ AP6211_DEBUG("wl_iw_get_wireless_stats counters rxundec=%d\n", dtoh32(cnt.rxundec)); ++ AP6211_DEBUG("wl_iw_get_wireless_stats counters rxfragerr=%d\n", dtoh32(cnt.rxfragerr)); ++ AP6211_DEBUG("wl_iw_get_wireless_stats counters txfail=%d\n", dtoh32(cnt.txfail)); ++ AP6211_DEBUG("wl_iw_get_wireless_stats counters rxrunt=%d\n", dtoh32(cnt.rxrunt)); ++ AP6211_DEBUG("wl_iw_get_wireless_stats counters rxgiant=%d\n", dtoh32(cnt.rxgiant)); ++ ++#endif /* WIRELESS_EXT > 11 */ ++ ++done: ++ return res; ++} ++ ++static void ++wl_iw_timerfunc(ulong data) ++{ ++ iscan_info_t *iscan = (iscan_info_t *)data; ++ iscan->timer_on = 0; ++ if (iscan->iscan_state != ISCAN_STATE_IDLE) { ++ AP6211_DEBUG("timer trigger\n"); ++ up(&iscan->sysioc_sem); ++ } ++} ++ ++static void ++wl_iw_set_event_mask(struct net_device *dev) ++{ ++ char eventmask[WL_EVENTING_MASK_LEN]; ++ char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */ ++ ++ dev_iw_iovar_getbuf(dev, "event_msgs", "", 0, iovbuf, sizeof(iovbuf)); ++ bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN); ++ setbit(eventmask, WLC_E_SCAN_COMPLETE); ++ dev_iw_iovar_setbuf(dev, "event_msgs", eventmask, WL_EVENTING_MASK_LEN, ++ iovbuf, sizeof(iovbuf)); ++ ++} ++ ++static int ++wl_iw_iscan_prep(wl_scan_params_t *params, wlc_ssid_t *ssid) ++{ ++ int err = 0; ++ ++ memcpy(¶ms->bssid, ðer_bcast, ETHER_ADDR_LEN); ++ params->bss_type = DOT11_BSSTYPE_ANY; ++ params->scan_type = 0; ++ params->nprobes = -1; ++ params->active_time = -1; ++ params->passive_time = -1; ++ params->home_time = -1; ++ params->channel_num = 0; ++ ++ params->nprobes = htod32(params->nprobes); ++ params->active_time = htod32(params->active_time); ++ params->passive_time = htod32(params->passive_time); ++ params->home_time = htod32(params->home_time); ++ if (ssid && ssid->SSID_len) ++ memcpy(¶ms->ssid, ssid, sizeof(wlc_ssid_t)); ++ ++ return err; ++} ++ ++static int ++wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action) ++{ ++ int params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params)); ++ wl_iscan_params_t *params; ++ int err = 0; ++ ++ if (ssid && ssid->SSID_len) { ++ params_size += sizeof(wlc_ssid_t); ++ } ++ params = (wl_iscan_params_t*)kmalloc(params_size, GFP_KERNEL); ++ if (params == NULL) { ++ return -ENOMEM; ++ } ++ memset(params, 0, params_size); ++ ASSERT(params_size < WLC_IOCTL_SMLEN); ++ ++ err = wl_iw_iscan_prep(¶ms->params, ssid); ++ ++ if (!err) { ++ params->version = htod32(ISCAN_REQ_VERSION); ++ params->action = htod16(action); ++ params->scan_duration = htod16(0); ++ ++ /* params_size += OFFSETOF(wl_iscan_params_t, params); */ ++ (void) dev_iw_iovar_setbuf(iscan->dev, "iscan", params, params_size, ++ iscan->ioctlbuf, WLC_IOCTL_SMLEN); ++ } ++ ++ kfree(params); ++ return err; ++} ++ ++static uint32 ++wl_iw_iscan_get(iscan_info_t *iscan) ++{ ++ iscan_buf_t * buf; ++ iscan_buf_t * ptr; ++ wl_iscan_results_t * list_buf; ++ wl_iscan_results_t list; ++ wl_scan_results_t *results; ++ uint32 status; ++ ++ /* buffers are allocated on demand */ ++ if (iscan->list_cur) { ++ buf = iscan->list_cur; ++ iscan->list_cur = buf->next; ++ } ++ else { ++ buf = kmalloc(sizeof(iscan_buf_t), GFP_KERNEL); ++ if (!buf) ++ return WL_SCAN_RESULTS_ABORTED; ++ buf->next = NULL; ++ if (!iscan->list_hdr) ++ iscan->list_hdr = buf; ++ else { ++ ptr = iscan->list_hdr; ++ while (ptr->next) { ++ ptr = ptr->next; ++ } ++ ptr->next = buf; ++ } ++ } ++ memset(buf->iscan_buf, 0, WLC_IW_ISCAN_MAXLEN); ++ list_buf = (wl_iscan_results_t*)buf->iscan_buf; ++ results = &list_buf->results; ++ results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE; ++ results->version = 0; ++ results->count = 0; ++ ++ memset(&list, 0, sizeof(list)); ++ list.results.buflen = htod32(WLC_IW_ISCAN_MAXLEN); ++ (void) dev_iw_iovar_getbuf( ++ iscan->dev, ++ "iscanresults", ++ &list, ++ WL_ISCAN_RESULTS_FIXED_SIZE, ++ buf->iscan_buf, ++ WLC_IW_ISCAN_MAXLEN); ++ results->buflen = dtoh32(results->buflen); ++ results->version = dtoh32(results->version); ++ results->count = dtoh32(results->count); ++ AP6211_DEBUG("results->count = %d\n", results->count); ++ ++ AP6211_DEBUG("results->buflen = %d\n", results->buflen); ++ status = dtoh32(list_buf->status); ++ return status; ++} ++ ++static void wl_iw_send_scan_complete(iscan_info_t *iscan) ++{ ++ union iwreq_data wrqu; ++ ++ memset(&wrqu, 0, sizeof(wrqu)); ++ ++ /* wext expects to get no data for SIOCGIWSCAN Event */ ++ wireless_send_event(iscan->dev, SIOCGIWSCAN, &wrqu, NULL); ++} ++ ++static int ++_iscan_sysioc_thread(void *data) ++{ ++ uint32 status; ++ iscan_info_t *iscan = (iscan_info_t *)data; ++ ++ DAEMONIZE("iscan_sysioc"); ++ ++ status = WL_SCAN_RESULTS_PARTIAL; ++ while (down_interruptible(&iscan->sysioc_sem) == 0) { ++ if (iscan->timer_on) { ++ del_timer(&iscan->timer); ++ iscan->timer_on = 0; ++ } ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ rtnl_lock(); ++#endif ++ status = wl_iw_iscan_get(iscan); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ rtnl_unlock(); ++#endif ++ ++ switch (status) { ++ case WL_SCAN_RESULTS_PARTIAL: ++ AP6211_DEBUG("iscanresults incomplete\n"); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ rtnl_lock(); ++#endif ++ /* make sure our buffer size is enough before going next round */ ++ wl_iw_iscan(iscan, NULL, WL_SCAN_ACTION_CONTINUE); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ rtnl_unlock(); ++#endif ++ /* Reschedule the timer */ ++ iscan->timer.expires = jiffies + msecs_to_jiffies(iscan->timer_ms); ++ add_timer(&iscan->timer); ++ iscan->timer_on = 1; ++ break; ++ case WL_SCAN_RESULTS_SUCCESS: ++ AP6211_DEBUG("iscanresults complete\n"); ++ iscan->iscan_state = ISCAN_STATE_IDLE; ++ wl_iw_send_scan_complete(iscan); ++ break; ++ case WL_SCAN_RESULTS_PENDING: ++ AP6211_DEBUG("iscanresults pending\n"); ++ /* Reschedule the timer */ ++ iscan->timer.expires = jiffies + msecs_to_jiffies(iscan->timer_ms); ++ add_timer(&iscan->timer); ++ iscan->timer_on = 1; ++ break; ++ case WL_SCAN_RESULTS_ABORTED: ++ AP6211_DEBUG("iscanresults aborted\n"); ++ iscan->iscan_state = ISCAN_STATE_IDLE; ++ wl_iw_send_scan_complete(iscan); ++ break; ++ default: ++ AP6211_DEBUG("iscanresults returned unknown status %d\n", status); ++ break; ++ } ++ } ++ complete_and_exit(&iscan->sysioc_exited, 0); ++} ++ ++int ++wl_iw_attach(struct net_device *dev, void * dhdp) ++{ ++ iscan_info_t *iscan = NULL; ++ ++ if (!dev) ++ return 0; ++ ++ iscan = kmalloc(sizeof(iscan_info_t), GFP_KERNEL); ++ if (!iscan) ++ return -ENOMEM; ++ memset(iscan, 0, sizeof(iscan_info_t)); ++ iscan->sysioc_pid = -1; ++ /* we only care about main interface so save a global here */ ++ g_iscan = iscan; ++ iscan->dev = dev; ++ iscan->iscan_state = ISCAN_STATE_IDLE; ++ ++ ++ /* Set up the timer */ ++ iscan->timer_ms = 2000; ++ init_timer(&iscan->timer); ++ iscan->timer.data = (ulong)iscan; ++ iscan->timer.function = wl_iw_timerfunc; ++ ++ sema_init(&iscan->sysioc_sem, 0); ++ init_completion(&iscan->sysioc_exited); ++ iscan->sysioc_pid = kernel_thread(_iscan_sysioc_thread, iscan, 0); ++ if (iscan->sysioc_pid < 0) ++ return -ENOMEM; ++ return 0; ++} ++ ++void wl_iw_detach(void) ++{ ++ iscan_buf_t *buf; ++ iscan_info_t *iscan = g_iscan; ++ if (!iscan) ++ return; ++ if (iscan->sysioc_pid >= 0) { ++ KILL_PROC(iscan->sysioc_pid, SIGTERM); ++ wait_for_completion(&iscan->sysioc_exited); ++ } ++ ++ while (iscan->list_hdr) { ++ buf = iscan->list_hdr->next; ++ kfree(iscan->list_hdr); ++ iscan->list_hdr = buf; ++ } ++ kfree(iscan); ++ g_iscan = NULL; ++} ++ ++#endif /* USE_IW */ +diff --git a/drivers/net/wireless/ap6211/wl_iw.h b/drivers/net/wireless/ap6211/wl_iw.h +new file mode 100755 +index 0000000..c675a56 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/wl_iw.h +@@ -0,0 +1,161 @@ ++/* ++ * Linux Wireless Extensions support ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: wl_iw.h 291086 2011-10-21 01:17:24Z $ ++ */ ++ ++#ifndef _wl_iw_h_ ++#define _wl_iw_h_ ++ ++#include ++ ++#include ++#include ++#include ++ ++#define WL_SCAN_PARAMS_SSID_MAX 10 ++#define GET_SSID "SSID=" ++#define GET_CHANNEL "CH=" ++#define GET_NPROBE "NPROBE=" ++#define GET_ACTIVE_ASSOC_DWELL "ACTIVE=" ++#define GET_PASSIVE_ASSOC_DWELL "PASSIVE=" ++#define GET_HOME_DWELL "HOME=" ++#define GET_SCAN_TYPE "TYPE=" ++ ++#define BAND_GET_CMD "GETBAND" ++#define BAND_SET_CMD "SETBAND" ++#define DTIM_SKIP_GET_CMD "DTIMSKIPGET" ++#define DTIM_SKIP_SET_CMD "DTIMSKIPSET" ++#define SETSUSPEND_CMD "SETSUSPENDOPT" ++#define PNOSSIDCLR_SET_CMD "PNOSSIDCLR" ++/* Lin - Is the extra space needed? */ ++#define PNOSETUP_SET_CMD "PNOSETUP " /* TLV command has extra end space */ ++#define PNOENABLE_SET_CMD "PNOFORCE" ++#define PNODEBUG_SET_CMD "PNODEBUG" ++#define TXPOWER_SET_CMD "TXPOWER" ++ ++#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] ++#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" ++ ++/* Structure to keep global parameters */ ++typedef struct wl_iw_extra_params { ++ int target_channel; /* target channel */ ++} wl_iw_extra_params_t; ++ ++struct cntry_locales_custom { ++ char iso_abbrev[WLC_CNTRY_BUF_SZ]; /* ISO 3166-1 country abbreviation */ ++ char custom_locale[WLC_CNTRY_BUF_SZ]; /* Custom firmware locale */ ++ int32 custom_locale_rev; /* Custom local revisin default -1 */ ++}; ++/* ============================================== */ ++/* Defines from wlc_pub.h */ ++#define WL_IW_RSSI_MINVAL -200 /* Low value, e.g. for forcing roam */ ++#define WL_IW_RSSI_NO_SIGNAL -91 /* NDIS RSSI link quality cutoffs */ ++#define WL_IW_RSSI_VERY_LOW -80 /* Very low quality cutoffs */ ++#define WL_IW_RSSI_LOW -70 /* Low quality cutoffs */ ++#define WL_IW_RSSI_GOOD -68 /* Good quality cutoffs */ ++#define WL_IW_RSSI_VERY_GOOD -58 /* Very good quality cutoffs */ ++#define WL_IW_RSSI_EXCELLENT -57 /* Excellent quality cutoffs */ ++#define WL_IW_RSSI_INVALID 0 /* invalid RSSI value */ ++#define MAX_WX_STRING 80 ++#define SSID_FMT_BUF_LEN ((4 * 32) + 1) ++#define isprint(c) bcm_isprint(c) ++#define WL_IW_SET_ACTIVE_SCAN (SIOCIWFIRSTPRIV+1) ++#define WL_IW_GET_RSSI (SIOCIWFIRSTPRIV+3) ++#define WL_IW_SET_PASSIVE_SCAN (SIOCIWFIRSTPRIV+5) ++#define WL_IW_GET_LINK_SPEED (SIOCIWFIRSTPRIV+7) ++#define WL_IW_GET_CURR_MACADDR (SIOCIWFIRSTPRIV+9) ++#define WL_IW_SET_STOP (SIOCIWFIRSTPRIV+11) ++#define WL_IW_SET_START (SIOCIWFIRSTPRIV+13) ++ ++#define G_SCAN_RESULTS 8*1024 ++#define WE_ADD_EVENT_FIX 0x80 ++#define G_WLAN_SET_ON 0 ++#define G_WLAN_SET_OFF 1 ++ ++ ++typedef struct wl_iw { ++ char nickname[IW_ESSID_MAX_SIZE]; ++ ++ struct iw_statistics wstats; ++ ++ int spy_num; ++ uint32 pwsec; /* pairwise wsec setting */ ++ uint32 gwsec; /* group wsec setting */ ++ bool privacy_invoked; /* IW_AUTH_PRIVACY_INVOKED setting */ ++ struct ether_addr spy_addr[IW_MAX_SPY]; ++ struct iw_quality spy_qual[IW_MAX_SPY]; ++ void *wlinfo; ++} wl_iw_t; ++ ++struct wl_ctrl { ++ struct timer_list *timer; ++ struct net_device *dev; ++ long sysioc_pid; ++ struct semaphore sysioc_sem; ++ struct completion sysioc_exited; ++}; ++ ++ ++#if WIRELESS_EXT > 12 ++#include ++extern const struct iw_handler_def wl_iw_handler_def; ++#endif /* WIRELESS_EXT > 12 */ ++ ++extern int wl_iw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); ++extern void wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data); ++extern int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats); ++int wl_iw_attach(struct net_device *dev, void * dhdp); ++int wl_iw_send_priv_event(struct net_device *dev, char *flag); ++ ++void wl_iw_detach(void); ++ ++#define CSCAN_COMMAND "CSCAN " ++#define CSCAN_TLV_PREFIX 'S' ++#define CSCAN_TLV_VERSION 1 ++#define CSCAN_TLV_SUBVERSION 0 ++#define CSCAN_TLV_TYPE_SSID_IE 'S' ++#define CSCAN_TLV_TYPE_CHANNEL_IE 'C' ++#define CSCAN_TLV_TYPE_NPROBE_IE 'N' ++#define CSCAN_TLV_TYPE_ACTIVE_IE 'A' ++#define CSCAN_TLV_TYPE_PASSIVE_IE 'P' ++#define CSCAN_TLV_TYPE_HOME_IE 'H' ++#define CSCAN_TLV_TYPE_STYPE_IE 'T' ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) ++#define IWE_STREAM_ADD_EVENT(info, stream, ends, iwe, extra) \ ++ iwe_stream_add_event(info, stream, ends, iwe, extra) ++#define IWE_STREAM_ADD_VALUE(info, event, value, ends, iwe, event_len) \ ++ iwe_stream_add_value(info, event, value, ends, iwe, event_len) ++#define IWE_STREAM_ADD_POINT(info, stream, ends, iwe, extra) \ ++ iwe_stream_add_point(info, stream, ends, iwe, extra) ++#else ++#define IWE_STREAM_ADD_EVENT(info, stream, ends, iwe, extra) \ ++ iwe_stream_add_event(stream, ends, iwe, extra) ++#define IWE_STREAM_ADD_VALUE(info, event, value, ends, iwe, event_len) \ ++ iwe_stream_add_value(event, value, ends, iwe, event_len) ++#define IWE_STREAM_ADD_POINT(info, stream, ends, iwe, extra) \ ++ iwe_stream_add_point(stream, ends, iwe, extra) ++#endif ++ ++#endif /* _wl_iw_h_ */ +diff --git a/drivers/net/wireless/ap6211/wl_linux_mon.c b/drivers/net/wireless/ap6211/wl_linux_mon.c +new file mode 100755 +index 0000000..3210664 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/wl_linux_mon.c +@@ -0,0 +1,422 @@ ++/* ++ * Broadcom Dongle Host Driver (DHD), Linux monitor network interface ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd_linux_mon.c 280623 2011-08-30 14:49:39Z $ ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++typedef enum monitor_states ++{ ++ MONITOR_STATE_DEINIT = 0x0, ++ MONITOR_STATE_INIT = 0x1, ++ MONITOR_STATE_INTERFACE_ADDED = 0x2, ++ MONITOR_STATE_INTERFACE_DELETED = 0x4 ++} monitor_states_t; ++int dhd_add_monitor(char *name, struct net_device **new_ndev); ++extern int dhd_start_xmit(struct sk_buff *skb, struct net_device *net); ++int dhd_del_monitor(struct net_device *ndev); ++int dhd_monitor_init(void *dhd_pub); ++int dhd_monitor_uninit(void); ++ ++/** ++ * Local declarations and defintions (not exposed) ++ */ ++#ifndef DHD_MAX_IFS ++#define DHD_MAX_IFS 16 ++#endif ++ ++typedef struct monitor_interface { ++ int radiotap_enabled; ++ struct net_device* real_ndev; /* The real interface that the monitor is on */ ++ struct net_device* mon_ndev; ++} monitor_interface; ++ ++typedef struct dhd_linux_monitor { ++ void *dhd_pub; ++ monitor_states_t monitor_state; ++ monitor_interface mon_if[DHD_MAX_IFS]; ++ struct mutex lock; /* lock to protect mon_if */ ++} dhd_linux_monitor_t; ++ ++static dhd_linux_monitor_t g_monitor; ++ ++static struct net_device* lookup_real_netdev(char *name); ++static monitor_interface* ndev_to_monif(struct net_device *ndev); ++static int dhd_mon_if_open(struct net_device *ndev); ++static int dhd_mon_if_stop(struct net_device *ndev); ++static int dhd_mon_if_subif_start_xmit(struct sk_buff *skb, struct net_device *ndev); ++static void dhd_mon_if_set_multicast_list(struct net_device *ndev); ++static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr); ++ ++static const struct net_device_ops dhd_mon_if_ops = { ++ .ndo_open = dhd_mon_if_open, ++ .ndo_stop = dhd_mon_if_stop, ++ .ndo_start_xmit = dhd_mon_if_subif_start_xmit, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) ++ .ndo_set_rx_mode = dhd_mon_if_set_multicast_list, ++#else ++ .ndo_set_multicast_list = dhd_mon_if_set_multicast_list, ++#endif ++ .ndo_set_mac_address = dhd_mon_if_change_mac, ++}; ++ ++/** ++ * Local static function defintions ++ */ ++ ++/* Look up dhd's net device table to find a match (e.g. interface "eth0" is a match for "mon.eth0" ++ * "p2p-eth0-0" is a match for "mon.p2p-eth0-0") ++ */ ++static struct net_device* lookup_real_netdev(char *name) ++{ ++ struct net_device *ndev_found = NULL; ++ ++ int i; ++ int len = 0; ++ int last_name_len = 0; ++ struct net_device *ndev; ++ ++ /* We need to find interface "p2p-p2p-0" corresponding to monitor interface "mon-p2p-0", ++ * Once mon iface name reaches IFNAMSIZ, it is reset to p2p0-0 and corresponding mon ++ * iface would be mon-p2p0-0. ++ */ ++ for (i = 0; i < DHD_MAX_IFS; i++) { ++ ndev = dhd_idx2net(g_monitor.dhd_pub, i); ++ ++ /* Skip "p2p" and look for "-p2p0-x" in monitor interface name. If it ++ * it matches, then this netdev is the corresponding real_netdev. ++ */ ++ if (ndev && strstr(ndev->name, "p2p-p2p0")) { ++ len = strlen("p2p"); ++ } else { ++ /* if p2p- is not present, then the IFNAMSIZ have reached and name ++ * would have got reset. In this casse,look for p2p0-x in mon-p2p0-x ++ */ ++ len = 0; ++ } ++ if (ndev && strstr(name, (ndev->name + len))) { ++ if (strlen(ndev->name) > last_name_len) { ++ ndev_found = ndev; ++ last_name_len = strlen(ndev->name); ++ } ++ } ++ } ++ ++ return ndev_found; ++} ++ ++static monitor_interface* ndev_to_monif(struct net_device *ndev) ++{ ++ int i; ++ ++ for (i = 0; i < DHD_MAX_IFS; i++) { ++ if (g_monitor.mon_if[i].mon_ndev == ndev) ++ return &g_monitor.mon_if[i]; ++ } ++ ++ return NULL; ++} ++ ++static int dhd_mon_if_open(struct net_device *ndev) ++{ ++ int ret = 0; ++ ++ AP6211_DEBUG("enter\n"); ++ return ret; ++} ++ ++static int dhd_mon_if_stop(struct net_device *ndev) ++{ ++ int ret = 0; ++ ++ AP6211_DEBUG("enter\n"); ++ return ret; ++} ++ ++static int dhd_mon_if_subif_start_xmit(struct sk_buff *skb, struct net_device *ndev) ++{ ++ int ret = 0; ++ int rtap_len; ++ int qos_len = 0; ++ int dot11_hdr_len = 24; ++ int snap_len = 6; ++ unsigned char *pdata; ++ unsigned short frame_ctl; ++ unsigned char src_mac_addr[6]; ++ unsigned char dst_mac_addr[6]; ++ struct ieee80211_hdr *dot11_hdr; ++ struct ieee80211_radiotap_header *rtap_hdr; ++ monitor_interface* mon_if; ++ ++ AP6211_DEBUG("enter\n"); ++ ++ mon_if = ndev_to_monif(ndev); ++ if (mon_if == NULL || mon_if->real_ndev == NULL) { ++ AP6211_DEBUG(" cannot find matched net dev, skip the packet\n"); ++ goto fail; ++ } ++ ++ if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header))) ++ goto fail; ++ ++ rtap_hdr = (struct ieee80211_radiotap_header *)skb->data; ++ if (unlikely(rtap_hdr->it_version)) ++ goto fail; ++ ++ rtap_len = ieee80211_get_radiotap_len(skb->data); ++ if (unlikely(skb->len < rtap_len)) ++ goto fail; ++ ++ AP6211_DEBUG("radiotap len (should be 14): %d\n", rtap_len); ++ ++ /* Skip the ratio tap header */ ++ skb_pull(skb, rtap_len); ++ ++ dot11_hdr = (struct ieee80211_hdr *)skb->data; ++ frame_ctl = le16_to_cpu(dot11_hdr->frame_control); ++ /* Check if the QoS bit is set */ ++ if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) { ++ /* Check if this ia a Wireless Distribution System (WDS) frame ++ * which has 4 MAC addresses ++ */ ++ if (dot11_hdr->frame_control & 0x0080) ++ qos_len = 2; ++ if ((dot11_hdr->frame_control & 0x0300) == 0x0300) ++ dot11_hdr_len += 6; ++ ++ memcpy(dst_mac_addr, dot11_hdr->addr1, sizeof(dst_mac_addr)); ++ memcpy(src_mac_addr, dot11_hdr->addr2, sizeof(src_mac_addr)); ++ ++ /* Skip the 802.11 header, QoS (if any) and SNAP, but leave spaces for ++ * for two MAC addresses ++ */ ++ skb_pull(skb, dot11_hdr_len + qos_len + snap_len - sizeof(src_mac_addr) * 2); ++ pdata = (unsigned char*)skb->data; ++ memcpy(pdata, dst_mac_addr, sizeof(dst_mac_addr)); ++ memcpy(pdata + sizeof(dst_mac_addr), src_mac_addr, sizeof(src_mac_addr)); ++ PKTSETPRIO(skb, 0); ++ ++ AP6211_DEBUG("if name: %s, matched if name %s\n", ndev->name, mon_if->real_ndev->name); ++ ++ /* Use the real net device to transmit the packet */ ++ ret = dhd_start_xmit(skb, mon_if->real_ndev); ++ ++ return ret; ++ } ++fail: ++ dev_kfree_skb(skb); ++ return 0; ++} ++ ++static void dhd_mon_if_set_multicast_list(struct net_device *ndev) ++{ ++ monitor_interface* mon_if; ++ ++ mon_if = ndev_to_monif(ndev); ++ if (mon_if == NULL || mon_if->real_ndev == NULL) { ++ AP6211_DEBUG(" cannot find matched net dev, skip the packet\n"); ++ } else { ++ AP6211_DEBUG("enter, if name: %s, matched if name %s\n", ++ ndev->name, mon_if->real_ndev->name); ++ } ++} ++ ++static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr) ++{ ++ int ret = 0; ++ monitor_interface* mon_if; ++ ++ mon_if = ndev_to_monif(ndev); ++ if (mon_if == NULL || mon_if->real_ndev == NULL) { ++ AP6211_DEBUG(" cannot find matched net dev, skip the packet\n"); ++ } else { ++ AP6211_DEBUG("enter, if name: %s, matched if name %s\n", ++ ndev->name, mon_if->real_ndev->name); ++ } ++ return ret; ++} ++ ++/** ++ * Global function definitions (declared in dhd_linux_mon.h) ++ */ ++ ++int dhd_add_monitor(char *name, struct net_device **new_ndev) ++{ ++ int i; ++ int idx = -1; ++ int ret = 0; ++ struct net_device* ndev = NULL; ++ dhd_linux_monitor_t **dhd_mon; ++ ++ mutex_lock(&g_monitor.lock); ++ ++ AP6211_DEBUG("enter, if name: %s\n", name); ++ if (!name || !new_ndev) { ++ AP6211_DEBUG("invalid parameters\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ /* ++ * Find a vacancy ++ */ ++ for (i = 0; i < DHD_MAX_IFS; i++) ++ if (g_monitor.mon_if[i].mon_ndev == NULL) { ++ idx = i; ++ break; ++ } ++ if (idx == -1) { ++ AP6211_DEBUG("exceeds maximum interfaces\n"); ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ ndev = alloc_etherdev(sizeof(dhd_linux_monitor_t*)); ++ if (!ndev) { ++ AP6211_DEBUG("failed to allocate memory\n"); ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ ndev->type = ARPHRD_IEEE80211_RADIOTAP; ++ strncpy(ndev->name, name, IFNAMSIZ); ++ ndev->name[IFNAMSIZ - 1] = 0; ++ ndev->netdev_ops = &dhd_mon_if_ops; ++ ++ ret = register_netdevice(ndev); ++ if (ret) { ++ AP6211_DEBUG(" register_netdevice failed (%d)\n", ret); ++ goto out; ++ } ++ ++ *new_ndev = ndev; ++ g_monitor.mon_if[idx].radiotap_enabled = TRUE; ++ g_monitor.mon_if[idx].mon_ndev = ndev; ++ g_monitor.mon_if[idx].real_ndev = lookup_real_netdev(name); ++ dhd_mon = (dhd_linux_monitor_t **)netdev_priv(ndev); ++ *dhd_mon = &g_monitor; ++ g_monitor.monitor_state = MONITOR_STATE_INTERFACE_ADDED; ++ AP6211_DEBUG("net device returned: 0x%p\n", ndev); ++ AP6211_DEBUG("found a matched net device, name %s\n", g_monitor.mon_if[idx].real_ndev->name); ++ ++out: ++ if (ret && ndev) ++ free_netdev(ndev); ++ ++ mutex_unlock(&g_monitor.lock); ++ return ret; ++ ++} ++ ++int dhd_del_monitor(struct net_device *ndev) ++{ ++ int i; ++ bool rollback_lock = false; ++ if (!ndev) ++ return -EINVAL; ++ mutex_lock(&g_monitor.lock); ++ for (i = 0; i < DHD_MAX_IFS; i++) { ++ if (g_monitor.mon_if[i].mon_ndev == ndev || ++ g_monitor.mon_if[i].real_ndev == ndev) { ++ g_monitor.mon_if[i].real_ndev = NULL; ++ if (rtnl_is_locked()) { ++ rtnl_unlock(); ++ rollback_lock = true; ++ } ++ unregister_netdev(g_monitor.mon_if[i].mon_ndev); ++ free_netdev(g_monitor.mon_if[i].mon_ndev); ++ g_monitor.mon_if[i].mon_ndev = NULL; ++ g_monitor.monitor_state = MONITOR_STATE_INTERFACE_DELETED; ++ break; ++ } ++ } ++ if (rollback_lock) { ++ rtnl_lock(); ++ rollback_lock = false; ++ } ++ ++ if (g_monitor.monitor_state != ++ MONITOR_STATE_INTERFACE_DELETED) ++ AP6211_DEBUG("interface not found in monitor IF array, is this a monitor IF? 0x%p\n", ++ ndev); ++ mutex_unlock(&g_monitor.lock); ++ ++ return 0; ++} ++ ++int dhd_monitor_init(void *dhd_pub) ++{ ++ if (g_monitor.monitor_state == MONITOR_STATE_DEINIT) { ++ g_monitor.dhd_pub = dhd_pub; ++ mutex_init(&g_monitor.lock); ++ g_monitor.monitor_state = MONITOR_STATE_INIT; ++ } ++ return 0; ++} ++ ++int dhd_monitor_uninit(void) ++{ ++ int i; ++ struct net_device *ndev; ++ bool rollback_lock = false; ++ mutex_lock(&g_monitor.lock); ++ if (g_monitor.monitor_state != MONITOR_STATE_DEINIT) { ++ for (i = 0; i < DHD_MAX_IFS; i++) { ++ ndev = g_monitor.mon_if[i].mon_ndev; ++ if (ndev) { ++ if (rtnl_is_locked()) { ++ rtnl_unlock(); ++ rollback_lock = true; ++ } ++ unregister_netdev(ndev); ++ free_netdev(ndev); ++ g_monitor.mon_if[i].real_ndev = NULL; ++ g_monitor.mon_if[i].mon_ndev = NULL; ++ if (rollback_lock) { ++ rtnl_lock(); ++ rollback_lock = false; ++ } ++ } ++ } ++ g_monitor.monitor_state = MONITOR_STATE_DEINIT; ++ } ++ mutex_unlock(&g_monitor.lock); ++ return 0; ++} +diff --git a/drivers/net/wireless/ap6211/wldev_common.c b/drivers/net/wireless/ap6211/wldev_common.c +new file mode 100755 +index 0000000..596e448 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/wldev_common.c +@@ -0,0 +1,374 @@ ++/* ++ * Common function shared by Linux WEXT, cfg80211 and p2p drivers ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: wldev_common.c,v 1.1.4.1.2.14 2011-02-09 01:40:07 $ ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++ ++#define htod32(i) i ++#define htod16(i) i ++#define dtoh32(i) i ++#define dtoh16(i) i ++#define htodchanspec(i) i ++#define dtohchanspec(i) i ++ ++extern int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd); ++ ++s32 wldev_ioctl( ++ struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set) ++{ ++ s32 ret = 0; ++ struct wl_ioctl ioc; ++ ++ ++ memset(&ioc, 0, sizeof(ioc)); ++ ioc.cmd = cmd; ++ ioc.buf = arg; ++ ioc.len = len; ++ ioc.set = set; ++ ++ ret = dhd_ioctl_entry_local(dev, &ioc, cmd); ++ ++ return ret; ++} ++ ++/* Format a iovar buffer, not bsscfg indexed. The bsscfg index will be ++ * taken care of in dhd_ioctl_entry. Internal use only, not exposed to ++ * wl_iw, wl_cfg80211 and wl_cfgp2p ++ */ ++static s32 wldev_mkiovar( ++ s8 *iovar_name, s8 *param, s32 paramlen, ++ s8 *iovar_buf, u32 buflen) ++{ ++ s32 iolen = 0; ++ ++ iolen = bcm_mkiovar(iovar_name, param, paramlen, iovar_buf, buflen); ++ return iolen; ++} ++ ++s32 wldev_iovar_getbuf( ++ struct net_device *dev, s8 *iovar_name, ++ void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync) ++{ ++ s32 ret = 0; ++ if (buf_sync) { ++ mutex_lock(buf_sync); ++ } ++ wldev_mkiovar(iovar_name, param, paramlen, buf, buflen); ++ ret = wldev_ioctl(dev, WLC_GET_VAR, buf, buflen, FALSE); ++ if (buf_sync) ++ mutex_unlock(buf_sync); ++ return ret; ++} ++ ++ ++s32 wldev_iovar_setbuf( ++ struct net_device *dev, s8 *iovar_name, ++ void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync) ++{ ++ s32 ret = 0; ++ s32 iovar_len; ++ if (buf_sync) { ++ mutex_lock(buf_sync); ++ } ++ iovar_len = wldev_mkiovar(iovar_name, param, paramlen, buf, buflen); ++ if (iovar_len > 0) ++ ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE); ++ else ++ ret = BCME_BUFTOOSHORT; ++ if (buf_sync) ++ mutex_unlock(buf_sync); ++ return ret; ++} ++ ++s32 wldev_iovar_setint( ++ struct net_device *dev, s8 *iovar, s32 val) ++{ ++ s8 iovar_buf[WLC_IOCTL_SMLEN]; ++ ++ val = htod32(val); ++ memset(iovar_buf, 0, sizeof(iovar_buf)); ++ return wldev_iovar_setbuf(dev, iovar, &val, sizeof(val), iovar_buf, ++ sizeof(iovar_buf), NULL); ++} ++ ++ ++s32 wldev_iovar_getint( ++ struct net_device *dev, s8 *iovar, s32 *pval) ++{ ++ s8 iovar_buf[WLC_IOCTL_SMLEN]; ++ s32 err; ++ ++ memset(iovar_buf, 0, sizeof(iovar_buf)); ++ err = wldev_iovar_getbuf(dev, iovar, pval, sizeof(*pval), iovar_buf, ++ sizeof(iovar_buf), NULL); ++ if (err == 0) ++ { ++ memcpy(pval, iovar_buf, sizeof(*pval)); ++ *pval = dtoh32(*pval); ++ } ++ return err; ++} ++ ++/** Format a bsscfg indexed iovar buffer. The bsscfg index will be ++ * taken care of in dhd_ioctl_entry. Internal use only, not exposed to ++ * wl_iw, wl_cfg80211 and wl_cfgp2p ++ */ ++s32 wldev_mkiovar_bsscfg( ++ const s8 *iovar_name, s8 *param, s32 paramlen, ++ s8 *iovar_buf, s32 buflen, s32 bssidx) ++{ ++ const s8 *prefix = "bsscfg:"; ++ s8 *p; ++ u32 prefixlen; ++ u32 namelen; ++ u32 iolen; ++ ++ if (bssidx == 0) { ++ return wldev_mkiovar((s8*)iovar_name, (s8 *)param, paramlen, ++ (s8 *) iovar_buf, buflen); ++ } ++ ++ prefixlen = (u32) strlen(prefix); /* lengh of bsscfg prefix */ ++ namelen = (u32) strlen(iovar_name) + 1; /* lengh of iovar name + null */ ++ iolen = prefixlen + namelen + sizeof(u32) + paramlen; ++ ++ if (buflen < 0 || iolen > (u32)buflen) ++ { ++ AP6211_ERR("%s: buffer is too short\n", __FUNCTION__); ++ return BCME_BUFTOOSHORT; ++ } ++ ++ p = (s8 *)iovar_buf; ++ ++ /* copy prefix, no null */ ++ memcpy(p, prefix, prefixlen); ++ p += prefixlen; ++ ++ /* copy iovar name including null */ ++ memcpy(p, iovar_name, namelen); ++ p += namelen; ++ ++ /* bss config index as first param */ ++ bssidx = htod32(bssidx); ++ memcpy(p, &bssidx, sizeof(u32)); ++ p += sizeof(u32); ++ ++ /* parameter buffer follows */ ++ if (paramlen) ++ memcpy(p, param, paramlen); ++ ++ return iolen; ++ ++} ++ ++s32 wldev_iovar_getbuf_bsscfg( ++ struct net_device *dev, s8 *iovar_name, ++ void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync) ++{ ++ s32 ret = 0; ++ if (buf_sync) { ++ mutex_lock(buf_sync); ++ } ++ ++ wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx); ++ ret = wldev_ioctl(dev, WLC_GET_VAR, buf, buflen, FALSE); ++ if (buf_sync) { ++ mutex_unlock(buf_sync); ++ } ++ return ret; ++ ++} ++ ++s32 wldev_iovar_setbuf_bsscfg( ++ struct net_device *dev, s8 *iovar_name, ++ void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync) ++{ ++ s32 ret = 0; ++ s32 iovar_len; ++ if (buf_sync) { ++ mutex_lock(buf_sync); ++ } ++ iovar_len = wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx); ++ if (iovar_len > 0) ++ ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE); ++ else { ++ ret = BCME_BUFTOOSHORT; ++ } ++ ++ if (buf_sync) { ++ mutex_unlock(buf_sync); ++ } ++ return ret; ++} ++ ++s32 wldev_iovar_setint_bsscfg( ++ struct net_device *dev, s8 *iovar, s32 val, s32 bssidx) ++{ ++ s8 iovar_buf[WLC_IOCTL_SMLEN]; ++ ++ val = htod32(val); ++ memset(iovar_buf, 0, sizeof(iovar_buf)); ++ return wldev_iovar_setbuf_bsscfg(dev, iovar, &val, sizeof(val), iovar_buf, ++ sizeof(iovar_buf), bssidx, NULL); ++} ++ ++ ++s32 wldev_iovar_getint_bsscfg( ++ struct net_device *dev, s8 *iovar, s32 *pval, s32 bssidx) ++{ ++ s8 iovar_buf[WLC_IOCTL_SMLEN]; ++ s32 err; ++ ++ memset(iovar_buf, 0, sizeof(iovar_buf)); ++ err = wldev_iovar_getbuf_bsscfg(dev, iovar, pval, sizeof(*pval), iovar_buf, ++ sizeof(iovar_buf), bssidx, NULL); ++ if (err == 0) ++ { ++ memcpy(pval, iovar_buf, sizeof(*pval)); ++ *pval = dtoh32(*pval); ++ } ++ return err; ++} ++ ++int wldev_get_link_speed( ++ struct net_device *dev, int *plink_speed) ++{ ++ int error; ++ ++ if (!plink_speed) ++ return -ENOMEM; ++ error = wldev_ioctl(dev, WLC_GET_RATE, plink_speed, sizeof(int), 0); ++ if (unlikely(error)) ++ return error; ++ ++ /* Convert internal 500Kbps to Kbps */ ++ *plink_speed *= 500; ++ return error; ++} ++ ++int wldev_get_rssi( ++ struct net_device *dev, int *prssi) ++{ ++ scb_val_t scb_val; ++ int error; ++ ++ if (!prssi) ++ return -ENOMEM; ++ bzero(&scb_val, sizeof(scb_val_t)); ++ ++ error = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t), 0); ++ if (unlikely(error)) ++ return error; ++ ++ *prssi = dtoh32(scb_val.val); ++ return error; ++} ++ ++int wldev_get_ssid( ++ struct net_device *dev, wlc_ssid_t *pssid) ++{ ++ int error; ++ ++ if (!pssid) ++ return -ENOMEM; ++ error = wldev_ioctl(dev, WLC_GET_SSID, pssid, sizeof(wlc_ssid_t), 0); ++ if (unlikely(error)) ++ return error; ++ pssid->SSID_len = dtoh32(pssid->SSID_len); ++ return error; ++} ++ ++int wldev_get_band( ++ struct net_device *dev, uint *pband) ++{ ++ int error; ++ ++ error = wldev_ioctl(dev, WLC_GET_BAND, pband, sizeof(uint), 0); ++ return error; ++} ++ ++int wldev_set_band( ++ struct net_device *dev, uint band) ++{ ++ int error = -1; ++ ++ if ((band == WLC_BAND_AUTO) || (band == WLC_BAND_5G) || (band == WLC_BAND_2G)) { ++ error = wldev_ioctl(dev, WLC_SET_BAND, &band, sizeof(band), true); ++ if (!error) ++ dhd_bus_band_set(dev, band); ++ } ++ return error; ++} ++ ++int wldev_set_country( ++ struct net_device *dev, char *country_code) ++{ ++ int error = -1; ++ wl_country_t cspec = {{0}, 0, {0}}; ++ scb_val_t scbval; ++ char smbuf[WLC_IOCTL_SMLEN]; ++ ++ if (!country_code) ++ return error; ++ ++ error = wldev_iovar_getbuf(dev, "country", &cspec, sizeof(cspec), ++ smbuf, sizeof(smbuf), NULL); ++ if (error < 0) ++ AP6211_ERR("%s: get country failed = %d\n", __FUNCTION__, error); ++ ++ if ((error < 0) || ++ (strncmp(country_code, smbuf, WLC_CNTRY_BUF_SZ) != 0)) { ++ bzero(&scbval, sizeof(scb_val_t)); ++ error = wldev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), true); ++ if (error < 0) { ++ AP6211_ERR("%s: set country failed due to Disassoc error %d\n", ++ __FUNCTION__, error); ++ return error; ++ } ++ cspec.rev = -1; ++ memcpy(cspec.country_abbrev, country_code, WLC_CNTRY_BUF_SZ); ++ memcpy(cspec.ccode, country_code, WLC_CNTRY_BUF_SZ); ++ get_customized_country_code((char *)&cspec.country_abbrev, &cspec); ++ error = wldev_iovar_setbuf(dev, "country", &cspec, sizeof(cspec), ++ smbuf, sizeof(smbuf), NULL); ++ if (error < 0) { ++ AP6211_ERR("%s: set country for %s as %s rev %d failed\n", ++ __FUNCTION__, country_code, cspec.ccode, cspec.rev); ++ return error; ++ } ++ dhd_bus_country_set(dev, &cspec); ++ AP6211_ERR("%s: set country for %s as %s rev %d\n", ++ __FUNCTION__, country_code, cspec.ccode, cspec.rev); ++ } ++ return 0; ++} +diff --git a/drivers/net/wireless/ap6211/wldev_common.h b/drivers/net/wireless/ap6211/wldev_common.h +new file mode 100755 +index 0000000..f9bf425 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/wldev_common.h +@@ -0,0 +1,111 @@ ++/* ++ * Common function shared by Linux WEXT, cfg80211 and p2p drivers ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: wldev_common.h,v 1.1.4.1.2.14 2011-02-09 01:40:07 $ ++ */ ++#ifndef __WLDEV_COMMON_H__ ++#define __WLDEV_COMMON_H__ ++ ++#include ++ ++/* wl_dev_ioctl - get/set IOCTLs, will call net_device's do_ioctl (or ++ * netdev_ops->ndo_do_ioctl in new kernels) ++ * @dev: the net_device handle ++ */ ++s32 wldev_ioctl( ++ struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set); ++ ++/** Retrieve named IOVARs, this function calls wl_dev_ioctl with ++ * WLC_GET_VAR IOCTL code ++ */ ++s32 wldev_iovar_getbuf( ++ struct net_device *dev, s8 *iovar_name, ++ void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync); ++ ++/** Set named IOVARs, this function calls wl_dev_ioctl with ++ * WLC_SET_VAR IOCTL code ++ */ ++s32 wldev_iovar_setbuf( ++ struct net_device *dev, s8 *iovar_name, ++ void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync); ++ ++s32 wldev_iovar_setint( ++ struct net_device *dev, s8 *iovar, s32 val); ++ ++s32 wldev_iovar_getint( ++ struct net_device *dev, s8 *iovar, s32 *pval); ++ ++/** The following function can be implemented if there is a need for bsscfg ++ * indexed IOVARs ++ */ ++ ++s32 wldev_mkiovar_bsscfg( ++ const s8 *iovar_name, s8 *param, s32 paramlen, ++ s8 *iovar_buf, s32 buflen, s32 bssidx); ++ ++/** Retrieve named and bsscfg indexed IOVARs, this function calls wl_dev_ioctl with ++ * WLC_GET_VAR IOCTL code ++ */ ++s32 wldev_iovar_getbuf_bsscfg( ++ struct net_device *dev, s8 *iovar_name, void *param, s32 paramlen, ++ void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync); ++ ++/** Set named and bsscfg indexed IOVARs, this function calls wl_dev_ioctl with ++ * WLC_SET_VAR IOCTL code ++ */ ++s32 wldev_iovar_setbuf_bsscfg( ++ struct net_device *dev, s8 *iovar_name, void *param, s32 paramlen, ++ void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync); ++ ++s32 wldev_iovar_getint_bsscfg( ++ struct net_device *dev, s8 *iovar, s32 *pval, s32 bssidx); ++ ++s32 wldev_iovar_setint_bsscfg( ++ struct net_device *dev, s8 *iovar, s32 val, s32 bssidx); ++ ++extern void get_customized_country_code(char *country_iso_code, wl_country_t *cspec); ++extern void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec); ++extern void dhd_bus_band_set(struct net_device *dev, uint band); ++extern int wldev_set_country(struct net_device *dev, char *country_code); ++extern int net_os_wake_lock(struct net_device *dev); ++extern int net_os_wake_unlock(struct net_device *dev); ++extern int net_os_wake_lock_timeout(struct net_device *dev); ++extern int net_os_wake_lock_timeout_enable(struct net_device *dev, int val); ++extern int net_os_set_dtim_skip(struct net_device *dev, int val); ++extern int net_os_set_suspend_disable(struct net_device *dev, int val); ++extern int net_os_set_suspend(struct net_device *dev, int val, int force); ++extern int wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid, ++ int max, int *bytes_left); ++ ++/* Get the link speed from dongle, speed is in kpbs */ ++int wldev_get_link_speed(struct net_device *dev, int *plink_speed); ++ ++int wldev_get_rssi(struct net_device *dev, int *prssi); ++ ++int wldev_get_ssid(struct net_device *dev, wlc_ssid_t *pssid); ++ ++int wldev_get_band(struct net_device *dev, uint *pband); ++ ++int wldev_set_band(struct net_device *dev, uint band); ++ ++#endif /* __WLDEV_COMMON_H__ */ +-- +1.9.1 +