From 9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 Mon Sep 17 00:00:00 2001 From: Yunhong Jiang Date: Tue, 4 Aug 2015 12:17:53 -0700 Subject: Add the rt linux 4.1.3-rt3 as base Import the rt linux 4.1.3-rt3 as OPNFV kvm base. It's from git://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git linux-4.1.y-rt and the base is: commit 0917f823c59692d751951bf5ea699a2d1e2f26a2 Author: Sebastian Andrzej Siewior Date: Sat Jul 25 12:13:34 2015 +0200 Prepare v4.1.3-rt3 Signed-off-by: Sebastian Andrzej Siewior We lose all the git history this way and it's not good. We should apply another opnfv project repo in future. Change-Id: I87543d81c9df70d99c5001fbdf646b202c19f423 Signed-off-by: Yunhong Jiang --- kernel/drivers/staging/rtl8192e/Kconfig | 47 + kernel/drivers/staging/rtl8192e/Makefile | 21 + kernel/drivers/staging/rtl8192e/TODO | 2 + kernel/drivers/staging/rtl8192e/dot11d.c | 216 ++ kernel/drivers/staging/rtl8192e/dot11d.h | 103 + kernel/drivers/staging/rtl8192e/license | 339 ++ kernel/drivers/staging/rtl8192e/rtl8192e/Kconfig | 9 + kernel/drivers/staging/rtl8192e/rtl8192e/Makefile | 20 + .../drivers/staging/rtl8192e/rtl8192e/r8190P_def.h | 410 +++ .../staging/rtl8192e/rtl8192e/r8190P_rtl8256.c | 309 ++ .../staging/rtl8192e/rtl8192e/r8190P_rtl8256.h | 31 + .../staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c | 380 ++ .../staging/rtl8192e/rtl8192e/r8192E_cmdpkt.h | 159 + .../drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2416 +++++++++++++ .../drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h | 62 + .../staging/rtl8192e/rtl8192e/r8192E_firmware.c | 319 ++ .../staging/rtl8192e/rtl8192e/r8192E_firmware.h | 72 + .../drivers/staging/rtl8192e/rtl8192e/r8192E_hw.h | 453 +++ .../staging/rtl8192e/rtl8192e/r8192E_hwimg.c | 565 +++ .../staging/rtl8192e/rtl8192e/r8192E_hwimg.h | 51 + .../drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c | 1636 +++++++++ .../drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h | 120 + .../staging/rtl8192e/rtl8192e/r8192E_phyreg.h | 852 +++++ .../staging/rtl8192e/rtl8192e/r819xE_phyreg.h | 908 +++++ kernel/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c | 277 ++ kernel/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h | 44 + .../drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 3122 ++++++++++++++++ .../drivers/staging/rtl8192e/rtl8192e/rtl_core.h | 1076 ++++++ .../drivers/staging/rtl8192e/rtl8192e/rtl_crypto.h | 382 ++ kernel/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c | 2995 ++++++++++++++++ kernel/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h | 316 ++ .../drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c | 139 + .../drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.h | 29 + .../staging/rtl8192e/rtl8192e/rtl_ethtool.c | 53 + kernel/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c | 100 + kernel/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h | 51 + kernel/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c | 119 + kernel/drivers/staging/rtl8192e/rtl8192e/rtl_pm.h | 29 + kernel/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c | 316 ++ kernel/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h | 47 + kernel/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c | 1341 +++++++ kernel/drivers/staging/rtl8192e/rtl8192e/rtl_wx.h | 30 + kernel/drivers/staging/rtl8192e/rtl819x_BA.h | 77 + kernel/drivers/staging/rtl8192e/rtl819x_BAProc.c | 571 +++ kernel/drivers/staging/rtl8192e/rtl819x_HT.h | 428 +++ kernel/drivers/staging/rtl8192e/rtl819x_HTProc.c | 919 +++++ kernel/drivers/staging/rtl8192e/rtl819x_Qos.h | 389 ++ kernel/drivers/staging/rtl8192e/rtl819x_TS.h | 73 + kernel/drivers/staging/rtl8192e/rtl819x_TSProc.c | 554 +++ kernel/drivers/staging/rtl8192e/rtllib.h | 2975 ++++++++++++++++ kernel/drivers/staging/rtl8192e/rtllib_crypt.c | 254 ++ kernel/drivers/staging/rtl8192e/rtllib_crypt.h | 34 + .../drivers/staging/rtl8192e/rtllib_crypt_ccmp.c | 457 +++ .../drivers/staging/rtl8192e/rtllib_crypt_tkip.c | 779 ++++ kernel/drivers/staging/rtl8192e/rtllib_crypt_wep.c | 289 ++ kernel/drivers/staging/rtl8192e/rtllib_debug.h | 88 + kernel/drivers/staging/rtl8192e/rtllib_module.c | 268 ++ kernel/drivers/staging/rtl8192e/rtllib_rx.c | 2678 ++++++++++++++ kernel/drivers/staging/rtl8192e/rtllib_softmac.c | 3758 ++++++++++++++++++++ .../drivers/staging/rtl8192e/rtllib_softmac_wx.c | 661 ++++ kernel/drivers/staging/rtl8192e/rtllib_tx.c | 988 +++++ kernel/drivers/staging/rtl8192e/rtllib_wx.c | 881 +++++ 62 files changed, 37087 insertions(+) create mode 100644 kernel/drivers/staging/rtl8192e/Kconfig create mode 100644 kernel/drivers/staging/rtl8192e/Makefile create mode 100644 kernel/drivers/staging/rtl8192e/TODO create mode 100644 kernel/drivers/staging/rtl8192e/dot11d.c create mode 100644 kernel/drivers/staging/rtl8192e/dot11d.h create mode 100644 kernel/drivers/staging/rtl8192e/license create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/Kconfig create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/Makefile create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/r8190P_def.h create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.h create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_hw.h create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_hwimg.c create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_hwimg.h create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_phyreg.h create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/r819xE_phyreg.h create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/rtl_core.c create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/rtl_core.h create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/rtl_crypto.h create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.h create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/rtl_ethtool.c create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/rtl_pm.h create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c create mode 100644 kernel/drivers/staging/rtl8192e/rtl8192e/rtl_wx.h create mode 100644 kernel/drivers/staging/rtl8192e/rtl819x_BA.h create mode 100644 kernel/drivers/staging/rtl8192e/rtl819x_BAProc.c create mode 100644 kernel/drivers/staging/rtl8192e/rtl819x_HT.h create mode 100644 kernel/drivers/staging/rtl8192e/rtl819x_HTProc.c create mode 100644 kernel/drivers/staging/rtl8192e/rtl819x_Qos.h create mode 100644 kernel/drivers/staging/rtl8192e/rtl819x_TS.h create mode 100644 kernel/drivers/staging/rtl8192e/rtl819x_TSProc.c create mode 100644 kernel/drivers/staging/rtl8192e/rtllib.h create mode 100644 kernel/drivers/staging/rtl8192e/rtllib_crypt.c create mode 100644 kernel/drivers/staging/rtl8192e/rtllib_crypt.h create mode 100644 kernel/drivers/staging/rtl8192e/rtllib_crypt_ccmp.c create mode 100644 kernel/drivers/staging/rtl8192e/rtllib_crypt_tkip.c create mode 100644 kernel/drivers/staging/rtl8192e/rtllib_crypt_wep.c create mode 100644 kernel/drivers/staging/rtl8192e/rtllib_debug.h create mode 100644 kernel/drivers/staging/rtl8192e/rtllib_module.c create mode 100644 kernel/drivers/staging/rtl8192e/rtllib_rx.c create mode 100644 kernel/drivers/staging/rtl8192e/rtllib_softmac.c create mode 100644 kernel/drivers/staging/rtl8192e/rtllib_softmac_wx.c create mode 100644 kernel/drivers/staging/rtl8192e/rtllib_tx.c create mode 100644 kernel/drivers/staging/rtl8192e/rtllib_wx.c (limited to 'kernel/drivers/staging/rtl8192e') diff --git a/kernel/drivers/staging/rtl8192e/Kconfig b/kernel/drivers/staging/rtl8192e/Kconfig new file mode 100644 index 000000000..4602a47cd --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/Kconfig @@ -0,0 +1,47 @@ +config RTLLIB + tristate "Support for rtllib wireless devices" + depends on WLAN && m + default n + select LIB80211 + ---help--- + If you have a wireless card that uses rtllib, say + Y. Currently the only card is the rtl8192e. + + If unsure, say N. + +if RTLLIB + +config RTLLIB_CRYPTO_CCMP + tristate "Support for rtllib CCMP crypto" + depends on RTLLIB + select CRYPTO_AES + default y + ---help--- + CCMP crypto driver for rtllib. + + If you enabled RTLLIB, you want this. + +config RTLLIB_CRYPTO_TKIP + tristate "Support for rtllib TKIP crypto" + depends on RTLLIB + select CRYPTO_ARC4 + select CRYPTO_MICHAEL_MIC + default y + ---help--- + TKIP crypto driver for rtllib. + + If you enabled RTLLIB, you want this. + +config RTLLIB_CRYPTO_WEP + tristate "Support for rtllib WEP crypto" + select CRYPTO_ARC4 + depends on RTLLIB + default y + ---help--- + TKIP crypto driver for rtllib. + + If you enabled RTLLIB, you want this. + +source "drivers/staging/rtl8192e/rtl8192e/Kconfig" + +endif diff --git a/kernel/drivers/staging/rtl8192e/Makefile b/kernel/drivers/staging/rtl8192e/Makefile new file mode 100644 index 000000000..cb18db74d --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/Makefile @@ -0,0 +1,21 @@ +rtllib-objs := \ + dot11d.o \ + rtllib_module.o \ + rtllib_rx.o \ + rtllib_tx.o \ + rtllib_wx.o \ + rtllib_softmac.o \ + rtllib_softmac_wx.o \ + rtl819x_BAProc.o \ + rtl819x_HTProc.o \ + rtl819x_TSProc.o + +obj-$(CONFIG_RTLLIB) += rtllib.o + +obj-$(CONFIG_RTLLIB_CRYPTO_CCMP) += rtllib_crypt_ccmp.o +obj-$(CONFIG_RTLLIB_CRYPTO_TKIP) += rtllib_crypt_tkip.o +obj-$(CONFIG_RTLLIB_CRYPTO_WEP) += rtllib_crypt_wep.o + +obj-$(CONFIG_RTL8192E) += rtl8192e/ + +ccflags-y += -D__CHECK_ENDIAN__ diff --git a/kernel/drivers/staging/rtl8192e/TODO b/kernel/drivers/staging/rtl8192e/TODO new file mode 100644 index 000000000..d51f159d1 --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/TODO @@ -0,0 +1,2 @@ +* merge into drivers/net/wireless/rtllib/rtl8192e +* clean up function naming diff --git a/kernel/drivers/staging/rtl8192e/dot11d.c b/kernel/drivers/staging/rtl8192e/dot11d.c new file mode 100644 index 000000000..ef9da863c --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/dot11d.c @@ -0,0 +1,216 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ +#include "dot11d.h" + +struct channel_list { + u8 Channel[32]; + u8 Len; +}; + +static struct channel_list ChannelPlan[] = { + {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 52, 56, 60, 64, + 149, 153, 157, 161, 165}, 24}, + {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 11}, + {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, 44, 48, 52, 56, + 60, 64}, 21}, + {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13}, + {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13}, + {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 36, 40, 44, 48, 52, + 56, 60, 64}, 22}, + {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 36, 40, 44, 48, 52, + 56, 60, 64}, 22}, + {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13}, + {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 36, 40, 44, 48, 52, + 56, 60, 64}, 22}, + {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 36, 40, 44, 48, 52, + 56, 60, 64}, 22}, + {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, 14}, + {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13}, + {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, 44, 48, 52, + 56, 60, 64}, 21} +}; + +void dot11d_init(struct rtllib_device *ieee) +{ + struct rt_dot11d_info *pDot11dInfo = GET_DOT11D_INFO(ieee); + + pDot11dInfo->bEnabled = false; + + pDot11dInfo->State = DOT11D_STATE_NONE; + pDot11dInfo->CountryIeLen = 0; + memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1); + memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1); + RESET_CIE_WATCHDOG(ieee); + +} +EXPORT_SYMBOL(dot11d_init); + +void Dot11d_Channelmap(u8 channel_plan, struct rtllib_device *ieee) +{ + int i, max_chan = 14, min_chan = 1; + + ieee->bGlobalDomain = false; + + if (ChannelPlan[channel_plan].Len != 0) { + memset(GET_DOT11D_INFO(ieee)->channel_map, 0, + sizeof(GET_DOT11D_INFO(ieee)->channel_map)); + for (i = 0; i < ChannelPlan[channel_plan].Len; i++) { + if (ChannelPlan[channel_plan].Channel[i] < min_chan || + ChannelPlan[channel_plan].Channel[i] > max_chan) + break; + GET_DOT11D_INFO(ieee)->channel_map[ChannelPlan + [channel_plan].Channel[i]] = 1; + } + } + + switch (channel_plan) { + case COUNTRY_CODE_GLOBAL_DOMAIN: + ieee->bGlobalDomain = true; + for (i = 12; i <= 14; i++) + GET_DOT11D_INFO(ieee)->channel_map[i] = 2; + ieee->IbssStartChnl = 10; + ieee->ibss_maxjoin_chal = 11; + break; + + case COUNTRY_CODE_WORLD_WIDE_13: + for (i = 12; i <= 13; i++) + GET_DOT11D_INFO(ieee)->channel_map[i] = 2; + ieee->IbssStartChnl = 10; + ieee->ibss_maxjoin_chal = 11; + break; + + default: + ieee->IbssStartChnl = 1; + ieee->ibss_maxjoin_chal = 14; + break; + } +} +EXPORT_SYMBOL(Dot11d_Channelmap); + + +void Dot11d_Reset(struct rtllib_device *ieee) +{ + struct rt_dot11d_info *pDot11dInfo = GET_DOT11D_INFO(ieee); + u32 i; + + memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1); + memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1); + for (i = 1; i <= 11; i++) + (pDot11dInfo->channel_map)[i] = 1; + for (i = 12; i <= 14; i++) + (pDot11dInfo->channel_map)[i] = 2; + pDot11dInfo->State = DOT11D_STATE_NONE; + pDot11dInfo->CountryIeLen = 0; + RESET_CIE_WATCHDOG(ieee); +} + +void Dot11d_UpdateCountryIe(struct rtllib_device *dev, u8 *pTaddr, + u16 CoutryIeLen, u8 *pCoutryIe) +{ + struct rt_dot11d_info *pDot11dInfo = GET_DOT11D_INFO(dev); + u8 i, j, NumTriples, MaxChnlNum; + struct chnl_txpow_triple *pTriple; + + memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1); + memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1); + MaxChnlNum = 0; + NumTriples = (CoutryIeLen - 3) / 3; + pTriple = (struct chnl_txpow_triple *)(pCoutryIe + 3); + for (i = 0; i < NumTriples; i++) { + if (MaxChnlNum >= pTriple->FirstChnl) { + netdev_info(dev->dev, "Dot11d_UpdateCountryIe(): Invalid country IE, skip it........1\n"); + return; + } + if (MAX_CHANNEL_NUMBER < (pTriple->FirstChnl + + pTriple->NumChnls)) { + netdev_info(dev->dev, "Dot11d_UpdateCountryIe(): Invalid country IE, skip it........2\n"); + return; + } + + for (j = 0; j < pTriple->NumChnls; j++) { + pDot11dInfo->channel_map[pTriple->FirstChnl + j] = 1; + pDot11dInfo->MaxTxPwrDbmList[pTriple->FirstChnl + j] = + pTriple->MaxTxPowerInDbm; + MaxChnlNum = pTriple->FirstChnl + j; + } + + pTriple = (struct chnl_txpow_triple *)((u8 *)pTriple + 3); + } + + UPDATE_CIE_SRC(dev, pTaddr); + + pDot11dInfo->CountryIeLen = CoutryIeLen; + memcpy(pDot11dInfo->CountryIeBuf, pCoutryIe, CoutryIeLen); + pDot11dInfo->State = DOT11D_STATE_LEARNED; +} + +u8 DOT11D_GetMaxTxPwrInDbm(struct rtllib_device *dev, u8 Channel) +{ + struct rt_dot11d_info *pDot11dInfo = GET_DOT11D_INFO(dev); + u8 MaxTxPwrInDbm = 255; + + if (MAX_CHANNEL_NUMBER < Channel) { + netdev_info(dev->dev, "DOT11D_GetMaxTxPwrInDbm(): Invalid Channel\n"); + return MaxTxPwrInDbm; + } + if (pDot11dInfo->channel_map[Channel]) + MaxTxPwrInDbm = pDot11dInfo->MaxTxPwrDbmList[Channel]; + + return MaxTxPwrInDbm; +} + +void DOT11D_ScanComplete(struct rtllib_device *dev) +{ + struct rt_dot11d_info *pDot11dInfo = GET_DOT11D_INFO(dev); + + switch (pDot11dInfo->State) { + case DOT11D_STATE_LEARNED: + pDot11dInfo->State = DOT11D_STATE_DONE; + break; + case DOT11D_STATE_DONE: + Dot11d_Reset(dev); + break; + case DOT11D_STATE_NONE: + break; + } +} + +int ToLegalChannel(struct rtllib_device *dev, u8 channel) +{ + struct rt_dot11d_info *pDot11dInfo = GET_DOT11D_INFO(dev); + u8 default_chn = 0; + u32 i; + + for (i = 1; i <= MAX_CHANNEL_NUMBER; i++) { + if (pDot11dInfo->channel_map[i] > 0) { + default_chn = i; + break; + } + } + + if (MAX_CHANNEL_NUMBER < channel) { + netdev_err(dev->dev, "%s(): Invalid Channel\n", __func__); + return default_chn; + } + + if (pDot11dInfo->channel_map[channel] > 0) + return channel; + + return default_chn; +} diff --git a/kernel/drivers/staging/rtl8192e/dot11d.h b/kernel/drivers/staging/rtl8192e/dot11d.h new file mode 100644 index 000000000..aad339439 --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/dot11d.h @@ -0,0 +1,103 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ +#ifndef __INC_DOT11D_H +#define __INC_DOT11D_H + +#include "rtllib.h" + + + +struct chnl_txpow_triple { + u8 FirstChnl; + u8 NumChnls; + u8 MaxTxPowerInDbm; +}; + +enum dot11d_state { + DOT11D_STATE_NONE = 0, + DOT11D_STATE_LEARNED, + DOT11D_STATE_DONE, +}; + +/** + * struct rt_dot11d_info * @CountryIeLen: value greater than 0 if @CountryIeBuf contains + * valid country information element. + * @channel_map: holds channel values + * 0 - invalid, + * 1 - valid (active scan), + * 2 - valid (passive scan) + * @CountryIeSrcAddr - Source AP of the country IE + */ + +struct rt_dot11d_info { + + bool bEnabled; + + u16 CountryIeLen; + u8 CountryIeBuf[MAX_IE_LEN]; + u8 CountryIeSrcAddr[6]; + u8 CountryIeWatchdog; + + u8 channel_map[MAX_CHANNEL_NUMBER+1]; + u8 MaxTxPwrDbmList[MAX_CHANNEL_NUMBER+1]; + + enum dot11d_state State; +}; + +static inline void cpMacAddr(unsigned char *des, unsigned char *src) +{ + memcpy(des, src, 6); +} + +#define GET_DOT11D_INFO(__pIeeeDev) \ + ((struct rt_dot11d_info *)((__pIeeeDev)->pDot11dInfo)) + +#define IS_DOT11D_ENABLE(__pIeeeDev) \ + (GET_DOT11D_INFO(__pIeeeDev)->bEnabled) +#define IS_COUNTRY_IE_VALID(__pIeeeDev) \ + (GET_DOT11D_INFO(__pIeeeDev)->CountryIeLen > 0) + +#define IS_EQUAL_CIE_SRC(__pIeeeDev, __pTa) \ + ether_addr_equal_unaligned(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, \ + __pTa) +#define UPDATE_CIE_SRC(__pIeeeDev, __pTa) \ + cpMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa) + +#define CIE_WATCHDOG_TH 1 +#define GET_CIE_WATCHDOG(__pIeeeDev) \ + (GET_DOT11D_INFO(__pIeeeDev)->CountryIeWatchdog) +static inline void RESET_CIE_WATCHDOG(struct rtllib_device *__pIeeeDev) +{ + GET_CIE_WATCHDOG(__pIeeeDev) = 0; +} +#define UPDATE_CIE_WATCHDOG(__pIeeeDev) (++GET_CIE_WATCHDOG(__pIeeeDev)) + +#define IS_DOT11D_STATE_DONE(__pIeeeDev) \ + (GET_DOT11D_INFO(__pIeeeDev)->State == DOT11D_STATE_DONE) + +void dot11d_init(struct rtllib_device *dev); +void Dot11d_Channelmap(u8 channel_plan, struct rtllib_device *ieee); +void Dot11d_Reset(struct rtllib_device *dev); +void Dot11d_UpdateCountryIe(struct rtllib_device *dev, u8 *pTaddr, + u16 CoutryIeLen, u8 *pCoutryIe); +u8 DOT11D_GetMaxTxPwrInDbm(struct rtllib_device *dev, u8 Channel); +void DOT11D_ScanComplete(struct rtllib_device *dev); +int ToLegalChannel(struct rtllib_device *dev, u8 channel); + +#endif diff --git a/kernel/drivers/staging/rtl8192e/license b/kernel/drivers/staging/rtl8192e/license new file mode 100644 index 000000000..4bea9fa60 --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/license @@ -0,0 +1,339 @@ + +"This software program is licensed subject to the GNU General Public License +(GPL). Version 2, June 1991, available at + +******************************************************************************/ + + +#ifndef R8190P_DEF_H +#define R8190P_DEF_H + +#include + +#define MAX_SILENT_RESET_RX_SLOT_NUM 10 + +#define RX_MPDU_QUEUE 0 +#define RX_CMD_QUEUE 1 + + +enum rtl819x_loopback { + RTL819X_NO_LOOPBACK = 0, + RTL819X_MAC_LOOPBACK = 1, + RTL819X_DMA_LOOPBACK = 2, + RTL819X_CCK_LOOPBACK = 3, +}; + + +#define RESET_DELAY_8185 20 + +#define RT_IBSS_INT_MASKS (IMR_BcnInt | IMR_BcnInt | IMR_TBDOK | IMR_TBDER) + +#define DESC90_RATE1M 0x00 +#define DESC90_RATE2M 0x01 +#define DESC90_RATE5_5M 0x02 +#define DESC90_RATE11M 0x03 +#define DESC90_RATE6M 0x04 +#define DESC90_RATE9M 0x05 +#define DESC90_RATE12M 0x06 +#define DESC90_RATE18M 0x07 +#define DESC90_RATE24M 0x08 +#define DESC90_RATE36M 0x09 +#define DESC90_RATE48M 0x0a +#define DESC90_RATE54M 0x0b +#define DESC90_RATEMCS0 0x00 +#define DESC90_RATEMCS1 0x01 +#define DESC90_RATEMCS2 0x02 +#define DESC90_RATEMCS3 0x03 +#define DESC90_RATEMCS4 0x04 +#define DESC90_RATEMCS5 0x05 +#define DESC90_RATEMCS6 0x06 +#define DESC90_RATEMCS7 0x07 +#define DESC90_RATEMCS8 0x08 +#define DESC90_RATEMCS9 0x09 +#define DESC90_RATEMCS10 0x0a +#define DESC90_RATEMCS11 0x0b +#define DESC90_RATEMCS12 0x0c +#define DESC90_RATEMCS13 0x0d +#define DESC90_RATEMCS14 0x0e +#define DESC90_RATEMCS15 0x0f +#define DESC90_RATEMCS32 0x20 + +#define SHORT_SLOT_TIME 9 +#define NON_SHORT_SLOT_TIME 20 + + +#define MAX_LINES_HWCONFIG_TXT 1000 +#define MAX_BYTES_LINE_HWCONFIG_TXT 128 + +#define SW_THREE_WIRE 0 +#define HW_THREE_WIRE 2 + +#define BT_DEMO_BOARD 0 +#define BT_QA_BOARD 1 +#define BT_FPGA 2 + +#define RX_SMOOTH 20 + +#define QSLT_BK 0x1 +#define QSLT_BE 0x0 +#define QSLT_VI 0x4 +#define QSLT_VO 0x6 +#define QSLT_BEACON 0x10 +#define QSLT_HIGH 0x11 +#define QSLT_MGNT 0x12 +#define QSLT_CMD 0x13 + +#define NUM_OF_FIRMWARE_QUEUE 10 +#define NUM_OF_PAGES_IN_FW 0x100 +#define NUM_OF_PAGE_IN_FW_QUEUE_BK 0x007 +#define NUM_OF_PAGE_IN_FW_QUEUE_BE 0x0aa +#define NUM_OF_PAGE_IN_FW_QUEUE_VI 0x024 +#define NUM_OF_PAGE_IN_FW_QUEUE_VO 0x007 +#define NUM_OF_PAGE_IN_FW_QUEUE_HCCA 0 +#define NUM_OF_PAGE_IN_FW_QUEUE_CMD 0x2 +#define NUM_OF_PAGE_IN_FW_QUEUE_MGNT 0x10 +#define NUM_OF_PAGE_IN_FW_QUEUE_HIGH 0 +#define NUM_OF_PAGE_IN_FW_QUEUE_BCN 0x4 +#define NUM_OF_PAGE_IN_FW_QUEUE_PUB 0xd + +#define NUM_OF_PAGE_IN_FW_QUEUE_BK_DTM 0x026 +#define NUM_OF_PAGE_IN_FW_QUEUE_BE_DTM 0x048 +#define NUM_OF_PAGE_IN_FW_QUEUE_VI_DTM 0x048 +#define NUM_OF_PAGE_IN_FW_QUEUE_VO_DTM 0x026 +#define NUM_OF_PAGE_IN_FW_QUEUE_PUB_DTM 0x00 + +#define APPLIED_RESERVED_QUEUE_IN_FW 0x80000000 +#define RSVD_FW_QUEUE_PAGE_BK_SHIFT 0x00 +#define RSVD_FW_QUEUE_PAGE_BE_SHIFT 0x08 +#define RSVD_FW_QUEUE_PAGE_VI_SHIFT 0x10 +#define RSVD_FW_QUEUE_PAGE_VO_SHIFT 0x18 +#define RSVD_FW_QUEUE_PAGE_MGNT_SHIFT 0x10 +#define RSVD_FW_QUEUE_PAGE_BCN_SHIFT 0x00 +#define RSVD_FW_QUEUE_PAGE_PUB_SHIFT 0x08 + +#define HAL_PRIME_CHNL_OFFSET_DONT_CARE 0 +#define HAL_PRIME_CHNL_OFFSET_LOWER 1 +#define HAL_PRIME_CHNL_OFFSET_UPPER 2 + + +enum version_8190_loopback { + VERSION_8190_BD = 0x3, + VERSION_8190_BE +}; + +#define IC_VersionCut_C 0x2 +#define IC_VersionCut_D 0x3 +#define IC_VersionCut_E 0x4 + +enum rf_optype { + RF_OP_By_SW_3wire = 0, + RF_OP_By_FW, + RF_OP_MAX +}; + + +enum power_save_mode { + POWER_SAVE_MODE_ACTIVE, + POWER_SAVE_MODE_SAVE, +}; + +enum interface_select_8190pci { + INTF_SEL1_MINICARD = 0, + INTF_SEL0_PCIE = 1, + INTF_SEL2_RSV = 2, + INTF_SEL3_RSV = 3, +}; + +struct bb_reg_definition { + u32 rfintfs; + u32 rfintfi; + u32 rfintfo; + u32 rfintfe; + u32 rf3wireOffset; + u32 rfLSSI_Select; + u32 rfTxGainStage; + u32 rfHSSIPara1; + u32 rfHSSIPara2; + u32 rfSwitchControl; + u32 rfAGCControl1; + u32 rfAGCControl2; + u32 rfRxIQImbalance; + u32 rfRxAFE; + u32 rfTxIQImbalance; + u32 rfTxAFE; + u32 rfLSSIReadBack; + u32 rfLSSIReadBackPi; +}; + +struct tx_fwinfo { + u8 TxRate:7; + u8 CtsEnable:1; + u8 RtsRate:7; + u8 RtsEnable:1; + u8 TxHT:1; + u8 Short:1; + u8 TxBandwidth:1; + u8 TxSubCarrier:2; + u8 STBC:2; + u8 AllowAggregation:1; + u8 RtsHT:1; + u8 RtsShort:1; + u8 RtsBandwidth:1; + u8 RtsSubcarrier:2; + u8 RtsSTBC:2; + u8 EnableCPUDur:1; + + u32 RxMF:2; + u32 RxAMD:3; + u32 Reserved1:3; + u32 TxAGCOffset:4; + u32 TxAGCSign:1; + u32 Tx_INFO_RSVD:6; + u32 PacketID:13; +}; + +struct tx_fwinfo_8190pci { + u8 TxRate:7; + u8 CtsEnable:1; + u8 RtsRate:7; + u8 RtsEnable:1; + u8 TxHT:1; + u8 Short:1; + u8 TxBandwidth:1; + u8 TxSubCarrier:2; + u8 STBC:2; + u8 AllowAggregation:1; + u8 RtsHT:1; + u8 RtsShort:1; + u8 RtsBandwidth:1; + u8 RtsSubcarrier:2; + u8 RtsSTBC:2; + u8 EnableCPUDur:1; + + u32 RxMF:2; + u32 RxAMD:3; + u32 TxPerPktInfoFeedback:1; + u32 Reserved1:2; + u32 TxAGCOffset:4; + u32 TxAGCSign:1; + u32 RAW_TXD:1; + u32 Retry_Limit:4; + u32 Reserved2:1; + u32 PacketID:13; + + +}; + + +#define TX_DESC_SIZE 32 + +#define TX_DESC_CMD_SIZE 32 + + +#define TX_STATUS_DESC_SIZE 32 + +#define TX_FWINFO_SIZE 8 + + +#define RX_DESC_SIZE 16 + +#define RX_STATUS_DESC_SIZE 16 + +#define RX_DRIVER_INFO_SIZE 8 + +struct log_int_8190 { + u32 nIMR_COMDOK; + u32 nIMR_MGNTDOK; + u32 nIMR_HIGH; + u32 nIMR_VODOK; + u32 nIMR_VIDOK; + u32 nIMR_BEDOK; + u32 nIMR_BKDOK; + u32 nIMR_ROK; + u32 nIMR_RCOK; + u32 nIMR_TBDOK; + u32 nIMR_BDOK; + u32 nIMR_RXFOVW; +}; + +struct phy_ofdm_rx_status_rxsc_sgien_exintfflag { + u8 reserved:4; + u8 rxsc:2; + u8 sgi_en:1; + u8 ex_intf_flag:1; +}; + +struct phy_sts_ofdm_819xpci { + u8 trsw_gain_X[4]; + u8 pwdb_all; + u8 cfosho_X[4]; + u8 cfotail_X[4]; + u8 rxevm_X[2]; + u8 rxsnr_X[4]; + u8 pdsnr_X[2]; + u8 csi_current_X[2]; + u8 csi_target_X[2]; + u8 sigevm; + u8 max_ex_pwr; + u8 sgi_en; + u8 rxsc_sgien_exflg; +}; + +struct phy_sts_cck_819xpci { + u8 adc_pwdb_X[4]; + u8 sq_rpt; + u8 cck_agc_rpt; +}; + + +#define PHY_RSSI_SLID_WIN_MAX 100 +#define PHY_Beacon_RSSI_SLID_WIN_MAX 10 + +struct tx_desc { + u16 PktSize; + u8 Offset; + u8 Reserved1:3; + u8 CmdInit:1; + u8 LastSeg:1; + u8 FirstSeg:1; + u8 LINIP:1; + u8 OWN:1; + + u8 TxFWInfoSize; + u8 RATid:3; + u8 DISFB:1; + u8 USERATE:1; + u8 MOREFRAG:1; + u8 NoEnc:1; + u8 PIFS:1; + u8 QueueSelect:5; + u8 NoACM:1; + u8 Resv:2; + u8 SecCAMID:5; + u8 SecDescAssign:1; + u8 SecType:2; + + u16 TxBufferSize; + u8 PktId:7; + u8 Resv1:1; + u8 Reserved2; + + u32 TxBuffAddr; + + u32 NextDescAddress; + + u32 Reserved5; + u32 Reserved6; + u32 Reserved7; +}; + + +struct tx_desc_cmd { + u16 PktSize; + u8 Reserved1; + u8 CmdType:3; + u8 CmdInit:1; + u8 LastSeg:1; + u8 FirstSeg:1; + u8 LINIP:1; + u8 OWN:1; + + u16 ElementReport; + u16 Reserved2; + + u16 TxBufferSize; + u16 Reserved3; + + u32 TxBuffAddr; + u32 NextDescAddress; + u32 Reserved4; + u32 Reserved5; + u32 Reserved6; +}; + +struct rx_desc { + u16 Length:14; + u16 CRC32:1; + u16 ICV:1; + u8 RxDrvInfoSize; + u8 Shift:2; + u8 PHYStatus:1; + u8 SWDec:1; + u8 LastSeg:1; + u8 FirstSeg:1; + u8 EOR:1; + u8 OWN:1; + + u32 Reserved2; + + u32 Reserved3; + + u32 BufferAddress; + +}; + + +struct rx_fwinfo { + u16 Reserved1:12; + u16 PartAggr:1; + u16 FirstAGGR:1; + u16 Reserved2:2; + + u8 RxRate:7; + u8 RxHT:1; + + u8 BW:1; + u8 SPLCP:1; + u8 Reserved3:2; + u8 PAM:1; + u8 Mcast:1; + u8 Bcast:1; + u8 Reserved4:1; + + u32 TSFL; + +}; + +#endif diff --git a/kernel/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c b/kernel/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c new file mode 100644 index 000000000..01d2201af --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c @@ -0,0 +1,309 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ + +#include "rtl_core.h" +#include "r8192E_phyreg.h" +#include "r8192E_phy.h" +#include "r8190P_rtl8256.h" + +void PHY_SetRF8256Bandwidth(struct net_device *dev, + enum ht_channel_width Bandwidth) +{ + u8 eRFPath; + struct r8192_priv *priv = rtllib_priv(dev); + + for (eRFPath = 0; eRFPath < priv->NumTotalRFPath; eRFPath++) { + if (!rtl8192_phy_CheckIsLegalRFPath(dev, eRFPath)) + continue; + + switch (Bandwidth) { + case HT_CHANNEL_WIDTH_20: + if (priv->card_8192_version == VERSION_8190_BD || + priv->card_8192_version == VERSION_8190_BE) { + rtl8192_phy_SetRFReg(dev, + (enum rf90_radio_path)eRFPath, + 0x0b, bMask12Bits, 0x100); + rtl8192_phy_SetRFReg(dev, + (enum rf90_radio_path)eRFPath, + 0x2c, bMask12Bits, 0x3d7); + rtl8192_phy_SetRFReg(dev, + (enum rf90_radio_path)eRFPath, + 0x0e, bMask12Bits, 0x021); + + } else { + RT_TRACE(COMP_ERR, + "PHY_SetRF8256Bandwidth(): unknown hardware version\n"); + } + + break; + case HT_CHANNEL_WIDTH_20_40: + if (priv->card_8192_version == VERSION_8190_BD || + priv->card_8192_version == VERSION_8190_BE) { + rtl8192_phy_SetRFReg(dev, + (enum rf90_radio_path)eRFPath, + 0x0b, bMask12Bits, 0x300); + rtl8192_phy_SetRFReg(dev, + (enum rf90_radio_path)eRFPath, + 0x2c, bMask12Bits, 0x3ff); + rtl8192_phy_SetRFReg(dev, + (enum rf90_radio_path)eRFPath, + 0x0e, bMask12Bits, 0x0e1); + + } else { + RT_TRACE(COMP_ERR, + "PHY_SetRF8256Bandwidth(): unknown hardware version\n"); + } + + + break; + default: + RT_TRACE(COMP_ERR, + "PHY_SetRF8256Bandwidth(): unknown Bandwidth: %#X\n", + Bandwidth); + break; + + } + } +} + +bool PHY_RF8256_Config(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + priv->NumTotalRFPath = RTL819X_TOTAL_RF_PATH; + return phy_RF8256_Config_ParaFile(dev); +} + +bool phy_RF8256_Config_ParaFile(struct net_device *dev) +{ + u32 u4RegValue = 0; + u8 eRFPath; + bool rtStatus = true; + struct bb_reg_definition *pPhyReg; + struct r8192_priv *priv = rtllib_priv(dev); + u32 RegOffSetToBeCheck = 0x3; + u32 RegValueToBeCheck = 0x7f1; + u32 RF3_Final_Value = 0; + u8 ConstRetryTimes = 5, RetryTimes = 5; + u8 ret = 0; + + for (eRFPath = (enum rf90_radio_path)RF90_PATH_A; + eRFPath < priv->NumTotalRFPath; eRFPath++) { + if (!rtl8192_phy_CheckIsLegalRFPath(dev, eRFPath)) + continue; + + pPhyReg = &priv->PHYRegDef[eRFPath]; + + + switch (eRFPath) { + case RF90_PATH_A: + case RF90_PATH_C: + u4RegValue = rtl8192_QueryBBReg(dev, pPhyReg->rfintfs, + bRFSI_RFENV); + break; + case RF90_PATH_B: + case RF90_PATH_D: + u4RegValue = rtl8192_QueryBBReg(dev, pPhyReg->rfintfs, + bRFSI_RFENV<<16); + break; + } + + rtl8192_setBBreg(dev, pPhyReg->rfintfe, bRFSI_RFENV<<16, 0x1); + + rtl8192_setBBreg(dev, pPhyReg->rfintfo, bRFSI_RFENV, 0x1); + + rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2, + b3WireAddressLength, 0x0); + rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2, + b3WireDataLength, 0x0); + + rtl8192_phy_SetRFReg(dev, (enum rf90_radio_path) eRFPath, 0x0, + bMask12Bits, 0xbf); + + rtStatus = rtl8192_phy_checkBBAndRF(dev, HW90_BLOCK_RF, + (enum rf90_radio_path)eRFPath); + if (!rtStatus) { + RT_TRACE(COMP_ERR, + "PHY_RF8256_Config():Check Radio[%d] Fail!!\n", + eRFPath); + goto phy_RF8256_Config_ParaFile_Fail; + } + + RetryTimes = ConstRetryTimes; + RF3_Final_Value = 0; + switch (eRFPath) { + case RF90_PATH_A: + while (RF3_Final_Value != RegValueToBeCheck && + RetryTimes != 0) { + ret = rtl8192_phy_ConfigRFWithHeaderFile(dev, + (enum rf90_radio_path)eRFPath); + RF3_Final_Value = rtl8192_phy_QueryRFReg(dev, + (enum rf90_radio_path)eRFPath, + RegOffSetToBeCheck, + bMask12Bits); + RT_TRACE(COMP_RF, + "RF %d %d register final value: %x\n", + eRFPath, RegOffSetToBeCheck, + RF3_Final_Value); + RetryTimes--; + } + break; + case RF90_PATH_B: + while (RF3_Final_Value != RegValueToBeCheck && + RetryTimes != 0) { + ret = rtl8192_phy_ConfigRFWithHeaderFile(dev, + (enum rf90_radio_path)eRFPath); + RF3_Final_Value = rtl8192_phy_QueryRFReg(dev, + (enum rf90_radio_path)eRFPath, + RegOffSetToBeCheck, + bMask12Bits); + RT_TRACE(COMP_RF, + "RF %d %d register final value: %x\n", + eRFPath, RegOffSetToBeCheck, + RF3_Final_Value); + RetryTimes--; + } + break; + case RF90_PATH_C: + while (RF3_Final_Value != RegValueToBeCheck && + RetryTimes != 0) { + ret = rtl8192_phy_ConfigRFWithHeaderFile(dev, + (enum rf90_radio_path)eRFPath); + RF3_Final_Value = rtl8192_phy_QueryRFReg(dev, + (enum rf90_radio_path)eRFPath, + RegOffSetToBeCheck, + bMask12Bits); + RT_TRACE(COMP_RF, + "RF %d %d register final value: %x\n", + eRFPath, RegOffSetToBeCheck, + RF3_Final_Value); + RetryTimes--; + } + break; + case RF90_PATH_D: + while (RF3_Final_Value != RegValueToBeCheck && + RetryTimes != 0) { + ret = rtl8192_phy_ConfigRFWithHeaderFile(dev, + (enum rf90_radio_path)eRFPath); + RF3_Final_Value = rtl8192_phy_QueryRFReg(dev, + (enum rf90_radio_path)eRFPath, + RegOffSetToBeCheck, bMask12Bits); + RT_TRACE(COMP_RF, + "RF %d %d register final value: %x\n", + eRFPath, RegOffSetToBeCheck, + RF3_Final_Value); + RetryTimes--; + } + break; + } + + switch (eRFPath) { + case RF90_PATH_A: + case RF90_PATH_C: + rtl8192_setBBreg(dev, pPhyReg->rfintfs, bRFSI_RFENV, + u4RegValue); + break; + case RF90_PATH_B: + case RF90_PATH_D: + rtl8192_setBBreg(dev, pPhyReg->rfintfs, bRFSI_RFENV<<16, + u4RegValue); + break; + } + + if (ret) { + RT_TRACE(COMP_ERR, + "phy_RF8256_Config_ParaFile():Radio[%d] Fail!!", + eRFPath); + goto phy_RF8256_Config_ParaFile_Fail; + } + + } + + RT_TRACE(COMP_PHY, "PHY Initialization Success\n"); + return true; + +phy_RF8256_Config_ParaFile_Fail: + RT_TRACE(COMP_ERR, "PHY Initialization failed\n"); + return false; +} + +void PHY_SetRF8256CCKTxPower(struct net_device *dev, u8 powerlevel) +{ + u32 TxAGC = 0; + struct r8192_priv *priv = rtllib_priv(dev); + + TxAGC = powerlevel; + if (priv->bDynamicTxLowPower) { + if (priv->CustomerID == RT_CID_819x_Netcore) + TxAGC = 0x22; + else + TxAGC += priv->CckPwEnl; + } + if (TxAGC > 0x24) + TxAGC = 0x24; + rtl8192_setBBreg(dev, rTxAGC_CCK_Mcs32, bTxAGCRateCCK, TxAGC); +} + + +void PHY_SetRF8256OFDMTxPower(struct net_device *dev, u8 powerlevel) +{ + struct r8192_priv *priv = rtllib_priv(dev); + u32 writeVal, powerBase0, powerBase1, writeVal_tmp; + u8 index = 0; + u16 RegOffset[6] = {0xe00, 0xe04, 0xe10, 0xe14, 0xe18, 0xe1c}; + u8 byte0, byte1, byte2, byte3; + + powerBase0 = powerlevel + priv->LegacyHTTxPowerDiff; + powerBase0 = (powerBase0 << 24) | (powerBase0 << 16) | + (powerBase0 << 8) | powerBase0; + powerBase1 = powerlevel; + powerBase1 = (powerBase1 << 24) | (powerBase1 << 16) | + (powerBase1 << 8) | powerBase1; + + for (index = 0; index < 6; index++) { + writeVal = (u32)(priv->MCSTxPowerLevelOriginalOffset[index] + + ((index < 2) ? powerBase0 : powerBase1)); + byte0 = (u8)(writeVal & 0x7f); + byte1 = (u8)((writeVal & 0x7f00)>>8); + byte2 = (u8)((writeVal & 0x7f0000)>>16); + byte3 = (u8)((writeVal & 0x7f000000)>>24); + if (byte0 > 0x24) + byte0 = 0x24; + if (byte1 > 0x24) + byte1 = 0x24; + if (byte2 > 0x24) + byte2 = 0x24; + if (byte3 > 0x24) + byte3 = 0x24; + + if (index == 3) { + writeVal_tmp = (byte3 << 24) | (byte2 << 16) | + (byte1 << 8) | byte0; + priv->Pwr_Track = writeVal_tmp; + } + + if (priv->bDynamicTxHighPower) + writeVal = 0x03030303; + else + writeVal = (byte3 << 24) | (byte2 << 16) | + (byte1 << 8) | byte0; + rtl8192_setBBreg(dev, RegOffset[index], 0x7f7f7f7f, writeVal); + } + +} diff --git a/kernel/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h b/kernel/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h new file mode 100644 index 000000000..64e831d2f --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h @@ -0,0 +1,31 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ + +#ifndef RTL8225H +#define RTL8225H + +#define RTL819X_TOTAL_RF_PATH 2 +extern void PHY_SetRF8256Bandwidth(struct net_device *dev, + enum ht_channel_width Bandwidth); +extern bool PHY_RF8256_Config(struct net_device *dev); +extern bool phy_RF8256_Config_ParaFile(struct net_device *dev); +extern void PHY_SetRF8256CCKTxPower(struct net_device *dev, u8 powerlevel); +extern void PHY_SetRF8256OFDMTxPower(struct net_device *dev, u8 powerlevel); + +#endif diff --git a/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c b/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c new file mode 100644 index 000000000..ecdd2e5c6 --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c @@ -0,0 +1,380 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ + +#include "rtl_core.h" +#include "r8192E_hw.h" +#include "r8192E_cmdpkt.h" + +bool cmpk_message_handle_tx( + struct net_device *dev, + u8 *code_virtual_address, + u32 packettype, + u32 buffer_len) +{ + + bool rt_status = true; + struct r8192_priv *priv = rtllib_priv(dev); + u16 frag_threshold; + u16 frag_length = 0, frag_offset = 0; + struct rt_firmware *pfirmware = priv->pFirmware; + struct sk_buff *skb; + unsigned char *seg_ptr; + struct cb_desc *tcb_desc; + u8 bLastIniPkt; + + struct tx_fwinfo_8190pci *pTxFwInfo = NULL; + + RT_TRACE(COMP_CMDPKT, "%s(),buffer_len is %d\n", __func__, buffer_len); + firmware_init_param(dev); + frag_threshold = pfirmware->cmdpacket_frag_thresold; + + do { + if ((buffer_len - frag_offset) > frag_threshold) { + frag_length = frag_threshold; + bLastIniPkt = 0; + + } else { + frag_length = (u16)(buffer_len - frag_offset); + bLastIniPkt = 1; + } + + skb = dev_alloc_skb(frag_length + + priv->rtllib->tx_headroom + 4); + + if (skb == NULL) { + rt_status = false; + goto Failed; + } + + memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev)); + tcb_desc = (struct cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); + tcb_desc->queue_index = TXCMD_QUEUE; + tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_NORMAL; + tcb_desc->bLastIniPkt = bLastIniPkt; + tcb_desc->pkt_size = frag_length; + + seg_ptr = skb_put(skb, priv->rtllib->tx_headroom); + pTxFwInfo = (struct tx_fwinfo_8190pci *)seg_ptr; + memset(pTxFwInfo, 0, sizeof(struct tx_fwinfo_8190pci)); + memset(pTxFwInfo, 0x12, 8); + + seg_ptr = skb_put(skb, frag_length); + memcpy(seg_ptr, code_virtual_address, (u32)frag_length); + + priv->rtllib->softmac_hard_start_xmit(skb, dev); + + code_virtual_address += frag_length; + frag_offset += frag_length; + + } while (frag_offset < buffer_len); + + write_nic_byte(dev, TPPoll, TPPoll_CQ); +Failed: + return rt_status; +} + +static void +cmpk_count_txstatistic( + struct net_device *dev, + struct cmpk_txfb *pstx_fb) +{ + struct r8192_priv *priv = rtllib_priv(dev); +#ifdef ENABLE_PS + enum rt_rf_power_state rtState; + + pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, + (pu1Byte)(&rtState)); + + if (rtState == eRfOff) + return; +#endif + + if (pstx_fb->tok) { + priv->stats.txfeedbackok++; + priv->stats.txoktotal++; + priv->stats.txokbytestotal += pstx_fb->pkt_length; + priv->stats.txokinperiod++; + + if (pstx_fb->pkt_type == PACKET_MULTICAST) { + priv->stats.txmulticast++; + priv->stats.txbytesmulticast += pstx_fb->pkt_length; + } else if (pstx_fb->pkt_type == PACKET_BROADCAST) { + priv->stats.txbroadcast++; + priv->stats.txbytesbroadcast += pstx_fb->pkt_length; + } else { + priv->stats.txunicast++; + priv->stats.txbytesunicast += pstx_fb->pkt_length; + } + } else { + priv->stats.txfeedbackfail++; + priv->stats.txerrtotal++; + priv->stats.txerrbytestotal += pstx_fb->pkt_length; + + if (pstx_fb->pkt_type == PACKET_MULTICAST) + priv->stats.txerrmulticast++; + else if (pstx_fb->pkt_type == PACKET_BROADCAST) + priv->stats.txerrbroadcast++; + else + priv->stats.txerrunicast++; + } + + priv->stats.txretrycount += pstx_fb->retry_cnt; + priv->stats.txfeedbackretry += pstx_fb->retry_cnt; +} + +static void cmpk_handle_tx_feedback(struct net_device *dev, u8 *pmsg) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct cmpk_txfb rx_tx_fb; + + priv->stats.txfeedback++; + + + memcpy((u8 *)&rx_tx_fb, pmsg, sizeof(struct cmpk_txfb)); + cmpk_count_txstatistic(dev, &rx_tx_fb); +} + +static void cmdpkt_beacontimerinterrupt_819xusb(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + if ((priv->rtllib->current_network.mode == IEEE_A) || + (priv->rtllib->current_network.mode == IEEE_N_5G) || + ((priv->rtllib->current_network.mode == IEEE_N_24G) && + (!priv->rtllib->pHTInfo->bCurSuppCCK))) + DMESG("send beacon frame tx rate is 6Mbpm\n"); + else + DMESG("send beacon frame tx rate is 1Mbpm\n"); +} + +static void cmpk_handle_interrupt_status(struct net_device *dev, u8 *pmsg) +{ + struct cmpk_intr_sta rx_intr_status; + struct r8192_priv *priv = rtllib_priv(dev); + + DMESG("---> cmpk_Handle_Interrupt_Status()\n"); + + rx_intr_status.length = pmsg[1]; + if (rx_intr_status.length != (sizeof(struct cmpk_intr_sta) - 2)) { + DMESG("cmpk_Handle_Interrupt_Status: wrong length!\n"); + return; + } + + if (priv->rtllib->iw_mode == IW_MODE_ADHOC) { + rx_intr_status.interrupt_status = *((u32 *)(pmsg + 4)); + + DMESG("interrupt status = 0x%x\n", + rx_intr_status.interrupt_status); + + if (rx_intr_status.interrupt_status & ISR_TxBcnOk) { + priv->rtllib->bibsscoordinator = true; + priv->stats.txbeaconokint++; + } else if (rx_intr_status.interrupt_status & ISR_TxBcnErr) { + priv->rtllib->bibsscoordinator = false; + priv->stats.txbeaconerr++; + } + + if (rx_intr_status.interrupt_status & ISR_BcnTimerIntr) + cmdpkt_beacontimerinterrupt_819xusb(dev); + } + + DMESG("<---- cmpk_handle_interrupt_status()\n"); + +} + +static void cmpk_handle_query_config_rx(struct net_device *dev, u8 *pmsg) +{ + cmpk_query_cfg_t rx_query_cfg; + + + rx_query_cfg.cfg_action = (pmsg[4] & 0x80000000)>>31; + rx_query_cfg.cfg_type = (pmsg[4] & 0x60) >> 5; + rx_query_cfg.cfg_size = (pmsg[4] & 0x18) >> 3; + rx_query_cfg.cfg_page = (pmsg[6] & 0x0F) >> 0; + rx_query_cfg.cfg_offset = pmsg[7]; + rx_query_cfg.value = (pmsg[8] << 24) | (pmsg[9] << 16) | + (pmsg[10] << 8) | (pmsg[11] << 0); + rx_query_cfg.mask = (pmsg[12] << 24) | (pmsg[13] << 16) | + (pmsg[14] << 8) | (pmsg[15] << 0); + +} + +static void cmpk_count_tx_status(struct net_device *dev, + struct cmpk_tx_status *pstx_status) +{ + struct r8192_priv *priv = rtllib_priv(dev); + +#ifdef ENABLE_PS + + enum rt_rf_power_state rtstate; + + pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, + (pu1Byte)(&rtState)); + + if (rtState == eRfOff) + return; +#endif + + priv->stats.txfeedbackok += pstx_status->txok; + priv->stats.txoktotal += pstx_status->txok; + + priv->stats.txfeedbackfail += pstx_status->txfail; + priv->stats.txerrtotal += pstx_status->txfail; + + priv->stats.txretrycount += pstx_status->txretry; + priv->stats.txfeedbackretry += pstx_status->txretry; + + + priv->stats.txmulticast += pstx_status->txmcok; + priv->stats.txbroadcast += pstx_status->txbcok; + priv->stats.txunicast += pstx_status->txucok; + + priv->stats.txerrmulticast += pstx_status->txmcfail; + priv->stats.txerrbroadcast += pstx_status->txbcfail; + priv->stats.txerrunicast += pstx_status->txucfail; + + priv->stats.txbytesmulticast += pstx_status->txmclength; + priv->stats.txbytesbroadcast += pstx_status->txbclength; + priv->stats.txbytesunicast += pstx_status->txuclength; + + priv->stats.last_packet_rate = pstx_status->rate; +} + +static void cmpk_handle_tx_status(struct net_device *dev, u8 *pmsg) +{ + struct cmpk_tx_status rx_tx_sts; + + memcpy((void *)&rx_tx_sts, (void *)pmsg, sizeof(struct cmpk_tx_status)); + cmpk_count_tx_status(dev, &rx_tx_sts); +} + +static void cmpk_handle_tx_rate_history(struct net_device *dev, u8 *pmsg) +{ + struct cmpk_tx_rahis *ptxrate; + u8 i, j; + u16 length = sizeof(struct cmpk_tx_rahis); + u32 *ptemp; + struct r8192_priv *priv = rtllib_priv(dev); + +#ifdef ENABLE_PS + pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, + (pu1Byte)(&rtState)); + + if (rtState == eRfOff) + return; +#endif + + ptemp = (u32 *)pmsg; + + for (i = 0; i < (length / 4); i++) { + u16 temp1, temp2; + + temp1 = ptemp[i] & 0x0000FFFF; + temp2 = ptemp[i] >> 16; + ptemp[i] = (temp1 << 16) | temp2; + } + + ptxrate = (struct cmpk_tx_rahis *)pmsg; + + if (ptxrate == NULL) + return; + + for (i = 0; i < 16; i++) { + if (i < 4) + priv->stats.txrate.cck[i] += ptxrate->cck[i]; + + if (i < 8) + priv->stats.txrate.ofdm[i] += ptxrate->ofdm[i]; + + for (j = 0; j < 4; j++) + priv->stats.txrate.ht_mcs[j][i] += + ptxrate->ht_mcs[j][i]; + } +} + +u32 cmpk_message_handle_rx(struct net_device *dev, + struct rtllib_rx_stats *pstats) +{ + int total_length; + u8 cmd_length, exe_cnt = 0; + u8 element_id; + u8 *pcmd_buff; + + RT_TRACE(COMP_CMDPKT, "---->cmpk_message_handle_rx()\n"); + + if (pstats == NULL) + return 0; + + total_length = pstats->Length; + + pcmd_buff = pstats->virtual_address; + + element_id = pcmd_buff[0]; + + while (total_length > 0 || exe_cnt++ > 100) { + element_id = pcmd_buff[0]; + + switch (element_id) { + case RX_TX_FEEDBACK: + RT_TRACE(COMP_CMDPKT, + "---->cmpk_message_handle_rx():RX_TX_FEEDBACK\n"); + cmpk_handle_tx_feedback(dev, pcmd_buff); + cmd_length = CMPK_RX_TX_FB_SIZE; + break; + case RX_INTERRUPT_STATUS: + RT_TRACE(COMP_CMDPKT, + "---->cmpk_message_handle_rx():RX_INTERRUPT_STATUS\n"); + cmpk_handle_interrupt_status(dev, pcmd_buff); + cmd_length = sizeof(struct cmpk_intr_sta); + break; + case BOTH_QUERY_CONFIG: + RT_TRACE(COMP_CMDPKT, + "---->cmpk_message_handle_rx():BOTH_QUERY_CONFIG\n"); + cmpk_handle_query_config_rx(dev, pcmd_buff); + cmd_length = CMPK_BOTH_QUERY_CONFIG_SIZE; + break; + case RX_TX_STATUS: + RT_TRACE(COMP_CMDPKT, + "---->cmpk_message_handle_rx():RX_TX_STATUS\n"); + cmpk_handle_tx_status(dev, pcmd_buff); + cmd_length = CMPK_RX_TX_STS_SIZE; + break; + case RX_TX_PER_PKT_FEEDBACK: + RT_TRACE(COMP_CMDPKT, + "---->cmpk_message_handle_rx():RX_TX_PER_PKT_FEEDBACK\n"); + cmd_length = CMPK_RX_TX_FB_SIZE; + break; + case RX_TX_RATE_HISTORY: + RT_TRACE(COMP_CMDPKT, + "---->cmpk_message_handle_rx():RX_TX_HISTORY\n"); + cmpk_handle_tx_rate_history(dev, pcmd_buff); + cmd_length = CMPK_TX_RAHIS_SIZE; + break; + default: + + RT_TRACE(COMP_CMDPKT, + "---->cmpk_message_handle_rx():unknown CMD Element\n"); + return 1; + } + + total_length -= cmd_length; + pcmd_buff += cmd_length; + } + return 1; +} diff --git a/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.h b/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.h new file mode 100644 index 000000000..269368264 --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.h @@ -0,0 +1,159 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ +#ifndef R819XUSB_CMDPKT_H +#define R819XUSB_CMDPKT_H +#define CMPK_RX_TX_FB_SIZE sizeof(struct cmpk_txfb) +#define CMPK_TX_SET_CONFIG_SIZE sizeof(struct cmpk_set_cfg) +#define CMPK_BOTH_QUERY_CONFIG_SIZE sizeof(struct cmpk_set_cfg) +#define CMPK_RX_TX_STS_SIZE sizeof(struct cmpk_tx_status) +#define CMPK_RX_DBG_MSG_SIZE sizeof(struct cmpk_rx_dbginfo) +#define CMPK_TX_RAHIS_SIZE sizeof(struct cmpk_tx_rahis) + +#define ISR_TxBcnOk BIT27 +#define ISR_TxBcnErr BIT26 +#define ISR_BcnTimerIntr BIT13 + + +struct cmpk_txfb { + u8 element_id; + u8 length; + u8 TID:4; + u8 fail_reason:3; + u8 tok:1; + u8 reserve1:4; + u8 pkt_type:2; + u8 bandwidth:1; + u8 qos_pkt:1; + + u8 reserve2; + u8 retry_cnt; + u16 pkt_id; + + u16 seq_num; + u8 s_rate; + u8 f_rate; + + u8 s_rts_rate; + u8 f_rts_rate; + u16 pkt_length; + + u16 reserve3; + u16 duration; +}; + +struct cmpk_intr_sta { + u8 element_id; + u8 length; + u16 reserve; + u32 interrupt_status; +}; + + +struct cmpk_set_cfg { + u8 element_id; + u8 length; + u16 reserve1; + u8 cfg_reserve1:3; + u8 cfg_size:2; + u8 cfg_type:2; + u8 cfg_action:1; + u8 cfg_reserve2; + u8 cfg_page:4; + u8 cfg_reserve3:4; + u8 cfg_offset; + u32 value; + u32 mask; +}; + +#define cmpk_query_cfg_t struct cmpk_set_cfg + +struct cmpk_tx_status { + u16 reserve1; + u8 length; + u8 element_id; + + u16 txfail; + u16 txok; + + u16 txmcok; + u16 txretry; + + u16 txucok; + u16 txbcok; + + u16 txbcfail; + u16 txmcfail; + + u16 reserve2; + u16 txucfail; + + u32 txmclength; + u32 txbclength; + u32 txuclength; + + u16 reserve3_23; + u8 reserve3_1; + u8 rate; +} __packed; + +struct cmpk_rx_dbginfo { + u16 reserve1; + u8 length; + u8 element_id; + + +}; + +struct cmpk_tx_rahis { + u8 element_id; + u8 length; + u16 reserved1; + + u16 cck[4]; + + u16 ofdm[8]; + + + + + + u16 ht_mcs[4][16]; + +} __packed; + +enum cmpk_element { + RX_TX_FEEDBACK = 0, + RX_INTERRUPT_STATUS = 1, + TX_SET_CONFIG = 2, + BOTH_QUERY_CONFIG = 3, + RX_TX_STATUS = 4, + RX_DBGINFO_FEEDBACK = 5, + RX_TX_PER_PKT_FEEDBACK = 6, + RX_TX_RATE_HISTORY = 7, + RX_CMD_ELE_MAX +}; + +extern u32 cmpk_message_handle_rx(struct net_device *dev, + struct rtllib_rx_stats *pstats); +extern bool cmpk_message_handle_tx(struct net_device *dev, + u8 *codevirtualaddress, u32 packettype, + u32 buffer_len); + + +#endif diff --git a/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c new file mode 100644 index 000000000..286960243 --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -0,0 +1,2416 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * Based on the r8180 driver, which is: + * Copyright 2004-2005 Andrea Merello , et al. + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ +#include "rtl_core.h" +#include "r8192E_phy.h" +#include "r8192E_phyreg.h" +#include "r8190P_rtl8256.h" +#include "r8192E_cmdpkt.h" +#include "rtl_dm.h" +#include "rtl_wx.h" + +static int WDCAPARA_ADD[] = {EDCAPARA_BE, EDCAPARA_BK, EDCAPARA_VI, EDCAPARA_VO}; + +void rtl8192e_start_beacon(struct net_device *dev) +{ + struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); + struct rtllib_network *net = &priv->rtllib->current_network; + u16 BcnTimeCfg = 0; + u16 BcnCW = 6; + u16 BcnIFS = 0xf; + + DMESG("Enabling beacon TX"); + rtl8192_irq_disable(dev); + + write_nic_word(dev, ATIMWND, 2); + + write_nic_word(dev, BCN_INTERVAL, net->beacon_interval); + write_nic_word(dev, BCN_DRV_EARLY_INT, 10); + write_nic_word(dev, BCN_DMATIME, 256); + + write_nic_byte(dev, BCN_ERR_THRESH, 100); + + BcnTimeCfg |= BcnCW<rtllib->iw_mode) { + case IW_MODE_INFRA: + if (priv->rtllib->state == RTLLIB_LINKED) + msr |= (MSR_LINK_MANAGED << MSR_LINK_SHIFT); + else + msr |= (MSR_LINK_NONE << MSR_LINK_SHIFT); + LedAction = LED_CTL_LINK; + break; + case IW_MODE_ADHOC: + if (priv->rtllib->state == RTLLIB_LINKED) + msr |= (MSR_LINK_ADHOC << MSR_LINK_SHIFT); + else + msr |= (MSR_LINK_NONE << MSR_LINK_SHIFT); + break; + case IW_MODE_MASTER: + if (priv->rtllib->state == RTLLIB_LINKED) + msr |= (MSR_LINK_MASTER << MSR_LINK_SHIFT); + else + msr |= (MSR_LINK_NONE << MSR_LINK_SHIFT); + break; + default: + break; + } + + write_nic_byte(dev, MSR, msr); + if (priv->rtllib->LedControlHandler) + priv->rtllib->LedControlHandler(dev, LedAction); +} + +void rtl8192e_SetHwReg(struct net_device *dev, u8 variable, u8 *val) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + switch (variable) { + case HW_VAR_BSSID: + write_nic_dword(dev, BSSIDR, ((u32 *)(val))[0]); + write_nic_word(dev, BSSIDR+2, ((u16 *)(val+2))[0]); + break; + + case HW_VAR_MEDIA_STATUS: + { + enum rt_op_mode OpMode = *((enum rt_op_mode *)(val)); + enum led_ctl_mode LedAction = LED_CTL_NO_LINK; + u8 btMsr = read_nic_byte(dev, MSR); + + btMsr &= 0xfc; + + switch (OpMode) { + case RT_OP_MODE_INFRASTRUCTURE: + btMsr |= MSR_INFRA; + LedAction = LED_CTL_LINK; + break; + + case RT_OP_MODE_IBSS: + btMsr |= MSR_ADHOC; + break; + + case RT_OP_MODE_AP: + btMsr |= MSR_AP; + LedAction = LED_CTL_LINK; + break; + + default: + btMsr |= MSR_NOLINK; + break; + } + + write_nic_byte(dev, MSR, btMsr); + + } + break; + + case HW_VAR_CECHK_BSSID: + { + u32 RegRCR, Type; + + Type = ((u8 *)(val))[0]; + RegRCR = read_nic_dword(dev, RCR); + priv->ReceiveConfig = RegRCR; + + if (Type == true) + RegRCR |= (RCR_CBSSID); + else if (Type == false) + RegRCR &= (~RCR_CBSSID); + + write_nic_dword(dev, RCR, RegRCR); + priv->ReceiveConfig = RegRCR; + + } + break; + + case HW_VAR_SLOT_TIME: + + priv->slot_time = val[0]; + write_nic_byte(dev, SLOT_TIME, val[0]); + + break; + + case HW_VAR_ACK_PREAMBLE: + { + u32 regTmp; + + priv->short_preamble = (bool)(*(u8 *)val); + regTmp = priv->basic_rate; + if (priv->short_preamble) + regTmp |= BRSR_AckShortPmb; + write_nic_dword(dev, RRSR, regTmp); + break; + } + + case HW_VAR_CPU_RST: + write_nic_dword(dev, CPU_GEN, ((u32 *)(val))[0]); + break; + + case HW_VAR_AC_PARAM: + { + u8 pAcParam = *((u8 *)val); + u32 eACI = pAcParam; + u8 u1bAIFS; + u32 u4bAcParam; + u8 mode = priv->rtllib->mode; + struct rtllib_qos_parameters *qos_parameters = + &priv->rtllib->current_network.qos_data.parameters; + + u1bAIFS = qos_parameters->aifs[pAcParam] * + ((mode&(IEEE_G|IEEE_N_24G)) ? 9 : 20) + aSifsTime; + + dm_init_edca_turbo(dev); + + u4bAcParam = (((le16_to_cpu( + qos_parameters->tx_op_limit[pAcParam])) << + AC_PARAM_TXOP_LIMIT_OFFSET) | + ((le16_to_cpu(qos_parameters->cw_max[pAcParam])) << + AC_PARAM_ECW_MAX_OFFSET) | + ((le16_to_cpu(qos_parameters->cw_min[pAcParam])) << + AC_PARAM_ECW_MIN_OFFSET) | + (((u32)u1bAIFS) << AC_PARAM_AIFS_OFFSET)); + + RT_TRACE(COMP_DBG, "%s():HW_VAR_AC_PARAM eACI:%x:%x\n", + __func__, eACI, u4bAcParam); + switch (eACI) { + case AC1_BK: + write_nic_dword(dev, EDCAPARA_BK, u4bAcParam); + break; + + case AC0_BE: + write_nic_dword(dev, EDCAPARA_BE, u4bAcParam); + break; + + case AC2_VI: + write_nic_dword(dev, EDCAPARA_VI, u4bAcParam); + break; + + case AC3_VO: + write_nic_dword(dev, EDCAPARA_VO, u4bAcParam); + break; + + default: + netdev_info(dev, "SetHwReg8185(): invalid ACI: %d !\n", + eACI); + break; + } + priv->rtllib->SetHwRegHandler(dev, HW_VAR_ACM_CTRL, + (u8 *)(&pAcParam)); + break; + } + + case HW_VAR_ACM_CTRL: + { + struct rtllib_qos_parameters *qos_parameters = + &priv->rtllib->current_network.qos_data.parameters; + u8 pAcParam = *((u8 *)val); + u32 eACI = pAcParam; + union aci_aifsn *pAciAifsn = (union aci_aifsn *) & + (qos_parameters->aifs[0]); + u8 acm = pAciAifsn->f.acm; + u8 AcmCtrl = read_nic_byte(dev, AcmHwCtrl); + + RT_TRACE(COMP_DBG, "===========>%s():HW_VAR_ACM_CTRL:%x\n", + __func__, eACI); + AcmCtrl = AcmCtrl | ((priv->AcmMethod == 2) ? 0x0 : 0x1); + + if (acm) { + switch (eACI) { + case AC0_BE: + AcmCtrl |= AcmHw_BeqEn; + break; + + case AC2_VI: + AcmCtrl |= AcmHw_ViqEn; + break; + + case AC3_VO: + AcmCtrl |= AcmHw_VoqEn; + break; + + default: + RT_TRACE(COMP_QOS, + "SetHwReg8185(): [HW_VAR_ACM_CTRL] acm set failed: eACI is %d\n", + eACI); + break; + } + } else { + switch (eACI) { + case AC0_BE: + AcmCtrl &= (~AcmHw_BeqEn); + break; + + case AC2_VI: + AcmCtrl &= (~AcmHw_ViqEn); + break; + + case AC3_VO: + AcmCtrl &= (~AcmHw_BeqEn); + break; + + default: + break; + } + } + + RT_TRACE(COMP_QOS, + "SetHwReg8190pci(): [HW_VAR_ACM_CTRL] Write 0x%X\n", + AcmCtrl); + write_nic_byte(dev, AcmHwCtrl, AcmCtrl); + break; + } + + case HW_VAR_SIFS: + write_nic_byte(dev, SIFS, val[0]); + write_nic_byte(dev, SIFS+1, val[0]); + break; + + case HW_VAR_RF_TIMING: + { + u8 Rf_Timing = *((u8 *)val); + + write_nic_byte(dev, rFPGA0_RFTiming1, Rf_Timing); + break; + } + + default: + break; + } + +} + +static void rtl8192_read_eeprom_info(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + u8 tempval; + u8 ICVer8192, ICVer8256; + u16 i, usValue, IC_Version; + u16 EEPROMId; + u8 bMac_Tmp_Addr[6] = {0x00, 0xe0, 0x4c, 0x00, 0x00, 0x01}; + + RT_TRACE(COMP_INIT, "====> rtl8192_read_eeprom_info\n"); + + EEPROMId = eprom_read(dev, 0); + if (EEPROMId != RTL8190_EEPROM_ID) { + RT_TRACE(COMP_ERR, "EEPROM ID is invalid:%x, %x\n", + EEPROMId, RTL8190_EEPROM_ID); + priv->AutoloadFailFlag = true; + } else { + priv->AutoloadFailFlag = false; + } + + if (!priv->AutoloadFailFlag) { + priv->eeprom_vid = eprom_read(dev, EEPROM_VID >> 1); + priv->eeprom_did = eprom_read(dev, EEPROM_DID >> 1); + + usValue = eprom_read(dev, (u16)(EEPROM_Customer_ID>>1)) >> 8; + priv->eeprom_CustomerID = (u8)(usValue & 0xff); + usValue = eprom_read(dev, EEPROM_ICVersion_ChannelPlan>>1); + priv->eeprom_ChannelPlan = usValue&0xff; + IC_Version = (usValue & 0xff00)>>8; + + ICVer8192 = (IC_Version&0xf); + ICVer8256 = (IC_Version & 0xf0)>>4; + RT_TRACE(COMP_INIT, "\nICVer8192 = 0x%x\n", ICVer8192); + RT_TRACE(COMP_INIT, "\nICVer8256 = 0x%x\n", ICVer8256); + if (ICVer8192 == 0x2) { + if (ICVer8256 == 0x5) + priv->card_8192_version = VERSION_8190_BE; + } + switch (priv->card_8192_version) { + case VERSION_8190_BD: + case VERSION_8190_BE: + break; + default: + priv->card_8192_version = VERSION_8190_BD; + break; + } + RT_TRACE(COMP_INIT, "\nIC Version = 0x%x\n", + priv->card_8192_version); + } else { + priv->card_8192_version = VERSION_8190_BD; + priv->eeprom_vid = 0; + priv->eeprom_did = 0; + priv->eeprom_CustomerID = 0; + priv->eeprom_ChannelPlan = 0; + RT_TRACE(COMP_INIT, "\nIC Version = 0x%x\n", 0xff); + } + + RT_TRACE(COMP_INIT, "EEPROM VID = 0x%4x\n", priv->eeprom_vid); + RT_TRACE(COMP_INIT, "EEPROM DID = 0x%4x\n", priv->eeprom_did); + RT_TRACE(COMP_INIT, "EEPROM Customer ID: 0x%2x\n", + priv->eeprom_CustomerID); + + if (!priv->AutoloadFailFlag) { + for (i = 0; i < 6; i += 2) { + usValue = eprom_read(dev, + (u16)((EEPROM_NODE_ADDRESS_BYTE_0 + i) >> 1)); + *(u16 *)(&dev->dev_addr[i]) = usValue; + } + } else { + memcpy(dev->dev_addr, bMac_Tmp_Addr, 6); + } + + RT_TRACE(COMP_INIT, "Permanent Address = %pM\n", + dev->dev_addr); + + if (priv->card_8192_version > VERSION_8190_BD) + priv->bTXPowerDataReadFromEEPORM = true; + else + priv->bTXPowerDataReadFromEEPORM = false; + + priv->rf_type = RTL819X_DEFAULT_RF_TYPE; + + if (priv->card_8192_version > VERSION_8190_BD) { + if (!priv->AutoloadFailFlag) { + tempval = (eprom_read(dev, (EEPROM_RFInd_PowerDiff >> + 1))) & 0xff; + priv->EEPROMLegacyHTTxPowerDiff = tempval & 0xf; + + if (tempval&0x80) + priv->rf_type = RF_1T2R; + else + priv->rf_type = RF_2T4R; + } else { + priv->EEPROMLegacyHTTxPowerDiff = 0x04; + } + RT_TRACE(COMP_INIT, "EEPROMLegacyHTTxPowerDiff = %d\n", + priv->EEPROMLegacyHTTxPowerDiff); + + if (!priv->AutoloadFailFlag) + priv->EEPROMThermalMeter = (u8)(((eprom_read(dev, + (EEPROM_ThermalMeter>>1))) & + 0xff00)>>8); + else + priv->EEPROMThermalMeter = EEPROM_Default_ThermalMeter; + RT_TRACE(COMP_INIT, "ThermalMeter = %d\n", + priv->EEPROMThermalMeter); + priv->TSSI_13dBm = priv->EEPROMThermalMeter * 100; + + if (priv->epromtype == EEPROM_93C46) { + if (!priv->AutoloadFailFlag) { + usValue = eprom_read(dev, + EEPROM_TxPwDiff_CrystalCap >> 1); + priv->EEPROMAntPwDiff = (usValue&0x0fff); + priv->EEPROMCrystalCap = (u8)((usValue & 0xf000) + >> 12); + } else { + priv->EEPROMAntPwDiff = + EEPROM_Default_AntTxPowerDiff; + priv->EEPROMCrystalCap = + EEPROM_Default_TxPwDiff_CrystalCap; + } + RT_TRACE(COMP_INIT, "EEPROMAntPwDiff = %d\n", + priv->EEPROMAntPwDiff); + RT_TRACE(COMP_INIT, "EEPROMCrystalCap = %d\n", + priv->EEPROMCrystalCap); + + for (i = 0; i < 14; i += 2) { + if (!priv->AutoloadFailFlag) + usValue = eprom_read(dev, + (u16)((EEPROM_TxPwIndex_CCK + + i) >> 1)); + else + usValue = EEPROM_Default_TxPower; + *((u16 *)(&priv->EEPROMTxPowerLevelCCK[i])) = + usValue; + RT_TRACE(COMP_INIT, + "CCK Tx Power Level, Index %d = 0x%02x\n", + i, priv->EEPROMTxPowerLevelCCK[i]); + RT_TRACE(COMP_INIT, + "CCK Tx Power Level, Index %d = 0x%02x\n", + i+1, priv->EEPROMTxPowerLevelCCK[i+1]); + } + for (i = 0; i < 14; i += 2) { + if (!priv->AutoloadFailFlag) + usValue = eprom_read(dev, + (u16)((EEPROM_TxPwIndex_OFDM_24G + + i) >> 1)); + else + usValue = EEPROM_Default_TxPower; + *((u16 *)(&priv->EEPROMTxPowerLevelOFDM24G[i])) + = usValue; + RT_TRACE(COMP_INIT, + "OFDM 2.4G Tx Power Level, Index %d = 0x%02x\n", + i, priv->EEPROMTxPowerLevelOFDM24G[i]); + RT_TRACE(COMP_INIT, + "OFDM 2.4G Tx Power Level, Index %d = 0x%02x\n", + i + 1, + priv->EEPROMTxPowerLevelOFDM24G[i+1]); + } + } + if (priv->epromtype == EEPROM_93C46) { + for (i = 0; i < 14; i++) { + priv->TxPowerLevelCCK[i] = + priv->EEPROMTxPowerLevelCCK[i]; + priv->TxPowerLevelOFDM24G[i] = + priv->EEPROMTxPowerLevelOFDM24G[i]; + } + priv->LegacyHTTxPowerDiff = + priv->EEPROMLegacyHTTxPowerDiff; + priv->AntennaTxPwDiff[0] = (priv->EEPROMAntPwDiff & + 0xf); + priv->AntennaTxPwDiff[1] = (priv->EEPROMAntPwDiff & + 0xf0) >> 4; + priv->AntennaTxPwDiff[2] = (priv->EEPROMAntPwDiff & + 0xf00) >> 8; + priv->CrystalCap = priv->EEPROMCrystalCap; + priv->ThermalMeter[0] = (priv->EEPROMThermalMeter & + 0xf); + priv->ThermalMeter[1] = (priv->EEPROMThermalMeter & + 0xf0) >> 4; + } else if (priv->epromtype == EEPROM_93C56) { + + for (i = 0; i < 3; i++) { + priv->TxPowerLevelCCK_A[i] = + priv->EEPROMRfACCKChnl1TxPwLevel[0]; + priv->TxPowerLevelOFDM24G_A[i] = + priv->EEPROMRfAOfdmChnlTxPwLevel[0]; + priv->TxPowerLevelCCK_C[i] = + priv->EEPROMRfCCCKChnl1TxPwLevel[0]; + priv->TxPowerLevelOFDM24G_C[i] = + priv->EEPROMRfCOfdmChnlTxPwLevel[0]; + } + for (i = 3; i < 9; i++) { + priv->TxPowerLevelCCK_A[i] = + priv->EEPROMRfACCKChnl1TxPwLevel[1]; + priv->TxPowerLevelOFDM24G_A[i] = + priv->EEPROMRfAOfdmChnlTxPwLevel[1]; + priv->TxPowerLevelCCK_C[i] = + priv->EEPROMRfCCCKChnl1TxPwLevel[1]; + priv->TxPowerLevelOFDM24G_C[i] = + priv->EEPROMRfCOfdmChnlTxPwLevel[1]; + } + for (i = 9; i < 14; i++) { + priv->TxPowerLevelCCK_A[i] = + priv->EEPROMRfACCKChnl1TxPwLevel[2]; + priv->TxPowerLevelOFDM24G_A[i] = + priv->EEPROMRfAOfdmChnlTxPwLevel[2]; + priv->TxPowerLevelCCK_C[i] = + priv->EEPROMRfCCCKChnl1TxPwLevel[2]; + priv->TxPowerLevelOFDM24G_C[i] = + priv->EEPROMRfCOfdmChnlTxPwLevel[2]; + } + for (i = 0; i < 14; i++) + RT_TRACE(COMP_INIT, + "priv->TxPowerLevelCCK_A[%d] = 0x%x\n", + i, priv->TxPowerLevelCCK_A[i]); + for (i = 0; i < 14; i++) + RT_TRACE(COMP_INIT, + "priv->TxPowerLevelOFDM24G_A[%d] = 0x%x\n", + i, priv->TxPowerLevelOFDM24G_A[i]); + for (i = 0; i < 14; i++) + RT_TRACE(COMP_INIT, + "priv->TxPowerLevelCCK_C[%d] = 0x%x\n", + i, priv->TxPowerLevelCCK_C[i]); + for (i = 0; i < 14; i++) + RT_TRACE(COMP_INIT, + "priv->TxPowerLevelOFDM24G_C[%d] = 0x%x\n", + i, priv->TxPowerLevelOFDM24G_C[i]); + priv->LegacyHTTxPowerDiff = + priv->EEPROMLegacyHTTxPowerDiff; + priv->AntennaTxPwDiff[0] = 0; + priv->AntennaTxPwDiff[1] = 0; + priv->AntennaTxPwDiff[2] = 0; + priv->CrystalCap = priv->EEPROMCrystalCap; + priv->ThermalMeter[0] = (priv->EEPROMThermalMeter & + 0xf); + priv->ThermalMeter[1] = (priv->EEPROMThermalMeter & + 0xf0) >> 4; + } + } + + if (priv->rf_type == RF_1T2R) { + /* no matter what checkpatch says, the braces are needed */ + RT_TRACE(COMP_INIT, "\n1T2R config\n"); + } else if (priv->rf_type == RF_2T4R) { + RT_TRACE(COMP_INIT, "\n2T4R config\n"); + } + + init_rate_adaptive(dev); + + priv->rf_chip = RF_8256; + + if (priv->RegChannelPlan == 0xf) + priv->ChannelPlan = priv->eeprom_ChannelPlan; + else + priv->ChannelPlan = priv->RegChannelPlan; + + if (priv->eeprom_vid == 0x1186 && priv->eeprom_did == 0x3304) + priv->CustomerID = RT_CID_DLINK; + + switch (priv->eeprom_CustomerID) { + case EEPROM_CID_DEFAULT: + priv->CustomerID = RT_CID_DEFAULT; + break; + case EEPROM_CID_CAMEO: + priv->CustomerID = RT_CID_819x_CAMEO; + break; + case EEPROM_CID_RUNTOP: + priv->CustomerID = RT_CID_819x_RUNTOP; + break; + case EEPROM_CID_NetCore: + priv->CustomerID = RT_CID_819x_Netcore; + break; + case EEPROM_CID_TOSHIBA: + priv->CustomerID = RT_CID_TOSHIBA; + if (priv->eeprom_ChannelPlan&0x80) + priv->ChannelPlan = priv->eeprom_ChannelPlan&0x7f; + else + priv->ChannelPlan = 0x0; + RT_TRACE(COMP_INIT, "Toshiba ChannelPlan = 0x%x\n", + priv->ChannelPlan); + break; + case EEPROM_CID_Nettronix: + priv->ScanDelay = 100; + priv->CustomerID = RT_CID_Nettronix; + break; + case EEPROM_CID_Pronet: + priv->CustomerID = RT_CID_PRONET; + break; + case EEPROM_CID_DLINK: + priv->CustomerID = RT_CID_DLINK; + break; + + case EEPROM_CID_WHQL: + break; + default: + break; + } + + if (priv->ChannelPlan > CHANNEL_PLAN_LEN - 1) + priv->ChannelPlan = 0; + priv->ChannelPlan = COUNTRY_CODE_WORLD_WIDE_13; + + if (priv->eeprom_vid == 0x1186 && priv->eeprom_did == 0x3304) + priv->rtllib->bSupportRemoteWakeUp = true; + else + priv->rtllib->bSupportRemoteWakeUp = false; + + RT_TRACE(COMP_INIT, "RegChannelPlan(%d)\n", priv->RegChannelPlan); + RT_TRACE(COMP_INIT, "ChannelPlan = %d\n", priv->ChannelPlan); + RT_TRACE(COMP_TRACE, "<==== ReadAdapterInfo\n"); +} + +void rtl8192_get_eeprom_size(struct net_device *dev) +{ + u16 curCR; + struct r8192_priv *priv = rtllib_priv(dev); + + RT_TRACE(COMP_INIT, "===========>%s()\n", __func__); + curCR = read_nic_dword(dev, EPROM_CMD); + RT_TRACE(COMP_INIT, "read from Reg Cmd9346CR(%x):%x\n", EPROM_CMD, + curCR); + priv->epromtype = (curCR & EPROM_CMD_9356SEL) ? EEPROM_93C56 : + EEPROM_93C46; + RT_TRACE(COMP_INIT, "<===========%s(), epromtype:%d\n", __func__, + priv->epromtype); + rtl8192_read_eeprom_info(dev); +} + +static void rtl8192_hwconfig(struct net_device *dev) +{ + u32 regRATR = 0, regRRSR = 0; + u8 regBwOpMode = 0, regTmp = 0; + struct r8192_priv *priv = rtllib_priv(dev); + + switch (priv->rtllib->mode) { + case WIRELESS_MODE_B: + regBwOpMode = BW_OPMODE_20MHZ; + regRATR = RATE_ALL_CCK; + regRRSR = RATE_ALL_CCK; + break; + case WIRELESS_MODE_A: + regBwOpMode = BW_OPMODE_5G | BW_OPMODE_20MHZ; + regRATR = RATE_ALL_OFDM_AG; + regRRSR = RATE_ALL_OFDM_AG; + break; + case WIRELESS_MODE_G: + regBwOpMode = BW_OPMODE_20MHZ; + regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; + regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; + break; + case WIRELESS_MODE_AUTO: + case WIRELESS_MODE_N_24G: + regBwOpMode = BW_OPMODE_20MHZ; + regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG | + RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS; + regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; + break; + case WIRELESS_MODE_N_5G: + regBwOpMode = BW_OPMODE_5G; + regRATR = RATE_ALL_OFDM_AG | RATE_ALL_OFDM_1SS | + RATE_ALL_OFDM_2SS; + regRRSR = RATE_ALL_OFDM_AG; + break; + default: + regBwOpMode = BW_OPMODE_20MHZ; + regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; + regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; + break; + } + + write_nic_byte(dev, BW_OPMODE, regBwOpMode); + { + u32 ratr_value = 0; + + ratr_value = regRATR; + if (priv->rf_type == RF_1T2R) + ratr_value &= ~(RATE_ALL_OFDM_2SS); + write_nic_dword(dev, RATR0, ratr_value); + write_nic_byte(dev, UFWP, 1); + } + regTmp = read_nic_byte(dev, 0x313); + regRRSR = ((regTmp) << 24) | (regRRSR & 0x00ffffff); + write_nic_dword(dev, RRSR, regRRSR); + + write_nic_word(dev, RETRY_LIMIT, + priv->ShortRetryLimit << RETRY_LIMIT_SHORT_SHIFT | + priv->LongRetryLimit << RETRY_LIMIT_LONG_SHIFT); +} + +bool rtl8192_adapter_start(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + u32 ulRegRead; + bool rtStatus = true; + u8 tmpvalue; + u8 ICVersion, SwitchingRegulatorOutput; + bool bfirmwareok = true; + u32 tmpRegA, tmpRegC, TempCCk; + int i = 0; + u32 retry_times = 0; + + RT_TRACE(COMP_INIT, "====>%s()\n", __func__); + priv->being_init_adapter = true; + +start: + rtl8192_pci_resetdescring(dev); + priv->Rf_Mode = RF_OP_By_SW_3wire; + if (priv->ResetProgress == RESET_TYPE_NORESET) { + write_nic_byte(dev, ANAPAR, 0x37); + mdelay(500); + } + priv->pFirmware->firmware_status = FW_STATUS_0_INIT; + + if (priv->RegRfOff) + priv->rtllib->eRFPowerState = eRfOff; + + ulRegRead = read_nic_dword(dev, CPU_GEN); + if (priv->pFirmware->firmware_status == FW_STATUS_0_INIT) + ulRegRead |= CPU_GEN_SYSTEM_RESET; + else if (priv->pFirmware->firmware_status == FW_STATUS_5_READY) + ulRegRead |= CPU_GEN_FIRMWARE_RESET; + else + RT_TRACE(COMP_ERR, + "ERROR in %s(): undefined firmware state(%d)\n", + __func__, priv->pFirmware->firmware_status); + + write_nic_dword(dev, CPU_GEN, ulRegRead); + + ICVersion = read_nic_byte(dev, IC_VERRSION); + if (ICVersion >= 0x4) { + SwitchingRegulatorOutput = read_nic_byte(dev, SWREGULATOR); + if (SwitchingRegulatorOutput != 0xb8) { + write_nic_byte(dev, SWREGULATOR, 0xa8); + mdelay(1); + write_nic_byte(dev, SWREGULATOR, 0xb8); + } + } + RT_TRACE(COMP_INIT, "BB Config Start!\n"); + rtStatus = rtl8192_BBConfig(dev); + if (!rtStatus) { + RT_TRACE(COMP_ERR, "BB Config failed\n"); + return rtStatus; + } + RT_TRACE(COMP_INIT, "BB Config Finished!\n"); + + priv->LoopbackMode = RTL819X_NO_LOOPBACK; + if (priv->ResetProgress == RESET_TYPE_NORESET) { + ulRegRead = read_nic_dword(dev, CPU_GEN); + if (priv->LoopbackMode == RTL819X_NO_LOOPBACK) + ulRegRead = ((ulRegRead & CPU_GEN_NO_LOOPBACK_MSK) | + CPU_GEN_NO_LOOPBACK_SET); + else if (priv->LoopbackMode == RTL819X_MAC_LOOPBACK) + ulRegRead |= CPU_CCK_LOOPBACK; + else + RT_TRACE(COMP_ERR, + "Serious error: wrong loopback mode setting\n"); + + write_nic_dword(dev, CPU_GEN, ulRegRead); + + udelay(500); + } + rtl8192_hwconfig(dev); + write_nic_byte(dev, CMDR, CR_RE | CR_TE); + + write_nic_byte(dev, PCIF, ((MXDMA2_NoLimit<dev_addr)[0]); + write_nic_word(dev, MAC4, ((u16 *)(dev->dev_addr + 4))[0]); + write_nic_dword(dev, RCR, priv->ReceiveConfig); + + write_nic_dword(dev, RQPN1, NUM_OF_PAGE_IN_FW_QUEUE_BK << + RSVD_FW_QUEUE_PAGE_BK_SHIFT | + NUM_OF_PAGE_IN_FW_QUEUE_BE << + RSVD_FW_QUEUE_PAGE_BE_SHIFT | + NUM_OF_PAGE_IN_FW_QUEUE_VI << + RSVD_FW_QUEUE_PAGE_VI_SHIFT | + NUM_OF_PAGE_IN_FW_QUEUE_VO << + RSVD_FW_QUEUE_PAGE_VO_SHIFT); + write_nic_dword(dev, RQPN2, NUM_OF_PAGE_IN_FW_QUEUE_MGNT << + RSVD_FW_QUEUE_PAGE_MGNT_SHIFT); + write_nic_dword(dev, RQPN3, APPLIED_RESERVED_QUEUE_IN_FW | + NUM_OF_PAGE_IN_FW_QUEUE_BCN << + RSVD_FW_QUEUE_PAGE_BCN_SHIFT| + NUM_OF_PAGE_IN_FW_QUEUE_PUB << + RSVD_FW_QUEUE_PAGE_PUB_SHIFT); + + rtl8192_tx_enable(dev); + rtl8192_rx_enable(dev); + ulRegRead = (0xFFF00000 & read_nic_dword(dev, RRSR)) | + RATE_ALL_OFDM_AG | RATE_ALL_CCK; + write_nic_dword(dev, RRSR, ulRegRead); + write_nic_dword(dev, RATR0+4*7, (RATE_ALL_OFDM_AG | RATE_ALL_CCK)); + + write_nic_byte(dev, ACK_TIMEOUT, 0x30); + + if (priv->ResetProgress == RESET_TYPE_NORESET) + rtl8192_SetWirelessMode(dev, priv->rtllib->mode); + CamResetAllEntry(dev); + { + u8 SECR_value = 0x0; + + SECR_value |= SCR_TxEncEnable; + SECR_value |= SCR_RxDecEnable; + SECR_value |= SCR_NoSKMC; + write_nic_byte(dev, SECR, SECR_value); + } + write_nic_word(dev, ATIMWND, 2); + write_nic_word(dev, BCN_INTERVAL, 100); + { + int i; + + for (i = 0; i < QOS_QUEUE_NUM; i++) + write_nic_dword(dev, WDCAPARA_ADD[i], 0x005e4332); + } + write_nic_byte(dev, 0xbe, 0xc0); + + rtl8192_phy_configmac(dev); + + if (priv->card_8192_version > (u8) VERSION_8190_BD) { + rtl8192_phy_getTxPower(dev); + rtl8192_phy_setTxPower(dev, priv->chan); + } + + tmpvalue = read_nic_byte(dev, IC_VERRSION); + priv->IC_Cut = tmpvalue; + RT_TRACE(COMP_INIT, "priv->IC_Cut= 0x%x\n", priv->IC_Cut); + if (priv->IC_Cut >= IC_VersionCut_D) { + if (priv->IC_Cut == IC_VersionCut_D) { + /* no matter what checkpatch says, braces are needed */ + RT_TRACE(COMP_INIT, "D-cut\n"); + } else if (priv->IC_Cut == IC_VersionCut_E) { + RT_TRACE(COMP_INIT, "E-cut\n"); + } + } else { + RT_TRACE(COMP_INIT, "Before C-cut\n"); + } + + RT_TRACE(COMP_INIT, "Load Firmware!\n"); + bfirmwareok = init_firmware(dev); + if (!bfirmwareok) { + if (retry_times < 10) { + retry_times++; + goto start; + } else { + rtStatus = false; + goto end; + } + } + RT_TRACE(COMP_INIT, "Load Firmware finished!\n"); + if (priv->ResetProgress == RESET_TYPE_NORESET) { + RT_TRACE(COMP_INIT, "RF Config Started!\n"); + rtStatus = rtl8192_phy_RFConfig(dev); + if (!rtStatus) { + RT_TRACE(COMP_ERR, "RF Config failed\n"); + return rtStatus; + } + RT_TRACE(COMP_INIT, "RF Config Finished!\n"); + } + rtl8192_phy_updateInitGain(dev); + + rtl8192_setBBreg(dev, rFPGA0_RFMOD, bCCKEn, 0x1); + rtl8192_setBBreg(dev, rFPGA0_RFMOD, bOFDMEn, 0x1); + + write_nic_byte(dev, 0x87, 0x0); + + if (priv->RegRfOff) { + RT_TRACE((COMP_INIT | COMP_RF | COMP_POWER), + "%s(): Turn off RF for RegRfOff ----------\n", + __func__); + MgntActSet_RF_State(dev, eRfOff, RF_CHANGE_BY_SW, true); + } else if (priv->rtllib->RfOffReason > RF_CHANGE_BY_PS) { + RT_TRACE((COMP_INIT|COMP_RF|COMP_POWER), + "%s(): Turn off RF for RfOffReason(%d) ----------\n", + __func__, priv->rtllib->RfOffReason); + MgntActSet_RF_State(dev, eRfOff, priv->rtllib->RfOffReason, + true); + } else if (priv->rtllib->RfOffReason >= RF_CHANGE_BY_IPS) { + RT_TRACE((COMP_INIT|COMP_RF|COMP_POWER), + "%s(): Turn off RF for RfOffReason(%d) ----------\n", + __func__, priv->rtllib->RfOffReason); + MgntActSet_RF_State(dev, eRfOff, priv->rtllib->RfOffReason, + true); + } else { + RT_TRACE((COMP_INIT|COMP_RF|COMP_POWER), "%s(): RF-ON\n", + __func__); + priv->rtllib->eRFPowerState = eRfOn; + priv->rtllib->RfOffReason = 0; + } + + if (priv->rtllib->FwRWRF) + priv->Rf_Mode = RF_OP_By_FW; + else + priv->Rf_Mode = RF_OP_By_SW_3wire; + + if (priv->ResetProgress == RESET_TYPE_NORESET) { + dm_initialize_txpower_tracking(dev); + + if (priv->IC_Cut >= IC_VersionCut_D) { + tmpRegA = rtl8192_QueryBBReg(dev, + rOFDM0_XATxIQImbalance, bMaskDWord); + tmpRegC = rtl8192_QueryBBReg(dev, + rOFDM0_XCTxIQImbalance, bMaskDWord); + for (i = 0; i < TxBBGainTableLength; i++) { + if (tmpRegA == + priv->txbbgain_table[i].txbbgain_value) { + priv->rfa_txpowertrackingindex = (u8)i; + priv->rfa_txpowertrackingindex_real = + (u8)i; + priv->rfa_txpowertracking_default = + priv->rfa_txpowertrackingindex; + break; + } + } + + TempCCk = rtl8192_QueryBBReg(dev, + rCCK0_TxFilter1, bMaskByte2); + + for (i = 0; i < CCKTxBBGainTableLength; i++) { + if (TempCCk == priv->cck_txbbgain_table[i].ccktxbb_valuearray[0]) { + priv->CCKPresentAttentuation_20Mdefault = (u8)i; + break; + } + } + priv->CCKPresentAttentuation_40Mdefault = 0; + priv->CCKPresentAttentuation_difference = 0; + priv->CCKPresentAttentuation = + priv->CCKPresentAttentuation_20Mdefault; + RT_TRACE(COMP_POWER_TRACKING, + "priv->rfa_txpowertrackingindex_initial = %d\n", + priv->rfa_txpowertrackingindex); + RT_TRACE(COMP_POWER_TRACKING, + "priv->rfa_txpowertrackingindex_real__initial = %d\n", + priv->rfa_txpowertrackingindex_real); + RT_TRACE(COMP_POWER_TRACKING, + "priv->CCKPresentAttentuation_difference_initial = %d\n", + priv->CCKPresentAttentuation_difference); + RT_TRACE(COMP_POWER_TRACKING, + "priv->CCKPresentAttentuation_initial = %d\n", + priv->CCKPresentAttentuation); + priv->btxpower_tracking = false; + } + } + rtl8192_irq_enable(dev); +end: + priv->being_init_adapter = false; + return rtStatus; +} + +static void rtl8192_net_update(struct net_device *dev) +{ + + struct r8192_priv *priv = rtllib_priv(dev); + struct rtllib_network *net; + u16 BcnTimeCfg = 0, BcnCW = 6, BcnIFS = 0xf; + u16 rate_config = 0; + + net = &priv->rtllib->current_network; + rtl8192_config_rate(dev, &rate_config); + priv->dot11CurrentPreambleMode = PREAMBLE_AUTO; + priv->basic_rate = rate_config &= 0x15f; + write_nic_dword(dev, BSSIDR, ((u32 *)net->bssid)[0]); + write_nic_word(dev, BSSIDR+4, ((u16 *)net->bssid)[2]); + + if (priv->rtllib->iw_mode == IW_MODE_ADHOC) { + write_nic_word(dev, ATIMWND, 2); + write_nic_word(dev, BCN_DMATIME, 256); + write_nic_word(dev, BCN_INTERVAL, net->beacon_interval); + write_nic_word(dev, BCN_DRV_EARLY_INT, 10); + write_nic_byte(dev, BCN_ERR_THRESH, 100); + + BcnTimeCfg |= (BcnCW<rtllib; + + if (!priv->up) + return; + + if (ieee->state == RTLLIB_LINKED) { + rtl8192_net_update(dev); + priv->ops->update_ratr_table(dev); + if ((KEY_TYPE_WEP40 == ieee->pairwise_key_type) || + (KEY_TYPE_WEP104 == ieee->pairwise_key_type)) + EnableHWSecurityConfig8192(dev); + } else { + write_nic_byte(dev, 0x173, 0); + } + rtl8192e_update_msr(dev); + + if (ieee->iw_mode == IW_MODE_INFRA || ieee->iw_mode == IW_MODE_ADHOC) { + u32 reg = 0; + + reg = read_nic_dword(dev, RCR); + if (priv->rtllib->state == RTLLIB_LINKED) { + if (ieee->IntelPromiscuousModeInfo.bPromiscuousOn) + ; + else + priv->ReceiveConfig = reg |= RCR_CBSSID; + } else + priv->ReceiveConfig = reg &= ~RCR_CBSSID; + + write_nic_dword(dev, RCR, reg); + } +} + +void rtl8192_AllowAllDestAddr(struct net_device *dev, + bool bAllowAllDA, bool WriteIntoReg) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + if (bAllowAllDA) + priv->ReceiveConfig |= RCR_AAP; + else + priv->ReceiveConfig &= ~RCR_AAP; + + if (WriteIntoReg) + write_nic_dword(dev, RCR, priv->ReceiveConfig); +} + +static u8 MRateToHwRate8190Pci(u8 rate) +{ + u8 ret = DESC90_RATE1M; + + switch (rate) { + case MGN_1M: + ret = DESC90_RATE1M; + break; + case MGN_2M: + ret = DESC90_RATE2M; + break; + case MGN_5_5M: + ret = DESC90_RATE5_5M; + break; + case MGN_11M: + ret = DESC90_RATE11M; + break; + case MGN_6M: + ret = DESC90_RATE6M; + break; + case MGN_9M: + ret = DESC90_RATE9M; + break; + case MGN_12M: + ret = DESC90_RATE12M; + break; + case MGN_18M: + ret = DESC90_RATE18M; + break; + case MGN_24M: + ret = DESC90_RATE24M; + break; + case MGN_36M: + ret = DESC90_RATE36M; + break; + case MGN_48M: + ret = DESC90_RATE48M; + break; + case MGN_54M: + ret = DESC90_RATE54M; + break; + case MGN_MCS0: + ret = DESC90_RATEMCS0; + break; + case MGN_MCS1: + ret = DESC90_RATEMCS1; + break; + case MGN_MCS2: + ret = DESC90_RATEMCS2; + break; + case MGN_MCS3: + ret = DESC90_RATEMCS3; + break; + case MGN_MCS4: + ret = DESC90_RATEMCS4; + break; + case MGN_MCS5: + ret = DESC90_RATEMCS5; + break; + case MGN_MCS6: + ret = DESC90_RATEMCS6; + break; + case MGN_MCS7: + ret = DESC90_RATEMCS7; + break; + case MGN_MCS8: + ret = DESC90_RATEMCS8; + break; + case MGN_MCS9: + ret = DESC90_RATEMCS9; + break; + case MGN_MCS10: + ret = DESC90_RATEMCS10; + break; + case MGN_MCS11: + ret = DESC90_RATEMCS11; + break; + case MGN_MCS12: + ret = DESC90_RATEMCS12; + break; + case MGN_MCS13: + ret = DESC90_RATEMCS13; + break; + case MGN_MCS14: + ret = DESC90_RATEMCS14; + break; + case MGN_MCS15: + ret = DESC90_RATEMCS15; + break; + case (0x80|0x20): + ret = DESC90_RATEMCS32; + break; + default: + break; + } + return ret; +} + +static u8 rtl8192_MapHwQueueToFirmwareQueue(u8 QueueID, u8 priority) +{ + u8 QueueSelect = 0x0; + + switch (QueueID) { + case BE_QUEUE: + QueueSelect = QSLT_BE; + break; + + case BK_QUEUE: + QueueSelect = QSLT_BK; + break; + + case VO_QUEUE: + QueueSelect = QSLT_VO; + break; + + case VI_QUEUE: + QueueSelect = QSLT_VI; + break; + case MGNT_QUEUE: + QueueSelect = QSLT_MGNT; + break; + case BEACON_QUEUE: + QueueSelect = QSLT_BEACON; + break; + case TXCMD_QUEUE: + QueueSelect = QSLT_CMD; + break; + case HIGH_QUEUE: + QueueSelect = QSLT_HIGH; + break; + default: + RT_TRACE(COMP_ERR, + "TransmitTCB(): Impossible Queue Selection: %d\n", + QueueID); + break; + } + return QueueSelect; +} + +void rtl8192_tx_fill_desc(struct net_device *dev, struct tx_desc *pdesc, + struct cb_desc *cb_desc, struct sk_buff *skb) +{ + struct r8192_priv *priv = rtllib_priv(dev); + dma_addr_t mapping = pci_map_single(priv->pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); + struct tx_fwinfo_8190pci *pTxFwInfo = NULL; + + pTxFwInfo = (struct tx_fwinfo_8190pci *)skb->data; + memset(pTxFwInfo, 0, sizeof(struct tx_fwinfo_8190pci)); + pTxFwInfo->TxHT = (cb_desc->data_rate & 0x80) ? 1 : 0; + pTxFwInfo->TxRate = MRateToHwRate8190Pci((u8)cb_desc->data_rate); + pTxFwInfo->EnableCPUDur = cb_desc->bTxEnableFwCalcDur; + pTxFwInfo->Short = rtl8192_QueryIsShort(pTxFwInfo->TxHT, + pTxFwInfo->TxRate, + cb_desc); + + if (pci_dma_mapping_error(priv->pdev, mapping)) + RT_TRACE(COMP_ERR, "DMA Mapping error\n"); + if (cb_desc->bAMPDUEnable) { + pTxFwInfo->AllowAggregation = 1; + pTxFwInfo->RxMF = cb_desc->ampdu_factor; + pTxFwInfo->RxAMD = cb_desc->ampdu_density; + } else { + pTxFwInfo->AllowAggregation = 0; + pTxFwInfo->RxMF = 0; + pTxFwInfo->RxAMD = 0; + } + + pTxFwInfo->RtsEnable = (cb_desc->bRTSEnable) ? 1 : 0; + pTxFwInfo->CtsEnable = (cb_desc->bCTSEnable) ? 1 : 0; + pTxFwInfo->RtsSTBC = (cb_desc->bRTSSTBC) ? 1 : 0; + pTxFwInfo->RtsHT = (cb_desc->rts_rate&0x80) ? 1 : 0; + pTxFwInfo->RtsRate = MRateToHwRate8190Pci((u8)cb_desc->rts_rate); + pTxFwInfo->RtsBandwidth = 0; + pTxFwInfo->RtsSubcarrier = cb_desc->RTSSC; + pTxFwInfo->RtsShort = (pTxFwInfo->RtsHT == 0) ? + (cb_desc->bRTSUseShortPreamble ? 1 : 0) : + (cb_desc->bRTSUseShortGI ? 1 : 0); + if (priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20_40) { + if (cb_desc->bPacketBW) { + pTxFwInfo->TxBandwidth = 1; + pTxFwInfo->TxSubCarrier = 0; + } else { + pTxFwInfo->TxBandwidth = 0; + pTxFwInfo->TxSubCarrier = priv->nCur40MhzPrimeSC; + } + } else { + pTxFwInfo->TxBandwidth = 0; + pTxFwInfo->TxSubCarrier = 0; + } + + memset((u8 *)pdesc, 0, 12); + pdesc->LINIP = 0; + pdesc->CmdInit = 1; + pdesc->Offset = sizeof(struct tx_fwinfo_8190pci) + 8; + pdesc->PktSize = (u16)skb->len-sizeof(struct tx_fwinfo_8190pci); + + pdesc->SecCAMID = 0; + pdesc->RATid = cb_desc->RATRIndex; + + + pdesc->NoEnc = 1; + pdesc->SecType = 0x0; + if (cb_desc->bHwSec) { + static u8 tmp; + + if (!tmp) { + RT_TRACE(COMP_DBG, "==>================hw sec\n"); + tmp = 1; + } + switch (priv->rtllib->pairwise_key_type) { + case KEY_TYPE_WEP40: + case KEY_TYPE_WEP104: + pdesc->SecType = 0x1; + pdesc->NoEnc = 0; + break; + case KEY_TYPE_TKIP: + pdesc->SecType = 0x2; + pdesc->NoEnc = 0; + break; + case KEY_TYPE_CCMP: + pdesc->SecType = 0x3; + pdesc->NoEnc = 0; + break; + case KEY_TYPE_NA: + pdesc->SecType = 0x0; + pdesc->NoEnc = 1; + break; + } + } + + pdesc->PktId = 0x0; + + pdesc->QueueSelect = rtl8192_MapHwQueueToFirmwareQueue( + cb_desc->queue_index, + cb_desc->priority); + pdesc->TxFWInfoSize = sizeof(struct tx_fwinfo_8190pci); + + pdesc->DISFB = cb_desc->bTxDisableRateFallBack; + pdesc->USERATE = cb_desc->bTxUseDriverAssingedRate; + + pdesc->FirstSeg = 1; + pdesc->LastSeg = 1; + pdesc->TxBufferSize = skb->len; + + pdesc->TxBuffAddr = mapping; +} + +void rtl8192_tx_fill_cmd_desc(struct net_device *dev, + struct tx_desc_cmd *entry, + struct cb_desc *cb_desc, struct sk_buff *skb) +{ + struct r8192_priv *priv = rtllib_priv(dev); + dma_addr_t mapping = pci_map_single(priv->pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); + + if (pci_dma_mapping_error(priv->pdev, mapping)) + RT_TRACE(COMP_ERR, "DMA Mapping error\n"); + memset(entry, 0, 12); + entry->LINIP = cb_desc->bLastIniPkt; + entry->FirstSeg = 1; + entry->LastSeg = 1; + if (cb_desc->bCmdOrInit == DESC_PACKET_TYPE_INIT) { + entry->CmdInit = DESC_PACKET_TYPE_INIT; + } else { + struct tx_desc *entry_tmp = (struct tx_desc *)entry; + + entry_tmp->CmdInit = DESC_PACKET_TYPE_NORMAL; + entry_tmp->Offset = sizeof(struct tx_fwinfo_8190pci) + 8; + entry_tmp->PktSize = (u16)(cb_desc->pkt_size + + entry_tmp->Offset); + entry_tmp->QueueSelect = QSLT_CMD; + entry_tmp->TxFWInfoSize = 0x08; + entry_tmp->RATid = (u8)DESC_PACKET_TYPE_INIT; + } + entry->TxBufferSize = skb->len; + entry->TxBuffAddr = mapping; + entry->OWN = 1; +} + +static u8 HwRateToMRate90(bool bIsHT, u8 rate) +{ + u8 ret_rate = 0x02; + + if (!bIsHT) { + switch (rate) { + case DESC90_RATE1M: + ret_rate = MGN_1M; + break; + case DESC90_RATE2M: + ret_rate = MGN_2M; + break; + case DESC90_RATE5_5M: + ret_rate = MGN_5_5M; + break; + case DESC90_RATE11M: + ret_rate = MGN_11M; + break; + case DESC90_RATE6M: + ret_rate = MGN_6M; + break; + case DESC90_RATE9M: + ret_rate = MGN_9M; + break; + case DESC90_RATE12M: + ret_rate = MGN_12M; + break; + case DESC90_RATE18M: + ret_rate = MGN_18M; + break; + case DESC90_RATE24M: + ret_rate = MGN_24M; + break; + case DESC90_RATE36M: + ret_rate = MGN_36M; + break; + case DESC90_RATE48M: + ret_rate = MGN_48M; + break; + case DESC90_RATE54M: + ret_rate = MGN_54M; + break; + + default: + RT_TRACE(COMP_RECV, + "HwRateToMRate90(): Non supportedRate [%x], bIsHT = %d!!!\n", + rate, bIsHT); + break; + } + + } else { + switch (rate) { + case DESC90_RATEMCS0: + ret_rate = MGN_MCS0; + break; + case DESC90_RATEMCS1: + ret_rate = MGN_MCS1; + break; + case DESC90_RATEMCS2: + ret_rate = MGN_MCS2; + break; + case DESC90_RATEMCS3: + ret_rate = MGN_MCS3; + break; + case DESC90_RATEMCS4: + ret_rate = MGN_MCS4; + break; + case DESC90_RATEMCS5: + ret_rate = MGN_MCS5; + break; + case DESC90_RATEMCS6: + ret_rate = MGN_MCS6; + break; + case DESC90_RATEMCS7: + ret_rate = MGN_MCS7; + break; + case DESC90_RATEMCS8: + ret_rate = MGN_MCS8; + break; + case DESC90_RATEMCS9: + ret_rate = MGN_MCS9; + break; + case DESC90_RATEMCS10: + ret_rate = MGN_MCS10; + break; + case DESC90_RATEMCS11: + ret_rate = MGN_MCS11; + break; + case DESC90_RATEMCS12: + ret_rate = MGN_MCS12; + break; + case DESC90_RATEMCS13: + ret_rate = MGN_MCS13; + break; + case DESC90_RATEMCS14: + ret_rate = MGN_MCS14; + break; + case DESC90_RATEMCS15: + ret_rate = MGN_MCS15; + break; + case DESC90_RATEMCS32: + ret_rate = (0x80|0x20); + break; + + default: + RT_TRACE(COMP_RECV, + "HwRateToMRate90(): Non supported Rate [%x], bIsHT = %d!!!\n", + rate, bIsHT); + break; + } + } + + return ret_rate; +} + +static long rtl8192_signal_scale_mapping(struct r8192_priv *priv, long currsig) +{ + long retsig; + + if (currsig >= 61 && currsig <= 100) + retsig = 90 + ((currsig - 60) / 4); + else if (currsig >= 41 && currsig <= 60) + retsig = 78 + ((currsig - 40) / 2); + else if (currsig >= 31 && currsig <= 40) + retsig = 66 + (currsig - 30); + else if (currsig >= 21 && currsig <= 30) + retsig = 54 + (currsig - 20); + else if (currsig >= 5 && currsig <= 20) + retsig = 42 + (((currsig - 5) * 2) / 3); + else if (currsig == 4) + retsig = 36; + else if (currsig == 3) + retsig = 27; + else if (currsig == 2) + retsig = 18; + else if (currsig == 1) + retsig = 9; + else + retsig = currsig; + + return retsig; +} + + +#define rx_hal_is_cck_rate(_pdrvinfo)\ + ((_pdrvinfo->RxRate == DESC90_RATE1M ||\ + _pdrvinfo->RxRate == DESC90_RATE2M ||\ + _pdrvinfo->RxRate == DESC90_RATE5_5M ||\ + _pdrvinfo->RxRate == DESC90_RATE11M) &&\ + !_pdrvinfo->RxHT) + +static void rtl8192_query_rxphystatus( + struct r8192_priv *priv, + struct rtllib_rx_stats *pstats, + struct rx_desc *pdesc, + struct rx_fwinfo *pdrvinfo, + struct rtllib_rx_stats *precord_stats, + bool bpacket_match_bssid, + bool bpacket_toself, + bool bPacketBeacon, + bool bToSelfBA + ) +{ + struct phy_sts_ofdm_819xpci *pofdm_buf; + struct phy_sts_cck_819xpci *pcck_buf; + struct phy_ofdm_rx_status_rxsc_sgien_exintfflag *prxsc; + u8 *prxpkt; + u8 i, max_spatial_stream, tmp_rxsnr, tmp_rxevm, rxsc_sgien_exflg; + char rx_pwr[4], rx_pwr_all = 0; + char rx_snrX, rx_evmX; + u8 evm, pwdb_all; + u32 RSSI, total_rssi = 0; + u8 is_cck_rate = 0; + u8 rf_rx_num = 0; + static u8 check_reg824; + static u32 reg824_bit9; + + priv->stats.numqry_phystatus++; + + is_cck_rate = rx_hal_is_cck_rate(pdrvinfo); + memset(precord_stats, 0, sizeof(struct rtllib_rx_stats)); + pstats->bPacketMatchBSSID = precord_stats->bPacketMatchBSSID = + bpacket_match_bssid; + pstats->bPacketToSelf = precord_stats->bPacketToSelf = bpacket_toself; + pstats->bIsCCK = precord_stats->bIsCCK = is_cck_rate; + pstats->bPacketBeacon = precord_stats->bPacketBeacon = bPacketBeacon; + pstats->bToSelfBA = precord_stats->bToSelfBA = bToSelfBA; + if (check_reg824 == 0) { + reg824_bit9 = rtl8192_QueryBBReg(priv->rtllib->dev, + rFPGA0_XA_HSSIParameter2, 0x200); + check_reg824 = 1; + } + + + prxpkt = (u8 *)pdrvinfo; + + prxpkt += sizeof(struct rx_fwinfo); + + pcck_buf = (struct phy_sts_cck_819xpci *)prxpkt; + pofdm_buf = (struct phy_sts_ofdm_819xpci *)prxpkt; + + pstats->RxMIMOSignalQuality[0] = -1; + pstats->RxMIMOSignalQuality[1] = -1; + precord_stats->RxMIMOSignalQuality[0] = -1; + precord_stats->RxMIMOSignalQuality[1] = -1; + + if (is_cck_rate) { + u8 report; + + priv->stats.numqry_phystatusCCK++; + if (!reg824_bit9) { + report = pcck_buf->cck_agc_rpt & 0xc0; + report >>= 6; + switch (report) { + case 0x3: + rx_pwr_all = -35 - (pcck_buf->cck_agc_rpt & + 0x3e); + break; + case 0x2: + rx_pwr_all = -23 - (pcck_buf->cck_agc_rpt & + 0x3e); + break; + case 0x1: + rx_pwr_all = -11 - (pcck_buf->cck_agc_rpt & + 0x3e); + break; + case 0x0: + rx_pwr_all = 8 - (pcck_buf->cck_agc_rpt & 0x3e); + break; + } + } else { + report = pcck_buf->cck_agc_rpt & 0x60; + report >>= 5; + switch (report) { + case 0x3: + rx_pwr_all = -35 - + ((pcck_buf->cck_agc_rpt & + 0x1f) << 1); + break; + case 0x2: + rx_pwr_all = -23 - + ((pcck_buf->cck_agc_rpt & + 0x1f) << 1); + break; + case 0x1: + rx_pwr_all = -11 - + ((pcck_buf->cck_agc_rpt & + 0x1f) << 1); + break; + case 0x0: + rx_pwr_all = -8 - + ((pcck_buf->cck_agc_rpt & + 0x1f) << 1); + break; + } + } + + pwdb_all = rtl819x_query_rxpwrpercentage(rx_pwr_all); + pstats->RxPWDBAll = precord_stats->RxPWDBAll = pwdb_all; + pstats->RecvSignalPower = rx_pwr_all; + + if (bpacket_match_bssid) { + u8 sq; + + if (pstats->RxPWDBAll > 40) { + sq = 100; + } else { + sq = pcck_buf->sq_rpt; + + if (pcck_buf->sq_rpt > 64) + sq = 0; + else if (pcck_buf->sq_rpt < 20) + sq = 100; + else + sq = ((64-sq) * 100) / 44; + } + pstats->SignalQuality = sq; + precord_stats->SignalQuality = sq; + pstats->RxMIMOSignalQuality[0] = sq; + precord_stats->RxMIMOSignalQuality[0] = sq; + pstats->RxMIMOSignalQuality[1] = -1; + precord_stats->RxMIMOSignalQuality[1] = -1; + } + } else { + priv->stats.numqry_phystatusHT++; + for (i = RF90_PATH_A; i < RF90_PATH_MAX; i++) { + if (priv->brfpath_rxenable[i]) + rf_rx_num++; + + rx_pwr[i] = ((pofdm_buf->trsw_gain_X[i] & 0x3F) * + 2) - 110; + + tmp_rxsnr = pofdm_buf->rxsnr_X[i]; + rx_snrX = (char)(tmp_rxsnr); + rx_snrX /= 2; + priv->stats.rxSNRdB[i] = (long)rx_snrX; + + RSSI = rtl819x_query_rxpwrpercentage(rx_pwr[i]); + if (priv->brfpath_rxenable[i]) + total_rssi += RSSI; + + if (bpacket_match_bssid) { + pstats->RxMIMOSignalStrength[i] = (u8) RSSI; + precord_stats->RxMIMOSignalStrength[i] = + (u8) RSSI; + } + } + + + rx_pwr_all = (((pofdm_buf->pwdb_all) >> 1) & 0x7f) - 106; + pwdb_all = rtl819x_query_rxpwrpercentage(rx_pwr_all); + + pstats->RxPWDBAll = precord_stats->RxPWDBAll = pwdb_all; + pstats->RxPower = precord_stats->RxPower = rx_pwr_all; + pstats->RecvSignalPower = rx_pwr_all; + if (pdrvinfo->RxHT && pdrvinfo->RxRate >= DESC90_RATEMCS8 && + pdrvinfo->RxRate <= DESC90_RATEMCS15) + max_spatial_stream = 2; + else + max_spatial_stream = 1; + + for (i = 0; i < max_spatial_stream; i++) { + tmp_rxevm = pofdm_buf->rxevm_X[i]; + rx_evmX = (char)(tmp_rxevm); + + rx_evmX /= 2; + + evm = rtl819x_evm_dbtopercentage(rx_evmX); + if (bpacket_match_bssid) { + if (i == 0) { + pstats->SignalQuality = (u8)(evm & + 0xff); + precord_stats->SignalQuality = (u8)(evm + & 0xff); + } + pstats->RxMIMOSignalQuality[i] = (u8)(evm & + 0xff); + precord_stats->RxMIMOSignalQuality[i] = (u8)(evm + & 0xff); + } + } + + + rxsc_sgien_exflg = pofdm_buf->rxsc_sgien_exflg; + prxsc = (struct phy_ofdm_rx_status_rxsc_sgien_exintfflag *) + &rxsc_sgien_exflg; + if (pdrvinfo->BW) + priv->stats.received_bwtype[1+prxsc->rxsc]++; + else + priv->stats.received_bwtype[0]++; + } + + if (is_cck_rate) { + pstats->SignalStrength = precord_stats->SignalStrength = + (u8)(rtl8192_signal_scale_mapping(priv, + (long)pwdb_all)); + + } else { + if (rf_rx_num != 0) + pstats->SignalStrength = precord_stats->SignalStrength = + (u8)(rtl8192_signal_scale_mapping(priv, + (long)(total_rssi /= rf_rx_num))); + } +} + +static void rtl8192_process_phyinfo(struct r8192_priv *priv, u8 *buffer, + struct rtllib_rx_stats *prev_st, + struct rtllib_rx_stats *curr_st) +{ + bool bcheck = false; + u8 rfpath; + u32 ij, tmp_val; + static u32 slide_rssi_index, slide_rssi_statistics; + static u32 slide_evm_index, slide_evm_statistics; + static u32 last_rssi, last_evm; + static u32 slide_beacon_adc_pwdb_index; + static u32 slide_beacon_adc_pwdb_statistics; + static u32 last_beacon_adc_pwdb; + struct rtllib_hdr_3addr *hdr; + u16 sc; + unsigned int frag, seq; + + hdr = (struct rtllib_hdr_3addr *)buffer; + sc = le16_to_cpu(hdr->seq_ctl); + frag = WLAN_GET_SEQ_FRAG(sc); + seq = WLAN_GET_SEQ_SEQ(sc); + curr_st->Seq_Num = seq; + if (!prev_st->bIsAMPDU) + bcheck = true; + + if (slide_rssi_statistics++ >= PHY_RSSI_SLID_WIN_MAX) { + slide_rssi_statistics = PHY_RSSI_SLID_WIN_MAX; + last_rssi = priv->stats.slide_signal_strength[slide_rssi_index]; + priv->stats.slide_rssi_total -= last_rssi; + } + priv->stats.slide_rssi_total += prev_st->SignalStrength; + + priv->stats.slide_signal_strength[slide_rssi_index++] = + prev_st->SignalStrength; + if (slide_rssi_index >= PHY_RSSI_SLID_WIN_MAX) + slide_rssi_index = 0; + + tmp_val = priv->stats.slide_rssi_total/slide_rssi_statistics; + priv->stats.signal_strength = rtl819x_translate_todbm(priv, + (u8)tmp_val); + curr_st->rssi = priv->stats.signal_strength; + if (!prev_st->bPacketMatchBSSID) { + if (!prev_st->bToSelfBA) + return; + } + + if (!bcheck) + return; + + rtl819x_process_cck_rxpathsel(priv, prev_st); + + priv->stats.num_process_phyinfo++; + if (!prev_st->bIsCCK && prev_st->bPacketToSelf) { + for (rfpath = RF90_PATH_A; rfpath < RF90_PATH_C; rfpath++) { + if (!rtl8192_phy_CheckIsLegalRFPath(priv->rtllib->dev, + rfpath)) + continue; + RT_TRACE(COMP_DBG, + "Jacken -> pPreviousstats->RxMIMOSignalStrength[rfpath] = %d\n", + prev_st->RxMIMOSignalStrength[rfpath]); + if (priv->stats.rx_rssi_percentage[rfpath] == 0) { + priv->stats.rx_rssi_percentage[rfpath] = + prev_st->RxMIMOSignalStrength[rfpath]; + } + if (prev_st->RxMIMOSignalStrength[rfpath] > + priv->stats.rx_rssi_percentage[rfpath]) { + priv->stats.rx_rssi_percentage[rfpath] = + ((priv->stats.rx_rssi_percentage[rfpath] + * (RX_SMOOTH - 1)) + + (prev_st->RxMIMOSignalStrength + [rfpath])) / (RX_SMOOTH); + priv->stats.rx_rssi_percentage[rfpath] = + priv->stats.rx_rssi_percentage[rfpath] + + 1; + } else { + priv->stats.rx_rssi_percentage[rfpath] = + ((priv->stats.rx_rssi_percentage[rfpath] * + (RX_SMOOTH-1)) + + (prev_st->RxMIMOSignalStrength[rfpath])) / + (RX_SMOOTH); + } + RT_TRACE(COMP_DBG, + "Jacken -> priv->RxStats.RxRSSIPercentage[rfPath] = %d\n", + priv->stats.rx_rssi_percentage[rfpath]); + } + } + + + if (prev_st->bPacketBeacon) { + if (slide_beacon_adc_pwdb_statistics++ >= + PHY_Beacon_RSSI_SLID_WIN_MAX) { + slide_beacon_adc_pwdb_statistics = + PHY_Beacon_RSSI_SLID_WIN_MAX; + last_beacon_adc_pwdb = priv->stats.Slide_Beacon_pwdb + [slide_beacon_adc_pwdb_index]; + priv->stats.Slide_Beacon_Total -= last_beacon_adc_pwdb; + } + priv->stats.Slide_Beacon_Total += prev_st->RxPWDBAll; + priv->stats.Slide_Beacon_pwdb[slide_beacon_adc_pwdb_index] = + prev_st->RxPWDBAll; + slide_beacon_adc_pwdb_index++; + if (slide_beacon_adc_pwdb_index >= PHY_Beacon_RSSI_SLID_WIN_MAX) + slide_beacon_adc_pwdb_index = 0; + prev_st->RxPWDBAll = priv->stats.Slide_Beacon_Total / + slide_beacon_adc_pwdb_statistics; + if (prev_st->RxPWDBAll >= 3) + prev_st->RxPWDBAll -= 3; + } + + RT_TRACE(COMP_RXDESC, "Smooth %s PWDB = %d\n", + prev_st->bIsCCK ? "CCK" : "OFDM", + prev_st->RxPWDBAll); + + if (prev_st->bPacketToSelf || prev_st->bPacketBeacon || + prev_st->bToSelfBA) { + if (priv->undecorated_smoothed_pwdb < 0) + priv->undecorated_smoothed_pwdb = prev_st->RxPWDBAll; + if (prev_st->RxPWDBAll > (u32)priv->undecorated_smoothed_pwdb) { + priv->undecorated_smoothed_pwdb = + (((priv->undecorated_smoothed_pwdb) * + (RX_SMOOTH-1)) + + (prev_st->RxPWDBAll)) / (RX_SMOOTH); + priv->undecorated_smoothed_pwdb = + priv->undecorated_smoothed_pwdb + 1; + } else { + priv->undecorated_smoothed_pwdb = + (((priv->undecorated_smoothed_pwdb) * + (RX_SMOOTH-1)) + + (prev_st->RxPWDBAll)) / (RX_SMOOTH); + } + rtl819x_update_rxsignalstatistics8190pci(priv, prev_st); + } + + if (prev_st->SignalQuality != 0) { + if (prev_st->bPacketToSelf || prev_st->bPacketBeacon || + prev_st->bToSelfBA) { + if (slide_evm_statistics++ >= PHY_RSSI_SLID_WIN_MAX) { + slide_evm_statistics = PHY_RSSI_SLID_WIN_MAX; + last_evm = + priv->stats.slide_evm[slide_evm_index]; + priv->stats.slide_evm_total -= last_evm; + } + + priv->stats.slide_evm_total += prev_st->SignalQuality; + + priv->stats.slide_evm[slide_evm_index++] = + prev_st->SignalQuality; + if (slide_evm_index >= PHY_RSSI_SLID_WIN_MAX) + slide_evm_index = 0; + + tmp_val = priv->stats.slide_evm_total / + slide_evm_statistics; + priv->stats.signal_quality = tmp_val; + priv->stats.last_signal_strength_inpercent = tmp_val; + } + + if (prev_st->bPacketToSelf || + prev_st->bPacketBeacon || + prev_st->bToSelfBA) { + for (ij = 0; ij < 2; ij++) { + if (prev_st->RxMIMOSignalQuality[ij] != -1) { + if (priv->stats.rx_evm_percentage[ij] == 0) + priv->stats.rx_evm_percentage[ij] = + prev_st->RxMIMOSignalQuality[ij]; + priv->stats.rx_evm_percentage[ij] = + ((priv->stats.rx_evm_percentage[ij] * + (RX_SMOOTH - 1)) + + (prev_st->RxMIMOSignalQuality[ij])) / + (RX_SMOOTH); + } + } + } + } +} + +static void rtl8192_TranslateRxSignalStuff(struct net_device *dev, + struct sk_buff *skb, + struct rtllib_rx_stats *pstats, + struct rx_desc *pdesc, + struct rx_fwinfo *pdrvinfo) +{ + struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); + bool bpacket_match_bssid, bpacket_toself; + bool bPacketBeacon = false; + struct rtllib_hdr_3addr *hdr; + bool bToSelfBA = false; + static struct rtllib_rx_stats previous_stats; + u16 fc, type; + u8 *tmp_buf; + u8 *praddr; + + tmp_buf = skb->data + pstats->RxDrvInfoSize + pstats->RxBufShift; + + hdr = (struct rtllib_hdr_3addr *)tmp_buf; + fc = le16_to_cpu(hdr->frame_ctl); + type = WLAN_FC_GET_TYPE(fc); + praddr = hdr->addr1; + + bpacket_match_bssid = + ((RTLLIB_FTYPE_CTL != type) && + ether_addr_equal(priv->rtllib->current_network.bssid, + (fc & RTLLIB_FCTL_TODS) ? hdr->addr1 : + (fc & RTLLIB_FCTL_FROMDS) ? hdr->addr2 : + hdr->addr3) && + (!pstats->bHwError) && (!pstats->bCRC) && (!pstats->bICV)); + bpacket_toself = bpacket_match_bssid && /* check this */ + ether_addr_equal(praddr, priv->rtllib->dev->dev_addr); + if (WLAN_FC_GET_FRAMETYPE(fc) == RTLLIB_STYPE_BEACON) + bPacketBeacon = true; + if (bpacket_match_bssid) + priv->stats.numpacket_matchbssid++; + if (bpacket_toself) + priv->stats.numpacket_toself++; + rtl8192_process_phyinfo(priv, tmp_buf, &previous_stats, pstats); + rtl8192_query_rxphystatus(priv, pstats, pdesc, pdrvinfo, + &previous_stats, bpacket_match_bssid, + bpacket_toself, bPacketBeacon, bToSelfBA); + rtl8192_record_rxdesc_forlateruse(pstats, &previous_stats); +} + +static void rtl8192_UpdateReceivedRateHistogramStatistics( + struct net_device *dev, + struct rtllib_rx_stats *pstats) +{ + struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); + u32 rcvType = 1; + u32 rateIndex; + u32 preamble_guardinterval; + + if (pstats->bCRC) + rcvType = 2; + else if (pstats->bICV) + rcvType = 3; + + if (pstats->bShortPreamble) + preamble_guardinterval = 1; + else + preamble_guardinterval = 0; + + switch (pstats->rate) { + case MGN_1M: + rateIndex = 0; + break; + case MGN_2M: + rateIndex = 1; + break; + case MGN_5_5M: + rateIndex = 2; + break; + case MGN_11M: + rateIndex = 3; + break; + case MGN_6M: + rateIndex = 4; + break; + case MGN_9M: + rateIndex = 5; + break; + case MGN_12M: + rateIndex = 6; + break; + case MGN_18M: + rateIndex = 7; + break; + case MGN_24M: + rateIndex = 8; + break; + case MGN_36M: + rateIndex = 9; + break; + case MGN_48M: + rateIndex = 10; + break; + case MGN_54M: + rateIndex = 11; + break; + case MGN_MCS0: + rateIndex = 12; + break; + case MGN_MCS1: + rateIndex = 13; + break; + case MGN_MCS2: + rateIndex = 14; + break; + case MGN_MCS3: + rateIndex = 15; + break; + case MGN_MCS4: + rateIndex = 16; + break; + case MGN_MCS5: + rateIndex = 17; + break; + case MGN_MCS6: + rateIndex = 18; + break; + case MGN_MCS7: + rateIndex = 19; + break; + case MGN_MCS8: + rateIndex = 20; + break; + case MGN_MCS9: + rateIndex = 21; + break; + case MGN_MCS10: + rateIndex = 22; + break; + case MGN_MCS11: + rateIndex = 23; + break; + case MGN_MCS12: + rateIndex = 24; + break; + case MGN_MCS13: + rateIndex = 25; + break; + case MGN_MCS14: + rateIndex = 26; + break; + case MGN_MCS15: + rateIndex = 27; + break; + default: + rateIndex = 28; + break; + } + priv->stats.received_preamble_GI[preamble_guardinterval][rateIndex]++; + priv->stats.received_rate_histogram[0][rateIndex]++; + priv->stats.received_rate_histogram[rcvType][rateIndex]++; +} + +bool rtl8192_rx_query_status_desc(struct net_device *dev, + struct rtllib_rx_stats *stats, + struct rx_desc *pdesc, + struct sk_buff *skb) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct rx_fwinfo *pDrvInfo = NULL; + + stats->bICV = pdesc->ICV; + stats->bCRC = pdesc->CRC32; + stats->bHwError = pdesc->CRC32 | pdesc->ICV; + + stats->Length = pdesc->Length; + if (stats->Length < 24) + stats->bHwError |= 1; + + if (stats->bHwError) { + stats->bShift = false; + + if (pdesc->CRC32) { + if (pdesc->Length < 500) + priv->stats.rxcrcerrmin++; + else if (pdesc->Length > 1000) + priv->stats.rxcrcerrmax++; + else + priv->stats.rxcrcerrmid++; + } + return false; + } + + stats->RxDrvInfoSize = pdesc->RxDrvInfoSize; + stats->RxBufShift = ((pdesc->Shift)&0x03); + stats->Decrypted = !pdesc->SWDec; + + pDrvInfo = (struct rx_fwinfo *)(skb->data + stats->RxBufShift); + + stats->rate = HwRateToMRate90((bool)pDrvInfo->RxHT, + (u8)pDrvInfo->RxRate); + stats->bShortPreamble = pDrvInfo->SPLCP; + + rtl8192_UpdateReceivedRateHistogramStatistics(dev, stats); + + stats->bIsAMPDU = (pDrvInfo->PartAggr == 1); + stats->bFirstMPDU = (pDrvInfo->PartAggr == 1) && + (pDrvInfo->FirstAGGR == 1); + + stats->TimeStampLow = pDrvInfo->TSFL; + stats->TimeStampHigh = read_nic_dword(dev, TSFR+4); + + rtl819x_UpdateRxPktTimeStamp(dev, stats); + + if ((stats->RxBufShift + stats->RxDrvInfoSize) > 0) + stats->bShift = 1; + + stats->RxIs40MHzPacket = pDrvInfo->BW; + + rtl8192_TranslateRxSignalStuff(dev, skb, stats, pdesc, + pDrvInfo); + + if (pDrvInfo->FirstAGGR == 1 || pDrvInfo->PartAggr == 1) + RT_TRACE(COMP_RXDESC, + "pDrvInfo->FirstAGGR = %d, pDrvInfo->PartAggr = %d\n", + pDrvInfo->FirstAGGR, pDrvInfo->PartAggr); + skb_trim(skb, skb->len - 4/*sCrcLng*/); + + + stats->packetlength = stats->Length-4; + stats->fraglength = stats->packetlength; + stats->fragoffset = 0; + stats->ntotalfrag = 1; + return true; +} + +void rtl8192_halt_adapter(struct net_device *dev, bool reset) +{ + struct r8192_priv *priv = rtllib_priv(dev); + int i; + u8 OpMode; + u8 u1bTmp; + u32 ulRegRead; + + OpMode = RT_OP_MODE_NO_LINK; + priv->rtllib->SetHwRegHandler(dev, HW_VAR_MEDIA_STATUS, &OpMode); + + if (!priv->rtllib->bSupportRemoteWakeUp) { + u1bTmp = 0x0; + write_nic_byte(dev, CMDR, u1bTmp); + } + + mdelay(20); + + if (!reset) { + mdelay(150); + + priv->bHwRfOffAction = 2; + + if (!priv->rtllib->bSupportRemoteWakeUp) { + PHY_SetRtl8192eRfOff(dev); + ulRegRead = read_nic_dword(dev, CPU_GEN); + ulRegRead |= CPU_GEN_SYSTEM_RESET; + write_nic_dword(dev, CPU_GEN, ulRegRead); + } else { + write_nic_dword(dev, WFCRC0, 0xffffffff); + write_nic_dword(dev, WFCRC1, 0xffffffff); + write_nic_dword(dev, WFCRC2, 0xffffffff); + + + write_nic_byte(dev, PMR, 0x5); + write_nic_byte(dev, MacBlkCtrl, 0xa); + } + } + + for (i = 0; i < MAX_QUEUE_SIZE; i++) + skb_queue_purge(&priv->rtllib->skb_waitQ[i]); + for (i = 0; i < MAX_QUEUE_SIZE; i++) + skb_queue_purge(&priv->rtllib->skb_aggQ[i]); + + skb_queue_purge(&priv->skb_queue); +} + +void rtl8192_update_ratr_table(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct rtllib_device *ieee = priv->rtllib; + u8 *pMcsRate = ieee->dot11HTOperationalRateSet; + u32 ratr_value = 0; + u16 rate_config = 0; + u8 rate_index = 0; + + rtl8192_config_rate(dev, &rate_config); + ratr_value = rate_config | *pMcsRate << 12; + switch (ieee->mode) { + case IEEE_A: + ratr_value &= 0x00000FF0; + break; + case IEEE_B: + ratr_value &= 0x0000000F; + break; + case IEEE_G: + case IEEE_G|IEEE_B: + ratr_value &= 0x00000FF7; + break; + case IEEE_N_24G: + case IEEE_N_5G: + if (ieee->pHTInfo->PeerMimoPs == 0) { + ratr_value &= 0x0007F007; + } else { + if (priv->rf_type == RF_1T2R) + ratr_value &= 0x000FF007; + else + ratr_value &= 0x0F81F007; + } + break; + default: + break; + } + ratr_value &= 0x0FFFFFFF; + if (ieee->pHTInfo->bCurTxBW40MHz && + ieee->pHTInfo->bCurShortGI40MHz) + ratr_value |= 0x80000000; + else if (!ieee->pHTInfo->bCurTxBW40MHz && + ieee->pHTInfo->bCurShortGI20MHz) + ratr_value |= 0x80000000; + write_nic_dword(dev, RATR0+rate_index*4, ratr_value); + write_nic_byte(dev, UFWP, 1); +} + +void +rtl8192_InitializeVariables(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + strcpy(priv->nick, "rtl8192E"); + + priv->rtllib->softmac_features = IEEE_SOFTMAC_SCAN | + IEEE_SOFTMAC_ASSOCIATE | IEEE_SOFTMAC_PROBERQ | + IEEE_SOFTMAC_PROBERS | IEEE_SOFTMAC_TX_QUEUE; + + priv->rtllib->tx_headroom = sizeof(struct tx_fwinfo_8190pci); + + priv->ShortRetryLimit = 0x30; + priv->LongRetryLimit = 0x30; + + priv->EarlyRxThreshold = 7; + priv->pwrGroupCnt = 0; + + priv->bIgnoreSilentReset = false; + priv->enable_gpio0 = 0; + + priv->TransmitConfig = 0; + + priv->ReceiveConfig = RCR_ADD3 | + RCR_AMF | RCR_ADF | + RCR_AICV | + RCR_AB | RCR_AM | RCR_APM | + RCR_AAP | ((u32)7<irq_mask[0] = (u32)(IMR_ROK | IMR_VODOK | IMR_VIDOK | + IMR_BEDOK | IMR_BKDOK | IMR_HCCADOK | + IMR_MGNTDOK | IMR_COMDOK | IMR_HIGHDOK | + IMR_BDOK | IMR_RXCMDOK | IMR_TIMEOUT0 | + IMR_RDU | IMR_RXFOVW | IMR_TXFOVW | + IMR_BcnInt | IMR_TBDOK | IMR_TBDER); + + + priv->MidHighPwrTHR_L1 = 0x3B; + priv->MidHighPwrTHR_L2 = 0x40; + priv->PwrDomainProtect = false; + + priv->bfirst_after_down = false; +} + +void rtl8192_EnableInterrupt(struct net_device *dev) +{ + struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); + + priv->irq_enabled = 1; + + write_nic_dword(dev, INTA_MASK, priv->irq_mask[0]); + +} + +void rtl8192_DisableInterrupt(struct net_device *dev) +{ + struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); + + write_nic_dword(dev, INTA_MASK, 0); + + priv->irq_enabled = 0; +} + +void rtl8192_ClearInterrupt(struct net_device *dev) +{ + u32 tmp = 0; + + tmp = read_nic_dword(dev, ISR); + write_nic_dword(dev, ISR, tmp); +} + + +void rtl8192_enable_rx(struct net_device *dev) +{ + struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); + + write_nic_dword(dev, RDQDA, priv->rx_ring_dma[RX_MPDU_QUEUE]); +} + +static const u32 TX_DESC_BASE[] = { + BKQDA, BEQDA, VIQDA, VOQDA, HCCAQDA, CQDA, MQDA, HQDA, BQDA +}; + +void rtl8192_enable_tx(struct net_device *dev) +{ + struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); + u32 i; + + for (i = 0; i < MAX_TX_QUEUE_COUNT; i++) + write_nic_dword(dev, TX_DESC_BASE[i], priv->tx_ring[i].dma); +} + + +void rtl8192_interrupt_recognized(struct net_device *dev, u32 *p_inta, + u32 *p_intb) +{ + *p_inta = read_nic_dword(dev, ISR); + write_nic_dword(dev, ISR, *p_inta); +} + +bool rtl8192_HalRxCheckStuck(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + u16 RegRxCounter = read_nic_word(dev, 0x130); + bool bStuck = false; + static u8 rx_chk_cnt; + u32 SlotIndex = 0, TotalRxStuckCount = 0; + u8 i; + u8 SilentResetRxSoltNum = 4; + + RT_TRACE(COMP_RESET, "%s(): RegRxCounter is %d, RxCounter is %d\n", + __func__, RegRxCounter, priv->RxCounter); + + rx_chk_cnt++; + if (priv->undecorated_smoothed_pwdb >= (RateAdaptiveTH_High+5)) { + rx_chk_cnt = 0; + } else if ((priv->undecorated_smoothed_pwdb < (RateAdaptiveTH_High + 5)) + && (((priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) && + (priv->undecorated_smoothed_pwdb >= RateAdaptiveTH_Low_40M)) + || ((priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20) && + (priv->undecorated_smoothed_pwdb >= RateAdaptiveTH_Low_20M)))) { + if (rx_chk_cnt < 2) + return bStuck; + rx_chk_cnt = 0; + } else if ((((priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) && + (priv->undecorated_smoothed_pwdb < RateAdaptiveTH_Low_40M)) || + ((priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20) && + (priv->undecorated_smoothed_pwdb < RateAdaptiveTH_Low_20M))) && + priv->undecorated_smoothed_pwdb >= VeryLowRSSI) { + if (rx_chk_cnt < 4) + return bStuck; + rx_chk_cnt = 0; + } else { + if (rx_chk_cnt < 8) + return bStuck; + rx_chk_cnt = 0; + } + + + SlotIndex = (priv->SilentResetRxSlotIndex++)%SilentResetRxSoltNum; + + if (priv->RxCounter == RegRxCounter) { + priv->SilentResetRxStuckEvent[SlotIndex] = 1; + + for (i = 0; i < SilentResetRxSoltNum; i++) + TotalRxStuckCount += priv->SilentResetRxStuckEvent[i]; + + if (TotalRxStuckCount == SilentResetRxSoltNum) { + bStuck = true; + for (i = 0; i < SilentResetRxSoltNum; i++) + TotalRxStuckCount += + priv->SilentResetRxStuckEvent[i]; + } + + + } else { + priv->SilentResetRxStuckEvent[SlotIndex] = 0; + } + + priv->RxCounter = RegRxCounter; + + return bStuck; +} + +bool rtl8192_HalTxCheckStuck(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + bool bStuck = false; + u16 RegTxCounter = read_nic_word(dev, 0x128); + + RT_TRACE(COMP_RESET, "%s():RegTxCounter is %d,TxCounter is %d\n", + __func__, RegTxCounter, priv->TxCounter); + + if (priv->TxCounter == RegTxCounter) + bStuck = true; + + priv->TxCounter = RegTxCounter; + + return bStuck; +} + +bool rtl8192_GetNmodeSupportBySecCfg(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct rtllib_device *ieee = priv->rtllib; + + if (ieee->rtllib_ap_sec_type && + (ieee->rtllib_ap_sec_type(priv->rtllib)&(SEC_ALG_WEP | + SEC_ALG_TKIP))) { + return false; + } else { + return true; + } +} + +bool rtl8192_GetHalfNmodeSupportByAPs(struct net_device *dev) +{ + bool Reval; + struct r8192_priv *priv = rtllib_priv(dev); + struct rtllib_device *ieee = priv->rtllib; + + if (ieee->bHalfWirelessN24GMode == true) + Reval = true; + else + Reval = false; + + return Reval; +} + +u8 rtl8192_QueryIsShort(u8 TxHT, u8 TxRate, struct cb_desc *tcb_desc) +{ + u8 tmp_Short; + + tmp_Short = (TxHT == 1) ? ((tcb_desc->bUseShortGI) ? 1 : 0) : + ((tcb_desc->bUseShortPreamble) ? 1 : 0); + if (TxHT == 1 && TxRate != DESC90_RATEMCS15) + tmp_Short = 0; + + return tmp_Short; +} + +void ActUpdateChannelAccessSetting(struct net_device *dev, + enum wireless_mode WirelessMode, + struct channel_access_setting *ChnlAccessSetting) +{ +} diff --git a/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h b/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h new file mode 100644 index 000000000..dbe0e1c87 --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h @@ -0,0 +1,62 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * Based on the r8180 driver, which is: + * Copyright 2004-2005 Andrea Merello , et al. + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ +#ifndef _RTL8192E_H +#define _RTL8192E_H + +#include "r8190P_def.h" + +u8 rtl8192_QueryIsShort(u8 TxHT, u8 TxRate, struct cb_desc *tcb_desc); +bool rtl8192_GetHalfNmodeSupportByAPs(struct net_device *dev); +bool rtl8192_GetNmodeSupportBySecCfg(struct net_device *dev); +bool rtl8192_HalTxCheckStuck(struct net_device *dev); +bool rtl8192_HalRxCheckStuck(struct net_device *dev); +void rtl8192_interrupt_recognized(struct net_device *dev, u32 *p_inta, + u32 *p_intb); +void rtl8192_enable_rx(struct net_device *dev); +void rtl8192_enable_tx(struct net_device *dev); +void rtl8192_EnableInterrupt(struct net_device *dev); +void rtl8192_DisableInterrupt(struct net_device *dev); +void rtl8192_ClearInterrupt(struct net_device *dev); +void rtl8192_InitializeVariables(struct net_device *dev); +void rtl8192e_start_beacon(struct net_device *dev); +void rtl8192e_SetHwReg(struct net_device *dev, u8 variable, u8 *val); +void rtl8192_get_eeprom_size(struct net_device *dev); +bool rtl8192_adapter_start(struct net_device *dev); +void rtl8192_link_change(struct net_device *dev); +void rtl8192_AllowAllDestAddr(struct net_device *dev, bool bAllowAllDA, + bool WriteIntoReg); +void rtl8192_tx_fill_desc(struct net_device *dev, struct tx_desc *pdesc, + struct cb_desc *cb_desc, + struct sk_buff *skb); +void rtl8192_tx_fill_cmd_desc(struct net_device *dev, + struct tx_desc_cmd *entry, + struct cb_desc *cb_desc, struct sk_buff *skb); +bool rtl8192_rx_query_status_desc(struct net_device *dev, + struct rtllib_rx_stats *stats, + struct rx_desc *pdesc, + struct sk_buff *skb); +void rtl8192_halt_adapter(struct net_device *dev, bool reset); +void rtl8192_update_ratr_table(struct net_device *dev); +#endif diff --git a/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c b/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c new file mode 100644 index 000000000..c465f8749 --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c @@ -0,0 +1,319 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ + +#include "rtl_core.h" +#include "r8192E_hw.h" +#include "r8192E_hwimg.h" +#include "r8192E_firmware.h" +#include + +void firmware_init_param(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct rt_firmware *pfirmware = priv->pFirmware; + + pfirmware->cmdpacket_frag_thresold = GET_COMMAND_PACKET_FRAG_THRESHOLD( + MAX_TRANSMIT_BUFFER_SIZE); +} + +static bool fw_download_code(struct net_device *dev, u8 *code_virtual_address, + u32 buffer_len) +{ + struct r8192_priv *priv = rtllib_priv(dev); + u16 frag_threshold; + u16 frag_length, frag_offset = 0; + int i; + + struct rt_firmware *pfirmware = priv->pFirmware; + struct sk_buff *skb; + unsigned char *seg_ptr; + struct cb_desc *tcb_desc; + u8 bLastIniPkt; + + firmware_init_param(dev); + frag_threshold = pfirmware->cmdpacket_frag_thresold; + do { + if ((buffer_len - frag_offset) > frag_threshold) { + frag_length = frag_threshold; + bLastIniPkt = 0; + + } else { + frag_length = buffer_len - frag_offset; + bLastIniPkt = 1; + + } + + skb = dev_alloc_skb(frag_length + 4); + memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev)); + tcb_desc = (struct cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); + tcb_desc->queue_index = TXCMD_QUEUE; + tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_INIT; + tcb_desc->bLastIniPkt = bLastIniPkt; + + seg_ptr = skb->data; + for (i = 0; i < frag_length; i += 4) { + *seg_ptr++ = ((i+0) < frag_length) ? + code_virtual_address[i+3] : 0; + *seg_ptr++ = ((i+1) < frag_length) ? + code_virtual_address[i+2] : 0; + *seg_ptr++ = ((i+2) < frag_length) ? + code_virtual_address[i+1] : 0; + *seg_ptr++ = ((i+3) < frag_length) ? + code_virtual_address[i+0] : 0; + } + tcb_desc->txbuf_size = (u16)i; + skb_put(skb, i); + + if (!priv->rtllib->check_nic_enough_desc(dev, tcb_desc->queue_index) || + (!skb_queue_empty(&priv->rtllib->skb_waitQ[tcb_desc->queue_index])) || + (priv->rtllib->queue_stop)) { + RT_TRACE(COMP_FIRMWARE, + "===================> tx full!\n"); + skb_queue_tail(&priv->rtllib->skb_waitQ + [tcb_desc->queue_index], skb); + } else { + priv->rtllib->softmac_hard_start_xmit(skb, dev); + } + + code_virtual_address += frag_length; + frag_offset += frag_length; + + } while (frag_offset < buffer_len); + + write_nic_byte(dev, TPPoll, TPPoll_CQ); + + return true; +} + +static bool CPUcheck_maincodeok_turnonCPU(struct net_device *dev) +{ + bool rt_status = true; + u32 CPU_status = 0; + unsigned long timeout; + + timeout = jiffies + msecs_to_jiffies(200); + while (time_before(jiffies, timeout)) { + CPU_status = read_nic_dword(dev, CPU_GEN); + if (CPU_status & CPU_GEN_PUT_CODE_OK) + break; + mdelay(2); + } + + if (!(CPU_status&CPU_GEN_PUT_CODE_OK)) { + RT_TRACE(COMP_ERR, "Download Firmware: Put code fail!\n"); + goto CPUCheckMainCodeOKAndTurnOnCPU_Fail; + } else { + RT_TRACE(COMP_FIRMWARE, "Download Firmware: Put code ok!\n"); + } + + CPU_status = read_nic_dword(dev, CPU_GEN); + write_nic_byte(dev, CPU_GEN, + (u8)((CPU_status|CPU_GEN_PWR_STB_CPU)&0xff)); + mdelay(1); + + timeout = jiffies + msecs_to_jiffies(200); + while (time_before(jiffies, timeout)) { + CPU_status = read_nic_dword(dev, CPU_GEN); + if (CPU_status&CPU_GEN_BOOT_RDY) + break; + mdelay(2); + } + + if (!(CPU_status&CPU_GEN_BOOT_RDY)) + goto CPUCheckMainCodeOKAndTurnOnCPU_Fail; + else + RT_TRACE(COMP_FIRMWARE, "Download Firmware: Boot ready!\n"); + + return rt_status; + +CPUCheckMainCodeOKAndTurnOnCPU_Fail: + RT_TRACE(COMP_ERR, "ERR in %s()\n", __func__); + rt_status = false; + return rt_status; +} + +static bool CPUcheck_firmware_ready(struct net_device *dev) +{ + + bool rt_status = true; + u32 CPU_status = 0; + unsigned long timeout; + + timeout = jiffies + msecs_to_jiffies(20); + while (time_before(jiffies, timeout)) { + CPU_status = read_nic_dword(dev, CPU_GEN); + if (CPU_status&CPU_GEN_FIRM_RDY) + break; + mdelay(2); + } + + if (!(CPU_status&CPU_GEN_FIRM_RDY)) + goto CPUCheckFirmwareReady_Fail; + else + RT_TRACE(COMP_FIRMWARE, "Download Firmware: Firmware ready!\n"); + + return rt_status; + +CPUCheckFirmwareReady_Fail: + RT_TRACE(COMP_ERR, "ERR in %s()\n", __func__); + rt_status = false; + return rt_status; + +} + +static bool firmware_check_ready(struct net_device *dev, + u8 load_fw_status) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct rt_firmware *pfirmware = priv->pFirmware; + bool rt_status = true; + + switch (load_fw_status) { + case FW_INIT_STEP0_BOOT: + pfirmware->firmware_status = FW_STATUS_1_MOVE_BOOT_CODE; + break; + + case FW_INIT_STEP1_MAIN: + pfirmware->firmware_status = FW_STATUS_2_MOVE_MAIN_CODE; + + rt_status = CPUcheck_maincodeok_turnonCPU(dev); + if (rt_status) + pfirmware->firmware_status = FW_STATUS_3_TURNON_CPU; + else + RT_TRACE(COMP_FIRMWARE, + "CPUcheck_maincodeok_turnonCPU fail!\n"); + + break; + + case FW_INIT_STEP2_DATA: + pfirmware->firmware_status = FW_STATUS_4_MOVE_DATA_CODE; + mdelay(1); + + rt_status = CPUcheck_firmware_ready(dev); + if (rt_status) + pfirmware->firmware_status = FW_STATUS_5_READY; + else + RT_TRACE(COMP_FIRMWARE, + "CPUcheck_firmware_ready fail(%d)!\n", + rt_status); + + break; + default: + rt_status = false; + RT_TRACE(COMP_FIRMWARE, "Unknown firmware status"); + break; + } + + return rt_status; +} + +bool init_firmware(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + bool rt_status = true; + + u32 file_length = 0; + u8 *mapped_file = NULL; + u8 init_step = 0; + enum opt_rst_type rst_opt = OPT_SYSTEM_RESET; + enum firmware_init_step starting_state = FW_INIT_STEP0_BOOT; + + struct rt_firmware *pfirmware = priv->pFirmware; + + RT_TRACE(COMP_FIRMWARE, " PlatformInitFirmware()==>\n"); + + if (pfirmware->firmware_status == FW_STATUS_0_INIT) { + rst_opt = OPT_SYSTEM_RESET; + starting_state = FW_INIT_STEP0_BOOT; + + } else if (pfirmware->firmware_status == FW_STATUS_5_READY) { + rst_opt = OPT_FIRMWARE_RESET; + starting_state = FW_INIT_STEP2_DATA; + } else { + RT_TRACE(COMP_FIRMWARE, + "PlatformInitFirmware: undefined firmware state\n"); + } + + for (init_step = starting_state; init_step <= FW_INIT_STEP2_DATA; + init_step++) { + if (rst_opt == OPT_SYSTEM_RESET) { + if (pfirmware->firmware_buf_size[init_step] == 0) { + const char *fw_name[3] = { + RTL8192E_BOOT_IMG_FW, + RTL8192E_MAIN_IMG_FW, + RTL8192E_DATA_IMG_FW + }; + const struct firmware *fw_entry; + int rc; + + rc = request_firmware(&fw_entry, + fw_name[init_step], + &priv->pdev->dev); + if (rc < 0) { + RT_TRACE(COMP_FIRMWARE, + "request firmware fail!\n"); + goto download_firmware_fail; + } + if (fw_entry->size > + sizeof(pfirmware->firmware_buf[init_step])) { + RT_TRACE(COMP_FIRMWARE, + "img file size exceed the container struct buffer fail!\n"); + goto download_firmware_fail; + } + + if (init_step != FW_INIT_STEP1_MAIN) { + memcpy(pfirmware->firmware_buf[init_step], + fw_entry->data, fw_entry->size); + pfirmware->firmware_buf_size[init_step] = + fw_entry->size; + + } else { + memset(pfirmware->firmware_buf[init_step], + 0, 128); + memcpy(&pfirmware->firmware_buf[init_step][128], + fw_entry->data, fw_entry->size); + pfirmware->firmware_buf_size[init_step] = + fw_entry->size + 128; + } + + if (rst_opt == OPT_SYSTEM_RESET) + release_firmware(fw_entry); + } + } + + mapped_file = pfirmware->firmware_buf[init_step]; + file_length = pfirmware->firmware_buf_size[init_step]; + + rt_status = fw_download_code(dev, mapped_file, file_length); + if (!rt_status) + goto download_firmware_fail; + + if (!firmware_check_ready(dev, init_step)) + goto download_firmware_fail; + } + + RT_TRACE(COMP_FIRMWARE, "Firmware Download Success\n"); + return rt_status; + +download_firmware_fail: + RT_TRACE(COMP_ERR, "ERR in %s()\n", __func__); + rt_status = false; + return rt_status; + +} diff --git a/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h b/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h new file mode 100644 index 000000000..94fa16b49 --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h @@ -0,0 +1,72 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ +#ifndef __INC_FIRMWARE_H +#define __INC_FIRMWARE_H + +#define RTL8190_CPU_START_OFFSET 0x80 + +#define GET_COMMAND_PACKET_FRAG_THRESHOLD(v) (4*(v/4) - 8) + +#define RTL8192E_BOOT_IMG_FW "RTL8192E/boot.img" +#define RTL8192E_MAIN_IMG_FW "RTL8192E/main.img" +#define RTL8192E_DATA_IMG_FW "RTL8192E/data.img" + +enum firmware_init_step { + FW_INIT_STEP0_BOOT = 0, + FW_INIT_STEP1_MAIN = 1, + FW_INIT_STEP2_DATA = 2, +}; + +enum opt_rst_type { + OPT_SYSTEM_RESET = 0, + OPT_FIRMWARE_RESET = 1, +}; + +enum desc_packet_type { + DESC_PACKET_TYPE_INIT = 0, + DESC_PACKET_TYPE_NORMAL = 1, +}; + +enum firmware_status { + FW_STATUS_0_INIT = 0, + FW_STATUS_1_MOVE_BOOT_CODE = 1, + FW_STATUS_2_MOVE_MAIN_CODE = 2, + FW_STATUS_3_TURNON_CPU = 3, + FW_STATUS_4_MOVE_DATA_CODE = 4, + FW_STATUS_5_READY = 5, +}; + +struct fw_seg_container { + u16 seg_size; + u8 *seg_ptr; +}; + +struct rt_firmware { + enum firmware_status firmware_status; + u16 cmdpacket_frag_thresold; +#define RTL8190_MAX_FIRMWARE_CODE_SIZE 64000 +#define MAX_FW_INIT_STEP 3 + u8 firmware_buf[MAX_FW_INIT_STEP][RTL8190_MAX_FIRMWARE_CODE_SIZE]; + u16 firmware_buf_size[MAX_FW_INIT_STEP]; +}; + +bool init_firmware(struct net_device *dev); +extern void firmware_init_param(struct net_device *dev); + +#endif diff --git a/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_hw.h b/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_hw.h new file mode 100644 index 000000000..43c3fb859 --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_hw.h @@ -0,0 +1,453 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ + + +#ifndef R8180_HW +#define R8180_HW + +enum baseband_config { + BaseBand_Config_PHY_REG = 0, + BaseBand_Config_AGC_TAB = 1, +}; + +#define RTL8187_REQT_READ 0xc0 +#define RTL8187_REQT_WRITE 0x40 +#define RTL8187_REQ_GET_REGS 0x05 +#define RTL8187_REQ_SET_REGS 0x05 + +#define MAX_TX_URB 5 +#define MAX_RX_URB 16 +#define RX_URB_SIZE 9100 + +#define BB_ANTATTEN_CHAN14 0x0c +#define BB_ANTENNA_B 0x40 + +#define BB_HOST_BANG (1<<30) +#define BB_HOST_BANG_EN (1<<2) +#define BB_HOST_BANG_CLK (1<<1) +#define BB_HOST_BANG_RW (1<<3) +#define BB_HOST_BANG_DATA 1 + +#define RTL8190_EEPROM_ID 0x8129 +#define EEPROM_VID 0x02 +#define EEPROM_DID 0x04 +#define EEPROM_NODE_ADDRESS_BYTE_0 0x0C + +#define EEPROM_TxPowerDiff 0x1F + + +#define EEPROM_PwDiff 0x21 +#define EEPROM_CrystalCap 0x22 + + + +#define EEPROM_TxPwIndex_CCK_V1 0x29 +#define EEPROM_TxPwIndex_OFDM_24G_V1 0x2C +#define EEPROM_TxPwIndex_Ver 0x27 + +#define EEPROM_Default_TxPowerDiff 0x0 +#define EEPROM_Default_ThermalMeter 0x77 +#define EEPROM_Default_AntTxPowerDiff 0x0 +#define EEPROM_Default_TxPwDiff_CrystalCap 0x5 +#define EEPROM_Default_PwDiff 0x4 +#define EEPROM_Default_CrystalCap 0x5 +#define EEPROM_Default_TxPower 0x1010 +#define EEPROM_ICVersion_ChannelPlan 0x7C +#define EEPROM_Customer_ID 0x7B +#define EEPROM_RFInd_PowerDiff 0x28 +#define EEPROM_ThermalMeter 0x29 +#define EEPROM_TxPwDiff_CrystalCap 0x2A +#define EEPROM_TxPwIndex_CCK 0x2C +#define EEPROM_TxPwIndex_OFDM_24G 0x3A +#define EEPROM_Default_TxPowerLevel 0x10 +#define EEPROM_IC_VER 0x7d +#define EEPROM_CRC 0x7e + +#define EEPROM_CID_DEFAULT 0x0 +#define EEPROM_CID_CAMEO 0x1 +#define EEPROM_CID_RUNTOP 0x2 +#define EEPROM_CID_Senao 0x3 +#define EEPROM_CID_TOSHIBA 0x4 +#define EEPROM_CID_NetCore 0x5 +#define EEPROM_CID_Nettronix 0x6 +#define EEPROM_CID_Pronet 0x7 +#define EEPROM_CID_DLINK 0x8 +#define EEPROM_CID_WHQL 0xFE +enum _RTL8192Pci_HW { + MAC0 = 0x000, + MAC1 = 0x001, + MAC2 = 0x002, + MAC3 = 0x003, + MAC4 = 0x004, + MAC5 = 0x005, + PCIF = 0x009, +#define MXDMA2_16bytes 0x000 +#define MXDMA2_32bytes 0x001 +#define MXDMA2_64bytes 0x010 +#define MXDMA2_128bytes 0x011 +#define MXDMA2_256bytes 0x100 +#define MXDMA2_512bytes 0x101 +#define MXDMA2_1024bytes 0x110 +#define MXDMA2_NoLimit 0x7 + +#define MULRW_SHIFT 3 +#define MXDMA2_RX_SHIFT 4 +#define MXDMA2_TX_SHIFT 0 + PMR = 0x00c, + EPROM_CMD = 0x00e, +#define EPROM_CMD_RESERVED_MASK BIT5 +#define EPROM_CMD_9356SEL BIT4 +#define EPROM_CMD_OPERATING_MODE_SHIFT 6 +#define EPROM_CMD_OPERATING_MODE_MASK ((1<<7)|(1<<6)) +#define EPROM_CMD_CONFIG 0x3 +#define EPROM_CMD_NORMAL 0 +#define EPROM_CMD_LOAD 1 +#define EPROM_CMD_PROGRAM 2 +#define EPROM_CS_SHIFT 3 +#define EPROM_CK_SHIFT 2 +#define EPROM_W_SHIFT 1 +#define EPROM_R_SHIFT 0 + + AFR = 0x010, +#define AFR_CardBEn (1<<0) +#define AFR_CLKRUN_SEL (1<<1) +#define AFR_FuncRegEn (1<<2) + + ANAPAR = 0x17, +#define BB_GLOBAL_RESET_BIT 0x1 + BB_GLOBAL_RESET = 0x020, + BSSIDR = 0x02E, + CMDR = 0x037, +#define CR_RST 0x10 +#define CR_RE 0x08 +#define CR_TE 0x04 +#define CR_MulRW 0x01 + SIFS = 0x03E, + TCR = 0x040, + RCR = 0x044, +#define RCR_FILTER_MASK (BIT0 | BIT1 | BIT2 | BIT3 | BIT5 | BIT12 | \ + BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23) +#define RCR_ONLYERLPKT BIT31 +#define RCR_ENCS2 BIT30 +#define RCR_ENCS1 BIT29 +#define RCR_ENMBID BIT27 +#define RCR_ACKTXBW (BIT24|BIT25) +#define RCR_CBSSID BIT23 +#define RCR_APWRMGT BIT22 +#define RCR_ADD3 BIT21 +#define RCR_AMF BIT20 +#define RCR_ACF BIT19 +#define RCR_ADF BIT18 +#define RCR_RXFTH BIT13 +#define RCR_AICV BIT12 +#define RCR_ACRC32 BIT5 +#define RCR_AB BIT3 +#define RCR_AM BIT2 +#define RCR_APM BIT1 +#define RCR_AAP BIT0 +#define RCR_MXDMA_OFFSET 8 +#define RCR_FIFO_OFFSET 13 + SLOT_TIME = 0x049, + ACK_TIMEOUT = 0x04c, + PIFS_TIME = 0x04d, + USTIME = 0x04e, + EDCAPARA_BE = 0x050, + EDCAPARA_BK = 0x054, + EDCAPARA_VO = 0x058, + EDCAPARA_VI = 0x05C, +#define AC_PARAM_TXOP_LIMIT_OFFSET 16 +#define AC_PARAM_ECW_MAX_OFFSET 12 +#define AC_PARAM_ECW_MIN_OFFSET 8 +#define AC_PARAM_AIFS_OFFSET 0 + RFPC = 0x05F, + CWRR = 0x060, + BCN_TCFG = 0x062, +#define BCN_TCFG_CW_SHIFT 8 +#define BCN_TCFG_IFS 0 + BCN_INTERVAL = 0x070, + ATIMWND = 0x072, + BCN_DRV_EARLY_INT = 0x074, +#define BCN_DRV_EARLY_INT_SWBCN_SHIFT 8 +#define BCN_DRV_EARLY_INT_TIME_SHIFT 0 + BCN_DMATIME = 0x076, + BCN_ERR_THRESH = 0x078, + RWCAM = 0x0A0, +#define CAM_CM_SecCAMPolling BIT31 +#define CAM_CM_SecCAMClr BIT30 +#define CAM_CM_SecCAMWE BIT16 +#define CAM_VALID BIT15 +#define CAM_NOTVALID 0x0000 +#define CAM_USEDK BIT5 + +#define CAM_NONE 0x0 +#define CAM_WEP40 0x01 +#define CAM_TKIP 0x02 +#define CAM_AES 0x04 +#define CAM_WEP104 0x05 + +#define TOTAL_CAM_ENTRY 32 + +#define CAM_CONFIG_USEDK true +#define CAM_CONFIG_NO_USEDK false +#define CAM_WRITE BIT16 +#define CAM_READ 0x00000000 +#define CAM_POLLINIG BIT31 +#define SCR_UseDK 0x01 + WCAMI = 0x0A4, + RCAMO = 0x0A8, + SECR = 0x0B0, +#define SCR_TxUseDK BIT0 +#define SCR_RxUseDK BIT1 +#define SCR_TxEncEnable BIT2 +#define SCR_RxDecEnable BIT3 +#define SCR_SKByA2 BIT4 +#define SCR_NoSKMC BIT5 + SWREGULATOR = 0x0BD, + INTA_MASK = 0x0f4, +#define IMR8190_DISABLED 0x0 +#define IMR_ATIMEND BIT28 +#define IMR_TBDOK BIT27 +#define IMR_TBDER BIT26 +#define IMR_TXFOVW BIT15 +#define IMR_TIMEOUT0 BIT14 +#define IMR_BcnInt BIT13 +#define IMR_RXFOVW BIT12 +#define IMR_RDU BIT11 +#define IMR_RXCMDOK BIT10 +#define IMR_BDOK BIT9 +#define IMR_HIGHDOK BIT8 +#define IMR_COMDOK BIT7 +#define IMR_MGNTDOK BIT6 +#define IMR_HCCADOK BIT5 +#define IMR_BKDOK BIT4 +#define IMR_BEDOK BIT3 +#define IMR_VIDOK BIT2 +#define IMR_VODOK BIT1 +#define IMR_ROK BIT0 + ISR = 0x0f8, + TPPoll = 0x0fd, +#define TPPoll_BKQ BIT0 +#define TPPoll_BEQ BIT1 +#define TPPoll_VIQ BIT2 +#define TPPoll_VOQ BIT3 +#define TPPoll_BQ BIT4 +#define TPPoll_CQ BIT5 +#define TPPoll_MQ BIT6 +#define TPPoll_HQ BIT7 +#define TPPoll_HCCAQ BIT8 +#define TPPoll_StopBK BIT9 +#define TPPoll_StopBE BIT10 +#define TPPoll_StopVI BIT11 +#define TPPoll_StopVO BIT12 +#define TPPoll_StopMgt BIT13 +#define TPPoll_StopHigh BIT14 +#define TPPoll_StopHCCA BIT15 +#define TPPoll_SHIFT 8 + + PSR = 0x0ff, +#define PSR_GEN 0x0 +#define PSR_CPU 0x1 + CPU_GEN = 0x100, + BB_RESET = 0x101, +#define CPU_CCK_LOOPBACK 0x00030000 +#define CPU_GEN_SYSTEM_RESET 0x00000001 +#define CPU_GEN_FIRMWARE_RESET 0x00000008 +#define CPU_GEN_BOOT_RDY 0x00000010 +#define CPU_GEN_FIRM_RDY 0x00000020 +#define CPU_GEN_PUT_CODE_OK 0x00000080 +#define CPU_GEN_BB_RST 0x00000100 +#define CPU_GEN_PWR_STB_CPU 0x00000004 +#define CPU_GEN_NO_LOOPBACK_MSK 0xFFF8FFFF +#define CPU_GEN_NO_LOOPBACK_SET 0x00080000 +#define CPU_GEN_GPIO_UART 0x00007000 + + LED1Cfg = 0x154, + LED0Cfg = 0x155, + + AcmAvg = 0x170, + AcmHwCtrl = 0x171, +#define AcmHw_HwEn BIT0 +#define AcmHw_BeqEn BIT1 +#define AcmHw_ViqEn BIT2 +#define AcmHw_VoqEn BIT3 +#define AcmHw_BeqStatus BIT4 +#define AcmHw_ViqStatus BIT5 +#define AcmHw_VoqStatus BIT6 + AcmFwCtrl = 0x172, +#define AcmFw_BeqStatus BIT0 +#define AcmFw_ViqStatus BIT1 +#define AcmFw_VoqStatus BIT2 + VOAdmTime = 0x174, + VIAdmTime = 0x178, + BEAdmTime = 0x17C, + RQPN1 = 0x180, + RQPN2 = 0x184, + RQPN3 = 0x188, + QPRR = 0x1E0, + QPNR = 0x1F0, + BQDA = 0x200, + HQDA = 0x204, + CQDA = 0x208, + MQDA = 0x20C, + HCCAQDA = 0x210, + VOQDA = 0x214, + VIQDA = 0x218, + BEQDA = 0x21C, + BKQDA = 0x220, + RCQDA = 0x224, + RDQDA = 0x228, + + MAR0 = 0x240, + MAR4 = 0x244, + + CCX_PERIOD = 0x250, + CLM_RESULT = 0x251, + NHM_PERIOD = 0x252, + + NHM_THRESHOLD0 = 0x253, + NHM_THRESHOLD1 = 0x254, + NHM_THRESHOLD2 = 0x255, + NHM_THRESHOLD3 = 0x256, + NHM_THRESHOLD4 = 0x257, + NHM_THRESHOLD5 = 0x258, + NHM_THRESHOLD6 = 0x259, + + MCTRL = 0x25A, + + NHM_RPI_COUNTER0 = 0x264, + NHM_RPI_COUNTER1 = 0x265, + NHM_RPI_COUNTER2 = 0x266, + NHM_RPI_COUNTER3 = 0x267, + NHM_RPI_COUNTER4 = 0x268, + NHM_RPI_COUNTER5 = 0x269, + NHM_RPI_COUNTER6 = 0x26A, + NHM_RPI_COUNTER7 = 0x26B, + WFCRC0 = 0x2f0, + WFCRC1 = 0x2f4, + WFCRC2 = 0x2f8, + + BW_OPMODE = 0x300, +#define BW_OPMODE_11J BIT0 +#define BW_OPMODE_5G BIT1 +#define BW_OPMODE_20MHZ BIT2 + IC_VERRSION = 0x301, + MSR = 0x303, +#define MSR_LINK_MASK ((1<<0)|(1<<1)) +#define MSR_LINK_MANAGED 2 +#define MSR_LINK_NONE 0 +#define MSR_LINK_SHIFT 0 +#define MSR_LINK_ADHOC 1 +#define MSR_LINK_MASTER 3 +#define MSR_LINK_ENEDCA (1<<4) + +#define MSR_NOLINK 0x00 +#define MSR_ADHOC 0x01 +#define MSR_INFRA 0x02 +#define MSR_AP 0x03 + + RETRY_LIMIT = 0x304, +#define RETRY_LIMIT_SHORT_SHIFT 8 +#define RETRY_LIMIT_LONG_SHIFT 0 + TSFR = 0x308, + RRSR = 0x310, +#define RRSR_RSC_OFFSET 21 +#define RRSR_SHORT_OFFSET 23 +#define RRSR_RSC_DUPLICATE 0x600000 +#define RRSR_RSC_UPSUBCHNL 0x400000 +#define RRSR_RSC_LOWSUBCHNL 0x200000 +#define RRSR_SHORT 0x800000 +#define RRSR_1M BIT0 +#define RRSR_2M BIT1 +#define RRSR_5_5M BIT2 +#define RRSR_11M BIT3 +#define RRSR_6M BIT4 +#define RRSR_9M BIT5 +#define RRSR_12M BIT6 +#define RRSR_18M BIT7 +#define RRSR_24M BIT8 +#define RRSR_36M BIT9 +#define RRSR_48M BIT10 +#define RRSR_54M BIT11 +#define RRSR_MCS0 BIT12 +#define RRSR_MCS1 BIT13 +#define RRSR_MCS2 BIT14 +#define RRSR_MCS3 BIT15 +#define RRSR_MCS4 BIT16 +#define RRSR_MCS5 BIT17 +#define RRSR_MCS6 BIT18 +#define RRSR_MCS7 BIT19 +#define BRSR_AckShortPmb BIT23 + UFWP = 0x318, + RATR0 = 0x320, +#define RATR_1M 0x00000001 +#define RATR_2M 0x00000002 +#define RATR_55M 0x00000004 +#define RATR_11M 0x00000008 +#define RATR_6M 0x00000010 +#define RATR_9M 0x00000020 +#define RATR_12M 0x00000040 +#define RATR_18M 0x00000080 +#define RATR_24M 0x00000100 +#define RATR_36M 0x00000200 +#define RATR_48M 0x00000400 +#define RATR_54M 0x00000800 +#define RATR_MCS0 0x00001000 +#define RATR_MCS1 0x00002000 +#define RATR_MCS2 0x00004000 +#define RATR_MCS3 0x00008000 +#define RATR_MCS4 0x00010000 +#define RATR_MCS5 0x00020000 +#define RATR_MCS6 0x00040000 +#define RATR_MCS7 0x00080000 +#define RATR_MCS8 0x00100000 +#define RATR_MCS9 0x00200000 +#define RATR_MCS10 0x00400000 +#define RATR_MCS11 0x00800000 +#define RATR_MCS12 0x01000000 +#define RATR_MCS13 0x02000000 +#define RATR_MCS14 0x04000000 +#define RATR_MCS15 0x08000000 +#define RATE_ALL_CCK (RATR_1M | RATR_2M | RATR_55M | RATR_11M) +#define RATE_ALL_OFDM_AG (RATR_6M | RATR_9M | RATR_12M | RATR_18M | \ + RATR_24M | RATR_36M | RATR_48M | RATR_54M) +#define RATE_ALL_OFDM_1SS (RATR_MCS0 | RATR_MCS1 | RATR_MCS2 | \ + RATR_MCS3 | RATR_MCS4 | RATR_MCS5 | \ + RATR_MCS6 | RATR_MCS7) +#define RATE_ALL_OFDM_2SS (RATR_MCS8 | RATR_MCS9 | RATR_MCS10 | \ + RATR_MCS11 | RATR_MCS12 | RATR_MCS13 | \ + RATR_MCS14|RATR_MCS15) + + + DRIVER_RSSI = 0x32c, + MCS_TXAGC = 0x340, + CCK_TXAGC = 0x348, + MacBlkCtrl = 0x403, + +} +; + +#define GPI 0x108 +#define GPO 0x109 +#define GPE 0x10a + +#define HWSET_MAX_SIZE_92S 128 + +#define ANAPAR_FOR_8192PciE 0x17 + +#endif diff --git a/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_hwimg.c b/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_hwimg.c new file mode 100644 index 000000000..6767b5965 --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_hwimg.c @@ -0,0 +1,565 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ +/*Created on 2008/11/18, 3: 7*/ + +#include "r8192E_hwimg.h" + +u32 Rtl8192PciEPHY_REGArray[PHY_REGArrayLengthPciE] = {0x0,}; + +u32 Rtl8192PciEPHY_REG_1T2RArray[PHY_REG_1T2RArrayLengthPciE] = { + 0x800, 0x00000000, + 0x804, 0x00000001, + 0x808, 0x0000fc00, + 0x80c, 0x0000001c, + 0x810, 0x801010aa, + 0x814, 0x008514d0, + 0x818, 0x00000040, + 0x81c, 0x00000000, + 0x820, 0x00000004, + 0x824, 0x00690000, + 0x828, 0x00000004, + 0x82c, 0x00e90000, + 0x830, 0x00000004, + 0x834, 0x00690000, + 0x838, 0x00000004, + 0x83c, 0x00e90000, + 0x840, 0x00000000, + 0x844, 0x00000000, + 0x848, 0x00000000, + 0x84c, 0x00000000, + 0x850, 0x00000000, + 0x854, 0x00000000, + 0x858, 0x65a965a9, + 0x85c, 0x65a965a9, + 0x860, 0x001f0010, + 0x864, 0x007f0010, + 0x868, 0x001f0010, + 0x86c, 0x007f0010, + 0x870, 0x0f100f70, + 0x874, 0x0f100f70, + 0x878, 0x00000000, + 0x87c, 0x00000000, + 0x880, 0x6870e36c, + 0x884, 0xe3573600, + 0x888, 0x4260c340, + 0x88c, 0x0000ff00, + 0x890, 0x00000000, + 0x894, 0xfffffffe, + 0x898, 0x4c42382f, + 0x89c, 0x00656056, + 0x8b0, 0x00000000, + 0x8e0, 0x00000000, + 0x8e4, 0x00000000, + 0x900, 0x00000000, + 0x904, 0x00000023, + 0x908, 0x00000000, + 0x90c, 0x31121311, + 0xa00, 0x00d0c7d8, + 0xa04, 0x811f0008, + 0xa08, 0x80cd8300, + 0xa0c, 0x2e62740f, + 0xa10, 0x95009b78, + 0xa14, 0x11145008, + 0xa18, 0x00881117, + 0xa1c, 0x89140fa0, + 0xa20, 0x1a1b0000, + 0xa24, 0x090e1317, + 0xa28, 0x00000204, + 0xa2c, 0x00000000, + 0xc00, 0x00000040, + 0xc04, 0x00005433, + 0xc08, 0x000000e4, + 0xc0c, 0x6c6c6c6c, + 0xc10, 0x08800000, + 0xc14, 0x40000100, + 0xc18, 0x08000000, + 0xc1c, 0x40000100, + 0xc20, 0x08000000, + 0xc24, 0x40000100, + 0xc28, 0x08000000, + 0xc2c, 0x40000100, + 0xc30, 0x6de9ac44, + 0xc34, 0x465c52cd, + 0xc38, 0x497f5994, + 0xc3c, 0x0a969764, + 0xc40, 0x1f7c403f, + 0xc44, 0x000100b7, + 0xc48, 0xec020000, + 0xc4c, 0x00000300, + 0xc50, 0x69543420, + 0xc54, 0x433c0094, + 0xc58, 0x69543420, + 0xc5c, 0x433c0094, + 0xc60, 0x69543420, + 0xc64, 0x433c0094, + 0xc68, 0x69543420, + 0xc6c, 0x433c0094, + 0xc70, 0x2c7f000d, + 0xc74, 0x0186175b, + 0xc78, 0x0000001f, + 0xc7c, 0x00b91612, + 0xc80, 0x40000100, + 0xc84, 0x20000000, + 0xc88, 0x40000100, + 0xc8c, 0x20200000, + 0xc90, 0x40000100, + 0xc94, 0x00000000, + 0xc98, 0x40000100, + 0xc9c, 0x00000000, + 0xca0, 0x00492492, + 0xca4, 0x00000000, + 0xca8, 0x00000000, + 0xcac, 0x00000000, + 0xcb0, 0x00000000, + 0xcb4, 0x00000000, + 0xcb8, 0x00000000, + 0xcbc, 0x00492492, + 0xcc0, 0x00000000, + 0xcc4, 0x00000000, + 0xcc8, 0x00000000, + 0xccc, 0x00000000, + 0xcd0, 0x00000000, + 0xcd4, 0x00000000, + 0xcd8, 0x64b22427, + 0xcdc, 0x00766932, + 0xce0, 0x00222222, + 0xd00, 0x00000750, + 0xd04, 0x00000403, + 0xd08, 0x0000907f, + 0xd0c, 0x00000001, + 0xd10, 0xa0633333, + 0xd14, 0x33333c63, + 0xd18, 0x6a8f5b6b, + 0xd1c, 0x00000000, + 0xd20, 0x00000000, + 0xd24, 0x00000000, + 0xd28, 0x00000000, + 0xd2c, 0xcc979975, + 0xd30, 0x00000000, + 0xd34, 0x00000000, + 0xd38, 0x00000000, + 0xd3c, 0x00027293, + 0xd40, 0x00000000, + 0xd44, 0x00000000, + 0xd48, 0x00000000, + 0xd4c, 0x00000000, + 0xd50, 0x6437140a, + 0xd54, 0x024dbd02, + 0xd58, 0x00000000, + 0xd5c, 0x04032064, + 0xe00, 0x161a1a1a, + 0xe04, 0x12121416, + 0xe08, 0x00001800, + 0xe0c, 0x00000000, + 0xe10, 0x161a1a1a, + 0xe14, 0x12121416, + 0xe18, 0x161a1a1a, + 0xe1c, 0x12121416, +}; + +u32 Rtl8192PciERadioA_Array[RadioA_ArrayLengthPciE] = { + 0x019, 0x00000003, + 0x000, 0x000000bf, + 0x001, 0x00000ee0, + 0x002, 0x0000004c, + 0x003, 0x000007f1, + 0x004, 0x00000975, + 0x005, 0x00000c58, + 0x006, 0x00000ae6, + 0x007, 0x000000ca, + 0x008, 0x00000e1c, + 0x009, 0x000007f0, + 0x00a, 0x000009d0, + 0x00b, 0x000001ba, + 0x00c, 0x00000240, + 0x00e, 0x00000020, + 0x00f, 0x00000990, + 0x012, 0x00000806, + 0x014, 0x000005ab, + 0x015, 0x00000f80, + 0x016, 0x00000020, + 0x017, 0x00000597, + 0x018, 0x0000050a, + 0x01a, 0x00000f80, + 0x01b, 0x00000f5e, + 0x01c, 0x00000008, + 0x01d, 0x00000607, + 0x01e, 0x000006cc, + 0x01f, 0x00000000, + 0x020, 0x000001a5, + 0x01f, 0x00000001, + 0x020, 0x00000165, + 0x01f, 0x00000002, + 0x020, 0x000000c6, + 0x01f, 0x00000003, + 0x020, 0x00000086, + 0x01f, 0x00000004, + 0x020, 0x00000046, + 0x01f, 0x00000005, + 0x020, 0x000001e6, + 0x01f, 0x00000006, + 0x020, 0x000001a6, + 0x01f, 0x00000007, + 0x020, 0x00000166, + 0x01f, 0x00000008, + 0x020, 0x000000c7, + 0x01f, 0x00000009, + 0x020, 0x00000087, + 0x01f, 0x0000000a, + 0x020, 0x000000f7, + 0x01f, 0x0000000b, + 0x020, 0x000000d7, + 0x01f, 0x0000000c, + 0x020, 0x000000b7, + 0x01f, 0x0000000d, + 0x020, 0x00000097, + 0x01f, 0x0000000e, + 0x020, 0x00000077, + 0x01f, 0x0000000f, + 0x020, 0x00000057, + 0x01f, 0x00000010, + 0x020, 0x00000037, + 0x01f, 0x00000011, + 0x020, 0x000000fb, + 0x01f, 0x00000012, + 0x020, 0x000000db, + 0x01f, 0x00000013, + 0x020, 0x000000bb, + 0x01f, 0x00000014, + 0x020, 0x000000ff, + 0x01f, 0x00000015, + 0x020, 0x000000e3, + 0x01f, 0x00000016, + 0x020, 0x000000c3, + 0x01f, 0x00000017, + 0x020, 0x000000a3, + 0x01f, 0x00000018, + 0x020, 0x00000083, + 0x01f, 0x00000019, + 0x020, 0x00000063, + 0x01f, 0x0000001a, + 0x020, 0x00000043, + 0x01f, 0x0000001b, + 0x020, 0x00000023, + 0x01f, 0x0000001c, + 0x020, 0x00000003, + 0x01f, 0x0000001d, + 0x020, 0x000001e3, + 0x01f, 0x0000001e, + 0x020, 0x000001c3, + 0x01f, 0x0000001f, + 0x020, 0x000001a3, + 0x01f, 0x00000020, + 0x020, 0x00000183, + 0x01f, 0x00000021, + 0x020, 0x00000163, + 0x01f, 0x00000022, + 0x020, 0x00000143, + 0x01f, 0x00000023, + 0x020, 0x00000123, + 0x01f, 0x00000024, + 0x020, 0x00000103, + 0x023, 0x00000203, + 0x024, 0x00000100, + 0x00b, 0x000001ba, + 0x02c, 0x000003d7, + 0x02d, 0x00000ff0, + 0x000, 0x00000037, + 0x004, 0x00000160, + 0x007, 0x00000080, + 0x002, 0x0000088d, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x016, 0x00000200, + 0x016, 0x00000380, + 0x016, 0x00000020, + 0x016, 0x000001a0, + 0x000, 0x000000bf, + 0x00d, 0x0000001f, + 0x00d, 0x00000c9f, + 0x002, 0x0000004d, + 0x000, 0x00000cbf, + 0x004, 0x00000975, + 0x007, 0x00000700, +}; + +u32 Rtl8192PciERadioB_Array[RadioB_ArrayLengthPciE] = { + 0x019, 0x00000003, + 0x000, 0x000000bf, + 0x001, 0x000006e0, + 0x002, 0x0000004c, + 0x003, 0x000007f1, + 0x004, 0x00000975, + 0x005, 0x00000c58, + 0x006, 0x00000ae6, + 0x007, 0x000000ca, + 0x008, 0x00000e1c, + 0x000, 0x000000b7, + 0x00a, 0x00000850, + 0x000, 0x000000bf, + 0x00b, 0x000001ba, + 0x00c, 0x00000240, + 0x00e, 0x00000020, + 0x015, 0x00000f80, + 0x016, 0x00000020, + 0x017, 0x00000597, + 0x018, 0x0000050a, + 0x01a, 0x00000e00, + 0x01b, 0x00000f5e, + 0x01d, 0x00000607, + 0x01e, 0x000006cc, + 0x00b, 0x000001ba, + 0x023, 0x00000203, + 0x024, 0x00000100, + 0x000, 0x00000037, + 0x004, 0x00000160, + 0x016, 0x00000200, + 0x016, 0x00000380, + 0x016, 0x00000020, + 0x016, 0x000001a0, + 0x00d, 0x00000ccc, + 0x000, 0x000000bf, + 0x002, 0x0000004d, + 0x000, 0x00000cbf, + 0x004, 0x00000975, + 0x007, 0x00000700, +}; + +u32 Rtl8192PciERadioC_Array[RadioC_ArrayLengthPciE] = { + 0x0, }; + +u32 Rtl8192PciERadioD_Array[RadioD_ArrayLengthPciE] = { + 0x0, }; + +u32 Rtl8192PciEMACPHY_Array[] = { + 0x03c, 0xffff0000, 0x00000f0f, + 0x340, 0xffffffff, 0x161a1a1a, + 0x344, 0xffffffff, 0x12121416, + 0x348, 0x0000ffff, 0x00001818, + 0x12c, 0xffffffff, 0x04000802, + 0x318, 0x00000fff, 0x00000100, +}; + +u32 Rtl8192PciEMACPHY_Array_PG[] = { + 0x03c, 0xffff0000, 0x00000f0f, + 0xe00, 0xffffffff, 0x06090909, + 0xe04, 0xffffffff, 0x00030306, + 0xe08, 0x0000ff00, 0x00000000, + 0xe10, 0xffffffff, 0x0a0c0d0f, + 0xe14, 0xffffffff, 0x06070809, + 0xe18, 0xffffffff, 0x0a0c0d0f, + 0xe1c, 0xffffffff, 0x06070809, + 0x12c, 0xffffffff, 0x04000802, + 0x318, 0x00000fff, 0x00000800, +}; + +u32 Rtl8192PciEAGCTAB_Array[AGCTAB_ArrayLengthPciE] = { + 0xc78, 0x7d000001, + 0xc78, 0x7d010001, + 0xc78, 0x7d020001, + 0xc78, 0x7d030001, + 0xc78, 0x7d040001, + 0xc78, 0x7d050001, + 0xc78, 0x7c060001, + 0xc78, 0x7b070001, + 0xc78, 0x7a080001, + 0xc78, 0x79090001, + 0xc78, 0x780a0001, + 0xc78, 0x770b0001, + 0xc78, 0x760c0001, + 0xc78, 0x750d0001, + 0xc78, 0x740e0001, + 0xc78, 0x730f0001, + 0xc78, 0x72100001, + 0xc78, 0x71110001, + 0xc78, 0x70120001, + 0xc78, 0x6f130001, + 0xc78, 0x6e140001, + 0xc78, 0x6d150001, + 0xc78, 0x6c160001, + 0xc78, 0x6b170001, + 0xc78, 0x6a180001, + 0xc78, 0x69190001, + 0xc78, 0x681a0001, + 0xc78, 0x671b0001, + 0xc78, 0x661c0001, + 0xc78, 0x651d0001, + 0xc78, 0x641e0001, + 0xc78, 0x491f0001, + 0xc78, 0x48200001, + 0xc78, 0x47210001, + 0xc78, 0x46220001, + 0xc78, 0x45230001, + 0xc78, 0x44240001, + 0xc78, 0x43250001, + 0xc78, 0x28260001, + 0xc78, 0x27270001, + 0xc78, 0x26280001, + 0xc78, 0x25290001, + 0xc78, 0x242a0001, + 0xc78, 0x232b0001, + 0xc78, 0x222c0001, + 0xc78, 0x212d0001, + 0xc78, 0x202e0001, + 0xc78, 0x0a2f0001, + 0xc78, 0x08300001, + 0xc78, 0x06310001, + 0xc78, 0x05320001, + 0xc78, 0x04330001, + 0xc78, 0x03340001, + 0xc78, 0x02350001, + 0xc78, 0x01360001, + 0xc78, 0x00370001, + 0xc78, 0x00380001, + 0xc78, 0x00390001, + 0xc78, 0x003a0001, + 0xc78, 0x003b0001, + 0xc78, 0x003c0001, + 0xc78, 0x003d0001, + 0xc78, 0x003e0001, + 0xc78, 0x003f0001, + 0xc78, 0x7d400001, + 0xc78, 0x7d410001, + 0xc78, 0x7d420001, + 0xc78, 0x7d430001, + 0xc78, 0x7d440001, + 0xc78, 0x7d450001, + 0xc78, 0x7c460001, + 0xc78, 0x7b470001, + 0xc78, 0x7a480001, + 0xc78, 0x79490001, + 0xc78, 0x784a0001, + 0xc78, 0x774b0001, + 0xc78, 0x764c0001, + 0xc78, 0x754d0001, + 0xc78, 0x744e0001, + 0xc78, 0x734f0001, + 0xc78, 0x72500001, + 0xc78, 0x71510001, + 0xc78, 0x70520001, + 0xc78, 0x6f530001, + 0xc78, 0x6e540001, + 0xc78, 0x6d550001, + 0xc78, 0x6c560001, + 0xc78, 0x6b570001, + 0xc78, 0x6a580001, + 0xc78, 0x69590001, + 0xc78, 0x685a0001, + 0xc78, 0x675b0001, + 0xc78, 0x665c0001, + 0xc78, 0x655d0001, + 0xc78, 0x645e0001, + 0xc78, 0x495f0001, + 0xc78, 0x48600001, + 0xc78, 0x47610001, + 0xc78, 0x46620001, + 0xc78, 0x45630001, + 0xc78, 0x44640001, + 0xc78, 0x43650001, + 0xc78, 0x28660001, + 0xc78, 0x27670001, + 0xc78, 0x26680001, + 0xc78, 0x25690001, + 0xc78, 0x246a0001, + 0xc78, 0x236b0001, + 0xc78, 0x226c0001, + 0xc78, 0x216d0001, + 0xc78, 0x206e0001, + 0xc78, 0x0a6f0001, + 0xc78, 0x08700001, + 0xc78, 0x06710001, + 0xc78, 0x05720001, + 0xc78, 0x04730001, + 0xc78, 0x03740001, + 0xc78, 0x02750001, + 0xc78, 0x01760001, + 0xc78, 0x00770001, + 0xc78, 0x00780001, + 0xc78, 0x00790001, + 0xc78, 0x007a0001, + 0xc78, 0x007b0001, + 0xc78, 0x007c0001, + 0xc78, 0x007d0001, + 0xc78, 0x007e0001, + 0xc78, 0x007f0001, + 0xc78, 0x2e00001e, + 0xc78, 0x2e01001e, + 0xc78, 0x2e02001e, + 0xc78, 0x2e03001e, + 0xc78, 0x2e04001e, + 0xc78, 0x2e05001e, + 0xc78, 0x3006001e, + 0xc78, 0x3407001e, + 0xc78, 0x3908001e, + 0xc78, 0x3c09001e, + 0xc78, 0x3f0a001e, + 0xc78, 0x420b001e, + 0xc78, 0x440c001e, + 0xc78, 0x450d001e, + 0xc78, 0x460e001e, + 0xc78, 0x460f001e, + 0xc78, 0x4710001e, + 0xc78, 0x4811001e, + 0xc78, 0x4912001e, + 0xc78, 0x4a13001e, + 0xc78, 0x4b14001e, + 0xc78, 0x4b15001e, + 0xc78, 0x4c16001e, + 0xc78, 0x4d17001e, + 0xc78, 0x4e18001e, + 0xc78, 0x4f19001e, + 0xc78, 0x4f1a001e, + 0xc78, 0x501b001e, + 0xc78, 0x511c001e, + 0xc78, 0x521d001e, + 0xc78, 0x521e001e, + 0xc78, 0x531f001e, + 0xc78, 0x5320001e, + 0xc78, 0x5421001e, + 0xc78, 0x5522001e, + 0xc78, 0x5523001e, + 0xc78, 0x5624001e, + 0xc78, 0x5725001e, + 0xc78, 0x5726001e, + 0xc78, 0x5827001e, + 0xc78, 0x5828001e, + 0xc78, 0x5929001e, + 0xc78, 0x592a001e, + 0xc78, 0x5a2b001e, + 0xc78, 0x5b2c001e, + 0xc78, 0x5c2d001e, + 0xc78, 0x5c2e001e, + 0xc78, 0x5d2f001e, + 0xc78, 0x5e30001e, + 0xc78, 0x5f31001e, + 0xc78, 0x6032001e, + 0xc78, 0x6033001e, + 0xc78, 0x6134001e, + 0xc78, 0x6235001e, + 0xc78, 0x6336001e, + 0xc78, 0x6437001e, + 0xc78, 0x6438001e, + 0xc78, 0x6539001e, + 0xc78, 0x663a001e, + 0xc78, 0x673b001e, + 0xc78, 0x673c001e, + 0xc78, 0x683d001e, + 0xc78, 0x693e001e, + 0xc78, 0x6a3f001e, +}; diff --git a/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_hwimg.h b/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_hwimg.h new file mode 100644 index 000000000..d804876dd --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_hwimg.h @@ -0,0 +1,51 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ +#ifndef __INC_HAL8192PciE_FW_IMG_H +#define __INC_HAL8192PciE_FW_IMG_H + +/*Created on 2008/11/18, 3: 7*/ + +#include + +#define BootArrayLengthPciE 344 +extern u8 Rtl8192PciEFwBootArray[BootArrayLengthPciE]; +#define MainArrayLengthPciE 43012 +extern u8 Rtl8192PciEFwMainArray[MainArrayLengthPciE]; +#define DataArrayLengthPciE 848 +extern u8 Rtl8192PciEFwDataArray[DataArrayLengthPciE]; +#define PHY_REGArrayLengthPciE 1 +extern u32 Rtl8192PciEPHY_REGArray[PHY_REGArrayLengthPciE]; +#define PHY_REG_1T2RArrayLengthPciE 296 +extern u32 Rtl8192PciEPHY_REG_1T2RArray[PHY_REG_1T2RArrayLengthPciE]; +#define RadioA_ArrayLengthPciE 246 +extern u32 Rtl8192PciERadioA_Array[RadioA_ArrayLengthPciE]; +#define RadioB_ArrayLengthPciE 78 +extern u32 Rtl8192PciERadioB_Array[RadioB_ArrayLengthPciE]; +#define RadioC_ArrayLengthPciE 2 +extern u32 Rtl8192PciERadioC_Array[RadioC_ArrayLengthPciE]; +#define RadioD_ArrayLengthPciE 2 +extern u32 Rtl8192PciERadioD_Array[RadioD_ArrayLengthPciE]; +#define MACPHY_ArrayLengthPciE 18 +extern u32 Rtl8192PciEMACPHY_Array[MACPHY_ArrayLengthPciE]; +#define MACPHY_Array_PGLengthPciE 30 +extern u32 Rtl8192PciEMACPHY_Array_PG[MACPHY_Array_PGLengthPciE]; +#define AGCTAB_ArrayLengthPciE 384 +extern u32 Rtl8192PciEAGCTAB_Array[AGCTAB_ArrayLengthPciE]; + +#endif diff --git a/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c new file mode 100644 index 000000000..4664a4fd1 --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -0,0 +1,1636 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ + +#include "rtl_core.h" +#include "r8192E_hw.h" +#include "r8192E_phyreg.h" +#include "r8190P_rtl8256.h" +#include "r8192E_phy.h" +#include "rtl_dm.h" + +#include "r8192E_hwimg.h" + +static u32 RF_CHANNEL_TABLE_ZEBRA[] = { + 0, + 0x085c, + 0x08dc, + 0x095c, + 0x09dc, + 0x0a5c, + 0x0adc, + 0x0b5c, + 0x0bdc, + 0x0c5c, + 0x0cdc, + 0x0d5c, + 0x0ddc, + 0x0e5c, + 0x0f72, +}; + +/*************************Define local function prototype**********************/ + +static u32 phy_FwRFSerialRead(struct net_device *dev, + enum rf90_radio_path eRFPath, + u32 Offset); +static void phy_FwRFSerialWrite(struct net_device *dev, + enum rf90_radio_path eRFPath, + u32 Offset, u32 Data); + +static u32 rtl8192_CalculateBitShift(u32 dwBitMask) +{ + u32 i; + + for (i = 0; i <= 31; i++) { + if (((dwBitMask >> i) & 0x1) == 1) + break; + } + return i; +} + +u8 rtl8192_phy_CheckIsLegalRFPath(struct net_device *dev, u32 eRFPath) +{ + u8 ret = 1; + struct r8192_priv *priv = rtllib_priv(dev); + + if (priv->rf_type == RF_2T4R) + ret = 0; + else if (priv->rf_type == RF_1T2R) { + if (eRFPath == RF90_PATH_A || eRFPath == RF90_PATH_B) + ret = 1; + else if (eRFPath == RF90_PATH_C || eRFPath == RF90_PATH_D) + ret = 0; + } + return ret; +} + +void rtl8192_setBBreg(struct net_device *dev, u32 dwRegAddr, u32 dwBitMask, + u32 dwData) +{ + + u32 OriginalValue, BitShift, NewValue; + + if (dwBitMask != bMaskDWord) { + OriginalValue = read_nic_dword(dev, dwRegAddr); + BitShift = rtl8192_CalculateBitShift(dwBitMask); + NewValue = (((OriginalValue) & (~dwBitMask)) | + (dwData << BitShift)); + write_nic_dword(dev, dwRegAddr, NewValue); + } else + write_nic_dword(dev, dwRegAddr, dwData); +} + +u32 rtl8192_QueryBBReg(struct net_device *dev, u32 dwRegAddr, u32 dwBitMask) +{ + u32 Ret = 0, OriginalValue, BitShift; + + OriginalValue = read_nic_dword(dev, dwRegAddr); + BitShift = rtl8192_CalculateBitShift(dwBitMask); + Ret = (OriginalValue & dwBitMask) >> BitShift; + + return Ret; +} +static u32 rtl8192_phy_RFSerialRead(struct net_device *dev, + enum rf90_radio_path eRFPath, u32 Offset) +{ + struct r8192_priv *priv = rtllib_priv(dev); + u32 ret = 0; + u32 NewOffset = 0; + struct bb_reg_definition *pPhyReg = &priv->PHYRegDef[eRFPath]; + + Offset &= 0x3f; + + if (priv->rf_chip == RF_8256) { + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0xf00, 0x0); + if (Offset >= 31) { + priv->RfReg0Value[eRFPath] |= 0x140; + rtl8192_setBBreg(dev, pPhyReg->rf3wireOffset, + bMaskDWord, + (priv->RfReg0Value[eRFPath]<<16)); + NewOffset = Offset - 30; + } else if (Offset >= 16) { + priv->RfReg0Value[eRFPath] |= 0x100; + priv->RfReg0Value[eRFPath] &= (~0x40); + rtl8192_setBBreg(dev, pPhyReg->rf3wireOffset, + bMaskDWord, + (priv->RfReg0Value[eRFPath]<<16)); + + NewOffset = Offset - 15; + } else + NewOffset = Offset; + } else { + RT_TRACE((COMP_PHY|COMP_ERR), + "check RF type here, need to be 8256\n"); + NewOffset = Offset; + } + rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2, bLSSIReadAddress, + NewOffset); + rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2, bLSSIReadEdge, 0x0); + rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2, bLSSIReadEdge, 0x1); + + mdelay(1); + + ret = rtl8192_QueryBBReg(dev, pPhyReg->rfLSSIReadBack, + bLSSIReadBackData); + + if (priv->rf_chip == RF_8256) { + priv->RfReg0Value[eRFPath] &= 0xebf; + + rtl8192_setBBreg(dev, pPhyReg->rf3wireOffset, bMaskDWord, + (priv->RfReg0Value[eRFPath] << 16)); + + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0x300, 0x3); + } + + + return ret; + +} + +static void rtl8192_phy_RFSerialWrite(struct net_device *dev, + enum rf90_radio_path eRFPath, u32 Offset, + u32 Data) +{ + struct r8192_priv *priv = rtllib_priv(dev); + u32 DataAndAddr = 0, NewOffset = 0; + struct bb_reg_definition *pPhyReg = &priv->PHYRegDef[eRFPath]; + + Offset &= 0x3f; + if (priv->rf_chip == RF_8256) { + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0xf00, 0x0); + + if (Offset >= 31) { + priv->RfReg0Value[eRFPath] |= 0x140; + rtl8192_setBBreg(dev, pPhyReg->rf3wireOffset, + bMaskDWord, + (priv->RfReg0Value[eRFPath] << 16)); + NewOffset = Offset - 30; + } else if (Offset >= 16) { + priv->RfReg0Value[eRFPath] |= 0x100; + priv->RfReg0Value[eRFPath] &= (~0x40); + rtl8192_setBBreg(dev, pPhyReg->rf3wireOffset, + bMaskDWord, + (priv->RfReg0Value[eRFPath] << 16)); + NewOffset = Offset - 15; + } else + NewOffset = Offset; + } else { + RT_TRACE((COMP_PHY|COMP_ERR), + "check RF type here, need to be 8256\n"); + NewOffset = Offset; + } + + DataAndAddr = (Data<<16) | (NewOffset&0x3f); + + rtl8192_setBBreg(dev, pPhyReg->rf3wireOffset, bMaskDWord, DataAndAddr); + + if (Offset == 0x0) + priv->RfReg0Value[eRFPath] = Data; + + if (priv->rf_chip == RF_8256) { + if (Offset != 0) { + priv->RfReg0Value[eRFPath] &= 0xebf; + rtl8192_setBBreg( + dev, + pPhyReg->rf3wireOffset, + bMaskDWord, + (priv->RfReg0Value[eRFPath] << 16)); + } + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0x300, 0x3); + } +} + +void rtl8192_phy_SetRFReg(struct net_device *dev, enum rf90_radio_path eRFPath, + u32 RegAddr, u32 BitMask, u32 Data) +{ + struct r8192_priv *priv = rtllib_priv(dev); + u32 Original_Value, BitShift, New_Value; + + if (!rtl8192_phy_CheckIsLegalRFPath(dev, eRFPath)) + return; + if (priv->rtllib->eRFPowerState != eRfOn && !priv->being_init_adapter) + return; + + RT_TRACE(COMP_PHY, "FW RF CTRL is not ready now\n"); + if (priv->Rf_Mode == RF_OP_By_FW) { + if (BitMask != bMask12Bits) { + Original_Value = phy_FwRFSerialRead(dev, eRFPath, + RegAddr); + BitShift = rtl8192_CalculateBitShift(BitMask); + New_Value = (((Original_Value) & (~BitMask)) | + (Data << BitShift)); + + phy_FwRFSerialWrite(dev, eRFPath, RegAddr, New_Value); + } else + phy_FwRFSerialWrite(dev, eRFPath, RegAddr, Data); + udelay(200); + + } else { + if (BitMask != bMask12Bits) { + Original_Value = rtl8192_phy_RFSerialRead(dev, eRFPath, + RegAddr); + BitShift = rtl8192_CalculateBitShift(BitMask); + New_Value = (((Original_Value) & (~BitMask)) | + (Data << BitShift)); + + rtl8192_phy_RFSerialWrite(dev, eRFPath, RegAddr, + New_Value); + } else + rtl8192_phy_RFSerialWrite(dev, eRFPath, RegAddr, Data); + } +} + +u32 rtl8192_phy_QueryRFReg(struct net_device *dev, enum rf90_radio_path eRFPath, + u32 RegAddr, u32 BitMask) +{ + u32 Original_Value, Readback_Value, BitShift; + struct r8192_priv *priv = rtllib_priv(dev); + + if (!rtl8192_phy_CheckIsLegalRFPath(dev, eRFPath)) + return 0; + if (priv->rtllib->eRFPowerState != eRfOn && !priv->being_init_adapter) + return 0; + down(&priv->rf_sem); + if (priv->Rf_Mode == RF_OP_By_FW) { + Original_Value = phy_FwRFSerialRead(dev, eRFPath, RegAddr); + udelay(200); + } else { + Original_Value = rtl8192_phy_RFSerialRead(dev, eRFPath, + RegAddr); + } + BitShift = rtl8192_CalculateBitShift(BitMask); + Readback_Value = (Original_Value & BitMask) >> BitShift; + up(&priv->rf_sem); + return Readback_Value; +} + +static u32 phy_FwRFSerialRead(struct net_device *dev, + enum rf90_radio_path eRFPath, u32 Offset) +{ + u32 Data = 0; + u8 time = 0; + + Data |= ((Offset & 0xFF) << 12); + Data |= ((eRFPath & 0x3) << 20); + Data |= 0x80000000; + while (read_nic_dword(dev, QPNR)&0x80000000) { + if (time++ < 100) + udelay(10); + else + break; + } + write_nic_dword(dev, QPNR, Data); + while (read_nic_dword(dev, QPNR) & 0x80000000) { + if (time++ < 100) + udelay(10); + else + return 0; + } + return read_nic_dword(dev, RF_DATA); + +} + +static void phy_FwRFSerialWrite(struct net_device *dev, + enum rf90_radio_path eRFPath, + u32 Offset, u32 Data) +{ + u8 time = 0; + + Data |= ((Offset & 0xFF) << 12); + Data |= ((eRFPath & 0x3) << 20); + Data |= 0x400000; + Data |= 0x80000000; + + while (read_nic_dword(dev, QPNR) & 0x80000000) { + if (time++ < 100) + udelay(10); + else + break; + } + write_nic_dword(dev, QPNR, Data); + +} + + +void rtl8192_phy_configmac(struct net_device *dev) +{ + u32 dwArrayLen = 0, i = 0; + u32 *pdwArray = NULL; + struct r8192_priv *priv = rtllib_priv(dev); + + if (priv->bTXPowerDataReadFromEEPORM) { + RT_TRACE(COMP_PHY, "Rtl819XMACPHY_Array_PG\n"); + dwArrayLen = MACPHY_Array_PGLength; + pdwArray = Rtl819XMACPHY_Array_PG; + + } else { + RT_TRACE(COMP_PHY, "Read rtl819XMACPHY_Array\n"); + dwArrayLen = MACPHY_ArrayLength; + pdwArray = Rtl819XMACPHY_Array; + } + for (i = 0; i < dwArrayLen; i += 3) { + RT_TRACE(COMP_DBG, + "The Rtl8190MACPHY_Array[0] is %x Rtl8190MACPHY_Array[1] is %x Rtl8190MACPHY_Array[2] is %x\n", + pdwArray[i], pdwArray[i+1], pdwArray[i+2]); + if (pdwArray[i] == 0x318) + pdwArray[i+2] = 0x00000800; + rtl8192_setBBreg(dev, pdwArray[i], pdwArray[i+1], + pdwArray[i+2]); + } + return; + +} + +void rtl8192_phyConfigBB(struct net_device *dev, u8 ConfigType) +{ + int i; + u32 *Rtl819XPHY_REGArray_Table = NULL; + u32 *Rtl819XAGCTAB_Array_Table = NULL; + u16 AGCTAB_ArrayLen, PHY_REGArrayLen = 0; + struct r8192_priv *priv = rtllib_priv(dev); + + AGCTAB_ArrayLen = AGCTAB_ArrayLength; + Rtl819XAGCTAB_Array_Table = Rtl819XAGCTAB_Array; + if (priv->rf_type == RF_2T4R) { + PHY_REGArrayLen = PHY_REGArrayLength; + Rtl819XPHY_REGArray_Table = Rtl819XPHY_REGArray; + } else if (priv->rf_type == RF_1T2R) { + PHY_REGArrayLen = PHY_REG_1T2RArrayLength; + Rtl819XPHY_REGArray_Table = Rtl819XPHY_REG_1T2RArray; + } + + if (ConfigType == BaseBand_Config_PHY_REG) { + for (i = 0; i < PHY_REGArrayLen; i += 2) { + rtl8192_setBBreg(dev, Rtl819XPHY_REGArray_Table[i], + bMaskDWord, + Rtl819XPHY_REGArray_Table[i+1]); + RT_TRACE(COMP_DBG, + "i: %x, The Rtl819xUsbPHY_REGArray[0] is %x Rtl819xUsbPHY_REGArray[1] is %x\n", + i, Rtl819XPHY_REGArray_Table[i], + Rtl819XPHY_REGArray_Table[i+1]); + } + } else if (ConfigType == BaseBand_Config_AGC_TAB) { + for (i = 0; i < AGCTAB_ArrayLen; i += 2) { + rtl8192_setBBreg(dev, Rtl819XAGCTAB_Array_Table[i], + bMaskDWord, + Rtl819XAGCTAB_Array_Table[i+1]); + RT_TRACE(COMP_DBG, + "i:%x, The rtl819XAGCTAB_Array[0] is %x rtl819XAGCTAB_Array[1] is %x\n", + i, Rtl819XAGCTAB_Array_Table[i], + Rtl819XAGCTAB_Array_Table[i+1]); + } + } +} + +static void rtl8192_InitBBRFRegDef(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + priv->PHYRegDef[RF90_PATH_A].rfintfs = rFPGA0_XAB_RFInterfaceSW; + priv->PHYRegDef[RF90_PATH_B].rfintfs = rFPGA0_XAB_RFInterfaceSW; + priv->PHYRegDef[RF90_PATH_C].rfintfs = rFPGA0_XCD_RFInterfaceSW; + priv->PHYRegDef[RF90_PATH_D].rfintfs = rFPGA0_XCD_RFInterfaceSW; + + priv->PHYRegDef[RF90_PATH_A].rfintfi = rFPGA0_XAB_RFInterfaceRB; + priv->PHYRegDef[RF90_PATH_B].rfintfi = rFPGA0_XAB_RFInterfaceRB; + priv->PHYRegDef[RF90_PATH_C].rfintfi = rFPGA0_XCD_RFInterfaceRB; + priv->PHYRegDef[RF90_PATH_D].rfintfi = rFPGA0_XCD_RFInterfaceRB; + + priv->PHYRegDef[RF90_PATH_A].rfintfo = rFPGA0_XA_RFInterfaceOE; + priv->PHYRegDef[RF90_PATH_B].rfintfo = rFPGA0_XB_RFInterfaceOE; + priv->PHYRegDef[RF90_PATH_C].rfintfo = rFPGA0_XC_RFInterfaceOE; + priv->PHYRegDef[RF90_PATH_D].rfintfo = rFPGA0_XD_RFInterfaceOE; + + priv->PHYRegDef[RF90_PATH_A].rfintfe = rFPGA0_XA_RFInterfaceOE; + priv->PHYRegDef[RF90_PATH_B].rfintfe = rFPGA0_XB_RFInterfaceOE; + priv->PHYRegDef[RF90_PATH_C].rfintfe = rFPGA0_XC_RFInterfaceOE; + priv->PHYRegDef[RF90_PATH_D].rfintfe = rFPGA0_XD_RFInterfaceOE; + + priv->PHYRegDef[RF90_PATH_A].rf3wireOffset = rFPGA0_XA_LSSIParameter; + priv->PHYRegDef[RF90_PATH_B].rf3wireOffset = rFPGA0_XB_LSSIParameter; + priv->PHYRegDef[RF90_PATH_C].rf3wireOffset = rFPGA0_XC_LSSIParameter; + priv->PHYRegDef[RF90_PATH_D].rf3wireOffset = rFPGA0_XD_LSSIParameter; + + priv->PHYRegDef[RF90_PATH_A].rfLSSI_Select = rFPGA0_XAB_RFParameter; + priv->PHYRegDef[RF90_PATH_B].rfLSSI_Select = rFPGA0_XAB_RFParameter; + priv->PHYRegDef[RF90_PATH_C].rfLSSI_Select = rFPGA0_XCD_RFParameter; + priv->PHYRegDef[RF90_PATH_D].rfLSSI_Select = rFPGA0_XCD_RFParameter; + + priv->PHYRegDef[RF90_PATH_A].rfTxGainStage = rFPGA0_TxGainStage; + priv->PHYRegDef[RF90_PATH_B].rfTxGainStage = rFPGA0_TxGainStage; + priv->PHYRegDef[RF90_PATH_C].rfTxGainStage = rFPGA0_TxGainStage; + priv->PHYRegDef[RF90_PATH_D].rfTxGainStage = rFPGA0_TxGainStage; + + priv->PHYRegDef[RF90_PATH_A].rfHSSIPara1 = rFPGA0_XA_HSSIParameter1; + priv->PHYRegDef[RF90_PATH_B].rfHSSIPara1 = rFPGA0_XB_HSSIParameter1; + priv->PHYRegDef[RF90_PATH_C].rfHSSIPara1 = rFPGA0_XC_HSSIParameter1; + priv->PHYRegDef[RF90_PATH_D].rfHSSIPara1 = rFPGA0_XD_HSSIParameter1; + + priv->PHYRegDef[RF90_PATH_A].rfHSSIPara2 = rFPGA0_XA_HSSIParameter2; + priv->PHYRegDef[RF90_PATH_B].rfHSSIPara2 = rFPGA0_XB_HSSIParameter2; + priv->PHYRegDef[RF90_PATH_C].rfHSSIPara2 = rFPGA0_XC_HSSIParameter2; + priv->PHYRegDef[RF90_PATH_D].rfHSSIPara2 = rFPGA0_XD_HSSIParameter2; + + priv->PHYRegDef[RF90_PATH_A].rfSwitchControl = rFPGA0_XAB_SwitchControl; + priv->PHYRegDef[RF90_PATH_B].rfSwitchControl = rFPGA0_XAB_SwitchControl; + priv->PHYRegDef[RF90_PATH_C].rfSwitchControl = rFPGA0_XCD_SwitchControl; + priv->PHYRegDef[RF90_PATH_D].rfSwitchControl = rFPGA0_XCD_SwitchControl; + + priv->PHYRegDef[RF90_PATH_A].rfAGCControl1 = rOFDM0_XAAGCCore1; + priv->PHYRegDef[RF90_PATH_B].rfAGCControl1 = rOFDM0_XBAGCCore1; + priv->PHYRegDef[RF90_PATH_C].rfAGCControl1 = rOFDM0_XCAGCCore1; + priv->PHYRegDef[RF90_PATH_D].rfAGCControl1 = rOFDM0_XDAGCCore1; + + priv->PHYRegDef[RF90_PATH_A].rfAGCControl2 = rOFDM0_XAAGCCore2; + priv->PHYRegDef[RF90_PATH_B].rfAGCControl2 = rOFDM0_XBAGCCore2; + priv->PHYRegDef[RF90_PATH_C].rfAGCControl2 = rOFDM0_XCAGCCore2; + priv->PHYRegDef[RF90_PATH_D].rfAGCControl2 = rOFDM0_XDAGCCore2; + + priv->PHYRegDef[RF90_PATH_A].rfRxIQImbalance = rOFDM0_XARxIQImbalance; + priv->PHYRegDef[RF90_PATH_B].rfRxIQImbalance = rOFDM0_XBRxIQImbalance; + priv->PHYRegDef[RF90_PATH_C].rfRxIQImbalance = rOFDM0_XCRxIQImbalance; + priv->PHYRegDef[RF90_PATH_D].rfRxIQImbalance = rOFDM0_XDRxIQImbalance; + + priv->PHYRegDef[RF90_PATH_A].rfRxAFE = rOFDM0_XARxAFE; + priv->PHYRegDef[RF90_PATH_B].rfRxAFE = rOFDM0_XBRxAFE; + priv->PHYRegDef[RF90_PATH_C].rfRxAFE = rOFDM0_XCRxAFE; + priv->PHYRegDef[RF90_PATH_D].rfRxAFE = rOFDM0_XDRxAFE; + + priv->PHYRegDef[RF90_PATH_A].rfTxIQImbalance = rOFDM0_XATxIQImbalance; + priv->PHYRegDef[RF90_PATH_B].rfTxIQImbalance = rOFDM0_XBTxIQImbalance; + priv->PHYRegDef[RF90_PATH_C].rfTxIQImbalance = rOFDM0_XCTxIQImbalance; + priv->PHYRegDef[RF90_PATH_D].rfTxIQImbalance = rOFDM0_XDTxIQImbalance; + + priv->PHYRegDef[RF90_PATH_A].rfTxAFE = rOFDM0_XATxAFE; + priv->PHYRegDef[RF90_PATH_B].rfTxAFE = rOFDM0_XBTxAFE; + priv->PHYRegDef[RF90_PATH_C].rfTxAFE = rOFDM0_XCTxAFE; + priv->PHYRegDef[RF90_PATH_D].rfTxAFE = rOFDM0_XDTxAFE; + + priv->PHYRegDef[RF90_PATH_A].rfLSSIReadBack = rFPGA0_XA_LSSIReadBack; + priv->PHYRegDef[RF90_PATH_B].rfLSSIReadBack = rFPGA0_XB_LSSIReadBack; + priv->PHYRegDef[RF90_PATH_C].rfLSSIReadBack = rFPGA0_XC_LSSIReadBack; + priv->PHYRegDef[RF90_PATH_D].rfLSSIReadBack = rFPGA0_XD_LSSIReadBack; + +} + +bool rtl8192_phy_checkBBAndRF(struct net_device *dev, + enum hw90_block CheckBlock, + enum rf90_radio_path eRFPath) +{ + bool ret = true; + u32 i, CheckTimes = 4, dwRegRead = 0; + u32 WriteAddr[4]; + u32 WriteData[] = {0xfffff027, 0xaa55a02f, 0x00000027, 0x55aa502f}; + + WriteAddr[HW90_BLOCK_MAC] = 0x100; + WriteAddr[HW90_BLOCK_PHY0] = 0x900; + WriteAddr[HW90_BLOCK_PHY1] = 0x800; + WriteAddr[HW90_BLOCK_RF] = 0x3; + RT_TRACE(COMP_PHY, "=======>%s(), CheckBlock:%d\n", __func__, + CheckBlock); + for (i = 0; i < CheckTimes; i++) { + switch (CheckBlock) { + case HW90_BLOCK_MAC: + RT_TRACE(COMP_ERR, + "PHY_CheckBBRFOK(): Never Write 0x100 here!"); + break; + + case HW90_BLOCK_PHY0: + case HW90_BLOCK_PHY1: + write_nic_dword(dev, WriteAddr[CheckBlock], + WriteData[i]); + dwRegRead = read_nic_dword(dev, WriteAddr[CheckBlock]); + break; + + case HW90_BLOCK_RF: + WriteData[i] &= 0xfff; + rtl8192_phy_SetRFReg(dev, eRFPath, + WriteAddr[HW90_BLOCK_RF], + bMask12Bits, WriteData[i]); + mdelay(10); + dwRegRead = rtl8192_phy_QueryRFReg(dev, eRFPath, + WriteAddr[HW90_BLOCK_RF], + bMaskDWord); + mdelay(10); + break; + + default: + ret = false; + break; + } + + + if (dwRegRead != WriteData[i]) { + RT_TRACE(COMP_ERR, + "====>error=====dwRegRead: %x, WriteData: %x\n", + dwRegRead, WriteData[i]); + ret = false; + break; + } + } + + return ret; +} + +static bool rtl8192_BB_Config_ParaFile(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + bool rtStatus = true; + u8 bRegValue = 0, eCheckItem = 0; + u32 dwRegValue = 0; + + bRegValue = read_nic_byte(dev, BB_GLOBAL_RESET); + write_nic_byte(dev, BB_GLOBAL_RESET, (bRegValue|BB_GLOBAL_RESET_BIT)); + + dwRegValue = read_nic_dword(dev, CPU_GEN); + write_nic_dword(dev, CPU_GEN, (dwRegValue&(~CPU_GEN_BB_RST))); + + for (eCheckItem = (enum hw90_block)HW90_BLOCK_PHY0; + eCheckItem <= HW90_BLOCK_PHY1; eCheckItem++) { + rtStatus = rtl8192_phy_checkBBAndRF(dev, + (enum hw90_block)eCheckItem, + (enum rf90_radio_path)0); + if (!rtStatus) { + RT_TRACE((COMP_ERR | COMP_PHY), + "PHY_RF8256_Config():Check PHY%d Fail!!\n", + eCheckItem-1); + return rtStatus; + } + } + rtl8192_setBBreg(dev, rFPGA0_RFMOD, bCCKEn|bOFDMEn, 0x0); + rtl8192_phyConfigBB(dev, BaseBand_Config_PHY_REG); + + dwRegValue = read_nic_dword(dev, CPU_GEN); + write_nic_dword(dev, CPU_GEN, (dwRegValue|CPU_GEN_BB_RST)); + + rtl8192_phyConfigBB(dev, BaseBand_Config_AGC_TAB); + + if (priv->IC_Cut > VERSION_8190_BD) { + if (priv->rf_type == RF_2T4R) + dwRegValue = (priv->AntennaTxPwDiff[2]<<8 | + priv->AntennaTxPwDiff[1]<<4 | + priv->AntennaTxPwDiff[0]); + else + dwRegValue = 0x0; + rtl8192_setBBreg(dev, rFPGA0_TxGainStage, + (bXBTxAGC|bXCTxAGC|bXDTxAGC), dwRegValue); + + + dwRegValue = priv->CrystalCap; + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, bXtalCap92x, + dwRegValue); + } + + return rtStatus; +} +bool rtl8192_BBConfig(struct net_device *dev) +{ + rtl8192_InitBBRFRegDef(dev); + return rtl8192_BB_Config_ParaFile(dev); +} + +void rtl8192_phy_getTxPower(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + priv->MCSTxPowerLevelOriginalOffset[0] = + read_nic_dword(dev, rTxAGC_Rate18_06); + priv->MCSTxPowerLevelOriginalOffset[1] = + read_nic_dword(dev, rTxAGC_Rate54_24); + priv->MCSTxPowerLevelOriginalOffset[2] = + read_nic_dword(dev, rTxAGC_Mcs03_Mcs00); + priv->MCSTxPowerLevelOriginalOffset[3] = + read_nic_dword(dev, rTxAGC_Mcs07_Mcs04); + priv->MCSTxPowerLevelOriginalOffset[4] = + read_nic_dword(dev, rTxAGC_Mcs11_Mcs08); + priv->MCSTxPowerLevelOriginalOffset[5] = + read_nic_dword(dev, rTxAGC_Mcs15_Mcs12); + + priv->DefaultInitialGain[0] = read_nic_byte(dev, rOFDM0_XAAGCCore1); + priv->DefaultInitialGain[1] = read_nic_byte(dev, rOFDM0_XBAGCCore1); + priv->DefaultInitialGain[2] = read_nic_byte(dev, rOFDM0_XCAGCCore1); + priv->DefaultInitialGain[3] = read_nic_byte(dev, rOFDM0_XDAGCCore1); + RT_TRACE(COMP_INIT, + "Default initial gain (c50=0x%x, c58=0x%x, c60=0x%x, c68=0x%x)\n", + priv->DefaultInitialGain[0], priv->DefaultInitialGain[1], + priv->DefaultInitialGain[2], priv->DefaultInitialGain[3]); + + priv->framesync = read_nic_byte(dev, rOFDM0_RxDetector3); + priv->framesyncC34 = read_nic_dword(dev, rOFDM0_RxDetector2); + RT_TRACE(COMP_INIT, "Default framesync (0x%x) = 0x%x\n", + rOFDM0_RxDetector3, priv->framesync); + priv->SifsTime = read_nic_word(dev, SIFS); +} + +void rtl8192_phy_setTxPower(struct net_device *dev, u8 channel) +{ + struct r8192_priv *priv = rtllib_priv(dev); + u8 powerlevel = 0, powerlevelOFDM24G = 0; + char ant_pwr_diff; + u32 u4RegValue; + + if (priv->epromtype == EEPROM_93C46) { + powerlevel = priv->TxPowerLevelCCK[channel-1]; + powerlevelOFDM24G = priv->TxPowerLevelOFDM24G[channel-1]; + } else if (priv->epromtype == EEPROM_93C56) { + if (priv->rf_type == RF_1T2R) { + powerlevel = priv->TxPowerLevelCCK_C[channel-1]; + powerlevelOFDM24G = priv->TxPowerLevelOFDM24G_C[channel-1]; + } else if (priv->rf_type == RF_2T4R) { + powerlevel = priv->TxPowerLevelCCK_A[channel-1]; + powerlevelOFDM24G = priv->TxPowerLevelOFDM24G_A[channel-1]; + + ant_pwr_diff = priv->TxPowerLevelOFDM24G_C[channel-1] + - priv->TxPowerLevelOFDM24G_A[channel-1]; + + priv->RF_C_TxPwDiff = ant_pwr_diff; + + ant_pwr_diff &= 0xf; + + priv->AntennaTxPwDiff[2] = 0; + priv->AntennaTxPwDiff[1] = (u8)(ant_pwr_diff); + priv->AntennaTxPwDiff[0] = 0; + + u4RegValue = (priv->AntennaTxPwDiff[2]<<8 | + priv->AntennaTxPwDiff[1]<<4 | + priv->AntennaTxPwDiff[0]); + + rtl8192_setBBreg(dev, rFPGA0_TxGainStage, + (bXBTxAGC|bXCTxAGC|bXDTxAGC), u4RegValue); + } + } + switch (priv->rf_chip) { + case RF_8225: + break; + case RF_8256: + PHY_SetRF8256CCKTxPower(dev, powerlevel); + PHY_SetRF8256OFDMTxPower(dev, powerlevelOFDM24G); + break; + case RF_8258: + break; + default: + RT_TRACE(COMP_ERR, "unknown rf chip in function %s()\n", + __func__); + break; + } +} + +bool rtl8192_phy_RFConfig(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + bool rtStatus = true; + + switch (priv->rf_chip) { + case RF_8225: + break; + case RF_8256: + rtStatus = PHY_RF8256_Config(dev); + break; + + case RF_8258: + break; + case RF_PSEUDO_11N: + break; + + default: + RT_TRACE(COMP_ERR, "error chip id\n"); + break; + } + return rtStatus; +} + +void rtl8192_phy_updateInitGain(struct net_device *dev) +{ +} + +u8 rtl8192_phy_ConfigRFWithHeaderFile(struct net_device *dev, + enum rf90_radio_path eRFPath) +{ + + int i; + + switch (eRFPath) { + case RF90_PATH_A: + for (i = 0; i < RadioA_ArrayLength; i += 2) { + if (Rtl819XRadioA_Array[i] == 0xfe) { + msleep(100); + continue; + } + rtl8192_phy_SetRFReg(dev, eRFPath, + Rtl819XRadioA_Array[i], + bMask12Bits, + Rtl819XRadioA_Array[i+1]); + + } + break; + case RF90_PATH_B: + for (i = 0; i < RadioB_ArrayLength; i += 2) { + if (Rtl819XRadioB_Array[i] == 0xfe) { + msleep(100); + continue; + } + rtl8192_phy_SetRFReg(dev, eRFPath, + Rtl819XRadioB_Array[i], + bMask12Bits, + Rtl819XRadioB_Array[i+1]); + + } + break; + case RF90_PATH_C: + for (i = 0; i < RadioC_ArrayLength; i += 2) { + if (Rtl819XRadioC_Array[i] == 0xfe) { + msleep(100); + continue; + } + rtl8192_phy_SetRFReg(dev, eRFPath, + Rtl819XRadioC_Array[i], + bMask12Bits, + Rtl819XRadioC_Array[i+1]); + + } + break; + case RF90_PATH_D: + for (i = 0; i < RadioD_ArrayLength; i += 2) { + if (Rtl819XRadioD_Array[i] == 0xfe) { + msleep(100); + continue; + } + rtl8192_phy_SetRFReg(dev, eRFPath, + Rtl819XRadioD_Array[i], bMask12Bits, + Rtl819XRadioD_Array[i+1]); + + } + break; + default: + break; + } + + return 0; + +} +static void rtl8192_SetTxPowerLevel(struct net_device *dev, u8 channel) +{ + struct r8192_priv *priv = rtllib_priv(dev); + u8 powerlevel = priv->TxPowerLevelCCK[channel-1]; + u8 powerlevelOFDM24G = priv->TxPowerLevelOFDM24G[channel-1]; + + switch (priv->rf_chip) { + case RF_8225: + break; + + case RF_8256: + PHY_SetRF8256CCKTxPower(dev, powerlevel); + PHY_SetRF8256OFDMTxPower(dev, powerlevelOFDM24G); + break; + + case RF_8258: + break; + default: + RT_TRACE(COMP_ERR, + "unknown rf chip ID in rtl8192_SetTxPowerLevel()\n"); + break; + } +} + +static u8 rtl8192_phy_SetSwChnlCmdArray(struct sw_chnl_cmd *CmdTable, + u32 CmdTableIdx, u32 CmdTableSz, + enum sw_chnl_cmd_id CmdID, + u32 Para1, u32 Para2, u32 msDelay) +{ + struct sw_chnl_cmd *pCmd; + + if (CmdTable == NULL) { + RT_TRACE(COMP_ERR, + "phy_SetSwChnlCmdArray(): CmdTable cannot be NULL.\n"); + return false; + } + if (CmdTableIdx >= CmdTableSz) { + RT_TRACE(COMP_ERR, + "phy_SetSwChnlCmdArray(): Access invalid index, please check size of the table, CmdTableIdx:%d, CmdTableSz:%d\n", + CmdTableIdx, CmdTableSz); + return false; + } + + pCmd = CmdTable + CmdTableIdx; + pCmd->CmdID = CmdID; + pCmd->Para1 = Para1; + pCmd->Para2 = Para2; + pCmd->msDelay = msDelay; + + return true; +} + +static u8 rtl8192_phy_SwChnlStepByStep(struct net_device *dev, u8 channel, + u8 *stage, u8 *step, u32 *delay) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct rtllib_device *ieee = priv->rtllib; + u32 PreCommonCmdCnt; + u32 PostCommonCmdCnt; + u32 RfDependCmdCnt; + struct sw_chnl_cmd *CurrentCmd = NULL; + u8 eRFPath; + + RT_TRACE(COMP_TRACE, "====>%s()====stage:%d, step:%d, channel:%d\n", + __func__, *stage, *step, channel); + + if (!rtllib_legal_channel(priv->rtllib, channel)) { + RT_TRACE(COMP_ERR, "=============>set to illegal channel:%d\n", + channel); + return true; + } + + { + PreCommonCmdCnt = 0; + rtl8192_phy_SetSwChnlCmdArray(ieee->PreCommonCmd, + PreCommonCmdCnt++, + MAX_PRECMD_CNT, CmdID_SetTxPowerLevel, + 0, 0, 0); + rtl8192_phy_SetSwChnlCmdArray(ieee->PreCommonCmd, + PreCommonCmdCnt++, + MAX_PRECMD_CNT, CmdID_End, 0, 0, 0); + + PostCommonCmdCnt = 0; + + rtl8192_phy_SetSwChnlCmdArray(ieee->PostCommonCmd, + PostCommonCmdCnt++, + MAX_POSTCMD_CNT, CmdID_End, 0, 0, 0); + + RfDependCmdCnt = 0; + switch (priv->rf_chip) { + case RF_8225: + if (!(channel >= 1 && channel <= 14)) { + RT_TRACE(COMP_ERR, + "illegal channel for Zebra 8225: %d\n", + channel); + return false; + } + rtl8192_phy_SetSwChnlCmdArray(ieee->RfDependCmd, + RfDependCmdCnt++, MAX_RFDEPENDCMD_CNT, + CmdID_RF_WriteReg, rZebra1_Channel, + RF_CHANNEL_TABLE_ZEBRA[channel], 10); + rtl8192_phy_SetSwChnlCmdArray(ieee->RfDependCmd, + RfDependCmdCnt++, MAX_RFDEPENDCMD_CNT, + CmdID_End, 0, 0, 0); + break; + + case RF_8256: + if (!(channel >= 1 && channel <= 14)) { + RT_TRACE(COMP_ERR, + "illegal channel for Zebra 8256: %d\n", + channel); + return false; + } + rtl8192_phy_SetSwChnlCmdArray(ieee->RfDependCmd, + RfDependCmdCnt++, MAX_RFDEPENDCMD_CNT, + CmdID_RF_WriteReg, rZebra1_Channel, channel, + 10); + rtl8192_phy_SetSwChnlCmdArray(ieee->RfDependCmd, + + RfDependCmdCnt++, + MAX_RFDEPENDCMD_CNT, + CmdID_End, 0, 0, 0); + break; + + case RF_8258: + break; + + default: + RT_TRACE(COMP_ERR, "Unknown RFChipID: %d\n", + priv->rf_chip); + return false; + } + + + do { + switch (*stage) { + case 0: + CurrentCmd = &ieee->PreCommonCmd[*step]; + break; + case 1: + CurrentCmd = &ieee->RfDependCmd[*step]; + break; + case 2: + CurrentCmd = &ieee->PostCommonCmd[*step]; + break; + } + + if (CurrentCmd && CurrentCmd->CmdID == CmdID_End) { + if ((*stage) == 2) + return true; + (*stage)++; + (*step) = 0; + continue; + } + + if (!CurrentCmd) + continue; + switch (CurrentCmd->CmdID) { + case CmdID_SetTxPowerLevel: + if (priv->IC_Cut > (u8)VERSION_8190_BD) + rtl8192_SetTxPowerLevel(dev, channel); + break; + case CmdID_WritePortUlong: + write_nic_dword(dev, CurrentCmd->Para1, + CurrentCmd->Para2); + break; + case CmdID_WritePortUshort: + write_nic_word(dev, CurrentCmd->Para1, + (u16)CurrentCmd->Para2); + break; + case CmdID_WritePortUchar: + write_nic_byte(dev, CurrentCmd->Para1, + (u8)CurrentCmd->Para2); + break; + case CmdID_RF_WriteReg: + for (eRFPath = 0; eRFPath < + priv->NumTotalRFPath; eRFPath++) + rtl8192_phy_SetRFReg(dev, + (enum rf90_radio_path)eRFPath, + CurrentCmd->Para1, bMask12Bits, + CurrentCmd->Para2<<7); + break; + default: + break; + } + + break; + } while (true); + } /*for (Number of RF paths)*/ + + (*delay) = CurrentCmd->msDelay; + (*step)++; + return false; +} + +static void rtl8192_phy_FinishSwChnlNow(struct net_device *dev, u8 channel) +{ + struct r8192_priv *priv = rtllib_priv(dev); + u32 delay = 0; + + while (!rtl8192_phy_SwChnlStepByStep(dev, channel, &priv->SwChnlStage, + &priv->SwChnlStep, &delay)) { + if (delay > 0) + msleep(delay); + if (!priv->up) + break; + } +} +void rtl8192_SwChnl_WorkItem(struct net_device *dev) +{ + + struct r8192_priv *priv = rtllib_priv(dev); + + RT_TRACE(COMP_TRACE, "==> SwChnlCallback819xUsbWorkItem()\n"); + + RT_TRACE(COMP_TRACE, "=====>--%s(), set chan:%d, priv:%p\n", __func__, + priv->chan, priv); + + rtl8192_phy_FinishSwChnlNow(dev , priv->chan); + + RT_TRACE(COMP_TRACE, "<== SwChnlCallback819xUsbWorkItem()\n"); +} + +u8 rtl8192_phy_SwChnl(struct net_device *dev, u8 channel) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + RT_TRACE(COMP_PHY, "=====>%s()\n", __func__); + if (!priv->up) { + RT_TRACE(COMP_ERR, "%s(): ERR !! driver is not up\n", __func__); + return false; + } + if (priv->SwChnlInProgress) + return false; + + + switch (priv->rtllib->mode) { + case WIRELESS_MODE_A: + case WIRELESS_MODE_N_5G: + if (channel <= 14) { + RT_TRACE(COMP_ERR, "WIRELESS_MODE_A but channel<=14"); + return false; + } + break; + case WIRELESS_MODE_B: + if (channel > 14) { + RT_TRACE(COMP_ERR, "WIRELESS_MODE_B but channel>14"); + return false; + } + break; + case WIRELESS_MODE_G: + case WIRELESS_MODE_N_24G: + if (channel > 14) { + RT_TRACE(COMP_ERR, "WIRELESS_MODE_G but channel>14"); + return false; + } + break; + } + + priv->SwChnlInProgress = true; + if (channel == 0) + channel = 1; + + priv->chan = channel; + + priv->SwChnlStage = 0; + priv->SwChnlStep = 0; + + if (priv->up) + rtl8192_SwChnl_WorkItem(dev); + priv->SwChnlInProgress = false; + return true; +} + +static void CCK_Tx_Power_Track_BW_Switch_TSSI(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + switch (priv->CurrentChannelBW) { + case HT_CHANNEL_WIDTH_20: + priv->CCKPresentAttentuation = + priv->CCKPresentAttentuation_20Mdefault + + priv->CCKPresentAttentuation_difference; + + if (priv->CCKPresentAttentuation > + (CCKTxBBGainTableLength-1)) + priv->CCKPresentAttentuation = + CCKTxBBGainTableLength-1; + if (priv->CCKPresentAttentuation < 0) + priv->CCKPresentAttentuation = 0; + + RT_TRACE(COMP_POWER_TRACKING, + "20M, priv->CCKPresentAttentuation = %d\n", + priv->CCKPresentAttentuation); + + if (priv->rtllib->current_network.channel == 14 && + !priv->bcck_in_ch14) { + priv->bcck_in_ch14 = true; + dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); + } else if (priv->rtllib->current_network.channel != + 14 && priv->bcck_in_ch14) { + priv->bcck_in_ch14 = false; + dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); + } else { + dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); + } + break; + + case HT_CHANNEL_WIDTH_20_40: + priv->CCKPresentAttentuation = + priv->CCKPresentAttentuation_40Mdefault + + priv->CCKPresentAttentuation_difference; + + RT_TRACE(COMP_POWER_TRACKING, + "40M, priv->CCKPresentAttentuation = %d\n", + priv->CCKPresentAttentuation); + if (priv->CCKPresentAttentuation > + (CCKTxBBGainTableLength - 1)) + priv->CCKPresentAttentuation = + CCKTxBBGainTableLength-1; + if (priv->CCKPresentAttentuation < 0) + priv->CCKPresentAttentuation = 0; + + if (priv->rtllib->current_network.channel == 14 && + !priv->bcck_in_ch14) { + priv->bcck_in_ch14 = true; + dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); + } else if (priv->rtllib->current_network.channel != 14 + && priv->bcck_in_ch14) { + priv->bcck_in_ch14 = false; + dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); + } else { + dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); + } + break; + } +} + +static void CCK_Tx_Power_Track_BW_Switch_ThermalMeter(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + if (priv->rtllib->current_network.channel == 14 && + !priv->bcck_in_ch14) + priv->bcck_in_ch14 = true; + else if (priv->rtllib->current_network.channel != 14 && + priv->bcck_in_ch14) + priv->bcck_in_ch14 = false; + + switch (priv->CurrentChannelBW) { + case HT_CHANNEL_WIDTH_20: + if (priv->Record_CCK_20Mindex == 0) + priv->Record_CCK_20Mindex = 6; + priv->CCK_index = priv->Record_CCK_20Mindex; + RT_TRACE(COMP_POWER_TRACKING, + "20MHz, CCK_Tx_Power_Track_BW_Switch_ThermalMeter(),CCK_index = %d\n", + priv->CCK_index); + break; + + case HT_CHANNEL_WIDTH_20_40: + priv->CCK_index = priv->Record_CCK_40Mindex; + RT_TRACE(COMP_POWER_TRACKING, + "40MHz, CCK_Tx_Power_Track_BW_Switch_ThermalMeter(), CCK_index = %d\n", + priv->CCK_index); + break; + } + dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); +} + +static void CCK_Tx_Power_Track_BW_Switch(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + if (priv->IC_Cut >= IC_VersionCut_D) + CCK_Tx_Power_Track_BW_Switch_TSSI(dev); + else + CCK_Tx_Power_Track_BW_Switch_ThermalMeter(dev); +} + +void rtl8192_SetBWModeWorkItem(struct net_device *dev) +{ + + struct r8192_priv *priv = rtllib_priv(dev); + u8 regBwOpMode; + + RT_TRACE(COMP_SWBW, + "==>rtl8192_SetBWModeWorkItem() Switch to %s bandwidth\n", + priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20 ? + "20MHz" : "40MHz"); + + + if (priv->rf_chip == RF_PSEUDO_11N) { + priv->SetBWModeInProgress = false; + return; + } + if (!priv->up) { + RT_TRACE(COMP_ERR, "%s(): ERR!! driver is not up\n", __func__); + return; + } + regBwOpMode = read_nic_byte(dev, BW_OPMODE); + + switch (priv->CurrentChannelBW) { + case HT_CHANNEL_WIDTH_20: + regBwOpMode |= BW_OPMODE_20MHZ; + write_nic_byte(dev, BW_OPMODE, regBwOpMode); + break; + + case HT_CHANNEL_WIDTH_20_40: + regBwOpMode &= ~BW_OPMODE_20MHZ; + write_nic_byte(dev, BW_OPMODE, regBwOpMode); + break; + + default: + RT_TRACE(COMP_ERR, + "SetChannelBandwidth819xUsb(): unknown Bandwidth: %#X\n", + priv->CurrentChannelBW); + break; + } + + switch (priv->CurrentChannelBW) { + case HT_CHANNEL_WIDTH_20: + rtl8192_setBBreg(dev, rFPGA0_RFMOD, bRFMOD, 0x0); + rtl8192_setBBreg(dev, rFPGA1_RFMOD, bRFMOD, 0x0); + + if (!priv->btxpower_tracking) { + write_nic_dword(dev, rCCK0_TxFilter1, 0x1a1b0000); + write_nic_dword(dev, rCCK0_TxFilter2, 0x090e1317); + write_nic_dword(dev, rCCK0_DebugPort, 0x00000204); + } else { + CCK_Tx_Power_Track_BW_Switch(dev); + } + + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x00100000, 1); + + break; + case HT_CHANNEL_WIDTH_20_40: + rtl8192_setBBreg(dev, rFPGA0_RFMOD, bRFMOD, 0x1); + rtl8192_setBBreg(dev, rFPGA1_RFMOD, bRFMOD, 0x1); + + if (!priv->btxpower_tracking) { + write_nic_dword(dev, rCCK0_TxFilter1, 0x35360000); + write_nic_dword(dev, rCCK0_TxFilter2, 0x121c252e); + write_nic_dword(dev, rCCK0_DebugPort, 0x00000409); + } else { + CCK_Tx_Power_Track_BW_Switch(dev); + } + + rtl8192_setBBreg(dev, rCCK0_System, bCCKSideBand, + (priv->nCur40MhzPrimeSC>>1)); + rtl8192_setBBreg(dev, rOFDM1_LSTF, 0xC00, + priv->nCur40MhzPrimeSC); + + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x00100000, 0); + break; + default: + RT_TRACE(COMP_ERR, + "SetChannelBandwidth819xUsb(): unknown Bandwidth: %#X\n", + priv->CurrentChannelBW); + break; + + } + + switch (priv->rf_chip) { + case RF_8225: + break; + + case RF_8256: + PHY_SetRF8256Bandwidth(dev, priv->CurrentChannelBW); + break; + + case RF_8258: + break; + + case RF_PSEUDO_11N: + break; + + default: + RT_TRACE(COMP_ERR, "Unknown RFChipID: %d\n", priv->rf_chip); + break; + } + + atomic_dec(&(priv->rtllib->atm_swbw)); + priv->SetBWModeInProgress = false; + + RT_TRACE(COMP_SWBW, "<==SetBWMode819xUsb()"); +} + +void rtl8192_SetBWMode(struct net_device *dev, enum ht_channel_width Bandwidth, + enum ht_extchnl_offset Offset) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + + if (priv->SetBWModeInProgress) + return; + + atomic_inc(&(priv->rtllib->atm_swbw)); + priv->SetBWModeInProgress = true; + + priv->CurrentChannelBW = Bandwidth; + + if (Offset == HT_EXTCHNL_OFFSET_LOWER) + priv->nCur40MhzPrimeSC = HAL_PRIME_CHNL_OFFSET_UPPER; + else if (Offset == HT_EXTCHNL_OFFSET_UPPER) + priv->nCur40MhzPrimeSC = HAL_PRIME_CHNL_OFFSET_LOWER; + else + priv->nCur40MhzPrimeSC = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + + rtl8192_SetBWModeWorkItem(dev); + +} + +void InitialGain819xPci(struct net_device *dev, u8 Operation) +{ +#define SCAN_RX_INITIAL_GAIN 0x17 +#define POWER_DETECTION_TH 0x08 + struct r8192_priv *priv = rtllib_priv(dev); + u32 BitMask; + u8 initial_gain; + + if (priv->up) { + switch (Operation) { + case IG_Backup: + RT_TRACE(COMP_SCAN, + "IG_Backup, backup the initial gain.\n"); + initial_gain = SCAN_RX_INITIAL_GAIN; + BitMask = bMaskByte0; + if (dm_digtable.dig_algorithm == + DIG_ALGO_BY_FALSE_ALARM) + rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); + priv->initgain_backup.xaagccore1 = + (u8)rtl8192_QueryBBReg(dev, rOFDM0_XAAGCCore1, + BitMask); + priv->initgain_backup.xbagccore1 = + (u8)rtl8192_QueryBBReg(dev, rOFDM0_XBAGCCore1, + BitMask); + priv->initgain_backup.xcagccore1 = + (u8)rtl8192_QueryBBReg(dev, rOFDM0_XCAGCCore1, + BitMask); + priv->initgain_backup.xdagccore1 = + (u8)rtl8192_QueryBBReg(dev, rOFDM0_XDAGCCore1, + BitMask); + BitMask = bMaskByte2; + priv->initgain_backup.cca = (u8)rtl8192_QueryBBReg(dev, + rCCK0_CCA, BitMask); + + RT_TRACE(COMP_SCAN, + "Scan InitialGainBackup 0xc50 is %x\n", + priv->initgain_backup.xaagccore1); + RT_TRACE(COMP_SCAN, + "Scan InitialGainBackup 0xc58 is %x\n", + priv->initgain_backup.xbagccore1); + RT_TRACE(COMP_SCAN, + "Scan InitialGainBackup 0xc60 is %x\n", + priv->initgain_backup.xcagccore1); + RT_TRACE(COMP_SCAN, + "Scan InitialGainBackup 0xc68 is %x\n", + priv->initgain_backup.xdagccore1); + RT_TRACE(COMP_SCAN, + "Scan InitialGainBackup 0xa0a is %x\n", + priv->initgain_backup.cca); + + RT_TRACE(COMP_SCAN, "Write scan initial gain = 0x%x\n", + initial_gain); + write_nic_byte(dev, rOFDM0_XAAGCCore1, initial_gain); + write_nic_byte(dev, rOFDM0_XBAGCCore1, initial_gain); + write_nic_byte(dev, rOFDM0_XCAGCCore1, initial_gain); + write_nic_byte(dev, rOFDM0_XDAGCCore1, initial_gain); + RT_TRACE(COMP_SCAN, "Write scan 0xa0a = 0x%x\n", + POWER_DETECTION_TH); + write_nic_byte(dev, 0xa0a, POWER_DETECTION_TH); + break; + case IG_Restore: + RT_TRACE(COMP_SCAN, + "IG_Restore, restore the initial gain.\n"); + BitMask = 0x7f; + if (dm_digtable.dig_algorithm == + DIG_ALGO_BY_FALSE_ALARM) + rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); + + rtl8192_setBBreg(dev, rOFDM0_XAAGCCore1, BitMask, + (u32)priv->initgain_backup.xaagccore1); + rtl8192_setBBreg(dev, rOFDM0_XBAGCCore1, BitMask, + (u32)priv->initgain_backup.xbagccore1); + rtl8192_setBBreg(dev, rOFDM0_XCAGCCore1, BitMask, + (u32)priv->initgain_backup.xcagccore1); + rtl8192_setBBreg(dev, rOFDM0_XDAGCCore1, BitMask, + (u32)priv->initgain_backup.xdagccore1); + BitMask = bMaskByte2; + rtl8192_setBBreg(dev, rCCK0_CCA, BitMask, + (u32)priv->initgain_backup.cca); + + RT_TRACE(COMP_SCAN, + "Scan BBInitialGainRestore 0xc50 is %x\n", + priv->initgain_backup.xaagccore1); + RT_TRACE(COMP_SCAN, + "Scan BBInitialGainRestore 0xc58 is %x\n", + priv->initgain_backup.xbagccore1); + RT_TRACE(COMP_SCAN, + "Scan BBInitialGainRestore 0xc60 is %x\n", + priv->initgain_backup.xcagccore1); + RT_TRACE(COMP_SCAN, + "Scan BBInitialGainRestore 0xc68 is %x\n", + priv->initgain_backup.xdagccore1); + RT_TRACE(COMP_SCAN, + "Scan BBInitialGainRestore 0xa0a is %x\n", + priv->initgain_backup.cca); + + rtl8192_phy_setTxPower(dev, + priv->rtllib->current_network.channel); + + if (dm_digtable.dig_algorithm == + DIG_ALGO_BY_FALSE_ALARM) + rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x1); + break; + default: + RT_TRACE(COMP_SCAN, "Unknown IG Operation.\n"); + break; + } + } +} + +void PHY_SetRtl8192eRfOff(struct net_device *dev) +{ + + rtl8192_setBBreg(dev, rFPGA0_XA_RFInterfaceOE, BIT4, 0x0); + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0x300, 0x0); + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x18, 0x0); + rtl8192_setBBreg(dev, rOFDM0_TRxPathEnable, 0xf, 0x0); + rtl8192_setBBreg(dev, rOFDM1_TRxPathEnable, 0xf, 0x0); + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x60, 0x0); + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x4, 0x0); + write_nic_byte(dev, ANAPAR_FOR_8192PciE, 0x07); + +} + +static bool SetRFPowerState8190(struct net_device *dev, + enum rt_rf_power_state eRFPowerState) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct rt_pwr_save_ctrl *pPSC = (struct rt_pwr_save_ctrl *) + (&(priv->rtllib->PowerSaveControl)); + bool bResult = true; + u8 i = 0, QueueID = 0; + struct rtl8192_tx_ring *ring = NULL; + + if (priv->SetRFPowerStateInProgress) + return false; + RT_TRACE(COMP_PS, "===========> SetRFPowerState8190()!\n"); + priv->SetRFPowerStateInProgress = true; + + switch (priv->rf_chip) { + case RF_8256: + switch (eRFPowerState) { + case eRfOn: + RT_TRACE(COMP_PS, "SetRFPowerState8190() eRfOn!\n"); + if ((priv->rtllib->eRFPowerState == eRfOff) && + RT_IN_PS_LEVEL(pPSC, RT_RF_OFF_LEVL_HALT_NIC)) { + bool rtstatus = true; + u32 InitilizeCount = 3; + + do { + InitilizeCount--; + priv->RegRfOff = false; + rtstatus = NicIFEnableNIC(dev); + } while (!rtstatus && (InitilizeCount > 0)); + + if (!rtstatus) { + RT_TRACE(COMP_ERR, + "%s():Initialize Adapter fail,return\n", + __func__); + priv->SetRFPowerStateInProgress = false; + return false; + } + + RT_CLEAR_PS_LEVEL(pPSC, + RT_RF_OFF_LEVL_HALT_NIC); + } else { + write_nic_byte(dev, ANAPAR, 0x37); + mdelay(1); + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, + 0x4, 0x1); + priv->bHwRfOffAction = 0; + + rtl8192_setBBreg(dev, rFPGA0_XA_RFInterfaceOE, + BIT4, 0x1); + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, + 0x300, 0x3); + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, + 0x18, 0x3); + rtl8192_setBBreg(dev, rOFDM0_TRxPathEnable, 0x3, + 0x3); + rtl8192_setBBreg(dev, rOFDM1_TRxPathEnable, 0x3, + 0x3); + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, + 0x60, 0x3); + + } + + break; + + case eRfSleep: + if (priv->rtllib->eRFPowerState == eRfOff) + break; + + + for (QueueID = 0, i = 0; QueueID < MAX_TX_QUEUE; ) { + ring = &priv->tx_ring[QueueID]; + + if (skb_queue_len(&ring->queue) == 0) { + QueueID++; + continue; + } else { + RT_TRACE((COMP_POWER|COMP_RF), + "eRf Off/Sleep: %d times TcbBusyQueue[%d] !=0 before doze!\n", + (i+1), QueueID); + udelay(10); + i++; + } + + if (i >= MAX_DOZE_WAITING_TIMES_9x) { + RT_TRACE(COMP_POWER, + "\n\n\n TimeOut!! SetRFPowerState8190(): eRfOff: %d times TcbBusyQueue[%d] != 0 !!!\n", + MAX_DOZE_WAITING_TIMES_9x, + QueueID); + break; + } + } + PHY_SetRtl8192eRfOff(dev); + break; + + case eRfOff: + RT_TRACE(COMP_PS, + "SetRFPowerState8190() eRfOff/Sleep !\n"); + + for (QueueID = 0, i = 0; QueueID < MAX_TX_QUEUE; ) { + ring = &priv->tx_ring[QueueID]; + + if (skb_queue_len(&ring->queue) == 0) { + QueueID++; + continue; + } else { + RT_TRACE(COMP_POWER, + "eRf Off/Sleep: %d times TcbBusyQueue[%d] !=0 before doze!\n", + (i+1), QueueID); + udelay(10); + i++; + } + + if (i >= MAX_DOZE_WAITING_TIMES_9x) { + RT_TRACE(COMP_POWER, + "\n\n\n SetZebra: RFPowerState8185B(): eRfOff: %d times TcbBusyQueue[%d] != 0 !!!\n", + MAX_DOZE_WAITING_TIMES_9x, + QueueID); + break; + } + } + + if (pPSC->RegRfPsLevel & RT_RF_OFF_LEVL_HALT_NIC && + !RT_IN_PS_LEVEL(pPSC, RT_RF_OFF_LEVL_HALT_NIC)) { + NicIFDisableNIC(dev); + RT_SET_PS_LEVEL(pPSC, RT_RF_OFF_LEVL_HALT_NIC); + } else if (!(pPSC->RegRfPsLevel & + RT_RF_OFF_LEVL_HALT_NIC)) { + PHY_SetRtl8192eRfOff(dev); + } + + break; + + default: + bResult = false; + RT_TRACE(COMP_ERR, + "SetRFPowerState8190(): unknown state to set: 0x%X!!!\n", + eRFPowerState); + break; + } + + break; + + default: + RT_TRACE(COMP_ERR, "SetRFPowerState8190(): Unknown RF type\n"); + break; + } + + if (bResult) { + priv->rtllib->eRFPowerState = eRFPowerState; + + switch (priv->rf_chip) { + case RF_8256: + break; + + default: + RT_TRACE(COMP_ERR, + "SetRFPowerState8190(): Unknown RF type\n"); + break; + } + } + + priv->SetRFPowerStateInProgress = false; + RT_TRACE(COMP_PS, "<=========== SetRFPowerState8190() bResult = %d!\n", + bResult); + return bResult; +} + +bool SetRFPowerState(struct net_device *dev, + enum rt_rf_power_state eRFPowerState) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + bool bResult = false; + + RT_TRACE(COMP_PS, "---------> SetRFPowerState(): eRFPowerState(%d)\n", + eRFPowerState); + if (eRFPowerState == priv->rtllib->eRFPowerState && + priv->bHwRfOffAction == 0) { + RT_TRACE(COMP_PS, + "<--------- SetRFPowerState(): discard the request for eRFPowerState(%d) is the same.\n", + eRFPowerState); + return bResult; + } + + bResult = SetRFPowerState8190(dev, eRFPowerState); + + RT_TRACE(COMP_PS, "<--------- SetRFPowerState(): bResult(%d)\n", + bResult); + + return bResult; +} + +void PHY_ScanOperationBackup8192(struct net_device *dev, u8 Operation) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + if (priv->up) { + switch (Operation) { + case SCAN_OPT_BACKUP: + priv->rtllib->InitialGainHandler(dev, IG_Backup); + break; + + case SCAN_OPT_RESTORE: + priv->rtllib->InitialGainHandler(dev, IG_Restore); + break; + + default: + RT_TRACE(COMP_SCAN, "Unknown Scan Backup Operation.\n"); + break; + } + } + +} diff --git a/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h b/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h new file mode 100644 index 000000000..7318f8857 --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h @@ -0,0 +1,120 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ +#ifndef _R819XU_PHY_H +#define _R819XU_PHY_H + +#define MAX_DOZE_WAITING_TIMES_9x 64 + +#define AGCTAB_ArrayLength AGCTAB_ArrayLengthPciE +#define MACPHY_ArrayLength MACPHY_ArrayLengthPciE +#define RadioA_ArrayLength RadioA_ArrayLengthPciE +#define RadioB_ArrayLength RadioB_ArrayLengthPciE +#define MACPHY_Array_PGLength MACPHY_Array_PGLengthPciE +#define RadioC_ArrayLength RadioC_ArrayLengthPciE +#define RadioD_ArrayLength RadioD_ArrayLengthPciE +#define PHY_REGArrayLength PHY_REGArrayLengthPciE +#define PHY_REG_1T2RArrayLength PHY_REG_1T2RArrayLengthPciE + +#define Rtl819XMACPHY_Array_PG Rtl8192PciEMACPHY_Array_PG +#define Rtl819XMACPHY_Array Rtl8192PciEMACPHY_Array +#define Rtl819XRadioA_Array Rtl8192PciERadioA_Array +#define Rtl819XRadioB_Array Rtl8192PciERadioB_Array +#define Rtl819XRadioC_Array Rtl8192PciERadioC_Array +#define Rtl819XRadioD_Array Rtl8192PciERadioD_Array +#define Rtl819XAGCTAB_Array Rtl8192PciEAGCTAB_Array +#define Rtl819XPHY_REGArray Rtl8192PciEPHY_REGArray +#define Rtl819XPHY_REG_1T2RArray Rtl8192PciEPHY_REG_1T2RArray + +extern u32 rtl819XMACPHY_Array_PG[]; +extern u32 rtl819XPHY_REG_1T2RArray[]; +extern u32 rtl819XAGCTAB_Array[]; +extern u32 rtl819XRadioA_Array[]; +extern u32 rtl819XRadioB_Array[]; +extern u32 rtl819XRadioC_Array[]; +extern u32 rtl819XRadioD_Array[]; + +enum hw90_block { + HW90_BLOCK_MAC = 0, + HW90_BLOCK_PHY0 = 1, + HW90_BLOCK_PHY1 = 2, + HW90_BLOCK_RF = 3, + HW90_BLOCK_MAXIMUM = 4, +}; + +enum rf90_radio_path { + RF90_PATH_A = 0, + RF90_PATH_B = 1, + RF90_PATH_C = 2, + RF90_PATH_D = 3, + RF90_PATH_MAX +}; + +#define bMaskByte0 0xff +#define bMaskByte1 0xff00 +#define bMaskByte2 0xff0000 +#define bMaskByte3 0xff000000 +#define bMaskHWord 0xffff0000 +#define bMaskLWord 0x0000ffff +#define bMaskDWord 0xffffffff + +extern u8 rtl8192_phy_CheckIsLegalRFPath(struct net_device *dev, + u32 eRFPath); +extern void rtl8192_setBBreg(struct net_device *dev, u32 dwRegAddr, + u32 dwBitMask, u32 dwData); +extern u32 rtl8192_QueryBBReg(struct net_device *dev, u32 dwRegAddr, + u32 dwBitMask); +extern void rtl8192_phy_SetRFReg(struct net_device *dev, + enum rf90_radio_path eRFPath, + u32 RegAddr, u32 BitMask, u32 Data); +extern u32 rtl8192_phy_QueryRFReg(struct net_device *dev, + enum rf90_radio_path eRFPath, + u32 RegAddr, u32 BitMask); +extern void rtl8192_phy_configmac(struct net_device *dev); +extern void rtl8192_phyConfigBB(struct net_device *dev, u8 ConfigType); +extern bool rtl8192_phy_checkBBAndRF(struct net_device *dev, + enum hw90_block CheckBlock, + enum rf90_radio_path eRFPath); +extern bool rtl8192_BBConfig(struct net_device *dev); +extern void rtl8192_phy_getTxPower(struct net_device *dev); +extern void rtl8192_phy_setTxPower(struct net_device *dev, u8 channel); +extern bool rtl8192_phy_RFConfig(struct net_device *dev); +extern void rtl8192_phy_updateInitGain(struct net_device *dev); +extern u8 rtl8192_phy_ConfigRFWithHeaderFile(struct net_device *dev, + enum rf90_radio_path eRFPath); + +extern u8 rtl8192_phy_SwChnl(struct net_device *dev, u8 channel); +extern void rtl8192_SetBWMode(struct net_device *dev, + enum ht_channel_width Bandwidth, + enum ht_extchnl_offset Offset); +extern void rtl8192_SwChnl_WorkItem(struct net_device *dev); +extern void rtl8192_SetBWModeWorkItem(struct net_device *dev); +extern void InitialGain819xPci(struct net_device *dev, u8 Operation); + +extern void PHY_SetRtl8192eRfOff(struct net_device *dev); + +bool +SetRFPowerState( + struct net_device *dev, + enum rt_rf_power_state eRFPowerState + ); +#define PHY_SetRFPowerState SetRFPowerState + +extern void PHY_ScanOperationBackup8192(struct net_device *dev, u8 Operation); + +#endif diff --git a/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_phyreg.h b/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_phyreg.h new file mode 100644 index 000000000..7899dd538 --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl8192e/r8192E_phyreg.h @@ -0,0 +1,852 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ +#ifndef _R819XU_PHYREG_H +#define _R819XU_PHYREG_H + + +#define RF_DATA 0x1d4 + +#define rPMAC_Reset 0x100 +#define rPMAC_TxStart 0x104 +#define rPMAC_TxLegacySIG 0x108 +#define rPMAC_TxHTSIG1 0x10c +#define rPMAC_TxHTSIG2 0x110 +#define rPMAC_PHYDebug 0x114 +#define rPMAC_TxPacketNum 0x118 +#define rPMAC_TxIdle 0x11c +#define rPMAC_TxMACHeader0 0x120 +#define rPMAC_TxMACHeader1 0x124 +#define rPMAC_TxMACHeader2 0x128 +#define rPMAC_TxMACHeader3 0x12c +#define rPMAC_TxMACHeader4 0x130 +#define rPMAC_TxMACHeader5 0x134 +#define rPMAC_TxDataType 0x138 +#define rPMAC_TxRandomSeed 0x13c +#define rPMAC_CCKPLCPPreamble 0x140 +#define rPMAC_CCKPLCPHeader 0x144 +#define rPMAC_CCKCRC16 0x148 +#define rPMAC_OFDMRxCRC32OK 0x170 +#define rPMAC_OFDMRxCRC32Er 0x174 +#define rPMAC_OFDMRxParityEr 0x178 +#define rPMAC_OFDMRxCRC8Er 0x17c +#define rPMAC_CCKCRxRC16Er 0x180 +#define rPMAC_CCKCRxRC32Er 0x184 +#define rPMAC_CCKCRxRC32OK 0x188 +#define rPMAC_TxStatus 0x18c + +#define MCS_TXAGC 0x340 +#define CCK_TXAGC 0x348 + +/*---------------------0x400~0x4ff----------------------*/ +#define MacBlkCtrl 0x403 + +#define rFPGA0_RFMOD 0x800 +#define rFPGA0_TxInfo 0x804 +#define rFPGA0_PSDFunction 0x808 +#define rFPGA0_TxGainStage 0x80c +#define rFPGA0_RFTiming1 0x810 +#define rFPGA0_RFTiming2 0x814 +#define rFPGA0_XA_HSSIParameter1 0x820 +#define rFPGA0_XA_HSSIParameter2 0x824 +#define rFPGA0_XB_HSSIParameter1 0x828 +#define rFPGA0_XB_HSSIParameter2 0x82c +#define rFPGA0_XC_HSSIParameter1 0x830 +#define rFPGA0_XC_HSSIParameter2 0x834 +#define rFPGA0_XD_HSSIParameter1 0x838 +#define rFPGA0_XD_HSSIParameter2 0x83c +#define rFPGA0_XA_LSSIParameter 0x840 +#define rFPGA0_XB_LSSIParameter 0x844 +#define rFPGA0_XC_LSSIParameter 0x848 +#define rFPGA0_XD_LSSIParameter 0x84c +#define rFPGA0_RFWakeUpParameter 0x850 +#define rFPGA0_RFSleepUpParameter 0x854 +#define rFPGA0_XAB_SwitchControl 0x858 +#define rFPGA0_XCD_SwitchControl 0x85c +#define rFPGA0_XA_RFInterfaceOE 0x860 +#define rFPGA0_XB_RFInterfaceOE 0x864 +#define rFPGA0_XC_RFInterfaceOE 0x868 +#define rFPGA0_XD_RFInterfaceOE 0x86c +#define rFPGA0_XAB_RFInterfaceSW 0x870 +#define rFPGA0_XCD_RFInterfaceSW 0x874 +#define rFPGA0_XAB_RFParameter 0x878 +#define rFPGA0_XCD_RFParameter 0x87c +#define rFPGA0_AnalogParameter1 0x880 +#define rFPGA0_AnalogParameter2 0x884 +#define rFPGA0_AnalogParameter3 0x888 +#define rFPGA0_AnalogParameter4 0x88c +#define rFPGA0_XA_LSSIReadBack 0x8a0 +#define rFPGA0_XB_LSSIReadBack 0x8a4 +#define rFPGA0_XC_LSSIReadBack 0x8a8 +#define rFPGA0_XD_LSSIReadBack 0x8ac +#define rFPGA0_PSDReport 0x8b4 +#define rFPGA0_XAB_RFInterfaceRB 0x8e0 +#define rFPGA0_XCD_RFInterfaceRB 0x8e4 + +#define rFPGA1_RFMOD 0x900 +#define rFPGA1_TxBlock 0x904 +#define rFPGA1_DebugSelect 0x908 +#define rFPGA1_TxInfo 0x90c + +#define rCCK0_System 0xa00 +#define rCCK0_AFESetting 0xa04 +#define rCCK0_CCA 0xa08 +#define rCCK0_RxAGC1 0xa0c +#define rCCK0_RxAGC2 0xa10 +#define rCCK0_RxHP 0xa14 +#define rCCK0_DSPParameter1 0xa18 +#define rCCK0_DSPParameter2 0xa1c +#define rCCK0_TxFilter1 0xa20 +#define rCCK0_TxFilter2 0xa24 +#define rCCK0_DebugPort 0xa28 +#define rCCK0_FalseAlarmReport 0xa2c +#define rCCK0_TRSSIReport 0xa50 +#define rCCK0_RxReport 0xa54 +#define rCCK0_FACounterLower 0xa5c +#define rCCK0_FACounterUpper 0xa58 + +#define rOFDM0_LSTF 0xc00 +#define rOFDM0_TRxPathEnable 0xc04 +#define rOFDM0_TRMuxPar 0xc08 +#define rOFDM0_TRSWIsolation 0xc0c +#define rOFDM0_XARxAFE 0xc10 +#define rOFDM0_XARxIQImbalance 0xc14 +#define rOFDM0_XBRxAFE 0xc18 +#define rOFDM0_XBRxIQImbalance 0xc1c +#define rOFDM0_XCRxAFE 0xc20 +#define rOFDM0_XCRxIQImbalance 0xc24 +#define rOFDM0_XDRxAFE 0xc28 +#define rOFDM0_XDRxIQImbalance 0xc2c +#define rOFDM0_RxDetector1 0xc30 +#define rOFDM0_RxDetector2 0xc34 +#define rOFDM0_RxDetector3 0xc38 +#define rOFDM0_RxDetector4 0xc3c +#define rOFDM0_RxDSP 0xc40 +#define rOFDM0_CFOandDAGC 0xc44 +#define rOFDM0_CCADropThreshold 0xc48 +#define rOFDM0_ECCAThreshold 0xc4c +#define rOFDM0_XAAGCCore1 0xc50 +#define rOFDM0_XAAGCCore2 0xc54 +#define rOFDM0_XBAGCCore1 0xc58 +#define rOFDM0_XBAGCCore2 0xc5c +#define rOFDM0_XCAGCCore1 0xc60 +#define rOFDM0_XCAGCCore2 0xc64 +#define rOFDM0_XDAGCCore1 0xc68 +#define rOFDM0_XDAGCCore2 0xc6c +#define rOFDM0_AGCParameter1 0xc70 +#define rOFDM0_AGCParameter2 0xc74 +#define rOFDM0_AGCRSSITable 0xc78 +#define rOFDM0_HTSTFAGC 0xc7c +#define rOFDM0_XATxIQImbalance 0xc80 +#define rOFDM0_XATxAFE 0xc84 +#define rOFDM0_XBTxIQImbalance 0xc88 +#define rOFDM0_XBTxAFE 0xc8c +#define rOFDM0_XCTxIQImbalance 0xc90 +#define rOFDM0_XCTxAFE 0xc94 +#define rOFDM0_XDTxIQImbalance 0xc98 +#define rOFDM0_XDTxAFE 0xc9c +#define rOFDM0_RxHPParameter 0xce0 +#define rOFDM0_TxPseudoNoiseWgt 0xce4 +#define rOFDM0_FrameSync 0xcf0 +#define rOFDM0_DFSReport 0xcf4 +#define rOFDM0_TxCoeff1 0xca4 +#define rOFDM0_TxCoeff2 0xca8 +#define rOFDM0_TxCoeff3 0xcac +#define rOFDM0_TxCoeff4 0xcb0 +#define rOFDM0_TxCoeff5 0xcb4 +#define rOFDM0_TxCoeff6 0xcb8 + + +#define rOFDM1_LSTF 0xd00 +#define rOFDM1_TRxPathEnable 0xd04 +#define rOFDM1_CFO 0xd08 +#define rOFDM1_CSI1 0xd10 +#define rOFDM1_SBD 0xd14 +#define rOFDM1_CSI2 0xd18 +#define rOFDM1_CFOTracking 0xd2c +#define rOFDM1_TRxMesaure1 0xd34 +#define rOFDM1_IntfDet 0xd3c +#define rOFDM1_PseudoNoiseStateAB 0xd50 +#define rOFDM1_PseudoNoiseStateCD 0xd54 +#define rOFDM1_RxPseudoNoiseWgt 0xd58 +#define rOFDM_PHYCounter1 0xda0 +#define rOFDM_PHYCounter2 0xda4 +#define rOFDM_PHYCounter3 0xda8 +#define rOFDM_ShortCFOAB 0xdac +#define rOFDM_ShortCFOCD 0xdb0 +#define rOFDM_LongCFOAB 0xdb4 +#define rOFDM_LongCFOCD 0xdb8 +#define rOFDM_TailCFOAB 0xdbc +#define rOFDM_TailCFOCD 0xdc0 +#define rOFDM_PWMeasure1 0xdc4 +#define rOFDM_PWMeasure2 0xdc8 +#define rOFDM_BWReport 0xdcc +#define rOFDM_AGCReport 0xdd0 +#define rOFDM_RxSNR 0xdd4 +#define rOFDM_RxEVMCSI 0xdd8 +#define rOFDM_SIGReport 0xddc + +#define rTxAGC_Rate18_06 0xe00 +#define rTxAGC_Rate54_24 0xe04 +#define rTxAGC_CCK_Mcs32 0xe08 +#define rTxAGC_Mcs03_Mcs00 0xe10 +#define rTxAGC_Mcs07_Mcs04 0xe14 +#define rTxAGC_Mcs11_Mcs08 0xe18 +#define rTxAGC_Mcs15_Mcs12 0xe1c + + +#define rZebra1_HSSIEnable 0x0 +#define rZebra1_TRxEnable1 0x1 +#define rZebra1_TRxEnable2 0x2 +#define rZebra1_AGC 0x4 +#define rZebra1_ChargePump 0x5 +#define rZebra1_Channel 0x7 +#define rZebra1_TxGain 0x8 +#define rZebra1_TxLPF 0x9 +#define rZebra1_RxLPF 0xb +#define rZebra1_RxHPFCorner 0xc + +#define rGlobalCtrl 0 +#define rRTL8256_TxLPF 19 +#define rRTL8256_RxLPF 11 + +#define rRTL8258_TxLPF 0x11 +#define rRTL8258_RxLPF 0x13 +#define rRTL8258_RSSILPF 0xa + +#define bBBResetB 0x100 +#define bGlobalResetB 0x200 +#define bOFDMTxStart 0x4 +#define bCCKTxStart 0x8 +#define bCRC32Debug 0x100 +#define bPMACLoopback 0x10 +#define bTxLSIG 0xffffff +#define bOFDMTxRate 0xf +#define bOFDMTxReserved 0x10 +#define bOFDMTxLength 0x1ffe0 +#define bOFDMTxParity 0x20000 +#define bTxHTSIG1 0xffffff +#define bTxHTMCSRate 0x7f +#define bTxHTBW 0x80 +#define bTxHTLength 0xffff00 +#define bTxHTSIG2 0xffffff +#define bTxHTSmoothing 0x1 +#define bTxHTSounding 0x2 +#define bTxHTReserved 0x4 +#define bTxHTAggreation 0x8 +#define bTxHTSTBC 0x30 +#define bTxHTAdvanceCoding 0x40 +#define bTxHTShortGI 0x80 +#define bTxHTNumberHT_LTF 0x300 +#define bTxHTCRC8 0x3fc00 +#define bCounterReset 0x10000 +#define bNumOfOFDMTx 0xffff +#define bNumOfCCKTx 0xffff0000 +#define bTxIdleInterval 0xffff +#define bOFDMService 0xffff0000 +#define bTxMACHeader 0xffffffff +#define bTxDataInit 0xff +#define bTxHTMode 0x100 +#define bTxDataType 0x30000 +#define bTxRandomSeed 0xffffffff +#define bCCKTxPreamble 0x1 +#define bCCKTxSFD 0xffff0000 +#define bCCKTxSIG 0xff +#define bCCKTxService 0xff00 +#define bCCKLengthExt 0x8000 +#define bCCKTxLength 0xffff0000 +#define bCCKTxCRC16 0xffff +#define bCCKTxStatus 0x1 +#define bOFDMTxStatus 0x2 + +#define bRFMOD 0x1 +#define bJapanMode 0x2 +#define bCCKTxSC 0x30 +#define bCCKEn 0x1000000 +#define bOFDMEn 0x2000000 +#define bOFDMRxADCPhase 0x10000 +#define bOFDMTxDACPhase 0x40000 +#define bXATxAGC 0x3f +#define bXBTxAGC 0xf00 +#define bXCTxAGC 0xf000 +#define bXDTxAGC 0xf0000 +#define bPAStart 0xf0000000 +#define bTRStart 0x00f00000 +#define bRFStart 0x0000f000 +#define bBBStart 0x000000f0 +#define bBBCCKStart 0x0000000f +#define bPAEnd 0xf +#define bTREnd 0x0f000000 +#define bRFEnd 0x000f0000 +#define bCCAMask 0x000000f0 +#define bR2RCCAMask 0x00000f00 +#define bHSSI_R2TDelay 0xf8000000 +#define bHSSI_T2RDelay 0xf80000 +#define bContTxHSSI 0x400 +#define bIGFromCCK 0x200 +#define bAGCAddress 0x3f +#define bRxHPTx 0x7000 +#define bRxHPT2R 0x38000 +#define bRxHPCCKIni 0xc0000 +#define bAGCTxCode 0xc00000 +#define bAGCRxCode 0x300000 +#define b3WireDataLength 0x800 +#define b3WireAddressLength 0x400 +#define b3WireRFPowerDown 0x1 +#define b5GPAPEPolarity 0x40000000 +#define b2GPAPEPolarity 0x80000000 +#define bRFSW_TxDefaultAnt 0x3 +#define bRFSW_TxOptionAnt 0x30 +#define bRFSW_RxDefaultAnt 0x300 +#define bRFSW_RxOptionAnt 0x3000 +#define bRFSI_3WireData 0x1 +#define bRFSI_3WireClock 0x2 +#define bRFSI_3WireLoad 0x4 +#define bRFSI_3WireRW 0x8 +#define bRFSI_3Wire 0xf +#define bRFSI_RFENV 0x10 +#define bRFSI_TRSW 0x20 +#define bRFSI_TRSWB 0x40 +#define bRFSI_ANTSW 0x100 +#define bRFSI_ANTSWB 0x200 +#define bRFSI_PAPE 0x400 +#define bRFSI_PAPE5G 0x800 +#define bBandSelect 0x1 +#define bHTSIG2_GI 0x80 +#define bHTSIG2_Smoothing 0x01 +#define bHTSIG2_Sounding 0x02 +#define bHTSIG2_Aggreaton 0x08 +#define bHTSIG2_STBC 0x30 +#define bHTSIG2_AdvCoding 0x40 +#define bHTSIG2_NumOfHTLTF 0x300 +#define bHTSIG2_CRC8 0x3fc +#define bHTSIG1_MCS 0x7f +#define bHTSIG1_BandWidth 0x80 +#define bHTSIG1_HTLength 0xffff +#define bLSIG_Rate 0xf +#define bLSIG_Reserved 0x10 +#define bLSIG_Length 0x1fffe +#define bLSIG_Parity 0x20 +#define bCCKRxPhase 0x4 +#define bLSSIReadAddress 0x3f000000 +#define bLSSIReadEdge 0x80000000 +#define bLSSIReadBackData 0xfff +#define bLSSIReadOKFlag 0x1000 +#define bCCKSampleRate 0x8 + +#define bRegulator0Standby 0x1 +#define bRegulatorPLLStandby 0x2 +#define bRegulator1Standby 0x4 +#define bPLLPowerUp 0x8 +#define bDPLLPowerUp 0x10 +#define bDA10PowerUp 0x20 +#define bAD7PowerUp 0x200 +#define bDA6PowerUp 0x2000 +#define bXtalPowerUp 0x4000 +#define b40MDClkPowerUP 0x8000 +#define bDA6DebugMode 0x20000 +#define bDA6Swing 0x380000 +#define bADClkPhase 0x4000000 +#define b80MClkDelay 0x18000000 +#define bAFEWatchDogEnable 0x20000000 +#define bXtalCap 0x0f000000 +#define bXtalCap01 0xc0000000 +#define bXtalCap23 0x3 +#define bXtalCap92x 0x0f000000 +#define bIntDifClkEnable 0x400 +#define bExtSigClkEnable 0x800 +#define bBandgapMbiasPowerUp 0x10000 +#define bAD11SHGain 0xc0000 +#define bAD11InputRange 0x700000 +#define bAD11OPCurrent 0x3800000 +#define bIPathLoopback 0x4000000 +#define bQPathLoopback 0x8000000 +#define bAFELoopback 0x10000000 +#define bDA10Swing 0x7e0 +#define bDA10Reverse 0x800 +#define bDAClkSource 0x1000 +#define bAD7InputRange 0x6000 +#define bAD7Gain 0x38000 +#define bAD7OutputCMMode 0x40000 +#define bAD7InputCMMode 0x380000 +#define bAD7Current 0xc00000 +#define bRegulatorAdjust 0x7000000 +#define bAD11PowerUpAtTx 0x1 +#define bDA10PSAtTx 0x10 +#define bAD11PowerUpAtRx 0x100 +#define bDA10PSAtRx 0x1000 + +#define bCCKRxAGCFormat 0x200 + +#define bPSDFFTSamplepPoint 0xc000 +#define bPSDAverageNum 0x3000 +#define bIQPathControl 0xc00 +#define bPSDFreq 0x3ff +#define bPSDAntennaPath 0x30 +#define bPSDIQSwitch 0x40 +#define bPSDRxTrigger 0x400000 +#define bPSDTxTrigger 0x80000000 +#define bPSDSineToneScale 0x7f000000 +#define bPSDReport 0xffff + +#define bOFDMTxSC 0x30000000 +#define bCCKTxOn 0x1 +#define bOFDMTxOn 0x2 +#define bDebugPage 0xfff +#define bDebugItem 0xff +#define bAntL 0x10 +#define bAntNonHT 0x100 +#define bAntHT1 0x1000 +#define bAntHT2 0x10000 +#define bAntHT1S1 0x100000 +#define bAntNonHTS1 0x1000000 + +#define bCCKBBMode 0x3 +#define bCCKTxPowerSaving 0x80 +#define bCCKRxPowerSaving 0x40 +#define bCCKSideBand 0x10 +#define bCCKScramble 0x8 +#define bCCKAntDiversity 0x8000 +#define bCCKCarrierRecovery 0x4000 +#define bCCKTxRate 0x3000 +#define bCCKDCCancel 0x0800 +#define bCCKISICancel 0x0400 +#define bCCKMatchFilter 0x0200 +#define bCCKEqualizer 0x0100 +#define bCCKPreambleDetect 0x800000 +#define bCCKFastFalseCCA 0x400000 +#define bCCKChEstStart 0x300000 +#define bCCKCCACount 0x080000 +#define bCCKcs_lim 0x070000 +#define bCCKBistMode 0x80000000 +#define bCCKCCAMask 0x40000000 +#define bCCKTxDACPhase 0x4 +#define bCCKRxADCPhase 0x20000000 +#define bCCKr_cp_mode0 0x0100 +#define bCCKTxDCOffset 0xf0 +#define bCCKRxDCOffset 0xf +#define bCCKCCAMode 0xc000 +#define bCCKFalseCS_lim 0x3f00 +#define bCCKCS_ratio 0xc00000 +#define bCCKCorgBit_sel 0x300000 +#define bCCKPD_lim 0x0f0000 +#define bCCKNewCCA 0x80000000 +#define bCCKRxHPofIG 0x8000 +#define bCCKRxIG 0x7f00 +#define bCCKLNAPolarity 0x800000 +#define bCCKRx1stGain 0x7f0000 +#define bCCKRFExtend 0x20000000 +#define bCCKRxAGCSatLevel 0x1f000000 +#define bCCKRxAGCSatCount 0xe0 +#define bCCKRxRFSettle 0x1f +#define bCCKFixedRxAGC 0x8000 +#define bCCKAntennaPolarity 0x2000 +#define bCCKTxFilterType 0x0c00 +#define bCCKRxAGCReportType 0x0300 +#define bCCKRxDAGCEn 0x80000000 +#define bCCKRxDAGCPeriod 0x20000000 +#define bCCKRxDAGCSatLevel 0x1f000000 +#define bCCKTimingRecovery 0x800000 +#define bCCKTxC0 0x3f0000 +#define bCCKTxC1 0x3f000000 +#define bCCKTxC2 0x3f +#define bCCKTxC3 0x3f00 +#define bCCKTxC4 0x3f0000 +#define bCCKTxC5 0x3f000000 +#define bCCKTxC6 0x3f +#define bCCKTxC7 0x3f00 +#define bCCKDebugPort 0xff0000 +#define bCCKDACDebug 0x0f000000 +#define bCCKFalseAlarmEnable 0x8000 +#define bCCKFalseAlarmRead 0x4000 +#define bCCKTRSSI 0x7f +#define bCCKRxAGCReport 0xfe +#define bCCKRxReport_AntSel 0x80000000 +#define bCCKRxReport_MFOff 0x40000000 +#define bCCKRxRxReport_SQLoss 0x20000000 +#define bCCKRxReport_Pktloss 0x10000000 +#define bCCKRxReport_Lockedbit 0x08000000 +#define bCCKRxReport_RateError 0x04000000 +#define bCCKRxReport_RxRate 0x03000000 +#define bCCKRxFACounterLower 0xff +#define bCCKRxFACounterUpper 0xff000000 +#define bCCKRxHPAGCStart 0xe000 +#define bCCKRxHPAGCFinal 0x1c00 + +#define bCCKRxFalseAlarmEnable 0x8000 +#define bCCKFACounterFreeze 0x4000 + +#define bCCKTxPathSel 0x10000000 +#define bCCKDefaultRxPath 0xc000000 +#define bCCKOptionRxPath 0x3000000 + +#define bNumOfSTF 0x3 +#define bShift_L 0xc0 +#define bGI_TH 0xc +#define bRxPathA 0x1 +#define bRxPathB 0x2 +#define bRxPathC 0x4 +#define bRxPathD 0x8 +#define bTxPathA 0x1 +#define bTxPathB 0x2 +#define bTxPathC 0x4 +#define bTxPathD 0x8 +#define bTRSSIFreq 0x200 +#define bADCBackoff 0x3000 +#define bDFIRBackoff 0xc000 +#define bTRSSILatchPhase 0x10000 +#define bRxIDCOffset 0xff +#define bRxQDCOffset 0xff00 +#define bRxDFIRMode 0x1800000 +#define bRxDCNFType 0xe000000 +#define bRXIQImb_A 0x3ff +#define bRXIQImb_B 0xfc00 +#define bRXIQImb_C 0x3f0000 +#define bRXIQImb_D 0xffc00000 +#define bDC_dc_Notch 0x60000 +#define bRxNBINotch 0x1f000000 +#define bPD_TH 0xf +#define bPD_TH_Opt2 0xc000 +#define bPWED_TH 0x700 +#define bIfMF_Win_L 0x800 +#define bPD_Option 0x1000 +#define bMF_Win_L 0xe000 +#define bBW_Search_L 0x30000 +#define bwin_enh_L 0xc0000 +#define bBW_TH 0x700000 +#define bED_TH2 0x3800000 +#define bBW_option 0x4000000 +#define bRatio_TH 0x18000000 +#define bWindow_L 0xe0000000 +#define bSBD_Option 0x1 +#define bFrame_TH 0x1c +#define bFS_Option 0x60 +#define bDC_Slope_check 0x80 +#define bFGuard_Counter_DC_L 0xe00 +#define bFrame_Weight_Short 0x7000 +#define bSub_Tune 0xe00000 +#define bFrame_DC_Length 0xe000000 +#define bSBD_start_offset 0x30000000 +#define bFrame_TH_2 0x7 +#define bFrame_GI2_TH 0x38 +#define bGI2_Sync_en 0x40 +#define bSarch_Short_Early 0x300 +#define bSarch_Short_Late 0xc00 +#define bSarch_GI2_Late 0x70000 +#define bCFOAntSum 0x1 +#define bCFOAcc 0x2 +#define bCFOStartOffset 0xc +#define bCFOLookBack 0x70 +#define bCFOSumWeight 0x80 +#define bDAGCEnable 0x10000 +#define bTXIQImb_A 0x3ff +#define bTXIQImb_B 0xfc00 +#define bTXIQImb_C 0x3f0000 +#define bTXIQImb_D 0xffc00000 +#define bTxIDCOffset 0xff +#define bTxQDCOffset 0xff00 +#define bTxDFIRMode 0x10000 +#define bTxPesudoNoiseOn 0x4000000 +#define bTxPesudoNoise_A 0xff +#define bTxPesudoNoise_B 0xff00 +#define bTxPesudoNoise_C 0xff0000 +#define bTxPesudoNoise_D 0xff000000 +#define bCCADropOption 0x20000 +#define bCCADropThres 0xfff00000 +#define bEDCCA_H 0xf +#define bEDCCA_L 0xf0 +#define bLambda_ED 0x300 +#define bRxInitialGain 0x7f +#define bRxAntDivEn 0x80 +#define bRxAGCAddressForLNA 0x7f00 +#define bRxHighPowerFlow 0x8000 +#define bRxAGCFreezeThres 0xc0000 +#define bRxFreezeStep_AGC1 0x300000 +#define bRxFreezeStep_AGC2 0xc00000 +#define bRxFreezeStep_AGC3 0x3000000 +#define bRxFreezeStep_AGC0 0xc000000 +#define bRxRssi_Cmp_En 0x10000000 +#define bRxQuickAGCEn 0x20000000 +#define bRxAGCFreezeThresMode 0x40000000 +#define bRxOverFlowCheckType 0x80000000 +#define bRxAGCShift 0x7f +#define bTRSW_Tri_Only 0x80 +#define bPowerThres 0x300 +#define bRxAGCEn 0x1 +#define bRxAGCTogetherEn 0x2 +#define bRxAGCMin 0x4 +#define bRxHP_Ini 0x7 +#define bRxHP_TRLNA 0x70 +#define bRxHP_RSSI 0x700 +#define bRxHP_BBP1 0x7000 +#define bRxHP_BBP2 0x70000 +#define bRxHP_BBP3 0x700000 +#define bRSSI_H 0x7f0000 +#define bRSSI_Gen 0x7f000000 +#define bRxSettle_TRSW 0x7 +#define bRxSettle_LNA 0x38 +#define bRxSettle_RSSI 0x1c0 +#define bRxSettle_BBP 0xe00 +#define bRxSettle_RxHP 0x7000 +#define bRxSettle_AntSW_RSSI 0x38000 +#define bRxSettle_AntSW 0xc0000 +#define bRxProcessTime_DAGC 0x300000 +#define bRxSettle_HSSI 0x400000 +#define bRxProcessTime_BBPPW 0x800000 +#define bRxAntennaPowerShift 0x3000000 +#define bRSSITableSelect 0xc000000 +#define bRxHP_Final 0x7000000 +#define bRxHTSettle_BBP 0x7 +#define bRxHTSettle_HSSI 0x8 +#define bRxHTSettle_RxHP 0x70 +#define bRxHTSettle_BBPPW 0x80 +#define bRxHTSettle_Idle 0x300 +#define bRxHTSettle_Reserved 0x1c00 +#define bRxHTRxHPEn 0x8000 +#define bRxHTAGCFreezeThres 0x30000 +#define bRxHTAGCTogetherEn 0x40000 +#define bRxHTAGCMin 0x80000 +#define bRxHTAGCEn 0x100000 +#define bRxHTDAGCEn 0x200000 +#define bRxHTRxHP_BBP 0x1c00000 +#define bRxHTRxHP_Final 0xe0000000 +#define bRxPWRatioTH 0x3 +#define bRxPWRatioEn 0x4 +#define bRxMFHold 0x3800 +#define bRxPD_Delay_TH1 0x38 +#define bRxPD_Delay_TH2 0x1c0 +#define bRxPD_DC_COUNT_MAX 0x600 +#define bRxPD_Delay_TH 0x8000 +#define bRxProcess_Delay 0xf0000 +#define bRxSearchrange_GI2_Early 0x700000 +#define bRxFrame_Guard_Counter_L 0x3800000 +#define bRxSGI_Guard_L 0xc000000 +#define bRxSGI_Search_L 0x30000000 +#define bRxSGI_TH 0xc0000000 +#define bDFSCnt0 0xff +#define bDFSCnt1 0xff00 +#define bDFSFlag 0xf0000 + +#define bMFWeightSum 0x300000 +#define bMinIdxTH 0x7f000000 + +#define bDAFormat 0x40000 + +#define bTxChEmuEnable 0x01000000 + +#define bTRSWIsolation_A 0x7f +#define bTRSWIsolation_B 0x7f00 +#define bTRSWIsolation_C 0x7f0000 +#define bTRSWIsolation_D 0x7f000000 + +#define bExtLNAGain 0x7c00 + +#define bSTBCEn 0x4 +#define bAntennaMapping 0x10 +#define bNss 0x20 +#define bCFOAntSumD 0x200 +#define bPHYCounterReset 0x8000000 +#define bCFOReportGet 0x4000000 +#define bOFDMContinueTx 0x10000000 +#define bOFDMSingleCarrier 0x20000000 +#define bOFDMSingleTone 0x40000000 +#define bHTDetect 0x100 +#define bCFOEn 0x10000 +#define bCFOValue 0xfff00000 +#define bSigTone_Re 0x3f +#define bSigTone_Im 0x7f00 +#define bCounter_CCA 0xffff +#define bCounter_ParityFail 0xffff0000 +#define bCounter_RateIllegal 0xffff +#define bCounter_CRC8Fail 0xffff0000 +#define bCounter_MCSNoSupport 0xffff +#define bCounter_FastSync 0xffff +#define bShortCFO 0xfff +#define bShortCFOTLength 12 +#define bShortCFOFLength 11 +#define bLongCFO 0x7ff +#define bLongCFOTLength 11 +#define bLongCFOFLength 11 +#define bTailCFO 0x1fff +#define bTailCFOTLength 13 +#define bTailCFOFLength 12 + +#define bmax_en_pwdB 0xffff +#define bCC_power_dB 0xffff0000 +#define bnoise_pwdB 0xffff +#define bPowerMeasTLength 10 +#define bPowerMeasFLength 3 +#define bRx_HT_BW 0x1 +#define bRxSC 0x6 +#define bRx_HT 0x8 + +#define bNB_intf_det_on 0x1 +#define bIntf_win_len_cfg 0x30 +#define bNB_Intf_TH_cfg 0x1c0 + +#define bRFGain 0x3f +#define bTableSel 0x40 +#define bTRSW 0x80 + +#define bRxSNR_A 0xff +#define bRxSNR_B 0xff00 +#define bRxSNR_C 0xff0000 +#define bRxSNR_D 0xff000000 +#define bSNREVMTLength 8 +#define bSNREVMFLength 1 + +#define bCSI1st 0xff +#define bCSI2nd 0xff00 +#define bRxEVM1st 0xff0000 +#define bRxEVM2nd 0xff000000 + +#define bSIGEVM 0xff +#define bPWDB 0xff00 +#define bSGIEN 0x10000 + +#define bSFactorQAM1 0xf +#define bSFactorQAM2 0xf0 +#define bSFactorQAM3 0xf00 +#define bSFactorQAM4 0xf000 +#define bSFactorQAM5 0xf0000 +#define bSFactorQAM6 0xf0000 +#define bSFactorQAM7 0xf00000 +#define bSFactorQAM8 0xf000000 +#define bSFactorQAM9 0xf0000000 +#define bCSIScheme 0x100000 + +#define bNoiseLvlTopSet 0x3 +#define bChSmooth 0x4 +#define bChSmoothCfg1 0x38 +#define bChSmoothCfg2 0x1c0 +#define bChSmoothCfg3 0xe00 +#define bChSmoothCfg4 0x7000 +#define bMRCMode 0x800000 +#define bTHEVMCfg 0x7000000 + +#define bLoopFitType 0x1 +#define bUpdCFO 0x40 +#define bUpdCFOOffData 0x80 +#define bAdvUpdCFO 0x100 +#define bAdvTimeCtrl 0x800 +#define bUpdClko 0x1000 +#define bFC 0x6000 +#define bTrackingMode 0x8000 +#define bPhCmpEnable 0x10000 +#define bUpdClkoLTF 0x20000 +#define bComChCFO 0x40000 +#define bCSIEstiMode 0x80000 +#define bAdvUpdEqz 0x100000 +#define bUChCfg 0x7000000 +#define bUpdEqz 0x8000000 + +#define bTxAGCRate18_06 0x7f7f7f7f +#define bTxAGCRate54_24 0x7f7f7f7f +#define bTxAGCRateMCS32 0x7f +#define bTxAGCRateCCK 0x7f00 +#define bTxAGCRateMCS3_MCS0 0x7f7f7f7f +#define bTxAGCRateMCS7_MCS4 0x7f7f7f7f +#define bTxAGCRateMCS11_MCS8 0x7f7f7f7f +#define bTxAGCRateMCS15_MCS12 0x7f7f7f7f + + +#define bRxPesudoNoiseOn 0x20000000 +#define bRxPesudoNoise_A 0xff +#define bRxPesudoNoise_B 0xff00 +#define bRxPesudoNoise_C 0xff0000 +#define bRxPesudoNoise_D 0xff000000 +#define bPesudoNoiseState_A 0xffff +#define bPesudoNoiseState_B 0xffff0000 +#define bPesudoNoiseState_C 0xffff +#define bPesudoNoiseState_D 0xffff0000 + +#define bZebra1_HSSIEnable 0x8 +#define bZebra1_TRxControl 0xc00 +#define bZebra1_TRxGainSetting 0x07f +#define bZebra1_RxCorner 0xc00 +#define bZebra1_TxChargePump 0x38 +#define bZebra1_RxChargePump 0x7 +#define bZebra1_ChannelNum 0xf80 +#define bZebra1_TxLPFBW 0x400 +#define bZebra1_RxLPFBW 0x600 + +#define bRTL8256RegModeCtrl1 0x100 +#define bRTL8256RegModeCtrl0 0x40 +#define bRTL8256_TxLPFBW 0x18 +#define bRTL8256_RxLPFBW 0x600 + +#define bRTL8258_TxLPFBW 0xc +#define bRTL8258_RxLPFBW 0xc00 +#define bRTL8258_RSSILPFBW 0xc0 + +#define bByte0 0x1 +#define bByte1 0x2 +#define bByte2 0x4 +#define bByte3 0x8 +#define bWord0 0x3 +#define bWord1 0xc +#define bDWord 0xf + +#define bMaskByte0 0xff +#define bMaskByte1 0xff00 +#define bMaskByte2 0xff0000 +#define bMaskByte3 0xff000000 +#define bMaskHWord 0xffff0000 +#define bMaskLWord 0x0000ffff +#define bMaskDWord 0xffffffff + +#define bMask12Bits 0xfff + +#define bEnable 0x1 +#define bDisable 0x0 + +#define LeftAntenna 0x0 +#define RightAntenna 0x1 + +#define tCheckTxStatus 500 +#define tUpdateRxCounter 100 + +#define rateCCK 0 +#define rateOFDM 1 +#define rateHT 2 + +#define bPMAC_End 0x1ff +#define bFPGAPHY0_End 0x8ff +#define bFPGAPHY1_End 0x9ff +#define bCCKPHY0_End 0xaff +#define bOFDMPHY0_End 0xcff +#define bOFDMPHY1_End 0xdff + + +#define bPMACControl 0x0 +#define bWMACControl 0x1 +#define bWNICControl 0x2 + +#define PathA 0x0 +#define PathB 0x1 +#define PathC 0x2 +#define PathD 0x3 + +#define rRTL8256RxMixerPole 0xb +#define bZebraRxMixerPole 0x6 +#define rRTL8256TxBBOPBias 0x9 +#define bRTL8256TxBBOPBias 0x400 +#define rRTL8256TxBBBW 19 +#define bRTL8256TxBBBW 0x18 + +#endif diff --git a/kernel/drivers/staging/rtl8192e/rtl8192e/r819xE_phyreg.h b/kernel/drivers/staging/rtl8192e/rtl8192e/r819xE_phyreg.h new file mode 100644 index 000000000..03eee3d05 --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl8192e/r819xE_phyreg.h @@ -0,0 +1,908 @@ +#ifndef _R819XU_PHYREG_H +#define _R819XU_PHYREG_H + + +#define RF_DATA 0x1d4 // FW will write RF data in the register. + +//Register //duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF +//page 1 +#define rPMAC_Reset 0x100 +#define rPMAC_TxStart 0x104 +#define rPMAC_TxLegacySIG 0x108 +#define rPMAC_TxHTSIG1 0x10c +#define rPMAC_TxHTSIG2 0x110 +#define rPMAC_PHYDebug 0x114 +#define rPMAC_TxPacketNum 0x118 +#define rPMAC_TxIdle 0x11c +#define rPMAC_TxMACHeader0 0x120 +#define rPMAC_TxMACHeader1 0x124 +#define rPMAC_TxMACHeader2 0x128 +#define rPMAC_TxMACHeader3 0x12c +#define rPMAC_TxMACHeader4 0x130 +#define rPMAC_TxMACHeader5 0x134 +#define rPMAC_TxDataType 0x138 +#define rPMAC_TxRandomSeed 0x13c +#define rPMAC_CCKPLCPPreamble 0x140 +#define rPMAC_CCKPLCPHeader 0x144 +#define rPMAC_CCKCRC16 0x148 +#define rPMAC_OFDMRxCRC32OK 0x170 +#define rPMAC_OFDMRxCRC32Er 0x174 +#define rPMAC_OFDMRxParityEr 0x178 +#define rPMAC_OFDMRxCRC8Er 0x17c +#define rPMAC_CCKCRxRC16Er 0x180 +#define rPMAC_CCKCRxRC32Er 0x184 +#define rPMAC_CCKCRxRC32OK 0x188 +#define rPMAC_TxStatus 0x18c + +//90P +#define MCS_TXAGC 0x340 // MCS AGC +#define CCK_TXAGC 0x348 // CCK AGC + +#define MacBlkCtrl 0x403 // Mac block on/off control register + +//page8 +#define rFPGA0_RFMOD 0x800 //RF mode & CCK TxSC +#define rFPGA0_TxInfo 0x804 +#define rFPGA0_PSDFunction 0x808 +#define rFPGA0_TxGainStage 0x80c +#define rFPGA0_RFTiming1 0x810 +#define rFPGA0_RFTiming2 0x814 +//#define rFPGA0_XC_RFTiming 0x818 +//#define rFPGA0_XD_RFTiming 0x81c +#define rFPGA0_XA_HSSIParameter1 0x820 +#define rFPGA0_XA_HSSIParameter2 0x824 +#define rFPGA0_XB_HSSIParameter1 0x828 +#define rFPGA0_XB_HSSIParameter2 0x82c +#define rFPGA0_XC_HSSIParameter1 0x830 +#define rFPGA0_XC_HSSIParameter2 0x834 +#define rFPGA0_XD_HSSIParameter1 0x838 +#define rFPGA0_XD_HSSIParameter2 0x83c +#define rFPGA0_XA_LSSIParameter 0x840 +#define rFPGA0_XB_LSSIParameter 0x844 +#define rFPGA0_XC_LSSIParameter 0x848 +#define rFPGA0_XD_LSSIParameter 0x84c +#define rFPGA0_RFWakeUpParameter 0x850 +#define rFPGA0_RFSleepUpParameter 0x854 +#define rFPGA0_XAB_SwitchControl 0x858 +#define rFPGA0_XCD_SwitchControl 0x85c +#define rFPGA0_XA_RFInterfaceOE 0x860 +#define rFPGA0_XB_RFInterfaceOE 0x864 +#define rFPGA0_XC_RFInterfaceOE 0x868 +#define rFPGA0_XD_RFInterfaceOE 0x86c +#define rFPGA0_XAB_RFInterfaceSW 0x870 +#define rFPGA0_XCD_RFInterfaceSW 0x874 +#define rFPGA0_XAB_RFParameter 0x878 +#define rFPGA0_XCD_RFParameter 0x87c +#define rFPGA0_AnalogParameter1 0x880 +#define rFPGA0_AnalogParameter2 0x884 +#define rFPGA0_AnalogParameter3 0x888 +#define rFPGA0_AnalogParameter4 0x88c +#define rFPGA0_XA_LSSIReadBack 0x8a0 +#define rFPGA0_XB_LSSIReadBack 0x8a4 +#define rFPGA0_XC_LSSIReadBack 0x8a8 +#define rFPGA0_XD_LSSIReadBack 0x8ac +#define rFPGA0_PSDReport 0x8b4 +#define rFPGA0_XAB_RFInterfaceRB 0x8e0 +#define rFPGA0_XCD_RFInterfaceRB 0x8e4 + +/* Page 9 - RF mode & OFDM TxSC */ +#define rFPGA1_RFMOD 0x900 +#define rFPGA1_TxBlock 0x904 +#define rFPGA1_DebugSelect 0x908 +#define rFPGA1_TxInfo 0x90c + +/* Page a */ +#define rCCK0_System 0xa00 +#define rCCK0_AFESetting 0xa04 +#define rCCK0_CCA 0xa08 +/* AGC default value, saturation level */ +#define rCCK0_RxAGC1 0xa0c +/* AGC & DAGC */ +#define rCCK0_RxAGC2 0xa10 +#define rCCK0_RxHP 0xa14 +/* Timing recovery & channel estimation threshold */ +#define rCCK0_DSPParameter1 0xa18 +/* SQ threshold */ +#define rCCK0_DSPParameter2 0xa1c +#define rCCK0_TxFilter1 0xa20 +#define rCCK0_TxFilter2 0xa24 +/* Debug port and TX filter 3 */ +#define rCCK0_DebugPort 0xa28 +#define rCCK0_FalseAlarmReport 0xa2c +#define rCCK0_TRSSIReport 0xa50 +#define rCCK0_RxReport 0xa54 +#define rCCK0_FACounterLower 0xa5c +#define rCCK0_FACounterUpper 0xa58 + +/* Page c */ +#define rOFDM0_LSTF 0xc00 +#define rOFDM0_TRxPathEnable 0xc04 +#define rOFDM0_TRMuxPar 0xc08 +#define rOFDM0_TRSWIsolation 0xc0c +/* RxIQ DC offset, Rx digital filter, DC notch filter */ +#define rOFDM0_XARxAFE 0xc10 +/* RxIQ imblance matrix */ +#define rOFDM0_XARxIQImbalance 0xc14 +#define rOFDM0_XBRxAFE 0xc18 +#define rOFDM0_XBRxIQImbalance 0xc1c +#define rOFDM0_XCRxAFE 0xc20 +#define rOFDM0_XCRxIQImbalance 0xc24 +#define rOFDM0_XDRxAFE 0xc28 +#define rOFDM0_XDRxIQImbalance 0xc2c +/* PD, BW & SBD */ +#define rOFDM0_RxDetector1 0xc30 +/* SBD */ +#define rOFDM0_RxDetector2 0xc34 +/* Frame Sync */ +#define rOFDM0_RxDetector3 0xc38 +/* PD, SBD, Frame Sync & Short-GI */ +#define rOFDM0_RxDetector4 0xc3c +/* Rx Sync Path */ +#define rOFDM0_RxDSP 0xc40 +/* CFO & DAGC */ +#define rOFDM0_CFOandDAGC 0xc44 +/* CCA Drop threshold */ +#define rOFDM0_CCADropThreshold 0xc48 +/* Energy CCA */ +#define rOFDM0_ECCAThreshold 0xc4c +#define rOFDM0_XAAGCCore1 0xc50 +#define rOFDM0_XAAGCCore2 0xc54 +#define rOFDM0_XBAGCCore1 0xc58 +#define rOFDM0_XBAGCCore2 0xc5c +#define rOFDM0_XCAGCCore1 0xc60 +#define rOFDM0_XCAGCCore2 0xc64 +#define rOFDM0_XDAGCCore1 0xc68 +#define rOFDM0_XDAGCCore2 0xc6c +#define rOFDM0_AGCParameter1 0xc70 +#define rOFDM0_AGCParameter2 0xc74 +#define rOFDM0_AGCRSSITable 0xc78 +#define rOFDM0_HTSTFAGC 0xc7c +#define rOFDM0_XATxIQImbalance 0xc80 +#define rOFDM0_XATxAFE 0xc84 +#define rOFDM0_XBTxIQImbalance 0xc88 +#define rOFDM0_XBTxAFE 0xc8c +#define rOFDM0_XCTxIQImbalance 0xc90 +#define rOFDM0_XCTxAFE 0xc94 +#define rOFDM0_XDTxIQImbalance 0xc98 +#define rOFDM0_XDTxAFE 0xc9c +#define rOFDM0_RxHPParameter 0xce0 +#define rOFDM0_TxPseudoNoiseWgt 0xce4 +#define rOFDM0_FrameSync 0xcf0 +#define rOFDM0_DFSReport 0xcf4 +#define rOFDM0_TxCoeff1 0xca4 +#define rOFDM0_TxCoeff2 0xca8 +#define rOFDM0_TxCoeff3 0xcac +#define rOFDM0_TxCoeff4 0xcb0 +#define rOFDM0_TxCoeff5 0xcb4 +#define rOFDM0_TxCoeff6 0xcb8 + + +/* Page d */ +#define rOFDM1_LSTF 0xd00 +#define rOFDM1_TRxPathEnable 0xd04 +#define rOFDM1_CFO 0xd08 +#define rOFDM1_CSI1 0xd10 +#define rOFDM1_SBD 0xd14 +#define rOFDM1_CSI2 0xd18 +#define rOFDM1_CFOTracking 0xd2c +#define rOFDM1_TRxMesaure1 0xd34 +#define rOFDM1_IntfDet 0xd3c +#define rOFDM1_PseudoNoiseStateAB 0xd50 +#define rOFDM1_PseudoNoiseStateCD 0xd54 +#define rOFDM1_RxPseudoNoiseWgt 0xd58 +/* cca, parity fail */ +#define rOFDM_PHYCounter1 0xda0 +/* rate illegal, crc8 fail */ +#define rOFDM_PHYCounter2 0xda4 +/* MCS not supported */ +#define rOFDM_PHYCounter3 0xda8 +#define rOFDM_ShortCFOAB 0xdac +#define rOFDM_ShortCFOCD 0xdb0 +#define rOFDM_LongCFOAB 0xdb4 +#define rOFDM_LongCFOCD 0xdb8 +#define rOFDM_TailCFOAB 0xdbc +#define rOFDM_TailCFOCD 0xdc0 +#define rOFDM_PWMeasure1 0xdc4 +#define rOFDM_PWMeasure2 0xdc8 +#define rOFDM_BWReport 0xdcc +#define rOFDM_AGCReport 0xdd0 +#define rOFDM_RxSNR 0xdd4 +#define rOFDM_RxEVMCSI 0xdd8 +#define rOFDM_SIGReport 0xddc + +/* Page e */ +#define rTxAGC_Rate18_06 0xe00 +#define rTxAGC_Rate54_24 0xe04 +#define rTxAGC_CCK_Mcs32 0xe08 +#define rTxAGC_Mcs03_Mcs00 0xe10 +#define rTxAGC_Mcs07_Mcs04 0xe14 +#define rTxAGC_Mcs11_Mcs08 0xe18 +#define rTxAGC_Mcs15_Mcs12 0xe1c + + +/* RF Zebra 1 */ +#define rZebra1_HSSIEnable 0x0 +#define rZebra1_TRxEnable1 0x1 +#define rZebra1_TRxEnable2 0x2 +#define rZebra1_AGC 0x4 +#define rZebra1_ChargePump 0x5 +#define rZebra1_Channel 0x7 +#define rZebra1_TxGain 0x8 +#define rZebra1_TxLPF 0x9 +#define rZebra1_RxLPF 0xb +#define rZebra1_RxHPFCorner 0xc + +/* Zebra 4 */ +#define rGlobalCtrl 0 +#define rRTL8256_TxLPF 19 +#define rRTL8256_RxLPF 11 + +/* RTL8258 */ +#define rRTL8258_TxLPF 0x11 +#define rRTL8258_RxLPF 0x13 +#define rRTL8258_RSSILPF 0xa + +/* Bit Mask */ +/* Page 1 */ +#define bBBResetB 0x100 +#define bGlobalResetB 0x200 +#define bOFDMTxStart 0x4 +#define bCCKTxStart 0x8 +#define bCRC32Debug 0x100 +#define bPMACLoopback 0x10 +#define bTxLSIG 0xffffff +#define bOFDMTxRate 0xf +#define bOFDMTxReserved 0x10 +#define bOFDMTxLength 0x1ffe0 +#define bOFDMTxParity 0x20000 +#define bTxHTSIG1 0xffffff +#define bTxHTMCSRate 0x7f +#define bTxHTBW 0x80 +#define bTxHTLength 0xffff00 +#define bTxHTSIG2 0xffffff +#define bTxHTSmoothing 0x1 +#define bTxHTSounding 0x2 +#define bTxHTReserved 0x4 +#define bTxHTAggreation 0x8 +#define bTxHTSTBC 0x30 +#define bTxHTAdvanceCoding 0x40 +#define bTxHTShortGI 0x80 +#define bTxHTNumberHT_LTF 0x300 +#define bTxHTCRC8 0x3fc00 +#define bCounterReset 0x10000 +#define bNumOfOFDMTx 0xffff +#define bNumOfCCKTx 0xffff0000 +#define bTxIdleInterval 0xffff +#define bOFDMService 0xffff0000 +#define bTxMACHeader 0xffffffff +#define bTxDataInit 0xff +#define bTxHTMode 0x100 +#define bTxDataType 0x30000 +#define bTxRandomSeed 0xffffffff +#define bCCKTxPreamble 0x1 +#define bCCKTxSFD 0xffff0000 +#define bCCKTxSIG 0xff +#define bCCKTxService 0xff00 +#define bCCKLengthExt 0x8000 +#define bCCKTxLength 0xffff0000 +#define bCCKTxCRC16 0xffff +#define bCCKTxStatus 0x1 +#define bOFDMTxStatus 0x2 + +/* Page 8 */ +#define bRFMOD 0x1 +#define bJapanMode 0x2 +#define bCCKTxSC 0x30 +#define bCCKEn 0x1000000 +#define bOFDMEn 0x2000000 +#define bOFDMRxADCPhase 0x10000 +#define bOFDMTxDACPhase 0x40000 +#define bXATxAGC 0x3f +#define bXBTxAGC 0xf00 +#define bXCTxAGC 0xf000 +#define bXDTxAGC 0xf0000 +#define bPAStart 0xf0000000 +#define bTRStart 0x00f00000 +#define bRFStart 0x0000f000 +#define bBBStart 0x000000f0 +#define bBBCCKStart 0x0000000f +/* Reg x814 */ +#define bPAEnd 0xf +#define bTREnd 0x0f000000 +#define bRFEnd 0x000f0000 +/* T2R */ +#define bCCAMask 0x000000f0 +#define bR2RCCAMask 0x00000f00 +#define bHSSI_R2TDelay 0xf8000000 +#define bHSSI_T2RDelay 0xf80000 +/* Channel gain at continue TX. */ +#define bContTxHSSI 0x400 +#define bIGFromCCK 0x200 +#define bAGCAddress 0x3f +#define bRxHPTx 0x7000 +#define bRxHPT2R 0x38000 +#define bRxHPCCKIni 0xc0000 +#define bAGCTxCode 0xc00000 +#define bAGCRxCode 0x300000 +#define b3WireDataLength 0x800 +#define b3WireAddressLength 0x400 +#define b3WireRFPowerDown 0x1 +/*#define bHWSISelect 0x8 */ +#define b5GPAPEPolarity 0x40000000 +#define b2GPAPEPolarity 0x80000000 +#define bRFSW_TxDefaultAnt 0x3 +#define bRFSW_TxOptionAnt 0x30 +#define bRFSW_RxDefaultAnt 0x300 +#define bRFSW_RxOptionAnt 0x3000 +#define bRFSI_3WireData 0x1 +#define bRFSI_3WireClock 0x2 +#define bRFSI_3WireLoad 0x4 +#define bRFSI_3WireRW 0x8 +/* 3-wire total control */ +#define bRFSI_3Wire 0xf +#define bRFSI_RFENV 0x10 +#define bRFSI_TRSW 0x20 +#define bRFSI_TRSWB 0x40 +#define bRFSI_ANTSW 0x100 +#define bRFSI_ANTSWB 0x200 +#define bRFSI_PAPE 0x400 +#define bRFSI_PAPE5G 0x800 +#define bBandSelect 0x1 +#define bHTSIG2_GI 0x80 +#define bHTSIG2_Smoothing 0x01 +#define bHTSIG2_Sounding 0x02 +#define bHTSIG2_Aggreaton 0x08 +#define bHTSIG2_STBC 0x30 +#define bHTSIG2_AdvCoding 0x40 +#define bHTSIG2_NumOfHTLTF 0x300 +#define bHTSIG2_CRC8 0x3fc +#define bHTSIG1_MCS 0x7f +#define bHTSIG1_BandWidth 0x80 +#define bHTSIG1_HTLength 0xffff +#define bLSIG_Rate 0xf +#define bLSIG_Reserved 0x10 +#define bLSIG_Length 0x1fffe +#define bLSIG_Parity 0x20 +#define bCCKRxPhase 0x4 +/* LSSI "read" address */ +#define bLSSIReadAddress 0x3f000000 +/* LSSI "read" edge signal */ +#define bLSSIReadEdge 0x80000000 +#define bLSSIReadBackData 0xfff +#define bLSSIReadOKFlag 0x1000 +/* 0: 44 MHz, 1: 88MHz */ +#define bCCKSampleRate 0x8 + +#define bRegulator0Standby 0x1 +#define bRegulatorPLLStandby 0x2 +#define bRegulator1Standby 0x4 +#define bPLLPowerUp 0x8 +#define bDPLLPowerUp 0x10 +#define bDA10PowerUp 0x20 +#define bAD7PowerUp 0x200 +#define bDA6PowerUp 0x2000 +#define bXtalPowerUp 0x4000 +#define b40MDClkPowerUP 0x8000 +#define bDA6DebugMode 0x20000 +#define bDA6Swing 0x380000 +#define bADClkPhase 0x4000000 +#define b80MClkDelay 0x18000000 +#define bAFEWatchDogEnable 0x20000000 +#define bXtalCap 0x0f000000 +#define bXtalCap01 0xc0000000 +#define bXtalCap23 0x3 +#define bXtalCap92x 0x0f000000 +#define bIntDifClkEnable 0x400 +#define bExtSigClkEnable 0x800 +#define bBandgapMbiasPowerUp 0x10000 +#define bAD11SHGain 0xc0000 +#define bAD11InputRange 0x700000 +#define bAD11OPCurrent 0x3800000 +#define bIPathLoopback 0x4000000 +#define bQPathLoopback 0x8000000 +#define bAFELoopback 0x10000000 +#define bDA10Swing 0x7e0 +#define bDA10Reverse 0x800 +#define bDAClkSource 0x1000 +#define bAD7InputRange 0x6000 +#define bAD7Gain 0x38000 +#define bAD7OutputCMMode 0x40000 +#define bAD7InputCMMode 0x380000 +#define bAD7Current 0xc00000 +#define bRegulatorAdjust 0x7000000 +#define bAD11PowerUpAtTx 0x1 +#define bDA10PSAtTx 0x10 +#define bAD11PowerUpAtRx 0x100 +#define bDA10PSAtRx 0x1000 + +#define bCCKRxAGCFormat 0x200 + +#define bPSDFFTSamplepPoint 0xc000 +#define bPSDAverageNum 0x3000 +#define bIQPathControl 0xc00 +#define bPSDFreq 0x3ff +#define bPSDAntennaPath 0x30 +#define bPSDIQSwitch 0x40 +#define bPSDRxTrigger 0x400000 +#define bPSDTxTrigger 0x80000000 +#define bPSDSineToneScale 0x7f000000 +#define bPSDReport 0xffff + +/* Page 8 */ +#define bOFDMTxSC 0x30000000 +#define bCCKTxOn 0x1 +#define bOFDMTxOn 0x2 +/* Reset debug page and also HWord, LWord */ +#define bDebugPage 0xfff +/* Reset debug page and LWord */ +#define bDebugItem 0xff +#define bAntL 0x10 +#define bAntNonHT 0x100 +#define bAntHT1 0x1000 +#define bAntHT2 0x10000 +#define bAntHT1S1 0x100000 +#define bAntNonHTS1 0x1000000 + +/* Page a */ +#define bCCKBBMode 0x3 +#define bCCKTxPowerSaving 0x80 +#define bCCKRxPowerSaving 0x40 +#define bCCKSideBand 0x10 +#define bCCKScramble 0x8 +#define bCCKAntDiversity 0x8000 +#define bCCKCarrierRecovery 0x4000 +#define bCCKTxRate 0x3000 +#define bCCKDCCancel 0x0800 +#define bCCKISICancel 0x0400 +#define bCCKMatchFilter 0x0200 +#define bCCKEqualizer 0x0100 +#define bCCKPreambleDetect 0x800000 +#define bCCKFastFalseCCA 0x400000 +#define bCCKChEstStart 0x300000 +#define bCCKCCACount 0x080000 +#define bCCKcs_lim 0x070000 +#define bCCKBistMode 0x80000000 +#define bCCKCCAMask 0x40000000 +#define bCCKTxDACPhase 0x4 +/* r_rx_clk */ +#define bCCKRxADCPhase 0x20000000 +#define bCCKr_cp_mode0 0x0100 +#define bCCKTxDCOffset 0xf0 +#define bCCKRxDCOffset 0xf +#define bCCKCCAMode 0xc000 +#define bCCKFalseCS_lim 0x3f00 +#define bCCKCS_ratio 0xc00000 +#define bCCKCorgBit_sel 0x300000 +#define bCCKPD_lim 0x0f0000 +#define bCCKNewCCA 0x80000000 +#define bCCKRxHPofIG 0x8000 +#define bCCKRxIG 0x7f00 +#define bCCKLNAPolarity 0x800000 +#define bCCKRx1stGain 0x7f0000 +/* CCK Rx Initial gain polarity */ +#define bCCKRFExtend 0x20000000 +#define bCCKRxAGCSatLevel 0x1f000000 +#define bCCKRxAGCSatCount 0xe0 +/* AGCSAmp_dly */ +#define bCCKRxRFSettle 0x1f +#define bCCKFixedRxAGC 0x8000 +/*#define bCCKRxAGCFormat 0x4000 remove to HSSI register 0x824 */ +#define bCCKAntennaPolarity 0x2000 +#define bCCKTxFilterType 0x0c00 +#define bCCKRxAGCReportType 0x0300 +#define bCCKRxDAGCEn 0x80000000 +#define bCCKRxDAGCPeriod 0x20000000 +#define bCCKRxDAGCSatLevel 0x1f000000 +#define bCCKTimingRecovery 0x800000 +#define bCCKTxC0 0x3f0000 +#define bCCKTxC1 0x3f000000 +#define bCCKTxC2 0x3f +#define bCCKTxC3 0x3f00 +#define bCCKTxC4 0x3f0000 +#define bCCKTxC5 0x3f000000 +#define bCCKTxC6 0x3f +#define bCCKTxC7 0x3f00 +#define bCCKDebugPort 0xff0000 +#define bCCKDACDebug 0x0f000000 +#define bCCKFalseAlarmEnable 0x8000 +#define bCCKFalseAlarmRead 0x4000 +#define bCCKTRSSI 0x7f +#define bCCKRxAGCReport 0xfe +#define bCCKRxReport_AntSel 0x80000000 +#define bCCKRxReport_MFOff 0x40000000 +#define bCCKRxRxReport_SQLoss 0x20000000 +#define bCCKRxReport_Pktloss 0x10000000 +#define bCCKRxReport_Lockedbit 0x08000000 +#define bCCKRxReport_RateError 0x04000000 +#define bCCKRxReport_RxRate 0x03000000 +#define bCCKRxFACounterLower 0xff +#define bCCKRxFACounterUpper 0xff000000 +#define bCCKRxHPAGCStart 0xe000 +#define bCCKRxHPAGCFinal 0x1c00 + +#define bCCKRxFalseAlarmEnable 0x8000 +#define bCCKFACounterFreeze 0x4000 + +#define bCCKTxPathSel 0x10000000 +#define bCCKDefaultRxPath 0xc000000 +#define bCCKOptionRxPath 0x3000000 + +/* Page c */ +#define bNumOfSTF 0x3 +#define bShift_L 0xc0 +#define bGI_TH 0xc +#define bRxPathA 0x1 +#define bRxPathB 0x2 +#define bRxPathC 0x4 +#define bRxPathD 0x8 +#define bTxPathA 0x1 +#define bTxPathB 0x2 +#define bTxPathC 0x4 +#define bTxPathD 0x8 +#define bTRSSIFreq 0x200 +#define bADCBackoff 0x3000 +#define bDFIRBackoff 0xc000 +#define bTRSSILatchPhase 0x10000 +#define bRxIDCOffset 0xff +#define bRxQDCOffset 0xff00 +#define bRxDFIRMode 0x1800000 +#define bRxDCNFType 0xe000000 +#define bRXIQImb_A 0x3ff +#define bRXIQImb_B 0xfc00 +#define bRXIQImb_C 0x3f0000 +#define bRXIQImb_D 0xffc00000 +#define bDC_dc_Notch 0x60000 +#define bRxNBINotch 0x1f000000 +#define bPD_TH 0xf +#define bPD_TH_Opt2 0xc000 +#define bPWED_TH 0x700 +#define bIfMF_Win_L 0x800 +#define bPD_Option 0x1000 +#define bMF_Win_L 0xe000 +#define bBW_Search_L 0x30000 +#define bwin_enh_L 0xc0000 +#define bBW_TH 0x700000 +#define bED_TH2 0x3800000 +#define bBW_option 0x4000000 +#define bRatio_TH 0x18000000 +#define bWindow_L 0xe0000000 +#define bSBD_Option 0x1 +#define bFrame_TH 0x1c +#define bFS_Option 0x60 +#define bDC_Slope_check 0x80 +#define bFGuard_Counter_DC_L 0xe00 +#define bFrame_Weight_Short 0x7000 +#define bSub_Tune 0xe00000 +#define bFrame_DC_Length 0xe000000 +#define bSBD_start_offset 0x30000000 +#define bFrame_TH_2 0x7 +#define bFrame_GI2_TH 0x38 +#define bGI2_Sync_en 0x40 +#define bSarch_Short_Early 0x300 +#define bSarch_Short_Late 0xc00 +#define bSarch_GI2_Late 0x70000 +#define bCFOAntSum 0x1 +#define bCFOAcc 0x2 +#define bCFOStartOffset 0xc +#define bCFOLookBack 0x70 +#define bCFOSumWeight 0x80 +#define bDAGCEnable 0x10000 +#define bTXIQImb_A 0x3ff +#define bTXIQImb_B 0xfc00 +#define bTXIQImb_C 0x3f0000 +#define bTXIQImb_D 0xffc00000 +#define bTxIDCOffset 0xff +#define bTxQDCOffset 0xff00 +#define bTxDFIRMode 0x10000 +#define bTxPesudoNoiseOn 0x4000000 +#define bTxPesudoNoise_A 0xff +#define bTxPesudoNoise_B 0xff00 +#define bTxPesudoNoise_C 0xff0000 +#define bTxPesudoNoise_D 0xff000000 +#define bCCADropOption 0x20000 +#define bCCADropThres 0xfff00000 +#define bEDCCA_H 0xf +#define bEDCCA_L 0xf0 +#define bLambda_ED 0x300 +#define bRxInitialGain 0x7f +#define bRxAntDivEn 0x80 +#define bRxAGCAddressForLNA 0x7f00 +#define bRxHighPowerFlow 0x8000 +#define bRxAGCFreezeThres 0xc0000 +#define bRxFreezeStep_AGC1 0x300000 +#define bRxFreezeStep_AGC2 0xc00000 +#define bRxFreezeStep_AGC3 0x3000000 +#define bRxFreezeStep_AGC0 0xc000000 +#define bRxRssi_Cmp_En 0x10000000 +#define bRxQuickAGCEn 0x20000000 +#define bRxAGCFreezeThresMode 0x40000000 +#define bRxOverFlowCheckType 0x80000000 +#define bRxAGCShift 0x7f +#define bTRSW_Tri_Only 0x80 +#define bPowerThres 0x300 +#define bRxAGCEn 0x1 +#define bRxAGCTogetherEn 0x2 +#define bRxAGCMin 0x4 +#define bRxHP_Ini 0x7 +#define bRxHP_TRLNA 0x70 +#define bRxHP_RSSI 0x700 +#define bRxHP_BBP1 0x7000 +#define bRxHP_BBP2 0x70000 +#define bRxHP_BBP3 0x700000 +/* The threshold for high power */ +#define bRSSI_H 0x7f0000 +/* The threshold for ant diversity */ +#define bRSSI_Gen 0x7f000000 +#define bRxSettle_TRSW 0x7 +#define bRxSettle_LNA 0x38 +#define bRxSettle_RSSI 0x1c0 +#define bRxSettle_BBP 0xe00 +#define bRxSettle_RxHP 0x7000 +#define bRxSettle_AntSW_RSSI 0x38000 +#define bRxSettle_AntSW 0xc0000 +#define bRxProcessTime_DAGC 0x300000 +#define bRxSettle_HSSI 0x400000 +#define bRxProcessTime_BBPPW 0x800000 +#define bRxAntennaPowerShift 0x3000000 +#define bRSSITableSelect 0xc000000 +#define bRxHP_Final 0x7000000 +#define bRxHTSettle_BBP 0x7 +#define bRxHTSettle_HSSI 0x8 +#define bRxHTSettle_RxHP 0x70 +#define bRxHTSettle_BBPPW 0x80 +#define bRxHTSettle_Idle 0x300 +#define bRxHTSettle_Reserved 0x1c00 +#define bRxHTRxHPEn 0x8000 +#define bRxHTAGCFreezeThres 0x30000 +#define bRxHTAGCTogetherEn 0x40000 +#define bRxHTAGCMin 0x80000 +#define bRxHTAGCEn 0x100000 +#define bRxHTDAGCEn 0x200000 +#define bRxHTRxHP_BBP 0x1c00000 +#define bRxHTRxHP_Final 0xe0000000 +#define bRxPWRatioTH 0x3 +#define bRxPWRatioEn 0x4 +#define bRxMFHold 0x3800 +#define bRxPD_Delay_TH1 0x38 +#define bRxPD_Delay_TH2 0x1c0 +#define bRxPD_DC_COUNT_MAX 0x600 +/*#define bRxMF_Hold 0x3800*/ +#define bRxPD_Delay_TH 0x8000 +#define bRxProcess_Delay 0xf0000 +#define bRxSearchrange_GI2_Early 0x700000 +#define bRxFrame_Guard_Counter_L 0x3800000 +#define bRxSGI_Guard_L 0xc000000 +#define bRxSGI_Search_L 0x30000000 +#define bRxSGI_TH 0xc0000000 +#define bDFSCnt0 0xff +#define bDFSCnt1 0xff00 +#define bDFSFlag 0xf0000 + +#define bMFWeightSum 0x300000 +#define bMinIdxTH 0x7f000000 + +#define bDAFormat 0x40000 + +#define bTxChEmuEnable 0x01000000 + +#define bTRSWIsolation_A 0x7f +#define bTRSWIsolation_B 0x7f00 +#define bTRSWIsolation_C 0x7f0000 +#define bTRSWIsolation_D 0x7f000000 + +#define bExtLNAGain 0x7c00 + +/* Page d */ +#define bSTBCEn 0x4 +#define bAntennaMapping 0x10 +#define bNss 0x20 +#define bCFOAntSumD 0x200 +#define bPHYCounterReset 0x8000000 +#define bCFOReportGet 0x4000000 +#define bOFDMContinueTx 0x10000000 +#define bOFDMSingleCarrier 0x20000000 +#define bOFDMSingleTone 0x40000000 +/*#define bRxPath1 0x01 +#define bRxPath2 0x02 +#define bRxPath3 0x04 +#define bRxPath4 0x08 +#define bTxPath1 0x10 +#define bTxPath2 0x20*/ +#define bHTDetect 0x100 +#define bCFOEn 0x10000 +#define bCFOValue 0xfff00000 +#define bSigTone_Re 0x3f +#define bSigTone_Im 0x7f00 +#define bCounter_CCA 0xffff +#define bCounter_ParityFail 0xffff0000 +#define bCounter_RateIllegal 0xffff +#define bCounter_CRC8Fail 0xffff0000 +#define bCounter_MCSNoSupport 0xffff +#define bCounter_FastSync 0xffff +#define bShortCFO 0xfff +/* total */ +#define bShortCFOTLength 12 +/* fraction */ +#define bShortCFOFLength 11 +#define bLongCFO 0x7ff +#define bLongCFOTLength 11 +#define bLongCFOFLength 11 +#define bTailCFO 0x1fff +#define bTailCFOTLength 13 +#define bTailCFOFLength 12 + +#define bmax_en_pwdB 0xffff +#define bCC_power_dB 0xffff0000 +#define bnoise_pwdB 0xffff +#define bPowerMeasTLength 10 +#define bPowerMeasFLength 3 +#define bRx_HT_BW 0x1 +#define bRxSC 0x6 +#define bRx_HT 0x8 + +#define bNB_intf_det_on 0x1 +#define bIntf_win_len_cfg 0x30 +#define bNB_Intf_TH_cfg 0x1c0 + +#define bRFGain 0x3f +#define bTableSel 0x40 +#define bTRSW 0x80 + +#define bRxSNR_A 0xff +#define bRxSNR_B 0xff00 +#define bRxSNR_C 0xff0000 +#define bRxSNR_D 0xff000000 +#define bSNREVMTLength 8 +#define bSNREVMFLength 1 + +#define bCSI1st 0xff +#define bCSI2nd 0xff00 +#define bRxEVM1st 0xff0000 +#define bRxEVM2nd 0xff000000 + +#define bSIGEVM 0xff +#define bPWDB 0xff00 +#define bSGIEN 0x10000 + +#define bSFactorQAM1 0xf +#define bSFactorQAM2 0xf0 +#define bSFactorQAM3 0xf00 +#define bSFactorQAM4 0xf000 +#define bSFactorQAM5 0xf0000 +#define bSFactorQAM6 0xf0000 +#define bSFactorQAM7 0xf00000 +#define bSFactorQAM8 0xf000000 +#define bSFactorQAM9 0xf0000000 +#define bCSIScheme 0x100000 + +#define bNoiseLvlTopSet 0x3 +#define bChSmooth 0x4 +#define bChSmoothCfg1 0x38 +#define bChSmoothCfg2 0x1c0 +#define bChSmoothCfg3 0xe00 +#define bChSmoothCfg4 0x7000 +#define bMRCMode 0x800000 +#define bTHEVMCfg 0x7000000 + +#define bLoopFitType 0x1 +#define bUpdCFO 0x40 +#define bUpdCFOOffData 0x80 +#define bAdvUpdCFO 0x100 +#define bAdvTimeCtrl 0x800 +#define bUpdClko 0x1000 +#define bFC 0x6000 +#define bTrackingMode 0x8000 +#define bPhCmpEnable 0x10000 +#define bUpdClkoLTF 0x20000 +#define bComChCFO 0x40000 +#define bCSIEstiMode 0x80000 +#define bAdvUpdEqz 0x100000 +#define bUChCfg 0x7000000 +#define bUpdEqz 0x8000000 + +/* Page e */ +#define bTxAGCRate18_06 0x7f7f7f7f +#define bTxAGCRate54_24 0x7f7f7f7f +#define bTxAGCRateMCS32 0x7f +#define bTxAGCRateCCK 0x7f00 +#define bTxAGCRateMCS3_MCS0 0x7f7f7f7f +#define bTxAGCRateMCS7_MCS4 0x7f7f7f7f +#define bTxAGCRateMCS11_MCS8 0x7f7f7f7f +#define bTxAGCRateMCS15_MCS12 0x7f7f7f7f + + +/* Rx Pseduo noise */ +#define bRxPesudoNoiseOn 0x20000000 +#define bRxPesudoNoise_A 0xff +#define bRxPesudoNoise_B 0xff00 +#define bRxPesudoNoise_C 0xff0000 +#define bRxPesudoNoise_D 0xff000000 +#define bPesudoNoiseState_A 0xffff +#define bPesudoNoiseState_B 0xffff0000 +#define bPesudoNoiseState_C 0xffff +#define bPesudoNoiseState_D 0xffff0000 + +/* RF Zebra 1 */ +#define bZebra1_HSSIEnable 0x8 +#define bZebra1_TRxControl 0xc00 +#define bZebra1_TRxGainSetting 0x07f +#define bZebra1_RxCorner 0xc00 +#define bZebra1_TxChargePump 0x38 +#define bZebra1_RxChargePump 0x7 +#define bZebra1_ChannelNum 0xf80 +#define bZebra1_TxLPFBW 0x400 +#define bZebra1_RxLPFBW 0x600 + +/* Zebra4 */ +#define bRTL8256RegModeCtrl1 0x100 +#define bRTL8256RegModeCtrl0 0x40 +#define bRTL8256_TxLPFBW 0x18 +#define bRTL8256_RxLPFBW 0x600 + +//RTL8258 +#define bRTL8258_TxLPFBW 0xc +#define bRTL8258_RxLPFBW 0xc00 +#define bRTL8258_RSSILPFBW 0xc0 + +/* byte enable for sb_write */ +#define bByte0 0x1 +#define bByte1 0x2 +#define bByte2 0x4 +#define bByte3 0x8 +#define bWord0 0x3 +#define bWord1 0xc +#define bDWord 0xf + +/* for PutRegsetting & GetRegSetting BitMask */ +#define bMaskByte0 0xff +#define bMaskByte1 0xff00 +#define bMaskByte2 0xff0000 +#define bMaskByte3 0xff000000 +#define bMaskHWord 0xffff0000 +#define bMaskLWord 0x0000ffff +#define bMaskDWord 0xffffffff + +/* for PutRFRegsetting & GetRFRegSetting BitMask */ +#define bMask12Bits 0xfff + +#define bEnable 0x1 +#define bDisable 0x0 + +#define LeftAntenna 0x0 +#define RightAntenna 0x1 + +/* 500 ms */ +#define tCheckTxStatus 500 +/* 100 ms */ +#define tUpdateRxCounter 100 + +#define rateCCK 0 +#define rateOFDM 1 +#define rateHT 2 + +/* define Register-End */ +#define bPMAC_End 0x1ff +#define bFPGAPHY0_End 0x8ff +#define bFPGAPHY1_End 0x9ff +#define bCCKPHY0_End 0xaff +#define bOFDMPHY0_End 0xcff +#define bOFDMPHY1_End 0xdff + +#define bPMACControl 0x0 +#define bWMACControl 0x1 +#define bWNICControl 0x2 + +#define PathA 0x0 +#define PathB 0x1 +#define PathC 0x2 +#define PathD 0x3 + +#define rRTL8256RxMixerPole 0xb +#define bZebraRxMixerPole 0x6 +#define rRTL8256TxBBOPBias 0x9 +#define bRTL8256TxBBOPBias 0x400 +#define rRTL8256TxBBBW 19 +#define bRTL8256TxBBBW 0x18 + + +#endif /* __INC_HAL8190PCIPHYREG_H */ diff --git a/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c b/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c new file mode 100644 index 000000000..41b025e25 --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c @@ -0,0 +1,277 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * Based on the r8180 driver, which is: + * Copyright 2004-2005 Andrea Merello , et al. + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ +#include "rtl_core.h" +#include "r8192E_phy.h" +#include "r8192E_phyreg.h" +#include "r8190P_rtl8256.h" /* RTL8225 Radio frontend */ +#include "r8192E_cmdpkt.h" + +void CamResetAllEntry(struct net_device *dev) +{ + u32 ulcommand = 0; + + ulcommand |= BIT31|BIT30; + write_nic_dword(dev, RWCAM, ulcommand); +} + +void write_cam(struct net_device *dev, u8 addr, u32 data) +{ + write_nic_dword(dev, WCAMI, data); + write_nic_dword(dev, RWCAM, BIT31|BIT16|(addr&0xff)); +} + +u32 read_cam(struct net_device *dev, u8 addr) +{ + write_nic_dword(dev, RWCAM, 0x80000000|(addr&0xff)); + return read_nic_dword(dev, 0xa8); +} + +void EnableHWSecurityConfig8192(struct net_device *dev) +{ + u8 SECR_value = 0x0; + struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); + struct rtllib_device *ieee = priv->rtllib; + + SECR_value = SCR_TxEncEnable | SCR_RxDecEnable; + if (((KEY_TYPE_WEP40 == ieee->pairwise_key_type) || + (KEY_TYPE_WEP104 == ieee->pairwise_key_type)) && + (priv->rtllib->auth_mode != 2)) { + SECR_value |= SCR_RxUseDK; + SECR_value |= SCR_TxUseDK; + } else if ((ieee->iw_mode == IW_MODE_ADHOC) && + (ieee->pairwise_key_type & (KEY_TYPE_CCMP | + KEY_TYPE_TKIP))) { + SECR_value |= SCR_RxUseDK; + SECR_value |= SCR_TxUseDK; + } + + + ieee->hwsec_active = 1; + if ((ieee->pHTInfo->IOTAction&HT_IOT_ACT_PURE_N_MODE) || !hwwep) { + ieee->hwsec_active = 0; + SECR_value &= ~SCR_RxDecEnable; + } + + RT_TRACE(COMP_SEC, "%s:, hwsec:%d, pairwise_key:%d, SECR_value:%x\n", + __func__, ieee->hwsec_active, ieee->pairwise_key_type, + SECR_value); + write_nic_byte(dev, SECR, SECR_value); +} + +void set_swcam(struct net_device *dev, u8 EntryNo, u8 KeyIndex, u16 KeyType, + u8 *MacAddr, u8 DefaultKey, u32 *KeyContent, u8 is_mesh) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct rtllib_device *ieee = priv->rtllib; + + RT_TRACE(COMP_DBG, + "===========>%s():EntryNo is %d,KeyIndex is %d,KeyType is %d,is_mesh is %d\n", + __func__, EntryNo, KeyIndex, KeyType, is_mesh); + if (!is_mesh) { + ieee->swcamtable[EntryNo].bused = true; + ieee->swcamtable[EntryNo].key_index = KeyIndex; + ieee->swcamtable[EntryNo].key_type = KeyType; + memcpy(ieee->swcamtable[EntryNo].macaddr, MacAddr, 6); + ieee->swcamtable[EntryNo].useDK = DefaultKey; + memcpy(ieee->swcamtable[EntryNo].key_buf, (u8 *)KeyContent, 16); + } +} + +void setKey(struct net_device *dev, u8 EntryNo, u8 KeyIndex, u16 KeyType, + u8 *MacAddr, u8 DefaultKey, u32 *KeyContent) +{ + u32 TargetCommand = 0; + u32 TargetContent = 0; + u16 usConfig = 0; + u8 i; + struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); + enum rt_rf_power_state rtState; + + rtState = priv->rtllib->eRFPowerState; + if (priv->rtllib->PowerSaveControl.bInactivePs) { + if (rtState == eRfOff) { + if (priv->rtllib->RfOffReason > RF_CHANGE_BY_IPS) { + RT_TRACE(COMP_ERR, "%s(): RF is OFF.\n", + __func__); + return; + } + down(&priv->rtllib->ips_sem); + IPSLeave(dev); + up(&priv->rtllib->ips_sem); + } + } + priv->rtllib->is_set_key = true; + if (EntryNo >= TOTAL_CAM_ENTRY) + RT_TRACE(COMP_ERR, "cam entry exceeds in setKey()\n"); + + RT_TRACE(COMP_SEC, + "====>to setKey(), dev:%p, EntryNo:%d, KeyIndex:%d,KeyType:%d, MacAddr %pM\n", + dev, EntryNo, KeyIndex, KeyType, MacAddr); + + if (DefaultKey) + usConfig |= BIT15 | (KeyType<<2); + else + usConfig |= BIT15 | (KeyType<<2) | KeyIndex; + + + for (i = 0; i < CAM_CONTENT_COUNT; i++) { + TargetCommand = i + CAM_CONTENT_COUNT * EntryNo; + TargetCommand |= BIT31|BIT16; + + if (i == 0) { + TargetContent = (u32)(*(MacAddr+0)) << 16 | + (u32)(*(MacAddr+1)) << 24 | + (u32)usConfig; + + write_nic_dword(dev, WCAMI, TargetContent); + write_nic_dword(dev, RWCAM, TargetCommand); + } else if (i == 1) { + TargetContent = (u32)(*(MacAddr+2)) | + (u32)(*(MacAddr+3)) << 8 | + (u32)(*(MacAddr+4)) << 16 | + (u32)(*(MacAddr+5)) << 24; + write_nic_dword(dev, WCAMI, TargetContent); + write_nic_dword(dev, RWCAM, TargetCommand); + } else { + if (KeyContent != NULL) { + write_nic_dword(dev, WCAMI, + (u32)(*(KeyContent+i-2))); + write_nic_dword(dev, RWCAM, TargetCommand); + udelay(100); + } + } + } + RT_TRACE(COMP_SEC, "=========>after set key, usconfig:%x\n", usConfig); +} + +void CamRestoreAllEntry(struct net_device *dev) +{ + u8 EntryId = 0; + struct r8192_priv *priv = rtllib_priv(dev); + u8 *MacAddr = priv->rtllib->current_network.bssid; + + static u8 CAM_CONST_ADDR[4][6] = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x03} + }; + static u8 CAM_CONST_BROAD[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; + + RT_TRACE(COMP_SEC, "CamRestoreAllEntry:\n"); + + + if ((priv->rtllib->pairwise_key_type == KEY_TYPE_WEP40) || + (priv->rtllib->pairwise_key_type == KEY_TYPE_WEP104)) { + + for (EntryId = 0; EntryId < 4; EntryId++) { + MacAddr = CAM_CONST_ADDR[EntryId]; + if (priv->rtllib->swcamtable[EntryId].bused) { + setKey(dev, EntryId, EntryId, + priv->rtllib->pairwise_key_type, MacAddr, + 0, (u32 *)(&priv->rtllib->swcamtable + [EntryId].key_buf[0])); + } + } + + } else if (priv->rtllib->pairwise_key_type == KEY_TYPE_TKIP) { + if (priv->rtllib->iw_mode == IW_MODE_ADHOC) { + setKey(dev, 4, 0, priv->rtllib->pairwise_key_type, + (u8 *)dev->dev_addr, 0, + (u32 *)(&priv->rtllib->swcamtable[4].key_buf[0])); + } else { + setKey(dev, 4, 0, priv->rtllib->pairwise_key_type, + MacAddr, 0, + (u32 *)(&priv->rtllib->swcamtable[4].key_buf[0])); + } + + } else if (priv->rtllib->pairwise_key_type == KEY_TYPE_CCMP) { + if (priv->rtllib->iw_mode == IW_MODE_ADHOC) { + setKey(dev, 4, 0, + priv->rtllib->pairwise_key_type, + (u8 *)dev->dev_addr, 0, + (u32 *)(&priv->rtllib->swcamtable[4]. + key_buf[0])); + } else { + setKey(dev, 4, 0, + priv->rtllib->pairwise_key_type, MacAddr, + 0, (u32 *)(&priv->rtllib->swcamtable[4]. + key_buf[0])); + } + } + + if (priv->rtllib->group_key_type == KEY_TYPE_TKIP) { + MacAddr = CAM_CONST_BROAD; + for (EntryId = 1; EntryId < 4; EntryId++) { + if (priv->rtllib->swcamtable[EntryId].bused) { + setKey(dev, EntryId, EntryId, + priv->rtllib->group_key_type, + MacAddr, 0, + (u32 *)(&priv->rtllib->swcamtable[EntryId].key_buf[0]) + ); + } + } + if (priv->rtllib->iw_mode == IW_MODE_ADHOC) { + if (priv->rtllib->swcamtable[0].bused) { + setKey(dev, 0, 0, + priv->rtllib->group_key_type, + CAM_CONST_ADDR[0], 0, + (u32 *)(&priv->rtllib->swcamtable[0].key_buf[0]) + ); + } else { + RT_TRACE(COMP_ERR, + "===>%s():ERR!! ADHOC TKIP ,but 0 entry is have no data\n", + __func__); + return; + } + } + } else if (priv->rtllib->group_key_type == KEY_TYPE_CCMP) { + MacAddr = CAM_CONST_BROAD; + for (EntryId = 1; EntryId < 4; EntryId++) { + if (priv->rtllib->swcamtable[EntryId].bused) { + setKey(dev, EntryId, EntryId, + priv->rtllib->group_key_type, + MacAddr, 0, + (u32 *)(&priv->rtllib->swcamtable[EntryId].key_buf[0])); + } + } + + if (priv->rtllib->iw_mode == IW_MODE_ADHOC) { + if (priv->rtllib->swcamtable[0].bused) { + setKey(dev, 0, 0, + priv->rtllib->group_key_type, + CAM_CONST_ADDR[0], 0, + (u32 *)(&priv->rtllib->swcamtable[0].key_buf[0])); + } else { + RT_TRACE(COMP_ERR, + "===>%s():ERR!! ADHOC CCMP ,but 0 entry is have no data\n", + __func__); + return; + } + } + } +} diff --git a/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h b/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h new file mode 100644 index 000000000..3c4c0e61c --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h @@ -0,0 +1,44 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * Based on the r8180 driver, which is: + * Copyright 2004-2005 Andrea Merello , et al. + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ +#ifndef _RTL_CAM_H +#define _RTL_CAM_H + +#include +struct net_device; + +void CamResetAllEntry(struct net_device *dev); +void EnableHWSecurityConfig8192(struct net_device *dev); +void setKey(struct net_device *dev, u8 EntryNo, u8 KeyIndex, u16 KeyType, + u8 *MacAddr, u8 DefaultKey, u32 *KeyContent); +void set_swcam(struct net_device *dev, u8 EntryNo, u8 KeyIndex, u16 KeyType, + u8 *MacAddr, u8 DefaultKey, u32 *KeyContent, u8 is_mesh); +void CamPrintDbgReg(struct net_device *dev); + +u32 read_cam(struct net_device *dev, u8 addr); +void write_cam(struct net_device *dev, u8 addr, u32 data); + +void CamRestoreAllEntry(struct net_device *dev); + +#endif diff --git a/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_core.c new file mode 100644 index 000000000..352d381b7 --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -0,0 +1,3122 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * Based on the r8180 driver, which is: + * Copyright 2004-2005 Andrea Merello , et al. + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ +#undef RX_DONT_PASS_UL +#undef DEBUG_EPROM +#undef DEBUG_RX_VERBOSE +#undef DUMMY_RX +#undef DEBUG_ZERO_RX +#undef DEBUG_RX_SKB +#undef DEBUG_TX_FRAG +#undef DEBUG_RX_FRAG +#undef DEBUG_TX_FILLDESC +#undef DEBUG_TX +#undef DEBUG_IRQ +#undef DEBUG_RX +#undef DEBUG_RXALLOC +#undef DEBUG_REGISTERS +#undef DEBUG_RING +#undef DEBUG_IRQ_TASKLET +#undef DEBUG_TX_ALLOC +#undef DEBUG_TX_DESC + +#include +#include +#include +#include "rtl_core.h" +#include "r8192E_phy.h" +#include "r8192E_phyreg.h" +#include "r8190P_rtl8256.h" +#include "r8192E_cmdpkt.h" + +#include "rtl_wx.h" +#include "rtl_dm.h" + +#include "rtl_pm.h" + +int hwwep = 1; +static int channels = 0x3fff; +static char *ifname = "wlan%d"; + + +static struct rtl819x_ops rtl819xp_ops = { + .nic_type = NIC_8192E, + .get_eeprom_size = rtl8192_get_eeprom_size, + .init_adapter_variable = rtl8192_InitializeVariables, + .initialize_adapter = rtl8192_adapter_start, + .link_change = rtl8192_link_change, + .tx_fill_descriptor = rtl8192_tx_fill_desc, + .tx_fill_cmd_descriptor = rtl8192_tx_fill_cmd_desc, + .rx_query_status_descriptor = rtl8192_rx_query_status_desc, + .rx_command_packet_handler = NULL, + .stop_adapter = rtl8192_halt_adapter, + .update_ratr_table = rtl8192_update_ratr_table, + .irq_enable = rtl8192_EnableInterrupt, + .irq_disable = rtl8192_DisableInterrupt, + .irq_clear = rtl8192_ClearInterrupt, + .rx_enable = rtl8192_enable_rx, + .tx_enable = rtl8192_enable_tx, + .interrupt_recognized = rtl8192_interrupt_recognized, + .TxCheckStuckHandler = rtl8192_HalTxCheckStuck, + .RxCheckStuckHandler = rtl8192_HalRxCheckStuck, +}; + +static struct pci_device_id rtl8192_pci_id_tbl[] = { + {RTL_PCI_DEVICE(0x10ec, 0x8192, rtl819xp_ops)}, + {RTL_PCI_DEVICE(0x07aa, 0x0044, rtl819xp_ops)}, + {RTL_PCI_DEVICE(0x07aa, 0x0047, rtl819xp_ops)}, + {} +}; + +MODULE_DEVICE_TABLE(pci, rtl8192_pci_id_tbl); + +static int rtl8192_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id); +static void rtl8192_pci_disconnect(struct pci_dev *pdev); +static irqreturn_t rtl8192_interrupt(int irq, void *netdev); + +static struct pci_driver rtl8192_pci_driver = { + .name = DRV_NAME, /* Driver name */ + .id_table = rtl8192_pci_id_tbl, /* PCI_ID table */ + .probe = rtl8192_pci_probe, /* probe fn */ + .remove = rtl8192_pci_disconnect, /* remove fn */ + .suspend = rtl8192E_suspend, /* PM suspend fn */ + .resume = rtl8192E_resume, /* PM resume fn */ +}; + +/**************************************************************************** + -----------------------------IO STUFF------------------------- +*****************************************************************************/ +static bool PlatformIOCheckPageLegalAndGetRegMask(u32 u4bPage, u8 *pu1bPageMask) +{ + bool bReturn = false; + + *pu1bPageMask = 0xfe; + + switch (u4bPage) { + case 1: case 2: case 3: case 4: + case 8: case 9: case 10: case 12: case 13: + bReturn = true; + *pu1bPageMask = 0xf0; + break; + + default: + bReturn = false; + break; + } + + return bReturn; +} + +void write_nic_io_byte(struct net_device *dev, int x, u8 y) +{ + u32 u4bPage = x >> 8; + u8 u1PageMask = 0; + bool bIsLegalPage = false; + + if (u4bPage == 0) { + outb(y&0xff, dev->base_addr + x); + + } else { + bIsLegalPage = PlatformIOCheckPageLegalAndGetRegMask(u4bPage, + &u1PageMask); + if (bIsLegalPage) { + u8 u1bPsr = read_nic_io_byte(dev, PSR); + + write_nic_io_byte(dev, PSR, ((u1bPsr & u1PageMask) | + (u8)u4bPage)); + write_nic_io_byte(dev, (x & 0xff), y); + write_nic_io_byte(dev, PSR, (u1bPsr & u1PageMask)); + } + } +} + +void write_nic_io_word(struct net_device *dev, int x, u16 y) +{ + u32 u4bPage = x >> 8; + u8 u1PageMask = 0; + bool bIsLegalPage = false; + + if (u4bPage == 0) { + outw(y, dev->base_addr + x); + } else { + bIsLegalPage = PlatformIOCheckPageLegalAndGetRegMask(u4bPage, + &u1PageMask); + if (bIsLegalPage) { + u8 u1bPsr = read_nic_io_byte(dev, PSR); + + write_nic_io_byte(dev, PSR, ((u1bPsr & u1PageMask) | + (u8)u4bPage)); + write_nic_io_word(dev, (x & 0xff), y); + write_nic_io_byte(dev, PSR, (u1bPsr & u1PageMask)); + + } + } +} + +void write_nic_io_dword(struct net_device *dev, int x, u32 y) +{ + u32 u4bPage = x >> 8; + u8 u1PageMask = 0; + bool bIsLegalPage = false; + + if (u4bPage == 0) { + outl(y, dev->base_addr + x); + } else { + bIsLegalPage = PlatformIOCheckPageLegalAndGetRegMask(u4bPage, + &u1PageMask); + if (bIsLegalPage) { + u8 u1bPsr = read_nic_io_byte(dev, PSR); + + write_nic_io_byte(dev, PSR, ((u1bPsr & u1PageMask) | + (u8)u4bPage)); + write_nic_io_dword(dev, (x & 0xff), y); + write_nic_io_byte(dev, PSR, (u1bPsr & u1PageMask)); + } + } +} + +u8 read_nic_io_byte(struct net_device *dev, int x) +{ + u32 u4bPage = x >> 8; + u8 u1PageMask = 0; + bool bIsLegalPage = false; + u8 Data = 0; + + if (u4bPage == 0) + return 0xff&inb(dev->base_addr + x); + + bIsLegalPage = PlatformIOCheckPageLegalAndGetRegMask(u4bPage, + &u1PageMask); + if (bIsLegalPage) { + u8 u1bPsr = read_nic_io_byte(dev, PSR); + + write_nic_io_byte(dev, PSR, ((u1bPsr & u1PageMask) | + (u8)u4bPage)); + Data = read_nic_io_byte(dev, (x & 0xff)); + write_nic_io_byte(dev, PSR, (u1bPsr & u1PageMask)); + } + + return Data; +} + +u16 read_nic_io_word(struct net_device *dev, int x) +{ + u32 u4bPage = x >> 8; + u8 u1PageMask = 0; + bool bIsLegalPage = false; + u16 Data = 0; + + if (u4bPage == 0) + return inw(dev->base_addr + x); + bIsLegalPage = PlatformIOCheckPageLegalAndGetRegMask(u4bPage, + &u1PageMask); + if (bIsLegalPage) { + u8 u1bPsr = read_nic_io_byte(dev, PSR); + + write_nic_io_byte(dev, PSR, ((u1bPsr & u1PageMask) | + (u8)u4bPage)); + Data = read_nic_io_word(dev, (x & 0xff)); + write_nic_io_byte(dev, PSR, (u1bPsr & u1PageMask)); + } + + return Data; +} + +u32 read_nic_io_dword(struct net_device *dev, int x) +{ + u32 u4bPage = x >> 8; + u8 u1PageMask = 0; + bool bIsLegalPage = false; + u32 Data = 0; + + if (u4bPage == 0) + return inl(dev->base_addr + x); + bIsLegalPage = PlatformIOCheckPageLegalAndGetRegMask(u4bPage, + &u1PageMask); + if (bIsLegalPage) { + u8 u1bPsr = read_nic_io_byte(dev, PSR); + + write_nic_io_byte(dev, PSR, ((u1bPsr & u1PageMask) | + (u8)u4bPage)); + Data = read_nic_io_dword(dev, (x & 0xff)); + write_nic_io_byte(dev, PSR, (u1bPsr & u1PageMask)); + } + + return Data; +} + +u8 read_nic_byte(struct net_device *dev, int x) +{ + return 0xff & readb((u8 __iomem *)dev->mem_start + x); +} + +u32 read_nic_dword(struct net_device *dev, int x) +{ + return readl((u8 __iomem *)dev->mem_start + x); +} + +u16 read_nic_word(struct net_device *dev, int x) +{ + return readw((u8 __iomem *)dev->mem_start + x); +} + +void write_nic_byte(struct net_device *dev, int x, u8 y) +{ + writeb(y, (u8 __iomem *)dev->mem_start + x); + + udelay(20); +} + +void write_nic_dword(struct net_device *dev, int x, u32 y) +{ + writel(y, (u8 __iomem *)dev->mem_start + x); + + udelay(20); +} + +void write_nic_word(struct net_device *dev, int x, u16 y) +{ + writew(y, (u8 __iomem *)dev->mem_start + x); + + udelay(20); +} + +/**************************************************************************** + -----------------------------GENERAL FUNCTION------------------------- +*****************************************************************************/ +bool MgntActSet_RF_State(struct net_device *dev, + enum rt_rf_power_state StateToSet, + RT_RF_CHANGE_SOURCE ChangeSource, + bool ProtectOrNot) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct rtllib_device *ieee = priv->rtllib; + bool bActionAllowed = false; + bool bConnectBySSID = false; + enum rt_rf_power_state rtState; + u16 RFWaitCounter = 0; + unsigned long flag; + + RT_TRACE((COMP_PS | COMP_RF), + "===>MgntActSet_RF_State(): StateToSet(%d)\n", StateToSet); + + ProtectOrNot = false; + + + if (!ProtectOrNot) { + while (true) { + spin_lock_irqsave(&priv->rf_ps_lock, flag); + if (priv->RFChangeInProgress) { + spin_unlock_irqrestore(&priv->rf_ps_lock, flag); + RT_TRACE((COMP_PS | COMP_RF), + "MgntActSet_RF_State(): RF Change in progress! Wait to set..StateToSet(%d).\n", + StateToSet); + + while (priv->RFChangeInProgress) { + RFWaitCounter++; + RT_TRACE((COMP_PS | COMP_RF), + "MgntActSet_RF_State(): Wait 1 ms (%d times)...\n", + RFWaitCounter); + mdelay(1); + + if (RFWaitCounter > 100) { + RT_TRACE(COMP_ERR, + "MgntActSet_RF_State(): Wait too logn to set RF\n"); + return false; + } + } + } else { + priv->RFChangeInProgress = true; + spin_unlock_irqrestore(&priv->rf_ps_lock, flag); + break; + } + } + } + + rtState = priv->rtllib->eRFPowerState; + + switch (StateToSet) { + case eRfOn: + priv->rtllib->RfOffReason &= (~ChangeSource); + + if ((ChangeSource == RF_CHANGE_BY_HW) && priv->bHwRadioOff) + priv->bHwRadioOff = false; + + if (!priv->rtllib->RfOffReason) { + priv->rtllib->RfOffReason = 0; + bActionAllowed = true; + + + if (rtState == eRfOff && + ChangeSource >= RF_CHANGE_BY_HW) + bConnectBySSID = true; + } else { + RT_TRACE((COMP_PS | COMP_RF), + "MgntActSet_RF_State - eRfon reject pMgntInfo->RfOffReason= 0x%x, ChangeSource=0x%X\n", + priv->rtllib->RfOffReason, ChangeSource); + } + + break; + + case eRfOff: + + if ((priv->rtllib->iw_mode == IW_MODE_INFRA) || + (priv->rtllib->iw_mode == IW_MODE_ADHOC)) { + if ((priv->rtllib->RfOffReason > RF_CHANGE_BY_IPS) || + (ChangeSource > RF_CHANGE_BY_IPS)) { + if (ieee->state == RTLLIB_LINKED) + priv->blinked_ingpio = true; + else + priv->blinked_ingpio = false; + rtllib_MgntDisconnect(priv->rtllib, + disas_lv_ss); + } + } + if ((ChangeSource == RF_CHANGE_BY_HW) && !priv->bHwRadioOff) + priv->bHwRadioOff = true; + priv->rtllib->RfOffReason |= ChangeSource; + bActionAllowed = true; + break; + + case eRfSleep: + priv->rtllib->RfOffReason |= ChangeSource; + bActionAllowed = true; + break; + + default: + break; + } + + if (bActionAllowed) { + RT_TRACE((COMP_PS | COMP_RF), + "MgntActSet_RF_State(): Action is allowed.... StateToSet(%d), RfOffReason(%#X)\n", + StateToSet, priv->rtllib->RfOffReason); + PHY_SetRFPowerState(dev, StateToSet); + if (StateToSet == eRfOn) { + + if (bConnectBySSID && priv->blinked_ingpio) { + queue_delayed_work_rsl(ieee->wq, + &ieee->associate_procedure_wq, 0); + priv->blinked_ingpio = false; + } + } + } else { + RT_TRACE((COMP_PS | COMP_RF), + "MgntActSet_RF_State(): Action is rejected.... StateToSet(%d), ChangeSource(%#X), RfOffReason(%#X)\n", + StateToSet, ChangeSource, priv->rtllib->RfOffReason); + } + + if (!ProtectOrNot) { + spin_lock_irqsave(&priv->rf_ps_lock, flag); + priv->RFChangeInProgress = false; + spin_unlock_irqrestore(&priv->rf_ps_lock, flag); + } + + RT_TRACE((COMP_PS | COMP_RF), "<===MgntActSet_RF_State()\n"); + return bActionAllowed; +} + + +static short rtl8192_get_nic_desc_num(struct net_device *dev, int prio) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct rtl8192_tx_ring *ring = &priv->tx_ring[prio]; + + /* For now, we reserved two free descriptor as a safety boundary + * between the tail and the head + */ + if ((prio == MGNT_QUEUE) && (skb_queue_len(&ring->queue) > 10)) + RT_TRACE(COMP_DBG, + "-----[%d]---------ring->idx=%d queue_len=%d---------\n", + prio, ring->idx, skb_queue_len(&ring->queue)); + return skb_queue_len(&ring->queue); +} + +static short rtl8192_check_nic_enough_desc(struct net_device *dev, int prio) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct rtl8192_tx_ring *ring = &priv->tx_ring[prio]; + + if (ring->entries - skb_queue_len(&ring->queue) >= 2) + return 1; + return 0; +} + +void rtl8192_tx_timeout(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + schedule_work(&priv->reset_wq); + netdev_info(dev, "TXTIMEOUT"); +} + +void rtl8192_irq_enable(struct net_device *dev) +{ + struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); + + priv->irq_enabled = 1; + + priv->ops->irq_enable(dev); +} + +void rtl8192_irq_disable(struct net_device *dev) +{ + struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); + + priv->ops->irq_disable(dev); + + priv->irq_enabled = 0; +} + +void rtl8192_set_chan(struct net_device *dev, short ch) +{ + struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); + + RT_TRACE(COMP_CH, "=====>%s()====ch:%d\n", __func__, ch); + if (priv->chan_forced) + return; + + priv->chan = ch; + + if (priv->rf_set_chan) + priv->rf_set_chan(dev, priv->chan); +} + +void rtl8192_update_cap(struct net_device *dev, u16 cap) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct rtllib_network *net = &priv->rtllib->current_network; + bool ShortPreamble; + + if (cap & WLAN_CAPABILITY_SHORT_PREAMBLE) { + if (priv->dot11CurrentPreambleMode != PREAMBLE_SHORT) { + ShortPreamble = true; + priv->dot11CurrentPreambleMode = PREAMBLE_SHORT; + RT_TRACE(COMP_DBG, + "%s(): WLAN_CAPABILITY_SHORT_PREAMBLE\n", + __func__); + priv->rtllib->SetHwRegHandler(dev, HW_VAR_ACK_PREAMBLE, + (unsigned char *)&ShortPreamble); + } + } else { + if (priv->dot11CurrentPreambleMode != PREAMBLE_LONG) { + ShortPreamble = false; + priv->dot11CurrentPreambleMode = PREAMBLE_LONG; + RT_TRACE(COMP_DBG, + "%s(): WLAN_CAPABILITY_LONG_PREAMBLE\n", + __func__); + priv->rtllib->SetHwRegHandler(dev, HW_VAR_ACK_PREAMBLE, + (unsigned char *)&ShortPreamble); + } + } + + if (net->mode & (IEEE_G|IEEE_N_24G)) { + u8 slot_time_val; + u8 CurSlotTime = priv->slot_time; + + if ((cap & WLAN_CAPABILITY_SHORT_SLOT_TIME) && + (!priv->rtllib->pHTInfo->bCurrentRT2RTLongSlotTime)) { + if (CurSlotTime != SHORT_SLOT_TIME) { + slot_time_val = SHORT_SLOT_TIME; + priv->rtllib->SetHwRegHandler(dev, + HW_VAR_SLOT_TIME, &slot_time_val); + } + } else { + if (CurSlotTime != NON_SHORT_SLOT_TIME) { + slot_time_val = NON_SHORT_SLOT_TIME; + priv->rtllib->SetHwRegHandler(dev, + HW_VAR_SLOT_TIME, &slot_time_val); + } + } + } +} + +static struct rtllib_qos_parameters def_qos_parameters = { + {cpu_to_le16(3), cpu_to_le16(3), cpu_to_le16(3), cpu_to_le16(3)}, + {cpu_to_le16(7), cpu_to_le16(7), cpu_to_le16(7), cpu_to_le16(7)}, + {2, 2, 2, 2}, + {0, 0, 0, 0}, + {0, 0, 0, 0} +}; + +static void rtl8192_update_beacon(void *data) +{ + struct r8192_priv *priv = container_of_work_rsl(data, struct r8192_priv, + update_beacon_wq.work); + struct net_device *dev = priv->rtllib->dev; + struct rtllib_device *ieee = priv->rtllib; + struct rtllib_network *net = &ieee->current_network; + + if (ieee->pHTInfo->bCurrentHTSupport) + HT_update_self_and_peer_setting(ieee, net); + ieee->pHTInfo->bCurrentRT2RTLongSlotTime = + net->bssht.bdRT2RTLongSlotTime; + ieee->pHTInfo->RT2RT_HT_Mode = net->bssht.RT2RT_HT_Mode; + rtl8192_update_cap(dev, net->capability); +} + +static void rtl8192_qos_activate(void *data) +{ + struct r8192_priv *priv = container_of_work_rsl(data, struct r8192_priv, + qos_activate); + struct net_device *dev = priv->rtllib->dev; + int i; + + mutex_lock(&priv->mutex); + if (priv->rtllib->state != RTLLIB_LINKED) + goto success; + RT_TRACE(COMP_QOS, + "qos active process with associate response received\n"); + + for (i = 0; i < QOS_QUEUE_NUM; i++) + priv->rtllib->SetHwRegHandler(dev, HW_VAR_AC_PARAM, (u8 *)(&i)); + + +success: + mutex_unlock(&priv->mutex); +} + +static int rtl8192_qos_handle_probe_response(struct r8192_priv *priv, + int active_network, + struct rtllib_network *network) +{ + int ret = 0; + u32 size = sizeof(struct rtllib_qos_parameters); + + if (priv->rtllib->state != RTLLIB_LINKED) + return ret; + + if (priv->rtllib->iw_mode != IW_MODE_INFRA) + return ret; + + if (network->flags & NETWORK_HAS_QOS_MASK) { + if (active_network && + (network->flags & NETWORK_HAS_QOS_PARAMETERS)) + network->qos_data.active = network->qos_data.supported; + + if ((network->qos_data.active == 1) && (active_network == 1) && + (network->flags & NETWORK_HAS_QOS_PARAMETERS) && + (network->qos_data.old_param_count != + network->qos_data.param_count)) { + network->qos_data.old_param_count = + network->qos_data.param_count; + priv->rtllib->wmm_acm = network->qos_data.wmm_acm; + queue_work_rsl(priv->priv_wq, &priv->qos_activate); + RT_TRACE(COMP_QOS, + "QoS parameters change call qos_activate\n"); + } + } else { + memcpy(&priv->rtllib->current_network.qos_data.parameters, + &def_qos_parameters, size); + + if ((network->qos_data.active == 1) && (active_network == 1)) { + queue_work_rsl(priv->priv_wq, &priv->qos_activate); + RT_TRACE(COMP_QOS, + "QoS was disabled call qos_activate\n"); + } + network->qos_data.active = 0; + network->qos_data.supported = 0; + } + + return 0; +} + +static int rtl8192_handle_beacon(struct net_device *dev, + struct rtllib_beacon *beacon, + struct rtllib_network *network) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + rtl8192_qos_handle_probe_response(priv, 1, network); + + queue_delayed_work_rsl(priv->priv_wq, &priv->update_beacon_wq, 0); + return 0; + +} + +static int rtl8192_qos_association_resp(struct r8192_priv *priv, + struct rtllib_network *network) +{ + unsigned long flags; + u32 size = sizeof(struct rtllib_qos_parameters); + int set_qos_param = 0; + + if ((priv == NULL) || (network == NULL)) + return 0; + + if (priv->rtllib->state != RTLLIB_LINKED) + return 0; + + if (priv->rtllib->iw_mode != IW_MODE_INFRA) + return 0; + + spin_lock_irqsave(&priv->rtllib->lock, flags); + if (network->flags & NETWORK_HAS_QOS_PARAMETERS) { + memcpy(&priv->rtllib->current_network.qos_data.parameters, + &network->qos_data.parameters, + sizeof(struct rtllib_qos_parameters)); + priv->rtllib->current_network.qos_data.active = 1; + priv->rtllib->wmm_acm = network->qos_data.wmm_acm; + set_qos_param = 1; + priv->rtllib->current_network.qos_data.old_param_count = + priv->rtllib->current_network.qos_data.param_count; + priv->rtllib->current_network.qos_data.param_count = + network->qos_data.param_count; + } else { + memcpy(&priv->rtllib->current_network.qos_data.parameters, + &def_qos_parameters, size); + priv->rtllib->current_network.qos_data.active = 0; + priv->rtllib->current_network.qos_data.supported = 0; + set_qos_param = 1; + } + + spin_unlock_irqrestore(&priv->rtllib->lock, flags); + + RT_TRACE(COMP_QOS, "%s: network->flags = %d,%d\n", __func__, + network->flags, priv->rtllib->current_network.qos_data.active); + if (set_qos_param == 1) { + dm_init_edca_turbo(priv->rtllib->dev); + queue_work_rsl(priv->priv_wq, &priv->qos_activate); + } + return 0; +} + +static int rtl8192_handle_assoc_response(struct net_device *dev, + struct rtllib_assoc_response_frame *resp, + struct rtllib_network *network) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + rtl8192_qos_association_resp(priv, network); + return 0; +} + +static void rtl8192_prepare_beacon(struct r8192_priv *priv) +{ + struct net_device *dev = priv->rtllib->dev; + struct sk_buff *pskb = NULL, *pnewskb = NULL; + struct cb_desc *tcb_desc = NULL; + struct rtl8192_tx_ring *ring = NULL; + struct tx_desc *pdesc = NULL; + + ring = &priv->tx_ring[BEACON_QUEUE]; + pskb = __skb_dequeue(&ring->queue); + kfree_skb(pskb); + + pnewskb = rtllib_get_beacon(priv->rtllib); + if (!pnewskb) + return; + + tcb_desc = (struct cb_desc *)(pnewskb->cb + 8); + tcb_desc->queue_index = BEACON_QUEUE; + tcb_desc->data_rate = 2; + tcb_desc->RATRIndex = 7; + tcb_desc->bTxDisableRateFallBack = 1; + tcb_desc->bTxUseDriverAssingedRate = 1; + skb_push(pnewskb, priv->rtllib->tx_headroom); + + pdesc = &ring->desc[0]; + priv->ops->tx_fill_descriptor(dev, pdesc, tcb_desc, pnewskb); + __skb_queue_tail(&ring->queue, pnewskb); + pdesc->OWN = 1; +} + +static void rtl8192_stop_beacon(struct net_device *dev) +{ +} + +void rtl8192_config_rate(struct net_device *dev, u16 *rate_config) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct rtllib_network *net; + u8 i = 0, basic_rate = 0; + + net = &priv->rtllib->current_network; + + for (i = 0; i < net->rates_len; i++) { + basic_rate = net->rates[i] & 0x7f; + switch (basic_rate) { + case MGN_1M: + *rate_config |= RRSR_1M; + break; + case MGN_2M: + *rate_config |= RRSR_2M; + break; + case MGN_5_5M: + *rate_config |= RRSR_5_5M; + break; + case MGN_11M: + *rate_config |= RRSR_11M; + break; + case MGN_6M: + *rate_config |= RRSR_6M; + break; + case MGN_9M: + *rate_config |= RRSR_9M; + break; + case MGN_12M: + *rate_config |= RRSR_12M; + break; + case MGN_18M: + *rate_config |= RRSR_18M; + break; + case MGN_24M: + *rate_config |= RRSR_24M; + break; + case MGN_36M: + *rate_config |= RRSR_36M; + break; + case MGN_48M: + *rate_config |= RRSR_48M; + break; + case MGN_54M: + *rate_config |= RRSR_54M; + break; + } + } + + for (i = 0; i < net->rates_ex_len; i++) { + basic_rate = net->rates_ex[i] & 0x7f; + switch (basic_rate) { + case MGN_1M: + *rate_config |= RRSR_1M; + break; + case MGN_2M: + *rate_config |= RRSR_2M; + break; + case MGN_5_5M: + *rate_config |= RRSR_5_5M; + break; + case MGN_11M: + *rate_config |= RRSR_11M; + break; + case MGN_6M: + *rate_config |= RRSR_6M; + break; + case MGN_9M: + *rate_config |= RRSR_9M; + break; + case MGN_12M: + *rate_config |= RRSR_12M; + break; + case MGN_18M: + *rate_config |= RRSR_18M; + break; + case MGN_24M: + *rate_config |= RRSR_24M; + break; + case MGN_36M: + *rate_config |= RRSR_36M; + break; + case MGN_48M: + *rate_config |= RRSR_48M; + break; + case MGN_54M: + *rate_config |= RRSR_54M; + break; + } + } +} + +static void rtl8192_refresh_supportrate(struct r8192_priv *priv) +{ + struct rtllib_device *ieee = priv->rtllib; + + if (ieee->mode == WIRELESS_MODE_N_24G || + ieee->mode == WIRELESS_MODE_N_5G) { + memcpy(ieee->Regdot11HTOperationalRateSet, + ieee->RegHTSuppRateSet, 16); + memcpy(ieee->Regdot11TxHTOperationalRateSet, + ieee->RegHTSuppRateSet, 16); + + } else { + memset(ieee->Regdot11HTOperationalRateSet, 0, 16); + } +} + +static u8 rtl8192_getSupportedWireleeMode(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + u8 ret = 0; + + switch (priv->rf_chip) { + case RF_8225: + case RF_8256: + case RF_6052: + case RF_PSEUDO_11N: + ret = (WIRELESS_MODE_N_24G|WIRELESS_MODE_G | WIRELESS_MODE_B); + break; + case RF_8258: + ret = (WIRELESS_MODE_A | WIRELESS_MODE_N_5G); + break; + default: + ret = WIRELESS_MODE_B; + break; + } + return ret; +} + +void rtl8192_SetWirelessMode(struct net_device *dev, u8 wireless_mode) +{ + struct r8192_priv *priv = rtllib_priv(dev); + u8 bSupportMode = rtl8192_getSupportedWireleeMode(dev); + + if ((wireless_mode == WIRELESS_MODE_AUTO) || + ((wireless_mode & bSupportMode) == 0)) { + if (bSupportMode & WIRELESS_MODE_N_24G) { + wireless_mode = WIRELESS_MODE_N_24G; + } else if (bSupportMode & WIRELESS_MODE_N_5G) { + wireless_mode = WIRELESS_MODE_N_5G; + } else if ((bSupportMode & WIRELESS_MODE_A)) { + wireless_mode = WIRELESS_MODE_A; + } else if ((bSupportMode & WIRELESS_MODE_G)) { + wireless_mode = WIRELESS_MODE_G; + } else if ((bSupportMode & WIRELESS_MODE_B)) { + wireless_mode = WIRELESS_MODE_B; + } else { + RT_TRACE(COMP_ERR, + "%s(), No valid wireless mode supported (%x)!!!\n", + __func__, bSupportMode); + wireless_mode = WIRELESS_MODE_B; + } + } + + if ((wireless_mode & (WIRELESS_MODE_B | WIRELESS_MODE_G)) == + (WIRELESS_MODE_G | WIRELESS_MODE_B)) + wireless_mode = WIRELESS_MODE_G; + + priv->rtllib->mode = wireless_mode; + + ActUpdateChannelAccessSetting(dev, wireless_mode, + &priv->ChannelAccessSetting); + + if ((wireless_mode == WIRELESS_MODE_N_24G) || + (wireless_mode == WIRELESS_MODE_N_5G)) { + priv->rtllib->pHTInfo->bEnableHT = 1; + RT_TRACE(COMP_DBG, "%s(), wireless_mode:%x, bEnableHT = 1\n", + __func__, wireless_mode); + } else { + priv->rtllib->pHTInfo->bEnableHT = 0; + RT_TRACE(COMP_DBG, "%s(), wireless_mode:%x, bEnableHT = 0\n", + __func__, wireless_mode); + } + + RT_TRACE(COMP_INIT, "Current Wireless Mode is %x\n", wireless_mode); + rtl8192_refresh_supportrate(priv); +} + +static int _rtl8192_sta_up(struct net_device *dev, bool is_silent_reset) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct rt_pwr_save_ctrl *pPSC = (struct rt_pwr_save_ctrl *) + (&(priv->rtllib->PowerSaveControl)); + bool init_status = true; + + priv->bDriverIsGoingToUnload = false; + priv->bdisable_nic = false; + + priv->up = 1; + priv->rtllib->ieee_up = 1; + + priv->up_first_time = 0; + RT_TRACE(COMP_INIT, "Bringing up iface"); + priv->bfirst_init = true; + init_status = priv->ops->initialize_adapter(dev); + if (!init_status) { + RT_TRACE(COMP_ERR, "ERR!!! %s(): initialization is failed!\n", + __func__); + priv->bfirst_init = false; + return -1; + } + + RT_TRACE(COMP_INIT, "start adapter finished\n"); + RT_CLEAR_PS_LEVEL(pPSC, RT_RF_OFF_LEVL_HALT_NIC); + priv->bfirst_init = false; + + if (priv->polling_timer_on == 0) + check_rfctrl_gpio_timer((unsigned long)dev); + + if (priv->rtllib->state != RTLLIB_LINKED) + rtllib_softmac_start_protocol(priv->rtllib, 0); + rtllib_reset_queue(priv->rtllib); + watch_dog_timer_callback((unsigned long) dev); + + if (!netif_queue_stopped(dev)) + netif_start_queue(dev); + else + netif_wake_queue(dev); + + return 0; +} + +static int rtl8192_sta_down(struct net_device *dev, bool shutdownrf) +{ + struct r8192_priv *priv = rtllib_priv(dev); + unsigned long flags = 0; + u8 RFInProgressTimeOut = 0; + + if (priv->up == 0) + return -1; + + if (priv->rtllib->rtllib_ips_leave != NULL) + priv->rtllib->rtllib_ips_leave(dev); + + if (priv->rtllib->state == RTLLIB_LINKED) + LeisurePSLeave(dev); + + priv->bDriverIsGoingToUnload = true; + priv->up = 0; + priv->rtllib->ieee_up = 0; + priv->bfirst_after_down = true; + RT_TRACE(COMP_DOWN, "==========>%s()\n", __func__); + if (!netif_queue_stopped(dev)) + netif_stop_queue(dev); + + priv->rtllib->wpa_ie_len = 0; + kfree(priv->rtllib->wpa_ie); + priv->rtllib->wpa_ie = NULL; + CamResetAllEntry(dev); + memset(priv->rtllib->swcamtable, 0, sizeof(struct sw_cam_table) * 32); + rtl8192_irq_disable(dev); + + del_timer_sync(&priv->watch_dog_timer); + rtl8192_cancel_deferred_work(priv); + cancel_delayed_work(&priv->rtllib->hw_wakeup_wq); + + rtllib_softmac_stop_protocol(priv->rtllib, 0, true); + spin_lock_irqsave(&priv->rf_ps_lock, flags); + while (priv->RFChangeInProgress) { + spin_unlock_irqrestore(&priv->rf_ps_lock, flags); + if (RFInProgressTimeOut > 100) { + spin_lock_irqsave(&priv->rf_ps_lock, flags); + break; + } + RT_TRACE(COMP_DBG, + "===>%s():RF is in progress, need to wait until rf change is done.\n", + __func__); + mdelay(1); + RFInProgressTimeOut++; + spin_lock_irqsave(&priv->rf_ps_lock, flags); + } + priv->RFChangeInProgress = true; + spin_unlock_irqrestore(&priv->rf_ps_lock, flags); + priv->ops->stop_adapter(dev, false); + spin_lock_irqsave(&priv->rf_ps_lock, flags); + priv->RFChangeInProgress = false; + spin_unlock_irqrestore(&priv->rf_ps_lock, flags); + udelay(100); + memset(&priv->rtllib->current_network, 0, + offsetof(struct rtllib_network, list)); + RT_TRACE(COMP_DOWN, "<==========%s()\n", __func__); + + return 0; +} + +static void rtl8192_init_priv_handler(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + priv->rtllib->softmac_hard_start_xmit = rtl8192_hard_start_xmit; + priv->rtllib->set_chan = rtl8192_set_chan; + priv->rtllib->link_change = priv->ops->link_change; + priv->rtllib->softmac_data_hard_start_xmit = rtl8192_hard_data_xmit; + priv->rtllib->data_hard_stop = rtl8192_data_hard_stop; + priv->rtllib->data_hard_resume = rtl8192_data_hard_resume; + priv->rtllib->check_nic_enough_desc = rtl8192_check_nic_enough_desc; + priv->rtllib->get_nic_desc_num = rtl8192_get_nic_desc_num; + priv->rtllib->handle_assoc_response = rtl8192_handle_assoc_response; + priv->rtllib->handle_beacon = rtl8192_handle_beacon; + priv->rtllib->SetWirelessMode = rtl8192_SetWirelessMode; + priv->rtllib->LeisurePSLeave = LeisurePSLeave; + priv->rtllib->SetBWModeHandler = rtl8192_SetBWMode; + priv->rf_set_chan = rtl8192_phy_SwChnl; + + priv->rtllib->start_send_beacons = rtl8192e_start_beacon; + priv->rtllib->stop_send_beacons = rtl8192_stop_beacon; + + priv->rtllib->sta_wake_up = rtl8192_hw_wakeup; + priv->rtllib->enter_sleep_state = rtl8192_hw_to_sleep; + priv->rtllib->ps_is_queue_empty = rtl8192_is_tx_queue_empty; + + priv->rtllib->GetNmodeSupportBySecCfg = rtl8192_GetNmodeSupportBySecCfg; + priv->rtllib->GetHalfNmodeSupportByAPsHandler = + rtl8192_GetHalfNmodeSupportByAPs; + + priv->rtllib->SetHwRegHandler = rtl8192e_SetHwReg; + priv->rtllib->AllowAllDestAddrHandler = rtl8192_AllowAllDestAddr; + priv->rtllib->SetFwCmdHandler = NULL; + priv->rtllib->InitialGainHandler = InitialGain819xPci; + priv->rtllib->rtllib_ips_leave_wq = rtllib_ips_leave_wq; + priv->rtllib->rtllib_ips_leave = rtllib_ips_leave; + + priv->rtllib->LedControlHandler = NULL; + priv->rtllib->UpdateBeaconInterruptHandler = NULL; + + priv->rtllib->ScanOperationBackupHandler = PHY_ScanOperationBackup8192; + + priv->rtllib->rtllib_rfkill_poll = NULL; +} + +static void rtl8192_init_priv_constant(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct rt_pwr_save_ctrl *pPSC = (struct rt_pwr_save_ctrl *) + &(priv->rtllib->PowerSaveControl); + + pPSC->RegMaxLPSAwakeIntvl = 5; + + priv->RegPciASPM = 2; + + priv->RegDevicePciASPMSetting = 0x03; + + priv->RegHostPciASPMSetting = 0x02; + + priv->RegHwSwRfOffD3 = 2; + + priv->RegSupportPciASPM = 2; +} + + +static void rtl8192_init_priv_variable(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + u8 i; + + priv->AcmMethod = eAcmWay2_SW; + priv->dot11CurrentPreambleMode = PREAMBLE_AUTO; + priv->rtllib->hwscan_sem_up = 1; + priv->rtllib->status = 0; + priv->H2CTxCmdSeq = 0; + priv->bDisableFrameBursting = false; + priv->bDMInitialGainEnable = true; + priv->polling_timer_on = 0; + priv->up_first_time = 1; + priv->blinked_ingpio = false; + priv->bDriverIsGoingToUnload = false; + priv->being_init_adapter = false; + priv->initialized_at_probe = false; + priv->sw_radio_on = true; + priv->bdisable_nic = false; + priv->bfirst_init = false; + priv->txringcount = 64; + priv->rxbuffersize = 9100; + priv->rxringcount = MAX_RX_COUNT; + priv->irq_enabled = 0; + priv->chan = 1; + priv->RegWirelessMode = WIRELESS_MODE_AUTO; + priv->RegChannelPlan = 0xf; + priv->nrxAMPDU_size = 0; + priv->nrxAMPDU_aggr_num = 0; + priv->last_rxdesc_tsf_high = 0; + priv->last_rxdesc_tsf_low = 0; + priv->rtllib->mode = WIRELESS_MODE_AUTO; + priv->rtllib->iw_mode = IW_MODE_INFRA; + priv->rtllib->bNetPromiscuousMode = false; + priv->rtllib->IntelPromiscuousModeInfo.bPromiscuousOn = false; + priv->rtllib->IntelPromiscuousModeInfo.bFilterSourceStationFrame = + false; + priv->rtllib->ieee_up = 0; + priv->retry_rts = DEFAULT_RETRY_RTS; + priv->retry_data = DEFAULT_RETRY_DATA; + priv->rtllib->rts = DEFAULT_RTS_THRESHOLD; + priv->rtllib->rate = 110; + priv->rtllib->short_slot = 1; + priv->promisc = (dev->flags & IFF_PROMISC) ? 1 : 0; + priv->bcck_in_ch14 = false; + priv->bfsync_processing = false; + priv->CCKPresentAttentuation = 0; + priv->rfa_txpowertrackingindex = 0; + priv->rfc_txpowertrackingindex = 0; + priv->CckPwEnl = 6; + priv->ScanDelay = 50; + priv->ResetProgress = RESET_TYPE_NORESET; + priv->bForcedSilentReset = false; + priv->bDisableNormalResetCheck = false; + priv->force_reset = false; + memset(priv->rtllib->swcamtable, 0, sizeof(struct sw_cam_table) * 32); + + memset(&priv->InterruptLog, 0, sizeof(struct log_int_8190)); + priv->RxCounter = 0; + priv->rtllib->wx_set_enc = 0; + priv->bHwRadioOff = false; + priv->RegRfOff = false; + priv->isRFOff = false; + priv->bInPowerSaveMode = false; + priv->rtllib->RfOffReason = 0; + priv->RFChangeInProgress = false; + priv->bHwRfOffAction = 0; + priv->SetRFPowerStateInProgress = false; + priv->rtllib->PowerSaveControl.bInactivePs = true; + priv->rtllib->PowerSaveControl.bIPSModeBackup = false; + priv->rtllib->PowerSaveControl.bLeisurePs = true; + priv->rtllib->PowerSaveControl.bFwCtrlLPS = false; + priv->rtllib->LPSDelayCnt = 0; + priv->rtllib->sta_sleep = LPS_IS_WAKE; + priv->rtllib->eRFPowerState = eRfOn; + + priv->txpower_checkcnt = 0; + priv->thermal_readback_index = 0; + priv->txpower_tracking_callback_cnt = 0; + priv->ccktxpower_adjustcnt_ch14 = 0; + priv->ccktxpower_adjustcnt_not_ch14 = 0; + + priv->rtllib->current_network.beacon_interval = DEFAULT_BEACONINTERVAL; + priv->rtllib->iw_mode = IW_MODE_INFRA; + priv->rtllib->active_scan = 1; + priv->rtllib->be_scan_inprogress = false; + priv->rtllib->modulation = RTLLIB_CCK_MODULATION | + RTLLIB_OFDM_MODULATION; + priv->rtllib->host_encrypt = 1; + priv->rtllib->host_decrypt = 1; + + priv->rtllib->dot11PowerSaveMode = eActive; + priv->rtllib->fts = DEFAULT_FRAG_THRESHOLD; + priv->rtllib->MaxMssDensity = 0; + priv->rtllib->MinSpaceCfg = 0; + + priv->card_type = PCI; + + priv->AcmControl = 0; + priv->pFirmware = vzalloc(sizeof(struct rt_firmware)); + if (!priv->pFirmware) + netdev_err(dev, + "rtl8192e: Unable to allocate space for firmware\n"); + + skb_queue_head_init(&priv->rx_queue); + skb_queue_head_init(&priv->skb_queue); + + for (i = 0; i < MAX_QUEUE_SIZE; i++) + skb_queue_head_init(&priv->rtllib->skb_waitQ[i]); + for (i = 0; i < MAX_QUEUE_SIZE; i++) + skb_queue_head_init(&priv->rtllib->skb_aggQ[i]); +} + +static void rtl8192_init_priv_lock(struct r8192_priv *priv) +{ + spin_lock_init(&priv->fw_scan_lock); + spin_lock_init(&priv->tx_lock); + spin_lock_init(&priv->irq_lock); + spin_lock_init(&priv->irq_th_lock); + spin_lock_init(&priv->rf_ps_lock); + spin_lock_init(&priv->ps_lock); + spin_lock_init(&priv->rf_lock); + spin_lock_init(&priv->rt_h2c_lock); + sema_init(&priv->wx_sem, 1); + sema_init(&priv->rf_sem, 1); + mutex_init(&priv->mutex); +} + +static void rtl8192_init_priv_task(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + priv->priv_wq = create_workqueue(DRV_NAME); + INIT_WORK_RSL(&priv->reset_wq, (void *)rtl8192_restart, dev); + INIT_WORK_RSL(&priv->rtllib->ips_leave_wq, (void *)IPSLeave_wq, dev); + INIT_DELAYED_WORK_RSL(&priv->watch_dog_wq, + (void *)rtl819x_watchdog_wqcallback, dev); + INIT_DELAYED_WORK_RSL(&priv->txpower_tracking_wq, + (void *)dm_txpower_trackingcallback, dev); + INIT_DELAYED_WORK_RSL(&priv->rfpath_check_wq, + (void *)dm_rf_pathcheck_workitemcallback, dev); + INIT_DELAYED_WORK_RSL(&priv->update_beacon_wq, + (void *)rtl8192_update_beacon, dev); + INIT_WORK_RSL(&priv->qos_activate, (void *)rtl8192_qos_activate, dev); + INIT_DELAYED_WORK_RSL(&priv->rtllib->hw_wakeup_wq, + (void *) rtl8192_hw_wakeup_wq, dev); + INIT_DELAYED_WORK_RSL(&priv->rtllib->hw_sleep_wq, + (void *) rtl8192_hw_sleep_wq, dev); + tasklet_init(&priv->irq_rx_tasklet, + (void(*)(unsigned long))rtl8192_irq_rx_tasklet, + (unsigned long)priv); + tasklet_init(&priv->irq_tx_tasklet, + (void(*)(unsigned long))rtl8192_irq_tx_tasklet, + (unsigned long)priv); + tasklet_init(&priv->irq_prepare_beacon_tasklet, + (void(*)(unsigned long))rtl8192_prepare_beacon, + (unsigned long)priv); +} + +static short rtl8192_get_channel_map(struct net_device *dev) +{ + int i; + + struct r8192_priv *priv = rtllib_priv(dev); + + if ((priv->rf_chip != RF_8225) && (priv->rf_chip != RF_8256) + && (priv->rf_chip != RF_6052)) { + RT_TRACE(COMP_ERR, + "%s: unknown rf chip, can't set channel map\n", + __func__); + return -1; + } + + if (priv->ChannelPlan >= COUNTRY_CODE_MAX) { + netdev_info(dev, + "rtl819x_init:Error channel plan! Set to default.\n"); + priv->ChannelPlan = COUNTRY_CODE_FCC; + } + RT_TRACE(COMP_INIT, "Channel plan is %d\n", priv->ChannelPlan); + dot11d_init(priv->rtllib); + Dot11d_Channelmap(priv->ChannelPlan, priv->rtllib); + for (i = 1; i <= 11; i++) + (priv->rtllib->active_channel_map)[i] = 1; + (priv->rtllib->active_channel_map)[12] = 2; + (priv->rtllib->active_channel_map)[13] = 2; + + return 0; +} + +static short rtl8192_init(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + memset(&(priv->stats), 0, sizeof(struct rt_stats)); + + rtl8192_init_priv_handler(dev); + rtl8192_init_priv_constant(dev); + rtl8192_init_priv_variable(dev); + rtl8192_init_priv_lock(priv); + rtl8192_init_priv_task(dev); + priv->ops->get_eeprom_size(dev); + priv->ops->init_adapter_variable(dev); + rtl8192_get_channel_map(dev); + + init_hal_dm(dev); + + init_timer(&priv->watch_dog_timer); + setup_timer(&priv->watch_dog_timer, + watch_dog_timer_callback, + (unsigned long) dev); + + init_timer(&priv->gpio_polling_timer); + setup_timer(&priv->gpio_polling_timer, + check_rfctrl_gpio_timer, + (unsigned long)dev); + + rtl8192_irq_disable(dev); + if (request_irq(dev->irq, rtl8192_interrupt, IRQF_SHARED, + dev->name, dev)) { + netdev_err(dev, "Error allocating IRQ %d", dev->irq); + return -1; + } + + priv->irq = dev->irq; + RT_TRACE(COMP_INIT, "IRQ %d\n", dev->irq); + + if (rtl8192_pci_initdescring(dev) != 0) { + netdev_err(dev, "Endopoints initialization failed"); + free_irq(dev->irq, dev); + return -1; + } + + return 0; +} + +/*************************************************************************** + -------------------------------WATCHDOG STUFF--------------------------- +***************************************************************************/ +short rtl8192_is_tx_queue_empty(struct net_device *dev) +{ + int i = 0; + struct r8192_priv *priv = rtllib_priv(dev); + + for (i = 0; i <= MGNT_QUEUE; i++) { + if ((i == TXCMD_QUEUE) || (i == HCCA_QUEUE)) + continue; + if (skb_queue_len(&(&priv->tx_ring[i])->queue) > 0) { + netdev_info(dev, "===>tx queue is not empty:%d, %d\n", + i, skb_queue_len(&(&priv->tx_ring[i])->queue)); + return 0; + } + } + return 1; +} + +static enum reset_type rtl819x_TxCheckStuck(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + u8 QueueID; + u8 ResetThreshold = NIC_SEND_HANG_THRESHOLD_POWERSAVE; + bool bCheckFwTxCnt = false; + struct rtl8192_tx_ring *ring = NULL; + struct sk_buff *skb = NULL; + struct cb_desc *tcb_desc = NULL; + unsigned long flags = 0; + + switch (priv->rtllib->ps) { + case RTLLIB_PS_DISABLED: + ResetThreshold = NIC_SEND_HANG_THRESHOLD_NORMAL; + break; + case (RTLLIB_PS_MBCAST|RTLLIB_PS_UNICAST): + ResetThreshold = NIC_SEND_HANG_THRESHOLD_POWERSAVE; + break; + default: + ResetThreshold = NIC_SEND_HANG_THRESHOLD_POWERSAVE; + break; + } + spin_lock_irqsave(&priv->irq_th_lock, flags); + for (QueueID = 0; QueueID < MAX_TX_QUEUE; QueueID++) { + if (QueueID == TXCMD_QUEUE) + continue; + + if (QueueID == BEACON_QUEUE) + continue; + + ring = &priv->tx_ring[QueueID]; + + if (skb_queue_len(&ring->queue) == 0) { + continue; + } else { + skb = (&ring->queue)->next; + tcb_desc = (struct cb_desc *)(skb->cb + + MAX_DEV_ADDR_SIZE); + tcb_desc->nStuckCount++; + bCheckFwTxCnt = true; + if (tcb_desc->nStuckCount > 1) + netdev_info(dev, + "%s: QueueID=%d tcb_desc->nStuckCount=%d\n", + __func__, QueueID, + tcb_desc->nStuckCount); + } + } + spin_unlock_irqrestore(&priv->irq_th_lock, flags); + + if (bCheckFwTxCnt) { + if (priv->ops->TxCheckStuckHandler(dev)) { + RT_TRACE(COMP_RESET, + "TxCheckStuck(): Fw indicates no Tx condition!\n"); + return RESET_TYPE_SILENT; + } + } + + return RESET_TYPE_NORESET; +} + +static enum reset_type rtl819x_RxCheckStuck(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + if (priv->ops->RxCheckStuckHandler(dev)) { + RT_TRACE(COMP_RESET, "RxStuck Condition\n"); + return RESET_TYPE_SILENT; + } + + return RESET_TYPE_NORESET; +} + +static enum reset_type rtl819x_ifcheck_resetornot(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + enum reset_type TxResetType = RESET_TYPE_NORESET; + enum reset_type RxResetType = RESET_TYPE_NORESET; + enum rt_rf_power_state rfState; + + rfState = priv->rtllib->eRFPowerState; + + if (rfState == eRfOn) + TxResetType = rtl819x_TxCheckStuck(dev); + + if (rfState == eRfOn && + (priv->rtllib->iw_mode == IW_MODE_INFRA) && + (priv->rtllib->state == RTLLIB_LINKED)) + RxResetType = rtl819x_RxCheckStuck(dev); + + if (TxResetType == RESET_TYPE_NORMAL || + RxResetType == RESET_TYPE_NORMAL) { + netdev_info(dev, "%s(): TxResetType is %d, RxResetType is %d\n", + __func__, TxResetType, RxResetType); + return RESET_TYPE_NORMAL; + } else if (TxResetType == RESET_TYPE_SILENT || + RxResetType == RESET_TYPE_SILENT) { + netdev_info(dev, "%s(): TxResetType is %d, RxResetType is %d\n", + __func__, TxResetType, RxResetType); + return RESET_TYPE_SILENT; + } else { + return RESET_TYPE_NORESET; + } + +} + +static void rtl819x_silentreset_mesh_bk(struct net_device *dev, u8 IsPortal) +{ +} + +static void rtl819x_ifsilentreset(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + u8 reset_times = 0; + int reset_status = 0; + struct rtllib_device *ieee = priv->rtllib; + unsigned long flag; + + u8 IsPortal = 0; + + + if (priv->ResetProgress == RESET_TYPE_NORESET) { + + RT_TRACE(COMP_RESET, "=========>Reset progress!!\n"); + + priv->ResetProgress = RESET_TYPE_SILENT; + + spin_lock_irqsave(&priv->rf_ps_lock, flag); + if (priv->RFChangeInProgress) { + spin_unlock_irqrestore(&priv->rf_ps_lock, flag); + goto END; + } + priv->RFChangeInProgress = true; + priv->bResetInProgress = true; + spin_unlock_irqrestore(&priv->rf_ps_lock, flag); + +RESET_START: + + down(&priv->wx_sem); + + if (priv->rtllib->state == RTLLIB_LINKED) + LeisurePSLeave(dev); + + if (priv->up) { + RT_TRACE(COMP_ERR, + "%s():the driver is not up! return\n", + __func__); + up(&priv->wx_sem); + return; + } + priv->up = 0; + + RT_TRACE(COMP_RESET, "%s():======>start to down the driver\n", + __func__); + mdelay(1000); + RT_TRACE(COMP_RESET, + "%s():111111111111111111111111======>start to down the driver\n", + __func__); + + if (!netif_queue_stopped(dev)) + netif_stop_queue(dev); + + rtl8192_irq_disable(dev); + del_timer_sync(&priv->watch_dog_timer); + rtl8192_cancel_deferred_work(priv); + deinit_hal_dm(dev); + rtllib_stop_scan_syncro(ieee); + + if (ieee->state == RTLLIB_LINKED) { + SEM_DOWN_IEEE_WX(&ieee->wx_sem); + netdev_info(dev, "ieee->state is RTLLIB_LINKED\n"); + rtllib_stop_send_beacons(priv->rtllib); + del_timer_sync(&ieee->associate_timer); + cancel_delayed_work(&ieee->associate_retry_wq); + rtllib_stop_scan(ieee); + netif_carrier_off(dev); + SEM_UP_IEEE_WX(&ieee->wx_sem); + } else { + netdev_info(dev, "ieee->state is NOT LINKED\n"); + rtllib_softmac_stop_protocol(priv->rtllib, 0 , true); + } + + dm_backup_dynamic_mechanism_state(dev); + + up(&priv->wx_sem); + RT_TRACE(COMP_RESET, + "%s():<==========down process is finished\n", + __func__); + + RT_TRACE(COMP_RESET, "%s():<===========up process start\n", + __func__); + reset_status = _rtl8192_up(dev, true); + + RT_TRACE(COMP_RESET, + "%s():<===========up process is finished\n", __func__); + if (reset_status == -1) { + if (reset_times < 3) { + reset_times++; + goto RESET_START; + } else { + RT_TRACE(COMP_ERR, + " ERR!!! %s(): Reset Failed!!\n", + __func__); + } + } + + ieee->is_silent_reset = 1; + + spin_lock_irqsave(&priv->rf_ps_lock, flag); + priv->RFChangeInProgress = false; + spin_unlock_irqrestore(&priv->rf_ps_lock, flag); + + EnableHWSecurityConfig8192(dev); + + if (ieee->state == RTLLIB_LINKED && ieee->iw_mode == + IW_MODE_INFRA) { + ieee->set_chan(ieee->dev, + ieee->current_network.channel); + + queue_work_rsl(ieee->wq, &ieee->associate_complete_wq); + + } else if (ieee->state == RTLLIB_LINKED && ieee->iw_mode == + IW_MODE_ADHOC) { + ieee->set_chan(ieee->dev, + ieee->current_network.channel); + ieee->link_change(ieee->dev); + + notify_wx_assoc_event(ieee); + + rtllib_start_send_beacons(ieee); + + if (ieee->data_hard_resume) + ieee->data_hard_resume(ieee->dev); + netif_carrier_on(ieee->dev); + } else if (ieee->iw_mode == IW_MODE_MESH) { + rtl819x_silentreset_mesh_bk(dev, IsPortal); + } + + CamRestoreAllEntry(dev); + dm_restore_dynamic_mechanism_state(dev); +END: + priv->ResetProgress = RESET_TYPE_NORESET; + priv->reset_count++; + + priv->bForcedSilentReset = false; + priv->bResetInProgress = false; + + write_nic_byte(dev, UFWP, 1); + RT_TRACE(COMP_RESET, "Reset finished!! ====>[%d]\n", + priv->reset_count); + } +} + +static void rtl819x_update_rxcounts(struct r8192_priv *priv, u32 *TotalRxBcnNum, + u32 *TotalRxDataNum) +{ + u16 SlotIndex; + u8 i; + + *TotalRxBcnNum = 0; + *TotalRxDataNum = 0; + + SlotIndex = (priv->rtllib->LinkDetectInfo.SlotIndex++) % + (priv->rtllib->LinkDetectInfo.SlotNum); + priv->rtllib->LinkDetectInfo.RxBcnNum[SlotIndex] = + priv->rtllib->LinkDetectInfo.NumRecvBcnInPeriod; + priv->rtllib->LinkDetectInfo.RxDataNum[SlotIndex] = + priv->rtllib->LinkDetectInfo.NumRecvDataInPeriod; + for (i = 0; i < priv->rtllib->LinkDetectInfo.SlotNum; i++) { + *TotalRxBcnNum += priv->rtllib->LinkDetectInfo.RxBcnNum[i]; + *TotalRxDataNum += priv->rtllib->LinkDetectInfo.RxDataNum[i]; + } +} + + +void rtl819x_watchdog_wqcallback(void *data) +{ + struct r8192_priv *priv = container_of_dwork_rsl(data, + struct r8192_priv, watch_dog_wq); + struct net_device *dev = priv->rtllib->dev; + struct rtllib_device *ieee = priv->rtllib; + enum reset_type ResetType = RESET_TYPE_NORESET; + static u8 check_reset_cnt; + unsigned long flags; + struct rt_pwr_save_ctrl *pPSC = (struct rt_pwr_save_ctrl *) + (&(priv->rtllib->PowerSaveControl)); + bool bBusyTraffic = false; + bool bHigherBusyTraffic = false; + bool bHigherBusyRxTraffic = false; + bool bEnterPS = false; + + if (!priv->up || priv->bHwRadioOff) + return; + + if (priv->rtllib->state >= RTLLIB_LINKED) { + if (priv->rtllib->CntAfterLink < 2) + priv->rtllib->CntAfterLink++; + } else { + priv->rtllib->CntAfterLink = 0; + } + + hal_dm_watchdog(dev); + + if (rtllib_act_scanning(priv->rtllib, false) == false) { + if ((ieee->iw_mode == IW_MODE_INFRA) && (ieee->state == + RTLLIB_NOLINK) && + (ieee->eRFPowerState == eRfOn) && !ieee->is_set_key && + (!ieee->proto_stoppping) && !ieee->wx_set_enc) { + if ((ieee->PowerSaveControl.ReturnPoint == + IPS_CALLBACK_NONE) && + (!ieee->bNetPromiscuousMode)) { + RT_TRACE(COMP_PS, + "====================>haha: IPSEnter()\n"); + IPSEnter(dev); + } + } + } + if ((ieee->state == RTLLIB_LINKED) && (ieee->iw_mode == + IW_MODE_INFRA) && (!ieee->bNetPromiscuousMode)) { + if (ieee->LinkDetectInfo.NumRxOkInPeriod > 100 || + ieee->LinkDetectInfo.NumTxOkInPeriod > 100) + bBusyTraffic = true; + + + if (ieee->LinkDetectInfo.NumRxOkInPeriod > 4000 || + ieee->LinkDetectInfo.NumTxOkInPeriod > 4000) { + bHigherBusyTraffic = true; + if (ieee->LinkDetectInfo.NumRxOkInPeriod > 5000) + bHigherBusyRxTraffic = true; + else + bHigherBusyRxTraffic = false; + } + + if (((ieee->LinkDetectInfo.NumRxUnicastOkInPeriod + + ieee->LinkDetectInfo.NumTxOkInPeriod) > 8) || + (ieee->LinkDetectInfo.NumRxUnicastOkInPeriod > 2)) + bEnterPS = false; + else + bEnterPS = true; + + if (ieee->current_network.beacon_interval < 95) + bEnterPS = false; + + if (bEnterPS) + LeisurePSEnter(dev); + else + LeisurePSLeave(dev); + + } else { + RT_TRACE(COMP_LPS, "====>no link LPS leave\n"); + LeisurePSLeave(dev); + } + + ieee->LinkDetectInfo.NumRxOkInPeriod = 0; + ieee->LinkDetectInfo.NumTxOkInPeriod = 0; + ieee->LinkDetectInfo.NumRxUnicastOkInPeriod = 0; + ieee->LinkDetectInfo.bBusyTraffic = bBusyTraffic; + + ieee->LinkDetectInfo.bHigherBusyTraffic = bHigherBusyTraffic; + ieee->LinkDetectInfo.bHigherBusyRxTraffic = bHigherBusyRxTraffic; + + if (ieee->state == RTLLIB_LINKED && ieee->iw_mode == IW_MODE_INFRA) { + u32 TotalRxBcnNum = 0; + u32 TotalRxDataNum = 0; + + rtl819x_update_rxcounts(priv, &TotalRxBcnNum, &TotalRxDataNum); + + if ((TotalRxBcnNum+TotalRxDataNum) == 0) + priv->check_roaming_cnt++; + else + priv->check_roaming_cnt = 0; + + + if (priv->check_roaming_cnt > 0) { + if (ieee->eRFPowerState == eRfOff) + RT_TRACE(COMP_ERR, "========>%s()\n", __func__); + + netdev_info(dev, + "===>%s(): AP is power off, chan:%d, connect another one\n", + __func__, priv->chan); + + ieee->state = RTLLIB_ASSOCIATING; + + RemovePeerTS(priv->rtllib, + priv->rtllib->current_network.bssid); + ieee->is_roaming = true; + ieee->is_set_key = false; + ieee->link_change(dev); + if (ieee->LedControlHandler) + ieee->LedControlHandler(ieee->dev, + LED_CTL_START_TO_LINK); + + notify_wx_assoc_event(ieee); + + if (!(ieee->rtllib_ap_sec_type(ieee) & + (SEC_ALG_CCMP|SEC_ALG_TKIP))) + queue_delayed_work_rsl(ieee->wq, + &ieee->associate_procedure_wq, 0); + + priv->check_roaming_cnt = 0; + } + ieee->LinkDetectInfo.NumRecvBcnInPeriod = 0; + ieee->LinkDetectInfo.NumRecvDataInPeriod = 0; + + } + + spin_lock_irqsave(&priv->tx_lock, flags); + if ((check_reset_cnt++ >= 3) && (!ieee->is_roaming) && + (!priv->RFChangeInProgress) && (!pPSC->bSwRfProcessing)) { + ResetType = rtl819x_ifcheck_resetornot(dev); + check_reset_cnt = 3; + } + spin_unlock_irqrestore(&priv->tx_lock, flags); + + if (!priv->bDisableNormalResetCheck && ResetType == RESET_TYPE_NORMAL) { + priv->ResetProgress = RESET_TYPE_NORMAL; + RT_TRACE(COMP_RESET, "%s(): NOMAL RESET\n", __func__); + return; + } + + if (((priv->force_reset) || (!priv->bDisableNormalResetCheck && + ResetType == RESET_TYPE_SILENT))) + rtl819x_ifsilentreset(dev); + priv->force_reset = false; + priv->bForcedSilentReset = false; + priv->bResetInProgress = false; + RT_TRACE(COMP_TRACE, " <==RtUsbCheckForHangWorkItemCallback()\n"); +} + +void watch_dog_timer_callback(unsigned long data) +{ + struct r8192_priv *priv = rtllib_priv((struct net_device *)data); + + queue_delayed_work_rsl(priv->priv_wq, &priv->watch_dog_wq, 0); + mod_timer(&priv->watch_dog_timer, jiffies + + msecs_to_jiffies(RTLLIB_WATCH_DOG_TIME)); +} + +/**************************************************************************** + ---------------------------- NIC TX/RX STUFF--------------------------- +*****************************************************************************/ +void rtl8192_rx_enable(struct net_device *dev) +{ + struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); + + priv->ops->rx_enable(dev); +} + +void rtl8192_tx_enable(struct net_device *dev) +{ + struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); + + priv->ops->tx_enable(dev); + + rtllib_reset_queue(priv->rtllib); +} + + +static void rtl8192_free_rx_ring(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + int i, rx_queue_idx; + + for (rx_queue_idx = 0; rx_queue_idx < MAX_RX_QUEUE; + rx_queue_idx++) { + for (i = 0; i < priv->rxringcount; i++) { + struct sk_buff *skb = priv->rx_buf[rx_queue_idx][i]; + + if (!skb) + continue; + + pci_unmap_single(priv->pdev, + *((dma_addr_t *)skb->cb), + priv->rxbuffersize, PCI_DMA_FROMDEVICE); + kfree_skb(skb); + } + + pci_free_consistent(priv->pdev, + sizeof(*priv->rx_ring[rx_queue_idx]) * + priv->rxringcount, + priv->rx_ring[rx_queue_idx], + priv->rx_ring_dma[rx_queue_idx]); + priv->rx_ring[rx_queue_idx] = NULL; + } +} + +static void rtl8192_free_tx_ring(struct net_device *dev, unsigned int prio) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct rtl8192_tx_ring *ring = &priv->tx_ring[prio]; + + while (skb_queue_len(&ring->queue)) { + struct tx_desc *entry = &ring->desc[ring->idx]; + struct sk_buff *skb = __skb_dequeue(&ring->queue); + + pci_unmap_single(priv->pdev, entry->TxBuffAddr, + skb->len, PCI_DMA_TODEVICE); + kfree_skb(skb); + ring->idx = (ring->idx + 1) % ring->entries; + } + + pci_free_consistent(priv->pdev, sizeof(*ring->desc)*ring->entries, + ring->desc, ring->dma); + ring->desc = NULL; +} + +void rtl8192_data_hard_stop(struct net_device *dev) +{ +} + + +void rtl8192_data_hard_resume(struct net_device *dev) +{ +} + +void rtl8192_hard_data_xmit(struct sk_buff *skb, struct net_device *dev, + int rate) +{ + struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); + int ret; + struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + + MAX_DEV_ADDR_SIZE); + u8 queue_index = tcb_desc->queue_index; + + if ((priv->rtllib->eRFPowerState == eRfOff) || !priv->up || + priv->bResetInProgress) { + kfree_skb(skb); + return; + } + + assert(queue_index != TXCMD_QUEUE); + + + memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev)); + skb_push(skb, priv->rtllib->tx_headroom); + ret = rtl8192_tx(dev, skb); + if (ret != 0) + kfree_skb(skb); + + if (queue_index != MGNT_QUEUE) { + priv->rtllib->stats.tx_bytes += (skb->len - + priv->rtllib->tx_headroom); + priv->rtllib->stats.tx_packets++; + } +} + +int rtl8192_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); + int ret; + struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + + MAX_DEV_ADDR_SIZE); + u8 queue_index = tcb_desc->queue_index; + + if (queue_index != TXCMD_QUEUE) { + if ((priv->rtllib->eRFPowerState == eRfOff) || + !priv->up || priv->bResetInProgress) { + kfree_skb(skb); + return 0; + } + } + + memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev)); + if (queue_index == TXCMD_QUEUE) { + rtl8192_tx_cmd(dev, skb); + return 0; + } + + tcb_desc->RATRIndex = 7; + tcb_desc->bTxDisableRateFallBack = 1; + tcb_desc->bTxUseDriverAssingedRate = 1; + tcb_desc->bTxEnableFwCalcDur = 1; + skb_push(skb, priv->rtllib->tx_headroom); + ret = rtl8192_tx(dev, skb); + if (ret != 0) + kfree_skb(skb); + return ret; +} + +static void rtl8192_tx_isr(struct net_device *dev, int prio) +{ + struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); + + struct rtl8192_tx_ring *ring = &priv->tx_ring[prio]; + + while (skb_queue_len(&ring->queue)) { + struct tx_desc *entry = &ring->desc[ring->idx]; + struct sk_buff *skb; + + if (prio != BEACON_QUEUE) { + if (entry->OWN) + return; + ring->idx = (ring->idx + 1) % ring->entries; + } + + skb = __skb_dequeue(&ring->queue); + pci_unmap_single(priv->pdev, entry->TxBuffAddr, + skb->len, PCI_DMA_TODEVICE); + + kfree_skb(skb); + } + if (prio != BEACON_QUEUE) + tasklet_schedule(&priv->irq_tx_tasklet); +} + +void rtl8192_tx_cmd(struct net_device *dev, struct sk_buff *skb) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct rtl8192_tx_ring *ring; + struct tx_desc_cmd *entry; + unsigned int idx; + struct cb_desc *tcb_desc; + unsigned long flags; + + spin_lock_irqsave(&priv->irq_th_lock, flags); + ring = &priv->tx_ring[TXCMD_QUEUE]; + + idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries; + entry = (struct tx_desc_cmd *) &ring->desc[idx]; + + tcb_desc = (struct cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); + + priv->ops->tx_fill_cmd_descriptor(dev, entry, tcb_desc, skb); + + __skb_queue_tail(&ring->queue, skb); + spin_unlock_irqrestore(&priv->irq_th_lock, flags); +} + +short rtl8192_tx(struct net_device *dev, struct sk_buff *skb) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct rtl8192_tx_ring *ring; + unsigned long flags; + struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + + MAX_DEV_ADDR_SIZE); + struct tx_desc *pdesc = NULL; + struct rtllib_hdr_1addr *header = NULL; + u16 fc = 0, type = 0, stype = 0; + bool multi_addr = false, broad_addr = false, uni_addr = false; + u8 *pda_addr = NULL; + int idx; + u32 fwinfo_size = 0; + + if (priv->bdisable_nic) { + RT_TRACE(COMP_ERR, + "%s: ERR!! Nic is disabled! Can't tx packet len=%d qidx=%d!!!\n", + __func__, skb->len, tcb_desc->queue_index); + return skb->len; + } + + priv->rtllib->bAwakePktSent = true; + + fwinfo_size = sizeof(struct tx_fwinfo_8190pci); + + header = (struct rtllib_hdr_1addr *)(((u8 *)skb->data) + fwinfo_size); + fc = le16_to_cpu(header->frame_ctl); + type = WLAN_FC_GET_TYPE(fc); + stype = WLAN_FC_GET_STYPE(fc); + pda_addr = header->addr1; + + if (is_broadcast_ether_addr(pda_addr)) + broad_addr = true; + else if (is_multicast_ether_addr(pda_addr)) + multi_addr = true; + else + uni_addr = true; + + if (uni_addr) + priv->stats.txbytesunicast += skb->len - fwinfo_size; + else if (multi_addr) + priv->stats.txbytesmulticast += skb->len - fwinfo_size; + else + priv->stats.txbytesbroadcast += skb->len - fwinfo_size; + + spin_lock_irqsave(&priv->irq_th_lock, flags); + ring = &priv->tx_ring[tcb_desc->queue_index]; + if (tcb_desc->queue_index != BEACON_QUEUE) + idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries; + else + idx = 0; + + pdesc = &ring->desc[idx]; + if ((pdesc->OWN == 1) && (tcb_desc->queue_index != BEACON_QUEUE)) { + RT_TRACE(COMP_ERR, + "No more TX desc@%d, ring->idx = %d, idx = %d, skblen = 0x%x queuelen=%d", + tcb_desc->queue_index, ring->idx, idx, skb->len, + skb_queue_len(&ring->queue)); + spin_unlock_irqrestore(&priv->irq_th_lock, flags); + return skb->len; + } + + if (type == RTLLIB_FTYPE_DATA) { + if (priv->rtllib->LedControlHandler) + priv->rtllib->LedControlHandler(dev, LED_CTL_TX); + } + priv->ops->tx_fill_descriptor(dev, pdesc, tcb_desc, skb); + __skb_queue_tail(&ring->queue, skb); + pdesc->OWN = 1; + spin_unlock_irqrestore(&priv->irq_th_lock, flags); + dev->trans_start = jiffies; + + write_nic_word(dev, TPPoll, 0x01 << tcb_desc->queue_index); + return 0; +} + +static short rtl8192_alloc_rx_desc_ring(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct rx_desc *entry = NULL; + int i, rx_queue_idx; + + for (rx_queue_idx = 0; rx_queue_idx < MAX_RX_QUEUE; rx_queue_idx++) { + priv->rx_ring[rx_queue_idx] = + pci_zalloc_consistent(priv->pdev, + sizeof(*priv->rx_ring[rx_queue_idx]) * priv->rxringcount, + &priv->rx_ring_dma[rx_queue_idx]); + if (!priv->rx_ring[rx_queue_idx] || + (unsigned long)priv->rx_ring[rx_queue_idx] & 0xFF) { + RT_TRACE(COMP_ERR, "Cannot allocate RX ring\n"); + return -ENOMEM; + } + + priv->rx_idx[rx_queue_idx] = 0; + + for (i = 0; i < priv->rxringcount; i++) { + struct sk_buff *skb = dev_alloc_skb(priv->rxbuffersize); + dma_addr_t *mapping; + + entry = &priv->rx_ring[rx_queue_idx][i]; + if (!skb) + return 0; + skb->dev = dev; + priv->rx_buf[rx_queue_idx][i] = skb; + mapping = (dma_addr_t *)skb->cb; + *mapping = pci_map_single(priv->pdev, + skb_tail_pointer_rsl(skb), + priv->rxbuffersize, + PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(priv->pdev, *mapping)) { + dev_kfree_skb_any(skb); + return -1; + } + entry->BufferAddress = *mapping; + + entry->Length = priv->rxbuffersize; + entry->OWN = 1; + } + + if(entry) + entry->EOR = 1; + } + return 0; +} + +static int rtl8192_alloc_tx_desc_ring(struct net_device *dev, + unsigned int prio, unsigned int entries) +{ + struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); + struct tx_desc *ring; + dma_addr_t dma; + int i; + + ring = pci_zalloc_consistent(priv->pdev, sizeof(*ring) * entries, &dma); + if (!ring || (unsigned long)ring & 0xFF) { + RT_TRACE(COMP_ERR, "Cannot allocate TX ring (prio = %d)\n", + prio); + return -ENOMEM; + } + + priv->tx_ring[prio].desc = ring; + priv->tx_ring[prio].dma = dma; + priv->tx_ring[prio].idx = 0; + priv->tx_ring[prio].entries = entries; + skb_queue_head_init(&priv->tx_ring[prio].queue); + + for (i = 0; i < entries; i++) + ring[i].NextDescAddress = + (u32)dma + ((i + 1) % entries) * + sizeof(*ring); + + return 0; +} + + +short rtl8192_pci_initdescring(struct net_device *dev) +{ + u32 ret; + int i; + struct r8192_priv *priv = rtllib_priv(dev); + + ret = rtl8192_alloc_rx_desc_ring(dev); + if (ret) + return ret; + + for (i = 0; i < MAX_TX_QUEUE_COUNT; i++) { + ret = rtl8192_alloc_tx_desc_ring(dev, i, priv->txringcount); + if (ret) + goto err_free_rings; + } + + return 0; + +err_free_rings: + rtl8192_free_rx_ring(dev); + for (i = 0; i < MAX_TX_QUEUE_COUNT; i++) + if (priv->tx_ring[i].desc) + rtl8192_free_tx_ring(dev, i); + return 1; +} + +void rtl8192_pci_resetdescring(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + int i, rx_queue_idx; + unsigned long flags = 0; + + for (rx_queue_idx = 0; rx_queue_idx < MAX_RX_QUEUE; rx_queue_idx++) { + if (priv->rx_ring[rx_queue_idx]) { + struct rx_desc *entry = NULL; + + for (i = 0; i < priv->rxringcount; i++) { + entry = &priv->rx_ring[rx_queue_idx][i]; + entry->OWN = 1; + } + priv->rx_idx[rx_queue_idx] = 0; + } + } + + spin_lock_irqsave(&priv->irq_th_lock, flags); + for (i = 0; i < MAX_TX_QUEUE_COUNT; i++) { + if (priv->tx_ring[i].desc) { + struct rtl8192_tx_ring *ring = &priv->tx_ring[i]; + + while (skb_queue_len(&ring->queue)) { + struct tx_desc *entry = &ring->desc[ring->idx]; + struct sk_buff *skb = + __skb_dequeue(&ring->queue); + + pci_unmap_single(priv->pdev, + entry->TxBuffAddr, + skb->len, PCI_DMA_TODEVICE); + kfree_skb(skb); + ring->idx = (ring->idx + 1) % ring->entries; + } + ring->idx = 0; + } + } + spin_unlock_irqrestore(&priv->irq_th_lock, flags); +} + +void rtl819x_UpdateRxPktTimeStamp(struct net_device *dev, + struct rtllib_rx_stats *stats) +{ + struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); + + if (stats->bIsAMPDU && !stats->bFirstMPDU) + stats->mac_time = priv->LastRxDescTSF; + else + priv->LastRxDescTSF = stats->mac_time; +} + +long rtl819x_translate_todbm(struct r8192_priv *priv, u8 signal_strength_index) +{ + long signal_power; + + signal_power = (long)((signal_strength_index + 1) >> 1); + signal_power -= 95; + + return signal_power; +} + + +void +rtl819x_update_rxsignalstatistics8190pci( + struct r8192_priv *priv, + struct rtllib_rx_stats *pprevious_stats + ) +{ + int weighting = 0; + + + if (priv->stats.recv_signal_power == 0) + priv->stats.recv_signal_power = + pprevious_stats->RecvSignalPower; + + if (pprevious_stats->RecvSignalPower > priv->stats.recv_signal_power) + weighting = 5; + else if (pprevious_stats->RecvSignalPower < + priv->stats.recv_signal_power) + weighting = (-5); + priv->stats.recv_signal_power = (priv->stats.recv_signal_power * 5 + + pprevious_stats->RecvSignalPower + + weighting) / 6; +} + +void rtl819x_process_cck_rxpathsel(struct r8192_priv *priv, + struct rtllib_rx_stats *pprevious_stats) +{ +} + + +u8 rtl819x_query_rxpwrpercentage(char antpower) +{ + if ((antpower <= -100) || (antpower >= 20)) + return 0; + else if (antpower >= 0) + return 100; + else + return 100 + antpower; + +} /* QueryRxPwrPercentage */ + +u8 +rtl819x_evm_dbtopercentage( + char value + ) +{ + char ret_val; + + ret_val = value; + + if (ret_val >= 0) + ret_val = 0; + if (ret_val <= -33) + ret_val = -33; + ret_val = 0 - ret_val; + ret_val *= 3; + if (ret_val == 99) + ret_val = 100; + return ret_val; +} + +void +rtl8192_record_rxdesc_forlateruse( + struct rtllib_rx_stats *psrc_stats, + struct rtllib_rx_stats *ptarget_stats +) +{ + ptarget_stats->bIsAMPDU = psrc_stats->bIsAMPDU; + ptarget_stats->bFirstMPDU = psrc_stats->bFirstMPDU; +} + + + +static void rtl8192_rx_normal(struct net_device *dev) +{ + struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); + struct rtllib_hdr_1addr *rtllib_hdr = NULL; + bool unicast_packet = false; + bool bLedBlinking = true; + u16 fc = 0, type = 0; + u32 skb_len = 0; + int rx_queue_idx = RX_MPDU_QUEUE; + + struct rtllib_rx_stats stats = { + .signal = 0, + .noise = -98, + .rate = 0, + .freq = RTLLIB_24GHZ_BAND, + }; + unsigned int count = priv->rxringcount; + + stats.nic_type = NIC_8192E; + + while (count--) { + struct rx_desc *pdesc = &priv->rx_ring[rx_queue_idx] + [priv->rx_idx[rx_queue_idx]]; + struct sk_buff *skb = priv->rx_buf[rx_queue_idx] + [priv->rx_idx[rx_queue_idx]]; + struct sk_buff *new_skb; + + if (pdesc->OWN) + return; + if (!priv->ops->rx_query_status_descriptor(dev, &stats, + pdesc, skb)) + goto done; + new_skb = dev_alloc_skb(priv->rxbuffersize); + /* if allocation of new skb failed - drop current packet + * and reuse skb + */ + if (unlikely(!new_skb)) + goto done; + + pci_unmap_single(priv->pdev, + *((dma_addr_t *)skb->cb), + priv->rxbuffersize, + PCI_DMA_FROMDEVICE); + + skb_put(skb, pdesc->Length); + skb_reserve(skb, stats.RxDrvInfoSize + + stats.RxBufShift); + skb_trim(skb, skb->len - 4/*sCrcLng*/); + rtllib_hdr = (struct rtllib_hdr_1addr *)skb->data; + if (!is_multicast_ether_addr(rtllib_hdr->addr1)) { + /* unicast packet */ + unicast_packet = true; + } + fc = le16_to_cpu(rtllib_hdr->frame_ctl); + type = WLAN_FC_GET_TYPE(fc); + if (type == RTLLIB_FTYPE_MGMT) + bLedBlinking = false; + + if (bLedBlinking) + if (priv->rtllib->LedControlHandler) + priv->rtllib->LedControlHandler(dev, + LED_CTL_RX); + + if (stats.bCRC) { + if (type != RTLLIB_FTYPE_MGMT) + priv->stats.rxdatacrcerr++; + else + priv->stats.rxmgmtcrcerr++; + } + + skb_len = skb->len; + + if (!rtllib_rx(priv->rtllib, skb, &stats)) { + dev_kfree_skb_any(skb); + } else { + priv->stats.rxok++; + if (unicast_packet) + priv->stats.rxbytesunicast += skb_len; + } + + skb = new_skb; + skb->dev = dev; + + priv->rx_buf[rx_queue_idx][priv->rx_idx[rx_queue_idx]] = + skb; + *((dma_addr_t *) skb->cb) = pci_map_single(priv->pdev, + skb_tail_pointer_rsl(skb), + priv->rxbuffersize, + PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(priv->pdev, + *((dma_addr_t *)skb->cb))) { + dev_kfree_skb_any(skb); + return; + } +done: + pdesc->BufferAddress = *((dma_addr_t *)skb->cb); + pdesc->OWN = 1; + pdesc->Length = priv->rxbuffersize; + if (priv->rx_idx[rx_queue_idx] == priv->rxringcount-1) + pdesc->EOR = 1; + priv->rx_idx[rx_queue_idx] = (priv->rx_idx[rx_queue_idx] + 1) % + priv->rxringcount; + } + +} + +static void rtl8192_rx_cmd(struct net_device *dev) +{ +} + + +static void rtl8192_tx_resume(struct net_device *dev) +{ + struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); + struct rtllib_device *ieee = priv->rtllib; + struct sk_buff *skb; + int queue_index; + + for (queue_index = BK_QUEUE; + queue_index < MAX_QUEUE_SIZE; queue_index++) { + while ((!skb_queue_empty(&ieee->skb_waitQ[queue_index])) && + (priv->rtllib->check_nic_enough_desc(dev, queue_index) > 0)) { + skb = skb_dequeue(&ieee->skb_waitQ[queue_index]); + ieee->softmac_data_hard_start_xmit(skb, dev, 0); + } + } +} + +void rtl8192_irq_tx_tasklet(struct r8192_priv *priv) +{ + rtl8192_tx_resume(priv->rtllib->dev); +} + +void rtl8192_irq_rx_tasklet(struct r8192_priv *priv) +{ + rtl8192_rx_normal(priv->rtllib->dev); + + if (MAX_RX_QUEUE > 1) + rtl8192_rx_cmd(priv->rtllib->dev); + + write_nic_dword(priv->rtllib->dev, INTA_MASK, + read_nic_dword(priv->rtllib->dev, INTA_MASK) | IMR_RDU); +} + +/**************************************************************************** + ---------------------------- NIC START/CLOSE STUFF--------------------------- +*****************************************************************************/ +void rtl8192_cancel_deferred_work(struct r8192_priv *priv) +{ + cancel_delayed_work(&priv->watch_dog_wq); + cancel_delayed_work(&priv->update_beacon_wq); + cancel_delayed_work(&priv->rtllib->hw_sleep_wq); + cancel_work_sync(&priv->reset_wq); + cancel_work_sync(&priv->qos_activate); +} + +int _rtl8192_up(struct net_device *dev, bool is_silent_reset) +{ + if (_rtl8192_sta_up(dev, is_silent_reset) == -1) + return -1; + return 0; +} + + +static int rtl8192_open(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + int ret; + + down(&priv->wx_sem); + ret = rtl8192_up(dev); + up(&priv->wx_sem); + return ret; + +} + + +int rtl8192_up(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + if (priv->up == 1) + return -1; + return _rtl8192_up(dev, false); +} + + +static int rtl8192_close(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + int ret; + + if ((rtllib_act_scanning(priv->rtllib, false)) && + !(priv->rtllib->softmac_features & IEEE_SOFTMAC_SCAN)) { + rtllib_stop_scan(priv->rtllib); + } + + down(&priv->wx_sem); + + ret = rtl8192_down(dev, true); + + up(&priv->wx_sem); + + return ret; + +} + +int rtl8192_down(struct net_device *dev, bool shutdownrf) +{ + if (rtl8192_sta_down(dev, shutdownrf) == -1) + return -1; + + return 0; +} + +void rtl8192_commit(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + if (priv->up == 0) + return; + rtllib_softmac_stop_protocol(priv->rtllib, 0 , true); + rtl8192_irq_disable(dev); + priv->ops->stop_adapter(dev, true); + _rtl8192_up(dev, false); +} + +void rtl8192_restart(void *data) +{ + struct r8192_priv *priv = container_of_work_rsl(data, struct r8192_priv, + reset_wq); + struct net_device *dev = priv->rtllib->dev; + + down(&priv->wx_sem); + + rtl8192_commit(dev); + + up(&priv->wx_sem); +} + +static void r8192_set_multicast(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + short promisc; + + promisc = (dev->flags & IFF_PROMISC) ? 1 : 0; + priv->promisc = promisc; + +} + + +static int r8192_set_mac_adr(struct net_device *dev, void *mac) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct sockaddr *addr = mac; + + down(&priv->wx_sem); + + ether_addr_copy(dev->dev_addr, addr->sa_data); + + schedule_work(&priv->reset_wq); + up(&priv->wx_sem); + + return 0; +} + +/* based on ipw2200 driver */ +static int rtl8192_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); + struct iwreq *wrq = (struct iwreq *)rq; + int ret = -1; + struct rtllib_device *ieee = priv->rtllib; + u32 key[4]; + u8 broadcast_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + u8 zero_addr[6] = {0}; + struct iw_point *p = &wrq->u.data; + struct ieee_param *ipw = NULL; + + down(&priv->wx_sem); + + switch (cmd) { + case RTL_IOCTL_WPA_SUPPLICANT: + if (p->length < sizeof(struct ieee_param) || !p->pointer) { + ret = -EINVAL; + goto out; + } + + ipw = memdup_user(p->pointer, p->length); + if (IS_ERR(ipw)) { + ret = PTR_ERR(ipw); + goto out; + } + + if (ipw->cmd == IEEE_CMD_SET_ENCRYPTION) { + if (ipw->u.crypt.set_tx) { + if (strcmp(ipw->u.crypt.alg, "CCMP") == 0) + ieee->pairwise_key_type = KEY_TYPE_CCMP; + else if (strcmp(ipw->u.crypt.alg, "TKIP") == 0) + ieee->pairwise_key_type = KEY_TYPE_TKIP; + else if (strcmp(ipw->u.crypt.alg, "WEP") == 0) { + if (ipw->u.crypt.key_len == 13) + ieee->pairwise_key_type = + KEY_TYPE_WEP104; + else if (ipw->u.crypt.key_len == 5) + ieee->pairwise_key_type = + KEY_TYPE_WEP40; + } else { + ieee->pairwise_key_type = KEY_TYPE_NA; + } + + if (ieee->pairwise_key_type) { + if (memcmp(ieee->ap_mac_addr, zero_addr, + 6) == 0) + ieee->iw_mode = IW_MODE_ADHOC; + memcpy((u8 *)key, ipw->u.crypt.key, 16); + EnableHWSecurityConfig8192(dev); + set_swcam(dev, 4, ipw->u.crypt.idx, + ieee->pairwise_key_type, + (u8 *)ieee->ap_mac_addr, + 0, key, 0); + setKey(dev, 4, ipw->u.crypt.idx, + ieee->pairwise_key_type, + (u8 *)ieee->ap_mac_addr, 0, key); + if (ieee->iw_mode == IW_MODE_ADHOC) { + set_swcam(dev, ipw->u.crypt.idx, + ipw->u.crypt.idx, + ieee->pairwise_key_type, + (u8 *)ieee->ap_mac_addr, + 0, key, 0); + setKey(dev, ipw->u.crypt.idx, + ipw->u.crypt.idx, + ieee->pairwise_key_type, + (u8 *)ieee->ap_mac_addr, + 0, key); + } + } + if ((ieee->pairwise_key_type == KEY_TYPE_CCMP) + && ieee->pHTInfo->bCurrentHTSupport) { + write_nic_byte(dev, 0x173, 1); + } + + } else { + memcpy((u8 *)key, ipw->u.crypt.key, 16); + if (strcmp(ipw->u.crypt.alg, "CCMP") == 0) + ieee->group_key_type = KEY_TYPE_CCMP; + else if (strcmp(ipw->u.crypt.alg, "TKIP") == 0) + ieee->group_key_type = KEY_TYPE_TKIP; + else if (strcmp(ipw->u.crypt.alg, "WEP") == 0) { + if (ipw->u.crypt.key_len == 13) + ieee->group_key_type = + KEY_TYPE_WEP104; + else if (ipw->u.crypt.key_len == 5) + ieee->group_key_type = + KEY_TYPE_WEP40; + } else + ieee->group_key_type = KEY_TYPE_NA; + + if (ieee->group_key_type) { + set_swcam(dev, ipw->u.crypt.idx, + ipw->u.crypt.idx, + ieee->group_key_type, + broadcast_addr, 0, key, 0); + setKey(dev, ipw->u.crypt.idx, + ipw->u.crypt.idx, + ieee->group_key_type, + broadcast_addr, 0, key); + } + } + } + + ret = rtllib_wpa_supplicant_ioctl(priv->rtllib, &wrq->u.data, + 0); + kfree(ipw); + break; + default: + ret = -EOPNOTSUPP; + break; + } + +out: + up(&priv->wx_sem); + + return ret; +} + + +static irqreturn_t rtl8192_interrupt(int irq, void *netdev) +{ + struct net_device *dev = (struct net_device *) netdev; + struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); + unsigned long flags; + u32 inta; + u32 intb; + + intb = 0; + + if (priv->irq_enabled == 0) + goto done; + + spin_lock_irqsave(&priv->irq_th_lock, flags); + + priv->ops->interrupt_recognized(dev, &inta, &intb); + priv->stats.shints++; + + if (!inta) { + spin_unlock_irqrestore(&priv->irq_th_lock, flags); + goto done; + } + + if (inta == 0xffff) { + spin_unlock_irqrestore(&priv->irq_th_lock, flags); + goto done; + } + + priv->stats.ints++; + + if (!netif_running(dev)) { + spin_unlock_irqrestore(&priv->irq_th_lock, flags); + goto done; + } + + if (inta & IMR_TBDOK) { + RT_TRACE(COMP_INTR, "beacon ok interrupt!\n"); + priv->stats.txbeaconokint++; + } + + if (inta & IMR_TBDER) { + RT_TRACE(COMP_INTR, "beacon ok interrupt!\n"); + priv->stats.txbeaconerr++; + } + + if (inta & IMR_BDOK) + RT_TRACE(COMP_INTR, "beacon interrupt!\n"); + + if (inta & IMR_MGNTDOK) { + RT_TRACE(COMP_INTR, "Manage ok interrupt!\n"); + priv->stats.txmanageokint++; + rtl8192_tx_isr(dev, MGNT_QUEUE); + spin_unlock_irqrestore(&priv->irq_th_lock, flags); + if (priv->rtllib->ack_tx_to_ieee) { + if (rtl8192_is_tx_queue_empty(dev)) { + priv->rtllib->ack_tx_to_ieee = 0; + rtllib_ps_tx_ack(priv->rtllib, 1); + } + } + spin_lock_irqsave(&priv->irq_th_lock, flags); + } + + if (inta & IMR_COMDOK) { + priv->stats.txcmdpktokint++; + rtl8192_tx_isr(dev, TXCMD_QUEUE); + } + + if (inta & IMR_HIGHDOK) + rtl8192_tx_isr(dev, HIGH_QUEUE); + + if (inta & IMR_ROK) { + priv->stats.rxint++; + priv->InterruptLog.nIMR_ROK++; + tasklet_schedule(&priv->irq_rx_tasklet); + } + + if (inta & IMR_BcnInt) { + RT_TRACE(COMP_INTR, "prepare beacon for interrupt!\n"); + tasklet_schedule(&priv->irq_prepare_beacon_tasklet); + } + + if (inta & IMR_RDU) { + RT_TRACE(COMP_INTR, "rx descriptor unavailable!\n"); + priv->stats.rxrdu++; + write_nic_dword(dev, INTA_MASK, + read_nic_dword(dev, INTA_MASK) & ~IMR_RDU); + tasklet_schedule(&priv->irq_rx_tasklet); + } + + if (inta & IMR_RXFOVW) { + RT_TRACE(COMP_INTR, "rx overflow !\n"); + priv->stats.rxoverflow++; + tasklet_schedule(&priv->irq_rx_tasklet); + } + + if (inta & IMR_TXFOVW) + priv->stats.txoverflow++; + + if (inta & IMR_BKDOK) { + RT_TRACE(COMP_INTR, "BK Tx OK interrupt!\n"); + priv->stats.txbkokint++; + priv->rtllib->LinkDetectInfo.NumTxOkInPeriod++; + rtl8192_tx_isr(dev, BK_QUEUE); + } + + if (inta & IMR_BEDOK) { + RT_TRACE(COMP_INTR, "BE TX OK interrupt!\n"); + priv->stats.txbeokint++; + priv->rtllib->LinkDetectInfo.NumTxOkInPeriod++; + rtl8192_tx_isr(dev, BE_QUEUE); + } + + if (inta & IMR_VIDOK) { + RT_TRACE(COMP_INTR, "VI TX OK interrupt!\n"); + priv->stats.txviokint++; + priv->rtllib->LinkDetectInfo.NumTxOkInPeriod++; + rtl8192_tx_isr(dev, VI_QUEUE); + } + + if (inta & IMR_VODOK) { + priv->stats.txvookint++; + RT_TRACE(COMP_INTR, "Vo TX OK interrupt!\n"); + priv->rtllib->LinkDetectInfo.NumTxOkInPeriod++; + rtl8192_tx_isr(dev, VO_QUEUE); + } + + spin_unlock_irqrestore(&priv->irq_th_lock, flags); + +done: + + return IRQ_HANDLED; +} + + + +/**************************************************************************** + ---------------------------- PCI_STUFF--------------------------- +*****************************************************************************/ +static const struct net_device_ops rtl8192_netdev_ops = { + .ndo_open = rtl8192_open, + .ndo_stop = rtl8192_close, + .ndo_tx_timeout = rtl8192_tx_timeout, + .ndo_do_ioctl = rtl8192_ioctl, + .ndo_set_rx_mode = r8192_set_multicast, + .ndo_set_mac_address = r8192_set_mac_adr, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, + .ndo_start_xmit = rtllib_xmit, +}; + +static int rtl8192_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + unsigned long ioaddr = 0; + struct net_device *dev = NULL; + struct r8192_priv *priv = NULL; + struct rtl819x_ops *ops = (struct rtl819x_ops *)(id->driver_data); + unsigned long pmem_start, pmem_len, pmem_flags; + int err = -ENOMEM; + bool bdma64 = false; + u8 revision_id; + + RT_TRACE(COMP_INIT, "Configuring chip resources"); + + if (pci_enable_device(pdev)) { + RT_TRACE(COMP_ERR, "Failed to enable PCI device"); + return -EIO; + } + + pci_set_master(pdev); + + if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { + if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) { + dev_info(&pdev->dev, + "Unable to obtain 32bit DMA for consistent allocations\n"); + goto err_pci_disable; + } + } + dev = alloc_rtllib(sizeof(struct r8192_priv)); + if (!dev) + goto err_pci_disable; + + err = -ENODEV; + if (bdma64) + dev->features |= NETIF_F_HIGHDMA; + + pci_set_drvdata(pdev, dev); + SET_NETDEV_DEV(dev, &pdev->dev); + priv = rtllib_priv(dev); + priv->rtllib = (struct rtllib_device *)netdev_priv_rsl(dev); + priv->pdev = pdev; + priv->rtllib->pdev = pdev; + if ((pdev->subsystem_vendor == PCI_VENDOR_ID_DLINK) && + (pdev->subsystem_device == 0x3304)) + priv->rtllib->bSupportRemoteWakeUp = 1; + else + priv->rtllib->bSupportRemoteWakeUp = 0; + + pmem_start = pci_resource_start(pdev, 1); + pmem_len = pci_resource_len(pdev, 1); + pmem_flags = pci_resource_flags(pdev, 1); + + if (!(pmem_flags & IORESOURCE_MEM)) { + RT_TRACE(COMP_ERR, "region #1 not a MMIO resource, aborting"); + goto err_rel_rtllib; + } + + dev_info(&pdev->dev, "Memory mapped space start: 0x%08lx\n", + pmem_start); + if (!request_mem_region(pmem_start, pmem_len, DRV_NAME)) { + RT_TRACE(COMP_ERR, "request_mem_region failed!"); + goto err_rel_rtllib; + } + + + ioaddr = (unsigned long)ioremap_nocache(pmem_start, pmem_len); + if (ioaddr == (unsigned long)NULL) { + RT_TRACE(COMP_ERR, "ioremap failed!"); + goto err_rel_mem; + } + + dev->mem_start = ioaddr; + dev->mem_end = ioaddr + pci_resource_len(pdev, 0); + + pci_read_config_byte(pdev, 0x08, &revision_id); + /* If the revisionid is 0x10, the device uses rtl8192se. */ + if (pdev->device == 0x8192 && revision_id == 0x10) + goto err_rel_mem; + + priv->ops = ops; + + if (rtl8192_pci_findadapter(pdev, dev) == false) + goto err_rel_mem; + + dev->irq = pdev->irq; + priv->irq = 0; + + dev->netdev_ops = &rtl8192_netdev_ops; + + dev->wireless_handlers = &r8192_wx_handlers_def; + dev->ethtool_ops = &rtl819x_ethtool_ops; + + dev->type = ARPHRD_ETHER; + dev->watchdog_timeo = HZ * 3; + + if (dev_alloc_name(dev, ifname) < 0) { + RT_TRACE(COMP_INIT, + "Oops: devname already taken! Trying wlan%%d...\n"); + dev_alloc_name(dev, ifname); + } + + RT_TRACE(COMP_INIT, "Driver probe completed1\n"); + if (rtl8192_init(dev) != 0) { + RT_TRACE(COMP_ERR, "Initialization failed"); + goto err_free_irq; + } + + netif_carrier_off(dev); + netif_stop_queue(dev); + + if (register_netdev(dev)) + goto err_free_irq; + RT_TRACE(COMP_INIT, "dev name: %s\n", dev->name); + + if (priv->polling_timer_on == 0) + check_rfctrl_gpio_timer((unsigned long)dev); + + RT_TRACE(COMP_INIT, "Driver probe completed\n"); + return 0; + +err_free_irq: + free_irq(dev->irq, dev); + priv->irq = 0; +err_rel_mem: + release_mem_region(pmem_start, pmem_len); +err_rel_rtllib: + free_rtllib(dev); + + DMESG("wlan driver load failed\n"); +err_pci_disable: + pci_disable_device(pdev); + return err; +} + +static void rtl8192_pci_disconnect(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct r8192_priv *priv; + u32 i; + + if (dev) { + unregister_netdev(dev); + + priv = rtllib_priv(dev); + + del_timer_sync(&priv->gpio_polling_timer); + cancel_delayed_work(&priv->gpio_change_rf_wq); + priv->polling_timer_on = 0; + rtl8192_down(dev, true); + deinit_hal_dm(dev); + if (priv->pFirmware) { + vfree(priv->pFirmware); + priv->pFirmware = NULL; + } + destroy_workqueue(priv->priv_wq); + rtl8192_free_rx_ring(dev); + for (i = 0; i < MAX_TX_QUEUE_COUNT; i++) + rtl8192_free_tx_ring(dev, i); + + if (priv->irq) { + dev_info(&pdev->dev, "Freeing irq %d\n", dev->irq); + free_irq(dev->irq, dev); + priv->irq = 0; + } + free_rtllib(dev); + + kfree(priv->scan_cmd); + + if (dev->mem_start != 0) { + iounmap((void __iomem *)dev->mem_start); + release_mem_region(pci_resource_start(pdev, 1), + pci_resource_len(pdev, 1)); + } + } else { + priv = rtllib_priv(dev); + } + + pci_disable_device(pdev); + RT_TRACE(COMP_DOWN, "wlan driver removed\n"); +} + +bool NicIFEnableNIC(struct net_device *dev) +{ + bool init_status = true; + struct r8192_priv *priv = rtllib_priv(dev); + struct rt_pwr_save_ctrl *pPSC = (struct rt_pwr_save_ctrl *) + (&(priv->rtllib->PowerSaveControl)); + + if (!priv->up) { + RT_TRACE(COMP_ERR, "ERR!!! %s(): Driver is already down!\n", + __func__); + priv->bdisable_nic = false; + return false; + } + + RT_TRACE(COMP_PS, "===========>%s()\n", __func__); + priv->bfirst_init = true; + init_status = priv->ops->initialize_adapter(dev); + if (!init_status) { + RT_TRACE(COMP_ERR, "ERR!!! %s(): initialization is failed!\n", + __func__); + priv->bdisable_nic = false; + return false; + } + RT_TRACE(COMP_INIT, "start adapter finished\n"); + RT_CLEAR_PS_LEVEL(pPSC, RT_RF_OFF_LEVL_HALT_NIC); + priv->bfirst_init = false; + + rtl8192_irq_enable(dev); + priv->bdisable_nic = false; + RT_TRACE(COMP_PS, "<===========%s()\n", __func__); + return init_status; +} +bool NicIFDisableNIC(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + u8 tmp_state = 0; + + RT_TRACE(COMP_PS, "=========>%s()\n", __func__); + priv->bdisable_nic = true; + tmp_state = priv->rtllib->state; + rtllib_softmac_stop_protocol(priv->rtllib, 0, false); + priv->rtllib->state = tmp_state; + rtl8192_cancel_deferred_work(priv); + rtl8192_irq_disable(dev); + + priv->ops->stop_adapter(dev, false); + RT_TRACE(COMP_PS, "<=========%s()\n", __func__); + + return true; +} + +static int __init rtl8192_pci_module_init(void) +{ + pr_info("\nLinux kernel driver for RTL8192E WLAN cards\n"); + pr_info("Copyright (c) 2007-2008, Realsil Wlan Driver\n"); + + if (0 != pci_register_driver(&rtl8192_pci_driver)) { + DMESG("No device found"); + /*pci_unregister_driver (&rtl8192_pci_driver);*/ + return -ENODEV; + } + return 0; +} + +static void __exit rtl8192_pci_module_exit(void) +{ + pci_unregister_driver(&rtl8192_pci_driver); + + RT_TRACE(COMP_DOWN, "Exiting"); +} + +void check_rfctrl_gpio_timer(unsigned long data) +{ + struct r8192_priv *priv = rtllib_priv((struct net_device *)data); + + priv->polling_timer_on = 1; + + queue_delayed_work_rsl(priv->priv_wq, &priv->gpio_change_rf_wq, 0); + + mod_timer(&priv->gpio_polling_timer, jiffies + + msecs_to_jiffies(RTLLIB_WATCH_DOG_TIME)); +} + +/*************************************************************************** + ------------------- module init / exit stubs ---------------- +****************************************************************************/ +module_init(rtl8192_pci_module_init); +module_exit(rtl8192_pci_module_exit); + +MODULE_DESCRIPTION("Linux driver for Realtek RTL819x WiFi cards"); +MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); +MODULE_VERSION(DRV_VERSION); +MODULE_LICENSE("GPL"); +MODULE_FIRMWARE(RTL8192E_BOOT_IMG_FW); +MODULE_FIRMWARE(RTL8192E_MAIN_IMG_FW); +MODULE_FIRMWARE(RTL8192E_DATA_IMG_FW); + +module_param(ifname, charp, S_IRUGO|S_IWUSR); +module_param(hwwep, int, S_IRUGO|S_IWUSR); +module_param(channels, int, S_IRUGO|S_IWUSR); + +MODULE_PARM_DESC(ifname, " Net interface name, wlan%d=default"); +MODULE_PARM_DESC(hwwep, " Try to use hardware WEP support(default use hw. set 0 to use software security)"); +MODULE_PARM_DESC(channels, " Channel bitmask for specific locales. NYI"); diff --git a/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_core.h new file mode 100644 index 000000000..d365af6eb --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -0,0 +1,1076 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * Based on the r8180 driver, which is: + * Copyright 2004-2005 Andrea Merello , et al. + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ + +#ifndef _RTL_CORE_H +#define _RTL_CORE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Need this defined before including local include files */ +#define DRV_NAME "rtl819xE" + +#include "../rtllib.h" + +#include "../dot11d.h" + +#include "r8192E_firmware.h" +#include "r8192E_hw.h" + +#include "r8190P_def.h" +#include "r8192E_dev.h" + +#include "rtl_eeprom.h" +#include "rtl_ps.h" +#include "rtl_pci.h" +#include "rtl_cam.h" + +#define DRV_COPYRIGHT \ + "Copyright(c) 2008 - 2010 Realsil Semiconductor Corporation" +#define DRV_AUTHOR "" +#define DRV_VERSION "0014.0401.2010" + +#define IS_HARDWARE_TYPE_819xP(_priv) \ + ((((struct r8192_priv *)rtllib_priv(dev))->card_8192 == NIC_8190P) || \ + (((struct r8192_priv *)rtllib_priv(dev))->card_8192 == NIC_8192E)) +#define IS_HARDWARE_TYPE_8192SE(_priv) \ + (((struct r8192_priv *)rtllib_priv(dev))->card_8192 == NIC_8192SE) +#define IS_HARDWARE_TYPE_8192CE(_priv) \ + (((struct r8192_priv *)rtllib_priv(dev))->card_8192 == NIC_8192CE) +#define IS_HARDWARE_TYPE_8192CU(_priv) \ + (((struct r8192_priv *)rtllib_priv(dev))->card_8192 == NIC_8192CU) +#define IS_HARDWARE_TYPE_8192DE(_priv) \ + (((struct r8192_priv *)rtllib_priv(dev))->card_8192 == NIC_8192DE) +#define IS_HARDWARE_TYPE_8192DU(_priv) \ + (((struct r8192_priv *)rtllib_priv(dev))->card_8192 == NIC_8192DU) + +#define RTL_PCI_DEVICE(vend, dev, cfg) \ + .vendor = (vend), .device = (dev), \ + .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID , \ + .driver_data = (kernel_ulong_t)&(cfg) + +#define RTL_MAX_SCAN_SIZE 128 + +#define RTL_RATE_MAX 30 + +#define TOTAL_CAM_ENTRY 32 +#define CAM_CONTENT_COUNT 8 + +#ifndef BIT +#define BIT(_i) (1<<(_i)) +#endif + +#define IS_ADAPTER_SENDS_BEACON(dev) 0 + +#define HAL_MEMORY_MAPPED_IO_RANGE_8190PCI 0x1000 +#define HAL_HW_PCI_REVISION_ID_8190PCI 0x00 +#define HAL_MEMORY_MAPPED_IO_RANGE_8192PCIE 0x4000 +#define HAL_HW_PCI_REVISION_ID_8192PCIE 0x01 +#define HAL_MEMORY_MAPPED_IO_RANGE_8192SE 0x4000 +#define HAL_HW_PCI_REVISION_ID_8192SE 0x10 +#define HAL_HW_PCI_REVISION_ID_8192CE 0x1 +#define HAL_MEMORY_MAPPED_IO_RANGE_8192CE 0x4000 +#define HAL_HW_PCI_REVISION_ID_8192DE 0x0 +#define HAL_MEMORY_MAPPED_IO_RANGE_8192DE 0x4000 + +#define HAL_HW_PCI_8180_DEVICE_ID 0x8180 +#define HAL_HW_PCI_8185_DEVICE_ID 0x8185 +#define HAL_HW_PCI_8188_DEVICE_ID 0x8188 +#define HAL_HW_PCI_8198_DEVICE_ID 0x8198 +#define HAL_HW_PCI_8190_DEVICE_ID 0x8190 +#define HAL_HW_PCI_8192_DEVICE_ID 0x8192 +#define HAL_HW_PCI_8192SE_DEVICE_ID 0x8192 +#define HAL_HW_PCI_8174_DEVICE_ID 0x8174 +#define HAL_HW_PCI_8173_DEVICE_ID 0x8173 +#define HAL_HW_PCI_8172_DEVICE_ID 0x8172 +#define HAL_HW_PCI_8171_DEVICE_ID 0x8171 +#define HAL_HW_PCI_0045_DEVICE_ID 0x0045 +#define HAL_HW_PCI_0046_DEVICE_ID 0x0046 +#define HAL_HW_PCI_0044_DEVICE_ID 0x0044 +#define HAL_HW_PCI_0047_DEVICE_ID 0x0047 +#define HAL_HW_PCI_700F_DEVICE_ID 0x700F +#define HAL_HW_PCI_701F_DEVICE_ID 0x701F +#define HAL_HW_PCI_DLINK_DEVICE_ID 0x3304 +#define HAL_HW_PCI_8192CET_DEVICE_ID 0x8191 +#define HAL_HW_PCI_8192CE_DEVICE_ID 0x8178 +#define HAL_HW_PCI_8191CE_DEVICE_ID 0x8177 +#define HAL_HW_PCI_8188CE_DEVICE_ID 0x8176 +#define HAL_HW_PCI_8192CU_DEVICE_ID 0x8191 +#define HAL_HW_PCI_8192DE_DEVICE_ID 0x092D +#define HAL_HW_PCI_8192DU_DEVICE_ID 0x092D + +#define RTL819X_DEFAULT_RF_TYPE RF_1T2R + +#define RTLLIB_WATCH_DOG_TIME 2000 + +#define MAX_DEV_ADDR_SIZE 8 /*support till 64 bit bus width OS*/ +#define MAX_FIRMWARE_INFORMATION_SIZE 32 +#define MAX_802_11_HEADER_LENGTH (40 + MAX_FIRMWARE_INFORMATION_SIZE) +#define ENCRYPTION_MAX_OVERHEAD 128 +#define MAX_FRAGMENT_COUNT 8 +#define MAX_TRANSMIT_BUFFER_SIZE \ + (1600 + (MAX_802_11_HEADER_LENGTH + ENCRYPTION_MAX_OVERHEAD) * \ + MAX_FRAGMENT_COUNT) + +#define scrclng 4 + +#define DEFAULT_FRAG_THRESHOLD 2342U +#define MIN_FRAG_THRESHOLD 256U +#define DEFAULT_BEACONINTERVAL 0x64U + +#define DEFAULT_SSID "" +#define DEFAULT_RETRY_RTS 7 +#define DEFAULT_RETRY_DATA 7 +#define PRISM_HDR_SIZE 64 + +#define PHY_RSSI_SLID_WIN_MAX 100 + +#define RTL_IOCTL_WPA_SUPPLICANT (SIOCIWFIRSTPRIV + 30) + +#define TxBBGainTableLength 37 +#define CCKTxBBGainTableLength 23 + +#define CHANNEL_PLAN_LEN 10 +#define sCrcLng 4 + +#define NIC_SEND_HANG_THRESHOLD_NORMAL 4 +#define NIC_SEND_HANG_THRESHOLD_POWERSAVE 8 + +#define MAX_TX_QUEUE 9 + +#define MAX_RX_QUEUE 1 + +#define MAX_RX_COUNT 64 +#define MAX_TX_QUEUE_COUNT 9 + +extern int hwwep; + +enum RTL819x_PHY_PARAM { + RTL819X_PHY_MACPHY_REG = 0, + RTL819X_PHY_MACPHY_REG_PG = 1, + RTL8188C_PHY_MACREG = 2, + RTL8192C_PHY_MACREG = 3, + RTL819X_PHY_REG = 4, + RTL819X_PHY_REG_1T2R = 5, + RTL819X_PHY_REG_to1T1R = 6, + RTL819X_PHY_REG_to1T2R = 7, + RTL819X_PHY_REG_to2T2R = 8, + RTL819X_PHY_REG_PG = 9, + RTL819X_AGC_TAB = 10, + RTL819X_PHY_RADIO_A = 11, + RTL819X_PHY_RADIO_A_1T = 12, + RTL819X_PHY_RADIO_A_2T = 13, + RTL819X_PHY_RADIO_B = 14, + RTL819X_PHY_RADIO_B_GM = 15, + RTL819X_PHY_RADIO_C = 16, + RTL819X_PHY_RADIO_D = 17, + RTL819X_EEPROM_MAP = 18, + RTL819X_EFUSE_MAP = 19, +}; + +enum nic_t { + NIC_UNKNOWN = 0, + NIC_8192E = 1, + NIC_8190P = 2, + NIC_8192SE = 4, + NIC_8192CE = 5, + NIC_8192CU = 6, + NIC_8192DE = 7, + NIC_8192DU = 8, +}; + +enum rt_eeprom_type { + EEPROM_93C46, + EEPROM_93C56, + EEPROM_BOOT_EFUSE, +}; + +enum dcmg_txcmd_op { + TXCMD_TXRA_HISTORY_CTRL = 0xFF900000, + TXCMD_RESET_TX_PKT_BUFF = 0xFF900001, + TXCMD_RESET_RX_PKT_BUFF = 0xFF900002, + TXCMD_SET_TX_DURATION = 0xFF900003, + TXCMD_SET_RX_RSSI = 0xFF900004, + TXCMD_SET_TX_PWR_TRACKING = 0xFF900005, + TXCMD_XXXX_CTRL, +}; + +enum rt_rf_type_819xu { + RF_TYPE_MIN = 0, + RF_8225, + RF_8256, + RF_8258, + RF_6052 = 4, + RF_PSEUDO_11N = 5, +}; + +enum rf_step { + RF_STEP_INIT = 0, + RF_STEP_NORMAL, + RF_STEP_MAX +}; + +enum rt_status { + RT_STATUS_SUCCESS, + RT_STATUS_FAILURE, + RT_STATUS_PENDING, + RT_STATUS_RESOURCE +}; + +enum rt_customer_id { + RT_CID_DEFAULT = 0, + RT_CID_8187_ALPHA0 = 1, + RT_CID_8187_SERCOMM_PS = 2, + RT_CID_8187_HW_LED = 3, + RT_CID_8187_NETGEAR = 4, + RT_CID_WHQL = 5, + RT_CID_819x_CAMEO = 6, + RT_CID_819x_RUNTOP = 7, + RT_CID_819x_Senao = 8, + RT_CID_TOSHIBA = 9, + RT_CID_819x_Netcore = 10, + RT_CID_Nettronix = 11, + RT_CID_DLINK = 12, + RT_CID_PRONET = 13, + RT_CID_COREGA = 14, + RT_CID_819x_ALPHA = 15, + RT_CID_819x_Sitecom = 16, + RT_CID_CCX = 17, + RT_CID_819x_Lenovo = 18, + RT_CID_819x_QMI = 19, + RT_CID_819x_Edimax_Belkin = 20, + RT_CID_819x_Sercomm_Belkin = 21, + RT_CID_819x_CAMEO1 = 22, + RT_CID_819x_MSI = 23, + RT_CID_819x_Acer = 24, + RT_CID_819x_HP = 27, + RT_CID_819x_CLEVO = 28, + RT_CID_819x_Arcadyan_Belkin = 29, + RT_CID_819x_SAMSUNG = 30, + RT_CID_819x_WNC_COREGA = 31, +}; + +enum reset_type { + RESET_TYPE_NORESET = 0x00, + RESET_TYPE_NORMAL = 0x01, + RESET_TYPE_SILENT = 0x02 +}; + +enum ic_inferiority_8192s { + IC_INFERIORITY_A = 0, + IC_INFERIORITY_B = 1, +}; + +enum pci_bridge_vendor { + PCI_BRIDGE_VENDOR_INTEL = 0x0, + PCI_BRIDGE_VENDOR_ATI, + PCI_BRIDGE_VENDOR_AMD, + PCI_BRIDGE_VENDOR_SIS , + PCI_BRIDGE_VENDOR_UNKNOWN, + PCI_BRIDGE_VENDOR_MAX , +}; + +struct buffer { + struct buffer *next; + u32 *buf; + dma_addr_t dma; + +}; + +struct rtl_reg_debug { + unsigned int cmd; + struct { + unsigned char type; + unsigned char addr; + unsigned char page; + unsigned char length; + } head; + unsigned char buf[0xff]; +}; + +struct rt_tx_rahis { + u32 cck[4]; + u32 ofdm[8]; + u32 ht_mcs[4][16]; +}; + +struct rt_smooth_data_4rf { + char elements[4][100]; + u32 index; + u32 TotalNum; + u32 TotalVal[4]; +}; + +struct rt_stats { + unsigned long txrdu; + unsigned long rxrdu; + unsigned long rxok; + unsigned long rxframgment; + unsigned long rxurberr; + unsigned long rxstaterr; + unsigned long rxdatacrcerr; + unsigned long rxmgmtcrcerr; + unsigned long rxcrcerrmin; + unsigned long rxcrcerrmid; + unsigned long rxcrcerrmax; + unsigned long received_rate_histogram[4][32]; + unsigned long received_preamble_GI[2][32]; + unsigned long rx_AMPDUsize_histogram[5]; + unsigned long rx_AMPDUnum_histogram[5]; + unsigned long numpacket_matchbssid; + unsigned long numpacket_toself; + unsigned long num_process_phyinfo; + unsigned long numqry_phystatus; + unsigned long numqry_phystatusCCK; + unsigned long numqry_phystatusHT; + unsigned long received_bwtype[5]; + unsigned long txnperr; + unsigned long txnpdrop; + unsigned long txresumed; + unsigned long rxoverflow; + unsigned long rxint; + unsigned long txnpokint; + unsigned long ints; + unsigned long shints; + unsigned long txoverflow; + unsigned long txlpokint; + unsigned long txlpdrop; + unsigned long txlperr; + unsigned long txbeokint; + unsigned long txbedrop; + unsigned long txbeerr; + unsigned long txbkokint; + unsigned long txbkdrop; + unsigned long txbkerr; + unsigned long txviokint; + unsigned long txvidrop; + unsigned long txvierr; + unsigned long txvookint; + unsigned long txvodrop; + unsigned long txvoerr; + unsigned long txbeaconokint; + unsigned long txbeacondrop; + unsigned long txbeaconerr; + unsigned long txmanageokint; + unsigned long txmanagedrop; + unsigned long txmanageerr; + unsigned long txcmdpktokint; + unsigned long txdatapkt; + unsigned long txfeedback; + unsigned long txfeedbackok; + unsigned long txoktotal; + unsigned long txokbytestotal; + unsigned long txokinperiod; + unsigned long txmulticast; + unsigned long txbytesmulticast; + unsigned long txbroadcast; + unsigned long txbytesbroadcast; + unsigned long txunicast; + unsigned long txbytesunicast; + unsigned long rxbytesunicast; + unsigned long txfeedbackfail; + unsigned long txerrtotal; + unsigned long txerrbytestotal; + unsigned long txerrmulticast; + unsigned long txerrbroadcast; + unsigned long txerrunicast; + unsigned long txretrycount; + unsigned long txfeedbackretry; + u8 last_packet_rate; + unsigned long slide_signal_strength[100]; + unsigned long slide_evm[100]; + unsigned long slide_rssi_total; + unsigned long slide_evm_total; + long signal_strength; + long signal_quality; + long last_signal_strength_inpercent; + long recv_signal_power; + u8 rx_rssi_percentage[4]; + u8 rx_evm_percentage[2]; + long rxSNRdB[4]; + struct rt_tx_rahis txrate; + u32 Slide_Beacon_pwdb[100]; + u32 Slide_Beacon_Total; + struct rt_smooth_data_4rf cck_adc_pwdb; + u32 CurrentShowTxate; +}; + +struct channel_access_setting { + u16 SIFS_Timer; + u16 DIFS_Timer; + u16 SlotTimeTimer; + u16 EIFS_Timer; + u16 CWminIndex; + u16 CWmaxIndex; +}; + +enum two_port_status { + TWO_PORT_STATUS__DEFAULT_ONLY, + TWO_PORT_STATUS__EXTENSION_ONLY, + TWO_PORT_STATUS__EXTENSION_FOLLOW_DEFAULT, + TWO_PORT_STATUS__DEFAULT_G_EXTENSION_N20, + TWO_PORT_STATUS__ADHOC, + TWO_PORT_STATUS__WITHOUT_ANY_ASSOCIATE +}; + +struct txbbgain_struct { + long txbb_iq_amplifygain; + u32 txbbgain_value; +}; + +struct ccktxbbgain { + u8 ccktxbb_valuearray[8]; +}; + +struct init_gain { + u8 xaagccore1; + u8 xbagccore1; + u8 xcagccore1; + u8 xdagccore1; + u8 cca; + +}; + +struct tx_ring { + u32 *desc; + u8 nStuckCount; + struct tx_ring *next; +} __packed; + +struct rtl8192_tx_ring { + struct tx_desc *desc; + dma_addr_t dma; + unsigned int idx; + unsigned int entries; + struct sk_buff_head queue; +}; + + + +struct rtl819x_ops { + enum nic_t nic_type; + void (*get_eeprom_size)(struct net_device *dev); + void (*init_adapter_variable)(struct net_device *dev); + void (*init_before_adapter_start)(struct net_device *dev); + bool (*initialize_adapter)(struct net_device *dev); + void (*link_change)(struct net_device *dev); + void (*tx_fill_descriptor)(struct net_device *dev, + struct tx_desc *tx_desc, + struct cb_desc *cb_desc, + struct sk_buff *skb); + void (*tx_fill_cmd_descriptor)(struct net_device *dev, + struct tx_desc_cmd *entry, + struct cb_desc *cb_desc, + struct sk_buff *skb); + bool (*rx_query_status_descriptor)(struct net_device *dev, + struct rtllib_rx_stats *stats, + struct rx_desc *pdesc, + struct sk_buff *skb); + bool (*rx_command_packet_handler)(struct net_device *dev, + struct sk_buff *skb, + struct rx_desc *pdesc); + void (*stop_adapter)(struct net_device *dev, bool reset); + void (*update_ratr_table)(struct net_device *dev); + void (*irq_enable)(struct net_device *dev); + void (*irq_disable)(struct net_device *dev); + void (*irq_clear)(struct net_device *dev); + void (*rx_enable)(struct net_device *dev); + void (*tx_enable)(struct net_device *dev); + void (*interrupt_recognized)(struct net_device *dev, + u32 *p_inta, u32 *p_intb); + bool (*TxCheckStuckHandler)(struct net_device *dev); + bool (*RxCheckStuckHandler)(struct net_device *dev); +}; + +struct r8192_priv { + struct pci_dev *pdev; + struct pci_dev *bridge_pdev; + + bool bfirst_init; + bool bfirst_after_down; + bool initialized_at_probe; + bool being_init_adapter; + bool bDriverIsGoingToUnload; + + int irq; + short irq_enabled; + + short up; + short up_first_time; + struct delayed_work update_beacon_wq; + struct delayed_work watch_dog_wq; + struct delayed_work txpower_tracking_wq; + struct delayed_work rfpath_check_wq; + struct delayed_work gpio_change_rf_wq; + struct delayed_work initialgain_operate_wq; + struct delayed_work check_hw_scan_wq; + struct delayed_work hw_scan_simu_wq; + struct delayed_work start_hw_scan_wq; + + struct workqueue_struct *priv_wq; + + struct channel_access_setting ChannelAccessSetting; + + struct mp_adapter NdisAdapter; + + struct rtl819x_ops *ops; + struct rtllib_device *rtllib; + + struct work_struct reset_wq; + + struct log_int_8190 InterruptLog; + + enum rt_customer_id CustomerID; + + + enum rt_rf_type_819xu rf_chip; + enum ic_inferiority_8192s IC_Class; + enum ht_channel_width CurrentChannelBW; + struct bb_reg_definition PHYRegDef[4]; + struct rate_adaptive rate_adaptive; + + struct ccktxbbgain cck_txbbgain_table[CCKTxBBGainTableLength]; + struct ccktxbbgain cck_txbbgain_ch14_table[CCKTxBBGainTableLength]; + + struct txbbgain_struct txbbgain_table[TxBBGainTableLength]; + + enum acm_method AcmMethod; + + struct rt_firmware *pFirmware; + enum rtl819x_loopback LoopbackMode; + + struct timer_list watch_dog_timer; + struct timer_list fsync_timer; + struct timer_list gpio_polling_timer; + + spinlock_t fw_scan_lock; + spinlock_t irq_lock; + spinlock_t irq_th_lock; + spinlock_t tx_lock; + spinlock_t rf_ps_lock; + spinlock_t rw_lock; + spinlock_t rt_h2c_lock; + spinlock_t rf_lock; + spinlock_t ps_lock; + + struct sk_buff_head rx_queue; + struct sk_buff_head skb_queue; + + struct tasklet_struct irq_rx_tasklet; + struct tasklet_struct irq_tx_tasklet; + struct tasklet_struct irq_prepare_beacon_tasklet; + + struct semaphore wx_sem; + struct semaphore rf_sem; + struct mutex mutex; + + struct rt_stats stats; + struct iw_statistics wstats; + struct proc_dir_entry *dir_dev; + + short (*rf_set_sens)(struct net_device *dev, short sens); + u8 (*rf_set_chan)(struct net_device *dev, u8 ch); + void (*rf_close)(struct net_device *dev); + void (*rf_init)(struct net_device *dev); + + struct rx_desc *rx_ring[MAX_RX_QUEUE]; + struct sk_buff *rx_buf[MAX_RX_QUEUE][MAX_RX_COUNT]; + dma_addr_t rx_ring_dma[MAX_RX_QUEUE]; + unsigned int rx_idx[MAX_RX_QUEUE]; + int rxringcount; + u16 rxbuffersize; + + u64 LastRxDescTSF; + + u16 EarlyRxThreshold; + u32 ReceiveConfig; + u8 AcmControl; + u8 RFProgType; + u8 retry_data; + u8 retry_rts; + u16 rts; + + struct rtl8192_tx_ring tx_ring[MAX_TX_QUEUE_COUNT]; + int txringcount; + int txbuffsize; + int txfwbuffersize; + atomic_t tx_pending[0x10]; + + u16 ShortRetryLimit; + u16 LongRetryLimit; + u32 TransmitConfig; + u8 RegCWinMin; + u8 keepAliveLevel; + + bool sw_radio_on; + bool bHwRadioOff; + bool pwrdown; + bool blinked_ingpio; + u8 polling_timer_on; + + /**********************************************************/ + + enum card_type { + PCI, MINIPCI, + CARDBUS, USB + } card_type; + + struct work_struct qos_activate; + + u8 bIbssCoordinator; + + short promisc; + short crcmon; + + int txbeaconcount; + + short chan; + short sens; + short max_sens; + u32 rx_prevlen; + + u8 ScanDelay; + bool ps_force; + + u32 irq_mask[2]; + + u8 Rf_Mode; + enum nic_t card_8192; + u8 card_8192_version; + + short enable_gpio0; + + u8 rf_type; + u8 IC_Cut; + char nick[IW_ESSID_MAX_SIZE + 1]; + + u8 RegBcnCtrlVal; + bool bHwAntDiv; + + bool bTKIPinNmodeFromReg; + bool bWEPinNmodeFromReg; + + bool bLedOpenDrain; + + u8 check_roaming_cnt; + + bool bIgnoreSilentReset; + u32 SilentResetRxSoltNum; + u32 SilentResetRxSlotIndex; + u32 SilentResetRxStuckEvent[MAX_SILENT_RESET_RX_SLOT_NUM]; + + void *scan_cmd; + u8 hwscan_bw_40; + + u16 nrxAMPDU_size; + u8 nrxAMPDU_aggr_num; + + u32 last_rxdesc_tsf_high; + u32 last_rxdesc_tsf_low; + + u16 basic_rate; + u8 short_preamble; + u8 dot11CurrentPreambleMode; + u8 slot_time; + u16 SifsTime; + + u8 RegWirelessMode; + + u8 firmware_version; + u16 FirmwareSubVersion; + u16 rf_pathmap; + bool AutoloadFailFlag; + + u8 RegPciASPM; + u8 RegAMDPciASPM; + u8 RegHwSwRfOffD3; + u8 RegSupportPciASPM; + bool bSupportASPM; + + u32 RfRegChnlVal[2]; + + u8 ShowRateMode; + u8 RATRTableBitmap; + + u8 EfuseMap[2][HWSET_MAX_SIZE_92S]; + u16 EfuseUsedBytes; + u8 EfuseUsedPercentage; + + short epromtype; + u16 eeprom_vid; + u16 eeprom_did; + u16 eeprom_svid; + u16 eeprom_smid; + u8 eeprom_CustomerID; + u16 eeprom_ChannelPlan; + u8 eeprom_version; + + u8 EEPROMRegulatory; + u8 EEPROMPwrGroup[2][3]; + u8 EEPROMOptional; + + u8 EEPROMTxPowerLevelCCK[14]; + u8 EEPROMTxPowerLevelOFDM24G[14]; + u8 EEPROMTxPowerLevelOFDM5G[24]; + u8 EEPROMRfACCKChnl1TxPwLevel[3]; + u8 EEPROMRfAOfdmChnlTxPwLevel[3]; + u8 EEPROMRfCCCKChnl1TxPwLevel[3]; + u8 EEPROMRfCOfdmChnlTxPwLevel[3]; + u16 EEPROMTxPowerDiff; + u16 EEPROMAntPwDiff; + u8 EEPROMThermalMeter; + u8 EEPROMPwDiff; + u8 EEPROMCrystalCap; + + u8 EEPROMBluetoothCoexist; + u8 EEPROMBluetoothType; + u8 EEPROMBluetoothAntNum; + u8 EEPROMBluetoothAntIsolation; + u8 EEPROMBluetoothRadioShared; + + + u8 EEPROMSupportWoWLAN; + u8 EEPROMBoardType; + u8 EEPROM_Def_Ver; + u8 EEPROMHT2T_TxPwr[6]; + u8 EEPROMTSSI_A; + u8 EEPROMTSSI_B; + u8 EEPROMTxPowerLevelCCK_V1[3]; + u8 EEPROMLegacyHTTxPowerDiff; + + u8 BluetoothCoexist; + + u8 CrystalCap; + u8 ThermalMeter[2]; + + u16 FwCmdIOMap; + u32 FwCmdIOParam; + + u8 SwChnlInProgress; + u8 SwChnlStage; + u8 SwChnlStep; + u8 SetBWModeInProgress; + + u8 nCur40MhzPrimeSC; + + u32 RfReg0Value[4]; + u8 NumTotalRFPath; + bool brfpath_rxenable[4]; + + bool bTXPowerDataReadFromEEPORM; + + u16 RegChannelPlan; + u16 ChannelPlan; + bool bChnlPlanFromHW; + + bool RegRfOff; + bool isRFOff; + bool bInPowerSaveMode; + u8 bHwRfOffAction; + + bool aspm_clkreq_enable; + u32 pci_bridge_vendor; + u8 RegHostPciASPMSetting; + u8 RegDevicePciASPMSetting; + + bool RFChangeInProgress; + bool SetRFPowerStateInProgress; + bool bdisable_nic; + + u8 pwrGroupCnt; + + u8 ThermalValue_LCK; + u8 ThermalValue_IQK; + bool bRfPiEnable; + + u32 APKoutput[2][2]; + bool bAPKdone; + + long RegE94; + long RegE9C; + long RegEB4; + long RegEBC; + + u32 RegC04; + u32 Reg874; + u32 RegC08; + u32 ADDA_backup[16]; + u32 IQK_MAC_backup[3]; + + bool SetFwCmdInProgress; + u8 CurrentFwCmdIO; + + u8 rssi_level; + + bool bInformFWDriverControlDM; + u8 PwrGroupHT20[2][14]; + u8 PwrGroupHT40[2][14]; + + u8 ThermalValue; + long EntryMinUndecoratedSmoothedPWDB; + long EntryMaxUndecoratedSmoothedPWDB; + u8 DynamicTxHighPowerLvl; + u8 LastDTPLvl; + u32 CurrentRATR0; + struct false_alarm_stats FalseAlmCnt; + + u8 DMFlag; + u8 DM_Type; + + u8 CckPwEnl; + u16 TSSI_13dBm; + u32 Pwr_Track; + u8 CCKPresentAttentuation_20Mdefault; + u8 CCKPresentAttentuation_40Mdefault; + char CCKPresentAttentuation_difference; + char CCKPresentAttentuation; + u8 bCckHighPower; + long undecorated_smoothed_pwdb; + long undecorated_smoothed_cck_adc_pwdb[4]; + + u32 MCSTxPowerLevelOriginalOffset[6]; + u32 CCKTxPowerLevelOriginalOffset; + u8 TxPowerLevelCCK[14]; + u8 TxPowerLevelCCK_A[14]; + u8 TxPowerLevelCCK_C[14]; + u8 TxPowerLevelOFDM24G[14]; + u8 TxPowerLevelOFDM5G[14]; + u8 TxPowerLevelOFDM24G_A[14]; + u8 TxPowerLevelOFDM24G_C[14]; + u8 LegacyHTTxPowerDiff; + u8 TxPowerDiff; + s8 RF_C_TxPwDiff; + s8 RF_B_TxPwDiff; + u8 RfTxPwrLevelCck[2][14]; + u8 RfTxPwrLevelOfdm1T[2][14]; + u8 RfTxPwrLevelOfdm2T[2][14]; + u8 AntennaTxPwDiff[3]; + u8 TxPwrHt20Diff[2][14]; + u8 TxPwrLegacyHtDiff[2][14]; + u8 TxPwrSafetyFlag; + u8 HT2T_TxPwr_A[14]; + u8 HT2T_TxPwr_B[14]; + u8 CurrentCckTxPwrIdx; + u8 CurrentOfdm24GTxPwrIdx; + + bool bdynamic_txpower; + bool bDynamicTxHighPower; + bool bDynamicTxLowPower; + bool bLastDTPFlag_High; + bool bLastDTPFlag_Low; + + bool bstore_last_dtpflag; + bool bstart_txctrl_bydtp; + + u8 rfa_txpowertrackingindex; + u8 rfa_txpowertrackingindex_real; + u8 rfa_txpowertracking_default; + u8 rfc_txpowertrackingindex; + u8 rfc_txpowertrackingindex_real; + u8 rfc_txpowertracking_default; + bool btxpower_tracking; + bool bcck_in_ch14; + + u8 TxPowerTrackControl; + u8 txpower_count; + bool btxpower_trackingInit; + + u8 OFDM_index[2]; + u8 CCK_index; + + u8 Record_CCK_20Mindex; + u8 Record_CCK_40Mindex; + + struct init_gain initgain_backup; + u8 DefaultInitialGain[4]; + bool bis_any_nonbepkts; + bool bcurrent_turbo_EDCA; + bool bis_cur_rdlstate; + + bool bCCKinCH14; + + u8 MidHighPwrTHR_L1; + u8 MidHighPwrTHR_L2; + + bool bfsync_processing; + u32 rate_record; + u32 rateCountDiffRecord; + u32 ContinueDiffCount; + bool bswitch_fsync; + u8 framesync; + u32 framesyncC34; + u8 framesyncMonitor; + + bool bDMInitialGainEnable; + bool MutualAuthenticationFail; + + bool bDisableFrameBursting; + + u32 reset_count; + bool bpbc_pressed; + + u32 txpower_checkcnt; + u32 txpower_tracking_callback_cnt; + u8 thermal_read_val[40]; + u8 thermal_readback_index; + u32 ccktxpower_adjustcnt_not_ch14; + u32 ccktxpower_adjustcnt_ch14; + + enum reset_type ResetProgress; + bool bForcedSilentReset; + bool bDisableNormalResetCheck; + u16 TxCounter; + u16 RxCounter; + int IrpPendingCount; + bool bResetInProgress; + bool force_reset; + bool force_lps; + u8 InitialGainOperateType; + + bool chan_forced; + bool bSingleCarrier; + bool RegBoard; + bool bCckContTx; + bool bOfdmContTx; + bool bStartContTx; + u8 RegPaModel; + u8 btMpCckTxPower; + u8 btMpOfdmTxPower; + + u32 MptActType; + u32 MptIoOffset; + u32 MptIoValue; + u32 MptRfPath; + + u32 MptBandWidth; + u32 MptRateIndex; + u8 MptChannelToSw; + u32 MptRCR; + + u8 PwrDomainProtect; + u8 H2CTxCmdSeq; + + +}; + +extern const struct ethtool_ops rtl819x_ethtool_ops; + +void rtl8192_tx_cmd(struct net_device *dev, struct sk_buff *skb); +short rtl8192_tx(struct net_device *dev, struct sk_buff *skb); + +u8 read_nic_io_byte(struct net_device *dev, int x); +u32 read_nic_io_dword(struct net_device *dev, int x); +u16 read_nic_io_word(struct net_device *dev, int x); +void write_nic_io_byte(struct net_device *dev, int x, u8 y); +void write_nic_io_word(struct net_device *dev, int x, u16 y); +void write_nic_io_dword(struct net_device *dev, int x, u32 y); + +u8 read_nic_byte(struct net_device *dev, int x); +u32 read_nic_dword(struct net_device *dev, int x); +u16 read_nic_word(struct net_device *dev, int x); +void write_nic_byte(struct net_device *dev, int x, u8 y); +void write_nic_word(struct net_device *dev, int x, u16 y); +void write_nic_dword(struct net_device *dev, int x, u32 y); + +void force_pci_posting(struct net_device *dev); + +void rtl8192_rx_enable(struct net_device *); +void rtl8192_tx_enable(struct net_device *); + +int rtl8192_hard_start_xmit(struct sk_buff *skb, struct net_device *dev); +void rtl8192_hard_data_xmit(struct sk_buff *skb, struct net_device *dev, + int rate); +void rtl8192_data_hard_stop(struct net_device *dev); +void rtl8192_data_hard_resume(struct net_device *dev); +void rtl8192_restart(void *data); +void rtl819x_watchdog_wqcallback(void *data); +void rtl8192_hw_sleep_wq(void *data); +void watch_dog_timer_callback(unsigned long data); +void rtl8192_irq_rx_tasklet(struct r8192_priv *priv); +void rtl8192_irq_tx_tasklet(struct r8192_priv *priv); +int rtl8192_down(struct net_device *dev, bool shutdownrf); +int rtl8192_up(struct net_device *dev); +void rtl8192_commit(struct net_device *dev); +void rtl8192_set_chan(struct net_device *dev, short ch); + +void check_rfctrl_gpio_timer(unsigned long data); + +void rtl8192_hw_wakeup_wq(void *data); +short rtl8192_pci_initdescring(struct net_device *dev); + +void rtl8192_cancel_deferred_work(struct r8192_priv *priv); + +int _rtl8192_up(struct net_device *dev, bool is_silent_reset); + +short rtl8192_is_tx_queue_empty(struct net_device *dev); +void rtl8192_irq_disable(struct net_device *dev); + +void rtl8192_tx_timeout(struct net_device *dev); +void rtl8192_pci_resetdescring(struct net_device *dev); +void rtl8192_SetWirelessMode(struct net_device *dev, u8 wireless_mode); +void rtl8192_irq_enable(struct net_device *dev); +void rtl8192_config_rate(struct net_device *dev, u16 *rate_config); +void rtl8192_update_cap(struct net_device *dev, u16 cap); +void rtl8192_irq_disable(struct net_device *dev); + +void rtl819x_UpdateRxPktTimeStamp(struct net_device *dev, + struct rtllib_rx_stats *stats); +long rtl819x_translate_todbm(struct r8192_priv *priv, u8 signal_strength_index); +void rtl819x_update_rxsignalstatistics8190pci(struct r8192_priv *priv, + struct rtllib_rx_stats *pprevious_stats); +u8 rtl819x_evm_dbtopercentage(char value); +void rtl819x_process_cck_rxpathsel(struct r8192_priv *priv, + struct rtllib_rx_stats *pprevious_stats); +u8 rtl819x_query_rxpwrpercentage(char antpower); +void rtl8192_record_rxdesc_forlateruse(struct rtllib_rx_stats *psrc_stats, + struct rtllib_rx_stats *ptarget_stats); +bool NicIFEnableNIC(struct net_device *dev); +bool NicIFDisableNIC(struct net_device *dev); + +bool MgntActSet_RF_State(struct net_device *dev, + enum rt_rf_power_state StateToSet, + RT_RF_CHANGE_SOURCE ChangeSource, + bool ProtectOrNot); +void ActUpdateChannelAccessSetting(struct net_device *dev, + enum wireless_mode WirelessMode, + struct channel_access_setting *ChnlAccessSetting); + +#endif diff --git a/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_crypto.h b/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_crypto.h new file mode 100644 index 000000000..ee57c0f4f --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_crypto.h @@ -0,0 +1,382 @@ +/* + * Scatterlist Cryptographic API. + * + * Copyright (c) 2002 James Morris + * Copyright (c) 2002 David S. Miller (davem@redhat.com) + * + * Portions derived from Cryptoapi, by Alexander Kjeldaas + * and Nettle, by Niels Mé°ˆler. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ +#ifndef _LINUX_CRYPTO_H +#define _LINUX_CRYPTO_H + +#include +#include +#include +#include +#include +#include +#include + +#define crypto_register_alg crypto_register_alg_rsl +#define crypto_unregister_alg crypto_unregister_alg_rsl +#define crypto_alloc_tfm crypto_alloc_tfm_rsl +#define crypto_free_tfm crypto_free_tfm_rsl +#define crypto_alg_available crypto_alg_available_rsl + +/* + * Algorithm masks and types. + */ +#define CRYPTO_ALG_TYPE_MASK 0x000000ff +#define CRYPTO_ALG_TYPE_CIPHER 0x00000001 +#define CRYPTO_ALG_TYPE_DIGEST 0x00000002 +#define CRYPTO_ALG_TYPE_COMPRESS 0x00000004 + +/* + * Transform masks and values (for crt_flags). + */ +#define CRYPTO_TFM_MODE_MASK 0x000000ff +#define CRYPTO_TFM_REQ_MASK 0x000fff00 +#define CRYPTO_TFM_RES_MASK 0xfff00000 + +#define CRYPTO_TFM_MODE_ECB 0x00000001 +#define CRYPTO_TFM_MODE_CBC 0x00000002 +#define CRYPTO_TFM_MODE_CFB 0x00000004 +#define CRYPTO_TFM_MODE_CTR 0x00000008 + +#define CRYPTO_TFM_REQ_WEAK_KEY 0x00000100 +#define CRYPTO_TFM_RES_WEAK_KEY 0x00100000 +#define CRYPTO_TFM_RES_BAD_KEY_LEN 0x00200000 +#define CRYPTO_TFM_RES_BAD_KEY_SCHED 0x00400000 +#define CRYPTO_TFM_RES_BAD_BLOCK_LEN 0x00800000 +#define CRYPTO_TFM_RES_BAD_FLAGS 0x01000000 + +/* + * Miscellaneous stuff. + */ +#define CRYPTO_UNSPEC 0 +#define CRYPTO_MAX_ALG_NAME 64 + +struct scatterlist; + +/* + * Algorithms: modular crypto algorithm implementations, managed + * via crypto_register_alg() and crypto_unregister_alg(). + */ +struct cipher_alg { + unsigned int cia_min_keysize; + unsigned int cia_max_keysize; + int (*cia_setkey)(void *ctx, const u8 *key, + unsigned int keylen, u32 *flags); + void (*cia_encrypt)(void *ctx, u8 *dst, const u8 *src); + void (*cia_decrypt)(void *ctx, u8 *dst, const u8 *src); +}; + +struct digest_alg { + unsigned int dia_digestsize; + void (*dia_init)(void *ctx); + void (*dia_update)(void *ctx, const u8 *data, unsigned int len); + void (*dia_final)(void *ctx, u8 *out); + int (*dia_setkey)(void *ctx, const u8 *key, + unsigned int keylen, u32 *flags); +}; + +struct compress_alg { + int (*coa_init)(void *ctx); + void (*coa_exit)(void *ctx); + int (*coa_compress)(void *ctx, const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen); + int (*coa_decompress)(void *ctx, const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen); +}; + +#define cra_cipher cra_u.cipher +#define cra_digest cra_u.digest +#define cra_compress cra_u.compress + +struct crypto_alg { + struct list_head cra_list; + u32 cra_flags; + unsigned int cra_blocksize; + unsigned int cra_ctxsize; + const char cra_name[CRYPTO_MAX_ALG_NAME]; + + union { + struct cipher_alg cipher; + struct digest_alg digest; + struct compress_alg compress; + } cra_u; + + struct module *cra_module; +}; + +/* + * Algorithm registration interface. + */ +int crypto_register_alg(struct crypto_alg *alg); +int crypto_unregister_alg(struct crypto_alg *alg); + +/* + * Algorithm query interface. + */ +int crypto_alg_available(const char *name, u32 flags); + +/* + * Transforms: user-instantiated objects which encapsulate algorithms + * and core processing logic. Managed via crypto_alloc_tfm() and + * crypto_free_tfm(), as well as the various helpers below. + */ +struct crypto_tfm; + +struct cipher_tfm { + void *cit_iv; + unsigned int cit_ivsize; + u32 cit_mode; + int (*cit_setkey)(struct crypto_tfm *tfm, + const u8 *key, unsigned int keylen); + int (*cit_encrypt)(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes); + int (*cit_encrypt_iv)(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes, u8 *iv); + int (*cit_decrypt)(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes); + int (*cit_decrypt_iv)(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes, u8 *iv); + void (*cit_xor_block)(u8 *dst, const u8 *src); +}; + +struct digest_tfm { + void (*dit_init)(struct crypto_tfm *tfm); + void (*dit_update)(struct crypto_tfm *tfm, + struct scatterlist *sg, unsigned int nsg); + void (*dit_final)(struct crypto_tfm *tfm, u8 *out); + void (*dit_digest)(struct crypto_tfm *tfm, struct scatterlist *sg, + unsigned int nsg, u8 *out); + int (*dit_setkey)(struct crypto_tfm *tfm, + const u8 *key, unsigned int keylen); +}; + +struct compress_tfm { + int (*cot_compress)(struct crypto_tfm *tfm, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen); + int (*cot_decompress)(struct crypto_tfm *tfm, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen); +}; + +#define crt_cipher crt_u.cipher +#define crt_digest crt_u.digest +#define crt_compress crt_u.compress + +struct crypto_tfm { + + u32 crt_flags; + + union { + struct cipher_tfm cipher; + struct digest_tfm digest; + struct compress_tfm compress; + } crt_u; + + struct crypto_alg *__crt_alg; +}; + +/* + * Transform user interface. + */ + +/* + * crypto_alloc_tfm() will first attempt to locate an already loaded algorithm. + * If that fails and the kernel supports dynamically loadable modules, it + * will then attempt to load a module of the same name or alias. A refcount + * is grabbed on the algorithm which is then associated with the new transform. + * + * crypto_free_tfm() frees up the transform and any associated resources, + * then drops the refcount on the associated algorithm. + */ +struct crypto_tfm *crypto_alloc_tfm(const char *alg_name, u32 tfm_flags); +void crypto_free_tfm(struct crypto_tfm *tfm); + +/* + * Transform helpers which query the underlying algorithm. + */ +static inline const char *crypto_tfm_alg_name(struct crypto_tfm *tfm) +{ + return tfm->__crt_alg->cra_name; +} + +static inline const char *crypto_tfm_alg_modname(struct crypto_tfm *tfm) +{ + struct crypto_alg *alg = tfm->__crt_alg; + + if (alg->cra_module) + return alg->cra_module->name; + else + return NULL; +} + +static inline u32 crypto_tfm_alg_type(struct crypto_tfm *tfm) +{ + return tfm->__crt_alg->cra_flags & CRYPTO_ALG_TYPE_MASK; +} + +static inline unsigned int crypto_tfm_alg_min_keysize(struct crypto_tfm *tfm) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + return tfm->__crt_alg->cra_cipher.cia_min_keysize; +} + +static inline unsigned int crypto_tfm_alg_max_keysize(struct crypto_tfm *tfm) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + return tfm->__crt_alg->cra_cipher.cia_max_keysize; +} + +static inline unsigned int crypto_tfm_alg_ivsize(struct crypto_tfm *tfm) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + return tfm->crt_cipher.cit_ivsize; +} + +static inline unsigned int crypto_tfm_alg_blocksize(struct crypto_tfm *tfm) +{ + return tfm->__crt_alg->cra_blocksize; +} + +static inline unsigned int crypto_tfm_alg_digestsize(struct crypto_tfm *tfm) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); + return tfm->__crt_alg->cra_digest.dia_digestsize; +} + +/* + * API wrappers. + */ +static inline void crypto_digest_init(struct crypto_tfm *tfm) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); + tfm->crt_digest.dit_init(tfm); +} + +static inline void crypto_digest_update(struct crypto_tfm *tfm, + struct scatterlist *sg, + unsigned int nsg) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); + tfm->crt_digest.dit_update(tfm, sg, nsg); +} + +static inline void crypto_digest_final(struct crypto_tfm *tfm, u8 *out) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); + tfm->crt_digest.dit_final(tfm, out); +} + +static inline void crypto_digest_digest(struct crypto_tfm *tfm, + struct scatterlist *sg, + unsigned int nsg, u8 *out) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); + tfm->crt_digest.dit_digest(tfm, sg, nsg, out); +} + +static inline int crypto_digest_setkey(struct crypto_tfm *tfm, + const u8 *key, unsigned int keylen) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); + if (tfm->crt_digest.dit_setkey == NULL) + return -ENOSYS; + return tfm->crt_digest.dit_setkey(tfm, key, keylen); +} + +static inline int crypto_cipher_setkey(struct crypto_tfm *tfm, + const u8 *key, unsigned int keylen) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + return tfm->crt_cipher.cit_setkey(tfm, key, keylen); +} + +static inline int crypto_cipher_encrypt(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + return tfm->crt_cipher.cit_encrypt(tfm, dst, src, nbytes); +} + +static inline int crypto_cipher_encrypt_iv(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes, u8 *iv) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + BUG_ON(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_ECB); + return tfm->crt_cipher.cit_encrypt_iv(tfm, dst, src, nbytes, iv); +} + +static inline int crypto_cipher_decrypt(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + return tfm->crt_cipher.cit_decrypt(tfm, dst, src, nbytes); +} + +static inline int crypto_cipher_decrypt_iv(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes, u8 *iv) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + BUG_ON(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_ECB); + return tfm->crt_cipher.cit_decrypt_iv(tfm, dst, src, nbytes, iv); +} + +static inline void crypto_cipher_set_iv(struct crypto_tfm *tfm, + const u8 *src, unsigned int len) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + memcpy(tfm->crt_cipher.cit_iv, src, len); +} + +static inline void crypto_cipher_get_iv(struct crypto_tfm *tfm, + u8 *dst, unsigned int len) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + memcpy(dst, tfm->crt_cipher.cit_iv, len); +} + +static inline int crypto_comp_compress(struct crypto_tfm *tfm, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_COMPRESS); + return tfm->crt_compress.cot_compress(tfm, src, slen, dst, dlen); +} + +static inline int crypto_comp_decompress(struct crypto_tfm *tfm, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_COMPRESS); + return tfm->crt_compress.cot_decompress(tfm, src, slen, dst, dlen); +} + +#endif /* _LINUX_CRYPTO_H */ diff --git a/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c new file mode 100644 index 000000000..df4bbcf38 --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c @@ -0,0 +1,2995 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ +#include "rtl_core.h" +#include "rtl_dm.h" +#include "r8192E_hw.h" +#include "r8192E_phy.h" +#include "r8192E_phyreg.h" +#include "r8190P_rtl8256.h" +#include "r8192E_cmdpkt.h" + +/*---------------------------Define Local Constant---------------------------*/ +static u32 edca_setting_DL[HT_IOT_PEER_MAX] = { + 0x5e4322, + 0x5e4322, + 0x5ea44f, + 0x5e4322, + 0x604322, + 0xa44f, + 0x5e4322, + 0x5e4332 +}; + +static u32 edca_setting_DL_GMode[HT_IOT_PEER_MAX] = { + 0x5e4322, + 0x5e4322, + 0x5e4322, + 0x5e4322, + 0x604322, + 0xa44f, + 0x5e4322, + 0x5e4322 +}; + +static u32 edca_setting_UL[HT_IOT_PEER_MAX] = { + 0x5e4322, + 0xa44f, + 0x5ea44f, + 0x5e4322, + 0x604322, + 0x5e4322, + 0x5e4322, + 0x5e4332 +}; + +#define RTK_UL_EDCA 0xa44f +#define RTK_DL_EDCA 0x5e4322 +/*---------------------------Define Local Constant---------------------------*/ + + +/*------------------------Define global variable-----------------------------*/ +struct dig_t dm_digtable; +u8 dm_shadow[16][256] = { + {0} +}; + +struct drx_path_sel DM_RxPathSelTable; +/*------------------------Define global variable-----------------------------*/ + + +/*------------------------Define local variable------------------------------*/ +/*------------------------Define local variable------------------------------*/ + + + +/*---------------------Define local function prototype-----------------------*/ +static void dm_check_rate_adaptive(struct net_device *dev); + +static void dm_init_bandwidth_autoswitch(struct net_device *dev); +static void dm_bandwidth_autoswitch(struct net_device *dev); + + +static void dm_check_txpower_tracking(struct net_device *dev); + + + + + +static void dm_bb_initialgain_restore(struct net_device *dev); + + +static void dm_bb_initialgain_backup(struct net_device *dev); + +static void dm_dig_init(struct net_device *dev); +static void dm_ctrl_initgain_byrssi(struct net_device *dev); +static void dm_ctrl_initgain_byrssi_highpwr(struct net_device *dev); +static void dm_ctrl_initgain_byrssi_by_driverrssi(struct net_device *dev); +static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm(struct net_device *dev); +static void dm_initial_gain(struct net_device *dev); +static void dm_pd_th(struct net_device *dev); +static void dm_cs_ratio(struct net_device *dev); + +static void dm_init_ctstoself(struct net_device *dev); +static void dm_Init_WA_Broadcom_IOT(struct net_device *dev); + +static void dm_check_edca_turbo(struct net_device *dev); + +static void dm_check_pbc_gpio(struct net_device *dev); + + +static void dm_check_rx_path_selection(struct net_device *dev); +static void dm_init_rxpath_selection(struct net_device *dev); +static void dm_rxpath_sel_byrssi(struct net_device *dev); + + +static void dm_init_fsync(struct net_device *dev); +static void dm_deInit_fsync(struct net_device *dev); + +static void dm_check_txrateandretrycount(struct net_device *dev); +static void dm_check_ac_dc_power(struct net_device *dev); + +/*---------------------Define local function prototype-----------------------*/ + +static void dm_init_dynamic_txpower(struct net_device *dev); +static void dm_dynamic_txpower(struct net_device *dev); + + +static void dm_send_rssi_tofw(struct net_device *dev); +static void dm_ctstoself(struct net_device *dev); +/*---------------------------Define function prototype------------------------*/ + +void init_hal_dm(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + priv->DM_Type = DM_Type_ByDriver; + + priv->undecorated_smoothed_pwdb = -1; + + dm_init_dynamic_txpower(dev); + + init_rate_adaptive(dev); + + dm_dig_init(dev); + dm_init_edca_turbo(dev); + dm_init_bandwidth_autoswitch(dev); + dm_init_fsync(dev); + dm_init_rxpath_selection(dev); + dm_init_ctstoself(dev); + if (IS_HARDWARE_TYPE_8192SE(dev)) + dm_Init_WA_Broadcom_IOT(dev); + + INIT_DELAYED_WORK_RSL(&priv->gpio_change_rf_wq, (void *)dm_CheckRfCtrlGPIO, dev); +} + +void deinit_hal_dm(struct net_device *dev) +{ + + dm_deInit_fsync(dev); + +} + +void hal_dm_watchdog(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + if (priv->being_init_adapter) + return; + + dm_check_ac_dc_power(dev); + + dm_check_pbc_gpio(dev); + dm_check_txrateandretrycount(dev); + dm_check_edca_turbo(dev); + + dm_check_rate_adaptive(dev); + dm_dynamic_txpower(dev); + dm_check_txpower_tracking(dev); + + dm_ctrl_initgain_byrssi(dev); + dm_bandwidth_autoswitch(dev); + + dm_check_rx_path_selection(dev); + dm_check_fsync(dev); + + dm_send_rssi_tofw(dev); + dm_ctstoself(dev); +} + +static void dm_check_ac_dc_power(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + static char *ac_dc_check_script_path = "/etc/acpi/wireless-rtl-ac-dc-power.sh"; + char *argv[] = {ac_dc_check_script_path, DRV_NAME, NULL}; + static char *envp[] = {"HOME=/", + "TERM=linux", + "PATH=/usr/bin:/bin", + NULL}; + + if (priv->ResetProgress == RESET_TYPE_SILENT) { + RT_TRACE((COMP_INIT | COMP_POWER | COMP_RF), + "GPIOChangeRFWorkItemCallBack(): Silent Reset!!!!!!!\n"); + return; + } + + if (priv->rtllib->state != RTLLIB_LINKED) + return; + call_usermodehelper(ac_dc_check_script_path, argv, envp, UMH_WAIT_PROC); + + return; +}; + + +void init_rate_adaptive(struct net_device *dev) +{ + + struct r8192_priv *priv = rtllib_priv(dev); + struct rate_adaptive *pra = (struct rate_adaptive *)&priv->rate_adaptive; + + pra->ratr_state = DM_RATR_STA_MAX; + pra->high2low_rssi_thresh_for_ra = RateAdaptiveTH_High; + pra->low2high_rssi_thresh_for_ra20M = RateAdaptiveTH_Low_20M+5; + pra->low2high_rssi_thresh_for_ra40M = RateAdaptiveTH_Low_40M+5; + + pra->high_rssi_thresh_for_ra = RateAdaptiveTH_High+5; + pra->low_rssi_thresh_for_ra20M = RateAdaptiveTH_Low_20M; + pra->low_rssi_thresh_for_ra40M = RateAdaptiveTH_Low_40M; + + if (priv->CustomerID == RT_CID_819x_Netcore) + pra->ping_rssi_enable = 1; + else + pra->ping_rssi_enable = 0; + pra->ping_rssi_thresh_for_ra = 15; + + + if (priv->rf_type == RF_2T4R) { + pra->upper_rssi_threshold_ratr = 0x8f0f0000; + pra->middle_rssi_threshold_ratr = 0x8f0ff000; + pra->low_rssi_threshold_ratr = 0x8f0ff001; + pra->low_rssi_threshold_ratr_40M = 0x8f0ff005; + pra->low_rssi_threshold_ratr_20M = 0x8f0ff001; + pra->ping_rssi_ratr = 0x0000000d; + } else if (priv->rf_type == RF_1T2R) { + pra->upper_rssi_threshold_ratr = 0x000fc000; + pra->middle_rssi_threshold_ratr = 0x000ff000; + pra->low_rssi_threshold_ratr = 0x000ff001; + pra->low_rssi_threshold_ratr_40M = 0x000ff005; + pra->low_rssi_threshold_ratr_20M = 0x000ff001; + pra->ping_rssi_ratr = 0x0000000d; + } + +} + + +static void dm_check_rate_adaptive(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct rt_hi_throughput *pHTInfo = priv->rtllib->pHTInfo; + struct rate_adaptive *pra = (struct rate_adaptive *)&priv->rate_adaptive; + u32 currentRATR, targetRATR = 0; + u32 LowRSSIThreshForRA = 0, HighRSSIThreshForRA = 0; + bool bshort_gi_enabled = false; + static u8 ping_rssi_state; + + if (!priv->up) { + RT_TRACE(COMP_RATE, "<---- dm_check_rate_adaptive(): driver is going to unload\n"); + return; + } + + if (pra->rate_adaptive_disabled) + return; + + if (!(priv->rtllib->mode == WIRELESS_MODE_N_24G || + priv->rtllib->mode == WIRELESS_MODE_N_5G)) + return; + + if (priv->rtllib->state == RTLLIB_LINKED) { + + bshort_gi_enabled = (pHTInfo->bCurTxBW40MHz && pHTInfo->bCurShortGI40MHz) || + (!pHTInfo->bCurTxBW40MHz && pHTInfo->bCurShortGI20MHz); + + + pra->upper_rssi_threshold_ratr = + (pra->upper_rssi_threshold_ratr & (~BIT31)) | ((bshort_gi_enabled) ? BIT31 : 0); + + pra->middle_rssi_threshold_ratr = + (pra->middle_rssi_threshold_ratr & (~BIT31)) | ((bshort_gi_enabled) ? BIT31 : 0); + + if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) { + pra->low_rssi_threshold_ratr = + (pra->low_rssi_threshold_ratr_40M & (~BIT31)) | ((bshort_gi_enabled) ? BIT31 : 0); + } else { + pra->low_rssi_threshold_ratr = + (pra->low_rssi_threshold_ratr_20M & (~BIT31)) | ((bshort_gi_enabled) ? BIT31 : 0); + } + pra->ping_rssi_ratr = + (pra->ping_rssi_ratr & (~BIT31)) | ((bshort_gi_enabled) ? BIT31 : 0); + + if (pra->ratr_state == DM_RATR_STA_HIGH) { + HighRSSIThreshForRA = pra->high2low_rssi_thresh_for_ra; + LowRSSIThreshForRA = (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) ? + (pra->low_rssi_thresh_for_ra40M) : (pra->low_rssi_thresh_for_ra20M); + } else if (pra->ratr_state == DM_RATR_STA_LOW) { + HighRSSIThreshForRA = pra->high_rssi_thresh_for_ra; + LowRSSIThreshForRA = (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) ? + (pra->low2high_rssi_thresh_for_ra40M) : (pra->low2high_rssi_thresh_for_ra20M); + } else { + HighRSSIThreshForRA = pra->high_rssi_thresh_for_ra; + LowRSSIThreshForRA = (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) ? + (pra->low_rssi_thresh_for_ra40M) : (pra->low_rssi_thresh_for_ra20M); + } + + if (priv->undecorated_smoothed_pwdb >= (long)HighRSSIThreshForRA) { + pra->ratr_state = DM_RATR_STA_HIGH; + targetRATR = pra->upper_rssi_threshold_ratr; + } else if (priv->undecorated_smoothed_pwdb >= (long)LowRSSIThreshForRA) { + pra->ratr_state = DM_RATR_STA_MIDDLE; + targetRATR = pra->middle_rssi_threshold_ratr; + } else { + pra->ratr_state = DM_RATR_STA_LOW; + targetRATR = pra->low_rssi_threshold_ratr; + } + + if (pra->ping_rssi_enable) { + if (priv->undecorated_smoothed_pwdb < (long)(pra->ping_rssi_thresh_for_ra+5)) { + if ((priv->undecorated_smoothed_pwdb < (long)pra->ping_rssi_thresh_for_ra) || + ping_rssi_state) { + pra->ratr_state = DM_RATR_STA_LOW; + targetRATR = pra->ping_rssi_ratr; + ping_rssi_state = 1; + } + } else { + ping_rssi_state = 0; + } + } + + if (priv->rtllib->GetHalfNmodeSupportByAPsHandler(dev)) + targetRATR &= 0xf00fffff; + + currentRATR = read_nic_dword(dev, RATR0); + if (targetRATR != currentRATR) { + u32 ratr_value; + + ratr_value = targetRATR; + RT_TRACE(COMP_RATE, + "currentRATR = %x, targetRATR = %x\n", + currentRATR, targetRATR); + if (priv->rf_type == RF_1T2R) + ratr_value &= ~(RATE_ALL_OFDM_2SS); + write_nic_dword(dev, RATR0, ratr_value); + write_nic_byte(dev, UFWP, 1); + + pra->last_ratr = targetRATR; + } + + } else { + pra->ratr_state = DM_RATR_STA_MAX; + } +} + +static void dm_init_bandwidth_autoswitch(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + priv->rtllib->bandwidth_auto_switch.threshold_20Mhzto40Mhz = BW_AUTO_SWITCH_LOW_HIGH; + priv->rtllib->bandwidth_auto_switch.threshold_40Mhzto20Mhz = BW_AUTO_SWITCH_HIGH_LOW; + priv->rtllib->bandwidth_auto_switch.bforced_tx20Mhz = false; + priv->rtllib->bandwidth_auto_switch.bautoswitch_enable = false; +} + +static void dm_bandwidth_autoswitch(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + if (priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20 || + !priv->rtllib->bandwidth_auto_switch.bautoswitch_enable) + return; + if (priv->rtllib->bandwidth_auto_switch.bforced_tx20Mhz == false) { + if (priv->undecorated_smoothed_pwdb <= + priv->rtllib->bandwidth_auto_switch.threshold_40Mhzto20Mhz) + priv->rtllib->bandwidth_auto_switch.bforced_tx20Mhz = true; + } else { + if (priv->undecorated_smoothed_pwdb >= + priv->rtllib->bandwidth_auto_switch.threshold_20Mhzto40Mhz) + priv->rtllib->bandwidth_auto_switch.bforced_tx20Mhz = false; + } +} + +static u32 OFDMSwingTable[OFDM_Table_Length] = { + 0x7f8001fe, + 0x71c001c7, + 0x65400195, + 0x5a400169, + 0x50800142, + 0x47c0011f, + 0x40000100, + 0x390000e4, + 0x32c000cb, + 0x2d4000b5, + 0x288000a2, + 0x24000090, + 0x20000080, + 0x1c800072, + 0x19800066, + 0x26c0005b, + 0x24400051, + 0x12000048, + 0x10000040 +}; + +static u8 CCKSwingTable_Ch1_Ch13[CCK_Table_length][8] = { + {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04}, + {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, + {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, + {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, + {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, + {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, + {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, + {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, + {0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, + {0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, + {0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, + {0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01} +}; + +static u8 CCKSwingTable_Ch14[CCK_Table_length][8] = { + {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00}, + {0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, + {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, + {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, + {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, + {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, + {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, + {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, + {0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, + {0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, + {0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, + {0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00} +}; + +#define Pw_Track_Flag 0x11d +#define Tssi_Mea_Value 0x13c +#define Tssi_Report_Value1 0x134 +#define Tssi_Report_Value2 0x13e +#define FW_Busy_Flag 0x13f + +static void dm_TXPowerTrackingCallback_TSSI(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + bool bHighpowerstate, viviflag = false; + struct dcmd_txcmd tx_cmd; + u8 powerlevelOFDM24G; + int i = 0, j = 0, k = 0; + u8 RF_Type, tmp_report[5] = {0, 0, 0, 0, 0}; + u32 Value; + u8 Pwr_Flag; + u16 Avg_TSSI_Meas, TSSI_13dBm, Avg_TSSI_Meas_from_driver = 0; + u32 delta = 0; + + RT_TRACE(COMP_POWER_TRACKING, "%s()\n", __func__); + write_nic_byte(dev, Pw_Track_Flag, 0); + write_nic_byte(dev, FW_Busy_Flag, 0); + priv->rtllib->bdynamic_txpower_enable = false; + bHighpowerstate = priv->bDynamicTxHighPower; + + powerlevelOFDM24G = (u8)(priv->Pwr_Track>>24); + RF_Type = priv->rf_type; + Value = (RF_Type<<8) | powerlevelOFDM24G; + + RT_TRACE(COMP_POWER_TRACKING, "powerlevelOFDM24G = %x\n", + powerlevelOFDM24G); + + + for (j = 0; j <= 30; j++) { + + tx_cmd.Op = TXCMD_SET_TX_PWR_TRACKING; + tx_cmd.Length = 4; + tx_cmd.Value = Value; + cmpk_message_handle_tx(dev, (u8 *)&tx_cmd, + DESC_PACKET_TYPE_INIT, + sizeof(struct dcmd_txcmd)); + mdelay(1); + for (i = 0; i <= 30; i++) { + Pwr_Flag = read_nic_byte(dev, Pw_Track_Flag); + + if (Pwr_Flag == 0) { + mdelay(1); + + if (priv->bResetInProgress) { + RT_TRACE(COMP_POWER_TRACKING, + "we are in silent reset progress, so return\n"); + write_nic_byte(dev, Pw_Track_Flag, 0); + write_nic_byte(dev, FW_Busy_Flag, 0); + return; + } + if (priv->rtllib->eRFPowerState != eRfOn) { + RT_TRACE(COMP_POWER_TRACKING, + "we are in power save, so return\n"); + write_nic_byte(dev, Pw_Track_Flag, 0); + write_nic_byte(dev, FW_Busy_Flag, 0); + return; + } + + continue; + } + + Avg_TSSI_Meas = read_nic_word(dev, Tssi_Mea_Value); + + if (Avg_TSSI_Meas == 0) { + write_nic_byte(dev, Pw_Track_Flag, 0); + write_nic_byte(dev, FW_Busy_Flag, 0); + return; + } + + for (k = 0; k < 5; k++) { + if (k != 4) + tmp_report[k] = read_nic_byte(dev, + Tssi_Report_Value1+k); + else + tmp_report[k] = read_nic_byte(dev, + Tssi_Report_Value2); + + RT_TRACE(COMP_POWER_TRACKING, + "TSSI_report_value = %d\n", + tmp_report[k]); + + if (tmp_report[k] <= 20) { + viviflag = true; + break; + } + } + + if (viviflag) { + write_nic_byte(dev, Pw_Track_Flag, 0); + viviflag = false; + RT_TRACE(COMP_POWER_TRACKING, "we filted this data\n"); + for (k = 0; k < 5; k++) + tmp_report[k] = 0; + break; + } + + for (k = 0; k < 5; k++) + Avg_TSSI_Meas_from_driver += tmp_report[k]; + + Avg_TSSI_Meas_from_driver = Avg_TSSI_Meas_from_driver*100/5; + RT_TRACE(COMP_POWER_TRACKING, + "Avg_TSSI_Meas_from_driver = %d\n", + Avg_TSSI_Meas_from_driver); + TSSI_13dBm = priv->TSSI_13dBm; + RT_TRACE(COMP_POWER_TRACKING, "TSSI_13dBm = %d\n", TSSI_13dBm); + + if (Avg_TSSI_Meas_from_driver > TSSI_13dBm) + delta = Avg_TSSI_Meas_from_driver - TSSI_13dBm; + else + delta = TSSI_13dBm - Avg_TSSI_Meas_from_driver; + + if (delta <= E_FOR_TX_POWER_TRACK) { + priv->rtllib->bdynamic_txpower_enable = true; + write_nic_byte(dev, Pw_Track_Flag, 0); + write_nic_byte(dev, FW_Busy_Flag, 0); + RT_TRACE(COMP_POWER_TRACKING, + "tx power track is done\n"); + RT_TRACE(COMP_POWER_TRACKING, + "priv->rfa_txpowertrackingindex = %d\n", + priv->rfa_txpowertrackingindex); + RT_TRACE(COMP_POWER_TRACKING, + "priv->rfa_txpowertrackingindex_real = %d\n", + priv->rfa_txpowertrackingindex_real); + RT_TRACE(COMP_POWER_TRACKING, + "priv->CCKPresentAttentuation_difference = %d\n", + priv->CCKPresentAttentuation_difference); + RT_TRACE(COMP_POWER_TRACKING, + "priv->CCKPresentAttentuation = %d\n", + priv->CCKPresentAttentuation); + return; + } + if (Avg_TSSI_Meas_from_driver < TSSI_13dBm - E_FOR_TX_POWER_TRACK) { + if (RF_Type == RF_2T4R) { + + if ((priv->rfa_txpowertrackingindex > 0) && + (priv->rfc_txpowertrackingindex > 0)) { + priv->rfa_txpowertrackingindex--; + if (priv->rfa_txpowertrackingindex_real > 4) { + priv->rfa_txpowertrackingindex_real--; + rtl8192_setBBreg(dev, + rOFDM0_XATxIQImbalance, + bMaskDWord, + priv->txbbgain_table[priv->rfa_txpowertrackingindex_real].txbbgain_value); + } + + priv->rfc_txpowertrackingindex--; + if (priv->rfc_txpowertrackingindex_real > 4) { + priv->rfc_txpowertrackingindex_real--; + rtl8192_setBBreg(dev, + rOFDM0_XCTxIQImbalance, + bMaskDWord, + priv->txbbgain_table[priv->rfc_txpowertrackingindex_real].txbbgain_value); + } + } else { + rtl8192_setBBreg(dev, rOFDM0_XATxIQImbalance, + bMaskDWord, + priv->txbbgain_table[4].txbbgain_value); + rtl8192_setBBreg(dev, + rOFDM0_XCTxIQImbalance, + bMaskDWord, priv->txbbgain_table[4].txbbgain_value); + } + } else { + if (priv->rfa_txpowertrackingindex > 0) { + priv->rfa_txpowertrackingindex--; + if (priv->rfa_txpowertrackingindex_real > 4) { + priv->rfa_txpowertrackingindex_real--; + rtl8192_setBBreg(dev, + rOFDM0_XATxIQImbalance, + bMaskDWord, + priv->txbbgain_table[priv->rfa_txpowertrackingindex_real].txbbgain_value); + } + } else + rtl8192_setBBreg(dev, rOFDM0_XATxIQImbalance, + bMaskDWord, priv->txbbgain_table[4].txbbgain_value); + + } + } else { + if (RF_Type == RF_2T4R) { + if ((priv->rfa_txpowertrackingindex < + TxBBGainTableLength - 1) && + (priv->rfc_txpowertrackingindex < + TxBBGainTableLength - 1)) { + priv->rfa_txpowertrackingindex++; + priv->rfa_txpowertrackingindex_real++; + rtl8192_setBBreg(dev, + rOFDM0_XATxIQImbalance, + bMaskDWord, + priv->txbbgain_table + [priv->rfa_txpowertrackingindex_real].txbbgain_value); + priv->rfc_txpowertrackingindex++; + priv->rfc_txpowertrackingindex_real++; + rtl8192_setBBreg(dev, + rOFDM0_XCTxIQImbalance, + bMaskDWord, + priv->txbbgain_table[priv->rfc_txpowertrackingindex_real].txbbgain_value); + } else { + rtl8192_setBBreg(dev, + rOFDM0_XATxIQImbalance, + bMaskDWord, + priv->txbbgain_table[TxBBGainTableLength - 1].txbbgain_value); + rtl8192_setBBreg(dev, + rOFDM0_XCTxIQImbalance, + bMaskDWord, priv->txbbgain_table[TxBBGainTableLength - 1].txbbgain_value); + } + } else { + if (priv->rfa_txpowertrackingindex < (TxBBGainTableLength - 1)) { + priv->rfa_txpowertrackingindex++; + priv->rfa_txpowertrackingindex_real++; + rtl8192_setBBreg(dev, rOFDM0_XATxIQImbalance, + bMaskDWord, + priv->txbbgain_table[priv->rfa_txpowertrackingindex_real].txbbgain_value); + } else + rtl8192_setBBreg(dev, rOFDM0_XATxIQImbalance, + bMaskDWord, + priv->txbbgain_table[TxBBGainTableLength - 1].txbbgain_value); + } + } + if (RF_Type == RF_2T4R) { + priv->CCKPresentAttentuation_difference + = priv->rfa_txpowertrackingindex - priv->rfa_txpowertracking_default; + } else { + priv->CCKPresentAttentuation_difference + = priv->rfa_txpowertrackingindex_real - priv->rfa_txpowertracking_default; + } + + if (priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20) + priv->CCKPresentAttentuation = + priv->CCKPresentAttentuation_20Mdefault + + priv->CCKPresentAttentuation_difference; + else + priv->CCKPresentAttentuation = + priv->CCKPresentAttentuation_40Mdefault + + priv->CCKPresentAttentuation_difference; + + if (priv->CCKPresentAttentuation > (CCKTxBBGainTableLength-1)) + priv->CCKPresentAttentuation = CCKTxBBGainTableLength-1; + if (priv->CCKPresentAttentuation < 0) + priv->CCKPresentAttentuation = 0; + + if (priv->CCKPresentAttentuation > -1 && + priv->CCKPresentAttentuation < CCKTxBBGainTableLength) { + if (priv->rtllib->current_network.channel == 14 && + !priv->bcck_in_ch14) { + priv->bcck_in_ch14 = true; + dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); + } else if (priv->rtllib->current_network.channel != 14 && priv->bcck_in_ch14) { + priv->bcck_in_ch14 = false; + dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); + } else + dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); + } + RT_TRACE(COMP_POWER_TRACKING, + "priv->rfa_txpowertrackingindex = %d\n", + priv->rfa_txpowertrackingindex); + RT_TRACE(COMP_POWER_TRACKING, + "priv->rfa_txpowertrackingindex_real = %d\n", + priv->rfa_txpowertrackingindex_real); + RT_TRACE(COMP_POWER_TRACKING, + "priv->CCKPresentAttentuation_difference = %d\n", + priv->CCKPresentAttentuation_difference); + RT_TRACE(COMP_POWER_TRACKING, + "priv->CCKPresentAttentuation = %d\n", + priv->CCKPresentAttentuation); + + if (priv->CCKPresentAttentuation_difference <= -12 || priv->CCKPresentAttentuation_difference >= 24) { + priv->rtllib->bdynamic_txpower_enable = true; + write_nic_byte(dev, Pw_Track_Flag, 0); + write_nic_byte(dev, FW_Busy_Flag, 0); + RT_TRACE(COMP_POWER_TRACKING, "tx power track--->limited\n"); + return; + } + + write_nic_byte(dev, Pw_Track_Flag, 0); + Avg_TSSI_Meas_from_driver = 0; + for (k = 0; k < 5; k++) + tmp_report[k] = 0; + break; + } + write_nic_byte(dev, FW_Busy_Flag, 0); + } + priv->rtllib->bdynamic_txpower_enable = true; + write_nic_byte(dev, Pw_Track_Flag, 0); +} + +static void dm_TXPowerTrackingCallback_ThermalMeter(struct net_device *dev) +{ +#define ThermalMeterVal 9 + struct r8192_priv *priv = rtllib_priv(dev); + u32 tmpRegA, TempCCk; + u8 tmpOFDMindex, tmpCCKindex, tmpCCK20Mindex, tmpCCK40Mindex, tmpval; + int i = 0, CCKSwingNeedUpdate = 0; + + if (!priv->btxpower_trackingInit) { + tmpRegA = rtl8192_QueryBBReg(dev, rOFDM0_XATxIQImbalance, bMaskDWord); + for (i = 0; i < OFDM_Table_Length; i++) { + if (tmpRegA == OFDMSwingTable[i]) { + priv->OFDM_index[0] = (u8)i; + RT_TRACE(COMP_POWER_TRACKING, "Initial reg0x%x = 0x%x, OFDM_index = 0x%x\n", + rOFDM0_XATxIQImbalance, tmpRegA, priv->OFDM_index[0]); + } + } + + TempCCk = rtl8192_QueryBBReg(dev, rCCK0_TxFilter1, bMaskByte2); + for (i = 0; i < CCK_Table_length; i++) { + if (TempCCk == (u32)CCKSwingTable_Ch1_Ch13[i][0]) { + priv->CCK_index = (u8) i; + RT_TRACE(COMP_POWER_TRACKING, + "Initial reg0x%x = 0x%x, CCK_index = 0x%x\n", + rCCK0_TxFilter1, TempCCk, + priv->CCK_index); + break; + } + } + priv->btxpower_trackingInit = true; + return; + } + + tmpRegA = rtl8192_phy_QueryRFReg(dev, RF90_PATH_A, 0x12, 0x078); + RT_TRACE(COMP_POWER_TRACKING, "Readback ThermalMeterA = %d\n", tmpRegA); + if (tmpRegA < 3 || tmpRegA > 13) + return; + if (tmpRegA >= 12) + tmpRegA = 12; + RT_TRACE(COMP_POWER_TRACKING, "Valid ThermalMeterA = %d\n", tmpRegA); + priv->ThermalMeter[0] = ThermalMeterVal; + priv->ThermalMeter[1] = ThermalMeterVal; + + if (priv->ThermalMeter[0] >= (u8)tmpRegA) { + tmpOFDMindex = tmpCCK20Mindex = 6+(priv->ThermalMeter[0] - + (u8)tmpRegA); + tmpCCK40Mindex = tmpCCK20Mindex - 6; + if (tmpOFDMindex >= OFDM_Table_Length) + tmpOFDMindex = OFDM_Table_Length-1; + if (tmpCCK20Mindex >= CCK_Table_length) + tmpCCK20Mindex = CCK_Table_length-1; + if (tmpCCK40Mindex >= CCK_Table_length) + tmpCCK40Mindex = CCK_Table_length-1; + } else { + tmpval = ((u8)tmpRegA - priv->ThermalMeter[0]); + if (tmpval >= 6) + tmpOFDMindex = tmpCCK20Mindex = 0; + else + tmpOFDMindex = tmpCCK20Mindex = 6 - tmpval; + tmpCCK40Mindex = 0; + } + if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) + tmpCCKindex = tmpCCK40Mindex; + else + tmpCCKindex = tmpCCK20Mindex; + + priv->Record_CCK_20Mindex = tmpCCK20Mindex; + priv->Record_CCK_40Mindex = tmpCCK40Mindex; + RT_TRACE(COMP_POWER_TRACKING, + "Record_CCK_20Mindex / Record_CCK_40Mindex = %d / %d.\n", + priv->Record_CCK_20Mindex, priv->Record_CCK_40Mindex); + + if (priv->rtllib->current_network.channel == 14 && + !priv->bcck_in_ch14) { + priv->bcck_in_ch14 = true; + CCKSwingNeedUpdate = 1; + } else if (priv->rtllib->current_network.channel != 14 && + priv->bcck_in_ch14) { + priv->bcck_in_ch14 = false; + CCKSwingNeedUpdate = 1; + } + + if (priv->CCK_index != tmpCCKindex) { + priv->CCK_index = tmpCCKindex; + CCKSwingNeedUpdate = 1; + } + + if (CCKSwingNeedUpdate) + dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); + if (priv->OFDM_index[0] != tmpOFDMindex) { + priv->OFDM_index[0] = tmpOFDMindex; + rtl8192_setBBreg(dev, rOFDM0_XATxIQImbalance, bMaskDWord, + OFDMSwingTable[priv->OFDM_index[0]]); + RT_TRACE(COMP_POWER_TRACKING, "Update OFDMSwing[%d] = 0x%x\n", + priv->OFDM_index[0], + OFDMSwingTable[priv->OFDM_index[0]]); + } + priv->txpower_count = 0; +} + +void dm_txpower_trackingcallback(void *data) +{ + struct r8192_priv *priv = container_of_dwork_rsl(data, + struct r8192_priv, txpower_tracking_wq); + struct net_device *dev = priv->rtllib->dev; + + if (priv->IC_Cut >= IC_VersionCut_D) + dm_TXPowerTrackingCallback_TSSI(dev); + else + dm_TXPowerTrackingCallback_ThermalMeter(dev); +} + +static void dm_InitializeTXPowerTracking_TSSI(struct net_device *dev) +{ + + struct r8192_priv *priv = rtllib_priv(dev); + + priv->txbbgain_table[0].txbb_iq_amplifygain = 12; + priv->txbbgain_table[0].txbbgain_value = 0x7f8001fe; + priv->txbbgain_table[1].txbb_iq_amplifygain = 11; + priv->txbbgain_table[1].txbbgain_value = 0x788001e2; + priv->txbbgain_table[2].txbb_iq_amplifygain = 10; + priv->txbbgain_table[2].txbbgain_value = 0x71c001c7; + priv->txbbgain_table[3].txbb_iq_amplifygain = 9; + priv->txbbgain_table[3].txbbgain_value = 0x6b8001ae; + priv->txbbgain_table[4].txbb_iq_amplifygain = 8; + priv->txbbgain_table[4].txbbgain_value = 0x65400195; + priv->txbbgain_table[5].txbb_iq_amplifygain = 7; + priv->txbbgain_table[5].txbbgain_value = 0x5fc0017f; + priv->txbbgain_table[6].txbb_iq_amplifygain = 6; + priv->txbbgain_table[6].txbbgain_value = 0x5a400169; + priv->txbbgain_table[7].txbb_iq_amplifygain = 5; + priv->txbbgain_table[7].txbbgain_value = 0x55400155; + priv->txbbgain_table[8].txbb_iq_amplifygain = 4; + priv->txbbgain_table[8].txbbgain_value = 0x50800142; + priv->txbbgain_table[9].txbb_iq_amplifygain = 3; + priv->txbbgain_table[9].txbbgain_value = 0x4c000130; + priv->txbbgain_table[10].txbb_iq_amplifygain = 2; + priv->txbbgain_table[10].txbbgain_value = 0x47c0011f; + priv->txbbgain_table[11].txbb_iq_amplifygain = 1; + priv->txbbgain_table[11].txbbgain_value = 0x43c0010f; + priv->txbbgain_table[12].txbb_iq_amplifygain = 0; + priv->txbbgain_table[12].txbbgain_value = 0x40000100; + priv->txbbgain_table[13].txbb_iq_amplifygain = -1; + priv->txbbgain_table[13].txbbgain_value = 0x3c8000f2; + priv->txbbgain_table[14].txbb_iq_amplifygain = -2; + priv->txbbgain_table[14].txbbgain_value = 0x390000e4; + priv->txbbgain_table[15].txbb_iq_amplifygain = -3; + priv->txbbgain_table[15].txbbgain_value = 0x35c000d7; + priv->txbbgain_table[16].txbb_iq_amplifygain = -4; + priv->txbbgain_table[16].txbbgain_value = 0x32c000cb; + priv->txbbgain_table[17].txbb_iq_amplifygain = -5; + priv->txbbgain_table[17].txbbgain_value = 0x300000c0; + priv->txbbgain_table[18].txbb_iq_amplifygain = -6; + priv->txbbgain_table[18].txbbgain_value = 0x2d4000b5; + priv->txbbgain_table[19].txbb_iq_amplifygain = -7; + priv->txbbgain_table[19].txbbgain_value = 0x2ac000ab; + priv->txbbgain_table[20].txbb_iq_amplifygain = -8; + priv->txbbgain_table[20].txbbgain_value = 0x288000a2; + priv->txbbgain_table[21].txbb_iq_amplifygain = -9; + priv->txbbgain_table[21].txbbgain_value = 0x26000098; + priv->txbbgain_table[22].txbb_iq_amplifygain = -10; + priv->txbbgain_table[22].txbbgain_value = 0x24000090; + priv->txbbgain_table[23].txbb_iq_amplifygain = -11; + priv->txbbgain_table[23].txbbgain_value = 0x22000088; + priv->txbbgain_table[24].txbb_iq_amplifygain = -12; + priv->txbbgain_table[24].txbbgain_value = 0x20000080; + priv->txbbgain_table[25].txbb_iq_amplifygain = -13; + priv->txbbgain_table[25].txbbgain_value = 0x1a00006c; + priv->txbbgain_table[26].txbb_iq_amplifygain = -14; + priv->txbbgain_table[26].txbbgain_value = 0x1c800072; + priv->txbbgain_table[27].txbb_iq_amplifygain = -15; + priv->txbbgain_table[27].txbbgain_value = 0x18000060; + priv->txbbgain_table[28].txbb_iq_amplifygain = -16; + priv->txbbgain_table[28].txbbgain_value = 0x19800066; + priv->txbbgain_table[29].txbb_iq_amplifygain = -17; + priv->txbbgain_table[29].txbbgain_value = 0x15800056; + priv->txbbgain_table[30].txbb_iq_amplifygain = -18; + priv->txbbgain_table[30].txbbgain_value = 0x26c0005b; + priv->txbbgain_table[31].txbb_iq_amplifygain = -19; + priv->txbbgain_table[31].txbbgain_value = 0x14400051; + priv->txbbgain_table[32].txbb_iq_amplifygain = -20; + priv->txbbgain_table[32].txbbgain_value = 0x24400051; + priv->txbbgain_table[33].txbb_iq_amplifygain = -21; + priv->txbbgain_table[33].txbbgain_value = 0x1300004c; + priv->txbbgain_table[34].txbb_iq_amplifygain = -22; + priv->txbbgain_table[34].txbbgain_value = 0x12000048; + priv->txbbgain_table[35].txbb_iq_amplifygain = -23; + priv->txbbgain_table[35].txbbgain_value = 0x11000044; + priv->txbbgain_table[36].txbb_iq_amplifygain = -24; + priv->txbbgain_table[36].txbbgain_value = 0x10000040; + + priv->cck_txbbgain_table[0].ccktxbb_valuearray[0] = 0x36; + priv->cck_txbbgain_table[0].ccktxbb_valuearray[1] = 0x35; + priv->cck_txbbgain_table[0].ccktxbb_valuearray[2] = 0x2e; + priv->cck_txbbgain_table[0].ccktxbb_valuearray[3] = 0x25; + priv->cck_txbbgain_table[0].ccktxbb_valuearray[4] = 0x1c; + priv->cck_txbbgain_table[0].ccktxbb_valuearray[5] = 0x12; + priv->cck_txbbgain_table[0].ccktxbb_valuearray[6] = 0x09; + priv->cck_txbbgain_table[0].ccktxbb_valuearray[7] = 0x04; + + priv->cck_txbbgain_table[1].ccktxbb_valuearray[0] = 0x33; + priv->cck_txbbgain_table[1].ccktxbb_valuearray[1] = 0x32; + priv->cck_txbbgain_table[1].ccktxbb_valuearray[2] = 0x2b; + priv->cck_txbbgain_table[1].ccktxbb_valuearray[3] = 0x23; + priv->cck_txbbgain_table[1].ccktxbb_valuearray[4] = 0x1a; + priv->cck_txbbgain_table[1].ccktxbb_valuearray[5] = 0x11; + priv->cck_txbbgain_table[1].ccktxbb_valuearray[6] = 0x08; + priv->cck_txbbgain_table[1].ccktxbb_valuearray[7] = 0x04; + + priv->cck_txbbgain_table[2].ccktxbb_valuearray[0] = 0x30; + priv->cck_txbbgain_table[2].ccktxbb_valuearray[1] = 0x2f; + priv->cck_txbbgain_table[2].ccktxbb_valuearray[2] = 0x29; + priv->cck_txbbgain_table[2].ccktxbb_valuearray[3] = 0x21; + priv->cck_txbbgain_table[2].ccktxbb_valuearray[4] = 0x19; + priv->cck_txbbgain_table[2].ccktxbb_valuearray[5] = 0x10; + priv->cck_txbbgain_table[2].ccktxbb_valuearray[6] = 0x08; + priv->cck_txbbgain_table[2].ccktxbb_valuearray[7] = 0x03; + + priv->cck_txbbgain_table[3].ccktxbb_valuearray[0] = 0x2d; + priv->cck_txbbgain_table[3].ccktxbb_valuearray[1] = 0x2d; + priv->cck_txbbgain_table[3].ccktxbb_valuearray[2] = 0x27; + priv->cck_txbbgain_table[3].ccktxbb_valuearray[3] = 0x1f; + priv->cck_txbbgain_table[3].ccktxbb_valuearray[4] = 0x18; + priv->cck_txbbgain_table[3].ccktxbb_valuearray[5] = 0x0f; + priv->cck_txbbgain_table[3].ccktxbb_valuearray[6] = 0x08; + priv->cck_txbbgain_table[3].ccktxbb_valuearray[7] = 0x03; + + priv->cck_txbbgain_table[4].ccktxbb_valuearray[0] = 0x2b; + priv->cck_txbbgain_table[4].ccktxbb_valuearray[1] = 0x2a; + priv->cck_txbbgain_table[4].ccktxbb_valuearray[2] = 0x25; + priv->cck_txbbgain_table[4].ccktxbb_valuearray[3] = 0x1e; + priv->cck_txbbgain_table[4].ccktxbb_valuearray[4] = 0x16; + priv->cck_txbbgain_table[4].ccktxbb_valuearray[5] = 0x0e; + priv->cck_txbbgain_table[4].ccktxbb_valuearray[6] = 0x07; + priv->cck_txbbgain_table[4].ccktxbb_valuearray[7] = 0x03; + + priv->cck_txbbgain_table[5].ccktxbb_valuearray[0] = 0x28; + priv->cck_txbbgain_table[5].ccktxbb_valuearray[1] = 0x28; + priv->cck_txbbgain_table[5].ccktxbb_valuearray[2] = 0x22; + priv->cck_txbbgain_table[5].ccktxbb_valuearray[3] = 0x1c; + priv->cck_txbbgain_table[5].ccktxbb_valuearray[4] = 0x15; + priv->cck_txbbgain_table[5].ccktxbb_valuearray[5] = 0x0d; + priv->cck_txbbgain_table[5].ccktxbb_valuearray[6] = 0x07; + priv->cck_txbbgain_table[5].ccktxbb_valuearray[7] = 0x03; + + priv->cck_txbbgain_table[6].ccktxbb_valuearray[0] = 0x26; + priv->cck_txbbgain_table[6].ccktxbb_valuearray[1] = 0x25; + priv->cck_txbbgain_table[6].ccktxbb_valuearray[2] = 0x21; + priv->cck_txbbgain_table[6].ccktxbb_valuearray[3] = 0x1b; + priv->cck_txbbgain_table[6].ccktxbb_valuearray[4] = 0x14; + priv->cck_txbbgain_table[6].ccktxbb_valuearray[5] = 0x0d; + priv->cck_txbbgain_table[6].ccktxbb_valuearray[6] = 0x06; + priv->cck_txbbgain_table[6].ccktxbb_valuearray[7] = 0x03; + + priv->cck_txbbgain_table[7].ccktxbb_valuearray[0] = 0x24; + priv->cck_txbbgain_table[7].ccktxbb_valuearray[1] = 0x23; + priv->cck_txbbgain_table[7].ccktxbb_valuearray[2] = 0x1f; + priv->cck_txbbgain_table[7].ccktxbb_valuearray[3] = 0x19; + priv->cck_txbbgain_table[7].ccktxbb_valuearray[4] = 0x13; + priv->cck_txbbgain_table[7].ccktxbb_valuearray[5] = 0x0c; + priv->cck_txbbgain_table[7].ccktxbb_valuearray[6] = 0x06; + priv->cck_txbbgain_table[7].ccktxbb_valuearray[7] = 0x03; + + priv->cck_txbbgain_table[8].ccktxbb_valuearray[0] = 0x22; + priv->cck_txbbgain_table[8].ccktxbb_valuearray[1] = 0x21; + priv->cck_txbbgain_table[8].ccktxbb_valuearray[2] = 0x1d; + priv->cck_txbbgain_table[8].ccktxbb_valuearray[3] = 0x18; + priv->cck_txbbgain_table[8].ccktxbb_valuearray[4] = 0x11; + priv->cck_txbbgain_table[8].ccktxbb_valuearray[5] = 0x0b; + priv->cck_txbbgain_table[8].ccktxbb_valuearray[6] = 0x06; + priv->cck_txbbgain_table[8].ccktxbb_valuearray[7] = 0x02; + + priv->cck_txbbgain_table[9].ccktxbb_valuearray[0] = 0x20; + priv->cck_txbbgain_table[9].ccktxbb_valuearray[1] = 0x20; + priv->cck_txbbgain_table[9].ccktxbb_valuearray[2] = 0x1b; + priv->cck_txbbgain_table[9].ccktxbb_valuearray[3] = 0x16; + priv->cck_txbbgain_table[9].ccktxbb_valuearray[4] = 0x11; + priv->cck_txbbgain_table[9].ccktxbb_valuearray[5] = 0x08; + priv->cck_txbbgain_table[9].ccktxbb_valuearray[6] = 0x05; + priv->cck_txbbgain_table[9].ccktxbb_valuearray[7] = 0x02; + + priv->cck_txbbgain_table[10].ccktxbb_valuearray[0] = 0x1f; + priv->cck_txbbgain_table[10].ccktxbb_valuearray[1] = 0x1e; + priv->cck_txbbgain_table[10].ccktxbb_valuearray[2] = 0x1a; + priv->cck_txbbgain_table[10].ccktxbb_valuearray[3] = 0x15; + priv->cck_txbbgain_table[10].ccktxbb_valuearray[4] = 0x10; + priv->cck_txbbgain_table[10].ccktxbb_valuearray[5] = 0x0a; + priv->cck_txbbgain_table[10].ccktxbb_valuearray[6] = 0x05; + priv->cck_txbbgain_table[10].ccktxbb_valuearray[7] = 0x02; + + priv->cck_txbbgain_table[11].ccktxbb_valuearray[0] = 0x1d; + priv->cck_txbbgain_table[11].ccktxbb_valuearray[1] = 0x1c; + priv->cck_txbbgain_table[11].ccktxbb_valuearray[2] = 0x18; + priv->cck_txbbgain_table[11].ccktxbb_valuearray[3] = 0x14; + priv->cck_txbbgain_table[11].ccktxbb_valuearray[4] = 0x0f; + priv->cck_txbbgain_table[11].ccktxbb_valuearray[5] = 0x0a; + priv->cck_txbbgain_table[11].ccktxbb_valuearray[6] = 0x05; + priv->cck_txbbgain_table[11].ccktxbb_valuearray[7] = 0x02; + + priv->cck_txbbgain_table[12].ccktxbb_valuearray[0] = 0x1b; + priv->cck_txbbgain_table[12].ccktxbb_valuearray[1] = 0x1a; + priv->cck_txbbgain_table[12].ccktxbb_valuearray[2] = 0x17; + priv->cck_txbbgain_table[12].ccktxbb_valuearray[3] = 0x13; + priv->cck_txbbgain_table[12].ccktxbb_valuearray[4] = 0x0e; + priv->cck_txbbgain_table[12].ccktxbb_valuearray[5] = 0x09; + priv->cck_txbbgain_table[12].ccktxbb_valuearray[6] = 0x04; + priv->cck_txbbgain_table[12].ccktxbb_valuearray[7] = 0x02; + + priv->cck_txbbgain_table[13].ccktxbb_valuearray[0] = 0x1a; + priv->cck_txbbgain_table[13].ccktxbb_valuearray[1] = 0x19; + priv->cck_txbbgain_table[13].ccktxbb_valuearray[2] = 0x16; + priv->cck_txbbgain_table[13].ccktxbb_valuearray[3] = 0x12; + priv->cck_txbbgain_table[13].ccktxbb_valuearray[4] = 0x0d; + priv->cck_txbbgain_table[13].ccktxbb_valuearray[5] = 0x09; + priv->cck_txbbgain_table[13].ccktxbb_valuearray[6] = 0x04; + priv->cck_txbbgain_table[13].ccktxbb_valuearray[7] = 0x02; + + priv->cck_txbbgain_table[14].ccktxbb_valuearray[0] = 0x18; + priv->cck_txbbgain_table[14].ccktxbb_valuearray[1] = 0x17; + priv->cck_txbbgain_table[14].ccktxbb_valuearray[2] = 0x15; + priv->cck_txbbgain_table[14].ccktxbb_valuearray[3] = 0x11; + priv->cck_txbbgain_table[14].ccktxbb_valuearray[4] = 0x0c; + priv->cck_txbbgain_table[14].ccktxbb_valuearray[5] = 0x08; + priv->cck_txbbgain_table[14].ccktxbb_valuearray[6] = 0x04; + priv->cck_txbbgain_table[14].ccktxbb_valuearray[7] = 0x02; + + priv->cck_txbbgain_table[15].ccktxbb_valuearray[0] = 0x17; + priv->cck_txbbgain_table[15].ccktxbb_valuearray[1] = 0x16; + priv->cck_txbbgain_table[15].ccktxbb_valuearray[2] = 0x13; + priv->cck_txbbgain_table[15].ccktxbb_valuearray[3] = 0x10; + priv->cck_txbbgain_table[15].ccktxbb_valuearray[4] = 0x0c; + priv->cck_txbbgain_table[15].ccktxbb_valuearray[5] = 0x08; + priv->cck_txbbgain_table[15].ccktxbb_valuearray[6] = 0x04; + priv->cck_txbbgain_table[15].ccktxbb_valuearray[7] = 0x02; + + priv->cck_txbbgain_table[16].ccktxbb_valuearray[0] = 0x16; + priv->cck_txbbgain_table[16].ccktxbb_valuearray[1] = 0x15; + priv->cck_txbbgain_table[16].ccktxbb_valuearray[2] = 0x12; + priv->cck_txbbgain_table[16].ccktxbb_valuearray[3] = 0x0f; + priv->cck_txbbgain_table[16].ccktxbb_valuearray[4] = 0x0b; + priv->cck_txbbgain_table[16].ccktxbb_valuearray[5] = 0x07; + priv->cck_txbbgain_table[16].ccktxbb_valuearray[6] = 0x04; + priv->cck_txbbgain_table[16].ccktxbb_valuearray[7] = 0x01; + + priv->cck_txbbgain_table[17].ccktxbb_valuearray[0] = 0x14; + priv->cck_txbbgain_table[17].ccktxbb_valuearray[1] = 0x14; + priv->cck_txbbgain_table[17].ccktxbb_valuearray[2] = 0x11; + priv->cck_txbbgain_table[17].ccktxbb_valuearray[3] = 0x0e; + priv->cck_txbbgain_table[17].ccktxbb_valuearray[4] = 0x0b; + priv->cck_txbbgain_table[17].ccktxbb_valuearray[5] = 0x07; + priv->cck_txbbgain_table[17].ccktxbb_valuearray[6] = 0x03; + priv->cck_txbbgain_table[17].ccktxbb_valuearray[7] = 0x02; + + priv->cck_txbbgain_table[18].ccktxbb_valuearray[0] = 0x13; + priv->cck_txbbgain_table[18].ccktxbb_valuearray[1] = 0x13; + priv->cck_txbbgain_table[18].ccktxbb_valuearray[2] = 0x10; + priv->cck_txbbgain_table[18].ccktxbb_valuearray[3] = 0x0d; + priv->cck_txbbgain_table[18].ccktxbb_valuearray[4] = 0x0a; + priv->cck_txbbgain_table[18].ccktxbb_valuearray[5] = 0x06; + priv->cck_txbbgain_table[18].ccktxbb_valuearray[6] = 0x03; + priv->cck_txbbgain_table[18].ccktxbb_valuearray[7] = 0x01; + + priv->cck_txbbgain_table[19].ccktxbb_valuearray[0] = 0x12; + priv->cck_txbbgain_table[19].ccktxbb_valuearray[1] = 0x12; + priv->cck_txbbgain_table[19].ccktxbb_valuearray[2] = 0x0f; + priv->cck_txbbgain_table[19].ccktxbb_valuearray[3] = 0x0c; + priv->cck_txbbgain_table[19].ccktxbb_valuearray[4] = 0x09; + priv->cck_txbbgain_table[19].ccktxbb_valuearray[5] = 0x06; + priv->cck_txbbgain_table[19].ccktxbb_valuearray[6] = 0x03; + priv->cck_txbbgain_table[19].ccktxbb_valuearray[7] = 0x01; + + priv->cck_txbbgain_table[20].ccktxbb_valuearray[0] = 0x11; + priv->cck_txbbgain_table[20].ccktxbb_valuearray[1] = 0x11; + priv->cck_txbbgain_table[20].ccktxbb_valuearray[2] = 0x0f; + priv->cck_txbbgain_table[20].ccktxbb_valuearray[3] = 0x0c; + priv->cck_txbbgain_table[20].ccktxbb_valuearray[4] = 0x09; + priv->cck_txbbgain_table[20].ccktxbb_valuearray[5] = 0x06; + priv->cck_txbbgain_table[20].ccktxbb_valuearray[6] = 0x03; + priv->cck_txbbgain_table[20].ccktxbb_valuearray[7] = 0x01; + + priv->cck_txbbgain_table[21].ccktxbb_valuearray[0] = 0x10; + priv->cck_txbbgain_table[21].ccktxbb_valuearray[1] = 0x10; + priv->cck_txbbgain_table[21].ccktxbb_valuearray[2] = 0x0e; + priv->cck_txbbgain_table[21].ccktxbb_valuearray[3] = 0x0b; + priv->cck_txbbgain_table[21].ccktxbb_valuearray[4] = 0x08; + priv->cck_txbbgain_table[21].ccktxbb_valuearray[5] = 0x05; + priv->cck_txbbgain_table[21].ccktxbb_valuearray[6] = 0x03; + priv->cck_txbbgain_table[21].ccktxbb_valuearray[7] = 0x01; + + priv->cck_txbbgain_table[22].ccktxbb_valuearray[0] = 0x0f; + priv->cck_txbbgain_table[22].ccktxbb_valuearray[1] = 0x0f; + priv->cck_txbbgain_table[22].ccktxbb_valuearray[2] = 0x0d; + priv->cck_txbbgain_table[22].ccktxbb_valuearray[3] = 0x0b; + priv->cck_txbbgain_table[22].ccktxbb_valuearray[4] = 0x08; + priv->cck_txbbgain_table[22].ccktxbb_valuearray[5] = 0x05; + priv->cck_txbbgain_table[22].ccktxbb_valuearray[6] = 0x03; + priv->cck_txbbgain_table[22].ccktxbb_valuearray[7] = 0x01; + + priv->cck_txbbgain_ch14_table[0].ccktxbb_valuearray[0] = 0x36; + priv->cck_txbbgain_ch14_table[0].ccktxbb_valuearray[1] = 0x35; + priv->cck_txbbgain_ch14_table[0].ccktxbb_valuearray[2] = 0x2e; + priv->cck_txbbgain_ch14_table[0].ccktxbb_valuearray[3] = 0x1b; + priv->cck_txbbgain_ch14_table[0].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[0].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[0].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[0].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[1].ccktxbb_valuearray[0] = 0x33; + priv->cck_txbbgain_ch14_table[1].ccktxbb_valuearray[1] = 0x32; + priv->cck_txbbgain_ch14_table[1].ccktxbb_valuearray[2] = 0x2b; + priv->cck_txbbgain_ch14_table[1].ccktxbb_valuearray[3] = 0x19; + priv->cck_txbbgain_ch14_table[1].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[1].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[1].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[1].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[2].ccktxbb_valuearray[0] = 0x30; + priv->cck_txbbgain_ch14_table[2].ccktxbb_valuearray[1] = 0x2f; + priv->cck_txbbgain_ch14_table[2].ccktxbb_valuearray[2] = 0x29; + priv->cck_txbbgain_ch14_table[2].ccktxbb_valuearray[3] = 0x18; + priv->cck_txbbgain_ch14_table[2].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[2].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[2].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[2].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[3].ccktxbb_valuearray[0] = 0x2d; + priv->cck_txbbgain_ch14_table[3].ccktxbb_valuearray[1] = 0x2d; + priv->cck_txbbgain_ch14_table[3].ccktxbb_valuearray[2] = 0x27; + priv->cck_txbbgain_ch14_table[3].ccktxbb_valuearray[3] = 0x17; + priv->cck_txbbgain_ch14_table[3].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[3].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[3].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[3].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[4].ccktxbb_valuearray[0] = 0x2b; + priv->cck_txbbgain_ch14_table[4].ccktxbb_valuearray[1] = 0x2a; + priv->cck_txbbgain_ch14_table[4].ccktxbb_valuearray[2] = 0x25; + priv->cck_txbbgain_ch14_table[4].ccktxbb_valuearray[3] = 0x15; + priv->cck_txbbgain_ch14_table[4].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[4].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[4].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[4].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[5].ccktxbb_valuearray[0] = 0x28; + priv->cck_txbbgain_ch14_table[5].ccktxbb_valuearray[1] = 0x28; + priv->cck_txbbgain_ch14_table[5].ccktxbb_valuearray[2] = 0x22; + priv->cck_txbbgain_ch14_table[5].ccktxbb_valuearray[3] = 0x14; + priv->cck_txbbgain_ch14_table[5].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[5].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[5].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[5].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[6].ccktxbb_valuearray[0] = 0x26; + priv->cck_txbbgain_ch14_table[6].ccktxbb_valuearray[1] = 0x25; + priv->cck_txbbgain_ch14_table[6].ccktxbb_valuearray[2] = 0x21; + priv->cck_txbbgain_ch14_table[6].ccktxbb_valuearray[3] = 0x13; + priv->cck_txbbgain_ch14_table[6].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[6].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[6].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[6].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[7].ccktxbb_valuearray[0] = 0x24; + priv->cck_txbbgain_ch14_table[7].ccktxbb_valuearray[1] = 0x23; + priv->cck_txbbgain_ch14_table[7].ccktxbb_valuearray[2] = 0x1f; + priv->cck_txbbgain_ch14_table[7].ccktxbb_valuearray[3] = 0x12; + priv->cck_txbbgain_ch14_table[7].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[7].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[7].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[7].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[8].ccktxbb_valuearray[0] = 0x22; + priv->cck_txbbgain_ch14_table[8].ccktxbb_valuearray[1] = 0x21; + priv->cck_txbbgain_ch14_table[8].ccktxbb_valuearray[2] = 0x1d; + priv->cck_txbbgain_ch14_table[8].ccktxbb_valuearray[3] = 0x11; + priv->cck_txbbgain_ch14_table[8].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[8].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[8].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[8].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[9].ccktxbb_valuearray[0] = 0x20; + priv->cck_txbbgain_ch14_table[9].ccktxbb_valuearray[1] = 0x20; + priv->cck_txbbgain_ch14_table[9].ccktxbb_valuearray[2] = 0x1b; + priv->cck_txbbgain_ch14_table[9].ccktxbb_valuearray[3] = 0x10; + priv->cck_txbbgain_ch14_table[9].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[9].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[9].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[9].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[10].ccktxbb_valuearray[0] = 0x1f; + priv->cck_txbbgain_ch14_table[10].ccktxbb_valuearray[1] = 0x1e; + priv->cck_txbbgain_ch14_table[10].ccktxbb_valuearray[2] = 0x1a; + priv->cck_txbbgain_ch14_table[10].ccktxbb_valuearray[3] = 0x0f; + priv->cck_txbbgain_ch14_table[10].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[10].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[10].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[10].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[11].ccktxbb_valuearray[0] = 0x1d; + priv->cck_txbbgain_ch14_table[11].ccktxbb_valuearray[1] = 0x1c; + priv->cck_txbbgain_ch14_table[11].ccktxbb_valuearray[2] = 0x18; + priv->cck_txbbgain_ch14_table[11].ccktxbb_valuearray[3] = 0x0e; + priv->cck_txbbgain_ch14_table[11].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[11].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[11].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[11].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[12].ccktxbb_valuearray[0] = 0x1b; + priv->cck_txbbgain_ch14_table[12].ccktxbb_valuearray[1] = 0x1a; + priv->cck_txbbgain_ch14_table[12].ccktxbb_valuearray[2] = 0x17; + priv->cck_txbbgain_ch14_table[12].ccktxbb_valuearray[3] = 0x0e; + priv->cck_txbbgain_ch14_table[12].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[12].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[12].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[12].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[13].ccktxbb_valuearray[0] = 0x1a; + priv->cck_txbbgain_ch14_table[13].ccktxbb_valuearray[1] = 0x19; + priv->cck_txbbgain_ch14_table[13].ccktxbb_valuearray[2] = 0x16; + priv->cck_txbbgain_ch14_table[13].ccktxbb_valuearray[3] = 0x0d; + priv->cck_txbbgain_ch14_table[13].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[13].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[13].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[13].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[14].ccktxbb_valuearray[0] = 0x18; + priv->cck_txbbgain_ch14_table[14].ccktxbb_valuearray[1] = 0x17; + priv->cck_txbbgain_ch14_table[14].ccktxbb_valuearray[2] = 0x15; + priv->cck_txbbgain_ch14_table[14].ccktxbb_valuearray[3] = 0x0c; + priv->cck_txbbgain_ch14_table[14].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[14].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[14].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[14].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[15].ccktxbb_valuearray[0] = 0x17; + priv->cck_txbbgain_ch14_table[15].ccktxbb_valuearray[1] = 0x16; + priv->cck_txbbgain_ch14_table[15].ccktxbb_valuearray[2] = 0x13; + priv->cck_txbbgain_ch14_table[15].ccktxbb_valuearray[3] = 0x0b; + priv->cck_txbbgain_ch14_table[15].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[15].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[15].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[15].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[16].ccktxbb_valuearray[0] = 0x16; + priv->cck_txbbgain_ch14_table[16].ccktxbb_valuearray[1] = 0x15; + priv->cck_txbbgain_ch14_table[16].ccktxbb_valuearray[2] = 0x12; + priv->cck_txbbgain_ch14_table[16].ccktxbb_valuearray[3] = 0x0b; + priv->cck_txbbgain_ch14_table[16].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[16].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[16].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[16].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[17].ccktxbb_valuearray[0] = 0x14; + priv->cck_txbbgain_ch14_table[17].ccktxbb_valuearray[1] = 0x14; + priv->cck_txbbgain_ch14_table[17].ccktxbb_valuearray[2] = 0x11; + priv->cck_txbbgain_ch14_table[17].ccktxbb_valuearray[3] = 0x0a; + priv->cck_txbbgain_ch14_table[17].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[17].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[17].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[17].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[18].ccktxbb_valuearray[0] = 0x13; + priv->cck_txbbgain_ch14_table[18].ccktxbb_valuearray[1] = 0x13; + priv->cck_txbbgain_ch14_table[18].ccktxbb_valuearray[2] = 0x10; + priv->cck_txbbgain_ch14_table[18].ccktxbb_valuearray[3] = 0x0a; + priv->cck_txbbgain_ch14_table[18].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[18].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[18].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[18].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[19].ccktxbb_valuearray[0] = 0x12; + priv->cck_txbbgain_ch14_table[19].ccktxbb_valuearray[1] = 0x12; + priv->cck_txbbgain_ch14_table[19].ccktxbb_valuearray[2] = 0x0f; + priv->cck_txbbgain_ch14_table[19].ccktxbb_valuearray[3] = 0x09; + priv->cck_txbbgain_ch14_table[19].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[19].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[19].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[19].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[20].ccktxbb_valuearray[0] = 0x11; + priv->cck_txbbgain_ch14_table[20].ccktxbb_valuearray[1] = 0x11; + priv->cck_txbbgain_ch14_table[20].ccktxbb_valuearray[2] = 0x0f; + priv->cck_txbbgain_ch14_table[20].ccktxbb_valuearray[3] = 0x09; + priv->cck_txbbgain_ch14_table[20].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[20].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[20].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[20].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[21].ccktxbb_valuearray[0] = 0x10; + priv->cck_txbbgain_ch14_table[21].ccktxbb_valuearray[1] = 0x10; + priv->cck_txbbgain_ch14_table[21].ccktxbb_valuearray[2] = 0x0e; + priv->cck_txbbgain_ch14_table[21].ccktxbb_valuearray[3] = 0x08; + priv->cck_txbbgain_ch14_table[21].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[21].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[21].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[21].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[22].ccktxbb_valuearray[0] = 0x0f; + priv->cck_txbbgain_ch14_table[22].ccktxbb_valuearray[1] = 0x0f; + priv->cck_txbbgain_ch14_table[22].ccktxbb_valuearray[2] = 0x0d; + priv->cck_txbbgain_ch14_table[22].ccktxbb_valuearray[3] = 0x08; + priv->cck_txbbgain_ch14_table[22].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[22].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[22].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[22].ccktxbb_valuearray[7] = 0x00; + + priv->btxpower_tracking = true; + priv->txpower_count = 0; + priv->btxpower_trackingInit = false; + +} + +static void dm_InitializeTXPowerTracking_ThermalMeter(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + + if (priv->rtllib->FwRWRF) + priv->btxpower_tracking = true; + else + priv->btxpower_tracking = false; + priv->txpower_count = 0; + priv->btxpower_trackingInit = false; + RT_TRACE(COMP_POWER_TRACKING, "pMgntInfo->bTXPowerTracking = %d\n", + priv->btxpower_tracking); +} + +void dm_initialize_txpower_tracking(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + if (priv->IC_Cut >= IC_VersionCut_D) + dm_InitializeTXPowerTracking_TSSI(dev); + else + dm_InitializeTXPowerTracking_ThermalMeter(dev); +} + +static void dm_CheckTXPowerTracking_TSSI(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + static u32 tx_power_track_counter; + + RT_TRACE(COMP_POWER_TRACKING, "%s()\n", __func__); + if (read_nic_byte(dev, 0x11e) == 1) + return; + if (!priv->btxpower_tracking) + return; + tx_power_track_counter++; + + + if (tx_power_track_counter >= 180) { + queue_delayed_work_rsl(priv->priv_wq, &priv->txpower_tracking_wq, 0); + tx_power_track_counter = 0; + } + +} +static void dm_CheckTXPowerTracking_ThermalMeter(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + static u8 TM_Trigger; + u8 TxPowerCheckCnt = 0; + + if (IS_HARDWARE_TYPE_8192SE(dev)) + TxPowerCheckCnt = 5; + else + TxPowerCheckCnt = 2; + if (!priv->btxpower_tracking) + return; + + if (priv->txpower_count <= TxPowerCheckCnt) { + priv->txpower_count++; + return; + } + + if (!TM_Trigger) { + { + rtl8192_phy_SetRFReg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4d); + rtl8192_phy_SetRFReg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4f); + rtl8192_phy_SetRFReg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4d); + rtl8192_phy_SetRFReg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4f); + } + TM_Trigger = 1; + return; + } + netdev_info(dev, "===============>Schedule TxPowerTrackingWorkItem\n"); + queue_delayed_work_rsl(priv->priv_wq, &priv->txpower_tracking_wq, 0); + TM_Trigger = 0; + +} + +static void dm_check_txpower_tracking(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + if (priv->IC_Cut >= IC_VersionCut_D) + dm_CheckTXPowerTracking_TSSI(dev); + else + dm_CheckTXPowerTracking_ThermalMeter(dev); +} + +static void dm_CCKTxPowerAdjust_TSSI(struct net_device *dev, bool bInCH14) +{ + u32 TempVal; + struct r8192_priv *priv = rtllib_priv(dev); + + TempVal = 0; + if (!bInCH14) { + TempVal = (u32)(priv->cck_txbbgain_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[0] + + (priv->cck_txbbgain_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[1]<<8)); + + rtl8192_setBBreg(dev, rCCK0_TxFilter1, bMaskHWord, TempVal); + TempVal = (u32)(priv->cck_txbbgain_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[2] + + (priv->cck_txbbgain_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[3]<<8) + + (priv->cck_txbbgain_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[4]<<16)+ + (priv->cck_txbbgain_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[5]<<24)); + rtl8192_setBBreg(dev, rCCK0_TxFilter2, bMaskDWord, TempVal); + TempVal = (u32)(priv->cck_txbbgain_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[6] + + (priv->cck_txbbgain_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[7]<<8)); + + rtl8192_setBBreg(dev, rCCK0_DebugPort, bMaskLWord, TempVal); + } else { + TempVal = (u32)(priv->cck_txbbgain_ch14_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[0] + + (priv->cck_txbbgain_ch14_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[1]<<8)); + + rtl8192_setBBreg(dev, rCCK0_TxFilter1, bMaskHWord, TempVal); + TempVal = (u32)(priv->cck_txbbgain_ch14_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[2] + + (priv->cck_txbbgain_ch14_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[3]<<8) + + (priv->cck_txbbgain_ch14_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[4]<<16)+ + (priv->cck_txbbgain_ch14_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[5]<<24)); + rtl8192_setBBreg(dev, rCCK0_TxFilter2, bMaskDWord, TempVal); + TempVal = (u32)(priv->cck_txbbgain_ch14_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[6] + + (priv->cck_txbbgain_ch14_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[7]<<8)); + + rtl8192_setBBreg(dev, rCCK0_DebugPort, bMaskLWord, TempVal); + } + + +} + +static void dm_CCKTxPowerAdjust_ThermalMeter(struct net_device *dev, bool bInCH14) +{ + u32 TempVal; + struct r8192_priv *priv = rtllib_priv(dev); + + TempVal = 0; + if (!bInCH14) { + TempVal = CCKSwingTable_Ch1_Ch13[priv->CCK_index][0] + + (CCKSwingTable_Ch1_Ch13[priv->CCK_index][1]<<8); + rtl8192_setBBreg(dev, rCCK0_TxFilter1, bMaskHWord, TempVal); + RT_TRACE(COMP_POWER_TRACKING, "CCK not chnl 14, reg 0x%x = 0x%x\n", + rCCK0_TxFilter1, TempVal); + TempVal = CCKSwingTable_Ch1_Ch13[priv->CCK_index][2] + + (CCKSwingTable_Ch1_Ch13[priv->CCK_index][3]<<8) + + (CCKSwingTable_Ch1_Ch13[priv->CCK_index][4]<<16)+ + (CCKSwingTable_Ch1_Ch13[priv->CCK_index][5]<<24); + rtl8192_setBBreg(dev, rCCK0_TxFilter2, bMaskDWord, TempVal); + RT_TRACE(COMP_POWER_TRACKING, "CCK not chnl 14, reg 0x%x = 0x%x\n", + rCCK0_TxFilter2, TempVal); + TempVal = CCKSwingTable_Ch1_Ch13[priv->CCK_index][6] + + (CCKSwingTable_Ch1_Ch13[priv->CCK_index][7]<<8); + + rtl8192_setBBreg(dev, rCCK0_DebugPort, bMaskLWord, TempVal); + RT_TRACE(COMP_POWER_TRACKING, "CCK not chnl 14, reg 0x%x = 0x%x\n", + rCCK0_DebugPort, TempVal); + } else { + TempVal = CCKSwingTable_Ch14[priv->CCK_index][0] + + (CCKSwingTable_Ch14[priv->CCK_index][1]<<8); + + rtl8192_setBBreg(dev, rCCK0_TxFilter1, bMaskHWord, TempVal); + RT_TRACE(COMP_POWER_TRACKING, "CCK chnl 14, reg 0x%x = 0x%x\n", + rCCK0_TxFilter1, TempVal); + TempVal = CCKSwingTable_Ch14[priv->CCK_index][2] + + (CCKSwingTable_Ch14[priv->CCK_index][3]<<8) + + (CCKSwingTable_Ch14[priv->CCK_index][4]<<16)+ + (CCKSwingTable_Ch14[priv->CCK_index][5]<<24); + rtl8192_setBBreg(dev, rCCK0_TxFilter2, bMaskDWord, TempVal); + RT_TRACE(COMP_POWER_TRACKING, "CCK chnl 14, reg 0x%x = 0x%x\n", + rCCK0_TxFilter2, TempVal); + TempVal = CCKSwingTable_Ch14[priv->CCK_index][6] + + (CCKSwingTable_Ch14[priv->CCK_index][7]<<8); + + rtl8192_setBBreg(dev, rCCK0_DebugPort, bMaskLWord, TempVal); + RT_TRACE(COMP_POWER_TRACKING, "CCK chnl 14, reg 0x%x = 0x%x\n", + rCCK0_DebugPort, TempVal); + } + } + +void dm_cck_txpower_adjust(struct net_device *dev, bool binch14) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + if (priv->IC_Cut >= IC_VersionCut_D) + dm_CCKTxPowerAdjust_TSSI(dev, binch14); + else + dm_CCKTxPowerAdjust_ThermalMeter(dev, binch14); +} + +static void dm_txpower_reset_recovery(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + RT_TRACE(COMP_POWER_TRACKING, "Start Reset Recovery ==>\n"); + rtl8192_setBBreg(dev, rOFDM0_XATxIQImbalance, bMaskDWord, + priv->txbbgain_table[priv->rfa_txpowertrackingindex].txbbgain_value); + RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: Fill in 0xc80 is %08x\n", + priv->txbbgain_table[priv->rfa_txpowertrackingindex].txbbgain_value); + RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: Fill in RFA_txPowerTrackingIndex is %x\n", + priv->rfa_txpowertrackingindex); + RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery : RF A I/Q Amplify Gain is %ld\n", + priv->txbbgain_table[priv->rfa_txpowertrackingindex].txbb_iq_amplifygain); + RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: CCK Attenuation is %d dB\n", + priv->CCKPresentAttentuation); + dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); + + rtl8192_setBBreg(dev, rOFDM0_XCTxIQImbalance, bMaskDWord, + priv->txbbgain_table[priv->rfc_txpowertrackingindex].txbbgain_value); + RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: Fill in 0xc90 is %08x\n", + priv->txbbgain_table[priv->rfc_txpowertrackingindex].txbbgain_value); + RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: Fill in RFC_txPowerTrackingIndex is %x\n", + priv->rfc_txpowertrackingindex); + RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery : RF C I/Q Amplify Gain is %ld\n", + priv->txbbgain_table[priv->rfc_txpowertrackingindex].txbb_iq_amplifygain); + +} + +void dm_restore_dynamic_mechanism_state(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + u32 reg_ratr = priv->rate_adaptive.last_ratr; + u32 ratr_value; + + if (!priv->up) { + RT_TRACE(COMP_RATE, "<---- dm_restore_dynamic_mechanism_state(): driver is going to unload\n"); + return; + } + + if (priv->rate_adaptive.rate_adaptive_disabled) + return; + if (!(priv->rtllib->mode == WIRELESS_MODE_N_24G || + priv->rtllib->mode == WIRELESS_MODE_N_5G)) + return; + ratr_value = reg_ratr; + if (priv->rf_type == RF_1T2R) + ratr_value &= ~(RATE_ALL_OFDM_2SS); + write_nic_dword(dev, RATR0, ratr_value); + write_nic_byte(dev, UFWP, 1); + if (priv->btxpower_trackingInit && priv->btxpower_tracking) + dm_txpower_reset_recovery(dev); + + dm_bb_initialgain_restore(dev); + +} + +static void dm_bb_initialgain_restore(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + u32 bit_mask = 0x7f; + + if (dm_digtable.dig_algorithm == DIG_ALGO_BY_RSSI) + return; + + rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); + rtl8192_setBBreg(dev, rOFDM0_XAAGCCore1, bit_mask, (u32)priv->initgain_backup.xaagccore1); + rtl8192_setBBreg(dev, rOFDM0_XBAGCCore1, bit_mask, (u32)priv->initgain_backup.xbagccore1); + rtl8192_setBBreg(dev, rOFDM0_XCAGCCore1, bit_mask, (u32)priv->initgain_backup.xcagccore1); + rtl8192_setBBreg(dev, rOFDM0_XDAGCCore1, bit_mask, (u32)priv->initgain_backup.xdagccore1); + bit_mask = bMaskByte2; + rtl8192_setBBreg(dev, rCCK0_CCA, bit_mask, (u32)priv->initgain_backup.cca); + + RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xc50 is %x\n", priv->initgain_backup.xaagccore1); + RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xc58 is %x\n", priv->initgain_backup.xbagccore1); + RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xc60 is %x\n", priv->initgain_backup.xcagccore1); + RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xc68 is %x\n", priv->initgain_backup.xdagccore1); + RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xa0a is %x\n", priv->initgain_backup.cca); + rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x1); + +} + + +void dm_backup_dynamic_mechanism_state(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + priv->bswitch_fsync = false; + priv->bfsync_processing = false; + dm_bb_initialgain_backup(dev); + +} + + +static void dm_bb_initialgain_backup(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + u32 bit_mask = bMaskByte0; + + if (dm_digtable.dig_algorithm == DIG_ALGO_BY_RSSI) + return; + + rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); + priv->initgain_backup.xaagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XAAGCCore1, bit_mask); + priv->initgain_backup.xbagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XBAGCCore1, bit_mask); + priv->initgain_backup.xcagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XCAGCCore1, bit_mask); + priv->initgain_backup.xdagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XDAGCCore1, bit_mask); + bit_mask = bMaskByte2; + priv->initgain_backup.cca = (u8)rtl8192_QueryBBReg(dev, rCCK0_CCA, bit_mask); + + RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xc50 is %x\n", priv->initgain_backup.xaagccore1); + RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xc58 is %x\n", priv->initgain_backup.xbagccore1); + RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xc60 is %x\n", priv->initgain_backup.xcagccore1); + RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xc68 is %x\n", priv->initgain_backup.xdagccore1); + RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xa0a is %x\n", priv->initgain_backup.cca); + +} + +void dm_change_dynamic_initgain_thresh(struct net_device *dev, + u32 dm_type, u32 dm_value) +{ + if (dm_type == DIG_TYPE_THRESH_HIGH) { + dm_digtable.rssi_high_thresh = dm_value; + } else if (dm_type == DIG_TYPE_THRESH_LOW) { + dm_digtable.rssi_low_thresh = dm_value; + } else if (dm_type == DIG_TYPE_THRESH_HIGHPWR_HIGH) { + dm_digtable.rssi_high_power_highthresh = dm_value; + } else if (dm_type == DIG_TYPE_THRESH_HIGHPWR_LOW) { + dm_digtable.rssi_high_power_lowthresh = dm_value; + } else if (dm_type == DIG_TYPE_ENABLE) { + dm_digtable.dig_state = DM_STA_DIG_MAX; + dm_digtable.dig_enable_flag = true; + } else if (dm_type == DIG_TYPE_DISABLE) { + dm_digtable.dig_state = DM_STA_DIG_MAX; + dm_digtable.dig_enable_flag = false; + } else if (dm_type == DIG_TYPE_DBG_MODE) { + if (dm_value >= DM_DBG_MAX) + dm_value = DM_DBG_OFF; + dm_digtable.dbg_mode = (u8)dm_value; + } else if (dm_type == DIG_TYPE_RSSI) { + if (dm_value > 100) + dm_value = 30; + dm_digtable.rssi_val = (long)dm_value; + } else if (dm_type == DIG_TYPE_ALGORITHM) { + if (dm_value >= DIG_ALGO_MAX) + dm_value = DIG_ALGO_BY_FALSE_ALARM; + if (dm_digtable.dig_algorithm != (u8)dm_value) + dm_digtable.dig_algorithm_switch = 1; + dm_digtable.dig_algorithm = (u8)dm_value; + } else if (dm_type == DIG_TYPE_BACKOFF) { + if (dm_value > 30) + dm_value = 30; + dm_digtable.backoff_val = (u8)dm_value; + } else if (dm_type == DIG_TYPE_RX_GAIN_MIN) { + if (dm_value == 0) + dm_value = 0x1; + dm_digtable.rx_gain_range_min = (u8)dm_value; + } else if (dm_type == DIG_TYPE_RX_GAIN_MAX) { + if (dm_value > 0x50) + dm_value = 0x50; + dm_digtable.rx_gain_range_max = (u8)dm_value; + } +} + +static void dm_dig_init(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + dm_digtable.dig_enable_flag = true; + dm_digtable.Backoff_Enable_Flag = true; + + dm_digtable.dig_algorithm = DIG_ALGO_BY_RSSI; + + dm_digtable.Dig_TwoPort_Algorithm = DIG_TWO_PORT_ALGO_RSSI; + dm_digtable.Dig_Ext_Port_Stage = DIG_EXT_PORT_STAGE_MAX; + dm_digtable.dbg_mode = DM_DBG_OFF; + dm_digtable.dig_algorithm_switch = 0; + + dm_digtable.dig_state = DM_STA_DIG_MAX; + dm_digtable.dig_highpwr_state = DM_STA_DIG_MAX; + dm_digtable.CurSTAConnectState = dm_digtable.PreSTAConnectState = DIG_STA_DISCONNECT; + dm_digtable.CurAPConnectState = dm_digtable.PreAPConnectState = DIG_AP_DISCONNECT; + dm_digtable.initialgain_lowerbound_state = false; + + dm_digtable.rssi_low_thresh = DM_DIG_THRESH_LOW; + dm_digtable.rssi_high_thresh = DM_DIG_THRESH_HIGH; + + dm_digtable.FALowThresh = DM_FALSEALARM_THRESH_LOW; + dm_digtable.FAHighThresh = DM_FALSEALARM_THRESH_HIGH; + + dm_digtable.rssi_high_power_lowthresh = DM_DIG_HIGH_PWR_THRESH_LOW; + dm_digtable.rssi_high_power_highthresh = DM_DIG_HIGH_PWR_THRESH_HIGH; + + dm_digtable.rssi_val = 50; + dm_digtable.backoff_val = DM_DIG_BACKOFF; + dm_digtable.rx_gain_range_max = DM_DIG_MAX; + if (priv->CustomerID == RT_CID_819x_Netcore) + dm_digtable.rx_gain_range_min = DM_DIG_MIN_Netcore; + else + dm_digtable.rx_gain_range_min = DM_DIG_MIN; + + dm_digtable.BackoffVal_range_max = DM_DIG_BACKOFF_MAX; + dm_digtable.BackoffVal_range_min = DM_DIG_BACKOFF_MIN; +} + +static void dm_ctrl_initgain_byrssi(struct net_device *dev) +{ + + if (dm_digtable.dig_enable_flag == false) + return; + + if (dm_digtable.dig_algorithm == DIG_ALGO_BY_FALSE_ALARM) + dm_ctrl_initgain_byrssi_by_fwfalse_alarm(dev); + else if (dm_digtable.dig_algorithm == DIG_ALGO_BY_RSSI) + dm_ctrl_initgain_byrssi_by_driverrssi(dev); + else + return; +} + +/*----------------------------------------------------------------------------- + * Function: dm_CtrlInitGainBeforeConnectByRssiAndFalseAlarm() + * + * Overview: Driver monitor RSSI and False Alarm to change initial gain. + Only change initial gain during link in progress. + * + * Input: IN PADAPTER pAdapter + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 03/04/2009 hpfan Create Version 0. + * + *---------------------------------------------------------------------------*/ + +static void dm_ctrl_initgain_byrssi_by_driverrssi( + struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + u8 i; + static u8 fw_dig; + + if (dm_digtable.dig_enable_flag == false) + return; + + if (dm_digtable.dig_algorithm_switch) + fw_dig = 0; + if (fw_dig <= 3) { + for (i = 0; i < 3; i++) + rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); + fw_dig++; + dm_digtable.dig_state = DM_STA_DIG_OFF; + } + + if (priv->rtllib->state == RTLLIB_LINKED) + dm_digtable.CurSTAConnectState = DIG_STA_CONNECT; + else + dm_digtable.CurSTAConnectState = DIG_STA_DISCONNECT; + + + if (dm_digtable.dbg_mode == DM_DBG_OFF) + dm_digtable.rssi_val = priv->undecorated_smoothed_pwdb; + dm_initial_gain(dev); + dm_pd_th(dev); + dm_cs_ratio(dev); + if (dm_digtable.dig_algorithm_switch) + dm_digtable.dig_algorithm_switch = 0; + dm_digtable.PreSTAConnectState = dm_digtable.CurSTAConnectState; + +} + +static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm( + struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + static u32 reset_cnt; + u8 i; + + if (dm_digtable.dig_enable_flag == false) + return; + + if (dm_digtable.dig_algorithm_switch) { + dm_digtable.dig_state = DM_STA_DIG_MAX; + for (i = 0; i < 3; i++) + rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x1); + dm_digtable.dig_algorithm_switch = 0; + } + + if (priv->rtllib->state != RTLLIB_LINKED) + return; + + if ((priv->undecorated_smoothed_pwdb > dm_digtable.rssi_low_thresh) && + (priv->undecorated_smoothed_pwdb < dm_digtable.rssi_high_thresh)) + return; + if (priv->undecorated_smoothed_pwdb <= dm_digtable.rssi_low_thresh) { + if (dm_digtable.dig_state == DM_STA_DIG_OFF && + (priv->reset_count == reset_cnt)) + return; + reset_cnt = priv->reset_count; + + dm_digtable.dig_highpwr_state = DM_STA_DIG_MAX; + dm_digtable.dig_state = DM_STA_DIG_OFF; + + rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); + + write_nic_byte(dev, rOFDM0_XAAGCCore1, 0x17); + write_nic_byte(dev, rOFDM0_XBAGCCore1, 0x17); + write_nic_byte(dev, rOFDM0_XCAGCCore1, 0x17); + write_nic_byte(dev, rOFDM0_XDAGCCore1, 0x17); + + if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) + write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x00); + else + write_nic_byte(dev, rOFDM0_RxDetector1, 0x42); + + write_nic_byte(dev, 0xa0a, 0x08); + + return; + } + + if (priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_thresh) { + u8 reset_flag = 0; + + if (dm_digtable.dig_state == DM_STA_DIG_ON && + (priv->reset_count == reset_cnt)) { + dm_ctrl_initgain_byrssi_highpwr(dev); + return; + } + if (priv->reset_count != reset_cnt) + reset_flag = 1; + + reset_cnt = priv->reset_count; + + dm_digtable.dig_state = DM_STA_DIG_ON; + + if (reset_flag == 1) { + write_nic_byte(dev, rOFDM0_XAAGCCore1, 0x2c); + write_nic_byte(dev, rOFDM0_XBAGCCore1, 0x2c); + write_nic_byte(dev, rOFDM0_XCAGCCore1, 0x2c); + write_nic_byte(dev, rOFDM0_XDAGCCore1, 0x2c); + } else { + write_nic_byte(dev, rOFDM0_XAAGCCore1, 0x20); + write_nic_byte(dev, rOFDM0_XBAGCCore1, 0x20); + write_nic_byte(dev, rOFDM0_XCAGCCore1, 0x20); + write_nic_byte(dev, rOFDM0_XDAGCCore1, 0x20); + } + + if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) + write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x20); + else + write_nic_byte(dev, rOFDM0_RxDetector1, 0x44); + + write_nic_byte(dev, 0xa0a, 0xcd); + + rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x1); + } + dm_ctrl_initgain_byrssi_highpwr(dev); +} + + +static void dm_ctrl_initgain_byrssi_highpwr(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + static u32 reset_cnt_highpwr; + + if ((priv->undecorated_smoothed_pwdb > dm_digtable.rssi_high_power_lowthresh) && + (priv->undecorated_smoothed_pwdb < dm_digtable.rssi_high_power_highthresh)) + return; + + if (priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_power_highthresh) { + if (dm_digtable.dig_highpwr_state == DM_STA_DIG_ON && + (priv->reset_count == reset_cnt_highpwr)) + return; + dm_digtable.dig_highpwr_state = DM_STA_DIG_ON; + + if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) + write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x10); + else + write_nic_byte(dev, rOFDM0_RxDetector1, 0x43); + } else { + if (dm_digtable.dig_highpwr_state == DM_STA_DIG_OFF && + (priv->reset_count == reset_cnt_highpwr)) + return; + dm_digtable.dig_highpwr_state = DM_STA_DIG_OFF; + + if (priv->undecorated_smoothed_pwdb < dm_digtable.rssi_high_power_lowthresh && + priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_thresh) { + if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) + write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x20); + else + write_nic_byte(dev, rOFDM0_RxDetector1, 0x44); + } + } + reset_cnt_highpwr = priv->reset_count; +} + +static void dm_initial_gain(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + u8 initial_gain = 0; + static u8 initialized, force_write; + static u32 reset_cnt; + + if (dm_digtable.dig_algorithm_switch) { + initialized = 0; + reset_cnt = 0; + } + + if (rtllib_act_scanning(priv->rtllib, true) == true) { + force_write = 1; + return; + } + + if (dm_digtable.PreSTAConnectState == dm_digtable.CurSTAConnectState) { + if (dm_digtable.CurSTAConnectState == DIG_STA_CONNECT) { + if ((dm_digtable.rssi_val+10-dm_digtable.backoff_val) > dm_digtable.rx_gain_range_max) + dm_digtable.cur_ig_value = dm_digtable.rx_gain_range_max; + else if ((dm_digtable.rssi_val+10-dm_digtable.backoff_val) < dm_digtable.rx_gain_range_min) + dm_digtable.cur_ig_value = dm_digtable.rx_gain_range_min; + else + dm_digtable.cur_ig_value = dm_digtable.rssi_val+10-dm_digtable.backoff_val; + } else { + if (dm_digtable.cur_ig_value == 0) + dm_digtable.cur_ig_value = priv->DefaultInitialGain[0]; + else + dm_digtable.cur_ig_value = dm_digtable.pre_ig_value; + } + } else { + dm_digtable.cur_ig_value = priv->DefaultInitialGain[0]; + dm_digtable.pre_ig_value = 0; + } + + if (priv->reset_count != reset_cnt) { + force_write = 1; + reset_cnt = priv->reset_count; + } + + if (dm_digtable.pre_ig_value != read_nic_byte(dev, rOFDM0_XAAGCCore1)) + force_write = 1; + + if ((dm_digtable.pre_ig_value != dm_digtable.cur_ig_value) + || !initialized || force_write) { + initial_gain = (u8)dm_digtable.cur_ig_value; + write_nic_byte(dev, rOFDM0_XAAGCCore1, initial_gain); + write_nic_byte(dev, rOFDM0_XBAGCCore1, initial_gain); + write_nic_byte(dev, rOFDM0_XCAGCCore1, initial_gain); + write_nic_byte(dev, rOFDM0_XDAGCCore1, initial_gain); + dm_digtable.pre_ig_value = dm_digtable.cur_ig_value; + initialized = 1; + force_write = 0; + } +} + +static void dm_pd_th(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + static u8 initialized, force_write; + static u32 reset_cnt; + + if (dm_digtable.dig_algorithm_switch) { + initialized = 0; + reset_cnt = 0; + } + + if (dm_digtable.PreSTAConnectState == dm_digtable.CurSTAConnectState) { + if (dm_digtable.CurSTAConnectState == DIG_STA_CONNECT) { + if (dm_digtable.rssi_val >= dm_digtable.rssi_high_power_highthresh) + dm_digtable.curpd_thstate = DIG_PD_AT_HIGH_POWER; + else if (dm_digtable.rssi_val <= dm_digtable.rssi_low_thresh) + dm_digtable.curpd_thstate = DIG_PD_AT_LOW_POWER; + else if ((dm_digtable.rssi_val >= dm_digtable.rssi_high_thresh) && + (dm_digtable.rssi_val < dm_digtable.rssi_high_power_lowthresh)) + dm_digtable.curpd_thstate = DIG_PD_AT_NORMAL_POWER; + else + dm_digtable.curpd_thstate = dm_digtable.prepd_thstate; + } else { + dm_digtable.curpd_thstate = DIG_PD_AT_LOW_POWER; + } + } else { + dm_digtable.curpd_thstate = DIG_PD_AT_LOW_POWER; + } + + if (priv->reset_count != reset_cnt) { + force_write = 1; + reset_cnt = priv->reset_count; + } + + if ((dm_digtable.prepd_thstate != dm_digtable.curpd_thstate) || + (initialized <= 3) || force_write) { + if (dm_digtable.curpd_thstate == DIG_PD_AT_LOW_POWER) { + if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) + write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x00); + else + write_nic_byte(dev, rOFDM0_RxDetector1, 0x42); + } else if (dm_digtable.curpd_thstate == DIG_PD_AT_NORMAL_POWER) { + if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) + write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x20); + else + write_nic_byte(dev, rOFDM0_RxDetector1, 0x44); + } else if (dm_digtable.curpd_thstate == DIG_PD_AT_HIGH_POWER) { + if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) + write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x10); + else + write_nic_byte(dev, rOFDM0_RxDetector1, 0x43); + } + dm_digtable.prepd_thstate = dm_digtable.curpd_thstate; + if (initialized <= 3) + initialized++; + force_write = 0; + } +} + +static void dm_cs_ratio(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + static u8 initialized, force_write; + static u32 reset_cnt; + + if (dm_digtable.dig_algorithm_switch) { + initialized = 0; + reset_cnt = 0; + } + + if (dm_digtable.PreSTAConnectState == dm_digtable.CurSTAConnectState) { + if (dm_digtable.CurSTAConnectState == DIG_STA_CONNECT) { + if (dm_digtable.rssi_val <= dm_digtable.rssi_low_thresh) + dm_digtable.curcs_ratio_state = DIG_CS_RATIO_LOWER; + else if (dm_digtable.rssi_val >= dm_digtable.rssi_high_thresh) + dm_digtable.curcs_ratio_state = DIG_CS_RATIO_HIGHER; + else + dm_digtable.curcs_ratio_state = dm_digtable.precs_ratio_state; + } else { + dm_digtable.curcs_ratio_state = DIG_CS_RATIO_LOWER; + } + } else { + dm_digtable.curcs_ratio_state = DIG_CS_RATIO_LOWER; + } + + if (priv->reset_count != reset_cnt) { + force_write = 1; + reset_cnt = priv->reset_count; + } + + + if ((dm_digtable.precs_ratio_state != dm_digtable.curcs_ratio_state) || + !initialized || force_write) { + if (dm_digtable.curcs_ratio_state == DIG_CS_RATIO_LOWER) + write_nic_byte(dev, 0xa0a, 0x08); + else if (dm_digtable.curcs_ratio_state == DIG_CS_RATIO_HIGHER) + write_nic_byte(dev, 0xa0a, 0xcd); + dm_digtable.precs_ratio_state = dm_digtable.curcs_ratio_state; + initialized = 1; + force_write = 0; + } +} + +void dm_init_edca_turbo(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + priv->bcurrent_turbo_EDCA = false; + priv->rtllib->bis_any_nonbepkts = false; + priv->bis_cur_rdlstate = false; +} + +static void dm_check_edca_turbo(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct rt_hi_throughput *pHTInfo = priv->rtllib->pHTInfo; + + static unsigned long lastTxOkCnt; + static unsigned long lastRxOkCnt; + unsigned long curTxOkCnt = 0; + unsigned long curRxOkCnt = 0; + + if (priv->rtllib->iw_mode == IW_MODE_ADHOC) + goto dm_CheckEdcaTurbo_EXIT; + if (priv->rtllib->state != RTLLIB_LINKED) + goto dm_CheckEdcaTurbo_EXIT; + if (priv->rtllib->pHTInfo->IOTAction & HT_IOT_ACT_DISABLE_EDCA_TURBO) + goto dm_CheckEdcaTurbo_EXIT; + + { + u8 *peername[11] = { + "unknown", "realtek_90", "realtek_92se", "broadcom", + "ralink", "atheros", "cisco", "marvell", "92u_softap", + "self_softap" + }; + static int wb_tmp; + + if (wb_tmp == 0) { + netdev_info(dev, + "%s():iot peer is %s, bssid: %pM\n", + __func__, peername[pHTInfo->IOTPeer], + priv->rtllib->current_network.bssid); + wb_tmp = 1; + } + } + if (!priv->rtllib->bis_any_nonbepkts) { + curTxOkCnt = priv->stats.txbytesunicast - lastTxOkCnt; + curRxOkCnt = priv->stats.rxbytesunicast - lastRxOkCnt; + if (pHTInfo->IOTAction & HT_IOT_ACT_EDCA_BIAS_ON_RX) { + if (curTxOkCnt > 4*curRxOkCnt) { + if (priv->bis_cur_rdlstate || + !priv->bcurrent_turbo_EDCA) { + write_nic_dword(dev, EDCAPARA_BE, + edca_setting_UL[pHTInfo->IOTPeer]); + priv->bis_cur_rdlstate = false; + } + } else { + if (!priv->bis_cur_rdlstate || + !priv->bcurrent_turbo_EDCA) { + if (priv->rtllib->mode == WIRELESS_MODE_G) + write_nic_dword(dev, EDCAPARA_BE, + edca_setting_DL_GMode[pHTInfo->IOTPeer]); + else + write_nic_dword(dev, EDCAPARA_BE, + edca_setting_DL[pHTInfo->IOTPeer]); + priv->bis_cur_rdlstate = true; + } + } + priv->bcurrent_turbo_EDCA = true; + } else { + if (curRxOkCnt > 4*curTxOkCnt) { + if (!priv->bis_cur_rdlstate || !priv->bcurrent_turbo_EDCA) { + if (priv->rtllib->mode == WIRELESS_MODE_G) + write_nic_dword(dev, EDCAPARA_BE, + edca_setting_DL_GMode[pHTInfo->IOTPeer]); + else + write_nic_dword(dev, EDCAPARA_BE, + edca_setting_DL[pHTInfo->IOTPeer]); + priv->bis_cur_rdlstate = true; + } + } else { + if (priv->bis_cur_rdlstate || + !priv->bcurrent_turbo_EDCA) { + write_nic_dword(dev, EDCAPARA_BE, + edca_setting_UL[pHTInfo->IOTPeer]); + priv->bis_cur_rdlstate = false; + } + + } + + priv->bcurrent_turbo_EDCA = true; + } + } else { + if (priv->bcurrent_turbo_EDCA) { + u8 tmp = AC0_BE; + + priv->rtllib->SetHwRegHandler(dev, HW_VAR_AC_PARAM, (u8 *)(&tmp)); + priv->bcurrent_turbo_EDCA = false; + } + } + + +dm_CheckEdcaTurbo_EXIT: + priv->rtllib->bis_any_nonbepkts = false; + lastTxOkCnt = priv->stats.txbytesunicast; + lastRxOkCnt = priv->stats.rxbytesunicast; +} + +static void dm_init_ctstoself(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv((struct net_device *)dev); + + priv->rtllib->bCTSToSelfEnable = true; + priv->rtllib->CTSToSelfTH = CTSToSelfTHVal; +} + +static void dm_ctstoself(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv((struct net_device *)dev); + struct rt_hi_throughput *pHTInfo = priv->rtllib->pHTInfo; + static unsigned long lastTxOkCnt; + static unsigned long lastRxOkCnt; + unsigned long curTxOkCnt = 0; + unsigned long curRxOkCnt = 0; + + if (priv->rtllib->bCTSToSelfEnable != true) { + pHTInfo->IOTAction &= ~HT_IOT_ACT_FORCED_CTS2SELF; + return; + } + if (pHTInfo->IOTPeer == HT_IOT_PEER_BROADCOM) { + curTxOkCnt = priv->stats.txbytesunicast - lastTxOkCnt; + curRxOkCnt = priv->stats.rxbytesunicast - lastRxOkCnt; + if (curRxOkCnt > 4*curTxOkCnt) + pHTInfo->IOTAction &= ~HT_IOT_ACT_FORCED_CTS2SELF; + else + pHTInfo->IOTAction |= HT_IOT_ACT_FORCED_CTS2SELF; + + lastTxOkCnt = priv->stats.txbytesunicast; + lastRxOkCnt = priv->stats.rxbytesunicast; + } +} + + +static void dm_Init_WA_Broadcom_IOT(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv((struct net_device *)dev); + struct rt_hi_throughput *pHTInfo = priv->rtllib->pHTInfo; + + pHTInfo->bWAIotBroadcom = false; + pHTInfo->WAIotTH = WAIotTHVal; +} + +static void dm_check_pbc_gpio(struct net_device *dev) +{ +} + +void dm_CheckRfCtrlGPIO(void *data) +{ + struct r8192_priv *priv = container_of_dwork_rsl(data, + struct r8192_priv, gpio_change_rf_wq); + struct net_device *dev = priv->rtllib->dev; + u8 tmp1byte; + enum rt_rf_power_state eRfPowerStateToSet; + bool bActuallySet = false; + char *argv[3]; + static char *RadioPowerPath = "/etc/acpi/events/RadioPower.sh"; + static char *envp[] = {"HOME=/", "TERM=linux", "PATH=/usr/bin:/bin", NULL}; + + bActuallySet = false; + + if ((priv->up_first_time == 1) || (priv->being_init_adapter)) + return; + + if (priv->bfirst_after_down) { + priv->bfirst_after_down = true; + return; + } + + tmp1byte = read_nic_byte(dev, GPI); + + eRfPowerStateToSet = (tmp1byte&BIT1) ? eRfOn : eRfOff; + + if (priv->bHwRadioOff && (eRfPowerStateToSet == eRfOn)) { + RT_TRACE(COMP_RF, "gpiochangeRF - HW Radio ON\n"); + netdev_info(dev, "gpiochangeRF - HW Radio ON\n"); + priv->bHwRadioOff = false; + bActuallySet = true; + } else if (!priv->bHwRadioOff && (eRfPowerStateToSet == eRfOff)) { + RT_TRACE(COMP_RF, "gpiochangeRF - HW Radio OFF\n"); + netdev_info(dev, "gpiochangeRF - HW Radio OFF\n"); + priv->bHwRadioOff = true; + bActuallySet = true; + } + + if (bActuallySet) { + mdelay(1000); + priv->bHwRfOffAction = 1; + MgntActSet_RF_State(dev, eRfPowerStateToSet, RF_CHANGE_BY_HW, true); + if (priv->bHwRadioOff) + argv[1] = "RFOFF"; + else + argv[1] = "RFON"; + + argv[0] = RadioPowerPath; + argv[2] = NULL; + call_usermodehelper(RadioPowerPath, argv, envp, UMH_WAIT_PROC); + } +} + +void dm_rf_pathcheck_workitemcallback(void *data) +{ + struct r8192_priv *priv = container_of_dwork_rsl(data, + struct r8192_priv, + rfpath_check_wq); + struct net_device *dev = priv->rtllib->dev; + u8 rfpath = 0, i; + + rfpath = read_nic_byte(dev, 0xc04); + + for (i = 0; i < RF90_PATH_MAX; i++) { + if (rfpath & (0x01<brfpath_rxenable[i] = true; + else + priv->brfpath_rxenable[i] = false; + } + if (!DM_RxPathSelTable.Enable) + return; + + dm_rxpath_sel_byrssi(dev); +} + +static void dm_init_rxpath_selection(struct net_device *dev) +{ + u8 i; + struct r8192_priv *priv = rtllib_priv(dev); + + DM_RxPathSelTable.Enable = 1; + DM_RxPathSelTable.SS_TH_low = RxPathSelection_SS_TH_low; + DM_RxPathSelTable.diff_TH = RxPathSelection_diff_TH; + if (priv->CustomerID == RT_CID_819x_Netcore) + DM_RxPathSelTable.cck_method = CCK_Rx_Version_2; + else + DM_RxPathSelTable.cck_method = CCK_Rx_Version_1; + DM_RxPathSelTable.DbgMode = DM_DBG_OFF; + DM_RxPathSelTable.disabledRF = 0; + for (i = 0; i < 4; i++) { + DM_RxPathSelTable.rf_rssi[i] = 50; + DM_RxPathSelTable.cck_pwdb_sta[i] = -64; + DM_RxPathSelTable.rf_enable_rssi_th[i] = 100; + } +} + +#define PWDB_IN_RANGE ((cur_cck_pwdb < tmp_cck_max_pwdb) && \ + (cur_cck_pwdb > tmp_cck_sec_pwdb)) + +static void dm_rxpath_sel_byrssi(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + u8 i, max_rssi_index = 0, min_rssi_index = 0; + u8 sec_rssi_index = 0, rf_num = 0; + u8 tmp_max_rssi = 0, tmp_min_rssi = 0, tmp_sec_rssi = 0; + u8 cck_default_Rx = 0x2; + u8 cck_optional_Rx = 0x3; + long tmp_cck_max_pwdb = 0, tmp_cck_min_pwdb = 0, tmp_cck_sec_pwdb = 0; + u8 cck_rx_ver2_max_index = 0, cck_rx_ver2_min_index = 0; + u8 cck_rx_ver2_sec_index = 0; + u8 cur_rf_rssi; + long cur_cck_pwdb; + static u8 disabled_rf_cnt, cck_Rx_Path_initialized; + u8 update_cck_rx_path; + + if (priv->rf_type != RF_2T4R) + return; + + if (!cck_Rx_Path_initialized) { + DM_RxPathSelTable.cck_Rx_path = (read_nic_byte(dev, 0xa07)&0xf); + cck_Rx_Path_initialized = 1; + } + + DM_RxPathSelTable.disabledRF = 0xf; + DM_RxPathSelTable.disabledRF &= ~(read_nic_byte(dev, 0xc04)); + + if (priv->rtllib->mode == WIRELESS_MODE_B) + DM_RxPathSelTable.cck_method = CCK_Rx_Version_2; + + for (i = 0; i < RF90_PATH_MAX; i++) { + if (!DM_RxPathSelTable.DbgMode) + DM_RxPathSelTable.rf_rssi[i] = priv->stats.rx_rssi_percentage[i]; + + if (priv->brfpath_rxenable[i]) { + rf_num++; + cur_rf_rssi = DM_RxPathSelTable.rf_rssi[i]; + + if (rf_num == 1) { + max_rssi_index = min_rssi_index = sec_rssi_index = i; + tmp_max_rssi = tmp_min_rssi = tmp_sec_rssi = cur_rf_rssi; + } else if (rf_num == 2) { + if (cur_rf_rssi >= tmp_max_rssi) { + tmp_max_rssi = cur_rf_rssi; + max_rssi_index = i; + } else { + tmp_sec_rssi = tmp_min_rssi = cur_rf_rssi; + sec_rssi_index = min_rssi_index = i; + } + } else { + if (cur_rf_rssi > tmp_max_rssi) { + tmp_sec_rssi = tmp_max_rssi; + sec_rssi_index = max_rssi_index; + tmp_max_rssi = cur_rf_rssi; + max_rssi_index = i; + } else if (cur_rf_rssi == tmp_max_rssi) { + tmp_sec_rssi = cur_rf_rssi; + sec_rssi_index = i; + } else if ((cur_rf_rssi < tmp_max_rssi) && + (cur_rf_rssi > tmp_sec_rssi)) { + tmp_sec_rssi = cur_rf_rssi; + sec_rssi_index = i; + } else if (cur_rf_rssi == tmp_sec_rssi) { + if (tmp_sec_rssi == tmp_min_rssi) { + tmp_sec_rssi = cur_rf_rssi; + sec_rssi_index = i; + } + } else if ((cur_rf_rssi < tmp_sec_rssi) && + (cur_rf_rssi > tmp_min_rssi)) { + ; + } else if (cur_rf_rssi == tmp_min_rssi) { + if (tmp_sec_rssi == tmp_min_rssi) { + tmp_min_rssi = cur_rf_rssi; + min_rssi_index = i; + } + } else if (cur_rf_rssi < tmp_min_rssi) { + tmp_min_rssi = cur_rf_rssi; + min_rssi_index = i; + } + } + } + } + + rf_num = 0; + if (DM_RxPathSelTable.cck_method == CCK_Rx_Version_2) { + for (i = 0; i < RF90_PATH_MAX; i++) { + if (priv->brfpath_rxenable[i]) { + rf_num++; + cur_cck_pwdb = + DM_RxPathSelTable.cck_pwdb_sta[i]; + + if (rf_num == 1) { + cck_rx_ver2_max_index = i; + cck_rx_ver2_min_index = i; + cck_rx_ver2_sec_index = i; + tmp_cck_max_pwdb = cur_cck_pwdb; + tmp_cck_min_pwdb = cur_cck_pwdb; + tmp_cck_sec_pwdb = cur_cck_pwdb; + } else if (rf_num == 2) { + if (cur_cck_pwdb >= tmp_cck_max_pwdb) { + tmp_cck_max_pwdb = cur_cck_pwdb; + cck_rx_ver2_max_index = i; + } else { + tmp_cck_sec_pwdb = cur_cck_pwdb; + tmp_cck_min_pwdb = cur_cck_pwdb; + cck_rx_ver2_sec_index = i; + cck_rx_ver2_min_index = i; + } + } else { + if (cur_cck_pwdb > tmp_cck_max_pwdb) { + tmp_cck_sec_pwdb = + tmp_cck_max_pwdb; + cck_rx_ver2_sec_index = + cck_rx_ver2_max_index; + tmp_cck_max_pwdb = cur_cck_pwdb; + cck_rx_ver2_max_index = i; + } else if (cur_cck_pwdb == + tmp_cck_max_pwdb) { + tmp_cck_sec_pwdb = cur_cck_pwdb; + cck_rx_ver2_sec_index = i; + } else if (PWDB_IN_RANGE) { + tmp_cck_sec_pwdb = cur_cck_pwdb; + cck_rx_ver2_sec_index = i; + } else if (cur_cck_pwdb == + tmp_cck_sec_pwdb) { + if (tmp_cck_sec_pwdb == + tmp_cck_min_pwdb) { + tmp_cck_sec_pwdb = + cur_cck_pwdb; + cck_rx_ver2_sec_index = + i; + } + } else if ((cur_cck_pwdb < tmp_cck_sec_pwdb) && + (cur_cck_pwdb > tmp_cck_min_pwdb)) { + ; + } else if (cur_cck_pwdb == tmp_cck_min_pwdb) { + if (tmp_cck_sec_pwdb == tmp_cck_min_pwdb) { + tmp_cck_min_pwdb = cur_cck_pwdb; + cck_rx_ver2_min_index = i; + } + } else if (cur_cck_pwdb < tmp_cck_min_pwdb) { + tmp_cck_min_pwdb = cur_cck_pwdb; + cck_rx_ver2_min_index = i; + } + } + + } + } + } + + update_cck_rx_path = 0; + if (DM_RxPathSelTable.cck_method == CCK_Rx_Version_2) { + cck_default_Rx = cck_rx_ver2_max_index; + cck_optional_Rx = cck_rx_ver2_sec_index; + if (tmp_cck_max_pwdb != -64) + update_cck_rx_path = 1; + } + + if (tmp_min_rssi < DM_RxPathSelTable.SS_TH_low && disabled_rf_cnt < 2) { + if ((tmp_max_rssi - tmp_min_rssi) >= + DM_RxPathSelTable.diff_TH) { + DM_RxPathSelTable.rf_enable_rssi_th[min_rssi_index] = + tmp_max_rssi+5; + rtl8192_setBBreg(dev, rOFDM0_TRxPathEnable, + 0x1<>i) & 0x1) { + if (tmp_max_rssi >= + DM_RxPathSelTable.rf_enable_rssi_th[i]) { + rtl8192_setBBreg(dev, + rOFDM0_TRxPathEnable, 0x1 << i, + 0x1); + rtl8192_setBBreg(dev, + rOFDM1_TRxPathEnable, + 0x1 << i, 0x1); + DM_RxPathSelTable.rf_enable_rssi_th[i] + = 100; + disabled_rf_cnt--; + } + } + } + } +} + +static void dm_check_rx_path_selection(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + queue_delayed_work_rsl(priv->priv_wq, &priv->rfpath_check_wq, 0); +} + + +static void dm_init_fsync(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + priv->rtllib->fsync_time_interval = 500; + priv->rtllib->fsync_rate_bitmap = 0x0f000800; + priv->rtllib->fsync_rssi_threshold = 30; + priv->rtllib->bfsync_enable = false; + priv->rtllib->fsync_multiple_timeinterval = 3; + priv->rtllib->fsync_firstdiff_ratethreshold = 100; + priv->rtllib->fsync_seconddiff_ratethreshold = 200; + priv->rtllib->fsync_state = Default_Fsync; + priv->framesyncMonitor = 1; + + init_timer(&priv->fsync_timer); + setup_timer(&priv->fsync_timer, dm_fsync_timer_callback, + (unsigned long) dev); +} + + +static void dm_deInit_fsync(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + del_timer_sync(&priv->fsync_timer); +} + +void dm_fsync_timer_callback(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct r8192_priv *priv = rtllib_priv((struct net_device *)data); + u32 rate_index, rate_count = 0, rate_count_diff = 0; + bool bSwitchFromCountDiff = false; + bool bDoubleTimeInterval = false; + + if (priv->rtllib->state == RTLLIB_LINKED && + priv->rtllib->bfsync_enable && + (priv->rtllib->pHTInfo->IOTAction & HT_IOT_ACT_CDD_FSYNC)) { + u32 rate_bitmap; + + for (rate_index = 0; rate_index <= 27; rate_index++) { + rate_bitmap = 1 << rate_index; + if (priv->rtllib->fsync_rate_bitmap & rate_bitmap) + rate_count += + priv->stats.received_rate_histogram[1] + [rate_index]; + } + + if (rate_count < priv->rate_record) + rate_count_diff = 0xffffffff - rate_count + + priv->rate_record; + else + rate_count_diff = rate_count - priv->rate_record; + if (rate_count_diff < priv->rateCountDiffRecord) { + + u32 DiffNum = priv->rateCountDiffRecord - + rate_count_diff; + if (DiffNum >= + priv->rtllib->fsync_seconddiff_ratethreshold) + priv->ContinueDiffCount++; + else + priv->ContinueDiffCount = 0; + + if (priv->ContinueDiffCount >= 2) { + bSwitchFromCountDiff = true; + priv->ContinueDiffCount = 0; + } + } else { + priv->ContinueDiffCount = 0; + } + + if (rate_count_diff <= + priv->rtllib->fsync_firstdiff_ratethreshold) { + bSwitchFromCountDiff = true; + priv->ContinueDiffCount = 0; + } + priv->rate_record = rate_count; + priv->rateCountDiffRecord = rate_count_diff; + RT_TRACE(COMP_HALDM, + "rateRecord %d rateCount %d, rateCountdiff %d bSwitchFsync %d\n", + priv->rate_record, rate_count, rate_count_diff, + priv->bswitch_fsync); + if (priv->undecorated_smoothed_pwdb > + priv->rtllib->fsync_rssi_threshold && + bSwitchFromCountDiff) { + bDoubleTimeInterval = true; + priv->bswitch_fsync = !priv->bswitch_fsync; + if (priv->bswitch_fsync) { + write_nic_byte(dev, 0xC36, 0x1c); + write_nic_byte(dev, 0xC3e, 0x90); + } else { + write_nic_byte(dev, 0xC36, 0x5c); + write_nic_byte(dev, 0xC3e, 0x96); + } + } else if (priv->undecorated_smoothed_pwdb <= + priv->rtllib->fsync_rssi_threshold) { + if (priv->bswitch_fsync) { + priv->bswitch_fsync = false; + write_nic_byte(dev, 0xC36, 0x5c); + write_nic_byte(dev, 0xC3e, 0x96); + } + } + if (bDoubleTimeInterval) { + if (timer_pending(&priv->fsync_timer)) + del_timer_sync(&priv->fsync_timer); + priv->fsync_timer.expires = jiffies + + msecs_to_jiffies(priv->rtllib->fsync_time_interval * + priv->rtllib->fsync_multiple_timeinterval); + add_timer(&priv->fsync_timer); + } else { + if (timer_pending(&priv->fsync_timer)) + del_timer_sync(&priv->fsync_timer); + priv->fsync_timer.expires = jiffies + + msecs_to_jiffies(priv->rtllib->fsync_time_interval); + add_timer(&priv->fsync_timer); + } + } else { + if (priv->bswitch_fsync) { + priv->bswitch_fsync = false; + write_nic_byte(dev, 0xC36, 0x5c); + write_nic_byte(dev, 0xC3e, 0x96); + } + priv->ContinueDiffCount = 0; + write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c52cd); + } + RT_TRACE(COMP_HALDM, "ContinueDiffCount %d\n", priv->ContinueDiffCount); + RT_TRACE(COMP_HALDM, + "rateRecord %d rateCount %d, rateCountdiff %d bSwitchFsync %d\n", + priv->rate_record, rate_count, rate_count_diff, + priv->bswitch_fsync); +} + +static void dm_StartHWFsync(struct net_device *dev) +{ + u8 rf_timing = 0x77; + struct r8192_priv *priv = rtllib_priv(dev); + + RT_TRACE(COMP_HALDM, "%s\n", __func__); + write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c12cf); + priv->rtllib->SetHwRegHandler(dev, HW_VAR_RF_TIMING, + (u8 *)(&rf_timing)); + write_nic_byte(dev, 0xc3b, 0x41); +} + +static void dm_EndHWFsync(struct net_device *dev) +{ + u8 rf_timing = 0xaa; + struct r8192_priv *priv = rtllib_priv(dev); + + RT_TRACE(COMP_HALDM, "%s\n", __func__); + write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c52cd); + priv->rtllib->SetHwRegHandler(dev, HW_VAR_RF_TIMING, (u8 *) + (&rf_timing)); + write_nic_byte(dev, 0xc3b, 0x49); +} + +static void dm_EndSWFsync(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + RT_TRACE(COMP_HALDM, "%s\n", __func__); + del_timer_sync(&(priv->fsync_timer)); + + if (priv->bswitch_fsync) { + priv->bswitch_fsync = false; + + write_nic_byte(dev, 0xC36, 0x5c); + + write_nic_byte(dev, 0xC3e, 0x96); + } + + priv->ContinueDiffCount = 0; + write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c52cd); +} + +static void dm_StartSWFsync(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + u32 rateIndex; + u32 rateBitmap; + + RT_TRACE(COMP_HALDM, "%s\n", __func__); + priv->rate_record = 0; + priv->ContinueDiffCount = 0; + priv->rateCountDiffRecord = 0; + priv->bswitch_fsync = false; + + if (priv->rtllib->mode == WIRELESS_MODE_N_24G) { + priv->rtllib->fsync_firstdiff_ratethreshold = 600; + priv->rtllib->fsync_seconddiff_ratethreshold = 0xffff; + } else { + priv->rtllib->fsync_firstdiff_ratethreshold = 200; + priv->rtllib->fsync_seconddiff_ratethreshold = 200; + } + for (rateIndex = 0; rateIndex <= 27; rateIndex++) { + rateBitmap = 1 << rateIndex; + if (priv->rtllib->fsync_rate_bitmap & rateBitmap) + priv->rate_record += + priv->stats.received_rate_histogram[1] + [rateIndex]; + } + if (timer_pending(&priv->fsync_timer)) + del_timer_sync(&priv->fsync_timer); + priv->fsync_timer.expires = jiffies + + msecs_to_jiffies(priv->rtllib->fsync_time_interval); + add_timer(&priv->fsync_timer); + + write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c12cd); + +} + +void dm_check_fsync(struct net_device *dev) +{ +#define RegC38_Default 0 +#define RegC38_NonFsync_Other_AP 1 +#define RegC38_Fsync_AP_BCM 2 + struct r8192_priv *priv = rtllib_priv(dev); + static u8 reg_c38_State = RegC38_Default; + static u32 reset_cnt; + + RT_TRACE(COMP_HALDM, + "RSSI %d TimeInterval %d MultipleTimeInterval %d\n", + priv->rtllib->fsync_rssi_threshold, + priv->rtllib->fsync_time_interval, + priv->rtllib->fsync_multiple_timeinterval); + RT_TRACE(COMP_HALDM, + "RateBitmap 0x%x FirstDiffRateThreshold %d SecondDiffRateThreshold %d\n", + priv->rtllib->fsync_rate_bitmap, + priv->rtllib->fsync_firstdiff_ratethreshold, + priv->rtllib->fsync_seconddiff_ratethreshold); + + if (priv->rtllib->state == RTLLIB_LINKED && + priv->rtllib->pHTInfo->IOTPeer == HT_IOT_PEER_BROADCOM) { + if (priv->rtllib->bfsync_enable == 0) { + switch (priv->rtllib->fsync_state) { + case Default_Fsync: + dm_StartHWFsync(dev); + priv->rtllib->fsync_state = HW_Fsync; + break; + case SW_Fsync: + dm_EndSWFsync(dev); + dm_StartHWFsync(dev); + priv->rtllib->fsync_state = HW_Fsync; + break; + case HW_Fsync: + default: + break; + } + } else { + switch (priv->rtllib->fsync_state) { + case Default_Fsync: + dm_StartSWFsync(dev); + priv->rtllib->fsync_state = SW_Fsync; + break; + case HW_Fsync: + dm_EndHWFsync(dev); + dm_StartSWFsync(dev); + priv->rtllib->fsync_state = SW_Fsync; + break; + case SW_Fsync: + default: + break; + + } + } + if (priv->framesyncMonitor) { + if (reg_c38_State != RegC38_Fsync_AP_BCM) { + write_nic_byte(dev, rOFDM0_RxDetector3, 0x95); + + reg_c38_State = RegC38_Fsync_AP_BCM; + } + } + } else { + switch (priv->rtllib->fsync_state) { + case HW_Fsync: + dm_EndHWFsync(dev); + priv->rtllib->fsync_state = Default_Fsync; + break; + case SW_Fsync: + dm_EndSWFsync(dev); + priv->rtllib->fsync_state = Default_Fsync; + break; + case Default_Fsync: + default: + break; + } + + if (priv->framesyncMonitor) { + if (priv->rtllib->state == RTLLIB_LINKED) { + if (priv->undecorated_smoothed_pwdb <= + RegC38_TH) { + if (reg_c38_State != + RegC38_NonFsync_Other_AP) { + write_nic_byte(dev, + rOFDM0_RxDetector3, + 0x90); + + reg_c38_State = + RegC38_NonFsync_Other_AP; + } + } else if (priv->undecorated_smoothed_pwdb >= + (RegC38_TH+5)) { + if (reg_c38_State) { + write_nic_byte(dev, + rOFDM0_RxDetector3, + priv->framesync); + reg_c38_State = RegC38_Default; + } + } + } else { + if (reg_c38_State) { + write_nic_byte(dev, rOFDM0_RxDetector3, + priv->framesync); + reg_c38_State = RegC38_Default; + } + } + } + } + if (priv->framesyncMonitor) { + if (priv->reset_count != reset_cnt) { + write_nic_byte(dev, rOFDM0_RxDetector3, + priv->framesync); + reg_c38_State = RegC38_Default; + reset_cnt = priv->reset_count; + } + } else { + if (reg_c38_State) { + write_nic_byte(dev, rOFDM0_RxDetector3, + priv->framesync); + reg_c38_State = RegC38_Default; + } + } +} + +void dm_shadow_init(struct net_device *dev) +{ + u8 page; + u16 offset; + + for (page = 0; page < 5; page++) + for (offset = 0; offset < 256; offset++) + dm_shadow[page][offset] = read_nic_byte(dev, + offset+page * 256); + + for (page = 8; page < 11; page++) + for (offset = 0; offset < 256; offset++) + dm_shadow[page][offset] = read_nic_byte(dev, + offset+page * 256); + + for (page = 12; page < 15; page++) + for (offset = 0; offset < 256; offset++) + dm_shadow[page][offset] = read_nic_byte(dev, + offset+page*256); + +} + +/*---------------------------Define function prototype------------------------*/ +static void dm_init_dynamic_txpower(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + priv->rtllib->bdynamic_txpower_enable = true; + priv->bLastDTPFlag_High = false; + priv->bLastDTPFlag_Low = false; + priv->bDynamicTxHighPower = false; + priv->bDynamicTxLowPower = false; +} + +static void dm_dynamic_txpower(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + unsigned int txhipower_threshhold = 0; + unsigned int txlowpower_threshold = 0; + + if (priv->rtllib->bdynamic_txpower_enable != true) { + priv->bDynamicTxHighPower = false; + priv->bDynamicTxLowPower = false; + return; + } + if ((priv->rtllib->pHTInfo->IOTPeer == HT_IOT_PEER_ATHEROS) && + (priv->rtllib->mode == IEEE_G)) { + txhipower_threshhold = TX_POWER_ATHEROAP_THRESH_HIGH; + txlowpower_threshold = TX_POWER_ATHEROAP_THRESH_LOW; + } else { + txhipower_threshhold = TX_POWER_NEAR_FIELD_THRESH_HIGH; + txlowpower_threshold = TX_POWER_NEAR_FIELD_THRESH_LOW; + } + + RT_TRACE(COMP_TXAGC, "priv->undecorated_smoothed_pwdb = %ld\n", + priv->undecorated_smoothed_pwdb); + + if (priv->rtllib->state == RTLLIB_LINKED) { + if (priv->undecorated_smoothed_pwdb >= txhipower_threshhold) { + priv->bDynamicTxHighPower = true; + priv->bDynamicTxLowPower = false; + } else { + if (priv->undecorated_smoothed_pwdb < + txlowpower_threshold && priv->bDynamicTxHighPower) + priv->bDynamicTxHighPower = false; + if (priv->undecorated_smoothed_pwdb < 35) + priv->bDynamicTxLowPower = true; + else if (priv->undecorated_smoothed_pwdb >= 40) + priv->bDynamicTxLowPower = false; + } + } else { + priv->bDynamicTxHighPower = false; + priv->bDynamicTxLowPower = false; + } + + if ((priv->bDynamicTxHighPower != priv->bLastDTPFlag_High) || + (priv->bDynamicTxLowPower != priv->bLastDTPFlag_Low)) { + RT_TRACE(COMP_TXAGC, "SetTxPowerLevel8190() channel = %d\n", + priv->rtllib->current_network.channel); + + rtl8192_phy_setTxPower(dev, + priv->rtllib->current_network.channel); + } + priv->bLastDTPFlag_High = priv->bDynamicTxHighPower; + priv->bLastDTPFlag_Low = priv->bDynamicTxLowPower; + +} + +static void dm_check_txrateandretrycount(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct rtllib_device *ieee = priv->rtllib; + + ieee->softmac_stats.CurrentShowTxate = read_nic_byte(dev, + Current_Tx_Rate_Reg); + + ieee->softmac_stats.last_packet_rate = read_nic_byte(dev, + Initial_Tx_Rate_Reg); + + ieee->softmac_stats.txretrycount = read_nic_dword(dev, + Tx_Retry_Count_Reg); +} + +static void dm_send_rssi_tofw(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + write_nic_byte(dev, DRIVER_RSSI, (u8)priv->undecorated_smoothed_pwdb); +} diff --git a/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h b/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h new file mode 100644 index 000000000..3f02e11cf --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h @@ -0,0 +1,316 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ +#ifndef __R8192UDM_H__ +#define __R8192UDM_H__ + + +/*--------------------------Define Parameters-------------------------------*/ +#define OFDM_Table_Length 19 +#define CCK_Table_length 12 + +#define DM_DIG_THRESH_HIGH 40 +#define DM_DIG_THRESH_LOW 35 + +#define DM_FALSEALARM_THRESH_LOW 40 +#define DM_FALSEALARM_THRESH_HIGH 1000 + +#define DM_DIG_HIGH_PWR_THRESH_HIGH 75 +#define DM_DIG_HIGH_PWR_THRESH_LOW 70 + +#define BW_AUTO_SWITCH_HIGH_LOW 25 +#define BW_AUTO_SWITCH_LOW_HIGH 30 + +#define DM_check_fsync_time_interval 500 + + +#define DM_DIG_BACKOFF 12 +#define DM_DIG_MAX 0x36 +#define DM_DIG_MIN 0x1c +#define DM_DIG_MIN_Netcore 0x12 + +#define DM_DIG_BACKOFF_MAX 12 +#define DM_DIG_BACKOFF_MIN -4 + +#define RxPathSelection_SS_TH_low 30 +#define RxPathSelection_diff_TH 18 + +#define RateAdaptiveTH_High 50 +#define RateAdaptiveTH_Low_20M 30 +#define RateAdaptiveTH_Low_40M 10 +#define VeryLowRSSI 15 + +#define CTSToSelfTHVal 35 + +#define WAIotTHVal 25 + +#define E_FOR_TX_POWER_TRACK 300 +#define TX_POWER_NEAR_FIELD_THRESH_HIGH 68 +#define TX_POWER_NEAR_FIELD_THRESH_LOW 62 +#define TX_POWER_ATHEROAP_THRESH_HIGH 78 +#define TX_POWER_ATHEROAP_THRESH_LOW 72 + +#define Current_Tx_Rate_Reg 0x1e0 +#define Initial_Tx_Rate_Reg 0x1e1 +#define Tx_Retry_Count_Reg 0x1ac +#define RegC38_TH 20 + +#define TX_POWER_NEAR_FIELD_THRESH_LVL2 74 +#define TX_POWER_NEAR_FIELD_THRESH_LVL1 67 + +#define TxHighPwrLevel_Normal 0 +#define TxHighPwrLevel_Level1 1 +#define TxHighPwrLevel_Level2 2 + +#define DM_Type_ByFW 0 +#define DM_Type_ByDriver 1 + +/*--------------------------Define Parameters-------------------------------*/ + + +/*------------------------------Define structure----------------------------*/ +struct dig_t { + u8 dig_enable_flag; + u8 dig_algorithm; + u8 Dig_TwoPort_Algorithm; + u8 Dig_Ext_Port_Stage; + u8 dbg_mode; + u8 dig_algorithm_switch; + + long rssi_low_thresh; + long rssi_high_thresh; + + u32 FALowThresh; + u32 FAHighThresh; + + long rssi_high_power_lowthresh; + long rssi_high_power_highthresh; + + u8 dig_state; + u8 dig_highpwr_state; + u8 CurSTAConnectState; + u8 PreSTAConnectState; + u8 CurAPConnectState; + u8 PreAPConnectState; + + u8 curpd_thstate; + u8 prepd_thstate; + u8 curcs_ratio_state; + u8 precs_ratio_state; + + u32 pre_ig_value; + u32 cur_ig_value; + + u8 Backoff_Enable_Flag; + u8 backoff_val; + char BackoffVal_range_max; + char BackoffVal_range_min; + u8 rx_gain_range_max; + u8 rx_gain_range_min; + bool initialgain_lowerbound_state; + + long rssi_val; +}; + +enum dm_dig_sta { + DM_STA_DIG_OFF = 0, + DM_STA_DIG_ON, + DM_STA_DIG_MAX +}; + + +enum dm_ratr_sta { + DM_RATR_STA_HIGH = 0, + DM_RATR_STA_MIDDLE = 1, + DM_RATR_STA_LOW = 2, + DM_RATR_STA_MAX +}; + +enum dm_dig_op_sta { + DIG_TYPE_THRESH_HIGH = 0, + DIG_TYPE_THRESH_LOW = 1, + DIG_TYPE_THRESH_HIGHPWR_HIGH = 2, + DIG_TYPE_THRESH_HIGHPWR_LOW = 3, + DIG_TYPE_DBG_MODE = 4, + DIG_TYPE_RSSI = 5, + DIG_TYPE_ALGORITHM = 6, + DIG_TYPE_BACKOFF = 7, + DIG_TYPE_PWDB_FACTOR = 8, + DIG_TYPE_RX_GAIN_MIN = 9, + DIG_TYPE_RX_GAIN_MAX = 10, + DIG_TYPE_ENABLE = 20, + DIG_TYPE_DISABLE = 30, + DIG_OP_TYPE_MAX +}; + +enum dm_dig_alg { + DIG_ALGO_BY_FALSE_ALARM = 0, + DIG_ALGO_BY_RSSI = 1, + DIG_ALGO_BEFORE_CONNECT_BY_RSSI_AND_ALARM = 2, + DIG_ALGO_BY_TOW_PORT = 3, + DIG_ALGO_MAX +}; + +enum dm_dig_two_port_alg { + DIG_TWO_PORT_ALGO_RSSI = 0, + DIG_TWO_PORT_ALGO_FALSE_ALARM = 1, +}; + + +enum dm_dig_ext_port_alg { + DIG_EXT_PORT_STAGE_0 = 0, + DIG_EXT_PORT_STAGE_1 = 1, + DIG_EXT_PORT_STAGE_2 = 2, + DIG_EXT_PORT_STAGE_3 = 3, + DIG_EXT_PORT_STAGE_MAX = 4, +}; + +enum dm_dig_dbg { + DIG_DBG_OFF = 0, + DIG_DBG_ON = 1, + DIG_DBG_MAX +}; + +enum dm_dig_connect { + DIG_STA_DISCONNECT = 0, + DIG_STA_CONNECT = 1, + DIG_STA_BEFORE_CONNECT = 2, + DIG_AP_DISCONNECT = 3, + DIG_AP_CONNECT = 4, + DIG_AP_ADD_STATION = 5, + DIG_CONNECT_MAX +}; + +enum dm_dig_pd_th { + DIG_PD_AT_LOW_POWER = 0, + DIG_PD_AT_NORMAL_POWER = 1, + DIG_PD_AT_HIGH_POWER = 2, + DIG_PD_MAX +}; + +enum dm_dig_cs_ratio { + DIG_CS_RATIO_LOWER = 0, + DIG_CS_RATIO_HIGHER = 1, + DIG_CS_MAX +}; + +struct drx_path_sel { + u8 Enable; + u8 DbgMode; + u8 cck_method; + u8 cck_Rx_path; + + u8 SS_TH_low; + u8 diff_TH; + u8 disabledRF; + u8 reserved; + + u8 rf_rssi[4]; + u8 rf_enable_rssi_th[4]; + long cck_pwdb_sta[4]; +}; + +enum dm_cck_rx_path_method { + CCK_Rx_Version_1 = 0, + CCK_Rx_Version_2 = 1, + CCK_Rx_Version_MAX +}; + + +enum dm_dbg { + DM_DBG_OFF = 0, + DM_DBG_ON = 1, + DM_DBG_MAX +}; + +struct dcmd_txcmd { + u32 Op; + u32 Length; + u32 Value; +}; +/*------------------------------Define structure----------------------------*/ + + +/*------------------------Export global variable----------------------------*/ +extern struct dig_t dm_digtable; +extern u8 dm_shadow[16][256]; +extern struct drx_path_sel DM_RxPathSelTable; + +extern u8 test_flag; +/*------------------------Export global variable----------------------------*/ + + +/*--------------------------Exported Function prototype---------------------*/ +/*--------------------------Exported Function prototype---------------------*/ +extern void init_hal_dm(struct net_device *dev); +extern void deinit_hal_dm(struct net_device *dev); + +extern void hal_dm_watchdog(struct net_device *dev); + + +extern void init_rate_adaptive(struct net_device *dev); +extern void dm_txpower_trackingcallback(void *data); + +extern void dm_cck_txpower_adjust(struct net_device *dev, bool binch14); + +extern void dm_restore_dynamic_mechanism_state(struct net_device *dev); +extern void dm_backup_dynamic_mechanism_state(struct net_device *dev); +extern void dm_change_dynamic_initgain_thresh(struct net_device *dev, + u32 dm_type, + u32 dm_value); +extern void DM_ChangeFsyncSetting(struct net_device *dev, + s32 DM_Type, + s32 DM_Value); +extern void dm_force_tx_fw_info(struct net_device *dev, + u32 force_type, + u32 force_value); +extern void dm_init_edca_turbo(struct net_device *dev); +extern void dm_rf_operation_test_callback(unsigned long data); +extern void dm_rf_pathcheck_workitemcallback(void *data); +extern void dm_fsync_timer_callback(unsigned long data); +extern void dm_check_fsync(struct net_device *dev); +extern void dm_shadow_init(struct net_device *dev); +extern void dm_initialize_txpower_tracking(struct net_device *dev); +extern void dm_CheckRfCtrlGPIO(void *data); +extern void dm_InitRateAdaptiveMask(struct net_device *dev); +extern void init_hal_dm(struct net_device *dev); +extern void deinit_hal_dm(struct net_device *dev); +extern void hal_dm_watchdog(struct net_device *dev); +extern void init_rate_adaptive(struct net_device *dev); +extern void dm_txpower_trackingcallback(void *data); +extern void dm_restore_dynamic_mechanism_state(struct net_device *dev); +extern void dm_backup_dynamic_mechanism_state(struct net_device *dev); +extern void dm_change_dynamic_initgain_thresh(struct net_device *dev, + u32 dm_type, + u32 dm_value); +extern void DM_ChangeFsyncSetting(struct net_device *dev, + s32 DM_Type, + s32 DM_Value); +extern void dm_force_tx_fw_info(struct net_device *dev, + u32 force_type, + u32 force_value); +extern void dm_init_edca_turbo(struct net_device *dev); +extern void dm_rf_operation_test_callback(unsigned long data); +extern void dm_rf_pathcheck_workitemcallback(void *data); +extern void dm_fsync_timer_callback(unsigned long data); +extern void dm_check_fsync(struct net_device *dev); +extern void dm_shadow_init(struct net_device *dev); +extern void dm_initialize_txpower_tracking(struct net_device *dev); +extern void dm_CheckRfCtrlGPIO(void *data); + +#endif /*__R8192UDM_H__ */ diff --git a/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c b/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c new file mode 100644 index 000000000..a6778e085 --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c @@ -0,0 +1,139 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * Based on the r8180 driver, which is: + * Copyright 2004-2005 Andrea Merello , et al. + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ +#include "rtl_core.h" +#include "rtl_eeprom.h" + +static void eprom_cs(struct net_device *dev, short bit) +{ + if (bit) + write_nic_byte(dev, EPROM_CMD, + (1 << EPROM_CS_SHIFT) | + read_nic_byte(dev, EPROM_CMD)); + else + write_nic_byte(dev, EPROM_CMD, read_nic_byte(dev, EPROM_CMD) + & ~(1<epromtype == EEPROM_93C56) { + addr_str[7] = addr & 1; + addr_str[6] = addr & (1<<1); + addr_str[5] = addr & (1<<2); + addr_str[4] = addr & (1<<3); + addr_str[3] = addr & (1<<4); + addr_str[2] = addr & (1<<5); + addr_str[1] = addr & (1<<6); + addr_str[0] = addr & (1<<7); + addr_len = 8; + } else { + addr_str[5] = addr & 1; + addr_str[4] = addr & (1<<1); + addr_str[3] = addr & (1<<2); + addr_str[2] = addr & (1<<3); + addr_str[1] = addr & (1<<4); + addr_str[0] = addr & (1<<5); + addr_len = 6; + } + eprom_cs(dev, 1); + eprom_ck_cycle(dev); + eprom_send_bits_string(dev, read_cmd, 3); + eprom_send_bits_string(dev, addr_str, addr_len); + + eprom_w(dev, 0); + + for (i = 0; i < 16; i++) { + eprom_ck_cycle(dev); + ret |= (eprom_r(dev)<<(15-i)); + } + + eprom_cs(dev, 0); + eprom_ck_cycle(dev); + + write_nic_byte(dev, EPROM_CMD, + (EPROM_CMD_NORMAL<, et al. + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ + + +#define EPROM_DELAY 10 + +u32 eprom_read(struct net_device *dev, u32 addr); diff --git a/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_ethtool.c b/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_ethtool.c new file mode 100644 index 000000000..529ea54d1 --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_ethtool.c @@ -0,0 +1,53 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * Based on the r8180 driver, which is: + * Copyright 2004-2005 Andrea Merello , et al. + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + ***************************************************************************** + */ +#include +#include +#include + +#include "rtl_core.h" + +static void rtl819x_ethtool_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); + strlcpy(info->version, DRV_VERSION, sizeof(info->version)); + strlcpy(info->bus_info, pci_name(priv->pdev), sizeof(info->bus_info)); +} + +static u32 rtl819x_ethtool_get_link(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + return ((priv->rtllib->state == RTLLIB_LINKED) || + (priv->rtllib->state == RTLLIB_LINKED_SCANNING)); +} + +const struct ethtool_ops rtl819x_ethtool_ops = { + .get_drvinfo = rtl819x_ethtool_get_drvinfo, + .get_link = rtl819x_ethtool_get_link, +}; diff --git a/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c b/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c new file mode 100644 index 000000000..51f53be2d --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c @@ -0,0 +1,100 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * Based on the r8180 driver, which is: + * Copyright 2004-2005 Andrea Merello , et al. + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + *****************************************************************************/ +#include "rtl_pci.h" +#include "rtl_core.h" + +static void rtl8192_parse_pci_configuration(struct pci_dev *pdev, + struct net_device *dev) +{ + struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); + + u8 tmp; + u16 LinkCtrlReg; + + pcie_capability_read_word(priv->pdev, PCI_EXP_LNKCTL, &LinkCtrlReg); + priv->NdisAdapter.LinkCtrlReg = (u8)LinkCtrlReg; + + RT_TRACE(COMP_INIT, "Link Control Register =%x\n", + priv->NdisAdapter.LinkCtrlReg); + + pci_read_config_byte(pdev, 0x98, &tmp); + tmp |= BIT4; + pci_write_config_byte(pdev, 0x98, tmp); + + tmp = 0x17; + pci_write_config_byte(pdev, 0x70f, tmp); +} + +bool rtl8192_pci_findadapter(struct pci_dev *pdev, struct net_device *dev) +{ + struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); + u16 VenderID; + u16 DeviceID; + u8 RevisionID; + u16 IrqLine; + + VenderID = pdev->vendor; + DeviceID = pdev->device; + RevisionID = pdev->revision; + pci_read_config_word(pdev, 0x3C, &IrqLine); + + priv->card_8192 = priv->ops->nic_type; + + if (DeviceID == 0x8172) { + switch (RevisionID) { + case HAL_HW_PCI_REVISION_ID_8192PCIE: + dev_info(&pdev->dev, + "Adapter(8192 PCI-E) is found - DeviceID=%x\n", + DeviceID); + priv->card_8192 = NIC_8192E; + break; + case HAL_HW_PCI_REVISION_ID_8192SE: + dev_info(&pdev->dev, + "Adapter(8192SE) is found - DeviceID=%x\n", + DeviceID); + priv->card_8192 = NIC_8192SE; + break; + default: + dev_info(&pdev->dev, + "UNKNOWN nic type(%4x:%4x)\n", + pdev->vendor, pdev->device); + priv->card_8192 = NIC_UNKNOWN; + return false; + } + } + + if (priv->ops->nic_type != priv->card_8192) { + dev_info(&pdev->dev, + "Detect info(%x) and hardware info(%x) not match!\n", + priv->ops->nic_type, priv->card_8192); + dev_info(&pdev->dev, + "Please select proper driver before install!!!!\n"); + return false; + } + + rtl8192_parse_pci_configuration(pdev, dev); + + return true; +} diff --git a/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h b/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h new file mode 100644 index 000000000..4b94653c5 --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h @@ -0,0 +1,51 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * Based on the r8180 driver, which is: + * Copyright 2004-2005 Andrea Merello , et al. + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + ******************************************************************************/ +#ifndef _RTL_PCI_H +#define _RTL_PCI_H + +#include +#include + +struct mp_adapter { + u8 LinkCtrlReg; + + u8 BusNumber; + u8 DevNumber; + u8 FuncNumber; + + u8 PciBridgeBusNum; + u8 PciBridgeDevNum; + u8 PciBridgeFuncNum; + u8 PciBridgeVendor; + u16 PciBridgeVendorId; + u16 PciBridgeDeviceId; + u8 PciBridgePCIeHdrOffset; + u8 PciBridgeLinkCtrlReg; +}; + +struct net_device; +bool rtl8192_pci_findadapter(struct pci_dev *pdev, struct net_device *dev); + +#endif diff --git a/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c b/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c new file mode 100644 index 000000000..ca6ecfc82 --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c @@ -0,0 +1,119 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ + +#include "rtl_core.h" +#include "r8192E_hw.h" +#include "r8190P_rtl8256.h" +#include "rtl_pm.h" + + +int rtl8192E_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct r8192_priv *priv = rtllib_priv(dev); + u32 ulRegRead; + + netdev_info(dev, "============> r8192E suspend call.\n"); + del_timer_sync(&priv->gpio_polling_timer); + cancel_delayed_work(&priv->gpio_change_rf_wq); + priv->polling_timer_on = 0; + + if (!netif_running(dev)) { + netdev_info(dev, + "RTL819XE:UI is open out of suspend function\n"); + goto out_pci_suspend; + } + + if (dev->netdev_ops->ndo_stop) + dev->netdev_ops->ndo_stop(dev); + netif_device_detach(dev); + + if (!priv->rtllib->bSupportRemoteWakeUp) { + MgntActSet_RF_State(dev, eRfOff, RF_CHANGE_BY_INIT, true); + ulRegRead = read_nic_dword(dev, CPU_GEN); + ulRegRead |= CPU_GEN_SYSTEM_RESET; + write_nic_dword(dev, CPU_GEN, ulRegRead); + } else { + write_nic_dword(dev, WFCRC0, 0xffffffff); + write_nic_dword(dev, WFCRC1, 0xffffffff); + write_nic_dword(dev, WFCRC2, 0xffffffff); + write_nic_byte(dev, PMR, 0x5); + write_nic_byte(dev, MacBlkCtrl, 0xa); + } +out_pci_suspend: + netdev_info(dev, "r8192E support WOL call??????????????????????\n"); + if (priv->rtllib->bSupportRemoteWakeUp) + RT_TRACE(COMP_POWER, + "r8192E support WOL call!!!!!!!!!!!!!!!!!!.\n"); + pci_save_state(pdev); + pci_disable_device(pdev); + pci_enable_wake(pdev, pci_choose_state(pdev, state), + priv->rtllib->bSupportRemoteWakeUp ? 1 : 0); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + mdelay(20); + + return 0; +} + +int rtl8192E_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct r8192_priv *priv = rtllib_priv(dev); + int err; + u32 val; + + netdev_info(dev, "================>r8192E resume call.\n"); + + pci_set_power_state(pdev, PCI_D0); + + err = pci_enable_device(pdev); + if (err) { + netdev_err(dev, "pci_enable_device failed on resume\n"); + return err; + } + pci_restore_state(pdev); + + pci_read_config_dword(pdev, 0x40, &val); + if ((val & 0x0000ff00) != 0) + pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); + + pci_enable_wake(pdev, PCI_D0, 0); + + if (priv->polling_timer_on == 0) + check_rfctrl_gpio_timer((unsigned long)dev); + + if (!netif_running(dev)) { + netdev_info(dev, + "RTL819XE:UI is open out of resume function\n"); + goto out; + } + + netif_device_attach(dev); + if (dev->netdev_ops->ndo_open) + dev->netdev_ops->ndo_open(dev); + + if (!priv->rtllib->bSupportRemoteWakeUp) + MgntActSet_RF_State(dev, eRfOn, RF_CHANGE_BY_INIT, true); + +out: + RT_TRACE(COMP_POWER, "<================r8192E resume call.\n"); + return 0; +} + diff --git a/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_pm.h b/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_pm.h new file mode 100644 index 000000000..7bfe44817 --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_pm.h @@ -0,0 +1,29 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ + +#ifndef R8192E_PM_H +#define R8192E_PM_H + +#include +#include + +int rtl8192E_suspend(struct pci_dev *dev, pm_message_t state); +int rtl8192E_resume(struct pci_dev *dev); + +#endif diff --git a/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c b/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c new file mode 100644 index 000000000..0bbffec0c --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c @@ -0,0 +1,316 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * Based on the r8180 driver, which is: + * Copyright 2004-2005 Andrea Merello , et al. + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + *****************************************************************************/ +#include "rtl_ps.h" +#include "rtl_core.h" +#include "r8192E_phy.h" +#include "r8192E_phyreg.h" +#include "r8190P_rtl8256.h" /* RTL8225 Radio frontend */ +#include "r8192E_cmdpkt.h" + +static void rtl8192_hw_sleep_down(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + unsigned long flags = 0; + + spin_lock_irqsave(&priv->rf_ps_lock, flags); + if (priv->RFChangeInProgress) { + spin_unlock_irqrestore(&priv->rf_ps_lock, flags); + RT_TRACE(COMP_DBG, + "rtl8192_hw_sleep_down(): RF Change in progress!\n"); + return; + } + spin_unlock_irqrestore(&priv->rf_ps_lock, flags); + RT_TRACE(COMP_DBG, "%s()============>come to sleep down\n", __func__); + + MgntActSet_RF_State(dev, eRfSleep, RF_CHANGE_BY_PS, false); +} + +void rtl8192_hw_sleep_wq(void *data) +{ + struct rtllib_device *ieee = container_of_dwork_rsl(data, + struct rtllib_device, hw_sleep_wq); + struct net_device *dev = ieee->dev; + + rtl8192_hw_sleep_down(dev); +} + +void rtl8192_hw_wakeup(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + unsigned long flags = 0; + + spin_lock_irqsave(&priv->rf_ps_lock, flags); + if (priv->RFChangeInProgress) { + spin_unlock_irqrestore(&priv->rf_ps_lock, flags); + RT_TRACE(COMP_DBG, + "rtl8192_hw_wakeup(): RF Change in progress!\n"); + queue_delayed_work_rsl(priv->rtllib->wq, + &priv->rtllib->hw_wakeup_wq, + msecs_to_jiffies(10)); + return; + } + spin_unlock_irqrestore(&priv->rf_ps_lock, flags); + RT_TRACE(COMP_PS, "%s()============>come to wake up\n", __func__); + MgntActSet_RF_State(dev, eRfOn, RF_CHANGE_BY_PS, false); +} + +void rtl8192_hw_wakeup_wq(void *data) +{ + struct rtllib_device *ieee = container_of_dwork_rsl(data, + struct rtllib_device, hw_wakeup_wq); + struct net_device *dev = ieee->dev; + + rtl8192_hw_wakeup(dev); +} + +#define MIN_SLEEP_TIME 50 +#define MAX_SLEEP_TIME 10000 +void rtl8192_hw_to_sleep(struct net_device *dev, u64 time) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + u32 tmp; + unsigned long flags; + + spin_lock_irqsave(&priv->ps_lock, flags); + + time -= msecs_to_jiffies(8 + 16 + 7); + + if ((time - jiffies) <= msecs_to_jiffies(MIN_SLEEP_TIME)) { + spin_unlock_irqrestore(&priv->ps_lock, flags); + netdev_info(dev, "too short to sleep::%lld < %ld\n", + time - jiffies, msecs_to_jiffies(MIN_SLEEP_TIME)); + return; + } + + if ((time - jiffies) > msecs_to_jiffies(MAX_SLEEP_TIME)) { + netdev_info(dev, "========>too long to sleep:%lld > %ld\n", + time - jiffies, msecs_to_jiffies(MAX_SLEEP_TIME)); + spin_unlock_irqrestore(&priv->ps_lock, flags); + return; + } + tmp = time - jiffies; + queue_delayed_work_rsl(priv->rtllib->wq, + &priv->rtllib->hw_wakeup_wq, tmp); + queue_delayed_work_rsl(priv->rtllib->wq, + (void *)&priv->rtllib->hw_sleep_wq, 0); + spin_unlock_irqrestore(&priv->ps_lock, flags); +} + +static void InactivePsWorkItemCallback(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct rt_pwr_save_ctrl *pPSC = (struct rt_pwr_save_ctrl *) + &(priv->rtllib->PowerSaveControl); + + RT_TRACE(COMP_PS, "InactivePsWorkItemCallback() --------->\n"); + pPSC->bSwRfProcessing = true; + + RT_TRACE(COMP_PS, "InactivePsWorkItemCallback(): Set RF to %s.\n", + pPSC->eInactivePowerState == eRfOff ? "OFF" : "ON"); + MgntActSet_RF_State(dev, pPSC->eInactivePowerState, RF_CHANGE_BY_IPS, + false); + + pPSC->bSwRfProcessing = false; + RT_TRACE(COMP_PS, "InactivePsWorkItemCallback() <---------\n"); +} + +void IPSEnter(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct rt_pwr_save_ctrl *pPSC = (struct rt_pwr_save_ctrl *) + &(priv->rtllib->PowerSaveControl); + enum rt_rf_power_state rtState; + + if (pPSC->bInactivePs) { + rtState = priv->rtllib->eRFPowerState; + if (rtState == eRfOn && !pPSC->bSwRfProcessing && + (priv->rtllib->state != RTLLIB_LINKED) && + (priv->rtllib->iw_mode != IW_MODE_MASTER)) { + RT_TRACE(COMP_PS, "IPSEnter(): Turn off RF.\n"); + pPSC->eInactivePowerState = eRfOff; + priv->isRFOff = true; + priv->bInPowerSaveMode = true; + InactivePsWorkItemCallback(dev); + } + } +} + +void IPSLeave(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct rt_pwr_save_ctrl *pPSC = (struct rt_pwr_save_ctrl *) + &(priv->rtllib->PowerSaveControl); + enum rt_rf_power_state rtState; + + if (pPSC->bInactivePs) { + rtState = priv->rtllib->eRFPowerState; + if (rtState != eRfOn && !pPSC->bSwRfProcessing && + priv->rtllib->RfOffReason <= RF_CHANGE_BY_IPS) { + RT_TRACE(COMP_PS, "IPSLeave(): Turn on RF.\n"); + pPSC->eInactivePowerState = eRfOn; + priv->bInPowerSaveMode = false; + InactivePsWorkItemCallback(dev); + } + } +} + +void IPSLeave_wq(void *data) +{ + struct rtllib_device *ieee = container_of_work_rsl(data, + struct rtllib_device, ips_leave_wq); + struct net_device *dev = ieee->dev; + struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); + + down(&priv->rtllib->ips_sem); + IPSLeave(dev); + up(&priv->rtllib->ips_sem); +} + +void rtllib_ips_leave_wq(struct net_device *dev) +{ + struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); + enum rt_rf_power_state rtState; + + rtState = priv->rtllib->eRFPowerState; + + if (priv->rtllib->PowerSaveControl.bInactivePs) { + if (rtState == eRfOff) { + if (priv->rtllib->RfOffReason > RF_CHANGE_BY_IPS) { + RT_TRACE(COMP_ERR, "%s(): RF is OFF.\n", + __func__); + return; + } + netdev_info(dev, "=========>%s(): IPSLeave\n", + __func__); + queue_work_rsl(priv->rtllib->wq, + &priv->rtllib->ips_leave_wq); + } + } +} + +void rtllib_ips_leave(struct net_device *dev) +{ + struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); + + down(&priv->rtllib->ips_sem); + IPSLeave(dev); + up(&priv->rtllib->ips_sem); +} + +static bool MgntActSet_802_11_PowerSaveMode(struct net_device *dev, + u8 rtPsMode) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + if (priv->rtllib->iw_mode == IW_MODE_ADHOC) + return false; + + RT_TRACE(COMP_LPS, "%s(): set ieee->ps = %x\n", __func__, rtPsMode); + if (!priv->ps_force) + priv->rtllib->ps = rtPsMode; + if (priv->rtllib->sta_sleep != LPS_IS_WAKE && + rtPsMode == RTLLIB_PS_DISABLED) { + unsigned long flags; + + rtl8192_hw_wakeup(dev); + priv->rtllib->sta_sleep = LPS_IS_WAKE; + + spin_lock_irqsave(&(priv->rtllib->mgmt_tx_lock), flags); + RT_TRACE(COMP_DBG, + "LPS leave: notify AP we are awaked ++++++++++ SendNullFunctionData\n"); + rtllib_sta_ps_send_null_frame(priv->rtllib, 0); + spin_unlock_irqrestore(&(priv->rtllib->mgmt_tx_lock), flags); + } + + return true; +} + +void LeisurePSEnter(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct rt_pwr_save_ctrl *pPSC = (struct rt_pwr_save_ctrl *) + &(priv->rtllib->PowerSaveControl); + + RT_TRACE(COMP_PS, "LeisurePSEnter()...\n"); + RT_TRACE(COMP_PS, + "pPSC->bLeisurePs = %d, ieee->ps = %d,pPSC->LpsIdleCount is %d,RT_CHECK_FOR_HANG_PERIOD is %d\n", + pPSC->bLeisurePs, priv->rtllib->ps, pPSC->LpsIdleCount, + RT_CHECK_FOR_HANG_PERIOD); + + if (!((priv->rtllib->iw_mode == IW_MODE_INFRA) && + (priv->rtllib->state == RTLLIB_LINKED)) + || (priv->rtllib->iw_mode == IW_MODE_ADHOC) || + (priv->rtllib->iw_mode == IW_MODE_MASTER)) + return; + + if (pPSC->bLeisurePs) { + if (pPSC->LpsIdleCount >= RT_CHECK_FOR_HANG_PERIOD) { + + if (priv->rtllib->ps == RTLLIB_PS_DISABLED) { + + RT_TRACE(COMP_LPS, + "LeisurePSEnter(): Enter 802.11 power save mode...\n"); + + if (!pPSC->bFwCtrlLPS) { + if (priv->rtllib->SetFwCmdHandler) + priv->rtllib->SetFwCmdHandler( + dev, FW_CMD_LPS_ENTER); + } + MgntActSet_802_11_PowerSaveMode(dev, + RTLLIB_PS_MBCAST | + RTLLIB_PS_UNICAST); + } + } else + pPSC->LpsIdleCount++; + } +} + +void LeisurePSLeave(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct rt_pwr_save_ctrl *pPSC = (struct rt_pwr_save_ctrl *) + &(priv->rtllib->PowerSaveControl); + + + RT_TRACE(COMP_PS, "LeisurePSLeave()...\n"); + RT_TRACE(COMP_PS, "pPSC->bLeisurePs = %d, ieee->ps = %d\n", + pPSC->bLeisurePs, priv->rtllib->ps); + + if (pPSC->bLeisurePs) { + if (priv->rtllib->ps != RTLLIB_PS_DISABLED) { + RT_TRACE(COMP_LPS, + "LeisurePSLeave(): Busy Traffic , Leave 802.11 power save..\n"); + MgntActSet_802_11_PowerSaveMode(dev, + RTLLIB_PS_DISABLED); + + if (!pPSC->bFwCtrlLPS) { + if (priv->rtllib->SetFwCmdHandler) + priv->rtllib->SetFwCmdHandler(dev, + FW_CMD_LPS_LEAVE); + } + } + } +} diff --git a/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h b/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h new file mode 100644 index 000000000..962f2e5b8 --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h @@ -0,0 +1,47 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * Based on the r8180 driver, which is: + * Copyright 2004-2005 Andrea Merello , et al. + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + ******************************************************************************/ +#ifndef _RTL_PS_H +#define _RTL_PS_H + +#include + +struct net_device; + +#define RT_CHECK_FOR_HANG_PERIOD 2 +#define INIT_DEFAULT_CHAN 1 + +void rtl8192_hw_wakeup(struct net_device *dev); +void rtl8192_hw_to_sleep(struct net_device *dev, u64 time); +void rtllib_ips_leave_wq(struct net_device *dev); +void rtllib_ips_leave(struct net_device *dev); +void IPSLeave_wq(void *data); + +void IPSEnter(struct net_device *dev); +void IPSLeave(struct net_device *dev); + +void LeisurePSEnter(struct net_device *dev); +void LeisurePSLeave(struct net_device *dev); + +#endif diff --git a/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c b/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c new file mode 100644 index 000000000..8d6a109e0 --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c @@ -0,0 +1,1341 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ + +#include +#include "rtl_core.h" +#include "rtl_wx.h" + +#define RATE_COUNT 12 +static u32 rtl8192_rates[] = { + 1000000, 2000000, 5500000, 11000000, 6000000, 9000000, 12000000, + 18000000, 24000000, 36000000, 48000000, 54000000 +}; + +#ifndef ENETDOWN +#define ENETDOWN 1 +#endif + +static int r8192_wx_get_freq(struct net_device *dev, + struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + return rtllib_wx_get_freq(priv->rtllib, a, wrqu, b); +} + + +static int r8192_wx_get_mode(struct net_device *dev, struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + return rtllib_wx_get_mode(priv->rtllib, a, wrqu, b); +} + +static int r8192_wx_get_rate(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + return rtllib_wx_get_rate(priv->rtllib, info, wrqu, extra); +} + + + +static int r8192_wx_set_rate(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + struct r8192_priv *priv = rtllib_priv(dev); + + if (priv->bHwRadioOff) + return 0; + + down(&priv->wx_sem); + + ret = rtllib_wx_set_rate(priv->rtllib, info, wrqu, extra); + + up(&priv->wx_sem); + + return ret; +} + + +static int r8192_wx_set_rts(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + struct r8192_priv *priv = rtllib_priv(dev); + + if (priv->bHwRadioOff) + return 0; + + down(&priv->wx_sem); + + ret = rtllib_wx_set_rts(priv->rtllib, info, wrqu, extra); + + up(&priv->wx_sem); + + return ret; +} + +static int r8192_wx_get_rts(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + return rtllib_wx_get_rts(priv->rtllib, info, wrqu, extra); +} + +static int r8192_wx_set_power(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + struct r8192_priv *priv = rtllib_priv(dev); + + if (priv->bHwRadioOff) { + RT_TRACE(COMP_ERR, + "%s():Hw is Radio Off, we can't set Power,return\n", + __func__); + return 0; + } + down(&priv->wx_sem); + + ret = rtllib_wx_set_power(priv->rtllib, info, wrqu, extra); + + up(&priv->wx_sem); + + return ret; +} + +static int r8192_wx_get_power(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + return rtllib_wx_get_power(priv->rtllib, info, wrqu, extra); +} + +static int r8192_wx_set_rawtx(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = rtllib_priv(dev); + int ret; + + if (priv->bHwRadioOff) + return 0; + + down(&priv->wx_sem); + + ret = rtllib_wx_set_rawtx(priv->rtllib, info, wrqu, extra); + + up(&priv->wx_sem); + + return ret; + +} + +static int r8192_wx_force_reset(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + down(&priv->wx_sem); + + RT_TRACE(COMP_DBG, "%s(): force reset ! extra is %d\n", + __func__, *extra); + priv->force_reset = *extra; + up(&priv->wx_sem); + return 0; + +} + +static int r8192_wx_force_mic_error(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct rtllib_device *ieee = priv->rtllib; + + down(&priv->wx_sem); + + RT_TRACE(COMP_DBG, "%s(): force mic error !\n", __func__); + ieee->force_mic_error = true; + up(&priv->wx_sem); + return 0; + +} + +#define MAX_ADHOC_PEER_NUM 64 +struct adhoc_peer_entry { + unsigned char MacAddr[ETH_ALEN]; + unsigned char WirelessMode; + unsigned char bCurTxBW40MHz; +}; +struct adhoc_peers_info { + struct adhoc_peer_entry Entry[MAX_ADHOC_PEER_NUM]; + unsigned char num; +}; + +static int r8192_wx_get_adhoc_peers(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + return 0; +} + + +static int r8191se_wx_get_firm_version(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrqu, char *extra) +{ + return 0; +} + +static int r8192_wx_adapter_power_status(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct rt_pwr_save_ctrl *pPSC = (struct rt_pwr_save_ctrl *) + (&(priv->rtllib->PowerSaveControl)); + struct rtllib_device *ieee = priv->rtllib; + + down(&priv->wx_sem); + + RT_TRACE(COMP_POWER, "%s(): %s\n", __func__, (*extra == 6) ? + "DC power" : "AC power"); + if (*extra || priv->force_lps) { + priv->ps_force = false; + pPSC->bLeisurePs = true; + } else { + if (priv->rtllib->state == RTLLIB_LINKED) + LeisurePSLeave(dev); + + priv->ps_force = true; + pPSC->bLeisurePs = false; + ieee->ps = *extra; + } + + up(&priv->wx_sem); + + return 0; +} + +static int r8192se_wx_set_radio(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + down(&priv->wx_sem); + + netdev_info(dev, "%s(): set radio ! extra is %d\n", __func__, *extra); + if ((*extra != 0) && (*extra != 1)) { + RT_TRACE(COMP_ERR, + "%s(): set radio an err value,must 0(radio off) or 1(radio on)\n", + __func__); + up(&priv->wx_sem); + return -1; + } + priv->sw_radio_on = *extra; + up(&priv->wx_sem); + return 0; + +} + +static int r8192se_wx_set_lps_awake_interval(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct rt_pwr_save_ctrl *pPSC = (struct rt_pwr_save_ctrl *) + (&(priv->rtllib->PowerSaveControl)); + + down(&priv->wx_sem); + + netdev_info(dev, "%s(): set lps awake interval ! extra is %d\n", + __func__, *extra); + + pPSC->RegMaxLPSAwakeIntvl = *extra; + up(&priv->wx_sem); + return 0; +} + +static int r8192se_wx_set_force_lps(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + down(&priv->wx_sem); + + netdev_info(dev, + "%s(): force LPS ! extra is %d (1 is open 0 is close)\n", + __func__, *extra); + priv->force_lps = *extra; + up(&priv->wx_sem); + return 0; + +} + +static int r8192_wx_set_debugflag(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = rtllib_priv(dev); + u8 c = *extra; + + if (priv->bHwRadioOff) + return 0; + + netdev_info(dev, "=====>%s(), *extra:%x, debugflag:%x\n", __func__, + *extra, rt_global_debug_component); + if (c > 0) + rt_global_debug_component |= (1<bHwRadioOff) + return 0; + rtState = priv->rtllib->eRFPowerState; + down(&priv->wx_sem); + if (wrqu->mode == IW_MODE_ADHOC || wrqu->mode == IW_MODE_MONITOR || + ieee->bNetPromiscuousMode) { + if (priv->rtllib->PowerSaveControl.bInactivePs) { + if (rtState == eRfOff) { + if (priv->rtllib->RfOffReason > + RF_CHANGE_BY_IPS) { + RT_TRACE(COMP_ERR, "%s(): RF is OFF.\n", + __func__); + up(&priv->wx_sem); + return -1; + } + netdev_info(dev, "=========>%s(): IPSLeave\n", + __func__); + down(&priv->rtllib->ips_sem); + IPSLeave(dev); + up(&priv->rtllib->ips_sem); + } + } + } + ret = rtllib_wx_set_mode(priv->rtllib, a, wrqu, b); + + up(&priv->wx_sem); + return ret; +} + +struct iw_range_with_scan_capa { + /* Informative stuff (to choose between different interface) */ + __u32 throughput; /* To give an idea... */ + /* In theory this value should be the maximum benchmarked + * TCP/IP throughput, because with most of these devices the + * bit rate is meaningless (overhead an co) to estimate how + * fast the connection will go and pick the fastest one. + * I suggest people to play with Netperf or any benchmark... + */ + + /* NWID (or domain id) */ + __u32 min_nwid; /* Minimal NWID we are able to set */ + __u32 max_nwid; /* Maximal NWID we are able to set */ + + /* Old Frequency (backward compat - moved lower ) */ + __u16 old_num_channels; + __u8 old_num_frequency; + + /* Scan capabilities */ + __u8 scan_capa; +}; + +static int rtl8192_wx_get_range(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct iw_range *range = (struct iw_range *)extra; + struct r8192_priv *priv = rtllib_priv(dev); + u16 val; + int i; + + wrqu->data.length = sizeof(*range); + memset(range, 0, sizeof(*range)); + + /* ~130 Mb/s real (802.11n) */ + range->throughput = 130 * 1000 * 1000; + + if (priv->rf_set_sens != NULL) { + /* signal level threshold range */ + range->sensitivity = priv->max_sens; + } + + range->max_qual.qual = 100; + range->max_qual.level = 0; + range->max_qual.noise = 0; + range->max_qual.updated = 7; /* Updated all three */ + + range->avg_qual.qual = 70; /* > 8% missed beacons is 'bad' */ + range->avg_qual.level = 0; + range->avg_qual.noise = 0; + range->avg_qual.updated = 7; /* Updated all three */ + + range->num_bitrates = min(RATE_COUNT, IW_MAX_BITRATES); + + for (i = 0; i < range->num_bitrates; i++) + range->bitrate[i] = rtl8192_rates[i]; + + range->max_rts = DEFAULT_RTS_THRESHOLD; + range->min_frag = MIN_FRAG_THRESHOLD; + range->max_frag = MAX_FRAG_THRESHOLD; + + range->min_pmp = 0; + range->max_pmp = 5000000; + range->min_pmt = 0; + range->max_pmt = 65535*1000; + range->pmp_flags = IW_POWER_PERIOD; + range->pmt_flags = IW_POWER_TIMEOUT; + range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R; + range->we_version_compiled = WIRELESS_EXT; + range->we_version_source = 18; + + for (i = 0, val = 0; i < 14; i++) { + if ((priv->rtllib->active_channel_map)[i+1]) { + range->freq[val].i = i + 1; + range->freq[val].m = rtllib_wlan_frequencies[i] * + 100000; + range->freq[val].e = 1; + val++; + } + + if (val == IW_MAX_FREQUENCIES) + break; + } + range->num_frequency = val; + range->num_channels = val; + range->enc_capa = IW_ENC_CAPA_WPA|IW_ENC_CAPA_WPA2| + IW_ENC_CAPA_CIPHER_TKIP|IW_ENC_CAPA_CIPHER_CCMP; + range->scan_capa = IW_SCAN_CAPA_ESSID | IW_SCAN_CAPA_TYPE; + + /* Event capability (kernel + driver) */ + + return 0; +} + +static int r8192_wx_set_scan(struct net_device *dev, struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct rtllib_device *ieee = priv->rtllib; + enum rt_rf_power_state rtState; + int ret; + + if (!(ieee->softmac_features & IEEE_SOFTMAC_SCAN)) { + if ((ieee->state >= RTLLIB_ASSOCIATING) && + (ieee->state <= RTLLIB_ASSOCIATING_AUTHENTICATED)) + return 0; + if ((priv->rtllib->state == RTLLIB_LINKED) && + (priv->rtllib->CntAfterLink < 2)) + return 0; + } + + if (priv->bHwRadioOff) { + netdev_info(dev, "================>%s(): hwradio off\n", + __func__); + return 0; + } + rtState = priv->rtllib->eRFPowerState; + if (!priv->up) + return -ENETDOWN; + if (priv->rtllib->LinkDetectInfo.bBusyTraffic == true) + return -EAGAIN; + + if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { + struct iw_scan_req *req = (struct iw_scan_req *)b; + + if (req->essid_len) { + ieee->current_network.ssid_len = req->essid_len; + memcpy(ieee->current_network.ssid, req->essid, + req->essid_len); + } + } + + down(&priv->wx_sem); + + priv->rtllib->FirstIe_InScan = true; + + if (priv->rtllib->state != RTLLIB_LINKED) { + if (priv->rtllib->PowerSaveControl.bInactivePs) { + if (rtState == eRfOff) { + if (priv->rtllib->RfOffReason > + RF_CHANGE_BY_IPS) { + RT_TRACE(COMP_ERR, + "%s(): RF is OFF.\n", + __func__); + up(&priv->wx_sem); + return -1; + } + RT_TRACE(COMP_PS, "=========>%s(): IPSLeave\n", + __func__); + down(&priv->rtllib->ips_sem); + IPSLeave(dev); + up(&priv->rtllib->ips_sem); + } + } + rtllib_stop_scan(priv->rtllib); + if (priv->rtllib->LedControlHandler) + priv->rtllib->LedControlHandler(dev, + LED_CTL_SITE_SURVEY); + + if (priv->rtllib->eRFPowerState != eRfOff) { + priv->rtllib->actscanning = true; + + if (ieee->ScanOperationBackupHandler) + ieee->ScanOperationBackupHandler(ieee->dev, + SCAN_OPT_BACKUP); + + rtllib_start_scan_syncro(priv->rtllib, 0); + + if (ieee->ScanOperationBackupHandler) + ieee->ScanOperationBackupHandler(ieee->dev, + SCAN_OPT_RESTORE); + } + ret = 0; + } else { + priv->rtllib->actscanning = true; + ret = rtllib_wx_set_scan(priv->rtllib, a, wrqu, b); + } + + up(&priv->wx_sem); + return ret; +} + + +static int r8192_wx_get_scan(struct net_device *dev, struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + + int ret; + struct r8192_priv *priv = rtllib_priv(dev); + + if (!priv->up) + return -ENETDOWN; + + if (priv->bHwRadioOff) + return 0; + + + down(&priv->wx_sem); + + ret = rtllib_wx_get_scan(priv->rtllib, a, wrqu, b); + + up(&priv->wx_sem); + + return ret; +} + +static int r8192_wx_set_essid(struct net_device *dev, + struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + struct r8192_priv *priv = rtllib_priv(dev); + int ret; + + if (priv->bHwRadioOff) { + netdev_info(dev, + "=========>%s():hw radio off,or Rf state is eRfOff, return\n", + __func__); + return 0; + } + down(&priv->wx_sem); + ret = rtllib_wx_set_essid(priv->rtllib, a, wrqu, b); + + up(&priv->wx_sem); + + return ret; +} + +static int r8192_wx_get_essid(struct net_device *dev, + struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + int ret; + struct r8192_priv *priv = rtllib_priv(dev); + + down(&priv->wx_sem); + + ret = rtllib_wx_get_essid(priv->rtllib, a, wrqu, b); + + up(&priv->wx_sem); + + return ret; +} + +static int r8192_wx_set_nick(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + if (wrqu->data.length > IW_ESSID_MAX_SIZE) + return -E2BIG; + down(&priv->wx_sem); + wrqu->data.length = min_t(size_t, wrqu->data.length, sizeof(priv->nick)); + memset(priv->nick, 0, sizeof(priv->nick)); + memcpy(priv->nick, extra, wrqu->data.length); + up(&priv->wx_sem); + return 0; + +} + +static int r8192_wx_get_nick(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + down(&priv->wx_sem); + wrqu->data.length = strlen(priv->nick); + memcpy(extra, priv->nick, wrqu->data.length); + wrqu->data.flags = 1; /* active */ + up(&priv->wx_sem); + return 0; +} + +static int r8192_wx_set_freq(struct net_device *dev, struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + int ret; + struct r8192_priv *priv = rtllib_priv(dev); + + if (priv->bHwRadioOff) + return 0; + + down(&priv->wx_sem); + + ret = rtllib_wx_set_freq(priv->rtllib, a, wrqu, b); + + up(&priv->wx_sem); + return ret; +} + +static int r8192_wx_get_name(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + return rtllib_wx_get_name(priv->rtllib, info, wrqu, extra); +} + + +static int r8192_wx_set_frag(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + if (priv->bHwRadioOff) + return 0; + + if (wrqu->frag.disabled) + priv->rtllib->fts = DEFAULT_FRAG_THRESHOLD; + else { + if (wrqu->frag.value < MIN_FRAG_THRESHOLD || + wrqu->frag.value > MAX_FRAG_THRESHOLD) + return -EINVAL; + + priv->rtllib->fts = wrqu->frag.value & ~0x1; + } + + return 0; +} + + +static int r8192_wx_get_frag(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + wrqu->frag.value = priv->rtllib->fts; + wrqu->frag.fixed = 0; /* no auto select */ + wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FRAG_THRESHOLD); + + return 0; +} + + +static int r8192_wx_set_wap(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *awrq, + char *extra) +{ + int ret; + struct r8192_priv *priv = rtllib_priv(dev); + + if (priv->bHwRadioOff) + return 0; + + down(&priv->wx_sem); + + ret = rtllib_wx_set_wap(priv->rtllib, info, awrq, extra); + + up(&priv->wx_sem); + + return ret; + +} + + +static int r8192_wx_get_wap(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + return rtllib_wx_get_wap(priv->rtllib, info, wrqu, extra); +} + + +static int r8192_wx_get_enc(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *key) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + return rtllib_wx_get_encode(priv->rtllib, info, wrqu, key); +} + +static int r8192_wx_set_enc(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *key) +{ + struct r8192_priv *priv = rtllib_priv(dev); + int ret; + + struct rtllib_device *ieee = priv->rtllib; + u32 hwkey[4] = {0, 0, 0, 0}; + u8 mask = 0xff; + u32 key_idx = 0; + u8 zero_addr[4][6] = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x03} }; + int i; + + if (priv->bHwRadioOff) + return 0; + + if (!priv->up) + return -ENETDOWN; + + priv->rtllib->wx_set_enc = 1; + down(&priv->rtllib->ips_sem); + IPSLeave(dev); + up(&priv->rtllib->ips_sem); + down(&priv->wx_sem); + + RT_TRACE(COMP_SEC, "Setting SW wep key"); + ret = rtllib_wx_set_encode(priv->rtllib, info, wrqu, key); + up(&priv->wx_sem); + + + if (wrqu->encoding.flags & IW_ENCODE_DISABLED) { + ieee->pairwise_key_type = ieee->group_key_type = KEY_TYPE_NA; + CamResetAllEntry(dev); + memset(priv->rtllib->swcamtable, 0, + sizeof(struct sw_cam_table) * 32); + goto end_hw_sec; + } + if (wrqu->encoding.length != 0) { + + for (i = 0; i < 4; i++) { + hwkey[i] |= key[4*i+0]&mask; + if (i == 1 && (4 * i + 1) == wrqu->encoding.length) + mask = 0x00; + if (i == 3 && (4 * i + 1) == wrqu->encoding.length) + mask = 0x00; + hwkey[i] |= (key[4 * i + 1] & mask) << 8; + hwkey[i] |= (key[4 * i + 2] & mask) << 16; + hwkey[i] |= (key[4 * i + 3] & mask) << 24; + } + + #define CONF_WEP40 0x4 + #define CONF_WEP104 0x14 + + switch (wrqu->encoding.flags & IW_ENCODE_INDEX) { + case 0: + key_idx = ieee->crypt_info.tx_keyidx; + break; + case 1: + key_idx = 0; + break; + case 2: + key_idx = 1; + break; + case 3: + key_idx = 2; + break; + case 4: + key_idx = 3; + break; + default: + break; + } + if (wrqu->encoding.length == 0x5) { + ieee->pairwise_key_type = KEY_TYPE_WEP40; + EnableHWSecurityConfig8192(dev); + } + + else if (wrqu->encoding.length == 0xd) { + ieee->pairwise_key_type = KEY_TYPE_WEP104; + EnableHWSecurityConfig8192(dev); + setKey(dev, key_idx, key_idx, KEY_TYPE_WEP104, + zero_addr[key_idx], 0, hwkey); + set_swcam(dev, key_idx, key_idx, KEY_TYPE_WEP104, + zero_addr[key_idx], 0, hwkey, 0); + } else { + netdev_info(dev, + "wrong type in WEP, not WEP40 and WEP104\n"); + } + } + +end_hw_sec: + priv->rtllib->wx_set_enc = 0; + return ret; +} + +static int r8192_wx_set_scan_type(struct net_device *dev, + struct iw_request_info *aa, + union iwreq_data *wrqu, char *p) +{ + struct r8192_priv *priv = rtllib_priv(dev); + int *parms = (int *)p; + int mode = parms[0]; + + if (priv->bHwRadioOff) + return 0; + + priv->rtllib->active_scan = mode; + + return 1; +} + + + +#define R8192_MAX_RETRY 255 +static int r8192_wx_set_retry(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = rtllib_priv(dev); + int err = 0; + + if (priv->bHwRadioOff) + return 0; + + down(&priv->wx_sem); + + if (wrqu->retry.flags & IW_RETRY_LIFETIME || + wrqu->retry.disabled) { + err = -EINVAL; + goto exit; + } + if (!(wrqu->retry.flags & IW_RETRY_LIMIT)) { + err = -EINVAL; + goto exit; + } + + if (wrqu->retry.value > R8192_MAX_RETRY) { + err = -EINVAL; + goto exit; + } + if (wrqu->retry.flags & IW_RETRY_MAX) { + priv->retry_rts = wrqu->retry.value; + DMESG("Setting retry for RTS/CTS data to %d", + wrqu->retry.value); + + } else { + priv->retry_data = wrqu->retry.value; + DMESG("Setting retry for non RTS/CTS data to %d", + wrqu->retry.value); + } + + + rtl8192_commit(dev); +exit: + up(&priv->wx_sem); + + return err; +} + +static int r8192_wx_get_retry(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + + wrqu->retry.disabled = 0; /* can't be disabled */ + + if ((wrqu->retry.flags & IW_RETRY_TYPE) == + IW_RETRY_LIFETIME) + return -EINVAL; + + if (wrqu->retry.flags & IW_RETRY_MAX) { + wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + wrqu->retry.value = priv->retry_rts; + } else { + wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN; + wrqu->retry.value = priv->retry_data; + } + return 0; +} + +static int r8192_wx_get_sens(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + if (priv->rf_set_sens == NULL) + return -1; /* we have not this support for this radio */ + wrqu->sens.value = priv->sens; + return 0; +} + + +static int r8192_wx_set_sens(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + + struct r8192_priv *priv = rtllib_priv(dev); + + short err = 0; + + if (priv->bHwRadioOff) + return 0; + + down(&priv->wx_sem); + if (priv->rf_set_sens == NULL) { + err = -1; /* we have not this support for this radio */ + goto exit; + } + if (priv->rf_set_sens(dev, wrqu->sens.value) == 0) + priv->sens = wrqu->sens.value; + else + err = -EINVAL; + +exit: + up(&priv->wx_sem); + + return err; +} + +static int r8192_wx_set_enc_ext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret = 0; + struct r8192_priv *priv = rtllib_priv(dev); + struct rtllib_device *ieee = priv->rtllib; + + if (priv->bHwRadioOff) + return 0; + + down(&priv->wx_sem); + + priv->rtllib->wx_set_enc = 1; + down(&priv->rtllib->ips_sem); + IPSLeave(dev); + up(&priv->rtllib->ips_sem); + + ret = rtllib_wx_set_encode_ext(ieee, info, wrqu, extra); + { + u8 broadcast_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + u8 zero[6] = {0}; + u32 key[4] = {0}; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + struct iw_point *encoding = &wrqu->encoding; + u8 idx = 0, alg = 0, group = 0; + + if ((encoding->flags & IW_ENCODE_DISABLED) || + ext->alg == IW_ENCODE_ALG_NONE) { + ieee->pairwise_key_type = ieee->group_key_type + = KEY_TYPE_NA; + CamResetAllEntry(dev); + memset(priv->rtllib->swcamtable, 0, + sizeof(struct sw_cam_table) * 32); + goto end_hw_sec; + } + alg = (ext->alg == IW_ENCODE_ALG_CCMP) ? KEY_TYPE_CCMP : + ext->alg; + idx = encoding->flags & IW_ENCODE_INDEX; + if (idx) + idx--; + group = ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY; + + if ((!group) || (IW_MODE_ADHOC == ieee->iw_mode) || + (alg == KEY_TYPE_WEP40)) { + if ((ext->key_len == 13) && (alg == KEY_TYPE_WEP40)) + alg = KEY_TYPE_WEP104; + ieee->pairwise_key_type = alg; + EnableHWSecurityConfig8192(dev); + } + memcpy((u8 *)key, ext->key, 16); + + if ((alg & KEY_TYPE_WEP40) && (ieee->auth_mode != 2)) { + if (ext->key_len == 13) + ieee->pairwise_key_type = alg = KEY_TYPE_WEP104; + setKey(dev, idx, idx, alg, zero, 0, key); + set_swcam(dev, idx, idx, alg, zero, 0, key, 0); + } else if (group) { + ieee->group_key_type = alg; + setKey(dev, idx, idx, alg, broadcast_addr, 0, key); + set_swcam(dev, idx, idx, alg, broadcast_addr, 0, + key, 0); + } else { + if ((ieee->pairwise_key_type == KEY_TYPE_CCMP) && + ieee->pHTInfo->bCurrentHTSupport) + write_nic_byte(dev, 0x173, 1); + setKey(dev, 4, idx, alg, (u8 *)ieee->ap_mac_addr, + 0, key); + set_swcam(dev, 4, idx, alg, (u8 *)ieee->ap_mac_addr, + 0, key, 0); + } + + + } + +end_hw_sec: + priv->rtllib->wx_set_enc = 0; + up(&priv->wx_sem); + return ret; + +} +static int r8192_wx_set_auth(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *data, char *extra) +{ + int ret = 0; + + struct r8192_priv *priv = rtllib_priv(dev); + + if (priv->bHwRadioOff) + return 0; + + down(&priv->wx_sem); + ret = rtllib_wx_set_auth(priv->rtllib, info, &(data->param), extra); + up(&priv->wx_sem); + return ret; +} + +static int r8192_wx_set_mlme(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + + int ret = 0; + + struct r8192_priv *priv = rtllib_priv(dev); + + if (priv->bHwRadioOff) + return 0; + + down(&priv->wx_sem); + ret = rtllib_wx_set_mlme(priv->rtllib, info, wrqu, extra); + up(&priv->wx_sem); + return ret; +} + +static int r8192_wx_set_gen_ie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *data, char *extra) +{ + int ret = 0; + + struct r8192_priv *priv = rtllib_priv(dev); + + if (priv->bHwRadioOff) + return 0; + + down(&priv->wx_sem); + ret = rtllib_wx_set_gen_ie(priv->rtllib, extra, data->data.length); + up(&priv->wx_sem); + return ret; +} + +static int r8192_wx_get_gen_ie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *data, char *extra) +{ + int ret = 0; + struct r8192_priv *priv = rtllib_priv(dev); + struct rtllib_device *ieee = priv->rtllib; + + if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) { + data->data.length = 0; + return 0; + } + + if (data->data.length < ieee->wpa_ie_len) + return -E2BIG; + + data->data.length = ieee->wpa_ie_len; + memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len); + return ret; +} + +#define OID_RT_INTEL_PROMISCUOUS_MODE 0xFF0101F6 + +static int r8192_wx_set_PromiscuousMode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct rtllib_device *ieee = priv->rtllib; + + u32 info_buf[3]; + + u32 oid; + u32 bPromiscuousOn; + u32 bFilterSourceStationFrame; + + if (copy_from_user(info_buf, wrqu->data.pointer, sizeof(info_buf))) + return -EFAULT; + + oid = info_buf[0]; + bPromiscuousOn = info_buf[1]; + bFilterSourceStationFrame = info_buf[2]; + + if (OID_RT_INTEL_PROMISCUOUS_MODE == oid) { + ieee->IntelPromiscuousModeInfo.bPromiscuousOn = + (bPromiscuousOn) ? (true) : (false); + ieee->IntelPromiscuousModeInfo.bFilterSourceStationFrame = + (bFilterSourceStationFrame) ? (true) : (false); + (bPromiscuousOn) ? + (rtllib_EnableIntelPromiscuousMode(dev, false)) : + (rtllib_DisableIntelPromiscuousMode(dev, false)); + + netdev_info(dev, + "=======>%s(), on = %d, filter src sta = %d\n", + __func__, bPromiscuousOn, + bFilterSourceStationFrame); + } else { + return -1; + } + + return 0; +} + + +static int r8192_wx_get_PromiscuousMode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct rtllib_device *ieee = priv->rtllib; + + down(&priv->wx_sem); + + snprintf(extra, 45, "PromiscuousMode:%d, FilterSrcSTAFrame:%d", + ieee->IntelPromiscuousModeInfo.bPromiscuousOn, + ieee->IntelPromiscuousModeInfo.bFilterSourceStationFrame); + wrqu->data.length = strlen(extra) + 1; + + up(&priv->wx_sem); + + return 0; +} + + +#define IW_IOCTL(x) [(x)-SIOCSIWCOMMIT] +static iw_handler r8192_wx_handlers[] = { + IW_IOCTL(SIOCGIWNAME) = r8192_wx_get_name, + IW_IOCTL(SIOCSIWFREQ) = r8192_wx_set_freq, + IW_IOCTL(SIOCGIWFREQ) = r8192_wx_get_freq, + IW_IOCTL(SIOCSIWMODE) = r8192_wx_set_mode, + IW_IOCTL(SIOCGIWMODE) = r8192_wx_get_mode, + IW_IOCTL(SIOCSIWSENS) = r8192_wx_set_sens, + IW_IOCTL(SIOCGIWSENS) = r8192_wx_get_sens, + IW_IOCTL(SIOCGIWRANGE) = rtl8192_wx_get_range, + IW_IOCTL(SIOCSIWAP) = r8192_wx_set_wap, + IW_IOCTL(SIOCGIWAP) = r8192_wx_get_wap, + IW_IOCTL(SIOCSIWSCAN) = r8192_wx_set_scan, + IW_IOCTL(SIOCGIWSCAN) = r8192_wx_get_scan, + IW_IOCTL(SIOCSIWESSID) = r8192_wx_set_essid, + IW_IOCTL(SIOCGIWESSID) = r8192_wx_get_essid, + IW_IOCTL(SIOCSIWNICKN) = r8192_wx_set_nick, + IW_IOCTL(SIOCGIWNICKN) = r8192_wx_get_nick, + IW_IOCTL(SIOCSIWRATE) = r8192_wx_set_rate, + IW_IOCTL(SIOCGIWRATE) = r8192_wx_get_rate, + IW_IOCTL(SIOCSIWRTS) = r8192_wx_set_rts, + IW_IOCTL(SIOCGIWRTS) = r8192_wx_get_rts, + IW_IOCTL(SIOCSIWFRAG) = r8192_wx_set_frag, + IW_IOCTL(SIOCGIWFRAG) = r8192_wx_get_frag, + IW_IOCTL(SIOCSIWRETRY) = r8192_wx_set_retry, + IW_IOCTL(SIOCGIWRETRY) = r8192_wx_get_retry, + IW_IOCTL(SIOCSIWENCODE) = r8192_wx_set_enc, + IW_IOCTL(SIOCGIWENCODE) = r8192_wx_get_enc, + IW_IOCTL(SIOCSIWPOWER) = r8192_wx_set_power, + IW_IOCTL(SIOCGIWPOWER) = r8192_wx_get_power, + IW_IOCTL(SIOCSIWGENIE) = r8192_wx_set_gen_ie, + IW_IOCTL(SIOCGIWGENIE) = r8192_wx_get_gen_ie, + IW_IOCTL(SIOCSIWMLME) = r8192_wx_set_mlme, + IW_IOCTL(SIOCSIWAUTH) = r8192_wx_set_auth, + IW_IOCTL(SIOCSIWENCODEEXT) = r8192_wx_set_enc_ext, +}; + +/* the following rule need to be following, + * Odd : get (world access), + * even : set (root access) + */ +static const struct iw_priv_args r8192_private_args[] = { + { + SIOCIWFIRSTPRIV + 0x0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_debugflag" + }, { + SIOCIWFIRSTPRIV + 0x1, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "activescan" + }, { + SIOCIWFIRSTPRIV + 0x2, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "rawtx" + }, { + SIOCIWFIRSTPRIV + 0x3, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "forcereset" + }, { + SIOCIWFIRSTPRIV + 0x4, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "force_mic_error" + }, { + SIOCIWFIRSTPRIV + 0x5, + IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT|IW_PRIV_SIZE_FIXED|1, + "firm_ver" + }, { + SIOCIWFIRSTPRIV + 0x6, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED|1, IW_PRIV_TYPE_NONE, + "set_power" + }, { + SIOCIWFIRSTPRIV + 0x9, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED|1, IW_PRIV_TYPE_NONE, + "radio" + }, { + SIOCIWFIRSTPRIV + 0xa, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED|1, IW_PRIV_TYPE_NONE, + "lps_interv" + }, { + SIOCIWFIRSTPRIV + 0xb, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED|1, IW_PRIV_TYPE_NONE, + "lps_force" + }, { + SIOCIWFIRSTPRIV + 0xc, + 0, IW_PRIV_TYPE_CHAR|2047, "adhoc_peer_list" + }, { + SIOCIWFIRSTPRIV + 0x16, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, 0, "setpromisc" + }, { + SIOCIWFIRSTPRIV + 0x17, + 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 45, "getpromisc" + } + +}; + +static iw_handler r8192_private_handler[] = { + (iw_handler)r8192_wx_set_debugflag, /*SIOCIWSECONDPRIV*/ + (iw_handler)r8192_wx_set_scan_type, + (iw_handler)r8192_wx_set_rawtx, + (iw_handler)r8192_wx_force_reset, + (iw_handler)r8192_wx_force_mic_error, + (iw_handler)r8191se_wx_get_firm_version, + (iw_handler)r8192_wx_adapter_power_status, + (iw_handler)NULL, + (iw_handler)NULL, + (iw_handler)r8192se_wx_set_radio, + (iw_handler)r8192se_wx_set_lps_awake_interval, + (iw_handler)r8192se_wx_set_force_lps, + (iw_handler)r8192_wx_get_adhoc_peers, + (iw_handler)NULL, + (iw_handler)NULL, + (iw_handler)NULL, + (iw_handler)NULL, + (iw_handler)NULL, + (iw_handler)NULL, + (iw_handler)NULL, + (iw_handler)NULL, + (iw_handler)NULL, + (iw_handler)r8192_wx_set_PromiscuousMode, + (iw_handler)r8192_wx_get_PromiscuousMode, +}; + +static struct iw_statistics *r8192_get_wireless_stats(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + struct rtllib_device *ieee = priv->rtllib; + struct iw_statistics *wstats = &priv->wstats; + int tmp_level = 0; + int tmp_qual = 0; + int tmp_noise = 0; + + if (ieee->state < RTLLIB_LINKED) { + wstats->qual.qual = 10; + wstats->qual.level = 0; + wstats->qual.noise = -100; + wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; + return wstats; + } + + tmp_level = (&ieee->current_network)->stats.rssi; + tmp_qual = (&ieee->current_network)->stats.signal; + tmp_noise = (&ieee->current_network)->stats.noise; + + wstats->qual.level = tmp_level; + wstats->qual.qual = tmp_qual; + wstats->qual.noise = tmp_noise; + wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; + return wstats; +} + +const struct iw_handler_def r8192_wx_handlers_def = { + .standard = r8192_wx_handlers, + .num_standard = ARRAY_SIZE(r8192_wx_handlers), + .private = r8192_private_handler, + .num_private = ARRAY_SIZE(r8192_private_handler), + .num_private_args = sizeof(r8192_private_args) / + sizeof(struct iw_priv_args), + .get_wireless_stats = r8192_get_wireless_stats, + .private_args = (struct iw_priv_args *)r8192_private_args, +}; diff --git a/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_wx.h b/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_wx.h new file mode 100644 index 000000000..58398517f --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl8192e/rtl_wx.h @@ -0,0 +1,30 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ + +#ifndef R819x_WX_H +#define R819x_WX_H + +struct net_device; +struct iw_handler_def; +struct iw_statistics; + +extern const struct iw_handler_def r8192_wx_handlers_def; +u16 rtl8192_11n_user_show_rates(struct net_device *dev); + +#endif diff --git a/kernel/drivers/staging/rtl8192e/rtl819x_BA.h b/kernel/drivers/staging/rtl8192e/rtl819x_BA.h new file mode 100644 index 000000000..613e14c12 --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl819x_BA.h @@ -0,0 +1,77 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ +#ifndef _BATYPE_H_ +#define _BATYPE_H_ + +#define TOTAL_TXBA_NUM 16 +#define TOTAL_RXBA_NUM 16 + +#define BA_SETUP_TIMEOUT 200 +#define BA_INACT_TIMEOUT 60000 + +#define BA_POLICY_DELAYED 0 +#define BA_POLICY_IMMEDIATE 1 + +#define ADDBA_STATUS_SUCCESS 0 +#define ADDBA_STATUS_REFUSED 37 +#define ADDBA_STATUS_INVALID_PARAM 38 + +#define DELBA_REASON_QSTA_LEAVING 36 +#define DELBA_REASON_END_BA 37 +#define DELBA_REASON_UNKNOWN_BA 38 +#define DELBA_REASON_TIMEOUT 39 +union sequence_control { + u16 ShortData; + struct { + u16 FragNum:4; + u16 SeqNum:12; + } field; +}; + +union ba_param_set { + u8 charData[2]; + u16 shortData; + struct { + u16 AMSDU_Support:1; + u16 BAPolicy:1; + u16 TID:4; + u16 BufferSize:10; + } field; +}; + +union delba_param_set { + u8 charData[2]; + u16 shortData; + struct { + u16 Reserved:11; + u16 Initiator:1; + u16 TID:4; + } field; +}; + +struct ba_record { + struct timer_list Timer; + u8 bValid; + u8 DialogToken; + union ba_param_set BaParamSet; + u16 BaTimeoutValue; + union sequence_control BaStartSeqCtrl; +}; + +#endif diff --git a/kernel/drivers/staging/rtl8192e/rtl819x_BAProc.c b/kernel/drivers/staging/rtl8192e/rtl819x_BAProc.c new file mode 100644 index 000000000..26258ea8d --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl819x_BAProc.c @@ -0,0 +1,571 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ +#include +#include +#include "rtllib.h" +#include "rtl819x_BA.h" + +static void ActivateBAEntry(struct rtllib_device *ieee, struct ba_record *pBA, + u16 Time) +{ + pBA->bValid = true; + if (Time != 0) + mod_timer(&pBA->Timer, jiffies + msecs_to_jiffies(Time)); +} + +static void DeActivateBAEntry(struct rtllib_device *ieee, struct ba_record *pBA) +{ + pBA->bValid = false; + del_timer_sync(&pBA->Timer); +} + +static u8 TxTsDeleteBA(struct rtllib_device *ieee, struct tx_ts_record *pTxTs) +{ + struct ba_record *pAdmittedBa = &pTxTs->TxAdmittedBARecord; + struct ba_record *pPendingBa = &pTxTs->TxPendingBARecord; + u8 bSendDELBA = false; + + if (pPendingBa->bValid) { + DeActivateBAEntry(ieee, pPendingBa); + bSendDELBA = true; + } + + if (pAdmittedBa->bValid) { + DeActivateBAEntry(ieee, pAdmittedBa); + bSendDELBA = true; + } + return bSendDELBA; +} + +static u8 RxTsDeleteBA(struct rtllib_device *ieee, struct rx_ts_record *pRxTs) +{ + struct ba_record *pBa = &pRxTs->RxAdmittedBARecord; + u8 bSendDELBA = false; + + if (pBa->bValid) { + DeActivateBAEntry(ieee, pBa); + bSendDELBA = true; + } + + return bSendDELBA; +} + +void ResetBaEntry(struct ba_record *pBA) +{ + pBA->bValid = false; + pBA->BaParamSet.shortData = 0; + pBA->BaTimeoutValue = 0; + pBA->DialogToken = 0; + pBA->BaStartSeqCtrl.ShortData = 0; +} +static struct sk_buff *rtllib_ADDBA(struct rtllib_device *ieee, u8 *Dst, + struct ba_record *pBA, + u16 StatusCode, u8 type) +{ + struct sk_buff *skb = NULL; + struct rtllib_hdr_3addr *BAReq = NULL; + u8 *tag = NULL; + u16 len = ieee->tx_headroom + 9; + + RTLLIB_DEBUG(RTLLIB_DL_TRACE | RTLLIB_DL_BA, + "========>%s(), frame(%d) sentd to: %pM, ieee->dev:%p\n", + __func__, type, Dst, ieee->dev); + if (pBA == NULL) { + RTLLIB_DEBUG(RTLLIB_DL_ERR, "pBA is NULL\n"); + return NULL; + } + skb = dev_alloc_skb(len + sizeof(struct rtllib_hdr_3addr)); + if (skb == NULL) { + RTLLIB_DEBUG(RTLLIB_DL_ERR, "can't alloc skb for ADDBA_REQ\n"); + return NULL; + } + + memset(skb->data, 0, sizeof(struct rtllib_hdr_3addr)); + + skb_reserve(skb, ieee->tx_headroom); + + BAReq = (struct rtllib_hdr_3addr *)skb_put(skb, + sizeof(struct rtllib_hdr_3addr)); + + memcpy(BAReq->addr1, Dst, ETH_ALEN); + memcpy(BAReq->addr2, ieee->dev->dev_addr, ETH_ALEN); + + memcpy(BAReq->addr3, ieee->current_network.bssid, ETH_ALEN); + BAReq->frame_ctl = cpu_to_le16(RTLLIB_STYPE_MANAGE_ACT); + + tag = (u8 *)skb_put(skb, 9); + *tag++ = ACT_CAT_BA; + *tag++ = type; + *tag++ = pBA->DialogToken; + + if (ACT_ADDBARSP == type) { + RT_TRACE(COMP_DBG, "====>to send ADDBARSP\n"); + + put_unaligned_le16(StatusCode, tag); + tag += 2; + } + + put_unaligned_le16(pBA->BaParamSet.shortData, tag); + tag += 2; + + put_unaligned_le16(pBA->BaTimeoutValue, tag); + tag += 2; + + if (ACT_ADDBAREQ == type) { + memcpy(tag, (u8 *)&(pBA->BaStartSeqCtrl), 2); + tag += 2; + } + + RTLLIB_DEBUG_DATA(RTLLIB_DL_DATA|RTLLIB_DL_BA, skb->data, skb->len); + return skb; +} + +static struct sk_buff *rtllib_DELBA(struct rtllib_device *ieee, u8 *dst, + struct ba_record *pBA, + enum tr_select TxRxSelect, u16 ReasonCode) +{ + union delba_param_set DelbaParamSet; + struct sk_buff *skb = NULL; + struct rtllib_hdr_3addr *Delba = NULL; + u8 *tag = NULL; + u16 len = 6 + ieee->tx_headroom; + + if (net_ratelimit()) + RTLLIB_DEBUG(RTLLIB_DL_TRACE | RTLLIB_DL_BA, + "========>%s(), ReasonCode(%d) sentd to: %pM\n", + __func__, ReasonCode, dst); + + memset(&DelbaParamSet, 0, 2); + + DelbaParamSet.field.Initiator = (TxRxSelect == TX_DIR) ? 1 : 0; + DelbaParamSet.field.TID = pBA->BaParamSet.field.TID; + + skb = dev_alloc_skb(len + sizeof(struct rtllib_hdr_3addr)); + if (skb == NULL) { + RTLLIB_DEBUG(RTLLIB_DL_ERR, "can't alloc skb for ADDBA_REQ\n"); + return NULL; + } + + skb_reserve(skb, ieee->tx_headroom); + + Delba = (struct rtllib_hdr_3addr *) skb_put(skb, + sizeof(struct rtllib_hdr_3addr)); + + memcpy(Delba->addr1, dst, ETH_ALEN); + memcpy(Delba->addr2, ieee->dev->dev_addr, ETH_ALEN); + memcpy(Delba->addr3, ieee->current_network.bssid, ETH_ALEN); + Delba->frame_ctl = cpu_to_le16(RTLLIB_STYPE_MANAGE_ACT); + + tag = (u8 *)skb_put(skb, 6); + + *tag++ = ACT_CAT_BA; + *tag++ = ACT_DELBA; + + + put_unaligned_le16(DelbaParamSet.shortData, tag); + tag += 2; + + put_unaligned_le16(ReasonCode, tag); + tag += 2; + + RTLLIB_DEBUG_DATA(RTLLIB_DL_DATA|RTLLIB_DL_BA, skb->data, skb->len); + if (net_ratelimit()) + RTLLIB_DEBUG(RTLLIB_DL_TRACE | RTLLIB_DL_BA, "<=====%s()\n", + __func__); + return skb; +} + +static void rtllib_send_ADDBAReq(struct rtllib_device *ieee, u8 *dst, + struct ba_record *pBA) +{ + struct sk_buff *skb = NULL; + + skb = rtllib_ADDBA(ieee, dst, pBA, 0, ACT_ADDBAREQ); + + if (skb) { + RT_TRACE(COMP_DBG, "====>to send ADDBAREQ!!!!!\n"); + softmac_mgmt_xmit(skb, ieee); + } else { + RTLLIB_DEBUG(RTLLIB_DL_ERR, + "alloc skb error in function %s()\n", __func__); + } +} + +static void rtllib_send_ADDBARsp(struct rtllib_device *ieee, u8 *dst, + struct ba_record *pBA, u16 StatusCode) +{ + struct sk_buff *skb = NULL; + + skb = rtllib_ADDBA(ieee, dst, pBA, StatusCode, ACT_ADDBARSP); + if (skb) + softmac_mgmt_xmit(skb, ieee); + else + RTLLIB_DEBUG(RTLLIB_DL_ERR, + "alloc skb error in function %s()\n", __func__); +} + +static void rtllib_send_DELBA(struct rtllib_device *ieee, u8 *dst, + struct ba_record *pBA, enum tr_select TxRxSelect, + u16 ReasonCode) +{ + struct sk_buff *skb = NULL; + + skb = rtllib_DELBA(ieee, dst, pBA, TxRxSelect, ReasonCode); + if (skb) + softmac_mgmt_xmit(skb, ieee); + else + RTLLIB_DEBUG(RTLLIB_DL_ERR, + "alloc skb error in function %s()\n", __func__); +} + +int rtllib_rx_ADDBAReq(struct rtllib_device *ieee, struct sk_buff *skb) +{ + struct rtllib_hdr_3addr *req = NULL; + u16 rc = 0; + u8 *dst = NULL, *pDialogToken = NULL, *tag = NULL; + struct ba_record *pBA = NULL; + union ba_param_set *pBaParamSet = NULL; + u16 *pBaTimeoutVal = NULL; + union sequence_control *pBaStartSeqCtrl = NULL; + struct rx_ts_record *pTS = NULL; + + if (skb->len < sizeof(struct rtllib_hdr_3addr) + 9) { + RTLLIB_DEBUG(RTLLIB_DL_ERR, + " Invalid skb len in BAREQ(%d / %d)\n", + (int)skb->len, + (int)(sizeof(struct rtllib_hdr_3addr) + 9)); + return -1; + } + + RTLLIB_DEBUG_DATA(RTLLIB_DL_DATA|RTLLIB_DL_BA, skb->data, skb->len); + + req = (struct rtllib_hdr_3addr *) skb->data; + tag = (u8 *)req; + dst = (u8 *)(&req->addr2[0]); + tag += sizeof(struct rtllib_hdr_3addr); + pDialogToken = tag + 2; + pBaParamSet = (union ba_param_set *)(tag + 3); + pBaTimeoutVal = (u16 *)(tag + 5); + pBaStartSeqCtrl = (union sequence_control *)(req + 7); + + RT_TRACE(COMP_DBG, "====>rx ADDBAREQ from : %pM\n", dst); + if (ieee->current_network.qos_data.active == 0 || + (ieee->pHTInfo->bCurrentHTSupport == false) || + (ieee->pHTInfo->IOTAction & HT_IOT_ACT_REJECT_ADDBA_REQ)) { + rc = ADDBA_STATUS_REFUSED; + RTLLIB_DEBUG(RTLLIB_DL_ERR, + "Failed to reply on ADDBA_REQ as some capability is not ready(%d, %d)\n", + ieee->current_network.qos_data.active, + ieee->pHTInfo->bCurrentHTSupport); + goto OnADDBAReq_Fail; + } + if (!GetTs(ieee, (struct ts_common_info **)(&pTS), dst, + (u8)(pBaParamSet->field.TID), RX_DIR, true)) { + rc = ADDBA_STATUS_REFUSED; + RTLLIB_DEBUG(RTLLIB_DL_ERR, "can't get TS in %s()\n", __func__); + goto OnADDBAReq_Fail; + } + pBA = &pTS->RxAdmittedBARecord; + + if (pBaParamSet->field.BAPolicy == BA_POLICY_DELAYED) { + rc = ADDBA_STATUS_INVALID_PARAM; + RTLLIB_DEBUG(RTLLIB_DL_ERR, + "BA Policy is not correct in %s()\n", __func__); + goto OnADDBAReq_Fail; + } + + rtllib_FlushRxTsPendingPkts(ieee, pTS); + + DeActivateBAEntry(ieee, pBA); + pBA->DialogToken = *pDialogToken; + pBA->BaParamSet = *pBaParamSet; + pBA->BaTimeoutValue = *pBaTimeoutVal; + pBA->BaStartSeqCtrl = *pBaStartSeqCtrl; + + if (ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev) || + (ieee->pHTInfo->IOTAction & HT_IOT_ACT_ALLOW_PEER_AGG_ONE_PKT)) + pBA->BaParamSet.field.BufferSize = 1; + else + pBA->BaParamSet.field.BufferSize = 32; + + ActivateBAEntry(ieee, pBA, 0); + rtllib_send_ADDBARsp(ieee, dst, pBA, ADDBA_STATUS_SUCCESS); + + return 0; + +OnADDBAReq_Fail: + { + struct ba_record BA; + + BA.BaParamSet = *pBaParamSet; + BA.BaTimeoutValue = *pBaTimeoutVal; + BA.DialogToken = *pDialogToken; + BA.BaParamSet.field.BAPolicy = BA_POLICY_IMMEDIATE; + rtllib_send_ADDBARsp(ieee, dst, &BA, rc); + return 0; + } +} + +int rtllib_rx_ADDBARsp(struct rtllib_device *ieee, struct sk_buff *skb) +{ + struct rtllib_hdr_3addr *rsp = NULL; + struct ba_record *pPendingBA, *pAdmittedBA; + struct tx_ts_record *pTS = NULL; + u8 *dst = NULL, *pDialogToken = NULL, *tag = NULL; + u16 *pStatusCode = NULL, *pBaTimeoutVal = NULL; + union ba_param_set *pBaParamSet = NULL; + u16 ReasonCode; + + if (skb->len < sizeof(struct rtllib_hdr_3addr) + 9) { + RTLLIB_DEBUG(RTLLIB_DL_ERR, + "Invalid skb len in BARSP(%d / %d)\n", + (int)skb->len, + (int)(sizeof(struct rtllib_hdr_3addr) + 9)); + return -1; + } + rsp = (struct rtllib_hdr_3addr *)skb->data; + tag = (u8 *)rsp; + dst = (u8 *)(&rsp->addr2[0]); + tag += sizeof(struct rtllib_hdr_3addr); + pDialogToken = tag + 2; + pStatusCode = (u16 *)(tag + 3); + pBaParamSet = (union ba_param_set *)(tag + 5); + pBaTimeoutVal = (u16 *)(tag + 7); + + RT_TRACE(COMP_DBG, "====>rx ADDBARSP from : %pM\n", dst); + if (ieee->current_network.qos_data.active == 0 || + ieee->pHTInfo->bCurrentHTSupport == false || + ieee->pHTInfo->bCurrentAMPDUEnable == false) { + RTLLIB_DEBUG(RTLLIB_DL_ERR, + "reject to ADDBA_RSP as some capability is not ready(%d, %d, %d)\n", + ieee->current_network.qos_data.active, + ieee->pHTInfo->bCurrentHTSupport, + ieee->pHTInfo->bCurrentAMPDUEnable); + ReasonCode = DELBA_REASON_UNKNOWN_BA; + goto OnADDBARsp_Reject; + } + + + if (!GetTs(ieee, (struct ts_common_info **)(&pTS), dst, + (u8)(pBaParamSet->field.TID), TX_DIR, false)) { + RTLLIB_DEBUG(RTLLIB_DL_ERR, "can't get TS in %s()\n", __func__); + ReasonCode = DELBA_REASON_UNKNOWN_BA; + goto OnADDBARsp_Reject; + } + + pTS->bAddBaReqInProgress = false; + pPendingBA = &pTS->TxPendingBARecord; + pAdmittedBA = &pTS->TxAdmittedBARecord; + + + if (pAdmittedBA->bValid == true) { + RTLLIB_DEBUG(RTLLIB_DL_BA, + "OnADDBARsp(): Recv ADDBA Rsp. Drop because already admit it!\n"); + return -1; + } else if ((pPendingBA->bValid == false) || + (*pDialogToken != pPendingBA->DialogToken)) { + RTLLIB_DEBUG(RTLLIB_DL_ERR, + "OnADDBARsp(): Recv ADDBA Rsp. BA invalid, DELBA!\n"); + ReasonCode = DELBA_REASON_UNKNOWN_BA; + goto OnADDBARsp_Reject; + } else { + RTLLIB_DEBUG(RTLLIB_DL_BA, + "OnADDBARsp(): Recv ADDBA Rsp. BA is admitted! Status code:%X\n", + *pStatusCode); + DeActivateBAEntry(ieee, pPendingBA); + } + + + if (*pStatusCode == ADDBA_STATUS_SUCCESS) { + if (pBaParamSet->field.BAPolicy == BA_POLICY_DELAYED) { + pTS->bAddBaReqDelayed = true; + DeActivateBAEntry(ieee, pAdmittedBA); + ReasonCode = DELBA_REASON_END_BA; + goto OnADDBARsp_Reject; + } + + + pAdmittedBA->DialogToken = *pDialogToken; + pAdmittedBA->BaTimeoutValue = *pBaTimeoutVal; + pAdmittedBA->BaStartSeqCtrl = pPendingBA->BaStartSeqCtrl; + pAdmittedBA->BaParamSet = *pBaParamSet; + DeActivateBAEntry(ieee, pAdmittedBA); + ActivateBAEntry(ieee, pAdmittedBA, *pBaTimeoutVal); + } else { + pTS->bAddBaReqDelayed = true; + pTS->bDisable_AddBa = true; + ReasonCode = DELBA_REASON_END_BA; + goto OnADDBARsp_Reject; + } + + return 0; + +OnADDBARsp_Reject: + { + struct ba_record BA; + + BA.BaParamSet = *pBaParamSet; + rtllib_send_DELBA(ieee, dst, &BA, TX_DIR, ReasonCode); + return 0; + } +} + +int rtllib_rx_DELBA(struct rtllib_device *ieee, struct sk_buff *skb) +{ + struct rtllib_hdr_3addr *delba = NULL; + union delba_param_set *pDelBaParamSet = NULL; + u16 *pReasonCode = NULL; + u8 *dst = NULL; + + if (skb->len < sizeof(struct rtllib_hdr_3addr) + 6) { + RTLLIB_DEBUG(RTLLIB_DL_ERR, + "Invalid skb len in DELBA(%d / %d)\n", + (int)skb->len, + (int)(sizeof(struct rtllib_hdr_3addr) + 6)); + return -1; + } + + if (ieee->current_network.qos_data.active == 0 || + ieee->pHTInfo->bCurrentHTSupport == false) { + RTLLIB_DEBUG(RTLLIB_DL_ERR, + "received DELBA while QOS or HT is not supported(%d, %d)\n", + ieee->current_network. qos_data.active, + ieee->pHTInfo->bCurrentHTSupport); + return -1; + } + + RTLLIB_DEBUG_DATA(RTLLIB_DL_DATA|RTLLIB_DL_BA, skb->data, skb->len); + delba = (struct rtllib_hdr_3addr *)skb->data; + dst = (u8 *)(&delba->addr2[0]); + delba += sizeof(struct rtllib_hdr_3addr); + pDelBaParamSet = (union delba_param_set *)(delba+2); + pReasonCode = (u16 *)(delba+4); + + if (pDelBaParamSet->field.Initiator == 1) { + struct rx_ts_record *pRxTs; + + if (!GetTs(ieee, (struct ts_common_info **)&pRxTs, dst, + (u8)pDelBaParamSet->field.TID, RX_DIR, false)) { + RTLLIB_DEBUG(RTLLIB_DL_ERR, + "can't get TS for RXTS in %s().dst: %pM TID:%d\n", + __func__, dst, + (u8)pDelBaParamSet->field.TID); + return -1; + } + + RxTsDeleteBA(ieee, pRxTs); + } else { + struct tx_ts_record *pTxTs; + + if (!GetTs(ieee, (struct ts_common_info **)&pTxTs, dst, + (u8)pDelBaParamSet->field.TID, TX_DIR, false)) { + RTLLIB_DEBUG(RTLLIB_DL_ERR, + "can't get TS for TXTS in %s()\n", + __func__); + return -1; + } + + pTxTs->bUsingBa = false; + pTxTs->bAddBaReqInProgress = false; + pTxTs->bAddBaReqDelayed = false; + del_timer_sync(&pTxTs->TsAddBaTimer); + TxTsDeleteBA(ieee, pTxTs); + } + return 0; +} + +void TsInitAddBA(struct rtllib_device *ieee, struct tx_ts_record *pTS, + u8 Policy, u8 bOverwritePending) +{ + struct ba_record *pBA = &pTS->TxPendingBARecord; + + if (pBA->bValid == true && bOverwritePending == false) + return; + + DeActivateBAEntry(ieee, pBA); + + pBA->DialogToken++; + pBA->BaParamSet.field.AMSDU_Support = 0; + pBA->BaParamSet.field.BAPolicy = Policy; + pBA->BaParamSet.field.TID = + pTS->TsCommonInfo.TSpec.f.TSInfo.field.ucTSID; + pBA->BaParamSet.field.BufferSize = 32; + pBA->BaTimeoutValue = 0; + pBA->BaStartSeqCtrl.field.SeqNum = (pTS->TxCurSeq + 3) % 4096; + + ActivateBAEntry(ieee, pBA, BA_SETUP_TIMEOUT); + + rtllib_send_ADDBAReq(ieee, pTS->TsCommonInfo.Addr, pBA); +} + +void TsInitDelBA(struct rtllib_device *ieee, + struct ts_common_info *pTsCommonInfo, + enum tr_select TxRxSelect) +{ + if (TxRxSelect == TX_DIR) { + struct tx_ts_record *pTxTs = + (struct tx_ts_record *)pTsCommonInfo; + + if (TxTsDeleteBA(ieee, pTxTs)) + rtllib_send_DELBA(ieee, pTsCommonInfo->Addr, + (pTxTs->TxAdmittedBARecord.bValid) ? + (&pTxTs->TxAdmittedBARecord) : + (&pTxTs->TxPendingBARecord), + TxRxSelect, DELBA_REASON_END_BA); + } else if (TxRxSelect == RX_DIR) { + struct rx_ts_record *pRxTs = + (struct rx_ts_record *)pTsCommonInfo; + if (RxTsDeleteBA(ieee, pRxTs)) + rtllib_send_DELBA(ieee, pTsCommonInfo->Addr, + &pRxTs->RxAdmittedBARecord, + TxRxSelect, DELBA_REASON_END_BA); + } +} + +void BaSetupTimeOut(unsigned long data) +{ + struct tx_ts_record *pTxTs = (struct tx_ts_record *)data; + + pTxTs->bAddBaReqInProgress = false; + pTxTs->bAddBaReqDelayed = true; + pTxTs->TxPendingBARecord.bValid = false; +} + +void TxBaInactTimeout(unsigned long data) +{ + struct tx_ts_record *pTxTs = (struct tx_ts_record *)data; + struct rtllib_device *ieee = container_of(pTxTs, struct rtllib_device, + TxTsRecord[pTxTs->num]); + TxTsDeleteBA(ieee, pTxTs); + rtllib_send_DELBA(ieee, pTxTs->TsCommonInfo.Addr, + &pTxTs->TxAdmittedBARecord, TX_DIR, + DELBA_REASON_TIMEOUT); +} + +void RxBaInactTimeout(unsigned long data) +{ + struct rx_ts_record *pRxTs = (struct rx_ts_record *)data; + struct rtllib_device *ieee = container_of(pRxTs, struct rtllib_device, + RxTsRecord[pRxTs->num]); + + RxTsDeleteBA(ieee, pRxTs); + rtllib_send_DELBA(ieee, pRxTs->TsCommonInfo.Addr, + &pRxTs->RxAdmittedBARecord, RX_DIR, + DELBA_REASON_TIMEOUT); +} diff --git a/kernel/drivers/staging/rtl8192e/rtl819x_HT.h b/kernel/drivers/staging/rtl8192e/rtl819x_HT.h new file mode 100644 index 000000000..f7076d7dd --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl819x_HT.h @@ -0,0 +1,428 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ +#ifndef _RTL819XU_HTTYPE_H_ +#define _RTL819XU_HTTYPE_H_ + + +#define HT_OPMODE_NO_PROTECT 0 +#define HT_OPMODE_OPTIONAL 1 +#define HT_OPMODE_40MHZ_PROTECT 2 +#define HT_OPMODE_MIXED 3 + +#define MIMO_PS_STATIC 0 +#define MIMO_PS_DYNAMIC 1 +#define MIMO_PS_NOLIMIT 3 + + + +#define sHTCLng 4 + + +#define HT_SUPPORTED_MCS_1SS_BITMAP 0x000000ff +#define HT_SUPPORTED_MCS_2SS_BITMAP 0x0000ff00 +#define HT_SUPPORTED_MCS_1SS_2SS_BITMAP \ + (HT_MCS_1SS_BITMAP | HT_MCS_1SS_2SS_BITMAP) + +enum ht_mcs_rate { + HT_MCS0 = 0x00000001, + HT_MCS1 = 0x00000002, + HT_MCS2 = 0x00000004, + HT_MCS3 = 0x00000008, + HT_MCS4 = 0x00000010, + HT_MCS5 = 0x00000020, + HT_MCS6 = 0x00000040, + HT_MCS7 = 0x00000080, + HT_MCS8 = 0x00000100, + HT_MCS9 = 0x00000200, + HT_MCS10 = 0x00000400, + HT_MCS11 = 0x00000800, + HT_MCS12 = 0x00001000, + HT_MCS13 = 0x00002000, + HT_MCS14 = 0x00004000, + HT_MCS15 = 0x00008000, +}; + +enum ht_channel_width { + HT_CHANNEL_WIDTH_20 = 0, + HT_CHANNEL_WIDTH_20_40 = 1, +}; + +enum ht_extchnl_offset { + HT_EXTCHNL_OFFSET_NO_EXT = 0, + HT_EXTCHNL_OFFSET_UPPER = 1, + HT_EXTCHNL_OFFSET_NO_DEF = 2, + HT_EXTCHNL_OFFSET_LOWER = 3, +}; + +enum chnl_op { + CHNLOP_NONE = 0, + CHNLOP_SCAN = 1, + CHNLOP_SWBW = 2, + CHNLOP_SWCHNL = 3, +}; + +enum ht_action { + ACT_RECOMMAND_WIDTH = 0, + ACT_MIMO_PWR_SAVE = 1, + ACT_PSMP = 2, + ACT_SET_PCO_PHASE = 3, + ACT_MIMO_CHL_MEASURE = 4, + ACT_RECIPROCITY_CORRECT = 5, + ACT_MIMO_CSI_MATRICS = 6, + ACT_MIMO_NOCOMPR_STEER = 7, + ACT_MIMO_COMPR_STEER = 8, + ACT_ANTENNA_SELECT = 9, +}; + + +enum ht_bw40_sc { + SC_MODE_DUPLICATE = 0, + SC_MODE_LOWER = 1, + SC_MODE_UPPER = 2, + SC_MODE_FULL40MHZ = 3, +}; + +struct ht_capab_ele { + + u8 AdvCoding:1; + u8 ChlWidth:1; + u8 MimoPwrSave:2; + u8 GreenField:1; + u8 ShortGI20Mhz:1; + u8 ShortGI40Mhz:1; + u8 TxSTBC:1; + u8 RxSTBC:2; + u8 DelayBA:1; + u8 MaxAMSDUSize:1; + u8 DssCCk:1; + u8 PSMP:1; + u8 Rsvd1:1; + u8 LSigTxopProtect:1; + + u8 MaxRxAMPDUFactor:2; + u8 MPDUDensity:3; + u8 Rsvd2:3; + + u8 MCS[16]; + + + u16 ExtHTCapInfo; + + u8 TxBFCap[4]; + + u8 ASCap; + +} __packed; + + +struct ht_info_ele { + u8 ControlChl; + + u8 ExtChlOffset:2; + u8 RecommemdedTxWidth:1; + u8 RIFS:1; + u8 PSMPAccessOnly:1; + u8 SrvIntGranularity:3; + + u8 OptMode:2; + u8 NonGFDevPresent:1; + u8 Revd1:5; + u8 Revd2:8; + + u8 Rsvd3:6; + u8 DualBeacon:1; + u8 DualCTSProtect:1; + + u8 SecondaryBeacon:1; + u8 LSigTxopProtectFull:1; + u8 PcoActive:1; + u8 PcoPhase:1; + u8 Rsvd4:4; + + u8 BasicMSC[16]; +} __packed; + +struct mimops_ctrl { + u8 MimoPsEnable:1; + u8 MimoPsMode:1; + u8 Reserved:6; +}; + +enum ht_spec_ver { + HT_SPEC_VER_IEEE = 0, + HT_SPEC_VER_EWC = 1, +}; + +enum ht_aggre_mode { + HT_AGG_AUTO = 0, + HT_AGG_FORCE_ENABLE = 1, + HT_AGG_FORCE_DISABLE = 2, +}; + + +struct rt_hi_throughput { + u8 bEnableHT; + u8 bCurrentHTSupport; + + u8 bRegBW40MHz; + u8 bCurBW40MHz; + + u8 bRegShortGI40MHz; + u8 bCurShortGI40MHz; + + u8 bRegShortGI20MHz; + u8 bCurShortGI20MHz; + + u8 bRegSuppCCK; + u8 bCurSuppCCK; + + enum ht_spec_ver ePeerHTSpecVer; + + + struct ht_capab_ele SelfHTCap; + struct ht_info_ele SelfHTInfo; + + u8 PeerHTCapBuf[32]; + u8 PeerHTInfoBuf[32]; + + + u8 bAMSDU_Support; + u16 nAMSDU_MaxSize; + u8 bCurrent_AMSDU_Support; + u16 nCurrent_AMSDU_MaxSize; + + u8 bAMPDUEnable; + u8 bCurrentAMPDUEnable; + u8 AMPDU_Factor; + u8 CurrentAMPDUFactor; + u8 MPDU_Density; + u8 CurrentMPDUDensity; + + enum ht_aggre_mode ForcedAMPDUMode; + u8 ForcedAMPDUFactor; + u8 ForcedMPDUDensity; + + enum ht_aggre_mode ForcedAMSDUMode; + u16 ForcedAMSDUMaxSize; + + u8 bForcedShortGI; + + u8 CurrentOpMode; + + u8 SelfMimoPs; + u8 PeerMimoPs; + + enum ht_extchnl_offset CurSTAExtChnlOffset; + u8 bCurTxBW40MHz; + u8 PeerBandwidth; + + u8 bSwBwInProgress; + enum chnl_op ChnlOp; + u8 SwBwStep; + + u8 bRegRT2RTAggregation; + u8 RT2RT_HT_Mode; + u8 bCurrentRT2RTAggregation; + u8 bCurrentRT2RTLongSlotTime; + u8 szRT2RTAggBuffer[10]; + + u8 bRegRxReorderEnable; + u8 bCurRxReorderEnable; + u8 RxReorderWinSize; + u8 RxReorderPendingTime; + u16 RxReorderDropCounter; + + u8 bIsPeerBcm; + + u8 IOTPeer; + u32 IOTAction; + u8 IOTRaFunc; + + u8 bWAIotBroadcom; + u8 WAIotTH; + + u8 bAcceptAddbaReq; +} __packed; + + + +struct rt_htinfo_sta_entry { + u8 bEnableHT; + + u8 bSupportCck; + + u16 AMSDU_MaxSize; + + u8 AMPDU_Factor; + u8 MPDU_Density; + + u8 HTHighestOperaRate; + + u8 bBw40MHz; + + u8 bCurTxBW40MHz; + + u8 bCurShortGI20MHz; + + u8 bCurShortGI40MHz; + + u8 MimoPs; + + u8 McsRateSet[16]; + + u8 bCurRxReorderEnable; + + u16 nAMSDU_MaxSize; + +}; + + + + + + +struct bss_ht { + + u8 bdSupportHT; + + u8 bdHTCapBuf[32]; + u16 bdHTCapLen; + u8 bdHTInfoBuf[32]; + u16 bdHTInfoLen; + + enum ht_spec_ver bdHTSpecVer; + enum ht_channel_width bdBandWidth; + + u8 bdRT2RTAggregation; + u8 bdRT2RTLongSlotTime; + u8 RT2RT_HT_Mode; + u8 bdHT1R; +}; + +struct mimo_rssi { + u32 EnableAntenna; + u32 AntennaA; + u32 AntennaB; + u32 AntennaC; + u32 AntennaD; + u32 Average; +}; + +struct mimo_evm { + u32 EVM1; + u32 EVM2; +}; + +struct false_alarm_stats { + u32 Cnt_Parity_Fail; + u32 Cnt_Rate_Illegal; + u32 Cnt_Crc8_fail; + u32 Cnt_Mcs_fail; + u32 Cnt_Ofdm_fail; + u32 Cnt_Cck_fail; + u32 Cnt_all; +}; + + +extern u8 MCS_FILTER_ALL[16]; +extern u8 MCS_FILTER_1SS[16]; + +#define RATE_ADPT_1SS_MASK 0xFF +#define RATE_ADPT_2SS_MASK 0xF0 +#define RATE_ADPT_MCS32_MASK 0x01 + +#define IS_11N_MCS_RATE(rate) (rate&0x80) + +enum ht_aggre_size { + HT_AGG_SIZE_8K = 0, + HT_AGG_SIZE_16K = 1, + HT_AGG_SIZE_32K = 2, + HT_AGG_SIZE_64K = 3, +}; + +enum ht_iot_peer { + HT_IOT_PEER_UNKNOWN = 0, + HT_IOT_PEER_REALTEK = 1, + HT_IOT_PEER_REALTEK_92SE = 2, + HT_IOT_PEER_BROADCOM = 3, + HT_IOT_PEER_RALINK = 4, + HT_IOT_PEER_ATHEROS = 5, + HT_IOT_PEER_CISCO = 6, + HT_IOT_PEER_MARVELL = 7, + HT_IOT_PEER_92U_SOFTAP = 8, + HT_IOT_PEER_SELF_SOFTAP = 9, + HT_IOT_PEER_AIRGO = 10, + HT_IOT_PEER_MAX = 11, +}; + +enum ht_iot_peer_subtype { + HT_IOT_PEER_ATHEROS_DIR635 = 0, +}; + +enum ht_iot_action { + HT_IOT_ACT_TX_USE_AMSDU_4K = 0x00000001, + HT_IOT_ACT_TX_USE_AMSDU_8K = 0x00000002, + HT_IOT_ACT_DISABLE_MCS14 = 0x00000004, + HT_IOT_ACT_DISABLE_MCS15 = 0x00000008, + HT_IOT_ACT_DISABLE_ALL_2SS = 0x00000010, + HT_IOT_ACT_DISABLE_EDCA_TURBO = 0x00000020, + HT_IOT_ACT_MGNT_USE_CCK_6M = 0x00000040, + HT_IOT_ACT_CDD_FSYNC = 0x00000080, + HT_IOT_ACT_PURE_N_MODE = 0x00000100, + HT_IOT_ACT_FORCED_CTS2SELF = 0x00000200, + HT_IOT_ACT_FORCED_RTS = 0x00000400, + HT_IOT_ACT_AMSDU_ENABLE = 0x00000800, + HT_IOT_ACT_REJECT_ADDBA_REQ = 0x00001000, + HT_IOT_ACT_ALLOW_PEER_AGG_ONE_PKT = 0x00002000, + HT_IOT_ACT_EDCA_BIAS_ON_RX = 0x00004000, + + HT_IOT_ACT_HYBRID_AGGREGATION = 0x00010000, + HT_IOT_ACT_DISABLE_SHORT_GI = 0x00020000, + HT_IOT_ACT_DISABLE_HIGH_POWER = 0x00040000, + HT_IOT_ACT_DISABLE_TX_40_MHZ = 0x00080000, + HT_IOT_ACT_TX_NO_AGGREGATION = 0x00100000, + HT_IOT_ACT_DISABLE_TX_2SS = 0x00200000, + + HT_IOT_ACT_MID_HIGHPOWER = 0x00400000, + HT_IOT_ACT_NULL_DATA_POWER_SAVING = 0x00800000, + + HT_IOT_ACT_DISABLE_CCK_RATE = 0x01000000, + HT_IOT_ACT_FORCED_ENABLE_BE_TXOP = 0x02000000, + HT_IOT_ACT_WA_IOT_Broadcom = 0x04000000, + + HT_IOT_ACT_DISABLE_RX_40MHZ_SHORT_GI = 0x08000000, + +}; + +enum ht_iot_rafunc { + HT_IOT_RAFUNC_DISABLE_ALL = 0x00, + HT_IOT_RAFUNC_PEER_1R = 0x01, + HT_IOT_RAFUNC_TX_AMSDU = 0x02, +}; + +enum rt_ht_capability { + RT_HT_CAP_USE_TURBO_AGGR = 0x01, + RT_HT_CAP_USE_LONG_PREAMBLE = 0x02, + RT_HT_CAP_USE_AMPDU = 0x04, + RT_HT_CAP_USE_WOW = 0x8, + RT_HT_CAP_USE_SOFTAP = 0x10, + RT_HT_CAP_USE_92SE = 0x20, +}; + +#endif diff --git a/kernel/drivers/staging/rtl8192e/rtl819x_HTProc.c b/kernel/drivers/staging/rtl8192e/rtl819x_HTProc.c new file mode 100644 index 000000000..7f103114d --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl819x_HTProc.c @@ -0,0 +1,919 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ +#include "rtllib.h" +#include "rtl819x_HT.h" +u8 MCS_FILTER_ALL[16] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +u8 MCS_FILTER_1SS[16] = { + 0xff, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} +; + +u16 MCS_DATA_RATE[2][2][77] = { + {{13, 26, 39, 52, 78, 104, 117, 130, 26, 52, 78, 104, 156, 208, 234, + 260, 39, 78, 117, 234, 312, 351, 390, 52, 104, 156, 208, 312, 416, + 468, 520, 0, 78, 104, 130, 117, 156, 195, 104, 130, 130, 156, 182, + 182, 208, 156, 195, 195, 234, 273, 273, 312, 130, 156, 181, 156, + 181, 208, 234, 208, 234, 260, 260, 286, 195, 234, 273, 234, 273, + 312, 351, 312, 351, 390, 390, 429}, + {14, 29, 43, 58, 87, 116, 130, 144, 29, 58, 87, 116, 173, 231, 260, 289, + 43, 87, 130, 173, 260, 347, 390, 433, 58, 116, 173, 231, 347, 462, 520, + 578, 0, 87, 116, 144, 130, 173, 217, 116, 144, 144, 173, 202, 202, 231, + 173, 217, 217, 260, 303, 303, 347, 144, 173, 202, 173, 202, 231, 260, + 231, 260, 289, 289, 318, 217, 260, 303, 260, 303, 347, 390, 347, 390, + 433, 433, 477} }, + {{27, 54, 81, 108, 162, 216, 243, 270, 54, 108, 162, 216, 324, 432, 486, + 540, 81, 162, 243, 324, 486, 648, 729, 810, 108, 216, 324, 432, 648, + 864, 972, 1080, 12, 162, 216, 270, 243, 324, 405, 216, 270, 270, 324, + 378, 378, 432, 324, 405, 405, 486, 567, 567, 648, 270, 324, 378, 324, + 378, 432, 486, 432, 486, 540, 540, 594, 405, 486, 567, 486, 567, 648, + 729, 648, 729, 810, 810, 891}, + {30, 60, 90, 120, 180, 240, 270, 300, 60, 120, 180, 240, 360, 480, 540, + 600, 90, 180, 270, 360, 540, 720, 810, 900, 120, 240, 360, 480, 720, + 960, 1080, 1200, 13, 180, 240, 300, 270, 360, 450, 240, 300, 300, 360, + 420, 420, 480, 360, 450, 450, 540, 630, 630, 720, 300, 360, 420, 360, + 420, 480, 540, 480, 540, 600, 600, 660, 450, 540, 630, 540, 630, 720, + 810, 720, 810, 900, 900, 990} } +}; + +static u8 UNKNOWN_BORADCOM[3] = {0x00, 0x14, 0xbf}; + +static u8 LINKSYSWRT330_LINKSYSWRT300_BROADCOM[3] = {0x00, 0x1a, 0x70}; + +static u8 LINKSYSWRT350_LINKSYSWRT150_BROADCOM[3] = {0x00, 0x1d, 0x7e}; + +static u8 BELKINF5D8233V1_RALINK[3] = {0x00, 0x17, 0x3f}; + +static u8 BELKINF5D82334V3_RALINK[3] = {0x00, 0x1c, 0xdf}; + +static u8 PCI_RALINK[3] = {0x00, 0x90, 0xcc}; + +static u8 EDIMAX_RALINK[3] = {0x00, 0x0e, 0x2e}; + +static u8 AIRLINK_RALINK[3] = {0x00, 0x18, 0x02}; + +static u8 DLINK_ATHEROS_1[3] = {0x00, 0x1c, 0xf0}; + +static u8 DLINK_ATHEROS_2[3] = {0x00, 0x21, 0x91}; + +static u8 CISCO_BROADCOM[3] = {0x00, 0x17, 0x94}; + +static u8 LINKSYS_MARVELL_4400N[3] = {0x00, 0x14, 0xa4}; + +void HTUpdateDefaultSetting(struct rtllib_device *ieee) +{ + struct rt_hi_throughput *pHTInfo = ieee->pHTInfo; + + pHTInfo->bAcceptAddbaReq = 1; + + pHTInfo->bRegShortGI20MHz = 1; + pHTInfo->bRegShortGI40MHz = 1; + + pHTInfo->bRegBW40MHz = 1; + + if (pHTInfo->bRegBW40MHz) + pHTInfo->bRegSuppCCK = 1; + else + pHTInfo->bRegSuppCCK = true; + + pHTInfo->nAMSDU_MaxSize = 7935UL; + pHTInfo->bAMSDU_Support = 0; + + pHTInfo->bAMPDUEnable = 1; + pHTInfo->AMPDU_Factor = 2; + pHTInfo->MPDU_Density = 0; + + pHTInfo->SelfMimoPs = 3; + if (pHTInfo->SelfMimoPs == 2) + pHTInfo->SelfMimoPs = 3; + ieee->bTxDisableRateFallBack = 0; + ieee->bTxUseDriverAssingedRate = 0; + + ieee->bTxEnableFwCalcDur = 1; + + pHTInfo->bRegRT2RTAggregation = 1; + + pHTInfo->bRegRxReorderEnable = 1; + pHTInfo->RxReorderWinSize = 64; + pHTInfo->RxReorderPendingTime = 30; +} + +u16 HTMcsToDataRate(struct rtllib_device *ieee, u8 nMcsRate) +{ + struct rt_hi_throughput *pHTInfo = ieee->pHTInfo; + + u8 is40MHz = (pHTInfo->bCurBW40MHz) ? 1 : 0; + u8 isShortGI = (pHTInfo->bCurBW40MHz) ? + ((pHTInfo->bCurShortGI40MHz) ? 1 : 0) : + ((pHTInfo->bCurShortGI20MHz) ? 1 : 0); + return MCS_DATA_RATE[is40MHz][isShortGI][(nMcsRate & 0x7f)]; +} + +u16 TxCountToDataRate(struct rtllib_device *ieee, u8 nDataRate) +{ + u16 CCKOFDMRate[12] = {0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, + 0x24, 0x30, 0x48, 0x60, 0x6c}; + u8 is40MHz = 0; + u8 isShortGI = 0; + + if (nDataRate < 12) + return CCKOFDMRate[nDataRate]; + if (nDataRate >= 0x10 && nDataRate <= 0x1f) { + is40MHz = 0; + isShortGI = 0; + } else if (nDataRate >= 0x20 && nDataRate <= 0x2f) { + is40MHz = 1; + isShortGI = 0; + } else if (nDataRate >= 0x30 && nDataRate <= 0x3f) { + is40MHz = 0; + isShortGI = 1; + } else if (nDataRate >= 0x40 && nDataRate <= 0x4f) { + is40MHz = 1; + isShortGI = 1; + } + return MCS_DATA_RATE[is40MHz][isShortGI][nDataRate&0xf]; +} + +bool IsHTHalfNmodeAPs(struct rtllib_device *ieee) +{ + bool retValue = false; + struct rtllib_network *net = &ieee->current_network; + + if ((memcmp(net->bssid, BELKINF5D8233V1_RALINK, 3) == 0) || + (memcmp(net->bssid, BELKINF5D82334V3_RALINK, 3) == 0) || + (memcmp(net->bssid, PCI_RALINK, 3) == 0) || + (memcmp(net->bssid, EDIMAX_RALINK, 3) == 0) || + (memcmp(net->bssid, AIRLINK_RALINK, 3) == 0) || + (net->ralink_cap_exist)) + retValue = true; + else if (!memcmp(net->bssid, UNKNOWN_BORADCOM, 3) || + !memcmp(net->bssid, LINKSYSWRT330_LINKSYSWRT300_BROADCOM, 3) || + !memcmp(net->bssid, LINKSYSWRT350_LINKSYSWRT150_BROADCOM, 3) || + (net->broadcom_cap_exist)) + retValue = true; + else if (net->bssht.bdRT2RTAggregation) + retValue = true; + else + retValue = false; + + return retValue; +} + +static void HTIOTPeerDetermine(struct rtllib_device *ieee) +{ + struct rt_hi_throughput *pHTInfo = ieee->pHTInfo; + struct rtllib_network *net = &ieee->current_network; + + if (net->bssht.bdRT2RTAggregation) { + pHTInfo->IOTPeer = HT_IOT_PEER_REALTEK; + if (net->bssht.RT2RT_HT_Mode & RT_HT_CAP_USE_92SE) + pHTInfo->IOTPeer = HT_IOT_PEER_REALTEK_92SE; + if (net->bssht.RT2RT_HT_Mode & RT_HT_CAP_USE_SOFTAP) + pHTInfo->IOTPeer = HT_IOT_PEER_92U_SOFTAP; + } else if (net->broadcom_cap_exist) + pHTInfo->IOTPeer = HT_IOT_PEER_BROADCOM; + else if (!memcmp(net->bssid, UNKNOWN_BORADCOM, 3) || + !memcmp(net->bssid, LINKSYSWRT330_LINKSYSWRT300_BROADCOM, 3) || + !memcmp(net->bssid, LINKSYSWRT350_LINKSYSWRT150_BROADCOM, 3)) + pHTInfo->IOTPeer = HT_IOT_PEER_BROADCOM; + else if ((memcmp(net->bssid, BELKINF5D8233V1_RALINK, 3) == 0) || + (memcmp(net->bssid, BELKINF5D82334V3_RALINK, 3) == 0) || + (memcmp(net->bssid, PCI_RALINK, 3) == 0) || + (memcmp(net->bssid, EDIMAX_RALINK, 3) == 0) || + (memcmp(net->bssid, AIRLINK_RALINK, 3) == 0) || + net->ralink_cap_exist) + pHTInfo->IOTPeer = HT_IOT_PEER_RALINK; + else if ((net->atheros_cap_exist) || + (memcmp(net->bssid, DLINK_ATHEROS_1, 3) == 0) || + (memcmp(net->bssid, DLINK_ATHEROS_2, 3) == 0)) + pHTInfo->IOTPeer = HT_IOT_PEER_ATHEROS; + else if ((memcmp(net->bssid, CISCO_BROADCOM, 3) == 0) || + net->cisco_cap_exist) + pHTInfo->IOTPeer = HT_IOT_PEER_CISCO; + else if ((memcmp(net->bssid, LINKSYS_MARVELL_4400N, 3) == 0) || + net->marvell_cap_exist) + pHTInfo->IOTPeer = HT_IOT_PEER_MARVELL; + else if (net->airgo_cap_exist) + pHTInfo->IOTPeer = HT_IOT_PEER_AIRGO; + else + pHTInfo->IOTPeer = HT_IOT_PEER_UNKNOWN; + + RTLLIB_DEBUG(RTLLIB_DL_IOT, "Joseph debug!! IOTPEER: %x\n", + pHTInfo->IOTPeer); +} + +static u8 HTIOTActIsDisableMCS14(struct rtllib_device *ieee, u8 *PeerMacAddr) +{ + return 0; +} + + +static bool HTIOTActIsDisableMCS15(struct rtllib_device *ieee) +{ + return false; +} + +static bool HTIOTActIsDisableMCSTwoSpatialStream(struct rtllib_device *ieee) +{ + return false; +} + +static u8 HTIOTActIsDisableEDCATurbo(struct rtllib_device *ieee, u8 *PeerMacAddr) +{ + return false; +} + +static u8 HTIOTActIsMgntUseCCK6M(struct rtllib_device *ieee, + struct rtllib_network *network) +{ + u8 retValue = 0; + + + if (ieee->pHTInfo->IOTPeer == HT_IOT_PEER_BROADCOM) + retValue = 1; + + return retValue; +} + +static u8 HTIOTActIsCCDFsync(struct rtllib_device *ieee) +{ + u8 retValue = 0; + + if (ieee->pHTInfo->IOTPeer == HT_IOT_PEER_BROADCOM) + retValue = 1; + return retValue; +} + +static void HTIOTActDetermineRaFunc(struct rtllib_device *ieee, bool bPeerRx2ss) +{ + struct rt_hi_throughput *pHTInfo = ieee->pHTInfo; + + pHTInfo->IOTRaFunc &= HT_IOT_RAFUNC_DISABLE_ALL; + + if (pHTInfo->IOTPeer == HT_IOT_PEER_RALINK && !bPeerRx2ss) + pHTInfo->IOTRaFunc |= HT_IOT_RAFUNC_PEER_1R; + + if (pHTInfo->IOTAction & HT_IOT_ACT_AMSDU_ENABLE) + pHTInfo->IOTRaFunc |= HT_IOT_RAFUNC_TX_AMSDU; + +} + +void HTResetIOTSetting(struct rt_hi_throughput *pHTInfo) +{ + pHTInfo->IOTAction = 0; + pHTInfo->IOTPeer = HT_IOT_PEER_UNKNOWN; + pHTInfo->IOTRaFunc = 0; +} + +void HTConstructCapabilityElement(struct rtllib_device *ieee, u8 *posHTCap, + u8 *len, u8 IsEncrypt, bool bAssoc) +{ + struct rt_hi_throughput *pHT = ieee->pHTInfo; + struct ht_capab_ele *pCapELE = NULL; + + if ((posHTCap == NULL) || (pHT == NULL)) { + RTLLIB_DEBUG(RTLLIB_DL_ERR, + "posHTCap or pHTInfo can't be null in HTConstructCapabilityElement()\n"); + return; + } + memset(posHTCap, 0, *len); + + if ((bAssoc) && (pHT->ePeerHTSpecVer == HT_SPEC_VER_EWC)) { + u8 EWC11NHTCap[] = {0x00, 0x90, 0x4c, 0x33}; + + memcpy(posHTCap, EWC11NHTCap, sizeof(EWC11NHTCap)); + pCapELE = (struct ht_capab_ele *)&(posHTCap[4]); + *len = 30 + 2; + } else { + pCapELE = (struct ht_capab_ele *)posHTCap; + *len = 26 + 2; + } + + pCapELE->AdvCoding = 0; + if (ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev)) + pCapELE->ChlWidth = 0; + else + pCapELE->ChlWidth = (pHT->bRegBW40MHz ? 1 : 0); + + pCapELE->MimoPwrSave = pHT->SelfMimoPs; + pCapELE->GreenField = 0; + pCapELE->ShortGI20Mhz = 1; + pCapELE->ShortGI40Mhz = 1; + + pCapELE->TxSTBC = 1; + pCapELE->RxSTBC = 0; + pCapELE->DelayBA = 0; + pCapELE->MaxAMSDUSize = (MAX_RECEIVE_BUFFER_SIZE >= 7935) ? 1 : 0; + pCapELE->DssCCk = ((pHT->bRegBW40MHz) ? (pHT->bRegSuppCCK ? 1 : 0) : 0); + pCapELE->PSMP = 0; + pCapELE->LSigTxopProtect = 0; + + + RTLLIB_DEBUG(RTLLIB_DL_HT, + "TX HT cap/info ele BW=%d MaxAMSDUSize:%d DssCCk:%d\n", + pCapELE->ChlWidth, pCapELE->MaxAMSDUSize, pCapELE->DssCCk); + + if (IsEncrypt) { + pCapELE->MPDUDensity = 7; + pCapELE->MaxRxAMPDUFactor = 2; + } else { + pCapELE->MaxRxAMPDUFactor = 3; + pCapELE->MPDUDensity = 0; + } + + memcpy(pCapELE->MCS, ieee->Regdot11HTOperationalRateSet, 16); + memset(&pCapELE->ExtHTCapInfo, 0, 2); + memset(pCapELE->TxBFCap, 0, 4); + + pCapELE->ASCap = 0; + + if (bAssoc) { + if (pHT->IOTAction & HT_IOT_ACT_DISABLE_MCS15) + pCapELE->MCS[1] &= 0x7f; + + if (pHT->IOTAction & HT_IOT_ACT_DISABLE_MCS14) + pCapELE->MCS[1] &= 0xbf; + + if (pHT->IOTAction & HT_IOT_ACT_DISABLE_ALL_2SS) + pCapELE->MCS[1] &= 0x00; + + if (pHT->IOTAction & HT_IOT_ACT_DISABLE_RX_40MHZ_SHORT_GI) + pCapELE->ShortGI40Mhz = 0; + + if (ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev)) { + pCapELE->ChlWidth = 0; + pCapELE->MCS[1] = 0; + } + } +} + +void HTConstructInfoElement(struct rtllib_device *ieee, u8 *posHTInfo, + u8 *len, u8 IsEncrypt) +{ + struct rt_hi_throughput *pHT = ieee->pHTInfo; + struct ht_info_ele *pHTInfoEle = (struct ht_info_ele *)posHTInfo; + + if ((posHTInfo == NULL) || (pHTInfoEle == NULL)) { + RTLLIB_DEBUG(RTLLIB_DL_ERR, + "posHTInfo or pHTInfoEle can't be null in HTConstructInfoElement()\n"); + return; + } + + memset(posHTInfo, 0, *len); + if ((ieee->iw_mode == IW_MODE_ADHOC) || + (ieee->iw_mode == IW_MODE_MASTER)) { + pHTInfoEle->ControlChl = ieee->current_network.channel; + pHTInfoEle->ExtChlOffset = ((pHT->bRegBW40MHz == false) ? + HT_EXTCHNL_OFFSET_NO_EXT : + (ieee->current_network.channel <= 6) + ? HT_EXTCHNL_OFFSET_UPPER : + HT_EXTCHNL_OFFSET_LOWER); + pHTInfoEle->RecommemdedTxWidth = pHT->bRegBW40MHz; + pHTInfoEle->RIFS = 0; + pHTInfoEle->PSMPAccessOnly = 0; + pHTInfoEle->SrvIntGranularity = 0; + pHTInfoEle->OptMode = pHT->CurrentOpMode; + pHTInfoEle->NonGFDevPresent = 0; + pHTInfoEle->DualBeacon = 0; + pHTInfoEle->SecondaryBeacon = 0; + pHTInfoEle->LSigTxopProtectFull = 0; + pHTInfoEle->PcoActive = 0; + pHTInfoEle->PcoPhase = 0; + + memset(pHTInfoEle->BasicMSC, 0, 16); + + + *len = 22 + 2; + + } else { + *len = 0; + } +} + +void HTConstructRT2RTAggElement(struct rtllib_device *ieee, u8 *posRT2RTAgg, + u8 *len) +{ + if (posRT2RTAgg == NULL) { + RTLLIB_DEBUG(RTLLIB_DL_ERR, + "posRT2RTAgg can't be null in HTConstructRT2RTAggElement()\n"); + return; + } + memset(posRT2RTAgg, 0, *len); + *posRT2RTAgg++ = 0x00; + *posRT2RTAgg++ = 0xe0; + *posRT2RTAgg++ = 0x4c; + *posRT2RTAgg++ = 0x02; + *posRT2RTAgg++ = 0x01; + + *posRT2RTAgg = 0x30; + + if (ieee->bSupportRemoteWakeUp) + *posRT2RTAgg |= RT_HT_CAP_USE_WOW; + + *len = 6 + 2; +} + +static u8 HT_PickMCSRate(struct rtllib_device *ieee, u8 *pOperateMCS) +{ + u8 i; + + if (pOperateMCS == NULL) { + RTLLIB_DEBUG(RTLLIB_DL_ERR, + "pOperateMCS can't be null in HT_PickMCSRate()\n"); + return false; + } + + switch (ieee->mode) { + case IEEE_A: + case IEEE_B: + case IEEE_G: + for (i = 0; i <= 15; i++) + pOperateMCS[i] = 0; + break; + case IEEE_N_24G: + case IEEE_N_5G: + pOperateMCS[0] &= RATE_ADPT_1SS_MASK; + pOperateMCS[1] &= RATE_ADPT_2SS_MASK; + pOperateMCS[3] &= RATE_ADPT_MCS32_MASK; + break; + default: + break; + + } + + return true; +} + +u8 HTGetHighestMCSRate(struct rtllib_device *ieee, u8 *pMCSRateSet, + u8 *pMCSFilter) +{ + u8 i, j; + u8 bitMap; + u8 mcsRate = 0; + u8 availableMcsRate[16]; + + if (pMCSRateSet == NULL || pMCSFilter == NULL) { + RTLLIB_DEBUG(RTLLIB_DL_ERR, + "pMCSRateSet or pMCSFilter can't be null in HTGetHighestMCSRate()\n"); + return false; + } + for (i = 0; i < 16; i++) + availableMcsRate[i] = pMCSRateSet[i] & pMCSFilter[i]; + + for (i = 0; i < 16; i++) { + if (availableMcsRate[i] != 0) + break; + } + if (i == 16) + return false; + + for (i = 0; i < 16; i++) { + if (availableMcsRate[i] != 0) { + bitMap = availableMcsRate[i]; + for (j = 0; j < 8; j++) { + if ((bitMap%2) != 0) { + if (HTMcsToDataRate(ieee, (8*i+j)) > + HTMcsToDataRate(ieee, mcsRate)) + mcsRate = (8*i+j); + } + bitMap >>= 1; + } + } + } + return mcsRate | 0x80; +} + +u8 HTFilterMCSRate(struct rtllib_device *ieee, u8 *pSupportMCS, u8 *pOperateMCS) +{ + + u8 i; + + for (i = 0; i <= 15; i++) + pOperateMCS[i] = ieee->Regdot11TxHTOperationalRateSet[i] & + pSupportMCS[i]; + + HT_PickMCSRate(ieee, pOperateMCS); + + if (ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev)) + pOperateMCS[1] = 0; + + for (i = 2; i <= 15; i++) + pOperateMCS[i] = 0; + + return true; +} + +void HTSetConnectBwMode(struct rtllib_device *ieee, + enum ht_channel_width Bandwidth, + enum ht_extchnl_offset Offset); + +void HTOnAssocRsp(struct rtllib_device *ieee) +{ + struct rt_hi_throughput *pHTInfo = ieee->pHTInfo; + struct ht_capab_ele *pPeerHTCap = NULL; + struct ht_info_ele *pPeerHTInfo = NULL; + u16 nMaxAMSDUSize = 0; + u8 *pMcsFilter = NULL; + + static u8 EWC11NHTCap[] = {0x00, 0x90, 0x4c, 0x33}; + static u8 EWC11NHTInfo[] = {0x00, 0x90, 0x4c, 0x34}; + + if (pHTInfo->bCurrentHTSupport == false) { + RTLLIB_DEBUG(RTLLIB_DL_ERR, + "<=== HTOnAssocRsp(): HT_DISABLE\n"); + return; + } + RTLLIB_DEBUG(RTLLIB_DL_HT, "===> HTOnAssocRsp_wq(): HT_ENABLE\n"); + + if (!memcmp(pHTInfo->PeerHTCapBuf, EWC11NHTCap, sizeof(EWC11NHTCap))) + pPeerHTCap = (struct ht_capab_ele *)(&pHTInfo->PeerHTCapBuf[4]); + else + pPeerHTCap = (struct ht_capab_ele *)(pHTInfo->PeerHTCapBuf); + + if (!memcmp(pHTInfo->PeerHTInfoBuf, EWC11NHTInfo, sizeof(EWC11NHTInfo))) + pPeerHTInfo = (struct ht_info_ele *) + (&pHTInfo->PeerHTInfoBuf[4]); + else + pPeerHTInfo = (struct ht_info_ele *)(pHTInfo->PeerHTInfoBuf); + + RTLLIB_DEBUG_DATA(RTLLIB_DL_DATA | RTLLIB_DL_HT, pPeerHTCap, + sizeof(struct ht_capab_ele)); + HTSetConnectBwMode(ieee, (enum ht_channel_width)(pPeerHTCap->ChlWidth), + (enum ht_extchnl_offset)(pPeerHTInfo->ExtChlOffset)); + pHTInfo->bCurTxBW40MHz = ((pPeerHTInfo->RecommemdedTxWidth == 1) ? + true : false); + + pHTInfo->bCurShortGI20MHz = ((pHTInfo->bRegShortGI20MHz) ? + ((pPeerHTCap->ShortGI20Mhz == 1) ? + true : false) : false); + pHTInfo->bCurShortGI40MHz = ((pHTInfo->bRegShortGI40MHz) ? + ((pPeerHTCap->ShortGI40Mhz == 1) ? + true : false) : false); + + pHTInfo->bCurSuppCCK = ((pHTInfo->bRegSuppCCK) ? + ((pPeerHTCap->DssCCk == 1) ? true : + false) : false); + + + pHTInfo->bCurrent_AMSDU_Support = pHTInfo->bAMSDU_Support; + + nMaxAMSDUSize = (pPeerHTCap->MaxAMSDUSize == 0) ? 3839 : 7935; + + if (pHTInfo->nAMSDU_MaxSize > nMaxAMSDUSize) + pHTInfo->nCurrent_AMSDU_MaxSize = nMaxAMSDUSize; + else + pHTInfo->nCurrent_AMSDU_MaxSize = pHTInfo->nAMSDU_MaxSize; + + pHTInfo->bCurrentAMPDUEnable = pHTInfo->bAMPDUEnable; + if (ieee->rtllib_ap_sec_type && + (ieee->rtllib_ap_sec_type(ieee)&(SEC_ALG_WEP|SEC_ALG_TKIP))) { + if ((pHTInfo->IOTPeer == HT_IOT_PEER_ATHEROS) || + (pHTInfo->IOTPeer == HT_IOT_PEER_UNKNOWN)) + pHTInfo->bCurrentAMPDUEnable = false; + } + + if (!pHTInfo->bRegRT2RTAggregation) { + if (pHTInfo->AMPDU_Factor > pPeerHTCap->MaxRxAMPDUFactor) + pHTInfo->CurrentAMPDUFactor = + pPeerHTCap->MaxRxAMPDUFactor; + else + pHTInfo->CurrentAMPDUFactor = pHTInfo->AMPDU_Factor; + + } else { + if (ieee->current_network.bssht.bdRT2RTAggregation) { + if (ieee->pairwise_key_type != KEY_TYPE_NA) + pHTInfo->CurrentAMPDUFactor = + pPeerHTCap->MaxRxAMPDUFactor; + else + pHTInfo->CurrentAMPDUFactor = HT_AGG_SIZE_64K; + } else { + if (pPeerHTCap->MaxRxAMPDUFactor < HT_AGG_SIZE_32K) + pHTInfo->CurrentAMPDUFactor = + pPeerHTCap->MaxRxAMPDUFactor; + else + pHTInfo->CurrentAMPDUFactor = HT_AGG_SIZE_32K; + } + } + if (pHTInfo->MPDU_Density > pPeerHTCap->MPDUDensity) + pHTInfo->CurrentMPDUDensity = pHTInfo->MPDU_Density; + else + pHTInfo->CurrentMPDUDensity = pPeerHTCap->MPDUDensity; + if (pHTInfo->IOTAction & HT_IOT_ACT_TX_USE_AMSDU_8K) { + pHTInfo->bCurrentAMPDUEnable = false; + pHTInfo->ForcedAMSDUMode = HT_AGG_FORCE_ENABLE; + pHTInfo->ForcedAMSDUMaxSize = 7935; + } + pHTInfo->bCurRxReorderEnable = pHTInfo->bRegRxReorderEnable; + + if (pPeerHTCap->MCS[0] == 0) + pPeerHTCap->MCS[0] = 0xff; + + HTIOTActDetermineRaFunc(ieee, ((pPeerHTCap->MCS[1]) != 0)); + + HTFilterMCSRate(ieee, pPeerHTCap->MCS, ieee->dot11HTOperationalRateSet); + + pHTInfo->PeerMimoPs = pPeerHTCap->MimoPwrSave; + if (pHTInfo->PeerMimoPs == MIMO_PS_STATIC) + pMcsFilter = MCS_FILTER_1SS; + else + pMcsFilter = MCS_FILTER_ALL; + ieee->HTHighestOperaRate = HTGetHighestMCSRate(ieee, + ieee->dot11HTOperationalRateSet, pMcsFilter); + ieee->HTCurrentOperaRate = ieee->HTHighestOperaRate; + + pHTInfo->CurrentOpMode = pPeerHTInfo->OptMode; +} + +void HTInitializeHTInfo(struct rtllib_device *ieee) +{ + struct rt_hi_throughput *pHTInfo = ieee->pHTInfo; + + RTLLIB_DEBUG(RTLLIB_DL_HT, "===========>%s()\n", __func__); + pHTInfo->bCurrentHTSupport = false; + + pHTInfo->bCurBW40MHz = false; + pHTInfo->bCurTxBW40MHz = false; + + pHTInfo->bCurShortGI20MHz = false; + pHTInfo->bCurShortGI40MHz = false; + pHTInfo->bForcedShortGI = false; + + pHTInfo->bCurSuppCCK = true; + + pHTInfo->bCurrent_AMSDU_Support = false; + pHTInfo->nCurrent_AMSDU_MaxSize = pHTInfo->nAMSDU_MaxSize; + pHTInfo->CurrentMPDUDensity = pHTInfo->MPDU_Density; + pHTInfo->CurrentAMPDUFactor = pHTInfo->AMPDU_Factor; + + memset((void *)(&(pHTInfo->SelfHTCap)), 0, + sizeof(pHTInfo->SelfHTCap)); + memset((void *)(&(pHTInfo->SelfHTInfo)), 0, + sizeof(pHTInfo->SelfHTInfo)); + memset((void *)(&(pHTInfo->PeerHTCapBuf)), 0, + sizeof(pHTInfo->PeerHTCapBuf)); + memset((void *)(&(pHTInfo->PeerHTInfoBuf)), 0, + sizeof(pHTInfo->PeerHTInfoBuf)); + + pHTInfo->bSwBwInProgress = false; + pHTInfo->ChnlOp = CHNLOP_NONE; + + pHTInfo->ePeerHTSpecVer = HT_SPEC_VER_IEEE; + + pHTInfo->bCurrentRT2RTAggregation = false; + pHTInfo->bCurrentRT2RTLongSlotTime = false; + pHTInfo->RT2RT_HT_Mode = (enum rt_ht_capability)0; + + pHTInfo->IOTPeer = 0; + pHTInfo->IOTAction = 0; + pHTInfo->IOTRaFunc = 0; + + { + u8 *RegHTSuppRateSets = &(ieee->RegHTSuppRateSet[0]); + + RegHTSuppRateSets[0] = 0xFF; + RegHTSuppRateSets[1] = 0xFF; + RegHTSuppRateSets[4] = 0x01; + } +} + +void HTInitializeBssDesc(struct bss_ht *pBssHT) +{ + + pBssHT->bdSupportHT = false; + memset(pBssHT->bdHTCapBuf, 0, sizeof(pBssHT->bdHTCapBuf)); + pBssHT->bdHTCapLen = 0; + memset(pBssHT->bdHTInfoBuf, 0, sizeof(pBssHT->bdHTInfoBuf)); + pBssHT->bdHTInfoLen = 0; + + pBssHT->bdHTSpecVer = HT_SPEC_VER_IEEE; + + pBssHT->bdRT2RTAggregation = false; + pBssHT->bdRT2RTLongSlotTime = false; + pBssHT->RT2RT_HT_Mode = (enum rt_ht_capability)0; +} + +void HTResetSelfAndSavePeerSetting(struct rtllib_device *ieee, + struct rtllib_network *pNetwork) +{ + struct rt_hi_throughput *pHTInfo = ieee->pHTInfo; + u8 bIOTAction = 0; + + RTLLIB_DEBUG(RTLLIB_DL_HT, "==============>%s()\n", __func__); + /* unmark bEnableHT flag here is the same reason why unmarked in + * function rtllib_softmac_new_net. WB 2008.09.10 + */ + if (pNetwork->bssht.bdSupportHT) { + pHTInfo->bCurrentHTSupport = true; + pHTInfo->ePeerHTSpecVer = pNetwork->bssht.bdHTSpecVer; + + if (pNetwork->bssht.bdHTCapLen > 0 && + pNetwork->bssht.bdHTCapLen <= sizeof(pHTInfo->PeerHTCapBuf)) + memcpy(pHTInfo->PeerHTCapBuf, + pNetwork->bssht.bdHTCapBuf, + pNetwork->bssht.bdHTCapLen); + + if (pNetwork->bssht.bdHTInfoLen > 0 && + pNetwork->bssht.bdHTInfoLen <= + sizeof(pHTInfo->PeerHTInfoBuf)) + memcpy(pHTInfo->PeerHTInfoBuf, + pNetwork->bssht.bdHTInfoBuf, + pNetwork->bssht.bdHTInfoLen); + + if (pHTInfo->bRegRT2RTAggregation) { + pHTInfo->bCurrentRT2RTAggregation = + pNetwork->bssht.bdRT2RTAggregation; + pHTInfo->bCurrentRT2RTLongSlotTime = + pNetwork->bssht.bdRT2RTLongSlotTime; + pHTInfo->RT2RT_HT_Mode = pNetwork->bssht.RT2RT_HT_Mode; + } else { + pHTInfo->bCurrentRT2RTAggregation = false; + pHTInfo->bCurrentRT2RTLongSlotTime = false; + pHTInfo->RT2RT_HT_Mode = (enum rt_ht_capability)0; + } + + HTIOTPeerDetermine(ieee); + + pHTInfo->IOTAction = 0; + bIOTAction = HTIOTActIsDisableMCS14(ieee, pNetwork->bssid); + if (bIOTAction) + pHTInfo->IOTAction |= HT_IOT_ACT_DISABLE_MCS14; + + bIOTAction = HTIOTActIsDisableMCS15(ieee); + if (bIOTAction) + pHTInfo->IOTAction |= HT_IOT_ACT_DISABLE_MCS15; + + bIOTAction = HTIOTActIsDisableMCSTwoSpatialStream(ieee); + if (bIOTAction) + pHTInfo->IOTAction |= HT_IOT_ACT_DISABLE_ALL_2SS; + + + bIOTAction = HTIOTActIsDisableEDCATurbo(ieee, pNetwork->bssid); + if (bIOTAction) + pHTInfo->IOTAction |= HT_IOT_ACT_DISABLE_EDCA_TURBO; + + bIOTAction = HTIOTActIsMgntUseCCK6M(ieee, pNetwork); + if (bIOTAction) + pHTInfo->IOTAction |= HT_IOT_ACT_MGNT_USE_CCK_6M; + bIOTAction = HTIOTActIsCCDFsync(ieee); + if (bIOTAction) + pHTInfo->IOTAction |= HT_IOT_ACT_CDD_FSYNC; + } else { + pHTInfo->bCurrentHTSupport = false; + pHTInfo->bCurrentRT2RTAggregation = false; + pHTInfo->bCurrentRT2RTLongSlotTime = false; + pHTInfo->RT2RT_HT_Mode = (enum rt_ht_capability)0; + + pHTInfo->IOTAction = 0; + pHTInfo->IOTRaFunc = 0; + } +} + +void HT_update_self_and_peer_setting(struct rtllib_device *ieee, + struct rtllib_network *pNetwork) +{ + struct rt_hi_throughput *pHTInfo = ieee->pHTInfo; + struct ht_info_ele *pPeerHTInfo = + (struct ht_info_ele *)pNetwork->bssht.bdHTInfoBuf; + + if (pHTInfo->bCurrentHTSupport) { + if (pNetwork->bssht.bdHTInfoLen != 0) + pHTInfo->CurrentOpMode = pPeerHTInfo->OptMode; + } +} +EXPORT_SYMBOL(HT_update_self_and_peer_setting); + +void HTUseDefaultSetting(struct rtllib_device *ieee) +{ + struct rt_hi_throughput *pHTInfo = ieee->pHTInfo; + + if (pHTInfo->bEnableHT) { + pHTInfo->bCurrentHTSupport = true; + pHTInfo->bCurSuppCCK = pHTInfo->bRegSuppCCK; + + pHTInfo->bCurBW40MHz = pHTInfo->bRegBW40MHz; + pHTInfo->bCurShortGI20MHz = pHTInfo->bRegShortGI20MHz; + + pHTInfo->bCurShortGI40MHz = pHTInfo->bRegShortGI40MHz; + + if (ieee->iw_mode == IW_MODE_ADHOC) + ieee->current_network.qos_data.active = + ieee->current_network.qos_data.supported; + pHTInfo->bCurrent_AMSDU_Support = pHTInfo->bAMSDU_Support; + pHTInfo->nCurrent_AMSDU_MaxSize = pHTInfo->nAMSDU_MaxSize; + + pHTInfo->bCurrentAMPDUEnable = pHTInfo->bAMPDUEnable; + pHTInfo->CurrentAMPDUFactor = pHTInfo->AMPDU_Factor; + + pHTInfo->CurrentMPDUDensity = pHTInfo->CurrentMPDUDensity; + + HTFilterMCSRate(ieee, ieee->Regdot11TxHTOperationalRateSet, + ieee->dot11HTOperationalRateSet); + ieee->HTHighestOperaRate = HTGetHighestMCSRate(ieee, + ieee->dot11HTOperationalRateSet, + MCS_FILTER_ALL); + ieee->HTCurrentOperaRate = ieee->HTHighestOperaRate; + + } else { + pHTInfo->bCurrentHTSupport = false; + } +} + +u8 HTCCheck(struct rtllib_device *ieee, u8 *pFrame) +{ + if (ieee->pHTInfo->bCurrentHTSupport) { + if ((IsQoSDataFrame(pFrame) && Frame_Order(pFrame)) == 1) { + RTLLIB_DEBUG(RTLLIB_DL_HT, + "HT CONTROL FILED EXIST!!\n"); + return true; + } + } + return false; +} + +static void HTSetConnectBwModeCallback(struct rtllib_device *ieee) +{ + struct rt_hi_throughput *pHTInfo = ieee->pHTInfo; + + RTLLIB_DEBUG(RTLLIB_DL_HT, "======>%s()\n", __func__); + if (pHTInfo->bCurBW40MHz) { + if (pHTInfo->CurSTAExtChnlOffset == HT_EXTCHNL_OFFSET_UPPER) + ieee->set_chan(ieee->dev, + ieee->current_network.channel + 2); + else if (pHTInfo->CurSTAExtChnlOffset == + HT_EXTCHNL_OFFSET_LOWER) + ieee->set_chan(ieee->dev, + ieee->current_network.channel - 2); + else + ieee->set_chan(ieee->dev, + ieee->current_network.channel); + + ieee->SetBWModeHandler(ieee->dev, HT_CHANNEL_WIDTH_20_40, + pHTInfo->CurSTAExtChnlOffset); + } else { + ieee->set_chan(ieee->dev, ieee->current_network.channel); + ieee->SetBWModeHandler(ieee->dev, HT_CHANNEL_WIDTH_20, + HT_EXTCHNL_OFFSET_NO_EXT); + } + + pHTInfo->bSwBwInProgress = false; +} + +void HTSetConnectBwMode(struct rtllib_device *ieee, + enum ht_channel_width Bandwidth, + enum ht_extchnl_offset Offset) +{ + struct rt_hi_throughput *pHTInfo = ieee->pHTInfo; + + if (pHTInfo->bRegBW40MHz == false) + return; + + if (ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev)) + Bandwidth = HT_CHANNEL_WIDTH_20; + + if (pHTInfo->bSwBwInProgress) { + pr_info("%s: bSwBwInProgress!!\n", __func__); + return; + } + if (Bandwidth == HT_CHANNEL_WIDTH_20_40) { + if (ieee->current_network.channel < 2 && + Offset == HT_EXTCHNL_OFFSET_LOWER) + Offset = HT_EXTCHNL_OFFSET_NO_EXT; + if (Offset == HT_EXTCHNL_OFFSET_UPPER || + Offset == HT_EXTCHNL_OFFSET_LOWER) { + pHTInfo->bCurBW40MHz = true; + pHTInfo->CurSTAExtChnlOffset = Offset; + } else { + pHTInfo->bCurBW40MHz = false; + pHTInfo->CurSTAExtChnlOffset = HT_EXTCHNL_OFFSET_NO_EXT; + } + } else { + pHTInfo->bCurBW40MHz = false; + pHTInfo->CurSTAExtChnlOffset = HT_EXTCHNL_OFFSET_NO_EXT; + } + + pr_info("%s():pHTInfo->bCurBW40MHz:%x\n", __func__, + pHTInfo->bCurBW40MHz); + + pHTInfo->bSwBwInProgress = true; + + HTSetConnectBwModeCallback(ieee); +} diff --git a/kernel/drivers/staging/rtl8192e/rtl819x_Qos.h b/kernel/drivers/staging/rtl8192e/rtl819x_Qos.h new file mode 100644 index 000000000..55ef7ec33 --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl819x_Qos.h @@ -0,0 +1,389 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ +#ifndef __INC_QOS_TYPE_H +#define __INC_QOS_TYPE_H + +#define BIT0 0x00000001 +#define BIT1 0x00000002 +#define BIT2 0x00000004 +#define BIT3 0x00000008 +#define BIT4 0x00000010 +#define BIT5 0x00000020 +#define BIT6 0x00000040 +#define BIT7 0x00000080 +#define BIT8 0x00000100 +#define BIT9 0x00000200 +#define BIT10 0x00000400 +#define BIT11 0x00000800 +#define BIT12 0x00001000 +#define BIT13 0x00002000 +#define BIT14 0x00004000 +#define BIT15 0x00008000 +#define BIT16 0x00010000 +#define BIT17 0x00020000 +#define BIT18 0x00040000 +#define BIT19 0x00080000 +#define BIT20 0x00100000 +#define BIT21 0x00200000 +#define BIT22 0x00400000 +#define BIT23 0x00800000 +#define BIT24 0x01000000 +#define BIT25 0x02000000 +#define BIT26 0x04000000 +#define BIT27 0x08000000 +#define BIT28 0x10000000 +#define BIT29 0x20000000 +#define BIT30 0x40000000 +#define BIT31 0x80000000 + +union qos_tsinfo { + u8 charData[3]; + struct { + u8 ucTrafficType:1; + u8 ucTSID:4; + u8 ucDirection:2; + u8 ucAccessPolicy:2; + u8 ucAggregation:1; + u8 ucPSB:1; + u8 ucUP:3; + u8 ucTSInfoAckPolicy:2; + u8 ucSchedule:1; + u8 ucReserved:7; + } field; +}; + +union tspec_body { + u8 charData[55]; + + struct { + union qos_tsinfo TSInfo; + u16 NominalMSDUsize; + u16 MaxMSDUsize; + u32 MinServiceItv; + u32 MaxServiceItv; + u32 InactivityItv; + u32 SuspenItv; + u32 ServiceStartTime; + u32 MinDataRate; + u32 MeanDataRate; + u32 PeakDataRate; + u32 MaxBurstSize; + u32 DelayBound; + u32 MinPhyRate; + u16 SurplusBandwidthAllowance; + u16 MediumTime; + } f; +}; + +struct wmm_tspec { + u8 ID; + u8 Length; + u8 OUI[3]; + u8 OUI_Type; + u8 OUI_SubType; + u8 Version; + union tspec_body Body; +}; + +struct octet_string { + u8 *Octet; + u16 Length; +}; + +#define MAX_WMMELE_LENGTH 64 + +#define QOS_MODE u32 + +#define QOS_DISABLE 0 +#define QOS_WMM 1 +#define QOS_WMMSA 2 +#define QOS_EDCA 4 +#define QOS_HCCA 8 +#define QOS_WMM_UAPSD 16 + +#define WMM_PARAM_ELE_BODY_LEN 18 + +#define MAX_STA_TS_COUNT 16 +#define MAX_AP_TS_COUNT 32 +#define QOS_TSTREAM_KEY_SIZE 13 + +#define WMM_ACTION_CATEGORY_CODE 17 +#define WMM_PARAM_ELE_BODY_LEN 18 + +#define MAX_TSPEC_TSID 15 +#define SESSION_REJECT_TSID 0xfe +#define DEFAULT_TSID 0xff + +#define ADDTS_TIME_SLOT 100 + +#define ACM_TIMEOUT 1000 +#define SESSION_REJECT_TIMEOUT 60000 + +enum ack_policy { + eAckPlc0_ACK = 0x00, + eAckPlc1_NoACK = 0x01, +}; + + +#define SET_WMM_QOS_INFO_FIELD(_pStart, _val) \ + WriteEF1Byte(_pStart, _val) + +#define GET_WMM_QOS_INFO_FIELD_PARAMETERSET_COUNT(_pStart) \ + LE_BITS_TO_1BYTE(_pStart, 0, 4) +#define SET_WMM_QOS_INFO_FIELD_PARAMETERSET_COUNT(_pStart, _val) \ + SET_BITS_TO_LE_1BYTE(_pStart, 0, 4, _val) + +#define GET_WMM_QOS_INFO_FIELD_AP_UAPSD(_pStart) \ + LE_BITS_TO_1BYTE(_pStart, 7, 1) +#define SET_WMM_QOS_INFO_FIELD_AP_UAPSD(_pStart, _val) \ + SET_BITS_TO_LE_1BYTE(_pStart, 7, 1, _val) + +#define GET_WMM_QOS_INFO_FIELD_STA_AC_VO_UAPSD(_pStart) \ + LE_BITS_TO_1BYTE(_pStart, 0, 1) +#define SET_WMM_QOS_INFO_FIELD_STA_AC_VO_UAPSD(_pStart, _val) \ + SET_BITS_TO_LE_1BYTE(_pStart, 0, 1, _val) + +#define GET_WMM_QOS_INFO_FIELD_STA_AC_VI_UAPSD(_pStart) \ + LE_BITS_TO_1BYTE(_pStart, 1, 1) +#define SET_WMM_QOS_INFO_FIELD_STA_AC_VI_UAPSD(_pStart, _val) \ + SET_BITS_TO_LE_1BYTE(_pStart, 1, 1, _val) + +#define GET_WMM_QOS_INFO_FIELD_STA_AC_BE_UAPSD(_pStart) \ + LE_BITS_TO_1BYTE(_pStart, 2, 1) +#define SET_WMM_QOS_INFO_FIELD_STA_AC_BE_UAPSD(_pStart, _val) \ + SET_BITS_TO_LE_1BYTE(_pStart, 2, 1, _val) + +#define GET_WMM_QOS_INFO_FIELD_STA_AC_BK_UAPSD(_pStart) \ + LE_BITS_TO_1BYTE(_pStart, 3, 1) +#define SET_WMM_QOS_INFO_FIELD_STA_AC_BK_UAPSD(_pStart, _val) \ + SET_BITS_TO_LE_1BYTE(_pStart, 3, 1, _val) + +#define GET_WMM_QOS_INFO_FIELD_STA_MAX_SP_LEN(_pStart) \ + LE_BITS_TO_1BYTE(_pStart, 5, 2) +#define SET_WMM_QOS_INFO_FIELD_STA_MAX_SP_LEN(_pStart, _val) \ + SET_BITS_TO_LE_1BYTE(_pStart, 5, 2, _val) + +enum qos_ie_source { + QOSIE_SRC_ADDTSREQ, + QOSIE_SRC_ADDTSRSP, + QOSIE_SRC_REASOCREQ, + QOSIE_SRC_REASOCRSP, + QOSIE_SRC_DELTS, +}; + + +#define AC_CODING u32 + +#define AC0_BE 0 +#define AC1_BK 1 +#define AC2_VI 2 +#define AC3_VO 3 +#define AC_MAX 4 + + +#define AC_PARAM_SIZE 4 + +#define WMM_PARAM_ELEMENT_SIZE (8+(4*AC_PARAM_SIZE)) + +enum qos_ele_subtype { + QOSELE_TYPE_INFO = 0x00, + QOSELE_TYPE_PARAM = 0x01, +}; + + +enum direction_value { + DIR_UP = 0, + DIR_DOWN = 1, + DIR_DIRECT = 2, + DIR_BI_DIR = 3, +}; + +enum acm_method { + eAcmWay0_SwAndHw = 0, + eAcmWay1_HW = 1, + eAcmWay2_SW = 2, +}; + + +struct acm { + u64 UsedTime; + u64 MediumTime; + u8 HwAcmCtl; +}; + + + +#define AC_UAPSD u8 + +#define GET_VO_UAPSD(_apsd) ((_apsd) & BIT0) +#define SET_VO_UAPSD(_apsd) ((_apsd) |= BIT0) + +#define GET_VI_UAPSD(_apsd) ((_apsd) & BIT1) +#define SET_VI_UAPSD(_apsd) ((_apsd) |= BIT1) + +#define GET_BK_UAPSD(_apsd) ((_apsd) & BIT2) +#define SET_BK_UAPSD(_apsd) ((_apsd) |= BIT2) + +#define GET_BE_UAPSD(_apsd) ((_apsd) & BIT3) +#define SET_BE_UAPSD(_apsd) ((_apsd) |= BIT3) + +union qos_tclas { + + struct _TYPE_GENERAL { + u8 Priority; + u8 ClassifierType; + u8 Mask; + } TYPE_GENERAL; + + struct _TYPE0_ETH { + u8 Priority; + u8 ClassifierType; + u8 Mask; + u8 SrcAddr[6]; + u8 DstAddr[6]; + u16 Type; + } TYPE0_ETH; + + struct _TYPE1_IPV4 { + u8 Priority; + u8 ClassifierType; + u8 Mask; + u8 Version; + u8 SrcIP[4]; + u8 DstIP[4]; + u16 SrcPort; + u16 DstPort; + u8 DSCP; + u8 Protocol; + u8 Reserved; + } TYPE1_IPV4; + + struct _TYPE1_IPV6 { + u8 Priority; + u8 ClassifierType; + u8 Mask; + u8 Version; + u8 SrcIP[16]; + u8 DstIP[16]; + u16 SrcPort; + u16 DstPort; + u8 FlowLabel[3]; + } TYPE1_IPV6; + + struct _TYPE2_8021Q { + u8 Priority; + u8 ClassifierType; + u8 Mask; + u16 TagType; + } TYPE2_8021Q; +}; + +struct qos_tstream { + + bool bUsed; + u16 MsduLifetime; + bool bEstablishing; + u8 TimeSlotCount; + u8 DialogToken; + struct wmm_tspec TSpec; + struct wmm_tspec OutStandingTSpec; + u8 NominalPhyRate; +}; + +struct sta_qos { + u8 WMMIEBuf[MAX_WMMELE_LENGTH]; + u8 *WMMIE; + + QOS_MODE QosCapability; + QOS_MODE CurrentQosMode; + + AC_UAPSD b4ac_Uapsd; + AC_UAPSD Curr4acUapsd; + u8 bInServicePeriod; + u8 MaxSPLength; + int NumBcnBeforeTrigger; + + u8 *pWMMInfoEle; + u8 WMMParamEle[WMM_PARAM_ELEMENT_SIZE]; + + struct acm acm[4]; + enum acm_method AcmMethod; + + struct qos_tstream StaTsArray[MAX_STA_TS_COUNT]; + u8 DialogToken; + struct wmm_tspec TSpec; + + u8 QBssWirelessMode; + + bool bNoAck; + + bool bEnableRxImmBA; + +}; + +#define QBSS_LOAD_SIZE 5 + +struct bss_qos { + QOS_MODE bdQoSMode; + u8 bdWMMIEBuf[MAX_WMMELE_LENGTH]; + struct octet_string bdWMMIE; + + enum qos_ele_subtype EleSubType; + + u8 *pWMMInfoEle; + u8 *pWMMParamEle; + + u8 QBssLoad[QBSS_LOAD_SIZE]; + bool bQBssLoadValid; +}; + +#define IsACValid(ac) ((ac >= 0 && ac <= 7) ? true : false) + + +union aci_aifsn { + u8 charData; + + struct { + u8 AIFSN:4; + u8 acm:1; + u8 ACI:2; + u8 Reserved:1; + } f; +}; + +union ecw { + u8 charData; + struct { + u8 ECWmin:4; + u8 ECWmax:4; + } f; +}; + +union ac_param { + u32 longData; + u8 charData[4]; + + struct { + union aci_aifsn AciAifsn; + union ecw Ecw; + u16 TXOPLimit; + } f; +}; + +#endif diff --git a/kernel/drivers/staging/rtl8192e/rtl819x_TS.h b/kernel/drivers/staging/rtl8192e/rtl819x_TS.h new file mode 100644 index 000000000..8601b1ad2 --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl819x_TS.h @@ -0,0 +1,73 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ +#ifndef _TSTYPE_H_ +#define _TSTYPE_H_ +#include "rtl819x_Qos.h" +#define TS_SETUP_TIMEOUT 60 +#define TS_INACT_TIMEOUT 60 +#define TS_ADDBA_DELAY 60 + +#define TOTAL_TS_NUM 16 +#define TCLAS_NUM 4 + +enum tr_select { + TX_DIR = 0, + RX_DIR = 1, +}; + +struct ts_common_info { + struct list_head List; + struct timer_list SetupTimer; + struct timer_list InactTimer; + u8 Addr[6]; + union tspec_body TSpec; + union qos_tclas TClass[TCLAS_NUM]; + u8 TClasProc; + u8 TClasNum; +}; + +struct tx_ts_record { + struct ts_common_info TsCommonInfo; + u16 TxCurSeq; + struct ba_record TxPendingBARecord; + struct ba_record TxAdmittedBARecord; + u8 bAddBaReqInProgress; + u8 bAddBaReqDelayed; + u8 bUsingBa; + u8 bDisable_AddBa; + struct timer_list TsAddBaTimer; + u8 num; +}; + +struct rx_ts_record { + struct ts_common_info TsCommonInfo; + u16 RxIndicateSeq; + u16 RxTimeoutIndicateSeq; + struct list_head RxPendingPktList; + struct timer_list RxPktPendingTimer; + struct ba_record RxAdmittedBARecord; + u16 RxLastSeqNum; + u8 RxLastFragNum; + u8 num; +}; + +void _setup_timer(struct timer_list *, void *, unsigned long); + + +#endif diff --git a/kernel/drivers/staging/rtl8192e/rtl819x_TSProc.c b/kernel/drivers/staging/rtl8192e/rtl819x_TSProc.c new file mode 100644 index 000000000..7d77d0562 --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtl819x_TSProc.c @@ -0,0 +1,554 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ +#include "rtllib.h" +#include +#include "rtl819x_TS.h" + +static void TsSetupTimeOut(unsigned long data) +{ +} + +static void TsInactTimeout(unsigned long data) +{ +} + +static void RxPktPendingTimeout(unsigned long data) +{ + struct rx_ts_record *pRxTs = (struct rx_ts_record *)data; + struct rtllib_device *ieee = container_of(pRxTs, struct rtllib_device, + RxTsRecord[pRxTs->num]); + + struct rx_reorder_entry *pReorderEntry = NULL; + + unsigned long flags = 0; + u8 index = 0; + bool bPktInBuf = false; + + spin_lock_irqsave(&(ieee->reorder_spinlock), flags); + if (pRxTs->RxTimeoutIndicateSeq != 0xffff) { + while (!list_empty(&pRxTs->RxPendingPktList)) { + pReorderEntry = (struct rx_reorder_entry *) + list_entry(pRxTs->RxPendingPktList.prev, + struct rx_reorder_entry, List); + if (index == 0) + pRxTs->RxIndicateSeq = pReorderEntry->SeqNum; + + if (SN_LESS(pReorderEntry->SeqNum, pRxTs->RxIndicateSeq) || + SN_EQUAL(pReorderEntry->SeqNum, pRxTs->RxIndicateSeq)) { + list_del_init(&pReorderEntry->List); + + if (SN_EQUAL(pReorderEntry->SeqNum, + pRxTs->RxIndicateSeq)) + pRxTs->RxIndicateSeq = + (pRxTs->RxIndicateSeq + 1) % 4096; + + RTLLIB_DEBUG(RTLLIB_DL_REORDER, + "%s(): Indicate SeqNum: %d\n", + __func__, pReorderEntry->SeqNum); + ieee->stats_IndicateArray[index] = + pReorderEntry->prxb; + index++; + + list_add_tail(&pReorderEntry->List, + &ieee->RxReorder_Unused_List); + } else { + bPktInBuf = true; + break; + } + } + } + + if (index > 0) { + pRxTs->RxTimeoutIndicateSeq = 0xffff; + + if (index > REORDER_WIN_SIZE) { + RTLLIB_DEBUG(RTLLIB_DL_ERR, + "RxReorderIndicatePacket(): Rx Reorder struct buffer full!!\n"); + spin_unlock_irqrestore(&(ieee->reorder_spinlock), + flags); + return; + } + rtllib_indicate_packets(ieee, ieee->stats_IndicateArray, index); + bPktInBuf = false; + } + + if (bPktInBuf && (pRxTs->RxTimeoutIndicateSeq == 0xffff)) { + pRxTs->RxTimeoutIndicateSeq = pRxTs->RxIndicateSeq; + mod_timer(&pRxTs->RxPktPendingTimer, jiffies + + msecs_to_jiffies(ieee->pHTInfo->RxReorderPendingTime)); + } + spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags); +} + +static void TsAddBaProcess(unsigned long data) +{ + struct tx_ts_record *pTxTs = (struct tx_ts_record *)data; + u8 num = pTxTs->num; + struct rtllib_device *ieee = container_of(pTxTs, struct rtllib_device, + TxTsRecord[num]); + + TsInitAddBA(ieee, pTxTs, BA_POLICY_IMMEDIATE, false); + RTLLIB_DEBUG(RTLLIB_DL_BA, + "TsAddBaProcess(): ADDBA Req is started!!\n"); +} + +static void ResetTsCommonInfo(struct ts_common_info *pTsCommonInfo) +{ + memset(pTsCommonInfo->Addr, 0, 6); + memset(&pTsCommonInfo->TSpec, 0, sizeof(union tspec_body)); + memset(&pTsCommonInfo->TClass, 0, sizeof(union qos_tclas)*TCLAS_NUM); + pTsCommonInfo->TClasProc = 0; + pTsCommonInfo->TClasNum = 0; +} + +static void ResetTxTsEntry(struct tx_ts_record *pTS) +{ + ResetTsCommonInfo(&pTS->TsCommonInfo); + pTS->TxCurSeq = 0; + pTS->bAddBaReqInProgress = false; + pTS->bAddBaReqDelayed = false; + pTS->bUsingBa = false; + pTS->bDisable_AddBa = false; + ResetBaEntry(&pTS->TxAdmittedBARecord); + ResetBaEntry(&pTS->TxPendingBARecord); +} + +static void ResetRxTsEntry(struct rx_ts_record *pTS) +{ + ResetTsCommonInfo(&pTS->TsCommonInfo); + pTS->RxIndicateSeq = 0xffff; + pTS->RxTimeoutIndicateSeq = 0xffff; + ResetBaEntry(&pTS->RxAdmittedBARecord); +} + +void TSInitialize(struct rtllib_device *ieee) +{ + struct tx_ts_record *pTxTS = ieee->TxTsRecord; + struct rx_ts_record *pRxTS = ieee->RxTsRecord; + struct rx_reorder_entry *pRxReorderEntry = ieee->RxReorderEntry; + u8 count = 0; + + RTLLIB_DEBUG(RTLLIB_DL_TS, "==========>%s()\n", __func__); + INIT_LIST_HEAD(&ieee->Tx_TS_Admit_List); + INIT_LIST_HEAD(&ieee->Tx_TS_Pending_List); + INIT_LIST_HEAD(&ieee->Tx_TS_Unused_List); + + for (count = 0; count < TOTAL_TS_NUM; count++) { + pTxTS->num = count; + _setup_timer(&pTxTS->TsCommonInfo.SetupTimer, + TsSetupTimeOut, + (unsigned long) pTxTS); + + _setup_timer(&pTxTS->TsCommonInfo.InactTimer, + TsInactTimeout, + (unsigned long) pTxTS); + + _setup_timer(&pTxTS->TsAddBaTimer, + TsAddBaProcess, + (unsigned long) pTxTS); + + _setup_timer(&pTxTS->TxPendingBARecord.Timer, + BaSetupTimeOut, + (unsigned long) pTxTS); + _setup_timer(&pTxTS->TxAdmittedBARecord.Timer, + TxBaInactTimeout, + (unsigned long) pTxTS); + + ResetTxTsEntry(pTxTS); + list_add_tail(&pTxTS->TsCommonInfo.List, + &ieee->Tx_TS_Unused_List); + pTxTS++; + } + + INIT_LIST_HEAD(&ieee->Rx_TS_Admit_List); + INIT_LIST_HEAD(&ieee->Rx_TS_Pending_List); + INIT_LIST_HEAD(&ieee->Rx_TS_Unused_List); + for (count = 0; count < TOTAL_TS_NUM; count++) { + pRxTS->num = count; + INIT_LIST_HEAD(&pRxTS->RxPendingPktList); + + _setup_timer(&pRxTS->TsCommonInfo.SetupTimer, + TsSetupTimeOut, + (unsigned long) pRxTS); + + _setup_timer(&pRxTS->TsCommonInfo.InactTimer, + TsInactTimeout, + (unsigned long) pRxTS); + + _setup_timer(&pRxTS->RxAdmittedBARecord.Timer, + RxBaInactTimeout, + (unsigned long) pRxTS); + + _setup_timer(&pRxTS->RxPktPendingTimer, + RxPktPendingTimeout, + (unsigned long) pRxTS); + + ResetRxTsEntry(pRxTS); + list_add_tail(&pRxTS->TsCommonInfo.List, + &ieee->Rx_TS_Unused_List); + pRxTS++; + } + INIT_LIST_HEAD(&ieee->RxReorder_Unused_List); + for (count = 0; count < REORDER_ENTRY_NUM; count++) { + list_add_tail(&pRxReorderEntry->List, + &ieee->RxReorder_Unused_List); + if (count == (REORDER_ENTRY_NUM-1)) + break; + pRxReorderEntry = &ieee->RxReorderEntry[count+1]; + } + +} + +static void AdmitTS(struct rtllib_device *ieee, + struct ts_common_info *pTsCommonInfo, u32 InactTime) +{ + del_timer_sync(&pTsCommonInfo->SetupTimer); + del_timer_sync(&pTsCommonInfo->InactTimer); + + if (InactTime != 0) + mod_timer(&pTsCommonInfo->InactTimer, jiffies + + msecs_to_jiffies(InactTime)); +} + +static struct ts_common_info *SearchAdmitTRStream(struct rtllib_device *ieee, + u8 *Addr, u8 TID, + enum tr_select TxRxSelect) +{ + u8 dir; + bool search_dir[4] = {0}; + struct list_head *psearch_list; + struct ts_common_info *pRet = NULL; + + if (ieee->iw_mode == IW_MODE_MASTER) { + if (TxRxSelect == TX_DIR) { + search_dir[DIR_DOWN] = true; + search_dir[DIR_BI_DIR] = true; + } else { + search_dir[DIR_UP] = true; + search_dir[DIR_BI_DIR] = true; + } + } else if (ieee->iw_mode == IW_MODE_ADHOC) { + if (TxRxSelect == TX_DIR) + search_dir[DIR_UP] = true; + else + search_dir[DIR_DOWN] = true; + } else { + if (TxRxSelect == TX_DIR) { + search_dir[DIR_UP] = true; + search_dir[DIR_BI_DIR] = true; + search_dir[DIR_DIRECT] = true; + } else { + search_dir[DIR_DOWN] = true; + search_dir[DIR_BI_DIR] = true; + search_dir[DIR_DIRECT] = true; + } + } + + if (TxRxSelect == TX_DIR) + psearch_list = &ieee->Tx_TS_Admit_List; + else + psearch_list = &ieee->Rx_TS_Admit_List; + + for (dir = 0; dir <= DIR_BI_DIR; dir++) { + if (!search_dir[dir]) + continue; + list_for_each_entry(pRet, psearch_list, List) { + if (memcmp(pRet->Addr, Addr, 6) == 0) + if (pRet->TSpec.f.TSInfo.field.ucTSID == TID) + if (pRet->TSpec.f.TSInfo.field.ucDirection == dir) + break; + + } + if (&pRet->List != psearch_list) + break; + } + + if (pRet && &pRet->List != psearch_list) + return pRet; + return NULL; +} + +static void MakeTSEntry(struct ts_common_info *pTsCommonInfo, u8 *Addr, + union tspec_body *pTSPEC, union qos_tclas *pTCLAS, + u8 TCLAS_Num, u8 TCLAS_Proc) +{ + u8 count; + + if (pTsCommonInfo == NULL) + return; + + memcpy(pTsCommonInfo->Addr, Addr, 6); + + if (pTSPEC != NULL) + memcpy((u8 *)(&(pTsCommonInfo->TSpec)), (u8 *)pTSPEC, + sizeof(union tspec_body)); + + for (count = 0; count < TCLAS_Num; count++) + memcpy((u8 *)(&(pTsCommonInfo->TClass[count])), + (u8 *)pTCLAS, sizeof(union qos_tclas)); + + pTsCommonInfo->TClasProc = TCLAS_Proc; + pTsCommonInfo->TClasNum = TCLAS_Num; +} + +bool GetTs(struct rtllib_device *ieee, struct ts_common_info **ppTS, + u8 *Addr, u8 TID, enum tr_select TxRxSelect, bool bAddNewTs) +{ + u8 UP = 0; + union tspec_body TSpec; + union qos_tsinfo *pTSInfo = &TSpec.f.TSInfo; + struct list_head *pUnusedList; + struct list_head *pAddmitList; + enum direction_value Dir; + + if (is_multicast_ether_addr(Addr)) { + RTLLIB_DEBUG(RTLLIB_DL_ERR, + "ERR! get TS for Broadcast or Multicast\n"); + return false; + } + if (ieee->current_network.qos_data.supported == 0) { + UP = 0; + } else { + if (!IsACValid(TID)) { + RTLLIB_DEBUG(RTLLIB_DL_ERR, + "ERR! in %s(), TID(%d) is not valid\n", + __func__, TID); + return false; + } + + switch (TID) { + case 0: + case 3: + UP = 0; + break; + case 1: + case 2: + UP = 2; + break; + case 4: + case 5: + UP = 5; + break; + case 6: + case 7: + UP = 7; + break; + } + } + + *ppTS = SearchAdmitTRStream(ieee, Addr, UP, TxRxSelect); + if (*ppTS != NULL) + return true; + + if (!bAddNewTs) { + RTLLIB_DEBUG(RTLLIB_DL_TS, + "add new TS failed(tid:%d)\n", UP); + return false; + } + + pUnusedList = (TxRxSelect == TX_DIR) ? + (&ieee->Tx_TS_Unused_List) : + (&ieee->Rx_TS_Unused_List); + + pAddmitList = (TxRxSelect == TX_DIR) ? + (&ieee->Tx_TS_Admit_List) : + (&ieee->Rx_TS_Admit_List); + + Dir = (ieee->iw_mode == IW_MODE_MASTER) ? + ((TxRxSelect == TX_DIR) ? DIR_DOWN : DIR_UP) : + ((TxRxSelect == TX_DIR) ? DIR_UP : DIR_DOWN); + + RTLLIB_DEBUG(RTLLIB_DL_TS, "to add Ts\n"); + if (!list_empty(pUnusedList)) { + (*ppTS) = list_entry(pUnusedList->next, + struct ts_common_info, List); + list_del_init(&(*ppTS)->List); + if (TxRxSelect == TX_DIR) { + struct tx_ts_record *tmp = + container_of(*ppTS, + struct tx_ts_record, + TsCommonInfo); + ResetTxTsEntry(tmp); + } else { + struct rx_ts_record *tmp = + container_of(*ppTS, + struct rx_ts_record, + TsCommonInfo); + ResetRxTsEntry(tmp); + } + + RTLLIB_DEBUG(RTLLIB_DL_TS, + "to init current TS, UP:%d, Dir:%d, addr: %pM ppTs=%p\n", + UP, Dir, Addr, *ppTS); + pTSInfo->field.ucTrafficType = 0; + pTSInfo->field.ucTSID = UP; + pTSInfo->field.ucDirection = Dir; + pTSInfo->field.ucAccessPolicy = 1; + pTSInfo->field.ucAggregation = 0; + pTSInfo->field.ucPSB = 0; + pTSInfo->field.ucUP = UP; + pTSInfo->field.ucTSInfoAckPolicy = 0; + pTSInfo->field.ucSchedule = 0; + + MakeTSEntry(*ppTS, Addr, &TSpec, NULL, 0, 0); + AdmitTS(ieee, *ppTS, 0); + list_add_tail(&((*ppTS)->List), pAddmitList); + + return true; + } + + RTLLIB_DEBUG(RTLLIB_DL_ERR, + "ERR!!in function %s() There is not enough dir=%d(0=up down=1) TS record to be used!!", + __func__, Dir); + return false; +} + +static void RemoveTsEntry(struct rtllib_device *ieee, struct ts_common_info *pTs, + enum tr_select TxRxSelect) +{ + del_timer_sync(&pTs->SetupTimer); + del_timer_sync(&pTs->InactTimer); + TsInitDelBA(ieee, pTs, TxRxSelect); + + if (TxRxSelect == RX_DIR) { + struct rx_reorder_entry *pRxReorderEntry; + struct rx_ts_record *pRxTS = (struct rx_ts_record *)pTs; + + if (timer_pending(&pRxTS->RxPktPendingTimer)) + del_timer_sync(&pRxTS->RxPktPendingTimer); + + while (!list_empty(&pRxTS->RxPendingPktList)) { + pRxReorderEntry = (struct rx_reorder_entry *) + list_entry(pRxTS->RxPendingPktList.prev, + struct rx_reorder_entry, List); + RTLLIB_DEBUG(RTLLIB_DL_REORDER, + "%s(): Delete SeqNum %d!\n", __func__, + pRxReorderEntry->SeqNum); + list_del_init(&pRxReorderEntry->List); + { + int i = 0; + struct rtllib_rxb *prxb = pRxReorderEntry->prxb; + + if (unlikely(!prxb)) + return; + for (i = 0; i < prxb->nr_subframes; i++) + dev_kfree_skb(prxb->subframes[i]); + kfree(prxb); + prxb = NULL; + } + list_add_tail(&pRxReorderEntry->List, + &ieee->RxReorder_Unused_List); + } + } else { + struct tx_ts_record *pTxTS = (struct tx_ts_record *)pTs; + + del_timer_sync(&pTxTS->TsAddBaTimer); + } +} + +void RemovePeerTS(struct rtllib_device *ieee, u8 *Addr) +{ + struct ts_common_info *pTS, *pTmpTS; + + netdev_info(ieee->dev, "===========>RemovePeerTS, %pM\n", Addr); + + list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, List) { + if (memcmp(pTS->Addr, Addr, 6) == 0) { + RemoveTsEntry(ieee, pTS, TX_DIR); + list_del_init(&pTS->List); + list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List); + } + } + + list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Admit_List, List) { + if (memcmp(pTS->Addr, Addr, 6) == 0) { + netdev_info(ieee->dev, + "====>remove Tx_TS_admin_list\n"); + RemoveTsEntry(ieee, pTS, TX_DIR); + list_del_init(&pTS->List); + list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List); + } + } + + list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Pending_List, List) { + if (memcmp(pTS->Addr, Addr, 6) == 0) { + RemoveTsEntry(ieee, pTS, RX_DIR); + list_del_init(&pTS->List); + list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List); + } + } + + list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Admit_List, List) { + if (memcmp(pTS->Addr, Addr, 6) == 0) { + RemoveTsEntry(ieee, pTS, RX_DIR); + list_del_init(&pTS->List); + list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List); + } + } +} +EXPORT_SYMBOL(RemovePeerTS); + +void RemoveAllTS(struct rtllib_device *ieee) +{ + struct ts_common_info *pTS, *pTmpTS; + + list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, List) { + RemoveTsEntry(ieee, pTS, TX_DIR); + list_del_init(&pTS->List); + list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List); + } + + list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Admit_List, List) { + RemoveTsEntry(ieee, pTS, TX_DIR); + list_del_init(&pTS->List); + list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List); + } + + list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Pending_List, List) { + RemoveTsEntry(ieee, pTS, RX_DIR); + list_del_init(&pTS->List); + list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List); + } + + list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Admit_List, List) { + RemoveTsEntry(ieee, pTS, RX_DIR); + list_del_init(&pTS->List); + list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List); + } +} + +void TsStartAddBaProcess(struct rtllib_device *ieee, struct tx_ts_record *pTxTS) +{ + if (pTxTS->bAddBaReqInProgress == false) { + pTxTS->bAddBaReqInProgress = true; + + if (pTxTS->bAddBaReqDelayed) { + RTLLIB_DEBUG(RTLLIB_DL_BA, + "TsStartAddBaProcess(): Delayed Start ADDBA after 60 sec!!\n"); + mod_timer(&pTxTS->TsAddBaTimer, jiffies + + msecs_to_jiffies(TS_ADDBA_DELAY)); + } else { + RTLLIB_DEBUG(RTLLIB_DL_BA, + "TsStartAddBaProcess(): Immediately Start ADDBA now!!\n"); + mod_timer(&pTxTS->TsAddBaTimer, jiffies+10); + } + } else + RTLLIB_DEBUG(RTLLIB_DL_BA, "%s()==>BA timer is already added\n", + __func__); +} diff --git a/kernel/drivers/staging/rtl8192e/rtllib.h b/kernel/drivers/staging/rtl8192e/rtllib.h new file mode 100644 index 000000000..3c8b708df --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtllib.h @@ -0,0 +1,2975 @@ +/* + * Merged with mainline rtllib.h in Aug 2004. Original ieee802_11 + * remains copyright by the original authors + * + * Portions of the merged code are based on Host AP (software wireless + * LAN access point) driver for Intersil Prism2/2.5/3. + * + * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen + * + * Copyright (c) 2002-2003, Jouni Malinen + * + * Adaption to a generic IEEE 802.11 stack by James Ketrenos + * + * Copyright (c) 2004, Intel Corporation + * + * Modified for Realtek's wi-fi cards by Andrea Merello + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. See README and COPYING for + * more details. + */ +#ifndef RTLLIB_H +#define RTLLIB_H +#include /* ETH_ALEN */ +#include /* ARRAY_SIZE */ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "rtllib_debug.h" +#include "rtl819x_HT.h" +#include "rtl819x_BA.h" +#include "rtl819x_TS.h" + +#include +#include /* ARPHRD_ETHER */ +#include + +#define MAX_PRECMD_CNT 16 +#define MAX_RFDEPENDCMD_CNT 16 +#define MAX_POSTCMD_CNT 16 + +#ifndef WIRELESS_SPY +#define WIRELESS_SPY +#endif +#include + +#ifndef IW_MODE_MONITOR +#define IW_MODE_MONITOR 6 +#endif + +#ifndef IWEVCUSTOM +#define IWEVCUSTOM 0x8c02 +#endif + +#ifndef IW_CUSTOM_MAX +/* Max number of char in custom event - use multiple of them if needed */ +#define IW_CUSTOM_MAX 256 /* In bytes */ +#endif + +#define skb_tail_pointer_rsl(skb) skb_tail_pointer(skb) + +#define queue_delayed_work_rsl(x, y, z) queue_delayed_work(x, y, z) +#define INIT_DELAYED_WORK_RSL(x, y, z) INIT_DELAYED_WORK(x, y) + +#define queue_work_rsl(x, y) queue_work(x, y) +#define INIT_WORK_RSL(x, y, z) INIT_WORK(x, y) + +#define container_of_work_rsl(x, y, z) container_of(x, y, z) +#define container_of_dwork_rsl(x, y, z) \ + container_of(container_of(x, struct delayed_work, work), y, z) + +#define iwe_stream_add_event_rsl(info, start, stop, iwe, len) \ + iwe_stream_add_event(info, start, stop, iwe, len) + +#define iwe_stream_add_point_rsl(info, start, stop, iwe, p) \ + iwe_stream_add_point(info, start, stop, iwe, p) + +#define usb_alloc_urb_rsl(x, y) usb_alloc_urb(x, y) +#define usb_submit_urb_rsl(x, y) usb_submit_urb(x, y) + +static inline void *netdev_priv_rsl(struct net_device *dev) +{ + return netdev_priv(dev); +} + +#define KEY_TYPE_NA 0x0 +#define KEY_TYPE_WEP40 0x1 +#define KEY_TYPE_TKIP 0x2 +#define KEY_TYPE_CCMP 0x4 +#define KEY_TYPE_WEP104 0x5 +/* added for rtl819x tx procedure */ +#define MAX_QUEUE_SIZE 0x10 + +#define BK_QUEUE 0 +#define BE_QUEUE 1 +#define VI_QUEUE 2 +#define VO_QUEUE 3 +#define HCCA_QUEUE 4 +#define TXCMD_QUEUE 5 +#define MGNT_QUEUE 6 +#define HIGH_QUEUE 7 +#define BEACON_QUEUE 8 + +#define LOW_QUEUE BE_QUEUE +#define NORMAL_QUEUE MGNT_QUEUE + +#ifndef IW_MODE_MESH +#define IW_MODE_MESH 7 +#endif +#define AMSDU_SUBHEADER_LEN 14 +#define SWRF_TIMEOUT 50 + +#define IE_CISCO_FLAG_POSITION 0x08 +#define SUPPORT_CKIP_MIC 0x08 +#define SUPPORT_CKIP_PK 0x10 +#define RT_RF_OFF_LEVL_ASPM BIT0 +#define RT_RF_OFF_LEVL_CLK_REQ BIT1 +#define RT_RF_OFF_LEVL_PCI_D3 BIT2 +#define RT_RF_OFF_LEVL_HALT_NIC BIT3 +#define RT_RF_OFF_LEVL_FREE_FW BIT4 +#define RT_RF_OFF_LEVL_FW_32K BIT5 +#define RT_RF_PS_LEVEL_ALWAYS_ASPM BIT6 +#define RT_RF_LPS_DISALBE_2R BIT30 +#define RT_RF_LPS_LEVEL_ASPM BIT31 +#define RT_IN_PS_LEVEL(pPSC, _PS_FLAG) \ + ((pPSC->CurPsLevel & _PS_FLAG) ? true : false) +#define RT_CLEAR_PS_LEVEL(pPSC, _PS_FLAG) \ + (pPSC->CurPsLevel &= (~(_PS_FLAG))) +#define RT_SET_PS_LEVEL(pPSC, _PS_FLAG) (pPSC->CurPsLevel |= _PS_FLAG) + +/* defined for skb cb field */ +/* At most 28 byte */ +struct cb_desc { + /* Tx Desc Related flags (8-9) */ + u8 bLastIniPkt:1; + u8 bCmdOrInit:1; + u8 bFirstSeg:1; + u8 bLastSeg:1; + u8 bEncrypt:1; + u8 bTxDisableRateFallBack:1; + u8 bTxUseDriverAssingedRate:1; + u8 bHwSec:1; + + u8 nStuckCount; + + /* Tx Firmware Related flags (10-11)*/ + u8 bCTSEnable:1; + u8 bRTSEnable:1; + u8 bUseShortGI:1; + u8 bUseShortPreamble:1; + u8 bTxEnableFwCalcDur:1; + u8 bAMPDUEnable:1; + u8 bRTSSTBC:1; + u8 RTSSC:1; + + u8 bRTSBW:1; + u8 bPacketBW:1; + u8 bRTSUseShortPreamble:1; + u8 bRTSUseShortGI:1; + u8 bMulticast:1; + u8 bBroadcast:1; + u8 drv_agg_enable:1; + u8 reserved2:1; + + /* Tx Desc related element(12-19) */ + u8 rata_index; + u8 queue_index; + u16 txbuf_size; + u8 RATRIndex; + u8 bAMSDU:1; + u8 bFromAggrQ:1; + u8 reserved6:6; + u8 macId; + u8 priority; + + /* Tx firmware related element(20-27) */ + u8 data_rate; + u8 rts_rate; + u8 ampdu_factor; + u8 ampdu_density; + u8 DrvAggrNum; + u8 bdhcp; + u16 pkt_size; + u8 bIsSpecialDataFrame; + + u8 bBTTxPacket; + u8 bIsBTProbRsp; +}; + +enum sw_chnl_cmd_id { + CmdID_End, + CmdID_SetTxPowerLevel, + CmdID_BBRegWrite10, + CmdID_WritePortUlong, + CmdID_WritePortUshort, + CmdID_WritePortUchar, + CmdID_RF_WriteReg, +}; + +struct sw_chnl_cmd { + enum sw_chnl_cmd_id CmdID; + u32 Para1; + u32 Para2; + u32 msDelay; +} __packed; + +/*--------------------------Define -------------------------------------------*/ +#define MGN_1M 0x02 +#define MGN_2M 0x04 +#define MGN_5_5M 0x0b +#define MGN_11M 0x16 + +#define MGN_6M 0x0c +#define MGN_9M 0x12 +#define MGN_12M 0x18 +#define MGN_18M 0x24 +#define MGN_24M 0x30 +#define MGN_36M 0x48 +#define MGN_48M 0x60 +#define MGN_54M 0x6c + +#define MGN_MCS0 0x80 +#define MGN_MCS1 0x81 +#define MGN_MCS2 0x82 +#define MGN_MCS3 0x83 +#define MGN_MCS4 0x84 +#define MGN_MCS5 0x85 +#define MGN_MCS6 0x86 +#define MGN_MCS7 0x87 +#define MGN_MCS8 0x88 +#define MGN_MCS9 0x89 +#define MGN_MCS10 0x8a +#define MGN_MCS11 0x8b +#define MGN_MCS12 0x8c +#define MGN_MCS13 0x8d +#define MGN_MCS14 0x8e +#define MGN_MCS15 0x8f +#define MGN_MCS0_SG 0x90 +#define MGN_MCS1_SG 0x91 +#define MGN_MCS2_SG 0x92 +#define MGN_MCS3_SG 0x93 +#define MGN_MCS4_SG 0x94 +#define MGN_MCS5_SG 0x95 +#define MGN_MCS6_SG 0x96 +#define MGN_MCS7_SG 0x97 +#define MGN_MCS8_SG 0x98 +#define MGN_MCS9_SG 0x99 +#define MGN_MCS10_SG 0x9a +#define MGN_MCS11_SG 0x9b +#define MGN_MCS12_SG 0x9c +#define MGN_MCS13_SG 0x9d +#define MGN_MCS14_SG 0x9e +#define MGN_MCS15_SG 0x9f + + +enum _ReasonCode { + unspec_reason = 0x1, + auth_not_valid = 0x2, + deauth_lv_ss = 0x3, + inactivity = 0x4, + ap_overload = 0x5, + class2_err = 0x6, + class3_err = 0x7, + disas_lv_ss = 0x8, + asoc_not_auth = 0x9, + + mic_failure = 0xe, + + invalid_IE = 0x0d, + four_way_tmout = 0x0f, + two_way_tmout = 0x10, + IE_dismatch = 0x11, + invalid_Gcipher = 0x12, + invalid_Pcipher = 0x13, + invalid_AKMP = 0x14, + unsup_RSNIEver = 0x15, + invalid_RSNIE = 0x16, + auth_802_1x_fail = 0x17, + ciper_reject = 0x18, + + QoS_unspec = 0x20, + QAP_bandwidth = 0x21, + poor_condition = 0x22, + no_facility = 0x23, + req_declined = 0x25, + invalid_param = 0x26, + req_not_honored = 0x27, + TS_not_created = 0x2F, + DL_not_allowed = 0x30, + dest_not_exist = 0x31, + dest_not_QSTA = 0x32, +}; + +enum hal_def_variable { + HAL_DEF_TPC_ENABLE, + HAL_DEF_INIT_GAIN, + HAL_DEF_PROT_IMP_MODE, + HAL_DEF_HIGH_POWER_MECHANISM, + HAL_DEF_RATE_ADAPTIVE_MECHANISM, + HAL_DEF_ANTENNA_DIVERSITY_MECHANISM, + HAL_DEF_LED, + HAL_DEF_CW_MAX_MIN, + + HAL_DEF_WOWLAN, + HAL_DEF_ENDPOINTS, + HAL_DEF_MIN_TX_POWER_DBM, + HAL_DEF_MAX_TX_POWER_DBM, + HW_DEF_EFUSE_REPG_SECTION1_FLAG, + HW_DEF_EFUSE_REPG_DATA, + HW_DEF_GPIO, + HAL_DEF_PCI_SUPPORT_ASPM, + HAL_DEF_THERMAL_VALUE, + HAL_DEF_USB_IN_TOKEN_REV, +}; + +enum hw_variables { + HW_VAR_ETHER_ADDR, + HW_VAR_MULTICAST_REG, + HW_VAR_BASIC_RATE, + HW_VAR_BSSID, + HW_VAR_MEDIA_STATUS, + HW_VAR_SECURITY_CONF, + HW_VAR_BEACON_INTERVAL, + HW_VAR_ATIM_WINDOW, + HW_VAR_LISTEN_INTERVAL, + HW_VAR_CS_COUNTER, + HW_VAR_DEFAULTKEY0, + HW_VAR_DEFAULTKEY1, + HW_VAR_DEFAULTKEY2, + HW_VAR_DEFAULTKEY3, + HW_VAR_SIFS, + HW_VAR_DIFS, + HW_VAR_EIFS, + HW_VAR_SLOT_TIME, + HW_VAR_ACK_PREAMBLE, + HW_VAR_CW_CONFIG, + HW_VAR_CW_VALUES, + HW_VAR_RATE_FALLBACK_CONTROL, + HW_VAR_CONTENTION_WINDOW, + HW_VAR_RETRY_COUNT, + HW_VAR_TR_SWITCH, + HW_VAR_COMMAND, + HW_VAR_WPA_CONFIG, + HW_VAR_AMPDU_MIN_SPACE, + HW_VAR_SHORTGI_DENSITY, + HW_VAR_AMPDU_FACTOR, + HW_VAR_MCS_RATE_AVAILABLE, + HW_VAR_AC_PARAM, + HW_VAR_ACM_CTRL, + HW_VAR_DIS_Req_Qsize, + HW_VAR_CCX_CHNL_LOAD, + HW_VAR_CCX_NOISE_HISTOGRAM, + HW_VAR_CCX_CLM_NHM, + HW_VAR_TxOPLimit, + HW_VAR_TURBO_MODE, + HW_VAR_RF_STATE, + HW_VAR_RF_OFF_BY_HW, + HW_VAR_BUS_SPEED, + HW_VAR_SET_DEV_POWER, + + HW_VAR_RCR, + HW_VAR_RATR_0, + HW_VAR_RRSR, + HW_VAR_CPU_RST, + HW_VAR_CECHK_BSSID, + HW_VAR_LBK_MODE, + HW_VAR_AES_11N_FIX, + HW_VAR_USB_RX_AGGR, + HW_VAR_USER_CONTROL_TURBO_MODE, + HW_VAR_RETRY_LIMIT, + HW_VAR_INIT_TX_RATE, + HW_VAR_TX_RATE_REG, + HW_VAR_EFUSE_USAGE, + HW_VAR_EFUSE_BYTES, + HW_VAR_AUTOLOAD_STATUS, + HW_VAR_RF_2R_DISABLE, + HW_VAR_SET_RPWM, + HW_VAR_H2C_FW_PWRMODE, + HW_VAR_H2C_FW_JOINBSSRPT, + HW_VAR_1X1_RECV_COMBINE, + HW_VAR_STOP_SEND_BEACON, + HW_VAR_TSF_TIMER, + HW_VAR_IO_CMD, + + HW_VAR_RF_RECOVERY, + HW_VAR_H2C_FW_UPDATE_GTK, + HW_VAR_WF_MASK, + HW_VAR_WF_CRC, + HW_VAR_WF_IS_MAC_ADDR, + HW_VAR_H2C_FW_OFFLOAD, + HW_VAR_RESET_WFCRC, + + HW_VAR_HANDLE_FW_C2H, + HW_VAR_DL_FW_RSVD_PAGE, + HW_VAR_AID, + HW_VAR_HW_SEQ_ENABLE, + HW_VAR_CORRECT_TSF, + HW_VAR_BCN_VALID, + HW_VAR_FWLPS_RF_ON, + HW_VAR_DUAL_TSF_RST, + HW_VAR_SWITCH_EPHY_WoWLAN, + HW_VAR_INT_MIGRATION, + HW_VAR_INT_AC, + HW_VAR_RF_TIMING, +}; + +enum rt_op_mode { + RT_OP_MODE_AP, + RT_OP_MODE_INFRASTRUCTURE, + RT_OP_MODE_IBSS, + RT_OP_MODE_NO_LINK, +}; + + +#define aSifsTime \ + (((priv->rtllib->current_network.mode == IEEE_A) \ + || (priv->rtllib->current_network.mode == IEEE_N_24G) \ + || (priv->rtllib->current_network.mode == IEEE_N_5G)) ? 16 : 10) + +#define MGMT_QUEUE_NUM 5 + +#define IEEE_CMD_SET_WPA_PARAM 1 +#define IEEE_CMD_SET_WPA_IE 2 +#define IEEE_CMD_SET_ENCRYPTION 3 +#define IEEE_CMD_MLME 4 + +#define IEEE_PARAM_WPA_ENABLED 1 +#define IEEE_PARAM_TKIP_COUNTERMEASURES 2 +#define IEEE_PARAM_DROP_UNENCRYPTED 3 +#define IEEE_PARAM_PRIVACY_INVOKED 4 +#define IEEE_PARAM_AUTH_ALGS 5 +#define IEEE_PARAM_IEEE_802_1X 6 +#define IEEE_PARAM_WPAX_SELECT 7 +#define IEEE_PROTO_WPA 1 +#define IEEE_PROTO_RSN 2 +#define IEEE_WPAX_USEGROUP 0 +#define IEEE_WPAX_WEP40 1 +#define IEEE_WPAX_TKIP 2 +#define IEEE_WPAX_WRAP 3 +#define IEEE_WPAX_CCMP 4 +#define IEEE_WPAX_WEP104 5 + +#define IEEE_KEY_MGMT_IEEE8021X 1 +#define IEEE_KEY_MGMT_PSK 2 + +#define IEEE_MLME_STA_DEAUTH 1 +#define IEEE_MLME_STA_DISASSOC 2 + + +#define IEEE_CRYPT_ERR_UNKNOWN_ALG 2 +#define IEEE_CRYPT_ERR_UNKNOWN_ADDR 3 +#define IEEE_CRYPT_ERR_CRYPT_INIT_FAILED 4 +#define IEEE_CRYPT_ERR_KEY_SET_FAILED 5 +#define IEEE_CRYPT_ERR_TX_KEY_SET_FAILED 6 +#define IEEE_CRYPT_ERR_CARD_CONF_FAILED 7 +#define IEEE_CRYPT_ALG_NAME_LEN 16 + +#define MAX_IE_LEN 0xff + +struct ieee_param { + u32 cmd; + u8 sta_addr[ETH_ALEN]; + union { + struct { + u8 name; + u32 value; + } wpa_param; + struct { + u32 len; + u8 reserved[32]; + u8 data[0]; + } wpa_ie; + struct { + int command; + int reason_code; + } mlme; + struct { + u8 alg[IEEE_CRYPT_ALG_NAME_LEN]; + u8 set_tx; + u32 err; + u8 idx; + u8 seq[8]; /* sequence counter (set: RX, get: TX) */ + u16 key_len; + u8 key[0]; + } crypt; + } u; +}; + + +#if WIRELESS_EXT < 17 +#define IW_QUAL_QUAL_INVALID 0x10 +#define IW_QUAL_LEVEL_INVALID 0x20 +#define IW_QUAL_NOISE_INVALID 0x40 +#define IW_QUAL_QUAL_UPDATED 0x1 +#define IW_QUAL_LEVEL_UPDATED 0x2 +#define IW_QUAL_NOISE_UPDATED 0x4 +#endif + +#define msleep_interruptible_rsl msleep_interruptible + +#define RTLLIB_DATA_LEN 2304 +/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section + * 6.2.1.1.2. + * + * The figure in section 7.1.2 suggests a body size of up to 2312 + * bytes is allowed, which is a bit confusing, I suspect this + * represents the 2304 bytes of real data, plus a possible 8 bytes of + * WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) + */ +#define RTLLIB_1ADDR_LEN 10 +#define RTLLIB_2ADDR_LEN 16 +#define RTLLIB_3ADDR_LEN 24 +#define RTLLIB_4ADDR_LEN 30 +#define RTLLIB_FCS_LEN 4 +#define RTLLIB_HLEN (RTLLIB_4ADDR_LEN) +#define RTLLIB_FRAME_LEN (RTLLIB_DATA_LEN + RTLLIB_HLEN) +#define RTLLIB_MGMT_HDR_LEN 24 +#define RTLLIB_DATA_HDR3_LEN 24 +#define RTLLIB_DATA_HDR4_LEN 30 + +#define RTLLIB_SKBBUFFER_SIZE 2500 + +#define MIN_FRAG_THRESHOLD 256U +#define MAX_FRAG_THRESHOLD 2346U +#define MAX_HT_DATA_FRAG_THRESHOLD 0x2000 + +#define HT_AMSDU_SIZE_4K 3839 +#define HT_AMSDU_SIZE_8K 7935 + +/* Frame control field constants */ +#define RTLLIB_FCTL_VERS 0x0003 +#define RTLLIB_FCTL_FTYPE 0x000c +#define RTLLIB_FCTL_STYPE 0x00f0 +#define RTLLIB_FCTL_FRAMETYPE 0x00fc +#define RTLLIB_FCTL_TODS 0x0100 +#define RTLLIB_FCTL_FROMDS 0x0200 +#define RTLLIB_FCTL_DSTODS 0x0300 +#define RTLLIB_FCTL_MOREFRAGS 0x0400 +#define RTLLIB_FCTL_RETRY 0x0800 +#define RTLLIB_FCTL_PM 0x1000 +#define RTLLIB_FCTL_MOREDATA 0x2000 +#define RTLLIB_FCTL_WEP 0x4000 +#define RTLLIB_FCTL_ORDER 0x8000 + +#define RTLLIB_FTYPE_MGMT 0x0000 +#define RTLLIB_FTYPE_CTL 0x0004 +#define RTLLIB_FTYPE_DATA 0x0008 + +/* management */ +#define RTLLIB_STYPE_ASSOC_REQ 0x0000 +#define RTLLIB_STYPE_ASSOC_RESP 0x0010 +#define RTLLIB_STYPE_REASSOC_REQ 0x0020 +#define RTLLIB_STYPE_REASSOC_RESP 0x0030 +#define RTLLIB_STYPE_PROBE_REQ 0x0040 +#define RTLLIB_STYPE_PROBE_RESP 0x0050 +#define RTLLIB_STYPE_BEACON 0x0080 +#define RTLLIB_STYPE_ATIM 0x0090 +#define RTLLIB_STYPE_DISASSOC 0x00A0 +#define RTLLIB_STYPE_AUTH 0x00B0 +#define RTLLIB_STYPE_DEAUTH 0x00C0 +#define RTLLIB_STYPE_MANAGE_ACT 0x00D0 + +/* control */ +#define RTLLIB_STYPE_PSPOLL 0x00A0 +#define RTLLIB_STYPE_RTS 0x00B0 +#define RTLLIB_STYPE_CTS 0x00C0 +#define RTLLIB_STYPE_ACK 0x00D0 +#define RTLLIB_STYPE_CFEND 0x00E0 +#define RTLLIB_STYPE_CFENDACK 0x00F0 +#define RTLLIB_STYPE_BLOCKACK 0x0094 + +/* data */ +#define RTLLIB_STYPE_DATA 0x0000 +#define RTLLIB_STYPE_DATA_CFACK 0x0010 +#define RTLLIB_STYPE_DATA_CFPOLL 0x0020 +#define RTLLIB_STYPE_DATA_CFACKPOLL 0x0030 +#define RTLLIB_STYPE_NULLFUNC 0x0040 +#define RTLLIB_STYPE_CFACK 0x0050 +#define RTLLIB_STYPE_CFPOLL 0x0060 +#define RTLLIB_STYPE_CFACKPOLL 0x0070 +#define RTLLIB_STYPE_QOS_DATA 0x0080 +#define RTLLIB_STYPE_QOS_NULL 0x00C0 + +#define RTLLIB_SCTL_FRAG 0x000F +#define RTLLIB_SCTL_SEQ 0xFFF0 + +/* QOS control */ +#define RTLLIB_QCTL_TID 0x000F + +#define FC_QOS_BIT BIT7 +#define IsDataFrame(pdu) (((pdu[0] & 0x0C) == 0x08) ? true : false) +#define IsLegacyDataFrame(pdu) (IsDataFrame(pdu) && (!(pdu[0]&FC_QOS_BIT))) +#define IsQoSDataFrame(pframe) \ + ((*(u16 *)pframe&(RTLLIB_STYPE_QOS_DATA|RTLLIB_FTYPE_DATA)) == \ + (RTLLIB_STYPE_QOS_DATA|RTLLIB_FTYPE_DATA)) +#define Frame_Order(pframe) (*(u16 *)pframe&RTLLIB_FCTL_ORDER) +#define SN_LESS(a, b) (((a-b)&0x800) != 0) +#define SN_EQUAL(a, b) (a == b) +#define MAX_DEV_ADDR_SIZE 8 + +enum act_category { + ACT_CAT_QOS = 1, + ACT_CAT_DLS = 2, + ACT_CAT_BA = 3, + ACT_CAT_HT = 7, + ACT_CAT_WMM = 17, +}; + +enum ts_action { + ACT_ADDTSREQ = 0, + ACT_ADDTSRSP = 1, + ACT_DELTS = 2, + ACT_SCHEDULE = 3, +}; + +enum ba_action { + ACT_ADDBAREQ = 0, + ACT_ADDBARSP = 1, + ACT_DELBA = 2, +}; + +enum init_gain_op_type { + IG_Backup = 0, + IG_Restore, + IG_Max +}; + +enum led_ctl_mode { + LED_CTL_POWER_ON = 1, + LED_CTL_LINK = 2, + LED_CTL_NO_LINK = 3, + LED_CTL_TX = 4, + LED_CTL_RX = 5, + LED_CTL_SITE_SURVEY = 6, + LED_CTL_POWER_OFF = 7, + LED_CTL_START_TO_LINK = 8, + LED_CTL_START_WPS = 9, + LED_CTL_STOP_WPS = 10, + LED_CTL_START_WPS_BOTTON = 11, + LED_CTL_STOP_WPS_FAIL = 12, + LED_CTL_STOP_WPS_FAIL_OVERLAP = 13, +}; + +enum rt_rf_type_def { + RF_1T2R = 0, + RF_2T4R, + RF_2T2R, + RF_1T1R, + RF_2T2R_GREEN, + RF_819X_MAX_TYPE +}; + +enum wireless_mode { + WIRELESS_MODE_UNKNOWN = 0x00, + WIRELESS_MODE_A = 0x01, + WIRELESS_MODE_B = 0x02, + WIRELESS_MODE_G = 0x04, + WIRELESS_MODE_AUTO = 0x08, + WIRELESS_MODE_N_24G = 0x10, + WIRELESS_MODE_N_5G = 0x20 +}; + +enum wireless_network_type { + WIRELESS_11B = 1, + WIRELESS_11G = 2, + WIRELESS_11A = 4, + WIRELESS_11N = 8 +}; + +#define OUI_SUBTYPE_WMM_INFO 0 +#define OUI_SUBTYPE_WMM_PARAM 1 +#define OUI_SUBTYPE_QOS_CAPABI 5 + +/* debug macros */ +extern u32 rtllib_debug_level; +#define RTLLIB_DEBUG(level, fmt, args...) \ +do { \ + if (rtllib_debug_level & (level)) \ + printk(KERN_DEBUG "rtllib: " fmt, ## args); \ +} while (0) + +#define RTLLIB_DEBUG_DATA(level, data, datalen) \ + do { \ + if ((rtllib_debug_level & (level)) == (level)) { \ + printk(KERN_DEBUG "rtllib: %s()\n", __func__); \ + print_hex_dump_bytes(KERN_DEBUG, DUMP_PREFIX_NONE, \ + data, datalen); \ + } \ + } while (0) + +/* To use the debug system; + * + * If you are defining a new debug classification, simply add it to the #define + * list here in the form of: + * + * #define RTLLIB_DL_xxxx VALUE + * + * shifting value to the left one bit from the previous entry. xxxx should be + * the name of the classification (for example, WEP) + * + * You then need to either add a RTLLIB_xxxx_DEBUG() macro definition for your + * classification, or use RTLLIB_DEBUG(RTLLIB_DL_xxxx, ...) whenever you want + * to send output to that classification. + * + * To add your debug level to the list of levels seen when you perform + * + * % cat /proc/net/ipw/debug_level + * + * you simply need to add your entry to the ipw_debug_levels array. + */ + +#define RTLLIB_DL_INFO (1<<0) +#define RTLLIB_DL_WX (1<<1) +#define RTLLIB_DL_SCAN (1<<2) +#define RTLLIB_DL_STATE (1<<3) +#define RTLLIB_DL_MGMT (1<<4) +#define RTLLIB_DL_FRAG (1<<5) +#define RTLLIB_DL_EAP (1<<6) +#define RTLLIB_DL_DROP (1<<7) + +#define RTLLIB_DL_TX (1<<8) +#define RTLLIB_DL_RX (1<<9) + +#define RTLLIB_DL_HT (1<<10) +#define RTLLIB_DL_BA (1<<11) +#define RTLLIB_DL_TS (1<<12) +#define RTLLIB_DL_QOS (1<<13) +#define RTLLIB_DL_REORDER (1<<14) +#define RTLLIB_DL_IOT (1<<15) +#define RTLLIB_DL_IPS (1<<16) +#define RTLLIB_DL_TRACE (1<<29) +#define RTLLIB_DL_DATA (1<<30) +#define RTLLIB_DL_ERR (1<<31) +#define RTLLIB_ERROR(f, a...) pr_err("rtllib: " f, ## a) +#define RTLLIB_WARNING(f, a...) pr_warn("rtllib: " f, ## a) +#define RTLLIB_DEBUG_INFO(f, a...) RTLLIB_DEBUG(RTLLIB_DL_INFO, f, ## a) + +#define RTLLIB_DEBUG_WX(f, a...) RTLLIB_DEBUG(RTLLIB_DL_WX, f, ## a) +#define RTLLIB_DEBUG_SCAN(f, a...) RTLLIB_DEBUG(RTLLIB_DL_SCAN, f, ## a) +#define RTLLIB_DEBUG_STATE(f, a...) RTLLIB_DEBUG(RTLLIB_DL_STATE, f, ## a) +#define RTLLIB_DEBUG_MGMT(f, a...) RTLLIB_DEBUG(RTLLIB_DL_MGMT, f, ## a) +#define RTLLIB_DEBUG_FRAG(f, a...) RTLLIB_DEBUG(RTLLIB_DL_FRAG, f, ## a) +#define RTLLIB_DEBUG_EAP(f, a...) RTLLIB_DEBUG(RTLLIB_DL_EAP, f, ## a) +#define RTLLIB_DEBUG_DROP(f, a...) RTLLIB_DEBUG(RTLLIB_DL_DROP, f, ## a) +#define RTLLIB_DEBUG_TX(f, a...) RTLLIB_DEBUG(RTLLIB_DL_TX, f, ## a) +#define RTLLIB_DEBUG_RX(f, a...) RTLLIB_DEBUG(RTLLIB_DL_RX, f, ## a) +#define RTLLIB_DEBUG_QOS(f, a...) RTLLIB_DEBUG(RTLLIB_DL_QOS, f, ## a) + +#ifndef ETH_P_PAE +#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ +#define ETH_P_IP 0x0800 /* Internet Protocol packet */ +#define ETH_P_ARP 0x0806 /* Address Resolution packet */ +#endif /* ETH_P_PAE */ + +#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */ + +#ifndef ETH_P_80211_RAW +#define ETH_P_80211_RAW (ETH_P_ECONET + 1) +#endif + +/* IEEE 802.11 defines */ + +#define P80211_OUI_LEN 3 + +struct rtllib_snap_hdr { + + u8 dsap; /* always 0xAA */ + u8 ssap; /* always 0xAA */ + u8 ctrl; /* always 0x03 */ + u8 oui[P80211_OUI_LEN]; /* organizational universal id */ + +} __packed; + +enum _REG_PREAMBLE_MODE { + PREAMBLE_LONG = 1, + PREAMBLE_AUTO = 2, + PREAMBLE_SHORT = 3, +}; + +#define SNAP_SIZE sizeof(struct rtllib_snap_hdr) + +#define WLAN_FC_GET_VERS(fc) ((fc) & RTLLIB_FCTL_VERS) +#define WLAN_FC_GET_TYPE(fc) ((fc) & RTLLIB_FCTL_FTYPE) +#define WLAN_FC_GET_STYPE(fc) ((fc) & RTLLIB_FCTL_STYPE) +#define WLAN_FC_MORE_DATA(fc) ((fc) & RTLLIB_FCTL_MOREDATA) + +#define WLAN_FC_GET_FRAMETYPE(fc) ((fc) & RTLLIB_FCTL_FRAMETYPE) +#define WLAN_GET_SEQ_FRAG(seq) ((seq) & RTLLIB_SCTL_FRAG) +#define WLAN_GET_SEQ_SEQ(seq) (((seq) & RTLLIB_SCTL_SEQ) >> 4) + +/* Authentication algorithms */ +#define WLAN_AUTH_OPEN 0 +#define WLAN_AUTH_SHARED_KEY 1 +#define WLAN_AUTH_LEAP 128 + +#define WLAN_AUTH_CHALLENGE_LEN 128 + +#define WLAN_CAPABILITY_ESS (1<<0) +#define WLAN_CAPABILITY_IBSS (1<<1) +#define WLAN_CAPABILITY_CF_POLLABLE (1<<2) +#define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3) +#define WLAN_CAPABILITY_PRIVACY (1<<4) +#define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5) +#define WLAN_CAPABILITY_PBCC (1<<6) +#define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7) +#define WLAN_CAPABILITY_SPECTRUM_MGMT (1<<8) +#define WLAN_CAPABILITY_QOS (1<<9) +#define WLAN_CAPABILITY_SHORT_SLOT_TIME (1<<10) +#define WLAN_CAPABILITY_DSSS_OFDM (1<<13) + +/* 802.11g ERP information element */ +#define WLAN_ERP_NON_ERP_PRESENT (1<<0) +#define WLAN_ERP_USE_PROTECTION (1<<1) +#define WLAN_ERP_BARKER_PREAMBLE (1<<2) + +#define RTLLIB_STATMASK_SIGNAL (1<<0) +#define RTLLIB_STATMASK_RSSI (1<<1) +#define RTLLIB_STATMASK_NOISE (1<<2) +#define RTLLIB_STATMASK_RATE (1<<3) +#define RTLLIB_STATMASK_WEMASK 0x7 + +#define RTLLIB_CCK_MODULATION (1<<0) +#define RTLLIB_OFDM_MODULATION (1<<1) + +#define RTLLIB_24GHZ_BAND (1<<0) +#define RTLLIB_52GHZ_BAND (1<<1) + +#define RTLLIB_CCK_RATE_LEN 4 +#define RTLLIB_CCK_RATE_1MB 0x02 +#define RTLLIB_CCK_RATE_2MB 0x04 +#define RTLLIB_CCK_RATE_5MB 0x0B +#define RTLLIB_CCK_RATE_11MB 0x16 +#define RTLLIB_OFDM_RATE_LEN 8 +#define RTLLIB_OFDM_RATE_6MB 0x0C +#define RTLLIB_OFDM_RATE_9MB 0x12 +#define RTLLIB_OFDM_RATE_12MB 0x18 +#define RTLLIB_OFDM_RATE_18MB 0x24 +#define RTLLIB_OFDM_RATE_24MB 0x30 +#define RTLLIB_OFDM_RATE_36MB 0x48 +#define RTLLIB_OFDM_RATE_48MB 0x60 +#define RTLLIB_OFDM_RATE_54MB 0x6C +#define RTLLIB_BASIC_RATE_MASK 0x80 + +#define RTLLIB_CCK_RATE_1MB_MASK (1<<0) +#define RTLLIB_CCK_RATE_2MB_MASK (1<<1) +#define RTLLIB_CCK_RATE_5MB_MASK (1<<2) +#define RTLLIB_CCK_RATE_11MB_MASK (1<<3) +#define RTLLIB_OFDM_RATE_6MB_MASK (1<<4) +#define RTLLIB_OFDM_RATE_9MB_MASK (1<<5) +#define RTLLIB_OFDM_RATE_12MB_MASK (1<<6) +#define RTLLIB_OFDM_RATE_18MB_MASK (1<<7) +#define RTLLIB_OFDM_RATE_24MB_MASK (1<<8) +#define RTLLIB_OFDM_RATE_36MB_MASK (1<<9) +#define RTLLIB_OFDM_RATE_48MB_MASK (1<<10) +#define RTLLIB_OFDM_RATE_54MB_MASK (1<<11) + +#define RTLLIB_CCK_RATES_MASK 0x0000000F +#define RTLLIB_CCK_BASIC_RATES_MASK (RTLLIB_CCK_RATE_1MB_MASK | \ + RTLLIB_CCK_RATE_2MB_MASK) +#define RTLLIB_CCK_DEFAULT_RATES_MASK (RTLLIB_CCK_BASIC_RATES_MASK | \ + RTLLIB_CCK_RATE_5MB_MASK | \ + RTLLIB_CCK_RATE_11MB_MASK) + +#define RTLLIB_OFDM_RATES_MASK 0x00000FF0 +#define RTLLIB_OFDM_BASIC_RATES_MASK (RTLLIB_OFDM_RATE_6MB_MASK | \ + RTLLIB_OFDM_RATE_12MB_MASK | \ + RTLLIB_OFDM_RATE_24MB_MASK) +#define RTLLIB_OFDM_DEFAULT_RATES_MASK (RTLLIB_OFDM_BASIC_RATES_MASK | \ + RTLLIB_OFDM_RATE_9MB_MASK | \ + RTLLIB_OFDM_RATE_18MB_MASK | \ + RTLLIB_OFDM_RATE_36MB_MASK | \ + RTLLIB_OFDM_RATE_48MB_MASK | \ + RTLLIB_OFDM_RATE_54MB_MASK) +#define RTLLIB_DEFAULT_RATES_MASK (RTLLIB_OFDM_DEFAULT_RATES_MASK | \ + RTLLIB_CCK_DEFAULT_RATES_MASK) + +#define RTLLIB_NUM_OFDM_RATES 8 +#define RTLLIB_NUM_CCK_RATES 4 +#define RTLLIB_OFDM_SHIFT_MASK_A 4 + + +/* this is stolen and modified from the madwifi driver*/ +#define RTLLIB_FC0_TYPE_MASK 0x0c +#define RTLLIB_FC0_TYPE_DATA 0x08 +#define RTLLIB_FC0_SUBTYPE_MASK 0xB0 +#define RTLLIB_FC0_SUBTYPE_QOS 0x80 + +#define RTLLIB_QOS_HAS_SEQ(fc) \ + (((fc) & (RTLLIB_FC0_TYPE_MASK | RTLLIB_FC0_SUBTYPE_MASK)) == \ + (RTLLIB_FC0_TYPE_DATA | RTLLIB_FC0_SUBTYPE_QOS)) + +/* this is stolen from ipw2200 driver */ +#define IEEE_IBSS_MAC_HASH_SIZE 31 +struct ieee_ibss_seq { + u8 mac[ETH_ALEN]; + u16 seq_num[17]; + u16 frag_num[17]; + unsigned long packet_time[17]; + struct list_head list; +}; + +/* NOTE: This data is for statistical purposes; not all hardware provides this + * information for frames received. Not setting these will not cause + * any adverse affects. */ +struct rtllib_rx_stats { + u64 mac_time; + s8 rssi; + u8 signal; + u8 noise; + u16 rate; /* in 100 kbps */ + u8 received_channel; + u8 control; + u8 mask; + u8 freq; + u16 len; + u64 tsf; + u32 beacon_time; + u8 nic_type; + u16 Length; + u8 SignalQuality; + s32 RecvSignalPower; + s8 RxPower; + u8 SignalStrength; + u16 bHwError:1; + u16 bCRC:1; + u16 bICV:1; + u16 bShortPreamble:1; + u16 Antenna:1; + u16 Decrypted:1; + u16 Wakeup:1; + u16 Reserved0:1; + u8 AGC; + u32 TimeStampLow; + u32 TimeStampHigh; + bool bShift; + bool bIsQosData; + u8 UserPriority; + + u8 RxDrvInfoSize; + u8 RxBufShift; + bool bIsAMPDU; + bool bFirstMPDU; + bool bContainHTC; + bool RxIs40MHzPacket; + u32 RxPWDBAll; + u8 RxMIMOSignalStrength[4]; + s8 RxMIMOSignalQuality[2]; + bool bPacketMatchBSSID; + bool bIsCCK; + bool bPacketToSelf; + u8 *virtual_address; + u16 packetlength; + u16 fraglength; + u16 fragoffset; + u16 ntotalfrag; + bool bisrxaggrsubframe; + bool bPacketBeacon; + bool bToSelfBA; + char cck_adc_pwdb[4]; + u16 Seq_Num; + u8 nTotalAggPkt; +}; + +/* IEEE 802.11 requires that STA supports concurrent reception of at least + * three fragmented frames. This define can be increased to support more + * concurrent frames, but it should be noted that each entry can consume about + * 2 kB of RAM and increasing cache size will slow down frame reassembly. + */ +#define RTLLIB_FRAG_CACHE_LEN 4 + +struct rtllib_frag_entry { + unsigned long first_frag_time; + unsigned int seq; + unsigned int last_frag; + struct sk_buff *skb; + u8 src_addr[ETH_ALEN]; + u8 dst_addr[ETH_ALEN]; +}; + +struct rtllib_stats { + unsigned int tx_unicast_frames; + unsigned int tx_multicast_frames; + unsigned int tx_fragments; + unsigned int tx_unicast_octets; + unsigned int tx_multicast_octets; + unsigned int tx_deferred_transmissions; + unsigned int tx_single_retry_frames; + unsigned int tx_multiple_retry_frames; + unsigned int tx_retry_limit_exceeded; + unsigned int tx_discards; + unsigned int rx_unicast_frames; + unsigned int rx_multicast_frames; + unsigned int rx_fragments; + unsigned int rx_unicast_octets; + unsigned int rx_multicast_octets; + unsigned int rx_fcs_errors; + unsigned int rx_discards_no_buffer; + unsigned int tx_discards_wrong_sa; + unsigned int rx_discards_undecryptable; + unsigned int rx_message_in_msg_fragments; + unsigned int rx_message_in_bad_msg_fragments; +}; + +struct rtllib_device; + +#define SEC_KEY_1 (1<<0) +#define SEC_KEY_2 (1<<1) +#define SEC_KEY_3 (1<<2) +#define SEC_KEY_4 (1<<3) +#define SEC_ACTIVE_KEY (1<<4) +#define SEC_AUTH_MODE (1<<5) +#define SEC_UNICAST_GROUP (1<<6) +#define SEC_LEVEL (1<<7) +#define SEC_ENABLED (1<<8) +#define SEC_ENCRYPT (1<<9) + +#define SEC_LEVEL_0 0 /* None */ +#define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */ +#define SEC_LEVEL_2 2 /* Level 1 + TKIP */ +#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */ +#define SEC_LEVEL_3 4 /* Level 2 + CCMP */ + +#define SEC_ALG_NONE 0 +#define SEC_ALG_WEP 1 +#define SEC_ALG_TKIP 2 +#define SEC_ALG_CCMP 4 + +#define WEP_KEY_LEN 13 +#define SCM_KEY_LEN 32 +#define SCM_TEMPORAL_KEY_LENGTH 16 + +struct rtllib_security { + u16 active_key:2, + enabled:1, + auth_mode:2, + auth_algo:4, + unicast_uses_group:1, + encrypt:1; + u8 key_sizes[NUM_WEP_KEYS]; + u8 keys[NUM_WEP_KEYS][SCM_KEY_LEN]; + u8 level; + u16 flags; +} __packed; + + +/* 802.11 data frame from AP + * ,-------------------------------------------------------------------. + * Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 | + * |------|------|---------|---------|---------|------|---------|------| + * Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | frame | fcs | + * | | tion | (BSSID) | | | ence | data | | + * `-------------------------------------------------------------------' + * Total: 28-2340 bytes + */ + +/* Management Frame Information Element Types */ +enum rtllib_mfie { + MFIE_TYPE_SSID = 0, + MFIE_TYPE_RATES = 1, + MFIE_TYPE_FH_SET = 2, + MFIE_TYPE_DS_SET = 3, + MFIE_TYPE_CF_SET = 4, + MFIE_TYPE_TIM = 5, + MFIE_TYPE_IBSS_SET = 6, + MFIE_TYPE_COUNTRY = 7, + MFIE_TYPE_HOP_PARAMS = 8, + MFIE_TYPE_HOP_TABLE = 9, + MFIE_TYPE_REQUEST = 10, + MFIE_TYPE_CHALLENGE = 16, + MFIE_TYPE_POWER_CONSTRAINT = 32, + MFIE_TYPE_POWER_CAPABILITY = 33, + MFIE_TYPE_TPC_REQUEST = 34, + MFIE_TYPE_TPC_REPORT = 35, + MFIE_TYPE_SUPP_CHANNELS = 36, + MFIE_TYPE_CSA = 37, + MFIE_TYPE_MEASURE_REQUEST = 38, + MFIE_TYPE_MEASURE_REPORT = 39, + MFIE_TYPE_QUIET = 40, + MFIE_TYPE_IBSS_DFS = 41, + MFIE_TYPE_ERP = 42, + MFIE_TYPE_HT_CAP = 45, + MFIE_TYPE_RSN = 48, + MFIE_TYPE_RATES_EX = 50, + MFIE_TYPE_HT_INFO = 61, + MFIE_TYPE_AIRONET = 133, + MFIE_TYPE_GENERIC = 221, + MFIE_TYPE_QOS_PARAMETER = 222, +}; + +/* Minimal header; can be used for passing 802.11 frames with sufficient + * information to determine what type of underlying data type is actually + * stored in the data. + */ +struct rtllib_pspoll_hdr { + __le16 frame_ctl; + __le16 aid; + u8 bssid[ETH_ALEN]; + u8 ta[ETH_ALEN]; +} __packed; + +struct rtllib_hdr { + __le16 frame_ctl; + __le16 duration_id; + u8 payload[0]; +} __packed; + +struct rtllib_hdr_1addr { + __le16 frame_ctl; + __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 payload[0]; +} __packed; + +struct rtllib_hdr_2addr { + __le16 frame_ctl; + __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 payload[0]; +} __packed; + +struct rtllib_hdr_3addr { + __le16 frame_ctl; + __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + __le16 seq_ctl; + u8 payload[0]; +} __packed; + +struct rtllib_hdr_4addr { + __le16 frame_ctl; + __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + __le16 seq_ctl; + u8 addr4[ETH_ALEN]; + u8 payload[0]; +} __packed; + +struct rtllib_hdr_3addrqos { + __le16 frame_ctl; + __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + __le16 seq_ctl; + __le16 qos_ctl; + u8 payload[0]; +} __packed; + +struct rtllib_hdr_4addrqos { + __le16 frame_ctl; + __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + __le16 seq_ctl; + u8 addr4[ETH_ALEN]; + __le16 qos_ctl; + u8 payload[0]; +} __packed; + +struct rtllib_info_element { + u8 id; + u8 len; + u8 data[0]; +} __packed; + +struct rtllib_authentication { + struct rtllib_hdr_3addr header; + __le16 algorithm; + __le16 transaction; + __le16 status; + /*challenge*/ + struct rtllib_info_element info_element[0]; +} __packed; + +struct rtllib_disauth { + struct rtllib_hdr_3addr header; + __le16 reason; +} __packed; + +struct rtllib_disassoc { + struct rtllib_hdr_3addr header; + __le16 reason; +} __packed; + +struct rtllib_probe_request { + struct rtllib_hdr_3addr header; + /* SSID, supported rates */ + struct rtllib_info_element info_element[0]; +} __packed; + +struct rtllib_probe_response { + struct rtllib_hdr_3addr header; + u32 time_stamp[2]; + __le16 beacon_interval; + __le16 capability; + /* SSID, supported rates, FH params, DS params, + * CF params, IBSS params, TIM (if beacon), RSN + */ + struct rtllib_info_element info_element[0]; +} __packed; + +/* Alias beacon for probe_response */ +#define rtllib_beacon rtllib_probe_response + +struct rtllib_assoc_request_frame { + struct rtllib_hdr_3addr header; + __le16 capability; + __le16 listen_interval; + /* SSID, supported rates, RSN */ + struct rtllib_info_element info_element[0]; +} __packed; + +struct rtllib_reassoc_request_frame { + struct rtllib_hdr_3addr header; + __le16 capability; + __le16 listen_interval; + u8 current_ap[ETH_ALEN]; + /* SSID, supported rates, RSN */ + struct rtllib_info_element info_element[0]; +} __packed; + +struct rtllib_assoc_response_frame { + struct rtllib_hdr_3addr header; + __le16 capability; + __le16 status; + __le16 aid; + struct rtllib_info_element info_element[0]; /* supported rates */ +} __packed; + +struct rtllib_txb { + u8 nr_frags; + u8 encrypted; + u8 queue_index; + u8 rts_included; + u16 reserved; + __le16 frag_size; + __le16 payload_size; + struct sk_buff *fragments[0]; +}; + +#define MAX_TX_AGG_COUNT 16 +struct rtllib_drv_agg_txb { + u8 nr_drv_agg_frames; + struct sk_buff *tx_agg_frames[MAX_TX_AGG_COUNT]; +} __packed; + +#define MAX_SUBFRAME_COUNT 64 +struct rtllib_rxb { + u8 nr_subframes; + struct sk_buff *subframes[MAX_SUBFRAME_COUNT]; + u8 dst[ETH_ALEN]; + u8 src[ETH_ALEN]; +} __packed; + +union frameqos { + u16 shortdata; + u8 chardata[2]; + struct { + u16 tid:4; + u16 eosp:1; + u16 ack_policy:2; + u16 reserved:1; + u16 txop:8; + } field; +}; + +/* SWEEP TABLE ENTRIES NUMBER*/ +#define MAX_SWEEP_TAB_ENTRIES 42 +#define MAX_SWEEP_TAB_ENTRIES_PER_PACKET 7 +/* MAX_RATES_LENGTH needs to be 12. The spec says 8, and many APs + * only use 8, and then use extended rates for the remaining supported + * rates. Other APs, however, stick all of their supported rates on the + * main rates information element... + */ +#define MAX_RATES_LENGTH ((u8)12) +#define MAX_RATES_EX_LENGTH ((u8)16) +#define MAX_NETWORK_COUNT 96 + +#define MAX_CHANNEL_NUMBER 161 +#define RTLLIB_SOFTMAC_SCAN_TIME 100 +#define RTLLIB_SOFTMAC_ASSOC_RETRY_TIME (HZ * 2) + +#define CRC_LENGTH 4U + +#define MAX_WPA_IE_LEN 64 +#define MAX_WZC_IE_LEN 256 + +#define NETWORK_EMPTY_ESSID (1<<0) +#define NETWORK_HAS_OFDM (1<<1) +#define NETWORK_HAS_CCK (1<<2) + +/* QoS structure */ +#define NETWORK_HAS_QOS_PARAMETERS (1<<3) +#define NETWORK_HAS_QOS_INFORMATION (1<<4) +#define NETWORK_HAS_QOS_MASK (NETWORK_HAS_QOS_PARAMETERS | \ + NETWORK_HAS_QOS_INFORMATION) +/* 802.11h */ +#define NETWORK_HAS_POWER_CONSTRAINT (1<<5) +#define NETWORK_HAS_CSA (1<<6) +#define NETWORK_HAS_QUIET (1<<7) +#define NETWORK_HAS_IBSS_DFS (1<<8) +#define NETWORK_HAS_TPC_REPORT (1<<9) + +#define NETWORK_HAS_ERP_VALUE (1<<10) + +#define QOS_QUEUE_NUM 4 +#define QOS_OUI_LEN 3 +#define QOS_OUI_TYPE 2 +#define QOS_ELEMENT_ID 221 +#define QOS_OUI_INFO_SUB_TYPE 0 +#define QOS_OUI_PARAM_SUB_TYPE 1 +#define QOS_VERSION_1 1 +#define QOS_AIFSN_MIN_VALUE 2 + +struct rtllib_qos_information_element { + u8 elementID; + u8 length; + u8 qui[QOS_OUI_LEN]; + u8 qui_type; + u8 qui_subtype; + u8 version; + u8 ac_info; +} __packed; + +struct rtllib_qos_ac_parameter { + u8 aci_aifsn; + u8 ecw_min_max; + __le16 tx_op_limit; +} __packed; + +struct rtllib_qos_parameter_info { + struct rtllib_qos_information_element info_element; + u8 reserved; + struct rtllib_qos_ac_parameter ac_params_record[QOS_QUEUE_NUM]; +} __packed; + +struct rtllib_qos_parameters { + __le16 cw_min[QOS_QUEUE_NUM]; + __le16 cw_max[QOS_QUEUE_NUM]; + u8 aifs[QOS_QUEUE_NUM]; + u8 flag[QOS_QUEUE_NUM]; + __le16 tx_op_limit[QOS_QUEUE_NUM]; +} __packed; + +struct rtllib_qos_data { + struct rtllib_qos_parameters parameters; + unsigned int wmm_acm; + int active; + int supported; + u8 param_count; + u8 old_param_count; +}; + +struct rtllib_tim_parameters { + u8 tim_count; + u8 tim_period; +} __packed; + +struct rtllib_wmm_ac_param { + u8 ac_aci_acm_aifsn; + u8 ac_ecwmin_ecwmax; + u16 ac_txop_limit; +}; + +struct rtllib_wmm_ts_info { + u8 ac_dir_tid; + u8 ac_up_psb; + u8 reserved; +} __packed; + +struct rtllib_wmm_tspec_elem { + struct rtllib_wmm_ts_info ts_info; + u16 norm_msdu_size; + u16 max_msdu_size; + u32 min_serv_inter; + u32 max_serv_inter; + u32 inact_inter; + u32 suspen_inter; + u32 serv_start_time; + u32 min_data_rate; + u32 mean_data_rate; + u32 peak_data_rate; + u32 max_burst_size; + u32 delay_bound; + u32 min_phy_rate; + u16 surp_band_allow; + u16 medium_time; +} __packed; + +enum eap_type { + EAP_PACKET = 0, + EAPOL_START, + EAPOL_LOGOFF, + EAPOL_KEY, + EAPOL_ENCAP_ASF_ALERT +}; + +static const char * const eap_types[] = { + [EAP_PACKET] = "EAP-Packet", + [EAPOL_START] = "EAPOL-Start", + [EAPOL_LOGOFF] = "EAPOL-Logoff", + [EAPOL_KEY] = "EAPOL-Key", + [EAPOL_ENCAP_ASF_ALERT] = "EAPOL-Encap-ASF-Alert" +}; + +static inline const char *eap_get_type(int type) +{ + return ((u32)type >= ARRAY_SIZE(eap_types)) ? "Unknown" : + eap_types[type]; +} +static inline u8 Frame_QoSTID(u8 *buf) +{ + struct rtllib_hdr_3addr *hdr; + u16 fc; + + hdr = (struct rtllib_hdr_3addr *)buf; + fc = le16_to_cpu(hdr->frame_ctl); + return (u8)((union frameqos *)(buf + (((fc & RTLLIB_FCTL_TODS) && + (fc & RTLLIB_FCTL_FROMDS)) ? 30 : 24)))->field.tid; +} + + +struct eapol { + u8 snap[6]; + u16 ethertype; + u8 version; + u8 type; + u16 length; +} __packed; + +struct rtllib_softmac_stats { + unsigned int rx_ass_ok; + unsigned int rx_ass_err; + unsigned int rx_probe_rq; + unsigned int tx_probe_rs; + unsigned int tx_beacons; + unsigned int rx_auth_rq; + unsigned int rx_auth_rs_ok; + unsigned int rx_auth_rs_err; + unsigned int tx_auth_rq; + unsigned int no_auth_rs; + unsigned int no_ass_rs; + unsigned int tx_ass_rq; + unsigned int rx_ass_rq; + unsigned int tx_probe_rq; + unsigned int reassoc; + unsigned int swtxstop; + unsigned int swtxawake; + unsigned char CurrentShowTxate; + unsigned char last_packet_rate; + unsigned int txretrycount; +}; + +#define BEACON_PROBE_SSID_ID_POSITION 12 + +struct rtllib_info_element_hdr { + u8 id; + u8 len; +} __packed; + +/* These are the data types that can make up management packets + * + * u16 auth_algorithm; + * u16 auth_sequence; + * u16 beacon_interval; + * u16 capability; + * u8 current_ap[ETH_ALEN]; + * u16 listen_interval; + * struct { + * u16 association_id:14, reserved:2; + * } __packed; + * u32 time_stamp[2]; + * u16 reason; + * u16 status; + */ + +#define RTLLIB_DEFAULT_TX_ESSID "Penguin" +#define RTLLIB_DEFAULT_BASIC_RATE 2 + +enum {WMM_all_frame, WMM_two_frame, WMM_four_frame, WMM_six_frame}; +#define MAX_SP_Len (WMM_all_frame << 4) +#define RTLLIB_QOS_TID 0x0f +#define QOS_CTL_NOTCONTAIN_ACK (0x01 << 5) + +#define RTLLIB_DTIM_MBCAST 4 +#define RTLLIB_DTIM_UCAST 2 +#define RTLLIB_DTIM_VALID 1 +#define RTLLIB_DTIM_INVALID 0 + +#define RTLLIB_PS_DISABLED 0 +#define RTLLIB_PS_UNICAST RTLLIB_DTIM_UCAST +#define RTLLIB_PS_MBCAST RTLLIB_DTIM_MBCAST + +#define WME_AC_BK 0x00 +#define WME_AC_BE 0x01 +#define WME_AC_VI 0x02 +#define WME_AC_VO 0x03 +#define WME_ACI_MASK 0x03 +#define WME_AIFSN_MASK 0x03 +#define WME_AC_PRAM_LEN 16 + +#define MAX_RECEIVE_BUFFER_SIZE 9100 + +#define UP2AC(up) ( \ + ((up) < 1) ? WME_AC_BE : \ + ((up) < 3) ? WME_AC_BK : \ + ((up) < 4) ? WME_AC_BE : \ + ((up) < 6) ? WME_AC_VI : \ + WME_AC_VO) + +#define AC2UP(_ac) ( \ + ((_ac) == WME_AC_VO) ? 6 : \ + ((_ac) == WME_AC_VI) ? 5 : \ + ((_ac) == WME_AC_BK) ? 1 : \ + 0) + +#define ETHER_ADDR_LEN 6 /* length of an Ethernet address */ +#define ETHERNET_HEADER_SIZE 14 /* length of two Ethernet address + * plus ether type*/ + +struct ether_header { + u8 ether_dhost[ETHER_ADDR_LEN]; + u8 ether_shost[ETHER_ADDR_LEN]; + u16 ether_type; +} __packed; + +#ifndef ETHERTYPE_PAE +#define ETHERTYPE_PAE 0x888e /* EAPOL PAE/802.1x */ +#endif +#ifndef ETHERTYPE_IP +#define ETHERTYPE_IP 0x0800 /* IP protocol */ +#endif + + +enum erp_t { + ERP_NonERPpresent = 0x01, + ERP_UseProtection = 0x02, + ERP_BarkerPreambleMode = 0x04, +}; + +struct rtllib_network { + /* These entries are used to identify a unique network */ + u8 bssid[ETH_ALEN]; + u8 channel; + /* Ensure null-terminated for any debug msgs */ + u8 ssid[IW_ESSID_MAX_SIZE + 1]; + u8 ssid_len; + u8 hidden_ssid[IW_ESSID_MAX_SIZE + 1]; + u8 hidden_ssid_len; + struct rtllib_qos_data qos_data; + + bool bWithAironetIE; + bool bCkipSupported; + bool bCcxRmEnable; + u16 CcxRmState[2]; + bool bMBssidValid; + u8 MBssidMask; + u8 MBssid[6]; + bool bWithCcxVerNum; + u8 BssCcxVerNumber; + /* These are network statistics */ + struct rtllib_rx_stats stats; + u16 capability; + u8 rates[MAX_RATES_LENGTH]; + u8 rates_len; + u8 rates_ex[MAX_RATES_EX_LENGTH]; + u8 rates_ex_len; + unsigned long last_scanned; + u8 mode; + u32 flags; + u32 last_associate; + u32 time_stamp[2]; + u16 beacon_interval; + u16 listen_interval; + u16 atim_window; + u8 erp_value; + u8 wpa_ie[MAX_WPA_IE_LEN]; + size_t wpa_ie_len; + u8 rsn_ie[MAX_WPA_IE_LEN]; + size_t rsn_ie_len; + u8 wzc_ie[MAX_WZC_IE_LEN]; + size_t wzc_ie_len; + + struct rtllib_tim_parameters tim; + u8 dtim_period; + u8 dtim_data; + u64 last_dtim_sta_time; + + u8 wmm_info; + struct rtllib_wmm_ac_param wmm_param[4]; + u8 Turbo_Enable; + u16 CountryIeLen; + u8 CountryIeBuf[MAX_IE_LEN]; + struct bss_ht bssht; + bool broadcom_cap_exist; + bool realtek_cap_exit; + bool marvell_cap_exist; + bool ralink_cap_exist; + bool atheros_cap_exist; + bool cisco_cap_exist; + bool airgo_cap_exist; + bool unknown_cap_exist; + bool berp_info_valid; + bool buseprotection; + bool bIsNetgear854T; + u8 SignalStrength; + u8 RSSI; + struct list_head list; +}; + +enum rtllib_state { + + /* the card is not linked at all */ + RTLLIB_NOLINK = 0, + + /* RTLLIB_ASSOCIATING* are for BSS client mode + * the driver shall not perform RX filtering unless + * the state is LINKED. + * The driver shall just check for the state LINKED and + * defaults to NOLINK for ALL the other states (including + * LINKED_SCANNING) + */ + + /* the association procedure will start (wq scheduling)*/ + RTLLIB_ASSOCIATING, + RTLLIB_ASSOCIATING_RETRY, + + /* the association procedure is sending AUTH request*/ + RTLLIB_ASSOCIATING_AUTHENTICATING, + + /* the association procedure has successfully authenticated + * and is sending association request + */ + RTLLIB_ASSOCIATING_AUTHENTICATED, + + /* the link is ok. the card associated to a BSS or linked + * to a ibss cell or acting as an AP and creating the bss + */ + RTLLIB_LINKED, + + /* same as LINKED, but the driver shall apply RX filter + * rules as we are in NO_LINK mode. As the card is still + * logically linked, but it is doing a syncro site survey + * then it will be back to LINKED state. + */ + RTLLIB_LINKED_SCANNING, +}; + +#define DEFAULT_MAX_SCAN_AGE (15 * HZ) +#define DEFAULT_FTS 2346 + +#define CFG_RTLLIB_RESERVE_FCS (1<<0) +#define CFG_RTLLIB_COMPUTE_FCS (1<<1) +#define CFG_RTLLIB_RTS (1<<2) + +#define RTLLIB_24GHZ_MIN_CHANNEL 1 +#define RTLLIB_24GHZ_MAX_CHANNEL 14 +#define RTLLIB_24GHZ_CHANNELS (RTLLIB_24GHZ_MAX_CHANNEL - \ + RTLLIB_24GHZ_MIN_CHANNEL + 1) + +#define RTLLIB_52GHZ_MIN_CHANNEL 34 +#define RTLLIB_52GHZ_MAX_CHANNEL 165 +#define RTLLIB_52GHZ_CHANNELS (RTLLIB_52GHZ_MAX_CHANNEL - \ + RTLLIB_52GHZ_MIN_CHANNEL + 1) +struct tx_pending { + int frag; + struct rtllib_txb *txb; +}; + +struct bandwidth_autoswitch { + long threshold_20Mhzto40Mhz; + long threshold_40Mhzto20Mhz; + bool bforced_tx20Mhz; + bool bautoswitch_enable; +}; + + + +#define REORDER_WIN_SIZE 128 +#define REORDER_ENTRY_NUM 128 +struct rx_reorder_entry { + struct list_head List; + u16 SeqNum; + struct rtllib_rxb *prxb; +}; +enum fsync_state { + Default_Fsync, + HW_Fsync, + SW_Fsync +}; + +enum rt_ps_mode { + eActive, + eMaxPs, + eFastPs, + eAutoPs, +}; + +enum ips_callback_function { + IPS_CALLBACK_NONE = 0, + IPS_CALLBACK_MGNT_LINK_REQUEST = 1, + IPS_CALLBACK_JOIN_REQUEST = 2, +}; + +enum rt_join_action { + RT_JOIN_INFRA = 1, + RT_JOIN_IBSS = 2, + RT_START_IBSS = 3, + RT_NO_ACTION = 4, +}; + +struct ibss_parms { + u16 atimWin; +}; +#define MAX_NUM_RATES 264 + +enum rt_rf_power_state { + eRfOn, + eRfSleep, + eRfOff +}; + +#define MAX_SUPPORT_WOL_PATTERN_NUM 8 + +#define MAX_WOL_BIT_MASK_SIZE 16 +#define MAX_WOL_PATTERN_SIZE 128 + +enum wol_pattern_type { + eNetBIOS = 0, + eIPv4IPv6ARP, + eIPv4IPv6TCPSYN, + eMACIDOnly, + eNoDefined, +}; + +struct rt_pm_wol_info { + u32 PatternId; + u32 Mask[4]; + u16 CrcRemainder; + u8 WFMIndex; + enum wol_pattern_type PatternType; +}; + +struct rt_pwr_save_ctrl { + + bool bInactivePs; + bool bIPSModeBackup; + bool bHaltAdapterClkRQ; + bool bSwRfProcessing; + enum rt_rf_power_state eInactivePowerState; + struct work_struct InactivePsWorkItem; + struct timer_list InactivePsTimer; + + enum ips_callback_function ReturnPoint; + + bool bTmpBssDesc; + enum rt_join_action tmpJoinAction; + struct rtllib_network tmpBssDesc; + + bool bTmpScanOnly; + bool bTmpActiveScan; + bool bTmpFilterHiddenAP; + bool bTmpUpdateParms; + u8 tmpSsidBuf[33]; + struct octet_string tmpSsid2Scan; + bool bTmpSsid2Scan; + u8 tmpNetworkType; + u8 tmpChannelNumber; + u16 tmpBcnPeriod; + u8 tmpDtimPeriod; + u16 tmpmCap; + struct octet_string tmpSuppRateSet; + u8 tmpSuppRateBuf[MAX_NUM_RATES]; + bool bTmpSuppRate; + struct ibss_parms tmpIbpm; + bool bTmpIbpm; + + bool bLeisurePs; + u32 PowerProfile; + u8 LpsIdleCount; + u8 RegMaxLPSAwakeIntvl; + u8 LPSAwakeIntvl; + + u32 CurPsLevel; + u32 RegRfPsLevel; + + bool bFwCtrlLPS; + u8 FWCtrlPSMode; + + bool LinkReqInIPSRFOffPgs; + bool BufConnectinfoBefore; + + + bool bGpioRfSw; + + u8 RegAMDPciASPM; + + u8 oWLANMode; + struct rt_pm_wol_info PmWoLPatternInfo[MAX_SUPPORT_WOL_PATTERN_NUM]; + +}; + +#define RT_RF_CHANGE_SOURCE u32 + +#define RF_CHANGE_BY_SW BIT31 +#define RF_CHANGE_BY_HW BIT30 +#define RF_CHANGE_BY_PS BIT29 +#define RF_CHANGE_BY_IPS BIT28 +#define RF_CHANGE_BY_INIT 0 + +enum country_code_type { + COUNTRY_CODE_FCC = 0, + COUNTRY_CODE_IC = 1, + COUNTRY_CODE_ETSI = 2, + COUNTRY_CODE_SPAIN = 3, + COUNTRY_CODE_FRANCE = 4, + COUNTRY_CODE_MKK = 5, + COUNTRY_CODE_MKK1 = 6, + COUNTRY_CODE_ISRAEL = 7, + COUNTRY_CODE_TELEC = 8, + COUNTRY_CODE_MIC = 9, + COUNTRY_CODE_GLOBAL_DOMAIN = 10, + COUNTRY_CODE_WORLD_WIDE_13 = 11, + COUNTRY_CODE_TELEC_NETGEAR = 12, + COUNTRY_CODE_MAX +}; + +enum scan_op_backup_opt { + SCAN_OPT_BACKUP = 0, + SCAN_OPT_RESTORE, + SCAN_OPT_MAX +}; + +enum fw_cmd_io_type { + FW_CMD_DIG_ENABLE = 0, + FW_CMD_DIG_DISABLE = 1, + FW_CMD_DIG_HALT = 2, + FW_CMD_DIG_RESUME = 3, + FW_CMD_HIGH_PWR_ENABLE = 4, + FW_CMD_HIGH_PWR_DISABLE = 5, + FW_CMD_RA_RESET = 6, + FW_CMD_RA_ACTIVE = 7, + FW_CMD_RA_REFRESH_N = 8, + FW_CMD_RA_REFRESH_BG = 9, + FW_CMD_RA_INIT = 10, + FW_CMD_IQK_ENABLE = 11, + FW_CMD_TXPWR_TRACK_ENABLE = 12, + FW_CMD_TXPWR_TRACK_DISABLE = 13, + FW_CMD_TXPWR_TRACK_THERMAL = 14, + FW_CMD_PAUSE_DM_BY_SCAN = 15, + FW_CMD_RESUME_DM_BY_SCAN = 16, + FW_CMD_RA_REFRESH_N_COMB = 17, + FW_CMD_RA_REFRESH_BG_COMB = 18, + FW_CMD_ANTENNA_SW_ENABLE = 19, + FW_CMD_ANTENNA_SW_DISABLE = 20, + FW_CMD_TX_FEEDBACK_CCX_ENABLE = 21, + FW_CMD_LPS_ENTER = 22, + FW_CMD_LPS_LEAVE = 23, + FW_CMD_DIG_MODE_SS = 24, + FW_CMD_DIG_MODE_FA = 25, + FW_CMD_ADD_A2_ENTRY = 26, + FW_CMD_CTRL_DM_BY_DRIVER = 27, + FW_CMD_CTRL_DM_BY_DRIVER_NEW = 28, + FW_CMD_PAPE_CONTROL = 29, + FW_CMD_CHAN_SET = 30, +}; + +#define RT_MAX_LD_SLOT_NUM 10 +struct rt_link_detect { + + u32 NumRecvBcnInPeriod; + u32 NumRecvDataInPeriod; + + u32 RxBcnNum[RT_MAX_LD_SLOT_NUM]; + u32 RxDataNum[RT_MAX_LD_SLOT_NUM]; + u16 SlotNum; + u16 SlotIndex; + + u32 NumTxOkInPeriod; + u32 NumRxOkInPeriod; + u32 NumRxUnicastOkInPeriod; + bool bBusyTraffic; + bool bHigherBusyTraffic; + bool bHigherBusyRxTraffic; + u8 IdleCount; + u32 NumTxUnicastOkInPeriod; + u32 LastNumTxUnicast; + u32 LastNumRxUnicast; +}; + +struct sw_cam_table { + + u8 macaddr[6]; + bool bused; + u8 key_buf[16]; + u16 key_type; + u8 useDK; + u8 key_index; + +}; +#define TOTAL_CAM_ENTRY 32 +struct rate_adaptive { + u8 rate_adaptive_disabled; + u8 ratr_state; + u16 reserve; + + u32 high_rssi_thresh_for_ra; + u32 high2low_rssi_thresh_for_ra; + u8 low2high_rssi_thresh_for_ra40M; + u32 low_rssi_thresh_for_ra40M; + u8 low2high_rssi_thresh_for_ra20M; + u32 low_rssi_thresh_for_ra20M; + u32 upper_rssi_threshold_ratr; + u32 middle_rssi_threshold_ratr; + u32 low_rssi_threshold_ratr; + u32 low_rssi_threshold_ratr_40M; + u32 low_rssi_threshold_ratr_20M; + u8 ping_rssi_enable; + u32 ping_rssi_ratr; + u32 ping_rssi_thresh_for_ra; + u32 last_ratr; + u8 PreRATRState; + +}; +enum ratr_table_mode_8192s { + RATR_INX_WIRELESS_NGB = 0, + RATR_INX_WIRELESS_NG = 1, + RATR_INX_WIRELESS_NB = 2, + RATR_INX_WIRELESS_N = 3, + RATR_INX_WIRELESS_GB = 4, + RATR_INX_WIRELESS_G = 5, + RATR_INX_WIRELESS_B = 6, + RATR_INX_WIRELESS_MC = 7, + RATR_INX_WIRELESS_A = 8, +}; + +#define NUM_PMKID_CACHE 16 +struct rt_pmkid_list { + u8 bUsed; + u8 Bssid[6]; + u8 PMKID[16]; + u8 SsidBuf[33]; + u8 *ssid_octet; + u16 ssid_length; +}; + +struct rt_intel_promisc_mode { + bool bPromiscuousOn; + bool bFilterSourceStationFrame; +}; + + +/*************** DRIVER STATUS *****/ +#define STATUS_SCANNING 0 +#define STATUS_SCAN_HW 1 +#define STATUS_SCAN_ABORTING 2 +#define STATUS_SETTING_CHAN 3 +/*************** DRIVER STATUS *****/ + +enum { + NO_USE = 0, + USED = 1, + HW_SEC = 2, + SW_SEC = 3, +}; + +enum { + LPS_IS_WAKE = 0, + LPS_IS_SLEEP = 1, + LPS_WAIT_NULL_DATA_SEND = 2, +}; + +struct rtllib_device { + struct pci_dev *pdev; + struct net_device *dev; + struct rtllib_security sec; + + bool disable_mgnt_queue; + + unsigned long status; + short hwscan_ch_bk; + enum ht_extchnl_offset chan_offset_bk; + enum ht_channel_width bandwidth_bk; + u8 hwscan_sem_up; + u8 CntAfterLink; + + enum rt_op_mode OpMode; + + u8 VersionID; + /* The last AssocReq/Resp IEs */ + u8 *assocreq_ies, *assocresp_ies; + size_t assocreq_ies_len, assocresp_ies_len; + + bool b_customer_lenovo_id; + bool bForcedShowRxRate; + bool bForcedShowRateStill; + u8 SystemQueryDataRateCount; + bool bForcedBgMode; + bool bUseRAMask; + bool b1x1RecvCombine; + u8 RF_Type; + bool b1SSSupport; + + u8 hwsec_active; + bool is_silent_reset; + bool force_mic_error; + bool is_roaming; + bool ieee_up; + bool cannot_notify; + bool bSupportRemoteWakeUp; + enum rt_ps_mode dot11PowerSaveMode; + bool actscanning; + bool FirstIe_InScan; + bool be_scan_inprogress; + bool beinretry; + enum rt_rf_power_state eRFPowerState; + RT_RF_CHANGE_SOURCE RfOffReason; + bool is_set_key; + bool wx_set_enc; + struct rt_hi_throughput *pHTInfo; + spinlock_t bw_spinlock; + + spinlock_t reorder_spinlock; + u8 Regdot11HTOperationalRateSet[16]; + u8 Regdot11TxHTOperationalRateSet[16]; + u8 dot11HTOperationalRateSet[16]; + u8 RegHTSuppRateSet[16]; + u8 HTCurrentOperaRate; + u8 HTHighestOperaRate; + u8 MinSpaceCfg; + u8 MaxMssDensity; + u8 bTxDisableRateFallBack; + u8 bTxUseDriverAssingedRate; + u8 bTxEnableFwCalcDur; + atomic_t atm_chnlop; + atomic_t atm_swbw; + + struct list_head Tx_TS_Admit_List; + struct list_head Tx_TS_Pending_List; + struct list_head Tx_TS_Unused_List; + struct tx_ts_record TxTsRecord[TOTAL_TS_NUM]; + struct list_head Rx_TS_Admit_List; + struct list_head Rx_TS_Pending_List; + struct list_head Rx_TS_Unused_List; + struct rx_ts_record RxTsRecord[TOTAL_TS_NUM]; + struct rx_reorder_entry RxReorderEntry[128]; + struct list_head RxReorder_Unused_List; + u8 ForcedPriority; + + + /* Bookkeeping structures */ + struct net_device_stats stats; + struct rtllib_stats ieee_stats; + struct rtllib_softmac_stats softmac_stats; + + /* Probe / Beacon management */ + struct list_head network_free_list; + struct list_head network_list; + struct rtllib_network *networks; + int scans; + int scan_age; + + int iw_mode; /* operating mode (IW_MODE_*) */ + bool bNetPromiscuousMode; + struct rt_intel_promisc_mode IntelPromiscuousModeInfo; + + struct iw_spy_data spy_data; + + spinlock_t lock; + spinlock_t wpax_suitlist_lock; + + int tx_headroom; /* Set to size of any additional room needed at front + * of allocated Tx SKBs + */ + u32 config; + + /* WEP and other encryption related settings at the device level */ + int open_wep; /* Set to 1 to allow unencrypted frames */ + int auth_mode; + int reset_on_keychange; /* Set to 1 if the HW needs to be reset on + * WEP key changes + */ + + /* If the host performs {en,de}cryption, then set to 1 */ + int host_encrypt; + int host_encrypt_msdu; + int host_decrypt; + /* host performs multicast decryption */ + int host_mc_decrypt; + + /* host should strip IV and ICV from protected frames */ + /* meaningful only when hardware decryption is being used */ + int host_strip_iv_icv; + + int host_open_frag; + int host_build_iv; + int ieee802_1x; /* is IEEE 802.1X used */ + + /* WPA data */ + bool bHalfNMode; + bool bHalfWirelessN24GMode; + int wpa_enabled; + int drop_unencrypted; + int tkip_countermeasures; + int privacy_invoked; + size_t wpa_ie_len; + u8 *wpa_ie; + size_t wps_ie_len; + u8 *wps_ie; + u8 ap_mac_addr[6]; + u16 pairwise_key_type; + u16 group_key_type; + + struct lib80211_crypt_info crypt_info; + + struct sw_cam_table swcamtable[TOTAL_CAM_ENTRY]; + int bcrx_sta_key; /* use individual keys to override default keys even + * with RX of broad/multicast frames */ + + struct rt_pmkid_list PMKIDList[NUM_PMKID_CACHE]; + + /* Fragmentation structures */ + struct rtllib_frag_entry frag_cache[17][RTLLIB_FRAG_CACHE_LEN]; + unsigned int frag_next_idx[17]; + u16 fts; /* Fragmentation Threshold */ +#define DEFAULT_RTS_THRESHOLD 2346U +#define MIN_RTS_THRESHOLD 1 +#define MAX_RTS_THRESHOLD 2346U + u16 rts; /* RTS threshold */ + + /* Association info */ + u8 bssid[ETH_ALEN]; + + /* This stores infos for the current network. + * Either the network we are associated in INFRASTRUCTURE + * or the network that we are creating in MASTER mode. + * ad-hoc is a mixture ;-). + * Note that in infrastructure mode, even when not associated, + * fields bssid and essid may be valid (if wpa_set and essid_set + * are true) as thy carry the value set by the user via iwconfig + */ + struct rtllib_network current_network; + + enum rtllib_state state; + + int short_slot; + int reg_mode; + int mode; /* A, B, G */ + int modulation; /* CCK, OFDM */ + int freq_band; /* 2.4Ghz, 5.2Ghz, Mixed */ + int abg_true; /* ABG flag */ + + /* used for forcing the ibss workqueue to terminate + * without wait for the syncro scan to terminate + */ + short sync_scan_hurryup; + u16 scan_watch_dog; + int perfect_rssi; + int worst_rssi; + + u16 prev_seq_ctl; /* used to drop duplicate frames */ + + /* map of allowed channels. 0 is dummy */ + void *pDot11dInfo; + bool bGlobalDomain; + u8 active_channel_map[MAX_CHANNEL_NUMBER+1]; + + u8 IbssStartChnl; + u8 ibss_maxjoin_chal; + + int rate; /* current rate */ + int basic_rate; + u32 currentRate; + + short active_scan; + + /* this contains flags for selectively enable softmac support */ + u16 softmac_features; + + /* if the sequence control field is not filled by HW */ + u16 seq_ctrl[5]; + + /* association procedure transaction sequence number */ + u16 associate_seq; + + /* AID for RTXed association responses */ + u16 assoc_id; + + /* power save mode related*/ + u8 ack_tx_to_ieee; + short ps; + short sta_sleep; + int ps_timeout; + int ps_period; + struct tasklet_struct ps_task; + u64 ps_time; + bool polling; + + short raw_tx; + /* used if IEEE_SOFTMAC_TX_QUEUE is set */ + short queue_stop; + short scanning_continue; + short proto_started; + short proto_stoppping; + + struct semaphore wx_sem; + struct semaphore scan_sem; + struct semaphore ips_sem; + + spinlock_t mgmt_tx_lock; + spinlock_t beacon_lock; + + short beacon_txing; + + short wap_set; + short ssid_set; + + /* set on initialization */ + u8 qos_support; + unsigned int wmm_acm; + + /* for discarding duplicated packets in IBSS */ + struct list_head ibss_mac_hash[IEEE_IBSS_MAC_HASH_SIZE]; + + /* for discarding duplicated packets in BSS */ + u16 last_rxseq_num[17]; /* rx seq previous per-tid */ + u16 last_rxfrag_num[17];/* tx frag previous per-tid */ + unsigned long last_packet_time[17]; + + /* for PS mode */ + unsigned long last_rx_ps_time; + bool bAwakePktSent; + u8 LPSDelayCnt; + + /* used if IEEE_SOFTMAC_SINGLE_QUEUE is set */ + struct sk_buff *mgmt_queue_ring[MGMT_QUEUE_NUM]; + int mgmt_queue_head; + int mgmt_queue_tail; +#define RTLLIB_QUEUE_LIMIT 128 + u8 AsocRetryCount; + unsigned int hw_header; + struct sk_buff_head skb_waitQ[MAX_QUEUE_SIZE]; + struct sk_buff_head skb_aggQ[MAX_QUEUE_SIZE]; + struct sk_buff_head skb_drv_aggQ[MAX_QUEUE_SIZE]; + u32 sta_edca_param[4]; + bool aggregation; + bool enable_rx_imm_BA; + bool bibsscoordinator; + + bool bdynamic_txpower_enable; + + bool bCTSToSelfEnable; + u8 CTSToSelfTH; + + u32 fsync_time_interval; + u32 fsync_rate_bitmap; + u8 fsync_rssi_threshold; + bool bfsync_enable; + + u8 fsync_multiple_timeinterval; + u32 fsync_firstdiff_ratethreshold; + u32 fsync_seconddiff_ratethreshold; + enum fsync_state fsync_state; + bool bis_any_nonbepkts; + struct bandwidth_autoswitch bandwidth_auto_switch; + bool FwRWRF; + + struct rt_link_detect LinkDetectInfo; + bool bIsAggregateFrame; + struct rt_pwr_save_ctrl PowerSaveControl; + u8 amsdu_in_process; + + /* used if IEEE_SOFTMAC_TX_QUEUE is set */ + struct tx_pending tx_pending; + + /* used if IEEE_SOFTMAC_ASSOCIATE is set */ + struct timer_list associate_timer; + + /* used if IEEE_SOFTMAC_BEACONS is set */ + struct timer_list beacon_timer; + u8 need_sw_enc; + struct work_struct associate_complete_wq; + struct work_struct ips_leave_wq; + struct delayed_work associate_procedure_wq; + struct delayed_work softmac_scan_wq; + struct delayed_work softmac_hint11d_wq; + struct delayed_work associate_retry_wq; + struct delayed_work start_ibss_wq; + struct delayed_work hw_wakeup_wq; + struct delayed_work hw_sleep_wq; + struct delayed_work link_change_wq; + struct work_struct wx_sync_scan_wq; + + struct workqueue_struct *wq; + union { + struct rtllib_rxb *RfdArray[REORDER_WIN_SIZE]; + struct rtllib_rxb *stats_IndicateArray[REORDER_WIN_SIZE]; + struct rtllib_rxb *prxbIndicateArray[REORDER_WIN_SIZE]; + struct { + struct sw_chnl_cmd PreCommonCmd[MAX_PRECMD_CNT]; + struct sw_chnl_cmd PostCommonCmd[MAX_POSTCMD_CNT]; + struct sw_chnl_cmd RfDependCmd[MAX_RFDEPENDCMD_CNT]; + }; + }; + + /* Callback functions */ + void (*set_security)(struct net_device *dev, + struct rtllib_security *sec); + + /* Used to TX data frame by using txb structs. + * this is not used if in the softmac_features + * is set the flag IEEE_SOFTMAC_TX_QUEUE + */ + int (*hard_start_xmit)(struct rtllib_txb *txb, + struct net_device *dev); + + int (*reset_port)(struct net_device *dev); + int (*is_queue_full)(struct net_device *dev, int pri); + + int (*handle_management)(struct net_device *dev, + struct rtllib_network *network, u16 type); + int (*is_qos_active)(struct net_device *dev, struct sk_buff *skb); + + /* Softmac-generated frames (management) are TXed via this + * callback if the flag IEEE_SOFTMAC_SINGLE_QUEUE is + * not set. As some cards may have different HW queues that + * one might want to use for data and management frames + * the option to have two callbacks might be useful. + * This function can't sleep. + */ + int (*softmac_hard_start_xmit)(struct sk_buff *skb, + struct net_device *dev); + + /* used instead of hard_start_xmit (not softmac_hard_start_xmit) + * if the IEEE_SOFTMAC_TX_QUEUE feature is used to TX data + * frames. If the option IEEE_SOFTMAC_SINGLE_QUEUE is also set + * then also management frames are sent via this callback. + * This function can't sleep. + */ + void (*softmac_data_hard_start_xmit)(struct sk_buff *skb, + struct net_device *dev, int rate); + + /* stops the HW queue for DATA frames. Useful to avoid + * waste time to TX data frame when we are reassociating + * This function can sleep. + */ + void (*data_hard_stop)(struct net_device *dev); + + /* OK this is complementing to data_poll_hard_stop */ + void (*data_hard_resume)(struct net_device *dev); + + /* ask to the driver to retune the radio. + * This function can sleep. the driver should ensure + * the radio has been switched before return. + */ + void (*set_chan)(struct net_device *dev, short ch); + + /* These are not used if the ieee stack takes care of + * scanning (IEEE_SOFTMAC_SCAN feature set). + * In this case only the set_chan is used. + * + * The syncro version is similar to the start_scan but + * does not return until all channels has been scanned. + * this is called in user context and should sleep, + * it is called in a work_queue when switching to ad-hoc mode + * or in behalf of iwlist scan when the card is associated + * and root user ask for a scan. + * the function stop_scan should stop both the syncro and + * background scanning and can sleep. + * The function start_scan should initiate the background + * scanning and can't sleep. + */ + void (*scan_syncro)(struct net_device *dev); + void (*start_scan)(struct net_device *dev); + void (*stop_scan)(struct net_device *dev); + + void (*rtllib_start_hw_scan)(struct net_device *dev); + void (*rtllib_stop_hw_scan)(struct net_device *dev); + + /* indicate the driver that the link state is changed + * for example it may indicate the card is associated now. + * Driver might be interested in this to apply RX filter + * rules or simply light the LINK led + */ + void (*link_change)(struct net_device *dev); + + /* these two function indicates to the HW when to start + * and stop to send beacons. This is used when the + * IEEE_SOFTMAC_BEACONS is not set. For now the + * stop_send_bacons is NOT guaranteed to be called only + * after start_send_beacons. + */ + void (*start_send_beacons)(struct net_device *dev); + void (*stop_send_beacons)(struct net_device *dev); + + /* power save mode related */ + void (*sta_wake_up)(struct net_device *dev); + void (*enter_sleep_state)(struct net_device *dev, u64 time); + short (*ps_is_queue_empty)(struct net_device *dev); + int (*handle_beacon)(struct net_device *dev, + struct rtllib_beacon *beacon, + struct rtllib_network *network); + int (*handle_assoc_response)(struct net_device *dev, + struct rtllib_assoc_response_frame *resp, + struct rtllib_network *network); + + + /* check whether Tx hw resource available */ + short (*check_nic_enough_desc)(struct net_device *dev, int queue_index); + short (*get_nic_desc_num)(struct net_device *dev, int queue_index); + void (*SetBWModeHandler)(struct net_device *dev, + enum ht_channel_width Bandwidth, + enum ht_extchnl_offset Offset); + bool (*GetNmodeSupportBySecCfg)(struct net_device *dev); + void (*SetWirelessMode)(struct net_device *dev, u8 wireless_mode); + bool (*GetHalfNmodeSupportByAPsHandler)(struct net_device *dev); + u8 (*rtllib_ap_sec_type)(struct rtllib_device *ieee); + void (*HalUsbRxAggrHandler)(struct net_device *dev, bool Value); + void (*InitialGainHandler)(struct net_device *dev, u8 Operation); + bool (*SetFwCmdHandler)(struct net_device *dev, + enum fw_cmd_io_type FwCmdIO); + void (*UpdateHalRAMaskHandler)(struct net_device *dev, bool bMulticast, + u8 macId, u8 MimoPs, u8 WirelessMode, + u8 bCurTxBW40MHz, u8 rssi_level); + void (*UpdateBeaconInterruptHandler)(struct net_device *dev, + bool start); + void (*UpdateInterruptMaskHandler)(struct net_device *dev, u32 AddMSR, + u32 RemoveMSR); + u16 (*rtl_11n_user_show_rates)(struct net_device *dev); + void (*ScanOperationBackupHandler)(struct net_device *dev, + u8 Operation); + void (*LedControlHandler)(struct net_device *dev, + enum led_ctl_mode LedAction); + void (*SetHwRegHandler)(struct net_device *dev, u8 variable, u8 *val); + void (*GetHwRegHandler)(struct net_device *dev, u8 variable, u8 *val); + + void (*AllowAllDestAddrHandler)(struct net_device *dev, + bool bAllowAllDA, bool WriteIntoReg); + + void (*rtllib_ips_leave_wq)(struct net_device *dev); + void (*rtllib_ips_leave)(struct net_device *dev); + void (*LeisurePSLeave)(struct net_device *dev); + void (*rtllib_rfkill_poll)(struct net_device *dev); + + /* This must be the last item so that it points to the data + * allocated beyond this structure by alloc_rtllib + */ + u8 priv[0]; +}; + +#define IEEE_A (1<<0) +#define IEEE_B (1<<1) +#define IEEE_G (1<<2) +#define IEEE_N_24G (1<<4) +#define IEEE_N_5G (1<<5) +#define IEEE_MODE_MASK (IEEE_A|IEEE_B|IEEE_G) + +/* Generate a 802.11 header */ + +/* Uses the channel change callback directly + * instead of [start/stop] scan callbacks + */ +#define IEEE_SOFTMAC_SCAN (1<<2) + +/* Perform authentication and association handshake */ +#define IEEE_SOFTMAC_ASSOCIATE (1<<3) + +/* Generate probe requests */ +#define IEEE_SOFTMAC_PROBERQ (1<<4) + +/* Generate response to probe requests */ +#define IEEE_SOFTMAC_PROBERS (1<<5) + +/* The ieee802.11 stack will manage the netif queue + * wake/stop for the driver, taking care of 802.11 + * fragmentation. See softmac.c for details. + */ +#define IEEE_SOFTMAC_TX_QUEUE (1<<7) + +/* Uses only the softmac_data_hard_start_xmit + * even for TX management frames. + */ +#define IEEE_SOFTMAC_SINGLE_QUEUE (1<<8) + +/* Generate beacons. The stack will enqueue beacons + * to the card + */ +#define IEEE_SOFTMAC_BEACONS (1<<6) + + +static inline void *rtllib_priv(struct net_device *dev) +{ + return ((struct rtllib_device *)netdev_priv(dev))->priv; +} + +static inline int rtllib_is_empty_essid(const char *essid, int essid_len) +{ + /* Single white space is for Linksys APs */ + if (essid_len == 1 && essid[0] == ' ') + return 1; + + /* Otherwise, if the entire essid is 0, we assume it is hidden */ + while (essid_len) { + essid_len--; + if (essid[essid_len] != '\0') + return 0; + } + + return 1; +} + +static inline int rtllib_is_valid_mode(struct rtllib_device *ieee, int mode) +{ + /* It is possible for both access points and our device to support + * combinations of modes, so as long as there is one valid combination + * of ap/device supported modes, then return success + */ + if ((mode & IEEE_A) && + (ieee->modulation & RTLLIB_OFDM_MODULATION) && + (ieee->freq_band & RTLLIB_52GHZ_BAND)) + return 1; + + if ((mode & IEEE_G) && + (ieee->modulation & RTLLIB_OFDM_MODULATION) && + (ieee->freq_band & RTLLIB_24GHZ_BAND)) + return 1; + + if ((mode & IEEE_B) && + (ieee->modulation & RTLLIB_CCK_MODULATION) && + (ieee->freq_band & RTLLIB_24GHZ_BAND)) + return 1; + + return 0; +} + +static inline int rtllib_get_hdrlen(u16 fc) +{ + int hdrlen = RTLLIB_3ADDR_LEN; + + switch (WLAN_FC_GET_TYPE(fc)) { + case RTLLIB_FTYPE_DATA: + if ((fc & RTLLIB_FCTL_FROMDS) && (fc & RTLLIB_FCTL_TODS)) + hdrlen = RTLLIB_4ADDR_LEN; /* Addr4 */ + if (RTLLIB_QOS_HAS_SEQ(fc)) + hdrlen += 2; /* QOS ctrl*/ + break; + case RTLLIB_FTYPE_CTL: + switch (WLAN_FC_GET_STYPE(fc)) { + case RTLLIB_STYPE_CTS: + case RTLLIB_STYPE_ACK: + hdrlen = RTLLIB_1ADDR_LEN; + break; + default: + hdrlen = RTLLIB_2ADDR_LEN; + break; + } + break; + } + + return hdrlen; +} + +static inline u8 *rtllib_get_payload(struct rtllib_hdr *hdr) +{ + switch (rtllib_get_hdrlen(le16_to_cpu(hdr->frame_ctl))) { + case RTLLIB_1ADDR_LEN: + return ((struct rtllib_hdr_1addr *)hdr)->payload; + case RTLLIB_2ADDR_LEN: + return ((struct rtllib_hdr_2addr *)hdr)->payload; + case RTLLIB_3ADDR_LEN: + return ((struct rtllib_hdr_3addr *)hdr)->payload; + case RTLLIB_4ADDR_LEN: + return ((struct rtllib_hdr_4addr *)hdr)->payload; + } + return NULL; +} + +static inline int rtllib_is_ofdm_rate(u8 rate) +{ + switch (rate & ~RTLLIB_BASIC_RATE_MASK) { + case RTLLIB_OFDM_RATE_6MB: + case RTLLIB_OFDM_RATE_9MB: + case RTLLIB_OFDM_RATE_12MB: + case RTLLIB_OFDM_RATE_18MB: + case RTLLIB_OFDM_RATE_24MB: + case RTLLIB_OFDM_RATE_36MB: + case RTLLIB_OFDM_RATE_48MB: + case RTLLIB_OFDM_RATE_54MB: + return 1; + } + return 0; +} + +static inline int rtllib_is_cck_rate(u8 rate) +{ + switch (rate & ~RTLLIB_BASIC_RATE_MASK) { + case RTLLIB_CCK_RATE_1MB: + case RTLLIB_CCK_RATE_2MB: + case RTLLIB_CCK_RATE_5MB: + case RTLLIB_CCK_RATE_11MB: + return 1; + } + return 0; +} + + +/* rtllib.c */ +extern void free_rtllib(struct net_device *dev); +extern struct net_device *alloc_rtllib(int sizeof_priv); + +extern int rtllib_set_encryption(struct rtllib_device *ieee); + +/* rtllib_tx.c */ + +extern int rtllib_encrypt_fragment( + struct rtllib_device *ieee, + struct sk_buff *frag, + int hdr_len); + +extern int rtllib_xmit(struct sk_buff *skb, struct net_device *dev); +extern int rtllib_xmit_inter(struct sk_buff *skb, struct net_device *dev); +extern void rtllib_txb_free(struct rtllib_txb *); + +/* rtllib_rx.c */ +extern int rtllib_rx(struct rtllib_device *ieee, struct sk_buff *skb, + struct rtllib_rx_stats *rx_stats); +extern void rtllib_rx_mgt(struct rtllib_device *ieee, + struct sk_buff *skb, + struct rtllib_rx_stats *stats); +extern void rtllib_rx_probe_rq(struct rtllib_device *ieee, + struct sk_buff *skb); +extern int rtllib_legal_channel(struct rtllib_device *rtllib, u8 channel); + +/* rtllib_wx.c */ +extern int rtllib_wx_get_scan(struct rtllib_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *key); +extern int rtllib_wx_set_encode(struct rtllib_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *key); +extern int rtllib_wx_get_encode(struct rtllib_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *key); +#if WIRELESS_EXT >= 18 +extern int rtllib_wx_get_encode_ext(struct rtllib_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); +extern int rtllib_wx_set_encode_ext(struct rtllib_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); +#endif +extern int rtllib_wx_set_auth(struct rtllib_device *ieee, + struct iw_request_info *info, + struct iw_param *data, char *extra); +extern int rtllib_wx_set_mlme(struct rtllib_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); +extern int rtllib_wx_set_gen_ie(struct rtllib_device *ieee, u8 *ie, size_t len); + +/* rtllib_softmac.c */ +extern short rtllib_is_54g(struct rtllib_network *net); +extern short rtllib_is_shortslot(const struct rtllib_network *net); +extern int rtllib_rx_frame_softmac(struct rtllib_device *ieee, + struct sk_buff *skb, + struct rtllib_rx_stats *rx_stats, u16 type, + u16 stype); +extern void rtllib_softmac_new_net(struct rtllib_device *ieee, + struct rtllib_network *net); + +void SendDisassociation(struct rtllib_device *ieee, bool deauth, u16 asRsn); +extern void rtllib_softmac_xmit(struct rtllib_txb *txb, + struct rtllib_device *ieee); + +extern void rtllib_stop_send_beacons(struct rtllib_device *ieee); +extern void notify_wx_assoc_event(struct rtllib_device *ieee); +extern void rtllib_softmac_check_all_nets(struct rtllib_device *ieee); +extern void rtllib_start_bss(struct rtllib_device *ieee); +extern void rtllib_start_master_bss(struct rtllib_device *ieee); +extern void rtllib_start_ibss(struct rtllib_device *ieee); +extern void rtllib_softmac_init(struct rtllib_device *ieee); +extern void rtllib_softmac_free(struct rtllib_device *ieee); +extern void rtllib_associate_abort(struct rtllib_device *ieee); +extern void rtllib_disassociate(struct rtllib_device *ieee); +extern void rtllib_stop_scan(struct rtllib_device *ieee); +extern bool rtllib_act_scanning(struct rtllib_device *ieee, bool sync_scan); +extern void rtllib_stop_scan_syncro(struct rtllib_device *ieee); +extern void rtllib_start_scan_syncro(struct rtllib_device *ieee, u8 is_mesh); +extern void rtllib_sta_ps_send_null_frame(struct rtllib_device *ieee, + short pwr); +extern void rtllib_sta_wakeup(struct rtllib_device *ieee, short nl); +extern void rtllib_sta_ps_send_pspoll_frame(struct rtllib_device *ieee); +extern void rtllib_check_all_nets(struct rtllib_device *ieee); +extern void rtllib_start_protocol(struct rtllib_device *ieee); +extern void rtllib_stop_protocol(struct rtllib_device *ieee, u8 shutdown); + +extern void rtllib_EnableNetMonitorMode(struct net_device *dev, + bool bInitState); +extern void rtllib_DisableNetMonitorMode(struct net_device *dev, + bool bInitState); +extern void rtllib_EnableIntelPromiscuousMode(struct net_device *dev, + bool bInitState); +extern void rtllib_DisableIntelPromiscuousMode(struct net_device *dev, + bool bInitState); +extern void rtllib_send_probe_requests(struct rtllib_device *ieee, u8 is_mesh); + +extern void rtllib_softmac_stop_protocol(struct rtllib_device *ieee, + u8 mesh_flag, u8 shutdown); +extern void rtllib_softmac_start_protocol(struct rtllib_device *ieee, + u8 mesh_flag); + +extern void rtllib_reset_queue(struct rtllib_device *ieee); +extern void rtllib_wake_queue(struct rtllib_device *ieee); +extern void rtllib_stop_queue(struct rtllib_device *ieee); +extern void rtllib_wake_all_queues(struct rtllib_device *ieee); +extern void rtllib_stop_all_queues(struct rtllib_device *ieee); +extern struct sk_buff *rtllib_get_beacon(struct rtllib_device *ieee); +extern void rtllib_start_send_beacons(struct rtllib_device *ieee); +extern void rtllib_stop_send_beacons(struct rtllib_device *ieee); +extern int rtllib_wpa_supplicant_ioctl(struct rtllib_device *ieee, + struct iw_point *p, u8 is_mesh); + +extern void notify_wx_assoc_event(struct rtllib_device *ieee); +extern void rtllib_ps_tx_ack(struct rtllib_device *ieee, short success); + +extern void softmac_mgmt_xmit(struct sk_buff *skb, + struct rtllib_device *ieee); +extern u16 rtllib_query_seqnum(struct rtllib_device *ieee, + struct sk_buff *skb, u8 *dst); +extern u8 rtllib_ap_sec_type(struct rtllib_device *ieee); + +/* rtllib_crypt_ccmp&tkip&wep.c */ +extern void rtllib_tkip_null(void); +extern void rtllib_wep_null(void); +extern void rtllib_ccmp_null(void); + +/* rtllib_softmac_wx.c */ + +extern int rtllib_wx_get_wap(struct rtllib_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *ext); + +extern int rtllib_wx_set_wap(struct rtllib_device *ieee, + struct iw_request_info *info, + union iwreq_data *awrq, + char *extra); + +extern int rtllib_wx_get_essid(struct rtllib_device *ieee, + struct iw_request_info *a, + union iwreq_data *wrqu, char *b); + +extern int rtllib_wx_set_rate(struct rtllib_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int rtllib_wx_get_rate(struct rtllib_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int rtllib_wx_set_mode(struct rtllib_device *ieee, + struct iw_request_info *a, + union iwreq_data *wrqu, char *b); + +extern int rtllib_wx_set_scan(struct rtllib_device *ieee, + struct iw_request_info *a, + union iwreq_data *wrqu, char *b); + +extern int rtllib_wx_set_essid(struct rtllib_device *ieee, + struct iw_request_info *a, + union iwreq_data *wrqu, char *extra); + +extern int rtllib_wx_get_mode(struct rtllib_device *ieee, + struct iw_request_info *a, + union iwreq_data *wrqu, char *b); + +extern int rtllib_wx_set_freq(struct rtllib_device *ieee, + struct iw_request_info *a, + union iwreq_data *wrqu, char *b); + +extern int rtllib_wx_get_freq(struct rtllib_device *ieee, + struct iw_request_info *a, + union iwreq_data *wrqu, char *b); +extern void rtllib_wx_sync_scan_wq(void *data); + +extern int rtllib_wx_set_rawtx(struct rtllib_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int rtllib_wx_get_name(struct rtllib_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int rtllib_wx_set_power(struct rtllib_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int rtllib_wx_get_power(struct rtllib_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int rtllib_wx_set_rts(struct rtllib_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int rtllib_wx_get_rts(struct rtllib_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); +#define MAX_RECEIVE_BUFFER_SIZE 9100 + +void HTSetConnectBwMode(struct rtllib_device *ieee, + enum ht_channel_width Bandwidth, + enum ht_extchnl_offset Offset); +extern void HTUpdateDefaultSetting(struct rtllib_device *ieee); +extern void HTConstructCapabilityElement(struct rtllib_device *ieee, + u8 *posHTCap, u8 *len, + u8 isEncrypt, bool bAssoc); +extern void HTConstructInfoElement(struct rtllib_device *ieee, + u8 *posHTInfo, u8 *len, u8 isEncrypt); +extern void HTConstructRT2RTAggElement(struct rtllib_device *ieee, + u8 *posRT2RTAgg, u8 *len); +extern void HTOnAssocRsp(struct rtllib_device *ieee); +extern void HTInitializeHTInfo(struct rtllib_device *ieee); +extern void HTInitializeBssDesc(struct bss_ht *pBssHT); +extern void HTResetSelfAndSavePeerSetting(struct rtllib_device *ieee, + struct rtllib_network *pNetwork); +extern void HT_update_self_and_peer_setting(struct rtllib_device *ieee, + struct rtllib_network *pNetwork); +extern u8 HTGetHighestMCSRate(struct rtllib_device *ieee, u8 *pMCSRateSet, + u8 *pMCSFilter); +extern u8 MCS_FILTER_ALL[]; +extern u16 MCS_DATA_RATE[2][2][77]; +extern u8 HTCCheck(struct rtllib_device *ieee, u8 *pFrame); +extern void HTResetIOTSetting(struct rt_hi_throughput *pHTInfo); +extern bool IsHTHalfNmodeAPs(struct rtllib_device *ieee); +extern u16 HTMcsToDataRate(struct rtllib_device *ieee, u8 nMcsRate); +extern u16 TxCountToDataRate(struct rtllib_device *ieee, u8 nDataRate); +extern int rtllib_rx_ADDBAReq(struct rtllib_device *ieee, struct sk_buff *skb); +extern int rtllib_rx_ADDBARsp(struct rtllib_device *ieee, struct sk_buff *skb); +extern int rtllib_rx_DELBA(struct rtllib_device *ieee, struct sk_buff *skb); +extern void TsInitAddBA(struct rtllib_device *ieee, struct tx_ts_record *pTS, + u8 Policy, u8 bOverwritePending); +extern void TsInitDelBA(struct rtllib_device *ieee, + struct ts_common_info *pTsCommonInfo, + enum tr_select TxRxSelect); +extern void BaSetupTimeOut(unsigned long data); +extern void TxBaInactTimeout(unsigned long data); +extern void RxBaInactTimeout(unsigned long data); +extern void ResetBaEntry(struct ba_record *pBA); +extern bool GetTs( + struct rtllib_device *ieee, + struct ts_common_info **ppTS, + u8 *Addr, + u8 TID, + enum tr_select TxRxSelect, + bool bAddNewTs +); +extern void TSInitialize(struct rtllib_device *ieee); +extern void TsStartAddBaProcess(struct rtllib_device *ieee, + struct tx_ts_record *pTxTS); +extern void RemovePeerTS(struct rtllib_device *ieee, u8 *Addr); +extern void RemoveAllTS(struct rtllib_device *ieee); +void rtllib_softmac_scan_syncro(struct rtllib_device *ieee, u8 is_mesh); + +extern const long rtllib_wlan_frequencies[]; + +static inline void rtllib_increment_scans(struct rtllib_device *ieee) +{ + ieee->scans++; +} + +static inline int rtllib_get_scans(struct rtllib_device *ieee) +{ + return ieee->scans; +} + +static inline const char *escape_essid(const char *essid, u8 essid_len) +{ + static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; + + if (rtllib_is_empty_essid(essid, essid_len)) { + memcpy(escaped, "", sizeof("")); + return escaped; + } + + snprintf(escaped, sizeof(escaped), "%*pEn", essid_len, essid); + return escaped; +} + +#define CONVERT_RATE(_ieee, _MGN_RATE) \ + ((_MGN_RATE < MGN_MCS0) ? (_MGN_RATE) : \ + (HTMcsToDataRate(_ieee, (u8)_MGN_RATE))) + +/* fun with the built-in rtllib stack... */ +bool rtllib_MgntDisconnect(struct rtllib_device *rtllib, u8 asRsn); + + +/* For the function is more related to hardware setting, it's better to use the + * ieee handler to refer to it. + */ +extern void rtllib_update_active_chan_map(struct rtllib_device *ieee); +extern void rtllib_FlushRxTsPendingPkts(struct rtllib_device *ieee, + struct rx_ts_record *pTS); +extern int rtllib_data_xmit(struct sk_buff *skb, struct net_device *dev); +extern int rtllib_parse_info_param(struct rtllib_device *ieee, + struct rtllib_info_element *info_element, + u16 length, + struct rtllib_network *network, + struct rtllib_rx_stats *stats); + +void rtllib_indicate_packets(struct rtllib_device *ieee, + struct rtllib_rxb **prxbIndicateArray, u8 index); +extern u8 HTFilterMCSRate(struct rtllib_device *ieee, u8 *pSupportMCS, + u8 *pOperateMCS); +extern void HTUseDefaultSetting(struct rtllib_device *ieee); +#define RT_ASOC_RETRY_LIMIT 5 +u8 MgntQuery_TxRateExcludeCCKRates(struct rtllib_device *ieee); +extern void rtllib_TURBO_Info(struct rtllib_device *ieee, u8 **tag_p); +#ifndef ENABLE_LOCK_DEBUG +#define SPIN_LOCK_IEEE(plock) spin_lock_irqsave((plock), flags) +#define SPIN_UNLOCK_IEEE(plock) spin_unlock_irqrestore((plock), flags) +#define SPIN_LOCK_IEEE_REORDER(plock) spin_lock_irqsave((plock), flags) +#define SPIN_UNLOCK_IEEE_REORDER(plock) spin_unlock_irqrestore((plock), flags) +#define SPIN_LOCK_IEEE_WPAX(plock) spin_lock_irqsave((plock), flags) +#define SPIN_UNLOCK_IEEE_WPAX(plock) spin_unlock_irqrestore((plock), flags) +#define SPIN_LOCK_IEEE_MGNTTX(plock) spin_lock_irqsave((plock), flags) +#define SPIN_UNLOCK_IEEE_MGNTTX(plock) spin_unlock_irqrestore((plock), flags) +#define SPIN_LOCK_IEEE_BCN(plock) spin_lock_irqsave((plock), flags) +#define SPIN_UNLOCK_IEEE_BCN(plock) spin_unlock_irqrestore((plock), flags) +#define SPIN_LOCK_MSH_STAINFO(plock) spin_lock_irqsave((plock), flags) +#define SPIN_UNLOCK_MSH_STAINFO(plock) spin_unlock_irqrestore((plock), flags) +#define SPIN_LOCK_MSH_PREQ(plock) spin_lock_irqsave((plock), flags) +#define SPIN_UNLOCK_MSH_PREQ(plock) spin_unlock_irqrestore((plock), flags) +#define SPIN_LOCK_MSH_QUEUE(plock) spin_lock_irqsave((plock), flags) +#define SPIN_UNLOCK_MSH_QUEUE(plock) spin_unlock_irqrestore((plock), flags) +#define SPIN_LOCK_PRIV_RFPS(plock) spin_lock_irqsave((plock), flags) +#define SPIN_UNLOCK_PRIV_RFPS(plock) spin_unlock_irqrestore((plock), flags) +#define SPIN_LOCK_PRIV_IRQTH(plock) spin_lock_irqsave((plock), flags) +#define SPIN_UNLOCK_PRIV_IRQTH(plock) spin_unlock_irqrestore((plock), flags) +#define SPIN_LOCK_PRIV_TX(plock) spin_lock_irqsave((plock), flags) +#define SPIN_UNLOCK_PRIV_TX(plock) spin_unlock_irqrestore((plock), flags) +#define SPIN_LOCK_PRIV_D3(plock) spin_lock_irqsave((plock), flags) +#define SPIN_UNLOCK_PRIV_D3(plock) spin_unlock_irqrestore((plock), flags) +#define SPIN_LOCK_PRIV_RF(plock) spin_lock_irqsave((plock), flags) +#define SPIN_UNLOCK_PRIV_RF(plock) spin_unlock_irqrestore((plock), flags) +#define SPIN_LOCK_PRIV_PS(plock) spin_lock_irqsave((plock), flags) +#define SPIN_UNLOCK_PRIV_PS(plock) spin_unlock_irqrestore((plock), flags) +#define SEM_DOWN_IEEE_WX(psem) down(psem) +#define SEM_UP_IEEE_WX(psem) up(psem) +#define SEM_DOWN_IEEE_SCAN(psem) down(psem) +#define SEM_UP_IEEE_SCAN(psem) up(psem) +#define SEM_DOWN_IEEE_IPS(psem) down(psem) +#define SEM_UP_IEEE_IPS(psem) up(psem) +#define SEM_DOWN_PRIV_WX(psem) down(psem) +#define SEM_UP_PRIV_WX(psem) up(psem) +#define SEM_DOWN_PRIV_RF(psem) down(psem) +#define SEM_UP_PRIV_RF(psem) up(psem) +#define MUTEX_LOCK_PRIV(pmutex) mutex_lock(pmutex) +#define MUTEX_UNLOCK_PRIV(pmutex) mutex_unlock(pmutex) +#endif + +#endif /* RTLLIB_H */ diff --git a/kernel/drivers/staging/rtl8192e/rtllib_crypt.c b/kernel/drivers/staging/rtl8192e/rtllib_crypt.c new file mode 100644 index 000000000..1e6ae9bea --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtllib_crypt.c @@ -0,0 +1,254 @@ +/* + * Host AP crypto routines + * + * Copyright (c) 2002-2003, Jouni Malinen + * Portions Copyright (C) 2004, Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. See README and COPYING for + * more details. + * + */ + +#include +#include +#include +#include +#include + +#include "rtllib.h" + +struct rtllib_crypto_alg { + struct list_head list; + struct lib80211_crypto_ops *ops; +}; + + +struct rtllib_crypto { + struct list_head algs; + spinlock_t lock; +}; + +static struct rtllib_crypto *hcrypt; + +void rtllib_crypt_deinit_entries(struct lib80211_crypt_info *info, + int force) +{ + struct list_head *ptr, *n; + struct lib80211_crypt_data *entry; + + for (ptr = info->crypt_deinit_list.next, n = ptr->next; + ptr != &info->crypt_deinit_list; ptr = n, n = ptr->next) { + entry = list_entry(ptr, struct lib80211_crypt_data, list); + + if (atomic_read(&entry->refcnt) != 0 && !force) + continue; + + list_del(ptr); + + if (entry->ops) + entry->ops->deinit(entry->priv); + kfree(entry); + } +} +EXPORT_SYMBOL(rtllib_crypt_deinit_entries); + +void rtllib_crypt_deinit_handler(unsigned long data) +{ + struct lib80211_crypt_info *info = (struct lib80211_crypt_info *)data; + unsigned long flags; + + spin_lock_irqsave(info->lock, flags); + rtllib_crypt_deinit_entries(info, 0); + if (!list_empty(&info->crypt_deinit_list)) { + printk(KERN_DEBUG + "%s: entries remaining in delayed crypt deletion list\n", + info->name); + info->crypt_deinit_timer.expires = jiffies + HZ; + add_timer(&info->crypt_deinit_timer); + } + spin_unlock_irqrestore(info->lock, flags); + +} +EXPORT_SYMBOL(rtllib_crypt_deinit_handler); + +void rtllib_crypt_delayed_deinit(struct lib80211_crypt_info *info, + struct lib80211_crypt_data **crypt) +{ + struct lib80211_crypt_data *tmp; + unsigned long flags; + + if (*crypt == NULL) + return; + + tmp = *crypt; + *crypt = NULL; + + /* must not run ops->deinit() while there may be pending encrypt or + * decrypt operations. Use a list of delayed deinits to avoid needing + * locking. + */ + + spin_lock_irqsave(info->lock, flags); + list_add(&tmp->list, &info->crypt_deinit_list); + if (!timer_pending(&info->crypt_deinit_timer)) { + info->crypt_deinit_timer.expires = jiffies + HZ; + add_timer(&info->crypt_deinit_timer); + } + spin_unlock_irqrestore(info->lock, flags); +} +EXPORT_SYMBOL(rtllib_crypt_delayed_deinit); + +int rtllib_register_crypto_ops(struct lib80211_crypto_ops *ops) +{ + unsigned long flags; + struct rtllib_crypto_alg *alg; + + if (hcrypt == NULL) + return -1; + + alg = kzalloc(sizeof(*alg), GFP_KERNEL); + if (alg == NULL) + return -ENOMEM; + + alg->ops = ops; + + spin_lock_irqsave(&hcrypt->lock, flags); + list_add(&alg->list, &hcrypt->algs); + spin_unlock_irqrestore(&hcrypt->lock, flags); + + printk(KERN_DEBUG "rtllib_crypt: registered algorithm '%s'\n", + ops->name); + + return 0; +} +EXPORT_SYMBOL(rtllib_register_crypto_ops); + +int rtllib_unregister_crypto_ops(struct lib80211_crypto_ops *ops) +{ + unsigned long flags; + struct list_head *ptr; + struct rtllib_crypto_alg *del_alg = NULL; + + if (hcrypt == NULL) + return -1; + + spin_lock_irqsave(&hcrypt->lock, flags); + for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) { + struct rtllib_crypto_alg *alg = + (struct rtllib_crypto_alg *) ptr; + if (alg->ops == ops) { + list_del(&alg->list); + del_alg = alg; + break; + } + } + spin_unlock_irqrestore(&hcrypt->lock, flags); + + if (del_alg) { + printk(KERN_DEBUG "rtllib_crypt: unregistered algorithm '%s'\n", + ops->name); + kfree(del_alg); + } + + return del_alg ? 0 : -1; +} +EXPORT_SYMBOL(rtllib_unregister_crypto_ops); + + +struct lib80211_crypto_ops *rtllib_get_crypto_ops(const char *name) +{ + unsigned long flags; + struct list_head *ptr; + struct rtllib_crypto_alg *found_alg = NULL; + + if (hcrypt == NULL) + return NULL; + + spin_lock_irqsave(&hcrypt->lock, flags); + for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) { + struct rtllib_crypto_alg *alg = + (struct rtllib_crypto_alg *) ptr; + if (strcmp(alg->ops->name, name) == 0) { + found_alg = alg; + break; + } + } + spin_unlock_irqrestore(&hcrypt->lock, flags); + + if (found_alg) + return found_alg->ops; + else + return NULL; +} +EXPORT_SYMBOL(rtllib_get_crypto_ops); + + +static void *rtllib_crypt_null_init(int keyidx) { return (void *) 1; } +static void rtllib_crypt_null_deinit(void *priv) {} + +static struct lib80211_crypto_ops rtllib_crypt_null = { + .name = "NULL", + .init = rtllib_crypt_null_init, + .deinit = rtllib_crypt_null_deinit, + .encrypt_mpdu = NULL, + .decrypt_mpdu = NULL, + .encrypt_msdu = NULL, + .decrypt_msdu = NULL, + .set_key = NULL, + .get_key = NULL, + .extra_mpdu_prefix_len = 0, + .extra_mpdu_postfix_len = 0, + .extra_msdu_prefix_len = 0, + .extra_msdu_postfix_len = 0, + .owner = THIS_MODULE, +}; + + +int __init rtllib_crypto_init(void) +{ + int ret = -ENOMEM; + + hcrypt = kzalloc(sizeof(*hcrypt), GFP_KERNEL); + if (!hcrypt) + goto out; + + INIT_LIST_HEAD(&hcrypt->algs); + spin_lock_init(&hcrypt->lock); + + ret = lib80211_register_crypto_ops(&rtllib_crypt_null); + if (ret < 0) { + kfree(hcrypt); + hcrypt = NULL; + } +out: + return ret; +} + + +void __exit rtllib_crypto_deinit(void) +{ + struct list_head *ptr, *n; + + if (hcrypt == NULL) + return; + + for (ptr = hcrypt->algs.next, n = ptr->next; ptr != &hcrypt->algs; + ptr = n, n = ptr->next) { + struct rtllib_crypto_alg *alg = + (struct rtllib_crypto_alg *) ptr; + list_del(ptr); + printk(KERN_DEBUG + "rtllib_crypt: unregistered algorithm '%s' (deinit)\n", + alg->ops->name); + kfree(alg); + } + + kfree(hcrypt); +} + +module_init(rtllib_crypto_init); +module_exit(rtllib_crypto_deinit); + +MODULE_LICENSE("GPL"); diff --git a/kernel/drivers/staging/rtl8192e/rtllib_crypt.h b/kernel/drivers/staging/rtl8192e/rtllib_crypt.h new file mode 100644 index 000000000..b8cf59f39 --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtllib_crypt.h @@ -0,0 +1,34 @@ +/* + * Original code based on Host AP (software wireless LAN access point) driver + * for Intersil Prism2/2.5/3. + * + * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen + * + * Copyright (c) 2002-2003, Jouni Malinen + * + * Adaption to a generic IEEE 802.11 stack by James Ketrenos + * + * + * Copyright (c) 2004, Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. See README and COPYING for + * more details. + */ + +/* This file defines the interface to the rtllib crypto module. + */ +#ifndef RTLLIB_CRYPT_H +#define RTLLIB_CRYPT_H + +#include + +int rtllib_register_crypto_ops(struct lib80211_crypto_ops *ops); +int rtllib_unregister_crypto_ops(struct lib80211_crypto_ops *ops); +struct lib80211_crypto_ops *rtllib_get_crypto_ops(const char *name); +void rtllib_crypt_deinit_entries(struct lib80211_crypt_info *info, int force); +void rtllib_crypt_deinit_handler(unsigned long data); +void rtllib_crypt_delayed_deinit(struct lib80211_crypt_info *info, + struct lib80211_crypt_data **crypt); +#endif diff --git a/kernel/drivers/staging/rtl8192e/rtllib_crypt_ccmp.c b/kernel/drivers/staging/rtl8192e/rtllib_crypt_ccmp.c new file mode 100644 index 000000000..7d486e888 --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtllib_crypt_ccmp.c @@ -0,0 +1,457 @@ +/* + * Host AP crypt: host-based CCMP encryption implementation for Host AP driver + * + * Copyright (c) 2003-2004, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. See README and COPYING for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rtllib.h" + +#include + +#include + +#define AES_BLOCK_LEN 16 +#define CCMP_HDR_LEN 8 +#define CCMP_MIC_LEN 8 +#define CCMP_TK_LEN 16 +#define CCMP_PN_LEN 6 + +struct rtllib_ccmp_data { + u8 key[CCMP_TK_LEN]; + int key_set; + + u8 tx_pn[CCMP_PN_LEN]; + u8 rx_pn[CCMP_PN_LEN]; + + u32 dot11RSNAStatsCCMPFormatErrors; + u32 dot11RSNAStatsCCMPReplays; + u32 dot11RSNAStatsCCMPDecryptErrors; + + int key_idx; + + struct crypto_tfm *tfm; + + /* scratch buffers for virt_to_page() (crypto API) */ + u8 tx_b0[AES_BLOCK_LEN], tx_b[AES_BLOCK_LEN], + tx_e[AES_BLOCK_LEN], tx_s0[AES_BLOCK_LEN]; + u8 rx_b0[AES_BLOCK_LEN], rx_b[AES_BLOCK_LEN], rx_a[AES_BLOCK_LEN]; +}; + +static void rtllib_ccmp_aes_encrypt(struct crypto_tfm *tfm, + const u8 pt[16], u8 ct[16]) +{ + crypto_cipher_encrypt_one((void *)tfm, ct, pt); +} + +static void *rtllib_ccmp_init(int key_idx) +{ + struct rtllib_ccmp_data *priv; + + priv = kzalloc(sizeof(*priv), GFP_ATOMIC); + if (priv == NULL) + goto fail; + priv->key_idx = key_idx; + + priv->tfm = (void *)crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(priv->tfm)) { + pr_debug("rtllib_crypt_ccmp: could not allocate crypto API aes\n"); + priv->tfm = NULL; + goto fail; + } + return priv; + +fail: + if (priv) { + if (priv->tfm) + crypto_free_cipher((void *)priv->tfm); + kfree(priv); + } + + return NULL; +} + + +static void rtllib_ccmp_deinit(void *priv) +{ + struct rtllib_ccmp_data *_priv = priv; + + if (_priv && _priv->tfm) + crypto_free_cipher((void *)_priv->tfm); + kfree(priv); +} + + +static inline void xor_block(u8 *b, u8 *a, size_t len) +{ + int i; + + for (i = 0; i < len; i++) + b[i] ^= a[i]; +} + + + +static void ccmp_init_blocks(struct crypto_tfm *tfm, + struct rtllib_hdr_4addr *hdr, + u8 *pn, size_t dlen, u8 *b0, u8 *auth, + u8 *s0) +{ + u8 *pos, qc = 0; + size_t aad_len; + u16 fc; + int a4_included, qc_included; + u8 aad[2 * AES_BLOCK_LEN]; + + fc = le16_to_cpu(hdr->frame_ctl); + a4_included = ((fc & (RTLLIB_FCTL_TODS | RTLLIB_FCTL_FROMDS)) == + (RTLLIB_FCTL_TODS | RTLLIB_FCTL_FROMDS)); + + qc_included = ((WLAN_FC_GET_TYPE(fc) == RTLLIB_FTYPE_DATA) && + (WLAN_FC_GET_STYPE(fc) & 0x80)); + aad_len = 22; + if (a4_included) + aad_len += 6; + if (qc_included) { + pos = (u8 *) &hdr->addr4; + if (a4_included) + pos += 6; + qc = *pos & 0x0f; + aad_len += 2; + } + /* CCM Initial Block: + * Flag (Include authentication header, M=3 (8-octet MIC), + * L=1 (2-octet Dlen)) + * Nonce: 0x00 | A2 | PN + * Dlen + */ + b0[0] = 0x59; + b0[1] = qc; + memcpy(b0 + 2, hdr->addr2, ETH_ALEN); + memcpy(b0 + 8, pn, CCMP_PN_LEN); + b0[14] = (dlen >> 8) & 0xff; + b0[15] = dlen & 0xff; + + /* AAD: + * FC with bits 4..6 and 11..13 masked to zero; 14 is always one + * A1 | A2 | A3 + * SC with bits 4..15 (seq#) masked to zero + * A4 (if present) + * QC (if present) + */ + pos = (u8 *) hdr; + aad[0] = 0; /* aad_len >> 8 */ + aad[1] = aad_len & 0xff; + aad[2] = pos[0] & 0x8f; + aad[3] = pos[1] & 0xc7; + memcpy(aad + 4, hdr->addr1, 3 * ETH_ALEN); + pos = (u8 *) &hdr->seq_ctl; + aad[22] = pos[0] & 0x0f; + aad[23] = 0; /* all bits masked */ + memset(aad + 24, 0, 8); + if (a4_included) + memcpy(aad + 24, hdr->addr4, ETH_ALEN); + if (qc_included) { + aad[a4_included ? 30 : 24] = qc; + /* rest of QC masked */ + } + + /* Start with the first block and AAD */ + rtllib_ccmp_aes_encrypt(tfm, b0, auth); + xor_block(auth, aad, AES_BLOCK_LEN); + rtllib_ccmp_aes_encrypt(tfm, auth, auth); + xor_block(auth, &aad[AES_BLOCK_LEN], AES_BLOCK_LEN); + rtllib_ccmp_aes_encrypt(tfm, auth, auth); + b0[0] &= 0x07; + b0[14] = b0[15] = 0; + rtllib_ccmp_aes_encrypt(tfm, b0, s0); +} + + + +static int rtllib_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct rtllib_ccmp_data *key = priv; + int data_len, i; + u8 *pos; + struct rtllib_hdr_4addr *hdr; + struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + + MAX_DEV_ADDR_SIZE); + if (skb_headroom(skb) < CCMP_HDR_LEN || + skb_tailroom(skb) < CCMP_MIC_LEN || + skb->len < hdr_len) + return -1; + + data_len = skb->len - hdr_len; + pos = skb_push(skb, CCMP_HDR_LEN); + memmove(pos, pos + CCMP_HDR_LEN, hdr_len); + pos += hdr_len; + + i = CCMP_PN_LEN - 1; + while (i >= 0) { + key->tx_pn[i]++; + if (key->tx_pn[i] != 0) + break; + i--; + } + + *pos++ = key->tx_pn[5]; + *pos++ = key->tx_pn[4]; + *pos++ = 0; + *pos++ = (key->key_idx << 6) | (1 << 5) /* Ext IV included */; + *pos++ = key->tx_pn[3]; + *pos++ = key->tx_pn[2]; + *pos++ = key->tx_pn[1]; + *pos++ = key->tx_pn[0]; + + + hdr = (struct rtllib_hdr_4addr *) skb->data; + if (!tcb_desc->bHwSec) { + int blocks, last, len; + u8 *mic; + u8 *b0 = key->tx_b0; + u8 *b = key->tx_b; + u8 *e = key->tx_e; + u8 *s0 = key->tx_s0; + + mic = skb_put(skb, CCMP_MIC_LEN); + + ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len, + b0, b, s0); + + blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN; + last = data_len % AES_BLOCK_LEN; + + for (i = 1; i <= blocks; i++) { + len = (i == blocks && last) ? last : AES_BLOCK_LEN; + /* Authentication */ + xor_block(b, pos, len); + rtllib_ccmp_aes_encrypt(key->tfm, b, b); + /* Encryption, with counter */ + b0[14] = (i >> 8) & 0xff; + b0[15] = i & 0xff; + rtllib_ccmp_aes_encrypt(key->tfm, b0, e); + xor_block(pos, e, len); + pos += len; + } + + for (i = 0; i < CCMP_MIC_LEN; i++) + mic[i] = b[i] ^ s0[i]; + } + return 0; +} + + +static int rtllib_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct rtllib_ccmp_data *key = priv; + u8 keyidx, *pos; + struct rtllib_hdr_4addr *hdr; + struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + + MAX_DEV_ADDR_SIZE); + u8 pn[6]; + + if (skb->len < hdr_len + CCMP_HDR_LEN + CCMP_MIC_LEN) { + key->dot11RSNAStatsCCMPFormatErrors++; + return -1; + } + + hdr = (struct rtllib_hdr_4addr *) skb->data; + pos = skb->data + hdr_len; + keyidx = pos[3]; + if (!(keyidx & (1 << 5))) { + if (net_ratelimit()) { + pr_debug("CCMP: received packet without ExtIV flag from %pM\n", + hdr->addr2); + } + key->dot11RSNAStatsCCMPFormatErrors++; + return -2; + } + keyidx >>= 6; + if (key->key_idx != keyidx) { + pr_debug("CCMP: RX tkey->key_idx=%d frame keyidx=%d priv=%p\n", + key->key_idx, keyidx, priv); + return -6; + } + if (!key->key_set) { + if (net_ratelimit()) { + pr_debug("CCMP: received packet from %pM with keyid=%d that does not have a configured key\n", + hdr->addr2, keyidx); + } + return -3; + } + + pn[0] = pos[7]; + pn[1] = pos[6]; + pn[2] = pos[5]; + pn[3] = pos[4]; + pn[4] = pos[1]; + pn[5] = pos[0]; + pos += 8; + if (memcmp(pn, key->rx_pn, CCMP_PN_LEN) <= 0) { + key->dot11RSNAStatsCCMPReplays++; + return -4; + } + if (!tcb_desc->bHwSec) { + size_t data_len = skb->len - hdr_len - CCMP_HDR_LEN - + CCMP_MIC_LEN; + u8 *mic = skb->data + skb->len - CCMP_MIC_LEN; + u8 *b0 = key->rx_b0; + u8 *b = key->rx_b; + u8 *a = key->rx_a; + int i, blocks, last, len; + + + ccmp_init_blocks(key->tfm, hdr, pn, data_len, b0, a, b); + xor_block(mic, b, CCMP_MIC_LEN); + + blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN; + last = data_len % AES_BLOCK_LEN; + + for (i = 1; i <= blocks; i++) { + len = (i == blocks && last) ? last : AES_BLOCK_LEN; + /* Decrypt, with counter */ + b0[14] = (i >> 8) & 0xff; + b0[15] = i & 0xff; + rtllib_ccmp_aes_encrypt(key->tfm, b0, b); + xor_block(pos, b, len); + /* Authentication */ + xor_block(a, pos, len); + rtllib_ccmp_aes_encrypt(key->tfm, a, a); + pos += len; + } + + if (memcmp(mic, a, CCMP_MIC_LEN) != 0) { + if (net_ratelimit()) { + pr_debug("CCMP: decrypt failed: STA= %pM\n", + hdr->addr2); + } + key->dot11RSNAStatsCCMPDecryptErrors++; + return -5; + } + + memcpy(key->rx_pn, pn, CCMP_PN_LEN); + } + /* Remove hdr and MIC */ + memmove(skb->data + CCMP_HDR_LEN, skb->data, hdr_len); + skb_pull(skb, CCMP_HDR_LEN); + skb_trim(skb, skb->len - CCMP_MIC_LEN); + + return keyidx; +} + + +static int rtllib_ccmp_set_key(void *key, int len, u8 *seq, void *priv) +{ + struct rtllib_ccmp_data *data = priv; + int keyidx; + struct crypto_tfm *tfm = data->tfm; + + keyidx = data->key_idx; + memset(data, 0, sizeof(*data)); + data->key_idx = keyidx; + data->tfm = tfm; + if (len == CCMP_TK_LEN) { + memcpy(data->key, key, CCMP_TK_LEN); + data->key_set = 1; + if (seq) { + data->rx_pn[0] = seq[5]; + data->rx_pn[1] = seq[4]; + data->rx_pn[2] = seq[3]; + data->rx_pn[3] = seq[2]; + data->rx_pn[4] = seq[1]; + data->rx_pn[5] = seq[0]; + } + crypto_cipher_setkey((void *)data->tfm, data->key, CCMP_TK_LEN); + } else if (len == 0) + data->key_set = 0; + else + return -1; + + return 0; +} + + +static int rtllib_ccmp_get_key(void *key, int len, u8 *seq, void *priv) +{ + struct rtllib_ccmp_data *data = priv; + + if (len < CCMP_TK_LEN) + return -1; + + if (!data->key_set) + return 0; + memcpy(key, data->key, CCMP_TK_LEN); + + if (seq) { + seq[0] = data->tx_pn[5]; + seq[1] = data->tx_pn[4]; + seq[2] = data->tx_pn[3]; + seq[3] = data->tx_pn[2]; + seq[4] = data->tx_pn[1]; + seq[5] = data->tx_pn[0]; + } + + return CCMP_TK_LEN; +} + + +static void rtllib_ccmp_print_stats(struct seq_file *m, void *priv) +{ + struct rtllib_ccmp_data *ccmp = priv; + + seq_printf(m, + "key[%d] alg=CCMP key_set=%d tx_pn=%pM rx_pn=%pM format_errors=%d replays=%d decrypt_errors=%d\n", + ccmp->key_idx, ccmp->key_set, + ccmp->tx_pn, ccmp->rx_pn, + ccmp->dot11RSNAStatsCCMPFormatErrors, + ccmp->dot11RSNAStatsCCMPReplays, + ccmp->dot11RSNAStatsCCMPDecryptErrors); +} + +static struct lib80211_crypto_ops rtllib_crypt_ccmp = { + .name = "R-CCMP", + .init = rtllib_ccmp_init, + .deinit = rtllib_ccmp_deinit, + .encrypt_mpdu = rtllib_ccmp_encrypt, + .decrypt_mpdu = rtllib_ccmp_decrypt, + .encrypt_msdu = NULL, + .decrypt_msdu = NULL, + .set_key = rtllib_ccmp_set_key, + .get_key = rtllib_ccmp_get_key, + .print_stats = rtllib_ccmp_print_stats, + .extra_mpdu_prefix_len = CCMP_HDR_LEN, + .extra_mpdu_postfix_len = CCMP_MIC_LEN, + .owner = THIS_MODULE, +}; + + +static int __init rtllib_crypto_ccmp_init(void) +{ + return lib80211_register_crypto_ops(&rtllib_crypt_ccmp); +} + + +static void __exit rtllib_crypto_ccmp_exit(void) +{ + lib80211_unregister_crypto_ops(&rtllib_crypt_ccmp); +} + +module_init(rtllib_crypto_ccmp_init); +module_exit(rtllib_crypto_ccmp_exit); + +MODULE_LICENSE("GPL"); diff --git a/kernel/drivers/staging/rtl8192e/rtllib_crypt_tkip.c b/kernel/drivers/staging/rtl8192e/rtllib_crypt_tkip.c new file mode 100644 index 000000000..656b4b359 --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtllib_crypt_tkip.c @@ -0,0 +1,779 @@ +/* + * Host AP crypt: host-based TKIP encryption implementation for Host AP driver + * + * Copyright (c) 2003-2004, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. See README and COPYING for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rtllib.h" + +struct rtllib_tkip_data { +#define TKIP_KEY_LEN 32 + u8 key[TKIP_KEY_LEN]; + int key_set; + + u32 tx_iv32; + u16 tx_iv16; + u16 tx_ttak[5]; + int tx_phase1_done; + + u32 rx_iv32; + u16 rx_iv16; + bool initialized; + u16 rx_ttak[5]; + int rx_phase1_done; + u32 rx_iv32_new; + u16 rx_iv16_new; + + u32 dot11RSNAStatsTKIPReplays; + u32 dot11RSNAStatsTKIPICVErrors; + u32 dot11RSNAStatsTKIPLocalMICFailures; + + int key_idx; + struct crypto_blkcipher *rx_tfm_arc4; + struct crypto_hash *rx_tfm_michael; + struct crypto_blkcipher *tx_tfm_arc4; + struct crypto_hash *tx_tfm_michael; + /* scratch buffers for virt_to_page() (crypto API) */ + u8 rx_hdr[16], tx_hdr[16]; +}; + +static void *rtllib_tkip_init(int key_idx) +{ + struct rtllib_tkip_data *priv; + + priv = kzalloc(sizeof(*priv), GFP_ATOMIC); + if (priv == NULL) + goto fail; + priv->key_idx = key_idx; + priv->tx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, + CRYPTO_ALG_ASYNC); + if (IS_ERR(priv->tx_tfm_arc4)) { + printk(KERN_DEBUG + "rtllib_crypt_tkip: could not allocate crypto API arc4\n"); + priv->tx_tfm_arc4 = NULL; + goto fail; + } + + priv->tx_tfm_michael = crypto_alloc_hash("michael_mic", 0, + CRYPTO_ALG_ASYNC); + if (IS_ERR(priv->tx_tfm_michael)) { + printk(KERN_DEBUG + "rtllib_crypt_tkip: could not allocate crypto API michael_mic\n"); + priv->tx_tfm_michael = NULL; + goto fail; + } + + priv->rx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, + CRYPTO_ALG_ASYNC); + if (IS_ERR(priv->rx_tfm_arc4)) { + printk(KERN_DEBUG + "rtllib_crypt_tkip: could not allocate crypto API arc4\n"); + priv->rx_tfm_arc4 = NULL; + goto fail; + } + + priv->rx_tfm_michael = crypto_alloc_hash("michael_mic", 0, + CRYPTO_ALG_ASYNC); + if (IS_ERR(priv->rx_tfm_michael)) { + printk(KERN_DEBUG + "rtllib_crypt_tkip: could not allocate crypto API michael_mic\n"); + priv->rx_tfm_michael = NULL; + goto fail; + } + return priv; + +fail: + if (priv) { + if (priv->tx_tfm_michael) + crypto_free_hash(priv->tx_tfm_michael); + if (priv->tx_tfm_arc4) + crypto_free_blkcipher(priv->tx_tfm_arc4); + if (priv->rx_tfm_michael) + crypto_free_hash(priv->rx_tfm_michael); + if (priv->rx_tfm_arc4) + crypto_free_blkcipher(priv->rx_tfm_arc4); + kfree(priv); + } + + return NULL; +} + + +static void rtllib_tkip_deinit(void *priv) +{ + struct rtllib_tkip_data *_priv = priv; + + if (_priv) { + if (_priv->tx_tfm_michael) + crypto_free_hash(_priv->tx_tfm_michael); + if (_priv->tx_tfm_arc4) + crypto_free_blkcipher(_priv->tx_tfm_arc4); + if (_priv->rx_tfm_michael) + crypto_free_hash(_priv->rx_tfm_michael); + if (_priv->rx_tfm_arc4) + crypto_free_blkcipher(_priv->rx_tfm_arc4); + } + kfree(priv); +} + + +static inline u16 RotR1(u16 val) +{ + return (val >> 1) | (val << 15); +} + + +static inline u8 Lo8(u16 val) +{ + return val & 0xff; +} + + +static inline u8 Hi8(u16 val) +{ + return val >> 8; +} + + +static inline u16 Lo16(u32 val) +{ + return val & 0xffff; +} + + +static inline u16 Hi16(u32 val) +{ + return val >> 16; +} + + +static inline u16 Mk16(u8 hi, u8 lo) +{ + return lo | (((u16) hi) << 8); +} + + +static inline u16 Mk16_le(u16 *v) +{ + return *v; +} + + +static const u16 Sbox[256] = { + 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154, + 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A, + 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B, + 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B, + 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F, + 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F, + 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5, + 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F, + 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB, + 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397, + 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED, + 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A, + 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194, + 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3, + 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104, + 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D, + 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39, + 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695, + 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83, + 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76, + 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4, + 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B, + 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0, + 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018, + 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751, + 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85, + 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12, + 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9, + 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7, + 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A, + 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8, + 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A, +}; + + +static inline u16 _S_(u16 v) +{ + u16 t = Sbox[Hi8(v)]; + return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8)); +} + + +#define PHASE1_LOOP_COUNT 8 + + +static void tkip_mixing_phase1(u16 *TTAK, const u8 *TK, const u8 *TA, u32 IV32) +{ + int i, j; + + /* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */ + TTAK[0] = Lo16(IV32); + TTAK[1] = Hi16(IV32); + TTAK[2] = Mk16(TA[1], TA[0]); + TTAK[3] = Mk16(TA[3], TA[2]); + TTAK[4] = Mk16(TA[5], TA[4]); + + for (i = 0; i < PHASE1_LOOP_COUNT; i++) { + j = 2 * (i & 1); + TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j])); + TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j])); + TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j])); + TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j])); + TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i; + } +} + + +static void tkip_mixing_phase2(u8 *WEPSeed, const u8 *TK, const u16 *TTAK, + u16 IV16) +{ + /* Make temporary area overlap WEP seed so that the final copy can be + * avoided on little endian hosts. + */ + u16 *PPK = (u16 *) &WEPSeed[4]; + + /* Step 1 - make copy of TTAK and bring in TSC */ + PPK[0] = TTAK[0]; + PPK[1] = TTAK[1]; + PPK[2] = TTAK[2]; + PPK[3] = TTAK[3]; + PPK[4] = TTAK[4]; + PPK[5] = TTAK[4] + IV16; + + /* Step 2 - 96-bit bijective mixing using S-box */ + PPK[0] += _S_(PPK[5] ^ Mk16_le((u16 *) &TK[0])); + PPK[1] += _S_(PPK[0] ^ Mk16_le((u16 *) &TK[2])); + PPK[2] += _S_(PPK[1] ^ Mk16_le((u16 *) &TK[4])); + PPK[3] += _S_(PPK[2] ^ Mk16_le((u16 *) &TK[6])); + PPK[4] += _S_(PPK[3] ^ Mk16_le((u16 *) &TK[8])); + PPK[5] += _S_(PPK[4] ^ Mk16_le((u16 *) &TK[10])); + + PPK[0] += RotR1(PPK[5] ^ Mk16_le((u16 *) &TK[12])); + PPK[1] += RotR1(PPK[0] ^ Mk16_le((u16 *) &TK[14])); + PPK[2] += RotR1(PPK[1]); + PPK[3] += RotR1(PPK[2]); + PPK[4] += RotR1(PPK[3]); + PPK[5] += RotR1(PPK[4]); + + /* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value + * WEPSeed[0..2] is transmitted as WEP IV + */ + WEPSeed[0] = Hi8(IV16); + WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F; + WEPSeed[2] = Lo8(IV16); + WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((u16 *) &TK[0])) >> 1); + +#ifdef __BIG_ENDIAN + { + int i; + + for (i = 0; i < 6; i++) + PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8); + } +#endif +} + + +static int rtllib_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct rtllib_tkip_data *tkey = priv; + int len; + u8 *pos; + struct rtllib_hdr_4addr *hdr; + struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + + MAX_DEV_ADDR_SIZE); + struct blkcipher_desc desc = {.tfm = tkey->tx_tfm_arc4}; + int ret = 0; + u8 rc4key[16], *icv; + u32 crc; + struct scatterlist sg; + + if (skb_headroom(skb) < 8 || skb_tailroom(skb) < 4 || + skb->len < hdr_len) + return -1; + + hdr = (struct rtllib_hdr_4addr *) skb->data; + + if (!tcb_desc->bHwSec) { + if (!tkey->tx_phase1_done) { + tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2, + tkey->tx_iv32); + tkey->tx_phase1_done = 1; + } + tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, + tkey->tx_iv16); + } else + tkey->tx_phase1_done = 1; + + + len = skb->len - hdr_len; + pos = skb_push(skb, 8); + memmove(pos, pos + 8, hdr_len); + pos += hdr_len; + + if (tcb_desc->bHwSec) { + *pos++ = Hi8(tkey->tx_iv16); + *pos++ = (Hi8(tkey->tx_iv16) | 0x20) & 0x7F; + *pos++ = Lo8(tkey->tx_iv16); + } else { + *pos++ = rc4key[0]; + *pos++ = rc4key[1]; + *pos++ = rc4key[2]; + } + + *pos++ = (tkey->key_idx << 6) | (1 << 5) /* Ext IV included */; + *pos++ = tkey->tx_iv32 & 0xff; + *pos++ = (tkey->tx_iv32 >> 8) & 0xff; + *pos++ = (tkey->tx_iv32 >> 16) & 0xff; + *pos++ = (tkey->tx_iv32 >> 24) & 0xff; + + if (!tcb_desc->bHwSec) { + icv = skb_put(skb, 4); + crc = ~crc32_le(~0, pos, len); + icv[0] = crc; + icv[1] = crc >> 8; + icv[2] = crc >> 16; + icv[3] = crc >> 24; + + sg_init_one(&sg, pos, len+4); + + + crypto_blkcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16); + ret = crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4); + } + + tkey->tx_iv16++; + if (tkey->tx_iv16 == 0) { + tkey->tx_phase1_done = 0; + tkey->tx_iv32++; + } + + if (!tcb_desc->bHwSec) + return ret; + else + return 0; + + +} + +static int rtllib_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct rtllib_tkip_data *tkey = priv; + u8 keyidx, *pos; + u32 iv32; + u16 iv16; + struct rtllib_hdr_4addr *hdr; + struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + + MAX_DEV_ADDR_SIZE); + struct blkcipher_desc desc = {.tfm = tkey->rx_tfm_arc4}; + u8 rc4key[16]; + u8 icv[4]; + u32 crc; + struct scatterlist sg; + int plen; + + if (skb->len < hdr_len + 8 + 4) + return -1; + + hdr = (struct rtllib_hdr_4addr *) skb->data; + pos = skb->data + hdr_len; + keyidx = pos[3]; + if (!(keyidx & (1 << 5))) { + if (net_ratelimit()) { + printk(KERN_DEBUG + "TKIP: received packet without ExtIV flag from %pM\n", + hdr->addr2); + } + return -2; + } + keyidx >>= 6; + if (tkey->key_idx != keyidx) { + printk(KERN_DEBUG + "TKIP: RX tkey->key_idx=%d frame keyidx=%d priv=%p\n", + tkey->key_idx, keyidx, priv); + return -6; + } + if (!tkey->key_set) { + if (net_ratelimit()) { + printk(KERN_DEBUG + "TKIP: received packet from %pM with keyid=%d that does not have a configured key\n", + hdr->addr2, keyidx); + } + return -3; + } + iv16 = (pos[0] << 8) | pos[2]; + iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24); + pos += 8; + + if (!tcb_desc->bHwSec || (skb->cb[0] == 1)) { + if ((iv32 < tkey->rx_iv32 || + (iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) && + tkey->initialized) { + if (net_ratelimit()) { + printk(KERN_DEBUG + "TKIP: replay detected: STA= %pM previous TSC %08x%04x received TSC %08x%04x\n", + hdr->addr2, tkey->rx_iv32, tkey->rx_iv16, + iv32, iv16); + } + tkey->dot11RSNAStatsTKIPReplays++; + return -4; + } + tkey->initialized = true; + + if (iv32 != tkey->rx_iv32 || !tkey->rx_phase1_done) { + tkip_mixing_phase1(tkey->rx_ttak, tkey->key, + hdr->addr2, iv32); + tkey->rx_phase1_done = 1; + } + tkip_mixing_phase2(rc4key, tkey->key, tkey->rx_ttak, iv16); + + plen = skb->len - hdr_len - 12; + + sg_init_one(&sg, pos, plen+4); + + crypto_blkcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16); + if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) { + if (net_ratelimit()) { + printk(KERN_DEBUG + ": TKIP: failed to decrypt received packet from %pM\n", + hdr->addr2); + } + return -7; + } + + crc = ~crc32_le(~0, pos, plen); + icv[0] = crc; + icv[1] = crc >> 8; + icv[2] = crc >> 16; + icv[3] = crc >> 24; + + if (memcmp(icv, pos + plen, 4) != 0) { + if (iv32 != tkey->rx_iv32) { + /* Previously cached Phase1 result was already + * lost, so it needs to be recalculated for the + * next packet. + */ + tkey->rx_phase1_done = 0; + } + if (net_ratelimit()) { + printk(KERN_DEBUG + "TKIP: ICV error detected: STA= %pM\n", + hdr->addr2); + } + tkey->dot11RSNAStatsTKIPICVErrors++; + return -5; + } + + } + + /* Update real counters only after Michael MIC verification has + * completed + */ + tkey->rx_iv32_new = iv32; + tkey->rx_iv16_new = iv16; + + /* Remove IV and ICV */ + memmove(skb->data + 8, skb->data, hdr_len); + skb_pull(skb, 8); + skb_trim(skb, skb->len - 4); + + return keyidx; +} + + +static int michael_mic(struct crypto_hash *tfm_michael, u8 *key, u8 *hdr, + u8 *data, size_t data_len, u8 *mic) +{ + struct hash_desc desc; + struct scatterlist sg[2]; + + if (tfm_michael == NULL) { + pr_warn("michael_mic: tfm_michael == NULL\n"); + return -1; + } + sg_init_table(sg, 2); + sg_set_buf(&sg[0], hdr, 16); + sg_set_buf(&sg[1], data, data_len); + + if (crypto_hash_setkey(tfm_michael, key, 8)) + return -1; + + desc.tfm = tfm_michael; + desc.flags = 0; + return crypto_hash_digest(&desc, sg, data_len + 16, mic); +} + +static void michael_mic_hdr(struct sk_buff *skb, u8 *hdr) +{ + struct rtllib_hdr_4addr *hdr11; + + hdr11 = (struct rtllib_hdr_4addr *) skb->data; + switch (le16_to_cpu(hdr11->frame_ctl) & + (RTLLIB_FCTL_FROMDS | RTLLIB_FCTL_TODS)) { + case RTLLIB_FCTL_TODS: + memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */ + memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */ + break; + case RTLLIB_FCTL_FROMDS: + memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */ + memcpy(hdr + ETH_ALEN, hdr11->addr3, ETH_ALEN); /* SA */ + break; + case RTLLIB_FCTL_FROMDS | RTLLIB_FCTL_TODS: + memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */ + memcpy(hdr + ETH_ALEN, hdr11->addr4, ETH_ALEN); /* SA */ + break; + case 0: + memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */ + memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */ + break; + } + + hdr[12] = 0; /* priority */ + + hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */ +} + + +static int rtllib_michael_mic_add(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct rtllib_tkip_data *tkey = priv; + u8 *pos; + struct rtllib_hdr_4addr *hdr; + + hdr = (struct rtllib_hdr_4addr *) skb->data; + + if (skb_tailroom(skb) < 8 || skb->len < hdr_len) { + printk(KERN_DEBUG + "Invalid packet for Michael MIC add (tailroom=%d hdr_len=%d skb->len=%d)\n", + skb_tailroom(skb), hdr_len, skb->len); + return -1; + } + + michael_mic_hdr(skb, tkey->tx_hdr); + + if (RTLLIB_QOS_HAS_SEQ(le16_to_cpu(hdr->frame_ctl))) + tkey->tx_hdr[12] = *(skb->data + hdr_len - 2) & 0x07; + pos = skb_put(skb, 8); + if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr, + skb->data + hdr_len, skb->len - 8 - hdr_len, pos)) + return -1; + + return 0; +} + + +static void rtllib_michael_mic_failure(struct net_device *dev, + struct rtllib_hdr_4addr *hdr, + int keyidx) +{ + union iwreq_data wrqu; + struct iw_michaelmicfailure ev; + + /* TODO: needed parameters: count, keyid, key type, TSC */ + memset(&ev, 0, sizeof(ev)); + ev.flags = keyidx & IW_MICFAILURE_KEY_ID; + if (hdr->addr1[0] & 0x01) + ev.flags |= IW_MICFAILURE_GROUP; + else + ev.flags |= IW_MICFAILURE_PAIRWISE; + ev.src_addr.sa_family = ARPHRD_ETHER; + memcpy(ev.src_addr.sa_data, hdr->addr2, ETH_ALEN); + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = sizeof(ev); + wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *) &ev); +} + +static int rtllib_michael_mic_verify(struct sk_buff *skb, int keyidx, + int hdr_len, void *priv) +{ + struct rtllib_tkip_data *tkey = priv; + u8 mic[8]; + struct rtllib_hdr_4addr *hdr; + + hdr = (struct rtllib_hdr_4addr *) skb->data; + + if (!tkey->key_set) + return -1; + + michael_mic_hdr(skb, tkey->rx_hdr); + if (RTLLIB_QOS_HAS_SEQ(le16_to_cpu(hdr->frame_ctl))) + tkey->rx_hdr[12] = *(skb->data + hdr_len - 2) & 0x07; + + if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr, + skb->data + hdr_len, skb->len - 8 - hdr_len, mic)) + return -1; + + if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) { + struct rtllib_hdr_4addr *hdr; + + hdr = (struct rtllib_hdr_4addr *) skb->data; + printk(KERN_DEBUG + "%s: Michael MIC verification failed for MSDU from %pM keyidx=%d\n", + skb->dev ? skb->dev->name : "N/A", hdr->addr2, + keyidx); + printk(KERN_DEBUG "%d\n", + memcmp(mic, skb->data + skb->len - 8, 8) != 0); + if (skb->dev) { + pr_info("skb->dev != NULL\n"); + rtllib_michael_mic_failure(skb->dev, hdr, keyidx); + } + tkey->dot11RSNAStatsTKIPLocalMICFailures++; + return -1; + } + + /* Update TSC counters for RX now that the packet verification has + * completed. + */ + tkey->rx_iv32 = tkey->rx_iv32_new; + tkey->rx_iv16 = tkey->rx_iv16_new; + + skb_trim(skb, skb->len - 8); + + return 0; +} + + +static int rtllib_tkip_set_key(void *key, int len, u8 *seq, void *priv) +{ + struct rtllib_tkip_data *tkey = priv; + int keyidx; + struct crypto_hash *tfm = tkey->tx_tfm_michael; + struct crypto_blkcipher *tfm2 = tkey->tx_tfm_arc4; + struct crypto_hash *tfm3 = tkey->rx_tfm_michael; + struct crypto_blkcipher *tfm4 = tkey->rx_tfm_arc4; + + keyidx = tkey->key_idx; + memset(tkey, 0, sizeof(*tkey)); + tkey->key_idx = keyidx; + tkey->tx_tfm_michael = tfm; + tkey->tx_tfm_arc4 = tfm2; + tkey->rx_tfm_michael = tfm3; + tkey->rx_tfm_arc4 = tfm4; + + if (len == TKIP_KEY_LEN) { + memcpy(tkey->key, key, TKIP_KEY_LEN); + tkey->key_set = 1; + tkey->tx_iv16 = 1; /* TSC is initialized to 1 */ + if (seq) { + tkey->rx_iv32 = (seq[5] << 24) | (seq[4] << 16) | + (seq[3] << 8) | seq[2]; + tkey->rx_iv16 = (seq[1] << 8) | seq[0]; + } + } else if (len == 0) + tkey->key_set = 0; + else + return -1; + + return 0; +} + + +static int rtllib_tkip_get_key(void *key, int len, u8 *seq, void *priv) +{ + struct rtllib_tkip_data *tkey = priv; + + if (len < TKIP_KEY_LEN) + return -1; + + if (!tkey->key_set) + return 0; + memcpy(key, tkey->key, TKIP_KEY_LEN); + + if (seq) { + /* Return the sequence number of the last transmitted frame. */ + u16 iv16 = tkey->tx_iv16; + u32 iv32 = tkey->tx_iv32; + + if (iv16 == 0) + iv32--; + iv16--; + seq[0] = tkey->tx_iv16; + seq[1] = tkey->tx_iv16 >> 8; + seq[2] = tkey->tx_iv32; + seq[3] = tkey->tx_iv32 >> 8; + seq[4] = tkey->tx_iv32 >> 16; + seq[5] = tkey->tx_iv32 >> 24; + } + + return TKIP_KEY_LEN; +} + + +static void rtllib_tkip_print_stats(struct seq_file *m, void *priv) +{ + struct rtllib_tkip_data *tkip = priv; + + seq_printf(m, + "key[%d] alg=TKIP key_set=%d tx_pn=%02x%02x%02x%02x%02x%02x rx_pn=%02x%02x%02x%02x%02x%02x replays=%d icv_errors=%d local_mic_failures=%d\n", + tkip->key_idx, tkip->key_set, + (tkip->tx_iv32 >> 24) & 0xff, + (tkip->tx_iv32 >> 16) & 0xff, + (tkip->tx_iv32 >> 8) & 0xff, + tkip->tx_iv32 & 0xff, + (tkip->tx_iv16 >> 8) & 0xff, + tkip->tx_iv16 & 0xff, + (tkip->rx_iv32 >> 24) & 0xff, + (tkip->rx_iv32 >> 16) & 0xff, + (tkip->rx_iv32 >> 8) & 0xff, + tkip->rx_iv32 & 0xff, + (tkip->rx_iv16 >> 8) & 0xff, + tkip->rx_iv16 & 0xff, + tkip->dot11RSNAStatsTKIPReplays, + tkip->dot11RSNAStatsTKIPICVErrors, + tkip->dot11RSNAStatsTKIPLocalMICFailures); +} + +static struct lib80211_crypto_ops rtllib_crypt_tkip = { + .name = "R-TKIP", + .init = rtllib_tkip_init, + .deinit = rtllib_tkip_deinit, + .encrypt_mpdu = rtllib_tkip_encrypt, + .decrypt_mpdu = rtllib_tkip_decrypt, + .encrypt_msdu = rtllib_michael_mic_add, + .decrypt_msdu = rtllib_michael_mic_verify, + .set_key = rtllib_tkip_set_key, + .get_key = rtllib_tkip_get_key, + .print_stats = rtllib_tkip_print_stats, + .extra_mpdu_prefix_len = 4 + 4, /* IV + ExtIV */ + .extra_mpdu_postfix_len = 4, /* ICV */ + .extra_msdu_postfix_len = 8, /* MIC */ + .owner = THIS_MODULE, +}; + + +static int __init rtllib_crypto_tkip_init(void) +{ + return lib80211_register_crypto_ops(&rtllib_crypt_tkip); +} + + +static void __exit rtllib_crypto_tkip_exit(void) +{ + lib80211_unregister_crypto_ops(&rtllib_crypt_tkip); +} + +module_init(rtllib_crypto_tkip_init); +module_exit(rtllib_crypto_tkip_exit); + +MODULE_LICENSE("GPL"); diff --git a/kernel/drivers/staging/rtl8192e/rtllib_crypt_wep.c b/kernel/drivers/staging/rtl8192e/rtllib_crypt_wep.c new file mode 100644 index 000000000..21d7eee4c --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtllib_crypt_wep.c @@ -0,0 +1,289 @@ +/* + * Host AP crypt: host-based WEP encryption implementation for Host AP driver + * + * Copyright (c) 2002-2004, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. See README and COPYING for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include "rtllib.h" + +#include + +#include +#include + +struct prism2_wep_data { + u32 iv; +#define WEP_KEY_LEN 13 + u8 key[WEP_KEY_LEN + 1]; + u8 key_len; + u8 key_idx; + struct crypto_blkcipher *tx_tfm; + struct crypto_blkcipher *rx_tfm; +}; + + +static void *prism2_wep_init(int keyidx) +{ + struct prism2_wep_data *priv; + + priv = kzalloc(sizeof(*priv), GFP_ATOMIC); + if (priv == NULL) + goto fail; + priv->key_idx = keyidx; + + priv->tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(priv->tx_tfm)) { + pr_debug("rtllib_crypt_wep: could not allocate crypto API arc4\n"); + priv->tx_tfm = NULL; + goto fail; + } + priv->rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(priv->rx_tfm)) { + pr_debug("rtllib_crypt_wep: could not allocate crypto API arc4\n"); + priv->rx_tfm = NULL; + goto fail; + } + + /* start WEP IV from a random value */ + get_random_bytes(&priv->iv, 4); + + return priv; + +fail: + if (priv) { + if (priv->tx_tfm) + crypto_free_blkcipher(priv->tx_tfm); + if (priv->rx_tfm) + crypto_free_blkcipher(priv->rx_tfm); + kfree(priv); + } + return NULL; +} + + +static void prism2_wep_deinit(void *priv) +{ + struct prism2_wep_data *_priv = priv; + + if (_priv) { + if (_priv->tx_tfm) + crypto_free_blkcipher(_priv->tx_tfm); + if (_priv->rx_tfm) + crypto_free_blkcipher(_priv->rx_tfm); + } + kfree(priv); +} + +/* Perform WEP encryption on given skb that has at least 4 bytes of headroom + * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted, + * so the payload length increases with 8 bytes. + * + * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data)) + */ +static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct prism2_wep_data *wep = priv; + u32 klen, len; + u8 key[WEP_KEY_LEN + 3]; + u8 *pos; + struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + + MAX_DEV_ADDR_SIZE); + struct blkcipher_desc desc = {.tfm = wep->tx_tfm}; + u32 crc; + u8 *icv; + struct scatterlist sg; + + if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 || + skb->len < hdr_len){ + pr_err("Error!!! headroom=%d tailroom=%d skblen=%d hdr_len=%d\n", + skb_headroom(skb), skb_tailroom(skb), skb->len, hdr_len); + return -1; + } + len = skb->len - hdr_len; + pos = skb_push(skb, 4); + memmove(pos, pos + 4, hdr_len); + pos += hdr_len; + + klen = 3 + wep->key_len; + + wep->iv++; + + /* Fluhrer, Mantin, and Shamir have reported weaknesses in the key + * scheduling algorithm of RC4. At least IVs (KeyByte + 3, 0xff, N) + * can be used to speedup attacks, so avoid using them. + */ + if ((wep->iv & 0xff00) == 0xff00) { + u8 B = (wep->iv >> 16) & 0xff; + + if (B >= 3 && B < klen) + wep->iv += 0x0100; + } + + /* Prepend 24-bit IV to RC4 key and TX frame */ + *pos++ = key[0] = (wep->iv >> 16) & 0xff; + *pos++ = key[1] = (wep->iv >> 8) & 0xff; + *pos++ = key[2] = wep->iv & 0xff; + *pos++ = wep->key_idx << 6; + + /* Copy rest of the WEP key (the secret part) */ + memcpy(key + 3, wep->key, wep->key_len); + + if (!tcb_desc->bHwSec) { + + /* Append little-endian CRC32 and encrypt it to produce ICV */ + crc = ~crc32_le(~0, pos, len); + icv = skb_put(skb, 4); + icv[0] = crc; + icv[1] = crc >> 8; + icv[2] = crc >> 16; + icv[3] = crc >> 24; + + sg_init_one(&sg, pos, len+4); + crypto_blkcipher_setkey(wep->tx_tfm, key, klen); + return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4); + } + + return 0; +} + + +/* Perform WEP decryption on given struct buffer. Buffer includes whole WEP + * part of the frame: IV (4 bytes), encrypted payload (including SNAP header), + * ICV (4 bytes). len includes both IV and ICV. + * + * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on + * failure. If frame is OK, IV and ICV will be removed. + */ +static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct prism2_wep_data *wep = priv; + u32 klen, plen; + u8 key[WEP_KEY_LEN + 3]; + u8 keyidx, *pos; + struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + + MAX_DEV_ADDR_SIZE); + struct blkcipher_desc desc = {.tfm = wep->rx_tfm}; + u32 crc; + u8 icv[4]; + struct scatterlist sg; + + if (skb->len < hdr_len + 8) + return -1; + + pos = skb->data + hdr_len; + key[0] = *pos++; + key[1] = *pos++; + key[2] = *pos++; + keyidx = *pos++ >> 6; + if (keyidx != wep->key_idx) + return -1; + + klen = 3 + wep->key_len; + + /* Copy rest of the WEP key (the secret part) */ + memcpy(key + 3, wep->key, wep->key_len); + + /* Apply RC4 to data and compute CRC32 over decrypted data */ + plen = skb->len - hdr_len - 8; + + if (!tcb_desc->bHwSec) { + sg_init_one(&sg, pos, plen+4); + crypto_blkcipher_setkey(wep->rx_tfm, key, klen); + if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) + return -7; + crc = ~crc32_le(~0, pos, plen); + icv[0] = crc; + icv[1] = crc >> 8; + icv[2] = crc >> 16; + icv[3] = crc >> 24; + if (memcmp(icv, pos + plen, 4) != 0) { + /* ICV mismatch - drop frame */ + return -2; + } + } + /* Remove IV and ICV */ + memmove(skb->data + 4, skb->data, hdr_len); + skb_pull(skb, 4); + skb_trim(skb, skb->len - 4); + + return 0; +} + + +static int prism2_wep_set_key(void *key, int len, u8 *seq, void *priv) +{ + struct prism2_wep_data *wep = priv; + + if (len < 0 || len > WEP_KEY_LEN) + return -1; + + memcpy(wep->key, key, len); + wep->key_len = len; + + return 0; +} + + +static int prism2_wep_get_key(void *key, int len, u8 *seq, void *priv) +{ + struct prism2_wep_data *wep = priv; + + if (len < wep->key_len) + return -1; + + memcpy(key, wep->key, wep->key_len); + + return wep->key_len; +} + + +static void prism2_wep_print_stats(struct seq_file *m, void *priv) +{ + struct prism2_wep_data *wep = priv; + + seq_printf(m, "key[%d] alg=WEP len=%d\n", wep->key_idx, wep->key_len); +} + +static struct lib80211_crypto_ops rtllib_crypt_wep = { + .name = "R-WEP", + .init = prism2_wep_init, + .deinit = prism2_wep_deinit, + .encrypt_mpdu = prism2_wep_encrypt, + .decrypt_mpdu = prism2_wep_decrypt, + .encrypt_msdu = NULL, + .decrypt_msdu = NULL, + .set_key = prism2_wep_set_key, + .get_key = prism2_wep_get_key, + .print_stats = prism2_wep_print_stats, + .extra_mpdu_prefix_len = 4, /* IV */ + .extra_mpdu_postfix_len = 4, /* ICV */ + .owner = THIS_MODULE, +}; + + +static int __init rtllib_crypto_wep_init(void) +{ + return lib80211_register_crypto_ops(&rtllib_crypt_wep); +} + + +static void __exit rtllib_crypto_wep_exit(void) +{ + lib80211_unregister_crypto_ops(&rtllib_crypt_wep); +} + +module_init(rtllib_crypto_wep_init); +module_exit(rtllib_crypto_wep_exit); + +MODULE_LICENSE("GPL"); diff --git a/kernel/drivers/staging/rtl8192e/rtllib_debug.h b/kernel/drivers/staging/rtl8192e/rtllib_debug.h new file mode 100644 index 000000000..119729d31 --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtllib_debug.h @@ -0,0 +1,88 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * Based on the r8180 driver, which is: + * Copyright 2004-2005 Andrea Merello , et al. + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae +******************************************************************************/ +#ifndef _RTL_DEBUG_H +#define _RTL_DEBUG_H + +/* Allow files to override DRV_NAME */ +#ifndef DRV_NAME +#define DRV_NAME "rtllib_92e" +#endif + +#define DMESG(x, a...) + +extern u32 rt_global_debug_component; + +/* These are the defines for rt_global_debug_component */ +enum RTL_DEBUG { + COMP_TRACE = (1 << 0), + COMP_DBG = (1 << 1), + COMP_INIT = (1 << 2), + COMP_RECV = (1 << 3), + COMP_SEND = (1 << 4), + COMP_CMD = (1 << 5), + COMP_POWER = (1 << 6), + COMP_EPROM = (1 << 7), + COMP_SWBW = (1 << 8), + COMP_SEC = (1 << 9), + COMP_LPS = (1 << 10), + COMP_QOS = (1 << 11), + COMP_RATE = (1 << 12), + COMP_RXDESC = (1 << 13), + COMP_PHY = (1 << 14), + COMP_DIG = (1 << 15), + COMP_TXAGC = (1 << 16), + COMP_HALDM = (1 << 17), + COMP_POWER_TRACKING = (1 << 18), + COMP_CH = (1 << 19), + COMP_RF = (1 << 20), + COMP_FIRMWARE = (1 << 21), + COMP_HT = (1 << 22), + COMP_RESET = (1 << 23), + COMP_CMDPKT = (1 << 24), + COMP_SCAN = (1 << 25), + COMP_PS = (1 << 26), + COMP_DOWN = (1 << 27), + COMP_INTR = (1 << 28), + COMP_LED = (1 << 29), + COMP_MLME = (1 << 30), + COMP_ERR = (1 << 31) +}; + +#define RT_TRACE(component, x, args...) \ +do { \ + if (rt_global_debug_component & component) \ + printk(KERN_DEBUG DRV_NAME ":" x "\n" , \ + ##args);\ +} while (0) + +#define assert(expr) \ +do { \ + if (!(expr)) { \ + pr_info("Assertion failed! %s,%s,%s,line=%d\n", \ + #expr, __FILE__, __func__, __LINE__); \ + } \ +} while (0) + +#endif diff --git a/kernel/drivers/staging/rtl8192e/rtllib_module.c b/kernel/drivers/staging/rtl8192e/rtllib_module.c new file mode 100644 index 000000000..32cc8df9d --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtllib_module.c @@ -0,0 +1,268 @@ +/******************************************************************************* + + Copyright(c) 2004 Intel Corporation. All rights reserved. + + Portions of this file are based on the WEP enablement code provided by the + Host AP project hostap-drivers v0.1.3 + Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen + + Copyright (c) 2002-2003, Jouni Malinen + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2 of the GNU General Public License as + published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., 59 + Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + James P. Ketrenos + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rtllib.h" + + +u32 rt_global_debug_component = COMP_ERR; +EXPORT_SYMBOL(rt_global_debug_component); + + +void _setup_timer(struct timer_list *ptimer, void *fun, unsigned long data) +{ + ptimer->function = fun; + ptimer->data = data; + init_timer(ptimer); +} + +static inline int rtllib_networks_allocate(struct rtllib_device *ieee) +{ + if (ieee->networks) + return 0; + + ieee->networks = kzalloc( + MAX_NETWORK_COUNT * sizeof(struct rtllib_network), + GFP_KERNEL); + if (!ieee->networks) + return -ENOMEM; + + return 0; +} + +static inline void rtllib_networks_free(struct rtllib_device *ieee) +{ + if (!ieee->networks) + return; + kfree(ieee->networks); + ieee->networks = NULL; +} + +static inline void rtllib_networks_initialize(struct rtllib_device *ieee) +{ + int i; + + INIT_LIST_HEAD(&ieee->network_free_list); + INIT_LIST_HEAD(&ieee->network_list); + for (i = 0; i < MAX_NETWORK_COUNT; i++) + list_add_tail(&ieee->networks[i].list, + &ieee->network_free_list); +} + +struct net_device *alloc_rtllib(int sizeof_priv) +{ + struct rtllib_device *ieee = NULL; + struct net_device *dev; + int i, err; + + RTLLIB_DEBUG_INFO("Initializing...\n"); + + dev = alloc_etherdev(sizeof(struct rtllib_device) + sizeof_priv); + if (!dev) { + RTLLIB_ERROR("Unable to network device.\n"); + return NULL; + } + ieee = (struct rtllib_device *)netdev_priv_rsl(dev); + memset(ieee, 0, sizeof(struct rtllib_device)+sizeof_priv); + ieee->dev = dev; + + err = rtllib_networks_allocate(ieee); + if (err) { + RTLLIB_ERROR("Unable to allocate beacon storage: %d\n", + err); + goto failed; + } + rtllib_networks_initialize(ieee); + + + /* Default fragmentation threshold is maximum payload size */ + ieee->fts = DEFAULT_FTS; + ieee->scan_age = DEFAULT_MAX_SCAN_AGE; + ieee->open_wep = 1; + + /* Default to enabling full open WEP with host based encrypt/decrypt */ + ieee->host_encrypt = 1; + ieee->host_decrypt = 1; + ieee->ieee802_1x = 1; /* Default to supporting 802.1x */ + + ieee->rtllib_ap_sec_type = rtllib_ap_sec_type; + + spin_lock_init(&ieee->lock); + spin_lock_init(&ieee->wpax_suitlist_lock); + spin_lock_init(&ieee->bw_spinlock); + spin_lock_init(&ieee->reorder_spinlock); + atomic_set(&(ieee->atm_chnlop), 0); + atomic_set(&(ieee->atm_swbw), 0); + + /* SAM FIXME */ + lib80211_crypt_info_init(&ieee->crypt_info, "RTLLIB", &ieee->lock); + + ieee->bHalfNMode = false; + ieee->wpa_enabled = 0; + ieee->tkip_countermeasures = 0; + ieee->drop_unencrypted = 0; + ieee->privacy_invoked = 0; + ieee->ieee802_1x = 1; + ieee->raw_tx = 0; + ieee->hwsec_active = 0; + + memset(ieee->swcamtable, 0, sizeof(struct sw_cam_table) * 32); + rtllib_softmac_init(ieee); + + ieee->pHTInfo = kzalloc(sizeof(struct rt_hi_throughput), GFP_KERNEL); + if (ieee->pHTInfo == NULL) + return NULL; + + HTUpdateDefaultSetting(ieee); + HTInitializeHTInfo(ieee); + TSInitialize(ieee); + for (i = 0; i < IEEE_IBSS_MAC_HASH_SIZE; i++) + INIT_LIST_HEAD(&ieee->ibss_mac_hash[i]); + + for (i = 0; i < 17; i++) { + ieee->last_rxseq_num[i] = -1; + ieee->last_rxfrag_num[i] = -1; + ieee->last_packet_time[i] = 0; + } + + return dev; + + failed: + free_netdev(dev); + return NULL; +} +EXPORT_SYMBOL(alloc_rtllib); + +void free_rtllib(struct net_device *dev) +{ + struct rtllib_device *ieee = (struct rtllib_device *) + netdev_priv_rsl(dev); + + kfree(ieee->pHTInfo); + ieee->pHTInfo = NULL; + rtllib_softmac_free(ieee); + + lib80211_crypt_info_free(&ieee->crypt_info); + + rtllib_networks_free(ieee); + free_netdev(dev); +} +EXPORT_SYMBOL(free_rtllib); + +u32 rtllib_debug_level; +static int debug = RTLLIB_DL_ERR; +static struct proc_dir_entry *rtllib_proc; + +static int show_debug_level(struct seq_file *m, void *v) +{ + seq_printf(m, "0x%08X\n", rtllib_debug_level); + + return 0; +} + +static ssize_t write_debug_level(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) +{ + unsigned long val; + int err = kstrtoul_from_user(buffer, count, 0, &val); + + if (err) + return err; + rtllib_debug_level = val; + return count; +} + +static int open_debug_level(struct inode *inode, struct file *file) +{ + return single_open(file, show_debug_level, NULL); +} + +static const struct file_operations fops = { + .open = open_debug_level, + .read = seq_read, + .llseek = seq_lseek, + .write = write_debug_level, + .release = single_release, +}; + +static int __init rtllib_init(void) +{ + struct proc_dir_entry *e; + + rtllib_debug_level = debug; + rtllib_proc = proc_mkdir(DRV_NAME, init_net.proc_net); + if (rtllib_proc == NULL) { + RTLLIB_ERROR("Unable to create " DRV_NAME + " proc directory\n"); + return -EIO; + } + e = proc_create("debug_level", S_IRUGO | S_IWUSR, rtllib_proc, &fops); + if (!e) { + remove_proc_entry(DRV_NAME, init_net.proc_net); + rtllib_proc = NULL; + return -EIO; + } + return 0; +} + +static void __exit rtllib_exit(void) +{ + if (rtllib_proc) { + remove_proc_entry("debug_level", rtllib_proc); + remove_proc_entry(DRV_NAME, init_net.proc_net); + rtllib_proc = NULL; + } +} + +module_init(rtllib_init); +module_exit(rtllib_exit); + +MODULE_LICENSE("GPL"); diff --git a/kernel/drivers/staging/rtl8192e/rtllib_rx.c b/kernel/drivers/staging/rtl8192e/rtllib_rx.c new file mode 100644 index 000000000..fe3e7e127 --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtllib_rx.c @@ -0,0 +1,2678 @@ +/* + * Original code based Host AP (software wireless LAN access point) driver + * for Intersil Prism2/2.5/3 - hostap.o module, common routines + * + * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen + * + * Copyright (c) 2002-2003, Jouni Malinen + * Copyright (c) 2004, Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. See README and COPYING for + * more details. + ****************************************************************************** + + Few modifications for Realtek's Wi-Fi drivers by + Andrea Merello + + A special thanks goes to Realtek for their support ! + +******************************************************************************/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rtllib.h" +#include "dot11d.h" + +static inline void rtllib_monitor_rx(struct rtllib_device *ieee, + struct sk_buff *skb, struct rtllib_rx_stats *rx_status, + size_t hdr_length) +{ + skb->dev = ieee->dev; + skb_reset_mac_header(skb); + skb_pull(skb, hdr_length); + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = htons(ETH_P_80211_RAW); + memset(skb->cb, 0, sizeof(skb->cb)); + netif_rx(skb); +} + +/* Called only as a tasklet (software IRQ) */ +static struct rtllib_frag_entry * +rtllib_frag_cache_find(struct rtllib_device *ieee, unsigned int seq, + unsigned int frag, u8 tid, u8 *src, u8 *dst) +{ + struct rtllib_frag_entry *entry; + int i; + + for (i = 0; i < RTLLIB_FRAG_CACHE_LEN; i++) { + entry = &ieee->frag_cache[tid][i]; + if (entry->skb != NULL && + time_after(jiffies, entry->first_frag_time + 2 * HZ)) { + RTLLIB_DEBUG_FRAG( + "expiring fragment cache entry seq=%u last_frag=%u\n", + entry->seq, entry->last_frag); + dev_kfree_skb_any(entry->skb); + entry->skb = NULL; + } + + if (entry->skb != NULL && entry->seq == seq && + (entry->last_frag + 1 == frag || frag == -1) && + memcmp(entry->src_addr, src, ETH_ALEN) == 0 && + memcmp(entry->dst_addr, dst, ETH_ALEN) == 0) + return entry; + } + + return NULL; +} + +/* Called only as a tasklet (software IRQ) */ +static struct sk_buff * +rtllib_frag_cache_get(struct rtllib_device *ieee, + struct rtllib_hdr_4addr *hdr) +{ + struct sk_buff *skb = NULL; + u16 fc = le16_to_cpu(hdr->frame_ctl); + u16 sc = le16_to_cpu(hdr->seq_ctl); + unsigned int frag = WLAN_GET_SEQ_FRAG(sc); + unsigned int seq = WLAN_GET_SEQ_SEQ(sc); + struct rtllib_frag_entry *entry; + struct rtllib_hdr_3addrqos *hdr_3addrqos; + struct rtllib_hdr_4addrqos *hdr_4addrqos; + u8 tid; + + if (((fc & RTLLIB_FCTL_DSTODS) == RTLLIB_FCTL_DSTODS) && RTLLIB_QOS_HAS_SEQ(fc)) { + hdr_4addrqos = (struct rtllib_hdr_4addrqos *)hdr; + tid = le16_to_cpu(hdr_4addrqos->qos_ctl) & RTLLIB_QCTL_TID; + tid = UP2AC(tid); + tid++; + } else if (RTLLIB_QOS_HAS_SEQ(fc)) { + hdr_3addrqos = (struct rtllib_hdr_3addrqos *)hdr; + tid = le16_to_cpu(hdr_3addrqos->qos_ctl) & RTLLIB_QCTL_TID; + tid = UP2AC(tid); + tid++; + } else { + tid = 0; + } + + if (frag == 0) { + /* Reserve enough space to fit maximum frame length */ + skb = dev_alloc_skb(ieee->dev->mtu + + sizeof(struct rtllib_hdr_4addr) + + 8 /* LLC */ + + 2 /* alignment */ + + 8 /* WEP */ + + ETH_ALEN /* WDS */ + + (RTLLIB_QOS_HAS_SEQ(fc) ? 2 : 0) /* QOS Control */); + if (skb == NULL) + return NULL; + + entry = &ieee->frag_cache[tid][ieee->frag_next_idx[tid]]; + ieee->frag_next_idx[tid]++; + if (ieee->frag_next_idx[tid] >= RTLLIB_FRAG_CACHE_LEN) + ieee->frag_next_idx[tid] = 0; + + if (entry->skb != NULL) + dev_kfree_skb_any(entry->skb); + + entry->first_frag_time = jiffies; + entry->seq = seq; + entry->last_frag = frag; + entry->skb = skb; + memcpy(entry->src_addr, hdr->addr2, ETH_ALEN); + memcpy(entry->dst_addr, hdr->addr1, ETH_ALEN); + } else { + /* received a fragment of a frame for which the head fragment + * should have already been received + */ + entry = rtllib_frag_cache_find(ieee, seq, frag, tid, hdr->addr2, + hdr->addr1); + if (entry != NULL) { + entry->last_frag = frag; + skb = entry->skb; + } + } + + return skb; +} + + +/* Called only as a tasklet (software IRQ) */ +static int rtllib_frag_cache_invalidate(struct rtllib_device *ieee, + struct rtllib_hdr_4addr *hdr) +{ + u16 fc = le16_to_cpu(hdr->frame_ctl); + u16 sc = le16_to_cpu(hdr->seq_ctl); + unsigned int seq = WLAN_GET_SEQ_SEQ(sc); + struct rtllib_frag_entry *entry; + struct rtllib_hdr_3addrqos *hdr_3addrqos; + struct rtllib_hdr_4addrqos *hdr_4addrqos; + u8 tid; + + if (((fc & RTLLIB_FCTL_DSTODS) == RTLLIB_FCTL_DSTODS) && RTLLIB_QOS_HAS_SEQ(fc)) { + hdr_4addrqos = (struct rtllib_hdr_4addrqos *)hdr; + tid = le16_to_cpu(hdr_4addrqos->qos_ctl) & RTLLIB_QCTL_TID; + tid = UP2AC(tid); + tid++; + } else if (RTLLIB_QOS_HAS_SEQ(fc)) { + hdr_3addrqos = (struct rtllib_hdr_3addrqos *)hdr; + tid = le16_to_cpu(hdr_3addrqos->qos_ctl) & RTLLIB_QCTL_TID; + tid = UP2AC(tid); + tid++; + } else { + tid = 0; + } + + entry = rtllib_frag_cache_find(ieee, seq, -1, tid, hdr->addr2, + hdr->addr1); + + if (entry == NULL) { + RTLLIB_DEBUG_FRAG( + "could not invalidate fragment cache entry (seq=%u)\n", seq); + return -1; + } + + entry->skb = NULL; + return 0; +} + +/* rtllib_rx_frame_mgtmt + * + * Responsible for handling management control frames + * + * Called by rtllib_rx + */ +static inline int +rtllib_rx_frame_mgmt(struct rtllib_device *ieee, struct sk_buff *skb, + struct rtllib_rx_stats *rx_stats, u16 type, + u16 stype) +{ + /* On the struct stats definition there is written that + * this is not mandatory.... but seems that the probe + * response parser uses it + */ + struct rtllib_hdr_3addr *hdr = (struct rtllib_hdr_3addr *)skb->data; + + rx_stats->len = skb->len; + rtllib_rx_mgt(ieee, skb, rx_stats); + if ((memcmp(hdr->addr1, ieee->dev->dev_addr, ETH_ALEN))) { + dev_kfree_skb_any(skb); + return 0; + } + rtllib_rx_frame_softmac(ieee, skb, rx_stats, type, stype); + + dev_kfree_skb_any(skb); + + return 0; +} + +/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation + * Ethernet-II snap header (RFC1042 for most EtherTypes) + */ +static unsigned char rfc1042_header[] = { + 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 +}; +/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ +static unsigned char bridge_tunnel_header[] = { + 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 +}; +/* No encapsulation header if EtherType < 0x600 (=length) */ + +/* Called by rtllib_rx_frame_decrypt */ +static int rtllib_is_eapol_frame(struct rtllib_device *ieee, + struct sk_buff *skb, size_t hdrlen) +{ + struct net_device *dev = ieee->dev; + u16 fc, ethertype; + struct rtllib_hdr_4addr *hdr; + u8 *pos; + + if (skb->len < 24) + return 0; + + hdr = (struct rtllib_hdr_4addr *) skb->data; + fc = le16_to_cpu(hdr->frame_ctl); + + /* check that the frame is unicast frame to us */ + if ((fc & (RTLLIB_FCTL_TODS | RTLLIB_FCTL_FROMDS)) == + RTLLIB_FCTL_TODS && + memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0 && + memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) { + /* ToDS frame with own addr BSSID and DA */ + } else if ((fc & (RTLLIB_FCTL_TODS | RTLLIB_FCTL_FROMDS)) == + RTLLIB_FCTL_FROMDS && + memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) { + /* FromDS frame with own addr as DA */ + } else + return 0; + + if (skb->len < 24 + 8) + return 0; + + /* check for port access entity Ethernet type */ + pos = skb->data + hdrlen; + ethertype = (pos[6] << 8) | pos[7]; + if (ethertype == ETH_P_PAE) + return 1; + + return 0; +} + +/* Called only as a tasklet (software IRQ), by rtllib_rx */ +static inline int +rtllib_rx_frame_decrypt(struct rtllib_device *ieee, struct sk_buff *skb, + struct lib80211_crypt_data *crypt) +{ + struct rtllib_hdr_4addr *hdr; + int res, hdrlen; + + if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL) + return 0; + + if (ieee->hwsec_active) { + struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); + + tcb_desc->bHwSec = 1; + + if (ieee->need_sw_enc) + tcb_desc->bHwSec = 0; + } + + hdr = (struct rtllib_hdr_4addr *) skb->data; + hdrlen = rtllib_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); + + atomic_inc(&crypt->refcnt); + res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv); + atomic_dec(&crypt->refcnt); + if (res < 0) { + RTLLIB_DEBUG_DROP( + "decryption failed (SA= %pM) res=%d\n", hdr->addr2, res); + if (res == -2) + RTLLIB_DEBUG_DROP("Decryption failed ICV mismatch (key %d)\n", + skb->data[hdrlen + 3] >> 6); + ieee->ieee_stats.rx_discards_undecryptable++; + return -1; + } + + return res; +} + + +/* Called only as a tasklet (software IRQ), by rtllib_rx */ +static inline int +rtllib_rx_frame_decrypt_msdu(struct rtllib_device *ieee, struct sk_buff *skb, + int keyidx, struct lib80211_crypt_data *crypt) +{ + struct rtllib_hdr_4addr *hdr; + int res, hdrlen; + + if (crypt == NULL || crypt->ops->decrypt_msdu == NULL) + return 0; + if (ieee->hwsec_active) { + struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); + + tcb_desc->bHwSec = 1; + + if (ieee->need_sw_enc) + tcb_desc->bHwSec = 0; + } + + hdr = (struct rtllib_hdr_4addr *) skb->data; + hdrlen = rtllib_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); + + atomic_inc(&crypt->refcnt); + res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv); + atomic_dec(&crypt->refcnt); + if (res < 0) { + printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed (SA= %pM keyidx=%d)\n", + ieee->dev->name, hdr->addr2, keyidx); + return -1; + } + + return 0; +} + + +/* this function is stolen from ipw2200 driver*/ +#define IEEE_PACKET_RETRY_TIME (5*HZ) +static int is_duplicate_packet(struct rtllib_device *ieee, + struct rtllib_hdr_4addr *header) +{ + u16 fc = le16_to_cpu(header->frame_ctl); + u16 sc = le16_to_cpu(header->seq_ctl); + u16 seq = WLAN_GET_SEQ_SEQ(sc); + u16 frag = WLAN_GET_SEQ_FRAG(sc); + u16 *last_seq, *last_frag; + unsigned long *last_time; + struct rtllib_hdr_3addrqos *hdr_3addrqos; + struct rtllib_hdr_4addrqos *hdr_4addrqos; + u8 tid; + + if (((fc & RTLLIB_FCTL_DSTODS) == RTLLIB_FCTL_DSTODS) && RTLLIB_QOS_HAS_SEQ(fc)) { + hdr_4addrqos = (struct rtllib_hdr_4addrqos *)header; + tid = le16_to_cpu(hdr_4addrqos->qos_ctl) & RTLLIB_QCTL_TID; + tid = UP2AC(tid); + tid++; + } else if (RTLLIB_QOS_HAS_SEQ(fc)) { + hdr_3addrqos = (struct rtllib_hdr_3addrqos *)header; + tid = le16_to_cpu(hdr_3addrqos->qos_ctl) & RTLLIB_QCTL_TID; + tid = UP2AC(tid); + tid++; + } else { + tid = 0; + } + + switch (ieee->iw_mode) { + case IW_MODE_ADHOC: + { + struct list_head *p; + struct ieee_ibss_seq *entry = NULL; + u8 *mac = header->addr2; + int index = mac[5] % IEEE_IBSS_MAC_HASH_SIZE; + + list_for_each(p, &ieee->ibss_mac_hash[index]) { + entry = list_entry(p, struct ieee_ibss_seq, list); + if (!memcmp(entry->mac, mac, ETH_ALEN)) + break; + } + if (p == &ieee->ibss_mac_hash[index]) { + entry = kmalloc(sizeof(struct ieee_ibss_seq), GFP_ATOMIC); + if (!entry) + return 0; + + memcpy(entry->mac, mac, ETH_ALEN); + entry->seq_num[tid] = seq; + entry->frag_num[tid] = frag; + entry->packet_time[tid] = jiffies; + list_add(&entry->list, &ieee->ibss_mac_hash[index]); + return 0; + } + last_seq = &entry->seq_num[tid]; + last_frag = &entry->frag_num[tid]; + last_time = &entry->packet_time[tid]; + break; + } + + case IW_MODE_INFRA: + last_seq = &ieee->last_rxseq_num[tid]; + last_frag = &ieee->last_rxfrag_num[tid]; + last_time = &ieee->last_packet_time[tid]; + break; + default: + return 0; + } + + if ((*last_seq == seq) && + time_after(*last_time + IEEE_PACKET_RETRY_TIME, jiffies)) { + if (*last_frag == frag) + goto drop; + if (*last_frag + 1 != frag) + /* out-of-order fragment */ + goto drop; + } else + *last_seq = seq; + + *last_frag = frag; + *last_time = jiffies; + return 0; + +drop: + + return 1; +} + +static bool AddReorderEntry(struct rx_ts_record *pTS, + struct rx_reorder_entry *pReorderEntry) +{ + struct list_head *pList = &pTS->RxPendingPktList; + + while (pList->next != &pTS->RxPendingPktList) { + if (SN_LESS(pReorderEntry->SeqNum, ((struct rx_reorder_entry *) + list_entry(pList->next, struct rx_reorder_entry, + List))->SeqNum)) + pList = pList->next; + else if (SN_EQUAL(pReorderEntry->SeqNum, + ((struct rx_reorder_entry *)list_entry(pList->next, + struct rx_reorder_entry, List))->SeqNum)) + return false; + else + break; + } + pReorderEntry->List.next = pList->next; + pReorderEntry->List.next->prev = &pReorderEntry->List; + pReorderEntry->List.prev = pList; + pList->next = &pReorderEntry->List; + + return true; +} + +void rtllib_indicate_packets(struct rtllib_device *ieee, struct rtllib_rxb **prxbIndicateArray, u8 index) +{ + struct net_device_stats *stats = &ieee->stats; + u8 i = 0 , j = 0; + u16 ethertype; + + for (j = 0; j < index; j++) { + struct rtllib_rxb *prxb = prxbIndicateArray[j]; + + for (i = 0; i < prxb->nr_subframes; i++) { + struct sk_buff *sub_skb = prxb->subframes[i]; + + /* convert hdr + possible LLC headers into Ethernet header */ + ethertype = (sub_skb->data[6] << 8) | sub_skb->data[7]; + if (sub_skb->len >= 8 && + ((memcmp(sub_skb->data, rfc1042_header, SNAP_SIZE) == 0 && + ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || + memcmp(sub_skb->data, bridge_tunnel_header, SNAP_SIZE) == 0)) { + /* remove RFC1042 or Bridge-Tunnel encapsulation + * and replace EtherType + */ + skb_pull(sub_skb, SNAP_SIZE); + memcpy(skb_push(sub_skb, ETH_ALEN), prxb->src, ETH_ALEN); + memcpy(skb_push(sub_skb, ETH_ALEN), prxb->dst, ETH_ALEN); + } else { + u16 len; + /* Leave Ethernet header part of hdr and full payload */ + len = sub_skb->len; + memcpy(skb_push(sub_skb, 2), &len, 2); + memcpy(skb_push(sub_skb, ETH_ALEN), prxb->src, ETH_ALEN); + memcpy(skb_push(sub_skb, ETH_ALEN), prxb->dst, ETH_ALEN); + } + + /* Indicate the packets to upper layer */ + if (sub_skb) { + stats->rx_packets++; + stats->rx_bytes += sub_skb->len; + + memset(sub_skb->cb, 0, sizeof(sub_skb->cb)); + sub_skb->protocol = eth_type_trans(sub_skb, ieee->dev); + sub_skb->dev = ieee->dev; + sub_skb->dev->stats.rx_packets++; + sub_skb->dev->stats.rx_bytes += sub_skb->len; + sub_skb->ip_summed = CHECKSUM_NONE; /* 802.11 crc not sufficient */ + ieee->last_rx_ps_time = jiffies; + netif_rx(sub_skb); + } + } + kfree(prxb); + prxb = NULL; + } +} + +void rtllib_FlushRxTsPendingPkts(struct rtllib_device *ieee, struct rx_ts_record *pTS) +{ + struct rx_reorder_entry *pRxReorderEntry; + u8 RfdCnt = 0; + + del_timer_sync(&pTS->RxPktPendingTimer); + while (!list_empty(&pTS->RxPendingPktList)) { + if (RfdCnt >= REORDER_WIN_SIZE) { + netdev_info(ieee->dev, + "-------------->%s() error! RfdCnt >= REORDER_WIN_SIZE\n", + __func__); + break; + } + + pRxReorderEntry = (struct rx_reorder_entry *)list_entry(pTS->RxPendingPktList.prev, struct rx_reorder_entry, List); + RTLLIB_DEBUG(RTLLIB_DL_REORDER, "%s(): Indicate SeqNum %d!\n", __func__, pRxReorderEntry->SeqNum); + list_del_init(&pRxReorderEntry->List); + + ieee->RfdArray[RfdCnt] = pRxReorderEntry->prxb; + + RfdCnt = RfdCnt + 1; + list_add_tail(&pRxReorderEntry->List, &ieee->RxReorder_Unused_List); + } + rtllib_indicate_packets(ieee, ieee->RfdArray, RfdCnt); + + pTS->RxIndicateSeq = 0xffff; +} + +static void RxReorderIndicatePacket(struct rtllib_device *ieee, + struct rtllib_rxb *prxb, + struct rx_ts_record *pTS, u16 SeqNum) +{ + struct rt_hi_throughput *pHTInfo = ieee->pHTInfo; + struct rx_reorder_entry *pReorderEntry = NULL; + u8 WinSize = pHTInfo->RxReorderWinSize; + u16 WinEnd = 0; + u8 index = 0; + bool bMatchWinStart = false, bPktInBuf = false; + unsigned long flags; + + RTLLIB_DEBUG(RTLLIB_DL_REORDER, "%s(): Seq is %d, pTS->RxIndicateSeq is %d, WinSize is %d\n", __func__, SeqNum, + pTS->RxIndicateSeq, WinSize); + + spin_lock_irqsave(&(ieee->reorder_spinlock), flags); + + WinEnd = (pTS->RxIndicateSeq + WinSize - 1) % 4096; + /* Rx Reorder initialize condition.*/ + if (pTS->RxIndicateSeq == 0xffff) + pTS->RxIndicateSeq = SeqNum; + + /* Drop out the packet which SeqNum is smaller than WinStart */ + if (SN_LESS(SeqNum, pTS->RxIndicateSeq)) { + RTLLIB_DEBUG(RTLLIB_DL_REORDER, "Packet Drop! IndicateSeq: %d, NewSeq: %d\n", + pTS->RxIndicateSeq, SeqNum); + pHTInfo->RxReorderDropCounter++; + { + int i; + + for (i = 0; i < prxb->nr_subframes; i++) + dev_kfree_skb(prxb->subframes[i]); + kfree(prxb); + prxb = NULL; + } + spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags); + return; + } + + /* Sliding window manipulation. Conditions includes: + * 1. Incoming SeqNum is equal to WinStart =>Window shift 1 + * 2. Incoming SeqNum is larger than the WinEnd => Window shift N + */ + if (SN_EQUAL(SeqNum, pTS->RxIndicateSeq)) { + pTS->RxIndicateSeq = (pTS->RxIndicateSeq + 1) % 4096; + bMatchWinStart = true; + } else if (SN_LESS(WinEnd, SeqNum)) { + if (SeqNum >= (WinSize - 1)) + pTS->RxIndicateSeq = SeqNum + 1 - WinSize; + else + pTS->RxIndicateSeq = 4095 - (WinSize - (SeqNum + 1)) + 1; + RTLLIB_DEBUG(RTLLIB_DL_REORDER, "Window Shift! IndicateSeq: %d, NewSeq: %d\n", pTS->RxIndicateSeq, SeqNum); + } + + /* Indication process. + * After Packet dropping and Sliding Window shifting as above, we can + * now just indicate the packets with the SeqNum smaller than latest + * WinStart and struct buffer other packets. + * + * For Rx Reorder condition: + * 1. All packets with SeqNum smaller than WinStart => Indicate + * 2. All packets with SeqNum larger than or equal to + * WinStart => Buffer it. + */ + if (bMatchWinStart) { + /* Current packet is going to be indicated.*/ + RTLLIB_DEBUG(RTLLIB_DL_REORDER, "Packets indication!! IndicateSeq: %d, NewSeq: %d\n", + pTS->RxIndicateSeq, SeqNum); + ieee->prxbIndicateArray[0] = prxb; + index = 1; + } else { + /* Current packet is going to be inserted into pending list.*/ + if (!list_empty(&ieee->RxReorder_Unused_List)) { + pReorderEntry = (struct rx_reorder_entry *) + list_entry(ieee->RxReorder_Unused_List.next, + struct rx_reorder_entry, List); + list_del_init(&pReorderEntry->List); + + /* Make a reorder entry and insert into a the packet list.*/ + pReorderEntry->SeqNum = SeqNum; + pReorderEntry->prxb = prxb; + + if (!AddReorderEntry(pTS, pReorderEntry)) { + RTLLIB_DEBUG(RTLLIB_DL_REORDER, + "%s(): Duplicate packet is dropped!! IndicateSeq: %d, NewSeq: %d\n", + __func__, pTS->RxIndicateSeq, + SeqNum); + list_add_tail(&pReorderEntry->List, + &ieee->RxReorder_Unused_List); { + int i; + + for (i = 0; i < prxb->nr_subframes; i++) + dev_kfree_skb(prxb->subframes[i]); + kfree(prxb); + prxb = NULL; + } + } else { + RTLLIB_DEBUG(RTLLIB_DL_REORDER, + "Pkt insert into struct buffer!! IndicateSeq: %d, NewSeq: %d\n", + pTS->RxIndicateSeq, SeqNum); + } + } else { + /* Packets are dropped if there are not enough reorder + * entries. This part should be modified!! We can just + * indicate all the packets in struct buffer and get + * reorder entries. + */ + RTLLIB_DEBUG(RTLLIB_DL_ERR, "RxReorderIndicatePacket(): There is no reorder entry!! Packet is dropped!!\n"); + { + int i; + + for (i = 0; i < prxb->nr_subframes; i++) + dev_kfree_skb(prxb->subframes[i]); + kfree(prxb); + prxb = NULL; + } + } + } + + /* Check if there is any packet need indicate.*/ + while (!list_empty(&pTS->RxPendingPktList)) { + RTLLIB_DEBUG(RTLLIB_DL_REORDER, "%s(): start RREORDER indicate\n", __func__); + + pReorderEntry = (struct rx_reorder_entry *)list_entry(pTS->RxPendingPktList.prev, + struct rx_reorder_entry, List); + if (SN_LESS(pReorderEntry->SeqNum, pTS->RxIndicateSeq) || + SN_EQUAL(pReorderEntry->SeqNum, pTS->RxIndicateSeq)) { + /* This protect struct buffer from overflow. */ + if (index >= REORDER_WIN_SIZE) { + RTLLIB_DEBUG(RTLLIB_DL_ERR, "RxReorderIndicatePacket(): Buffer overflow!!\n"); + bPktInBuf = true; + break; + } + + list_del_init(&pReorderEntry->List); + + if (SN_EQUAL(pReorderEntry->SeqNum, pTS->RxIndicateSeq)) + pTS->RxIndicateSeq = (pTS->RxIndicateSeq + 1) % 4096; + + ieee->prxbIndicateArray[index] = pReorderEntry->prxb; + RTLLIB_DEBUG(RTLLIB_DL_REORDER, "%s(): Indicate SeqNum %d!\n", __func__, pReorderEntry->SeqNum); + index++; + + list_add_tail(&pReorderEntry->List, + &ieee->RxReorder_Unused_List); + } else { + bPktInBuf = true; + break; + } + } + + /* Handling pending timer. Set this timer to prevent from long time + * Rx buffering. + */ + if (index > 0) { + if (timer_pending(&pTS->RxPktPendingTimer)) + del_timer_sync(&pTS->RxPktPendingTimer); + pTS->RxTimeoutIndicateSeq = 0xffff; + + if (index > REORDER_WIN_SIZE) { + RTLLIB_DEBUG(RTLLIB_DL_ERR, "RxReorderIndicatePacket(): Rx Reorder struct buffer full!!\n"); + spin_unlock_irqrestore(&(ieee->reorder_spinlock), + flags); + return; + } + rtllib_indicate_packets(ieee, ieee->prxbIndicateArray, index); + bPktInBuf = false; + } + + if (bPktInBuf && pTS->RxTimeoutIndicateSeq == 0xffff) { + RTLLIB_DEBUG(RTLLIB_DL_REORDER, "%s(): SET rx timeout timer\n", + __func__); + pTS->RxTimeoutIndicateSeq = pTS->RxIndicateSeq; + mod_timer(&pTS->RxPktPendingTimer, jiffies + + msecs_to_jiffies(pHTInfo->RxReorderPendingTime)); + } + spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags); +} + +static u8 parse_subframe(struct rtllib_device *ieee, struct sk_buff *skb, + struct rtllib_rx_stats *rx_stats, + struct rtllib_rxb *rxb, u8 *src, u8 *dst) +{ + struct rtllib_hdr_3addr *hdr = (struct rtllib_hdr_3addr *)skb->data; + u16 fc = le16_to_cpu(hdr->frame_ctl); + + u16 LLCOffset = sizeof(struct rtllib_hdr_3addr); + u16 ChkLength; + bool bIsAggregateFrame = false; + u16 nSubframe_Length; + u8 nPadding_Length = 0; + u16 SeqNum = 0; + struct sk_buff *sub_skb; + u8 *data_ptr; + /* just for debug purpose */ + SeqNum = WLAN_GET_SEQ_SEQ(le16_to_cpu(hdr->seq_ctl)); + if ((RTLLIB_QOS_HAS_SEQ(fc)) && + (((union frameqos *)(skb->data + RTLLIB_3ADDR_LEN))->field.reserved)) + bIsAggregateFrame = true; + + if (RTLLIB_QOS_HAS_SEQ(fc)) + LLCOffset += 2; + if (rx_stats->bContainHTC) + LLCOffset += sHTCLng; + + ChkLength = LLCOffset; + + if (skb->len <= ChkLength) + return 0; + + skb_pull(skb, LLCOffset); + ieee->bIsAggregateFrame = bIsAggregateFrame; + if (!bIsAggregateFrame) { + rxb->nr_subframes = 1; + + /* altered by clark 3/30/2010 + * The struct buffer size of the skb indicated to upper layer + * must be less than 5000, or the defraged IP datagram + * in the IP layer will exceed "ipfrag_high_tresh" and be + * discarded. so there must not use the function + * "skb_copy" and "skb_clone" for "skb". + */ + + /* Allocate new skb for releasing to upper layer */ + sub_skb = dev_alloc_skb(RTLLIB_SKBBUFFER_SIZE); + if (!sub_skb) + return 0; + skb_reserve(sub_skb, 12); + data_ptr = (u8 *)skb_put(sub_skb, skb->len); + memcpy(data_ptr, skb->data, skb->len); + sub_skb->dev = ieee->dev; + + rxb->subframes[0] = sub_skb; + + memcpy(rxb->src, src, ETH_ALEN); + memcpy(rxb->dst, dst, ETH_ALEN); + rxb->subframes[0]->dev = ieee->dev; + return 1; + } + + rxb->nr_subframes = 0; + memcpy(rxb->src, src, ETH_ALEN); + memcpy(rxb->dst, dst, ETH_ALEN); + while (skb->len > ETHERNET_HEADER_SIZE) { + /* Offset 12 denote 2 mac address */ + nSubframe_Length = *((u16 *)(skb->data + 12)); + nSubframe_Length = (nSubframe_Length >> 8) + + (nSubframe_Length << 8); + + if (skb->len < (ETHERNET_HEADER_SIZE + nSubframe_Length)) { + netdev_info(ieee->dev, + "%s: A-MSDU parse error!! pRfd->nTotalSubframe : %d\n", + __func__, rxb->nr_subframes); + netdev_info(ieee->dev, + "%s: A-MSDU parse error!! Subframe Length: %d\n", + __func__, nSubframe_Length); + netdev_info(ieee->dev, + "nRemain_Length is %d and nSubframe_Length is : %d\n", + skb->len, nSubframe_Length); + netdev_info(ieee->dev, + "The Packet SeqNum is %d\n", + SeqNum); + return 0; + } + + /* move the data point to data content */ + skb_pull(skb, ETHERNET_HEADER_SIZE); + + /* altered by clark 3/30/2010 + * The struct buffer size of the skb indicated to upper layer + * must be less than 5000, or the defraged IP datagram + * in the IP layer will exceed "ipfrag_high_tresh" and be + * discarded. so there must not use the function + * "skb_copy" and "skb_clone" for "skb". + */ + + /* Allocate new skb for releasing to upper layer */ + sub_skb = dev_alloc_skb(nSubframe_Length + 12); + if (!sub_skb) + return 0; + skb_reserve(sub_skb, 12); + data_ptr = (u8 *)skb_put(sub_skb, nSubframe_Length); + memcpy(data_ptr, skb->data, nSubframe_Length); + + sub_skb->dev = ieee->dev; + rxb->subframes[rxb->nr_subframes++] = sub_skb; + if (rxb->nr_subframes >= MAX_SUBFRAME_COUNT) { + RTLLIB_DEBUG_RX("ParseSubframe(): Too many Subframes! Packets dropped!\n"); + break; + } + skb_pull(skb, nSubframe_Length); + + if (skb->len != 0) { + nPadding_Length = 4 - ((nSubframe_Length + + ETHERNET_HEADER_SIZE) % 4); + if (nPadding_Length == 4) + nPadding_Length = 0; + + if (skb->len < nPadding_Length) + return 0; + + skb_pull(skb, nPadding_Length); + } + } + + return rxb->nr_subframes; +} + + +static size_t rtllib_rx_get_hdrlen(struct rtllib_device *ieee, + struct sk_buff *skb, + struct rtllib_rx_stats *rx_stats) +{ + struct rtllib_hdr_4addr *hdr = (struct rtllib_hdr_4addr *)skb->data; + u16 fc = le16_to_cpu(hdr->frame_ctl); + size_t hdrlen = 0; + + hdrlen = rtllib_get_hdrlen(fc); + if (HTCCheck(ieee, skb->data)) { + if (net_ratelimit()) + netdev_info(ieee->dev, "%s: find HTCControl!\n", + __func__); + hdrlen += 4; + rx_stats->bContainHTC = true; + } + + if (RTLLIB_QOS_HAS_SEQ(fc)) + rx_stats->bIsQosData = true; + + return hdrlen; +} + +static int rtllib_rx_check_duplicate(struct rtllib_device *ieee, + struct sk_buff *skb, u8 multicast) +{ + struct rtllib_hdr_4addr *hdr = (struct rtllib_hdr_4addr *)skb->data; + u16 fc, sc; + u8 frag, type, stype; + + fc = le16_to_cpu(hdr->frame_ctl); + type = WLAN_FC_GET_TYPE(fc); + stype = WLAN_FC_GET_STYPE(fc); + sc = le16_to_cpu(hdr->seq_ctl); + frag = WLAN_GET_SEQ_FRAG(sc); + + if ((ieee->pHTInfo->bCurRxReorderEnable == false) || + !ieee->current_network.qos_data.active || + !IsDataFrame(skb->data) || + IsLegacyDataFrame(skb->data)) { + if (!((type == RTLLIB_FTYPE_MGMT) && (stype == RTLLIB_STYPE_BEACON))) { + if (is_duplicate_packet(ieee, hdr)) + return -1; + } + } else { + struct rx_ts_record *pRxTS = NULL; + + if (GetTs(ieee, (struct ts_common_info **) &pRxTS, hdr->addr2, + (u8)Frame_QoSTID((u8 *)(skb->data)), RX_DIR, true)) { + if ((fc & (1<<11)) && (frag == pRxTS->RxLastFragNum) && + (WLAN_GET_SEQ_SEQ(sc) == pRxTS->RxLastSeqNum)) + return -1; + pRxTS->RxLastFragNum = frag; + pRxTS->RxLastSeqNum = WLAN_GET_SEQ_SEQ(sc); + } else { + RTLLIB_DEBUG(RTLLIB_DL_ERR, "ERR!!%s(): No TS!! Skip the check!!\n", __func__); + return -1; + } + } + + return 0; +} + +static void rtllib_rx_extract_addr(struct rtllib_device *ieee, + struct rtllib_hdr_4addr *hdr, u8 *dst, + u8 *src, u8 *bssid) +{ + u16 fc = le16_to_cpu(hdr->frame_ctl); + + switch (fc & (RTLLIB_FCTL_FROMDS | RTLLIB_FCTL_TODS)) { + case RTLLIB_FCTL_FROMDS: + memcpy(dst, hdr->addr1, ETH_ALEN); + memcpy(src, hdr->addr3, ETH_ALEN); + memcpy(bssid, hdr->addr2, ETH_ALEN); + break; + case RTLLIB_FCTL_TODS: + memcpy(dst, hdr->addr3, ETH_ALEN); + memcpy(src, hdr->addr2, ETH_ALEN); + memcpy(bssid, hdr->addr1, ETH_ALEN); + break; + case RTLLIB_FCTL_FROMDS | RTLLIB_FCTL_TODS: + memcpy(dst, hdr->addr3, ETH_ALEN); + memcpy(src, hdr->addr4, ETH_ALEN); + memcpy(bssid, ieee->current_network.bssid, ETH_ALEN); + break; + case 0: + memcpy(dst, hdr->addr1, ETH_ALEN); + memcpy(src, hdr->addr2, ETH_ALEN); + memcpy(bssid, hdr->addr3, ETH_ALEN); + break; + } +} + +static int rtllib_rx_data_filter(struct rtllib_device *ieee, u16 fc, + u8 *dst, u8 *src, u8 *bssid, u8 *addr2) +{ + u8 type, stype; + + type = WLAN_FC_GET_TYPE(fc); + stype = WLAN_FC_GET_STYPE(fc); + + /* Filter frames from different BSS */ + if (((fc & RTLLIB_FCTL_DSTODS) != RTLLIB_FCTL_DSTODS) && + !ether_addr_equal(ieee->current_network.bssid, bssid) && + !is_zero_ether_addr(ieee->current_network.bssid)) { + return -1; + } + + /* Filter packets sent by an STA that will be forwarded by AP */ + if (ieee->IntelPromiscuousModeInfo.bPromiscuousOn && + ieee->IntelPromiscuousModeInfo.bFilterSourceStationFrame) { + if ((fc & RTLLIB_FCTL_TODS) && !(fc & RTLLIB_FCTL_FROMDS) && + !ether_addr_equal(dst, ieee->current_network.bssid) && + ether_addr_equal(bssid, ieee->current_network.bssid)) { + return -1; + } + } + + /* Nullfunc frames may have PS-bit set, so they must be passed to + * hostap_handle_sta_rx() before being dropped here. + */ + if (!ieee->IntelPromiscuousModeInfo.bPromiscuousOn) { + if (stype != RTLLIB_STYPE_DATA && + stype != RTLLIB_STYPE_DATA_CFACK && + stype != RTLLIB_STYPE_DATA_CFPOLL && + stype != RTLLIB_STYPE_DATA_CFACKPOLL && + stype != RTLLIB_STYPE_QOS_DATA) { + if (stype != RTLLIB_STYPE_NULLFUNC) + RTLLIB_DEBUG_DROP( + "RX: dropped data frame with no data (type=0x%02x, subtype=0x%02x)\n", + type, stype); + return -1; + } + } + + if (ieee->iw_mode != IW_MODE_MESH) { + /* packets from our adapter are dropped (echo) */ + if (!memcmp(src, ieee->dev->dev_addr, ETH_ALEN)) + return -1; + + /* {broad,multi}cast packets to our BSS go through */ + if (is_multicast_ether_addr(dst)) { + if (memcmp(bssid, ieee->current_network.bssid, ETH_ALEN)) + return -1; + } + } + return 0; +} + +static int rtllib_rx_get_crypt(struct rtllib_device *ieee, struct sk_buff *skb, + struct lib80211_crypt_data **crypt, size_t hdrlen) +{ + struct rtllib_hdr_4addr *hdr = (struct rtllib_hdr_4addr *)skb->data; + u16 fc = le16_to_cpu(hdr->frame_ctl); + int idx = 0; + + if (ieee->host_decrypt) { + if (skb->len >= hdrlen + 3) + idx = skb->data[hdrlen + 3] >> 6; + + *crypt = ieee->crypt_info.crypt[idx]; + /* allow NULL decrypt to indicate an station specific override + * for default encryption + */ + if (*crypt && ((*crypt)->ops == NULL || + (*crypt)->ops->decrypt_mpdu == NULL)) + *crypt = NULL; + + if (!*crypt && (fc & RTLLIB_FCTL_WEP)) { + /* This seems to be triggered by some (multicast?) + * frames from other than current BSS, so just drop the + * frames silently instead of filling system log with + * these reports. + */ + RTLLIB_DEBUG_DROP("Decryption failed (not set) (SA= %pM)\n", + hdr->addr2); + ieee->ieee_stats.rx_discards_undecryptable++; + return -1; + } + } + + return 0; +} + +static int rtllib_rx_decrypt(struct rtllib_device *ieee, struct sk_buff *skb, + struct rtllib_rx_stats *rx_stats, + struct lib80211_crypt_data *crypt, size_t hdrlen) +{ + struct rtllib_hdr_4addr *hdr; + int keyidx = 0; + u16 fc, sc; + u8 frag; + + hdr = (struct rtllib_hdr_4addr *)skb->data; + fc = le16_to_cpu(hdr->frame_ctl); + sc = le16_to_cpu(hdr->seq_ctl); + frag = WLAN_GET_SEQ_FRAG(sc); + + if ((!rx_stats->Decrypted)) + ieee->need_sw_enc = 1; + else + ieee->need_sw_enc = 0; + + keyidx = rtllib_rx_frame_decrypt(ieee, skb, crypt); + if (ieee->host_decrypt && (fc & RTLLIB_FCTL_WEP) && (keyidx < 0)) { + netdev_info(ieee->dev, "%s: decrypt frame error\n", __func__); + return -1; + } + + hdr = (struct rtllib_hdr_4addr *) skb->data; + if ((frag != 0 || (fc & RTLLIB_FCTL_MOREFRAGS))) { + int flen; + struct sk_buff *frag_skb = rtllib_frag_cache_get(ieee, hdr); + + RTLLIB_DEBUG_FRAG("Rx Fragment received (%u)\n", frag); + + if (!frag_skb) { + RTLLIB_DEBUG(RTLLIB_DL_RX | RTLLIB_DL_FRAG, + "Rx cannot get skb from fragment cache (morefrag=%d seq=%u frag=%u)\n", + (fc & RTLLIB_FCTL_MOREFRAGS) != 0, + WLAN_GET_SEQ_SEQ(sc), frag); + return -1; + } + flen = skb->len; + if (frag != 0) + flen -= hdrlen; + + if (frag_skb->tail + flen > frag_skb->end) { + netdev_warn(ieee->dev, + "%s: host decrypted and reassembled frame did not fit skb\n", + __func__); + rtllib_frag_cache_invalidate(ieee, hdr); + return -1; + } + + if (frag == 0) { + /* copy first fragment (including full headers) into + * beginning of the fragment cache skb + */ + memcpy(skb_put(frag_skb, flen), skb->data, flen); + } else { + /* append frame payload to the end of the fragment + * cache skb + */ + memcpy(skb_put(frag_skb, flen), skb->data + hdrlen, + flen); + } + dev_kfree_skb_any(skb); + skb = NULL; + + if (fc & RTLLIB_FCTL_MOREFRAGS) { + /* more fragments expected - leave the skb in fragment + * cache for now; it will be delivered to upper layers + * after all fragments have been received + */ + return -2; + } + + /* this was the last fragment and the frame will be + * delivered, so remove skb from fragment cache + */ + skb = frag_skb; + hdr = (struct rtllib_hdr_4addr *) skb->data; + rtllib_frag_cache_invalidate(ieee, hdr); + } + + /* skb: hdr + (possible reassembled) full MSDU payload; possibly still + * encrypted/authenticated + */ + if (ieee->host_decrypt && (fc & RTLLIB_FCTL_WEP) && + rtllib_rx_frame_decrypt_msdu(ieee, skb, keyidx, crypt)) { + netdev_info(ieee->dev, "%s: ==>decrypt msdu error\n", __func__); + return -1; + } + + hdr = (struct rtllib_hdr_4addr *) skb->data; + if (crypt && !(fc & RTLLIB_FCTL_WEP) && !ieee->open_wep) { + if (/*ieee->ieee802_1x &&*/ + rtllib_is_eapol_frame(ieee, skb, hdrlen)) { + + /* pass unencrypted EAPOL frames even if encryption is + * configured + */ + struct eapol *eap = (struct eapol *)(skb->data + + 24); + RTLLIB_DEBUG_EAP("RX: IEEE 802.1X EAPOL frame: %s\n", + eap_get_type(eap->type)); + } else { + RTLLIB_DEBUG_DROP( + "encryption configured, but RX frame not encrypted (SA= %pM)\n", + hdr->addr2); + return -1; + } + } + + if (crypt && !(fc & RTLLIB_FCTL_WEP) && + rtllib_is_eapol_frame(ieee, skb, hdrlen)) { + struct eapol *eap = (struct eapol *)(skb->data + + 24); + RTLLIB_DEBUG_EAP("RX: IEEE 802.1X EAPOL frame: %s\n", + eap_get_type(eap->type)); + } + + if (crypt && !(fc & RTLLIB_FCTL_WEP) && !ieee->open_wep && + !rtllib_is_eapol_frame(ieee, skb, hdrlen)) { + RTLLIB_DEBUG_DROP( + "dropped unencrypted RX data frame from %pM (drop_unencrypted=1)\n", + hdr->addr2); + return -1; + } + + if (rtllib_is_eapol_frame(ieee, skb, hdrlen)) + netdev_warn(ieee->dev, "RX: IEEE802.1X EAPOL frame!\n"); + + return 0; +} + +static void rtllib_rx_check_leave_lps(struct rtllib_device *ieee, u8 unicast, u8 nr_subframes) +{ + if (unicast) { + + if (ieee->state == RTLLIB_LINKED) { + if (((ieee->LinkDetectInfo.NumRxUnicastOkInPeriod + + ieee->LinkDetectInfo.NumTxOkInPeriod) > 8) || + (ieee->LinkDetectInfo.NumRxUnicastOkInPeriod > 2)) { + if (ieee->LeisurePSLeave) + ieee->LeisurePSLeave(ieee->dev); + } + } + } + ieee->last_rx_ps_time = jiffies; +} + +static void rtllib_rx_indicate_pkt_legacy(struct rtllib_device *ieee, + struct rtllib_rx_stats *rx_stats, + struct rtllib_rxb *rxb, + u8 *dst, + u8 *src) +{ + struct net_device *dev = ieee->dev; + u16 ethertype; + int i = 0; + + if (rxb == NULL) { + netdev_info(dev, "%s: rxb is NULL!!\n", __func__); + return; + } + + for (i = 0; i < rxb->nr_subframes; i++) { + struct sk_buff *sub_skb = rxb->subframes[i]; + + if (sub_skb) { + /* convert hdr + possible LLC headers into Ethernet header */ + ethertype = (sub_skb->data[6] << 8) | sub_skb->data[7]; + if (sub_skb->len >= 8 && + ((memcmp(sub_skb->data, rfc1042_header, SNAP_SIZE) == 0 && + ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || + memcmp(sub_skb->data, bridge_tunnel_header, SNAP_SIZE) == 0)) { + /* remove RFC1042 or Bridge-Tunnel encapsulation and + * replace EtherType + */ + skb_pull(sub_skb, SNAP_SIZE); + memcpy(skb_push(sub_skb, ETH_ALEN), src, ETH_ALEN); + memcpy(skb_push(sub_skb, ETH_ALEN), dst, ETH_ALEN); + } else { + u16 len; + /* Leave Ethernet header part of hdr and full payload */ + len = sub_skb->len; + memcpy(skb_push(sub_skb, 2), &len, 2); + memcpy(skb_push(sub_skb, ETH_ALEN), src, ETH_ALEN); + memcpy(skb_push(sub_skb, ETH_ALEN), dst, ETH_ALEN); + } + + ieee->stats.rx_packets++; + ieee->stats.rx_bytes += sub_skb->len; + + if (is_multicast_ether_addr(dst)) + ieee->stats.multicast++; + + /* Indicate the packets to upper layer */ + memset(sub_skb->cb, 0, sizeof(sub_skb->cb)); + sub_skb->protocol = eth_type_trans(sub_skb, dev); + sub_skb->dev = dev; + sub_skb->dev->stats.rx_packets++; + sub_skb->dev->stats.rx_bytes += sub_skb->len; + sub_skb->ip_summed = CHECKSUM_NONE; /* 802.11 crc not sufficient */ + netif_rx(sub_skb); + } + } + kfree(rxb); +} + +static int rtllib_rx_InfraAdhoc(struct rtllib_device *ieee, struct sk_buff *skb, + struct rtllib_rx_stats *rx_stats) +{ + struct net_device *dev = ieee->dev; + struct rtllib_hdr_4addr *hdr = (struct rtllib_hdr_4addr *)skb->data; + struct lib80211_crypt_data *crypt = NULL; + struct rtllib_rxb *rxb = NULL; + struct rx_ts_record *pTS = NULL; + u16 fc, sc, SeqNum = 0; + u8 type, stype, multicast = 0, unicast = 0, nr_subframes = 0, TID = 0; + u8 dst[ETH_ALEN], src[ETH_ALEN], bssid[ETH_ALEN] = {0}, *payload; + size_t hdrlen = 0; + bool bToOtherSTA = false; + int ret = 0, i = 0; + + hdr = (struct rtllib_hdr_4addr *)skb->data; + fc = le16_to_cpu(hdr->frame_ctl); + type = WLAN_FC_GET_TYPE(fc); + stype = WLAN_FC_GET_STYPE(fc); + sc = le16_to_cpu(hdr->seq_ctl); + + /*Filter pkt not to me*/ + multicast = is_multicast_ether_addr(hdr->addr1); + unicast = !multicast; + if (unicast && !ether_addr_equal(dev->dev_addr, hdr->addr1)) { + if (ieee->bNetPromiscuousMode) + bToOtherSTA = true; + else + goto rx_dropped; + } + + /*Filter pkt has too small length */ + hdrlen = rtllib_rx_get_hdrlen(ieee, skb, rx_stats); + if (skb->len < hdrlen) { + netdev_info(dev, "%s():ERR!!! skb->len is smaller than hdrlen\n", + __func__); + goto rx_dropped; + } + + /* Filter Duplicate pkt */ + ret = rtllib_rx_check_duplicate(ieee, skb, multicast); + if (ret < 0) + goto rx_dropped; + + /* Filter CTRL Frame */ + if (type == RTLLIB_FTYPE_CTL) + goto rx_dropped; + + /* Filter MGNT Frame */ + if (type == RTLLIB_FTYPE_MGMT) { + if (bToOtherSTA) + goto rx_dropped; + if (rtllib_rx_frame_mgmt(ieee, skb, rx_stats, type, stype)) + goto rx_dropped; + else + goto rx_exit; + } + + /* Filter WAPI DATA Frame */ + + /* Update statstics for AP roaming */ + if (!bToOtherSTA) { + ieee->LinkDetectInfo.NumRecvDataInPeriod++; + ieee->LinkDetectInfo.NumRxOkInPeriod++; + } + dev->last_rx = jiffies; + + /* Data frame - extract src/dst addresses */ + rtllib_rx_extract_addr(ieee, hdr, dst, src, bssid); + + /* Filter Data frames */ + ret = rtllib_rx_data_filter(ieee, fc, dst, src, bssid, hdr->addr2); + if (ret < 0) + goto rx_dropped; + + if (skb->len == hdrlen) + goto rx_dropped; + + /* Send pspoll based on moredata */ + if ((ieee->iw_mode == IW_MODE_INFRA) && (ieee->sta_sleep == LPS_IS_SLEEP) + && (ieee->polling) && (!bToOtherSTA)) { + if (WLAN_FC_MORE_DATA(fc)) { + /* more data bit is set, let's request a new frame from the AP */ + rtllib_sta_ps_send_pspoll_frame(ieee); + } else { + ieee->polling = false; + } + } + + /* Get crypt if encrypted */ + ret = rtllib_rx_get_crypt(ieee, skb, &crypt, hdrlen); + if (ret == -1) + goto rx_dropped; + + /* Decrypt data frame (including reassemble) */ + ret = rtllib_rx_decrypt(ieee, skb, rx_stats, crypt, hdrlen); + if (ret == -1) + goto rx_dropped; + else if (ret == -2) + goto rx_exit; + + /* Get TS for Rx Reorder */ + hdr = (struct rtllib_hdr_4addr *) skb->data; + if (ieee->current_network.qos_data.active && IsQoSDataFrame(skb->data) + && !is_multicast_ether_addr(hdr->addr1) + && (!bToOtherSTA)) { + TID = Frame_QoSTID(skb->data); + SeqNum = WLAN_GET_SEQ_SEQ(sc); + GetTs(ieee, (struct ts_common_info **) &pTS, hdr->addr2, TID, RX_DIR, true); + if (TID != 0 && TID != 3) + ieee->bis_any_nonbepkts = true; + } + + /* Parse rx data frame (For AMSDU) */ + /* skb: hdr + (possible reassembled) full plaintext payload */ + payload = skb->data + hdrlen; + rxb = kmalloc(sizeof(struct rtllib_rxb), GFP_ATOMIC); + if (rxb == NULL) + goto rx_dropped; + + /* to parse amsdu packets */ + /* qos data packets & reserved bit is 1 */ + if (parse_subframe(ieee, skb, rx_stats, rxb, src, dst) == 0) { + /* only to free rxb, and not submit the packets to upper layer */ + for (i = 0; i < rxb->nr_subframes; i++) + dev_kfree_skb(rxb->subframes[i]); + kfree(rxb); + rxb = NULL; + goto rx_dropped; + } + + /* Update WAPI PN */ + + /* Check if leave LPS */ + if (!bToOtherSTA) { + if (ieee->bIsAggregateFrame) + nr_subframes = rxb->nr_subframes; + else + nr_subframes = 1; + if (unicast) + ieee->LinkDetectInfo.NumRxUnicastOkInPeriod += nr_subframes; + rtllib_rx_check_leave_lps(ieee, unicast, nr_subframes); + } + + /* Indicate packets to upper layer or Rx Reorder */ + if (ieee->pHTInfo->bCurRxReorderEnable == false || pTS == NULL || bToOtherSTA) + rtllib_rx_indicate_pkt_legacy(ieee, rx_stats, rxb, dst, src); + else + RxReorderIndicatePacket(ieee, rxb, pTS, SeqNum); + + dev_kfree_skb(skb); + + rx_exit: + return 1; + + rx_dropped: + ieee->stats.rx_dropped++; + + /* Returning 0 indicates to caller that we have not handled the SKB-- + * so it is still allocated and can be used again by underlying + * hardware as a DMA target + */ + return 0; +} + +static int rtllib_rx_Master(struct rtllib_device *ieee, struct sk_buff *skb, + struct rtllib_rx_stats *rx_stats) +{ + return 0; +} + +static int rtllib_rx_Monitor(struct rtllib_device *ieee, struct sk_buff *skb, + struct rtllib_rx_stats *rx_stats) +{ + struct rtllib_hdr_4addr *hdr = (struct rtllib_hdr_4addr *)skb->data; + u16 fc = le16_to_cpu(hdr->frame_ctl); + size_t hdrlen = rtllib_get_hdrlen(fc); + + if (skb->len < hdrlen) { + netdev_info(ieee->dev, + "%s():ERR!!! skb->len is smaller than hdrlen\n", + __func__); + return 0; + } + + if (HTCCheck(ieee, skb->data)) { + if (net_ratelimit()) + netdev_info(ieee->dev, "%s: Find HTCControl!\n", + __func__); + hdrlen += 4; + } + + rtllib_monitor_rx(ieee, skb, rx_stats, hdrlen); + ieee->stats.rx_packets++; + ieee->stats.rx_bytes += skb->len; + + return 1; +} + +static int rtllib_rx_Mesh(struct rtllib_device *ieee, struct sk_buff *skb, + struct rtllib_rx_stats *rx_stats) +{ + return 0; +} + +/* All received frames are sent to this function. @skb contains the frame in + * IEEE 802.11 format, i.e., in the format it was sent over air. + * This function is called only as a tasklet (software IRQ). + */ +int rtllib_rx(struct rtllib_device *ieee, struct sk_buff *skb, + struct rtllib_rx_stats *rx_stats) +{ + int ret = 0; + + if ((NULL == ieee) || (NULL == skb) || (NULL == rx_stats)) { + pr_info("%s: Input parameters NULL!\n", __func__); + goto rx_dropped; + } + if (skb->len < 10) { + netdev_info(ieee->dev, "%s: SKB length < 10\n", __func__); + goto rx_dropped; + } + + switch (ieee->iw_mode) { + case IW_MODE_ADHOC: + case IW_MODE_INFRA: + ret = rtllib_rx_InfraAdhoc(ieee, skb, rx_stats); + break; + case IW_MODE_MASTER: + case IW_MODE_REPEAT: + ret = rtllib_rx_Master(ieee, skb, rx_stats); + break; + case IW_MODE_MONITOR: + ret = rtllib_rx_Monitor(ieee, skb, rx_stats); + break; + case IW_MODE_MESH: + ret = rtllib_rx_Mesh(ieee, skb, rx_stats); + break; + default: + netdev_info(ieee->dev, "%s: ERR iw mode!!!\n", __func__); + break; + } + + return ret; + + rx_dropped: + if (ieee) + ieee->stats.rx_dropped++; + return 0; +} +EXPORT_SYMBOL(rtllib_rx); + +static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 }; + +/* Make ther structure we read from the beacon packet has the right values */ +static int rtllib_verify_qos_info(struct rtllib_qos_information_element + *info_element, int sub_type) +{ + + if (info_element->qui_subtype != sub_type) + return -1; + if (memcmp(info_element->qui, qos_oui, QOS_OUI_LEN)) + return -1; + if (info_element->qui_type != QOS_OUI_TYPE) + return -1; + if (info_element->version != QOS_VERSION_1) + return -1; + + return 0; +} + + +/* Parse a QoS parameter element */ +static int rtllib_read_qos_param_element(struct rtllib_qos_parameter_info + *element_param, struct rtllib_info_element + *info_element) +{ + int ret = 0; + u16 size = sizeof(struct rtllib_qos_parameter_info) - 2; + + if ((info_element == NULL) || (element_param == NULL)) + return -1; + + if (info_element->id == QOS_ELEMENT_ID && info_element->len == size) { + memcpy(element_param->info_element.qui, info_element->data, + info_element->len); + element_param->info_element.elementID = info_element->id; + element_param->info_element.length = info_element->len; + } else + ret = -1; + if (ret == 0) + ret = rtllib_verify_qos_info(&element_param->info_element, + QOS_OUI_PARAM_SUB_TYPE); + return ret; +} + +/* Parse a QoS information element */ +static int rtllib_read_qos_info_element(struct + rtllib_qos_information_element + *element_info, struct rtllib_info_element + *info_element) +{ + int ret = 0; + u16 size = sizeof(struct rtllib_qos_information_element) - 2; + + if (element_info == NULL) + return -1; + if (info_element == NULL) + return -1; + + if ((info_element->id == QOS_ELEMENT_ID) && (info_element->len == size)) { + memcpy(element_info->qui, info_element->data, + info_element->len); + element_info->elementID = info_element->id; + element_info->length = info_element->len; + } else + ret = -1; + + if (ret == 0) + ret = rtllib_verify_qos_info(element_info, + QOS_OUI_INFO_SUB_TYPE); + return ret; +} + + +/* Write QoS parameters from the ac parameters. */ +static int rtllib_qos_convert_ac_to_parameters(struct rtllib_qos_parameter_info *param_elm, + struct rtllib_qos_data *qos_data) +{ + struct rtllib_qos_ac_parameter *ac_params; + struct rtllib_qos_parameters *qos_param = &(qos_data->parameters); + int i; + u8 aci; + u8 acm; + + qos_data->wmm_acm = 0; + for (i = 0; i < QOS_QUEUE_NUM; i++) { + ac_params = &(param_elm->ac_params_record[i]); + + aci = (ac_params->aci_aifsn & 0x60) >> 5; + acm = (ac_params->aci_aifsn & 0x10) >> 4; + + if (aci >= QOS_QUEUE_NUM) + continue; + switch (aci) { + case 1: + /* BIT(0) | BIT(3) */ + if (acm) + qos_data->wmm_acm |= (0x01<<0)|(0x01<<3); + break; + case 2: + /* BIT(4) | BIT(5) */ + if (acm) + qos_data->wmm_acm |= (0x01<<4)|(0x01<<5); + break; + case 3: + /* BIT(6) | BIT(7) */ + if (acm) + qos_data->wmm_acm |= (0x01<<6)|(0x01<<7); + break; + case 0: + default: + /* BIT(1) | BIT(2) */ + if (acm) + qos_data->wmm_acm |= (0x01<<1)|(0x01<<2); + break; + } + + qos_param->aifs[aci] = (ac_params->aci_aifsn) & 0x0f; + + /* WMM spec P.11: The minimum value for AIFSN shall be 2 */ + qos_param->aifs[aci] = (qos_param->aifs[aci] < 2) ? 2 : qos_param->aifs[aci]; + + qos_param->cw_min[aci] = cpu_to_le16(ac_params->ecw_min_max & 0x0F); + + qos_param->cw_max[aci] = cpu_to_le16((ac_params->ecw_min_max & 0xF0) >> 4); + + qos_param->flag[aci] = + (ac_params->aci_aifsn & 0x10) ? 0x01 : 0x00; + qos_param->tx_op_limit[aci] = ac_params->tx_op_limit; + } + return 0; +} + +/* we have a generic data element which it may contain QoS information or + * parameters element. check the information element length to decide + * which type to read + */ +static int rtllib_parse_qos_info_param_IE(struct rtllib_info_element + *info_element, + struct rtllib_network *network) +{ + int rc = 0; + struct rtllib_qos_information_element qos_info_element; + + rc = rtllib_read_qos_info_element(&qos_info_element, info_element); + + if (rc == 0) { + network->qos_data.param_count = qos_info_element.ac_info & 0x0F; + network->flags |= NETWORK_HAS_QOS_INFORMATION; + } else { + struct rtllib_qos_parameter_info param_element; + + rc = rtllib_read_qos_param_element(¶m_element, + info_element); + if (rc == 0) { + rtllib_qos_convert_ac_to_parameters(¶m_element, + &(network->qos_data)); + network->flags |= NETWORK_HAS_QOS_PARAMETERS; + network->qos_data.param_count = + param_element.info_element.ac_info & 0x0F; + } + } + + if (rc == 0) { + RTLLIB_DEBUG_QOS("QoS is supported\n"); + network->qos_data.supported = 1; + } + return rc; +} + +#define MFIE_STRING(x) case MFIE_TYPE_ ##x: return #x + +static const char *get_info_element_string(u16 id) +{ + switch (id) { + MFIE_STRING(SSID); + MFIE_STRING(RATES); + MFIE_STRING(FH_SET); + MFIE_STRING(DS_SET); + MFIE_STRING(CF_SET); + MFIE_STRING(TIM); + MFIE_STRING(IBSS_SET); + MFIE_STRING(COUNTRY); + MFIE_STRING(HOP_PARAMS); + MFIE_STRING(HOP_TABLE); + MFIE_STRING(REQUEST); + MFIE_STRING(CHALLENGE); + MFIE_STRING(POWER_CONSTRAINT); + MFIE_STRING(POWER_CAPABILITY); + MFIE_STRING(TPC_REQUEST); + MFIE_STRING(TPC_REPORT); + MFIE_STRING(SUPP_CHANNELS); + MFIE_STRING(CSA); + MFIE_STRING(MEASURE_REQUEST); + MFIE_STRING(MEASURE_REPORT); + MFIE_STRING(QUIET); + MFIE_STRING(IBSS_DFS); + MFIE_STRING(RSN); + MFIE_STRING(RATES_EX); + MFIE_STRING(GENERIC); + MFIE_STRING(QOS_PARAMETER); + default: + return "UNKNOWN"; + } +} + +static inline void rtllib_extract_country_ie( + struct rtllib_device *ieee, + struct rtllib_info_element *info_element, + struct rtllib_network *network, + u8 *addr2) +{ + if (IS_DOT11D_ENABLE(ieee)) { + if (info_element->len != 0) { + memcpy(network->CountryIeBuf, info_element->data, info_element->len); + network->CountryIeLen = info_element->len; + + if (!IS_COUNTRY_IE_VALID(ieee)) { + if (rtllib_act_scanning(ieee, false) && ieee->FirstIe_InScan) + netdev_info(ieee->dev, + "Received beacon ContryIE, SSID: <%s>\n", + network->ssid); + Dot11d_UpdateCountryIe(ieee, addr2, info_element->len, info_element->data); + } + } + + if (IS_EQUAL_CIE_SRC(ieee, addr2)) + UPDATE_CIE_WATCHDOG(ieee); + } + +} + +int rtllib_parse_info_param(struct rtllib_device *ieee, + struct rtllib_info_element *info_element, + u16 length, + struct rtllib_network *network, + struct rtllib_rx_stats *stats) +{ + u8 i; + short offset; + u16 tmp_htcap_len = 0; + u16 tmp_htinfo_len = 0; + u16 ht_realtek_agg_len = 0; + u8 ht_realtek_agg_buf[MAX_IE_LEN]; + char rates_str[64]; + char *p; + + while (length >= sizeof(*info_element)) { + if (sizeof(*info_element) + info_element->len > length) { + RTLLIB_DEBUG_MGMT("Info elem: parse failed: info_element->len + 2 > left : info_element->len+2=%zd left=%d, id=%d.\n", + info_element->len + + sizeof(*info_element), + length, info_element->id); + /* We stop processing but don't return an error here + * because some misbehaviour APs break this rule. ie. + * Orinoco AP1000. + */ + break; + } + + switch (info_element->id) { + case MFIE_TYPE_SSID: + if (rtllib_is_empty_essid(info_element->data, + info_element->len)) { + network->flags |= NETWORK_EMPTY_ESSID; + break; + } + + network->ssid_len = min(info_element->len, + (u8) IW_ESSID_MAX_SIZE); + memcpy(network->ssid, info_element->data, network->ssid_len); + if (network->ssid_len < IW_ESSID_MAX_SIZE) + memset(network->ssid + network->ssid_len, 0, + IW_ESSID_MAX_SIZE - network->ssid_len); + + RTLLIB_DEBUG_MGMT("MFIE_TYPE_SSID: '%s' len=%d.\n", + network->ssid, network->ssid_len); + break; + + case MFIE_TYPE_RATES: + p = rates_str; + network->rates_len = min(info_element->len, + MAX_RATES_LENGTH); + for (i = 0; i < network->rates_len; i++) { + network->rates[i] = info_element->data[i]; + p += snprintf(p, sizeof(rates_str) - + (p - rates_str), "%02X ", + network->rates[i]); + if (rtllib_is_ofdm_rate + (info_element->data[i])) { + network->flags |= NETWORK_HAS_OFDM; + if (info_element->data[i] & + RTLLIB_BASIC_RATE_MASK) + network->flags &= + ~NETWORK_HAS_CCK; + } + + if (rtllib_is_cck_rate + (info_element->data[i])) { + network->flags |= NETWORK_HAS_CCK; + } + } + + RTLLIB_DEBUG_MGMT("MFIE_TYPE_RATES: '%s' (%d)\n", + rates_str, network->rates_len); + break; + + case MFIE_TYPE_RATES_EX: + p = rates_str; + network->rates_ex_len = min(info_element->len, + MAX_RATES_EX_LENGTH); + for (i = 0; i < network->rates_ex_len; i++) { + network->rates_ex[i] = info_element->data[i]; + p += snprintf(p, sizeof(rates_str) - + (p - rates_str), "%02X ", + network->rates_ex[i]); + if (rtllib_is_ofdm_rate + (info_element->data[i])) { + network->flags |= NETWORK_HAS_OFDM; + if (info_element->data[i] & + RTLLIB_BASIC_RATE_MASK) + network->flags &= + ~NETWORK_HAS_CCK; + } + } + + RTLLIB_DEBUG_MGMT("MFIE_TYPE_RATES_EX: '%s' (%d)\n", + rates_str, network->rates_ex_len); + break; + + case MFIE_TYPE_DS_SET: + RTLLIB_DEBUG_MGMT("MFIE_TYPE_DS_SET: %d\n", + info_element->data[0]); + network->channel = info_element->data[0]; + break; + + case MFIE_TYPE_FH_SET: + RTLLIB_DEBUG_MGMT("MFIE_TYPE_FH_SET: ignored\n"); + break; + + case MFIE_TYPE_CF_SET: + RTLLIB_DEBUG_MGMT("MFIE_TYPE_CF_SET: ignored\n"); + break; + + case MFIE_TYPE_TIM: + if (info_element->len < 4) + break; + + network->tim.tim_count = info_element->data[0]; + network->tim.tim_period = info_element->data[1]; + + network->dtim_period = info_element->data[1]; + if (ieee->state != RTLLIB_LINKED) + break; + network->last_dtim_sta_time = jiffies; + + network->dtim_data = RTLLIB_DTIM_VALID; + + + if (info_element->data[2] & 1) + network->dtim_data |= RTLLIB_DTIM_MBCAST; + + offset = (info_element->data[2] >> 1)*2; + + + if (ieee->assoc_id < 8*offset || + ieee->assoc_id > 8*(offset + info_element->len - 3)) + break; + + offset = (ieee->assoc_id / 8) - offset; + if (info_element->data[3 + offset] & + (1 << (ieee->assoc_id % 8))) + network->dtim_data |= RTLLIB_DTIM_UCAST; + + network->listen_interval = network->dtim_period; + break; + + case MFIE_TYPE_ERP: + network->erp_value = info_element->data[0]; + network->flags |= NETWORK_HAS_ERP_VALUE; + RTLLIB_DEBUG_MGMT("MFIE_TYPE_ERP_SET: %d\n", + network->erp_value); + break; + case MFIE_TYPE_IBSS_SET: + network->atim_window = info_element->data[0]; + RTLLIB_DEBUG_MGMT("MFIE_TYPE_IBSS_SET: %d\n", + network->atim_window); + break; + + case MFIE_TYPE_CHALLENGE: + RTLLIB_DEBUG_MGMT("MFIE_TYPE_CHALLENGE: ignored\n"); + break; + + case MFIE_TYPE_GENERIC: + RTLLIB_DEBUG_MGMT("MFIE_TYPE_GENERIC: %d bytes\n", + info_element->len); + if (!rtllib_parse_qos_info_param_IE(info_element, + network)) + break; + if (info_element->len >= 4 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0x50 && + info_element->data[2] == 0xf2 && + info_element->data[3] == 0x01) { + network->wpa_ie_len = min(info_element->len + 2, + MAX_WPA_IE_LEN); + memcpy(network->wpa_ie, info_element, + network->wpa_ie_len); + break; + } + if (info_element->len == 7 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0xe0 && + info_element->data[2] == 0x4c && + info_element->data[3] == 0x01 && + info_element->data[4] == 0x02) + network->Turbo_Enable = 1; + + if (tmp_htcap_len == 0) { + if (info_element->len >= 4 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0x90 && + info_element->data[2] == 0x4c && + info_element->data[3] == 0x033) { + + tmp_htcap_len = min_t(u8, info_element->len, MAX_IE_LEN); + if (tmp_htcap_len != 0) { + network->bssht.bdHTSpecVer = HT_SPEC_VER_EWC; + network->bssht.bdHTCapLen = tmp_htcap_len > sizeof(network->bssht.bdHTCapBuf) ? + sizeof(network->bssht.bdHTCapBuf) : tmp_htcap_len; + memcpy(network->bssht.bdHTCapBuf, info_element->data, network->bssht.bdHTCapLen); + } + } + if (tmp_htcap_len != 0) { + network->bssht.bdSupportHT = true; + network->bssht.bdHT1R = ((((struct ht_capab_ele *)(network->bssht.bdHTCapBuf))->MCS[1]) == 0); + } else { + network->bssht.bdSupportHT = false; + network->bssht.bdHT1R = false; + } + } + + + if (tmp_htinfo_len == 0) { + if (info_element->len >= 4 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0x90 && + info_element->data[2] == 0x4c && + info_element->data[3] == 0x034) { + tmp_htinfo_len = min_t(u8, info_element->len, MAX_IE_LEN); + if (tmp_htinfo_len != 0) { + network->bssht.bdHTSpecVer = HT_SPEC_VER_EWC; + if (tmp_htinfo_len) { + network->bssht.bdHTInfoLen = tmp_htinfo_len > sizeof(network->bssht.bdHTInfoBuf) ? + sizeof(network->bssht.bdHTInfoBuf) : tmp_htinfo_len; + memcpy(network->bssht.bdHTInfoBuf, info_element->data, network->bssht.bdHTInfoLen); + } + + } + + } + } + + if (ieee->aggregation) { + if (network->bssht.bdSupportHT) { + if (info_element->len >= 4 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0xe0 && + info_element->data[2] == 0x4c && + info_element->data[3] == 0x02) { + ht_realtek_agg_len = min_t(u8, info_element->len, MAX_IE_LEN); + memcpy(ht_realtek_agg_buf, info_element->data, info_element->len); + } + if (ht_realtek_agg_len >= 5) { + network->realtek_cap_exit = true; + network->bssht.bdRT2RTAggregation = true; + + if ((ht_realtek_agg_buf[4] == 1) && (ht_realtek_agg_buf[5] & 0x02)) + network->bssht.bdRT2RTLongSlotTime = true; + + if ((ht_realtek_agg_buf[4] == 1) && (ht_realtek_agg_buf[5] & RT_HT_CAP_USE_92SE)) + network->bssht.RT2RT_HT_Mode |= RT_HT_CAP_USE_92SE; + } + } + if (ht_realtek_agg_len >= 5) { + if ((ht_realtek_agg_buf[5] & RT_HT_CAP_USE_SOFTAP)) + network->bssht.RT2RT_HT_Mode |= RT_HT_CAP_USE_SOFTAP; + } + } + + if ((info_element->len >= 3 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0x05 && + info_element->data[2] == 0xb5) || + (info_element->len >= 3 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0x0a && + info_element->data[2] == 0xf7) || + (info_element->len >= 3 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0x10 && + info_element->data[2] == 0x18)) { + network->broadcom_cap_exist = true; + } + if (info_element->len >= 3 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0x0c && + info_element->data[2] == 0x43) + network->ralink_cap_exist = true; + if ((info_element->len >= 3 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0x03 && + info_element->data[2] == 0x7f) || + (info_element->len >= 3 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0x13 && + info_element->data[2] == 0x74)) + network->atheros_cap_exist = true; + + if ((info_element->len >= 3 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0x50 && + info_element->data[2] == 0x43)) + network->marvell_cap_exist = true; + if (info_element->len >= 3 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0x40 && + info_element->data[2] == 0x96) + network->cisco_cap_exist = true; + + + if (info_element->len >= 3 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0x0a && + info_element->data[2] == 0xf5) + network->airgo_cap_exist = true; + + if (info_element->len > 4 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0x40 && + info_element->data[2] == 0x96 && + info_element->data[3] == 0x01) { + if (info_element->len == 6) { + memcpy(network->CcxRmState, &info_element[4], 2); + if (network->CcxRmState[0] != 0) + network->bCcxRmEnable = true; + else + network->bCcxRmEnable = false; + network->MBssidMask = network->CcxRmState[1] & 0x07; + if (network->MBssidMask != 0) { + network->bMBssidValid = true; + network->MBssidMask = 0xff << (network->MBssidMask); + memcpy(network->MBssid, network->bssid, ETH_ALEN); + network->MBssid[5] &= network->MBssidMask; + } else { + network->bMBssidValid = false; + } + } else { + network->bCcxRmEnable = false; + } + } + if (info_element->len > 4 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0x40 && + info_element->data[2] == 0x96 && + info_element->data[3] == 0x03) { + if (info_element->len == 5) { + network->bWithCcxVerNum = true; + network->BssCcxVerNumber = info_element->data[4]; + } else { + network->bWithCcxVerNum = false; + network->BssCcxVerNumber = 0; + } + } + if (info_element->len > 4 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0x50 && + info_element->data[2] == 0xf2 && + info_element->data[3] == 0x04) { + RTLLIB_DEBUG_MGMT("MFIE_TYPE_WZC: %d bytes\n", + info_element->len); + network->wzc_ie_len = min(info_element->len+2, + MAX_WZC_IE_LEN); + memcpy(network->wzc_ie, info_element, + network->wzc_ie_len); + } + break; + + case MFIE_TYPE_RSN: + RTLLIB_DEBUG_MGMT("MFIE_TYPE_RSN: %d bytes\n", + info_element->len); + network->rsn_ie_len = min(info_element->len + 2, + MAX_WPA_IE_LEN); + memcpy(network->rsn_ie, info_element, + network->rsn_ie_len); + break; + + case MFIE_TYPE_HT_CAP: + RTLLIB_DEBUG_SCAN("MFIE_TYPE_HT_CAP: %d bytes\n", + info_element->len); + tmp_htcap_len = min_t(u8, info_element->len, MAX_IE_LEN); + if (tmp_htcap_len != 0) { + network->bssht.bdHTSpecVer = HT_SPEC_VER_EWC; + network->bssht.bdHTCapLen = tmp_htcap_len > sizeof(network->bssht.bdHTCapBuf) ? + sizeof(network->bssht.bdHTCapBuf) : tmp_htcap_len; + memcpy(network->bssht.bdHTCapBuf, + info_element->data, + network->bssht.bdHTCapLen); + + network->bssht.bdSupportHT = true; + network->bssht.bdHT1R = ((((struct ht_capab_ele *) + network->bssht.bdHTCapBuf))->MCS[1]) == 0; + + network->bssht.bdBandWidth = (enum ht_channel_width) + (((struct ht_capab_ele *) + (network->bssht.bdHTCapBuf))->ChlWidth); + } else { + network->bssht.bdSupportHT = false; + network->bssht.bdHT1R = false; + network->bssht.bdBandWidth = HT_CHANNEL_WIDTH_20; + } + break; + + + case MFIE_TYPE_HT_INFO: + RTLLIB_DEBUG_SCAN("MFIE_TYPE_HT_INFO: %d bytes\n", + info_element->len); + tmp_htinfo_len = min_t(u8, info_element->len, MAX_IE_LEN); + if (tmp_htinfo_len) { + network->bssht.bdHTSpecVer = HT_SPEC_VER_IEEE; + network->bssht.bdHTInfoLen = tmp_htinfo_len > + sizeof(network->bssht.bdHTInfoBuf) ? + sizeof(network->bssht.bdHTInfoBuf) : + tmp_htinfo_len; + memcpy(network->bssht.bdHTInfoBuf, + info_element->data, + network->bssht.bdHTInfoLen); + } + break; + + case MFIE_TYPE_AIRONET: + RTLLIB_DEBUG_SCAN("MFIE_TYPE_AIRONET: %d bytes\n", + info_element->len); + if (info_element->len > IE_CISCO_FLAG_POSITION) { + network->bWithAironetIE = true; + + if ((info_element->data[IE_CISCO_FLAG_POSITION] + & SUPPORT_CKIP_MIC) || + (info_element->data[IE_CISCO_FLAG_POSITION] + & SUPPORT_CKIP_PK)) + network->bCkipSupported = true; + else + network->bCkipSupported = false; + } else { + network->bWithAironetIE = false; + network->bCkipSupported = false; + } + break; + case MFIE_TYPE_QOS_PARAMETER: + netdev_err(ieee->dev, + "QoS Error need to parse QOS_PARAMETER IE\n"); + break; + + case MFIE_TYPE_COUNTRY: + RTLLIB_DEBUG_SCAN("MFIE_TYPE_COUNTRY: %d bytes\n", + info_element->len); + rtllib_extract_country_ie(ieee, info_element, network, + network->bssid); + break; +/* TODO */ + default: + RTLLIB_DEBUG_MGMT + ("Unsupported info element: %s (%d)\n", + get_info_element_string(info_element->id), + info_element->id); + break; + } + + length -= sizeof(*info_element) + info_element->len; + info_element = + (struct rtllib_info_element *)&info_element-> + data[info_element->len]; + } + + if (!network->atheros_cap_exist && !network->broadcom_cap_exist && + !network->cisco_cap_exist && !network->ralink_cap_exist && + !network->bssht.bdRT2RTAggregation) + network->unknown_cap_exist = true; + else + network->unknown_cap_exist = false; + return 0; +} + +static long rtllib_translate_todbm(u8 signal_strength_index) +{ + long signal_power; + + signal_power = (long)((signal_strength_index + 1) >> 1); + signal_power -= 95; + + return signal_power; +} + +static inline int rtllib_network_init( + struct rtllib_device *ieee, + struct rtllib_probe_response *beacon, + struct rtllib_network *network, + struct rtllib_rx_stats *stats) +{ + memset(&network->qos_data, 0, sizeof(struct rtllib_qos_data)); + + /* Pull out fixed field data */ + memcpy(network->bssid, beacon->header.addr3, ETH_ALEN); + network->capability = le16_to_cpu(beacon->capability); + network->last_scanned = jiffies; + network->time_stamp[0] = beacon->time_stamp[0]; + network->time_stamp[1] = beacon->time_stamp[1]; + network->beacon_interval = le16_to_cpu(beacon->beacon_interval); + /* Where to pull this? beacon->listen_interval;*/ + network->listen_interval = 0x0A; + network->rates_len = network->rates_ex_len = 0; + network->last_associate = 0; + network->ssid_len = 0; + network->hidden_ssid_len = 0; + memset(network->hidden_ssid, 0, sizeof(network->hidden_ssid)); + network->flags = 0; + network->atim_window = 0; + network->erp_value = (network->capability & WLAN_CAPABILITY_IBSS) ? + 0x3 : 0x0; + network->berp_info_valid = false; + network->broadcom_cap_exist = false; + network->ralink_cap_exist = false; + network->atheros_cap_exist = false; + network->cisco_cap_exist = false; + network->unknown_cap_exist = false; + network->realtek_cap_exit = false; + network->marvell_cap_exist = false; + network->airgo_cap_exist = false; + network->Turbo_Enable = 0; + network->SignalStrength = stats->SignalStrength; + network->RSSI = stats->SignalStrength; + network->CountryIeLen = 0; + memset(network->CountryIeBuf, 0, MAX_IE_LEN); + HTInitializeBssDesc(&network->bssht); + if (stats->freq == RTLLIB_52GHZ_BAND) { + /* for A band (No DS info) */ + network->channel = stats->received_channel; + } else + network->flags |= NETWORK_HAS_CCK; + + network->wpa_ie_len = 0; + network->rsn_ie_len = 0; + network->wzc_ie_len = 0; + + if (rtllib_parse_info_param(ieee, + beacon->info_element, + (stats->len - sizeof(*beacon)), + network, + stats)) + return 1; + + network->mode = 0; + if (stats->freq == RTLLIB_52GHZ_BAND) + network->mode = IEEE_A; + else { + if (network->flags & NETWORK_HAS_OFDM) + network->mode |= IEEE_G; + if (network->flags & NETWORK_HAS_CCK) + network->mode |= IEEE_B; + } + + if (network->mode == 0) { + RTLLIB_DEBUG_SCAN("Filtered out '%s (%pM)' network.\n", + escape_essid(network->ssid, + network->ssid_len), + network->bssid); + return 1; + } + + if (network->bssht.bdSupportHT) { + if (network->mode == IEEE_A) + network->mode = IEEE_N_5G; + else if (network->mode & (IEEE_G | IEEE_B)) + network->mode = IEEE_N_24G; + } + if (rtllib_is_empty_essid(network->ssid, network->ssid_len)) + network->flags |= NETWORK_EMPTY_ESSID; + stats->signal = 30 + (stats->SignalStrength * 70) / 100; + stats->noise = rtllib_translate_todbm((u8)(100-stats->signal)) - 25; + + memcpy(&network->stats, stats, sizeof(network->stats)); + + return 0; +} + +static inline int is_same_network(struct rtllib_network *src, + struct rtllib_network *dst, u8 ssidbroad) +{ + /* A network is only a duplicate if the channel, BSSID, ESSID + * and the capability field (in particular IBSS and BSS) all match. + * We treat all with the same BSSID and channel + * as one network + */ + return (((src->ssid_len == dst->ssid_len) || (!ssidbroad)) && + (src->channel == dst->channel) && + !memcmp(src->bssid, dst->bssid, ETH_ALEN) && + (!memcmp(src->ssid, dst->ssid, src->ssid_len) || + (!ssidbroad)) && + ((src->capability & WLAN_CAPABILITY_IBSS) == + (dst->capability & WLAN_CAPABILITY_IBSS)) && + ((src->capability & WLAN_CAPABILITY_ESS) == + (dst->capability & WLAN_CAPABILITY_ESS))); +} + + +static inline void update_network(struct rtllib_network *dst, + struct rtllib_network *src) +{ + int qos_active; + u8 old_param; + + memcpy(&dst->stats, &src->stats, sizeof(struct rtllib_rx_stats)); + dst->capability = src->capability; + memcpy(dst->rates, src->rates, src->rates_len); + dst->rates_len = src->rates_len; + memcpy(dst->rates_ex, src->rates_ex, src->rates_ex_len); + dst->rates_ex_len = src->rates_ex_len; + if (src->ssid_len > 0) { + if (dst->ssid_len == 0) { + memset(dst->hidden_ssid, 0, sizeof(dst->hidden_ssid)); + dst->hidden_ssid_len = src->ssid_len; + memcpy(dst->hidden_ssid, src->ssid, src->ssid_len); + } else { + memset(dst->ssid, 0, dst->ssid_len); + dst->ssid_len = src->ssid_len; + memcpy(dst->ssid, src->ssid, src->ssid_len); + } + } + dst->mode = src->mode; + dst->flags = src->flags; + dst->time_stamp[0] = src->time_stamp[0]; + dst->time_stamp[1] = src->time_stamp[1]; + if (src->flags & NETWORK_HAS_ERP_VALUE) { + dst->erp_value = src->erp_value; + dst->berp_info_valid = src->berp_info_valid = true; + } + dst->beacon_interval = src->beacon_interval; + dst->listen_interval = src->listen_interval; + dst->atim_window = src->atim_window; + dst->dtim_period = src->dtim_period; + dst->dtim_data = src->dtim_data; + dst->last_dtim_sta_time = src->last_dtim_sta_time; + memcpy(&dst->tim, &src->tim, sizeof(struct rtllib_tim_parameters)); + + dst->bssht.bdSupportHT = src->bssht.bdSupportHT; + dst->bssht.bdRT2RTAggregation = src->bssht.bdRT2RTAggregation; + dst->bssht.bdHTCapLen = src->bssht.bdHTCapLen; + memcpy(dst->bssht.bdHTCapBuf, src->bssht.bdHTCapBuf, + src->bssht.bdHTCapLen); + dst->bssht.bdHTInfoLen = src->bssht.bdHTInfoLen; + memcpy(dst->bssht.bdHTInfoBuf, src->bssht.bdHTInfoBuf, + src->bssht.bdHTInfoLen); + dst->bssht.bdHTSpecVer = src->bssht.bdHTSpecVer; + dst->bssht.bdRT2RTLongSlotTime = src->bssht.bdRT2RTLongSlotTime; + dst->broadcom_cap_exist = src->broadcom_cap_exist; + dst->ralink_cap_exist = src->ralink_cap_exist; + dst->atheros_cap_exist = src->atheros_cap_exist; + dst->realtek_cap_exit = src->realtek_cap_exit; + dst->marvell_cap_exist = src->marvell_cap_exist; + dst->cisco_cap_exist = src->cisco_cap_exist; + dst->airgo_cap_exist = src->airgo_cap_exist; + dst->unknown_cap_exist = src->unknown_cap_exist; + memcpy(dst->wpa_ie, src->wpa_ie, src->wpa_ie_len); + dst->wpa_ie_len = src->wpa_ie_len; + memcpy(dst->rsn_ie, src->rsn_ie, src->rsn_ie_len); + dst->rsn_ie_len = src->rsn_ie_len; + memcpy(dst->wzc_ie, src->wzc_ie, src->wzc_ie_len); + dst->wzc_ie_len = src->wzc_ie_len; + + dst->last_scanned = jiffies; + /* qos related parameters */ + qos_active = dst->qos_data.active; + old_param = dst->qos_data.param_count; + dst->qos_data.supported = src->qos_data.supported; + if (dst->flags & NETWORK_HAS_QOS_PARAMETERS) + memcpy(&dst->qos_data, &src->qos_data, + sizeof(struct rtllib_qos_data)); + if (dst->qos_data.supported == 1) { + if (dst->ssid_len) + RTLLIB_DEBUG_QOS + ("QoS the network %s is QoS supported\n", + dst->ssid); + else + RTLLIB_DEBUG_QOS + ("QoS the network is QoS supported\n"); + } + dst->qos_data.active = qos_active; + dst->qos_data.old_param_count = old_param; + + /* dst->last_associate is not overwritten */ + dst->wmm_info = src->wmm_info; + if (src->wmm_param[0].ac_aci_acm_aifsn || + src->wmm_param[1].ac_aci_acm_aifsn || + src->wmm_param[2].ac_aci_acm_aifsn || + src->wmm_param[3].ac_aci_acm_aifsn) + memcpy(dst->wmm_param, src->wmm_param, WME_AC_PRAM_LEN); + + dst->SignalStrength = src->SignalStrength; + dst->RSSI = src->RSSI; + dst->Turbo_Enable = src->Turbo_Enable; + + dst->CountryIeLen = src->CountryIeLen; + memcpy(dst->CountryIeBuf, src->CountryIeBuf, src->CountryIeLen); + + dst->bWithAironetIE = src->bWithAironetIE; + dst->bCkipSupported = src->bCkipSupported; + memcpy(dst->CcxRmState, src->CcxRmState, 2); + dst->bCcxRmEnable = src->bCcxRmEnable; + dst->MBssidMask = src->MBssidMask; + dst->bMBssidValid = src->bMBssidValid; + memcpy(dst->MBssid, src->MBssid, 6); + dst->bWithCcxVerNum = src->bWithCcxVerNum; + dst->BssCcxVerNumber = src->BssCcxVerNumber; +} + +static inline int is_beacon(__le16 fc) +{ + return (WLAN_FC_GET_STYPE(le16_to_cpu(fc)) == RTLLIB_STYPE_BEACON); +} + +static int IsPassiveChannel(struct rtllib_device *rtllib, u8 channel) +{ + if (MAX_CHANNEL_NUMBER < channel) { + netdev_info(rtllib->dev, "%s(): Invalid Channel\n", __func__); + return 0; + } + + if (rtllib->active_channel_map[channel] == 2) + return 1; + + return 0; +} + +int rtllib_legal_channel(struct rtllib_device *rtllib, u8 channel) +{ + if (MAX_CHANNEL_NUMBER < channel) { + netdev_info(rtllib->dev, "%s(): Invalid Channel\n", __func__); + return 0; + } + if (rtllib->active_channel_map[channel] > 0) + return 1; + + return 0; +} +EXPORT_SYMBOL(rtllib_legal_channel); + +static inline void rtllib_process_probe_response( + struct rtllib_device *ieee, + struct rtllib_probe_response *beacon, + struct rtllib_rx_stats *stats) +{ + struct rtllib_network *target; + struct rtllib_network *oldest = NULL; + struct rtllib_info_element *info_element = &beacon->info_element[0]; + unsigned long flags; + short renew; + struct rtllib_network *network = kzalloc(sizeof(struct rtllib_network), + GFP_ATOMIC); + + if (!network) + return; + + RTLLIB_DEBUG_SCAN( + "'%s' ( %pM ): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n", + escape_essid(info_element->data, info_element->len), + beacon->header.addr3, + (le16_to_cpu(beacon->capability) & (1<<0xf)) ? '1' : '0', + (le16_to_cpu(beacon->capability) & (1<<0xe)) ? '1' : '0', + (le16_to_cpu(beacon->capability) & (1<<0xd)) ? '1' : '0', + (le16_to_cpu(beacon->capability) & (1<<0xc)) ? '1' : '0', + (le16_to_cpu(beacon->capability) & (1<<0xb)) ? '1' : '0', + (le16_to_cpu(beacon->capability) & (1<<0xa)) ? '1' : '0', + (le16_to_cpu(beacon->capability) & (1<<0x9)) ? '1' : '0', + (le16_to_cpu(beacon->capability) & (1<<0x8)) ? '1' : '0', + (le16_to_cpu(beacon->capability) & (1<<0x7)) ? '1' : '0', + (le16_to_cpu(beacon->capability) & (1<<0x6)) ? '1' : '0', + (le16_to_cpu(beacon->capability) & (1<<0x5)) ? '1' : '0', + (le16_to_cpu(beacon->capability) & (1<<0x4)) ? '1' : '0', + (le16_to_cpu(beacon->capability) & (1<<0x3)) ? '1' : '0', + (le16_to_cpu(beacon->capability) & (1<<0x2)) ? '1' : '0', + (le16_to_cpu(beacon->capability) & (1<<0x1)) ? '1' : '0', + (le16_to_cpu(beacon->capability) & (1<<0x0)) ? '1' : '0'); + + if (rtllib_network_init(ieee, beacon, network, stats)) { + RTLLIB_DEBUG_SCAN("Dropped '%s' ( %pM) via %s.\n", + escape_essid(info_element->data, + info_element->len), + beacon->header.addr3, + WLAN_FC_GET_STYPE( + le16_to_cpu(beacon->header.frame_ctl)) == + RTLLIB_STYPE_PROBE_RESP ? + "PROBE RESPONSE" : "BEACON"); + goto free_network; + } + + + if (!rtllib_legal_channel(ieee, network->channel)) + goto free_network; + + if (WLAN_FC_GET_STYPE(le16_to_cpu(beacon->header.frame_ctl)) == + RTLLIB_STYPE_PROBE_RESP) { + if (IsPassiveChannel(ieee, network->channel)) { + netdev_info(ieee->dev, + "GetScanInfo(): For Global Domain, filter probe response at channel(%d).\n", + network->channel); + goto free_network; + } + } + + /* The network parsed correctly -- so now we scan our known networks + * to see if we can find it in our list. + * + * NOTE: This search is definitely not optimized. Once its doing + * the "right thing" we'll optimize it for efficiency if + * necessary + */ + + /* Search for this entry in the list and update it if it is + * already there. + */ + + spin_lock_irqsave(&ieee->lock, flags); + if (is_same_network(&ieee->current_network, network, + (network->ssid_len ? 1 : 0))) { + update_network(&ieee->current_network, network); + if ((ieee->current_network.mode == IEEE_N_24G || + ieee->current_network.mode == IEEE_G) + && ieee->current_network.berp_info_valid) { + if (ieee->current_network.erp_value & ERP_UseProtection) + ieee->current_network.buseprotection = true; + else + ieee->current_network.buseprotection = false; + } + if (is_beacon(beacon->header.frame_ctl)) { + if (ieee->state >= RTLLIB_LINKED) + ieee->LinkDetectInfo.NumRecvBcnInPeriod++; + } + } + list_for_each_entry(target, &ieee->network_list, list) { + if (is_same_network(target, network, + (target->ssid_len ? 1 : 0))) + break; + if ((oldest == NULL) || + (target->last_scanned < oldest->last_scanned)) + oldest = target; + } + + /* If we didn't find a match, then get a new network slot to initialize + * with this beacon's information + */ + if (&target->list == &ieee->network_list) { + if (list_empty(&ieee->network_free_list)) { + /* If there are no more slots, expire the oldest */ + list_del(&oldest->list); + target = oldest; + RTLLIB_DEBUG_SCAN("Expired '%s' ( %pM) from network list.\n", + escape_essid(target->ssid, + target->ssid_len), + target->bssid); + } else { + /* Otherwise just pull from the free list */ + target = list_entry(ieee->network_free_list.next, + struct rtllib_network, list); + list_del(ieee->network_free_list.next); + } + + + RTLLIB_DEBUG_SCAN("Adding '%s' ( %pM) via %s.\n", + escape_essid(network->ssid, + network->ssid_len), network->bssid, + WLAN_FC_GET_STYPE( + le16_to_cpu(beacon->header.frame_ctl)) == + RTLLIB_STYPE_PROBE_RESP ? + "PROBE RESPONSE" : "BEACON"); + memcpy(target, network, sizeof(*target)); + list_add_tail(&target->list, &ieee->network_list); + if (ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) + rtllib_softmac_new_net(ieee, network); + } else { + RTLLIB_DEBUG_SCAN("Updating '%s' ( %pM) via %s.\n", + escape_essid(target->ssid, + target->ssid_len), target->bssid, + WLAN_FC_GET_STYPE( + le16_to_cpu(beacon->header.frame_ctl)) == + RTLLIB_STYPE_PROBE_RESP ? + "PROBE RESPONSE" : "BEACON"); + + /* we have an entry and we are going to update it. But this + * entry may be already expired. In this case we do the same + * as we found a new net and call the new_net handler + */ + renew = !time_after(target->last_scanned + ieee->scan_age, + jiffies); + if ((!target->ssid_len) && + (((network->ssid_len > 0) && (target->hidden_ssid_len == 0)) + || ((ieee->current_network.ssid_len == network->ssid_len) && + (strncmp(ieee->current_network.ssid, network->ssid, + network->ssid_len) == 0) && + (ieee->state == RTLLIB_NOLINK)))) + renew = 1; + update_network(target, network); + if (renew && (ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE)) + rtllib_softmac_new_net(ieee, network); + } + + spin_unlock_irqrestore(&ieee->lock, flags); + if (is_beacon(beacon->header.frame_ctl) && + is_same_network(&ieee->current_network, network, + (network->ssid_len ? 1 : 0)) && + (ieee->state == RTLLIB_LINKED)) { + if (ieee->handle_beacon != NULL) + ieee->handle_beacon(ieee->dev, beacon, + &ieee->current_network); + } +free_network: + kfree(network); +} + +void rtllib_rx_mgt(struct rtllib_device *ieee, + struct sk_buff *skb, + struct rtllib_rx_stats *stats) +{ + struct rtllib_hdr_4addr *header = (struct rtllib_hdr_4addr *)skb->data; + + if ((WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl)) != + RTLLIB_STYPE_PROBE_RESP) && + (WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl)) != + RTLLIB_STYPE_BEACON)) + ieee->last_rx_ps_time = jiffies; + + switch (WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl))) { + + case RTLLIB_STYPE_BEACON: + RTLLIB_DEBUG_MGMT("received BEACON (%d)\n", + WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl))); + RTLLIB_DEBUG_SCAN("Beacon\n"); + rtllib_process_probe_response( + ieee, (struct rtllib_probe_response *)header, + stats); + + if (ieee->sta_sleep || (ieee->ps != RTLLIB_PS_DISABLED && + ieee->iw_mode == IW_MODE_INFRA && + ieee->state == RTLLIB_LINKED)) + tasklet_schedule(&ieee->ps_task); + + break; + + case RTLLIB_STYPE_PROBE_RESP: + RTLLIB_DEBUG_MGMT("received PROBE RESPONSE (%d)\n", + WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl))); + RTLLIB_DEBUG_SCAN("Probe response\n"); + rtllib_process_probe_response(ieee, + (struct rtllib_probe_response *)header, stats); + break; + case RTLLIB_STYPE_PROBE_REQ: + RTLLIB_DEBUG_MGMT("received PROBE RESQUEST (%d)\n", + WLAN_FC_GET_STYPE( + le16_to_cpu(header->frame_ctl))); + RTLLIB_DEBUG_SCAN("Probe request\n"); + if ((ieee->softmac_features & IEEE_SOFTMAC_PROBERS) && + ((ieee->iw_mode == IW_MODE_ADHOC || + ieee->iw_mode == IW_MODE_MASTER) && + ieee->state == RTLLIB_LINKED)) + rtllib_rx_probe_rq(ieee, skb); + break; + } +} diff --git a/kernel/drivers/staging/rtl8192e/rtllib_softmac.c b/kernel/drivers/staging/rtl8192e/rtllib_softmac.c new file mode 100644 index 000000000..23b7a4c3b --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtllib_softmac.c @@ -0,0 +1,3758 @@ +/* IEEE 802.11 SoftMAC layer + * Copyright (c) 2005 Andrea Merello + * + * Mostly extracted from the rtl8180-sa2400 driver for the + * in-kernel generic ieee802.11 stack. + * + * Few lines might be stolen from other part of the rtllib + * stack. Copyright who own it's copyright + * + * WPA code stolen from the ipw2200 driver. + * Copyright who own it's copyright. + * + * released under the GPL + */ + + +#include "rtllib.h" + +#include +#include +#include +#include +#include "dot11d.h" + +short rtllib_is_54g(struct rtllib_network *net) +{ + return (net->rates_ex_len > 0) || (net->rates_len > 4); +} + +short rtllib_is_shortslot(const struct rtllib_network *net) +{ + return net->capability & WLAN_CAPABILITY_SHORT_SLOT_TIME; +} + +/* returns the total length needed for placing the RATE MFIE + * tag and the EXTENDED RATE MFIE tag if needed. + * It encludes two bytes per tag for the tag itself and its len + */ +static unsigned int rtllib_MFIE_rate_len(struct rtllib_device *ieee) +{ + unsigned int rate_len = 0; + + if (ieee->modulation & RTLLIB_CCK_MODULATION) + rate_len = RTLLIB_CCK_RATE_LEN + 2; + + if (ieee->modulation & RTLLIB_OFDM_MODULATION) + + rate_len += RTLLIB_OFDM_RATE_LEN + 2; + + return rate_len; +} + +/* place the MFIE rate, tag to the memory (double) pointed. + * Then it updates the pointer so that + * it points after the new MFIE tag added. + */ +static void rtllib_MFIE_Brate(struct rtllib_device *ieee, u8 **tag_p) +{ + u8 *tag = *tag_p; + + if (ieee->modulation & RTLLIB_CCK_MODULATION) { + *tag++ = MFIE_TYPE_RATES; + *tag++ = 4; + *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_CCK_RATE_1MB; + *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_CCK_RATE_2MB; + *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_CCK_RATE_5MB; + *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_CCK_RATE_11MB; + } + + /* We may add an option for custom rates that specific HW + * might support + */ + *tag_p = tag; +} + +static void rtllib_MFIE_Grate(struct rtllib_device *ieee, u8 **tag_p) +{ + u8 *tag = *tag_p; + + if (ieee->modulation & RTLLIB_OFDM_MODULATION) { + *tag++ = MFIE_TYPE_RATES_EX; + *tag++ = 8; + *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_6MB; + *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_9MB; + *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_12MB; + *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_18MB; + *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_24MB; + *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_36MB; + *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_48MB; + *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_54MB; + } + /* We may add an option for custom rates that specific HW might + * support + */ + *tag_p = tag; +} + +static void rtllib_WMM_Info(struct rtllib_device *ieee, u8 **tag_p) +{ + u8 *tag = *tag_p; + + *tag++ = MFIE_TYPE_GENERIC; + *tag++ = 7; + *tag++ = 0x00; + *tag++ = 0x50; + *tag++ = 0xf2; + *tag++ = 0x02; + *tag++ = 0x00; + *tag++ = 0x01; + *tag++ = MAX_SP_Len; + *tag_p = tag; +} + +void rtllib_TURBO_Info(struct rtllib_device *ieee, u8 **tag_p) +{ + u8 *tag = *tag_p; + + *tag++ = MFIE_TYPE_GENERIC; + *tag++ = 7; + *tag++ = 0x00; + *tag++ = 0xe0; + *tag++ = 0x4c; + *tag++ = 0x01; + *tag++ = 0x02; + *tag++ = 0x11; + *tag++ = 0x00; + + *tag_p = tag; + netdev_alert(ieee->dev, "This is enable turbo mode IE process\n"); +} + +static void enqueue_mgmt(struct rtllib_device *ieee, struct sk_buff *skb) +{ + int nh; + + nh = (ieee->mgmt_queue_head + 1) % MGMT_QUEUE_NUM; + +/* if the queue is full but we have newer frames then + * just overwrites the oldest. + * + * if (nh == ieee->mgmt_queue_tail) + * return -1; + */ + ieee->mgmt_queue_head = nh; + ieee->mgmt_queue_ring[nh] = skb; + +} + +static struct sk_buff *dequeue_mgmt(struct rtllib_device *ieee) +{ + struct sk_buff *ret; + + if (ieee->mgmt_queue_tail == ieee->mgmt_queue_head) + return NULL; + + ret = ieee->mgmt_queue_ring[ieee->mgmt_queue_tail]; + + ieee->mgmt_queue_tail = + (ieee->mgmt_queue_tail+1) % MGMT_QUEUE_NUM; + + return ret; +} + +static void init_mgmt_queue(struct rtllib_device *ieee) +{ + ieee->mgmt_queue_tail = ieee->mgmt_queue_head = 0; +} + + +u8 +MgntQuery_TxRateExcludeCCKRates(struct rtllib_device *ieee) +{ + u16 i; + u8 QueryRate = 0; + u8 BasicRate; + + + for (i = 0; i < ieee->current_network.rates_len; i++) { + BasicRate = ieee->current_network.rates[i]&0x7F; + if (!rtllib_is_cck_rate(BasicRate)) { + if (QueryRate == 0) { + QueryRate = BasicRate; + } else { + if (BasicRate < QueryRate) + QueryRate = BasicRate; + } + } + } + + if (QueryRate == 0) { + QueryRate = 12; + netdev_info(ieee->dev, "No BasicRate found!!\n"); + } + return QueryRate; +} + +static u8 MgntQuery_MgntFrameTxRate(struct rtllib_device *ieee) +{ + struct rt_hi_throughput *pHTInfo = ieee->pHTInfo; + u8 rate; + + if (pHTInfo->IOTAction & HT_IOT_ACT_MGNT_USE_CCK_6M) + rate = 0x0c; + else + rate = ieee->basic_rate & 0x7f; + + if (rate == 0) { + if (ieee->mode == IEEE_A || + ieee->mode == IEEE_N_5G || + (ieee->mode == IEEE_N_24G && !pHTInfo->bCurSuppCCK)) + rate = 0x0c; + else + rate = 0x02; + } + + return rate; +} + +inline void softmac_mgmt_xmit(struct sk_buff *skb, struct rtllib_device *ieee) +{ + unsigned long flags; + short single = ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE; + struct rtllib_hdr_3addr *header = + (struct rtllib_hdr_3addr *) skb->data; + + struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + 8); + + spin_lock_irqsave(&ieee->lock, flags); + + /* called with 2nd param 0, no mgmt lock required */ + rtllib_sta_wakeup(ieee, 0); + + if (le16_to_cpu(header->frame_ctl) == RTLLIB_STYPE_BEACON) + tcb_desc->queue_index = BEACON_QUEUE; + else + tcb_desc->queue_index = MGNT_QUEUE; + + if (ieee->disable_mgnt_queue) + tcb_desc->queue_index = HIGH_QUEUE; + + tcb_desc->data_rate = MgntQuery_MgntFrameTxRate(ieee); + tcb_desc->RATRIndex = 7; + tcb_desc->bTxDisableRateFallBack = 1; + tcb_desc->bTxUseDriverAssingedRate = 1; + if (single) { + if (ieee->queue_stop) { + enqueue_mgmt(ieee, skb); + } else { + header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0]<<4); + + if (ieee->seq_ctrl[0] == 0xFFF) + ieee->seq_ctrl[0] = 0; + else + ieee->seq_ctrl[0]++; + + /* avoid watchdog triggers */ + ieee->softmac_data_hard_start_xmit(skb, ieee->dev, + ieee->basic_rate); + } + + spin_unlock_irqrestore(&ieee->lock, flags); + } else { + spin_unlock_irqrestore(&ieee->lock, flags); + spin_lock_irqsave(&ieee->mgmt_tx_lock, flags); + + header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); + + if (ieee->seq_ctrl[0] == 0xFFF) + ieee->seq_ctrl[0] = 0; + else + ieee->seq_ctrl[0]++; + + /* check whether the managed packet queued greater than 5 */ + if (!ieee->check_nic_enough_desc(ieee->dev, tcb_desc->queue_index) || + (skb_queue_len(&ieee->skb_waitQ[tcb_desc->queue_index]) != 0) || + (ieee->queue_stop)) { + /* insert the skb packet to the management queue + * + * as for the completion function, it does not need + * to check it any more. + */ + netdev_info(ieee->dev, + "%s():insert to waitqueue, queue_index:%d!\n", + __func__, tcb_desc->queue_index); + skb_queue_tail(&ieee->skb_waitQ[tcb_desc->queue_index], + skb); + } else { + ieee->softmac_hard_start_xmit(skb, ieee->dev); + } + spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags); + } +} + +inline void softmac_ps_mgmt_xmit(struct sk_buff *skb, + struct rtllib_device *ieee) +{ + short single = ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE; + struct rtllib_hdr_3addr *header = + (struct rtllib_hdr_3addr *) skb->data; + u16 fc, type, stype; + struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + 8); + + fc = le16_to_cpu(header->frame_ctl); + type = WLAN_FC_GET_TYPE(fc); + stype = WLAN_FC_GET_STYPE(fc); + + + if (stype != RTLLIB_STYPE_PSPOLL) + tcb_desc->queue_index = MGNT_QUEUE; + else + tcb_desc->queue_index = HIGH_QUEUE; + + if (ieee->disable_mgnt_queue) + tcb_desc->queue_index = HIGH_QUEUE; + + + tcb_desc->data_rate = MgntQuery_MgntFrameTxRate(ieee); + tcb_desc->RATRIndex = 7; + tcb_desc->bTxDisableRateFallBack = 1; + tcb_desc->bTxUseDriverAssingedRate = 1; + if (single) { + if (type != RTLLIB_FTYPE_CTL) { + header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); + + if (ieee->seq_ctrl[0] == 0xFFF) + ieee->seq_ctrl[0] = 0; + else + ieee->seq_ctrl[0]++; + + } + /* avoid watchdog triggers */ + ieee->softmac_data_hard_start_xmit(skb, ieee->dev, + ieee->basic_rate); + + } else { + if (type != RTLLIB_FTYPE_CTL) { + header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); + + if (ieee->seq_ctrl[0] == 0xFFF) + ieee->seq_ctrl[0] = 0; + else + ieee->seq_ctrl[0]++; + } + ieee->softmac_hard_start_xmit(skb, ieee->dev); + + } +} + +static inline struct sk_buff *rtllib_probe_req(struct rtllib_device *ieee) +{ + unsigned int len, rate_len; + u8 *tag; + struct sk_buff *skb; + struct rtllib_probe_request *req; + + len = ieee->current_network.ssid_len; + + rate_len = rtllib_MFIE_rate_len(ieee); + + skb = dev_alloc_skb(sizeof(struct rtllib_probe_request) + + 2 + len + rate_len + ieee->tx_headroom); + + if (!skb) + return NULL; + + skb_reserve(skb, ieee->tx_headroom); + + req = (struct rtllib_probe_request *) skb_put(skb, + sizeof(struct rtllib_probe_request)); + req->header.frame_ctl = cpu_to_le16(RTLLIB_STYPE_PROBE_REQ); + req->header.duration_id = 0; + + memset(req->header.addr1, 0xff, ETH_ALEN); + memcpy(req->header.addr2, ieee->dev->dev_addr, ETH_ALEN); + memset(req->header.addr3, 0xff, ETH_ALEN); + + tag = (u8 *) skb_put(skb, len + 2 + rate_len); + + *tag++ = MFIE_TYPE_SSID; + *tag++ = len; + memcpy(tag, ieee->current_network.ssid, len); + tag += len; + + rtllib_MFIE_Brate(ieee, &tag); + rtllib_MFIE_Grate(ieee, &tag); + + return skb; +} + +struct sk_buff *rtllib_get_beacon_(struct rtllib_device *ieee); + +static void rtllib_send_beacon(struct rtllib_device *ieee) +{ + struct sk_buff *skb; + + if (!ieee->ieee_up) + return; + skb = rtllib_get_beacon_(ieee); + + if (skb) { + softmac_mgmt_xmit(skb, ieee); + ieee->softmac_stats.tx_beacons++; + } + + if (ieee->beacon_txing && ieee->ieee_up) + mod_timer(&ieee->beacon_timer, jiffies + + (msecs_to_jiffies(ieee->current_network.beacon_interval - 5))); +} + + +static void rtllib_send_beacon_cb(unsigned long _ieee) +{ + struct rtllib_device *ieee = + (struct rtllib_device *) _ieee; + unsigned long flags; + + spin_lock_irqsave(&ieee->beacon_lock, flags); + rtllib_send_beacon(ieee); + spin_unlock_irqrestore(&ieee->beacon_lock, flags); +} + +/* Enables network monitor mode, all rx packets will be received. */ +void rtllib_EnableNetMonitorMode(struct net_device *dev, + bool bInitState) +{ + struct rtllib_device *ieee = netdev_priv_rsl(dev); + + netdev_info(dev, "========>Enter Monitor Mode\n"); + + ieee->AllowAllDestAddrHandler(dev, true, !bInitState); +} + + +/* Disables network monitor mode. Only packets destinated to + * us will be received. + */ +void rtllib_DisableNetMonitorMode(struct net_device *dev, + bool bInitState) +{ + struct rtllib_device *ieee = netdev_priv_rsl(dev); + + netdev_info(dev, "========>Exit Monitor Mode\n"); + + ieee->AllowAllDestAddrHandler(dev, false, !bInitState); +} + + +/* Enables the specialized promiscuous mode required by Intel. + * In this mode, Intel intends to hear traffics from/to other STAs in the + * same BSS. Therefore we don't have to disable checking BSSID and we only need + * to allow all dest. BUT: if we enable checking BSSID then we can't recv + * packets from other STA. + */ +void rtllib_EnableIntelPromiscuousMode(struct net_device *dev, + bool bInitState) +{ + bool bFilterOutNonAssociatedBSSID = false; + + struct rtllib_device *ieee = netdev_priv_rsl(dev); + + netdev_info(dev, "========>Enter Intel Promiscuous Mode\n"); + + ieee->AllowAllDestAddrHandler(dev, true, !bInitState); + ieee->SetHwRegHandler(dev, HW_VAR_CECHK_BSSID, + (u8 *)&bFilterOutNonAssociatedBSSID); + + ieee->bNetPromiscuousMode = true; +} +EXPORT_SYMBOL(rtllib_EnableIntelPromiscuousMode); + + +/* Disables the specialized promiscuous mode required by Intel. + * See MgntEnableIntelPromiscuousMode for detail. + */ +void rtllib_DisableIntelPromiscuousMode(struct net_device *dev, + bool bInitState) +{ + bool bFilterOutNonAssociatedBSSID = true; + + struct rtllib_device *ieee = netdev_priv_rsl(dev); + + netdev_info(dev, "========>Exit Intel Promiscuous Mode\n"); + + ieee->AllowAllDestAddrHandler(dev, false, !bInitState); + ieee->SetHwRegHandler(dev, HW_VAR_CECHK_BSSID, + (u8 *)&bFilterOutNonAssociatedBSSID); + + ieee->bNetPromiscuousMode = false; +} +EXPORT_SYMBOL(rtllib_DisableIntelPromiscuousMode); + +static void rtllib_send_probe(struct rtllib_device *ieee, u8 is_mesh) +{ + struct sk_buff *skb; + + skb = rtllib_probe_req(ieee); + if (skb) { + softmac_mgmt_xmit(skb, ieee); + ieee->softmac_stats.tx_probe_rq++; + } +} + + +void rtllib_send_probe_requests(struct rtllib_device *ieee, u8 is_mesh) +{ + if (ieee->active_scan && (ieee->softmac_features & + IEEE_SOFTMAC_PROBERQ)) { + rtllib_send_probe(ieee, 0); + rtllib_send_probe(ieee, 0); + } +} + +static void rtllib_softmac_hint11d_wq(void *data) +{ +} + +void rtllib_update_active_chan_map(struct rtllib_device *ieee) +{ + memcpy(ieee->active_channel_map, GET_DOT11D_INFO(ieee)->channel_map, + MAX_CHANNEL_NUMBER+1); +} + +/* this performs syncro scan blocking the caller until all channels + * in the allowed channel map has been checked. + */ +void rtllib_softmac_scan_syncro(struct rtllib_device *ieee, u8 is_mesh) +{ + union iwreq_data wrqu; + short ch = 0; + + rtllib_update_active_chan_map(ieee); + + ieee->be_scan_inprogress = true; + + down(&ieee->scan_sem); + + while (1) { + do { + ch++; + if (ch > MAX_CHANNEL_NUMBER) + goto out; /* scan completed */ + } while (!ieee->active_channel_map[ch]); + + /* this function can be called in two situations + * 1- We have switched to ad-hoc mode and we are + * performing a complete syncro scan before conclude + * there are no interesting cell and to create a + * new one. In this case the link state is + * RTLLIB_NOLINK until we found an interesting cell. + * If so the ieee8021_new_net, called by the RX path + * will set the state to RTLLIB_LINKED, so we stop + * scanning + * 2- We are linked and the root uses run iwlist scan. + * So we switch to RTLLIB_LINKED_SCANNING to remember + * that we are still logically linked (not interested in + * new network events, despite for updating the net list, + * but we are temporarly 'unlinked' as the driver shall + * not filter RX frames and the channel is changing. + * So the only situation in which are interested is to check + * if the state become LINKED because of the #1 situation + */ + + if (ieee->state == RTLLIB_LINKED) + goto out; + if (ieee->sync_scan_hurryup) { + netdev_info(ieee->dev, + "============>sync_scan_hurryup out\n"); + goto out; + } + + ieee->set_chan(ieee->dev, ch); + if (ieee->active_channel_map[ch] == 1) + rtllib_send_probe_requests(ieee, 0); + + /* this prevent excessive time wait when we + * need to wait for a syncro scan to end.. + */ + msleep_interruptible_rsl(RTLLIB_SOFTMAC_SCAN_TIME); + } +out: + ieee->actscanning = false; + ieee->sync_scan_hurryup = 0; + + if (ieee->state >= RTLLIB_LINKED) { + if (IS_DOT11D_ENABLE(ieee)) + DOT11D_ScanComplete(ieee); + } + up(&ieee->scan_sem); + + ieee->be_scan_inprogress = false; + + memset(&wrqu, 0, sizeof(wrqu)); + wireless_send_event(ieee->dev, SIOCGIWSCAN, &wrqu, NULL); +} + +static void rtllib_softmac_scan_wq(void *data) +{ + struct rtllib_device *ieee = container_of_dwork_rsl(data, + struct rtllib_device, softmac_scan_wq); + u8 last_channel = ieee->current_network.channel; + + rtllib_update_active_chan_map(ieee); + + if (!ieee->ieee_up) + return; + if (rtllib_act_scanning(ieee, true)) + return; + + down(&ieee->scan_sem); + + if (ieee->eRFPowerState == eRfOff) { + netdev_info(ieee->dev, + "======>%s():rf state is eRfOff, return\n", + __func__); + goto out1; + } + + do { + ieee->current_network.channel = + (ieee->current_network.channel + 1) % + MAX_CHANNEL_NUMBER; + if (ieee->scan_watch_dog++ > MAX_CHANNEL_NUMBER) { + if (!ieee->active_channel_map[ieee->current_network.channel]) + ieee->current_network.channel = 6; + goto out; /* no good chans */ + } + } while (!ieee->active_channel_map[ieee->current_network.channel]); + + if (ieee->scanning_continue == 0) + goto out; + + ieee->set_chan(ieee->dev, ieee->current_network.channel); + + if (ieee->active_channel_map[ieee->current_network.channel] == 1) + rtllib_send_probe_requests(ieee, 0); + + queue_delayed_work_rsl(ieee->wq, &ieee->softmac_scan_wq, + msecs_to_jiffies(RTLLIB_SOFTMAC_SCAN_TIME)); + + up(&ieee->scan_sem); + return; + +out: + if (IS_DOT11D_ENABLE(ieee)) + DOT11D_ScanComplete(ieee); + ieee->current_network.channel = last_channel; + +out1: + ieee->actscanning = false; + ieee->scan_watch_dog = 0; + ieee->scanning_continue = 0; + up(&ieee->scan_sem); +} + + + +static void rtllib_beacons_start(struct rtllib_device *ieee) +{ + unsigned long flags; + + spin_lock_irqsave(&ieee->beacon_lock, flags); + + ieee->beacon_txing = 1; + rtllib_send_beacon(ieee); + + spin_unlock_irqrestore(&ieee->beacon_lock, flags); +} + +static void rtllib_beacons_stop(struct rtllib_device *ieee) +{ + unsigned long flags; + + spin_lock_irqsave(&ieee->beacon_lock, flags); + + ieee->beacon_txing = 0; + del_timer_sync(&ieee->beacon_timer); + + spin_unlock_irqrestore(&ieee->beacon_lock, flags); + +} + + +void rtllib_stop_send_beacons(struct rtllib_device *ieee) +{ + if (ieee->stop_send_beacons) + ieee->stop_send_beacons(ieee->dev); + if (ieee->softmac_features & IEEE_SOFTMAC_BEACONS) + rtllib_beacons_stop(ieee); +} +EXPORT_SYMBOL(rtllib_stop_send_beacons); + + +void rtllib_start_send_beacons(struct rtllib_device *ieee) +{ + if (ieee->start_send_beacons) + ieee->start_send_beacons(ieee->dev); + if (ieee->softmac_features & IEEE_SOFTMAC_BEACONS) + rtllib_beacons_start(ieee); +} +EXPORT_SYMBOL(rtllib_start_send_beacons); + + +static void rtllib_softmac_stop_scan(struct rtllib_device *ieee) +{ + down(&ieee->scan_sem); + ieee->scan_watch_dog = 0; + if (ieee->scanning_continue == 1) { + ieee->scanning_continue = 0; + ieee->actscanning = false; + + cancel_delayed_work(&ieee->softmac_scan_wq); + } + + up(&ieee->scan_sem); +} + +void rtllib_stop_scan(struct rtllib_device *ieee) +{ + if (ieee->softmac_features & IEEE_SOFTMAC_SCAN) { + rtllib_softmac_stop_scan(ieee); + } else { + if (ieee->rtllib_stop_hw_scan) + ieee->rtllib_stop_hw_scan(ieee->dev); + } +} +EXPORT_SYMBOL(rtllib_stop_scan); + +void rtllib_stop_scan_syncro(struct rtllib_device *ieee) +{ + if (ieee->softmac_features & IEEE_SOFTMAC_SCAN) { + ieee->sync_scan_hurryup = 1; + } else { + if (ieee->rtllib_stop_hw_scan) + ieee->rtllib_stop_hw_scan(ieee->dev); + } +} +EXPORT_SYMBOL(rtllib_stop_scan_syncro); + +bool rtllib_act_scanning(struct rtllib_device *ieee, bool sync_scan) +{ + if (ieee->softmac_features & IEEE_SOFTMAC_SCAN) { + if (sync_scan) + return ieee->be_scan_inprogress; + else + return ieee->actscanning || ieee->be_scan_inprogress; + } else { + return test_bit(STATUS_SCANNING, &ieee->status); + } +} +EXPORT_SYMBOL(rtllib_act_scanning); + +/* called with ieee->lock held */ +static void rtllib_start_scan(struct rtllib_device *ieee) +{ + RT_TRACE(COMP_DBG, "===>%s()\n", __func__); + if (ieee->rtllib_ips_leave_wq != NULL) + ieee->rtllib_ips_leave_wq(ieee->dev); + + if (IS_DOT11D_ENABLE(ieee)) { + if (IS_COUNTRY_IE_VALID(ieee)) + RESET_CIE_WATCHDOG(ieee); + } + if (ieee->softmac_features & IEEE_SOFTMAC_SCAN) { + if (ieee->scanning_continue == 0) { + ieee->actscanning = true; + ieee->scanning_continue = 1; + queue_delayed_work_rsl(ieee->wq, + &ieee->softmac_scan_wq, 0); + } + } else { + if (ieee->rtllib_start_hw_scan) + ieee->rtllib_start_hw_scan(ieee->dev); + } +} + +/* called with wx_sem held */ +void rtllib_start_scan_syncro(struct rtllib_device *ieee, u8 is_mesh) +{ + if (IS_DOT11D_ENABLE(ieee)) { + if (IS_COUNTRY_IE_VALID(ieee)) + RESET_CIE_WATCHDOG(ieee); + } + ieee->sync_scan_hurryup = 0; + if (ieee->softmac_features & IEEE_SOFTMAC_SCAN) { + rtllib_softmac_scan_syncro(ieee, is_mesh); + } else { + if (ieee->rtllib_start_hw_scan) + ieee->rtllib_start_hw_scan(ieee->dev); + } +} +EXPORT_SYMBOL(rtllib_start_scan_syncro); + +inline struct sk_buff *rtllib_authentication_req(struct rtllib_network *beacon, + struct rtllib_device *ieee, int challengelen, u8 *daddr) +{ + struct sk_buff *skb; + struct rtllib_authentication *auth; + int len = 0; + + len = sizeof(struct rtllib_authentication) + challengelen + + ieee->tx_headroom + 4; + skb = dev_alloc_skb(len); + + if (!skb) + return NULL; + + skb_reserve(skb, ieee->tx_headroom); + + auth = (struct rtllib_authentication *) + skb_put(skb, sizeof(struct rtllib_authentication)); + + auth->header.frame_ctl = cpu_to_le16(RTLLIB_STYPE_AUTH); + if (challengelen) + auth->header.frame_ctl |= cpu_to_le16(RTLLIB_FCTL_WEP); + + auth->header.duration_id = cpu_to_le16(0x013a); + memcpy(auth->header.addr1, beacon->bssid, ETH_ALEN); + memcpy(auth->header.addr2, ieee->dev->dev_addr, ETH_ALEN); + memcpy(auth->header.addr3, beacon->bssid, ETH_ALEN); + if (ieee->auth_mode == 0) + auth->algorithm = WLAN_AUTH_OPEN; + else if (ieee->auth_mode == 1) + auth->algorithm = cpu_to_le16(WLAN_AUTH_SHARED_KEY); + else if (ieee->auth_mode == 2) + auth->algorithm = WLAN_AUTH_OPEN; + auth->transaction = cpu_to_le16(ieee->associate_seq); + ieee->associate_seq++; + + auth->status = cpu_to_le16(WLAN_STATUS_SUCCESS); + + return skb; +} + +static struct sk_buff *rtllib_probe_resp(struct rtllib_device *ieee, u8 *dest) +{ + u8 *tag; + int beacon_size; + struct rtllib_probe_response *beacon_buf; + struct sk_buff *skb = NULL; + int encrypt; + int atim_len, erp_len; + struct lib80211_crypt_data *crypt; + + char *ssid = ieee->current_network.ssid; + int ssid_len = ieee->current_network.ssid_len; + int rate_len = ieee->current_network.rates_len+2; + int rate_ex_len = ieee->current_network.rates_ex_len; + int wpa_ie_len = ieee->wpa_ie_len; + u8 erpinfo_content = 0; + + u8 *tmp_ht_cap_buf = NULL; + u8 tmp_ht_cap_len = 0; + u8 *tmp_ht_info_buf = NULL; + u8 tmp_ht_info_len = 0; + struct rt_hi_throughput *pHTInfo = ieee->pHTInfo; + u8 *tmp_generic_ie_buf = NULL; + u8 tmp_generic_ie_len = 0; + + if (rate_ex_len > 0) + rate_ex_len += 2; + + if (ieee->current_network.capability & WLAN_CAPABILITY_IBSS) + atim_len = 4; + else + atim_len = 0; + + if ((ieee->current_network.mode == IEEE_G) || + (ieee->current_network.mode == IEEE_N_24G && + ieee->pHTInfo->bCurSuppCCK)) { + erp_len = 3; + erpinfo_content = 0; + if (ieee->current_network.buseprotection) + erpinfo_content |= ERP_UseProtection; + } else + erp_len = 0; + + crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx]; + encrypt = ieee->host_encrypt && crypt && crypt->ops && + ((0 == strcmp(crypt->ops->name, "R-WEP") || wpa_ie_len)); + if (ieee->pHTInfo->bCurrentHTSupport) { + tmp_ht_cap_buf = (u8 *) &(ieee->pHTInfo->SelfHTCap); + tmp_ht_cap_len = sizeof(ieee->pHTInfo->SelfHTCap); + tmp_ht_info_buf = (u8 *) &(ieee->pHTInfo->SelfHTInfo); + tmp_ht_info_len = sizeof(ieee->pHTInfo->SelfHTInfo); + HTConstructCapabilityElement(ieee, tmp_ht_cap_buf, + &tmp_ht_cap_len, encrypt, false); + HTConstructInfoElement(ieee, tmp_ht_info_buf, &tmp_ht_info_len, + encrypt); + + if (pHTInfo->bRegRT2RTAggregation) { + tmp_generic_ie_buf = ieee->pHTInfo->szRT2RTAggBuffer; + tmp_generic_ie_len = + sizeof(ieee->pHTInfo->szRT2RTAggBuffer); + HTConstructRT2RTAggElement(ieee, tmp_generic_ie_buf, + &tmp_generic_ie_len); + } + } + + beacon_size = sizeof(struct rtllib_probe_response)+2+ + ssid_len + 3 + rate_len + rate_ex_len + atim_len + erp_len + + wpa_ie_len + ieee->tx_headroom; + skb = dev_alloc_skb(beacon_size); + if (!skb) + return NULL; + + skb_reserve(skb, ieee->tx_headroom); + + beacon_buf = (struct rtllib_probe_response *) skb_put(skb, + (beacon_size - ieee->tx_headroom)); + memcpy(beacon_buf->header.addr1, dest, ETH_ALEN); + memcpy(beacon_buf->header.addr2, ieee->dev->dev_addr, ETH_ALEN); + memcpy(beacon_buf->header.addr3, ieee->current_network.bssid, ETH_ALEN); + + beacon_buf->header.duration_id = 0; + beacon_buf->beacon_interval = + cpu_to_le16(ieee->current_network.beacon_interval); + beacon_buf->capability = + cpu_to_le16(ieee->current_network.capability & + WLAN_CAPABILITY_IBSS); + beacon_buf->capability |= + cpu_to_le16(ieee->current_network.capability & + WLAN_CAPABILITY_SHORT_PREAMBLE); + + if (ieee->short_slot && (ieee->current_network.capability & + WLAN_CAPABILITY_SHORT_SLOT_TIME)) + beacon_buf->capability |= + cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME); + + crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx]; + if (encrypt) + beacon_buf->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); + + + beacon_buf->header.frame_ctl = cpu_to_le16(RTLLIB_STYPE_PROBE_RESP); + beacon_buf->info_element[0].id = MFIE_TYPE_SSID; + beacon_buf->info_element[0].len = ssid_len; + + tag = (u8 *) beacon_buf->info_element[0].data; + + memcpy(tag, ssid, ssid_len); + + tag += ssid_len; + + *(tag++) = MFIE_TYPE_RATES; + *(tag++) = rate_len-2; + memcpy(tag, ieee->current_network.rates, rate_len-2); + tag += rate_len-2; + + *(tag++) = MFIE_TYPE_DS_SET; + *(tag++) = 1; + *(tag++) = ieee->current_network.channel; + + if (atim_len) { + u16 val16; + *(tag++) = MFIE_TYPE_IBSS_SET; + *(tag++) = 2; + val16 = ieee->current_network.atim_window; + memcpy((u8 *)tag, (u8 *)&val16, 2); + tag += 2; + } + + if (erp_len) { + *(tag++) = MFIE_TYPE_ERP; + *(tag++) = 1; + *(tag++) = erpinfo_content; + } + if (rate_ex_len) { + *(tag++) = MFIE_TYPE_RATES_EX; + *(tag++) = rate_ex_len-2; + memcpy(tag, ieee->current_network.rates_ex, rate_ex_len-2); + tag += rate_ex_len-2; + } + + if (wpa_ie_len) { + if (ieee->iw_mode == IW_MODE_ADHOC) + memcpy(&ieee->wpa_ie[14], &ieee->wpa_ie[8], 4); + memcpy(tag, ieee->wpa_ie, ieee->wpa_ie_len); + tag += ieee->wpa_ie_len; + } + return skb; +} + +static struct sk_buff *rtllib_assoc_resp(struct rtllib_device *ieee, u8 *dest) +{ + struct sk_buff *skb; + u8 *tag; + + struct lib80211_crypt_data *crypt; + struct rtllib_assoc_response_frame *assoc; + short encrypt; + + unsigned int rate_len = rtllib_MFIE_rate_len(ieee); + int len = sizeof(struct rtllib_assoc_response_frame) + rate_len + + ieee->tx_headroom; + + skb = dev_alloc_skb(len); + + if (!skb) + return NULL; + + skb_reserve(skb, ieee->tx_headroom); + + assoc = (struct rtllib_assoc_response_frame *) + skb_put(skb, sizeof(struct rtllib_assoc_response_frame)); + + assoc->header.frame_ctl = cpu_to_le16(RTLLIB_STYPE_ASSOC_RESP); + memcpy(assoc->header.addr1, dest, ETH_ALEN); + memcpy(assoc->header.addr3, ieee->dev->dev_addr, ETH_ALEN); + memcpy(assoc->header.addr2, ieee->dev->dev_addr, ETH_ALEN); + assoc->capability = cpu_to_le16(ieee->iw_mode == IW_MODE_MASTER ? + WLAN_CAPABILITY_ESS : WLAN_CAPABILITY_IBSS); + + + if (ieee->short_slot) + assoc->capability |= + cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME); + + if (ieee->host_encrypt) + crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx]; + else + crypt = NULL; + + encrypt = (crypt && crypt->ops); + + if (encrypt) + assoc->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); + + assoc->status = 0; + assoc->aid = cpu_to_le16(ieee->assoc_id); + if (ieee->assoc_id == 0x2007) + ieee->assoc_id = 0; + else + ieee->assoc_id++; + + tag = (u8 *) skb_put(skb, rate_len); + rtllib_MFIE_Brate(ieee, &tag); + rtllib_MFIE_Grate(ieee, &tag); + + return skb; +} + +static struct sk_buff *rtllib_auth_resp(struct rtllib_device *ieee, int status, + u8 *dest) +{ + struct sk_buff *skb = NULL; + struct rtllib_authentication *auth; + int len = ieee->tx_headroom + sizeof(struct rtllib_authentication) + 1; + + skb = dev_alloc_skb(len); + if (!skb) + return NULL; + + skb->len = sizeof(struct rtllib_authentication); + + skb_reserve(skb, ieee->tx_headroom); + + auth = (struct rtllib_authentication *) + skb_put(skb, sizeof(struct rtllib_authentication)); + + auth->status = cpu_to_le16(status); + auth->transaction = cpu_to_le16(2); + auth->algorithm = cpu_to_le16(WLAN_AUTH_OPEN); + + memcpy(auth->header.addr3, ieee->dev->dev_addr, ETH_ALEN); + memcpy(auth->header.addr2, ieee->dev->dev_addr, ETH_ALEN); + memcpy(auth->header.addr1, dest, ETH_ALEN); + auth->header.frame_ctl = cpu_to_le16(RTLLIB_STYPE_AUTH); + return skb; + + +} + +static struct sk_buff *rtllib_null_func(struct rtllib_device *ieee, short pwr) +{ + struct sk_buff *skb; + struct rtllib_hdr_3addr *hdr; + + skb = dev_alloc_skb(sizeof(struct rtllib_hdr_3addr)+ieee->tx_headroom); + if (!skb) + return NULL; + + skb_reserve(skb, ieee->tx_headroom); + + hdr = (struct rtllib_hdr_3addr *)skb_put(skb, + sizeof(struct rtllib_hdr_3addr)); + + memcpy(hdr->addr1, ieee->current_network.bssid, ETH_ALEN); + memcpy(hdr->addr2, ieee->dev->dev_addr, ETH_ALEN); + memcpy(hdr->addr3, ieee->current_network.bssid, ETH_ALEN); + + hdr->frame_ctl = cpu_to_le16(RTLLIB_FTYPE_DATA | + RTLLIB_STYPE_NULLFUNC | RTLLIB_FCTL_TODS | + (pwr ? RTLLIB_FCTL_PM : 0)); + + return skb; + + +} + +static struct sk_buff *rtllib_pspoll_func(struct rtllib_device *ieee) +{ + struct sk_buff *skb; + struct rtllib_pspoll_hdr *hdr; + + skb = dev_alloc_skb(sizeof(struct rtllib_pspoll_hdr)+ieee->tx_headroom); + if (!skb) + return NULL; + + skb_reserve(skb, ieee->tx_headroom); + + hdr = (struct rtllib_pspoll_hdr *)skb_put(skb, + sizeof(struct rtllib_pspoll_hdr)); + + memcpy(hdr->bssid, ieee->current_network.bssid, ETH_ALEN); + memcpy(hdr->ta, ieee->dev->dev_addr, ETH_ALEN); + + hdr->aid = cpu_to_le16(ieee->assoc_id | 0xc000); + hdr->frame_ctl = cpu_to_le16(RTLLIB_FTYPE_CTL | RTLLIB_STYPE_PSPOLL | + RTLLIB_FCTL_PM); + + return skb; + +} + +static void rtllib_resp_to_assoc_rq(struct rtllib_device *ieee, u8 *dest) +{ + struct sk_buff *buf = rtllib_assoc_resp(ieee, dest); + + if (buf) + softmac_mgmt_xmit(buf, ieee); +} + + +static void rtllib_resp_to_auth(struct rtllib_device *ieee, int s, u8 *dest) +{ + struct sk_buff *buf = rtllib_auth_resp(ieee, s, dest); + + if (buf) + softmac_mgmt_xmit(buf, ieee); +} + + +static void rtllib_resp_to_probe(struct rtllib_device *ieee, u8 *dest) +{ + struct sk_buff *buf = rtllib_probe_resp(ieee, dest); + + if (buf) + softmac_mgmt_xmit(buf, ieee); +} + + +inline int SecIsInPMKIDList(struct rtllib_device *ieee, u8 *bssid) +{ + int i = 0; + + do { + if ((ieee->PMKIDList[i].bUsed) && + (memcmp(ieee->PMKIDList[i].Bssid, bssid, ETH_ALEN) == 0)) + break; + i++; + } while (i < NUM_PMKID_CACHE); + + if (i == NUM_PMKID_CACHE) + i = -1; + return i; +} + +inline struct sk_buff *rtllib_association_req(struct rtllib_network *beacon, + struct rtllib_device *ieee) +{ + struct sk_buff *skb; + struct rtllib_assoc_request_frame *hdr; + u8 *tag, *ies; + int i; + u8 *ht_cap_buf = NULL; + u8 ht_cap_len = 0; + u8 *realtek_ie_buf = NULL; + u8 realtek_ie_len = 0; + int wpa_ie_len = ieee->wpa_ie_len; + int wps_ie_len = ieee->wps_ie_len; + unsigned int ckip_ie_len = 0; + unsigned int ccxrm_ie_len = 0; + unsigned int cxvernum_ie_len = 0; + struct lib80211_crypt_data *crypt; + int encrypt; + int PMKCacheIdx; + + unsigned int rate_len = (beacon->rates_len ? + (beacon->rates_len + 2) : 0) + + (beacon->rates_ex_len ? (beacon->rates_ex_len) + + 2 : 0); + + unsigned int wmm_info_len = beacon->qos_data.supported ? 9 : 0; + unsigned int turbo_info_len = beacon->Turbo_Enable ? 9 : 0; + + int len = 0; + + crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx]; + if (crypt != NULL) + encrypt = ieee->host_encrypt && crypt && crypt->ops && + ((0 == strcmp(crypt->ops->name, "R-WEP") || + wpa_ie_len)); + else + encrypt = 0; + + if ((ieee->rtllib_ap_sec_type && + (ieee->rtllib_ap_sec_type(ieee) & SEC_ALG_TKIP)) || + ieee->bForcedBgMode) { + ieee->pHTInfo->bEnableHT = 0; + ieee->mode = WIRELESS_MODE_G; + } + + if (ieee->pHTInfo->bCurrentHTSupport && ieee->pHTInfo->bEnableHT) { + ht_cap_buf = (u8 *)&(ieee->pHTInfo->SelfHTCap); + ht_cap_len = sizeof(ieee->pHTInfo->SelfHTCap); + HTConstructCapabilityElement(ieee, ht_cap_buf, &ht_cap_len, + encrypt, true); + if (ieee->pHTInfo->bCurrentRT2RTAggregation) { + realtek_ie_buf = ieee->pHTInfo->szRT2RTAggBuffer; + realtek_ie_len = + sizeof(ieee->pHTInfo->szRT2RTAggBuffer); + HTConstructRT2RTAggElement(ieee, realtek_ie_buf, + &realtek_ie_len); + } + } + + if (beacon->bCkipSupported) + ckip_ie_len = 30+2; + if (beacon->bCcxRmEnable) + ccxrm_ie_len = 6+2; + if (beacon->BssCcxVerNumber >= 2) + cxvernum_ie_len = 5+2; + + PMKCacheIdx = SecIsInPMKIDList(ieee, ieee->current_network.bssid); + if (PMKCacheIdx >= 0) { + wpa_ie_len += 18; + netdev_info(ieee->dev, "[PMK cache]: WPA2 IE length: %x\n", + wpa_ie_len); + } + len = sizeof(struct rtllib_assoc_request_frame) + 2 + + beacon->ssid_len + + rate_len + + wpa_ie_len + + wps_ie_len + + wmm_info_len + + turbo_info_len + + ht_cap_len + + realtek_ie_len + + ckip_ie_len + + ccxrm_ie_len + + cxvernum_ie_len + + ieee->tx_headroom; + + skb = dev_alloc_skb(len); + + if (!skb) + return NULL; + + skb_reserve(skb, ieee->tx_headroom); + + hdr = (struct rtllib_assoc_request_frame *) + skb_put(skb, sizeof(struct rtllib_assoc_request_frame) + 2); + + + hdr->header.frame_ctl = RTLLIB_STYPE_ASSOC_REQ; + hdr->header.duration_id = cpu_to_le16(37); + memcpy(hdr->header.addr1, beacon->bssid, ETH_ALEN); + memcpy(hdr->header.addr2, ieee->dev->dev_addr, ETH_ALEN); + memcpy(hdr->header.addr3, beacon->bssid, ETH_ALEN); + + memcpy(ieee->ap_mac_addr, beacon->bssid, ETH_ALEN); + + hdr->capability = cpu_to_le16(WLAN_CAPABILITY_ESS); + if (beacon->capability & WLAN_CAPABILITY_PRIVACY) + hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); + + if (beacon->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) + hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE); + + if (ieee->short_slot && + (beacon->capability&WLAN_CAPABILITY_SHORT_SLOT_TIME)) + hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME); + + + hdr->listen_interval = cpu_to_le16(beacon->listen_interval); + + hdr->info_element[0].id = MFIE_TYPE_SSID; + + hdr->info_element[0].len = beacon->ssid_len; + tag = skb_put(skb, beacon->ssid_len); + memcpy(tag, beacon->ssid, beacon->ssid_len); + + tag = skb_put(skb, rate_len); + + if (beacon->rates_len) { + *tag++ = MFIE_TYPE_RATES; + *tag++ = beacon->rates_len; + for (i = 0; i < beacon->rates_len; i++) + *tag++ = beacon->rates[i]; + } + + if (beacon->rates_ex_len) { + *tag++ = MFIE_TYPE_RATES_EX; + *tag++ = beacon->rates_ex_len; + for (i = 0; i < beacon->rates_ex_len; i++) + *tag++ = beacon->rates_ex[i]; + } + + if (beacon->bCkipSupported) { + static const u8 AironetIeOui[] = {0x00, 0x01, 0x66}; + u8 CcxAironetBuf[30]; + struct octet_string osCcxAironetIE; + + memset(CcxAironetBuf, 0, 30); + osCcxAironetIE.Octet = CcxAironetBuf; + osCcxAironetIE.Length = sizeof(CcxAironetBuf); + memcpy(osCcxAironetIE.Octet, AironetIeOui, + sizeof(AironetIeOui)); + + osCcxAironetIE.Octet[IE_CISCO_FLAG_POSITION] |= + (SUPPORT_CKIP_PK|SUPPORT_CKIP_MIC); + tag = skb_put(skb, ckip_ie_len); + *tag++ = MFIE_TYPE_AIRONET; + *tag++ = osCcxAironetIE.Length; + memcpy(tag, osCcxAironetIE.Octet, osCcxAironetIE.Length); + tag += osCcxAironetIE.Length; + } + + if (beacon->bCcxRmEnable) { + static const u8 CcxRmCapBuf[] = {0x00, 0x40, 0x96, 0x01, 0x01, + 0x00}; + struct octet_string osCcxRmCap; + + osCcxRmCap.Octet = (u8 *) CcxRmCapBuf; + osCcxRmCap.Length = sizeof(CcxRmCapBuf); + tag = skb_put(skb, ccxrm_ie_len); + *tag++ = MFIE_TYPE_GENERIC; + *tag++ = osCcxRmCap.Length; + memcpy(tag, osCcxRmCap.Octet, osCcxRmCap.Length); + tag += osCcxRmCap.Length; + } + + if (beacon->BssCcxVerNumber >= 2) { + u8 CcxVerNumBuf[] = {0x00, 0x40, 0x96, 0x03, 0x00}; + struct octet_string osCcxVerNum; + + CcxVerNumBuf[4] = beacon->BssCcxVerNumber; + osCcxVerNum.Octet = CcxVerNumBuf; + osCcxVerNum.Length = sizeof(CcxVerNumBuf); + tag = skb_put(skb, cxvernum_ie_len); + *tag++ = MFIE_TYPE_GENERIC; + *tag++ = osCcxVerNum.Length; + memcpy(tag, osCcxVerNum.Octet, osCcxVerNum.Length); + tag += osCcxVerNum.Length; + } + if (ieee->pHTInfo->bCurrentHTSupport && ieee->pHTInfo->bEnableHT) { + if (ieee->pHTInfo->ePeerHTSpecVer != HT_SPEC_VER_EWC) { + tag = skb_put(skb, ht_cap_len); + *tag++ = MFIE_TYPE_HT_CAP; + *tag++ = ht_cap_len - 2; + memcpy(tag, ht_cap_buf, ht_cap_len - 2); + tag += ht_cap_len - 2; + } + } + + if (wpa_ie_len) { + tag = skb_put(skb, ieee->wpa_ie_len); + memcpy(tag, ieee->wpa_ie, ieee->wpa_ie_len); + + if (PMKCacheIdx >= 0) { + tag = skb_put(skb, 18); + *tag = 1; + *(tag + 1) = 0; + memcpy((tag + 2), &ieee->PMKIDList[PMKCacheIdx].PMKID, + 16); + } + } + if (wmm_info_len) { + tag = skb_put(skb, wmm_info_len); + rtllib_WMM_Info(ieee, &tag); + } + + if (wps_ie_len && ieee->wps_ie) { + tag = skb_put(skb, wps_ie_len); + memcpy(tag, ieee->wps_ie, wps_ie_len); + } + + tag = skb_put(skb, turbo_info_len); + if (turbo_info_len) + rtllib_TURBO_Info(ieee, &tag); + + if (ieee->pHTInfo->bCurrentHTSupport && ieee->pHTInfo->bEnableHT) { + if (ieee->pHTInfo->ePeerHTSpecVer == HT_SPEC_VER_EWC) { + tag = skb_put(skb, ht_cap_len); + *tag++ = MFIE_TYPE_GENERIC; + *tag++ = ht_cap_len - 2; + memcpy(tag, ht_cap_buf, ht_cap_len - 2); + tag += ht_cap_len - 2; + } + + if (ieee->pHTInfo->bCurrentRT2RTAggregation) { + tag = skb_put(skb, realtek_ie_len); + *tag++ = MFIE_TYPE_GENERIC; + *tag++ = realtek_ie_len - 2; + memcpy(tag, realtek_ie_buf, realtek_ie_len - 2); + } + } + + kfree(ieee->assocreq_ies); + ieee->assocreq_ies = NULL; + ies = &(hdr->info_element[0].id); + ieee->assocreq_ies_len = (skb->data + skb->len) - ies; + ieee->assocreq_ies = kmalloc(ieee->assocreq_ies_len, GFP_ATOMIC); + if (ieee->assocreq_ies) + memcpy(ieee->assocreq_ies, ies, ieee->assocreq_ies_len); + else { + netdev_info(ieee->dev, + "%s()Warning: can't alloc memory for assocreq_ies\n", + __func__); + ieee->assocreq_ies_len = 0; + } + return skb; +} + +void rtllib_associate_abort(struct rtllib_device *ieee) +{ + unsigned long flags; + + spin_lock_irqsave(&ieee->lock, flags); + + ieee->associate_seq++; + + /* don't scan, and avoid to have the RX path possibily + * try again to associate. Even do not react to AUTH or + * ASSOC response. Just wait for the retry wq to be scheduled. + * Here we will check if there are good nets to associate + * with, so we retry or just get back to NO_LINK and scanning + */ + if (ieee->state == RTLLIB_ASSOCIATING_AUTHENTICATING) { + RTLLIB_DEBUG_MGMT("Authentication failed\n"); + ieee->softmac_stats.no_auth_rs++; + } else { + RTLLIB_DEBUG_MGMT("Association failed\n"); + ieee->softmac_stats.no_ass_rs++; + } + + ieee->state = RTLLIB_ASSOCIATING_RETRY; + + queue_delayed_work_rsl(ieee->wq, &ieee->associate_retry_wq, + RTLLIB_SOFTMAC_ASSOC_RETRY_TIME); + + spin_unlock_irqrestore(&ieee->lock, flags); +} + +static void rtllib_associate_abort_cb(unsigned long dev) +{ + rtllib_associate_abort((struct rtllib_device *) dev); +} + +static void rtllib_associate_step1(struct rtllib_device *ieee, u8 *daddr) +{ + struct rtllib_network *beacon = &ieee->current_network; + struct sk_buff *skb; + + RTLLIB_DEBUG_MGMT("Stopping scan\n"); + + ieee->softmac_stats.tx_auth_rq++; + + skb = rtllib_authentication_req(beacon, ieee, 0, daddr); + + if (!skb) + rtllib_associate_abort(ieee); + else { + ieee->state = RTLLIB_ASSOCIATING_AUTHENTICATING; + RTLLIB_DEBUG_MGMT("Sending authentication request\n"); + softmac_mgmt_xmit(skb, ieee); + if (!timer_pending(&ieee->associate_timer)) { + ieee->associate_timer.expires = jiffies + (HZ / 2); + add_timer(&ieee->associate_timer); + } + } +} + +static void rtllib_auth_challenge(struct rtllib_device *ieee, u8 *challenge, int chlen) +{ + u8 *c; + struct sk_buff *skb; + struct rtllib_network *beacon = &ieee->current_network; + + ieee->associate_seq++; + ieee->softmac_stats.tx_auth_rq++; + + skb = rtllib_authentication_req(beacon, ieee, chlen + 2, beacon->bssid); + + if (!skb) + rtllib_associate_abort(ieee); + else { + c = skb_put(skb, chlen+2); + *(c++) = MFIE_TYPE_CHALLENGE; + *(c++) = chlen; + memcpy(c, challenge, chlen); + + RTLLIB_DEBUG_MGMT("Sending authentication challenge response\n"); + + rtllib_encrypt_fragment(ieee, skb, + sizeof(struct rtllib_hdr_3addr)); + + softmac_mgmt_xmit(skb, ieee); + mod_timer(&ieee->associate_timer, jiffies + (HZ/2)); + } + kfree(challenge); +} + +static void rtllib_associate_step2(struct rtllib_device *ieee) +{ + struct sk_buff *skb; + struct rtllib_network *beacon = &ieee->current_network; + + del_timer_sync(&ieee->associate_timer); + + RTLLIB_DEBUG_MGMT("Sending association request\n"); + + ieee->softmac_stats.tx_ass_rq++; + skb = rtllib_association_req(beacon, ieee); + if (!skb) + rtllib_associate_abort(ieee); + else { + softmac_mgmt_xmit(skb, ieee); + mod_timer(&ieee->associate_timer, jiffies + (HZ/2)); + } +} + +#define CANCELLED 2 +static void rtllib_associate_complete_wq(void *data) +{ + struct rtllib_device *ieee = (struct rtllib_device *) + container_of_work_rsl(data, + struct rtllib_device, + associate_complete_wq); + struct rt_pwr_save_ctrl *pPSC = (struct rt_pwr_save_ctrl *) + (&(ieee->PowerSaveControl)); + netdev_info(ieee->dev, "Associated successfully\n"); + if (!ieee->is_silent_reset) { + netdev_info(ieee->dev, "normal associate\n"); + notify_wx_assoc_event(ieee); + } + + netif_carrier_on(ieee->dev); + ieee->is_roaming = false; + if (rtllib_is_54g(&ieee->current_network) && + (ieee->modulation & RTLLIB_OFDM_MODULATION)) { + ieee->rate = 108; + netdev_info(ieee->dev, "Using G rates:%d\n", ieee->rate); + } else { + ieee->rate = 22; + ieee->SetWirelessMode(ieee->dev, IEEE_B); + netdev_info(ieee->dev, "Using B rates:%d\n", ieee->rate); + } + if (ieee->pHTInfo->bCurrentHTSupport && ieee->pHTInfo->bEnableHT) { + netdev_info(ieee->dev, "Successfully associated, ht enabled\n"); + HTOnAssocRsp(ieee); + } else { + netdev_info(ieee->dev, + "Successfully associated, ht not enabled(%d, %d)\n", + ieee->pHTInfo->bCurrentHTSupport, + ieee->pHTInfo->bEnableHT); + memset(ieee->dot11HTOperationalRateSet, 0, 16); + } + ieee->LinkDetectInfo.SlotNum = 2 * (1 + + ieee->current_network.beacon_interval / + 500); + if (ieee->LinkDetectInfo.NumRecvBcnInPeriod == 0 || + ieee->LinkDetectInfo.NumRecvDataInPeriod == 0) { + ieee->LinkDetectInfo.NumRecvBcnInPeriod = 1; + ieee->LinkDetectInfo.NumRecvDataInPeriod = 1; + } + pPSC->LpsIdleCount = 0; + ieee->link_change(ieee->dev); + + if (ieee->is_silent_reset) { + netdev_info(ieee->dev, "silent reset associate\n"); + ieee->is_silent_reset = false; + } + + if (ieee->data_hard_resume) + ieee->data_hard_resume(ieee->dev); + +} + +static void rtllib_sta_send_associnfo(struct rtllib_device *ieee) +{ +} + +static void rtllib_associate_complete(struct rtllib_device *ieee) +{ + del_timer_sync(&ieee->associate_timer); + + ieee->state = RTLLIB_LINKED; + rtllib_sta_send_associnfo(ieee); + + queue_work_rsl(ieee->wq, &ieee->associate_complete_wq); +} + +static void rtllib_associate_procedure_wq(void *data) +{ + struct rtllib_device *ieee = container_of_dwork_rsl(data, + struct rtllib_device, + associate_procedure_wq); + rtllib_stop_scan_syncro(ieee); + if (ieee->rtllib_ips_leave != NULL) + ieee->rtllib_ips_leave(ieee->dev); + down(&ieee->wx_sem); + + if (ieee->data_hard_stop) + ieee->data_hard_stop(ieee->dev); + + rtllib_stop_scan(ieee); + RT_TRACE(COMP_DBG, "===>%s(), chan:%d\n", __func__, + ieee->current_network.channel); + HTSetConnectBwMode(ieee, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT); + if (ieee->eRFPowerState == eRfOff) { + RT_TRACE(COMP_DBG, + "=============>%s():Rf state is eRfOff, schedule ipsleave wq again,return\n", + __func__); + if (ieee->rtllib_ips_leave_wq != NULL) + ieee->rtllib_ips_leave_wq(ieee->dev); + up(&ieee->wx_sem); + return; + } + ieee->associate_seq = 1; + + rtllib_associate_step1(ieee, ieee->current_network.bssid); + + up(&ieee->wx_sem); +} + +inline void rtllib_softmac_new_net(struct rtllib_device *ieee, + struct rtllib_network *net) +{ + u8 tmp_ssid[IW_ESSID_MAX_SIZE + 1]; + int tmp_ssid_len = 0; + + short apset, ssidset, ssidbroad, apmatch, ssidmatch; + + /* we are interested in new new only if we are not associated + * and we are not associating / authenticating + */ + if (ieee->state != RTLLIB_NOLINK) + return; + + if ((ieee->iw_mode == IW_MODE_INFRA) && !(net->capability & + WLAN_CAPABILITY_ESS)) + return; + + if ((ieee->iw_mode == IW_MODE_ADHOC) && !(net->capability & + WLAN_CAPABILITY_IBSS)) + return; + + if ((ieee->iw_mode == IW_MODE_ADHOC) && + (net->channel > ieee->ibss_maxjoin_chal)) + return; + if (ieee->iw_mode == IW_MODE_INFRA || ieee->iw_mode == IW_MODE_ADHOC) { + /* if the user specified the AP MAC, we need also the essid + * This could be obtained by beacons or, if the network does not + * broadcast it, it can be put manually. + */ + apset = ieee->wap_set; + ssidset = ieee->ssid_set; + ssidbroad = !(net->ssid_len == 0 || net->ssid[0] == '\0'); + apmatch = (memcmp(ieee->current_network.bssid, net->bssid, + ETH_ALEN) == 0); + if (!ssidbroad) { + ssidmatch = (ieee->current_network.ssid_len == + net->hidden_ssid_len) && + (!strncmp(ieee->current_network.ssid, + net->hidden_ssid, net->hidden_ssid_len)); + if (net->hidden_ssid_len > 0) { + strncpy(net->ssid, net->hidden_ssid, + net->hidden_ssid_len); + net->ssid_len = net->hidden_ssid_len; + ssidbroad = 1; + } + } else + ssidmatch = + (ieee->current_network.ssid_len == net->ssid_len) && + (!strncmp(ieee->current_network.ssid, net->ssid, + net->ssid_len)); + + /* if the user set the AP check if match. + * if the network does not broadcast essid we check the + * user supplied ANY essid + * if the network does broadcast and the user does not set + * essid it is OK + * if the network does broadcast and the user did set essid + * check if essid match + * if the ap is not set, check that the user set the bssid + * and the network does broadcast and that those two bssid match + */ + if ((apset && apmatch && + ((ssidset && ssidbroad && ssidmatch) || + (ssidbroad && !ssidset) || (!ssidbroad && ssidset))) || + (!apset && ssidset && ssidbroad && ssidmatch) || + (ieee->is_roaming && ssidset && ssidbroad && ssidmatch)) { + /* if the essid is hidden replace it with the + * essid provided by the user. + */ + if (!ssidbroad) { + strncpy(tmp_ssid, ieee->current_network.ssid, + IW_ESSID_MAX_SIZE); + tmp_ssid_len = ieee->current_network.ssid_len; + } + memcpy(&ieee->current_network, net, + sizeof(struct rtllib_network)); + if (!ssidbroad) { + strncpy(ieee->current_network.ssid, tmp_ssid, + IW_ESSID_MAX_SIZE); + ieee->current_network.ssid_len = tmp_ssid_len; + } + netdev_info(ieee->dev, + "Linking with %s,channel:%d, qos:%d, myHT:%d, networkHT:%d, mode:%x cur_net.flags:0x%x\n", + ieee->current_network.ssid, + ieee->current_network.channel, + ieee->current_network.qos_data.supported, + ieee->pHTInfo->bEnableHT, + ieee->current_network.bssht.bdSupportHT, + ieee->current_network.mode, + ieee->current_network.flags); + + if ((rtllib_act_scanning(ieee, false)) && + !(ieee->softmac_features & IEEE_SOFTMAC_SCAN)) + rtllib_stop_scan_syncro(ieee); + + ieee->hwscan_ch_bk = ieee->current_network.channel; + HTResetIOTSetting(ieee->pHTInfo); + ieee->wmm_acm = 0; + if (ieee->iw_mode == IW_MODE_INFRA) { + /* Join the network for the first time */ + ieee->AsocRetryCount = 0; + if ((ieee->current_network.qos_data.supported == 1) && + ieee->current_network.bssht.bdSupportHT) + HTResetSelfAndSavePeerSetting(ieee, + &(ieee->current_network)); + else + ieee->pHTInfo->bCurrentHTSupport = + false; + + ieee->state = RTLLIB_ASSOCIATING; + if (ieee->LedControlHandler != NULL) + ieee->LedControlHandler(ieee->dev, + LED_CTL_START_TO_LINK); + queue_delayed_work_rsl(ieee->wq, + &ieee->associate_procedure_wq, 0); + } else { + if (rtllib_is_54g(&ieee->current_network) && + (ieee->modulation & RTLLIB_OFDM_MODULATION)) { + ieee->rate = 108; + ieee->SetWirelessMode(ieee->dev, IEEE_G); + netdev_info(ieee->dev, "Using G rates\n"); + } else { + ieee->rate = 22; + ieee->SetWirelessMode(ieee->dev, IEEE_B); + netdev_info(ieee->dev, "Using B rates\n"); + } + memset(ieee->dot11HTOperationalRateSet, 0, 16); + ieee->state = RTLLIB_LINKED; + } + } + } +} + +void rtllib_softmac_check_all_nets(struct rtllib_device *ieee) +{ + unsigned long flags; + struct rtllib_network *target; + + spin_lock_irqsave(&ieee->lock, flags); + + list_for_each_entry(target, &ieee->network_list, list) { + + /* if the state become different that NOLINK means + * we had found what we are searching for + */ + + if (ieee->state != RTLLIB_NOLINK) + break; + + if (ieee->scan_age == 0 || time_after(target->last_scanned + + ieee->scan_age, jiffies)) + rtllib_softmac_new_net(ieee, target); + } + spin_unlock_irqrestore(&ieee->lock, flags); +} + +static inline u16 auth_parse(struct sk_buff *skb, u8 **challenge, int *chlen) +{ + struct rtllib_authentication *a; + u8 *t; + + if (skb->len < (sizeof(struct rtllib_authentication) - + sizeof(struct rtllib_info_element))) { + RTLLIB_DEBUG_MGMT("invalid len in auth resp: %d\n", skb->len); + return 0xcafe; + } + *challenge = NULL; + a = (struct rtllib_authentication *) skb->data; + if (skb->len > (sizeof(struct rtllib_authentication) + 3)) { + t = skb->data + sizeof(struct rtllib_authentication); + + if (*(t++) == MFIE_TYPE_CHALLENGE) { + *chlen = *(t++); + *challenge = kmemdup(t, *chlen, GFP_ATOMIC); + if (!*challenge) + return -ENOMEM; + } + } + return cpu_to_le16(a->status); +} + +static int auth_rq_parse(struct sk_buff *skb, u8 *dest) +{ + struct rtllib_authentication *a; + + if (skb->len < (sizeof(struct rtllib_authentication) - + sizeof(struct rtllib_info_element))) { + RTLLIB_DEBUG_MGMT("invalid len in auth request: %d\n", + skb->len); + return -1; + } + a = (struct rtllib_authentication *) skb->data; + + memcpy(dest, a->header.addr2, ETH_ALEN); + + if (le16_to_cpu(a->algorithm) != WLAN_AUTH_OPEN) + return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; + + return WLAN_STATUS_SUCCESS; +} + +static short probe_rq_parse(struct rtllib_device *ieee, struct sk_buff *skb, + u8 *src) +{ + u8 *tag; + u8 *skbend; + u8 *ssid = NULL; + u8 ssidlen = 0; + struct rtllib_hdr_3addr *header = + (struct rtllib_hdr_3addr *) skb->data; + bool bssid_match; + + if (skb->len < sizeof(struct rtllib_hdr_3addr)) + return -1; /* corrupted */ + + bssid_match = + (memcmp(header->addr3, ieee->current_network.bssid, ETH_ALEN) != 0) && + (!is_broadcast_ether_addr(header->addr3)); + if (bssid_match) + return -1; + + memcpy(src, header->addr2, ETH_ALEN); + + skbend = (u8 *)skb->data + skb->len; + + tag = skb->data + sizeof(struct rtllib_hdr_3addr); + + while (tag + 1 < skbend) { + if (*tag == 0) { + ssid = tag + 2; + ssidlen = *(tag + 1); + break; + } + tag++; /* point to the len field */ + tag = tag + *(tag); /* point to the last data byte of the tag */ + tag++; /* point to the next tag */ + } + + if (ssidlen == 0) + return 1; + + if (!ssid) + return 1; /* ssid not found in tagged param */ + + return !strncmp(ssid, ieee->current_network.ssid, ssidlen); +} + +static int assoc_rq_parse(struct sk_buff *skb, u8 *dest) +{ + struct rtllib_assoc_request_frame *a; + + if (skb->len < (sizeof(struct rtllib_assoc_request_frame) - + sizeof(struct rtllib_info_element))) { + + RTLLIB_DEBUG_MGMT("invalid len in auth request:%d\n", skb->len); + return -1; + } + + a = (struct rtllib_assoc_request_frame *) skb->data; + + memcpy(dest, a->header.addr2, ETH_ALEN); + + return 0; +} + +static inline u16 assoc_parse(struct rtllib_device *ieee, struct sk_buff *skb, + int *aid) +{ + struct rtllib_assoc_response_frame *response_head; + u16 status_code; + + if (skb->len < sizeof(struct rtllib_assoc_response_frame)) { + RTLLIB_DEBUG_MGMT("invalid len in auth resp: %d\n", skb->len); + return 0xcafe; + } + + response_head = (struct rtllib_assoc_response_frame *) skb->data; + *aid = le16_to_cpu(response_head->aid) & 0x3fff; + + status_code = le16_to_cpu(response_head->status); + if ((status_code == WLAN_STATUS_ASSOC_DENIED_RATES || + status_code == WLAN_STATUS_CAPS_UNSUPPORTED) && + ((ieee->mode == IEEE_G) && + (ieee->current_network.mode == IEEE_N_24G) && + (ieee->AsocRetryCount++ < (RT_ASOC_RETRY_LIMIT-1)))) { + ieee->pHTInfo->IOTAction |= HT_IOT_ACT_PURE_N_MODE; + } else { + ieee->AsocRetryCount = 0; + } + + return le16_to_cpu(response_head->status); +} + +void rtllib_rx_probe_rq(struct rtllib_device *ieee, struct sk_buff *skb) +{ + u8 dest[ETH_ALEN]; + + ieee->softmac_stats.rx_probe_rq++; + if (probe_rq_parse(ieee, skb, dest) > 0) { + ieee->softmac_stats.tx_probe_rs++; + rtllib_resp_to_probe(ieee, dest); + } +} + +static inline void rtllib_rx_auth_rq(struct rtllib_device *ieee, + struct sk_buff *skb) +{ + u8 dest[ETH_ALEN]; + int status; + + ieee->softmac_stats.rx_auth_rq++; + + status = auth_rq_parse(skb, dest); + if (status != -1) + rtllib_resp_to_auth(ieee, status, dest); +} + +static inline void rtllib_rx_assoc_rq(struct rtllib_device *ieee, + struct sk_buff *skb) +{ + + u8 dest[ETH_ALEN]; + + ieee->softmac_stats.rx_ass_rq++; + if (assoc_rq_parse(skb, dest) != -1) + rtllib_resp_to_assoc_rq(ieee, dest); + + netdev_info(ieee->dev, "New client associated: %pM\n", dest); +} + +void rtllib_sta_ps_send_null_frame(struct rtllib_device *ieee, short pwr) +{ + + struct sk_buff *buf = rtllib_null_func(ieee, pwr); + + if (buf) + softmac_ps_mgmt_xmit(buf, ieee); +} +EXPORT_SYMBOL(rtllib_sta_ps_send_null_frame); + +void rtllib_sta_ps_send_pspoll_frame(struct rtllib_device *ieee) +{ + struct sk_buff *buf = rtllib_pspoll_func(ieee); + + if (buf) + softmac_ps_mgmt_xmit(buf, ieee); +} + +static short rtllib_sta_ps_sleep(struct rtllib_device *ieee, u64 *time) +{ + int timeout = ieee->ps_timeout; + u8 dtim; + struct rt_pwr_save_ctrl *pPSC = (struct rt_pwr_save_ctrl *) + (&(ieee->PowerSaveControl)); + + if (ieee->LPSDelayCnt) { + ieee->LPSDelayCnt--; + return 0; + } + + dtim = ieee->current_network.dtim_data; + if (!(dtim & RTLLIB_DTIM_VALID)) + return 0; + timeout = ieee->current_network.beacon_interval; + ieee->current_network.dtim_data = RTLLIB_DTIM_INVALID; + /* there's no need to nofity AP that I find you buffered + * with broadcast packet + */ + if (dtim & (RTLLIB_DTIM_UCAST & ieee->ps)) + return 2; + + if (!time_after(jiffies, + ieee->dev->trans_start + msecs_to_jiffies(timeout))) + return 0; + if (!time_after(jiffies, + ieee->last_rx_ps_time + msecs_to_jiffies(timeout))) + return 0; + if ((ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE) && + (ieee->mgmt_queue_tail != ieee->mgmt_queue_head)) + return 0; + + if (time) { + if (ieee->bAwakePktSent) { + pPSC->LPSAwakeIntvl = 1; + } else { + u8 MaxPeriod = 1; + + if (pPSC->LPSAwakeIntvl == 0) + pPSC->LPSAwakeIntvl = 1; + if (pPSC->RegMaxLPSAwakeIntvl == 0) + MaxPeriod = 1; + else if (pPSC->RegMaxLPSAwakeIntvl == 0xFF) + MaxPeriod = ieee->current_network.dtim_period; + else + MaxPeriod = pPSC->RegMaxLPSAwakeIntvl; + pPSC->LPSAwakeIntvl = (pPSC->LPSAwakeIntvl >= + MaxPeriod) ? MaxPeriod : + (pPSC->LPSAwakeIntvl + 1); + } + { + u8 LPSAwakeIntvl_tmp = 0; + u8 period = ieee->current_network.dtim_period; + u8 count = ieee->current_network.tim.tim_count; + + if (count == 0) { + if (pPSC->LPSAwakeIntvl > period) + LPSAwakeIntvl_tmp = period + + (pPSC->LPSAwakeIntvl - + period) - + ((pPSC->LPSAwakeIntvl-period) % + period); + else + LPSAwakeIntvl_tmp = pPSC->LPSAwakeIntvl; + + } else { + if (pPSC->LPSAwakeIntvl > + ieee->current_network.tim.tim_count) + LPSAwakeIntvl_tmp = count + + (pPSC->LPSAwakeIntvl - count) - + ((pPSC->LPSAwakeIntvl-count)%period); + else + LPSAwakeIntvl_tmp = pPSC->LPSAwakeIntvl; + } + + *time = ieee->current_network.last_dtim_sta_time + + msecs_to_jiffies(ieee->current_network.beacon_interval * + LPSAwakeIntvl_tmp); + } + } + + return 1; + + +} + +static inline void rtllib_sta_ps(struct rtllib_device *ieee) +{ + u64 time; + short sleep; + unsigned long flags, flags2; + + spin_lock_irqsave(&ieee->lock, flags); + + if ((ieee->ps == RTLLIB_PS_DISABLED || + ieee->iw_mode != IW_MODE_INFRA || + ieee->state != RTLLIB_LINKED)) { + RT_TRACE(COMP_DBG, + "=====>%s(): no need to ps,wake up!! ieee->ps is %d, ieee->iw_mode is %d, ieee->state is %d\n", + __func__, ieee->ps, ieee->iw_mode, ieee->state); + spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); + rtllib_sta_wakeup(ieee, 1); + + spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); + } + sleep = rtllib_sta_ps_sleep(ieee, &time); + /* 2 wake, 1 sleep, 0 do nothing */ + if (sleep == 0) + goto out; + if (sleep == 1) { + if (ieee->sta_sleep == LPS_IS_SLEEP) { + ieee->enter_sleep_state(ieee->dev, time); + } else if (ieee->sta_sleep == LPS_IS_WAKE) { + spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); + + if (ieee->ps_is_queue_empty(ieee->dev)) { + ieee->sta_sleep = LPS_WAIT_NULL_DATA_SEND; + ieee->ack_tx_to_ieee = 1; + rtllib_sta_ps_send_null_frame(ieee, 1); + ieee->ps_time = time; + } + spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); + + } + + ieee->bAwakePktSent = false; + + } else if (sleep == 2) { + spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); + + rtllib_sta_wakeup(ieee, 1); + + spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); + } + +out: + spin_unlock_irqrestore(&ieee->lock, flags); + +} + +void rtllib_sta_wakeup(struct rtllib_device *ieee, short nl) +{ + if (ieee->sta_sleep == LPS_IS_WAKE) { + if (nl) { + if (ieee->pHTInfo->IOTAction & + HT_IOT_ACT_NULL_DATA_POWER_SAVING) { + ieee->ack_tx_to_ieee = 1; + rtllib_sta_ps_send_null_frame(ieee, 0); + } else { + ieee->ack_tx_to_ieee = 1; + rtllib_sta_ps_send_pspoll_frame(ieee); + } + } + return; + + } + + if (ieee->sta_sleep == LPS_IS_SLEEP) + ieee->sta_wake_up(ieee->dev); + if (nl) { + if (ieee->pHTInfo->IOTAction & + HT_IOT_ACT_NULL_DATA_POWER_SAVING) { + ieee->ack_tx_to_ieee = 1; + rtllib_sta_ps_send_null_frame(ieee, 0); + } else { + ieee->ack_tx_to_ieee = 1; + ieee->polling = true; + rtllib_sta_ps_send_pspoll_frame(ieee); + } + + } else { + ieee->sta_sleep = LPS_IS_WAKE; + ieee->polling = false; + } +} + +void rtllib_ps_tx_ack(struct rtllib_device *ieee, short success) +{ + unsigned long flags, flags2; + + spin_lock_irqsave(&ieee->lock, flags); + + if (ieee->sta_sleep == LPS_WAIT_NULL_DATA_SEND) { + /* Null frame with PS bit set */ + if (success) { + ieee->sta_sleep = LPS_IS_SLEEP; + ieee->enter_sleep_state(ieee->dev, ieee->ps_time); + } + /* if the card report not success we can't be sure the AP + * has not RXed so we can't assume the AP believe us awake + */ + } else {/* 21112005 - tx again null without PS bit if lost */ + + if ((ieee->sta_sleep == LPS_IS_WAKE) && !success) { + spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); + if (ieee->pHTInfo->IOTAction & + HT_IOT_ACT_NULL_DATA_POWER_SAVING) + rtllib_sta_ps_send_null_frame(ieee, 0); + else + rtllib_sta_ps_send_pspoll_frame(ieee); + spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); + } + } + spin_unlock_irqrestore(&ieee->lock, flags); +} +EXPORT_SYMBOL(rtllib_ps_tx_ack); + +static void rtllib_process_action(struct rtllib_device *ieee, struct sk_buff *skb) +{ + struct rtllib_hdr_3addr *header = (struct rtllib_hdr_3addr *) skb->data; + u8 *act = rtllib_get_payload((struct rtllib_hdr *)header); + u8 category = 0; + + if (act == NULL) { + RTLLIB_DEBUG(RTLLIB_DL_ERR, + "error to get payload of action frame\n"); + return; + } + + category = *act; + act++; + switch (category) { + case ACT_CAT_BA: + switch (*act) { + case ACT_ADDBAREQ: + rtllib_rx_ADDBAReq(ieee, skb); + break; + case ACT_ADDBARSP: + rtllib_rx_ADDBARsp(ieee, skb); + break; + case ACT_DELBA: + rtllib_rx_DELBA(ieee, skb); + break; + } + break; + default: + break; + } +} + +inline int rtllib_rx_assoc_resp(struct rtllib_device *ieee, struct sk_buff *skb, + struct rtllib_rx_stats *rx_stats) +{ + u16 errcode; + int aid; + u8 *ies; + struct rtllib_assoc_response_frame *assoc_resp; + struct rtllib_hdr_3addr *header = (struct rtllib_hdr_3addr *) skb->data; + + RTLLIB_DEBUG_MGMT("received [RE]ASSOCIATION RESPONSE (%d)\n", + WLAN_FC_GET_STYPE(header->frame_ctl)); + + if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) && + ieee->state == RTLLIB_ASSOCIATING_AUTHENTICATED && + (ieee->iw_mode == IW_MODE_INFRA)) { + errcode = assoc_parse(ieee, skb, &aid); + if (0 == errcode) { + struct rtllib_network *network = + kzalloc(sizeof(struct rtllib_network), + GFP_ATOMIC); + + if (!network) + return 1; + ieee->state = RTLLIB_LINKED; + ieee->assoc_id = aid; + ieee->softmac_stats.rx_ass_ok++; + /* station support qos */ + /* Let the register setting default with Legacy station */ + assoc_resp = (struct rtllib_assoc_response_frame *)skb->data; + if (ieee->current_network.qos_data.supported == 1) { + if (rtllib_parse_info_param(ieee, assoc_resp->info_element, + rx_stats->len - sizeof(*assoc_resp), + network, rx_stats)) { + kfree(network); + return 1; + } + memcpy(ieee->pHTInfo->PeerHTCapBuf, + network->bssht.bdHTCapBuf, + network->bssht.bdHTCapLen); + memcpy(ieee->pHTInfo->PeerHTInfoBuf, + network->bssht.bdHTInfoBuf, + network->bssht.bdHTInfoLen); + if (ieee->handle_assoc_response != NULL) + ieee->handle_assoc_response(ieee->dev, + (struct rtllib_assoc_response_frame *)header, + network); + } + kfree(network); + + kfree(ieee->assocresp_ies); + ieee->assocresp_ies = NULL; + ies = &(assoc_resp->info_element[0].id); + ieee->assocresp_ies_len = (skb->data + skb->len) - ies; + ieee->assocresp_ies = kmalloc(ieee->assocresp_ies_len, + GFP_ATOMIC); + if (ieee->assocresp_ies) + memcpy(ieee->assocresp_ies, ies, + ieee->assocresp_ies_len); + else { + netdev_info(ieee->dev, + "%s()Warning: can't alloc memory for assocresp_ies\n", + __func__); + ieee->assocresp_ies_len = 0; + } + rtllib_associate_complete(ieee); + } else { + /* aid could not been allocated */ + ieee->softmac_stats.rx_ass_err++; + netdev_info(ieee->dev, + "Association response status code 0x%x\n", + errcode); + RTLLIB_DEBUG_MGMT( + "Association response status code 0x%x\n", + errcode); + if (ieee->AsocRetryCount < RT_ASOC_RETRY_LIMIT) + queue_delayed_work_rsl(ieee->wq, + &ieee->associate_procedure_wq, 0); + else + rtllib_associate_abort(ieee); + } + } + return 0; +} + +static void rtllib_rx_auth_resp(struct rtllib_device *ieee, struct sk_buff *skb) +{ + u16 errcode; + u8 *challenge; + int chlen = 0; + bool bSupportNmode = true, bHalfSupportNmode = false; + + errcode = auth_parse(skb, &challenge, &chlen); + + if (errcode) { + ieee->softmac_stats.rx_auth_rs_err++; + RTLLIB_DEBUG_MGMT("Authentication respose status code 0x%x", + errcode); + + netdev_info(ieee->dev, + "Authentication respose status code 0x%x", errcode); + rtllib_associate_abort(ieee); + return; + } + + if (ieee->open_wep || !challenge) { + ieee->state = RTLLIB_ASSOCIATING_AUTHENTICATED; + ieee->softmac_stats.rx_auth_rs_ok++; + if (!(ieee->pHTInfo->IOTAction & HT_IOT_ACT_PURE_N_MODE)) { + if (!ieee->GetNmodeSupportBySecCfg(ieee->dev)) { + if (IsHTHalfNmodeAPs(ieee)) { + bSupportNmode = true; + bHalfSupportNmode = true; + } else { + bSupportNmode = false; + bHalfSupportNmode = false; + } + } + } + /* Dummy wirless mode setting to avoid encryption issue */ + if (bSupportNmode) { + ieee->SetWirelessMode(ieee->dev, + ieee->current_network.mode); + } else { + /*TODO*/ + ieee->SetWirelessMode(ieee->dev, IEEE_G); + } + + if ((ieee->current_network.mode == IEEE_N_24G) && + bHalfSupportNmode) { + netdev_info(ieee->dev, "======>enter half N mode\n"); + ieee->bHalfWirelessN24GMode = true; + } else { + ieee->bHalfWirelessN24GMode = false; + } + rtllib_associate_step2(ieee); + } else { + rtllib_auth_challenge(ieee, challenge, chlen); + } +} + +inline int rtllib_rx_auth(struct rtllib_device *ieee, struct sk_buff *skb, + struct rtllib_rx_stats *rx_stats) +{ + + if (ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) { + if (ieee->state == RTLLIB_ASSOCIATING_AUTHENTICATING && + (ieee->iw_mode == IW_MODE_INFRA)) { + RTLLIB_DEBUG_MGMT("Received authentication response"); + rtllib_rx_auth_resp(ieee, skb); + } else if (ieee->iw_mode == IW_MODE_MASTER) { + rtllib_rx_auth_rq(ieee, skb); + } + } + return 0; +} + +inline int rtllib_rx_deauth(struct rtllib_device *ieee, struct sk_buff *skb) +{ + struct rtllib_hdr_3addr *header = (struct rtllib_hdr_3addr *) skb->data; + + if (memcmp(header->addr3, ieee->current_network.bssid, ETH_ALEN) != 0) + return 0; + + /* FIXME for now repeat all the association procedure + * both for disassociation and deauthentication + */ + if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) && + ieee->state == RTLLIB_LINKED && + (ieee->iw_mode == IW_MODE_INFRA)) { + netdev_info(ieee->dev, + "==========>received disassoc/deauth(%x) frame, reason code:%x\n", + WLAN_FC_GET_STYPE(header->frame_ctl), + ((struct rtllib_disassoc *)skb->data)->reason); + ieee->state = RTLLIB_ASSOCIATING; + ieee->softmac_stats.reassoc++; + ieee->is_roaming = true; + ieee->LinkDetectInfo.bBusyTraffic = false; + rtllib_disassociate(ieee); + RemovePeerTS(ieee, header->addr2); + if (ieee->LedControlHandler != NULL) + ieee->LedControlHandler(ieee->dev, + LED_CTL_START_TO_LINK); + + if (!(ieee->rtllib_ap_sec_type(ieee) & + (SEC_ALG_CCMP|SEC_ALG_TKIP))) + queue_delayed_work_rsl(ieee->wq, + &ieee->associate_procedure_wq, 5); + } + return 0; +} + +inline int rtllib_rx_frame_softmac(struct rtllib_device *ieee, + struct sk_buff *skb, + struct rtllib_rx_stats *rx_stats, u16 type, + u16 stype) +{ + struct rtllib_hdr_3addr *header = (struct rtllib_hdr_3addr *) skb->data; + + if (!ieee->proto_started) + return 0; + + switch (WLAN_FC_GET_STYPE(header->frame_ctl)) { + case RTLLIB_STYPE_ASSOC_RESP: + case RTLLIB_STYPE_REASSOC_RESP: + if (rtllib_rx_assoc_resp(ieee, skb, rx_stats) == 1) + return 1; + break; + case RTLLIB_STYPE_ASSOC_REQ: + case RTLLIB_STYPE_REASSOC_REQ: + if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) && + ieee->iw_mode == IW_MODE_MASTER) + rtllib_rx_assoc_rq(ieee, skb); + break; + case RTLLIB_STYPE_AUTH: + rtllib_rx_auth(ieee, skb, rx_stats); + break; + case RTLLIB_STYPE_DISASSOC: + case RTLLIB_STYPE_DEAUTH: + rtllib_rx_deauth(ieee, skb); + break; + case RTLLIB_STYPE_MANAGE_ACT: + rtllib_process_action(ieee, skb); + break; + default: + return -1; + } + return 0; +} + +/* following are for a simpler TX queue management. + * Instead of using netif_[stop/wake]_queue the driver + * will use these two functions (plus a reset one), that + * will internally use the kernel netif_* and takes + * care of the ieee802.11 fragmentation. + * So the driver receives a fragment per time and might + * call the stop function when it wants to not + * have enough room to TX an entire packet. + * This might be useful if each fragment needs it's own + * descriptor, thus just keep a total free memory > than + * the max fragmentation threshold is not enough.. If the + * ieee802.11 stack passed a TXB struct then you need + * to keep N free descriptors where + * N = MAX_PACKET_SIZE / MIN_FRAG_TRESHOLD + * In this way you need just one and the 802.11 stack + * will take care of buffering fragments and pass them to + * to the driver later, when it wakes the queue. + */ +void rtllib_softmac_xmit(struct rtllib_txb *txb, struct rtllib_device *ieee) +{ + + unsigned int queue_index = txb->queue_index; + unsigned long flags; + int i; + struct cb_desc *tcb_desc = NULL; + unsigned long queue_len = 0; + + spin_lock_irqsave(&ieee->lock, flags); + + /* called with 2nd parm 0, no tx mgmt lock required */ + rtllib_sta_wakeup(ieee, 0); + + /* update the tx status */ + tcb_desc = (struct cb_desc *)(txb->fragments[0]->cb + + MAX_DEV_ADDR_SIZE); + if (tcb_desc->bMulticast) + ieee->stats.multicast++; + + /* if xmit available, just xmit it immediately, else just insert it to + * the wait queue + */ + for (i = 0; i < txb->nr_frags; i++) { + queue_len = skb_queue_len(&ieee->skb_waitQ[queue_index]); + if ((queue_len != 0) || + (!ieee->check_nic_enough_desc(ieee->dev, queue_index)) || + (ieee->queue_stop)) { + /* insert the skb packet to the wait queue + * as for the completion function, it does not need + * to check it any more. + */ + if (queue_len < 200) + skb_queue_tail(&ieee->skb_waitQ[queue_index], + txb->fragments[i]); + else + kfree_skb(txb->fragments[i]); + } else { + ieee->softmac_data_hard_start_xmit( + txb->fragments[i], + ieee->dev, ieee->rate); + } + } + + rtllib_txb_free(txb); + + spin_unlock_irqrestore(&ieee->lock, flags); + +} + +/* called with ieee->lock acquired */ +static void rtllib_resume_tx(struct rtllib_device *ieee) +{ + int i; + + for (i = ieee->tx_pending.frag; i < ieee->tx_pending.txb->nr_frags; + i++) { + + if (ieee->queue_stop) { + ieee->tx_pending.frag = i; + return; + } + + ieee->softmac_data_hard_start_xmit( + ieee->tx_pending.txb->fragments[i], + ieee->dev, ieee->rate); + ieee->stats.tx_packets++; + } + + rtllib_txb_free(ieee->tx_pending.txb); + ieee->tx_pending.txb = NULL; +} + + +void rtllib_reset_queue(struct rtllib_device *ieee) +{ + unsigned long flags; + + spin_lock_irqsave(&ieee->lock, flags); + init_mgmt_queue(ieee); + if (ieee->tx_pending.txb) { + rtllib_txb_free(ieee->tx_pending.txb); + ieee->tx_pending.txb = NULL; + } + ieee->queue_stop = 0; + spin_unlock_irqrestore(&ieee->lock, flags); + +} +EXPORT_SYMBOL(rtllib_reset_queue); + +void rtllib_wake_queue(struct rtllib_device *ieee) +{ + + unsigned long flags; + struct sk_buff *skb; + struct rtllib_hdr_3addr *header; + + spin_lock_irqsave(&ieee->lock, flags); + if (!ieee->queue_stop) + goto exit; + + ieee->queue_stop = 0; + + if (ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE) { + while (!ieee->queue_stop && (skb = dequeue_mgmt(ieee))) { + + header = (struct rtllib_hdr_3addr *) skb->data; + + header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); + + if (ieee->seq_ctrl[0] == 0xFFF) + ieee->seq_ctrl[0] = 0; + else + ieee->seq_ctrl[0]++; + + ieee->softmac_data_hard_start_xmit(skb, ieee->dev, + ieee->basic_rate); + } + } + if (!ieee->queue_stop && ieee->tx_pending.txb) + rtllib_resume_tx(ieee); + + if (!ieee->queue_stop && netif_queue_stopped(ieee->dev)) { + ieee->softmac_stats.swtxawake++; + netif_wake_queue(ieee->dev); + } + +exit: + spin_unlock_irqrestore(&ieee->lock, flags); +} + + +void rtllib_stop_queue(struct rtllib_device *ieee) +{ + + if (!netif_queue_stopped(ieee->dev)) { + netif_stop_queue(ieee->dev); + ieee->softmac_stats.swtxstop++; + } + ieee->queue_stop = 1; + +} + +void rtllib_stop_all_queues(struct rtllib_device *ieee) +{ + unsigned int i; + + for (i = 0; i < ieee->dev->num_tx_queues; i++) + netdev_get_tx_queue(ieee->dev, i)->trans_start = jiffies; + + netif_tx_stop_all_queues(ieee->dev); +} + +void rtllib_wake_all_queues(struct rtllib_device *ieee) +{ + netif_tx_wake_all_queues(ieee->dev); +} + +inline void rtllib_randomize_cell(struct rtllib_device *ieee) +{ + + random_ether_addr(ieee->current_network.bssid); +} + +/* called in user context only */ +void rtllib_start_master_bss(struct rtllib_device *ieee) +{ + ieee->assoc_id = 1; + + if (ieee->current_network.ssid_len == 0) { + strncpy(ieee->current_network.ssid, + RTLLIB_DEFAULT_TX_ESSID, + IW_ESSID_MAX_SIZE); + + ieee->current_network.ssid_len = + strlen(RTLLIB_DEFAULT_TX_ESSID); + ieee->ssid_set = 1; + } + + memcpy(ieee->current_network.bssid, ieee->dev->dev_addr, ETH_ALEN); + + ieee->set_chan(ieee->dev, ieee->current_network.channel); + ieee->state = RTLLIB_LINKED; + ieee->link_change(ieee->dev); + notify_wx_assoc_event(ieee); + + if (ieee->data_hard_resume) + ieee->data_hard_resume(ieee->dev); + + netif_carrier_on(ieee->dev); +} + +static void rtllib_start_monitor_mode(struct rtllib_device *ieee) +{ + /* reset hardware status */ + if (ieee->raw_tx) { + if (ieee->data_hard_resume) + ieee->data_hard_resume(ieee->dev); + + netif_carrier_on(ieee->dev); + } +} + +static void rtllib_start_ibss_wq(void *data) +{ + struct rtllib_device *ieee = container_of_dwork_rsl(data, + struct rtllib_device, start_ibss_wq); + /* iwconfig mode ad-hoc will schedule this and return + * on the other hand this will block further iwconfig SET + * operations because of the wx_sem hold. + * Anyway some most set operations set a flag to speed-up + * (abort) this wq (when syncro scanning) before sleeping + * on the semaphore + */ + if (!ieee->proto_started) { + netdev_info(ieee->dev, "==========oh driver down return\n"); + return; + } + down(&ieee->wx_sem); + + if (ieee->current_network.ssid_len == 0) { + strcpy(ieee->current_network.ssid, RTLLIB_DEFAULT_TX_ESSID); + ieee->current_network.ssid_len = strlen(RTLLIB_DEFAULT_TX_ESSID); + ieee->ssid_set = 1; + } + + ieee->state = RTLLIB_NOLINK; + ieee->mode = IEEE_G; + /* check if we have this cell in our network list */ + rtllib_softmac_check_all_nets(ieee); + + + /* if not then the state is not linked. Maybe the user switched to + * ad-hoc mode just after being in monitor mode, or just after + * being very few time in managed mode (so the card have had no + * time to scan all the chans..) or we have just run up the iface + * after setting ad-hoc mode. So we have to give another try.. + * Here, in ibss mode, should be safe to do this without extra care + * (in bss mode we had to make sure no-one tried to associate when + * we had just checked the ieee->state and we was going to start the + * scan) because in ibss mode the rtllib_new_net function, when + * finds a good net, just set the ieee->state to RTLLIB_LINKED, + * so, at worst, we waste a bit of time to initiate an unneeded syncro + * scan, that will stop at the first round because it sees the state + * associated. + */ + if (ieee->state == RTLLIB_NOLINK) + rtllib_start_scan_syncro(ieee, 0); + + /* the network definitively is not here.. create a new cell */ + if (ieee->state == RTLLIB_NOLINK) { + netdev_info(ieee->dev, "creating new IBSS cell\n"); + ieee->current_network.channel = ieee->IbssStartChnl; + if (!ieee->wap_set) + rtllib_randomize_cell(ieee); + + if (ieee->modulation & RTLLIB_CCK_MODULATION) { + + ieee->current_network.rates_len = 4; + + ieee->current_network.rates[0] = + RTLLIB_BASIC_RATE_MASK | RTLLIB_CCK_RATE_1MB; + ieee->current_network.rates[1] = + RTLLIB_BASIC_RATE_MASK | RTLLIB_CCK_RATE_2MB; + ieee->current_network.rates[2] = + RTLLIB_BASIC_RATE_MASK | RTLLIB_CCK_RATE_5MB; + ieee->current_network.rates[3] = + RTLLIB_BASIC_RATE_MASK | RTLLIB_CCK_RATE_11MB; + + } else + ieee->current_network.rates_len = 0; + + if (ieee->modulation & RTLLIB_OFDM_MODULATION) { + ieee->current_network.rates_ex_len = 8; + + ieee->current_network.rates_ex[0] = + RTLLIB_OFDM_RATE_6MB; + ieee->current_network.rates_ex[1] = + RTLLIB_OFDM_RATE_9MB; + ieee->current_network.rates_ex[2] = + RTLLIB_OFDM_RATE_12MB; + ieee->current_network.rates_ex[3] = + RTLLIB_OFDM_RATE_18MB; + ieee->current_network.rates_ex[4] = + RTLLIB_OFDM_RATE_24MB; + ieee->current_network.rates_ex[5] = + RTLLIB_OFDM_RATE_36MB; + ieee->current_network.rates_ex[6] = + RTLLIB_OFDM_RATE_48MB; + ieee->current_network.rates_ex[7] = + RTLLIB_OFDM_RATE_54MB; + + ieee->rate = 108; + } else { + ieee->current_network.rates_ex_len = 0; + ieee->rate = 22; + } + + ieee->current_network.qos_data.supported = 0; + ieee->SetWirelessMode(ieee->dev, IEEE_G); + ieee->current_network.mode = ieee->mode; + ieee->current_network.atim_window = 0; + ieee->current_network.capability = WLAN_CAPABILITY_IBSS; + } + + netdev_info(ieee->dev, "%s(): ieee->mode = %d\n", __func__, ieee->mode); + if ((ieee->mode == IEEE_N_24G) || (ieee->mode == IEEE_N_5G)) + HTUseDefaultSetting(ieee); + else + ieee->pHTInfo->bCurrentHTSupport = false; + + ieee->SetHwRegHandler(ieee->dev, HW_VAR_MEDIA_STATUS, + (u8 *)(&ieee->state)); + + ieee->state = RTLLIB_LINKED; + ieee->link_change(ieee->dev); + + HTSetConnectBwMode(ieee, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT); + if (ieee->LedControlHandler != NULL) + ieee->LedControlHandler(ieee->dev, LED_CTL_LINK); + + rtllib_start_send_beacons(ieee); + + notify_wx_assoc_event(ieee); + + if (ieee->data_hard_resume) + ieee->data_hard_resume(ieee->dev); + + netif_carrier_on(ieee->dev); + + up(&ieee->wx_sem); +} + +inline void rtllib_start_ibss(struct rtllib_device *ieee) +{ + queue_delayed_work_rsl(ieee->wq, &ieee->start_ibss_wq, + msecs_to_jiffies(150)); +} + +/* this is called only in user context, with wx_sem held */ +void rtllib_start_bss(struct rtllib_device *ieee) +{ + unsigned long flags; + + if (IS_DOT11D_ENABLE(ieee) && !IS_COUNTRY_IE_VALID(ieee)) { + if (!ieee->bGlobalDomain) + return; + } + /* check if we have already found the net we + * are interested in (if any). + * if not (we are disassociated and we are not + * in associating / authenticating phase) start the background scanning. + */ + rtllib_softmac_check_all_nets(ieee); + + /* ensure no-one start an associating process (thus setting + * the ieee->state to rtllib_ASSOCIATING) while we + * have just checked it and we are going to enable scan. + * The rtllib_new_net function is always called with + * lock held (from both rtllib_softmac_check_all_nets and + * the rx path), so we cannot be in the middle of such function + */ + spin_lock_irqsave(&ieee->lock, flags); + + if (ieee->state == RTLLIB_NOLINK) + rtllib_start_scan(ieee); + spin_unlock_irqrestore(&ieee->lock, flags); +} + +static void rtllib_link_change_wq(void *data) +{ + struct rtllib_device *ieee = container_of_dwork_rsl(data, + struct rtllib_device, link_change_wq); + ieee->link_change(ieee->dev); +} +/* called only in userspace context */ +void rtllib_disassociate(struct rtllib_device *ieee) +{ + netif_carrier_off(ieee->dev); + if (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE) + rtllib_reset_queue(ieee); + + if (ieee->data_hard_stop) + ieee->data_hard_stop(ieee->dev); + if (IS_DOT11D_ENABLE(ieee)) + Dot11d_Reset(ieee); + ieee->state = RTLLIB_NOLINK; + ieee->is_set_key = false; + ieee->wap_set = 0; + + queue_delayed_work_rsl(ieee->wq, &ieee->link_change_wq, 0); + + notify_wx_assoc_event(ieee); +} + +static void rtllib_associate_retry_wq(void *data) +{ + struct rtllib_device *ieee = container_of_dwork_rsl(data, + struct rtllib_device, associate_retry_wq); + unsigned long flags; + + down(&ieee->wx_sem); + if (!ieee->proto_started) + goto exit; + + if (ieee->state != RTLLIB_ASSOCIATING_RETRY) + goto exit; + + /* until we do not set the state to RTLLIB_NOLINK + * there are no possibility to have someone else trying + * to start an association procedure (we get here with + * ieee->state = RTLLIB_ASSOCIATING). + * When we set the state to RTLLIB_NOLINK it is possible + * that the RX path run an attempt to associate, but + * both rtllib_softmac_check_all_nets and the + * RX path works with ieee->lock held so there are no + * problems. If we are still disassociated then start a scan. + * the lock here is necessary to ensure no one try to start + * an association procedure when we have just checked the + * state and we are going to start the scan. + */ + ieee->beinretry = true; + ieee->state = RTLLIB_NOLINK; + + rtllib_softmac_check_all_nets(ieee); + + spin_lock_irqsave(&ieee->lock, flags); + + if (ieee->state == RTLLIB_NOLINK) + rtllib_start_scan(ieee); + spin_unlock_irqrestore(&ieee->lock, flags); + + ieee->beinretry = false; +exit: + up(&ieee->wx_sem); +} + +struct sk_buff *rtllib_get_beacon_(struct rtllib_device *ieee) +{ + u8 broadcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + struct sk_buff *skb; + struct rtllib_probe_response *b; + + skb = rtllib_probe_resp(ieee, broadcast_addr); + + if (!skb) + return NULL; + + b = (struct rtllib_probe_response *) skb->data; + b->header.frame_ctl = cpu_to_le16(RTLLIB_STYPE_BEACON); + + return skb; + +} + +struct sk_buff *rtllib_get_beacon(struct rtllib_device *ieee) +{ + struct sk_buff *skb; + struct rtllib_probe_response *b; + + skb = rtllib_get_beacon_(ieee); + if (!skb) + return NULL; + + b = (struct rtllib_probe_response *) skb->data; + b->header.seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); + + if (ieee->seq_ctrl[0] == 0xFFF) + ieee->seq_ctrl[0] = 0; + else + ieee->seq_ctrl[0]++; + + return skb; +} +EXPORT_SYMBOL(rtllib_get_beacon); + +void rtllib_softmac_stop_protocol(struct rtllib_device *ieee, u8 mesh_flag, + u8 shutdown) +{ + rtllib_stop_scan_syncro(ieee); + down(&ieee->wx_sem); + rtllib_stop_protocol(ieee, shutdown); + up(&ieee->wx_sem); +} +EXPORT_SYMBOL(rtllib_softmac_stop_protocol); + + +void rtllib_stop_protocol(struct rtllib_device *ieee, u8 shutdown) +{ + if (!ieee->proto_started) + return; + + if (shutdown) { + ieee->proto_started = 0; + ieee->proto_stoppping = 1; + if (ieee->rtllib_ips_leave != NULL) + ieee->rtllib_ips_leave(ieee->dev); + } + + rtllib_stop_send_beacons(ieee); + del_timer_sync(&ieee->associate_timer); + cancel_delayed_work(&ieee->associate_retry_wq); + cancel_delayed_work(&ieee->start_ibss_wq); + cancel_delayed_work(&ieee->link_change_wq); + rtllib_stop_scan(ieee); + + if (ieee->state <= RTLLIB_ASSOCIATING_AUTHENTICATED) + ieee->state = RTLLIB_NOLINK; + + if (ieee->state == RTLLIB_LINKED) { + if (ieee->iw_mode == IW_MODE_INFRA) + SendDisassociation(ieee, 1, deauth_lv_ss); + rtllib_disassociate(ieee); + } + + if (shutdown) { + RemoveAllTS(ieee); + ieee->proto_stoppping = 0; + } + kfree(ieee->assocreq_ies); + ieee->assocreq_ies = NULL; + ieee->assocreq_ies_len = 0; + kfree(ieee->assocresp_ies); + ieee->assocresp_ies = NULL; + ieee->assocresp_ies_len = 0; +} + +void rtllib_softmac_start_protocol(struct rtllib_device *ieee, u8 mesh_flag) +{ + down(&ieee->wx_sem); + rtllib_start_protocol(ieee); + up(&ieee->wx_sem); +} +EXPORT_SYMBOL(rtllib_softmac_start_protocol); + +void rtllib_start_protocol(struct rtllib_device *ieee) +{ + short ch = 0; + int i = 0; + + rtllib_update_active_chan_map(ieee); + + if (ieee->proto_started) + return; + + ieee->proto_started = 1; + + if (ieee->current_network.channel == 0) { + do { + ch++; + if (ch > MAX_CHANNEL_NUMBER) + return; /* no channel found */ + } while (!ieee->active_channel_map[ch]); + ieee->current_network.channel = ch; + } + + if (ieee->current_network.beacon_interval == 0) + ieee->current_network.beacon_interval = 100; + + for (i = 0; i < 17; i++) { + ieee->last_rxseq_num[i] = -1; + ieee->last_rxfrag_num[i] = -1; + ieee->last_packet_time[i] = 0; + } + + if (ieee->UpdateBeaconInterruptHandler) + ieee->UpdateBeaconInterruptHandler(ieee->dev, false); + + ieee->wmm_acm = 0; + /* if the user set the MAC of the ad-hoc cell and then + * switch to managed mode, shall we make sure that association + * attempts does not fail just because the user provide the essid + * and the nic is still checking for the AP MAC ?? + */ + if (ieee->iw_mode == IW_MODE_INFRA) { + rtllib_start_bss(ieee); + } else if (ieee->iw_mode == IW_MODE_ADHOC) { + if (ieee->UpdateBeaconInterruptHandler) + ieee->UpdateBeaconInterruptHandler(ieee->dev, true); + + rtllib_start_ibss(ieee); + + } else if (ieee->iw_mode == IW_MODE_MASTER) { + rtllib_start_master_bss(ieee); + } else if (ieee->iw_mode == IW_MODE_MONITOR) { + rtllib_start_monitor_mode(ieee); + } +} + +void rtllib_softmac_init(struct rtllib_device *ieee) +{ + int i; + + memset(&ieee->current_network, 0, sizeof(struct rtllib_network)); + + ieee->state = RTLLIB_NOLINK; + for (i = 0; i < 5; i++) + ieee->seq_ctrl[i] = 0; + ieee->pDot11dInfo = kzalloc(sizeof(struct rt_dot11d_info), GFP_ATOMIC); + if (!ieee->pDot11dInfo) + RTLLIB_DEBUG(RTLLIB_DL_ERR, "can't alloc memory for DOT11D\n"); + ieee->LinkDetectInfo.SlotIndex = 0; + ieee->LinkDetectInfo.SlotNum = 2; + ieee->LinkDetectInfo.NumRecvBcnInPeriod = 0; + ieee->LinkDetectInfo.NumRecvDataInPeriod = 0; + ieee->LinkDetectInfo.NumTxOkInPeriod = 0; + ieee->LinkDetectInfo.NumRxOkInPeriod = 0; + ieee->LinkDetectInfo.NumRxUnicastOkInPeriod = 0; + ieee->bIsAggregateFrame = false; + ieee->assoc_id = 0; + ieee->queue_stop = 0; + ieee->scanning_continue = 0; + ieee->softmac_features = 0; + ieee->wap_set = 0; + ieee->ssid_set = 0; + ieee->proto_started = 0; + ieee->proto_stoppping = 0; + ieee->basic_rate = RTLLIB_DEFAULT_BASIC_RATE; + ieee->rate = 22; + ieee->ps = RTLLIB_PS_DISABLED; + ieee->sta_sleep = LPS_IS_WAKE; + + ieee->Regdot11HTOperationalRateSet[0] = 0xff; + ieee->Regdot11HTOperationalRateSet[1] = 0xff; + ieee->Regdot11HTOperationalRateSet[4] = 0x01; + + ieee->Regdot11TxHTOperationalRateSet[0] = 0xff; + ieee->Regdot11TxHTOperationalRateSet[1] = 0xff; + ieee->Regdot11TxHTOperationalRateSet[4] = 0x01; + + ieee->FirstIe_InScan = false; + ieee->actscanning = false; + ieee->beinretry = false; + ieee->is_set_key = false; + init_mgmt_queue(ieee); + + ieee->sta_edca_param[0] = 0x0000A403; + ieee->sta_edca_param[1] = 0x0000A427; + ieee->sta_edca_param[2] = 0x005E4342; + ieee->sta_edca_param[3] = 0x002F3262; + ieee->aggregation = true; + ieee->enable_rx_imm_BA = true; + ieee->tx_pending.txb = NULL; + + _setup_timer(&ieee->associate_timer, + rtllib_associate_abort_cb, + (unsigned long) ieee); + + _setup_timer(&ieee->beacon_timer, + rtllib_send_beacon_cb, + (unsigned long) ieee); + + + ieee->wq = create_workqueue(DRV_NAME); + + INIT_DELAYED_WORK_RSL(&ieee->link_change_wq, + (void *)rtllib_link_change_wq, ieee); + INIT_DELAYED_WORK_RSL(&ieee->start_ibss_wq, + (void *)rtllib_start_ibss_wq, ieee); + INIT_WORK_RSL(&ieee->associate_complete_wq, + (void *)rtllib_associate_complete_wq, ieee); + INIT_DELAYED_WORK_RSL(&ieee->associate_procedure_wq, + (void *)rtllib_associate_procedure_wq, ieee); + INIT_DELAYED_WORK_RSL(&ieee->softmac_scan_wq, + (void *)rtllib_softmac_scan_wq, ieee); + INIT_DELAYED_WORK_RSL(&ieee->softmac_hint11d_wq, + (void *)rtllib_softmac_hint11d_wq, ieee); + INIT_DELAYED_WORK_RSL(&ieee->associate_retry_wq, + (void *)rtllib_associate_retry_wq, ieee); + INIT_WORK_RSL(&ieee->wx_sync_scan_wq, (void *)rtllib_wx_sync_scan_wq, + ieee); + + sema_init(&ieee->wx_sem, 1); + sema_init(&ieee->scan_sem, 1); + sema_init(&ieee->ips_sem, 1); + + spin_lock_init(&ieee->mgmt_tx_lock); + spin_lock_init(&ieee->beacon_lock); + + tasklet_init(&ieee->ps_task, + (void(*)(unsigned long)) rtllib_sta_ps, + (unsigned long)ieee); + +} + +void rtllib_softmac_free(struct rtllib_device *ieee) +{ + down(&ieee->wx_sem); + kfree(ieee->pDot11dInfo); + ieee->pDot11dInfo = NULL; + del_timer_sync(&ieee->associate_timer); + + cancel_delayed_work(&ieee->associate_retry_wq); + destroy_workqueue(ieee->wq); + up(&ieee->wx_sem); + tasklet_kill(&ieee->ps_task); +} + +/******************************************************** + * Start of WPA code. * + * this is stolen from the ipw2200 driver * + ********************************************************/ + + +static int rtllib_wpa_enable(struct rtllib_device *ieee, int value) +{ + /* This is called when wpa_supplicant loads and closes the driver + * interface. + */ + netdev_info(ieee->dev, "%s WPA\n", value ? "enabling" : "disabling"); + ieee->wpa_enabled = value; + memset(ieee->ap_mac_addr, 0, 6); + return 0; +} + + +static void rtllib_wpa_assoc_frame(struct rtllib_device *ieee, char *wpa_ie, + int wpa_ie_len) +{ + /* make sure WPA is enabled */ + rtllib_wpa_enable(ieee, 1); + + rtllib_disassociate(ieee); +} + + +static int rtllib_wpa_mlme(struct rtllib_device *ieee, int command, int reason) +{ + + int ret = 0; + + switch (command) { + case IEEE_MLME_STA_DEAUTH: + break; + + case IEEE_MLME_STA_DISASSOC: + rtllib_disassociate(ieee); + break; + + default: + netdev_info(ieee->dev, "Unknown MLME request: %d\n", command); + ret = -EOPNOTSUPP; + } + + return ret; +} + + +static int rtllib_wpa_set_wpa_ie(struct rtllib_device *ieee, + struct ieee_param *param, int plen) +{ + u8 *buf; + + if (param->u.wpa_ie.len > MAX_WPA_IE_LEN || + (param->u.wpa_ie.len && param->u.wpa_ie.data == NULL)) + return -EINVAL; + + if (param->u.wpa_ie.len) { + buf = kmemdup(param->u.wpa_ie.data, param->u.wpa_ie.len, + GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + kfree(ieee->wpa_ie); + ieee->wpa_ie = buf; + ieee->wpa_ie_len = param->u.wpa_ie.len; + } else { + kfree(ieee->wpa_ie); + ieee->wpa_ie = NULL; + ieee->wpa_ie_len = 0; + } + + rtllib_wpa_assoc_frame(ieee, ieee->wpa_ie, ieee->wpa_ie_len); + return 0; +} + +#define AUTH_ALG_OPEN_SYSTEM 0x1 +#define AUTH_ALG_SHARED_KEY 0x2 +#define AUTH_ALG_LEAP 0x4 +static int rtllib_wpa_set_auth_algs(struct rtllib_device *ieee, int value) +{ + + struct rtllib_security sec = { + .flags = SEC_AUTH_MODE, + }; + + if (value & AUTH_ALG_SHARED_KEY) { + sec.auth_mode = WLAN_AUTH_SHARED_KEY; + ieee->open_wep = 0; + ieee->auth_mode = 1; + } else if (value & AUTH_ALG_OPEN_SYSTEM) { + sec.auth_mode = WLAN_AUTH_OPEN; + ieee->open_wep = 1; + ieee->auth_mode = 0; + } else if (value & AUTH_ALG_LEAP) { + sec.auth_mode = WLAN_AUTH_LEAP >> 6; + ieee->open_wep = 1; + ieee->auth_mode = 2; + } + + + if (ieee->set_security) + ieee->set_security(ieee->dev, &sec); + + return 0; +} + +static int rtllib_wpa_set_param(struct rtllib_device *ieee, u8 name, u32 value) +{ + int ret = 0; + unsigned long flags; + + switch (name) { + case IEEE_PARAM_WPA_ENABLED: + ret = rtllib_wpa_enable(ieee, value); + break; + + case IEEE_PARAM_TKIP_COUNTERMEASURES: + ieee->tkip_countermeasures = value; + break; + + case IEEE_PARAM_DROP_UNENCRYPTED: + { + /* HACK: + * + * wpa_supplicant calls set_wpa_enabled when the driver + * is loaded and unloaded, regardless of if WPA is being + * used. No other calls are made which can be used to + * determine if encryption will be used or not prior to + * association being expected. If encryption is not being + * used, drop_unencrypted is set to false, else true -- we + * can use this to determine if the CAP_PRIVACY_ON bit should + * be set. + */ + struct rtllib_security sec = { + .flags = SEC_ENABLED, + .enabled = value, + }; + ieee->drop_unencrypted = value; + /* We only change SEC_LEVEL for open mode. Others + * are set by ipw_wpa_set_encryption. + */ + if (!value) { + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_0; + } else { + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_1; + } + if (ieee->set_security) + ieee->set_security(ieee->dev, &sec); + break; + } + + case IEEE_PARAM_PRIVACY_INVOKED: + ieee->privacy_invoked = value; + break; + + case IEEE_PARAM_AUTH_ALGS: + ret = rtllib_wpa_set_auth_algs(ieee, value); + break; + + case IEEE_PARAM_IEEE_802_1X: + ieee->ieee802_1x = value; + break; + case IEEE_PARAM_WPAX_SELECT: + spin_lock_irqsave(&ieee->wpax_suitlist_lock, flags); + spin_unlock_irqrestore(&ieee->wpax_suitlist_lock, flags); + break; + + default: + netdev_info(ieee->dev, "Unknown WPA param: %d\n", name); + ret = -EOPNOTSUPP; + } + + return ret; +} + +/* implementation borrowed from hostap driver */ +static int rtllib_wpa_set_encryption(struct rtllib_device *ieee, + struct ieee_param *param, int param_len, + u8 is_mesh) +{ + int ret = 0; + struct lib80211_crypto_ops *ops; + struct lib80211_crypt_data **crypt; + + struct rtllib_security sec = { + .flags = 0, + }; + + param->u.crypt.err = 0; + param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0'; + + if (param_len != + (int) ((char *) param->u.crypt.key - (char *) param) + + param->u.crypt.key_len) { + netdev_info(ieee->dev, "Len mismatch %d, %d\n", param_len, + param->u.crypt.key_len); + return -EINVAL; + } + if (is_broadcast_ether_addr(param->sta_addr)) { + if (param->u.crypt.idx >= NUM_WEP_KEYS) + return -EINVAL; + crypt = &ieee->crypt_info.crypt[param->u.crypt.idx]; + } else { + return -EINVAL; + } + + if (strcmp(param->u.crypt.alg, "none") == 0) { + if (crypt) { + sec.enabled = 0; + sec.level = SEC_LEVEL_0; + sec.flags |= SEC_ENABLED | SEC_LEVEL; + lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); + } + goto done; + } + sec.enabled = 1; + sec.flags |= SEC_ENABLED; + + /* IPW HW cannot build TKIP MIC, host decryption still needed. */ + if (!(ieee->host_encrypt || ieee->host_decrypt) && + strcmp(param->u.crypt.alg, "R-TKIP")) + goto skip_host_crypt; + + ops = lib80211_get_crypto_ops(param->u.crypt.alg); + if (ops == NULL && strcmp(param->u.crypt.alg, "R-WEP") == 0) { + request_module("rtllib_crypt_wep"); + ops = lib80211_get_crypto_ops(param->u.crypt.alg); + } else if (ops == NULL && strcmp(param->u.crypt.alg, "R-TKIP") == 0) { + request_module("rtllib_crypt_tkip"); + ops = lib80211_get_crypto_ops(param->u.crypt.alg); + } else if (ops == NULL && strcmp(param->u.crypt.alg, "R-CCMP") == 0) { + request_module("rtllib_crypt_ccmp"); + ops = lib80211_get_crypto_ops(param->u.crypt.alg); + } + if (ops == NULL) { + netdev_info(ieee->dev, "unknown crypto alg '%s'\n", + param->u.crypt.alg); + param->u.crypt.err = IEEE_CRYPT_ERR_UNKNOWN_ALG; + ret = -EINVAL; + goto done; + } + if (*crypt == NULL || (*crypt)->ops != ops) { + struct lib80211_crypt_data *new_crypt; + + lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); + + new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL); + if (new_crypt == NULL) { + ret = -ENOMEM; + goto done; + } + new_crypt->ops = ops; + if (new_crypt->ops) + new_crypt->priv = + new_crypt->ops->init(param->u.crypt.idx); + + if (new_crypt->priv == NULL) { + kfree(new_crypt); + param->u.crypt.err = IEEE_CRYPT_ERR_CRYPT_INIT_FAILED; + ret = -EINVAL; + goto done; + } + + *crypt = new_crypt; + } + + if (param->u.crypt.key_len > 0 && (*crypt)->ops->set_key && + (*crypt)->ops->set_key(param->u.crypt.key, + param->u.crypt.key_len, param->u.crypt.seq, + (*crypt)->priv) < 0) { + netdev_info(ieee->dev, "key setting failed\n"); + param->u.crypt.err = IEEE_CRYPT_ERR_KEY_SET_FAILED; + ret = -EINVAL; + goto done; + } + + skip_host_crypt: + if (param->u.crypt.set_tx) { + ieee->crypt_info.tx_keyidx = param->u.crypt.idx; + sec.active_key = param->u.crypt.idx; + sec.flags |= SEC_ACTIVE_KEY; + } else + sec.flags &= ~SEC_ACTIVE_KEY; + + if (param->u.crypt.alg != NULL) { + memcpy(sec.keys[param->u.crypt.idx], + param->u.crypt.key, + param->u.crypt.key_len); + sec.key_sizes[param->u.crypt.idx] = param->u.crypt.key_len; + sec.flags |= (1 << param->u.crypt.idx); + + if (strcmp(param->u.crypt.alg, "R-WEP") == 0) { + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_1; + } else if (strcmp(param->u.crypt.alg, "R-TKIP") == 0) { + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_2; + } else if (strcmp(param->u.crypt.alg, "R-CCMP") == 0) { + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_3; + } + } + done: + if (ieee->set_security) + ieee->set_security(ieee->dev, &sec); + + /* Do not reset port if card is in Managed mode since resetting will + * generate new IEEE 802.11 authentication which may end up in looping + * with IEEE 802.1X. If your hardware requires a reset after WEP + * configuration (for example... Prism2), implement the reset_port in + * the callbacks structures used to initialize the 802.11 stack. + */ + if (ieee->reset_on_keychange && + ieee->iw_mode != IW_MODE_INFRA && + ieee->reset_port && + ieee->reset_port(ieee->dev)) { + netdev_info(ieee->dev, "reset_port failed\n"); + param->u.crypt.err = IEEE_CRYPT_ERR_CARD_CONF_FAILED; + return -EINVAL; + } + + return ret; +} + +inline struct sk_buff *rtllib_disauth_skb(struct rtllib_network *beacon, + struct rtllib_device *ieee, u16 asRsn) +{ + struct sk_buff *skb; + struct rtllib_disauth *disauth; + int len = sizeof(struct rtllib_disauth) + ieee->tx_headroom; + + skb = dev_alloc_skb(len); + if (!skb) + return NULL; + + skb_reserve(skb, ieee->tx_headroom); + + disauth = (struct rtllib_disauth *) skb_put(skb, + sizeof(struct rtllib_disauth)); + disauth->header.frame_ctl = cpu_to_le16(RTLLIB_STYPE_DEAUTH); + disauth->header.duration_id = 0; + + memcpy(disauth->header.addr1, beacon->bssid, ETH_ALEN); + memcpy(disauth->header.addr2, ieee->dev->dev_addr, ETH_ALEN); + memcpy(disauth->header.addr3, beacon->bssid, ETH_ALEN); + + disauth->reason = cpu_to_le16(asRsn); + return skb; +} + +inline struct sk_buff *rtllib_disassociate_skb(struct rtllib_network *beacon, + struct rtllib_device *ieee, u16 asRsn) +{ + struct sk_buff *skb; + struct rtllib_disassoc *disass; + int len = sizeof(struct rtllib_disassoc) + ieee->tx_headroom; + + skb = dev_alloc_skb(len); + + if (!skb) + return NULL; + + skb_reserve(skb, ieee->tx_headroom); + + disass = (struct rtllib_disassoc *) skb_put(skb, + sizeof(struct rtllib_disassoc)); + disass->header.frame_ctl = cpu_to_le16(RTLLIB_STYPE_DISASSOC); + disass->header.duration_id = 0; + + memcpy(disass->header.addr1, beacon->bssid, ETH_ALEN); + memcpy(disass->header.addr2, ieee->dev->dev_addr, ETH_ALEN); + memcpy(disass->header.addr3, beacon->bssid, ETH_ALEN); + + disass->reason = cpu_to_le16(asRsn); + return skb; +} + +void SendDisassociation(struct rtllib_device *ieee, bool deauth, u16 asRsn) +{ + struct rtllib_network *beacon = &ieee->current_network; + struct sk_buff *skb; + + if (deauth) + skb = rtllib_disauth_skb(beacon, ieee, asRsn); + else + skb = rtllib_disassociate_skb(beacon, ieee, asRsn); + + if (skb) + softmac_mgmt_xmit(skb, ieee); +} + +u8 rtllib_ap_sec_type(struct rtllib_device *ieee) +{ + static u8 ccmp_ie[4] = {0x00, 0x50, 0xf2, 0x04}; + static u8 ccmp_rsn_ie[4] = {0x00, 0x0f, 0xac, 0x04}; + int wpa_ie_len = ieee->wpa_ie_len; + struct lib80211_crypt_data *crypt; + int encrypt; + + crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx]; + encrypt = (ieee->current_network.capability & WLAN_CAPABILITY_PRIVACY) + || (ieee->host_encrypt && crypt && crypt->ops && + (0 == strcmp(crypt->ops->name, "R-WEP"))); + + /* simply judge */ + if (encrypt && (wpa_ie_len == 0)) { + return SEC_ALG_WEP; + } else if ((wpa_ie_len != 0)) { + if (((ieee->wpa_ie[0] == 0xdd) && + (!memcmp(&(ieee->wpa_ie[14]), ccmp_ie, 4))) || + ((ieee->wpa_ie[0] == 0x30) && + (!memcmp(&ieee->wpa_ie[10], ccmp_rsn_ie, 4)))) + return SEC_ALG_CCMP; + else + return SEC_ALG_TKIP; + } else { + return SEC_ALG_NONE; + } +} + +int rtllib_wpa_supplicant_ioctl(struct rtllib_device *ieee, struct iw_point *p, + u8 is_mesh) +{ + struct ieee_param *param; + int ret = 0; + + down(&ieee->wx_sem); + + if (p->length < sizeof(struct ieee_param) || !p->pointer) { + ret = -EINVAL; + goto out; + } + + param = memdup_user(p->pointer, p->length); + if (IS_ERR(param)) { + ret = PTR_ERR(param); + goto out; + } + + switch (param->cmd) { + case IEEE_CMD_SET_WPA_PARAM: + ret = rtllib_wpa_set_param(ieee, param->u.wpa_param.name, + param->u.wpa_param.value); + break; + + case IEEE_CMD_SET_WPA_IE: + ret = rtllib_wpa_set_wpa_ie(ieee, param, p->length); + break; + + case IEEE_CMD_SET_ENCRYPTION: + ret = rtllib_wpa_set_encryption(ieee, param, p->length, 0); + break; + + case IEEE_CMD_MLME: + ret = rtllib_wpa_mlme(ieee, param->u.mlme.command, + param->u.mlme.reason_code); + break; + + default: + netdev_info(ieee->dev, "Unknown WPA supplicant request: %d\n", + param->cmd); + ret = -EOPNOTSUPP; + break; + } + + if (ret == 0 && copy_to_user(p->pointer, param, p->length)) + ret = -EFAULT; + + kfree(param); +out: + up(&ieee->wx_sem); + + return ret; +} +EXPORT_SYMBOL(rtllib_wpa_supplicant_ioctl); + +static void rtllib_MgntDisconnectIBSS(struct rtllib_device *rtllib) +{ + u8 OpMode; + u8 i; + bool bFilterOutNonAssociatedBSSID = false; + + rtllib->state = RTLLIB_NOLINK; + + for (i = 0; i < 6; i++) + rtllib->current_network.bssid[i] = 0x55; + + rtllib->OpMode = RT_OP_MODE_NO_LINK; + rtllib->SetHwRegHandler(rtllib->dev, HW_VAR_BSSID, + rtllib->current_network.bssid); + OpMode = RT_OP_MODE_NO_LINK; + rtllib->SetHwRegHandler(rtllib->dev, HW_VAR_MEDIA_STATUS, &OpMode); + rtllib_stop_send_beacons(rtllib); + + bFilterOutNonAssociatedBSSID = false; + rtllib->SetHwRegHandler(rtllib->dev, HW_VAR_CECHK_BSSID, + (u8 *)(&bFilterOutNonAssociatedBSSID)); + notify_wx_assoc_event(rtllib); + +} + +static void rtllib_MlmeDisassociateRequest(struct rtllib_device *rtllib, u8 *asSta, + u8 asRsn) +{ + u8 i; + u8 OpMode; + + RemovePeerTS(rtllib, asSta); + + if (memcmp(rtllib->current_network.bssid, asSta, 6) == 0) { + rtllib->state = RTLLIB_NOLINK; + + for (i = 0; i < 6; i++) + rtllib->current_network.bssid[i] = 0x22; + OpMode = RT_OP_MODE_NO_LINK; + rtllib->OpMode = RT_OP_MODE_NO_LINK; + rtllib->SetHwRegHandler(rtllib->dev, HW_VAR_MEDIA_STATUS, + (u8 *)(&OpMode)); + rtllib_disassociate(rtllib); + + rtllib->SetHwRegHandler(rtllib->dev, HW_VAR_BSSID, + rtllib->current_network.bssid); + + } + +} + +static void +rtllib_MgntDisconnectAP( + struct rtllib_device *rtllib, + u8 asRsn +) +{ + bool bFilterOutNonAssociatedBSSID = false; + + bFilterOutNonAssociatedBSSID = false; + rtllib->SetHwRegHandler(rtllib->dev, HW_VAR_CECHK_BSSID, + (u8 *)(&bFilterOutNonAssociatedBSSID)); + rtllib_MlmeDisassociateRequest(rtllib, rtllib->current_network.bssid, + asRsn); + + rtllib->state = RTLLIB_NOLINK; +} + +bool rtllib_MgntDisconnect(struct rtllib_device *rtllib, u8 asRsn) +{ + if (rtllib->ps != RTLLIB_PS_DISABLED) + rtllib->sta_wake_up(rtllib->dev); + + if (rtllib->state == RTLLIB_LINKED) { + if (rtllib->iw_mode == IW_MODE_ADHOC) + rtllib_MgntDisconnectIBSS(rtllib); + if (rtllib->iw_mode == IW_MODE_INFRA) + rtllib_MgntDisconnectAP(rtllib, asRsn); + + } + + return true; +} +EXPORT_SYMBOL(rtllib_MgntDisconnect); + +void notify_wx_assoc_event(struct rtllib_device *ieee) +{ + union iwreq_data wrqu; + + if (ieee->cannot_notify) + return; + + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + if (ieee->state == RTLLIB_LINKED) + memcpy(wrqu.ap_addr.sa_data, ieee->current_network.bssid, + ETH_ALEN); + else { + + netdev_info(ieee->dev, "%s(): Tell user space disconnected\n", + __func__); + eth_zero_addr(wrqu.ap_addr.sa_data); + } + wireless_send_event(ieee->dev, SIOCGIWAP, &wrqu, NULL); +} +EXPORT_SYMBOL(notify_wx_assoc_event); diff --git a/kernel/drivers/staging/rtl8192e/rtllib_softmac_wx.c b/kernel/drivers/staging/rtl8192e/rtllib_softmac_wx.c new file mode 100644 index 000000000..9715a793f --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtllib_softmac_wx.c @@ -0,0 +1,661 @@ +/* IEEE 802.11 SoftMAC layer + * Copyright (c) 2005 Andrea Merello + * + * Mostly extracted from the rtl8180-sa2400 driver for the + * in-kernel generic ieee802.11 stack. + * + * Some pieces of code might be stolen from ipw2100 driver + * copyright of who own it's copyright ;-) + * + * PS wx handler mostly stolen from hostap, copyright who + * own it's copyright ;-) + * + * released under the GPL + */ + + +#include + +#include "rtllib.h" +#include "dot11d.h" +/* FIXME: add A freqs */ + +const long rtllib_wlan_frequencies[] = { + 2412, 2417, 2422, 2427, + 2432, 2437, 2442, 2447, + 2452, 2457, 2462, 2467, + 2472, 2484 +}; +EXPORT_SYMBOL(rtllib_wlan_frequencies); + + +int rtllib_wx_set_freq(struct rtllib_device *ieee, struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + int ret; + struct iw_freq *fwrq = &wrqu->freq; + + down(&ieee->wx_sem); + + if (ieee->iw_mode == IW_MODE_INFRA) { + ret = 0; + goto out; + } + + /* if setting by freq convert to channel */ + if (fwrq->e == 1) { + if ((fwrq->m >= (int) 2.412e8 && + fwrq->m <= (int) 2.487e8)) { + int f = fwrq->m / 100000; + int c = 0; + + while ((c < 14) && (f != rtllib_wlan_frequencies[c])) + c++; + + /* hack to fall through */ + fwrq->e = 0; + fwrq->m = c + 1; + } + } + + if (fwrq->e > 0 || fwrq->m > 14 || fwrq->m < 1) { + ret = -EOPNOTSUPP; + goto out; + + } else { /* Set the channel */ + + if (ieee->active_channel_map[fwrq->m] != 1) { + ret = -EINVAL; + goto out; + } + ieee->current_network.channel = fwrq->m; + ieee->set_chan(ieee->dev, ieee->current_network.channel); + + if (ieee->iw_mode == IW_MODE_ADHOC || + ieee->iw_mode == IW_MODE_MASTER) + if (ieee->state == RTLLIB_LINKED) { + rtllib_stop_send_beacons(ieee); + rtllib_start_send_beacons(ieee); + } + } + + ret = 0; +out: + up(&ieee->wx_sem); + return ret; +} +EXPORT_SYMBOL(rtllib_wx_set_freq); + + +int rtllib_wx_get_freq(struct rtllib_device *ieee, + struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + struct iw_freq *fwrq = &wrqu->freq; + + if (ieee->current_network.channel == 0) + return -1; + fwrq->m = rtllib_wlan_frequencies[ieee->current_network.channel-1] * + 100000; + fwrq->e = 1; + return 0; +} +EXPORT_SYMBOL(rtllib_wx_get_freq); + +int rtllib_wx_get_wap(struct rtllib_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + unsigned long flags; + + wrqu->ap_addr.sa_family = ARPHRD_ETHER; + + if (ieee->iw_mode == IW_MODE_MONITOR) + return -1; + + /* We want avoid to give to the user inconsistent infos*/ + spin_lock_irqsave(&ieee->lock, flags); + + if (ieee->state != RTLLIB_LINKED && + ieee->state != RTLLIB_LINKED_SCANNING && + ieee->wap_set == 0) + + eth_zero_addr(wrqu->ap_addr.sa_data); + else + memcpy(wrqu->ap_addr.sa_data, + ieee->current_network.bssid, ETH_ALEN); + + spin_unlock_irqrestore(&ieee->lock, flags); + + return 0; +} +EXPORT_SYMBOL(rtllib_wx_get_wap); + + +int rtllib_wx_set_wap(struct rtllib_device *ieee, + struct iw_request_info *info, + union iwreq_data *awrq, + char *extra) +{ + + int ret = 0; + unsigned long flags; + + short ifup = ieee->proto_started; + struct sockaddr *temp = (struct sockaddr *)awrq; + + rtllib_stop_scan_syncro(ieee); + + down(&ieee->wx_sem); + /* use ifconfig hw ether */ + if (ieee->iw_mode == IW_MODE_MASTER) { + ret = -1; + goto out; + } + + if (temp->sa_family != ARPHRD_ETHER) { + ret = -EINVAL; + goto out; + } + + if (is_zero_ether_addr(temp->sa_data)) { + spin_lock_irqsave(&ieee->lock, flags); + memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN); + ieee->wap_set = 0; + spin_unlock_irqrestore(&ieee->lock, flags); + ret = -1; + goto out; + } + + + if (ifup) + rtllib_stop_protocol(ieee, true); + + /* just to avoid to give inconsistent infos in the + * get wx method. not really needed otherwise + */ + spin_lock_irqsave(&ieee->lock, flags); + + ieee->cannot_notify = false; + memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN); + ieee->wap_set = !is_zero_ether_addr(temp->sa_data); + + spin_unlock_irqrestore(&ieee->lock, flags); + + if (ifup) + rtllib_start_protocol(ieee); +out: + up(&ieee->wx_sem); + return ret; +} +EXPORT_SYMBOL(rtllib_wx_set_wap); + +int rtllib_wx_get_essid(struct rtllib_device *ieee, struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + int len, ret = 0; + unsigned long flags; + + if (ieee->iw_mode == IW_MODE_MONITOR) + return -1; + + /* We want avoid to give to the user inconsistent infos*/ + spin_lock_irqsave(&ieee->lock, flags); + + if (ieee->current_network.ssid[0] == '\0' || + ieee->current_network.ssid_len == 0) { + ret = -1; + goto out; + } + + if (ieee->state != RTLLIB_LINKED && + ieee->state != RTLLIB_LINKED_SCANNING && + ieee->ssid_set == 0) { + ret = -1; + goto out; + } + len = ieee->current_network.ssid_len; + wrqu->essid.length = len; + strncpy(b, ieee->current_network.ssid, len); + wrqu->essid.flags = 1; + +out: + spin_unlock_irqrestore(&ieee->lock, flags); + + return ret; + +} +EXPORT_SYMBOL(rtllib_wx_get_essid); + +int rtllib_wx_set_rate(struct rtllib_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + + u32 target_rate = wrqu->bitrate.value; + + ieee->rate = target_rate/100000; + return 0; +} +EXPORT_SYMBOL(rtllib_wx_set_rate); + +int rtllib_wx_get_rate(struct rtllib_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + u32 tmp_rate = 0; + + tmp_rate = TxCountToDataRate(ieee, + ieee->softmac_stats.CurrentShowTxate); + wrqu->bitrate.value = tmp_rate * 500000; + + return 0; +} +EXPORT_SYMBOL(rtllib_wx_get_rate); + + +int rtllib_wx_set_rts(struct rtllib_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + if (wrqu->rts.disabled || !wrqu->rts.fixed) + ieee->rts = DEFAULT_RTS_THRESHOLD; + else { + if (wrqu->rts.value < MIN_RTS_THRESHOLD || + wrqu->rts.value > MAX_RTS_THRESHOLD) + return -EINVAL; + ieee->rts = wrqu->rts.value; + } + return 0; +} +EXPORT_SYMBOL(rtllib_wx_set_rts); + +int rtllib_wx_get_rts(struct rtllib_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + wrqu->rts.value = ieee->rts; + wrqu->rts.fixed = 0; /* no auto select */ + wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD); + return 0; +} +EXPORT_SYMBOL(rtllib_wx_get_rts); + +int rtllib_wx_set_mode(struct rtllib_device *ieee, struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + int set_mode_status = 0; + + rtllib_stop_scan_syncro(ieee); + down(&ieee->wx_sem); + switch (wrqu->mode) { + case IW_MODE_MONITOR: + case IW_MODE_ADHOC: + case IW_MODE_INFRA: + break; + case IW_MODE_AUTO: + wrqu->mode = IW_MODE_INFRA; + break; + default: + set_mode_status = -EINVAL; + goto out; + } + + if (wrqu->mode == ieee->iw_mode) + goto out; + + if (wrqu->mode == IW_MODE_MONITOR) { + ieee->dev->type = ARPHRD_IEEE80211; + rtllib_EnableNetMonitorMode(ieee->dev, false); + } else { + ieee->dev->type = ARPHRD_ETHER; + if (ieee->iw_mode == IW_MODE_MONITOR) + rtllib_DisableNetMonitorMode(ieee->dev, false); + } + + if (!ieee->proto_started) { + ieee->iw_mode = wrqu->mode; + } else { + rtllib_stop_protocol(ieee, true); + ieee->iw_mode = wrqu->mode; + rtllib_start_protocol(ieee); + } + +out: + up(&ieee->wx_sem); + return set_mode_status; +} +EXPORT_SYMBOL(rtllib_wx_set_mode); + +void rtllib_wx_sync_scan_wq(void *data) +{ + struct rtllib_device *ieee = container_of_work_rsl(data, + struct rtllib_device, wx_sync_scan_wq); + short chan; + enum ht_extchnl_offset chan_offset = 0; + enum ht_channel_width bandwidth = 0; + int b40M = 0; + + if (!(ieee->softmac_features & IEEE_SOFTMAC_SCAN)) { + rtllib_start_scan_syncro(ieee, 0); + goto out; + } + + chan = ieee->current_network.channel; + + if (ieee->LeisurePSLeave) + ieee->LeisurePSLeave(ieee->dev); + /* notify AP to be in PS mode */ + rtllib_sta_ps_send_null_frame(ieee, 1); + rtllib_sta_ps_send_null_frame(ieee, 1); + + rtllib_stop_all_queues(ieee); + + if (ieee->data_hard_stop) + ieee->data_hard_stop(ieee->dev); + rtllib_stop_send_beacons(ieee); + ieee->state = RTLLIB_LINKED_SCANNING; + ieee->link_change(ieee->dev); + /* wait for ps packet to be kicked out successfully */ + msleep(50); + + if (ieee->ScanOperationBackupHandler) + ieee->ScanOperationBackupHandler(ieee->dev, SCAN_OPT_BACKUP); + + if (ieee->pHTInfo->bCurrentHTSupport && ieee->pHTInfo->bEnableHT && + ieee->pHTInfo->bCurBW40MHz) { + b40M = 1; + chan_offset = ieee->pHTInfo->CurSTAExtChnlOffset; + bandwidth = (enum ht_channel_width)ieee->pHTInfo->bCurBW40MHz; + RT_TRACE(COMP_DBG, "Scan in 40M, force to 20M first:%d, %d\n", + chan_offset, bandwidth); + ieee->SetBWModeHandler(ieee->dev, HT_CHANNEL_WIDTH_20, + HT_EXTCHNL_OFFSET_NO_EXT); + } + + rtllib_start_scan_syncro(ieee, 0); + + if (b40M) { + RT_TRACE(COMP_DBG, "Scan in 20M, back to 40M\n"); + if (chan_offset == HT_EXTCHNL_OFFSET_UPPER) + ieee->set_chan(ieee->dev, chan + 2); + else if (chan_offset == HT_EXTCHNL_OFFSET_LOWER) + ieee->set_chan(ieee->dev, chan - 2); + else + ieee->set_chan(ieee->dev, chan); + ieee->SetBWModeHandler(ieee->dev, bandwidth, chan_offset); + } else { + ieee->set_chan(ieee->dev, chan); + } + + if (ieee->ScanOperationBackupHandler) + ieee->ScanOperationBackupHandler(ieee->dev, SCAN_OPT_RESTORE); + + ieee->state = RTLLIB_LINKED; + ieee->link_change(ieee->dev); + + /* Notify AP that I wake up again */ + rtllib_sta_ps_send_null_frame(ieee, 0); + + if (ieee->LinkDetectInfo.NumRecvBcnInPeriod == 0 || + ieee->LinkDetectInfo.NumRecvDataInPeriod == 0) { + ieee->LinkDetectInfo.NumRecvBcnInPeriod = 1; + ieee->LinkDetectInfo.NumRecvDataInPeriod = 1; + } + + if (ieee->data_hard_resume) + ieee->data_hard_resume(ieee->dev); + + if (ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER) + rtllib_start_send_beacons(ieee); + + rtllib_wake_all_queues(ieee); + +out: + up(&ieee->wx_sem); + +} + +int rtllib_wx_set_scan(struct rtllib_device *ieee, struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + int ret = 0; + + down(&ieee->wx_sem); + + if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)) { + ret = -1; + goto out; + } + + if (ieee->state == RTLLIB_LINKED) { + queue_work_rsl(ieee->wq, &ieee->wx_sync_scan_wq); + /* intentionally forget to up sem */ + return 0; + } + +out: + up(&ieee->wx_sem); + return ret; +} +EXPORT_SYMBOL(rtllib_wx_set_scan); + +int rtllib_wx_set_essid(struct rtllib_device *ieee, + struct iw_request_info *a, + union iwreq_data *wrqu, char *extra) +{ + + int ret = 0, len, i; + short proto_started; + unsigned long flags; + + rtllib_stop_scan_syncro(ieee); + down(&ieee->wx_sem); + + proto_started = ieee->proto_started; + + len = (wrqu->essid.length < IW_ESSID_MAX_SIZE) ? wrqu->essid.length : + IW_ESSID_MAX_SIZE; + + if (len > IW_ESSID_MAX_SIZE) { + ret = -E2BIG; + goto out; + } + + if (ieee->iw_mode == IW_MODE_MONITOR) { + ret = -1; + goto out; + } + + for (i = 0; i < len; i++) { + if (extra[i] < 0) { + ret = -1; + goto out; + } + } + + if (proto_started) + rtllib_stop_protocol(ieee, true); + + + /* this is just to be sure that the GET wx callback + * has consistent infos. not needed otherwise + */ + spin_lock_irqsave(&ieee->lock, flags); + + if (wrqu->essid.flags && wrqu->essid.length) { + strncpy(ieee->current_network.ssid, extra, len); + ieee->current_network.ssid_len = len; + ieee->cannot_notify = false; + ieee->ssid_set = 1; + } else { + ieee->ssid_set = 0; + ieee->current_network.ssid[0] = '\0'; + ieee->current_network.ssid_len = 0; + } + spin_unlock_irqrestore(&ieee->lock, flags); + + if (proto_started) + rtllib_start_protocol(ieee); +out: + up(&ieee->wx_sem); + return ret; +} +EXPORT_SYMBOL(rtllib_wx_set_essid); + +int rtllib_wx_get_mode(struct rtllib_device *ieee, struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + wrqu->mode = ieee->iw_mode; + return 0; +} +EXPORT_SYMBOL(rtllib_wx_get_mode); + +int rtllib_wx_set_rawtx(struct rtllib_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + + int *parms = (int *)extra; + int enable = (parms[0] > 0); + short prev = ieee->raw_tx; + + down(&ieee->wx_sem); + + if (enable) + ieee->raw_tx = 1; + else + ieee->raw_tx = 0; + + netdev_info(ieee->dev, "raw TX is %s\n", + ieee->raw_tx ? "enabled" : "disabled"); + + if (ieee->iw_mode == IW_MODE_MONITOR) { + if (prev == 0 && ieee->raw_tx) { + if (ieee->data_hard_resume) + ieee->data_hard_resume(ieee->dev); + + netif_carrier_on(ieee->dev); + } + + if (prev && ieee->raw_tx == 1) + netif_carrier_off(ieee->dev); + } + + up(&ieee->wx_sem); + + return 0; +} +EXPORT_SYMBOL(rtllib_wx_set_rawtx); + +int rtllib_wx_get_name(struct rtllib_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + strcpy(wrqu->name, "802.11"); + + if (ieee->modulation & RTLLIB_CCK_MODULATION) + strcat(wrqu->name, "b"); + if (ieee->modulation & RTLLIB_OFDM_MODULATION) + strcat(wrqu->name, "g"); + if (ieee->mode & (IEEE_N_24G | IEEE_N_5G)) + strcat(wrqu->name, "n"); + return 0; +} +EXPORT_SYMBOL(rtllib_wx_get_name); + + +/* this is mostly stolen from hostap */ +int rtllib_wx_set_power(struct rtllib_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret = 0; + + if ((!ieee->sta_wake_up) || + (!ieee->enter_sleep_state) || + (!ieee->ps_is_queue_empty)) { + RTLLIB_DEBUG(RTLLIB_DL_ERR, + "%s(): PS mode is tried to be use but driver missed a callback\n\n", + __func__); + return -1; + } + + down(&ieee->wx_sem); + + if (wrqu->power.disabled) { + RT_TRACE(COMP_DBG, "===>%s(): power disable\n", __func__); + ieee->ps = RTLLIB_PS_DISABLED; + goto exit; + } + if (wrqu->power.flags & IW_POWER_TIMEOUT) { + ieee->ps_timeout = wrqu->power.value / 1000; + RT_TRACE(COMP_DBG, "===>%s():ps_timeout is %d\n", __func__, + ieee->ps_timeout); + } + + if (wrqu->power.flags & IW_POWER_PERIOD) + ieee->ps_period = wrqu->power.value / 1000; + + switch (wrqu->power.flags & IW_POWER_MODE) { + case IW_POWER_UNICAST_R: + ieee->ps = RTLLIB_PS_UNICAST; + break; + case IW_POWER_MULTICAST_R: + ieee->ps = RTLLIB_PS_MBCAST; + break; + case IW_POWER_ALL_R: + ieee->ps = RTLLIB_PS_UNICAST | RTLLIB_PS_MBCAST; + break; + + case IW_POWER_ON: + break; + + default: + ret = -EINVAL; + goto exit; + + } +exit: + up(&ieee->wx_sem); + return ret; + +} +EXPORT_SYMBOL(rtllib_wx_set_power); + +/* this is stolen from hostap */ +int rtllib_wx_get_power(struct rtllib_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + down(&ieee->wx_sem); + + if (ieee->ps == RTLLIB_PS_DISABLED) { + wrqu->power.disabled = 1; + goto exit; + } + + wrqu->power.disabled = 0; + + if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { + wrqu->power.flags = IW_POWER_TIMEOUT; + wrqu->power.value = ieee->ps_timeout * 1000; + } else { + wrqu->power.flags = IW_POWER_PERIOD; + wrqu->power.value = ieee->ps_period * 1000; + } + + if ((ieee->ps & (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST)) == + (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST)) + wrqu->power.flags |= IW_POWER_ALL_R; + else if (ieee->ps & RTLLIB_PS_MBCAST) + wrqu->power.flags |= IW_POWER_MULTICAST_R; + else + wrqu->power.flags |= IW_POWER_UNICAST_R; + +exit: + up(&ieee->wx_sem); + return 0; + +} +EXPORT_SYMBOL(rtllib_wx_get_power); diff --git a/kernel/drivers/staging/rtl8192e/rtllib_tx.c b/kernel/drivers/staging/rtl8192e/rtllib_tx.c new file mode 100644 index 000000000..3b159638b --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtllib_tx.c @@ -0,0 +1,988 @@ +/****************************************************************************** + + Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2 of the GNU General Public License as + published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., 59 + Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + James P. Ketrenos + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +****************************************************************************** + + Few modifications for Realtek's Wi-Fi drivers by + Andrea Merello + + A special thanks goes to Realtek for their support ! + +******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rtllib.h" + +/* 802.11 Data Frame + * + * + * 802.11 frame_control for data frames - 2 bytes + * ,-----------------------------------------------------------------------------------------. + * bits | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | a | b | c | d | e | + * |----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|------| + * val | 0 | 0 | 0 | 1 | x | 0 | 0 | 0 | 1 | 0 | x | x | x | x | x | + * |----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|------| + * desc | ^-ver-^ | ^type-^ | ^-----subtype-----^ | to |from |more |retry| pwr |more |wep | + * | | | x=0 data,x=1 data+ack | DS | DS |frag | | mgm |data | | + * '-----------------------------------------------------------------------------------------' + * /\ + * | + * 802.11 Data Frame | + * ,--------- 'ctrl' expands to >-----------' + * | + * ,--'---,-------------------------------------------------------------. + * Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 | + * |------|------|---------|---------|---------|------|---------|------| + * Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | Frame | fcs | + * | | tion | (BSSID) | | | ence | data | | + * `--------------------------------------------------| |------' + * Total: 28 non-data bytes `----.----' + * | + * .- 'Frame data' expands to <---------------------------' + * | + * V + * ,---------------------------------------------------. + * Bytes | 1 | 1 | 1 | 3 | 2 | 0-2304 | + * |------|------|---------|----------|------|---------| + * Desc. | SNAP | SNAP | Control |Eth Tunnel| Type | IP | + * | DSAP | SSAP | | | | Packet | + * | 0xAA | 0xAA |0x03 (UI)|0x00-00-F8| | | + * `-----------------------------------------| | + * Total: 8 non-data bytes `----.----' + * | + * .- 'IP Packet' expands, if WEP enabled, to <--' + * | + * V + * ,-----------------------. + * Bytes | 4 | 0-2296 | 4 | + * |-----|-----------|-----| + * Desc. | IV | Encrypted | ICV | + * | | IP Packet | | + * `-----------------------' + * Total: 8 non-data bytes + * + * + * 802.3 Ethernet Data Frame + * + * ,-----------------------------------------. + * Bytes | 6 | 6 | 2 | Variable | 4 | + * |-------|-------|------|-----------|------| + * Desc. | Dest. | Source| Type | IP Packet | fcs | + * | MAC | MAC | | | | + * `-----------------------------------------' + * Total: 18 non-data bytes + * + * In the event that fragmentation is required, the incoming payload is split into + * N parts of size ieee->fts. The first fragment contains the SNAP header and the + * remaining packets are just data. + * + * If encryption is enabled, each fragment payload size is reduced by enough space + * to add the prefix and postfix (IV and ICV totalling 8 bytes in the case of WEP) + * So if you have 1500 bytes of payload with ieee->fts set to 500 without + * encryption it will take 3 frames. With WEP it will take 4 frames as the + * payload of each frame is reduced to 492 bytes. + * + * SKB visualization + * + * ,- skb->data + * | + * | ETHERNET HEADER ,-<-- PAYLOAD + * | | 14 bytes from skb->data + * | 2 bytes for Type --> ,T. | (sizeof ethhdr) + * | | | | + * |,-Dest.--. ,--Src.---. | | | + * | 6 bytes| | 6 bytes | | | | + * v | | | | | | + * 0 | v 1 | v | v 2 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + * ^ | ^ | ^ | + * | | | | | | + * | | | | `T' <---- 2 bytes for Type + * | | | | + * | | '---SNAP--' <-------- 6 bytes for SNAP + * | | + * `-IV--' <-------------------- 4 bytes for IV (WEP) + * + * SNAP HEADER + * + */ + +static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 }; +static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 }; + +inline int rtllib_put_snap(u8 *data, u16 h_proto) +{ + struct rtllib_snap_hdr *snap; + u8 *oui; + + snap = (struct rtllib_snap_hdr *)data; + snap->dsap = 0xaa; + snap->ssap = 0xaa; + snap->ctrl = 0x03; + + if (h_proto == 0x8137 || h_proto == 0x80f3) + oui = P802_1H_OUI; + else + oui = RFC1042_OUI; + snap->oui[0] = oui[0]; + snap->oui[1] = oui[1]; + snap->oui[2] = oui[2]; + + *(__be16 *)(data + SNAP_SIZE) = htons(h_proto); + + return SNAP_SIZE + sizeof(u16); +} + +int rtllib_encrypt_fragment(struct rtllib_device *ieee, struct sk_buff *frag, + int hdr_len) +{ + struct lib80211_crypt_data *crypt = NULL; + int res; + + crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx]; + + if (!(crypt && crypt->ops)) { + netdev_info(ieee->dev, "=========>%s(), crypt is null\n", + __func__); + return -1; + } + /* To encrypt, frame format is: + * IV (4 bytes), clear payload (including SNAP), ICV (4 bytes) + */ + + /* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so + * call both MSDU and MPDU encryption functions from here. + */ + atomic_inc(&crypt->refcnt); + res = 0; + if (crypt->ops->encrypt_msdu) + res = crypt->ops->encrypt_msdu(frag, hdr_len, crypt->priv); + if (res == 0 && crypt->ops->encrypt_mpdu) + res = crypt->ops->encrypt_mpdu(frag, hdr_len, crypt->priv); + + atomic_dec(&crypt->refcnt); + if (res < 0) { + netdev_info(ieee->dev, "%s: Encryption failed: len=%d.\n", + ieee->dev->name, frag->len); + ieee->ieee_stats.tx_discards++; + return -1; + } + + return 0; +} + + +void rtllib_txb_free(struct rtllib_txb *txb) +{ + if (unlikely(!txb)) + return; + kfree(txb); +} + +static struct rtllib_txb *rtllib_alloc_txb(int nr_frags, int txb_size, + gfp_t gfp_mask) +{ + struct rtllib_txb *txb; + int i; + + txb = kmalloc(sizeof(struct rtllib_txb) + (sizeof(u8 *) * nr_frags), + gfp_mask); + if (!txb) + return NULL; + + memset(txb, 0, sizeof(struct rtllib_txb)); + txb->nr_frags = nr_frags; + txb->frag_size = cpu_to_le16(txb_size); + + for (i = 0; i < nr_frags; i++) { + txb->fragments[i] = dev_alloc_skb(txb_size); + if (unlikely(!txb->fragments[i])) { + i--; + break; + } + memset(txb->fragments[i]->cb, 0, sizeof(txb->fragments[i]->cb)); + } + if (unlikely(i != nr_frags)) { + while (i >= 0) + dev_kfree_skb_any(txb->fragments[i--]); + kfree(txb); + return NULL; + } + return txb; +} + +static int rtllib_classify(struct sk_buff *skb, u8 bIsAmsdu) +{ + struct ethhdr *eth; + struct iphdr *ip; + + eth = (struct ethhdr *)skb->data; + if (eth->h_proto != htons(ETH_P_IP)) + return 0; + + RTLLIB_DEBUG_DATA(RTLLIB_DL_DATA, skb->data, skb->len); + ip = ip_hdr(skb); + switch (ip->tos & 0xfc) { + case 0x20: + return 2; + case 0x40: + return 1; + case 0x60: + return 3; + case 0x80: + return 4; + case 0xa0: + return 5; + case 0xc0: + return 6; + case 0xe0: + return 7; + default: + return 0; + } +} + +static void rtllib_tx_query_agg_cap(struct rtllib_device *ieee, + struct sk_buff *skb, + struct cb_desc *tcb_desc) +{ + struct rt_hi_throughput *pHTInfo = ieee->pHTInfo; + struct tx_ts_record *pTxTs = NULL; + struct rtllib_hdr_1addr *hdr = (struct rtllib_hdr_1addr *)skb->data; + + if (rtllib_act_scanning(ieee, false)) + return; + + if (!pHTInfo->bCurrentHTSupport || !pHTInfo->bEnableHT) + return; + if (!IsQoSDataFrame(skb->data)) + return; + if (is_multicast_ether_addr(hdr->addr1)) + return; + + if (tcb_desc->bdhcp || ieee->CntAfterLink < 2) + return; + + if (pHTInfo->IOTAction & HT_IOT_ACT_TX_NO_AGGREGATION) + return; + + if (!ieee->GetNmodeSupportBySecCfg(ieee->dev)) + return; + if (pHTInfo->bCurrentAMPDUEnable) { + if (!GetTs(ieee, (struct ts_common_info **)(&pTxTs), hdr->addr1, + skb->priority, TX_DIR, true)) { + netdev_info(ieee->dev, "%s: can't get TS\n", __func__); + return; + } + if (pTxTs->TxAdmittedBARecord.bValid == false) { + if (ieee->wpa_ie_len && (ieee->pairwise_key_type == + KEY_TYPE_NA)) { + ; + } else if (tcb_desc->bdhcp == 1) { + ; + } else if (!pTxTs->bDisable_AddBa) { + TsStartAddBaProcess(ieee, pTxTs); + } + goto FORCED_AGG_SETTING; + } else if (pTxTs->bUsingBa == false) { + if (SN_LESS(pTxTs->TxAdmittedBARecord.BaStartSeqCtrl.field.SeqNum, + (pTxTs->TxCurSeq+1)%4096)) + pTxTs->bUsingBa = true; + else + goto FORCED_AGG_SETTING; + } + if (ieee->iw_mode == IW_MODE_INFRA) { + tcb_desc->bAMPDUEnable = true; + tcb_desc->ampdu_factor = pHTInfo->CurrentAMPDUFactor; + tcb_desc->ampdu_density = pHTInfo->CurrentMPDUDensity; + } + } +FORCED_AGG_SETTING: + switch (pHTInfo->ForcedAMPDUMode) { + case HT_AGG_AUTO: + break; + + case HT_AGG_FORCE_ENABLE: + tcb_desc->bAMPDUEnable = true; + tcb_desc->ampdu_density = pHTInfo->ForcedMPDUDensity; + tcb_desc->ampdu_factor = pHTInfo->ForcedAMPDUFactor; + break; + + case HT_AGG_FORCE_DISABLE: + tcb_desc->bAMPDUEnable = false; + tcb_desc->ampdu_density = 0; + tcb_desc->ampdu_factor = 0; + break; + } +} + +static void rtllib_qurey_ShortPreambleMode(struct rtllib_device *ieee, + struct cb_desc *tcb_desc) +{ + tcb_desc->bUseShortPreamble = false; + if (tcb_desc->data_rate == 2) + return; + else if (ieee->current_network.capability & + WLAN_CAPABILITY_SHORT_PREAMBLE) + tcb_desc->bUseShortPreamble = true; +} + +static void rtllib_query_HTCapShortGI(struct rtllib_device *ieee, + struct cb_desc *tcb_desc) +{ + struct rt_hi_throughput *pHTInfo = ieee->pHTInfo; + + tcb_desc->bUseShortGI = false; + + if (!pHTInfo->bCurrentHTSupport || !pHTInfo->bEnableHT) + return; + + if (pHTInfo->bForcedShortGI) { + tcb_desc->bUseShortGI = true; + return; + } + + if ((pHTInfo->bCurBW40MHz == true) && pHTInfo->bCurShortGI40MHz) + tcb_desc->bUseShortGI = true; + else if ((pHTInfo->bCurBW40MHz == false) && pHTInfo->bCurShortGI20MHz) + tcb_desc->bUseShortGI = true; +} + +static void rtllib_query_BandwidthMode(struct rtllib_device *ieee, + struct cb_desc *tcb_desc) +{ + struct rt_hi_throughput *pHTInfo = ieee->pHTInfo; + + tcb_desc->bPacketBW = false; + + if (!pHTInfo->bCurrentHTSupport || !pHTInfo->bEnableHT) + return; + + if (tcb_desc->bMulticast || tcb_desc->bBroadcast) + return; + + if ((tcb_desc->data_rate & 0x80) == 0) + return; + if (pHTInfo->bCurBW40MHz && pHTInfo->bCurTxBW40MHz && + !ieee->bandwidth_auto_switch.bforced_tx20Mhz) + tcb_desc->bPacketBW = true; +} + +static void rtllib_query_protectionmode(struct rtllib_device *ieee, + struct cb_desc *tcb_desc, + struct sk_buff *skb) +{ + struct rt_hi_throughput *pHTInfo; + + tcb_desc->bRTSSTBC = false; + tcb_desc->bRTSUseShortGI = false; + tcb_desc->bCTSEnable = false; + tcb_desc->RTSSC = 0; + tcb_desc->bRTSBW = false; + + if (tcb_desc->bBroadcast || tcb_desc->bMulticast) + return; + + if (is_broadcast_ether_addr(skb->data+16)) + return; + + if (ieee->mode < IEEE_N_24G) { + if (skb->len > ieee->rts) { + tcb_desc->bRTSEnable = true; + tcb_desc->rts_rate = MGN_24M; + } else if (ieee->current_network.buseprotection) { + tcb_desc->bRTSEnable = true; + tcb_desc->bCTSEnable = true; + tcb_desc->rts_rate = MGN_24M; + } + return; + } + + pHTInfo = ieee->pHTInfo; + + while (true) { + if (pHTInfo->IOTAction & HT_IOT_ACT_FORCED_CTS2SELF) { + tcb_desc->bCTSEnable = true; + tcb_desc->rts_rate = MGN_24M; + tcb_desc->bRTSEnable = true; + break; + } else if (pHTInfo->IOTAction & (HT_IOT_ACT_FORCED_RTS | + HT_IOT_ACT_PURE_N_MODE)) { + tcb_desc->bRTSEnable = true; + tcb_desc->rts_rate = MGN_24M; + break; + } + if (ieee->current_network.buseprotection) { + tcb_desc->bRTSEnable = true; + tcb_desc->bCTSEnable = true; + tcb_desc->rts_rate = MGN_24M; + break; + } + if (pHTInfo->bCurrentHTSupport && pHTInfo->bEnableHT) { + u8 HTOpMode = pHTInfo->CurrentOpMode; + + if ((pHTInfo->bCurBW40MHz && (HTOpMode == 2 || + HTOpMode == 3)) || + (!pHTInfo->bCurBW40MHz && HTOpMode == 3)) { + tcb_desc->rts_rate = MGN_24M; + tcb_desc->bRTSEnable = true; + break; + } + } + if (skb->len > ieee->rts) { + tcb_desc->rts_rate = MGN_24M; + tcb_desc->bRTSEnable = true; + break; + } + if (tcb_desc->bAMPDUEnable) { + tcb_desc->rts_rate = MGN_24M; + tcb_desc->bRTSEnable = false; + break; + } + goto NO_PROTECTION; + } + if (ieee->current_network.capability & WLAN_CAPABILITY_SHORT_PREAMBLE) + tcb_desc->bUseShortPreamble = true; + if (ieee->iw_mode == IW_MODE_MASTER) + goto NO_PROTECTION; + return; +NO_PROTECTION: + tcb_desc->bRTSEnable = false; + tcb_desc->bCTSEnable = false; + tcb_desc->rts_rate = 0; + tcb_desc->RTSSC = 0; + tcb_desc->bRTSBW = false; +} + + +static void rtllib_txrate_selectmode(struct rtllib_device *ieee, + struct cb_desc *tcb_desc) +{ + if (ieee->bTxDisableRateFallBack) + tcb_desc->bTxDisableRateFallBack = true; + + if (ieee->bTxUseDriverAssingedRate) + tcb_desc->bTxUseDriverAssingedRate = true; + if (!tcb_desc->bTxDisableRateFallBack || + !tcb_desc->bTxUseDriverAssingedRate) { + if (ieee->iw_mode == IW_MODE_INFRA || + ieee->iw_mode == IW_MODE_ADHOC) + tcb_desc->RATRIndex = 0; + } +} + +u16 rtllib_query_seqnum(struct rtllib_device *ieee, struct sk_buff *skb, + u8 *dst) +{ + u16 seqnum = 0; + + if (is_multicast_ether_addr(dst)) + return 0; + if (IsQoSDataFrame(skb->data)) { + struct tx_ts_record *pTS = NULL; + + if (!GetTs(ieee, (struct ts_common_info **)(&pTS), dst, + skb->priority, TX_DIR, true)) + return 0; + seqnum = pTS->TxCurSeq; + pTS->TxCurSeq = (pTS->TxCurSeq+1)%4096; + return seqnum; + } + return 0; +} + +static int wme_downgrade_ac(struct sk_buff *skb) +{ + switch (skb->priority) { + case 6: + case 7: + skb->priority = 5; /* VO -> VI */ + return 0; + case 4: + case 5: + skb->priority = 3; /* VI -> BE */ + return 0; + case 0: + case 3: + skb->priority = 1; /* BE -> BK */ + return 0; + default: + return -1; + } +} + +static u8 rtllib_current_rate(struct rtllib_device *ieee) +{ + if (ieee->mode & IEEE_MODE_MASK) + return ieee->rate; + + if (ieee->HTCurrentOperaRate) + return ieee->HTCurrentOperaRate; + else + return ieee->rate & 0x7F; +} + +int rtllib_xmit_inter(struct sk_buff *skb, struct net_device *dev) +{ + struct rtllib_device *ieee = (struct rtllib_device *) + netdev_priv_rsl(dev); + struct rtllib_txb *txb = NULL; + struct rtllib_hdr_3addrqos *frag_hdr; + int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size; + unsigned long flags; + struct net_device_stats *stats = &ieee->stats; + int ether_type = 0, encrypt; + int bytes, fc, qos_ctl = 0, hdr_len; + struct sk_buff *skb_frag; + struct rtllib_hdr_3addrqos header = { /* Ensure zero initialized */ + .duration_id = 0, + .seq_ctl = 0, + .qos_ctl = 0 + }; + u8 dest[ETH_ALEN], src[ETH_ALEN]; + int qos_actived = ieee->current_network.qos_data.active; + struct lib80211_crypt_data *crypt = NULL; + struct cb_desc *tcb_desc; + u8 bIsMulticast = false; + u8 IsAmsdu = false; + bool bdhcp = false; + + spin_lock_irqsave(&ieee->lock, flags); + + /* If there is no driver handler to take the TXB, don't bother + * creating it... + */ + if ((!ieee->hard_start_xmit && !(ieee->softmac_features & + IEEE_SOFTMAC_TX_QUEUE)) || + ((!ieee->softmac_data_hard_start_xmit && + (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE)))) { + netdev_warn(ieee->dev, "No xmit handler.\n"); + goto success; + } + + + if (likely(ieee->raw_tx == 0)) { + if (unlikely(skb->len < SNAP_SIZE + sizeof(u16))) { + netdev_warn(ieee->dev, "skb too small (%d).\n", + skb->len); + goto success; + } + /* Save source and destination addresses */ + memcpy(dest, skb->data, ETH_ALEN); + memcpy(src, skb->data+ETH_ALEN, ETH_ALEN); + + memset(skb->cb, 0, sizeof(skb->cb)); + ether_type = ntohs(((struct ethhdr *)skb->data)->h_proto); + + if (ieee->iw_mode == IW_MODE_MONITOR) { + txb = rtllib_alloc_txb(1, skb->len, GFP_ATOMIC); + if (unlikely(!txb)) { + netdev_warn(ieee->dev, + "Could not allocate TXB\n"); + goto failed; + } + + txb->encrypted = 0; + txb->payload_size = cpu_to_le16(skb->len); + memcpy(skb_put(txb->fragments[0], skb->len), skb->data, + skb->len); + + goto success; + } + + if (skb->len > 282) { + if (ETH_P_IP == ether_type) { + const struct iphdr *ip = (struct iphdr *) + ((u8 *)skb->data+14); + if (IPPROTO_UDP == ip->protocol) { + struct udphdr *udp; + + udp = (struct udphdr *)((u8 *)ip + + (ip->ihl << 2)); + if (((((u8 *)udp)[1] == 68) && + (((u8 *)udp)[3] == 67)) || + ((((u8 *)udp)[1] == 67) && + (((u8 *)udp)[3] == 68))) { + bdhcp = true; + ieee->LPSDelayCnt = 200; + } + } + } else if (ETH_P_ARP == ether_type) { + netdev_info(ieee->dev, + "=================>DHCP Protocol start tx ARP pkt!!\n"); + bdhcp = true; + ieee->LPSDelayCnt = + ieee->current_network.tim.tim_count; + } + } + + skb->priority = rtllib_classify(skb, IsAmsdu); + crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx]; + encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) && + ieee->host_encrypt && crypt && crypt->ops; + if (!encrypt && ieee->ieee802_1x && + ieee->drop_unencrypted && ether_type != ETH_P_PAE) { + stats->tx_dropped++; + goto success; + } + if (crypt && !encrypt && ether_type == ETH_P_PAE) { + struct eapol *eap = (struct eapol *)(skb->data + + sizeof(struct ethhdr) - SNAP_SIZE - + sizeof(u16)); + RTLLIB_DEBUG_EAP("TX: IEEE 802.11 EAPOL frame: %s\n", + eap_get_type(eap->type)); + } + + /* Advance the SKB to the start of the payload */ + skb_pull(skb, sizeof(struct ethhdr)); + + /* Determine total amount of storage required for TXB packets */ + bytes = skb->len + SNAP_SIZE + sizeof(u16); + + if (encrypt) + fc = RTLLIB_FTYPE_DATA | RTLLIB_FCTL_WEP; + else + fc = RTLLIB_FTYPE_DATA; + + if (qos_actived) + fc |= RTLLIB_STYPE_QOS_DATA; + else + fc |= RTLLIB_STYPE_DATA; + + if (ieee->iw_mode == IW_MODE_INFRA) { + fc |= RTLLIB_FCTL_TODS; + /* To DS: Addr1 = BSSID, Addr2 = SA, + * Addr3 = DA + */ + memcpy(&header.addr1, ieee->current_network.bssid, + ETH_ALEN); + memcpy(&header.addr2, &src, ETH_ALEN); + if (IsAmsdu) + memcpy(&header.addr3, + ieee->current_network.bssid, ETH_ALEN); + else + memcpy(&header.addr3, &dest, ETH_ALEN); + } else if (ieee->iw_mode == IW_MODE_ADHOC) { + /* not From/To DS: Addr1 = DA, Addr2 = SA, + * Addr3 = BSSID + */ + memcpy(&header.addr1, dest, ETH_ALEN); + memcpy(&header.addr2, src, ETH_ALEN); + memcpy(&header.addr3, ieee->current_network.bssid, + ETH_ALEN); + } + + bIsMulticast = is_multicast_ether_addr(header.addr1); + + header.frame_ctl = cpu_to_le16(fc); + + /* Determine fragmentation size based on destination (multicast + * and broadcast are not fragmented) + */ + if (bIsMulticast) { + frag_size = MAX_FRAG_THRESHOLD; + qos_ctl |= QOS_CTL_NOTCONTAIN_ACK; + } else { + frag_size = ieee->fts; + qos_ctl = 0; + } + + if (qos_actived) { + hdr_len = RTLLIB_3ADDR_LEN + 2; + + /* in case we are a client verify acm is not set for this ac */ + while (unlikely(ieee->wmm_acm & (0x01 << skb->priority))) { + netdev_info(ieee->dev, "skb->priority = %x\n", + skb->priority); + if (wme_downgrade_ac(skb)) + break; + netdev_info(ieee->dev, "converted skb->priority = %x\n", + skb->priority); + } + qos_ctl |= skb->priority; + header.qos_ctl = cpu_to_le16(qos_ctl & RTLLIB_QOS_TID); + } else { + hdr_len = RTLLIB_3ADDR_LEN; + } + /* Determine amount of payload per fragment. Regardless of if + * this stack is providing the full 802.11 header, one will + * eventually be affixed to this fragment -- so we must account + * for it when determining the amount of payload space. + */ + bytes_per_frag = frag_size - hdr_len; + if (ieee->config & + (CFG_RTLLIB_COMPUTE_FCS | CFG_RTLLIB_RESERVE_FCS)) + bytes_per_frag -= RTLLIB_FCS_LEN; + + /* Each fragment may need to have room for encrypting + * pre/postfix + */ + if (encrypt) { + bytes_per_frag -= crypt->ops->extra_mpdu_prefix_len + + crypt->ops->extra_mpdu_postfix_len + + crypt->ops->extra_msdu_prefix_len + + crypt->ops->extra_msdu_postfix_len; + } + /* Number of fragments is the total bytes_per_frag / + * payload_per_fragment + */ + nr_frags = bytes / bytes_per_frag; + bytes_last_frag = bytes % bytes_per_frag; + if (bytes_last_frag) + nr_frags++; + else + bytes_last_frag = bytes_per_frag; + + /* When we allocate the TXB we allocate enough space for the + * reserve and full fragment bytes (bytes_per_frag doesn't + * include prefix, postfix, header, FCS, etc.) + */ + txb = rtllib_alloc_txb(nr_frags, frag_size + + ieee->tx_headroom, GFP_ATOMIC); + if (unlikely(!txb)) { + netdev_warn(ieee->dev, "Could not allocate TXB\n"); + goto failed; + } + txb->encrypted = encrypt; + txb->payload_size = cpu_to_le16(bytes); + + if (qos_actived) + txb->queue_index = UP2AC(skb->priority); + else + txb->queue_index = WME_AC_BE; + + for (i = 0; i < nr_frags; i++) { + skb_frag = txb->fragments[i]; + tcb_desc = (struct cb_desc *)(skb_frag->cb + + MAX_DEV_ADDR_SIZE); + if (qos_actived) { + skb_frag->priority = skb->priority; + tcb_desc->queue_index = UP2AC(skb->priority); + } else { + skb_frag->priority = WME_AC_BE; + tcb_desc->queue_index = WME_AC_BE; + } + skb_reserve(skb_frag, ieee->tx_headroom); + + if (encrypt) { + if (ieee->hwsec_active) + tcb_desc->bHwSec = 1; + else + tcb_desc->bHwSec = 0; + skb_reserve(skb_frag, + crypt->ops->extra_mpdu_prefix_len + + crypt->ops->extra_msdu_prefix_len); + } else { + tcb_desc->bHwSec = 0; + } + frag_hdr = (struct rtllib_hdr_3addrqos *) + skb_put(skb_frag, hdr_len); + memcpy(frag_hdr, &header, hdr_len); + + /* If this is not the last fragment, then add the + * MOREFRAGS bit to the frame control + */ + if (i != nr_frags - 1) { + frag_hdr->frame_ctl = cpu_to_le16( + fc | RTLLIB_FCTL_MOREFRAGS); + bytes = bytes_per_frag; + + } else { + /* The last fragment has the remaining length */ + bytes = bytes_last_frag; + } + if ((qos_actived) && (!bIsMulticast)) { + frag_hdr->seq_ctl = + cpu_to_le16(rtllib_query_seqnum(ieee, skb_frag, + header.addr1)); + frag_hdr->seq_ctl = + cpu_to_le16(le16_to_cpu(frag_hdr->seq_ctl)<<4 | i); + } else { + frag_hdr->seq_ctl = + cpu_to_le16(ieee->seq_ctrl[0]<<4 | i); + } + /* Put a SNAP header on the first fragment */ + if (i == 0) { + rtllib_put_snap( + skb_put(skb_frag, SNAP_SIZE + + sizeof(u16)), ether_type); + bytes -= SNAP_SIZE + sizeof(u16); + } + + memcpy(skb_put(skb_frag, bytes), skb->data, bytes); + + /* Advance the SKB... */ + skb_pull(skb, bytes); + + /* Encryption routine will move the header forward in + * order to insert the IV between the header and the + * payload + */ + if (encrypt) + rtllib_encrypt_fragment(ieee, skb_frag, + hdr_len); + if (ieee->config & + (CFG_RTLLIB_COMPUTE_FCS | CFG_RTLLIB_RESERVE_FCS)) + skb_put(skb_frag, 4); + } + + if ((qos_actived) && (!bIsMulticast)) { + if (ieee->seq_ctrl[UP2AC(skb->priority) + 1] == 0xFFF) + ieee->seq_ctrl[UP2AC(skb->priority) + 1] = 0; + else + ieee->seq_ctrl[UP2AC(skb->priority) + 1]++; + } else { + if (ieee->seq_ctrl[0] == 0xFFF) + ieee->seq_ctrl[0] = 0; + else + ieee->seq_ctrl[0]++; + } + } else { + if (unlikely(skb->len < sizeof(struct rtllib_hdr_3addr))) { + netdev_warn(ieee->dev, "skb too small (%d).\n", + skb->len); + goto success; + } + + txb = rtllib_alloc_txb(1, skb->len, GFP_ATOMIC); + if (!txb) { + netdev_warn(ieee->dev, "Could not allocate TXB\n"); + goto failed; + } + + txb->encrypted = 0; + txb->payload_size = cpu_to_le16(skb->len); + memcpy(skb_put(txb->fragments[0], skb->len), skb->data, + skb->len); + } + + success: + if (txb) { + struct cb_desc *tcb_desc = (struct cb_desc *) + (txb->fragments[0]->cb + MAX_DEV_ADDR_SIZE); + tcb_desc->bTxEnableFwCalcDur = 1; + tcb_desc->priority = skb->priority; + + if (ether_type == ETH_P_PAE) { + if (ieee->pHTInfo->IOTAction & + HT_IOT_ACT_WA_IOT_Broadcom) { + tcb_desc->data_rate = + MgntQuery_TxRateExcludeCCKRates(ieee); + tcb_desc->bTxDisableRateFallBack = false; + } else { + tcb_desc->data_rate = ieee->basic_rate; + tcb_desc->bTxDisableRateFallBack = 1; + } + + + tcb_desc->RATRIndex = 7; + tcb_desc->bTxUseDriverAssingedRate = 1; + } else { + if (is_multicast_ether_addr(header.addr1)) + tcb_desc->bMulticast = 1; + if (is_broadcast_ether_addr(header.addr1)) + tcb_desc->bBroadcast = 1; + rtllib_txrate_selectmode(ieee, tcb_desc); + if (tcb_desc->bMulticast || tcb_desc->bBroadcast) + tcb_desc->data_rate = ieee->basic_rate; + else + tcb_desc->data_rate = rtllib_current_rate(ieee); + + if (bdhcp) { + if (ieee->pHTInfo->IOTAction & + HT_IOT_ACT_WA_IOT_Broadcom) { + tcb_desc->data_rate = + MgntQuery_TxRateExcludeCCKRates(ieee); + tcb_desc->bTxDisableRateFallBack = false; + } else { + tcb_desc->data_rate = MGN_1M; + tcb_desc->bTxDisableRateFallBack = 1; + } + + + tcb_desc->RATRIndex = 7; + tcb_desc->bTxUseDriverAssingedRate = 1; + tcb_desc->bdhcp = 1; + } + + rtllib_qurey_ShortPreambleMode(ieee, tcb_desc); + rtllib_tx_query_agg_cap(ieee, txb->fragments[0], + tcb_desc); + rtllib_query_HTCapShortGI(ieee, tcb_desc); + rtllib_query_BandwidthMode(ieee, tcb_desc); + rtllib_query_protectionmode(ieee, tcb_desc, + txb->fragments[0]); + } + } + spin_unlock_irqrestore(&ieee->lock, flags); + dev_kfree_skb_any(skb); + if (txb) { + if (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE) { + dev->stats.tx_packets++; + dev->stats.tx_bytes += le16_to_cpu(txb->payload_size); + rtllib_softmac_xmit(txb, ieee); + } else { + if ((*ieee->hard_start_xmit)(txb, dev) == 0) { + stats->tx_packets++; + stats->tx_bytes += le16_to_cpu(txb->payload_size); + return 0; + } + rtllib_txb_free(txb); + } + } + + return 0; + + failed: + spin_unlock_irqrestore(&ieee->lock, flags); + netif_stop_queue(dev); + stats->tx_errors++; + return 1; + +} +int rtllib_xmit(struct sk_buff *skb, struct net_device *dev) +{ + memset(skb->cb, 0, sizeof(skb->cb)); + return rtllib_xmit_inter(skb, dev); +} +EXPORT_SYMBOL(rtllib_xmit); diff --git a/kernel/drivers/staging/rtl8192e/rtllib_wx.c b/kernel/drivers/staging/rtl8192e/rtllib_wx.c new file mode 100644 index 000000000..6234aae5b --- /dev/null +++ b/kernel/drivers/staging/rtl8192e/rtllib_wx.c @@ -0,0 +1,881 @@ +/****************************************************************************** + + Copyright(c) 2004 Intel Corporation. All rights reserved. + + Portions of this file are based on the WEP enablement code provided by the + Host AP project hostap-drivers v0.1.3 + Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen + + Copyright (c) 2002-2003, Jouni Malinen + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2 of the GNU General Public License as + published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., 59 + Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + James P. Ketrenos + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +******************************************************************************/ +#include +#include +#include +#include +#include "rtllib.h" +struct modes_unit { + char *mode_string; + int mode_size; +}; +static struct modes_unit rtllib_modes[] = { + {"a", 1}, + {"b", 1}, + {"g", 1}, + {"?", 1}, + {"N-24G", 5}, + {"N-5G", 4}, +}; + +#define MAX_CUSTOM_LEN 64 +static inline char *rtl819x_translate_scan(struct rtllib_device *ieee, + char *start, char *stop, + struct rtllib_network *network, + struct iw_request_info *info) +{ + char custom[MAX_CUSTOM_LEN]; + char proto_name[IFNAMSIZ]; + char *pname = proto_name; + char *p; + struct iw_event iwe; + int i, j; + u16 max_rate, rate; + static u8 EWC11NHTCap[] = {0x00, 0x90, 0x4c, 0x33}; + + /* First entry *MUST* be the AP MAC address */ + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + ether_addr_copy(iwe.u.ap_addr.sa_data, network->bssid); + start = iwe_stream_add_event_rsl(info, start, stop, + &iwe, IW_EV_ADDR_LEN); + /* Remaining entries will be displayed in the order we provide them */ + + /* Add the ESSID */ + iwe.cmd = SIOCGIWESSID; + iwe.u.data.flags = 1; + if (network->ssid_len > 0) { + iwe.u.data.length = min_t(u8, network->ssid_len, 32); + start = iwe_stream_add_point_rsl(info, start, stop, &iwe, + network->ssid); + } else if (network->hidden_ssid_len == 0) { + iwe.u.data.length = sizeof(""); + start = iwe_stream_add_point_rsl(info, start, stop, + &iwe, ""); + } else { + iwe.u.data.length = min_t(u8, network->hidden_ssid_len, 32); + start = iwe_stream_add_point_rsl(info, start, stop, &iwe, + network->hidden_ssid); + } + /* Add the protocol name */ + iwe.cmd = SIOCGIWNAME; + for (i = 0; i < ARRAY_SIZE(rtllib_modes); i++) { + if (network->mode&(1<capability & + (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) { + if (network->capability & WLAN_CAPABILITY_ESS) + iwe.u.mode = IW_MODE_MASTER; + else + iwe.u.mode = IW_MODE_ADHOC; + start = iwe_stream_add_event_rsl(info, start, stop, + &iwe, IW_EV_UINT_LEN); + } + + /* Add frequency/channel */ + iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = network->channel; + iwe.u.freq.e = 0; + iwe.u.freq.i = 0; + start = iwe_stream_add_event_rsl(info, start, stop, &iwe, + IW_EV_FREQ_LEN); + + /* Add encryption capability */ + iwe.cmd = SIOCGIWENCODE; + if (network->capability & WLAN_CAPABILITY_PRIVACY) + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + else + iwe.u.data.flags = IW_ENCODE_DISABLED; + iwe.u.data.length = 0; + start = iwe_stream_add_point_rsl(info, start, stop, + &iwe, network->ssid); + /* Add basic and extended rates */ + max_rate = 0; + p = custom; + p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): "); + for (i = 0, j = 0; i < network->rates_len;) { + if (j < network->rates_ex_len && + ((network->rates_ex[j] & 0x7F) < + (network->rates[i] & 0x7F))) + rate = network->rates_ex[j++] & 0x7F; + else + rate = network->rates[i++] & 0x7F; + if (rate > max_rate) + max_rate = rate; + p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), + "%d%s ", rate >> 1, (rate & 1) ? ".5" : ""); + } + for (; j < network->rates_ex_len; j++) { + rate = network->rates_ex[j] & 0x7F; + p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), + "%d%s ", rate >> 1, (rate & 1) ? ".5" : ""); + if (rate > max_rate) + max_rate = rate; + } + + if (network->mode >= IEEE_N_24G) { + struct ht_capab_ele *ht_cap = NULL; + bool is40M = false, isShortGI = false; + u8 max_mcs = 0; + + if (!memcmp(network->bssht.bdHTCapBuf, EWC11NHTCap, 4)) + ht_cap = (struct ht_capab_ele *) + &network->bssht.bdHTCapBuf[4]; + else + ht_cap = (struct ht_capab_ele *) + &network->bssht.bdHTCapBuf[0]; + is40M = (ht_cap->ChlWidth) ? 1 : 0; + isShortGI = (ht_cap->ChlWidth) ? + ((ht_cap->ShortGI40Mhz) ? 1 : 0) : + ((ht_cap->ShortGI20Mhz) ? 1 : 0); + + max_mcs = HTGetHighestMCSRate(ieee, ht_cap->MCS, + MCS_FILTER_ALL); + rate = MCS_DATA_RATE[is40M][isShortGI][max_mcs & 0x7f]; + if (rate > max_rate) + max_rate = rate; + } + iwe.cmd = SIOCGIWRATE; + iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; + iwe.u.bitrate.value = max_rate * 500000; + start = iwe_stream_add_event_rsl(info, start, stop, &iwe, + IW_EV_PARAM_LEN); + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = p - custom; + if (iwe.u.data.length) + start = iwe_stream_add_point_rsl(info, start, stop, + &iwe, custom); + /* Add quality statistics */ + /* TODO: Fix these values... */ + iwe.cmd = IWEVQUAL; + iwe.u.qual.qual = network->stats.signal; + iwe.u.qual.level = network->stats.rssi; + iwe.u.qual.noise = network->stats.noise; + iwe.u.qual.updated = network->stats.mask & RTLLIB_STATMASK_WEMASK; + if (!(network->stats.mask & RTLLIB_STATMASK_RSSI)) + iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID; + if (!(network->stats.mask & RTLLIB_STATMASK_NOISE)) + iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID; + if (!(network->stats.mask & RTLLIB_STATMASK_SIGNAL)) + iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID; + iwe.u.qual.updated = 7; + start = iwe_stream_add_event_rsl(info, start, stop, &iwe, + IW_EV_QUAL_LEN); + + iwe.cmd = IWEVCUSTOM; + p = custom; + iwe.u.data.length = p - custom; + if (iwe.u.data.length) + start = iwe_stream_add_point_rsl(info, start, stop, + &iwe, custom); + + memset(&iwe, 0, sizeof(iwe)); + if (network->wpa_ie_len) { + char buf[MAX_WPA_IE_LEN]; + + memcpy(buf, network->wpa_ie, network->wpa_ie_len); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = network->wpa_ie_len; + start = iwe_stream_add_point_rsl(info, start, stop, &iwe, buf); + } + memset(&iwe, 0, sizeof(iwe)); + if (network->rsn_ie_len) { + char buf[MAX_WPA_IE_LEN]; + + memcpy(buf, network->rsn_ie, network->rsn_ie_len); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = network->rsn_ie_len; + start = iwe_stream_add_point_rsl(info, start, stop, &iwe, buf); + } + + /* add info for WZC */ + memset(&iwe, 0, sizeof(iwe)); + if (network->wzc_ie_len) { + char buf[MAX_WZC_IE_LEN]; + + memcpy(buf, network->wzc_ie, network->wzc_ie_len); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = network->wzc_ie_len; + start = iwe_stream_add_point_rsl(info, start, stop, &iwe, buf); + } + + /* Add EXTRA: Age to display seconds since last beacon/probe response + * for given network. + */ + iwe.cmd = IWEVCUSTOM; + p = custom; + p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), + " Last beacon: %lums ago", + (jiffies - network->last_scanned) / (HZ / 100)); + iwe.u.data.length = p - custom; + if (iwe.u.data.length) + start = iwe_stream_add_point_rsl(info, start, stop, + &iwe, custom); + + return start; +} + +int rtllib_wx_get_scan(struct rtllib_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct rtllib_network *network; + unsigned long flags; + + char *ev = extra; + char *stop = ev + wrqu->data.length; + int i = 0; + int err = 0; + + RTLLIB_DEBUG_WX("Getting scan\n"); + down(&ieee->wx_sem); + spin_lock_irqsave(&ieee->lock, flags); + + list_for_each_entry(network, &ieee->network_list, list) { + i++; + if ((stop - ev) < 200) { + err = -E2BIG; + break; + } + if (ieee->scan_age == 0 || + time_after(network->last_scanned + ieee->scan_age, jiffies)) + ev = rtl819x_translate_scan(ieee, ev, stop, network, + info); + else + RTLLIB_DEBUG_SCAN("Not showing network '%s ( %pM)' due to age (%lums).\n", + escape_essid(network->ssid, + network->ssid_len), + network->bssid, + (jiffies - network->last_scanned) / (HZ / 100)); + } + + spin_unlock_irqrestore(&ieee->lock, flags); + up(&ieee->wx_sem); + wrqu->data.length = ev - extra; + wrqu->data.flags = 0; + + RTLLIB_DEBUG_WX("exit: %d networks returned.\n", i); + + return err; +} +EXPORT_SYMBOL(rtllib_wx_get_scan); + +int rtllib_wx_set_encode(struct rtllib_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *keybuf) +{ + struct iw_point *erq = &(wrqu->encoding); + struct net_device *dev = ieee->dev; + struct rtllib_security sec = { + .flags = 0 + }; + int i, key, key_provided, len; + struct lib80211_crypt_data **crypt; + + RTLLIB_DEBUG_WX("SET_ENCODE\n"); + + key = erq->flags & IW_ENCODE_INDEX; + if (key) { + if (key > NUM_WEP_KEYS) + return -EINVAL; + key--; + key_provided = 1; + } else { + key_provided = 0; + key = ieee->crypt_info.tx_keyidx; + } + + RTLLIB_DEBUG_WX("Key: %d [%s]\n", key, key_provided ? + "provided" : "default"); + crypt = &ieee->crypt_info.crypt[key]; + if (erq->flags & IW_ENCODE_DISABLED) { + if (key_provided && *crypt) { + RTLLIB_DEBUG_WX("Disabling encryption on key %d.\n", + key); + lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); + } else + RTLLIB_DEBUG_WX("Disabling encryption.\n"); + + /* Check all the keys to see if any are still configured, + * and if no key index was provided, de-init them all + */ + for (i = 0; i < NUM_WEP_KEYS; i++) { + if (ieee->crypt_info.crypt[i] != NULL) { + if (key_provided) + break; + lib80211_crypt_delayed_deinit(&ieee->crypt_info, + &ieee->crypt_info.crypt[i]); + } + } + + if (i == NUM_WEP_KEYS) { + sec.enabled = 0; + sec.level = SEC_LEVEL_0; + sec.flags |= SEC_ENABLED | SEC_LEVEL; + } + + goto done; + } + + + + sec.enabled = 1; + sec.flags |= SEC_ENABLED; + + if (*crypt != NULL && (*crypt)->ops != NULL && + strcmp((*crypt)->ops->name, "R-WEP") != 0) { + /* changing to use WEP; deinit previously used algorithm + * on this key + */ + lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); + } + + if (*crypt == NULL) { + struct lib80211_crypt_data *new_crypt; + + /* take WEP into use */ + new_crypt = kzalloc(sizeof(struct lib80211_crypt_data), + GFP_KERNEL); + if (new_crypt == NULL) + return -ENOMEM; + new_crypt->ops = lib80211_get_crypto_ops("R-WEP"); + if (!new_crypt->ops) { + request_module("rtllib_crypt_wep"); + new_crypt->ops = lib80211_get_crypto_ops("R-WEP"); + } + + if (new_crypt->ops) + new_crypt->priv = new_crypt->ops->init(key); + + if (!new_crypt->ops || !new_crypt->priv) { + kfree(new_crypt); + new_crypt = NULL; + + netdev_warn(dev, + "%s: could not initialize WEP: load module rtllib_crypt_wep\n", + dev->name); + return -EOPNOTSUPP; + } + *crypt = new_crypt; + } + + /* If a new key was provided, set it up */ + if (erq->length > 0) { + len = erq->length <= 5 ? 5 : 13; + memcpy(sec.keys[key], keybuf, erq->length); + if (len > erq->length) + memset(sec.keys[key] + erq->length, 0, + len - erq->length); + RTLLIB_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n", + key, escape_essid(sec.keys[key], len), + erq->length, len); + sec.key_sizes[key] = len; + (*crypt)->ops->set_key(sec.keys[key], len, NULL, + (*crypt)->priv); + sec.flags |= (1 << key); + /* This ensures a key will be activated if no key is + * explicitly set + */ + if (key == sec.active_key) + sec.flags |= SEC_ACTIVE_KEY; + ieee->crypt_info.tx_keyidx = key; + + } else { + len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN, + NULL, (*crypt)->priv); + if (len == 0) { + /* Set a default key of all 0 */ + netdev_info(ieee->dev, "Setting key %d to all zero.\n", + key); + + memset(sec.keys[key], 0, 13); + (*crypt)->ops->set_key(sec.keys[key], 13, NULL, + (*crypt)->priv); + sec.key_sizes[key] = 13; + sec.flags |= (1 << key); + } + + /* No key data - just set the default TX key index */ + if (key_provided) { + RTLLIB_DEBUG_WX("Setting key %d to default Tx key.\n", + key); + ieee->crypt_info.tx_keyidx = key; + sec.active_key = key; + sec.flags |= SEC_ACTIVE_KEY; + } + } + done: + ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED); + ieee->auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : + WLAN_AUTH_SHARED_KEY; + sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY; + sec.flags |= SEC_AUTH_MODE; + RTLLIB_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ? + "OPEN" : "SHARED KEY"); + + /* For now we just support WEP, so only set that security level... + * TODO: When WPA is added this is one place that needs to change + */ + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */ + + if (ieee->set_security) + ieee->set_security(dev, &sec); + + /* Do not reset port if card is in Managed mode since resetting will + * generate new IEEE 802.11 authentication which may end up in looping + * with IEEE 802.1X. If your hardware requires a reset after WEP + * configuration (for example... Prism2), implement the reset_port in + * the callbacks structures used to initialize the 802.11 stack. + */ + if (ieee->reset_on_keychange && + ieee->iw_mode != IW_MODE_INFRA && + ieee->reset_port && ieee->reset_port(dev)) { + netdev_dbg(dev, "%s: reset_port failed\n", dev->name); + return -EINVAL; + } + return 0; +} +EXPORT_SYMBOL(rtllib_wx_set_encode); + +int rtllib_wx_get_encode(struct rtllib_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *keybuf) +{ + struct iw_point *erq = &(wrqu->encoding); + int len, key; + struct lib80211_crypt_data *crypt; + + RTLLIB_DEBUG_WX("GET_ENCODE\n"); + + if (ieee->iw_mode == IW_MODE_MONITOR) + return -1; + + key = erq->flags & IW_ENCODE_INDEX; + if (key) { + if (key > NUM_WEP_KEYS) + return -EINVAL; + key--; + } else { + key = ieee->crypt_info.tx_keyidx; + } + crypt = ieee->crypt_info.crypt[key]; + + erq->flags = key + 1; + + if (crypt == NULL || crypt->ops == NULL) { + erq->length = 0; + erq->flags |= IW_ENCODE_DISABLED; + return 0; + } + len = crypt->ops->get_key(keybuf, SCM_KEY_LEN, NULL, crypt->priv); + erq->length = (len >= 0 ? len : 0); + + erq->flags |= IW_ENCODE_ENABLED; + + if (ieee->open_wep) + erq->flags |= IW_ENCODE_OPEN; + else + erq->flags |= IW_ENCODE_RESTRICTED; + + return 0; +} +EXPORT_SYMBOL(rtllib_wx_get_encode); + +int rtllib_wx_set_encode_ext(struct rtllib_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret = 0; + struct net_device *dev = ieee->dev; + struct iw_point *encoding = &wrqu->encoding; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + int i, idx; + int group_key = 0; + const char *alg, *module; + struct lib80211_crypto_ops *ops; + struct lib80211_crypt_data **crypt; + + struct rtllib_security sec = { + .flags = 0, + }; + idx = encoding->flags & IW_ENCODE_INDEX; + if (idx) { + if (idx < 1 || idx > NUM_WEP_KEYS) + return -EINVAL; + idx--; + } else{ + idx = ieee->crypt_info.tx_keyidx; + } + if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { + crypt = &ieee->crypt_info.crypt[idx]; + group_key = 1; + } else { + /* some Cisco APs use idx>0 for unicast in dynamic WEP */ + if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP) + return -EINVAL; + if (ieee->iw_mode == IW_MODE_INFRA) + crypt = &ieee->crypt_info.crypt[idx]; + else + return -EINVAL; + } + + sec.flags |= SEC_ENABLED; + if ((encoding->flags & IW_ENCODE_DISABLED) || + ext->alg == IW_ENCODE_ALG_NONE) { + if (*crypt) + lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); + + for (i = 0; i < NUM_WEP_KEYS; i++) { + if (ieee->crypt_info.crypt[i] != NULL) + break; + } + if (i == NUM_WEP_KEYS) { + sec.enabled = 0; + sec.level = SEC_LEVEL_0; + sec.flags |= SEC_LEVEL; + } + goto done; + } + + sec.enabled = 1; + switch (ext->alg) { + case IW_ENCODE_ALG_WEP: + alg = "R-WEP"; + module = "rtllib_crypt_wep"; + break; + case IW_ENCODE_ALG_TKIP: + alg = "R-TKIP"; + module = "rtllib_crypt_tkip"; + break; + case IW_ENCODE_ALG_CCMP: + alg = "R-CCMP"; + module = "rtllib_crypt_ccmp"; + break; + default: + RTLLIB_DEBUG_WX("%s: unknown crypto alg %d\n", + dev->name, ext->alg); + ret = -EINVAL; + goto done; + } + netdev_info(dev, "alg name:%s\n", alg); + + ops = lib80211_get_crypto_ops(alg); + if (ops == NULL) { + char tempbuf[100]; + + memset(tempbuf, 0x00, 100); + sprintf(tempbuf, "%s", module); + request_module("%s", tempbuf); + ops = lib80211_get_crypto_ops(alg); + } + if (ops == NULL) { + netdev_info(dev, "========>unknown crypto alg %d\n", ext->alg); + ret = -EINVAL; + goto done; + } + + if (*crypt == NULL || (*crypt)->ops != ops) { + struct lib80211_crypt_data *new_crypt; + + lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); + + new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL); + if (new_crypt == NULL) { + ret = -ENOMEM; + goto done; + } + new_crypt->ops = ops; + if (new_crypt->ops) + new_crypt->priv = new_crypt->ops->init(idx); + + if (new_crypt->priv == NULL) { + kfree(new_crypt); + ret = -EINVAL; + goto done; + } + *crypt = new_crypt; + + } + + if (ext->key_len > 0 && (*crypt)->ops->set_key && + (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq, + (*crypt)->priv) < 0) { + netdev_info(dev, "key setting failed\n"); + ret = -EINVAL; + goto done; + } + if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { + ieee->crypt_info.tx_keyidx = idx; + sec.active_key = idx; + sec.flags |= SEC_ACTIVE_KEY; + } + if (ext->alg != IW_ENCODE_ALG_NONE) { + sec.key_sizes[idx] = ext->key_len; + sec.flags |= (1 << idx); + if (ext->alg == IW_ENCODE_ALG_WEP) { + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_1; + } else if (ext->alg == IW_ENCODE_ALG_TKIP) { + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_2; + } else if (ext->alg == IW_ENCODE_ALG_CCMP) { + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_3; + } + /* Don't set sec level for group keys. */ + if (group_key) + sec.flags &= ~SEC_LEVEL; + } +done: + if (ieee->set_security) + ieee->set_security(ieee->dev, &sec); + + if (ieee->reset_on_keychange && + ieee->iw_mode != IW_MODE_INFRA && + ieee->reset_port && ieee->reset_port(dev)) { + RTLLIB_DEBUG_WX("%s: reset_port failed\n", dev->name); + return -EINVAL; + } + return ret; +} +EXPORT_SYMBOL(rtllib_wx_set_encode_ext); + +int rtllib_wx_get_encode_ext(struct rtllib_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct iw_point *encoding = &wrqu->encoding; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + struct lib80211_crypt_data *crypt; + int idx, max_key_len; + + max_key_len = encoding->length - sizeof(*ext); + if (max_key_len < 0) + return -EINVAL; + + idx = encoding->flags & IW_ENCODE_INDEX; + if (idx) { + if (idx < 1 || idx > NUM_WEP_KEYS) + return -EINVAL; + idx--; + } else { + idx = ieee->crypt_info.tx_keyidx; + } + if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) && + (ext->alg != IW_ENCODE_ALG_WEP)) + if (idx != 0 || (ieee->iw_mode != IW_MODE_INFRA)) + return -EINVAL; + + crypt = ieee->crypt_info.crypt[idx]; + + encoding->flags = idx + 1; + memset(ext, 0, sizeof(*ext)); + + if (crypt == NULL || crypt->ops == NULL) { + ext->alg = IW_ENCODE_ALG_NONE; + ext->key_len = 0; + encoding->flags |= IW_ENCODE_DISABLED; + } else { + if (strcmp(crypt->ops->name, "R-WEP") == 0) + ext->alg = IW_ENCODE_ALG_WEP; + else if (strcmp(crypt->ops->name, "R-TKIP")) + ext->alg = IW_ENCODE_ALG_TKIP; + else if (strcmp(crypt->ops->name, "R-CCMP")) + ext->alg = IW_ENCODE_ALG_CCMP; + else + return -EINVAL; + ext->key_len = crypt->ops->get_key(ext->key, SCM_KEY_LEN, + NULL, crypt->priv); + encoding->flags |= IW_ENCODE_ENABLED; + if (ext->key_len && + (ext->alg == IW_ENCODE_ALG_TKIP || + ext->alg == IW_ENCODE_ALG_CCMP)) + ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID; + + } + + return 0; +} + +int rtllib_wx_set_mlme(struct rtllib_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + u8 i = 0; + bool deauth = false; + struct iw_mlme *mlme = (struct iw_mlme *) extra; + + if (ieee->state != RTLLIB_LINKED) + return -ENOLINK; + + down(&ieee->wx_sem); + + switch (mlme->cmd) { + case IW_MLME_DEAUTH: + deauth = true; + /* leave break out intentionly */ + + case IW_MLME_DISASSOC: + if (deauth) + netdev_info(ieee->dev, "disauth packet !\n"); + else + netdev_info(ieee->dev, "dis associate packet!\n"); + + ieee->cannot_notify = true; + + SendDisassociation(ieee, deauth, mlme->reason_code); + rtllib_disassociate(ieee); + + ieee->wap_set = 0; + for (i = 0; i < 6; i++) + ieee->current_network.bssid[i] = 0x55; + + ieee->ssid_set = 0; + ieee->current_network.ssid[0] = '\0'; + ieee->current_network.ssid_len = 0; + break; + default: + up(&ieee->wx_sem); + return -EOPNOTSUPP; + } + + up(&ieee->wx_sem); + + return 0; +} +EXPORT_SYMBOL(rtllib_wx_set_mlme); + +int rtllib_wx_set_auth(struct rtllib_device *ieee, + struct iw_request_info *info, + struct iw_param *data, char *extra) +{ + switch (data->flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: + break; + case IW_AUTH_CIPHER_PAIRWISE: + case IW_AUTH_CIPHER_GROUP: + case IW_AUTH_KEY_MGMT: + /* Host AP driver does not use these parameters and allows + * wpa_supplicant to control them internally. + */ + break; + case IW_AUTH_TKIP_COUNTERMEASURES: + ieee->tkip_countermeasures = data->value; + break; + case IW_AUTH_DROP_UNENCRYPTED: + ieee->drop_unencrypted = data->value; + break; + + case IW_AUTH_80211_AUTH_ALG: + if (data->value & IW_AUTH_ALG_SHARED_KEY) { + ieee->open_wep = 0; + ieee->auth_mode = 1; + } else if (data->value & IW_AUTH_ALG_OPEN_SYSTEM) { + ieee->open_wep = 1; + ieee->auth_mode = 0; + } else if (data->value & IW_AUTH_ALG_LEAP) { + ieee->open_wep = 1; + ieee->auth_mode = 2; + } else + return -EINVAL; + break; + + case IW_AUTH_WPA_ENABLED: + ieee->wpa_enabled = (data->value) ? 1 : 0; + break; + + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + ieee->ieee802_1x = data->value; + break; + case IW_AUTH_PRIVACY_INVOKED: + ieee->privacy_invoked = data->value; + break; + default: + return -EOPNOTSUPP; + } + return 0; +} +EXPORT_SYMBOL(rtllib_wx_set_auth); + +int rtllib_wx_set_gen_ie(struct rtllib_device *ieee, u8 *ie, size_t len) +{ + u8 *buf; + u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04}; + + if (len > MAX_WPA_IE_LEN || (len && ie == NULL)) + return -EINVAL; + + if (len) { + eid = ie[0]; + if ((eid == MFIE_TYPE_GENERIC) && (!memcmp(&ie[2], + wps_oui, 4))) { + + ieee->wps_ie_len = (len < MAX_WZC_IE_LEN) ? (len) : + (MAX_WZC_IE_LEN); + buf = kmemdup(ie, ieee->wps_ie_len, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + ieee->wps_ie = buf; + return 0; + } + } + ieee->wps_ie_len = 0; + kfree(ieee->wps_ie); + ieee->wps_ie = NULL; + if (len) { + if (len != ie[1]+2) + return -EINVAL; + buf = kmemdup(ie, len, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + kfree(ieee->wpa_ie); + ieee->wpa_ie = buf; + ieee->wpa_ie_len = len; + } else { + kfree(ieee->wpa_ie); + ieee->wpa_ie = NULL; + ieee->wpa_ie_len = 0; + } + return 0; +} +EXPORT_SYMBOL(rtllib_wx_set_gen_ie); -- cgit 1.2.3-korg