staging: r8192ee: Add source files for core driver
authorLarry Finger <Larry.Finger@lwfinger.net>
Wed, 21 May 2014 21:25:33 +0000 (16:25 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 23 May 2014 02:33:55 +0000 (11:33 +0900)
This part is the equivalent of rtlwifi in the wireless tree. As the changes
needed for the RTL8192EE have not yet been merged, a separate version is still
needed.

Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
22 files changed:
drivers/staging/rtl8192ee/base.c [new file with mode: 0644]
drivers/staging/rtl8192ee/base.h [new file with mode: 0644]
drivers/staging/rtl8192ee/cam.c [new file with mode: 0644]
drivers/staging/rtl8192ee/cam.h [new file with mode: 0644]
drivers/staging/rtl8192ee/compat.h [new file with mode: 0644]
drivers/staging/rtl8192ee/core.c [new file with mode: 0644]
drivers/staging/rtl8192ee/core.h [new file with mode: 0644]
drivers/staging/rtl8192ee/debug.c [new file with mode: 0644]
drivers/staging/rtl8192ee/debug.h [new file with mode: 0644]
drivers/staging/rtl8192ee/efuse.c [new file with mode: 0644]
drivers/staging/rtl8192ee/efuse.h [new file with mode: 0644]
drivers/staging/rtl8192ee/pci.c [new file with mode: 0644]
drivers/staging/rtl8192ee/pci.h [new file with mode: 0644]
drivers/staging/rtl8192ee/ps.c [new file with mode: 0644]
drivers/staging/rtl8192ee/ps.h [new file with mode: 0644]
drivers/staging/rtl8192ee/rc.c [new file with mode: 0644]
drivers/staging/rtl8192ee/rc.h [new file with mode: 0644]
drivers/staging/rtl8192ee/regd.c [new file with mode: 0644]
drivers/staging/rtl8192ee/regd.h [new file with mode: 0644]
drivers/staging/rtl8192ee/stats.c [new file with mode: 0644]
drivers/staging/rtl8192ee/stats.h [new file with mode: 0644]
drivers/staging/rtl8192ee/wifi.h [new file with mode: 0644]

diff --git a/drivers/staging/rtl8192ee/base.c b/drivers/staging/rtl8192ee/base.c
new file mode 100644 (file)
index 0000000..64ade21
--- /dev/null
@@ -0,0 +1,1852 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include <linux/ip.h>
+#include <linux/module.h>
+#include "wifi.h"
+#include "rc.h"
+#include "base.h"
+#include "efuse.h"
+#include "cam.h"
+#include "ps.h"
+#include "regd.h"
+#include "pci.h"
+
+/*
+ *NOTICE!!!: This file will be very big, we hsould
+ *keep it clear under follwing roles:
+ *
+ *This file include follwing part, so, if you add new
+ *functions into this file, please check which part it
+ *should includes. or check if you should add new part
+ *for this file:
+ *
+ *1) mac80211 init functions
+ *2) tx information functions
+ *3) functions called by core.c
+ *4) wq & timer callback functions
+ *5) frame process functions
+ *6) IOT functions
+ *7) sysfs functions
+ *8) vif functions
+ *9) ...
+ */
+
+/*********************************************************
+ *
+ * mac80211 init functions
+ *
+ *********************************************************/
+static struct ieee80211_channel rtl_channeltable_2g[] = {
+       {.center_freq = 2412, .hw_value = 1,},
+       {.center_freq = 2417, .hw_value = 2,},
+       {.center_freq = 2422, .hw_value = 3,},
+       {.center_freq = 2427, .hw_value = 4,},
+       {.center_freq = 2432, .hw_value = 5,},
+       {.center_freq = 2437, .hw_value = 6,},
+       {.center_freq = 2442, .hw_value = 7,},
+       {.center_freq = 2447, .hw_value = 8,},
+       {.center_freq = 2452, .hw_value = 9,},
+       {.center_freq = 2457, .hw_value = 10,},
+       {.center_freq = 2462, .hw_value = 11,},
+       {.center_freq = 2467, .hw_value = 12,},
+       {.center_freq = 2472, .hw_value = 13,},
+       {.center_freq = 2484, .hw_value = 14,},
+};
+
+static struct ieee80211_channel rtl_channeltable_5g[] = {
+       {.center_freq = 5180, .hw_value = 36,},
+       {.center_freq = 5200, .hw_value = 40,},
+       {.center_freq = 5220, .hw_value = 44,},
+       {.center_freq = 5240, .hw_value = 48,},
+       {.center_freq = 5260, .hw_value = 52,},
+       {.center_freq = 5280, .hw_value = 56,},
+       {.center_freq = 5300, .hw_value = 60,},
+       {.center_freq = 5320, .hw_value = 64,},
+       {.center_freq = 5500, .hw_value = 100,},
+       {.center_freq = 5520, .hw_value = 104,},
+       {.center_freq = 5540, .hw_value = 108,},
+       {.center_freq = 5560, .hw_value = 112,},
+       {.center_freq = 5580, .hw_value = 116,},
+       {.center_freq = 5600, .hw_value = 120,},
+       {.center_freq = 5620, .hw_value = 124,},
+       {.center_freq = 5640, .hw_value = 128,},
+       {.center_freq = 5660, .hw_value = 132,},
+       {.center_freq = 5680, .hw_value = 136,},
+       {.center_freq = 5700, .hw_value = 140,},
+       {.center_freq = 5745, .hw_value = 149,},
+       {.center_freq = 5765, .hw_value = 153,},
+       {.center_freq = 5785, .hw_value = 157,},
+       {.center_freq = 5805, .hw_value = 161,},
+       {.center_freq = 5825, .hw_value = 165,},
+};
+
+static struct ieee80211_rate rtl_ratetable_2g[] = {
+       {.bitrate = 10, .hw_value = 0x00,},
+       {.bitrate = 20, .hw_value = 0x01,},
+       {.bitrate = 55, .hw_value = 0x02,},
+       {.bitrate = 110, .hw_value = 0x03,},
+       {.bitrate = 60, .hw_value = 0x04,},
+       {.bitrate = 90, .hw_value = 0x05,},
+       {.bitrate = 120, .hw_value = 0x06,},
+       {.bitrate = 180, .hw_value = 0x07,},
+       {.bitrate = 240, .hw_value = 0x08,},
+       {.bitrate = 360, .hw_value = 0x09,},
+       {.bitrate = 480, .hw_value = 0x0a,},
+       {.bitrate = 540, .hw_value = 0x0b,},
+};
+
+static struct ieee80211_rate rtl_ratetable_5g[] = {
+       {.bitrate = 60, .hw_value = 0x04,},
+       {.bitrate = 90, .hw_value = 0x05,},
+       {.bitrate = 120, .hw_value = 0x06,},
+       {.bitrate = 180, .hw_value = 0x07,},
+       {.bitrate = 240, .hw_value = 0x08,},
+       {.bitrate = 360, .hw_value = 0x09,},
+       {.bitrate = 480, .hw_value = 0x0a,},
+       {.bitrate = 540, .hw_value = 0x0b,},
+};
+
+static const struct ieee80211_supported_band rtl_band_2ghz = {
+       .band = IEEE80211_BAND_2GHZ,
+
+       .channels = rtl_channeltable_2g,
+       .n_channels = ARRAY_SIZE(rtl_channeltable_2g),
+
+       .bitrates = rtl_ratetable_2g,
+       .n_bitrates = ARRAY_SIZE(rtl_ratetable_2g),
+
+       .ht_cap = {0},
+};
+
+static struct ieee80211_supported_band rtl_band_5ghz = {
+       .band = IEEE80211_BAND_5GHZ,
+
+       .channels = rtl_channeltable_5g,
+       .n_channels = ARRAY_SIZE(rtl_channeltable_5g),
+
+       .bitrates = rtl_ratetable_5g,
+       .n_bitrates = ARRAY_SIZE(rtl_ratetable_5g),
+
+       .ht_cap = {0},
+};
+
+static const u8 tid_to_ac[] = {
+       2, /* IEEE80211_AC_BE */
+       3, /* IEEE80211_AC_BK */
+       3, /* IEEE80211_AC_BK */
+       2, /* IEEE80211_AC_BE */
+       1, /* IEEE80211_AC_VI */
+       1, /* IEEE80211_AC_VI */
+       0, /* IEEE80211_AC_VO */
+       0, /* IEEE80211_AC_VO */
+};
+
+u8 rtl92e_tid_to_ac(struct ieee80211_hw *hw, u8 tid)
+{
+       return tid_to_ac[tid];
+}
+
+static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw,
+                                 struct ieee80211_sta_ht_cap *ht_cap)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+       ht_cap->ht_supported = true;
+       ht_cap->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
+           IEEE80211_HT_CAP_SGI_40 |
+           IEEE80211_HT_CAP_SGI_20 |
+           IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU;
+
+       if (rtlpriv->rtlhal.disable_amsdu_8k)
+               ht_cap->cap &= ~IEEE80211_HT_CAP_MAX_AMSDU;
+
+       /*
+        *Maximum length of AMPDU that the STA can receive.
+        *Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets)
+        */
+       ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+
+       /*Minimum MPDU start spacing , */
+       ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
+
+       ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+
+       /*
+        *hw->wiphy->bands[IEEE80211_BAND_2GHZ]
+        *base on ant_num
+        *rx_mask: RX mask
+        *if rx_ant =1 rx_mask[0]=0xff;==>MCS0-MCS7
+        *if rx_ant =2 rx_mask[1]=0xff;==>MCS8-MCS15
+        *if rx_ant >=3 rx_mask[2]=0xff;
+        *if BW_40 rx_mask[4]=0x01;
+        *highest supported RX rate
+        */
+       if (rtlpriv->dm.supp_phymode_switch) {
+               RT_TRACE(COMP_INIT, DBG_EMERG, ("Support phy mode switch\n"));
+
+               ht_cap->mcs.rx_mask[0] = 0xFF;
+               ht_cap->mcs.rx_mask[1] = 0xFF;
+               ht_cap->mcs.rx_mask[4] = 0x01;
+
+               ht_cap->mcs.rx_highest = cpu_to_le16(MAX_BIT_RATE_40MHZ_MCS15);
+       } else {
+               if (get_rf_type(rtlphy) == RF_1T2R ||
+                   get_rf_type(rtlphy) == RF_2T2R) {
+                       RT_TRACE(COMP_INIT, DBG_DMESG, ("1T2R or 2T2R\n"));
+
+                       ht_cap->mcs.rx_mask[0] = 0xFF;
+                       ht_cap->mcs.rx_mask[1] = 0xFF;
+                       ht_cap->mcs.rx_mask[4] = 0x01;
+
+                       ht_cap->mcs.rx_highest = cpu_to_le16(MAX_BIT_RATE_40MHZ_MCS15);
+               } else if (get_rf_type(rtlphy) == RF_1T1R) {
+                       RT_TRACE(COMP_INIT, DBG_DMESG, ("1T1R\n"));
+
+                       ht_cap->mcs.rx_mask[0] = 0xFF;
+                       ht_cap->mcs.rx_mask[1] = 0x00;
+                       ht_cap->mcs.rx_mask[4] = 0x01;
+
+                       ht_cap->mcs.rx_highest = cpu_to_le16(MAX_BIT_RATE_40MHZ_MCS7);
+               }
+       }
+}
+
+static void _rtl_init_hw_vht_capab(struct ieee80211_hw *hw,
+                                  struct ieee80211_sta_vht_cap *vht_cap)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+
+       if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) {
+               u16 mcs_map;
+               vht_cap->vht_supported = true;
+               vht_cap->cap =
+                       IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 |
+                       IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 |
+                       IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
+                       IEEE80211_VHT_CAP_SHORT_GI_80 |
+                       IEEE80211_VHT_CAP_TXSTBC |
+                       IEEE80211_VHT_CAP_RXSTBC_1 |
+                       IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
+                       IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
+                       IEEE80211_VHT_CAP_HTC_VHT |
+                       IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK |
+                       IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
+                       IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN |
+                       0;
+
+               mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 |
+                       IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 |
+                       IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 |
+                       IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 |
+                       IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 |
+                       IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 |
+                       IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 |
+                       IEEE80211_VHT_MCS_NOT_SUPPORTED << 14;
+
+               vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
+               vht_cap->vht_mcs.rx_highest =
+                       cpu_to_le16(MAX_BIT_RATE_SHORT_GI_2NSS_80MHZ_MCS9);
+               vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
+               vht_cap->vht_mcs.tx_highest =
+                       cpu_to_le16(MAX_BIT_RATE_SHORT_GI_2NSS_80MHZ_MCS9);
+       } else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) {
+               u16 mcs_map;
+
+               vht_cap->vht_supported = true;
+               vht_cap->cap =
+                       IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 |
+                       IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 |
+                       IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
+                       IEEE80211_VHT_CAP_SHORT_GI_80 |
+                       IEEE80211_VHT_CAP_TXSTBC |
+                       IEEE80211_VHT_CAP_RXSTBC_1 |
+                       IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
+                       IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
+                       IEEE80211_VHT_CAP_HTC_VHT |
+                       IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK |
+                       IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
+                       IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN |
+                       0;
+
+               mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 |
+                       IEEE80211_VHT_MCS_NOT_SUPPORTED << 2 |
+                       IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 |
+                       IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 |
+                       IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 |
+                       IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 |
+                       IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 |
+                       IEEE80211_VHT_MCS_NOT_SUPPORTED << 14;
+
+               vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
+               vht_cap->vht_mcs.rx_highest =
+                       cpu_to_le16(MAX_BIT_RATE_SHORT_GI_1NSS_80MHZ_MCS9);
+               vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
+               vht_cap->vht_mcs.tx_highest =
+                       cpu_to_le16(MAX_BIT_RATE_SHORT_GI_1NSS_80MHZ_MCS9);
+       }
+}
+
+static void _rtl_init_mac80211(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+       struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw));
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       struct ieee80211_supported_band *sband;
+
+
+       if (rtlhal->macphymode == SINGLEMAC_SINGLEPHY &&
+           rtlhal->bandset == BAND_ON_BOTH) {
+               /* 1: 2.4 G bands */
+               /* <1> use  mac->bands as mem for hw->wiphy->bands */
+               sband = &(rtlmac->bands[IEEE80211_BAND_2GHZ]);
+
+               /* <2> set hw->wiphy->bands[IEEE80211_BAND_2GHZ]
+                * to default value(1T1R) */
+               memcpy(&(rtlmac->bands[IEEE80211_BAND_2GHZ]), &rtl_band_2ghz,
+                      sizeof(struct ieee80211_supported_band));
+
+               /* <3> init ht cap base on ant_num */
+               _rtl_init_hw_ht_capab(hw, &sband->ht_cap);
+
+               /* <4> set mac->sband to wiphy->sband */
+               hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband;
+
+               /* 2: 5 G bands */
+               /* <1> use  mac->bands as mem for hw->wiphy->bands */
+               sband = &(rtlmac->bands[IEEE80211_BAND_5GHZ]);
+
+               /* <2> set hw->wiphy->bands[IEEE80211_BAND_5GHZ]
+                * to default value(1T1R) */
+               memcpy(&(rtlmac->bands[IEEE80211_BAND_5GHZ]), &rtl_band_5ghz,
+                      sizeof(struct ieee80211_supported_band));
+
+               /* <3> init ht cap base on ant_num */
+               _rtl_init_hw_ht_capab(hw, &sband->ht_cap);
+
+               _rtl_init_hw_vht_capab(hw, &sband->vht_cap);
+
+               /* <4> set mac->sband to wiphy->sband */
+               hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband;
+       } else {
+               if (rtlhal->current_bandtype == BAND_ON_2_4G) {
+                       /* <1> use  mac->bands as mem for hw->wiphy->bands */
+                       sband = &(rtlmac->bands[IEEE80211_BAND_2GHZ]);
+
+                       /* <2> set hw->wiphy->bands[IEEE80211_BAND_2GHZ]
+                        * to default value(1T1R) */
+                       memcpy(&(rtlmac->bands[IEEE80211_BAND_2GHZ]),
+                              &rtl_band_2ghz,
+                              sizeof(struct ieee80211_supported_band));
+
+                       /* <3> init ht cap base on ant_num */
+                       _rtl_init_hw_ht_capab(hw, &sband->ht_cap);
+
+                       /* <4> set mac->sband to wiphy->sband */
+                       hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband;
+               } else if (rtlhal->current_bandtype == BAND_ON_5G) {
+                       /* <1> use  mac->bands as mem for hw->wiphy->bands */
+                       sband = &(rtlmac->bands[IEEE80211_BAND_5GHZ]);
+
+                       /* <2> set hw->wiphy->bands[IEEE80211_BAND_5GHZ]
+                        * to default value(1T1R) */
+                       memcpy(&(rtlmac->bands[IEEE80211_BAND_5GHZ]),
+                              &rtl_band_5ghz,
+                              sizeof(struct ieee80211_supported_band));
+
+                       /* <3> init ht cap base on ant_num */
+                       _rtl_init_hw_ht_capab(hw, &sband->ht_cap);
+
+                       _rtl_init_hw_vht_capab(hw, &sband->vht_cap);
+
+                       /* <4> set mac->sband to wiphy->sband */
+                       hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband;
+               } else {
+                       RT_TRACE(COMP_INIT, DBG_EMERG,
+                                ("Err BAND %d\n", rtlhal->current_bandtype));
+               }
+       }
+       /* <5> set hw caps */
+       hw->flags = IEEE80211_HW_SIGNAL_DBM |
+           IEEE80211_HW_RX_INCLUDES_FCS |
+           IEEE80211_HW_AMPDU_AGGREGATION |
+           IEEE80211_HW_REPORTS_TX_ACK_STATUS |
+           IEEE80211_HW_CONNECTION_MONITOR |
+           /* IEEE80211_HW_SUPPORTS_CQM_RSSI | */
+           IEEE80211_HW_MFP_CAPABLE | 0;
+
+       /* swlps or hwlps has been set in diff chip in init_sw_vars */
+       if (rtlpriv->psc.b_swctrl_lps)
+               hw->flags |= IEEE80211_HW_SUPPORTS_PS |
+                       IEEE80211_HW_PS_NULLFUNC_STACK |
+                       /* IEEE80211_HW_SUPPORTS_DYNAMIC_PS | */
+                       0;
+/*<delete in kernel start>*/
+       hw->wiphy->interface_modes =
+               BIT(NL80211_IFTYPE_AP) |
+               BIT(NL80211_IFTYPE_STATION) |
+               BIT(NL80211_IFTYPE_ADHOC) |
+               BIT(NL80211_IFTYPE_MESH_POINT) |
+               BIT(NL80211_IFTYPE_P2P_CLIENT) |
+               BIT(NL80211_IFTYPE_P2P_GO);
+       hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
+
+       hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+
+       hw->wiphy->rts_threshold = 2347;
+
+       hw->queues = AC_MAX;
+       hw->extra_tx_headroom = RTL_TX_HEADER_SIZE;
+
+       /* TODO: Correct this value for our hw */
+       /* TODO: define these hard code value */
+       /* hw->channel_change_time = 100; kernel does not use it*/
+       hw->max_listen_interval = 10;
+       hw->max_rate_tries = 4;
+       /* hw->max_rates = 1; */
+       hw->sta_data_size = sizeof(struct rtl_sta_info);
+
+/* wowlan is not supported by kernel if CONFIG_PM is not defined */
+#ifdef CONFIG_PM
+       if (rtlpriv->psc.wo_wlan_mode) {
+               if (rtlpriv->psc.wo_wlan_mode & WAKE_ON_MAGIC_PACKET)
+                       rtlpriv->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT;
+               if (rtlpriv->psc.wo_wlan_mode & WAKE_ON_PATTERN_MATCH) {
+                       rtlpriv->wowlan.n_patterns =
+                               MAX_SUPPORT_WOL_PATTERN_NUM;
+                       rtlpriv->wowlan.pattern_min_len = MIN_WOL_PATTERN_SIZE;
+                       rtlpriv->wowlan.pattern_max_len = MAX_WOL_PATTERN_SIZE;
+               }
+               hw->wiphy->wowlan = &(rtlpriv->wowlan);
+       }
+#endif
+
+       /* <6> mac address */
+       if (is_valid_ether_addr(rtlefuse->dev_addr)) {
+               SET_IEEE80211_PERM_ADDR(hw, rtlefuse->dev_addr);
+       } else {
+               u8 rtlmac[] = { 0x00, 0xe0, 0x4c, 0x81, 0x92, 0x00 };
+               get_random_bytes((rtlmac + (ETH_ALEN - 1)), 1);
+               SET_IEEE80211_PERM_ADDR(hw, rtlmac);
+       }
+}
+
+static void _rtl_init_deferred_work(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       /* <1> timer */
+       init_timer(&rtlpriv->works.watchdog_timer);
+       setup_timer(&rtlpriv->works.watchdog_timer,
+                   rtl92e_watch_dog_timer_callback, (unsigned long)hw);
+       init_timer(&rtlpriv->works.dualmac_easyconcurrent_retrytimer);
+       setup_timer(&rtlpriv->works.dualmac_easyconcurrent_retrytimer,
+                   rtl92e_easy_concurrent_retrytimer_callback, (unsigned long)hw);
+       /* <2> work queue */
+       rtlpriv->works.hw = hw;
+       rtlpriv->works.rtl_wq = alloc_workqueue(rtlpriv->cfg->name, 0, 0);
+       INIT_DELAYED_WORK(&rtlpriv->works.watchdog_wq,
+                         (void *)rtl92e_watchdog_wq_callback);
+       INIT_DELAYED_WORK(&rtlpriv->works.ips_nic_off_wq,
+                         (void *)rtl92e_ips_nic_off_wq_callback);
+       INIT_DELAYED_WORK(&rtlpriv->works.ps_work,
+                         (void *)rtl92e_swlps_wq_callback);
+       INIT_DELAYED_WORK(&rtlpriv->works.ps_rfon_wq,
+                         (void *)rtl92e_swlps_rfon_wq_callback);
+       INIT_DELAYED_WORK(&rtlpriv->works.fwevt_wq,
+                         (void *)rtl92e_fwevt_wq_callback);
+}
+
+void rtl92e_deinit_deferred_work(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       del_timer_sync(&rtlpriv->works.watchdog_timer);
+
+       cancel_delayed_work(&rtlpriv->works.watchdog_wq);
+       cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq);
+       cancel_delayed_work(&rtlpriv->works.ps_work);
+       cancel_delayed_work(&rtlpriv->works.ps_rfon_wq);
+       cancel_delayed_work(&rtlpriv->works.fwevt_wq);
+}
+
+void rtl92e_init_rfkill(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       bool radio_state;
+       bool blocked;
+       u8 valid = 0;
+
+       /*set init state to on */
+       rtlpriv->rfkill.rfkill_state = 1;
+       wiphy_rfkill_set_hw_state(hw->wiphy, 0);
+
+       radio_state = rtlpriv->cfg->ops->radio_onoff_checking(hw, &valid);
+
+       if (valid) {
+               pr_info("rtlwifi: wireless switch is %s\n",
+                       rtlpriv->rfkill.rfkill_state ? "on" : "off");
+
+               rtlpriv->rfkill.rfkill_state = radio_state;
+
+               blocked = (rtlpriv->rfkill.rfkill_state == 1) ? 0 : 1;
+               wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
+       }
+
+       wiphy_rfkill_start_polling(hw->wiphy);
+}
+
+void rtl92e_deinit_rfkill(struct ieee80211_hw *hw)
+{
+       wiphy_rfkill_stop_polling(hw->wiphy);
+}
+
+#ifdef VIF_TODO
+static void rtl_init_vif(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       INIT_LIST_HEAD(&rtlpriv->vif_priv.vif_list);
+
+       rtlpriv->vif_priv.vifs = 0;
+}
+#endif
+
+int rtl92e_init_core(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw));
+
+       /* <1> init mac80211 */
+       _rtl_init_mac80211(hw);
+       rtlmac->hw = hw;
+       rtlmac->link_state = MAC80211_NOLINK;
+
+       /* <2> rate control register */
+       hw->rate_control_algorithm = "rtl_rc";
+
+       /*
+        * <3> init CRDA must come after init
+        * mac80211 hw  in _rtl_init_mac80211.
+        */
+       if (rtl92e_regd_init(hw, rtl92e_reg_notifier)) {
+               RT_TRACE(COMP_ERR, DBG_EMERG, ("REGD init failed\n"));
+               return 1;
+       }
+
+       /* <4> locks */
+       mutex_init(&rtlpriv->locks.conf_mutex);
+       spin_lock_init(&rtlpriv->locks.ips_lock);
+       spin_lock_init(&rtlpriv->locks.irq_th_lock);
+       spin_lock_init(&rtlpriv->locks.h2c_lock);
+       spin_lock_init(&rtlpriv->locks.rf_ps_lock);
+       spin_lock_init(&rtlpriv->locks.rf_lock);
+       spin_lock_init(&rtlpriv->locks.lps_lock);
+       spin_lock_init(&rtlpriv->locks.waitq_lock);
+       spin_lock_init(&rtlpriv->locks.entry_list_lock);
+       spin_lock_init(&rtlpriv->locks.cck_and_rw_pagea_lock);
+       spin_lock_init(&rtlpriv->locks.check_sendpkt_lock);
+       spin_lock_init(&rtlpriv->locks.fw_ps_lock);
+       spin_lock_init(&rtlpriv->locks.iqk_lock);
+       /* <5> init list */
+       INIT_LIST_HEAD(&rtlpriv->entry_list);
+
+       /* <6> init deferred work */
+       _rtl_init_deferred_work(hw);
+
+       /* <7> */
+#ifdef VIF_TODO
+       rtl_init_vif(hw);
+#endif
+
+       return 0;
+}
+
+void rtl92e_deinit_core(struct ieee80211_hw *hw)
+{
+}
+
+void rtl92e_init_rx_config(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+
+       rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *)(&mac->rx_conf));
+}
+
+/*********************************************************
+ *
+ * tx information functions
+ *
+ *********************************************************/
+static void _rtl_qurey_shortpreamble_mode(struct ieee80211_hw *hw,
+                                         struct rtl_tcb_desc *tcb_desc,
+                                         struct ieee80211_tx_info *info)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 rate_flag = info->control.rates[0].flags;
+
+       tcb_desc->use_shortpreamble = false;
+
+       /* 1M can only use Long Preamble. 11B spec */
+       if (tcb_desc->hw_rate == rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M])
+               return;
+       else if (rate_flag & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
+               tcb_desc->use_shortpreamble = true;
+
+       return;
+}
+
+static void _rtl_query_shortgi(struct ieee80211_hw *hw,
+                              struct ieee80211_sta *sta,
+                              struct rtl_tcb_desc *tcb_desc,
+                              struct ieee80211_tx_info *info)
+{
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       u8 rate_flag = info->control.rates[0].flags;
+       u8 sgi_40 = 0, sgi_20 = 0, bw_40 = 0;
+       u8 sgi_80 = 0, bw_80 = 0;
+       tcb_desc->use_shortgi = false;
+
+       if (sta == NULL)
+               return;
+
+       sgi_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40;
+       sgi_20 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20;
+       sgi_80 = sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80;
+
+       if (!(sta->ht_cap.ht_supported) && !(sta->vht_cap.vht_supported))
+               return;
+
+       if (!sgi_40 && !sgi_20)
+               return;
+
+       if (mac->opmode == NL80211_IFTYPE_STATION) {
+               bw_40 = mac->bw_40;
+               bw_80 = mac->bw_80;
+       } else if (mac->opmode == NL80211_IFTYPE_AP ||
+                  mac->opmode == NL80211_IFTYPE_ADHOC ||
+                  mac->opmode == NL80211_IFTYPE_MESH_POINT) {
+               bw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+               bw_80 = sta->vht_cap.vht_supported;
+       }
+
+       if (bw_80) {
+               if (sgi_80)
+                       tcb_desc->use_shortgi = true;
+               else
+                       tcb_desc->use_shortgi = false;
+       } else {
+               if (bw_40 && sgi_40)
+                       tcb_desc->use_shortgi = true;
+               else if (!bw_40 && sgi_20)
+                       tcb_desc->use_shortgi = true;
+       }
+
+       if (!(rate_flag & IEEE80211_TX_RC_SHORT_GI))
+               tcb_desc->use_shortgi = false;
+}
+
+static void _rtl_query_protection_mode(struct ieee80211_hw *hw,
+                                      struct rtl_tcb_desc *tcb_desc,
+                                      struct ieee80211_tx_info *info)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 rate_flag = info->control.rates[0].flags;
+
+       /* Common Settings */
+       tcb_desc->b_rts_stbc = false;
+       tcb_desc->b_cts_enable = false;
+       tcb_desc->rts_sc = 0;
+       tcb_desc->b_rts_bw = false;
+       tcb_desc->b_rts_use_shortpreamble = false;
+       tcb_desc->b_rts_use_shortgi = false;
+
+       if (rate_flag & IEEE80211_TX_RC_USE_CTS_PROTECT) {
+               /* Use CTS-to-SELF in protection mode. */
+               tcb_desc->b_rts_enable = true;
+               tcb_desc->b_cts_enable = true;
+               tcb_desc->rts_rate = rtlpriv->cfg->maps[RTL_RC_OFDM_RATE24M];
+       } else if (rate_flag & IEEE80211_TX_RC_USE_RTS_CTS) {
+               /* Use RTS-CTS in protection mode. */
+               tcb_desc->b_rts_enable = true;
+               tcb_desc->rts_rate = rtlpriv->cfg->maps[RTL_RC_OFDM_RATE24M];
+       }
+}
+
+static void _rtl_txrate_selectmode(struct ieee80211_hw *hw,
+                                  struct ieee80211_sta *sta,
+                                  struct rtl_tcb_desc *tcb_desc)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_sta_info *sta_entry = NULL;
+       u8 ratr_index = 7;
+
+       if (sta) {
+               sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+               ratr_index = sta_entry->ratr_index;
+       }
+       if (!tcb_desc->disable_ratefallback || !tcb_desc->use_driver_rate) {
+               if (mac->opmode == NL80211_IFTYPE_STATION) {
+                       tcb_desc->ratr_index = 0;
+               } else if (mac->opmode == NL80211_IFTYPE_ADHOC ||
+                               mac->opmode == NL80211_IFTYPE_MESH_POINT) {
+                       if (tcb_desc->b_multicast || tcb_desc->b_broadcast) {
+                               tcb_desc->hw_rate =
+                                   rtlpriv->cfg->maps[RTL_RC_CCK_RATE2M];
+                               tcb_desc->use_driver_rate = 1;
+                               tcb_desc->ratr_index = RATR_INX_WIRELESS_MC;
+                       } else {
+                               tcb_desc->ratr_index = ratr_index;
+                       }
+               } else if (mac->opmode == NL80211_IFTYPE_AP) {
+                       tcb_desc->ratr_index = ratr_index;
+               }
+       }
+
+       if (rtlpriv->dm.b_useramask) {
+               tcb_desc->ratr_index = ratr_index;
+               /* TODO we will differentiate adhoc and station futrue  */
+               if (mac->opmode == NL80211_IFTYPE_STATION ||
+                   mac->opmode == NL80211_IFTYPE_MESH_POINT) {
+                       tcb_desc->mac_id = 0;
+
+                       if (mac->mode == WIRELESS_MODE_AC_5G)
+                               tcb_desc->ratr_index =
+                                       RATR_INX_WIRELESS_AC_5N;
+                       else if (mac->mode == WIRELESS_MODE_AC_24G)
+                               tcb_desc->ratr_index =
+                                       RATR_INX_WIRELESS_AC_24N;
+                       else if (mac->mode == WIRELESS_MODE_N_24G)
+                               tcb_desc->ratr_index = RATR_INX_WIRELESS_NGB;
+                       else if (mac->mode == WIRELESS_MODE_N_5G)
+                               tcb_desc->ratr_index = RATR_INX_WIRELESS_NG;
+                       else if (mac->mode & WIRELESS_MODE_G)
+                               tcb_desc->ratr_index = RATR_INX_WIRELESS_GB;
+                       else if (mac->mode & WIRELESS_MODE_B)
+                               tcb_desc->ratr_index = RATR_INX_WIRELESS_B;
+                       else if (mac->mode & WIRELESS_MODE_A)
+                               tcb_desc->ratr_index = RATR_INX_WIRELESS_G;
+
+               } else if (mac->opmode == NL80211_IFTYPE_AP ||
+                          mac->opmode == NL80211_IFTYPE_ADHOC) {
+                       if (sta) {
+                               if (sta->aid > 0)
+                                       tcb_desc->mac_id = sta->aid + 1;
+                               else
+                                       tcb_desc->mac_id = 1;
+                       } else {
+                               tcb_desc->mac_id = 0;
+                       }
+               }
+       }
+}
+
+static void _rtl_query_bandwidth_mode(struct ieee80211_hw *hw,
+                                     struct ieee80211_sta *sta,
+                                     struct rtl_tcb_desc *tcb_desc)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+
+       tcb_desc->packet_bw = 0;
+       if (!sta)
+               return;
+       if (mac->opmode == NL80211_IFTYPE_AP ||
+           mac->opmode == NL80211_IFTYPE_ADHOC ||
+           mac->opmode == NL80211_IFTYPE_MESH_POINT) {
+               if (!(sta->ht_cap.ht_supported) ||
+                   !(sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
+                       return;
+       } else if (mac->opmode == NL80211_IFTYPE_STATION) {
+               if (!mac->bw_40 || !(sta->ht_cap.ht_supported))
+                       return;
+       }
+       if (tcb_desc->b_multicast || tcb_desc->b_broadcast)
+               return;
+
+       /*use legency rate, shall use 20MHz */
+       if (tcb_desc->hw_rate <= rtlpriv->cfg->maps[RTL_RC_OFDM_RATE54M])
+               return;
+
+       tcb_desc->packet_bw = HT_CHANNEL_WIDTH_20_40;
+
+       if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8812AE ||
+           rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8821AE) {
+               if (mac->opmode == NL80211_IFTYPE_AP ||
+                   mac->opmode == NL80211_IFTYPE_ADHOC ||
+                   mac->opmode == NL80211_IFTYPE_MESH_POINT) {
+                       if (!(sta->vht_cap.vht_supported)) {
+                               return;
+                       } else if (mac->opmode == NL80211_IFTYPE_STATION) {
+                               if (!mac->bw_80 ||
+                                   !(sta->vht_cap.vht_supported))
+                                       return;
+                       }
+               }
+               if (tcb_desc->hw_rate <=
+                       rtlpriv->cfg->maps[RTL_RC_HT_RATEMCS15])
+                       return;
+               tcb_desc->packet_bw = HT_CHANNEL_WIDTH_80;
+       }
+}
+
+static u8 _rtl_get_vht_highest_n_rate(struct ieee80211_hw *hw,
+                                     struct ieee80211_sta *sta)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       u8 hw_rate;
+       u16 map = le16_to_cpu(sta->vht_cap.vht_mcs.tx_mcs_map);
+
+       if ((get_rf_type(rtlphy) == RF_2T2R) &&
+           (map & 0x000c) != 0x000c0) {
+               if ((map & 0x000c) >> 2 == IEEE80211_VHT_MCS_SUPPORT_0_7)
+                       hw_rate =
+                       rtlpriv->cfg->maps[RTL_RC_VHT_RATE_2SS_MCS7];
+               else if ((map  & 0x000c) >> 2 == IEEE80211_VHT_MCS_SUPPORT_0_8)
+                       hw_rate = rtlpriv->cfg->maps[RTL_RC_VHT_RATE_2SS_MCS9];
+               else
+                       hw_rate = rtlpriv->cfg->maps[RTL_RC_VHT_RATE_2SS_MCS9];
+       } else {
+               if ((map  & 0x0003) == IEEE80211_VHT_MCS_SUPPORT_0_7)
+                       hw_rate = rtlpriv->cfg->maps[RTL_RC_VHT_RATE_1SS_MCS7];
+               else if ((map  & 0x0003) == IEEE80211_VHT_MCS_SUPPORT_0_8)
+                       hw_rate = rtlpriv->cfg->maps[RTL_RC_VHT_RATE_1SS_MCS9];
+               else
+                       hw_rate = rtlpriv->cfg->maps[RTL_RC_VHT_RATE_1SS_MCS9];
+       }
+
+       return hw_rate;
+}
+
+static u8 _rtl_get_highest_n_rate(struct ieee80211_hw *hw,
+                                 struct ieee80211_sta *sta)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       u8 hw_rate;
+
+       if ((get_rf_type(rtlphy) == RF_2T2R) &&
+           (sta->ht_cap.mcs.rx_mask[1] != 0))
+               hw_rate = rtlpriv->cfg->maps[RTL_RC_HT_RATEMCS15];
+       else
+               hw_rate = rtlpriv->cfg->maps[RTL_RC_HT_RATEMCS7];
+
+       return hw_rate;
+}
+
+void stg_rtl_get_tcb_desc(struct ieee80211_hw *hw,
+                         struct ieee80211_tx_info *info,
+                         struct ieee80211_sta *sta,
+                         struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw));
+       struct ieee80211_hdr *hdr = rtl_get_hdr(skb);
+       struct ieee80211_rate *txrate;
+       __le16 fc = rtl_get_fc(skb);
+
+       txrate = ieee80211_get_tx_rate(hw, info);
+       if (txrate != NULL)
+               tcb_desc->hw_rate = txrate->hw_value;
+
+       if (ieee80211_is_data(fc)) {
+               /*
+                *we set data rate INX 0
+                *in rtl_rc.c   if skb is special data or
+                *mgt which need low data rate.
+                */
+
+               /*
+                *So tcb_desc->hw_rate is just used for
+                *special data and mgt frames
+                */
+               if (info->control.rates[0].idx == 0 ||
+                   ieee80211_is_nullfunc(fc)) {
+                       tcb_desc->use_driver_rate = true;
+                       tcb_desc->ratr_index = RATR_INX_WIRELESS_MC;
+
+                       tcb_desc->disable_ratefallback = 1;
+               } else {
+                       /*
+                        *because hw will nerver use hw_rate
+                        *when tcb_desc->use_driver_rate = false
+                        *so we never set highest N rate here,
+                        *and N rate will all be controled by FW
+                        *when tcb_desc->use_driver_rate = false
+                        */
+                       if (sta && sta->vht_cap.vht_supported) {
+                               tcb_desc->hw_rate =
+                               _rtl_get_vht_highest_n_rate(hw, sta);
+                       } else if (sta && (sta->ht_cap.ht_supported)) {
+                               tcb_desc->hw_rate =
+                                       _rtl_get_highest_n_rate(hw, sta);
+                       } else {
+                               if (rtlmac->mode == WIRELESS_MODE_B) {
+                                       tcb_desc->hw_rate =
+                                           rtlpriv->cfg->maps[RTL_RC_CCK_RATE11M];
+                               } else {
+                                       tcb_desc->hw_rate =
+                                           rtlpriv->cfg->maps[RTL_RC_OFDM_RATE54M];
+                               }
+                       }
+               }
+
+               if (is_multicast_ether_addr(ieee80211_get_DA(hdr)))
+                       tcb_desc->b_multicast = 1;
+               else if (is_broadcast_ether_addr(ieee80211_get_DA(hdr)))
+                       tcb_desc->b_broadcast = 1;
+
+               _rtl_txrate_selectmode(hw, sta, tcb_desc);
+               _rtl_query_bandwidth_mode(hw, sta, tcb_desc);
+               _rtl_qurey_shortpreamble_mode(hw, tcb_desc, info);
+               _rtl_query_shortgi(hw, sta, tcb_desc, info);
+               _rtl_query_protection_mode(hw, tcb_desc, info);
+       } else {
+               tcb_desc->use_driver_rate = true;
+               tcb_desc->ratr_index = RATR_INX_WIRELESS_MC;
+               tcb_desc->disable_ratefallback = 1;
+               tcb_desc->mac_id = 0;
+               tcb_desc->packet_bw = 0;
+       }
+}
+EXPORT_SYMBOL(stg_rtl_get_tcb_desc);
+
+bool rtl92e_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       __le16 fc = rtl_get_fc(skb);
+
+       if (rtlpriv->dm.supp_phymode_switch &&
+           mac->link_state < MAC80211_LINKED &&
+           (ieee80211_is_auth(fc) || ieee80211_is_probe_req(fc))) {
+               if (rtlpriv->cfg->ops->check_switch_to_dmdp)
+                       rtlpriv->cfg->ops->check_switch_to_dmdp(hw);
+       }
+       if (ieee80211_is_auth(fc)) {
+               RT_TRACE(COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n"));
+               rtl92e_ips_nic_on(hw);
+
+               mac->link_state = MAC80211_LINKING;
+               /* Dul mac */
+               rtlpriv->phy.b_need_iqk = true;
+       }
+       return true;
+}
+
+struct sk_buff *rtl92e_make_del_ba(struct ieee80211_hw *hw, u8 *sa,
+                                  u8 *bssid, u16 tid);
+
+bool rtl92e_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
+{
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct ieee80211_hdr *hdr = rtl_get_hdr(skb);
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       __le16 fc = rtl_get_fc(skb);
+       u8 *act = (u8 *)(((u8 *)skb->data + MAC80211_3ADDR_LEN));
+       u8 category;
+
+       if (!ieee80211_is_action(fc))
+               return true;
+
+       category = *act;
+       act++;
+       switch (category) {
+       case ACT_CAT_BA:
+               switch (*act) {
+               case ACT_ADDBAREQ:
+                       if (mac->act_scanning)
+                               return false;
+
+                       RT_TRACE((COMP_SEND | COMP_RECV), DBG_DMESG,
+                                ("%s ACT_ADDBAREQ From:%pM\n",
+                               is_tx ? "Tx" : "Rx", hdr->addr2));
+                       RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, "req\n",
+                                     skb->data, skb->len);
+                       if (!is_tx) {
+                               struct ieee80211_sta *sta = NULL;
+                               struct rtl_sta_info *sta_entry = NULL;
+                               struct ieee80211_mgmt *mgmt = (void *)skb->data;
+                               u16 capab = 0, tid = 0;
+                               struct rtl_tid_data *tid_data;
+                               struct sk_buff *skb_delba = NULL;
+                               struct ieee80211_rx_status rx_status = { 0 };
+
+                               rcu_read_lock();
+                               sta = rtl_find_sta(hw, hdr->addr3);
+                               if (sta == NULL) {
+                                       RT_TRACE((COMP_SEND | COMP_RECV),
+                                                DBG_TRACE, ("sta is NULL\n"));
+                                       rcu_read_unlock();
+                                       return true;
+                               }
+
+                               sta_entry =
+                                       (struct rtl_sta_info *)sta->drv_priv;
+                               if (!sta_entry) {
+                                       rcu_read_unlock();
+                                       return true;
+                               }
+                               capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
+                               tid = (capab &
+                                       IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
+                               tid_data = &sta_entry->tids[tid];
+                               if (tid_data->agg.rx_agg_state ==
+                                   RTL_RX_AGG_START) {
+                                       skb_delba = rtl92e_make_del_ba(hw,
+                                                                   hdr->addr2,
+                                                                   hdr->addr3,
+                                                                   tid);
+                                       if (skb_delba) {
+                                               rx_status.freq =
+                                                       hw->conf.chandef.chan->center_freq;
+                                               rx_status.band =
+                                                       hw->conf.chandef.chan->band;
+                                               rx_status.flag |= RX_FLAG_DECRYPTED;
+                                               rx_status.flag |= RX_FLAG_MACTIME_MPDU;
+                                               rx_status.rate_idx = 0;
+                                               rx_status.signal = 50 + 10;
+                                               memcpy(IEEE80211_SKB_RXCB(skb_delba),
+                                                      &rx_status, sizeof(rx_status));
+                                               RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG,
+                                                             "fake del\n",
+                                                             skb_delba->data, skb_delba->len);
+                                               ieee80211_rx_irqsafe(hw, skb_delba);
+                                       }
+                               }
+                               rcu_read_unlock();
+                       }
+                       break;
+               case ACT_ADDBARSP:
+                       RT_TRACE((COMP_SEND | COMP_RECV), DBG_DMESG,
+                                ("%s ACT_ADDBARSP From :%pM\n",
+                                 is_tx ? "Tx" : "Rx", hdr->addr2));
+                       break;
+               case ACT_DELBA:
+                       RT_TRACE((COMP_SEND | COMP_RECV), DBG_DMESG,
+                                ("ACT_ADDBADEL From :%pM\n", hdr->addr2));
+                       break;
+               }
+               break;
+       default:
+               break;
+       }
+
+       return true;
+}
+
+/*should call before software enc*/
+u8 rtl92e_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb,
+                         u8 is_tx)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       __le16 fc = rtl_get_fc(skb);
+       u16 ether_type;
+       u8 mac_hdr_len = ieee80211_get_hdrlen_from_skb(skb);
+       const struct iphdr *ip;
+
+       if (!ieee80211_is_data(fc))
+               goto end;
+
+       ip = (struct iphdr *)((u8 *)skb->data + mac_hdr_len +
+                             SNAP_SIZE + PROTOC_TYPE_SIZE);
+       ether_type = be16_to_cpup((__be16 *)
+                                 (skb->data + mac_hdr_len + SNAP_SIZE));
+
+       if (ETH_P_IP == ether_type) {
+               if (IPPROTO_UDP == ip->protocol) {
+                       struct udphdr *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))) {
+                               /*
+                                * 68 : UDP BOOTP client
+                                * 67 : UDP BOOTP server
+                                */
+                               RT_TRACE((COMP_SEND | COMP_RECV),
+                                        DBG_DMESG, ("dhcp %s !!\n",
+                                                    (is_tx) ? "Tx" : "Rx"));
+
+                               if (is_tx) {
+                                       rtlpriv->ra.is_special_data = true;
+                                       if (rtlpriv->cfg->ops->get_btc_status())
+                                               rtlpriv->btcoexist.btc_ops->btc_special_packet_notify(
+                                                                       rtlpriv, 1);
+                                       rtl92e_lps_leave(hw);
+                                       ppsc->last_delaylps_stamp_jiffies =
+                                                                       jiffies;
+                               }
+
+                               return true;
+                       }
+               }
+       } else if (ETH_P_ARP == ether_type) {
+               if (is_tx) {
+                       rtlpriv->ra.is_special_data = true;
+                       if (rtlpriv->cfg->ops->get_btc_status())
+                               rtlpriv->btcoexist.btc_ops->btc_special_packet_notify(
+                                                       rtlpriv, 1);
+                       rtl92e_lps_leave(hw);
+                       ppsc->last_delaylps_stamp_jiffies = jiffies;
+               }
+
+               return true;
+       } else if (ETH_P_PAE == ether_type) {
+               RT_TRACE((COMP_SEND | COMP_RECV), DBG_DMESG,
+                        ("802.1X %s EAPOL pkt!!\n", (is_tx) ? "Tx" : "Rx"));
+
+               if (is_tx) {
+                       rtlpriv->ra.is_special_data = true;
+                       rtl92e_lps_leave(hw);
+                       ppsc->last_delaylps_stamp_jiffies = jiffies;
+               }
+
+               return true;
+       } else if (0x86DD == ether_type) {
+               return true;
+       }
+
+end:
+       rtlpriv->ra.is_special_data = false;
+       return false;
+}
+
+/*********************************************************
+ *
+ * functions called by core.c
+ *
+ *********************************************************/
+int rtl92e_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                       struct ieee80211_sta *sta, u16 tid, u16 *ssn)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_tid_data *tid_data;
+       struct rtl_sta_info *sta_entry = NULL;
+
+       if (sta == NULL)
+               return -EINVAL;
+
+       if (unlikely(tid >= MAX_TID_COUNT))
+               return -EINVAL;
+
+       sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+       if (!sta_entry)
+               return -ENXIO;
+       tid_data = &sta_entry->tids[tid];
+
+       RT_TRACE(COMP_SEND, DBG_DMESG,
+                ("on ra = %pM tid = %d seq:%d\n", sta->addr, tid,
+                 tid_data->seq_number));
+
+       *ssn = tid_data->seq_number;
+       tid_data->agg.agg_state = RTL_AGG_START;
+
+       ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+       return 0;
+}
+
+int rtl92e_tx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                      struct ieee80211_sta *sta, u16 tid)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_tid_data *tid_data;
+       struct rtl_sta_info *sta_entry = NULL;
+
+       if (sta == NULL)
+               return -EINVAL;
+
+       /* Comparing an array to null is not useful */
+       /*if (!sta->addr) {
+               RT_TRACE(COMP_ERR, DBG_EMERG, ("ra = NULL\n"));
+               return -EINVAL;
+       }*/
+
+       RT_TRACE(COMP_SEND, DBG_DMESG,
+                ("on ra = %pM tid = %d\n", sta->addr, tid));
+
+       if (unlikely(tid >= MAX_TID_COUNT))
+               return -EINVAL;
+
+       sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+       tid_data = &sta_entry->tids[tid];
+       sta_entry->tids[tid].agg.agg_state = RTL_AGG_STOP;
+
+       ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+       return 0;
+}
+
+int rtl92e_rx_agg_start(struct ieee80211_hw *hw,
+                       struct ieee80211_sta *sta, u16 tid)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_tid_data *tid_data;
+       struct rtl_sta_info *sta_entry = NULL;
+
+       if (sta == NULL)
+               return -EINVAL;
+
+       if (unlikely(tid >= MAX_TID_COUNT))
+               return -EINVAL;
+
+       sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+       if (!sta_entry)
+               return -ENXIO;
+       tid_data = &sta_entry->tids[tid];
+
+       RT_TRACE(COMP_RECV, DBG_DMESG,
+                ("on ra = %pM tid = %d seq:%d\n", sta->addr, tid,
+                tid_data->seq_number));
+
+       tid_data->agg.rx_agg_state = RTL_RX_AGG_START;
+       return 0;
+}
+
+int rtl92e_rx_agg_stop(struct ieee80211_hw *hw,
+                      struct ieee80211_sta *sta, u16 tid)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_tid_data *tid_data;
+       struct rtl_sta_info *sta_entry = NULL;
+
+       if (sta == NULL)
+               return -EINVAL;
+
+       /* Comparing an array to null is not useful */
+       /*if (!sta->addr) {
+               RT_TRACE(COMP_ERR, DBG_EMERG, ("ra = NULL\n"));
+               return -EINVAL;
+       }*/
+
+       RT_TRACE(COMP_SEND, DBG_DMESG,
+                ("on ra = %pM tid = %d\n", sta->addr, tid));
+
+       if (unlikely(tid >= MAX_TID_COUNT))
+               return -EINVAL;
+
+       sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+       tid_data = &sta_entry->tids[tid];
+       sta_entry->tids[tid].agg.rx_agg_state = RTL_RX_AGG_STOP;
+
+       return 0;
+}
+
+int rtl92e_tx_agg_oper(struct ieee80211_hw *hw,
+                      struct ieee80211_sta *sta, u16 tid)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_tid_data *tid_data;
+       struct rtl_sta_info *sta_entry = NULL;
+
+       if (sta == NULL)
+               return -EINVAL;
+
+       /* Comparing an array to null is not useful */
+       /*if (!sta->addr) {
+               RT_TRACE(COMP_ERR, DBG_EMERG, ("ra = NULL\n"));
+               return -EINVAL;
+       }*/
+
+       RT_TRACE(COMP_SEND, DBG_DMESG,
+                ("on ra = %pM tid = %d\n", sta->addr, tid));
+
+       if (unlikely(tid >= MAX_TID_COUNT))
+               return -EINVAL;
+
+       sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+       tid_data = &sta_entry->tids[tid];
+       sta_entry->tids[tid].agg.agg_state = RTL_AGG_OPERATIONAL;
+
+       return 0;
+}
+
+/*********************************************************
+ *
+ * wq & timer callback functions
+ *
+ *********************************************************/
+/* this function is used for roaming */
+void rtl92e_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+
+       if (rtlpriv->mac80211.opmode != NL80211_IFTYPE_STATION)
+               return;
+
+       if (rtlpriv->mac80211.link_state < MAC80211_LINKED)
+               return;
+
+       /* check if this really is a beacon */
+       if (!ieee80211_is_beacon(hdr->frame_control) &&
+           !ieee80211_is_probe_resp(hdr->frame_control))
+               return;
+
+       /* min. beacon length + FCS_LEN */
+       if (skb->len <= 40 + FCS_LEN)
+               return;
+
+       /* and only beacons from the associated BSSID, please */
+       if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid))
+               return;
+
+       rtlpriv->link_info.bcn_rx_inperiod++;
+}
+
+void rtl92e_watchdog_wq_callback(void *data)
+{
+       struct rtl_works *rtlworks = container_of_dwork_rtl(data,
+                                                           struct rtl_works,
+                                                           watchdog_wq);
+       struct ieee80211_hw *hw = rtlworks->hw;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       bool b_busytraffic = false;
+       bool b_tx_busy_traffic = false;
+       bool b_rx_busy_traffic = false;
+       bool b_higher_busytraffic = false;
+       bool b_higher_busyrxtraffic = false;
+       u8 idx, tid;
+       u32 rx_cnt_inp4eriod = 0;
+       u32 tx_cnt_inp4eriod = 0;
+       u32 aver_rx_cnt_inperiod = 0;
+       u32 aver_tx_cnt_inperiod = 0;
+       u32 aver_tidtx_inperiod[MAX_TID_COUNT] = {0};
+       u32 tidtx_inp4eriod[MAX_TID_COUNT] = {0};
+       bool benter_ps = false;
+
+       if (is_hal_stop(rtlhal))
+               return;
+
+       /* <1> Determine if action frame is allowed */
+       if (mac->link_state > MAC80211_NOLINK) {
+               if (mac->cnt_after_linked < 20)
+                       mac->cnt_after_linked++;
+       } else {
+               mac->cnt_after_linked = 0;
+       }
+
+       /* <2> to check if traffic busy, if
+        * busytraffic we don't change channel */
+       if (mac->link_state >= MAC80211_LINKED) {
+               /* (1) get aver_rx_cnt_inperiod & aver_tx_cnt_inperiod */
+               for (idx = 0; idx <= 2; idx++) {
+                       rtlpriv->link_info.num_rx_in4period[idx] =
+                           rtlpriv->link_info.num_rx_in4period[idx + 1];
+                       rtlpriv->link_info.num_tx_in4period[idx] =
+                           rtlpriv->link_info.num_tx_in4period[idx + 1];
+               }
+               rtlpriv->link_info.num_rx_in4period[3] =
+                   rtlpriv->link_info.num_rx_inperiod;
+               rtlpriv->link_info.num_tx_in4period[3] =
+                   rtlpriv->link_info.num_tx_inperiod;
+               for (idx = 0; idx <= 3; idx++) {
+                       rx_cnt_inp4eriod +=
+                           rtlpriv->link_info.num_rx_in4period[idx];
+                       tx_cnt_inp4eriod +=
+                           rtlpriv->link_info.num_tx_in4period[idx];
+               }
+               aver_rx_cnt_inperiod = rx_cnt_inp4eriod / 4;
+               aver_tx_cnt_inperiod = tx_cnt_inp4eriod / 4;
+
+               /* (2) check traffic busy */
+               if (aver_rx_cnt_inperiod > 100 || aver_tx_cnt_inperiod > 100) {
+                       b_busytraffic = true;
+                       if (aver_rx_cnt_inperiod > aver_tx_cnt_inperiod)
+                               b_rx_busy_traffic = true;
+                       else
+                               b_tx_busy_traffic = false;
+               }
+
+               /* Higher Tx/Rx data. */
+               if (aver_rx_cnt_inperiod > 4000 ||
+                   aver_tx_cnt_inperiod > 4000) {
+                       b_higher_busytraffic = true;
+
+                       /* Extremely high Rx data. */
+                       if (aver_rx_cnt_inperiod > 5000)
+                               b_higher_busyrxtraffic = true;
+               }
+
+               /* check every tid's tx traffic */
+               for (tid = 0; tid <= 7; tid++) {
+                       for (idx = 0; idx <= 2; idx++)
+                               rtlpriv->link_info.tidtx_in4period[tid][idx] =
+                                       rtlpriv->link_info.tidtx_in4period[tid]
+                                       [idx + 1];
+                       rtlpriv->link_info.tidtx_in4period[tid][3] =
+                               rtlpriv->link_info.tidtx_inperiod[tid];
+
+                       for (idx = 0; idx <= 3; idx++)
+                               tidtx_inp4eriod[tid] +=
+                                  rtlpriv->link_info.tidtx_in4period[tid][idx];
+                       aver_tidtx_inperiod[tid] = tidtx_inp4eriod[tid] / 4;
+                       if (aver_tidtx_inperiod[tid] > 5000)
+                               rtlpriv->link_info.higher_busytxtraffic[tid] =
+                                                                       true;
+                       else
+                               rtlpriv->link_info.higher_busytxtraffic[tid] =
+                                                                       false;
+               }
+
+               if (((rtlpriv->link_info.num_rx_inperiod +
+                     rtlpriv->link_info.num_tx_inperiod) > 8) ||
+                   (rtlpriv->link_info.num_rx_inperiod > 2))
+                       benter_ps = false;
+               else
+                       benter_ps = true;
+
+               /* LeisurePS only work in infra mode. */
+               if (benter_ps)
+                       rtl92e_lps_enter(hw);
+               else
+                       rtl92e_lps_leave(hw);
+       }
+
+       rtlpriv->link_info.num_rx_inperiod = 0;
+       rtlpriv->link_info.num_tx_inperiod = 0;
+       for (tid = 0; tid <= 7; tid++)
+               rtlpriv->link_info.tidtx_inperiod[tid] = 0;
+
+       rtlpriv->link_info.b_busytraffic = b_busytraffic;
+       rtlpriv->link_info.b_rx_busy_traffic = b_rx_busy_traffic;
+       rtlpriv->link_info.b_tx_busy_traffic = b_tx_busy_traffic;
+       rtlpriv->link_info.b_higher_busytraffic = b_higher_busytraffic;
+       rtlpriv->link_info.b_higher_busyrxtraffic = b_higher_busyrxtraffic;
+
+       /* <3> DM */
+       rtlpriv->cfg->ops->dm_watchdog(hw);
+
+       /* <4> roaming */
+       if (mac->link_state == MAC80211_LINKED &&
+           mac->opmode == NL80211_IFTYPE_STATION) {
+               if ((rtlpriv->link_info.bcn_rx_inperiod +
+                       rtlpriv->link_info.num_rx_inperiod) == 0) {
+                       rtlpriv->link_info.roam_times++;
+                       RT_TRACE(COMP_ERR, DBG_DMESG,
+                                ("AP off for %d s\n",
+                                 (rtlpriv->link_info.roam_times * 2)));
+
+                       /* if we can't recv beacon for 10s,
+                       * we should reconnect this AP */
+                       if (rtlpriv->link_info.roam_times >= 5) {
+                               RT_TRACE(COMP_ERR, DBG_EMERG,
+                                        ("AP off, try to reconnect now\n"));
+                               rtlpriv->link_info.roam_times = 0;
+                               ieee80211_connection_loss(
+                                       rtlpriv->mac80211.vif);
+                       }
+               } else {
+                       rtlpriv->link_info.roam_times = 0;
+               }
+       }
+
+       if (rtlpriv->cfg->ops->get_btc_status())
+               rtlpriv->btcoexist.btc_ops->btc_periodical(rtlpriv);
+
+       rtlpriv->link_info.bcn_rx_inperiod = 0;
+}
+
+void rtl92e_watch_dog_timer_callback(unsigned long data)
+{
+       struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       queue_delayed_work(rtlpriv->works.rtl_wq,
+                          &rtlpriv->works.watchdog_wq, 0);
+
+       mod_timer(&rtlpriv->works.watchdog_timer,
+                 jiffies + MSECS(RTL_WATCH_DOG_TIME));
+}
+void rtl92e_fwevt_wq_callback(void *data)
+{
+       struct rtl_works *rtlworks =
+               container_of_dwork_rtl(data, struct rtl_works, fwevt_wq);
+       struct ieee80211_hw *hw = rtlworks->hw;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       rtlpriv->cfg->ops->c2h_command_handle(hw);
+}
+void rtl92e_easy_concurrent_retrytimer_callback(unsigned long data)
+{
+       struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_priv *buddy_priv = rtlpriv->buddy_priv;
+
+       if (buddy_priv == NULL)
+               return;
+
+       rtlpriv->cfg->ops->dualmac_easy_concurrent(hw);
+}
+/*********************************************************
+ *
+ * frame process functions
+ *
+ *********************************************************/
+u8 *rtl92e_find_ie(u8 *data, unsigned int len, u8 ie)
+{
+       struct ieee80211_mgmt *mgmt = (void *)data;
+       u8 *pos, *end;
+
+       pos = (u8 *)mgmt->u.beacon.variable;
+       end = data + len;
+       while (pos < end) {
+               if (pos + 2 + pos[1] > end)
+                       return NULL;
+
+               if (pos[0] == ie)
+                       return pos;
+
+               pos += 2 + pos[1];
+       }
+       return NULL;
+}
+
+/* when we use 2 rx ants we send IEEE80211_SMPS_OFF */
+/* when we use 1 rx ant we send IEEE80211_SMPS_STATIC */
+static struct sk_buff *rtl_make_smps_action(struct ieee80211_hw *hw,
+                                           enum ieee80211_smps_mode smps,
+                                           u8 *da, u8 *bssid)
+{
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       struct sk_buff *skb;
+       struct ieee80211_mgmt_compat *action_frame;
+
+       /* 27 = header + category + action + smps mode */
+       skb = dev_alloc_skb(27 + hw->extra_tx_headroom);
+       if (!skb)
+               return NULL;
+
+       skb_reserve(skb, hw->extra_tx_headroom);
+       action_frame = (void *)skb_put(skb, 27);
+       memset(action_frame, 0, 27);
+       ether_addr_copy(action_frame->da, da);
+       ether_addr_copy(action_frame->sa, rtlefuse->dev_addr);
+       ether_addr_copy(action_frame->bssid, bssid);
+       action_frame->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+                                                 IEEE80211_STYPE_ACTION);
+       action_frame->u.action.category = WLAN_CATEGORY_HT;
+       action_frame->u.action.u.ht_smps.action = WLAN_HT_ACTION_SMPS;
+       switch (smps) {
+       case IEEE80211_SMPS_AUTOMATIC:/* 0 */
+       case IEEE80211_SMPS_NUM_MODES:/* 4 */
+               WARN_ON(1);
+       /* Here will get a 'MISSING_BREAK' in Coverity Test, just ignore it.
+        * According to Kernel Code, here is right.
+        */
+       case IEEE80211_SMPS_OFF:/* 1 */ /*MIMO_PS_NOLIMIT*/
+               action_frame->u.action.u.ht_smps.smps_control =
+                               WLAN_HT_SMPS_CONTROL_DISABLED;/* 0 */
+               break;
+       case IEEE80211_SMPS_STATIC:/* 2 */ /*MIMO_PS_STATIC*/
+               action_frame->u.action.u.ht_smps.smps_control =
+                               WLAN_HT_SMPS_CONTROL_STATIC;/* 1 */
+               break;
+       case IEEE80211_SMPS_DYNAMIC:/* 3 */ /*MIMO_PS_DYNAMIC*/
+               action_frame->u.action.u.ht_smps.smps_control =
+                               WLAN_HT_SMPS_CONTROL_DYNAMIC;/* 3 */
+               break;
+       }
+
+       return skb;
+}
+
+int stg_rtl_send_smps_action(struct ieee80211_hw *hw,
+                            struct ieee80211_sta *sta,
+                            enum ieee80211_smps_mode smps)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       struct sk_buff *skb = NULL;
+       struct rtl_tcb_desc tcb_desc;
+       u8 bssid[ETH_ALEN] = {0};
+
+       memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
+
+       if (rtlpriv->mac80211.act_scanning)
+               goto err_free;
+
+       if (!sta)
+               goto err_free;
+
+       if (unlikely(is_hal_stop(rtlhal) || ppsc->rfpwr_state != ERFON))
+               goto err_free;
+
+       if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status))
+               goto err_free;
+
+       if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_AP)
+               ether_addr_copy(bssid, rtlpriv->efuse.dev_addr);
+       else
+               ether_addr_copy(bssid, rtlpriv->mac80211.bssid);
+
+       skb = rtl_make_smps_action(hw, smps, sta->addr, bssid);
+       /* this is a type = mgmt * stype = action frame */
+       if (skb) {
+               struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+               struct rtl_sta_info *sta_entry =
+                       (struct rtl_sta_info *)sta->drv_priv;
+               sta_entry->mimo_ps = smps;
+               /* rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0); */
+
+               info->control.rates[0].idx = 0;
+               info->band = hw->conf.chandef.chan->band;
+               rtlpriv->intf_ops->adapter_tx(hw, sta, skb, &tcb_desc);
+       }
+       return 1;
+
+err_free:
+       return 0;
+}
+EXPORT_SYMBOL(stg_rtl_send_smps_action);
+
+/* because mac80211 have issues when can receive del ba
+ * so here we just make a fake del_ba if we receive a ba_req
+ * but rx_agg was opened to let mac80211 release some ba
+ * related resources, so please this del_ba for tx */
+struct sk_buff *rtl92e_make_del_ba(struct ieee80211_hw *hw,
+                                  u8 *sa, u8 *bssid, u16 tid)
+{
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       struct sk_buff *skb;
+       struct ieee80211_mgmt *action_frame;
+       u16 params;
+
+       /* 27 = header + category + action + smps mode */
+       skb = dev_alloc_skb(34 + hw->extra_tx_headroom);
+       if (!skb)
+               return NULL;
+
+       skb_reserve(skb, hw->extra_tx_headroom);
+       action_frame = (void *)skb_put(skb, 34);
+       memset(action_frame, 0, 34);
+       ether_addr_copy(action_frame->sa, sa);
+       ether_addr_copy(action_frame->da, rtlefuse->dev_addr);
+       ether_addr_copy(action_frame->bssid, bssid);
+       action_frame->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+                                                 IEEE80211_STYPE_ACTION);
+       action_frame->u.action.category = WLAN_CATEGORY_BACK;
+       action_frame->u.action.u.delba.action_code = WLAN_ACTION_DELBA;
+       params = (u16)(1 << 11);        /* bit 11 initiator */
+       params |= (u16)(tid << 12);     /* bit 15:12 TID number */
+
+       action_frame->u.action.u.delba.params = cpu_to_le16(params);
+       action_frame->u.action.u.delba.reason_code =
+               cpu_to_le16(WLAN_REASON_QSTA_TIMEOUT);
+
+       return skb;
+}
+
+/*********************************************************
+ *
+ * IOT functions
+ *
+ *********************************************************/
+static bool rtl_chk_vendor_ouisub(struct ieee80211_hw *hw,
+                                 struct octet_string vendor_ie)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       bool matched = false;
+       static u8 athcap_1[] = { 0x00, 0x03, 0x7F };
+       static u8 athcap_2[] = { 0x00, 0x13, 0x74 };
+       static u8 broadcap_1[] = { 0x00, 0x10, 0x18 };
+       static u8 broadcap_2[] = { 0x00, 0x0a, 0xf7 };
+       static u8 broadcap_3[] = { 0x00, 0x05, 0xb5 };
+       static u8 racap[] = { 0x00, 0x0c, 0x43 };
+       static u8 ciscocap[] = { 0x00, 0x40, 0x96 };
+       static u8 marvcap[] = { 0x00, 0x50, 0x43 };
+
+       if (memcmp(vendor_ie.octet, athcap_1, 3) == 0 ||
+           memcmp(vendor_ie.octet, athcap_2, 3) == 0) {
+               rtlpriv->mac80211.vendor = PEER_ATH;
+               matched = true;
+       } else if (memcmp(vendor_ie.octet, broadcap_1, 3) == 0 ||
+                  memcmp(vendor_ie.octet, broadcap_2, 3) == 0 ||
+                  memcmp(vendor_ie.octet, broadcap_3, 3) == 0) {
+               rtlpriv->mac80211.vendor = PEER_BROAD;
+               matched = true;
+       } else if (memcmp(vendor_ie.octet, racap, 3) == 0) {
+               rtlpriv->mac80211.vendor = PEER_RAL;
+               matched = true;
+       } else if (memcmp(vendor_ie.octet, ciscocap, 3) == 0) {
+               rtlpriv->mac80211.vendor = PEER_CISCO;
+               matched = true;
+       } else if (memcmp(vendor_ie.octet, marvcap, 3) == 0) {
+               rtlpriv->mac80211.vendor = PEER_MARV;
+               matched = true;
+       }
+
+       return matched;
+}
+
+static bool rtl_find_221_ie(struct ieee80211_hw *hw, u8 *data, unsigned int len)
+{
+       struct ieee80211_mgmt *mgmt = (void *)data;
+       struct octet_string vendor_ie;
+       u8 *pos, *end;
+
+       pos = (u8 *)mgmt->u.beacon.variable;
+       end = data + len;
+       while (pos < end) {
+               if (pos[0] == 221) {
+                       vendor_ie.length = pos[1];
+                       vendor_ie.octet = &pos[2];
+                       if (rtl_chk_vendor_ouisub(hw, vendor_ie))
+                               return true;
+               }
+
+               if (pos + 2 + pos[1] > end)
+                       return false;
+
+               pos += 2 + pos[1];
+       }
+       return false;
+}
+
+void rtl92e_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct ieee80211_hdr *hdr = (void *)data;
+       u32 vendor = PEER_UNKNOWN;
+
+       static u8 ap3_1[3] = { 0x00, 0x14, 0xbf };
+       static u8 ap3_2[3] = { 0x00, 0x1a, 0x70 };
+       static u8 ap3_3[3] = { 0x00, 0x1d, 0x7e };
+       static u8 ap4_1[3] = { 0x00, 0x90, 0xcc };
+       static u8 ap4_2[3] = { 0x00, 0x0e, 0x2e };
+       static u8 ap4_3[3] = { 0x00, 0x18, 0x02 };
+       static u8 ap4_4[3] = { 0x00, 0x17, 0x3f };
+       static u8 ap4_5[3] = { 0x00, 0x1c, 0xdf };
+       static u8 ap5_1[3] = { 0x00, 0x1c, 0xf0 };
+       static u8 ap5_2[3] = { 0x00, 0x21, 0x91 };
+       static u8 ap5_3[3] = { 0x00, 0x24, 0x01 };
+       static u8 ap5_4[3] = { 0x00, 0x15, 0xe9 };
+       static u8 ap5_5[3] = { 0x00, 0x17, 0x9A };
+       static u8 ap5_6[3] = { 0x00, 0x18, 0xE7 };
+       static u8 ap6_1[3] = { 0x00, 0x17, 0x94 };
+       static u8 ap7_1[3] = { 0x00, 0x14, 0xa4 };
+
+       if (mac->opmode != NL80211_IFTYPE_STATION)
+               return;
+
+       if (mac->link_state == MAC80211_NOLINK) {
+               mac->vendor = PEER_UNKNOWN;
+               return;
+       }
+
+       if (mac->cnt_after_linked > 2)
+               return;
+
+       /* check if this really is a beacon */
+       if (!ieee80211_is_beacon(hdr->frame_control))
+               return;
+
+       /* min. beacon length + FCS_LEN */
+       if (len <= 40 + FCS_LEN)
+               return;
+
+       /* and only beacons from the associated BSSID, please */
+       if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid))
+               return;
+
+       if (rtl_find_221_ie(hw, data, len))
+               vendor = mac->vendor;
+
+       if ((memcmp(mac->bssid, ap5_1, 3) == 0) ||
+           (memcmp(mac->bssid, ap5_2, 3) == 0) ||
+           (memcmp(mac->bssid, ap5_3, 3) == 0) ||
+           (memcmp(mac->bssid, ap5_4, 3) == 0) ||
+           (memcmp(mac->bssid, ap5_5, 3) == 0) ||
+           (memcmp(mac->bssid, ap5_6, 3) == 0) ||
+               vendor == PEER_ATH) {
+               vendor = PEER_ATH;
+               RT_TRACE(COMP_MAC80211, DBG_LOUD, ("=>ath find\n"));
+       } else if ((memcmp(mac->bssid, ap4_4, 3) == 0) ||
+                  (memcmp(mac->bssid, ap4_5, 3) == 0) ||
+                  (memcmp(mac->bssid, ap4_1, 3) == 0) ||
+                  (memcmp(mac->bssid, ap4_2, 3) == 0) ||
+                  (memcmp(mac->bssid, ap4_3, 3) == 0) ||
+               vendor == PEER_RAL) {
+               RT_TRACE(COMP_MAC80211, DBG_LOUD, ("=>ral findn\n"));
+               vendor = PEER_RAL;
+       } else if (memcmp(mac->bssid, ap6_1, 3) == 0 ||
+               vendor == PEER_CISCO) {
+               vendor = PEER_CISCO;
+               RT_TRACE(COMP_MAC80211, DBG_LOUD, ("=>cisco find\n"));
+       } else if ((memcmp(mac->bssid, ap3_1, 3) == 0) ||
+               (memcmp(mac->bssid, ap3_2, 3) == 0) ||
+               (memcmp(mac->bssid, ap3_3, 3) == 0) ||
+               vendor == PEER_BROAD) {
+               RT_TRACE(COMP_MAC80211, DBG_LOUD, ("=>broad find\n"));
+               vendor = PEER_BROAD;
+       } else if (memcmp(mac->bssid, ap7_1, 3) == 0 ||
+               vendor == PEER_MARV) {
+               vendor = PEER_MARV;
+               RT_TRACE(COMP_MAC80211, DBG_LOUD, ("=>marv find\n"));
+       }
+
+       mac->vendor = vendor;
+}
+
+/*********************************************************
+ *
+ * sysfs functions
+ *
+ *********************************************************/
+struct rtl_global_var global_var = {};
+
+int  rtl_core_module_init(void)
+{
+       static int here_once;
+
+       if (here_once++)
+               return 0;
+
+       if (rtl92e_rate_control_register())
+               pr_debug("rtl: Unable to register rtl_rc, use default RC !!\n");
+
+       /* init some global vars */
+       INIT_LIST_HEAD(&global_var.glb_priv_list);
+       spin_lock_init(&global_var.glb_list_lock);
+
+       return 0;
+}
+void  rtl_core_module_exit(void)
+{
+       /*RC*/
+       rtl92e_rate_control_unregister();
+}
diff --git a/drivers/staging/rtl8192ee/base.h b/drivers/staging/rtl8192ee/base.h
new file mode 100644 (file)
index 0000000..c7929a7
--- /dev/null
@@ -0,0 +1,163 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL_BASE_H__
+#define __RTL_BASE_H__
+
+#include "compat.h"
+
+enum ap_peer {
+       PEER_UNKNOWN = 0,
+       PEER_RTL = 1,
+       PEER_RTL_92SE = 2,
+       PEER_BROAD = 3,
+       PEER_RAL = 4,
+       PEER_ATH = 5,
+       PEER_CISCO = 6,
+       PEER_MARV = 7,
+       PEER_AIRGO = 9,
+       PEER_MAX = 10,
+};
+
+#define RTL_DUMMY_OFFSET       0
+#define RTL_DUMMY_UNIT         8
+#define RTL_TX_DUMMY_SIZE      (RTL_DUMMY_OFFSET * RTL_DUMMY_UNIT)
+#define RTL_TX_DESC_SIZE       32
+#define RTL_TX_HEADER_SIZE     (RTL_TX_DESC_SIZE + RTL_TX_DUMMY_SIZE)
+
+#define HT_AMSDU_SIZE_4K       3839
+#define HT_AMSDU_SIZE_8K       7935
+
+#define MAX_BIT_RATE_40MHZ_MCS15       300     /* Mbps */
+#define MAX_BIT_RATE_40MHZ_MCS7                150     /* Mbps */
+
+#define MAX_BIT_RATE_SHORT_GI_2NSS_80MHZ_MCS9  867     /* Mbps */
+#define MAX_BIT_RATE_SHORT_GI_2NSS_80MHZ_MCS7  650     /* Mbps */
+#define MAX_BIT_RATE_LONG_GI_2NSS_80MHZ_MCS9   780     /* Mbps */
+#define MAX_BIT_RATE_LONG_GI_2NSS_80MHZ_MCS7   585     /* Mbps */
+
+#define MAX_BIT_RATE_SHORT_GI_1NSS_80MHZ_MCS9  434     /* Mbps */
+#define MAX_BIT_RATE_SHORT_GI_1NSS_80MHZ_MCS7  325     /* Mbps */
+#define MAX_BIT_RATE_LONG_GI_1NSS_80MHZ_MCS9   390     /* Mbps */
+#define MAX_BIT_RATE_LONG_GI_1NSS_80MHZ_MCS7   293     /* Mbps */
+
+
+#define RTL_RATE_COUNT_LEGACY          12
+#define RTL_CHANNEL_COUNT              14
+
+#define FRAME_OFFSET_FRAME_CONTROL     0
+#define FRAME_OFFSET_DURATION          2
+#define FRAME_OFFSET_ADDRESS1          4
+#define FRAME_OFFSET_ADDRESS2          10
+#define FRAME_OFFSET_ADDRESS3          16
+#define FRAME_OFFSET_SEQUENCE          22
+#define FRAME_OFFSET_ADDRESS4          24
+
+#define SET_80211_HDR_FRAME_CONTROL(_hdr, _val)                \
+       WRITEEF2BYTE(_hdr, _val)
+#define SET_80211_HDR_TYPE_AND_SUBTYPE(_hdr, _val)     \
+       WRITEEF1BYTE(_hdr, _val)
+#define SET_80211_HDR_PWR_MGNT(_hdr, _val)             \
+       SET_BITS_TO_LE_2BYTE(_hdr, 12, 1, _val)
+#define SET_80211_HDR_TO_DS(_hdr, _val)                        \
+       SET_BITS_TO_LE_2BYTE(_hdr, 8, 1, _val)
+
+#define SET_80211_PS_POLL_AID(_hdr, _val)              \
+       (*(u16 *)((u8 *)(_hdr) + 2) = _val)
+#define SET_80211_PS_POLL_BSSID(_hdr, _val)            \
+       memcpy(((u8 *)(_hdr)) + 4, (u8 *)(_val), ETH_ALEN)
+#define SET_80211_PS_POLL_TA(_hdr, _val)               \
+       memcpy(((u8 *)(_hdr)) + 10, (u8 *)(_val), ETH_ALEN)
+
+#define SET_80211_HDR_DURATION(_hdr, _val)     \
+       WRITEEF2BYTE((u8 *)(_hdr)+FRAME_OFFSET_DURATION, _val)
+#define SET_80211_HDR_ADDRESS1(_hdr, _val)     \
+       CP_MACADDR((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS1, (u8 *)(_val))
+#define SET_80211_HDR_ADDRESS2(_hdr, _val)     \
+       CP_MACADDR((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS2, (u8 *)(_val))
+#define SET_80211_HDR_ADDRESS3(_hdr, _val)     \
+       CP_MACADDR((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS3, (u8 *)(_val))
+#define SET_80211_HDR_FRAGMENT_SEQUENCE(_hdr, _val)  \
+       WRITEEF2BYTE((u8 *)(_hdr)+FRAME_OFFSET_SEQUENCE, _val)
+
+#define SET_BEACON_PROBE_RSP_TIME_STAMP_LOW(__phdr, __val)     \
+       WRITEEF4BYTE(((u8 *)(__phdr)) + 24, __val)
+#define SET_BEACON_PROBE_RSP_TIME_STAMP_HIGH(__phdr, __val) \
+       WRITEEF4BYTE(((u8 *)(__phdr)) + 28, __val)
+#define SET_BEACON_PROBE_RSP_BEACON_INTERVAL(__phdr, __val) \
+       WRITEEF2BYTE(((u8 *)(__phdr)) + 32, __val)
+#define GET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr)           \
+       READEF2BYTE(((u8 *)(__phdr)) + 34)
+#define SET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, __val) \
+       WRITEEF2BYTE(((u8 *)(__phdr)) + 34, __val)
+#define MASK_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, __val) \
+       SET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, \
+       (GET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr) & (~(__val))))
+
+int rtl92e_init_core(struct ieee80211_hw *hw);
+void rtl92e_deinit_core(struct ieee80211_hw *hw);
+void rtl92e_init_rx_config(struct ieee80211_hw *hw);
+void rtl92e_init_rfkill(struct ieee80211_hw *hw);
+void rtl92e_deinit_rfkill(struct ieee80211_hw *hw);
+
+void rtl92e_watch_dog_timer_callback(unsigned long data);
+void rtl92e_deinit_deferred_work(struct ieee80211_hw *hw);
+
+bool rtl92e_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx);
+bool rtl92e_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb);
+u8 rtl92e_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb,
+                         u8 is_tx);
+void rtl92e_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb);
+void rtl92e_watch_dog_timer_callback(unsigned long data);
+int rtl92e_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                       struct ieee80211_sta *sta, u16 tid, u16 *ssn);
+int rtl92e_tx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                      struct ieee80211_sta *sta, u16 tid);
+int rtl92e_tx_agg_oper(struct ieee80211_hw *hw,
+                      struct ieee80211_sta *sta, u16 tid);
+int rtl92e_rx_agg_start(struct ieee80211_hw *hw,
+                       struct ieee80211_sta *sta, u16 tid);
+int rtl92e_rx_agg_stop(struct ieee80211_hw *hw,
+                      struct ieee80211_sta *sta, u16 tid);
+void rtl92e_watchdog_wq_callback(void *data);
+void rtl92e_fwevt_wq_callback(void *data);
+
+void stg_rtl_get_tcb_desc(struct ieee80211_hw *hw,
+                         struct ieee80211_tx_info *info,
+                         struct ieee80211_sta *sta,
+                         struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc);
+
+int stg_rtl_send_smps_action(struct ieee80211_hw *hw,
+                            struct ieee80211_sta *sta,
+                            enum ieee80211_smps_mode smps);
+u8 *rtl92e_find_ie(u8 *data, unsigned int len, u8 ie);
+void rtl92e_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len);
+u8 rtl92e_tid_to_ac(struct ieee80211_hw *hw, u8 tid);
+void rtl92e_easy_concurrent_retrytimer_callback(unsigned long data);
+extern struct rtl_global_var global_var;
+int  rtl_core_module_init(void);
+void  rtl_core_module_exit(void);
+
+#endif
diff --git a/drivers/staging/rtl8192ee/cam.c b/drivers/staging/rtl8192ee/cam.c
new file mode 100644 (file)
index 0000000..e32c329
--- /dev/null
@@ -0,0 +1,337 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+#include "wifi.h"
+#include "cam.h"
+
+void rtl92e_cam_reset_sec_info(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       rtlpriv->sec.use_defaultkey = false;
+       rtlpriv->sec.pairwise_enc_algorithm = NO_ENCRYPTION;
+       rtlpriv->sec.group_enc_algorithm = NO_ENCRYPTION;
+       memset(rtlpriv->sec.key_buf, 0, KEY_BUF_SIZE * MAX_KEY_LEN);
+       memset(rtlpriv->sec.key_len, 0, KEY_BUF_SIZE);
+       rtlpriv->sec.pairwise_key = NULL;
+}
+
+static void rtl_cam_program_entry(struct ieee80211_hw *hw, u32 entry_no,
+                                 u8 *mac_addr, u8 *key_cont_128, u16 us_config)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       u32 target_command;
+       u32 target_content = 0;
+       u8 entry_i;
+
+       RT_PRINT_DATA(rtlpriv, COMP_SEC, DBG_DMESG, "Key content:",
+                     key_cont_128, 16);
+
+       for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) {
+               target_command = entry_i + CAM_CONTENT_COUNT * entry_no;
+               target_command = target_command | BIT(31) | BIT(16);
+
+               if (entry_i == 0) {
+                       target_content = (u32) (*(mac_addr + 0)) << 16 |
+                           (u32) (*(mac_addr + 1)) << 24 | (u32) us_config;
+
+                       rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI],
+                                       target_content);
+                       rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],
+                                       target_command);
+
+                       RT_TRACE(COMP_SEC, DBG_LOUD,
+                                ("WRITE %x: %x\n",
+                                 rtlpriv->cfg->maps[WCAMI], target_content));
+                       RT_TRACE(COMP_SEC, DBG_LOUD,
+                                ("The Key ID is %d\n", entry_no));
+                       RT_TRACE(COMP_SEC, DBG_LOUD,
+                                ("WRITE %x: %x\n",
+                                 rtlpriv->cfg->maps[RWCAM], target_command));
+               } else if (entry_i == 1) {
+                       target_content = (u32) (*(mac_addr + 5)) << 24 |
+                           (u32) (*(mac_addr + 4)) << 16 |
+                           (u32) (*(mac_addr + 3)) << 8 |
+                           (u32) (*(mac_addr + 2));
+
+                       rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI],
+                                       target_content);
+                       rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],
+                                       target_command);
+
+                       RT_TRACE(COMP_SEC, DBG_LOUD,
+                                ("WRITE A4: %x\n", target_content));
+                       RT_TRACE(COMP_SEC, DBG_LOUD,
+                                ("WRITE A0: %x\n", target_command));
+               } else {
+                       target_content =
+                           (u32) (*(key_cont_128 + (entry_i * 4 - 8) + 3)) <<
+                           24 | (u32) (*(key_cont_128 + (entry_i * 4 - 8) + 2))
+                           << 16 |
+                           (u32) (*(key_cont_128 + (entry_i * 4 - 8) + 1)) << 8
+                           | (u32) (*(key_cont_128 + (entry_i * 4 - 8) + 0));
+
+                       rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI],
+                                       target_content);
+                       rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],
+                                       target_command);
+                       udelay(100);
+
+                       RT_TRACE(COMP_SEC, DBG_LOUD,
+                                ("WRITE A4: %x\n", target_content));
+                       RT_TRACE(COMP_SEC, DBG_LOUD,
+                                ("WRITE A0: %x\n", target_command));
+               }
+       }
+
+       RT_TRACE(COMP_SEC, DBG_LOUD,
+                ("after set key, usconfig:%x\n", us_config));
+}
+
+u8 stg_rtl_cam_add_one_entry(struct ieee80211_hw *hw, u8 *mac_addr,
+                            u32 ul_key_id, u32 ul_entry_idx, u32 ul_enc_alg,
+                            u32 ul_default_key, u8 *key_content)
+{
+       u32 us_config;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       RT_TRACE(COMP_SEC, DBG_DMESG,
+                ("EntryNo:%x, ulKeyId=%x, ulEncAlg=%x, ulUseDK=%x MacAddr %pM\n",
+                 ul_entry_idx, ul_key_id, ul_enc_alg,
+                 ul_default_key, mac_addr));
+
+       if (ul_key_id == TOTAL_CAM_ENTRY) {
+               RT_TRACE(COMP_ERR, DBG_WARNING,
+                        ("ulKeyId exceed!\n"));
+               return 0;
+       }
+
+       if (ul_default_key == 1)
+               us_config = CFG_VALID | ((u16) (ul_enc_alg) << 2);
+       else
+               us_config = CFG_VALID | ((ul_enc_alg) << 2) | ul_key_id;
+
+       rtl_cam_program_entry(hw, ul_entry_idx, mac_addr,
+                             (u8 *)key_content, us_config);
+
+       RT_TRACE(COMP_SEC, DBG_DMESG, ("end\n"));
+
+       return 1;
+}
+EXPORT_SYMBOL(stg_rtl_cam_add_one_entry);
+
+int stg_rtl_cam_delete_one_entry(struct ieee80211_hw *hw,
+                                u8 *mac_addr, u32 ul_key_id)
+{
+       u32 ul_command;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       RT_TRACE(COMP_SEC, DBG_DMESG, ("key_idx:%d\n", ul_key_id));
+
+       ul_command = ul_key_id * CAM_CONTENT_COUNT;
+       ul_command = ul_command | BIT(31) | BIT(16);
+
+       rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], 0);
+       rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command);
+
+       RT_TRACE(COMP_SEC, DBG_DMESG,
+                ("stg_rtl_cam_delete_one_entry(): WRITE A4: %x\n", 0));
+       RT_TRACE(COMP_SEC, DBG_DMESG,
+                ("stg_rtl_cam_delete_one_entry(): WRITE A0: %x\n",
+                 ul_command));
+       return 0;
+}
+EXPORT_SYMBOL(stg_rtl_cam_delete_one_entry);
+
+void stg_rtl_cam_reset_all_entry(struct ieee80211_hw *hw)
+{
+       u32 ul_command;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       ul_command = BIT(31) | BIT(30);
+       rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command);
+}
+EXPORT_SYMBOL(stg_rtl_cam_reset_all_entry);
+
+void stg_rtl_cam_mark_invalid(struct ieee80211_hw *hw, u8 uc_index)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       u32 ul_command;
+       u32 ul_content;
+       u32 ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_AES];
+
+       switch (rtlpriv->sec.pairwise_enc_algorithm) {
+       case WEP40_ENCRYPTION:
+               ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_WEP40];
+               break;
+       case WEP104_ENCRYPTION:
+               ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_WEP104];
+               break;
+       case TKIP_ENCRYPTION:
+               ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_TKIP];
+               break;
+       case AESCCMP_ENCRYPTION:
+               ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_AES];
+               break;
+       default:
+               ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_AES];
+       }
+
+       ul_content = (uc_index & 3) | ((u16) (ul_enc_algo) << 2);
+
+       ul_content |= BIT(15);
+       ul_command = CAM_CONTENT_COUNT * uc_index;
+       ul_command = ul_command | BIT(31) | BIT(16);
+
+       rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], ul_content);
+       rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command);
+
+       RT_TRACE(COMP_SEC, DBG_DMESG,
+                ("stg_rtl_cam_mark_invalid(): WRITE A4: %x\n", ul_content));
+       RT_TRACE(COMP_SEC, DBG_DMESG,
+                ("stg_rtl_cam_mark_invalid(): WRITE A0: %x\n", ul_command));
+}
+EXPORT_SYMBOL(stg_rtl_cam_mark_invalid);
+
+void stg_rtl_cam_empty_entry(struct ieee80211_hw *hw, u8 uc_index)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       u32 ul_command;
+       u32 ul_content;
+       u32 ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_AES];
+       u8 entry_i;
+
+       switch (rtlpriv->sec.pairwise_enc_algorithm) {
+       case WEP40_ENCRYPTION:
+               ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_WEP40];
+               break;
+       case WEP104_ENCRYPTION:
+               ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_WEP104];
+               break;
+       case TKIP_ENCRYPTION:
+               ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_TKIP];
+               break;
+       case AESCCMP_ENCRYPTION:
+               ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_AES];
+               break;
+       default:
+               ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_AES];
+       }
+
+       for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) {
+               if (entry_i == 0) {
+                       ul_content =
+                           (uc_index & 0x03) | ((u16) (ul_encalgo) << 2);
+                       ul_content |= BIT(15);
+
+               } else {
+                       ul_content = 0;
+               }
+
+               ul_command = CAM_CONTENT_COUNT * uc_index + entry_i;
+               ul_command = ul_command | BIT(31) | BIT(16);
+
+               rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], ul_content);
+               rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command);
+
+               RT_TRACE(COMP_SEC, DBG_LOUD,
+                        ("stg_rtl_cam_empty_entry(): WRITE A4: %x\n",
+                         ul_content));
+               RT_TRACE(COMP_SEC, DBG_LOUD,
+                        ("stg_rtl_cam_empty_entry(): WRITE A0: %x\n",
+                         ul_command));
+       }
+}
+EXPORT_SYMBOL(stg_rtl_cam_empty_entry);
+
+u8 stg_rtl_cam_get_free_entry(struct ieee80211_hw *hw, u8 *sta_addr)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u32 bitmap = (rtlpriv->sec.hwsec_cam_bitmap) >> 4;
+       u8 entry_idx = 0;
+       u8 i, *addr;
+
+       if (!sta_addr) {
+               RT_TRACE(COMP_SEC, DBG_EMERG,
+                        ("sta_addr is NULL\n"));
+               return TOTAL_CAM_ENTRY;
+       }
+       /* Does STA already exist? */
+       for (i = 4; i < TOTAL_CAM_ENTRY; i++) {
+               addr = rtlpriv->sec.hwsec_cam_sta_addr[i];
+               if (memcmp(addr, sta_addr, ETH_ALEN) == 0)
+                       return i;
+       }
+       /* Get a free CAM entry. */
+       for (entry_idx = 4; entry_idx < TOTAL_CAM_ENTRY; entry_idx++) {
+               if ((bitmap & BIT(0)) == 0) {
+                       RT_TRACE(COMP_SEC, DBG_EMERG,
+                                ("-----hwsec_cam_bitmap: 0x%x entry_idx=%d\n",
+                                         rtlpriv->sec.hwsec_cam_bitmap, entry_idx));
+                       rtlpriv->sec.hwsec_cam_bitmap |= BIT(0) << entry_idx;
+                       memcpy(rtlpriv->sec.hwsec_cam_sta_addr[entry_idx],
+                              sta_addr, ETH_ALEN);
+                       return entry_idx;
+               }
+               bitmap = bitmap >> 1;
+       }
+       return TOTAL_CAM_ENTRY;
+}
+EXPORT_SYMBOL(stg_rtl_cam_get_free_entry);
+
+void stg_rtl_cam_del_entry(struct ieee80211_hw *hw, u8 *sta_addr)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u32 bitmap;
+       u8 i, *addr;
+
+       if (NULL == sta_addr) {
+               RT_TRACE(COMP_SEC, DBG_EMERG,
+                        ("sta_addr is NULL.\n"));
+               return;
+       }
+
+       if (is_zero_ether_addr(sta_addr)) {
+               RT_TRACE(COMP_SEC, DBG_EMERG,
+                        ("sta_addr is 00:00:00:00:00:00.\n"));
+               return;
+       }
+       /* Does STA already exist? */
+       for (i = 4; i < TOTAL_CAM_ENTRY; i++) {
+               addr = rtlpriv->sec.hwsec_cam_sta_addr[i];
+               bitmap = (rtlpriv->sec.hwsec_cam_bitmap) >> i;
+               if (((bitmap & BIT(0)) == BIT(0)) &&
+                   (memcmp(addr, sta_addr, ETH_ALEN) == 0)) {
+                       /* Remove from HW Security CAM */
+                       memset(rtlpriv->sec.hwsec_cam_sta_addr[i], 0, ETH_ALEN);
+                       rtlpriv->sec.hwsec_cam_bitmap &= ~(BIT(0) << i);
+                       pr_info("&&&&&&&&&del entry %d\n", i);
+               }
+       }
+       return;
+}
+EXPORT_SYMBOL(stg_rtl_cam_del_entry);
diff --git a/drivers/staging/rtl8192ee/cam.h b/drivers/staging/rtl8192ee/cam.h
new file mode 100644 (file)
index 0000000..b3a9464
--- /dev/null
@@ -0,0 +1,52 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL_CAM_H_
+#define __RTL_CAM_H_
+
+#define CAM_CONTENT_COUNT                              8
+
+#define CFG_DEFAULT_KEY                                        BIT(5)
+#define CFG_VALID                                      BIT(15)
+
+#define PAIRWISE_KEYIDX                                        0
+#define CAM_PAIRWISE_KEY_POSITION                      4
+
+#define        CAM_CONFIG_USEDK                                1
+#define        CAM_CONFIG_NO_USEDK                             0
+
+void stg_rtl_cam_reset_all_entry(struct ieee80211_hw *hw);
+u8 stg_rtl_cam_add_one_entry(struct ieee80211_hw *hw, u8 *mac_addr,
+                            u32 ul_key_id, u32 ul_entry_idx, u32 ul_enc_alg,
+                            u32 ul_default_key, u8 *key_content);
+int stg_rtl_cam_delete_one_entry(struct ieee80211_hw *hw, u8 *mac_addr,
+                                u32 ul_key_id);
+void stg_rtl_cam_mark_invalid(struct ieee80211_hw *hw, u8 uc_index);
+void stg_rtl_cam_empty_entry(struct ieee80211_hw *hw, u8 uc_index);
+void rtl92e_cam_reset_sec_info(struct ieee80211_hw *hw);
+u8 stg_rtl_cam_get_free_entry(struct ieee80211_hw *hw, u8 *sta_addr);
+void stg_rtl_cam_del_entry(struct ieee80211_hw *hw, u8 *sta_addr);
+
+#endif
diff --git a/drivers/staging/rtl8192ee/compat.h b/drivers/staging/rtl8192ee/compat.h
new file mode 100644 (file)
index 0000000..72a3c13
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef __RTL_COMPAT_H__
+#define __RTL_COMPAT_H__
+
+
+#define RX_FLAG_MACTIME_MPDU RX_FLAG_MACTIME_START
+
+#define IEEE80211_KEY_FLAG_SW_MGMT IEEE80211_KEY_FLAG_SW_MGMT_TX
+
+struct ieee80211_mgmt_compat {
+       __le16 frame_control;
+       __le16 duration;
+       u8 da[6];
+       u8 sa[6];
+       u8 bssid[6];
+       __le16 seq_ctrl;
+       union {
+               struct {
+                       u8 category;
+                       union {
+                               struct {
+                                       u8 action_code;
+                                       u8 dialog_token;
+                                       u8 status_code;
+                                       u8 variable[0];
+                               } __packed wme_action;
+                               struct {
+                                       u8 action_code;
+                                       u8 dialog_token;
+                                       __le16 capab;
+                                       __le16 timeout;
+                                       __le16 start_seq_num;
+                               } __packed addba_req;
+                               struct{
+                                       u8 action_code;
+                                       u8 dialog_token;
+                                       __le16 status;
+                                       __le16 capab;
+                                       __le16 timeout;
+                               } __packed addba_resp;
+                               struct {
+                                       u8 action_code;
+                                       __le16 params;
+                                       __le16 reason_code;
+                               } __packed delba;
+                               struct {
+                                       u8 action_code;
+                                       /* capab_info for open and confirm,
+                                        * reason for close
+                                        */
+                                       __le16 aux;
+                                       /* Followed in plink_confirm by status
+                                        * code, AID and supported rates,
+                                        * and directly by supported rates in
+                                        * plink_open and plink_close
+                                        */
+                                       u8 variable[0];
+                               } __packed plink_action;
+                               struct {
+                                       u8 action_code;
+                                       u8 variable[0];
+                               } __packed mesh_action;
+                               struct {
+                                       u8 action;
+                                       u8 smps_control;
+                               } __packed ht_smps;
+                       } u;
+               } __packed action;
+       } u;
+} __packed;
+#endif
diff --git a/drivers/staging/rtl8192ee/core.c b/drivers/staging/rtl8192ee/core.c
new file mode 100644 (file)
index 0000000..76ea356
--- /dev/null
@@ -0,0 +1,1600 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "wifi.h"
+#include "core.h"
+#include "cam.h"
+#include "base.h"
+#include "ps.h"
+
+#include "btcoexist/rtl_btc.h"
+
+/*mutex for start & stop is must here. */
+static int rtl_op_start(struct ieee80211_hw *hw)
+{
+       int err = 0;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+       if (!is_hal_stop(rtlhal))
+               return 0;
+       if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status))
+               return 0;
+       mutex_lock(&rtlpriv->locks.conf_mutex);
+       err = rtlpriv->intf_ops->adapter_start(hw);
+       if (err)
+               goto out;
+       rtl92e_watch_dog_timer_callback((unsigned long)hw);
+
+out:
+       mutex_unlock(&rtlpriv->locks.conf_mutex);
+       return err;
+}
+
+static void rtl_op_stop(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       bool b_support_remote_wakeup = false;
+
+       if (is_hal_stop(rtlhal))
+               return;
+
+       rtlpriv->cfg->ops->get_hw_reg(hw, HAL_DEF_WOWLAN,
+                                     (u8 *)(&b_support_remote_wakeup));
+       /* here is must, because adhoc do stop and start,
+        * but stop with RFOFF may cause something wrong,
+        * like adhoc TP */
+       if (unlikely(ppsc->rfpwr_state == ERFOFF))
+               rtl92e_ips_nic_on(hw);
+
+       mutex_lock(&rtlpriv->locks.conf_mutex);
+       /* if wowlan supported, DON'T clear connected info */
+       if (!(b_support_remote_wakeup &&
+             rtlhal->b_enter_pnp_sleep)) {
+               mac->link_state = MAC80211_NOLINK;
+               memset(mac->bssid, 0, 6);
+               mac->vendor = PEER_UNKNOWN;
+
+               /* reset sec info */
+               rtl92e_cam_reset_sec_info(hw);
+
+               rtl92e_deinit_deferred_work(hw);
+       }
+       rtlpriv->intf_ops->adapter_stop(hw);
+
+       mutex_unlock(&rtlpriv->locks.conf_mutex);
+}
+
+static void rtl_op_tx(struct ieee80211_hw *hw,
+                     struct ieee80211_tx_control *control,
+                     struct sk_buff *skb)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       struct rtl_tcb_desc tcb_desc;
+       memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
+
+       if (unlikely(is_hal_stop(rtlhal) || ppsc->rfpwr_state != ERFON))
+               goto err_free;
+
+       if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status))
+               goto err_free;
+
+       if (!rtlpriv->intf_ops->waitq_insert(hw, control->sta, skb))
+               rtlpriv->intf_ops->adapter_tx(hw, control->sta, skb, &tcb_desc);
+       return;
+
+err_free:
+       dev_kfree_skb_any(skb);
+       return;
+}
+
+static int rtl_op_add_interface(struct ieee80211_hw *hw,
+                               struct ieee80211_vif *vif)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       int err = 0;
+
+       if (mac->vif) {
+               RT_TRACE(COMP_ERR, DBG_WARNING,
+                        ("vif has been set!! mac->vif = 0x%p\n", mac->vif));
+               return -EOPNOTSUPP;
+       }
+
+       vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
+
+       rtl92e_ips_nic_on(hw);
+
+       mutex_lock(&rtlpriv->locks.conf_mutex);
+       switch (ieee80211_vif_type_p2p(vif)) {
+       case NL80211_IFTYPE_P2P_CLIENT:
+               mac->p2p = P2P_ROLE_CLIENT;
+               /*fall through*/
+       case NL80211_IFTYPE_STATION:
+               if (mac->beacon_enabled == 1) {
+                       RT_TRACE(COMP_MAC80211, DBG_LOUD,
+                                ("NL80211_IFTYPE_STATION\n"));
+                       mac->beacon_enabled = 0;
+                       rtlpriv->cfg->ops->update_interrupt_mask(hw, 0,
+                                       rtlpriv->cfg->maps[RTL_IBSS_INT_MASKS]);
+               }
+               break;
+       case NL80211_IFTYPE_ADHOC:
+               RT_TRACE(COMP_MAC80211, DBG_LOUD,
+                        ("NL80211_IFTYPE_ADHOC\n"));
+               mac->link_state = MAC80211_LINKED;
+               rtlpriv->cfg->ops->set_bcn_reg(hw);
+               if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G)
+                       mac->basic_rates = 0xfff;
+               else
+                       mac->basic_rates = 0xff0;
+               rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE,
+                               (u8 *)(&mac->basic_rates));
+               break;
+       case NL80211_IFTYPE_P2P_GO:
+               mac->p2p = P2P_ROLE_GO;
+               /*fall through*/
+       case NL80211_IFTYPE_AP:
+               RT_TRACE(COMP_MAC80211, DBG_LOUD,
+                        ("NL80211_IFTYPE_AP\n"));
+
+               mac->link_state = MAC80211_LINKED;
+               rtlpriv->cfg->ops->set_bcn_reg(hw);
+               if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G)
+                       mac->basic_rates = 0xfff;
+               else
+                       mac->basic_rates = 0xff0;
+               rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE,
+                                             (u8 *)(&mac->basic_rates));
+               break;
+       case NL80211_IFTYPE_MESH_POINT:
+               RT_TRACE(COMP_MAC80211, DBG_LOUD,
+                        ("NL80211_IFTYPE_MESH_POINT\n"));
+
+               mac->link_state = MAC80211_LINKED;
+               rtlpriv->cfg->ops->set_bcn_reg(hw);
+               if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G)
+                       mac->basic_rates = 0xfff;
+               else
+                       mac->basic_rates = 0xff0;
+               rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE,
+                               (u8 *)(&mac->basic_rates));
+               break;
+       default:
+               RT_TRACE(COMP_ERR, DBG_EMERG,
+                        ("operation mode %d is not support!\n", vif->type));
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+#ifdef VIF_TODO
+       if (!rtl_set_vif_info(hw, vif))
+               goto out;
+#endif
+
+       if (mac->p2p) {
+               RT_TRACE(COMP_MAC80211, DBG_LOUD,
+                        ("p2p role %x\n", vif->type));
+               mac->basic_rates = 0xff0;/*disable cck rate for p2p*/
+               rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE,
+                               (u8 *)(&mac->basic_rates));
+       }
+       mac->vif = vif;
+       mac->opmode = vif->type;
+       rtlpriv->cfg->ops->set_network_type(hw, vif->type);
+       ether_addr_copy(mac->mac_addr, vif->addr);
+       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr);
+
+out:
+       mutex_unlock(&rtlpriv->locks.conf_mutex);
+       return err;
+}
+
+static void rtl_op_remove_interface(struct ieee80211_hw *hw,
+                                   struct ieee80211_vif *vif)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+
+       mutex_lock(&rtlpriv->locks.conf_mutex);
+
+       /* Free beacon resources */
+       if ((vif->type == NL80211_IFTYPE_AP) ||
+           (vif->type == NL80211_IFTYPE_ADHOC) ||
+           (vif->type == NL80211_IFTYPE_MESH_POINT)) {
+               if (mac->beacon_enabled == 1) {
+                       mac->beacon_enabled = 0;
+                       rtlpriv->cfg->ops->update_interrupt_mask(hw, 0,
+                                       rtlpriv->cfg->maps[RTL_IBSS_INT_MASKS]);
+               }
+       }
+
+       /*
+        *Note: We assume NL80211_IFTYPE_UNSPECIFIED as
+        *NO LINK for our hardware.
+        */
+       mac->p2p = 0;
+       mac->vif = NULL;
+       mac->link_state = MAC80211_NOLINK;
+       memset(mac->bssid, 0, 6);
+       mac->vendor = PEER_UNKNOWN;
+       mac->opmode = NL80211_IFTYPE_UNSPECIFIED;
+       rtlpriv->cfg->ops->set_network_type(hw, mac->opmode);
+
+       mutex_unlock(&rtlpriv->locks.conf_mutex);
+}
+/*<delete in kernel start>*/
+static int rtl_op_change_interface(struct ieee80211_hw *hw,
+                                  struct ieee80211_vif *vif,
+                                  enum nl80211_iftype new_type, bool p2p)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       int ret;
+       rtl_op_remove_interface(hw, vif);
+
+       vif->type = new_type;
+       vif->p2p = p2p;
+       ret = rtl_op_add_interface(hw, vif);
+       RT_TRACE(COMP_MAC80211, DBG_LOUD,
+                (" p2p  %x\n", p2p));
+       return ret;
+}
+
+#ifdef CONFIG_PM
+static u16 crc16_ccitt(u8 data, u16 crc)
+{
+       u8 shift_in, data_bit, crc_bit11, crc_bit4, crc_bit15;
+       u8 i;
+       u16 result;
+
+       for (i = 0; i < 8; i++) {
+               crc_bit15 = ((crc & BIT(15)) ? 1 : 0);
+               data_bit  = (data & (BIT(0) << i) ? 1 : 0);
+               shift_in = crc_bit15 ^ data_bit;
+
+               result = crc << 1;
+               if (shift_in == 0)
+                       result &= (~BIT(0));
+               else
+                       result |= BIT(0);
+
+               crc_bit11 = ((crc & BIT(11)) ? 1 : 0) ^ shift_in;
+               if (crc_bit11 == 0)
+                       result &= (~BIT(12));
+               else
+                       result |= BIT(12);
+
+               crc_bit4 = ((crc & BIT(4)) ? 1 : 0) ^ shift_in;
+               if (crc_bit4 == 0)
+                       result &= (~BIT(5));
+               else
+                       result |= BIT(5);
+
+               crc = result;
+       }
+
+       return crc;
+}
+
+static u16 _calculate_wol_pattern_crc(u8 *pattern, u16 len)
+{
+       u16 crc = 0xffff;
+       u32 i;
+
+       for (i = 0; i < len; i++)
+               crc = crc16_ccitt(pattern[i], crc);
+       crc = ~crc;
+
+       return crc;
+}
+
+static void _rtl_add_wowlan_patterns(struct ieee80211_hw *hw,
+                                    struct cfg80211_wowlan *wow)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = &(rtlpriv->mac80211);
+       struct cfg80211_pkt_pattern *patterns = wow->patterns;
+       struct rtl_wow_pattern rtl_pattern;
+       u8 *pattern_os, *mask_os;
+       u8 mask[MAX_WOL_BIT_MASK_SIZE] = {0};
+       u8 content[MAX_WOL_PATTERN_SIZE] = {0};
+       u8 broadcast_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+       u8 multicast_addr1[2] = {0x33, 0x33};
+       u8 multicast_addr2[3] = {0x01, 0x00, 0x5e};
+       u8 i, mask_len;
+       u16 j, len;
+
+       for (i = 0; i < wow->n_patterns; i++) {
+               memset(&rtl_pattern, 0, sizeof(struct rtl_wow_pattern));
+               memset(mask, 0, MAX_WOL_BIT_MASK_SIZE);
+               if (patterns[i].pattern_len > MAX_WOL_PATTERN_SIZE) {
+                       RT_TRACE(COMP_POWER, DBG_WARNING,
+                                ("Pattern[%d] is too long\n", i));
+                       continue;
+               }
+               pattern_os = patterns[i].pattern;
+               mask_len = DIV_ROUND_UP(patterns[i].pattern_len, 8);
+               mask_os = patterns[i].mask;
+               RT_PRINT_DATA(rtlpriv, COMP_POWER, DBG_TRACE,
+                             "pattern content\n", pattern_os,
+                             patterns[i].pattern_len);
+               RT_PRINT_DATA(rtlpriv, COMP_POWER, DBG_TRACE,
+                             "mask content\n", mask_os, mask_len);
+               /* 1. unicast? multicast? or broadcast? */
+               if (memcmp(pattern_os, broadcast_addr, 6) == 0)
+                       rtl_pattern.type = BROADCAST_PATTERN;
+               else if (memcmp(pattern_os, multicast_addr1, 2) == 0 ||
+                        memcmp(pattern_os, multicast_addr2, 3) == 0)
+                       rtl_pattern.type = MULTICAST_PATTERN;
+               else if  (memcmp(pattern_os, mac->mac_addr, 6) == 0)
+                       rtl_pattern.type = UNICAST_PATTERN;
+               else
+                       rtl_pattern.type = UNKNOWN_TYPE;
+
+               /* 2. translate mask_from_os to mask_for_hw */
+
+/******************************************************************************
+ * pattern from OS uses 'ethenet frame', like this:
+
+                  |    6   |    6   |   2  |     20    |  Variable  |  4  |
+                  |--------+--------+------+-----------+------------+-----|
+                  |    802.3 Mac Header    | IP Header | TCP Packet | FCS |
+                  |   DA   |   SA   | Type |
+
+ * BUT, packet catched by our HW is in '802.11 frame', begin from LLC,
+
+       |     24 or 30      |    6   |   2  |     20    |  Variable  |  4  |
+       |-------------------+--------+------+-----------+------------+-----|
+       | 802.11 MAC Header |       LLC     | IP Header | TCP Packet | FCS |
+                           | Others | Tpye |
+
+ * Therefore, we need translate mask_from_OS to mask_to_hw.
+ * We should left-shift mask by 6 bits, then set the new bit[0~5] = 0,
+ * because new mask[0~5] means 'SA', but our HW packet begins from LLC,
+ * bit[0~5] corresponds to first 6 Bytes in LLC, they just don't match.
+ ******************************************************************************/
+
+               /* Shift 6 bits */
+               for (j = 0; j < mask_len - 1; j++) {
+                       mask[j] = mask_os[j] >> 6;
+                       mask[j] |= (mask_os[j + 1] & 0x3F) << 2;
+               }
+               mask[j] = (mask_os[j] >> 6) & 0x3F;
+               /* Set bit 0-5 to zero */
+               mask[0] &= 0xC0;
+
+               RT_PRINT_DATA(rtlpriv, COMP_POWER, DBG_TRACE,
+                             "mask to hw\n", mask, mask_len);
+               for (j = 0; j < (MAX_WOL_BIT_MASK_SIZE + 1) / 4; j++) {
+                       rtl_pattern.mask[j] = mask[j * 4];
+                       rtl_pattern.mask[j] |= (mask[j * 4 + 1] << 8);
+                       rtl_pattern.mask[j] |= (mask[j * 4 + 2] << 16);
+                       rtl_pattern.mask[j] |= (mask[j * 4 + 3] << 24);
+               }
+
+               /* To get the wake up pattern from the mask.
+                * We do not count first 12 bits which means
+                * DA[6] and SA[6] in the pattern to match HW design. */
+               len = 0;
+               for (j = 12; j < patterns[i].pattern_len; j++) {
+                       if ((mask_os[j / 8] >> (j % 8)) & 0x01) {
+                               content[len] = pattern_os[j];
+                               len++;
+                       }
+               }
+
+               RT_PRINT_DATA(rtlpriv, COMP_POWER, DBG_TRACE,
+                             "pattern to hw\n", content, len);
+               /* 3. calculate crc */
+               rtl_pattern.crc = _calculate_wol_pattern_crc(content, len);
+               RT_TRACE(COMP_POWER, DBG_TRACE,
+                        ("CRC_Remainder = 0x%x", rtl_pattern.crc));
+
+               /* 4. write crc & mask_for_hw to hw */
+               rtlpriv->cfg->ops->add_wowlan_pattern(hw, &rtl_pattern, i);
+       }
+       rtl_write_byte(rtlpriv, 0x698, wow->n_patterns);
+}
+
+static int rtl_op_suspend(struct ieee80211_hw *hw,
+                         struct cfg80211_wowlan *wow)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       struct timeval ts;
+
+       RT_TRACE(COMP_POWER, DBG_DMESG, ("\n"));
+       if (WARN_ON(!wow))
+               return -EINVAL;
+
+       /* to resolve s4 can not wake up*/
+       do_gettimeofday(&ts);
+       rtlhal->last_suspend_sec = ts.tv_sec;
+
+       if ((ppsc->wo_wlan_mode & WAKE_ON_PATTERN_MATCH) && wow->n_patterns)
+               _rtl_add_wowlan_patterns(hw, wow);
+
+       rtlhal->driver_is_goingto_unload = true;
+       rtlhal->b_enter_pnp_sleep = true;
+
+       rtl92e_lps_leave(hw);
+       rtl_op_stop(hw);
+       device_set_wakeup_enable(wiphy_dev(hw->wiphy), true);
+       return 0;
+}
+
+static int rtl_op_resume(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct timeval ts;
+
+       RT_TRACE(COMP_POWER, DBG_DMESG, ("\n"));
+       rtlhal->driver_is_goingto_unload = false;
+       rtlhal->b_enter_pnp_sleep = false;
+       rtlhal->b_wake_from_pnp_sleep = true;
+
+       /* to resovle s4 can not wake up*/
+       do_gettimeofday(&ts);
+       if (ts.tv_sec - rtlhal->last_suspend_sec < 5)
+               return -1;
+
+       rtl_op_start(hw);
+       device_set_wakeup_enable(wiphy_dev(hw->wiphy), false);
+       ieee80211_resume_disconnect(mac->vif);
+       rtlhal->b_wake_from_pnp_sleep = false;
+       return 0;
+}
+#endif
+
+static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       struct ieee80211_conf *conf = &hw->conf;
+
+       if (mac->skip_scan)
+               return 1;
+
+
+       mutex_lock(&rtlpriv->locks.conf_mutex);
+       if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) {  /* BIT(2) */
+               RT_TRACE(COMP_MAC80211, DBG_LOUD,
+                        ("IEEE80211_CONF_CHANGE_LISTEN_INTERVAL\n"));
+       }
+
+       /*For IPS */
+       if (changed & IEEE80211_CONF_CHANGE_IDLE) {
+               if (hw->conf.flags & IEEE80211_CONF_IDLE)
+                       rtl92e_ips_nic_off(hw);
+               else
+                       rtl92e_ips_nic_on(hw);
+       } else {
+               /*
+                *although rfoff may not cause by ips, but we will
+                *check the reason in set_rf_power_state function
+                */
+               if (unlikely(ppsc->rfpwr_state == ERFOFF))
+                       rtl92e_ips_nic_on(hw);
+       }
+
+       /*For LPS */
+       if (changed & IEEE80211_CONF_CHANGE_PS) {
+               cancel_delayed_work(&rtlpriv->works.ps_work);
+               cancel_delayed_work(&rtlpriv->works.ps_rfon_wq);
+               if (conf->flags & IEEE80211_CONF_PS) {
+                       rtlpriv->psc.sw_ps_enabled = true;
+                       /* sleep here is must, or we may recv the beacon and
+                        * cause mac80211 into wrong ps state, this will cause
+                        * power save nullfunc send fail, and further cause
+                        * pkt loss, So sleep must quickly but not immediatly
+                        * because that will cause nullfunc send by mac80211
+                        * fail, and cause pkt loss, we have tested that 5mA
+                        * is worked very well */
+                       if (!rtlpriv->psc.multi_buffered)
+                               queue_delayed_work(rtlpriv->works.rtl_wq,
+                                                  &rtlpriv->works.ps_work,
+                                                  MSECS(5));
+               } else {
+                       rtl92e_swlps_rf_awake(hw);
+                       rtlpriv->psc.sw_ps_enabled = false;
+               }
+       }
+
+       if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) {
+               RT_TRACE(COMP_MAC80211, DBG_LOUD,
+                        ("IEEE80211_CONF_CHANGE_RETRY_LIMITS %x\n",
+                         hw->conf.long_frame_max_tx_count));
+               mac->retry_long = hw->conf.long_frame_max_tx_count;
+               mac->retry_short = hw->conf.long_frame_max_tx_count;
+               rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RETRY_LIMIT,
+                               (u8 *)(&hw->conf.long_frame_max_tx_count));
+       }
+       if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
+           !rtlpriv->proximity.proxim_on) {
+               struct ieee80211_channel *channel = hw->conf.chandef.chan;
+               enum nl80211_chan_width width = hw->conf.chandef.width;
+               u8 wide_chan = (u8) channel->hw_value;
+               enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
+
+               /* channel_type is for 20&40M */
+               if (width < NL80211_CHAN_WIDTH_80)
+                       channel_type = cfg80211_get_chandef_type(&(hw->conf.chandef));
+               if (mac->act_scanning)
+                       mac->n_channels++;
+
+               if (rtlpriv->dm.supp_phymode_switch &&
+                   mac->link_state < MAC80211_LINKED &&
+                   !mac->act_scanning) {
+                       if (rtlpriv->cfg->ops->check_switch_to_dmdp)
+                               rtlpriv->cfg->ops->check_switch_to_dmdp(hw);
+               }
+
+               /*
+                *because we should back channel to
+                *current_network.chan in in scanning,
+                *So if set_chan == current_network.chan
+                *we should set it.
+                *because mac80211 tell us wrong bw40
+                *info for cisco1253 bw20, so we modify
+                *it here based on UPPER & LOWER
+                */
+
+               if (width >= NL80211_CHAN_WIDTH_80) {
+                       if (width == NL80211_CHAN_WIDTH_80) {
+                               u32 center_freq = hw->conf.chandef.center_freq1;
+                               u32 primary_freq =
+                               (u32)hw->conf.chandef.chan->center_freq;
+
+                               rtlphy->current_chan_bw =
+                                       HT_CHANNEL_WIDTH_80;
+                               mac->bw_80 = true;
+                               mac->bw_40 = true;
+                               if (center_freq > primary_freq) {
+                                       mac->cur_80_prime_sc =
+                                       PRIME_CHNL_OFFSET_LOWER;
+                                       if (center_freq - primary_freq == 10) {
+                                               mac->cur_40_prime_sc =
+                                               PRIME_CHNL_OFFSET_UPPER;
+
+                                               wide_chan += 2;
+                                       } else if (center_freq - primary_freq == 30) {
+                                               mac->cur_40_prime_sc =
+                                               PRIME_CHNL_OFFSET_LOWER;
+
+                                               wide_chan += 6;
+                                       }
+                               } else {
+                                       mac->cur_80_prime_sc =
+                                       PRIME_CHNL_OFFSET_UPPER;
+                                       if (primary_freq - center_freq == 10) {
+                                               mac->cur_40_prime_sc =
+                                               PRIME_CHNL_OFFSET_LOWER;
+
+                                               wide_chan -= 2;
+                                       } else if (primary_freq - center_freq == 30) {
+                                               mac->cur_40_prime_sc =
+                                               PRIME_CHNL_OFFSET_UPPER;
+
+                                               wide_chan -= 6;
+                                       }
+                               }
+                       }
+               } else {
+                       switch (channel_type) {
+                       case NL80211_CHAN_HT20:
+                       case NL80211_CHAN_NO_HT:
+                               /* SC */
+                               mac->cur_40_prime_sc =
+                                       PRIME_CHNL_OFFSET_DONT_CARE;
+                               rtlphy->current_chan_bw =
+                                       HT_CHANNEL_WIDTH_20;
+                               mac->bw_40 = false;
+                               mac->bw_80 = false;
+                               break;
+                       case NL80211_CHAN_HT40MINUS:
+                               /* SC */
+                               mac->cur_40_prime_sc =
+                                       PRIME_CHNL_OFFSET_UPPER;
+                               rtlphy->current_chan_bw =
+                                       HT_CHANNEL_WIDTH_20_40;
+                               mac->bw_40 = true;
+                               mac->bw_80 = false;
+
+                               /*wide channel */
+                               wide_chan -= 2;
+                               break;
+                       case NL80211_CHAN_HT40PLUS:
+                               /* SC */
+                               mac->cur_40_prime_sc =
+                                       PRIME_CHNL_OFFSET_LOWER;
+                               rtlphy->current_chan_bw =
+                                       HT_CHANNEL_WIDTH_20_40;
+                               mac->bw_40 = true;
+                               mac->bw_80 = false;
+                               /*wide channel */
+                               wide_chan += 2;
+                               break;
+                       default:
+                               mac->bw_40 = false;
+                               mac->bw_80 = false;
+                               RT_TRACE(COMP_ERR, DBG_EMERG,
+                                        ("switch case not processed\n"));
+                               break;
+                       }
+               }
+
+               if (wide_chan <= 0)
+                       wide_chan = 1;
+
+               /* in scanning, when before we offchannel we may send a ps=1
+                * null to AP, and then we may send a ps = 0 null to AP quickly,
+                * but first null have cause AP's put lots of packet to hw tx
+                * buffer, these packet must be tx before off channel so we must
+                * delay more time to let AP flush these packets before
+                * offchannel, or dis-association or delete BA will happen by AP
+                */
+               if (rtlpriv->mac80211.offchan_deley) {
+                       rtlpriv->mac80211.offchan_deley = false;
+                       mdelay(50);
+               }
+
+               rtlphy->current_channel = wide_chan;
+
+               rtlpriv->cfg->ops->switch_channel(hw);
+               rtlpriv->cfg->ops->set_channel_access(hw);
+               rtlpriv->cfg->ops->set_bw_mode(hw,
+                       channel_type);
+       }
+
+       mutex_unlock(&rtlpriv->locks.conf_mutex);
+
+       return 0;
+}
+
+static void rtl_op_configure_filter(struct ieee80211_hw *hw,
+                                   unsigned int changed_flags,
+                                   unsigned int *new_flags, u64 multicast)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+
+       *new_flags &= RTL_SUPPORTED_FILTERS;
+       if (0 == changed_flags)
+               return;
+
+       /*TODO: we disable broadcase now, so enable here */
+       if (changed_flags & FIF_ALLMULTI) {
+               if (*new_flags & FIF_ALLMULTI) {
+                       mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_AM] |
+                           rtlpriv->cfg->maps[MAC_RCR_AB];
+                       RT_TRACE(COMP_MAC80211, DBG_LOUD,
+                                ("Enable receive multicast frame.\n"));
+               } else {
+                       mac->rx_conf &= ~(rtlpriv->cfg->maps[MAC_RCR_AM] |
+                                         rtlpriv->cfg->maps[MAC_RCR_AB]);
+                       RT_TRACE(COMP_MAC80211, DBG_LOUD,
+                                ("Disable receive multicast frame.\n"));
+               }
+       }
+
+       if (changed_flags & FIF_FCSFAIL) {
+               if (*new_flags & FIF_FCSFAIL) {
+                       mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACRC32];
+                       RT_TRACE(COMP_MAC80211, DBG_LOUD,
+                                ("Enable receive FCS error frame.\n"));
+               } else {
+                       mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACRC32];
+                       RT_TRACE(COMP_MAC80211, DBG_LOUD,
+                                ("Disable receive FCS error frame.\n"));
+               }
+       }
+
+       /* if ssid not set to hw don't check bssid
+        * here just used for linked scanning, & linked
+        * and nolink check bssid is set in set network_type */
+       if ((changed_flags & FIF_BCN_PRBRESP_PROMISC) &&
+           (mac->link_state >= MAC80211_LINKED)) {
+               if (mac->opmode != NL80211_IFTYPE_AP &&
+                   mac->opmode != NL80211_IFTYPE_MESH_POINT) {
+                       if (*new_flags & FIF_BCN_PRBRESP_PROMISC)
+                               rtlpriv->cfg->ops->set_chk_bssid(hw, false);
+                       else
+                               rtlpriv->cfg->ops->set_chk_bssid(hw, true);
+               }
+       }
+
+       if (changed_flags & FIF_CONTROL) {
+               if (*new_flags & FIF_CONTROL) {
+                       mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACF];
+
+                       RT_TRACE(COMP_MAC80211, DBG_LOUD,
+                                ("Enable receive control frame.\n"));
+               } else {
+                       mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACF];
+                       RT_TRACE(COMP_MAC80211, DBG_LOUD,
+                                ("Disable receive control frame.\n"));
+               }
+       }
+
+       if (changed_flags & FIF_OTHER_BSS) {
+               if (*new_flags & FIF_OTHER_BSS) {
+                       mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_AAP];
+                       RT_TRACE(COMP_MAC80211, DBG_LOUD,
+                                ("Enable receive other BSS's frame.\n"));
+               } else {
+                       mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_AAP];
+                       RT_TRACE(COMP_MAC80211, DBG_LOUD,
+                                ("Disable receive other BSS's frame.\n"));
+               }
+       }
+}
+static int rtl_op_sta_add(struct ieee80211_hw *hw,
+                         struct ieee80211_vif *vif,
+                         struct ieee80211_sta *sta)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_sta_info *sta_entry;
+
+       if (sta) {
+               sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+               spin_lock_bh(&rtlpriv->locks.entry_list_lock);
+               list_add_tail(&sta_entry->list, &rtlpriv->entry_list);
+               spin_unlock_bh(&rtlpriv->locks.entry_list_lock);
+               if (rtlhal->current_bandtype == BAND_ON_2_4G) {
+                       sta_entry->wireless_mode = WIRELESS_MODE_G;
+                       if (sta->supp_rates[0] <= 0xf)
+                               sta_entry->wireless_mode = WIRELESS_MODE_B;
+                       if (sta->ht_cap.ht_supported)
+                               sta_entry->wireless_mode = WIRELESS_MODE_N_24G;
+
+                       if (vif->type == NL80211_IFTYPE_ADHOC)
+                               sta_entry->wireless_mode = WIRELESS_MODE_G;
+               } else if (rtlhal->current_bandtype == BAND_ON_5G) {
+                       sta_entry->wireless_mode = WIRELESS_MODE_A;
+                       if (sta->ht_cap.ht_supported)
+                               sta_entry->wireless_mode = WIRELESS_MODE_N_5G;
+                       if (sta->vht_cap.vht_supported)
+                               sta_entry->wireless_mode = WIRELESS_MODE_AC_5G;
+
+                       if (vif->type == NL80211_IFTYPE_ADHOC)
+                               sta_entry->wireless_mode = WIRELESS_MODE_A;
+               }
+               /*disable cck rate for p2p*/
+               if (mac->p2p)
+                       sta->supp_rates[0] &= 0xfffffff0;
+
+               ether_addr_copy(sta_entry->mac_addr, sta->addr);
+               RT_TRACE(COMP_MAC80211, DBG_DMESG,
+                        ("Add sta addr is %pM\n", sta->addr));
+               rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0);
+       }
+
+       return 0;
+}
+
+static int rtl_op_sta_remove(struct ieee80211_hw *hw,
+                            struct ieee80211_vif *vif,
+                            struct ieee80211_sta *sta)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_sta_info *sta_entry;
+       if (sta) {
+               RT_TRACE(COMP_MAC80211, DBG_DMESG,
+                        ("Remove sta addr is %pM\n", sta->addr));
+               sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+               sta_entry->wireless_mode = 0;
+               sta_entry->ratr_index = 0;
+               spin_lock_bh(&rtlpriv->locks.entry_list_lock);
+               list_del(&sta_entry->list);
+               spin_unlock_bh(&rtlpriv->locks.entry_list_lock);
+       }
+       return 0;
+}
+static int _rtl_get_hal_qnum(u16 queue)
+{
+       int qnum;
+
+       switch (queue) {
+       case 0:
+               qnum = AC3_VO;
+               break;
+       case 1:
+               qnum = AC2_VI;
+               break;
+       case 2:
+               qnum = AC0_BE;
+               break;
+       case 3:
+               qnum = AC1_BK;
+               break;
+       default:
+               qnum = AC0_BE;
+               break;
+       }
+       return qnum;
+}
+
+/*
+ *for mac80211 VO=0, VI=1, BE=2, BK=3
+ *for rtl819x  BE=0, BK=1, VI=2, VO=3
+ */
+static int rtl_op_conf_tx(struct ieee80211_hw *hw,
+                         struct ieee80211_vif *vif, u16 queue,
+                         const struct ieee80211_tx_queue_params *param)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       int aci;
+
+       if (queue >= AC_MAX) {
+               RT_TRACE(COMP_ERR, DBG_WARNING,
+                        ("queue number %d is incorrect!\n", queue));
+               return -EINVAL;
+       }
+
+       aci = _rtl_get_hal_qnum(queue);
+       mac->ac[aci].aifs = param->aifs;
+       mac->ac[aci].cw_min = cpu_to_le16(param->cw_min);
+       mac->ac[aci].cw_max = cpu_to_le16(param->cw_max);
+       mac->ac[aci].tx_op = cpu_to_le16(param->txop);
+       memcpy(&mac->edca_param[aci], param, sizeof(*param));
+       rtlpriv->cfg->ops->set_qos(hw, aci);
+       return 0;
+}
+
+static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
+                                   struct ieee80211_vif *vif,
+                                   struct ieee80211_bss_conf *bss_conf,
+                                   u32 changed)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+       mutex_lock(&rtlpriv->locks.conf_mutex);
+       if ((vif->type == NL80211_IFTYPE_ADHOC) ||
+           (vif->type == NL80211_IFTYPE_AP) ||
+           (vif->type == NL80211_IFTYPE_MESH_POINT)) {
+               if ((changed & BSS_CHANGED_BEACON) ||
+                   (changed & BSS_CHANGED_BEACON_ENABLED &&
+                    bss_conf->enable_beacon)) {
+                       if (mac->beacon_enabled == 0) {
+                               RT_TRACE(COMP_MAC80211, DBG_DMESG,
+                                        ("BSS_CHANGED_BEACON_ENABLED\n"));
+
+                               /*start hw beacon interrupt. */
+                               /*rtlpriv->cfg->ops->set_bcn_reg(hw); */
+                               mac->beacon_enabled = 1;
+                               rtlpriv->cfg->ops->update_interrupt_mask(hw,
+                                               rtlpriv->cfg->maps
+                                               [RTL_IBSS_INT_MASKS], 0);
+
+                               if (rtlpriv->cfg->ops->linked_set_reg)
+                                       rtlpriv->cfg->ops->linked_set_reg(hw);
+                       }
+               }
+               if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
+                   !bss_conf->enable_beacon) {
+                       if (mac->beacon_enabled == 1) {
+                               RT_TRACE(COMP_MAC80211, DBG_DMESG,
+                                        ("ADHOC DISABLE BEACON\n"));
+
+                               mac->beacon_enabled = 0;
+                               rtlpriv->cfg->ops->update_interrupt_mask(hw, 0,
+                                               rtlpriv->cfg->maps
+                                               [RTL_IBSS_INT_MASKS]);
+                       }
+               }
+               if (changed & BSS_CHANGED_BEACON_INT) {
+                       RT_TRACE(COMP_BEACON, DBG_TRACE,
+                                ("BSS_CHANGED_BEACON_INT\n"));
+                       mac->beacon_interval = bss_conf->beacon_int;
+                       rtlpriv->cfg->ops->set_bcn_intv(hw);
+               }
+       }
+
+       /*TODO: reference to enum ieee80211_bss_change */
+       if (changed & BSS_CHANGED_ASSOC) {
+               u8 mstatus;
+               if (bss_conf->assoc) {
+                       struct ieee80211_sta *sta = NULL;
+                       u8 keep_alive = 10;
+
+                       mstatus = RT_MEDIA_CONNECT;
+                       /* we should reset all sec info & cam
+                        * before set cam after linked, we should not
+                        * reset in disassoc, that will cause tkip->wep
+                        * fail because some flag will be wrong */
+                       /* reset sec info */
+                       rtl92e_cam_reset_sec_info(hw);
+                       /* reset cam to fix wep fail issue
+                        * when change from wpa to wep */
+                       stg_rtl_cam_reset_all_entry(hw);
+
+                       mac->link_state = MAC80211_LINKED;
+                       mac->cnt_after_linked = 0;
+                       mac->assoc_id = bss_conf->aid;
+                       memcpy(mac->bssid, bss_conf->bssid, 6);
+
+                       if (rtlpriv->cfg->ops->linked_set_reg)
+                               rtlpriv->cfg->ops->linked_set_reg(hw);
+
+                       rcu_read_lock();
+                       sta = ieee80211_find_sta(vif, (u8 *)bss_conf->bssid);
+                       if (!sta) {
+                               pr_err("ieee80211_find_sta returned NULL\n");
+                               rcu_read_unlock();
+                               goto out;
+                       }
+
+                       if (vif->type == NL80211_IFTYPE_STATION && sta)
+                               rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0);
+                       RT_TRACE(COMP_EASY_CONCURRENT, DBG_LOUD,
+                                ("send PS STATIC frame\n"));
+                       if (rtlpriv->dm.supp_phymode_switch) {
+                               if (sta->ht_cap.ht_supported)
+                                       stg_rtl_send_smps_action(hw, sta,
+                                                       IEEE80211_SMPS_STATIC);
+                       }
+
+                       if (rtlhal->current_bandtype == BAND_ON_5G) {
+                               mac->mode = WIRELESS_MODE_A;
+                       } else {
+                               if (sta->supp_rates[0] <= 0xf)
+                                       mac->mode = WIRELESS_MODE_B;
+                               else
+                                       mac->mode = WIRELESS_MODE_G;
+                       }
+
+                       if (sta->ht_cap.ht_supported) {
+                               if (rtlhal->current_bandtype == BAND_ON_2_4G)
+                                       mac->mode = WIRELESS_MODE_N_24G;
+                               else
+                                       mac->mode = WIRELESS_MODE_N_5G;
+                       }
+
+                       if (sta->vht_cap.vht_supported) {
+                               if (rtlhal->current_bandtype == BAND_ON_5G)
+                                       mac->mode = WIRELESS_MODE_AC_5G;
+                               else
+                                       mac->mode = WIRELESS_MODE_AC_24G;
+                       }
+
+                       rcu_read_unlock();
+
+                       /* to avoid AP Disassociation caused by inactivity */
+                       rtlpriv->cfg->ops->set_hw_reg(hw,
+                                                     HW_VAR_KEEP_ALIVE,
+                                                     (u8 *)(&keep_alive));
+
+                       RT_TRACE(COMP_MAC80211, DBG_DMESG,
+                                ("BSS_CHANGED_ASSOC\n"));
+               } else {
+                       mstatus = RT_MEDIA_DISCONNECT;
+
+                       if (mac->link_state == MAC80211_LINKED)
+                               rtl92e_lps_leave(hw);
+                       if (ppsc->p2p_ps_info.p2p_ps_mode > P2P_PS_NONE)
+                               rtl92e_p2p_ps_cmd(hw, P2P_PS_DISABLE);
+                       mac->link_state = MAC80211_NOLINK;
+                       memset(mac->bssid, 0, 6);
+                       mac->vendor = PEER_UNKNOWN;
+                       mac->mode = 0;
+
+                       if (rtlpriv->dm.supp_phymode_switch) {
+                               if (rtlpriv->cfg->ops->check_switch_to_dmdp)
+                                       rtlpriv->cfg->ops->check_switch_to_dmdp(hw);
+                       }
+                       RT_TRACE(COMP_MAC80211, DBG_DMESG,
+                                ("BSS_CHANGED_UN_ASSOC\n"));
+               }
+               rtlpriv->cfg->ops->set_network_type(hw, vif->type);
+               /* For FW LPS:
+                * To tell firmware we have connected or disconnected*/
+               rtlpriv->cfg->ops->set_hw_reg(hw,
+                                             HW_VAR_H2C_FW_JOINBSSRPT,
+                                             (u8 *)(&mstatus));
+               ppsc->report_linked = (mstatus == RT_MEDIA_CONNECT) ?
+                                     true : false;
+
+               if (rtlpriv->cfg->ops->get_btc_status())
+                       rtlpriv->btcoexist.btc_ops->btc_mediastatus_notify(
+                                                       rtlpriv, mstatus);
+       }
+
+       if (changed & BSS_CHANGED_ERP_CTS_PROT) {
+               RT_TRACE(COMP_MAC80211, DBG_TRACE,
+                        ("BSS_CHANGED_ERP_CTS_PROT\n"));
+               mac->use_cts_protect = bss_conf->use_cts_prot;
+       }
+
+       if (changed & BSS_CHANGED_ERP_PREAMBLE) {
+               RT_TRACE(COMP_MAC80211, DBG_LOUD,
+                        ("BSS_CHANGED_ERP_PREAMBLE use short preamble:%x\n",
+                         bss_conf->use_short_preamble));
+
+               mac->short_preamble = bss_conf->use_short_preamble;
+               rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACK_PREAMBLE,
+                                             (u8 *)(&mac->short_preamble));
+       }
+
+       if (changed & BSS_CHANGED_ERP_SLOT) {
+               RT_TRACE(COMP_MAC80211, DBG_TRACE,
+                        ("BSS_CHANGED_ERP_SLOT\n"));
+
+               if (bss_conf->use_short_slot)
+                       mac->slot_time = RTL_SLOT_TIME_9;
+               else
+                       mac->slot_time = RTL_SLOT_TIME_20;
+
+               rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME,
+                                             (u8 *)(&mac->slot_time));
+       }
+
+       if (changed & BSS_CHANGED_HT) {
+               struct ieee80211_sta *sta = NULL;
+
+               RT_TRACE(COMP_MAC80211, DBG_TRACE,
+                        ("BSS_CHANGED_HT\n"));
+
+               rcu_read_lock();
+               sta = ieee80211_find_sta(vif, (u8 *)bss_conf->bssid);
+               if (sta) {
+                       if (sta->ht_cap.ampdu_density >
+                           mac->current_ampdu_density)
+                               mac->current_ampdu_density =
+                                   sta->ht_cap.ampdu_density;
+                       if (sta->ht_cap.ampdu_factor <
+                           mac->current_ampdu_factor)
+                               mac->current_ampdu_factor =
+                                   sta->ht_cap.ampdu_factor;
+               }
+               rcu_read_unlock();
+
+               rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SHORTGI_DENSITY,
+                                             (u8 *)(&mac->max_mss_density));
+               rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AMPDU_FACTOR,
+                                             &mac->current_ampdu_factor);
+               rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AMPDU_MIN_SPACE,
+                                             &mac->current_ampdu_density);
+       }
+
+       if (changed & BSS_CHANGED_BSSID) {
+               u32 basic_rates;
+               struct ieee80211_sta *sta = NULL;
+
+               rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BSSID,
+                                             (u8 *)bss_conf->bssid);
+
+               RT_TRACE(COMP_MAC80211, DBG_DMESG,
+                        ("bssid: %pM\n", bss_conf->bssid));
+
+               mac->vendor = PEER_UNKNOWN;
+               memcpy(mac->bssid, bss_conf->bssid, 6);
+
+               rcu_read_lock();
+               sta = ieee80211_find_sta(vif, (u8 *)bss_conf->bssid);
+               if (!sta) {
+                       rcu_read_unlock();
+                       goto out;
+               }
+
+               if (rtlhal->current_bandtype == BAND_ON_5G) {
+                       mac->mode = WIRELESS_MODE_A;
+               } else {
+                       if (sta->supp_rates[0] <= 0xf)
+                               mac->mode = WIRELESS_MODE_B;
+                       else
+                               mac->mode = WIRELESS_MODE_G;
+               }
+
+               if (sta->ht_cap.ht_supported) {
+                       if (rtlhal->current_bandtype == BAND_ON_2_4G)
+                               mac->mode = WIRELESS_MODE_N_24G;
+                       else
+                               mac->mode = WIRELESS_MODE_N_5G;
+               }
+
+               if (sta->vht_cap.vht_supported) {
+                       if (rtlhal->current_bandtype == BAND_ON_5G)
+                               mac->mode = WIRELESS_MODE_AC_5G;
+                       else
+                               mac->mode = WIRELESS_MODE_AC_24G;
+               }
+
+               /* just station need it, because ibss & ap mode will
+                * set in sta_add, and will be NULL here */
+               if (vif->type == NL80211_IFTYPE_STATION) {
+                       struct rtl_sta_info *sta_entry;
+                       sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+                       sta_entry->wireless_mode = mac->mode;
+               }
+
+               if (sta->ht_cap.ht_supported) {
+                       mac->ht_enable = true;
+
+                       /*
+                        * for cisco 1252 bw20 it's wrong
+                        * if (ht_cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
+                        *      mac->bw_40 = true;
+                        * }
+                        * */
+               }
+
+               if (sta->vht_cap.vht_supported)
+                       mac->vht_enable = true;
+
+               if (changed & BSS_CHANGED_BASIC_RATES) {
+                       /* for 5G must << RATE_6M_INDEX=4,
+                        * because 5G have no cck rate*/
+                       if (rtlhal->current_bandtype == BAND_ON_5G)
+                               basic_rates = sta->supp_rates[1] << 4;
+                       else
+                               basic_rates = sta->supp_rates[0];
+
+                       mac->basic_rates = basic_rates;
+                       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE,
+                                       (u8 *)(&basic_rates));
+               }
+               rcu_read_unlock();
+       }
+out:
+       mutex_unlock(&rtlpriv->locks.conf_mutex);
+}
+
+static u64 rtl_op_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u64 tsf;
+
+       rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_CORRECT_TSF, (u8 *)(&tsf));
+       return tsf;
+}
+
+static void rtl_op_set_tsf(struct ieee80211_hw *hw,
+                          struct ieee80211_vif *vif, u64 tsf)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       u8 bibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ? 1 : 0;
+
+       mac->tsf = tsf;
+       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_CORRECT_TSF, (u8 *)(&bibss));
+}
+
+static void rtl_op_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 tmp = 0;
+
+       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_DUAL_TSF_RST, (u8 *)(&tmp));
+}
+
+static void rtl_op_sta_notify(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif,
+                             enum sta_notify_cmd cmd,
+                             struct ieee80211_sta *sta)
+{
+       switch (cmd) {
+       case STA_NOTIFY_SLEEP:
+               break;
+       case STA_NOTIFY_AWAKE:
+               break;
+       default:
+               break;
+       }
+}
+
+static int rtl_op_ampdu_action(struct ieee80211_hw *hw,
+                              struct ieee80211_vif *vif,
+                              enum ieee80211_ampdu_mlme_action action,
+                              struct ieee80211_sta *sta, u16 tid, u16 *ssn,
+                              u8 buf_size)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       switch (action) {
+       case IEEE80211_AMPDU_TX_START:
+               RT_TRACE(COMP_MAC80211, DBG_TRACE,
+                        ("IEEE80211_AMPDU_TX_START: TID:%d\n", tid));
+               return rtl92e_tx_agg_start(hw, vif, sta, tid, ssn);
+               break;
+       case IEEE80211_AMPDU_TX_STOP_CONT:
+       case IEEE80211_AMPDU_TX_STOP_FLUSH:
+       case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
+               RT_TRACE(COMP_MAC80211, DBG_TRACE,
+                        ("IEEE80211_AMPDU_TX_STOP: TID:%d\n", tid));
+               return rtl92e_tx_agg_stop(hw, vif, sta, tid);
+               break;
+       case IEEE80211_AMPDU_TX_OPERATIONAL:
+               RT_TRACE(COMP_MAC80211, DBG_TRACE,
+                        ("IEEE80211_AMPDU_TX_OPERATIONAL:TID:%d\n", tid));
+               rtl92e_tx_agg_oper(hw, sta, tid);
+               break;
+       case IEEE80211_AMPDU_RX_START:
+               RT_TRACE(COMP_MAC80211, DBG_TRACE,
+                        ("IEEE80211_AMPDU_RX_START:TID:%d\n", tid));
+               return rtl92e_rx_agg_start(hw, sta, tid);
+               break;
+       case IEEE80211_AMPDU_RX_STOP:
+               RT_TRACE(COMP_MAC80211, DBG_TRACE,
+                        ("IEEE80211_AMPDU_RX_STOP:TID:%d\n", tid));
+               return rtl92e_rx_agg_stop(hw, sta, tid);
+               break;
+       default:
+               RT_TRACE(COMP_ERR, DBG_EMERG,
+                        ("IEEE80211_AMPDU_ERR!!!!:\n"));
+               return -EOPNOTSUPP;
+       }
+       return 0;
+}
+
+static void rtl_op_sw_scan_start(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+
+       RT_TRACE(COMP_MAC80211, DBG_LOUD, ("\n"));
+       mac->act_scanning = true;
+       if (rtlpriv->link_info.b_higher_busytraffic) {
+               mac->skip_scan = true;
+               return;
+       }
+
+       if (rtlpriv->cfg->ops->get_btc_status())
+               rtlpriv->btcoexist.btc_ops->btc_scan_notify(rtlpriv, 1);
+
+       if (rtlpriv->dm.supp_phymode_switch) {
+               if (rtlpriv->cfg->ops->check_switch_to_dmdp)
+                       rtlpriv->cfg->ops->check_switch_to_dmdp(hw);
+       }
+
+       if (mac->link_state == MAC80211_LINKED) {
+               rtl92e_lps_leave(hw);
+               mac->link_state = MAC80211_LINKED_SCANNING;
+       } else {
+               rtl92e_ips_nic_on(hw);
+       }
+
+       /* Dul mac */
+       rtlpriv->rtlhal.b_load_imrandiqk_setting_for2g = false;
+
+       rtlpriv->cfg->ops->led_control(hw, LED_CTL_SITE_SURVEY);
+       rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_BACKUP_BAND0);
+}
+
+static void rtl_op_sw_scan_complete(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+
+       RT_TRACE(COMP_MAC80211, DBG_LOUD, ("\n"));
+       mac->act_scanning = false;
+       mac->skip_scan = false;
+       if (rtlpriv->link_info.b_higher_busytraffic)
+               return;
+
+       /* p2p will use 1/6/11 to scan */
+       if (mac->n_channels == 3)
+               mac->p2p_in_use = true;
+       else
+               mac->p2p_in_use = false;
+       mac->n_channels = 0;
+       /* Dul mac */
+       rtlpriv->rtlhal.b_load_imrandiqk_setting_for2g = false;
+
+       if (mac->link_state == MAC80211_LINKED_SCANNING) {
+               mac->link_state = MAC80211_LINKED;
+               if (mac->opmode == NL80211_IFTYPE_STATION) {
+                       /* fix fwlps issue */
+                       rtlpriv->cfg->ops->set_network_type(hw, mac->opmode);
+               }
+       }
+
+       rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_RESTORE);
+       if (rtlpriv->cfg->ops->get_btc_status())
+               rtlpriv->btcoexist.btc_ops->btc_scan_notify(rtlpriv, 0);
+}
+
+static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+                         struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+                         struct ieee80211_key_conf *key)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 key_type = NO_ENCRYPTION;
+       u8 key_idx;
+       bool group_key = false;
+       bool wep_only = false;
+       int err = 0;
+       u8 mac_addr[ETH_ALEN];
+       u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+       if (rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec) {
+               RT_TRACE(COMP_ERR, DBG_WARNING,
+                        ("not open hw encryption\n"));
+               return -ENOSPC; /*User disabled HW-crypto */
+       }
+       /* To support IBSS, use sw-crypto for GTK */
+       if (((vif->type == NL80211_IFTYPE_ADHOC) ||
+            (vif->type == NL80211_IFTYPE_MESH_POINT)) &&
+            !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
+               return -ENOSPC;
+       RT_TRACE(COMP_SEC, DBG_DMESG,
+                ("%s hardware based encryption for keyidx: %d, mac: %pM\n",
+                 cmd == SET_KEY ? "Using" : "Disabling", key->keyidx,
+                 sta ? sta->addr : bcast_addr));
+       rtlpriv->sec.being_setkey = true;
+       rtl92e_ips_nic_on(hw);
+       mutex_lock(&rtlpriv->locks.conf_mutex);
+       /* <1> get encryption alg */
+
+       switch (key->cipher) {
+       case WLAN_CIPHER_SUITE_WEP40:
+               key_type = WEP40_ENCRYPTION;
+               RT_TRACE(COMP_SEC, DBG_DMESG, ("alg:WEP40\n"));
+               break;
+       case WLAN_CIPHER_SUITE_WEP104:
+               RT_TRACE(COMP_SEC, DBG_DMESG, ("alg:WEP104\n"));
+               key_type = WEP104_ENCRYPTION;
+               break;
+       case WLAN_CIPHER_SUITE_TKIP:
+               key_type = TKIP_ENCRYPTION;
+               RT_TRACE(COMP_SEC, DBG_DMESG, ("alg:TKIP\n"));
+               break;
+       case WLAN_CIPHER_SUITE_CCMP:
+               key_type = AESCCMP_ENCRYPTION;
+               RT_TRACE(COMP_SEC, DBG_DMESG, ("alg:CCMP\n"));
+               break;
+       case WLAN_CIPHER_SUITE_AES_CMAC:
+               /* HW don't support CMAC encryption,
+                * use software CMAC encryption */
+               key_type = AESCMAC_ENCRYPTION;
+               RT_TRACE(COMP_SEC, DBG_DMESG, ("alg:CMAC\n"));
+               RT_TRACE(COMP_SEC, DBG_DMESG,
+                        ("HW don't support CMAC encrypiton, use software CMAC encryption\n"));
+               err = -EOPNOTSUPP;
+               goto out_unlock;
+       default:
+               RT_TRACE(COMP_ERR, DBG_EMERG,
+                        ("alg_err:%x!!!!:\n", key->cipher));
+               goto out_unlock;
+       }
+       if (key_type == WEP40_ENCRYPTION ||
+           key_type == WEP104_ENCRYPTION ||
+           vif->type == NL80211_IFTYPE_ADHOC)
+               rtlpriv->sec.use_defaultkey = true;
+
+       /* <2> get key_idx */
+       key_idx = (u8) (key->keyidx);
+       if (key_idx > 3)
+               goto out_unlock;
+       /* <3> if pairwise key enable_hw_sec */
+       group_key = !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE);
+
+       /* wep always be group key, but there are two conditions:
+        * 1) wep only: is just for wep enc, in this condition
+        * rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION
+        * will be true & enable_hw_sec will be set when wep
+        * ke setting.
+        * 2) wep(group) + AES(pairwise): some AP like cisco
+        * may use it, in this condition enable_hw_sec will not
+        * be set when wep key setting */
+       /* we must reset sec_info after lingked before set key,
+        * or some flag will be wrong*/
+       if (vif->type == NL80211_IFTYPE_AP ||
+           vif->type == NL80211_IFTYPE_MESH_POINT) {
+               if (!group_key || key_type == WEP40_ENCRYPTION ||
+                   key_type == WEP104_ENCRYPTION) {
+                       if (group_key)
+                               wep_only = true;
+                       rtlpriv->cfg->ops->enable_hw_sec(hw);
+               }
+       } else {
+               if ((!group_key) || (vif->type == NL80211_IFTYPE_ADHOC) ||
+                   rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION) {
+                       if (rtlpriv->sec.pairwise_enc_algorithm ==
+                           NO_ENCRYPTION &&
+                          (key_type == WEP40_ENCRYPTION ||
+                           key_type == WEP104_ENCRYPTION))
+                               wep_only = true;
+                       rtlpriv->sec.pairwise_enc_algorithm = key_type;
+                       RT_TRACE(COMP_SEC, DBG_DMESG,
+                                ("set enable_hw_sec, key_type:%x(OPEN:0 WEP40:1 TKIP:2 AES:4 WEP104:5)\n",
+                                 key_type));
+                       rtlpriv->cfg->ops->enable_hw_sec(hw);
+               }
+       }
+       /* <4> set key based on cmd */
+       switch (cmd) {
+       case SET_KEY:
+               if (wep_only) {
+                       RT_TRACE(COMP_SEC, DBG_DMESG,
+                                ("set WEP(group/pairwise) key\n"));
+                       /* Pairwise key with an assigned MAC address. */
+                       rtlpriv->sec.pairwise_enc_algorithm = key_type;
+                       rtlpriv->sec.group_enc_algorithm = key_type;
+                       /*set local buf about wep key. */
+                       memcpy(rtlpriv->sec.key_buf[key_idx],
+                              key->key, key->keylen);
+                       rtlpriv->sec.key_len[key_idx] = key->keylen;
+                       eth_zero_addr(mac_addr);
+               } else if (group_key) { /* group key */
+                       RT_TRACE(COMP_SEC, DBG_DMESG,
+                                ("set group key\n"));
+                       /* group key */
+                       rtlpriv->sec.group_enc_algorithm = key_type;
+                       /*set local buf about group key. */
+                       memcpy(rtlpriv->sec.key_buf[key_idx],
+                              key->key, key->keylen);
+                       rtlpriv->sec.key_len[key_idx] = key->keylen;
+                       ether_addr_copy(mac_addr, bcast_addr);
+               } else {        /* pairwise key */
+                       RT_TRACE(COMP_SEC, DBG_DMESG,
+                                ("set pairwise key\n"));
+                       if (!sta) {
+                               RT_ASSERT(false,
+                                         ("pairwise key without mac_addr\n"));
+
+                               err = -EOPNOTSUPP;
+                               goto out_unlock;
+                       }
+                       /* Pairwise key with an assigned MAC address. */
+                       rtlpriv->sec.pairwise_enc_algorithm = key_type;
+                       /*set local buf about pairwise key. */
+                       memcpy(rtlpriv->sec.key_buf[PAIRWISE_KEYIDX],
+                              key->key, key->keylen);
+                       rtlpriv->sec.key_len[PAIRWISE_KEYIDX] = key->keylen;
+                       rtlpriv->sec.pairwise_key =
+                           rtlpriv->sec.key_buf[PAIRWISE_KEYIDX];
+                       ether_addr_copy(mac_addr, sta->addr);
+               }
+               rtlpriv->cfg->ops->set_key(hw, key_idx, mac_addr,
+                                          group_key, key_type, wep_only,
+                                          false);
+               /* <5> tell mac80211 do something: */
+               /*must use sw generate IV, or can not work !!!!. */
+               key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+               key->hw_key_idx = key_idx;
+               if (key_type == TKIP_ENCRYPTION)
+                       key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+               /*use software CCMP encryption for management frames (MFP) */
+               if (key_type == AESCCMP_ENCRYPTION)
+                       key->flags |= IEEE80211_KEY_FLAG_SW_MGMT;
+               break;
+       case DISABLE_KEY:
+               RT_TRACE(COMP_SEC, DBG_DMESG,
+                        ("disable key delete one entry\n"));
+               /*set local buf about wep key. */
+               if (vif->type == NL80211_IFTYPE_AP ||
+                   vif->type == NL80211_IFTYPE_MESH_POINT) {
+                       if (sta)
+                               stg_rtl_cam_del_entry(hw, sta->addr);
+               }
+               memset(rtlpriv->sec.key_buf[key_idx], 0, key->keylen);
+               rtlpriv->sec.key_len[key_idx] = 0;
+               eth_zero_addr(mac_addr);
+               /*
+                *mac80211 will delete entrys one by one,
+                *so don't use stg_rtl_cam_reset_all_entry
+                *or clear all entry here.
+                */
+               stg_rtl_cam_delete_one_entry(hw, mac_addr, key_idx);
+               break;
+       default:
+               RT_TRACE(COMP_ERR, DBG_EMERG,
+                        ("cmd_err:%x!!!!:\n", cmd));
+       }
+out_unlock:
+       mutex_unlock(&rtlpriv->locks.conf_mutex);
+       rtlpriv->sec.being_setkey = false;
+       return err;
+}
+
+static void rtl_op_rfkill_poll(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       bool radio_state;
+       bool blocked;
+       u8 valid = 0;
+
+       if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status))
+               return;
+
+       mutex_lock(&rtlpriv->locks.conf_mutex);
+
+       /*if Radio On return true here */
+       radio_state = rtlpriv->cfg->ops->radio_onoff_checking(hw, &valid);
+
+       if (valid) {
+               if (unlikely(radio_state != rtlpriv->rfkill.rfkill_state)) {
+                       rtlpriv->rfkill.rfkill_state = radio_state;
+
+                       RT_TRACE(COMP_RF, DBG_DMESG,
+                                (KERN_INFO "wireless radio switch turned %s\n",
+                                 radio_state ? "on" : "off"));
+
+                       blocked = (rtlpriv->rfkill.rfkill_state == 1) ? 0 : 1;
+                       wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
+               }
+       }
+
+       mutex_unlock(&rtlpriv->locks.conf_mutex);
+}
+
+/* this function is called by mac80211 to flush tx buffer
+ * before switch channle or power save, or tx buffer packet
+ * maybe send after offchannel or rf sleep, this may cause
+ * dis-association by AP */
+static void rtl_op_flush(struct ieee80211_hw *hw,
+                        u32 queues, bool drop)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       if (rtlpriv->intf_ops->flush)
+               rtlpriv->intf_ops->flush(hw, queues, drop);
+}
+
+const struct ieee80211_ops rtl92e_ops = {
+       .start = rtl_op_start,
+       .stop = rtl_op_stop,
+       .tx = rtl_op_tx,
+       .add_interface = rtl_op_add_interface,
+       .remove_interface = rtl_op_remove_interface,
+       .change_interface = rtl_op_change_interface,
+#ifdef CONFIG_PM
+       .suspend = rtl_op_suspend,
+       .resume = rtl_op_resume,
+#endif
+       .config = rtl_op_config,
+       .configure_filter = rtl_op_configure_filter,
+       .set_key = rtl_op_set_key,
+       .conf_tx = rtl_op_conf_tx,
+       .bss_info_changed = rtl_op_bss_info_changed,
+       .get_tsf = rtl_op_get_tsf,
+       .set_tsf = rtl_op_set_tsf,
+       .reset_tsf = rtl_op_reset_tsf,
+       .sta_notify = rtl_op_sta_notify,
+       .ampdu_action = rtl_op_ampdu_action,
+       .sw_scan_start = rtl_op_sw_scan_start,
+       .sw_scan_complete = rtl_op_sw_scan_complete,
+       .rfkill_poll = rtl_op_rfkill_poll,
+       .sta_add = rtl_op_sta_add,
+       .sta_remove = rtl_op_sta_remove,
+       .flush = rtl_op_flush,
+};
diff --git a/drivers/staging/rtl8192ee/core.h b/drivers/staging/rtl8192ee/core.h
new file mode 100644 (file)
index 0000000..ef75ad5
--- /dev/null
@@ -0,0 +1,39 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * Tmis 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.
+ *
+ * Tme full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL_CORE_H__
+#define __RTL_CORE_H__
+
+#define RTL_SUPPORTED_FILTERS          \
+       (FIF_PROMISC_IN_BSS | \
+       FIF_ALLMULTI | FIF_CONTROL | \
+       FIF_OTHER_BSS | \
+       FIF_FCSFAIL | \
+       FIF_BCN_PRBRESP_PROMISC)
+
+#define RTL_SUPPORTED_CTRL_FILTER      0xFF
+
+extern const struct ieee80211_ops rtl92e_ops;
+#endif
diff --git a/drivers/staging/rtl8192ee/debug.c b/drivers/staging/rtl8192ee/debug.c
new file mode 100644 (file)
index 0000000..feec394
--- /dev/null
@@ -0,0 +1,978 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * Tmis 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "wifi.h"
+#include "cam.h"
+
+#define GET_INODE_DATA(__node)         PDE_DATA(__node)
+
+
+void rtl92e_dbgp_flag_init(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 i;
+
+       rtlpriv->dbg.global_debuglevel = DBG_DMESG;
+
+       rtlpriv->dbg.global_debugcomponents =
+               COMP_ERR |
+               COMP_FW |
+               COMP_INIT |
+               COMP_RECV |
+               COMP_SEND |
+               COMP_MLME |
+               COMP_SCAN |
+               COMP_INTR |
+               COMP_LED |
+               COMP_SEC |
+               COMP_BEACON |
+               COMP_RATE |
+               COMP_RXDESC |
+               COMP_DIG |
+               COMP_TXAGC |
+               COMP_POWER |
+               COMP_POWER_TRACKING |
+               COMP_BB_POWERSAVING |
+               COMP_SWAS |
+               COMP_RF |
+               COMP_TURBO |
+               COMP_RATR |
+               COMP_CMD |
+               COMP_EASY_CONCURRENT |
+               COMP_EFUSE |
+               COMP_QOS | COMP_MAC80211 | COMP_REGD |
+               COMP_CHAN |
+               COMP_BT_COEXIST |
+               COMP_IQK |
+               0;
+
+       for (i = 0; i < DBGP_TYPE_MAX; i++)
+               rtlpriv->dbg.dbgp_type[i] = 0;
+
+       /*Init Debug flag enable condition */
+}
+
+static struct proc_dir_entry *proc_topdir;
+
+static int rtl_proc_get_mac_0(struct seq_file *m, void *v)
+{
+       struct ieee80211_hw *hw = m->private;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       int i, n, page;
+       int max = 0xff;
+       page = 0x000;
+
+       for (n = 0; n <= max; ) {
+               seq_printf(m, "\n%8.8x  ", n + page);
+               for (i = 0; i < 4 && n <= max; i++, n += 4)
+                       seq_printf(m, "%8.8x    ",
+                                  rtl_read_dword(rtlpriv, (page | n)));
+       }
+       seq_puts(m, "\n");
+       return 0;
+}
+
+static int dl_proc_open_mac_0(struct inode *inode, struct file *file)
+{
+       return single_open(file, rtl_proc_get_mac_0, GET_INODE_DATA(inode));
+}
+
+static const struct file_operations file_ops_mac_0 = {
+       .open = dl_proc_open_mac_0,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+static int rtl_proc_get_mac_1(struct seq_file *m, void *v)
+{
+       struct ieee80211_hw *hw = m->private;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       int i, n, page;
+       int max = 0xff;
+       page = 0x100;
+
+       for (n = 0; n <= max; ) {
+               seq_printf(m, "\n%8.8x  ", n + page);
+               for (i = 0; i < 4 && n <= max; i++, n += 4)
+                       seq_printf(m, "%8.8x    ",
+                                  rtl_read_dword(rtlpriv, (page | n)));
+       }
+       seq_puts(m, "\n");
+       return 0;
+}
+
+static int dl_proc_open_mac_1(struct inode *inode, struct file *file)
+{
+       return single_open(file, rtl_proc_get_mac_1, GET_INODE_DATA(inode));
+}
+
+static const struct file_operations file_ops_mac_1 = {
+       .open = dl_proc_open_mac_1,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+static int rtl_proc_get_mac_2(struct seq_file *m, void *v)
+{
+       struct ieee80211_hw *hw = m->private;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       int i, n, page;
+       int max = 0xff;
+       page = 0x200;
+
+       for (n = 0; n <= max; ) {
+               seq_printf(m, "\n%8.8x  ", n + page);
+               for (i = 0; i < 4 && n <= max; i++, n += 4)
+                       seq_printf(m, "%8.8x    ",
+                                  rtl_read_dword(rtlpriv, (page | n)));
+       }
+       seq_puts(m, "\n");
+       return 0;
+}
+
+static int dl_proc_open_mac_2(struct inode *inode, struct file *file)
+{
+       return single_open(file, rtl_proc_get_mac_2, GET_INODE_DATA(inode));
+}
+
+static const struct file_operations file_ops_mac_2 = {
+       .open = dl_proc_open_mac_2,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+static int rtl_proc_get_mac_3(struct seq_file *m, void *v)
+{
+       struct ieee80211_hw *hw = m->private;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       int i, n, page;
+       int max = 0xff;
+       page = 0x300;
+
+       for (n = 0; n <= max; ) {
+               seq_printf(m, "\n%8.8x  ", n + page);
+               for (i = 0; i < 4 && n <= max; i++, n += 4)
+                       seq_printf(m, "%8.8x    ",
+                                  rtl_read_dword(rtlpriv, (page | n)));
+       }
+       seq_puts(m, "\n");
+       return 0;
+}
+
+static int dl_proc_open_mac_3(struct inode *inode, struct file *file)
+{
+       return single_open(file, rtl_proc_get_mac_3, GET_INODE_DATA(inode));
+}
+
+static const struct file_operations file_ops_mac_3 = {
+       .open = dl_proc_open_mac_3,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+static int rtl_proc_get_mac_4(struct seq_file *m, void *v)
+{
+       struct ieee80211_hw *hw = m->private;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       int i, n, page;
+       int max = 0xff;
+       page = 0x400;
+
+       for (n = 0; n <= max; ) {
+               seq_printf(m, "\n%8.8x  ", n + page);
+               for (i = 0; i < 4 && n <= max; i++, n += 4)
+                       seq_printf(m, "%8.8x    ",
+                                  rtl_read_dword(rtlpriv, (page | n)));
+       }
+       seq_puts(m, "\n");
+       return 0;
+}
+
+static int dl_proc_open_mac_4(struct inode *inode, struct file *file)
+{
+       return single_open(file, rtl_proc_get_mac_4, GET_INODE_DATA(inode));
+}
+
+static const struct file_operations file_ops_mac_4 = {
+       .open = dl_proc_open_mac_4,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+static int rtl_proc_get_mac_5(struct seq_file *m, void *v)
+{
+       struct ieee80211_hw *hw = m->private;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       int i, n, page;
+       int max = 0xff;
+       page = 0x500;
+
+       for (n = 0; n <= max; ) {
+               seq_printf(m, "\n%8.8x  ", n + page);
+               for (i = 0; i < 4 && n <= max; i++, n += 4)
+                       seq_printf(m, "%8.8x    ",
+                                  rtl_read_dword(rtlpriv, (page | n)));
+       }
+       seq_puts(m, "\n");
+       return 0;
+}
+
+static int dl_proc_open_mac_5(struct inode *inode, struct file *file)
+{
+       return single_open(file, rtl_proc_get_mac_5, GET_INODE_DATA(inode));
+}
+
+static const struct file_operations file_ops_mac_5 = {
+       .open = dl_proc_open_mac_5,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+static int rtl_proc_get_mac_6(struct seq_file *m, void *v)
+{
+       struct ieee80211_hw *hw = m->private;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       int i, n, page;
+       int max = 0xff;
+       page = 0x600;
+
+       for (n = 0; n <= max; ) {
+               seq_printf(m, "\n%8.8x  ", n + page);
+               for (i = 0; i < 4 && n <= max; i++, n += 4)
+                       seq_printf(m, "%8.8x    ",
+                                  rtl_read_dword(rtlpriv, (page | n)));
+       }
+       seq_puts(m, "\n");
+       return 0;
+}
+
+static int dl_proc_open_mac_6(struct inode *inode, struct file *file)
+{
+       return single_open(file, rtl_proc_get_mac_6, GET_INODE_DATA(inode));
+}
+
+static const struct file_operations file_ops_mac_6 = {
+       .open = dl_proc_open_mac_6,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+static int rtl_proc_get_mac_7(struct seq_file *m, void *v)
+{
+       struct ieee80211_hw *hw = m->private;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       int i, n, page;
+       int max = 0xff;
+       page = 0x700;
+
+       for (n = 0; n <= max; ) {
+               seq_printf(m, "\n%8.8x  ", n + page);
+               for (i = 0; i < 4 && n <= max; i++, n += 4)
+                       seq_printf(m, "%8.8x    ",
+                                  rtl_read_dword(rtlpriv, (page | n)));
+       }
+       seq_puts(m, "\n");
+       return 0;
+}
+
+static int dl_proc_open_mac_7(struct inode *inode, struct file *file)
+{
+       return single_open(file, rtl_proc_get_mac_7, GET_INODE_DATA(inode));
+}
+
+static const struct file_operations file_ops_mac_7 = {
+       .open = dl_proc_open_mac_7,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+static int rtl_proc_get_bb_8(struct seq_file *m, void *v)
+{
+       struct ieee80211_hw *hw = m->private;
+       int i, n, page;
+       int max = 0xff;
+       page = 0x800;
+
+       for (n = 0; n <= max; ) {
+               seq_printf(m, "\n%8.8x  ", n + page);
+               for (i = 0; i < 4 && n <= max; i++, n += 4)
+                       seq_printf(m, "%8.8x    ",
+                                  rtl_get_bbreg(hw, (page | n), 0xffffffff));
+       }
+       seq_puts(m, "\n");
+       return 0;
+}
+
+static int dl_proc_open_bb_8(struct inode *inode, struct file *file)
+{
+       return single_open(file, rtl_proc_get_bb_8, GET_INODE_DATA(inode));
+}
+
+static const struct file_operations file_ops_bb_8 = {
+       .open = dl_proc_open_bb_8,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+static int rtl_proc_get_bb_9(struct seq_file *m, void *v)
+{
+       struct ieee80211_hw *hw = m->private;
+       int i, n, page;
+       int max = 0xff;
+       page = 0x900;
+
+       for (n = 0; n <= max; ) {
+               seq_printf(m, "\n%8.8x  ", n + page);
+               for (i = 0; i < 4 && n <= max; i++, n += 4)
+                       seq_printf(m, "%8.8x    ",
+                                  rtl_get_bbreg(hw, (page | n), 0xffffffff));
+       }
+       seq_puts(m, "\n");
+       return 0;
+}
+
+static int dl_proc_open_bb_9(struct inode *inode, struct file *file)
+{
+       return single_open(file, rtl_proc_get_bb_9, GET_INODE_DATA(inode));
+}
+
+static const struct file_operations file_ops_bb_9 = {
+       .open = dl_proc_open_bb_9,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+static int rtl_proc_get_bb_a(struct seq_file *m, void *v)
+{
+       struct ieee80211_hw *hw = m->private;
+       int i, n, page;
+       int max = 0xff;
+       page = 0xa00;
+
+       for (n = 0; n <= max; ) {
+               seq_printf(m, "\n%8.8x  ", n + page);
+               for (i = 0; i < 4 && n <= max; i++, n += 4)
+                       seq_printf(m, "%8.8x    ",
+                                  rtl_get_bbreg(hw, (page | n), 0xffffffff));
+       }
+       seq_puts(m, "\n");
+       return 0;
+}
+
+static int dl_proc_open_bb_a(struct inode *inode, struct file *file)
+{
+       return single_open(file, rtl_proc_get_bb_a, GET_INODE_DATA(inode));
+}
+
+static const struct file_operations file_ops_bb_a = {
+       .open = dl_proc_open_bb_a,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+static int rtl_proc_get_bb_b(struct seq_file *m, void *v)
+{
+       struct ieee80211_hw *hw = m->private;
+       int i, n, page;
+       int max = 0xff;
+       page = 0xb00;
+
+       for (n = 0; n <= max; ) {
+               seq_printf(m, "\n%8.8x  ", n + page);
+               for (i = 0; i < 4 && n <= max; i++, n += 4)
+                       seq_printf(m, "%8.8x    ",
+                                  rtl_get_bbreg(hw, (page | n), 0xffffffff));
+       }
+       seq_puts(m, "\n");
+       return 0;
+}
+
+static int dl_proc_open_bb_b(struct inode *inode, struct file *file)
+{
+       return single_open(file, rtl_proc_get_bb_b, GET_INODE_DATA(inode));
+}
+
+static const struct file_operations file_ops_bb_b = {
+       .open = dl_proc_open_bb_b,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+static int rtl_proc_get_bb_c(struct seq_file *m, void *v)
+{
+       struct ieee80211_hw *hw = m->private;
+       int i, n, page;
+       int max = 0xff;
+       page = 0xc00;
+
+       for (n = 0; n <= max; ) {
+               seq_printf(m, "\n%8.8x  ", n + page);
+               for (i = 0; i < 4 && n <= max; i++, n += 4)
+                       seq_printf(m, "%8.8x    ",
+                                  rtl_get_bbreg(hw, (page | n), 0xffffffff));
+       }
+       seq_puts(m, "\n");
+       return 0;
+}
+
+static int dl_proc_open_bb_c(struct inode *inode, struct file *file)
+{
+       return single_open(file, rtl_proc_get_bb_c, GET_INODE_DATA(inode));
+}
+
+static const struct file_operations file_ops_bb_c = {
+       .open = dl_proc_open_bb_c,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+static int rtl_proc_get_bb_d(struct seq_file *m, void *v)
+{
+       struct ieee80211_hw *hw = m->private;
+       int i, n, page;
+       int max = 0xff;
+       page = 0xd00;
+
+       for (n = 0; n <= max; ) {
+               seq_printf(m, "\n%8.8x  ", n + page);
+               for (i = 0; i < 4 && n <= max; i++, n += 4)
+                       seq_printf(m, "%8.8x    ",
+                                  rtl_get_bbreg(hw, (page | n), 0xffffffff));
+       }
+       seq_puts(m, "\n");
+       return 0;
+}
+
+static int dl_proc_open_bb_d(struct inode *inode, struct file *file)
+{
+       return single_open(file, rtl_proc_get_bb_d, GET_INODE_DATA(inode));
+}
+
+static const struct file_operations file_ops_bb_d = {
+       .open = dl_proc_open_bb_d,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+static int rtl_proc_get_bb_e(struct seq_file *m, void *v)
+{
+       struct ieee80211_hw *hw = m->private;
+       int i, n, page;
+       int max = 0xff;
+       page = 0xe00;
+
+       for (n = 0; n <= max; ) {
+               seq_printf(m, "\n%8.8x  ", n + page);
+               for (i = 0; i < 4 && n <= max; i++, n += 4)
+                       seq_printf(m, "%8.8x    ",
+                                  rtl_get_bbreg(hw, (page | n), 0xffffffff));
+       }
+       seq_puts(m, "\n");
+       return 0;
+}
+
+static int dl_proc_open_bb_e(struct inode *inode, struct file *file)
+{
+       return single_open(file, rtl_proc_get_bb_e, GET_INODE_DATA(inode));
+}
+
+static const struct file_operations file_ops_bb_e = {
+       .open = dl_proc_open_bb_e,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+static int rtl_proc_get_bb_f(struct seq_file *m, void *v)
+{
+       struct ieee80211_hw *hw = m->private;
+       int i, n, page;
+       int max = 0xff;
+       page = 0xf00;
+
+       for (n = 0; n <= max; ) {
+               seq_printf(m, "\n%8.8x  ", n + page);
+               for (i = 0; i < 4 && n <= max; i++, n += 4)
+                       seq_printf(m, "%8.8x    ",
+                                  rtl_get_bbreg(hw, (page | n), 0xffffffff));
+       }
+       seq_puts(m, "\n");
+       return 0;
+}
+
+static int dl_proc_open_bb_f(struct inode *inode, struct file *file)
+{
+       return single_open(file, rtl_proc_get_bb_f, GET_INODE_DATA(inode));
+}
+
+static const struct file_operations file_ops_bb_f = {
+       .open = dl_proc_open_bb_f,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+static int rtl_proc_get_reg_rf_a(struct seq_file *m, void *v)
+{
+       struct ieee80211_hw *hw = m->private;
+       int i, n;
+       int max = 0x40;
+
+       for (n = 0; n <= max; ) {
+               seq_printf(m, "\n%8.8x  ", n);
+               for (i = 0; i < 4 && n <= max; n += 1, i++)
+                       seq_printf(m, "%8.8x    ",
+                                  rtl_get_rfreg(hw, RF90_PATH_A, n, 0xffffffff));
+       }
+       seq_puts(m, "\n");
+       return 0;
+}
+
+static int dl_proc_open_rf_a(struct inode *inode, struct file *file)
+{
+       return single_open(file, rtl_proc_get_reg_rf_a, GET_INODE_DATA(inode));
+}
+
+static const struct file_operations file_ops_rf_a = {
+       .open = dl_proc_open_rf_a,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+static int rtl_proc_get_reg_rf_b(struct seq_file *m, void *v)
+{
+       struct ieee80211_hw *hw = m->private;
+       int i, n;
+       int max = 0x40;
+
+       for (n = 0; n <= max; ) {
+               seq_printf(m, "\n%8.8x  ", n);
+               for (i = 0; i < 4 && n <= max; n += 1, i++)
+                       seq_printf(m, "%8.8x    ",
+                                  rtl_get_rfreg(hw, RF90_PATH_B, n,
+                                                0xffffffff));
+       }
+       seq_puts(m, "\n");
+       return 0;
+}
+
+static int dl_proc_open_rf_b(struct inode *inode, struct file *file)
+{
+       return single_open(file, rtl_proc_get_reg_rf_b, GET_INODE_DATA(inode));
+}
+
+static const struct file_operations file_ops_rf_b = {
+       .open = dl_proc_open_rf_b,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+static int rtl_proc_get_cam_register_1(struct seq_file *m, void *v)
+{
+       struct ieee80211_hw *hw = m->private;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u32 target_cmd = 0;
+       u32 target_val = 0;
+       u8 entry_i = 0;
+       u32 ulstatus;
+       int i = 100, j = 0;
+
+       /* This dump the current register page */
+       seq_puts(m,
+           "\n#################### SECURITY CAM (0-10) ##################\n ");
+
+       for (j = 0; j < 11; j++) {
+               seq_printf(m, "\nD:  %2x > ", j);
+               for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) {
+                       /* polling bit, and No Write enable, and address  */
+                       target_cmd = entry_i + CAM_CONTENT_COUNT * j;
+                       target_cmd = target_cmd | BIT(31);
+
+                       /* Check polling bit is clear */
+                       while ((i--) >= 0) {
+                               ulstatus = rtl_read_dword(rtlpriv,
+                                               rtlpriv->cfg->maps[RWCAM]);
+                               if (ulstatus & BIT(31))
+                                       continue;
+                               else
+                                       break;
+                       }
+
+                       rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],
+                                       target_cmd);
+                       target_val = rtl_read_dword(rtlpriv,
+                                                   rtlpriv->cfg->maps[RCAMO]);
+                       seq_printf(m, "%8.8x ", target_val);
+               }
+       }
+       seq_puts(m, "\n");
+       return 0;
+}
+
+static int dl_proc_open_cam_1(struct inode *inode, struct file *file)
+{
+       return single_open(file, rtl_proc_get_cam_register_1,
+                          GET_INODE_DATA(inode));
+}
+
+static const struct file_operations file_ops_cam_1 = {
+       .open = dl_proc_open_cam_1,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+static int rtl_proc_get_cam_register_2(struct seq_file *m, void *v)
+{
+       struct ieee80211_hw *hw = m->private;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u32 target_cmd = 0;
+       u32 target_val = 0;
+       u8 entry_i = 0;
+       u32 ulstatus;
+       int i = 100, j = 0;
+
+       /* This dump the current register page */
+       seq_puts(m,
+           "\n################### SECURITY CAM (11-21) ##################\n ");
+
+       for (j = 11; j < 22; j++) {
+               seq_printf(m, "\nD:  %2x > ", j);
+               for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) {
+                       target_cmd = entry_i + CAM_CONTENT_COUNT * j;
+                       target_cmd = target_cmd | BIT(31);
+
+                       while ((i--) >= 0) {
+                               ulstatus = rtl_read_dword(rtlpriv,
+                                               rtlpriv->cfg->maps[RWCAM]);
+                               if (ulstatus & BIT(31))
+                                       continue;
+                               else
+                                       break;
+                       }
+
+                       rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],
+                                       target_cmd);
+                       target_val = rtl_read_dword(rtlpriv,
+                                                   rtlpriv->cfg->maps[RCAMO]);
+                       seq_printf(m, "%8.8x ", target_val);
+               }
+       }
+       seq_puts(m, "\n");
+       return 0;
+}
+
+static int dl_proc_open_cam_2(struct inode *inode, struct file *file)
+{
+       return single_open(file, rtl_proc_get_cam_register_2,
+                          GET_INODE_DATA(inode));
+}
+
+static const struct file_operations file_ops_cam_2 = {
+       .open = dl_proc_open_cam_2,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+static int rtl_proc_get_cam_register_3(struct seq_file *m, void *v)
+{
+       struct ieee80211_hw *hw = m->private;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u32 target_cmd = 0;
+       u32 target_val = 0;
+       u8 entry_i = 0;
+       u32 ulstatus;
+       int i = 100, j = 0;
+
+       /* This dump the current register page */
+       seq_puts(m,
+           "\n################### SECURITY CAM (22-31) ##################\n ");
+
+       for (j = 22; j < TOTAL_CAM_ENTRY; j++) {
+               seq_printf(m, "\nD:  %2x > ", j);
+               for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) {
+                       target_cmd = entry_i+CAM_CONTENT_COUNT*j;
+                       target_cmd = target_cmd | BIT(31);
+
+                       while ((i--) >= 0) {
+                               ulstatus = rtl_read_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM]);
+                               if (ulstatus & BIT(31))
+                                       continue;
+                               else
+                                       break;
+                       }
+
+                       rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],
+                                       target_cmd);
+                       target_val = rtl_read_dword(rtlpriv,
+                                                   rtlpriv->cfg->maps[RCAMO]);
+                       seq_printf(m, "%8.8x ", target_val);
+               }
+       }
+       seq_puts(m, "\n");
+       return 0;
+}
+
+static int dl_proc_open_cam_3(struct inode *inode, struct file *file)
+{
+       return single_open(file, rtl_proc_get_cam_register_3,
+                          GET_INODE_DATA(inode));
+}
+
+static const struct file_operations file_ops_cam_3 = {
+       .open = dl_proc_open_cam_3,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+void rtl_proc_add_one(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       struct proc_dir_entry *entry;
+
+       snprintf(rtlpriv->dbg.proc_name, 18, "%x-%x-%x-%x-%x-%x",
+                rtlefuse->dev_addr[0], rtlefuse->dev_addr[1],
+                rtlefuse->dev_addr[2], rtlefuse->dev_addr[3],
+                rtlefuse->dev_addr[4], rtlefuse->dev_addr[5]);
+
+       rtlpriv->dbg.proc_dir = proc_mkdir(rtlpriv->dbg.proc_name, proc_topdir);
+       if (!rtlpriv->dbg.proc_dir) {
+               RT_TRACE(COMP_INIT, DBG_EMERG,
+                        ("Unable to init /proc/net/%s/%s\n",
+                         rtlpriv->cfg->name,
+                         rtlpriv->dbg.proc_name));
+               return;
+       }
+
+       entry = proc_create_data("mac-0", S_IFREG | S_IRUGO,
+                                rtlpriv->dbg.proc_dir, &file_ops_mac_0, hw);
+       if (!entry)
+               RT_TRACE(COMP_INIT, DBG_EMERG,
+                        ("Unable to initialize /proc/net/%s/%s/mac-0\n",
+                         rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
+
+       entry = proc_create_data("mac-1", S_IFREG | S_IRUGO,
+                                rtlpriv->dbg.proc_dir, &file_ops_mac_1, hw);
+       if (!entry)
+               RT_TRACE(COMP_INIT, COMP_ERR,
+                        ("Unable to initialize /proc/net/%s/%s/mac-1\n",
+                         rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
+
+       entry = proc_create_data("mac-2", S_IFREG | S_IRUGO,
+                                rtlpriv->dbg.proc_dir, &file_ops_mac_2, hw);
+       if (!entry)
+               RT_TRACE(COMP_INIT, COMP_ERR,
+                        ("Unable to initialize /proc/net/%s/%s/mac-2\n",
+                         rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
+
+       entry = proc_create_data("mac-3", S_IFREG | S_IRUGO,
+                                rtlpriv->dbg.proc_dir, &file_ops_mac_3, hw);
+       if (!entry)
+               RT_TRACE(COMP_INIT, COMP_ERR,
+                        ("Unable to initialize /proc/net/%s/%s/mac-3\n",
+                         rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
+
+       entry = proc_create_data("mac-4", S_IFREG | S_IRUGO,
+                                rtlpriv->dbg.proc_dir, &file_ops_mac_4, hw);
+       if (!entry)
+               RT_TRACE(COMP_INIT, COMP_ERR,
+                        ("Unable to initialize /proc/net/%s/%s/mac-4\n",
+                         rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
+
+       entry = proc_create_data("mac-5", S_IFREG | S_IRUGO,
+                                rtlpriv->dbg.proc_dir, &file_ops_mac_5, hw);
+       if (!entry)
+               RT_TRACE(COMP_INIT, COMP_ERR,
+                        ("Unable to initialize /proc/net/%s/%s/mac-5\n",
+                         rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
+
+       entry = proc_create_data("mac-6", S_IFREG | S_IRUGO,
+                                rtlpriv->dbg.proc_dir, &file_ops_mac_6, hw);
+       if (!entry)
+               RT_TRACE(COMP_INIT, COMP_ERR,
+                        ("Unable to initialize /proc/net/%s/%s/mac-6\n",
+                         rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
+
+       entry = proc_create_data("mac-7", S_IFREG | S_IRUGO,
+                                rtlpriv->dbg.proc_dir, &file_ops_mac_7, hw);
+       if (!entry)
+               RT_TRACE(COMP_INIT, COMP_ERR,
+                        ("Unable to initialize /proc/net/%s/%s/mac-7\n",
+                         rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
+
+       entry = proc_create_data("bb-8", S_IFREG | S_IRUGO,
+                                rtlpriv->dbg.proc_dir, &file_ops_bb_8, hw);
+       if (!entry)
+               RT_TRACE(COMP_INIT, COMP_ERR,
+                        ("Unable to initialize /proc/net/%s/%s/bb-8\n",
+                         rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
+
+       entry = proc_create_data("bb-9", S_IFREG | S_IRUGO,
+                                rtlpriv->dbg.proc_dir, &file_ops_bb_9, hw);
+       if (!entry)
+               RT_TRACE(COMP_INIT, COMP_ERR,
+                        ("Unable to initialize /proc/net/%s/%s/bb-9\n",
+                         rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
+
+       entry = proc_create_data("bb-a", S_IFREG | S_IRUGO,
+                                rtlpriv->dbg.proc_dir, &file_ops_bb_a, hw);
+       if (!entry)
+               RT_TRACE(COMP_INIT, COMP_ERR,
+                        ("Unable to initialize /proc/net/%s/%s/bb-a\n",
+                         rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
+
+       entry = proc_create_data("bb-b", S_IFREG | S_IRUGO,
+                                rtlpriv->dbg.proc_dir, &file_ops_bb_b, hw);
+       if (!entry)
+               RT_TRACE(COMP_INIT, COMP_ERR,
+                        ("Unable to initialize /proc/net/%s/%s/bb-b\n",
+                     rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
+
+       entry = proc_create_data("bb-c", S_IFREG | S_IRUGO,
+                                rtlpriv->dbg.proc_dir, &file_ops_bb_c, hw);
+       if (!entry)
+               RT_TRACE(COMP_INIT, COMP_ERR,
+                        ("Unable to initialize /proc/net/%s/%s/bb-c\n",
+                         rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
+
+       entry = proc_create_data("bb-d", S_IFREG | S_IRUGO,
+                                rtlpriv->dbg.proc_dir, &file_ops_bb_d, hw);
+       if (!entry)
+               RT_TRACE(COMP_INIT, COMP_ERR,
+                        ("Unable to initialize /proc/net/%s/%s/bb-d\n",
+                         rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
+
+       entry = proc_create_data("bb-e", S_IFREG | S_IRUGO,
+                                rtlpriv->dbg.proc_dir, &file_ops_bb_e, hw);
+       if (!entry)
+               RT_TRACE(COMP_INIT, COMP_ERR,
+                        ("Unable to initialize /proc/net/%s/%s/bb-e\n",
+                         rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
+
+       entry = proc_create_data("bb-f", S_IFREG | S_IRUGO,
+                                rtlpriv->dbg.proc_dir, &file_ops_bb_f, hw);
+       if (!entry)
+               RT_TRACE(COMP_INIT, COMP_ERR,
+                        ("Unable to initialize /proc/net/%s/%s/bb-f\n",
+                         rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
+
+       entry = proc_create_data("rf-a", S_IFREG | S_IRUGO,
+                                rtlpriv->dbg.proc_dir, &file_ops_rf_a, hw);
+       if (!entry)
+               RT_TRACE(COMP_INIT, COMP_ERR,
+                        ("Unable to initialize /proc/net/%s/%s/rf-a\n",
+                         rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
+
+       entry = proc_create_data("rf-b", S_IFREG | S_IRUGO,
+                                rtlpriv->dbg.proc_dir, &file_ops_rf_b, hw);
+       if (!entry)
+               RT_TRACE(COMP_INIT, COMP_ERR,
+                        ("Unable to initialize /proc/net/%s/%s/rf-b\n",
+                         rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
+
+       entry = proc_create_data("cam-1", S_IFREG | S_IRUGO,
+                                rtlpriv->dbg.proc_dir, &file_ops_cam_1, hw);
+       if (!entry)
+               RT_TRACE(COMP_INIT, COMP_ERR,
+                        ("Unable to initialize /proc/net/%s/%s/cam-1\n",
+                         rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
+
+       entry = proc_create_data("cam-2", S_IFREG | S_IRUGO,
+                                rtlpriv->dbg.proc_dir, &file_ops_cam_2, hw);
+       if (!entry)
+               RT_TRACE(COMP_INIT, COMP_ERR,
+                        ("Unable to initialize /proc/net/%s/%s/cam-2\n",
+                         rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
+
+       entry = proc_create_data("cam-3", S_IFREG | S_IRUGO,
+                                rtlpriv->dbg.proc_dir, &file_ops_cam_3, hw);
+       if (!entry)
+               RT_TRACE(COMP_INIT, COMP_ERR,
+                        ("Unable to initialize /proc/net/%s/%s/cam-3\n",
+                         rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
+}
+
+void rtl_proc_remove_one(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       if (rtlpriv->dbg.proc_dir) {
+               remove_proc_entry("mac-0", rtlpriv->dbg.proc_dir);
+               remove_proc_entry("mac-1", rtlpriv->dbg.proc_dir);
+               remove_proc_entry("mac-2", rtlpriv->dbg.proc_dir);
+               remove_proc_entry("mac-3", rtlpriv->dbg.proc_dir);
+               remove_proc_entry("mac-4", rtlpriv->dbg.proc_dir);
+               remove_proc_entry("mac-5", rtlpriv->dbg.proc_dir);
+               remove_proc_entry("mac-6", rtlpriv->dbg.proc_dir);
+               remove_proc_entry("mac-7", rtlpriv->dbg.proc_dir);
+               remove_proc_entry("bb-8", rtlpriv->dbg.proc_dir);
+               remove_proc_entry("bb-9", rtlpriv->dbg.proc_dir);
+               remove_proc_entry("bb-a", rtlpriv->dbg.proc_dir);
+               remove_proc_entry("bb-b", rtlpriv->dbg.proc_dir);
+               remove_proc_entry("bb-c", rtlpriv->dbg.proc_dir);
+               remove_proc_entry("bb-d", rtlpriv->dbg.proc_dir);
+               remove_proc_entry("bb-e", rtlpriv->dbg.proc_dir);
+               remove_proc_entry("bb-f", rtlpriv->dbg.proc_dir);
+               remove_proc_entry("rf-a", rtlpriv->dbg.proc_dir);
+               remove_proc_entry("rf-b", rtlpriv->dbg.proc_dir);
+               remove_proc_entry("cam-1", rtlpriv->dbg.proc_dir);
+               remove_proc_entry("cam-2", rtlpriv->dbg.proc_dir);
+               remove_proc_entry("cam-3", rtlpriv->dbg.proc_dir);
+
+               remove_proc_entry(rtlpriv->dbg.proc_name, proc_topdir);
+
+               rtlpriv->dbg.proc_dir = NULL;
+       }
+}
+
+void rtl_proc_add_topdir(void)
+{
+       proc_topdir = proc_mkdir("rtlwifi", init_net.proc_net);
+}
+
+void rtl_proc_remove_topdir(void)
+{
+       if (proc_topdir)
+               remove_proc_entry("rtlwifi", init_net.proc_net);
+}
diff --git a/drivers/staging/rtl8192ee/debug.h b/drivers/staging/rtl8192ee/debug.h
new file mode 100644 (file)
index 0000000..093128d
--- /dev/null
@@ -0,0 +1,221 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * Tmis 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.
+ *
+ * Tmis 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.
+ *
+ * Tme full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL_DEBUG_H__
+#define __RTL_DEBUG_H__
+
+/*--------------------------------------------------------------
+                       Debug level
+--------------------------------------------------------------*/
+/*
+ *Fatal bug.
+ *For example, Tx/Rx/IO locked up,
+ *memory access violation,
+ *resource allocation failed,
+ *unexpected HW behavior, HW BUG
+ *and so on.
+ */
+#define DBG_EMERG                      1
+
+/*
+ *Abnormal, rare, or unexpeted cases.
+ *For example, Packet/IO Ctl canceled,
+ *device suprisely unremoved and so on.
+ */
+#define        DBG_WARNING                     2
+
+/*
+ *Normal case driver developer should
+ *open, we can see link status like
+ *assoc/AddBA/DHCP/adapter start and
+ *so on basic and useful infromations.
+ */
+#define DBG_DMESG                      3
+
+/*
+ *Normal case with useful information
+ *about current SW or HW state.
+ *For example, Tx/Rx descriptor to fill,
+ *Tx/Rx descriptor completed status,
+ *SW protocol state change, dynamic
+ *mechanism state change and so on.
+ */
+#define DBG_LOUD                       4
+
+/*
+ *Normal case with detail execution
+ *flow or information.
+ */
+#define        DBG_TRACE                       5
+
+/*--------------------------------------------------------------
+               Define the rt_trace components
+--------------------------------------------------------------*/
+#define COMP_ERR                       BIT(0)
+#define COMP_FW                                BIT(1)
+#define COMP_INIT                      BIT(2)  /*For init/deinit */
+#define COMP_RECV                      BIT(3)  /*For Rx. */
+#define COMP_SEND                      BIT(4)  /*For Tx. */
+#define COMP_MLME                      BIT(5)  /*For MLME. */
+#define COMP_SCAN                      BIT(6)  /*For Scan. */
+#define COMP_INTR                      BIT(7)  /*For interrupt Related. */
+#define COMP_LED                       BIT(8)  /*For LED. */
+#define COMP_SEC                       BIT(9)  /*For sec. */
+#define COMP_BEACON                    BIT(10) /*For beacon. */
+#define COMP_RATE                      BIT(11) /*For rate. */
+#define COMP_RXDESC                    BIT(12) /*For rx desc. */
+#define COMP_DIG                       BIT(13) /*For DIG */
+#define COMP_TXAGC                     BIT(14) /*For Tx power */
+#define COMP_HIPWR                     BIT(15) /*For High Power Mechanism */
+#define COMP_POWER                     BIT(16) /*For lps/ips/aspm. */
+#define COMP_POWER_TRACKING            BIT(17) /*For TX POWER TRACKING */
+#define COMP_BB_POWERSAVING            BIT(18)
+#define COMP_SWAS                      BIT(19) /*For SW Antenna Switch */
+#define COMP_RF                                BIT(20) /*For RF. */
+#define COMP_TURBO                     BIT(21) /*For EDCA TURBO. */
+#define COMP_RATR                      BIT(22)
+#define COMP_CMD                       BIT(23)
+#define COMP_EFUSE                     BIT(24)
+#define COMP_QOS                       BIT(25)
+#define COMP_MAC80211                  BIT(26)
+#define COMP_REGD                      BIT(27)
+#define COMP_CHAN                      BIT(28)
+#define COMP_EASY_CONCURRENT           BIT(29)
+#define COMP_BT_COEXIST                        BIT(30)
+#define COMP_IQK                       BIT(31)
+
+/*--------------------------------------------------------------
+               Define the rt_print components
+--------------------------------------------------------------*/
+/* Define EEPROM and EFUSE  check module bit*/
+#define EEPROM_W                       BIT(0)
+#define EFUSE_PG                       BIT(1)
+#define EFUSE_READ_ALL                 BIT(2)
+
+/* Define init check for module bit*/
+#define        INIT_EEPROM                     BIT(0)
+#define        INIT_TxPower                    BIT(1)
+#define        INIT_IQK                        BIT(2)
+#define        INIT_RF                         BIT(3)
+
+/* Define PHY-BB/RF/MAC check module bit */
+#define        PHY_BBR                         BIT(0)
+#define        PHY_BBW                         BIT(1)
+#define        PHY_RFR                         BIT(2)
+#define        PHY_RFW                         BIT(3)
+#define        PHY_MACR                        BIT(4)
+#define        PHY_MACW                        BIT(5)
+#define        PHY_ALLR                        BIT(6)
+#define        PHY_ALLW                        BIT(7)
+#define        PHY_TXPWR                       BIT(8)
+#define        PHY_PWRDIFF                     BIT(9)
+
+/* Define Dynamic Mechanism check module bit --> FDM */
+#define WA_IOT                         BIT(0)
+#define DM_PWDB                                BIT(1)
+#define DM_MONITOR                     BIT(2)
+#define DM_DIG                         BIT(3)
+#define DM_EDCA_TURBO                  BIT(4)
+
+enum dbgp_flag_e {
+       FQOS = 0,
+       FTX = 1,
+       FRX = 2,
+       FSEC = 3,
+       FMGNT = 4,
+       FMLME = 5,
+       FRESOURCE = 6,
+       FBEACON = 7,
+       FISR = 8,
+       FPHY = 9,
+       FMP = 10,
+       FEEPROM = 11,
+       FPWR = 12,
+       FDM = 13,
+       FDBGCtrl = 14,
+       FC2H = 15,
+       FBT = 16,
+       FINIT = 17,
+       FIOCTL = 18,
+       DBGP_TYPE_MAX
+};
+
+#define RT_ASSERT(_exp , fmt)                          \
+       do { \
+               if (!(_exp))    {                       \
+                       pr_debug("%s:%s(): ", KBUILD_MODNAME, \
+                       __func__);      \
+                       pr_cont fmt;                    \
+               } \
+       } while (0)
+
+#define RT_TRACE(comp, level, fmt)\
+       do { \
+               if (unlikely(((comp) & rtlpriv->dbg.global_debugcomponents) && \
+                       ((level) <= rtlpriv->dbg.global_debuglevel))) {\
+                       pr_debug("%s-%d:%s():<%lx> ", \
+                       KBUILD_MODNAME, \
+                       rtlpriv->rtlhal.interfaceindex, __func__, \
+                       in_interrupt());        \
+                       pr_cont fmt;                    \
+               } \
+       } while (0)
+
+#define RTPRINT(rtlpriv, dbgtype, dbgflag, fmt, ...)                   \
+do {                                                                   \
+       if (unlikely(rtlpriv->dbg.dbgp_type[dbgtype] & dbgflag)) {      \
+               pr_debug(KBUILD_MODNAME ": " fmt,               \
+                      ##__VA_ARGS__);                                  \
+       }                                                               \
+} while (0)
+
+#define RT_PRINT_DATA(rtlpriv, _comp, _level, _titlestring, _hexdata, \
+               _hexdatalen) \
+       do {\
+               if (unlikely(((_comp) & rtlpriv->dbg.global_debugcomponents) &&\
+                       (_level <= rtlpriv->dbg.global_debuglevel)))    { \
+                       int __i;                                        \
+                       u8 *ptr = (u8 *)_hexdata;                       \
+                       pr_debug("%s: ", KBUILD_MODNAME);       \
+                       pr_cont("In process \"%s\" (pid %i):", \
+                                       current->comm,  \
+                                       current->pid); \
+                       pr_cont(_titlestring);          \
+                       for (__i = 0; __i < (int)_hexdatalen; __i++) {  \
+                               pr_cont("%02X%s", ptr[__i], (((__i + 1) % 4) \
+                                                       == 0) ? "  " : " ");\
+                               if (((__i + 1) % 16) == 0)      \
+                                       pr_cont("\n");  \
+                       }                               \
+                       pr_cont("\n");                  \
+               } \
+       } while (0)
+
+void rtl92e_dbgp_flag_init(struct ieee80211_hw *hw);
+void rtl_proc_add_one(struct ieee80211_hw *hw);
+void rtl_proc_remove_one(struct ieee80211_hw *hw);
+void rtl_proc_add_topdir(void);
+void rtl_proc_remove_topdir(void);
+#endif
diff --git a/drivers/staging/rtl8192ee/efuse.c b/drivers/staging/rtl8192ee/efuse.c
new file mode 100644 (file)
index 0000000..3fae183
--- /dev/null
@@ -0,0 +1,1233 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * Tmis 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+#include "wifi.h"
+#include "efuse.h"
+
+static const u8 MAX_PGPKT_SIZE = 9;
+static const u8 PGPKT_DATA_SIZE = 8;
+static const int EFUSE_MAX_SIZE = 512;
+
+static const struct efuse_map RTL8712_SDIO_EFUSE_TABLE[] = {
+       {0, 0, 0, 2},
+       {0, 1, 0, 2},
+       {0, 2, 0, 2},
+       {1, 0, 0, 1},
+       {1, 0, 1, 1},
+       {1, 1, 0, 1},
+       {1, 1, 1, 3},
+       {1, 3, 0, 17},
+       {3, 3, 1, 48},
+       {10, 0, 0, 6},
+       {10, 3, 0, 1},
+       {10, 3, 1, 1},
+       {11, 0, 0, 28}
+};
+
+static void efuse92e_shadow_read_1byte(struct ieee80211_hw *hw, u16 offset,
+                                      u8 *value);
+static void efuse92e_shadow_read_2byte(struct ieee80211_hw *hw, u16 offset,
+                                      u16 *value);
+static void efuse92e_shadow_read_4byte(struct ieee80211_hw *hw, u16 offset,
+                                      u32 *value);
+static void efuse92e_shadow_write_1byte(struct ieee80211_hw *hw, u16 offset,
+                                       u8 value);
+static void efuse92e_shadow_write_2byte(struct ieee80211_hw *hw, u16 offset,
+                                       u16 value);
+static void efuse92e_shadow_write_4byte(struct ieee80211_hw *hw, u16 offset,
+                                       u32 value);
+static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr,
+                               u8 data);
+static void efuse_read_all_map(struct ieee80211_hw *hw, u8 *efuse);
+static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset,
+                               u8 *data);
+static int efuse_pg_packet_write(struct ieee80211_hw *hw, u8 offset,
+                                u8 word_en, u8 *data);
+static void efuse_word_enable_data_read(u8 word_en, u8 *sourdata,
+                                       u8 *targetdata);
+static u8 efuse_word_enable_data_write(struct ieee80211_hw *hw,
+                                      u16 efuse_addr, u8 word_en, u8 *data);
+static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite,
+                              u8 pwrstate);
+static u16 efuse_get_current_size(struct ieee80211_hw *hw);
+static u8 efuse_calculate_word_cnts(u8 word_en);
+
+void efuse92e_initialize(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 bytetemp;
+       u8 temp;
+
+       bytetemp = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[SYS_FUNC_EN] + 1);
+       temp = bytetemp | 0x20;
+       rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[SYS_FUNC_EN] + 1, temp);
+
+       bytetemp = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[SYS_ISO_CTRL] + 1);
+       temp = bytetemp & 0xFE;
+       rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[SYS_ISO_CTRL] + 1, temp);
+
+       bytetemp = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3);
+       temp = bytetemp | 0x80;
+       rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3, temp);
+
+       rtl_write_byte(rtlpriv, 0x2F8, 0x3);
+
+       rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3, 0x72);
+}
+
+u8 stg_efuse_read_1byte(struct ieee80211_hw *hw, u16 address)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 data;
+       u8 bytetemp;
+       u8 temp;
+       u32 k = 0;
+       const u32 efuse_real_content_len =
+               rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE];
+
+       if (address < efuse_real_content_len) {
+               temp = address & 0xFF;
+               rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1,
+                              temp);
+               bytetemp = rtl_read_byte(rtlpriv,
+                                        rtlpriv->cfg->maps[EFUSE_CTRL] + 2);
+               temp = ((address >> 8) & 0x03) | (bytetemp & 0xFC);
+               rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2,
+                              temp);
+
+               bytetemp = rtl_read_byte(rtlpriv,
+                                        rtlpriv->cfg->maps[EFUSE_CTRL] + 3);
+               temp = bytetemp & 0x7F;
+               rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3,
+                              temp);
+
+               bytetemp = rtl_read_byte(rtlpriv,
+                                        rtlpriv->cfg->maps[EFUSE_CTRL] + 3);
+               while (!(bytetemp & 0x80)) {
+                       bytetemp = rtl_read_byte(rtlpriv,
+                                                rtlpriv->cfg->
+                                                maps[EFUSE_CTRL] + 3);
+                       k++;
+                       if (k == 1000) {
+                               k = 0;
+                               break;
+                       }
+               }
+               data = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]);
+               return data;
+       } else {
+               return 0xFF;
+       }
+}
+EXPORT_SYMBOL(stg_efuse_read_1byte);
+
+void efuse92e_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 bytetemp;
+       u8 temp;
+       u32 k = 0;
+       const u32 efuse_real_content_len =
+               rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE];
+
+       RT_TRACE(COMP_EFUSE, DBG_LOUD,
+                ("Addr=%x Data =%x\n", address, value));
+
+       if (address < efuse_real_content_len) {
+               rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL], value);
+
+               temp = address & 0xFF;
+               rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1,
+                              temp);
+               bytetemp = rtl_read_byte(rtlpriv,
+                                        rtlpriv->cfg->maps[EFUSE_CTRL] + 2);
+
+               temp = ((address >> 8) & 0x03) | (bytetemp & 0xFC);
+               rtl_write_byte(rtlpriv,
+                              rtlpriv->cfg->maps[EFUSE_CTRL] + 2, temp);
+
+               bytetemp = rtl_read_byte(rtlpriv,
+                                        rtlpriv->cfg->maps[EFUSE_CTRL] + 3);
+               temp = bytetemp | 0x80;
+               rtl_write_byte(rtlpriv,
+                              rtlpriv->cfg->maps[EFUSE_CTRL] + 3, temp);
+
+               bytetemp = rtl_read_byte(rtlpriv,
+                                        rtlpriv->cfg->maps[EFUSE_CTRL] + 3);
+
+               while (bytetemp & 0x80) {
+                       bytetemp = rtl_read_byte(rtlpriv,
+                                                rtlpriv->cfg->
+                                                maps[EFUSE_CTRL] + 3);
+                       k++;
+                       if (k == 100) {
+                               k = 0;
+                               break;
+                       }
+               }
+       }
+}
+
+void read92e_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u32 value32;
+       u8 readbyte;
+       u16 retry;
+
+       rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1,
+                      (_offset & 0xff));
+       readbyte = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2);
+       rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2,
+                      ((_offset >> 8) & 0x03) | (readbyte & 0xfc));
+
+       readbyte = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3);
+       rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3,
+                      (readbyte & 0x7f));
+
+       retry = 0;
+       value32 = rtl_read_dword(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]);
+       while (!(((value32 >> 24) & 0xff) & 0x80) && (retry < 10000)) {
+               value32 = rtl_read_dword(rtlpriv,
+                                        rtlpriv->cfg->maps[EFUSE_CTRL]);
+               retry++;
+       }
+
+       udelay(50);
+       value32 = rtl_read_dword(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]);
+
+       *pbuf = (u8) (value32 & 0xff);
+}
+
+void read92e_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte,
+                  u8 *pbuf)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       u8 *efuse_tbl;
+       u8 rtemp8[1];
+       u16 efuse_addr = 0;
+       u8 offset, wren;
+       u8 u1temp = 0;
+       u16 i;
+       u16 j;
+       const u16 efuse_max_section =
+               rtlpriv->cfg->maps[EFUSE_MAX_SECTION_MAP];
+       const u32 efuse_real_content_len =
+               rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE];
+       u16 **efuse_word;
+       u16 efuse_utilized = 0;
+       u8 efuse_usage;
+
+       if ((_offset + _size_byte) > rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]) {
+               RT_TRACE(COMP_EFUSE, DBG_LOUD,
+                        ("read92e_efuse(): Invalid offset(%#x) with read bytes(%#x)!!\n",
+                        _offset, _size_byte));
+               return;
+       }
+
+       /* allocate memory for efuse_tbl and efuse_word */
+       efuse_tbl = kmalloc(rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE] *
+                           sizeof(u8), GFP_ATOMIC);
+       if (!efuse_tbl)
+               return;
+       efuse_word = kzalloc(EFUSE_MAX_WORD_UNIT * sizeof(u16 *), GFP_ATOMIC);
+       if (!efuse_word)
+               goto out;
+       for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) {
+               efuse_word[i] = kmalloc(efuse_max_section * sizeof(u16),
+                                       GFP_ATOMIC);
+               if (!efuse_word[i])
+                       goto done;
+       }
+
+       for (i = 0; i < efuse_max_section; i++)
+               for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++)
+                       efuse_word[j][j] = 0xFFFF;
+
+       read92e_efuse_byte(hw, efuse_addr, rtemp8);
+       if (*rtemp8 != 0xFF) {
+               efuse_utilized++;
+               RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL,
+                       "Addr=%d\n", efuse_addr);
+               efuse_addr++;
+       }
+
+       while ((*rtemp8 != 0xFF) && (efuse_addr < efuse_real_content_len)) {
+               /*  Check PG header for section num.  */
+               if ((*rtemp8 & 0x1F) == 0x0F) {/* extended header */
+                       u1temp = ((*rtemp8 & 0xE0) >> 5);
+                       read92e_efuse_byte(hw, efuse_addr, rtemp8);
+
+                       if ((*rtemp8 & 0x0F) == 0x0F) {
+                               efuse_addr++;
+                               read92e_efuse_byte(hw, efuse_addr, rtemp8);
+
+                               if (*rtemp8 != 0xFF &&
+                                   (efuse_addr < efuse_real_content_len)) {
+                                       efuse_addr++;
+                               }
+                               continue;
+                       } else {
+                               offset = ((*rtemp8 & 0xF0) >> 1) | u1temp;
+                               wren = (*rtemp8 & 0x0F);
+                               efuse_addr++;
+                       }
+               } else {
+                       offset = ((*rtemp8 >> 4) & 0x0f);
+                       wren = (*rtemp8 & 0x0f);
+               }
+
+               if (offset < efuse_max_section) {
+                       RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL,
+                               "offset-%d Worden=%x\n", offset, wren);
+
+                       for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) {
+                               if (!(wren & 0x01)) {
+                                       RTPRINT(rtlpriv, FEEPROM,
+                                               EFUSE_READ_ALL, "Addr=%d\n",
+                                               efuse_addr);
+
+                                       read92e_efuse_byte(hw, efuse_addr,
+                                                          rtemp8);
+                                       efuse_addr++;
+                                       efuse_utilized++;
+                                       efuse_word[i][offset] = (*rtemp8 &
+                                                                0xff);
+
+                                       if (efuse_addr >=
+                                           efuse_real_content_len)
+                                               break;
+
+                                       RTPRINT(rtlpriv, FEEPROM,
+                                               EFUSE_READ_ALL, "Addr=%d\n",
+                                               efuse_addr);
+
+                                       read92e_efuse_byte(hw, efuse_addr,
+                                                          rtemp8);
+                                       efuse_addr++;
+                                       efuse_utilized++;
+                                       efuse_word[i][offset] |=
+                                           (((u16) *rtemp8 << 8) & 0xff00);
+
+                                       if (efuse_addr >=
+                                           efuse_real_content_len)
+                                               break;
+                               }
+
+                               wren >>= 1;
+                       }
+               }
+
+               RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL,
+                       "Addr=%d\n", efuse_addr);
+               read92e_efuse_byte(hw, efuse_addr, rtemp8);
+               if (*rtemp8 != 0xFF && (efuse_addr < efuse_real_content_len)) {
+                       efuse_utilized++;
+                       efuse_addr++;
+               }
+       }
+
+       for (i = 0; i < efuse_max_section; i++) {
+               for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) {
+                       efuse_tbl[(i * 8) + (j * 2)] =
+                           (efuse_word[j][i] & 0xff);
+                       efuse_tbl[(i * 8) + ((j * 2) + 1)] =
+                           ((efuse_word[j][i] >> 8) & 0xff);
+               }
+       }
+
+       for (i = 0; i < _size_byte; i++)
+               pbuf[i] = efuse_tbl[_offset + i];
+
+       rtlefuse->efuse_usedbytes = efuse_utilized;
+       efuse_usage = (u8) ((efuse_utilized * 100) / efuse_real_content_len);
+       rtlefuse->efuse_usedpercentage = efuse_usage;
+       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_EFUSE_BYTES,
+                                     (u8 *)&efuse_utilized);
+       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_EFUSE_USAGE,
+                                     (u8 *)&efuse_usage);
+done:
+       for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++)
+               kfree(efuse_word[i]);
+       kfree(efuse_word);
+out:
+       kfree(efuse_tbl);
+}
+
+bool efuse92e_shadow_update_chk(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       u8 section_idx, i, Base;
+       u16 words_need = 0, hdr_num = 0, totalbytes, efuse_used;
+       bool bwordchanged, bresult = true;
+
+       for (section_idx = 0; section_idx < 16; section_idx++) {
+               Base = section_idx * 8;
+               bwordchanged = false;
+
+               for (i = 0; i < 8; i = i + 2) {
+                       if ((rtlefuse->efuse_map[EFUSE_INIT_MAP][Base + i] !=
+                            rtlefuse->efuse_map[EFUSE_MODIFY_MAP][Base + i]) ||
+                           (rtlefuse->efuse_map[EFUSE_INIT_MAP][Base + i + 1] !=
+                            rtlefuse->efuse_map[EFUSE_MODIFY_MAP][Base + i +
+                                                                  1])) {
+                               words_need++;
+                               bwordchanged = true;
+                       }
+               }
+
+               if (bwordchanged)
+                       hdr_num++;
+       }
+
+       totalbytes = hdr_num + words_need * 2;
+       efuse_used = rtlefuse->efuse_usedbytes;
+
+       if ((totalbytes + efuse_used) >=
+           (EFUSE_MAX_SIZE - rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN]))
+               bresult = false;
+
+       RT_TRACE(COMP_EFUSE, DBG_LOUD,
+                ("efuse92e_shadow_update_chk(): totalbytes(%#x), hdr_num(%#x), words_need(%#x), efuse_used(%d)\n",
+                 totalbytes, hdr_num, words_need, efuse_used));
+
+       return bresult;
+}
+
+void efuse92e_shadow_read(struct ieee80211_hw *hw, u8 type,
+                      u16 offset, u32 *value)
+{
+       if (type == 1)
+               efuse92e_shadow_read_1byte(hw, offset, (u8 *)value);
+       else if (type == 2)
+               efuse92e_shadow_read_2byte(hw, offset, (u16 *)value);
+       else if (type == 4)
+               efuse92e_shadow_read_4byte(hw, offset, (u32 *)value);
+}
+EXPORT_SYMBOL(efuse92e_shadow_read);
+
+void efuse92e_shadow_write(struct ieee80211_hw *hw, u8 type, u16 offset,
+                          u32 value)
+{
+       if (type == 1)
+               efuse92e_shadow_write_1byte(hw, offset, (u8)value);
+       else if (type == 2)
+               efuse92e_shadow_write_2byte(hw, offset, (u16)value);
+       else if (type == 4)
+               efuse92e_shadow_write_4byte(hw, offset, (u32)value);
+}
+
+bool efuse92e_shadow_update(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       u16 i, offset, base;
+       u8 word_en = 0x0F;
+       u8 first_pg = false;
+
+       RT_TRACE(COMP_EFUSE, DBG_LOUD, ("\n"));
+
+       if (!efuse92e_shadow_update_chk(hw)) {
+               efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]);
+               memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0],
+                      &rtlefuse->efuse_map[EFUSE_INIT_MAP][0],
+                      rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]);
+
+               RT_TRACE(COMP_EFUSE, DBG_LOUD,
+                        ("efuse out of capacity!!\n"));
+               return false;
+       }
+       efuse_power_switch(hw, true, true);
+
+       for (offset = 0; offset < 16; offset++) {
+               word_en = 0x0F;
+               base = offset * 8;
+
+               for (i = 0; i < 8; i++) {
+                       if (first_pg) {
+                               word_en &= ~(BIT(i / 2));
+
+                               rtlefuse->efuse_map[EFUSE_INIT_MAP][base + i] =
+                                   rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base + i];
+                       } else {
+                               if (rtlefuse->efuse_map[EFUSE_INIT_MAP][base + i] !=
+                                   rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base + i]) {
+                                       word_en &= ~(BIT(i / 2));
+
+                                       rtlefuse->efuse_map[EFUSE_INIT_MAP][base + i] =
+                                           rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base + i];
+                               }
+                       }
+               }
+
+               if (word_en != 0x0F) {
+                       u8 tmpdata[8];
+                       memcpy(tmpdata,
+                              (&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base]),
+                              8);
+                       RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_LOUD,
+                                     "U-efuse\n", tmpdata, 8);
+
+                       if (!efuse_pg_packet_write(hw, (u8) offset, word_en,
+                                                  tmpdata)) {
+                               RT_TRACE(COMP_ERR, DBG_WARNING,
+                                        ("PG section(%#x) fail!!\n", offset));
+                               break;
+                       }
+               }
+       }
+
+       efuse_power_switch(hw, true, false);
+       efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]);
+
+       memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0],
+              &rtlefuse->efuse_map[EFUSE_INIT_MAP][0],
+              rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]);
+
+       RT_TRACE(COMP_EFUSE, DBG_LOUD, ("\n"));
+       return true;
+}
+
+void stg_rtl_efuse92e_shadow_map_update(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+
+       if (rtlefuse->autoload_failflag) {
+               memset(&rtlefuse->efuse_map[EFUSE_INIT_MAP][0],
+                      0xFF, rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]);
+       } else {
+               efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]);
+       }
+
+       memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0],
+              &rtlefuse->efuse_map[EFUSE_INIT_MAP][0],
+              rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]);
+}
+EXPORT_SYMBOL(stg_rtl_efuse92e_shadow_map_update);
+
+void efuse92e_force_write_vendor_Id(struct ieee80211_hw *hw)
+{
+       u8 tmpdata[8] = { 0xFF, 0xFF, 0xEC, 0x10, 0xFF, 0xFF, 0xFF, 0xFF };
+
+       efuse_power_switch(hw, true, true);
+       efuse_pg_packet_write(hw, 1, 0xD, tmpdata);
+       efuse_power_switch(hw, true, false);
+}
+
+void efuse92e_re_pg_section(struct ieee80211_hw *hw, u8 section_idx)
+{
+}
+
+static void efuse92e_shadow_read_1byte(struct ieee80211_hw *hw,
+                                      u16 offset, u8 *value)
+{
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       *value = rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset];
+}
+
+static void efuse92e_shadow_read_2byte(struct ieee80211_hw *hw,
+                                      u16 offset, u16 *value)
+{
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+
+       *value = rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset];
+       *value |= rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 1] << 8;
+}
+
+static void efuse92e_shadow_read_4byte(struct ieee80211_hw *hw,
+                                      u16 offset, u32 *value)
+{
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+
+       *value = rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset];
+       *value |= rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 1] << 8;
+       *value |= rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 2] << 16;
+       *value |= rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 3] << 24;
+}
+
+static void efuse92e_shadow_write_1byte(struct ieee80211_hw *hw,
+                                       u16 offset, u8 value)
+{
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+
+       rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset] = value;
+}
+
+static void efuse92e_shadow_write_2byte(struct ieee80211_hw *hw,
+                                       u16 offset, u16 value)
+{
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+
+       rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset] = value & 0x00FF;
+       rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 1] = value >> 8;
+}
+
+static void efuse92e_shadow_write_4byte(struct ieee80211_hw *hw,
+                                       u16 offset, u32 value)
+{
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+
+       rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset] =
+           (u8) (value & 0x000000FF);
+       rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 1] =
+           (u8) ((value >> 8) & 0x0000FF);
+       rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 2] =
+           (u8) ((value >> 16) & 0x00FF);
+       rtlefuse->efuse_map[EFUSE_MODIFY_MAP][offset + 3] =
+           (u8) ((value >> 24) & 0xFF);
+}
+
+int stg_efuse_one_byte_read(struct ieee80211_hw *hw, u16 addr, u8 *data)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 tmpidx = 0;
+       int bresult;
+
+       rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1,
+                      (u8) (addr & 0xff));
+       rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2,
+                      ((u8) ((addr >> 8) & 0x03)) |
+                      (rtl_read_byte(rtlpriv,
+                                     rtlpriv->cfg->maps[EFUSE_CTRL] + 2) &
+                       0xFC));
+
+       rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3, 0x72);
+
+       while (!(0x80 & rtl_read_byte(rtlpriv,
+                                     rtlpriv->cfg->maps[EFUSE_CTRL] + 3)) &&
+              (tmpidx < 100)) {
+               tmpidx++;
+       }
+
+       if (tmpidx < 100) {
+               *data = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]);
+               bresult = true;
+       } else {
+               *data = 0xff;
+               bresult = false;
+       }
+       return bresult;
+}
+EXPORT_SYMBOL(stg_efuse_one_byte_read);
+
+static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr, u8 data)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 tmpidx = 0;
+       bool bresult;
+
+       RT_TRACE(COMP_EFUSE, DBG_LOUD,
+                ("Addr = %x Data=%x\n", addr, data));
+
+       rtl_write_byte(rtlpriv,
+                      rtlpriv->cfg->maps[EFUSE_CTRL] + 1, (u8) (addr & 0xff));
+       rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2,
+                      (rtl_read_byte(rtlpriv,
+                        rtlpriv->cfg->maps[EFUSE_CTRL] +
+                        2) & 0xFC) | (u8) ((addr >> 8) & 0x03));
+
+       rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL], data);
+       rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 3, 0xF2);
+
+       while ((0x80 & rtl_read_byte(rtlpriv,
+                                    rtlpriv->cfg->maps[EFUSE_CTRL] + 3)) &&
+              (tmpidx < 100)) {
+               tmpidx++;
+       }
+
+       if (tmpidx < 100)
+               bresult = true;
+       else
+               bresult = false;
+
+       return bresult;
+}
+
+static void efuse_read_all_map(struct ieee80211_hw *hw, u8 *efuse)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       efuse_power_switch(hw, false, true);
+       read92e_efuse(hw, 0, rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE], efuse);
+       efuse_power_switch(hw, false, false);
+}
+
+static void efuse_read_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
+                               u8 efuse_data, u8 offset, u8 *tmpdata,
+                               u8 *readstate)
+{
+       bool bdataempty = true;
+       u8 hoffset;
+       u8 tmpidx;
+       u8 hworden;
+       u8 word_cnts;
+
+       hoffset = (efuse_data >> 4) & 0x0F;
+       hworden = efuse_data & 0x0F;
+       word_cnts = efuse_calculate_word_cnts(hworden);
+
+       if (hoffset == offset) {
+               for (tmpidx = 0; tmpidx < word_cnts * 2; tmpidx++) {
+                       if (stg_efuse_one_byte_read(hw, *efuse_addr + 1 + tmpidx,
+                                                   &efuse_data)) {
+                               tmpdata[tmpidx] = efuse_data;
+                               if (efuse_data != 0xff)
+                                       bdataempty = false;
+                       }
+               }
+
+               if (!bdataempty) {
+                       *readstate = PG_STATE_DATA;
+               } else {
+                       *efuse_addr = *efuse_addr + (word_cnts * 2) + 1;
+                       *readstate = PG_STATE_HEADER;
+               }
+
+       } else {
+               *efuse_addr = *efuse_addr + (word_cnts * 2) + 1;
+               *readstate = PG_STATE_HEADER;
+       }
+}
+
+static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data)
+{
+       u8 readstate = PG_STATE_HEADER;
+
+       bool bcontinual = true;
+
+       u8 efuse_data, word_cnts = 0;
+       u16 efuse_addr = 0;
+       u8 hworden = 0;
+       u8 tmpdata[8];
+
+       if (data == NULL)
+               return false;
+       if (offset > 15)
+               return false;
+
+       memset(data, 0xff, PGPKT_DATA_SIZE * sizeof(u8));
+       memset(tmpdata, 0xff, PGPKT_DATA_SIZE * sizeof(u8));
+
+       while (bcontinual && (efuse_addr < EFUSE_MAX_SIZE)) {
+               if (readstate & PG_STATE_HEADER) {
+                       if (stg_efuse_one_byte_read(hw, efuse_addr, &efuse_data) &&
+                           (efuse_data != 0xFF))
+                               efuse_read_data_case1(hw, &efuse_addr,
+                                                     efuse_data, offset,
+                                                     tmpdata, &readstate);
+                       else
+                               bcontinual = false;
+               } else if (readstate & PG_STATE_DATA) {
+                       efuse_word_enable_data_read(hworden, tmpdata, data);
+                       efuse_addr = efuse_addr + (word_cnts * 2) + 1;
+                       readstate = PG_STATE_HEADER;
+               }
+       }
+
+       if ((data[0] == 0xff) && (data[1] == 0xff) &&
+           (data[2] == 0xff) && (data[3] == 0xff) &&
+           (data[4] == 0xff) && (data[5] == 0xff) &&
+           (data[6] == 0xff) && (data[7] == 0xff))
+               return false;
+       else
+               return true;
+}
+
+static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
+                                  u8 efuse_data, u8 offset,
+                                  int *bcontinual, u8 *write_state,
+                                  struct pgpkt_struct *target_pkt,
+                                  int *repeat_times, int *bresult, u8 word_en)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct pgpkt_struct tmp_pkt;
+       int bdataempty = true;
+       u8 originaldata[8 * sizeof(u8)];
+       u8 badworden = 0x0F;
+       u8 match_word_en, tmp_word_en;
+       u8 tmpindex;
+       u8 tmp_header = efuse_data;
+       u8 tmp_word_cnts;
+
+       tmp_pkt.offset = (tmp_header >> 4) & 0x0F;
+       tmp_pkt.word_en = tmp_header & 0x0F;
+       tmp_word_cnts = efuse_calculate_word_cnts(tmp_pkt.word_en);
+
+       if (tmp_pkt.offset != target_pkt->offset) {
+               *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1;
+               *write_state = PG_STATE_HEADER;
+       } else {
+               for (tmpindex = 0; tmpindex < (tmp_word_cnts * 2); tmpindex++) {
+                       if (stg_efuse_one_byte_read(hw,
+                                               (*efuse_addr + 1 + tmpindex),
+                                               &efuse_data) &&
+                           (efuse_data != 0xFF))
+                               bdataempty = false;
+               }
+
+               if (!bdataempty) {
+                       *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1;
+                       *write_state = PG_STATE_HEADER;
+               } else {
+                       match_word_en = 0x0F;
+                       if (!((target_pkt->word_en & BIT(0)) |
+                           (tmp_pkt.word_en & BIT(0))))
+                               match_word_en &= (~BIT(0));
+
+                       if (!((target_pkt->word_en & BIT(1)) |
+                           (tmp_pkt.word_en & BIT(1))))
+                               match_word_en &= (~BIT(1));
+
+                       if (!((target_pkt->word_en & BIT(2)) |
+                           (tmp_pkt.word_en & BIT(2))))
+                               match_word_en &= (~BIT(2));
+
+                       if (!((target_pkt->word_en & BIT(3)) |
+                           (tmp_pkt.word_en & BIT(3))))
+                               match_word_en &= (~BIT(3));
+
+                       if ((match_word_en & 0x0F) != 0x0F) {
+                               badworden = efuse_word_enable_data_write(hw,
+                                                       *efuse_addr + 1,
+                                                       tmp_pkt.word_en,
+                                                       target_pkt->data);
+
+                               if (0x0F != (badworden & 0x0F)) {
+                                       u8 reorg_offset = offset;
+                                       u8 reorg_worden = badworden;
+                                       efuse_pg_packet_write(hw, reorg_offset,
+                                                             reorg_worden,
+                                                             originaldata);
+                               }
+
+                               tmp_word_en = 0x0F;
+                               if ((target_pkt->word_en & BIT(0)) ^
+                                   (match_word_en & BIT(0)))
+                                       tmp_word_en &= (~BIT(0));
+
+                               if ((target_pkt->word_en & BIT(1)) ^
+                                   (match_word_en & BIT(1)))
+                                       tmp_word_en &= (~BIT(1));
+
+                               if ((target_pkt->word_en & BIT(2)) ^
+                                   (match_word_en & BIT(2)))
+                                       tmp_word_en &= (~BIT(2));
+
+                               if ((target_pkt->word_en & BIT(3)) ^
+                                   (match_word_en & BIT(3)))
+                                       tmp_word_en &= (~BIT(3));
+
+                               if ((tmp_word_en & 0x0F) != 0x0F) {
+                                       *efuse_addr = efuse_get_current_size(hw);
+                                       target_pkt->offset = offset;
+                                       target_pkt->word_en = tmp_word_en;
+                               } else {
+                                       *bcontinual = false;
+                               }
+                               *write_state = PG_STATE_HEADER;
+                               *repeat_times += 1;
+                               if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) {
+                                       *bcontinual = false;
+                                       *bresult = false;
+                               }
+                       } else {
+                               *efuse_addr += (2 * tmp_word_cnts) + 1;
+                               target_pkt->offset = offset;
+                               target_pkt->word_en = word_en;
+                               *write_state = PG_STATE_HEADER;
+                       }
+               }
+       }
+       RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, "efuse PG_STATE_HEADER-1\n");
+}
+
+static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr,
+                                  int *bcontinual, u8 *write_state,
+                                  struct pgpkt_struct target_pkt,
+                                  int *repeat_times, int *bresult)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct pgpkt_struct tmp_pkt;
+       u8 pg_header;
+       u8 tmp_header;
+       u8 originaldata[8 * sizeof(u8)];
+       u8 tmp_word_cnts;
+       u8 badworden = 0x0F;
+
+       pg_header = ((target_pkt.offset << 4) & 0xf0) | target_pkt.word_en;
+       efuse_one_byte_write(hw, *efuse_addr, pg_header);
+       stg_efuse_one_byte_read(hw, *efuse_addr, &tmp_header);
+
+       if (tmp_header == pg_header) {
+               *write_state = PG_STATE_DATA;
+       } else if (tmp_header == 0xFF) {
+               *write_state = PG_STATE_HEADER;
+               *repeat_times += 1;
+               if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) {
+                       *bcontinual = false;
+                       *bresult = false;
+               }
+       } else {
+               tmp_pkt.offset = (tmp_header >> 4) & 0x0F;
+               tmp_pkt.word_en = tmp_header & 0x0F;
+
+               tmp_word_cnts = efuse_calculate_word_cnts(tmp_pkt.word_en);
+
+               memset(originaldata, 0xff,  8 * sizeof(u8));
+
+               if (efuse_pg_packet_read(hw, tmp_pkt.offset, originaldata)) {
+                       badworden = efuse_word_enable_data_write(hw,
+                                                                *efuse_addr + 1,
+                                                                tmp_pkt.word_en,
+                                                                originaldata);
+
+                       if (0x0F != (badworden & 0x0F)) {
+                               u8 reorg_offset = tmp_pkt.offset;
+                               u8 reorg_worden = badworden;
+                               efuse_pg_packet_write(hw, reorg_offset,
+                                                     reorg_worden,
+                                                     originaldata);
+                               *efuse_addr = efuse_get_current_size(hw);
+                       } else {
+                               *efuse_addr = *efuse_addr +
+                                             (tmp_word_cnts * 2) + 1;
+                       }
+               } else {
+                       *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1;
+               }
+
+               *write_state = PG_STATE_HEADER;
+               *repeat_times += 1;
+               if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) {
+                       *bcontinual = false;
+                       *bresult = false;
+               }
+
+               RTPRINT(rtlpriv, FEEPROM, EFUSE_PG,
+                       "efuse PG_STATE_HEADER-2\n");
+       }
+}
+
+static int efuse_pg_packet_write(struct ieee80211_hw *hw,
+                                u8 offset, u8 word_en, u8 *data)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct pgpkt_struct target_pkt;
+       u8 write_state = PG_STATE_HEADER;
+       int bcontinual = true, bdataempty = true, bresult = true;
+       u16 efuse_addr = 0;
+       u8 efuse_data;
+       u8 target_word_cnts = 0;
+       u8 badworden = 0x0F;
+       static int repeat_times;
+
+       if (efuse_get_current_size(hw) >= (EFUSE_MAX_SIZE -
+               rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN])) {
+               RTPRINT(rtlpriv, FEEPROM, EFUSE_PG,
+                       "efuse_pg_packet_write error\n");
+               return false;
+       }
+
+       target_pkt.offset = offset;
+       target_pkt.word_en = word_en;
+
+       memset(target_pkt.data, 0xFF,  8 * sizeof(u8));
+
+       efuse_word_enable_data_read(word_en, data, target_pkt.data);
+       target_word_cnts = efuse_calculate_word_cnts(target_pkt.word_en);
+
+       RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, "efuse Power ON\n");
+
+       while (bcontinual && (efuse_addr < (EFUSE_MAX_SIZE -
+              rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN]))) {
+               if (write_state == PG_STATE_HEADER) {
+                       bdataempty = true;
+                       badworden = 0x0F;
+                       RTPRINT(rtlpriv, FEEPROM, EFUSE_PG,
+                               "efuse PG_STATE_HEADER\n");
+
+                       if (stg_efuse_one_byte_read(hw, efuse_addr, &efuse_data) &&
+                           (efuse_data != 0xFF))
+                               efuse_write_data_case1(hw, &efuse_addr,
+                                                      efuse_data, offset,
+                                                      &bcontinual,
+                                                      &write_state,
+                                                      &target_pkt,
+                                                      &repeat_times, &bresult,
+                                                      word_en);
+                       else
+                               efuse_write_data_case2(hw, &efuse_addr,
+                                                      &bcontinual,
+                                                      &write_state,
+                                                      target_pkt,
+                                                      &repeat_times,
+                                                      &bresult);
+
+               } else if (write_state == PG_STATE_DATA) {
+                       RTPRINT(rtlpriv, FEEPROM, EFUSE_PG,
+                               "efuse PG_STATE_DATA\n");
+                       badworden = 0x0f;
+                       badworden =
+                           efuse_word_enable_data_write(hw, efuse_addr + 1,
+                                                        target_pkt.word_en,
+                                                        target_pkt.data);
+
+                       if ((badworden & 0x0F) == 0x0F) {
+                               bcontinual = false;
+                       } else {
+                               efuse_addr =
+                                   efuse_addr + (2 * target_word_cnts) + 1;
+
+                               target_pkt.offset = offset;
+                               target_pkt.word_en = badworden;
+                               target_word_cnts =
+                                   efuse_calculate_word_cnts(target_pkt.
+                                                             word_en);
+                               write_state = PG_STATE_HEADER;
+                               repeat_times++;
+                               if (repeat_times > EFUSE_REPEAT_THRESHOLD_) {
+                                       bcontinual = false;
+                                       bresult = false;
+                               }
+                               RTPRINT(rtlpriv, FEEPROM, EFUSE_PG,
+                                       "efuse PG_STATE_HEADER-3\n");
+                       }
+               }
+       }
+
+       if (efuse_addr >= (EFUSE_MAX_SIZE -
+               rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN])) {
+               RT_TRACE(COMP_EFUSE, DBG_LOUD,
+                        ("efuse_addr(%#x) Out of size!!\n", efuse_addr));
+       }
+
+       return true;
+}
+
+static void efuse_word_enable_data_read(u8 word_en, u8 *sourdata,
+                                       u8 *targetdata)
+{
+       if (!(word_en & BIT(0))) {
+               targetdata[0] = sourdata[0];
+               targetdata[1] = sourdata[1];
+       }
+
+       if (!(word_en & BIT(1))) {
+               targetdata[2] = sourdata[2];
+               targetdata[3] = sourdata[3];
+       }
+
+       if (!(word_en & BIT(2))) {
+               targetdata[4] = sourdata[4];
+               targetdata[5] = sourdata[5];
+       }
+
+       if (!(word_en & BIT(3))) {
+               targetdata[6] = sourdata[6];
+               targetdata[7] = sourdata[7];
+       }
+}
+
+static u8 efuse_word_enable_data_write(struct ieee80211_hw *hw,
+                                      u16 efuse_addr, u8 word_en, u8 *data)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u16 tmpaddr;
+       u16 start_addr = efuse_addr;
+       u8 badworden = 0x0F;
+       u8 tmpdata[8];
+
+       memset(tmpdata, 0xff, PGPKT_DATA_SIZE);
+       RT_TRACE(COMP_EFUSE, DBG_LOUD,
+                ("word_en = %x efuse_addr=%x\n", word_en, efuse_addr));
+
+       if (!(word_en & BIT(0))) {
+               tmpaddr = start_addr;
+               efuse_one_byte_write(hw, start_addr++, data[0]);
+               efuse_one_byte_write(hw, start_addr++, data[1]);
+
+               stg_efuse_one_byte_read(hw, tmpaddr, &tmpdata[0]);
+               stg_efuse_one_byte_read(hw, tmpaddr + 1, &tmpdata[1]);
+               if ((data[0] != tmpdata[0]) || (data[1] != tmpdata[1]))
+                       badworden &= (~BIT(0));
+       }
+
+       if (!(word_en & BIT(1))) {
+               tmpaddr = start_addr;
+               efuse_one_byte_write(hw, start_addr++, data[2]);
+               efuse_one_byte_write(hw, start_addr++, data[3]);
+
+               stg_efuse_one_byte_read(hw, tmpaddr, &tmpdata[2]);
+               stg_efuse_one_byte_read(hw, tmpaddr + 1, &tmpdata[3]);
+               if ((data[2] != tmpdata[2]) || (data[3] != tmpdata[3]))
+                       badworden &= (~BIT(1));
+       }
+
+       if (!(word_en & BIT(2))) {
+               tmpaddr = start_addr;
+               efuse_one_byte_write(hw, start_addr++, data[4]);
+               efuse_one_byte_write(hw, start_addr++, data[5]);
+
+               stg_efuse_one_byte_read(hw, tmpaddr, &tmpdata[4]);
+               stg_efuse_one_byte_read(hw, tmpaddr + 1, &tmpdata[5]);
+               if ((data[4] != tmpdata[4]) || (data[5] != tmpdata[5]))
+                       badworden &= (~BIT(2));
+       }
+
+       if (!(word_en & BIT(3))) {
+               tmpaddr = start_addr;
+               efuse_one_byte_write(hw, start_addr++, data[6]);
+               efuse_one_byte_write(hw, start_addr++, data[7]);
+
+               stg_efuse_one_byte_read(hw, tmpaddr, &tmpdata[6]);
+               stg_efuse_one_byte_read(hw, tmpaddr + 1, &tmpdata[7]);
+               if ((data[6] != tmpdata[6]) || (data[7] != tmpdata[7]))
+                       badworden &= (~BIT(3));
+       }
+
+       return badworden;
+}
+
+static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, u8 pwrstate)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       u8 tempval;
+       u16 tmpv16;
+
+       if (pwrstate && (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE)) {
+               if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192CE &&
+                   rtlhal->hw_type != HARDWARE_TYPE_RTL8192DE) {
+                       rtl_write_byte(rtlpriv,
+                                      rtlpriv->cfg->maps[EFUSE_ACCESS], 0x69);
+               } else {
+                       tmpv16 = rtl_read_word(rtlpriv,
+                                              rtlpriv->cfg->maps[SYS_ISO_CTRL]);
+                       if (!(tmpv16 & rtlpriv->cfg->maps[EFUSE_PWC_EV12V])) {
+                               tmpv16 |= rtlpriv->cfg->maps[EFUSE_PWC_EV12V];
+                               rtl_write_word(rtlpriv,
+                                              rtlpriv->cfg->maps[SYS_ISO_CTRL],
+                                              tmpv16);
+                       }
+               }
+               tmpv16 = rtl_read_word(rtlpriv,
+                                      rtlpriv->cfg->maps[SYS_FUNC_EN]);
+               if (!(tmpv16 & rtlpriv->cfg->maps[EFUSE_FEN_ELDR])) {
+                       tmpv16 |= rtlpriv->cfg->maps[EFUSE_FEN_ELDR];
+                       rtl_write_word(rtlpriv,
+                                      rtlpriv->cfg->maps[SYS_FUNC_EN], tmpv16);
+               }
+
+               tmpv16 = rtl_read_word(rtlpriv, rtlpriv->cfg->maps[SYS_CLK]);
+               if ((!(tmpv16 & rtlpriv->cfg->maps[EFUSE_LOADER_CLK_EN])) ||
+                   (!(tmpv16 & rtlpriv->cfg->maps[EFUSE_ANA8M]))) {
+                       tmpv16 |= (rtlpriv->cfg->maps[EFUSE_LOADER_CLK_EN] |
+                                  rtlpriv->cfg->maps[EFUSE_ANA8M]);
+                       rtl_write_word(rtlpriv,
+                                      rtlpriv->cfg->maps[SYS_CLK], tmpv16);
+               }
+       }
+
+       if (pwrstate) {
+               if (bwrite) {
+                       tempval = rtl_read_byte(rtlpriv,
+                                               rtlpriv->cfg->maps[EFUSE_TEST] +
+                                               3);
+
+                       if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) {
+                               tempval &= ~(BIT(3) | BIT(4) | BIT(5) | BIT(6));
+                               tempval |= (VOLTAGE_V25 << 3);
+                       } else if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE) {
+                               tempval &= 0x0F;
+                               tempval |= (VOLTAGE_V25 << 4);
+                       }
+
+                       rtl_write_byte(rtlpriv,
+                                      rtlpriv->cfg->maps[EFUSE_TEST] + 3,
+                                      (tempval | 0x80));
+               }
+
+               if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) {
+                       rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CLK],
+                                      0x03);
+               }
+       } else {
+               if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192CE &&
+                   rtlhal->hw_type != HARDWARE_TYPE_RTL8192DE)
+                       rtl_write_byte(rtlpriv,
+                                      rtlpriv->cfg->maps[EFUSE_ACCESS], 0);
+               if (bwrite) {
+                       tempval = rtl_read_byte(rtlpriv,
+                                               rtlpriv->cfg->maps[EFUSE_TEST] +
+                                               3);
+                       rtl_write_byte(rtlpriv,
+                                      rtlpriv->cfg->maps[EFUSE_TEST] + 3,
+                                      (tempval & 0x7F));
+               }
+
+               if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) {
+                       rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CLK],
+                                      0x02);
+               }
+       }
+}
+
+static u16 efuse_get_current_size(struct ieee80211_hw *hw)
+{
+       int bcontinual = true;
+       u16 efuse_addr = 0;
+       u8 hoffset, hworden;
+       u8 efuse_data, word_cnts;
+
+       while (bcontinual &&
+              stg_efuse_one_byte_read(hw, efuse_addr, &efuse_data) &&
+              (efuse_addr < EFUSE_MAX_SIZE)) {
+               if (efuse_data != 0xFF) {
+                       hoffset = (efuse_data >> 4) & 0x0F;
+                       hworden = efuse_data & 0x0F;
+                       word_cnts = efuse_calculate_word_cnts(hworden);
+                       efuse_addr = efuse_addr + (word_cnts * 2) + 1;
+               } else {
+                       bcontinual = false;
+               }
+       }
+
+       return efuse_addr;
+}
+
+static u8 efuse_calculate_word_cnts(u8 word_en)
+{
+       u8 word_cnts = 0;
+       if (!(word_en & BIT(0)))
+               word_cnts++;
+       if (!(word_en & BIT(1)))
+               word_cnts++;
+       if (!(word_en & BIT(2)))
+               word_cnts++;
+       if (!(word_en & BIT(3)))
+               word_cnts++;
+       return word_cnts;
+}
diff --git a/drivers/staging/rtl8192ee/efuse.h b/drivers/staging/rtl8192ee/efuse.h
new file mode 100644 (file)
index 0000000..cc3e111
--- /dev/null
@@ -0,0 +1,127 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL_EFUSE_H_
+#define __RTL_EFUSE_H_
+
+#define EFUSE_IC_ID_OFFSET             506
+
+/*
+#define EFUSE_REAL_CONTENT_LEN 512
+#define EFUSE_MAP_LEN                  128
+#define EFUSE_MAX_SECTION              16
+#define EFUSE_MAX_WORD_UNIT            4
+#define EFUSE_IC_ID_OFFSET             506
+*/
+
+#define EFUSE_MAX_WORD_UNIT            4
+
+#define EFUSE_INIT_MAP                 0
+#define EFUSE_MODIFY_MAP               1
+
+#define PG_STATE_HEADER                        0x01
+#define PG_STATE_WORD_0                        0x02
+#define PG_STATE_WORD_1                        0x04
+#define PG_STATE_WORD_2                        0x08
+#define PG_STATE_WORD_3                        0x10
+#define PG_STATE_DATA                  0x20
+
+#define PG_SWBYTE_H                    0x01
+#define PG_SWBYTE_L                    0x02
+
+#define _POWERON_DELAY_
+#define _PRE_EXECUTE_READ_CMD_
+
+#define EFUSE_REPEAT_THRESHOLD_                3
+#define EFUSE_ERROE_HANDLE             1
+
+struct efuse_map {
+       u8 offset;
+       u8 word_start;
+       u8 byte_start;
+       u8 byte_cnts;
+};
+
+struct pgpkt_struct {
+       u8 offset;
+       u8 word_en;
+       u8 data[8];
+};
+
+enum efuse_data_item {
+       EFUSE_CHIP_ID = 0,
+       EFUSE_LDO_SETTING,
+       EFUSE_CLK_SETTING,
+       EFUSE_SDIO_SETTING,
+       EFUSE_CCCR,
+       EFUSE_SDIO_MODE,
+       EFUSE_OCR,
+       EFUSE_F0CIS,
+       EFUSE_F1CIS,
+       EFUSE_MAC_ADDR,
+       EFUSE_EEPROM_VER,
+       EFUSE_CHAN_PLAN,
+       EFUSE_TXPW_TAB
+};
+
+enum {
+       VOLTAGE_V25 = 0x03,
+       LDOE25_SHIFT = 28,
+};
+
+struct efuse_priv {
+       u8 id[2];
+       u8 ldo_setting[2];
+       u8 clk_setting[2];
+       u8 cccr;
+       u8 sdio_mode;
+       u8 ocr[3];
+       u8 cis0[17];
+       u8 cis1[48];
+       u8 mac_addr[6];
+       u8 eeprom_verno;
+       u8 channel_plan;
+       u8 tx_power_b[14];
+       u8 tx_power_g[14];
+};
+
+void read92e_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf);
+void efuse92e_initialize(struct ieee80211_hw *hw);
+u8 stg_efuse_read_1byte(struct ieee80211_hw *hw, u16 address);
+int stg_efuse_one_byte_read(struct ieee80211_hw *hw, u16 addr, u8 *data);
+void efuse92e_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value);
+void read92e_efuse(struct ieee80211_hw *hw, u16 _offset,
+                  u16 _size_byte, u8 *pbuf);
+void efuse92e_shadow_read(struct ieee80211_hw *hw, u8 type,
+                         u16 offset, u32 *value);
+void efuse92e_shadow_write(struct ieee80211_hw *hw, u8 type,
+                          u16 offset, u32 value);
+bool efuse92e_shadow_update(struct ieee80211_hw *hw);
+bool efuse92e_shadow_update_chk(struct ieee80211_hw *hw);
+void stg_rtl_efuse92e_shadow_map_update(struct ieee80211_hw *hw);
+void efuse92e_force_write_vendor_Id(struct ieee80211_hw *hw);
+void efuse92e_re_pg_section(struct ieee80211_hw *hw, u8 section_idx);
+
+#endif
diff --git a/drivers/staging/rtl8192ee/pci.c b/drivers/staging/rtl8192ee/pci.c
new file mode 100644 (file)
index 0000000..3fe9b7b
--- /dev/null
@@ -0,0 +1,2397 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "core.h"
+#include "wifi.h"
+#include "pci.h"
+#include "base.h"
+#include "ps.h"
+#include "efuse.h"
+
+static const u16 pcibridge_vendors[PCI_BRIDGE_VENDOR_MAX] = {
+       INTEL_VENDOR_ID,
+       ATI_VENDOR_ID,
+       AMD_VENDOR_ID,
+       SIS_VENDOR_ID
+};
+
+static const u8 ac_to_hwq[] = {
+       VO_QUEUE,
+       VI_QUEUE,
+       BE_QUEUE,
+       BK_QUEUE
+};
+
+static u8 _rtl_mac_to_hwqueue(struct ieee80211_hw *hw,
+                             struct sk_buff *skb)
+{
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       __le16 fc = rtl_get_fc(skb);
+       u8 queue_index = skb_get_queue_mapping(skb);
+
+       if (unlikely(ieee80211_is_beacon(fc)))
+               return BEACON_QUEUE;
+       if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc))
+               return MGNT_QUEUE;
+       if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE)
+               if (ieee80211_is_nullfunc(fc))
+                       return HIGH_QUEUE;
+
+       return ac_to_hwq[queue_index];
+}
+
+/* Update PCI dependent default settings*/
+static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor;
+       u8 init_aspm;
+
+       ppsc->reg_rfps_level = 0;
+       ppsc->b_support_aspm = 0;
+
+       /*Update PCI ASPM setting */
+       ppsc->const_amdpci_aspm = rtlpci->const_amdpci_aspm;
+       switch (rtlpci->const_pci_aspm) {
+       case 0:
+               /*No ASPM */
+               break;
+
+       case 1:
+               /*ASPM dynamically enabled/disable. */
+               ppsc->reg_rfps_level |= RT_RF_LPS_LEVEL_ASPM;
+               break;
+
+       case 2:
+               /*ASPM with Clock Req dynamically enabled/disable. */
+               ppsc->reg_rfps_level |= (RT_RF_LPS_LEVEL_ASPM |
+                                        RT_RF_OFF_LEVL_CLK_REQ);
+               break;
+
+       case 3:
+               /*
+                * Always enable ASPM and Clock Req
+                * from initialization to halt.
+                * */
+               ppsc->reg_rfps_level &= ~(RT_RF_LPS_LEVEL_ASPM);
+               ppsc->reg_rfps_level |= (RT_RF_PS_LEVEL_ALWAYS_ASPM |
+                                        RT_RF_OFF_LEVL_CLK_REQ);
+               break;
+
+       case 4:
+               /*
+                * Always enable ASPM without Clock Req
+                * from initialization to halt.
+                * */
+               ppsc->reg_rfps_level &= ~(RT_RF_LPS_LEVEL_ASPM |
+                                         RT_RF_OFF_LEVL_CLK_REQ);
+               ppsc->reg_rfps_level |= RT_RF_PS_LEVEL_ALWAYS_ASPM;
+               break;
+       }
+
+       ppsc->reg_rfps_level |= RT_RF_OFF_LEVL_HALT_NIC;
+
+       /*Update Radio OFF setting */
+       switch (rtlpci->const_hwsw_rfoff_d3) {
+       case 1:
+               if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM)
+                       ppsc->reg_rfps_level |= RT_RF_OFF_LEVL_ASPM;
+               break;
+
+       case 2:
+               if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM)
+                       ppsc->reg_rfps_level |= RT_RF_OFF_LEVL_ASPM;
+               ppsc->reg_rfps_level |= RT_RF_OFF_LEVL_HALT_NIC;
+               break;
+
+       case 3:
+               ppsc->reg_rfps_level |= RT_RF_OFF_LEVL_PCI_D3;
+               break;
+       }
+
+       /*Set HW definition to determine if it supports ASPM. */
+       switch (rtlpci->const_support_pciaspm) {
+       case 0:{
+                       /*Not support ASPM. */
+                       bool b_support_aspm = false;
+                       ppsc->b_support_aspm = b_support_aspm;
+                       break;
+               }
+       case 1:{
+                       /*Support ASPM. */
+                       bool b_support_aspm = true;
+                       bool b_support_backdoor = true;
+                       ppsc->b_support_aspm = b_support_aspm;
+
+                       /*if (priv->oem_id == RT_CID_TOSHIBA &&
+                          !priv->ndis_adapter.amd_l1_patch)
+                          b_support_backdoor = false; */
+
+                       ppsc->b_support_backdoor = b_support_backdoor;
+
+                       break;
+               }
+       case 2:
+               /*ASPM value set by chipset. */
+               if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL) {
+                       bool b_support_aspm = true;
+                       ppsc->b_support_aspm = b_support_aspm;
+               }
+               break;
+       default:
+               RT_TRACE(COMP_ERR, DBG_EMERG,
+                        ("switch case not process\n"));
+               break;
+       }
+
+       /* toshiba aspm issue, toshiba will set aspm selfly
+        * so we should not set aspm in driver */
+       pci_read_config_byte(rtlpci->pdev, 0x80, &init_aspm);
+       if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8192SE &&
+           init_aspm == 0x43)
+               ppsc->b_support_aspm = false;
+}
+
+static bool _rtl_pci_platform_switch_device_pci_aspm(struct ieee80211_hw *hw,
+                                                    u8 value)
+{
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       bool bresult = false;
+
+       if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE)
+               value |= 0x40;
+
+       pci_write_config_byte(rtlpci->pdev, 0x80, value);
+
+       return bresult;
+}
+
+/*When we set 0x01 to enable clk request. Set 0x0 to disable clk req.*/
+static bool _rtl_pci_switch_clk_req(struct ieee80211_hw *hw, u8 value)
+{
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       bool bresult = false;
+
+       pci_write_config_byte(rtlpci->pdev, 0x81, value);
+       bresult = true;
+
+       if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE)
+               udelay(100);
+
+       return bresult;
+}
+
+/*Disable RTL8192SE ASPM & Disable Pci Bridge ASPM*/
+static void rtl_pci_disable_aspm(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor;
+       u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport;
+       u8 num4bytes = pcipriv->ndis_adapter.num4bytes;
+       /*Retrieve original configuration settings. */
+       u8 linkctrl_reg = pcipriv->ndis_adapter.linkctrl_reg;
+       u16 pcibridge_linkctrlreg = pcipriv->ndis_adapter.
+                               pcibridge_linkctrlreg;
+       u16 aspmlevel = 0;
+
+       if (!ppsc->b_support_aspm)
+               return;
+
+       if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) {
+               RT_TRACE(COMP_POWER, DBG_TRACE,
+                        ("PCI(Bridge) UNKNOWN.\n"));
+
+               return;
+       }
+
+       if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_CLK_REQ) {
+               RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_CLK_REQ);
+               _rtl_pci_switch_clk_req(hw, 0x0);
+       }
+
+       if (1) {
+               /*for promising device will in L0 state after an I/O. */
+               u8 tmp_u1b;
+               pci_read_config_byte(rtlpci->pdev, 0x80, &tmp_u1b);
+       }
+
+       /*Set corresponding value. */
+       aspmlevel |= BIT(0) | BIT(1);
+       linkctrl_reg &= ~aspmlevel;
+       pcibridge_linkctrlreg &= ~(BIT(0) | BIT(1));
+
+       _rtl_pci_platform_switch_device_pci_aspm(hw, linkctrl_reg);
+       udelay(50);
+
+       /*4 Disable Pci Bridge ASPM */
+       rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS,
+                                    pcicfg_addrport + (num4bytes << 2));
+       rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, pcibridge_linkctrlreg);
+
+       udelay(50);
+}
+
+/*
+ *Enable RTL8192SE ASPM & Enable Pci Bridge ASPM for
+ *power saving We should follow the sequence to enable
+ *RTL8192SE first then enable Pci Bridge ASPM
+ *or the system will show bluescreen.
+ */
+static void rtl_pci_enable_aspm(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor;
+       u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport;
+       u8 num4bytes = pcipriv->ndis_adapter.num4bytes;
+       u16 aspmlevel;
+       u8 u_pcibridge_aspmsetting;
+       u8 u_device_aspmsetting;
+
+       if (!ppsc->b_support_aspm)
+               return;
+
+       if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) {
+               RT_TRACE(COMP_POWER, DBG_TRACE,
+                        ("PCI(Bridge) UNKNOWN.\n"));
+               return;
+       }
+
+       /*4 Enable Pci Bridge ASPM */
+       rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS,
+                                    pcicfg_addrport + (num4bytes << 2));
+
+       u_pcibridge_aspmsetting =
+           pcipriv->ndis_adapter.pcibridge_linkctrlreg |
+           rtlpci->const_hostpci_aspm_setting;
+
+       if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL)
+               u_pcibridge_aspmsetting &= ~BIT(0);
+
+       rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, u_pcibridge_aspmsetting);
+
+       RT_TRACE(COMP_INIT, DBG_LOUD,
+                ("PlatformEnableASPM(): Write reg[%x] = %x\n",
+                 (pcipriv->ndis_adapter.pcibridge_pciehdr_offset + 0x10),
+                 u_pcibridge_aspmsetting));
+
+       udelay(50);
+
+       /*Get ASPM level (with/without Clock Req) */
+       aspmlevel = rtlpci->const_devicepci_aspm_setting;
+       u_device_aspmsetting = pcipriv->ndis_adapter.linkctrl_reg;
+
+       /*_rtl_pci_platform_switch_device_pci_aspm(dev,*/
+       /*(priv->ndis_adapter.linkctrl_reg | ASPMLevel)); */
+
+       u_device_aspmsetting |= aspmlevel;
+
+       _rtl_pci_platform_switch_device_pci_aspm(hw, u_device_aspmsetting);
+
+       if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_CLK_REQ) {
+               _rtl_pci_switch_clk_req(hw, (ppsc->reg_rfps_level &
+                                            RT_RF_OFF_LEVL_CLK_REQ) ? 1 : 0);
+               RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_CLK_REQ);
+       }
+       udelay(100);
+}
+
+static bool rtl_pci_get_amd_l1_patch(struct ieee80211_hw *hw)
+{
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+       u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport;
+
+       bool status = false;
+       u8 offset_e0;
+       unsigned offset_e4;
+
+       rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS, pcicfg_addrport + 0xE0);
+       rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, 0xA0);
+
+       rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS, pcicfg_addrport + 0xE0);
+       rtl_pci_raw_read_port_uchar(PCI_CONF_DATA, &offset_e0);
+
+       if (offset_e0 == 0xA0) {
+               rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS,
+                                            pcicfg_addrport + 0xE4);
+               rtl_pci_raw_read_port_ulong(PCI_CONF_DATA, &offset_e4);
+               if (offset_e4 & BIT(23))
+                       status = true;
+       }
+
+       return status;
+}
+
+static bool rtl_pci_check_buddy_priv(struct ieee80211_hw *hw,
+                                    struct rtl_priv **buddy_priv)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+       bool find_buddy_priv = false;
+       struct rtl_priv *tpriv = NULL;
+       struct rtl_pci_priv *tpcipriv = NULL;
+
+       if (!list_empty(&rtlpriv->glb_var->glb_priv_list)) {
+               list_for_each_entry(tpriv, &rtlpriv->glb_var->glb_priv_list,
+                                   list) {
+                       if (tpriv == NULL)
+                               break;
+
+                       tpcipriv = (struct rtl_pci_priv *)tpriv->priv;
+                       RT_TRACE(COMP_INIT, DBG_LOUD,
+                                ("pcipriv->ndis_adapter.funcnumber %x\n",
+                                 pcipriv->ndis_adapter.funcnumber));
+                       RT_TRACE(COMP_INIT, DBG_LOUD,
+                                ("tpcipriv->ndis_adapter.funcnumber %x\n",
+                                 tpcipriv->ndis_adapter.funcnumber));
+
+                       if ((pcipriv->ndis_adapter.busnumber ==
+                            tpcipriv->ndis_adapter.busnumber) &&
+                           (pcipriv->ndis_adapter.devnumber ==
+                            tpcipriv->ndis_adapter.devnumber) &&
+                           (pcipriv->ndis_adapter.funcnumber !=
+                            tpcipriv->ndis_adapter.funcnumber)) {
+                               find_buddy_priv = true;
+                               break;
+                       }
+               }
+       }
+
+       RT_TRACE(COMP_INIT, DBG_LOUD,
+                ("find_buddy_priv %d\n", find_buddy_priv));
+
+       if (find_buddy_priv)
+               *buddy_priv = tpriv;
+
+       return find_buddy_priv;
+}
+
+static void rtl_pci_get_linkcontrol_field(struct ieee80211_hw *hw)
+{
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+       u8 capabilityoffset = pcipriv->ndis_adapter.pcibridge_pciehdr_offset;
+       u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport;
+       u8 linkctrl_reg;
+       u8 num4bbytes;
+
+       num4bbytes = (capabilityoffset + 0x10) / 4;
+
+       /*Read  Link Control Register */
+       rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS,
+                                    pcicfg_addrport + (num4bbytes << 2));
+       rtl_pci_raw_read_port_uchar(PCI_CONF_DATA, &linkctrl_reg);
+
+       pcipriv->ndis_adapter.pcibridge_linkctrlreg = linkctrl_reg;
+}
+
+static void rtl_pci_parse_configuration(struct pci_dev *pdev,
+                                       struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+
+       u8 tmp;
+       int pos;
+       u8 linkctrl_reg;
+
+       /*Link Control Register */
+       pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+       pci_read_config_byte(pdev, pos + PCI_EXP_LNKCTL, &linkctrl_reg);
+       pcipriv->ndis_adapter.linkctrl_reg = linkctrl_reg;
+
+       RT_TRACE(COMP_INIT, DBG_TRACE,
+                ("Link Control Register =%x\n",
+                 pcipriv->ndis_adapter.linkctrl_reg));
+
+       pci_read_config_byte(pdev, 0x98, &tmp);
+       tmp |= BIT(4);
+       pci_write_config_byte(pdev, 0x98, tmp);
+
+       tmp = 0x17;
+       pci_write_config_byte(pdev, 0x70f, tmp);
+}
+
+static void rtl_pci_init_aspm(struct ieee80211_hw *hw)
+{
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+       _rtl_pci_update_default_setting(hw);
+
+       if (ppsc->reg_rfps_level & RT_RF_PS_LEVEL_ALWAYS_ASPM) {
+               /*Always enable ASPM & Clock Req. */
+               rtl_pci_enable_aspm(hw);
+               RT_SET_PS_LEVEL(ppsc, RT_RF_PS_LEVEL_ALWAYS_ASPM);
+       }
+}
+
+static void _rtl_pci_io_handler_init(struct device *dev,
+                                    struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       rtlpriv->io.dev = dev;
+
+       rtlpriv->io.write8_async = pci_write8_async;
+       rtlpriv->io.write16_async = pci_write16_async;
+       rtlpriv->io.write32_async = pci_write32_async;
+
+       rtlpriv->io.read8_sync = pci_read8_sync;
+       rtlpriv->io.read16_sync = pci_read16_sync;
+       rtlpriv->io.read32_sync = pci_read32_sync;
+}
+
+static bool _rtl_pci_update_earlymode_info(struct ieee80211_hw *hw,
+                                          struct sk_buff *skb,
+                                          struct rtl_tcb_desc *tcb_desc,
+                                          u8 tid)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       struct sk_buff *next_skb;
+       u8 additionlen = FCS_LEN;
+
+       /* here open is 4, wep/tkip is 8, aes is 12*/
+       if (info->control.hw_key)
+               additionlen += info->control.hw_key->icv_len;
+
+       /* The most skb num is 6 */
+       tcb_desc->empkt_num = 0;
+       spin_lock_bh(&rtlpriv->locks.waitq_lock);
+       skb_queue_walk(&rtlpriv->mac80211.skb_waitq[tid], next_skb) {
+               struct ieee80211_tx_info *next_info;
+
+               next_info = IEEE80211_SKB_CB(next_skb);
+               if (next_info->flags & IEEE80211_TX_CTL_AMPDU) {
+                       tcb_desc->empkt_len[tcb_desc->empkt_num] =
+                               next_skb->len + additionlen;
+                       tcb_desc->empkt_num++;
+               } else {
+                       break;
+               }
+
+               if (skb_queue_is_last(&rtlpriv->mac80211.skb_waitq[tid],
+                                     next_skb))
+                       break;
+
+               if (tcb_desc->empkt_num >= rtlhal->max_earlymode_num)
+                       break;
+       }
+       spin_unlock_bh(&rtlpriv->locks.waitq_lock);
+       return true;
+}
+
+/* just for early mode now */
+static void _rtl_pci_tx_chk_waitq(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       struct sk_buff *skb = NULL;
+       struct ieee80211_tx_info *info = NULL;
+       int tid; /* should be int */
+
+       if (!rtlpriv->rtlhal.b_earlymode_enable)
+               return;
+       if (rtlpriv->dm.supp_phymode_switch &&
+           (rtlpriv->easy_concurrent_ctl.bswitch_in_process ||
+           (rtlpriv->buddy_priv &&
+            rtlpriv->buddy_priv->easy_concurrent_ctl.bswitch_in_process)))
+               return;
+       /* we juse use em for BE/BK/VI/VO */
+       for (tid = 7; tid >= 0; tid--) {
+               u8 hw_queue = ac_to_hwq[rtl92e_tid_to_ac(hw, tid)];
+               struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue];
+               while (!mac->act_scanning &&
+                      rtlpriv->psc.rfpwr_state == ERFON) {
+                       struct rtl_tcb_desc tcb_desc;
+                       memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
+
+                       spin_lock_bh(&rtlpriv->locks.waitq_lock);
+                       if (!skb_queue_empty(&mac->skb_waitq[tid]) &&
+                           (ring->entries - skb_queue_len(&ring->queue) >
+                            rtlhal->max_earlymode_num)) {
+                               skb = skb_dequeue(&mac->skb_waitq[tid]);
+                       } else {
+                               spin_unlock_bh(&rtlpriv->locks.waitq_lock);
+                               break;
+                       }
+                       spin_unlock_bh(&rtlpriv->locks.waitq_lock);
+
+                       /* Some macaddr can't do early mode. like
+                        * multicast/broadcast/no_qos data */
+                       info = IEEE80211_SKB_CB(skb);
+                       if (info->flags & IEEE80211_TX_CTL_AMPDU)
+                               _rtl_pci_update_earlymode_info(hw, skb,
+                                                              &tcb_desc, tid);
+
+                       rtlpriv->intf_ops->adapter_tx(hw, NULL, skb, &tcb_desc);
+               }
+       }
+}
+
+static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[prio];
+
+       while (skb_queue_len(&ring->queue)) {
+               struct sk_buff *skb;
+               struct ieee80211_tx_info *info;
+               __le16 fc;
+               u8 tid;
+               u8 *entry;
+
+
+               if (rtlpriv->use_new_trx_flow)
+                       entry = (u8 *)(&ring->buffer_desc[ring->idx]);
+               else
+                       entry = (u8 *)(&ring->desc[ring->idx]);
+
+               if (rtlpriv->cfg->ops->is_tx_desc_closed &&
+                   !rtlpriv->cfg->ops->is_tx_desc_closed(hw, prio, ring->idx))
+                       return;
+
+               ring->idx = (ring->idx + 1) % ring->entries;
+
+               skb = __skb_dequeue(&ring->queue);
+
+               pci_unmap_single(rtlpci->pdev,
+                                rtlpriv->cfg->ops->
+                                            get_desc((u8 *)entry, true,
+                                                     HW_DESC_TXBUFF_ADDR),
+                                skb->len, PCI_DMA_TODEVICE);
+
+               /* remove early mode header */
+               if (rtlpriv->rtlhal.b_earlymode_enable)
+                       skb_pull(skb, EM_HDR_LEN);
+
+               RT_TRACE((COMP_INTR | COMP_SEND), DBG_TRACE,
+                        ("new ring->idx:%d, free: skb_queue_len:%d, free: seq:%d\n",
+                         ring->idx,
+                         skb_queue_len(&ring->queue),
+                         *(u16 *)(skb->data + 22)));
+
+               if (prio == TXCMD_QUEUE) {
+                       dev_kfree_skb(skb);
+                       goto tx_status_ok;
+               }
+
+               /* for sw LPS, just after NULL skb send out, we can
+                * sure AP knows that we are sleeping, our we should not let
+                * rf to sleep
+                */
+               fc = rtl_get_fc(skb);
+               if (ieee80211_is_nullfunc(fc)) {
+                       if (ieee80211_has_pm(fc)) {
+                               rtlpriv->mac80211.offchan_deley = true;
+                               rtlpriv->psc.state_inap = 1;
+                       } else {
+                               rtlpriv->psc.state_inap = 0;
+                       }
+               }
+               if (ieee80211_is_action(fc)) {
+                       struct ieee80211_mgmt_compat *action_frame =
+                               (struct ieee80211_mgmt_compat *)skb->data;
+                       if (action_frame->u.action.u.ht_smps.action ==
+                               WLAN_HT_ACTION_SMPS) {
+                               dev_kfree_skb(skb);
+                               goto tx_status_ok;
+                       }
+               }
+
+               /* update tid tx pkt num */
+               tid = rtl_get_tid(skb);
+               if (tid <= 7)
+                       rtlpriv->link_info.tidtx_inperiod[tid]++;
+
+               info = IEEE80211_SKB_CB(skb);
+               ieee80211_tx_info_clear_status(info);
+
+               info->flags |= IEEE80211_TX_STAT_ACK;
+               /*info->status.rates[0].count = 1; */
+
+               ieee80211_tx_status_irqsafe(hw, skb);
+
+               if ((ring->entries - skb_queue_len(&ring->queue)) == 2) {
+                       RT_TRACE(COMP_ERR, DBG_LOUD,
+                                ("more desc left, wake skb_queue@%d,ring->idx = %d, skb_queue_len = 0x%d\n",
+                                        prio, ring->idx,
+                                        skb_queue_len(&ring->queue)));
+
+                       ieee80211_wake_queue(hw, skb_get_queue_mapping
+                                            (skb));
+               }
+tx_status_ok:
+               skb = NULL;
+       }
+
+       if (((rtlpriv->link_info.num_rx_inperiod +
+               rtlpriv->link_info.num_tx_inperiod) > 8) ||
+               (rtlpriv->link_info.num_rx_inperiod > 2)) {
+               rtl92e_lps_leave(hw);
+       }
+}
+
+static int _rtl_pci_init_one_rxdesc(struct ieee80211_hw *hw,
+                                   u8 *entry, int rxring_idx, int desc_idx)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       struct sk_buff *skb;
+       u32 bufferaddress;
+       u8 tmp_one = 1;
+
+       skb = dev_alloc_skb(rtlpci->rxbuffersize);
+       if (!skb)
+               return 0;
+       rtlpci->rx_ring[rxring_idx].rx_buf[desc_idx] = skb;
+
+       /* just set skb->cb to mapping addr
+        * for pci_unmap_single use
+        */
+       *((dma_addr_t *)skb->cb) = pci_map_single(rtlpci->pdev,
+                               skb_tail_pointer(skb), rtlpci->rxbuffersize,
+                               PCI_DMA_FROMDEVICE);
+       bufferaddress = *((dma_addr_t *)skb->cb);
+       if (pci_dma_mapping_error(rtlpci->pdev, bufferaddress))
+               return 0;
+       if (rtlpriv->use_new_trx_flow) {
+               rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false,
+                                           HW_DESC_RX_PREPARE,
+                                           (u8 *)&bufferaddress);
+       } else {
+               rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false,
+                                           HW_DESC_RXBUFF_ADDR,
+                                           (u8 *)&bufferaddress);
+               rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false,
+                                           HW_DESC_RXPKT_LEN,
+                                           (u8 *)&rtlpci->rxbuffersize);
+               rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false,
+                                           HW_DESC_RXOWN,
+                                           (u8 *)&tmp_one);
+       }
+       return 1;
+}
+
+/* inorder to receive 8K AMSDU we have set skb to
+ * 9100bytes in init rx ring, but if this packet is
+ * not a AMSDU, this so big packet will be sent to
+ * TCP/IP directly, this cause big packet ping fail
+ * like: "ping -s 65507", so here we will realloc skb
+ * based on the true size of packet, I think mac80211
+ * do it will be better, but now mac80211 haven't */
+
+/* but some platform will fail when alloc skb sometimes.
+ * in this condition, we will send the old skb to
+ * mac80211 directly, this will not cause any other
+ * issues, but only be losted by TCP/IP */
+static void _rtl_pci_rx_to_mac80211(struct ieee80211_hw *hw,
+                                   struct sk_buff *skb,
+                                   struct ieee80211_rx_status rx_status)
+{
+       if (unlikely(!rtl92e_action_proc(hw, skb, false))) {
+               dev_kfree_skb_any(skb);
+       } else {
+               struct sk_buff *uskb = NULL;
+               u8 *pdata;
+
+               uskb = dev_alloc_skb(skb->len + 128);
+               if (likely(uskb)) {
+                       memcpy(IEEE80211_SKB_RXCB(uskb), &rx_status,
+                              sizeof(rx_status));
+                       pdata = (u8 *)skb_put(uskb, skb->len);
+                       memcpy(pdata, skb->data, skb->len);
+                       dev_kfree_skb_any(skb);
+
+                       ieee80211_rx_irqsafe(hw, uskb);
+               } else {
+                       ieee80211_rx_irqsafe(hw, skb);
+               }
+       }
+}
+
+/*hsisr interrupt handler*/
+static void _rtl_pci_hs_interrupt(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+       rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[MAC_HSISR],
+                      rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[MAC_HSISR]) |
+                      rtlpci->sys_irq_mask);
+}
+
+static void _rtl_receive_one(struct ieee80211_hw *hw, struct sk_buff *skb,
+                            struct ieee80211_rx_status rx_status)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct ieee80211_hdr *hdr = rtl_get_hdr(skb);
+       __le16 fc = rtl_get_fc(skb);
+       bool unicast = false;
+
+       memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
+
+       if (is_broadcast_ether_addr(hdr->addr1)) {
+               ;/*TODO*/
+       } else if (is_multicast_ether_addr(hdr->addr1)) {
+               ;/*TODO*/
+       } else {
+               unicast = true;
+               rtlpriv->stats.rxbytesunicast += skb->len;
+       }
+
+       rtl92e_is_special_data(hw, skb, false);
+       if (ieee80211_is_data(fc)) {
+               rtlpriv->cfg->ops->led_control(hw, LED_CTL_RX);
+
+               if (unicast)
+                       rtlpriv->link_info.num_rx_inperiod++;
+       }
+
+       /* static bcn for roaming */
+       rtl92e_beacon_statistic(hw, skb);
+       rtl92e_p2p_info(hw, (void *)skb->data, skb->len);
+
+       /* for sw lps */
+       rtl92e_swlps_beacon(hw, (void *)skb->data, skb->len);
+       rtl92e_recognize_peer(hw, (void *)skb->data, skb->len);
+       if ((rtlpriv->mac80211.opmode == NL80211_IFTYPE_AP) &&
+           (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) &&
+           (ieee80211_is_beacon(fc) ||
+            ieee80211_is_probe_resp(fc)))
+               dev_kfree_skb_any(skb);
+       else
+               _rtl_pci_rx_to_mac80211(hw, skb, rx_status);
+}
+
+static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       struct ieee80211_rx_status rx_status = { 0 };
+       int rxring_idx = RTL_PCI_RX_MPDU_QUEUE;
+       unsigned int count = rtlpci->rxringcount;
+       u8 hw_queue = 0;
+       unsigned int rx_remained_cnt;
+       u8 own;
+       u8 tmp_one;
+       static int err_count;
+       struct rtl_stats stats = {
+               .signal = 0,
+               .rate = 0,
+       };
+
+       /*RX NORMAL PKT */
+       while (count--) {
+               struct ieee80211_hdr *hdr;
+               __le16 fc;
+               u16 len;
+               /*rx buffer descriptor */
+               struct rtl_rx_buffer_desc *buffer_desc = NULL;
+               /*if use new trx flow, it means wifi info */
+               struct rtl_rx_desc *pdesc = NULL;
+               /*rx pkt */
+               struct sk_buff *skb = rtlpci->rx_ring[rxring_idx].rx_buf[
+                                       rtlpci->rx_ring[rxring_idx].idx];
+
+               if (rtlpriv->use_new_trx_flow) {
+                       rx_remained_cnt =
+                               rtlpriv->cfg->ops->rx_desc_buff_remained_cnt(hw,
+                                                                     hw_queue);
+                       if (rx_remained_cnt < 1)
+                               return;
+
+               } else {        /* rx descriptor */
+                       pdesc = &rtlpci->rx_ring[rxring_idx].desc[
+                               rtlpci->rx_ring[rxring_idx].idx];
+
+                       own = (u8) rtlpriv->cfg->ops->get_desc((u8 *)pdesc,
+                                                              false,
+                                                              HW_DESC_OWN);
+                       if (own) /* wait data to be filled by hardware */
+                               return;
+               }
+
+               /* If we get here, the data is filled already
+                * Attention !!!
+                * We can NOT access 'skb' before 'pci_unmap_single'
+                */
+               pci_unmap_single(rtlpci->pdev, *((dma_addr_t *)skb->cb),
+                                rtlpci->rxbuffersize, PCI_DMA_FROMDEVICE);
+
+               if (rtlpriv->use_new_trx_flow) {
+                       buffer_desc = &rtlpci->rx_ring[rxring_idx].buffer_desc[
+                               rtlpci->rx_ring[rxring_idx].idx];
+                       /*means rx wifi info*/
+                       pdesc = (struct rtl_rx_desc *)skb->data;
+               }
+               memset(&rx_status , 0 , sizeof(rx_status));
+               rtlpriv->cfg->ops->query_rx_desc(hw, &stats,
+                                                &rx_status, (u8 *)pdesc, skb);
+
+               if (rtlpriv->use_new_trx_flow)
+                       rtlpriv->cfg->ops->rx_check_dma_ok(hw,
+                                                          (u8 *)buffer_desc,
+                                                          hw_queue);
+               len = rtlpriv->cfg->ops->get_desc((u8 *)pdesc, false,
+                                                 HW_DESC_RXPKT_LEN);
+
+               if (skb->end - skb->tail > len) {
+                       skb_put(skb, len);
+                       if (rtlpriv->use_new_trx_flow)
+                               skb_reserve(skb, stats.rx_drvinfo_size +
+                                                stats.rx_bufshift + 24);
+                       else
+                               skb_reserve(skb, stats.rx_drvinfo_size +
+                                                stats.rx_bufshift);
+
+               } else {
+                       if (err_count++ < 10) {
+                               pr_info("skb->end (%d) - skb->tail (%d) > len (%d)\n",
+                                       skb->end, skb->tail, len);
+                               RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_EMERG,
+                                             "RX desc\n",
+                                             (u8 *)pdesc, 32);
+                       }
+                       break;
+               }
+
+               /* handle command packet here */
+               if (rtlpriv->cfg->ops->rx_command_packet(hw, stats, skb)) {
+                               dev_kfree_skb_any(skb);
+                               goto end;
+               }
+
+               /* NOTICE This can not be use for mac80211,
+                *this is done in mac80211 code,
+                *if you done here sec DHCP will fail
+                *skb_trim(skb, skb->len - 4);
+                */
+
+               hdr = rtl_get_hdr(skb);
+               fc = rtl_get_fc(skb);
+
+               if (!stats.b_crc && !stats.b_hwerror)
+                       _rtl_receive_one(hw, skb, rx_status);
+               else
+                       dev_kfree_skb_any(skb);
+               if (rtlpriv->use_new_trx_flow) {
+                       rtlpci->rx_ring[hw_queue].next_rx_rp += 1;
+                       rtlpci->rx_ring[hw_queue].next_rx_rp %=
+                                                       RTL_PCI_MAX_RX_COUNT;
+
+
+                       rx_remained_cnt--;
+                       rtl_write_word(rtlpriv, 0x3B4,
+                                      rtlpci->rx_ring[hw_queue].next_rx_rp);
+               }
+               if (((rtlpriv->link_info.num_rx_inperiod +
+                     rtlpriv->link_info.num_tx_inperiod) > 8) ||
+                   (rtlpriv->link_info.num_rx_inperiod > 2)) {
+                       rtl92e_lps_leave(hw);
+               }
+end:
+               if (rtlpriv->use_new_trx_flow) {
+                       _rtl_pci_init_one_rxdesc(hw, (u8 *)buffer_desc,
+                                                rxring_idx,
+                                              rtlpci->rx_ring[rxring_idx].idx);
+               } else {
+                       _rtl_pci_init_one_rxdesc(hw, (u8 *)pdesc, rxring_idx,
+                                                rtlpci->rx_ring[rxring_idx].idx);
+
+                       if (rtlpci->rx_ring[rxring_idx].idx ==
+                           rtlpci->rxringcount - 1)
+                               rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc,
+                                                           false,
+                                                           HW_DESC_RXERO,
+                                                           (u8 *)&tmp_one);
+               }
+               rtlpci->rx_ring[rxring_idx].idx =
+                               (rtlpci->rx_ring[rxring_idx].idx + 1) %
+                               rtlpci->rxringcount;
+       }
+}
+
+static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
+{
+       struct ieee80211_hw *hw = dev_id;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       unsigned long flags;
+       u32 inta = 0;
+       u32 intb = 0;
+
+       if (rtlpci->irq_enabled == 0)
+               return IRQ_HANDLED;
+
+       spin_lock_irqsave(&rtlpriv->locks.irq_th_lock , flags);
+       rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[MAC_HIMR], 0x0);
+       rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[MAC_HIMRE], 0x0);
+
+       /*read ISR: 4/8bytes */
+       rtlpriv->cfg->ops->interrupt_recognized(hw, &inta, &intb);
+
+       /*Shared IRQ or HW disappared */
+       if (!inta || inta == 0xffff)
+               goto done;
+       /*<1> beacon related */
+       if (inta & rtlpriv->cfg->maps[RTL_IMR_TBDOK])
+               RT_TRACE(COMP_INTR, DBG_TRACE, ("beacon ok interrupt!\n"));
+
+       if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_TBDER]))
+               RT_TRACE(COMP_INTR, DBG_TRACE, ("beacon err interrupt!\n"));
+
+       if (inta & rtlpriv->cfg->maps[RTL_IMR_BDOK])
+               RT_TRACE(COMP_INTR, DBG_TRACE, ("beacon interrupt!\n"));
+
+       if (inta & rtlpriv->cfg->maps[RTL_IMR_BcnInt]) {
+               RT_TRACE(COMP_INTR, DBG_TRACE,
+                        ("prepare beacon for interrupt!\n"));
+               tasklet_schedule(&rtlpriv->works.irq_prepare_bcn_tasklet);
+       }
+
+       /*<2> tx related */
+       if (unlikely(intb & rtlpriv->cfg->maps[RTL_IMR_TXFOVW]))
+               RT_TRACE(COMP_ERR, DBG_TRACE, ("IMR_TXFOVW!\n"));
+
+       if (inta & rtlpriv->cfg->maps[RTL_IMR_MGNTDOK]) {
+               RT_TRACE(COMP_INTR, DBG_TRACE, ("Manage ok interrupt!\n"));
+               _rtl_pci_tx_isr(hw, MGNT_QUEUE);
+       }
+
+       if (inta & rtlpriv->cfg->maps[RTL_IMR_HIGHDOK]) {
+               RT_TRACE(COMP_INTR, DBG_TRACE, ("HIGH_QUEUE ok interrupt!\n"));
+               _rtl_pci_tx_isr(hw, HIGH_QUEUE);
+       }
+
+       if (inta & rtlpriv->cfg->maps[RTL_IMR_BKDOK]) {
+               rtlpriv->link_info.num_tx_inperiod++;
+
+               RT_TRACE(COMP_INTR, DBG_TRACE, ("BK Tx OK interrupt!\n"));
+               _rtl_pci_tx_isr(hw, BK_QUEUE);
+       }
+
+       if (inta & rtlpriv->cfg->maps[RTL_IMR_BEDOK]) {
+               rtlpriv->link_info.num_tx_inperiod++;
+
+               RT_TRACE(COMP_INTR, DBG_TRACE, ("BE TX OK interrupt!\n"));
+               _rtl_pci_tx_isr(hw, BE_QUEUE);
+       }
+
+       if (inta & rtlpriv->cfg->maps[RTL_IMR_VIDOK]) {
+               rtlpriv->link_info.num_tx_inperiod++;
+
+               RT_TRACE(COMP_INTR, DBG_TRACE, ("VI TX OK interrupt!\n"));
+               _rtl_pci_tx_isr(hw, VI_QUEUE);
+       }
+
+       if (inta & rtlpriv->cfg->maps[RTL_IMR_VODOK]) {
+               rtlpriv->link_info.num_tx_inperiod++;
+
+               RT_TRACE(COMP_INTR, DBG_TRACE, ("Vo TX OK interrupt!\n"));
+               _rtl_pci_tx_isr(hw, VO_QUEUE);
+       }
+
+       if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) {
+               if (inta & rtlpriv->cfg->maps[RTL_IMR_COMDOK]) {
+                       rtlpriv->link_info.num_tx_inperiod++;
+
+                       RT_TRACE(COMP_INTR, DBG_TRACE,
+                                ("CMD TX OK interrupt!\n"));
+                       _rtl_pci_tx_isr(hw, TXCMD_QUEUE);
+               }
+       }
+
+       /*<3> rx related */
+       if (inta & rtlpriv->cfg->maps[RTL_IMR_ROK]) {
+               RT_TRACE(COMP_INTR, DBG_TRACE, ("Rx ok interrupt!\n"));
+               _rtl_pci_rx_interrupt(hw);
+       }
+
+       if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_RDU])) {
+               RT_TRACE(COMP_ERR, DBG_WARNING,
+                        ("rx descriptor unavailable!\n"));
+               _rtl_pci_rx_interrupt(hw);
+       }
+
+       if (unlikely(intb & rtlpriv->cfg->maps[RTL_IMR_RXFOVW])) {
+               RT_TRACE(COMP_ERR, DBG_WARNING, ("rx overflow !\n"));
+               _rtl_pci_rx_interrupt(hw);
+       }
+
+       /*<4> fw related*/
+       if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723AE) {
+               if (inta & rtlpriv->cfg->maps[RTL_IMR_C2HCMD]) {
+                       RT_TRACE(COMP_INTR, DBG_TRACE,
+                                ("firmware interrupt!\n"));
+                       queue_delayed_work(rtlpriv->works.rtl_wq,
+                                          &rtlpriv->works.fwevt_wq, 0);
+               }
+       }
+
+       /*<5> hsisr related*/
+       /* Only 8188EE & 8723BE Supported.
+        * If Other ICs Come in, System will corrupt,
+        * because maps[RTL_IMR_HSISR_IND] & maps[MAC_HSISR]
+        * are not initialized*/
+       if (rtlhal->hw_type == HARDWARE_TYPE_RTL8188EE ||
+           rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) {
+               if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_HSISR_IND])) {
+                       RT_TRACE(COMP_INTR, DBG_TRACE,
+                                ("hsisr interrupt!\n"));
+                       _rtl_pci_hs_interrupt(hw);
+               }
+       }
+
+
+       if (rtlpriv->rtlhal.b_earlymode_enable)
+               tasklet_schedule(&rtlpriv->works.irq_tasklet);
+
+done:
+       rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[MAC_HIMR],
+                       rtlpci->irq_mask[0]);
+       rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[MAC_HIMRE],
+                       rtlpci->irq_mask[1]);
+       spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
+       return IRQ_HANDLED;
+}
+
+static void _rtl_pci_irq_tasklet(struct ieee80211_hw *hw)
+{
+       _rtl_pci_tx_chk_waitq(hw);
+}
+
+static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl8192_tx_ring *ring = NULL;
+       struct ieee80211_hdr *hdr = NULL;
+       struct ieee80211_tx_info *info = NULL;
+       struct sk_buff *pskb = NULL;
+       struct rtl_tx_desc *pdesc = NULL;
+       struct rtl_tcb_desc tcb_desc;
+       /*This is for new trx flow*/
+       struct rtl_tx_buffer_desc *pbuffer_desc = NULL;
+       u8 temp_one = 1;
+
+       memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
+       ring = &rtlpci->tx_ring[BEACON_QUEUE];
+       pskb = __skb_dequeue(&ring->queue);
+       if (pskb)
+               kfree_skb(pskb);
+
+       /*NB: the beacon data buffer must be 32-bit aligned. */
+       pskb = ieee80211_beacon_get(hw, mac->vif);
+       if (pskb == NULL)
+               return;
+       hdr = rtl_get_hdr(pskb);
+       info = IEEE80211_SKB_CB(pskb);
+       pdesc = &ring->desc[0];
+       if (rtlpriv->use_new_trx_flow)
+               pbuffer_desc = &ring->buffer_desc[0];
+
+       rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc,
+                                       (u8 *)pbuffer_desc, info, NULL, pskb,
+                                       BEACON_QUEUE, &tcb_desc);
+
+       __skb_queue_tail(&ring->queue, pskb);
+
+       rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, true, HW_DESC_OWN,
+                                   (u8 *)&temp_one);
+
+       return;
+}
+
+static void _rtl_pci_init_trx_var(struct ieee80211_hw *hw)
+{
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+       u8 i;
+       u16 desc_num;
+
+       if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192EE)
+               desc_num = TX_DESC_NUM_92E;
+       else
+               desc_num = RT_TXDESC_NUM;
+
+       for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++)
+               rtlpci->txringcount[i] = desc_num;
+       /*
+        *we just alloc 2 desc for beacon queue,
+        *because we just need first desc in hw beacon.
+        */
+       rtlpci->txringcount[BEACON_QUEUE] = 2;
+
+       /*
+        *BE queue need more descriptor for performance
+        *consideration or, No more tx desc will happen,
+        *and may cause mac80211 mem leakage.
+        */
+       if (!rtl_priv(hw)->use_new_trx_flow)
+               rtlpci->txringcount[BE_QUEUE] = RT_TXDESC_NUM_BE_QUEUE;
+
+       rtlpci->rxbuffersize = 9100;    /*2048/1024; */
+       rtlpci->rxringcount = RTL_PCI_MAX_RX_COUNT;     /*64; */
+}
+
+static void _rtl_pci_init_struct(struct ieee80211_hw *hw,
+                                struct pci_dev *pdev)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+       rtlpriv->rtlhal.up_first_time = true;
+       rtlpriv->rtlhal.being_init_adapter = false;
+
+       rtlhal->hw = hw;
+       rtlpci->pdev = pdev;
+
+       /*Tx/Rx related var */
+       _rtl_pci_init_trx_var(hw);
+
+       /*IBSS*/ mac->beacon_interval = 100;
+
+       /*AMPDU*/
+       mac->min_space_cfg = 0;
+       mac->max_mss_density = 0;
+       /*set sane AMPDU defaults */
+       mac->current_ampdu_density = 7;
+       mac->current_ampdu_factor = 3;
+
+       /*QOS*/
+       rtlpci->acm_method = eAcmWay2_SW;
+
+       /*task */
+       tasklet_init(&rtlpriv->works.irq_tasklet,
+                    (void (*)(unsigned long))_rtl_pci_irq_tasklet,
+                    (unsigned long)hw);
+       tasklet_init(&rtlpriv->works.irq_prepare_bcn_tasklet,
+                    (void (*)(unsigned long))_rtl_pci_prepare_bcn_tasklet,
+                    (unsigned long)hw);
+}
+
+static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw,
+                                unsigned int prio, unsigned int entries)
+{
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_tx_buffer_desc *buffer_desc;
+       struct rtl_tx_desc *desc;
+       dma_addr_t buffer_desc_dma, desc_dma;
+       u32 nextdescaddress;
+       int i;
+
+       /* alloc tx buffer desc for new trx flow*/
+       if (rtlpriv->use_new_trx_flow) {
+               buffer_desc = pci_alloc_consistent(rtlpci->pdev,
+                                       sizeof(*buffer_desc) * entries,
+                                       &buffer_desc_dma);
+
+               if (!buffer_desc || (unsigned long)buffer_desc & 0xFF) {
+                       RT_TRACE(COMP_ERR, DBG_EMERG,
+                                ("Cannot allocate TX ring (prio = %d)\n",
+                                prio));
+                       return -ENOMEM;
+               }
+
+               memset(buffer_desc, 0, sizeof(*buffer_desc) * entries);
+               rtlpci->tx_ring[prio].buffer_desc = buffer_desc;
+               rtlpci->tx_ring[prio].buffer_desc_dma = buffer_desc_dma;
+
+               rtlpci->tx_ring[prio].cur_tx_rp = 0;
+               rtlpci->tx_ring[prio].cur_tx_wp = 0;
+               rtlpci->tx_ring[prio].avl_desc = entries;
+       }
+
+       /* alloc dma for this ring */
+       desc = pci_alloc_consistent(rtlpci->pdev,
+                                   sizeof(*desc) * entries, &desc_dma);
+
+       if (!desc || (unsigned long)desc & 0xFF) {
+               RT_TRACE(COMP_ERR, DBG_EMERG,
+                        ("Cannot allocate TX ring (prio = %d)\n", prio));
+               return -ENOMEM;
+       }
+
+       memset(desc, 0, sizeof(*desc) * entries);
+       rtlpci->tx_ring[prio].desc = desc;
+       rtlpci->tx_ring[prio].dma = desc_dma;
+
+       rtlpci->tx_ring[prio].idx = 0;
+       rtlpci->tx_ring[prio].entries = entries;
+       skb_queue_head_init(&rtlpci->tx_ring[prio].queue);
+       RT_TRACE(COMP_INIT, DBG_LOUD,
+                ("queue:%d, ring_addr:%p\n", prio, desc));
+
+       /* init every desc in this ring */
+       if (!rtlpriv->use_new_trx_flow) {
+               for (i = 0; i < entries; i++) {
+                       nextdescaddress = (u32) desc_dma +
+                                                     ((i +     1) % entries) *
+                                                     sizeof(*desc);
+
+                       rtlpriv->cfg->ops->set_desc(hw, (u8 *)&(desc[i]),
+                                                   true,
+                                                   HW_DESC_TX_NEXTDESC_ADDR,
+                                                   (u8 *)&nextdescaddress);
+               }
+       }
+       return 0;
+}
+
+static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw, int rxring_idx)
+{
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       int i;
+
+       if (rtlpriv->use_new_trx_flow) {
+               struct rtl_rx_buffer_desc *entry = NULL;
+               /* alloc dma for this ring */
+               rtlpci->rx_ring[rxring_idx].buffer_desc =
+                   pci_alloc_consistent(rtlpci->pdev,
+                                        sizeof(*rtlpci->rx_ring[rxring_idx].
+                                               buffer_desc) *
+                                               rtlpci->rxringcount,
+                                        &rtlpci->rx_ring[rxring_idx].dma);
+               if (!rtlpci->rx_ring[rxring_idx].buffer_desc ||
+                   (unsigned long)rtlpci->rx_ring[rxring_idx].buffer_desc & 0xFF) {
+                       RT_TRACE(COMP_ERR, DBG_EMERG,
+                                ("Cannot allocate RX ring\n"));
+                       return -ENOMEM;
+               }
+
+               memset(rtlpci->rx_ring[rxring_idx].buffer_desc, 0,
+                      sizeof(*rtlpci->rx_ring[rxring_idx].buffer_desc) *
+                      rtlpci->rxringcount);
+
+               /* init every desc in this ring */
+               rtlpci->rx_ring[rxring_idx].idx = 0;
+
+               for (i = 0; i < rtlpci->rxringcount; i++) {
+                       entry = &rtlpci->rx_ring[rxring_idx].buffer_desc[i];
+                       if (!_rtl_pci_init_one_rxdesc(hw, (u8 *)entry,
+                                                     rxring_idx, i))
+                               return -ENOMEM;
+               }
+       } else {
+               struct rtl_rx_desc *entry = NULL;
+               u8 tmp_one = 1;
+               /* alloc dma for this ring */
+               rtlpci->rx_ring[rxring_idx].desc =
+                   pci_alloc_consistent(rtlpci->pdev,
+                                        sizeof(*rtlpci->rx_ring[rxring_idx].
+                                       desc) * rtlpci->rxringcount,
+                                        &rtlpci->rx_ring[rxring_idx].dma);
+               if (!rtlpci->rx_ring[rxring_idx].desc ||
+                   (unsigned long)rtlpci->rx_ring[rxring_idx].desc & 0xFF) {
+                       RT_TRACE(COMP_ERR, DBG_EMERG,
+                                ("Cannot allocate RX ring\n"));
+                       return -ENOMEM;
+               }
+               memset(rtlpci->rx_ring[rxring_idx].desc, 0,
+                      sizeof(*rtlpci->rx_ring[rxring_idx].desc) *
+                      rtlpci->rxringcount);
+
+               /* init every desc in this ring */
+               rtlpci->rx_ring[rxring_idx].idx = 0;
+               for (i = 0; i < rtlpci->rxringcount; i++) {
+                       entry = &rtlpci->rx_ring[rxring_idx].desc[i];
+                       if (!_rtl_pci_init_one_rxdesc(hw, (u8 *)entry,
+                                                     rxring_idx, i))
+                               return -ENOMEM;
+               }
+               rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false,
+                                           HW_DESC_RXERO, (u8 *) &tmp_one);
+       }
+       return 0;
+}
+
+static void _rtl_pci_free_tx_ring(struct ieee80211_hw *hw,
+                                 unsigned int prio)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[prio];
+
+       /* free every desc in this ring */
+       while (skb_queue_len(&ring->queue)) {
+               struct sk_buff *skb = __skb_dequeue(&ring->queue);
+               u8 *entry;
+
+               if (rtlpriv->use_new_trx_flow)
+                       entry = (u8 *)(&ring->buffer_desc[ring->idx]);
+               else
+                       entry = (u8 *)(&ring->desc[ring->idx]);
+
+               pci_unmap_single(rtlpci->pdev,
+                                rtlpriv->cfg->ops->get_desc((u8 *)entry, true,
+                                HW_DESC_TXBUFF_ADDR),
+                                skb->len, PCI_DMA_TODEVICE);
+               kfree_skb(skb);
+               ring->idx = (ring->idx + 1) % ring->entries;
+       }
+
+       /* free dma of this ring */
+       pci_free_consistent(rtlpci->pdev,
+                           sizeof(*ring->desc) * ring->entries,
+                           ring->desc, ring->dma);
+       ring->desc = NULL;
+       if (rtlpriv->use_new_trx_flow) {
+               pci_free_consistent(rtlpci->pdev,
+                                   sizeof(*ring->buffer_desc) * ring->entries,
+                                   ring->buffer_desc, ring->buffer_desc_dma);
+               ring->buffer_desc = NULL;
+       }
+}
+
+static void _rtl_pci_free_rx_ring(struct ieee80211_hw *hw, int rxring_idx)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       int i;
+
+       /* free every desc in this ring */
+       for (i = 0; i < rtlpci->rxringcount; i++) {
+               struct sk_buff *skb = rtlpci->rx_ring[rxring_idx].rx_buf[i];
+
+               if (!skb)
+                       continue;
+
+               pci_unmap_single(rtlpci->pdev, *((dma_addr_t *)skb->cb),
+                                rtlpci->rxbuffersize, PCI_DMA_FROMDEVICE);
+               kfree_skb(skb);
+       }
+
+       /* free dma of this ring */
+       if (rtlpriv->use_new_trx_flow) {
+               pci_free_consistent(rtlpci->pdev,
+                                   sizeof(*rtlpci->rx_ring[rxring_idx].
+                                   buffer_desc) * rtlpci->rxringcount,
+                                   rtlpci->rx_ring[rxring_idx].buffer_desc,
+                                   rtlpci->rx_ring[rxring_idx].dma);
+               rtlpci->rx_ring[rxring_idx].buffer_desc = NULL;
+       } else {
+               pci_free_consistent(rtlpci->pdev,
+                                   sizeof(*rtlpci->rx_ring[rxring_idx].desc) *
+                                   rtlpci->rxringcount,
+                                   rtlpci->rx_ring[rxring_idx].desc,
+                                   rtlpci->rx_ring[rxring_idx].dma);
+               rtlpci->rx_ring[rxring_idx].desc = NULL;
+       }
+}
+
+static int _rtl_pci_init_trx_ring(struct ieee80211_hw *hw)
+{
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       int ret;
+       int i, rxring_idx;
+
+       /* rxring_idx 0:RX_MPDU_QUEUE
+        * rxring_idx 1:RX_CMD_QUEUE */
+       for (rxring_idx = 0; rxring_idx < RTL_PCI_MAX_RX_QUEUE; rxring_idx++) {
+               ret = _rtl_pci_init_rx_ring(hw, rxring_idx);
+               if (ret)
+                       return ret;
+       }
+
+       for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++) {
+               ret = _rtl_pci_init_tx_ring(hw, i,
+                                           rtlpci->txringcount[i]);
+               if (ret)
+                       goto err_free_rings;
+       }
+
+       return 0;
+
+err_free_rings:
+       for (rxring_idx = 0; rxring_idx < RTL_PCI_MAX_RX_QUEUE; rxring_idx++)
+               _rtl_pci_free_rx_ring(hw, rxring_idx);
+
+       for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++)
+               if (rtlpci->tx_ring[i].desc ||
+                   rtlpci->tx_ring[i].buffer_desc)
+                       _rtl_pci_free_tx_ring(hw, i);
+
+       return 1;
+}
+
+static int _rtl_pci_deinit_trx_ring(struct ieee80211_hw *hw)
+{
+       u32 i, rxring_idx;
+
+       /*free rx rings */
+       for (rxring_idx = 0; rxring_idx < RTL_PCI_MAX_RX_QUEUE; rxring_idx++)
+               _rtl_pci_free_rx_ring(hw, rxring_idx);
+
+       /*free tx rings */
+       for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++)
+               _rtl_pci_free_tx_ring(hw, i);
+
+       return 0;
+}
+
+int rtl92e_pci_reset_trx_ring(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       int i, rxring_idx;
+       unsigned long flags;
+       u8 tmp_one = 1;
+       /* rxring_idx 0:RX_MPDU_QUEUE */
+       /* rxring_idx 1:RX_CMD_QUEUE */
+       for (rxring_idx = 0; rxring_idx < RTL_PCI_MAX_RX_QUEUE; rxring_idx++) {
+               /* force the rx_ring[RX_MPDU_QUEUE]
+                * RX_CMD_QUEUE].idx to the first one
+                * If using the new trx flow, do nothing
+                */
+               if (!rtlpriv->use_new_trx_flow &&
+                   rtlpci->rx_ring[rxring_idx].desc) {
+                       struct rtl_rx_desc *entry = NULL;
+
+                       for (i = 0; i < rtlpci->rxringcount; i++) {
+                               entry = &rtlpci->rx_ring[rxring_idx].desc[i];
+                               rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry,
+                                                           false,
+                                                           HW_DESC_RXOWN,
+                                                           &tmp_one);
+                       }
+               }
+               rtlpci->rx_ring[rxring_idx].idx = 0;
+       }
+
+       /* after reset, release previous pending packet,
+        * and force the  tx idx to the first one
+        */
+       spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
+       for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++) {
+               if (rtlpci->tx_ring[i].desc ||
+                   rtlpci->tx_ring[i].buffer_desc) {
+                       struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[i];
+
+                       while (skb_queue_len(&ring->queue)) {
+                               struct sk_buff *skb =
+                                       __skb_dequeue(&ring->queue);
+                               u8 *entry;
+
+                               if (rtlpriv->use_new_trx_flow)
+                                       entry = (u8 *)(&ring->buffer_desc
+                                                               [ring->idx]);
+                               else
+                                       entry = (u8 *)(&ring->desc[ring->idx]);
+
+                               pci_unmap_single(rtlpci->pdev,
+                                                rtlpriv->cfg->ops->get_desc(
+                                                (u8 *)entry, true,
+                                                HW_DESC_TXBUFF_ADDR),
+                                       skb->len, PCI_DMA_TODEVICE);
+                               kfree_skb(skb);
+                               ring->idx = (ring->idx + 1) % ring->entries;
+                       }
+                       ring->idx = 0;
+               }
+       }
+
+       spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
+
+       return 0;
+}
+
+static bool rtl_pci_tx_chk_waitq_insert(struct ieee80211_hw *hw,
+                                       struct ieee80211_sta *sta,
+                                       struct sk_buff *skb)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_sta_info *sta_entry = NULL;
+       u8 tid = rtl_get_tid(skb);
+       __le16 fc = rtl_get_fc(skb);
+
+       if (!sta)
+               return false;
+       sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+
+       if (!rtlpriv->rtlhal.b_earlymode_enable)
+               return false;
+       if (ieee80211_is_nullfunc(fc))
+               return false;
+       if (ieee80211_is_qos_nullfunc(fc))
+               return false;
+       if (ieee80211_is_pspoll(fc))
+               return false;
+
+       if (sta_entry->tids[tid].agg.agg_state != RTL_AGG_OPERATIONAL)
+               return false;
+       if (_rtl_mac_to_hwqueue(hw, skb) > VO_QUEUE)
+               return false;
+       if (tid > 7)
+               return false;
+       /* maybe every tid should be checked */
+       if (!rtlpriv->link_info.higher_busytxtraffic[tid])
+               return false;
+
+       spin_lock_bh(&rtlpriv->locks.waitq_lock);
+       skb_queue_tail(&rtlpriv->mac80211.skb_waitq[tid], skb);
+       spin_unlock_bh(&rtlpriv->locks.waitq_lock);
+
+       return true;
+}
+
+static int rtl_pci_tx(struct ieee80211_hw *hw,
+                     struct ieee80211_sta *sta,
+                     struct sk_buff *skb,
+                     struct rtl_tcb_desc *ptcb_desc)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_sta_info *sta_entry = NULL;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct rtl8192_tx_ring *ring;
+       struct rtl_tx_desc *pdesc;
+       struct rtl_tx_buffer_desc *ptx_bd_desc = NULL;
+       u16 idx;
+       u8 own;
+       u8 temp_one = 1;
+       u8 hw_queue = _rtl_mac_to_hwqueue(hw, skb);
+       unsigned long flags;
+       struct ieee80211_hdr *hdr = rtl_get_hdr(skb);
+       __le16 fc = rtl_get_fc(skb);
+       u8 *pda_addr = hdr->addr1;
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       /*ssn */
+       u8 tid = 0;
+       u16 seq_number = 0;
+
+       if (ieee80211_is_mgmt(fc))
+               rtl92e_tx_mgmt_proc(hw, skb);
+
+       if (rtlpriv->psc.sw_ps_enabled) {
+               if (ieee80211_is_data(fc) && !ieee80211_is_nullfunc(fc) &&
+                   !ieee80211_has_pm(fc))
+                       hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
+       }
+
+       rtl92e_action_proc(hw, skb, true);
+
+       if (is_multicast_ether_addr(pda_addr))
+               rtlpriv->stats.txbytesmulticast += skb->len;
+       else if (is_broadcast_ether_addr(pda_addr))
+               rtlpriv->stats.txbytesbroadcast += skb->len;
+       else
+               rtlpriv->stats.txbytesunicast += skb->len;
+
+       spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
+       ring = &rtlpci->tx_ring[hw_queue];
+       if (hw_queue != BEACON_QUEUE) {
+               if (rtlpriv->use_new_trx_flow)
+                       idx = ring->cur_tx_wp;
+               else
+                       idx = (ring->idx + skb_queue_len(&ring->queue)) %
+                             ring->entries;
+       } else {
+               idx = 0;
+       }
+
+       pdesc = &ring->desc[idx];
+
+       if (rtlpriv->use_new_trx_flow) {
+               ptx_bd_desc = &ring->buffer_desc[idx];
+       } else {
+               own = (u8) rtlpriv->cfg->ops->get_desc((u8 *)pdesc,
+                               true, HW_DESC_OWN);
+
+               if ((own == 1) && (hw_queue != BEACON_QUEUE)) {
+                       RT_TRACE(COMP_ERR, DBG_WARNING,
+                                ("No more TX desc@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%d\n",
+                                 hw_queue, ring->idx, idx,
+                                 skb_queue_len(&ring->queue)));
+
+                       spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock,
+                                              flags);
+                       return skb->len;
+               }
+       }
+
+       if (ieee80211_is_data_qos(fc)) {
+               tid = rtl_get_tid(skb);
+               if (sta) {
+                       sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+                       seq_number = (le16_to_cpu(hdr->seq_ctrl) &
+                                     IEEE80211_SCTL_SEQ) >> 4;
+                       seq_number += 1;
+
+                       if (!ieee80211_has_morefrags(hdr->frame_control))
+                               sta_entry->tids[tid].seq_number = seq_number;
+               }
+       }
+
+       if (ieee80211_is_data(fc))
+               rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX);
+
+       rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc,
+                                       (u8 *)ptx_bd_desc, info, sta, skb,
+                                       hw_queue, ptcb_desc);
+
+       __skb_queue_tail(&ring->queue, skb);
+       if (rtlpriv->use_new_trx_flow) {
+               rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, true,
+                                           HW_DESC_OWN, (u8 *)&hw_queue);
+       } else {
+               rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, true,
+                                           HW_DESC_OWN, (u8 *)&temp_one);
+       }
+
+       if ((ring->entries - skb_queue_len(&ring->queue)) < 2 &&
+           hw_queue != BEACON_QUEUE) {
+               RT_TRACE(COMP_ERR, DBG_LOUD,
+                        ("less desc left, stop skb_queue@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%d\n",
+                         hw_queue, ring->idx, idx,
+                         skb_queue_len(&ring->queue)));
+
+               ieee80211_stop_queue(hw, skb_get_queue_mapping(skb));
+       }
+
+       spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
+
+       if (rtlpriv->cfg->ops->tx_polling)
+               rtlpriv->cfg->ops->tx_polling(hw, hw_queue);
+
+       return 0;
+}
+static void rtl_pci_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       u16 i = 0;
+       int queue_id;
+       struct rtl8192_tx_ring *ring;
+
+       if (mac->skip_scan)
+               return;
+
+       for (queue_id = RTL_PCI_MAX_TX_QUEUE_COUNT - 1; queue_id >= 0;) {
+               u32 queue_len;
+               if (((queues >> queue_id) & 0x1) == 0) {
+                       queue_id--;
+                       continue;
+               }
+               ring = &pcipriv->dev.tx_ring[queue_id];
+               queue_len = skb_queue_len(&ring->queue);
+               if (queue_len == 0 || queue_id == BEACON_QUEUE ||
+                   queue_id == TXCMD_QUEUE) {
+                       queue_id--;
+                       continue;
+               } else {
+                       msleep(5);
+                       i++;
+               }
+
+               /* we just wait 1s for all queues */
+               if (rtlpriv->psc.rfpwr_state == ERFOFF ||
+                   is_hal_stop(rtlhal) || i >= 200)
+                       return;
+       }
+}
+
+static void rtl_pci_deinit(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+       _rtl_pci_deinit_trx_ring(hw);
+
+       synchronize_irq(rtlpci->pdev->irq);
+       tasklet_kill(&rtlpriv->works.irq_tasklet);
+
+       flush_workqueue(rtlpriv->works.rtl_wq);
+       destroy_workqueue(rtlpriv->works.rtl_wq);
+}
+
+static int rtl_pci_init(struct ieee80211_hw *hw, struct pci_dev *pdev)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       int err;
+
+       _rtl_pci_init_struct(hw, pdev);
+
+       err = _rtl_pci_init_trx_ring(hw);
+       if (err) {
+               RT_TRACE(COMP_ERR, DBG_EMERG,
+                        ("tx ring initialization failed"));
+               return err;
+       }
+
+       return 1;
+}
+
+static int rtl_pci_start(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       int err = 0;
+
+       RT_TRACE(COMP_INIT, DBG_DMESG, (" rtl_pci_start\n"));
+       rtl92e_pci_reset_trx_ring(hw);
+
+       rtlpriv->rtlhal.driver_is_goingto_unload = false;
+       if (rtlpriv->cfg->ops->get_btc_status()) {
+               rtlpriv->btcoexist.btc_ops->btc_init_variables(rtlpriv);
+               rtlpriv->btcoexist.btc_ops->btc_init_hal_vars(rtlpriv);
+       }
+
+       err = rtlpriv->cfg->ops->hw_init(hw);
+       if (err) {
+               RT_TRACE(COMP_INIT, DBG_DMESG,
+                        ("Failed to config hardware err %x!\n" , err));
+               return err;
+       }
+
+       rtlpriv->cfg->ops->enable_interrupt(hw);
+       RT_TRACE(COMP_INIT, DBG_LOUD, ("enable_interrupt OK\n"));
+
+       rtl92e_init_rx_config(hw);
+
+       /*should after adapter start and interrupt enable. */
+       set_hal_start(rtlhal);
+
+       RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
+
+       rtlpriv->rtlhal.up_first_time = false;
+
+       RT_TRACE(COMP_INIT, DBG_DMESG, ("rtl_pci_start OK\n"));
+       return 0;
+}
+
+static void rtl_pci_stop(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       u8 RFInProgressTimeOut = 0;
+
+       if (rtlpriv->cfg->ops->get_btc_status())
+               rtlpriv->btcoexist.btc_ops->btc_halt_notify();
+
+       /*
+        *should before disable interrrupt&adapter
+        *and will do it immediately.
+        */
+       set_hal_stop(rtlhal);
+
+       rtlpriv->cfg->ops->disable_interrupt(hw);
+
+       spin_lock(&rtlpriv->locks.rf_ps_lock);
+       while (ppsc->rfchange_inprogress) {
+               spin_unlock(&rtlpriv->locks.rf_ps_lock);
+               if (RFInProgressTimeOut > 100) {
+                       spin_lock(&rtlpriv->locks.rf_ps_lock);
+                       break;
+               }
+               mdelay(1);
+               RFInProgressTimeOut++;
+               spin_lock(&rtlpriv->locks.rf_ps_lock);
+       }
+       ppsc->rfchange_inprogress = true;
+       spin_unlock(&rtlpriv->locks.rf_ps_lock);
+
+       rtlpriv->rtlhal.driver_is_goingto_unload = true;
+       rtlpriv->cfg->ops->hw_disable(hw);
+       rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF);
+
+       spin_lock(&rtlpriv->locks.rf_ps_lock);
+       ppsc->rfchange_inprogress = false;
+       spin_unlock(&rtlpriv->locks.rf_ps_lock);
+
+       rtl_pci_enable_aspm(hw);
+}
+
+static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
+                                 struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       struct pci_dev *bridge_pdev = pdev->bus->self;
+       u16 venderid;
+       u16 deviceid;
+       u8 revisionid;
+       u16 irqline;
+       u8 tmp;
+
+       venderid = pdev->vendor;
+       deviceid = pdev->device;
+       pci_read_config_byte(pdev, 0x8, &revisionid);
+       pci_read_config_word(pdev, 0x3C, &irqline);
+
+       if (deviceid == RTL_PCI_8192_DID ||
+           deviceid == RTL_PCI_0044_DID ||
+           deviceid == RTL_PCI_0047_DID ||
+           deviceid == RTL_PCI_8192SE_DID ||
+           deviceid == RTL_PCI_8174_DID ||
+           deviceid == RTL_PCI_8173_DID ||
+           deviceid == RTL_PCI_8172_DID ||
+           deviceid == RTL_PCI_8171_DID) {
+               switch (revisionid) {
+               case RTL_PCI_REVISION_ID_8192PCIE:
+                       RT_TRACE(COMP_INIT, DBG_DMESG,
+                                ("8192E is found but not supported now-vid/did=%x/%x\n",
+                                 venderid, deviceid));
+                       rtlhal->hw_type = HARDWARE_TYPE_RTL8192E;
+                       return false;
+                       break;
+               case RTL_PCI_REVISION_ID_8192SE:
+                       RT_TRACE(COMP_INIT, DBG_DMESG,
+                                ("8192SE is found - vid/did=%x/%x\n",
+                                 venderid, deviceid));
+                       rtlhal->hw_type = HARDWARE_TYPE_RTL8192SE;
+                       break;
+               default:
+                       RT_TRACE(COMP_ERR, DBG_WARNING,
+                                ("Err: Unknown device - vid/did=%x/%x\n",
+                                 venderid, deviceid));
+                       rtlhal->hw_type = HARDWARE_TYPE_RTL8192SE;
+                       break;
+               }
+       } else if (deviceid == RTL_PCI_8723AE_DID) {
+               rtlhal->hw_type = HARDWARE_TYPE_RTL8723AE;
+               RT_TRACE(COMP_INIT, DBG_DMESG,
+                        ("8723AE PCI-E is found - vid/did=%x/%x\n",
+                         venderid, deviceid));
+       } else if (deviceid == RTL_PCI_8192CET_DID ||
+                  deviceid == RTL_PCI_8192CE_DID ||
+                  deviceid == RTL_PCI_8191CE_DID ||
+                  deviceid == RTL_PCI_8188CE_DID) {
+               rtlhal->hw_type = HARDWARE_TYPE_RTL8192CE;
+               RT_TRACE(COMP_INIT, DBG_DMESG,
+                        ("8192C PCI-E is found - vid/did=%x/%x\n",
+                         venderid, deviceid));
+       } else if (deviceid == RTL_PCI_8192DE_DID ||
+                  deviceid == RTL_PCI_8192DE_DID2) {
+               rtlhal->hw_type = HARDWARE_TYPE_RTL8192DE;
+               RT_TRACE(COMP_INIT, DBG_DMESG,
+                        ("8192D PCI-E is found - vid/did=%x/%x\n",
+                         venderid, deviceid));
+       } else if (deviceid == RTL_PCI_8188EE_DID) {
+                       rtlhal->hw_type = HARDWARE_TYPE_RTL8188EE;
+                       RT_TRACE(COMP_INIT , DBG_LOUD,
+                                ("Find adapter, Hardware type is 8188EE\n"));
+       } else if (deviceid == RTL_PCI_8723BE_DID) {
+                       rtlhal->hw_type = HARDWARE_TYPE_RTL8723BE;
+                       RT_TRACE(COMP_INIT , DBG_LOUD,
+                                ("Find adapter, Hardware type is 8723BE\n"));
+       } else if (deviceid == RTL_PCI_8192EE_DID) {
+                       rtlhal->hw_type = HARDWARE_TYPE_RTL8192EE;
+                       RT_TRACE(COMP_INIT , DBG_LOUD,
+                                ("Find adapter, Hardware type is 8192EE\n"));
+       } else if (deviceid == RTL_PCI_8821AE_DID) {
+                       rtlhal->hw_type = HARDWARE_TYPE_RTL8821AE;
+                       RT_TRACE(COMP_INIT , DBG_LOUD,
+                                ("Find adapter, Hardware type is 8821AE\n"));
+       } else if (deviceid == RTL_PCI_8812AE_DID) {
+                       rtlhal->hw_type = HARDWARE_TYPE_RTL8812AE;
+                       RT_TRACE(COMP_INIT , DBG_LOUD,
+                                ("Find adapter, Hardware type is 8812AE\n"));
+       } else {
+               RT_TRACE(COMP_ERR, DBG_WARNING,
+                        ("Err: Unknown device - vid/did=%x/%x\n",
+                         venderid, deviceid));
+
+               rtlhal->hw_type = RTL_DEFAULT_HARDWARE_TYPE;
+       }
+
+       if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192DE) {
+               if (revisionid == 0 || revisionid == 1) {
+                       if (revisionid == 0) {
+                               RT_TRACE(COMP_INIT, DBG_LOUD,
+                                        ("Find 92DE MAC0.\n"));
+                               rtlhal->interfaceindex = 0;
+                       } else if (revisionid == 1) {
+                               RT_TRACE(COMP_INIT, DBG_LOUD,
+                                        ("Find 92DE MAC1.\n"));
+                               rtlhal->interfaceindex = 1;
+                       }
+               } else {
+                       RT_TRACE(COMP_INIT, DBG_LOUD,
+                                ("Unknown device - VendorID/DeviceID=%x/%x, Revision=%x\n",
+                                 venderid, deviceid, revisionid));
+                       rtlhal->interfaceindex = 0;
+               }
+       }
+
+       /* 92ee use new trx flow */
+       if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192EE)
+               rtlpriv->use_new_trx_flow = true;
+       else
+               rtlpriv->use_new_trx_flow = false;
+
+       /*find bus info */
+       pcipriv->ndis_adapter.busnumber = pdev->bus->number;
+       pcipriv->ndis_adapter.devnumber = PCI_SLOT(pdev->devfn);
+       pcipriv->ndis_adapter.funcnumber = PCI_FUNC(pdev->devfn);
+
+       /*find bridge info */
+       pcipriv->ndis_adapter.pcibridge_vendor = PCI_BRIDGE_VENDOR_UNKNOWN;
+       /* some ARM have no bridge_pdev and will crash here
+        * so we should check if bridge_pdev is NULL */
+       if (bridge_pdev) {
+               pcipriv->ndis_adapter.pcibridge_vendorid = bridge_pdev->vendor;
+               for (tmp = 0; tmp < PCI_BRIDGE_VENDOR_MAX; tmp++) {
+                       if (bridge_pdev->vendor == pcibridge_vendors[tmp]) {
+                               pcipriv->ndis_adapter.pcibridge_vendor = tmp;
+                               RT_TRACE(COMP_INIT, DBG_DMESG,
+                                        ("Pci Bridge Vendor is found index: %d\n",
+                                         tmp));
+                               break;
+                       }
+               }
+       }
+
+       if (pcipriv->ndis_adapter.pcibridge_vendor !=
+           PCI_BRIDGE_VENDOR_UNKNOWN) {
+               pcipriv->ndis_adapter.pcibridge_busnum =
+                   bridge_pdev->bus->number;
+               pcipriv->ndis_adapter.pcibridge_devnum =
+                   PCI_SLOT(bridge_pdev->devfn);
+               pcipriv->ndis_adapter.pcibridge_funcnum =
+                   PCI_FUNC(bridge_pdev->devfn);
+               pcipriv->ndis_adapter.pcicfg_addrport =
+                   (pcipriv->ndis_adapter.pcibridge_busnum << 16) |
+                   (pcipriv->ndis_adapter.pcibridge_devnum << 11) |
+                   (pcipriv->ndis_adapter.pcibridge_funcnum << 8) | (1 << 31);
+               pcipriv->ndis_adapter.pcibridge_pciehdr_offset =
+                   pci_pcie_cap(bridge_pdev);
+               pcipriv->ndis_adapter.num4bytes =
+                   (pcipriv->ndis_adapter.pcibridge_pciehdr_offset + 0x10) / 4;
+
+               rtl_pci_get_linkcontrol_field(hw);
+
+               if (pcipriv->ndis_adapter.pcibridge_vendor ==
+                   PCI_BRIDGE_VENDOR_AMD) {
+                       pcipriv->ndis_adapter.amd_l1_patch =
+                           rtl_pci_get_amd_l1_patch(hw);
+               }
+       }
+
+       RT_TRACE(COMP_INIT, DBG_DMESG,
+                ("pcidev busnumber:devnumber:funcnumber:vendor:link_ctl %d:%d:%d:%x:%x\n",
+                 pcipriv->ndis_adapter.busnumber,
+                 pcipriv->ndis_adapter.devnumber,
+                 pcipriv->ndis_adapter.funcnumber,
+                 pdev->vendor, pcipriv->ndis_adapter.linkctrl_reg));
+
+       RT_TRACE(COMP_INIT, DBG_DMESG,
+                ("pci_bridge busnumber:devnumber:funcnumber:vendor:pcie_cap:link_ctl_reg:amd %d:%d:%d:%x:%x:%x:%x\n",
+                 pcipriv->ndis_adapter.pcibridge_busnum,
+                 pcipriv->ndis_adapter.pcibridge_devnum,
+                 pcipriv->ndis_adapter.pcibridge_funcnum,
+                 pcibridge_vendors[pcipriv->ndis_adapter.pcibridge_vendor],
+                 pcipriv->ndis_adapter.pcibridge_pciehdr_offset,
+                 pcipriv->ndis_adapter.pcibridge_linkctrlreg,
+                 pcipriv->ndis_adapter.amd_l1_patch));
+
+       rtl_pci_parse_configuration(pdev, hw);
+       list_add_tail(&rtlpriv->list, &rtlpriv->glb_var->glb_priv_list);
+       return true;
+}
+
+static int rtl_pci_intr_mode_msi(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(pcipriv);
+       int ret;
+       ret = pci_enable_msi(rtlpci->pdev);
+       if (ret < 0)
+               return ret;
+
+       ret = request_irq(rtlpci->pdev->irq, &_rtl_pci_interrupt,
+                         IRQF_SHARED, KBUILD_MODNAME, hw);
+       if (ret < 0) {
+               pci_disable_msi(rtlpci->pdev);
+               return ret;
+       }
+
+       rtlpci->using_msi = true;
+
+       RT_TRACE(COMP_INIT|COMP_INTR, DBG_DMESG, ("MSI Interrupt Mode!\n"));
+       return 0;
+}
+
+static int rtl_pci_intr_mode_legacy(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(pcipriv);
+       int ret;
+
+       ret = request_irq(rtlpci->pdev->irq, &_rtl_pci_interrupt,
+                         IRQF_SHARED, KBUILD_MODNAME, hw);
+       if (ret < 0)
+               return ret;
+
+       rtlpci->using_msi = false;
+       RT_TRACE(COMP_INIT|COMP_INTR, DBG_DMESG,
+                ("Pin-based Interrupt Mode!\n"));
+       return 0;
+}
+
+static int rtl_pci_intr_mode_decide(struct ieee80211_hw *hw)
+{
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(pcipriv);
+       int ret;
+       if (rtlpci->msi_support) {
+               ret = rtl_pci_intr_mode_msi(hw);
+               if (ret < 0)
+                       ret = rtl_pci_intr_mode_legacy(hw);
+       } else {
+               ret = rtl_pci_intr_mode_legacy(hw);
+       }
+       return ret;
+}
+
+/* this is used for other modules get
+ * hw pointer in rtl_pci_get_hw_pointer */
+static struct ieee80211_hw *hw_export;
+
+int stg_rtl_pci_probe(struct pci_dev *pdev,
+                     const struct pci_device_id *id)
+{
+       struct ieee80211_hw *hw = NULL;
+       struct rtl_priv *rtlpriv = NULL;
+       struct rtl_pci_priv *pcipriv = NULL;
+       struct rtl_pci *rtlpci;
+       unsigned long pmem_start, pmem_len, pmem_flags;
+       int err;
+
+       err = pci_enable_device(pdev);
+       if (err) {
+               RT_ASSERT(false,
+                         ("%s : Cannot enable new PCI device\n",
+                          pci_name(pdev)));
+               return err;
+       }
+
+       if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
+               if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
+                       RT_ASSERT(false,
+                                 ("Unable to obtain 32bit DMA for consistent allocations\n"));
+                       pci_disable_device(pdev);
+                       return -ENOMEM;
+               }
+       }
+
+       pci_set_master(pdev);
+
+       hw = ieee80211_alloc_hw(sizeof(struct rtl_pci_priv) +
+                               sizeof(struct rtl_priv), &rtl92e_ops);
+       if (!hw) {
+               RT_ASSERT(false,
+                         ("%s : ieee80211 alloc failed\n", pci_name(pdev)));
+               err = -ENOMEM;
+               goto fail1;
+       }
+       hw_export = hw;
+
+       SET_IEEE80211_DEV(hw, &pdev->dev);
+       pci_set_drvdata(pdev, hw);
+
+       rtlpriv = hw->priv;
+       pcipriv = (void *)rtlpriv->priv;
+       pcipriv->dev.pdev = pdev;
+
+       /* init cfg & intf_ops */
+       rtlpriv->rtlhal.interface = INTF_PCI;
+       rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_data);
+       rtlpriv->intf_ops = &rtl92e_pci_ops;
+       rtlpriv->glb_var = &global_var;
+
+       /*
+        *init dbgp flags before all
+        *other functions, because we will
+        *use it in other funtions like
+        *RT_TRACE/RT_PRINT/RTL_PRINT_DATA
+        *you can not use these macro
+        *before this
+        */
+       rtl92e_dbgp_flag_init(hw);
+
+       /* MEM map */
+       err = pci_request_regions(pdev, KBUILD_MODNAME);
+       if (err) {
+               RT_ASSERT(false, ("Can't obtain PCI resources\n"));
+               return err;
+       }
+
+       pmem_start = pci_resource_start(pdev, rtlpriv->cfg->bar_id);
+       pmem_len = pci_resource_len(pdev, rtlpriv->cfg->bar_id);
+       pmem_flags = pci_resource_flags(pdev, rtlpriv->cfg->bar_id);
+
+       /*shared mem start */
+       rtlpriv->io.pci_mem_start =
+                       (unsigned long)pci_iomap(pdev,
+                       rtlpriv->cfg->bar_id, pmem_len);
+       if (rtlpriv->io.pci_mem_start == 0) {
+               RT_ASSERT(false, ("Can't map PCI mem\n"));
+               goto fail2;
+       }
+
+       RT_TRACE(COMP_INIT, DBG_DMESG,
+                ("mem mapped space: start: 0x%08lx len:%08lx flags:%08lx, after map:0x%08lx\n",
+                 pmem_start, pmem_len, pmem_flags,
+                 rtlpriv->io.pci_mem_start));
+
+       /* Disable Clk Request */
+       pci_write_config_byte(pdev, 0x81, 0);
+       /* leave D3 mode */
+       pci_write_config_byte(pdev, 0x44, 0);
+       pci_write_config_byte(pdev, 0x04, 0x06);
+       pci_write_config_byte(pdev, 0x04, 0x07);
+
+       /* The next statement is needed when built as single module */
+       rtl_core_module_init();
+
+       /* find adapter */
+       /* if chip not support, will return false */
+       if (!_rtl_pci_find_adapter(pdev, hw))
+               goto fail3;
+
+       /* Init IO handler */
+       _rtl_pci_io_handler_init(&pdev->dev, hw);
+
+       /*like read eeprom and so on */
+       rtlpriv->cfg->ops->read_eeprom_info(hw);
+
+       if (rtlpriv->cfg->ops->init_sw_vars(hw)) {
+               RT_TRACE(COMP_ERR, DBG_EMERG, ("Can't init_sw_vars.\n"));
+               goto fail3;
+       }
+
+       rtlpriv->cfg->ops->init_sw_leds(hw);
+
+       /*aspm */
+       rtl_pci_init_aspm(hw);
+
+       /* Init mac80211 sw */
+       err = rtl92e_init_core(hw);
+       if (err) {
+               RT_TRACE(COMP_ERR, DBG_EMERG,
+                        ("Can't allocate sw for mac80211.\n"));
+               goto fail3;
+       }
+
+       /* Init PCI sw */
+       err = !rtl_pci_init(hw, pdev);
+       if (err) {
+               RT_TRACE(COMP_ERR, DBG_EMERG, ("Failed to init PCI.\n"));
+               goto fail3;
+       }
+
+       err = ieee80211_register_hw(hw);
+       if (err) {
+               RT_TRACE(COMP_ERR, DBG_EMERG,
+                        ("Can't register mac80211 hw.\n"));
+               goto fail3;
+       } else {
+               rtlpriv->mac80211.mac80211_registered = 1;
+       }
+       /* the wiphy must have been registed to
+        * cfg80211 prior to regulatory_hint */
+       if (regulatory_hint(hw->wiphy, rtlpriv->regd.alpha2))
+               RT_TRACE(COMP_ERR, DBG_WARNING, ("regulatory_hint fail\n"));
+
+       /* add for prov */
+       rtl_proc_add_one(hw);
+
+       /*init rfkill */
+       rtl92e_init_rfkill(hw);
+
+       rtlpci = rtl_pcidev(pcipriv);
+       err = rtl_pci_intr_mode_decide(hw);
+       if (err) {
+               RT_TRACE(COMP_INIT, DBG_DMESG,
+                        ("%s: failed to register IRQ handler\n",
+                         wiphy_name(hw->wiphy)));
+               goto fail3;
+       } else {
+               rtlpci->irq_alloc = 1;
+       }
+
+       set_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status);
+       return 0;
+
+fail3:
+       pci_set_drvdata(pdev, NULL);
+       rtl92e_deinit_core(hw);
+       ieee80211_free_hw(hw);
+
+       if (rtlpriv->io.pci_mem_start != 0)
+               pci_iounmap(pdev, (void __iomem *)rtlpriv->io.pci_mem_start);
+
+fail2:
+       pci_release_regions(pdev);
+
+fail1:
+
+       pci_disable_device(pdev);
+
+       return -ENODEV;
+}
+EXPORT_SYMBOL(stg_rtl_pci_probe);
+
+struct ieee80211_hw *rtl_pci_get_hw_pointer(void)
+{
+       return hw_export;
+}
+EXPORT_SYMBOL(rtl_pci_get_hw_pointer);
+
+void stg_rtl_pci_disconnect(struct pci_dev *pdev)
+{
+       struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(pcipriv);
+       struct rtl_mac *rtlmac = rtl_mac(rtlpriv);
+
+       clear_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status);
+
+       /* add for prov */
+       rtl_proc_remove_one(hw);
+
+       /*ieee80211_unregister_hw will call ops_stop */
+       if (rtlmac->mac80211_registered == 1) {
+               ieee80211_unregister_hw(hw);
+               rtlmac->mac80211_registered = 0;
+       } else {
+               rtl92e_deinit_deferred_work(hw);
+               rtlpriv->intf_ops->adapter_stop(hw);
+       }
+
+       /*deinit rfkill */
+       rtl92e_deinit_rfkill(hw);
+
+       rtl_pci_deinit(hw);
+       rtl92e_deinit_core(hw);
+       rtlpriv->cfg->ops->deinit_sw_vars(hw);
+
+       if (rtlpci->irq_alloc) {
+               synchronize_irq(rtlpci->pdev->irq);
+               free_irq(rtlpci->pdev->irq, hw);
+               rtlpci->irq_alloc = 0;
+       }
+
+       if (rtlpci->using_msi)
+               pci_disable_msi(rtlpci->pdev);
+
+       list_del(&rtlpriv->list);
+       if (rtlpriv->io.pci_mem_start != 0) {
+               pci_iounmap(pdev, (void __iomem *)rtlpriv->io.pci_mem_start);
+               pci_release_regions(pdev);
+       }
+
+       pci_disable_device(pdev);
+
+       rtl_pci_disable_aspm(hw);
+
+       pci_set_drvdata(pdev, NULL);
+
+       ieee80211_free_hw(hw);
+}
+EXPORT_SYMBOL(stg_rtl_pci_disconnect);
+
+/***************************************
+kernel pci power state define:
+PCI_D0         ((pci_power_t __force) 0)
+PCI_D1         ((pci_power_t __force) 1)
+PCI_D2         ((pci_power_t __force) 2)
+PCI_D3hot      ((pci_power_t __force) 3)
+PCI_D3cold     ((pci_power_t __force) 4)
+PCI_UNKNOWN    ((pci_power_t __force) 5)
+
+This function is called when system
+goes into suspend state mac80211 will
+call rtl_mac_stop() from the mac80211
+suspend function first, So there is
+no need to call hw_disable here.
+****************************************/
+int stg_rtl_pci_suspend(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       rtlpriv->cfg->ops->hw_suspend(hw);
+       rtl92e_deinit_rfkill(hw);
+
+       return 0;
+}
+EXPORT_SYMBOL(stg_rtl_pci_suspend);
+
+int stg_rtl_pci_resume(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       rtlpriv->cfg->ops->hw_resume(hw);
+       rtl92e_init_rfkill(hw);
+
+       return 0;
+}
+EXPORT_SYMBOL(stg_rtl_pci_resume);
+
+struct rtl_intf_ops rtl92e_pci_ops = {
+       .read92e_efuse_byte = read92e_efuse_byte,
+       .adapter_start = rtl_pci_start,
+       .adapter_stop = rtl_pci_stop,
+       .check_buddy_priv = rtl_pci_check_buddy_priv,
+       .adapter_tx = rtl_pci_tx,
+       .flush = rtl_pci_flush,
+       .reset_trx_ring = rtl92e_pci_reset_trx_ring,
+       .waitq_insert = rtl_pci_tx_chk_waitq_insert,
+
+       .disable_aspm = rtl_pci_disable_aspm,
+       .enable_aspm = rtl_pci_enable_aspm,
+};
diff --git a/drivers/staging/rtl8192ee/pci.h b/drivers/staging/rtl8192ee/pci.h
new file mode 100644 (file)
index 0000000..62c23a7
--- /dev/null
@@ -0,0 +1,342 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL_PCI_H__
+#define __RTL_PCI_H__
+
+#include <linux/pci.h>
+/*
+1: MSDU packet queue,
+2: Rx Command Queue
+*/
+#define RTL_PCI_RX_MPDU_QUEUE                  0
+#define RTL_PCI_RX_CMD_QUEUE                   1
+#define RTL_PCI_MAX_RX_QUEUE                   2
+
+#define RTL_PCI_MAX_RX_COUNT                   512/*64*/
+#define RTL_PCI_MAX_TX_QUEUE_COUNT             9
+
+#define RT_TXDESC_NUM                          128
+#define TX_DESC_NUM_92E                                512
+#define RT_TXDESC_NUM_BE_QUEUE                 256
+
+#define BK_QUEUE                               0
+#define BE_QUEUE                               1
+#define VI_QUEUE                               2
+#define VO_QUEUE                               3
+#define BEACON_QUEUE                           4
+#define TXCMD_QUEUE                            5
+#define MGNT_QUEUE                             6
+#define HIGH_QUEUE                             7
+#define HCCA_QUEUE                             8
+
+#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 INTEL_VENDOR_ID                                0x8086
+#define SIS_VENDOR_ID                          0x1039
+#define ATI_VENDOR_ID                          0x1002
+#define ATI_DEVICE_ID                          0x7914
+#define AMD_VENDOR_ID                          0x1022
+
+#define PCI_MAX_BRIDGE_NUMBER                  255
+#define PCI_MAX_DEVICES                                32
+#define PCI_MAX_FUNCTION                       8
+
+#define PCI_CONF_ADDRESS       0x0CF8  /*PCI Configuration Space Address */
+#define PCI_CONF_DATA          0x0CFC  /*PCI Configuration Space Data */
+
+#define PCI_CLASS_BRIDGE_DEV           0x06
+#define PCI_SUBCLASS_BR_PCI_TO_PCI     0x04
+#define PCI_CAPABILITY_ID_PCI_EXPRESS  0x10
+#define PCI_CAP_ID_EXP                 0x10
+
+#define U1DONTCARE                     0xFF
+#define U2DONTCARE                     0xFFFF
+#define U4DONTCARE                     0xFFFFFFFF
+
+#define RTL_PCI_8192_DID       0x8192  /*8192 PCI-E */
+#define RTL_PCI_8192SE_DID     0x8192  /*8192 SE */
+#define RTL_PCI_8174_DID       0x8174  /*8192 SE */
+#define RTL_PCI_8173_DID       0x8173  /*8191 SE Crab */
+#define RTL_PCI_8172_DID       0x8172  /*8191 SE RE */
+#define RTL_PCI_8171_DID       0x8171  /*8191 SE Unicron */
+#define RTL_PCI_0045_DID       0x0045  /*8190 PCI for Ceraga */
+#define RTL_PCI_0046_DID       0x0046  /*8190 Cardbus for Ceraga */
+#define RTL_PCI_0044_DID       0x0044  /*8192e PCIE for Ceraga */
+#define RTL_PCI_0047_DID       0x0047  /*8192e Express Card for Ceraga */
+#define RTL_PCI_700F_DID       0x700F
+#define RTL_PCI_701F_DID       0x701F
+#define RTL_PCI_DLINK_DID      0x3304
+#define RTL_PCI_8723AE_DID     0x8723  /*8723e */
+#define RTL_PCI_8192CET_DID    0x8191  /*8192ce */
+#define RTL_PCI_8192CE_DID     0x8178  /*8192ce */
+#define RTL_PCI_8191CE_DID     0x8177  /*8192ce */
+#define RTL_PCI_8188CE_DID     0x8176  /*8192ce */
+#define RTL_PCI_8192CU_DID     0x8191  /*8192ce */
+#define RTL_PCI_8192DE_DID     0x8193  /*8192de */
+#define RTL_PCI_8192DE_DID2    0x002B  /*92DE*/
+#define RTL_PCI_8188EE_DID     0x8179  /*8188ee*/
+#define RTL_PCI_8723BE_DID     0xB723  /*8723be*/
+#define RTL_PCI_8192EE_DID     0x818B  /*8192ee*/
+#define RTL_PCI_8821AE_DID     0x8821  /*8821ae*/
+#define RTL_PCI_8812AE_DID     0x8812  /*8812ae*/
+
+/*8192 support 16 pages of IO registers*/
+#define RTL_MEM_MAPPED_IO_RANGE_8190PCI                0x1000
+#define RTL_MEM_MAPPED_IO_RANGE_8192PCIE       0x4000
+#define RTL_MEM_MAPPED_IO_RANGE_8192SE         0x4000
+#define RTL_MEM_MAPPED_IO_RANGE_8192CE         0x4000
+#define RTL_MEM_MAPPED_IO_RANGE_8192DE         0x4000
+
+#define RTL_PCI_REVISION_ID_8190PCI            0x00
+#define RTL_PCI_REVISION_ID_8192PCIE           0x01
+#define RTL_PCI_REVISION_ID_8192SE             0x10
+#define RTL_PCI_REVISION_ID_8192CE             0x1
+#define RTL_PCI_REVISION_ID_8192DE             0x0
+
+#define RTL_DEFAULT_HARDWARE_TYPE      HARDWARE_TYPE_RTL8192CE
+
+enum pci_bridge_vendor {
+       PCI_BRIDGE_VENDOR_INTEL = 0x0,  /*0b'0000,0001 */
+       PCI_BRIDGE_VENDOR_ATI,          /*0b'0000,0010*/
+       PCI_BRIDGE_VENDOR_AMD,          /*0b'0000,0100*/
+       PCI_BRIDGE_VENDOR_SIS,          /*0b'0000,1000*/
+       PCI_BRIDGE_VENDOR_UNKNOWN,      /*0b'0100,0000*/
+       PCI_BRIDGE_VENDOR_MAX,
+};
+
+struct rtl_pci_capabilities_header {
+       u8 capability_id;
+       u8 next;
+};
+
+/* In new TRX flow, Buffer_desc is new concept
+  * But TX wifi info == TX descriptor in old flow
+  * RX wifi info == RX descriptor in old flow */
+struct rtl_tx_buffer_desc {
+#if (RTL8192EE_SEG_NUM == 2)
+       u32 dword[2*(DMA_IS_64BIT + 1)*8]; /*seg = 8*/
+#elif (RTL8192EE_SEG_NUM == 1)
+       u32 dword[2*(DMA_IS_64BIT + 1)*4]; /*seg = 4*/
+#elif (RTL8192EE_SEG_NUM == 0)
+       u32 dword[2*(DMA_IS_64BIT + 1)*2]; /*seg = 2*/
+#endif
+} __packed;
+
+struct rtl_tx_desc {/*old: tx desc new: tx wifi info*/
+       u32 dword[16];
+} __packed;
+
+struct rtl_rx_buffer_desc { /*rx buffer desc*/
+       u32 dword[2];
+} __packed;
+
+struct rtl_rx_desc { /*old: rx desc new: rx wifi info*/
+       u32 dword[8];
+} __packed;
+
+struct rtl_tx_cmd_desc {
+       u32 dword[16];
+} __packed;
+
+struct rtl8192_tx_ring {
+       struct rtl_tx_desc *desc; /*tx desc / tx wifi info*/
+       dma_addr_t dma; /*tx desc dma memory / tx wifi info dma memory*/
+       unsigned int idx;
+       unsigned int entries;
+       struct sk_buff_head queue;
+       /*add for new trx flow*/
+       struct rtl_tx_buffer_desc *buffer_desc; /*tx buffer descriptor*/
+       dma_addr_t buffer_desc_dma; /*tx bufferd desc dma memory*/
+       u16 avl_desc; /* available_desc_to_write */
+       u16 cur_tx_wp; /* current_tx_write_point */
+       u16 cur_tx_rp; /* current_tx_read_point */
+};
+
+struct rtl8192_rx_ring {
+       struct rtl_rx_desc *desc;/*for old trx flow, not uesd in new trx*/
+       /*dma matches either 'desc' or 'buffer_desc'*/
+       dma_addr_t dma;
+       unsigned int idx;
+       struct sk_buff *rx_buf[RTL_PCI_MAX_RX_COUNT];
+       /*add for new trx flow*/
+       struct rtl_rx_buffer_desc *buffer_desc; /*rx buffer descriptor*/
+       u16 next_rx_rp; /* next_rx_read_point */
+};
+
+struct rtl_pci {
+       struct pci_dev *pdev;
+       bool irq_enabled;
+
+       /*Tx */
+       struct rtl8192_tx_ring tx_ring[RTL_PCI_MAX_TX_QUEUE_COUNT];
+       int txringcount[RTL_PCI_MAX_TX_QUEUE_COUNT];
+       u32 transmit_config;
+
+       /*Rx */
+       struct rtl8192_rx_ring rx_ring[RTL_PCI_MAX_RX_QUEUE];
+       int rxringcount;
+       u16 rxbuffersize;
+       u32 receive_config;
+
+       /*irq */
+       u8 irq_alloc;
+       u32 irq_mask[2];
+       u32 sys_irq_mask;
+
+       /*Bcn control register setting */
+       u32 reg_bcn_ctrl_val;
+
+        /*ASPM*/ u8 const_pci_aspm;
+       u8 const_amdpci_aspm;
+       u8 const_hwsw_rfoff_d3;
+       u8 const_support_pciaspm;
+       /*pci-e bridge */
+       u8 const_hostpci_aspm_setting;
+       /*pci-e device */
+       u8 const_devicepci_aspm_setting;
+       /*If it supports ASPM, Offset[560h] = 0x40,
+          otherwise Offset[560h] = 0x00. */
+       bool b_support_aspm;
+       bool b_support_backdoor;
+
+       /*QOS & EDCA */
+       enum acm_method acm_method;
+
+       u16 shortretry_limit;
+       u16 longretry_limit;
+
+       /* MSI support */
+       bool msi_support;
+       bool using_msi;
+};
+
+struct mp_adapter {
+       u8 linkctrl_reg;
+
+       u8 busnumber;
+       u8 devnumber;
+       u8 funcnumber;
+
+       u8 pcibridge_busnum;
+       u8 pcibridge_devnum;
+       u8 pcibridge_funcnum;
+
+       u8 pcibridge_vendor;
+       u16 pcibridge_vendorid;
+       u16 pcibridge_deviceid;
+
+       u32 pcicfg_addrport;
+       u8 num4bytes;
+
+       u8 pcibridge_pciehdr_offset;
+       u8 pcibridge_linkctrlreg;
+
+       bool amd_l1_patch;
+};
+
+struct rtl_pci_priv {
+       struct rtl_pci dev;
+       struct mp_adapter ndis_adapter;
+       struct rtl_led_ctl ledctl;
+       struct bt_coexist_info btcoexist;
+};
+
+#define rtl_pcipriv(hw)                (((struct rtl_pci_priv *)(rtl_priv(hw))->priv))
+#define rtl_pcidev(pcipriv)    (&((pcipriv)->dev))
+
+int rtl92e_pci_reset_trx_ring(struct ieee80211_hw *hw);
+
+extern struct rtl_intf_ops rtl92e_pci_ops;
+
+int stg_rtl_pci_probe(struct pci_dev *pdev,
+                     const struct pci_device_id *id);
+void stg_rtl_pci_disconnect(struct pci_dev *pdev);
+int stg_rtl_pci_suspend(struct device *dev);
+int stg_rtl_pci_resume(struct device *dev);
+
+static inline u8 pci_read8_sync(struct rtl_priv *rtlpriv, u32 addr)
+{
+       return 0xff & readb((u8 __iomem *)rtlpriv->io.pci_mem_start + addr);
+}
+
+static inline u16 pci_read16_sync(struct rtl_priv *rtlpriv, u32 addr)
+{
+       return readw((u8 __iomem *)rtlpriv->io.pci_mem_start + addr);
+}
+
+static inline u32 pci_read32_sync(struct rtl_priv *rtlpriv, u32 addr)
+{
+       return readl((u8 __iomem *)rtlpriv->io.pci_mem_start + addr);
+}
+
+static inline void pci_write8_async(struct rtl_priv *rtlpriv, u32 addr, u8 val)
+{
+       writeb(val, (u8 __iomem *)rtlpriv->io.pci_mem_start + addr);
+}
+
+static inline void pci_write16_async(struct rtl_priv *rtlpriv,
+                                    u32 addr, u16 val)
+{
+       writew(val, (u8 __iomem *)rtlpriv->io.pci_mem_start + addr);
+}
+
+static inline void pci_write32_async(struct rtl_priv *rtlpriv,
+                                    u32 addr, u32 val)
+{
+       writel(val, (u8 __iomem *)rtlpriv->io.pci_mem_start + addr);
+}
+
+static inline void rtl_pci_raw_write_port_ulong(u32 port, u32 val)
+{
+       outl(val, port);
+}
+
+static inline void rtl_pci_raw_write_port_uchar(u32 port, u8 val)
+{
+       outb(val, port);
+}
+
+static inline void rtl_pci_raw_read_port_uchar(u32 port, u8 *pval)
+{
+       *pval = inb(port);
+}
+
+static inline void rtl_pci_raw_read_port_ushort(u32 port, u16 *pval)
+{
+       *pval = inw(port);
+}
+
+static inline void rtl_pci_raw_read_port_ulong(u32 port, u32 *pval)
+{
+       *pval = inl(port);
+}
+
+#endif
diff --git a/drivers/staging/rtl8192ee/ps.c b/drivers/staging/rtl8192ee/ps.c
new file mode 100644 (file)
index 0000000..90c3fc2
--- /dev/null
@@ -0,0 +1,983 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "wifi.h"
+#include "base.h"
+#include "ps.h"
+#include "btcoexist/rtl_btc.h"
+
+bool stg_rtl_ps_enable_nic(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       bool init_status = true;
+
+       /*<1> reset trx ring */
+       if (rtlhal->interface == INTF_PCI)
+               rtlpriv->intf_ops->reset_trx_ring(hw);
+
+       if (is_hal_stop(rtlhal))
+               RT_TRACE(COMP_ERR, DBG_WARNING, ("Driver is already down!\n"));
+
+       /*<2> Enable Adapter */
+       rtlpriv->cfg->ops->hw_init(hw);
+       RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
+       /*init_status = false; */
+
+       /*<3> Enable Interrupt */
+       rtlpriv->cfg->ops->enable_interrupt(hw);
+
+       /*<enable timer> */
+       rtl92e_watch_dog_timer_callback((unsigned long)hw);
+
+       return init_status;
+}
+EXPORT_SYMBOL(stg_rtl_ps_enable_nic);
+
+bool stg_rtl_ps_disable_nic(struct ieee80211_hw *hw)
+{
+       bool status = true;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       /*<1> Stop all timer */
+       rtl92e_deinit_deferred_work(hw);
+
+       /*<2> Disable Interrupt */
+       rtlpriv->cfg->ops->disable_interrupt(hw);
+
+       /*<3> Disable Adapter */
+       rtlpriv->cfg->ops->hw_disable(hw);
+
+       return status;
+}
+EXPORT_SYMBOL(stg_rtl_ps_disable_nic);
+
+bool stg_rtl_ps_set_rf_state(struct ieee80211_hw *hw,
+                            enum rf_pwrstate state_toset,
+                            u32 changesource, bool protect_or_not)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       enum rf_pwrstate rtstate;
+       bool b_actionallowed = false;
+       u16 rfwait_cnt = 0;
+
+       /*protect_or_not = true; */
+
+       if (protect_or_not)
+               goto no_protect;
+
+       /*
+        *Only one thread can change
+        *the RF state at one time, and others
+        *should wait to be executed.
+        */
+       while (true) {
+               spin_lock(&rtlpriv->locks.rf_ps_lock);
+               if (ppsc->rfchange_inprogress) {
+                       spin_unlock(&rtlpriv->locks.rf_ps_lock);
+
+                       RT_TRACE(COMP_ERR, DBG_WARNING,
+                                ("RF Change in progress! Wait to set..state_toset(%d)\n",
+                                 state_toset));
+
+                       /* Set RF after the previous action is done.  */
+                       while (ppsc->rfchange_inprogress) {
+                               rfwait_cnt++;
+                               mdelay(1);
+                               /*
+                                *Wait too long, return false to avoid
+                                *to be stuck here.
+                                */
+                               if (rfwait_cnt > 100)
+                                       return false;
+                       }
+               } else {
+                       ppsc->rfchange_inprogress = true;
+                       spin_unlock(&rtlpriv->locks.rf_ps_lock);
+                       break;
+               }
+       }
+
+no_protect:
+       rtstate = ppsc->rfpwr_state;
+
+       switch (state_toset) {
+       case ERFON:
+               ppsc->rfoff_reason &= (~changesource);
+
+               if ((changesource == RF_CHANGE_BY_HW) &&
+                   (ppsc->b_hwradiooff)) {
+                       ppsc->b_hwradiooff = false;
+               }
+               if (!ppsc->rfoff_reason) {
+                       ppsc->rfoff_reason = 0;
+                       b_actionallowed = true;
+               }
+               break;
+       case ERFOFF:
+               if ((changesource == RF_CHANGE_BY_HW) &&
+                   (!ppsc->b_hwradiooff)) {
+                       ppsc->b_hwradiooff = true;
+               }
+               ppsc->rfoff_reason |= changesource;
+               b_actionallowed = true;
+               break;
+       case ERFSLEEP:
+               ppsc->rfoff_reason |= changesource;
+               b_actionallowed = true;
+               break;
+       default:
+               RT_TRACE(COMP_ERR, DBG_EMERG, ("switch case not process\n"));
+               break;
+       }
+
+       if (b_actionallowed)
+               rtlpriv->cfg->ops->set_rf_power_state(hw, state_toset);
+
+       if (!protect_or_not) {
+               spin_lock(&rtlpriv->locks.rf_ps_lock);
+               ppsc->rfchange_inprogress = false;
+               spin_unlock(&rtlpriv->locks.rf_ps_lock);
+       }
+
+       return b_actionallowed;
+}
+EXPORT_SYMBOL(stg_rtl_ps_set_rf_state);
+
+static void _rtl_ps_inactive_ps(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+       ppsc->b_swrf_processing = true;
+
+       if (ppsc->inactive_pwrstate == ERFON && rtlhal->interface == INTF_PCI) {
+               if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) &&
+                   RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) &&
+                   rtlhal->interface == INTF_PCI) {
+                       rtlpriv->intf_ops->disable_aspm(hw);
+                       RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
+               }
+       }
+
+       stg_rtl_ps_set_rf_state(hw, ppsc->inactive_pwrstate,
+                               RF_CHANGE_BY_IPS, false);
+
+       if (ppsc->inactive_pwrstate == ERFOFF &&
+           rtlhal->interface == INTF_PCI) {
+               if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM &&
+                   !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) {
+                       rtlpriv->intf_ops->enable_aspm(hw);
+                       RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
+               }
+       }
+
+       ppsc->b_swrf_processing = false;
+}
+
+void rtl92e_ips_nic_off_wq_callback(void *data)
+{
+       struct rtl_works *rtlworks =
+           container_of_dwork_rtl(data, struct rtl_works, ips_nic_off_wq);
+       struct ieee80211_hw *hw = rtlworks->hw;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       enum rf_pwrstate rtstate;
+
+       if (mac->opmode != NL80211_IFTYPE_STATION) {
+               RT_TRACE(COMP_ERR, DBG_WARNING, ("not station return\n"));
+               return;
+       }
+
+       if (mac->p2p_in_use)
+               return;
+
+       if (mac->link_state > MAC80211_NOLINK)
+               return;
+
+       if (is_hal_stop(rtlhal))
+               return;
+
+       if (rtlpriv->sec.being_setkey)
+               return;
+
+       if (rtlpriv->cfg->ops->bt_turn_off_bt_coexist_before_enter_lps)
+               rtlpriv->cfg->ops->bt_turn_off_bt_coexist_before_enter_lps(hw);
+
+       if (ppsc->b_inactiveps) {
+               rtstate = ppsc->rfpwr_state;
+
+               /*
+                *Do not enter IPS in the following conditions:
+                *(1) RF is already OFF or Sleep
+                *(2) b_swrf_processing (indicates the IPS is still under going)
+                *(3) Connectted (only disconnected can trigger IPS)
+                *(4) IBSS (send Beacon)
+                *(5) AP mode (send Beacon)
+                *(6) monitor mode (rcv packet)
+                */
+
+               if (rtstate == ERFON &&
+                   !ppsc->b_swrf_processing &&
+                   (mac->link_state == MAC80211_NOLINK) &&
+                   !mac->act_scanning) {
+                       RT_TRACE(COMP_RF, DBG_LOUD,
+                                ("IPSEnter(): Turn off RF.\n"));
+
+                       ppsc->inactive_pwrstate = ERFOFF;
+                       ppsc->b_in_powersavemode = true;
+
+                       /* call before RF off */
+                       if (rtlpriv->cfg->ops->get_btc_status())
+                               rtlpriv->btcoexist.btc_ops->btc_ips_notify(rtlpriv,
+                                                                       ppsc->inactive_pwrstate);
+
+                       /*rtl92e_pci_reset_trx_ring(hw); */
+                       _rtl_ps_inactive_ps(hw);
+               }
+       }
+}
+
+void rtl92e_ips_nic_off(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       /*
+        *because when link with ap, mac80211 will ask us
+        *to disable nic quickly after scan before linking,
+        *this will cause link failed, so we delay 100ms here
+        */
+       queue_delayed_work(rtlpriv->works.rtl_wq,
+                          &rtlpriv->works.ips_nic_off_wq, MSECS(100));
+}
+
+/* NOTICE: any opmode should exc nic_on, or disable without
+ * nic_on may something wrong, like adhoc TP*/
+void rtl92e_ips_nic_on(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       enum rf_pwrstate rtstate;
+
+       cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq);
+
+       spin_lock(&rtlpriv->locks.ips_lock);
+       if (ppsc->b_inactiveps) {
+               rtstate = ppsc->rfpwr_state;
+
+               if (rtstate != ERFON &&
+                   !ppsc->b_swrf_processing &&
+                   ppsc->rfoff_reason <= RF_CHANGE_BY_IPS) {
+                       ppsc->inactive_pwrstate = ERFON;
+                       ppsc->b_in_powersavemode = false;
+                       _rtl_ps_inactive_ps(hw);
+                       /* call after RF on */
+                       if (rtlpriv->cfg->ops->get_btc_status())
+                               rtlpriv->btcoexist.btc_ops->btc_ips_notify(rtlpriv,
+                                                                       ppsc->inactive_pwrstate);
+               }
+       }
+       spin_unlock(&rtlpriv->locks.ips_lock);
+}
+
+/*for FW LPS*/
+
+/*
+ *Determine if we can set Fw into PS mode
+ *in current condition.Return true if it
+ *can enter PS mode.
+ */
+static bool rtl_get_fwlps_doze(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       u32 ps_timediff;
+
+       ps_timediff = jiffies_to_msecs(jiffies -
+                                      ppsc->last_delaylps_stamp_jiffies);
+
+       if (ps_timediff < 2000) {
+               RT_TRACE(COMP_POWER, DBG_LOUD,
+                        ("Delay enter Fw LPS for DHCP, ARP, or EAPOL exchanging state\n"));
+               return false;
+       }
+
+       if (mac->link_state != MAC80211_LINKED)
+               return false;
+
+       if (mac->opmode == NL80211_IFTYPE_ADHOC)
+               return false;
+
+       return true;
+}
+
+/* Change current and default preamble mode.*/
+void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       bool enter_fwlps;
+
+       if (mac->opmode == NL80211_IFTYPE_ADHOC)
+               return;
+
+       if (mac->link_state != MAC80211_LINKED)
+               return;
+
+       if (ppsc->dot11_psmode == rt_psmode)
+               return;
+
+       /* Update power save mode configured. */
+       ppsc->dot11_psmode = rt_psmode;
+
+       /*
+        *<FW control LPS>
+        *1. Enter PS mode
+        *   Set RPWM to Fw to turn RF off and send H2C fw_pwrmode
+        *   cmd to set Fw into PS mode.
+        *2. Leave PS mode
+        *   Send H2C fw_pwrmode cmd to Fw to set Fw into Active
+        *   mode and set RPWM to turn RF on.
+        */
+
+       if ((ppsc->b_fwctrl_lps) && ppsc->report_linked) {
+               if (ppsc->dot11_psmode == EACTIVE) {
+                       RT_TRACE(COMP_RF, DBG_DMESG,
+                                ("FW LPS leave ps_mode:%x\n",
+                                 FW_PS_ACTIVE_MODE));
+                       enter_fwlps = false;
+                       ppsc->pwr_mode = FW_PS_ACTIVE_MODE;
+                       ppsc->smart_ps = 0;
+                       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_LPS_ACTION,
+                                                     (u8 *)(&enter_fwlps));
+                       if (ppsc->p2p_ps_info.opp_ps)
+                               rtl92e_p2p_ps_cmd(hw , P2P_PS_ENABLE);
+
+                       if (rtlpriv->cfg->ops->get_btc_status())
+                               rtlpriv->btcoexist.btc_ops->btc_lps_notify(rtlpriv, rt_psmode);
+               } else {
+                       if (rtl_get_fwlps_doze(hw)) {
+                               RT_TRACE(COMP_RF, DBG_DMESG,
+                                        ("FW LPS enter ps_mode:%x\n",
+                                        ppsc->fwctrl_psmode));
+                               if (rtlpriv->cfg->ops->get_btc_status())
+                                       rtlpriv->btcoexist.btc_ops->btc_lps_notify(rtlpriv, rt_psmode);
+                               enter_fwlps = true;
+                               ppsc->pwr_mode = ppsc->fwctrl_psmode;
+                               ppsc->smart_ps = 2;
+                               rtlpriv->cfg->ops->set_hw_reg(hw,
+                                                       HW_VAR_FW_LPS_ACTION,
+                                                       (u8 *)(&enter_fwlps));
+
+                       } else {
+                               /* Reset the power save related parameters. */
+                               ppsc->dot11_psmode = EACTIVE;
+                       }
+               }
+       }
+}
+
+/*Enter the leisure power save mode.*/
+void rtl92e_lps_enter(struct ieee80211_hw *hw)
+{
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       unsigned long flag;
+
+       if (!ppsc->b_fwctrl_lps)
+               return;
+
+       if (rtlpriv->sec.being_setkey)
+               return;
+
+       if (rtlpriv->link_info.b_busytraffic)
+               return;
+
+       /*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */
+       if (mac->cnt_after_linked < 5)
+               return;
+
+       if (mac->opmode == NL80211_IFTYPE_ADHOC)
+               return;
+
+       if (mac->link_state != MAC80211_LINKED)
+               return;
+
+       spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
+
+       /* Idle for a while if we connect to AP a while ago. */
+       if (mac->cnt_after_linked >= 2) {
+               if (ppsc->dot11_psmode == EACTIVE) {
+                       RT_TRACE(COMP_POWER, DBG_LOUD,
+                                ("Enter 802.11 power save mode...\n"));
+
+                       rtl_lps_set_psmode(hw, EAUTOPS);
+               }
+       }
+
+       spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
+}
+EXPORT_SYMBOL(rtl92e_lps_enter);
+
+/*Leave the leisure power save mode.*/
+void rtl92e_lps_leave(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       unsigned long flag;
+
+       spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
+
+       if (ppsc->b_fwctrl_lps) {
+               if (ppsc->dot11_psmode != EACTIVE) {
+                       if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM &&
+                           RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) &&
+                           rtlhal->interface == INTF_PCI) {
+                               rtlpriv->intf_ops->disable_aspm(hw);
+                               RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
+                       }
+
+                       RT_TRACE(COMP_POWER, DBG_LOUD,
+                                ("Busy Traffic,Leave 802.11 power save..\n"));
+
+                       rtl_lps_set_psmode(hw, EACTIVE);
+               }
+       }
+       spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
+}
+EXPORT_SYMBOL(rtl92e_lps_leave);
+
+/* For sw LPS*/
+void rtl92e_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct ieee80211_hdr *hdr = (void *)data;
+       struct ieee80211_tim_ie *tim_ie;
+       u8 *tim;
+       u8 tim_len;
+       bool u_buffed;
+       bool m_buffed;
+
+       if (mac->opmode != NL80211_IFTYPE_STATION)
+               return;
+
+       if (!rtlpriv->psc.b_swctrl_lps)
+               return;
+
+       if (rtlpriv->mac80211.link_state != MAC80211_LINKED)
+               return;
+
+       if (!rtlpriv->psc.sw_ps_enabled)
+               return;
+
+       if (rtlpriv->psc.b_fwctrl_lps)
+               return;
+
+       if (likely(!(hw->conf.flags & IEEE80211_CONF_PS)))
+               return;
+
+       /* check if this really is a beacon */
+       if (!ieee80211_is_beacon(hdr->frame_control))
+               return;
+
+       /* min. beacon length + FCS_LEN */
+       if (len <= 40 + FCS_LEN)
+               return;
+
+       /* and only beacons from the associated BSSID, please */
+       if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid))
+               return;
+
+       rtlpriv->psc.last_beacon = jiffies;
+
+       tim = rtl92e_find_ie(data, len - FCS_LEN, WLAN_EID_TIM);
+       if (!tim)
+               return;
+
+       if (tim[1] < sizeof(*tim_ie))
+               return;
+
+       tim_len = tim[1];
+       tim_ie = (struct ieee80211_tim_ie *)&tim[2];
+
+       if (!WARN_ON_ONCE(!hw->conf.ps_dtim_period))
+               rtlpriv->psc.dtim_counter = tim_ie->dtim_count;
+
+       /* Check whenever the PHY can be turned off again. */
+
+       /* 1. What about buffered unicast traffic for our AID? */
+       u_buffed = ieee80211_check_tim(tim_ie, tim_len,
+                                      rtlpriv->mac80211.assoc_id);
+
+       /* 2. Maybe the AP wants to send multicast/broadcast data? */
+       m_buffed = tim_ie->bitmap_ctrl & 0x01;
+       rtlpriv->psc.multi_buffered = m_buffed;
+
+       /* unicast will process by mac80211 through
+        * set ~IEEE80211_CONF_PS, So we just check
+        * multicast frames here */
+       if (!m_buffed) {/*&&) { !rtlpriv->psc.tx_doing) { */
+               /* back to low-power land. and delay is
+                * prevent null power save frame tx fail */
+               queue_delayed_work(rtlpriv->works.rtl_wq,
+                                  &rtlpriv->works.ps_work, MSECS(5));
+       } else {
+               RT_TRACE(COMP_POWER, DBG_DMESG,
+                        ("u_bufferd: %x, m_buffered: %x\n",
+                         u_buffed, m_buffed));
+       }
+}
+
+void rtl92e_swlps_rf_awake(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       unsigned long flag;
+
+       if (!rtlpriv->psc.b_swctrl_lps)
+               return;
+       if (mac->link_state != MAC80211_LINKED)
+               return;
+
+       if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM &&
+           RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) {
+               rtlpriv->intf_ops->disable_aspm(hw);
+               RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
+       }
+
+       spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
+       stg_rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS, false);
+       spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
+}
+
+void rtl92e_swlps_rfon_wq_callback(void *data)
+{
+       struct rtl_works *rtlworks =
+           container_of_dwork_rtl(data, struct rtl_works, ps_rfon_wq);
+       struct ieee80211_hw *hw = rtlworks->hw;
+
+       rtl92e_swlps_rf_awake(hw);
+}
+
+void rtl92e_swlps_rf_sleep(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       unsigned long flag;
+       u8 sleep_intv;
+
+       if (!rtlpriv->psc.sw_ps_enabled)
+               return;
+
+       if ((rtlpriv->sec.being_setkey) ||
+           (mac->opmode == NL80211_IFTYPE_ADHOC))
+               return;
+
+       /*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */
+       if ((mac->link_state != MAC80211_LINKED) || (mac->cnt_after_linked < 5))
+               return;
+
+       if (rtlpriv->link_info.b_busytraffic)
+               return;
+
+       spin_lock(&rtlpriv->locks.rf_ps_lock);
+       if (rtlpriv->psc.rfchange_inprogress) {
+               spin_unlock(&rtlpriv->locks.rf_ps_lock);
+               return;
+       }
+       spin_unlock(&rtlpriv->locks.rf_ps_lock);
+
+       spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
+       stg_rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS , false);
+       spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
+
+       if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM &&
+           !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) {
+               rtlpriv->intf_ops->enable_aspm(hw);
+               RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
+       }
+
+       /* here is power save alg, when this beacon is DTIM
+        * we will set sleep time to dtim_period * n;
+        * when this beacon is not DTIM, we will set sleep
+        * time to sleep_intv = rtlpriv->psc.dtim_counter or
+        * MAX_SW_LPS_SLEEP_INTV(default set to 5) */
+
+       if (rtlpriv->psc.dtim_counter == 0) {
+               if (hw->conf.ps_dtim_period == 1)
+                       sleep_intv = hw->conf.ps_dtim_period * 2;
+               else
+                       sleep_intv = hw->conf.ps_dtim_period;
+       } else {
+               sleep_intv = rtlpriv->psc.dtim_counter;
+       }
+
+       if (sleep_intv > MAX_SW_LPS_SLEEP_INTV)
+               sleep_intv = MAX_SW_LPS_SLEEP_INTV;
+
+       /* this print should always be dtim_conter = 0 &
+        * sleep  = dtim_period, that meaons, we should
+        * awake before every dtim */
+       RT_TRACE(COMP_POWER, DBG_DMESG,
+                ("dtim_counter:%x will sleep :%d beacon_intv\n",
+                 rtlpriv->psc.dtim_counter, sleep_intv));
+
+       /* we tested that 40ms is enough for sw & hw sw delay */
+       queue_delayed_work(rtlpriv->works.rtl_wq, &rtlpriv->works.ps_rfon_wq,
+                          MSECS(sleep_intv*mac->vif->bss_conf.beacon_int-40));
+}
+
+
+void rtl92e_swlps_wq_callback(void *data)
+{
+       struct rtl_works *rtlworks =
+               container_of_dwork_rtl(data, struct rtl_works, ps_work);
+       struct ieee80211_hw *hw = rtlworks->hw;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       bool ps = false;
+
+       ps = (hw->conf.flags & IEEE80211_CONF_PS);
+
+       /* we can sleep after ps null send ok */
+       if (rtlpriv->psc.state_inap) {
+               rtl92e_swlps_rf_sleep(hw);
+
+               if (rtlpriv->psc.state && !ps) {
+                       rtlpriv->psc.sleep_ms =
+                               jiffies_to_msecs(jiffies -
+                                                rtlpriv->psc.last_action);
+               }
+
+               if (ps)
+                       rtlpriv->psc.last_slept = jiffies;
+
+               rtlpriv->psc.last_action = jiffies;
+               rtlpriv->psc.state = ps;
+       }
+}
+
+static void rtl_p2p_noa_ie(struct ieee80211_hw *hw, void *data,
+                          unsigned int len)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct ieee80211_mgmt *mgmt = (void *)data;
+       struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info);
+       u8 *pos, *end, *ie;
+       u16 noa_len;
+       static u8 p2p_oui_ie_type[4] = {0x50, 0x6f, 0x9a, 0x09};
+       u8 noa_num, index , i, noa_index = 0;
+       bool find_p2p_ie = false , find_p2p_ps_ie = false;
+       pos = (u8 *)mgmt->u.beacon.variable;
+       end = data + len;
+       ie = NULL;
+
+       while (pos + 1 < end) {
+               if (pos + 2 + pos[1] > end)
+                       return;
+
+               if (pos[0] == 221 && pos[1] > 4) {
+                       if (memcmp(&pos[2], p2p_oui_ie_type, 4) == 0) {
+                               ie = pos + 2+4;
+                               break;
+                       }
+               }
+               pos += 2 + pos[1];
+       }
+
+       if (ie == NULL)
+               return;
+       find_p2p_ie = true;
+       /*to find noa ie*/
+       while (ie + 1 < end) {
+               noa_len = READEF2BYTE((__le16 *)&ie[1]);
+               if (ie + 3 + ie[1] > end)
+                       return;
+
+               if (ie[0] == 12) {
+                       find_p2p_ps_ie = true;
+                       if ((noa_len - 2) % 13 != 0) {
+                               RT_TRACE(COMP_INIT, DBG_LOUD,
+                                        ("P2P notice of absence: invalid length%d\n",
+                                        noa_len));
+                               return;
+                       } else {
+                               noa_num = (noa_len - 2) / 13;
+                       }
+                       noa_index = ie[3];
+                       if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode ==
+                           P2P_PS_NONE || noa_index != p2pinfo->noa_index) {
+                               RT_TRACE(COMP_FW, DBG_LOUD,
+                                        ("update NOA ie.\n"));
+                               p2pinfo->noa_index = noa_index;
+                               p2pinfo->opp_ps = (ie[4] >> 7);
+                               p2pinfo->ctwindow = ie[4] & 0x7F;
+                               p2pinfo->noa_num = noa_num;
+                               index = 5;
+                               for (i = 0; i < noa_num; i++) {
+                                       p2pinfo->noa_count_type[i] =
+                                                       READEF1BYTE(ie+index);
+                                       index += 1;
+                                       p2pinfo->noa_duration[i] =
+                                                READEF4BYTE((__le32 *)ie+index);
+                                       index += 4;
+                                       p2pinfo->noa_interval[i] =
+                                                READEF4BYTE((__le32 *)ie+index);
+                                       index += 4;
+                                       p2pinfo->noa_start_time[i] =
+                                                READEF4BYTE((__le32 *)ie+index);
+                                       index += 4;
+                               }
+
+                               if (p2pinfo->opp_ps == 1) {
+                                       p2pinfo->p2p_ps_mode = P2P_PS_CTWINDOW;
+                                       /* Driver should wait LPS
+                                        * entering CTWindow*/
+                                       if (rtlpriv->psc.b_fw_current_inpsmode) {
+                                               rtl92e_p2p_ps_cmd(hw,
+                                                              P2P_PS_ENABLE);
+                                       }
+                               } else if (p2pinfo->noa_num > 0) {
+                                       p2pinfo->p2p_ps_mode = P2P_PS_NOA;
+                                       rtl92e_p2p_ps_cmd(hw, P2P_PS_ENABLE);
+                               } else if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
+                                       rtl92e_p2p_ps_cmd(hw, P2P_PS_DISABLE);
+                               }
+                       }
+
+               break;
+               }
+               ie += 3 + noa_len;
+       }
+
+       if (find_p2p_ie) {
+               if ((p2pinfo->p2p_ps_mode > P2P_PS_NONE) &&
+                   (!find_p2p_ps_ie))
+                       rtl92e_p2p_ps_cmd(hw, P2P_PS_DISABLE);
+       }
+}
+
+static void rtl_p2p_action_ie(struct ieee80211_hw *hw, void *data,
+                             unsigned int len)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct ieee80211_mgmt *mgmt = (void *)data;
+       struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info);
+       bool find_p2p_ie = false, find_p2p_ps_ie = false;
+       u8 noa_num, index, i, noa_index = 0;
+       u8 *pos, *end, *ie;
+       u16 noa_len;
+       static u8 p2p_oui_ie_type[4] = {0x50, 0x6f, 0x9a, 0x09};
+
+       pos = (u8 *)&mgmt->u.action.category;
+       end = data + len;
+       ie = NULL;
+
+       if (pos[0] == 0x7f) {
+               if (memcmp(&pos[1], p2p_oui_ie_type, 4) == 0)
+                       ie = pos + 3+4;
+       }
+
+       if (ie == NULL)
+               return;
+       find_p2p_ie = true;
+
+       RT_TRACE(COMP_FW, DBG_LOUD, ("action frame find P2P IE.\n"));
+       /*to find noa ie*/
+       while (ie + 1 < end) {
+               noa_len = READEF2BYTE((__le16 *)&ie[1]);
+               if (ie + 3 + ie[1] > end)
+                       return;
+
+               if (ie[0] == 12) {
+                       RT_TRACE(COMP_FW, DBG_LOUD, ("find NOA IE\n"));
+                       RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_LOUD, "noa ie ",
+                                     ie, noa_len);
+                       find_p2p_ps_ie = true;
+                       if ((noa_len - 2) % 13 != 0) {
+                               RT_TRACE(COMP_FW, DBG_LOUD,
+                                        ("P2P notice of absence: invalid length%d\n",
+                                        noa_len));
+                               return;
+                       } else {
+                               noa_num = (noa_len - 2) / 13;
+                       }
+                       noa_index = ie[3];
+                       if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode ==
+                           P2P_PS_NONE ||
+                           noa_index != p2pinfo->noa_index) {
+                               p2pinfo->noa_index = noa_index;
+                               p2pinfo->opp_ps = (ie[4] >> 7);
+                               p2pinfo->ctwindow = ie[4] & 0x7F;
+                               p2pinfo->noa_num = noa_num;
+                               index = 5;
+                               for (i = 0; i < noa_num; i++) {
+                                       p2pinfo->noa_count_type[i] =
+                                                       READEF1BYTE(ie+index);
+                                       index += 1;
+                                       p2pinfo->noa_duration[i] =
+                                                READEF4BYTE((__le32 *)ie+index);
+                                       index += 4;
+                                       p2pinfo->noa_interval[i] =
+                                                READEF4BYTE((__le32 *)ie+index);
+                                       index += 4;
+                                       p2pinfo->noa_start_time[i] =
+                                                READEF4BYTE((__le32 *)ie+index);
+                                       index += 4;
+                               }
+
+                               if (p2pinfo->opp_ps == 1) {
+                                       p2pinfo->p2p_ps_mode = P2P_PS_CTWINDOW;
+                                       /* Driver should wait LPS
+                                        * entering CTWindow */
+                                       if (rtlpriv->psc.b_fw_current_inpsmode) {
+                                               rtl92e_p2p_ps_cmd(hw,
+                                                              P2P_PS_ENABLE);
+                                       }
+                               } else if (p2pinfo->noa_num > 0) {
+                                       p2pinfo->p2p_ps_mode = P2P_PS_NOA;
+                                       rtl92e_p2p_ps_cmd(hw, P2P_PS_ENABLE);
+                               } else if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
+                                       rtl92e_p2p_ps_cmd(hw, P2P_PS_DISABLE);
+                               }
+                       }
+
+               break;
+               }
+               ie += 3 + noa_len;
+       }
+}
+
+void rtl92e_p2p_ps_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
+       struct rtl_p2p_ps_info  *p2pinfo = &(rtlpriv->psc.p2p_ps_info);
+
+       RT_TRACE(COMP_FW, DBG_LOUD, ("p2p state %x\n", p2p_ps_state));
+       switch (p2p_ps_state) {
+       case P2P_PS_DISABLE:
+               p2pinfo->p2p_ps_state = p2p_ps_state;
+               rtlpriv->cfg->ops->set_hw_reg(hw,
+                                          HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
+                                          (u8 *)(&p2p_ps_state));
+
+               p2pinfo->noa_index = 0;
+               p2pinfo->ctwindow = 0;
+               p2pinfo->opp_ps = 0;
+               p2pinfo->noa_num = 0;
+               p2pinfo->p2p_ps_mode = P2P_PS_NONE;
+               if (rtlps->b_fw_current_inpsmode) {
+                       if (rtlps->smart_ps == 0) {
+                               rtlps->smart_ps = 2;
+                               rtlpriv->cfg->ops->set_hw_reg(hw,
+                                           HW_VAR_H2C_FW_PWRMODE,
+                                           (u8 *)(&rtlps->pwr_mode));
+                       }
+               }
+               break;
+       case P2P_PS_ENABLE:
+               if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
+                       p2pinfo->p2p_ps_state = p2p_ps_state;
+
+                       if (p2pinfo->ctwindow > 0) {
+                               if (rtlps->smart_ps != 0) {
+                                       rtlps->smart_ps = 0;
+                                       rtlpriv->cfg->ops->set_hw_reg(
+                                           hw, HW_VAR_H2C_FW_PWRMODE,
+                                           (u8 *)(&rtlps->pwr_mode));
+                               }
+                       }
+                       rtlpriv->cfg->ops->set_hw_reg(hw,
+                                               HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
+                                               (u8 *)(&p2p_ps_state));
+                       }
+                       break;
+       case P2P_PS_SCAN:
+       case P2P_PS_SCAN_DONE:
+       case P2P_PS_ALLSTASLEEP:
+               if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
+                       p2pinfo->p2p_ps_state = p2p_ps_state;
+                       rtlpriv->cfg->ops->set_hw_reg(hw,
+                                               HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
+                                               (u8 *)(&p2p_ps_state));
+               }
+               break;
+       default:
+               break;
+       }
+       RT_TRACE(COMP_FW, DBG_LOUD, (" ctwindow %x oppps %x\n",
+                                    p2pinfo->ctwindow , p2pinfo->opp_ps));
+       RT_TRACE(COMP_FW, DBG_LOUD,
+                ("count %x duration %x index %x interval %x start time %x noa num %x\n",
+                p2pinfo->noa_count_type[0],
+                p2pinfo->noa_duration[0],
+                p2pinfo->noa_index,
+                p2pinfo->noa_interval[0],
+                p2pinfo->noa_start_time[0],
+                p2pinfo->noa_num));
+       RT_TRACE(COMP_FW, DBG_LOUD, ("end\n"));
+}
+
+void rtl92e_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct ieee80211_hdr *hdr = (void *)data;
+
+       if (!mac->p2p)
+               return;
+       if (mac->link_state != MAC80211_LINKED)
+               return;
+       /* min. beacon length + FCS_LEN */
+       if (len <= 40 + FCS_LEN)
+               return;
+
+       /* and only beacons from the associated BSSID, please */
+       if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid))
+               return;
+
+       /* check if this really is a beacon */
+       if (!(ieee80211_is_beacon(hdr->frame_control) ||
+             ieee80211_is_probe_resp(hdr->frame_control) ||
+             ieee80211_is_action(hdr->frame_control)))
+               return;
+
+       if (ieee80211_is_action(hdr->frame_control))
+               rtl_p2p_action_ie(hw , data , len - FCS_LEN);
+       else
+               rtl_p2p_noa_ie(hw , data , len - FCS_LEN);
+}
diff --git a/drivers/staging/rtl8192ee/ps.h b/drivers/staging/rtl8192ee/ps.h
new file mode 100644 (file)
index 0000000..1533661
--- /dev/null
@@ -0,0 +1,52 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __REALTEK_RTL_PCI_PS_H__
+#define __REALTEK_RTL_PCI_PS_H__
+
+#define MAX_SW_LPS_SLEEP_INTV  5
+
+bool stg_rtl_ps_set_rf_state(struct ieee80211_hw *hw,
+                            enum rf_pwrstate state_toset, u32 changesource,
+                            bool protect_or_not);
+bool stg_rtl_ps_enable_nic(struct ieee80211_hw *hw);
+bool stg_rtl_ps_disable_nic(struct ieee80211_hw *hw);
+void rtl92e_ips_nic_off(struct ieee80211_hw *hw);
+void rtl92e_ips_nic_on(struct ieee80211_hw *hw);
+void rtl92e_ips_nic_off_wq_callback(void *data);
+void rtl92e_lps_enter(struct ieee80211_hw *hw);
+void rtl92e_lps_leave(struct ieee80211_hw *hw);
+
+void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode);
+
+void rtl92e_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len);
+void rtl92e_swlps_wq_callback(void *data);
+void rtl92e_swlps_rfon_wq_callback(void *data);
+void rtl92e_swlps_rf_awake(struct ieee80211_hw *hw);
+void rtl92e_swlps_rf_sleep(struct ieee80211_hw *hw);
+void rtl92e_p2p_ps_cmd(struct ieee80211_hw *hw , u8 p2p_ps_state);
+void rtl92e_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len);
+
+#endif
diff --git a/drivers/staging/rtl8192ee/rc.c b/drivers/staging/rtl8192ee/rc.c
new file mode 100644 (file)
index 0000000..f0ce6a9
--- /dev/null
@@ -0,0 +1,288 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "wifi.h"
+#include "base.h"
+#include "rc.h"
+
+/*
+ *Finds the highest rate index we can use
+ *if skb is special data like DHCP/EAPOL, we set should
+ *it to lowest rate CCK_1M, otherwise we set rate to
+ *highest rate based on wireless mode used for iwconfig
+ *show Tx rate.
+ */
+static u8 _rtl_rc_get_highest_rix(struct rtl_priv *rtlpriv,
+                                 struct ieee80211_sta *sta,
+                                 struct sk_buff *skb, bool not_data)
+{
+       struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_sta_info *sta_entry = NULL;
+       u8 wireless_mode = 0;
+
+       /*
+        *this rate is no use for true rate, firmware
+        *will control rate at all it just used for
+        *1.show in iwconfig in B/G mode
+        *2.in stg_rtl_get_tcb_desc when we check rate is
+        *      1M we will not use FW rate but user rate.
+        */
+
+       if (sta) {
+               sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+               wireless_mode = sta_entry->wireless_mode;
+       }
+
+       if (rtl92e_is_special_data(rtlpriv->mac80211.hw, skb, true) ||
+           not_data) {
+               return 0;
+       } else {
+               if (rtlhal->current_bandtype == BAND_ON_2_4G) {
+                       if (wireless_mode == WIRELESS_MODE_B) {
+                               return B_MODE_MAX_RIX;
+                       } else if (wireless_mode == WIRELESS_MODE_G) {
+                               return G_MODE_MAX_RIX;
+                       } else if (wireless_mode == WIRELESS_MODE_N_24G) {
+                               if (get_rf_type(rtlphy) != RF_2T2R)
+                                       return N_MODE_MCS7_RIX;
+                               else
+                                       return N_MODE_MCS15_RIX;
+                       } else if (wireless_mode == WIRELESS_MODE_AC_24G) {
+                               return AC_MODE_MCS9_RIX;
+                       } else {
+                               return 0;
+                       }
+               } else {
+                       if (wireless_mode == WIRELESS_MODE_A) {
+                               return A_MODE_MAX_RIX;
+                       } else if (wireless_mode == WIRELESS_MODE_N_5G) {
+                               if (get_rf_type(rtlphy) != RF_2T2R)
+                                       return N_MODE_MCS7_RIX;
+                               else
+                                       return N_MODE_MCS15_RIX;
+                       } else if (wireless_mode == WIRELESS_MODE_AC_5G) {
+                               return AC_MODE_MCS9_RIX;
+                       } else {
+                               return 0;
+                       }
+               }
+       }
+}
+
+static void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv,
+                                   struct ieee80211_sta *sta,
+                                   struct ieee80211_tx_rate *rate,
+                                   struct ieee80211_tx_rate_control *txrc,
+                                   u8 tries, char rix, int rtsctsenable,
+                                   bool not_data)
+{
+       struct rtl_mac *mac = rtl_mac(rtlpriv);
+       u8 sgi_20 = 0, sgi_40 = 0, sgi_80 = 0;
+
+       if (sta) {
+               sgi_20 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20;
+               sgi_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40;
+               sgi_80 = sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80;
+       }
+       rate->count = tries;
+       rate->idx = rix >= 0x00 ? rix : 0x00;
+
+       if (!not_data) {
+               if (txrc->short_preamble)
+                       rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE;
+               if (mac->opmode == NL80211_IFTYPE_AP ||
+                   mac->opmode == NL80211_IFTYPE_ADHOC) {
+                       if (sta && (sta->ht_cap.cap &
+                                   IEEE80211_HT_CAP_SUP_WIDTH_20_40))
+                               rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
+                       if (sta && (sta->vht_cap.vht_supported))
+                               rate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH;
+               } else {
+                       if (mac->bw_40)
+                               rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
+                       if (mac->bw_80)
+                               rate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH;
+               }
+
+               if (sgi_20 || sgi_40 || sgi_80)
+                       rate->flags |= IEEE80211_TX_RC_SHORT_GI;
+               if (sta && sta->ht_cap.ht_supported)
+                       rate->flags |= IEEE80211_TX_RC_MCS;
+               if (sta && sta->vht_cap.vht_supported)
+                       rate->flags |= IEEE80211_TX_RC_VHT_MCS;
+       }
+}
+
+static void rtl_get_rate(void *ppriv, struct ieee80211_sta *sta,
+                        void *priv_sta,
+                        struct ieee80211_tx_rate_control *txrc)
+{
+       struct rtl_priv *rtlpriv = ppriv;
+       struct sk_buff *skb = txrc->skb;
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_tx_rate *rates = tx_info->control.rates;
+       __le16 fc = rtl_get_fc(skb);
+       u8 try_per_rate, i, rix;
+       bool not_data = !ieee80211_is_data(fc);
+
+       if (rate_control_send_low(sta, priv_sta, txrc))
+               return;
+
+       rix = _rtl_rc_get_highest_rix(rtlpriv, sta, skb, not_data);
+       try_per_rate = 1;
+       _rtl_rc_rate_set_series(rtlpriv, sta, &rates[0], txrc,
+                               try_per_rate, rix, 1, not_data);
+
+       if (!not_data) {
+               for (i = 1; i < 4; i++)
+                       _rtl_rc_rate_set_series(rtlpriv, sta, &rates[i],
+                                               txrc, i, (rix - i), 1,
+                                               not_data);
+       }
+}
+
+static bool _rtl_tx_aggr_check(struct rtl_priv *rtlpriv,
+                              struct rtl_sta_info *sta_entry, u16 tid)
+{
+       struct rtl_mac *mac = rtl_mac(rtlpriv);
+
+       if (mac->act_scanning)
+               return false;
+
+       if (mac->opmode == NL80211_IFTYPE_STATION &&
+           mac->cnt_after_linked < 3)
+               return false;
+
+       if (sta_entry->tids[tid].agg.agg_state == RTL_AGG_STOP)
+               return true;
+
+       return false;
+}
+
+/*mac80211 Rate Control callbacks*/
+static void rtl_tx_status(void *ppriv,
+                         struct ieee80211_supported_band *sband,
+                         struct ieee80211_sta *sta, void *priv_sta,
+                         struct sk_buff *skb)
+{
+       struct rtl_priv *rtlpriv = ppriv;
+       struct rtl_mac *mac = rtl_mac(rtlpriv);
+       struct ieee80211_hdr *hdr = rtl_get_hdr(skb);
+       __le16 fc = rtl_get_fc(skb);
+       struct rtl_sta_info *sta_entry;
+
+       if (!priv_sta || !ieee80211_is_data(fc))
+               return;
+
+       if (rtl92e_is_special_data(mac->hw, skb, true))
+               return;
+
+       if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) ||
+           is_broadcast_ether_addr(ieee80211_get_DA(hdr)))
+               return;
+
+       if (sta) {
+               /* Check if aggregation has to be enabled for this tid */
+               sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+               if ((sta->ht_cap.ht_supported) &&
+                   !(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
+                       if (ieee80211_is_data_qos(fc)) {
+                               u8 tid = rtl_get_tid(skb);
+                               if (_rtl_tx_aggr_check(rtlpriv, sta_entry,
+                                                      tid)) {
+                                       sta_entry->tids[tid].agg.agg_state =
+                                               RTL_AGG_PROGRESS;
+                                       ieee80211_start_tx_ba_session(sta, tid,
+                                                                     5000);
+                               }
+                       }
+               }
+       }
+}
+
+static void rtl_rate_init(void *ppriv,
+                         struct ieee80211_supported_band *sband,
+                         struct cfg80211_chan_def *chandef,
+                         struct ieee80211_sta *sta, void *priv_sta)
+{
+}
+
+static void *rtl_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       return rtlpriv;
+}
+
+static void rtl_rate_free(void *rtlpriv)
+{
+       return;
+}
+
+static void *rtl_rate_alloc_sta(void *ppriv,
+                               struct ieee80211_sta *sta, gfp_t gfp)
+{
+       struct rtl_priv *rtlpriv = ppriv;
+       struct rtl_rate_priv *rate_priv;
+
+       rate_priv = kzalloc(sizeof(*rate_priv), gfp);
+       if (!rate_priv) {
+               RT_TRACE(COMP_ERR, DBG_EMERG,
+                        ("Unable to allocate private rc structure\n"));
+               return NULL;
+       }
+
+       rtlpriv->rate_priv = rate_priv;
+
+       return rate_priv;
+}
+
+static void rtl_rate_free_sta(void *rtlpriv,
+                             struct ieee80211_sta *sta, void *priv_sta)
+{
+       struct rtl_rate_priv *rate_priv = priv_sta;
+       kfree(rate_priv);
+}
+
+static struct rate_control_ops rtl_rate_ops = {
+       .name = "rtl_rc",
+       .alloc = rtl_rate_alloc,
+       .free = rtl_rate_free,
+       .alloc_sta = rtl_rate_alloc_sta,
+       .free_sta = rtl_rate_free_sta,
+       .rate_init = rtl_rate_init,
+       .tx_status = rtl_tx_status,
+       .get_rate = rtl_get_rate,
+};
+
+int rtl92e_rate_control_register(void)
+{
+       return ieee80211_rate_control_register(&rtl_rate_ops);
+}
+
+void rtl92e_rate_control_unregister(void)
+{
+       ieee80211_rate_control_unregister(&rtl_rate_ops);
+}
diff --git a/drivers/staging/rtl8192ee/rc.h b/drivers/staging/rtl8192ee/rc.h
new file mode 100644 (file)
index 0000000..928f570
--- /dev/null
@@ -0,0 +1,47 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL_RC_H__
+#define __RTL_RC_H__
+
+#define B_MODE_MAX_RIX 3
+#define G_MODE_MAX_RIX 11
+#define A_MODE_MAX_RIX 7
+
+/* in mac80211 mcs0-mcs15 is idx0-idx15*/
+#define N_MODE_MCS7_RIX 7
+#define N_MODE_MCS15_RIX 15
+
+#define AC_MODE_MCS7_RIX 7
+#define AC_MODE_MCS8_RIX 8
+#define AC_MODE_MCS9_RIX 9
+
+struct rtl_rate_priv {
+       u8 ht_cap;
+};
+
+int rtl92e_rate_control_register(void);
+void rtl92e_rate_control_unregister(void);
+#endif
diff --git a/drivers/staging/rtl8192ee/regd.c b/drivers/staging/rtl8192ee/regd.c
new file mode 100644 (file)
index 0000000..7272fae
--- /dev/null
@@ -0,0 +1,448 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "wifi.h"
+#include "regd.h"
+
+static struct country_code_to_enum_rd allcountries[] = {
+       {COUNTRY_CODE_FCC, "US"},
+       {COUNTRY_CODE_IC, "US"},
+       {COUNTRY_CODE_ETSI, "EC"},
+       {COUNTRY_CODE_SPAIN, "EC"},
+       {COUNTRY_CODE_FRANCE, "EC"},
+       {COUNTRY_CODE_MKK, "JP"},
+       {COUNTRY_CODE_MKK1, "JP"},
+       {COUNTRY_CODE_ISRAEL, "EC"},
+       {COUNTRY_CODE_TELEC, "JP"},
+       {COUNTRY_CODE_MIC, "JP"},
+       {COUNTRY_CODE_GLOBAL_DOMAIN, "JP"},
+       {COUNTRY_CODE_WORLD_WIDE_13, "EC"},
+       {COUNTRY_CODE_TELEC_NETGEAR, "EC"},
+};
+
+/*
+ *Only these channels all allow active
+ *scan on all world regulatory domains
+ */
+#define RTL819x_2GHZ_CH01_11   \
+       REG_RULE(2412-10, 2462+10, 40, 0, 20, 0)
+
+/*
+ *We enable active scan on these a case
+ *by case basis by regulatory domain
+ */
+#define RTL819x_2GHZ_CH12_13   \
+       REG_RULE(2467-10, 2472+10, 40, 0, 20,\
+       NL80211_RRF_PASSIVE_SCAN)
+
+#define RTL819x_2GHZ_CH14      \
+       REG_RULE(2484-10, 2484+10, 40, 0, 20, \
+       NL80211_RRF_PASSIVE_SCAN | \
+       NL80211_RRF_NO_OFDM)
+
+/* 5G chan 36 - chan 64*/
+#define RTL819x_5GHZ_5150_5350 \
+       REG_RULE(5150-10, 5350+10, 80, 0, 30, \
+       NL80211_RRF_PASSIVE_SCAN | \
+       NL80211_RRF_NO_IBSS)
+
+/* 5G chan 100 - chan 165*/
+#define RTL819x_5GHZ_5470_5850 \
+       REG_RULE(5470-10, 5850+10, 80, 0, 30, \
+       NL80211_RRF_PASSIVE_SCAN | \
+       NL80211_RRF_NO_IBSS)
+
+/* 5G chan 149 - chan 165*/
+#define RTL819x_5GHZ_5725_5850 \
+       REG_RULE(5725-10, 5850+10, 80, 0, 30, \
+       NL80211_RRF_PASSIVE_SCAN | \
+       NL80211_RRF_NO_IBSS)
+
+#define RTL819x_5GHZ_ALL       \
+       (RTL819x_5GHZ_5150_5350, RTL819x_5GHZ_5470_5850)
+
+static const struct ieee80211_regdomain rtl_regdom_11 = {
+       .n_reg_rules = 1,
+       .alpha2 = "99",
+       .reg_rules = {
+                     RTL819x_2GHZ_CH01_11,
+                     }
+};
+
+static const struct ieee80211_regdomain rtl_regdom_12_13 = {
+       .n_reg_rules = 2,
+       .alpha2 = "99",
+       .reg_rules = {
+                     RTL819x_2GHZ_CH01_11,
+                         RTL819x_2GHZ_CH12_13,
+                     }
+};
+
+static const struct ieee80211_regdomain rtl_regdom_no_midband = {
+       .n_reg_rules = 3,
+       .alpha2 = "99",
+       .reg_rules = {
+                     RTL819x_2GHZ_CH01_11,
+                         RTL819x_5GHZ_5150_5350,
+                         RTL819x_5GHZ_5725_5850,
+                     }
+};
+
+static const struct ieee80211_regdomain rtl_regdom_60_64 = {
+       .n_reg_rules = 3,
+       .alpha2 = "99",
+       .reg_rules = {
+                     RTL819x_2GHZ_CH01_11,
+                         RTL819x_2GHZ_CH12_13,
+                         RTL819x_5GHZ_5725_5850,
+                     }
+};
+
+static const struct ieee80211_regdomain rtl_regdom_14_60_64 = {
+       .n_reg_rules = 4,
+       .alpha2 = "99",
+       .reg_rules = {
+                     RTL819x_2GHZ_CH01_11,
+                         RTL819x_2GHZ_CH12_13,
+                         RTL819x_2GHZ_CH14,
+                         RTL819x_5GHZ_5725_5850,
+                     }
+};
+
+static const struct ieee80211_regdomain rtl_regdom_14 = {
+       .n_reg_rules = 3,
+       .alpha2 = "99",
+       .reg_rules = {
+                     RTL819x_2GHZ_CH01_11,
+                         RTL819x_2GHZ_CH12_13,
+                         RTL819x_2GHZ_CH14,
+                     }
+};
+
+static bool _rtl_is_radar_freq(u16 center_freq)
+{
+       return center_freq >= 5260 && center_freq <= 5700;
+}
+
+static void _rtl_reg_apply_beaconing_flags(struct wiphy *wiphy,
+                                          enum nl80211_reg_initiator initiator)
+{
+       enum ieee80211_band band;
+       struct ieee80211_supported_band *sband;
+       const struct ieee80211_reg_rule *reg_rule;
+       struct ieee80211_channel *ch;
+       unsigned int i;
+
+       for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+               if (!wiphy->bands[band])
+                       continue;
+
+               sband = wiphy->bands[band];
+
+               for (i = 0; i < sband->n_channels; i++) {
+                       ch = &sband->channels[i];
+                       if (_rtl_is_radar_freq(ch->center_freq) ||
+                           (ch->flags & IEEE80211_CHAN_RADAR))
+                               continue;
+                       if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
+                               reg_rule = freq_reg_info(wiphy,
+                                                        ch->center_freq);
+                               if (IS_ERR(reg_rule))
+                                       continue;
+
+                               /*
+                                *If 11d had a rule for this channel ensure
+                                *we enable adhoc/beaconing if it allows us to
+                                *use it. Note that we would have disabled it
+                                *by applying our static world regdomain by
+                                *default during init, prior to calling our
+                                *regulatory_hint().
+                                */
+
+                               if (!(reg_rule->flags & NL80211_RRF_NO_IBSS))
+                                       ch->flags &= ~IEEE80211_CHAN_NO_IBSS;
+                               if (!(reg_rule->flags &
+                                     NL80211_RRF_PASSIVE_SCAN))
+                                       ch->flags &=
+                                           ~IEEE80211_CHAN_PASSIVE_SCAN;
+                       } else {
+                               if (ch->beacon_found)
+                                       ch->flags &= ~(IEEE80211_CHAN_NO_IBSS |
+                                                  IEEE80211_CHAN_PASSIVE_SCAN);
+                       }
+               }
+       }
+}
+
+/* Allows active scan scan on Ch 12 and 13 */
+static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy,
+                                            enum nl80211_reg_initiator
+                                            initiator)
+{
+       struct ieee80211_supported_band *sband;
+       struct ieee80211_channel *ch;
+       const struct ieee80211_reg_rule *reg_rule;
+
+       if (!wiphy->bands[IEEE80211_BAND_2GHZ])
+               return;
+       sband = wiphy->bands[IEEE80211_BAND_2GHZ];
+
+       /*
+        *If no country IE has been received always enable active scan
+        *on these channels. This is only done for specific regulatory SKUs
+        */
+       if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
+               ch = &sband->channels[11];      /* CH 12 */
+               if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+                       ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
+               ch = &sband->channels[12];      /* CH 13 */
+               if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+                       ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
+               return;
+       }
+
+       /*
+        *If a country IE has been recieved check its rule for this
+        *channel first before enabling active scan. The passive scan
+        *would have been enforced by the initial processing of our
+        *custom regulatory domain.
+        */
+
+       ch = &sband->channels[11];      /* CH 12 */
+       reg_rule = freq_reg_info(wiphy, ch->center_freq);
+       if (!IS_ERR(reg_rule)) {
+               if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
+                       if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+                               ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
+       }
+
+       ch = &sband->channels[12];      /* CH 13 */
+       reg_rule = freq_reg_info(wiphy, ch->center_freq);
+       if (!IS_ERR(reg_rule)) {
+               if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
+                       if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+                               ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
+       }
+}
+
+/*
+ *Always apply Radar/DFS rules on
+ *freq range 5260 MHz - 5700 MHz
+ */
+static void _rtl_reg_apply_radar_flags(struct wiphy *wiphy)
+{
+       struct ieee80211_supported_band *sband;
+       struct ieee80211_channel *ch;
+       unsigned int i;
+
+       if (!wiphy->bands[IEEE80211_BAND_5GHZ])
+               return;
+
+       sband = wiphy->bands[IEEE80211_BAND_5GHZ];
+
+       for (i = 0; i < sband->n_channels; i++) {
+               ch = &sband->channels[i];
+               if (!_rtl_is_radar_freq(ch->center_freq))
+                       continue;
+
+               /*
+                *We always enable radar detection/DFS on this
+                *frequency range. Additionally we also apply on
+                *this frequency range:
+                *- If STA mode does not yet have DFS supports disable
+                * active scanning
+                *- If adhoc mode does not support DFS yet then disable
+                * adhoc in the frequency.
+                *- If AP mode does not yet support radar detection/DFS
+                *do not allow AP mode
+                */
+               if (!(ch->flags & IEEE80211_CHAN_DISABLED))
+                       ch->flags |= IEEE80211_CHAN_RADAR |
+                           IEEE80211_CHAN_NO_IBSS |
+                           IEEE80211_CHAN_PASSIVE_SCAN;
+       }
+}
+
+static void _rtl_reg_apply_world_flags(struct wiphy *wiphy,
+                                      enum nl80211_reg_initiator initiator,
+                                      struct rtl_regulatory *reg)
+{
+       _rtl_reg_apply_beaconing_flags(wiphy, initiator);
+       _rtl_reg_apply_active_scan_flags(wiphy, initiator);
+       return;
+}
+
+static void _rtl_dump_channel_map(struct wiphy *wiphy)
+{
+       enum ieee80211_band band;
+       struct ieee80211_supported_band *sband;
+       struct ieee80211_channel *ch;
+       unsigned int i;
+
+       for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+               if (!wiphy->bands[band])
+                       continue;
+               sband = wiphy->bands[band];
+               for (i = 0; i < sband->n_channels; i++)
+                       ch = &sband->channels[i];
+       }
+}
+
+static int _rtl92e_reg_notifier_apply(struct wiphy *wiphy,
+                                     struct regulatory_request *request,
+                                     struct rtl_regulatory *reg)
+{
+       /* We always apply this */
+       _rtl_reg_apply_radar_flags(wiphy);
+
+       switch (request->initiator) {
+       case NL80211_REGDOM_SET_BY_DRIVER:
+       case NL80211_REGDOM_SET_BY_CORE:
+       case NL80211_REGDOM_SET_BY_USER:
+               break;
+       case NL80211_REGDOM_SET_BY_COUNTRY_IE:
+               _rtl_reg_apply_world_flags(wiphy, request->initiator, reg);
+               break;
+       }
+
+       _rtl_dump_channel_map(wiphy);
+
+       return 0;
+}
+
+static const struct ieee80211_regdomain *_rtl_regdomain_select(
+                                               struct rtl_regulatory *reg)
+{
+       switch (reg->country_code) {
+       case COUNTRY_CODE_FCC:
+               return &rtl_regdom_no_midband;
+       case COUNTRY_CODE_IC:
+               return &rtl_regdom_11;
+       case COUNTRY_CODE_ETSI:
+       case COUNTRY_CODE_TELEC_NETGEAR:
+               return &rtl_regdom_60_64;
+       case COUNTRY_CODE_SPAIN:
+       case COUNTRY_CODE_FRANCE:
+       case COUNTRY_CODE_ISRAEL:
+       case COUNTRY_CODE_WORLD_WIDE_13:
+               return &rtl_regdom_12_13;
+       case COUNTRY_CODE_MKK:
+       case COUNTRY_CODE_MKK1:
+       case COUNTRY_CODE_TELEC:
+       case COUNTRY_CODE_MIC:
+               return &rtl_regdom_14_60_64;
+       case COUNTRY_CODE_GLOBAL_DOMAIN:
+               return &rtl_regdom_14;
+       default:
+               return &rtl_regdom_no_midband;
+       }
+}
+
+static int _rtl92e_regd_init_wiphy(struct rtl_regulatory *reg,
+                                  struct wiphy *wiphy,
+                                  void (*reg_notifier)(struct wiphy *wiphy,
+                                                       struct regulatory_request *
+                                                       request))
+{
+       const struct ieee80211_regdomain *regd;
+
+       wiphy->reg_notifier = reg_notifier;
+
+       wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
+       wiphy->regulatory_flags &= ~REGULATORY_STRICT_REG;
+       wiphy->regulatory_flags &= ~REGULATORY_DISABLE_BEACON_HINTS;
+
+       regd = _rtl_regdomain_select(reg);
+       wiphy_apply_custom_regulatory(wiphy, regd);
+       _rtl_reg_apply_radar_flags(wiphy);
+       _rtl_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER, reg);
+       return 0;
+}
+
+static struct country_code_to_enum_rd *_rtl_regd_find_country(u16 countrycode)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(allcountries); i++) {
+               if (allcountries[i].countrycode == countrycode)
+                       return &allcountries[i];
+       }
+       return NULL;
+}
+
+int rtl92e_regd_init(struct ieee80211_hw *hw,
+                    void (*reg_notifier)(struct wiphy *wiphy,
+                                         struct regulatory_request *request))
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct wiphy *wiphy = hw->wiphy;
+       struct country_code_to_enum_rd *country = NULL;
+
+       if (wiphy == NULL || &rtlpriv->regd == NULL)
+               return -EINVAL;
+
+       /* init country_code from efuse channel plan */
+       rtlpriv->regd.country_code = rtlpriv->efuse.channel_plan;
+
+       RT_TRACE(COMP_REGD, DBG_TRACE,
+                (KERN_DEBUG "rtl: EEPROM regdomain: 0x%0x\n",
+                 rtlpriv->regd.country_code));
+
+       if (rtlpriv->regd.country_code >= COUNTRY_CODE_MAX) {
+               RT_TRACE(COMP_REGD, DBG_DMESG,
+                        ("rtl: EEPROM indicates invalid contry code world wide 13 should be used\n"));
+
+               rtlpriv->regd.country_code = COUNTRY_CODE_WORLD_WIDE_13;
+       }
+
+       country = _rtl_regd_find_country(rtlpriv->regd.country_code);
+
+       if (country) {
+               rtlpriv->regd.alpha2[0] = country->iso_name[0];
+               rtlpriv->regd.alpha2[1] = country->iso_name[1];
+       } else {
+               rtlpriv->regd.alpha2[0] = '0';
+               rtlpriv->regd.alpha2[1] = '0';
+       }
+
+       RT_TRACE(COMP_REGD, DBG_TRACE,
+                (KERN_DEBUG "rtl: Country alpha2 being used: %c%c\n",
+                 rtlpriv->regd.alpha2[0], rtlpriv->regd.alpha2[1]));
+
+       _rtl92e_regd_init_wiphy(&rtlpriv->regd, wiphy, reg_notifier);
+
+       return 0;
+}
+
+void rtl92e_reg_notifier(struct wiphy *wiphy,
+                        struct regulatory_request *request)
+{
+       struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       RT_TRACE(COMP_REGD, DBG_LOUD, ("\n"));
+
+       _rtl92e_reg_notifier_apply(wiphy, request, &rtlpriv->regd);
+}
diff --git a/drivers/staging/rtl8192ee/regd.h b/drivers/staging/rtl8192ee/regd.h
new file mode 100644 (file)
index 0000000..1f26f0e
--- /dev/null
@@ -0,0 +1,63 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL_REGD_H__
+#define __RTL_REGD_H__
+
+/* for kernel 3.14 , both value are changed to IEEE80211_CHAN_NO_IR*/
+#define IEEE80211_CHAN_NO_IBSS IEEE80211_CHAN_NO_IR
+#define IEEE80211_CHAN_PASSIVE_SCAN IEEE80211_CHAN_NO_IR
+
+struct country_code_to_enum_rd {
+       u16 countrycode;
+       const char *iso_name;
+};
+
+enum country_code_type_t {
+       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,
+
+       /*add new channel plan above this line */
+       COUNTRY_CODE_MAX
+};
+
+int rtl92e_regd_init(struct ieee80211_hw *hw,
+                    void (*reg_notifier)(struct wiphy *wiphy,
+                                         struct regulatory_request *request));
+void rtl92e_reg_notifier(struct wiphy *wiphy,
+                        struct regulatory_request *request);
+
+#endif
diff --git a/drivers/staging/rtl8192ee/stats.c b/drivers/staging/rtl8192ee/stats.c
new file mode 100644 (file)
index 0000000..7ac302b
--- /dev/null
@@ -0,0 +1,290 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+#include "wifi.h"
+#include "stats.h"
+
+u8 stg_rtl_query_rxpwrpercentage(char antpower)
+{
+       if ((antpower <= -100) || (antpower >= 20))
+               return 0;
+       else if (antpower >= 0)
+               return 100;
+       else
+               return 100 + antpower;
+}
+EXPORT_SYMBOL(stg_rtl_query_rxpwrpercentage);
+
+u8 stg_rtl_evm_db_to_percentage(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;
+}
+EXPORT_SYMBOL(stg_rtl_evm_db_to_percentage);
+
+u8 rtl_evm_dbm_jaguar(char value)
+{
+       char ret_val;
+       ret_val = value;
+
+       /* -33dB~0dB to 33dB ~ 0dB*/
+       if (ret_val == -128)
+               ret_val = 127;
+       else if (ret_val < 0)
+               ret_val = 0 - ret_val;
+
+       ret_val  = ret_val >> 1;
+       return ret_val;
+}
+EXPORT_SYMBOL(rtl_evm_dbm_jaguar);
+
+static long rtl_translate_todbm(struct ieee80211_hw *hw,
+                               u8 signal_strength_index)
+{
+       long signal_power;
+
+       signal_power = (long)((signal_strength_index + 1) >> 1);
+       signal_power -= 95;
+       return signal_power;
+}
+
+long stg_rtl_signal_scale_mapping(struct ieee80211_hw *hw, 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;
+}
+EXPORT_SYMBOL(stg_rtl_signal_scale_mapping);
+
+static void rtl_process_ui_rssi(struct ieee80211_hw *hw, struct rtl_stats *pstatus)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       u8 rfpath;
+       u32 last_rssi, tmpval;
+
+       if (!pstatus->b_packet_toself && !pstatus->b_packet_beacon)
+               return;
+
+       rtlpriv->stats.pwdb_all_cnt += pstatus->rx_pwdb_all;
+       rtlpriv->stats.rssi_calculate_cnt++;
+
+       if (rtlpriv->stats.ui_rssi.total_num++ >= PHY_RSSI_SLID_WIN_MAX) {
+               rtlpriv->stats.ui_rssi.total_num = PHY_RSSI_SLID_WIN_MAX;
+               last_rssi = rtlpriv->stats.ui_rssi.elements[
+                       rtlpriv->stats.ui_rssi.index];
+               rtlpriv->stats.ui_rssi.total_val -= last_rssi;
+       }
+       rtlpriv->stats.ui_rssi.total_val += pstatus->signalstrength;
+       rtlpriv->stats.ui_rssi.elements[rtlpriv->stats.ui_rssi.index++] =
+           pstatus->signalstrength;
+       if (rtlpriv->stats.ui_rssi.index >= PHY_RSSI_SLID_WIN_MAX)
+               rtlpriv->stats.ui_rssi.index = 0;
+       tmpval = rtlpriv->stats.ui_rssi.total_val /
+               rtlpriv->stats.ui_rssi.total_num;
+       rtlpriv->stats.signal_strength = rtl_translate_todbm(hw,
+               (u8) tmpval);
+       pstatus->rssi = rtlpriv->stats.signal_strength;
+
+       if (pstatus->b_is_cck)
+               return;
+
+       for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath;
+            rfpath++) {
+               if (rtlpriv->stats.rx_rssi_percentage[rfpath] == 0) {
+                       rtlpriv->stats.rx_rssi_percentage[rfpath] =
+                           pstatus->rx_mimo_signalstrength[rfpath];
+               }
+               if (pstatus->rx_mimo_signalstrength[rfpath] >
+                   rtlpriv->stats.rx_rssi_percentage[rfpath]) {
+                       rtlpriv->stats.rx_rssi_percentage[rfpath] =
+                           ((rtlpriv->stats.rx_rssi_percentage[rfpath] *
+                             (RX_SMOOTH_FACTOR - 1)) +
+                            (pstatus->rx_mimo_signalstrength[rfpath])) /
+                           (RX_SMOOTH_FACTOR);
+                       rtlpriv->stats.rx_rssi_percentage[rfpath] =
+                           rtlpriv->stats.rx_rssi_percentage[rfpath] + 1;
+               } else {
+                       rtlpriv->stats.rx_rssi_percentage[rfpath] =
+                           ((rtlpriv->stats.rx_rssi_percentage[rfpath] *
+                             (RX_SMOOTH_FACTOR - 1)) +
+                            (pstatus->rx_mimo_signalstrength[rfpath])) /
+                           (RX_SMOOTH_FACTOR);
+               }
+               rtlpriv->stats.rx_snr_db[rfpath] = pstatus->rx_snr[rfpath];
+               rtlpriv->stats.rx_evm_dbm[rfpath] =
+                                       pstatus->rx_mimo_evm_dbm[rfpath];
+               rtlpriv->stats.rx_cfo_short[rfpath] =
+                                       pstatus->cfo_short[rfpath];
+               rtlpriv->stats.rx_cfo_tail[rfpath] = pstatus->cfo_tail[rfpath];
+       }
+}
+
+static void rtl_update_rxsignalstatistics(struct ieee80211_hw *hw,
+                                         struct rtl_stats *pstatus)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       int weighting = 0;
+
+       if (rtlpriv->stats.recv_signal_power == 0)
+               rtlpriv->stats.recv_signal_power = pstatus->recvsignalpower;
+       if (pstatus->recvsignalpower > rtlpriv->stats.recv_signal_power)
+               weighting = 5;
+       else if (pstatus->recvsignalpower < rtlpriv->stats.recv_signal_power)
+               weighting = (-5);
+       rtlpriv->stats.recv_signal_power = (rtlpriv->stats.recv_signal_power *
+               5 + pstatus->recvsignalpower + weighting) / 6;
+}
+
+static void rtl_process_pwdb(struct ieee80211_hw *hw, struct rtl_stats *pstatus)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_sta_info *drv_priv = NULL;
+       struct ieee80211_sta *sta = NULL;
+       long undecorated_smoothed_pwdb;
+
+       rcu_read_lock();
+       if (rtlpriv->mac80211.opmode != NL80211_IFTYPE_STATION)
+               sta = rtl_find_sta(hw, pstatus->psaddr);
+
+       /* adhoc or ap mode */
+       if (sta) {
+               drv_priv = (struct rtl_sta_info *)sta->drv_priv;
+               undecorated_smoothed_pwdb =
+                       drv_priv->rssi_stat.undecorated_smoothed_pwdb;
+       } else {
+               undecorated_smoothed_pwdb =
+                       rtlpriv->dm.undecorated_smoothed_pwdb;
+       }
+
+       if (undecorated_smoothed_pwdb < 0)
+               undecorated_smoothed_pwdb = pstatus->rx_pwdb_all;
+       if (pstatus->rx_pwdb_all > (u32) undecorated_smoothed_pwdb) {
+               undecorated_smoothed_pwdb = (((undecorated_smoothed_pwdb) *
+                     (RX_SMOOTH_FACTOR - 1)) +
+                    (pstatus->rx_pwdb_all)) / (RX_SMOOTH_FACTOR);
+               undecorated_smoothed_pwdb = undecorated_smoothed_pwdb + 1;
+       } else {
+               undecorated_smoothed_pwdb = (((undecorated_smoothed_pwdb) *
+                     (RX_SMOOTH_FACTOR - 1)) +
+                    (pstatus->rx_pwdb_all)) / (RX_SMOOTH_FACTOR);
+       }
+
+       if (sta) {
+               drv_priv->rssi_stat.undecorated_smoothed_pwdb =
+                       undecorated_smoothed_pwdb;
+       } else {
+               rtlpriv->dm.undecorated_smoothed_pwdb = undecorated_smoothed_pwdb;
+       }
+       rcu_read_unlock();
+
+       rtl_update_rxsignalstatistics(hw, pstatus);
+}
+
+static void rtl_process_ui_link_quality(struct ieee80211_hw *hw,
+                                       struct rtl_stats *pstatus)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u32 last_evm, n_stream, tmpval;
+
+       if (pstatus->signalquality == 0)
+               return;
+
+       if (rtlpriv->stats.ui_link_quality.total_num++ >=
+           PHY_LINKQUALITY_SLID_WIN_MAX) {
+               rtlpriv->stats.ui_link_quality.total_num =
+                   PHY_LINKQUALITY_SLID_WIN_MAX;
+               last_evm = rtlpriv->stats.ui_link_quality.elements[
+                       rtlpriv->stats.ui_link_quality.index];
+               rtlpriv->stats.ui_link_quality.total_val -= last_evm;
+       }
+       rtlpriv->stats.ui_link_quality.total_val += pstatus->signalquality;
+       rtlpriv->stats.ui_link_quality.elements[
+               rtlpriv->stats.ui_link_quality.index++] =
+                                                       pstatus->signalquality;
+       if (rtlpriv->stats.ui_link_quality.index >=
+           PHY_LINKQUALITY_SLID_WIN_MAX)
+               rtlpriv->stats.ui_link_quality.index = 0;
+       tmpval = rtlpriv->stats.ui_link_quality.total_val /
+           rtlpriv->stats.ui_link_quality.total_num;
+       rtlpriv->stats.signal_quality = tmpval;
+       rtlpriv->stats.last_sigstrength_inpercent = tmpval;
+       for (n_stream = 0; n_stream < 2; n_stream++) {
+               if (pstatus->rx_mimo_signalquality[n_stream] != -1) {
+                       if (rtlpriv->stats.rx_evm_percentage[n_stream] == 0) {
+                               rtlpriv->stats.rx_evm_percentage[n_stream] =
+                                   pstatus->rx_mimo_signalquality[n_stream];
+                       }
+                       rtlpriv->stats.rx_evm_percentage[n_stream] =
+                           ((rtlpriv->stats.rx_evm_percentage[n_stream]
+                             * (RX_SMOOTH_FACTOR - 1)) +
+                            (pstatus->rx_mimo_signalquality[n_stream] * 1)) /
+                           (RX_SMOOTH_FACTOR);
+               }
+       }
+}
+
+void stg_rtl_process_phyinfo(struct ieee80211_hw *hw, u8 *buffer,
+                            struct rtl_stats *pstatus)
+{
+       if (!pstatus->b_packet_matchbssid)
+               return;
+
+       rtl_process_ui_rssi(hw, pstatus);
+       rtl_process_pwdb(hw, pstatus);
+       rtl_process_ui_link_quality(hw, pstatus);
+}
+EXPORT_SYMBOL(stg_rtl_process_phyinfo);
diff --git a/drivers/staging/rtl8192ee/stats.h b/drivers/staging/rtl8192ee/stats.h
new file mode 100644 (file)
index 0000000..0728427
--- /dev/null
@@ -0,0 +1,43 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL_STATS_H__
+#define __RTL_STATS_H__
+
+#define        PHY_RSSI_SLID_WIN_MAX                   100
+#define        PHY_LINKQUALITY_SLID_WIN_MAX            20
+#define        PHY_BEACON_RSSI_SLID_WIN_MAX            10
+
+/* Rx smooth factor */
+#define        RX_SMOOTH_FACTOR                        20
+
+u8 stg_rtl_query_rxpwrpercentage(char antpower);
+u8 stg_rtl_evm_db_to_percentage(char value);
+u8 rtl_evm_dbm_jaguar(char value);
+long stg_rtl_signal_scale_mapping(struct ieee80211_hw *hw, long currsig);
+void stg_rtl_process_phyinfo(struct ieee80211_hw *hw, u8 *buffer,
+                            struct rtl_stats *pstatus);
+
+#endif
diff --git a/drivers/staging/rtl8192ee/wifi.h b/drivers/staging/rtl8192ee/wifi.h
new file mode 100644 (file)
index 0000000..9cb0811
--- /dev/null
@@ -0,0 +1,2645 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL_WIFI_H__
+#define __RTL_WIFI_H__
+
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/firmware.h>
+#include <linux/version.h>
+#include <linux/etherdevice.h>
+#include <net/mac80211.h>
+#include "debug.h"
+
+
+#define RF_CHANGE_BY_INIT              0
+#define RF_CHANGE_BY_IPS               BIT(28)
+#define RF_CHANGE_BY_PS                        BIT(29)
+#define RF_CHANGE_BY_HW                        BIT(30)
+#define RF_CHANGE_BY_SW                        BIT(31)
+
+#define IQK_ADDA_REG_NUM               16
+#define IQK_MAC_REG_NUM                        4
+#define IQK_THRESHOLD                  8
+
+#define MAX_KEY_LEN                    61
+#define KEY_BUF_SIZE                   5
+
+/* QoS related. */
+/*aci: 0x00    Best Effort*/
+/*aci: 0x01    Background*/
+/*aci: 0x10    Video*/
+/*aci: 0x11    Voice*/
+/*Max: define total number.*/
+#define AC0_BE                         0
+#define AC1_BK                         1
+#define AC2_VI                         2
+#define AC3_VO                         3
+#define AC_MAX                         4
+#define QOS_QUEUE_NUM                  4
+#define RTL_MAC80211_NUM_QUEUE         5
+
+#define QBSS_LOAD_SIZE                 5
+#define MAX_WMMELE_LENGTH              64
+
+#define TOTAL_CAM_ENTRY                        32
+
+/*slot time for 11g. */
+#define RTL_SLOT_TIME_9                        9
+#define RTL_SLOT_TIME_20               20
+
+/*related with tcp/ip. */
+/*if_ehther.h*/
+#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 */
+#define SNAP_SIZE                      6
+#define PROTOC_TYPE_SIZE               2
+
+/*related with 802.11 frame*/
+#define MAC80211_3ADDR_LEN             24
+#define MAC80211_4ADDR_LEN             30
+
+#define CHANNEL_MAX_NUMBER             (14 + 24 + 21)  /* 14 is the max
+                                                        * channel number */
+#define CHANNEL_MAX_NUMBER_2G          14
+#define CHANNEL_MAX_NUMBER_5G          54 /* Please refer to
+                                           *"phy_GetChnlGroup8812A" and
+                                           * "Hal_ReadTxPowerInfo8812A"*/
+
+#define MAX_REGULATION_NUM                     4
+#define MAX_RF_PATH_NUM        2
+#define MAX_RATE_SECTION_NUM           6
+#define MAX_2_4G_BANDWITH_NUM          2
+#define MAX_5G_BANDWITH_NUM            4
+
+
+
+
+#define CHANNEL_MAX_NUMBER_5G_80M      7
+#define CHANNEL_GROUP_MAX              (3 + 9) /* ch1~3, ch4~9, ch10~14
+                                                * total three groups */
+#define MAX_PG_GROUP                   13
+#define        CHANNEL_GROUP_MAX_2G            3
+#define        CHANNEL_GROUP_IDX_5GL           3
+#define        CHANNEL_GROUP_IDX_5GM           6
+#define        CHANNEL_GROUP_IDX_5GH           9
+#define        CHANNEL_GROUP_MAX_5G            9
+#define CHANNEL_MAX_NUMBER_2G          14
+#define AVG_THERMAL_NUM                        8
+#define AVG_THERMAL_NUM_92E            4
+#define AVG_THERMAL_NUM_88E            4
+#define AVG_THERMAL_NUM_8723BE         4
+#define MAX_TID_COUNT                  9
+#define MAX_NUM_RATES                  264
+
+/*for 88E use*/
+/*It must always set to 4, otherwise read efuse table secquence will be wrong.*/
+#define MAX_TX_COUNT                   4
+#define        MAX_RF_PATH                     4
+#define        MAX_CHNL_GROUP_24G              6
+#define        MAX_CHNL_GROUP_5G               14
+
+/* BK, BE, VI, VO, HCCA, MANAGEMENT, COMMAND, HIGH, BEACON. */
+#define MAX_TX_QUEUE                   9
+
+#define TX_PWR_BY_RATE_NUM_BAND                2
+#define TX_PWR_BY_RATE_NUM_RF          4
+#define TX_PWR_BY_RATE_NUM_SECTION     12
+#define MAX_BASE_NUM_IN_PHY_REG_PG_24G  6
+#define MAX_BASE_NUM_IN_PHY_REG_PG_5G  5
+
+#define DELTA_SWINGIDX_SIZE    30
+#define BAND_NUM                               3
+/*Now, it's just for 8192ee
+ *not OK yet, keep it 0*/
+#define DMA_IS_64BIT 0
+#define RTL8192EE_SEG_NUM              1 /* 0:2 seg, 1: 4 seg, 2: 8 seg */
+
+
+#define PACKET_NORMAL                  0
+#define PACKET_DHCP                    1
+#define PACKET_ARP                     2
+#define PACKET_EAPOL                   3
+
+#define        MAX_SUPPORT_WOL_PATTERN_NUM     16
+#define        RSVD_WOL_PATTERN_NUM            1
+#define        WKFMCAM_ADDR_NUM                6
+#define        WKFMCAM_SIZE                    24
+
+#define        MAX_WOL_BIT_MASK_SIZE           16
+/* MIN LEN keeps 13 here */
+#define        MIN_WOL_PATTERN_SIZE            13
+#define        MAX_WOL_PATTERN_SIZE            128
+
+#define        WAKE_ON_MAGIC_PACKET            BIT(0)
+#define        WAKE_ON_PATTERN_MATCH           BIT(1)
+
+#define        WOL_REASON_PTK_UPDATE           BIT(0)
+#define        WOL_REASON_GTK_UPDATE           BIT(1)
+#define        WOL_REASON_DISASSOC             BIT(2)
+#define        WOL_REASON_DEAUTH               BIT(3)
+#define        WOL_REASON_AP_LOST              BIT(4)
+#define        WOL_REASON_MAGIC_PKT            BIT(5)
+#define        WOL_REASON_UNICAST_PKT          BIT(6)
+#define        WOL_REASON_PATTERN_PKT          BIT(7)
+#define        WOL_REASON_RTD3_SSID_MATCH      BIT(8)
+#define        WOL_REASON_REALWOW_V2_WAKEUPPKT BIT(9)
+#define        WOL_REASON_REALWOW_V2_ACKLOST   BIT(10)
+
+struct txpower_info_2g {
+       u8 index_cck_base[MAX_RF_PATH][MAX_CHNL_GROUP_24G];
+       u8 index_bw40_base[MAX_RF_PATH][MAX_CHNL_GROUP_24G];
+       /*If only one tx, only BW20 and OFDM are used.*/
+       u8 cck_diff[MAX_RF_PATH][MAX_TX_COUNT];
+       u8 ofdm_diff[MAX_RF_PATH][MAX_TX_COUNT];
+       u8 bw20_diff[MAX_RF_PATH][MAX_TX_COUNT];
+       u8 bw40_diff[MAX_RF_PATH][MAX_TX_COUNT];
+};
+
+struct txpower_info_5g {
+       u8 index_bw40_base[MAX_RF_PATH][MAX_CHNL_GROUP_5G];
+       /*If only one tx, only BW20, OFDM, BW80 and BW160 are used.*/
+       u8 ofdm_diff[MAX_RF_PATH][MAX_TX_COUNT];
+       u8 bw20_diff[MAX_RF_PATH][MAX_TX_COUNT];
+       u8 bw40_diff[MAX_RF_PATH][MAX_TX_COUNT];
+       u8 bw80_diff[MAX_RF_PATH][MAX_TX_COUNT];
+       u8 bw160_diff[MAX_RF_PATH][MAX_TX_COUNT];
+};
+
+
+/* for early mode */
+#define EM_HDR_LEN                     8
+#define FCS_LEN                                4
+
+#define MAX_VIRTUAL_MAC                        1
+
+enum rf_tx_num {
+       RF_1TX = 0,
+       RF_2TX,
+       RF_MAX_TX_NUM,
+       RF_TX_NUM_NONIMPLEMENT,
+};
+
+enum rate_section {
+       CCK = 0,
+       OFDM,
+       HT_MCS0_MCS7,
+       HT_MCS8_MCS15,
+       VHT_1SSMCS0_1SSMCS9,
+       VHT_2SSMCS0_2SSMCS9,
+};
+
+enum intf_type {
+       INTF_PCI = 0,
+       INTF_USB = 1,
+};
+
+enum radio_path {
+       RF90_PATH_A = 0,
+       RF90_PATH_B = 1,
+       RF90_PATH_C = 2,
+       RF90_PATH_D = 3,
+};
+
+enum regulation_txpwr_lmt {
+       TXPWR_LMT_FCC = 0,
+       TXPWR_LMT_MKK = 1,
+       TXPWR_LMT_ETSI = 2,
+       TXPWR_LMT_WW = 3,
+
+       TXPWR_LMT_MAX_REGULATION_NUM = 4
+};
+
+
+enum rt_eeprom_type {
+       EEPROM_93C46,
+       EEPROM_93C56,
+       EEPROM_BOOT_EFUSE,
+};
+
+enum rtl_status {
+       RTL_STATUS_INTERFACE_START = 0,
+};
+
+enum hardware_type {
+       HARDWARE_TYPE_RTL8192E,
+       HARDWARE_TYPE_RTL8192U,
+       HARDWARE_TYPE_RTL8192SE,
+       HARDWARE_TYPE_RTL8192SU,
+       HARDWARE_TYPE_RTL8192CE,
+       HARDWARE_TYPE_RTL8192CU,
+       HARDWARE_TYPE_RTL8192DE,
+       HARDWARE_TYPE_RTL8192DU,
+       HARDWARE_TYPE_RTL8723AE,
+       HARDWARE_TYPE_RTL8188EE,
+       HARDWARE_TYPE_RTL8723BE,
+       HARDWARE_TYPE_RTL8192EE,
+       HARDWARE_TYPE_RTL8821AE,
+       HARDWARE_TYPE_RTL8812AE,
+       /* keep it last */
+       HARDWARE_TYPE_NUM
+};
+
+enum scan_operation_backup_opt {
+       SCAN_OPT_BACKUP_BAND0 = 0,
+       SCAN_OPT_BACKUP_BAND1,
+       SCAN_OPT_RESTORE,
+       SCAN_OPT_MAX
+};
+
+/*RF state.*/
+enum rf_pwrstate {
+       ERFON,
+       ERFSLEEP,
+       ERFOFF
+};
+
+struct bb_reg_def {
+       u32 rfintfs;
+       u32 rfintfi;
+       u32 rfintfo;
+       u32 rfintfe;
+       u32 rf3wire_offset;
+       u32 rflssi_select;
+       u32 rftxgain_stage;
+       u32 rfhssi_para1;
+       u32 rfhssi_para2;
+       u32 rfswitch_control;
+       u32 rfagc_control1;
+       u32 rfagc_control2;
+       u32 rfrxiq_imbalance;
+       u32 rfrx_afe;
+       u32 rftxiq_imbalance;
+       u32 rftx_afe;
+       u32 rflssi_readback;
+       u32 rflssi_readbackpi;
+};
+
+enum io_type {
+       IO_CMD_PAUSE_BAND0_DM_BY_SCAN = 0,
+       IO_CMD_PAUSE_BAND1_DM_BY_SCAN = 1,
+       IO_CMD_RESUME_DM_BY_SCAN = 2,
+};
+
+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_R2T_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_H2C_FW_MEDIASTATUSRPT,
+       HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
+       HW_VAR_FW_PSMODE_STATUS,
+       HW_VAR_INIT_RTS_RATE,
+       HW_VAR_RESUME_CLK_ON,
+       HW_VAR_FW_LPS_ACTION,
+       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,
+
+       HAL_DEF_WOWLAN,
+       HW_VAR_MRC,
+       HW_VAR_KEEP_ALIVE,
+       HW_VAR_NAV_UPPER,
+};
+
+enum rt_media_status {
+       RT_MEDIA_DISCONNECT = 0,
+       RT_MEDIA_CONNECT = 1
+};
+
+enum rt_oem_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,
+       RT_CID_819x_Foxcoon = 32,
+       RT_CID_819x_DELL = 33,
+       RT_CID_819x_PRONETS = 34,
+       RT_CID_819x_Edimax_ASUS = 35,
+       RT_CID_NETGEAR = 36,
+       RT_CID_PLANEX = 37,
+       RT_CID_CC_C = 38,
+};
+
+enum hw_descs {
+       HW_DESC_OWN,
+       HW_DESC_RXOWN,
+       HW_DESC_TX_NEXTDESC_ADDR,
+       HW_DESC_TXBUFF_ADDR,
+       HW_DESC_RXBUFF_ADDR,
+       HW_DESC_RXPKT_LEN,
+       HW_DESC_RXERO,
+       HW_DESC_RX_PREPARE,
+};
+
+enum prime_sc {
+       PRIME_CHNL_OFFSET_DONT_CARE = 0,
+       PRIME_CHNL_OFFSET_LOWER = 1,
+       PRIME_CHNL_OFFSET_UPPER = 2,
+};
+
+enum rf_type {
+       RF_1T1R = 0,
+       RF_1T2R = 1,
+       RF_2T2R = 2,
+       RF_2T2R_GREEN = 3,
+};
+
+enum ht_channel_width {
+       HT_CHANNEL_WIDTH_20 = 0,
+       HT_CHANNEL_WIDTH_20_40 = 1,
+       HT_CHANNEL_WIDTH_80 = 2,
+};
+
+/* Ref: 802.11i sepc D10.0 7.3.2.25.1
+Cipher Suites Encryption Algorithms */
+enum rt_enc_alg {
+       NO_ENCRYPTION = 0,
+       WEP40_ENCRYPTION = 1,
+       TKIP_ENCRYPTION = 2,
+       RSERVED_ENCRYPTION = 3,
+       AESCCMP_ENCRYPTION = 4,
+       WEP104_ENCRYPTION = 5,
+       AESCMAC_ENCRYPTION = 6, /*IEEE802.11w */
+};
+
+enum rtl_hal_state {
+       _HAL_STATE_STOP = 0,
+       _HAL_STATE_START = 1,
+};
+
+enum rtl_var_map {
+       /*reg map */
+       SYS_ISO_CTRL = 0,
+       SYS_FUNC_EN,
+       SYS_CLK,
+       MAC_RCR_AM,
+       MAC_RCR_AB,
+       MAC_RCR_ACRC32,
+       MAC_RCR_ACF,
+       MAC_RCR_AAP,
+       MAC_HIMR,
+       MAC_HIMRE,
+       MAC_HSISR,
+
+       /*efuse map */
+       EFUSE_TEST,
+       EFUSE_CTRL,
+       EFUSE_CLK,
+       EFUSE_CLK_CTRL,
+       EFUSE_PWC_EV12V,
+       EFUSE_FEN_ELDR,
+       EFUSE_LOADER_CLK_EN,
+       EFUSE_ANA8M,
+       EFUSE_HWSET_MAX_SIZE,
+       EFUSE_MAX_SECTION_MAP,
+       EFUSE_REAL_CONTENT_SIZE,
+       EFUSE_OOB_PROTECT_BYTES_LEN,
+       EFUSE_ACCESS,
+       /*CAM map */
+       RWCAM,
+       WCAMI,
+       RCAMO,
+       CAMDBG,
+       SECR,
+       SEC_CAM_NONE,
+       SEC_CAM_WEP40,
+       SEC_CAM_TKIP,
+       SEC_CAM_AES,
+       SEC_CAM_WEP104,
+
+       /*IMR map */
+       RTL_IMR_BCNDMAINT6,     /*Beacon DMA Interrupt 6 */
+       RTL_IMR_BCNDMAINT5,     /*Beacon DMA Interrupt 5 */
+       RTL_IMR_BCNDMAINT4,     /*Beacon DMA Interrupt 4 */
+       RTL_IMR_BCNDMAINT3,     /*Beacon DMA Interrupt 3 */
+       RTL_IMR_BCNDMAINT2,     /*Beacon DMA Interrupt 2 */
+       RTL_IMR_BCNDMAINT1,     /*Beacon DMA Interrupt 1 */
+       RTL_IMR_BCNDOK8,        /*Beacon Queue DMA OK Interrup 8 */
+       RTL_IMR_BCNDOK7,        /*Beacon Queue DMA OK Interrup 7 */
+       RTL_IMR_BCNDOK6,        /*Beacon Queue DMA OK Interrup 6 */
+       RTL_IMR_BCNDOK5,        /*Beacon Queue DMA OK Interrup 5 */
+       RTL_IMR_BCNDOK4,        /*Beacon Queue DMA OK Interrup 4 */
+       RTL_IMR_BCNDOK3,        /*Beacon Queue DMA OK Interrup 3 */
+       RTL_IMR_BCNDOK2,        /*Beacon Queue DMA OK Interrup 2 */
+       RTL_IMR_BCNDOK1,        /*Beacon Queue DMA OK Interrup 1 */
+       RTL_IMR_TIMEOUT2,       /*Timeout interrupt 2 */
+       RTL_IMR_TIMEOUT1,       /*Timeout interrupt 1 */
+       RTL_IMR_TXFOVW,         /*Transmit FIFO Overflow */
+       RTL_IMR_PSTIMEOUT,      /*Power save time out interrupt */
+       RTL_IMR_BcnInt,         /*Beacon DMA Interrupt 0 */
+       RTL_IMR_RXFOVW,         /*Receive FIFO Overflow */
+       RTL_IMR_RDU,            /*Receive Descriptor Unavailable */
+       RTL_IMR_ATIMEND,        /*For 92C,ATIM Window End Interrupt */
+       RTL_IMR_BDOK,           /*Beacon Queue DMA OK Interrup */
+       RTL_IMR_HIGHDOK,        /*High Queue DMA OK Interrupt */
+       RTL_IMR_COMDOK,         /*Command Queue DMA OK Interrupt*/
+       RTL_IMR_TBDOK,          /*Transmit Beacon OK interrup */
+       RTL_IMR_MGNTDOK,        /*Management Queue DMA OK Interrupt */
+       RTL_IMR_TBDER,          /*For 92C,Transmit Beacon Error Interrupt */
+       RTL_IMR_BKDOK,          /*AC_BK DMA OK Interrupt */
+       RTL_IMR_BEDOK,          /*AC_BE DMA OK Interrupt */
+       RTL_IMR_VIDOK,          /*AC_VI DMA OK Interrupt */
+       RTL_IMR_VODOK,          /*AC_VO DMA Interrupt */
+       RTL_IMR_ROK,            /*Receive DMA OK Interrupt */
+       RTL_IMR_HSISR_IND,  /*HSISR Interrupt*/
+       RTL_IBSS_INT_MASKS,     /*(RTL_IMR_BcnInt | RTL_IMR_TBDOK |
+                                * RTL_IMR_TBDER) */
+       RTL_IMR_C2HCMD,         /*fw interrupt*/
+
+       /*CCK Rates, TxHT = 0 */
+       RTL_RC_CCK_RATE1M,
+       RTL_RC_CCK_RATE2M,
+       RTL_RC_CCK_RATE5_5M,
+       RTL_RC_CCK_RATE11M,
+
+       /*OFDM Rates, TxHT = 0 */
+       RTL_RC_OFDM_RATE6M,
+       RTL_RC_OFDM_RATE9M,
+       RTL_RC_OFDM_RATE12M,
+       RTL_RC_OFDM_RATE18M,
+       RTL_RC_OFDM_RATE24M,
+       RTL_RC_OFDM_RATE36M,
+       RTL_RC_OFDM_RATE48M,
+       RTL_RC_OFDM_RATE54M,
+
+       RTL_RC_HT_RATEMCS7,
+       RTL_RC_HT_RATEMCS15,
+
+       RTL_RC_VHT_RATE_1SS_MCS7,
+       RTL_RC_VHT_RATE_1SS_MCS8,
+       RTL_RC_VHT_RATE_1SS_MCS9,
+       RTL_RC_VHT_RATE_2SS_MCS7,
+       RTL_RC_VHT_RATE_2SS_MCS8,
+       RTL_RC_VHT_RATE_2SS_MCS9,
+
+       /*keep it last */
+       RTL_VAR_MAP_MAX,
+};
+
+/*Firmware PS mode for control LPS.*/
+enum _fw_ps_mode {
+       FW_PS_ACTIVE_MODE = 0,
+       FW_PS_MIN_MODE = 1,
+       FW_PS_MAX_MODE = 2,
+       FW_PS_DTIM_MODE = 3,
+       FW_PS_VOIP_MODE = 4,
+       FW_PS_UAPSD_WMM_MODE = 5,
+       FW_PS_UAPSD_MODE = 6,
+       FW_PS_IBSS_MODE = 7,
+       FW_PS_WWLAN_MODE = 8,
+       FW_PS_PM_Radio_Off = 9,
+       FW_PS_PM_Card_Disable = 10,
+};
+
+enum rt_psmode {
+       EACTIVE,                /*Active/Continuous access. */
+       EMAXPS,                 /*Max power save mode. */
+       EFASTPS,                /*Fast power save mode. */
+       EAUTOPS,                /*Auto power save mode. */
+};
+
+/*LED related.*/
+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,
+};
+
+enum rtl_led_pin {
+       LED_PIN_GPIO0,
+       LED_PIN_LED0,
+       LED_PIN_LED1,
+       LED_PIN_LED2
+};
+
+/*QoS related.*/
+/*acm implementation method.*/
+enum acm_method {
+       eAcmWay0_SwAndHw = 0,
+       eAcmWay1_HW = 1,
+       eAcmWay2_SW = 2,
+};
+
+enum macphy_mode {
+       SINGLEMAC_SINGLEPHY = 0,
+       DUALMAC_DUALPHY,
+       DUALMAC_SINGLEPHY,
+};
+
+enum band_type {
+       BAND_ON_2_4G = 0,
+       BAND_ON_5G,
+       BAND_ON_BOTH,
+       BANDMAX
+};
+
+/*aci/aifsn Field.
+Ref: WMM spec 2.2.2: WME Parameter Element, p.12.*/
+union aci_aifsn {
+       u8 char_data;
+
+       struct {
+               u8 aifsn:4;
+               u8 acm:1;
+               u8 aci:2;
+               u8 reserved:1;
+       } f;                    /* Field */
+};
+
+/*mlme related.*/
+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,
+       WIRELESS_MODE_AC_5G = 0x40,
+       WIRELESS_MODE_AC_24G = 0x80,
+       WIRELESS_MODE_AC_ONLY = 0x100,
+       WIRELESS_MODE_MAX = 0x800
+};
+
+enum ratr_table_mode {
+       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_AC_5N = 8,
+       RATR_INX_WIRELESS_AC_24N = 9,
+};
+
+enum rtl_link_state {
+       MAC80211_NOLINK = 0,
+       MAC80211_LINKING = 1,
+       MAC80211_LINKED = 2,
+       MAC80211_LINKED_SCANNING = 3,
+};
+
+enum act_category {
+       ACT_CAT_QOS = 1,
+       ACT_CAT_DLS = 2,
+       ACT_CAT_BA = 3,
+       ACT_CAT_HT = 7,
+       ACT_CAT_WMM = 17,
+};
+
+enum ba_action {
+       ACT_ADDBAREQ = 0,
+       ACT_ADDBARSP = 1,
+       ACT_DELBA = 2,
+};
+
+enum rt_polarity_ctl {
+       RT_POLARITY_LOW_ACT = 0,
+       RT_POLARITY_HIGH_ACT = 1,
+};
+
+/* After 8188E, we use V2 reason define. 88C/8723A use V1 reason. */
+enum fw_wow_reason_v2 {
+       FW_WOW_V2_PTK_UPDATE_EVENT = 0x01,
+       FW_WOW_V2_GTK_UPDATE_EVENT = 0x02,
+       FW_WOW_V2_DISASSOC_EVENT = 0x04,
+       FW_WOW_V2_DEAUTH_EVENT = 0x08,
+       FW_WOW_V2_FW_DISCONNECT_EVENT = 0x10,
+       FW_WOW_V2_MAGIC_PKT_EVENT = 0x21,
+       FW_WOW_V2_UNICAST_PKT_EVENT = 0x22,
+       FW_WOW_V2_PATTERN_PKT_EVENT = 0x23,
+       FW_WOW_V2_RTD3_SSID_MATCH_EVENT = 0x24,
+       FW_WOW_V2_REALWOW_V2_WAKEUPPKT = 0x30,
+       FW_WOW_V2_REALWOW_V2_ACKLOST = 0x31,
+       FW_WOW_V2_REASON_MAX = 0xff,
+};
+
+enum wolpattern_type {
+       UNICAST_PATTERN = 0,
+       MULTICAST_PATTERN = 1,
+       BROADCAST_PATTERN = 2,
+       DONT_CARE_DA = 3,
+       UNKNOWN_TYPE = 4,
+};
+
+struct octet_string {
+       u8 *octet;
+       u16 length;
+};
+
+struct rtl_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 rtl_info_element {
+       u8 id;
+       u8 len;
+       u8 data[0];
+} __packed;
+
+struct rtl_probe_rsp {
+       struct rtl_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 rtl_info_element info_element[0];
+} __packed;
+
+/*LED related.*/
+/*ledpin Identify how to implement this SW led.*/
+struct rtl_led {
+       void *hw;
+       enum rtl_led_pin ledpin;
+       bool b_ledon;
+};
+
+struct rtl_led_ctl {
+       bool bled_opendrain;
+       struct rtl_led sw_led0;
+       struct rtl_led sw_led1;
+};
+
+struct rtl_qos_parameters {
+       __le16 cw_min;
+       __le16 cw_max;
+       u8 aifs;
+       u8 flag;
+       __le16 tx_op;
+} __packed;
+
+struct rt_smooth_data {
+       u32 elements[100];      /*array to store values */
+       u32 index;              /*index to current array to store */
+       u32 total_num;          /*num of valid elements */
+       u32 total_val;          /*sum of valid elements */
+};
+
+struct rtl_ht_agg {
+       u16 txq_id;
+       u16 wait_for_ba;
+       u16 start_idx;
+       u64 bitmap;
+       u32 rate_n_flags;
+       u8 agg_state;
+       u8 rx_agg_state;
+};
+
+struct rtl_tid_data {
+       u16 seq_number;
+       struct rtl_ht_agg agg;
+};
+
+struct rssi_sta {
+       long undecorated_smoothed_pwdb;
+};
+
+struct rtl_sta_info {
+       struct list_head list;
+       u8 ratr_index;
+       u8 wireless_mode;
+       u8 mimo_ps;
+       u8 mac_addr[6];
+       struct rtl_tid_data tids[MAX_TID_COUNT];
+
+       /* just used for ap adhoc or mesh*/
+       struct rssi_sta rssi_stat;
+} __packed;
+
+struct false_alarm_statistics {
+       u32 cnt_parity_fail;
+       u32 cnt_rate_illegal;
+       u32 cnt_crc8_fail;
+       u32 cnt_mcs_fail;
+       u32 cnt_fast_fsync_fail;
+       u32 cnt_sb_search_fail;
+       u32 cnt_ofdm_fail;
+       u32 cnt_cck_fail;
+       u32 cnt_all;
+       u32 cnt_ofdm_cca;
+       u32 cnt_cck_cca;
+       u32 cnt_cca_all;
+       u32 cnt_bw_usc;
+       u32 cnt_bw_lsc;
+};
+
+struct init_gain {
+       u8 xaagccore1;
+       u8 xbagccore1;
+       u8 xcagccore1;
+       u8 xdagccore1;
+       u8 cca;
+
+};
+
+struct wireless_stats {
+       unsigned long txbytesunicast;
+       unsigned long txbytesmulticast;
+       unsigned long txbytesbroadcast;
+       unsigned long rxbytesunicast;
+
+       long rx_snr_db[4];
+       /*Correct smoothed ss in Dbm, only used
+          in driver to report real power now. */
+       long recv_signal_power;
+       long signal_quality;
+       long last_sigstrength_inpercent;
+
+       u32 rssi_calculate_cnt;
+       u32 pwdb_all_cnt;
+
+       /*Transformed, in dbm. Beautified signal
+          strength for UI, not correct. */
+       long signal_strength;
+
+       u8 rx_rssi_percentage[4];
+       u8 rx_evm_dbm[4];
+       u8 rx_evm_percentage[2];
+
+       u16 rx_cfo_short[4];
+       u16 rx_cfo_tail[4];
+
+       struct rt_smooth_data ui_rssi;
+       struct rt_smooth_data ui_link_quality;
+};
+
+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_ra;
+       u32 low_rssi_thresh_for_ra;
+       u32 upper_rssi_threshold_ratr;
+       u32 middleupper_rssi_threshold_ratr;
+       u32 middle_rssi_threshold_ratr;
+       u32 middlelow_rssi_threshold_ratr;
+       u32 low_rssi_threshold_ratr;
+       u32 ultralow_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 pre_ratr_state;
+       u8 ldpc_thres;
+       bool use_ldpc;
+       bool lower_rts_rate;
+       bool is_special_data;
+};
+
+struct regd_pair_mapping {
+       u16 reg_dmnenum;
+       u16 reg_5ghz_ctl;
+       u16 reg_2ghz_ctl;
+};
+
+struct dynamic_primary_cca {
+       u8 pricca_flag;
+       u8 intf_flag;
+       u8 intf_type;
+       u8 dup_rts_flag;
+       u8 monitor_flag;
+       u8 ch_offset;
+       u8 mf_state;
+};
+
+struct rtl_regulatory {
+       char alpha2[2];
+       u16 country_code;
+       u16 max_power_level;
+       u32 tp_scale;
+       u16 current_rd;
+       u16 current_rd_ext;
+       int16_t power_limit;
+       struct regd_pair_mapping *regpair;
+};
+
+struct rtl_rfkill {
+       bool rfkill_state;      /*0 is off, 1 is on */
+};
+
+/*for P2P PS**/
+#define        P2P_MAX_NOA_NUM         2
+
+enum p2p_role {
+       P2P_ROLE_DISABLE = 0,
+       P2P_ROLE_DEVICE = 1,
+       P2P_ROLE_CLIENT = 2,
+       P2P_ROLE_GO = 3
+};
+
+enum p2p_ps_state {
+       P2P_PS_DISABLE = 0,
+       P2P_PS_ENABLE = 1,
+       P2P_PS_SCAN = 2,
+       P2P_PS_SCAN_DONE = 3,
+       P2P_PS_ALLSTASLEEP = 4, /* for P2P GO */
+};
+
+enum p2p_ps_mode {
+       P2P_PS_NONE = 0,
+       P2P_PS_CTWINDOW = 1,
+       P2P_PS_NOA = 2,
+       P2P_PS_MIX = 3, /* CTWindow and NoA*/
+};
+
+struct rtl_p2p_ps_info {
+       enum p2p_ps_mode p2p_ps_mode; /* indicate p2p ps mode */
+       enum p2p_ps_state p2p_ps_state; /* indicate p2p ps state */
+       u8 noa_index; /* Identifies and instance of Notice of Absence timing. */
+       /* Client traffic window. A period of time in TU after TBTT. */
+       u8 ctwindow;
+       u8 opp_ps; /* opportunistic power save. */
+       u8 noa_num; /* number of NoA descriptor in P2P IE. */
+       /* Count for owner, Type of client. */
+       u8 noa_count_type[P2P_MAX_NOA_NUM];
+       /* Max duration for owner, preferred or
+        * min acceptable duration for client. */
+       u32 noa_duration[P2P_MAX_NOA_NUM];
+       /* Length of interval for owner, preferred or
+        * max acceptable interval of client. */
+       u32 noa_interval[P2P_MAX_NOA_NUM];
+       /* schedule expressed in terms of the lower 4 bytes of the TSF timer. */
+       u32 noa_start_time[P2P_MAX_NOA_NUM];
+};
+
+struct p2p_ps_offload_t {
+       u8 Offload_En:1;
+       u8 role:1; /* 1: Owner, 0: Client */
+       u8 CTWindow_En:1;
+       u8 NoA0_En:1;
+       u8 NoA1_En:1;
+       u8 AllStaSleep:1;
+       u8 discovery:1;
+       u8 reserved:1;
+};
+
+#define IQK_MATRIX_REG_NUM     8
+/* Channels_2_4G_NUM + Channels_5G_20M_NUM + Channels_5G */
+#define IQK_MATRIX_SETTINGS_NUM        (14 + 24 + 21)
+struct iqk_matrix_regs {
+       bool b_iqk_done;
+       long value[1][IQK_MATRIX_REG_NUM];
+};
+
+struct rtl_phy {
+       struct bb_reg_def phyreg_def[4];        /*Radio A/B/C/D */
+       struct init_gain initgain_backup;
+       enum io_type current_io_type;
+
+       u8 rf_mode;
+       u8 rf_type;
+       u8 current_chan_bw;
+       u8 set_bwmode_inprogress;
+       u8 sw_chnl_inprogress;
+       u8 sw_chnl_stage;
+       u8 sw_chnl_step;
+       u8 current_channel;
+       u8 h2c_box_num;
+       u8 set_io_inprogress;
+       u8 lck_inprogress;
+       bool iqk_inprogress;
+
+       /* record for power tracking */
+       s32 reg_e94;
+       s32 reg_e9c;
+       s32 reg_ea4;
+       s32 reg_eac;
+       s32 reg_eb4;
+       s32 reg_ebc;
+       s32 reg_ec4;
+       s32 reg_ecc;
+       u8 rfpienable;
+       u8 reserve_0;
+       u16 reserve_1;
+       u32 reg_c04, reg_c08, reg_874;
+       u32 adda_backup[16];
+       u32 iqk_mac_backup[IQK_MAC_REG_NUM];
+       u32 iqk_bb_backup[10];
+       bool iqk_initialized;
+
+       bool rfpath_rx_enable[MAX_RF_PATH];
+       /*Jaguar*/
+       u8 reg_837;
+       /* Dul mac */
+       bool b_need_iqk;
+       struct iqk_matrix_regs iqk_matrix_regsetting[IQK_MATRIX_SETTINGS_NUM];
+
+       bool b_rfpi_enable;
+
+       u8 pwrgroup_cnt;
+       u8 bcck_high_power;
+       /* this is for 88E & 8723A */
+       u32 mcs_txpwrlevel_origoffset[MAX_PG_GROUP][16];
+       /* this is for 92EE */
+       u32 tx_power_by_rate_offset[TX_PWR_BY_RATE_NUM_BAND]
+                                  [TX_PWR_BY_RATE_NUM_RF]
+                                  [TX_PWR_BY_RATE_NUM_RF]
+                                  [TX_PWR_BY_RATE_NUM_SECTION];
+       u8 txpwr_by_rate_base_24g[TX_PWR_BY_RATE_NUM_RF]
+                                [TX_PWR_BY_RATE_NUM_RF]
+                                [MAX_BASE_NUM_IN_PHY_REG_PG_24G];
+
+       u8 txpwr_by_rate_base_5g[TX_PWR_BY_RATE_NUM_RF]
+                               [TX_PWR_BY_RATE_NUM_RF]
+                               [MAX_BASE_NUM_IN_PHY_REG_PG_5G];
+       u8 default_initialgain[4];
+
+       /* the current Tx power level */
+       u8 cur_cck_txpwridx;
+       u8 cur_ofdm24g_txpwridx;
+       u8 cur_bw20_txpwridx;
+       u8 cur_bw40_txpwridx;
+
+       char txpwr_limit_2_4g[MAX_REGULATION_NUM]
+                               [MAX_2_4G_BANDWITH_NUM]
+                               [MAX_RATE_SECTION_NUM]
+                               [CHANNEL_MAX_NUMBER_2G]
+                               [MAX_RF_PATH_NUM];
+       char txpwr_limit_5g[MAX_REGULATION_NUM]
+                          [MAX_5G_BANDWITH_NUM]
+                          [MAX_RATE_SECTION_NUM]
+                          [CHANNEL_MAX_NUMBER_5G]
+                          [MAX_RF_PATH_NUM];
+
+       u32 rfreg_chnlval[2];
+       bool b_apk_done;
+       u32 reg_rf3c[2];        /* pathA / pathB  */
+
+       u32 backup_rf_0x1a;/*92ee*/
+       /* bfsync */
+       u8 framesync;
+       u32 framesync_c34;
+
+       u8 num_total_rfpath;
+       u16 rf_pathmap;
+
+       enum rt_polarity_ctl polarity_ctl;
+};
+
+#define RTL_AGG_STOP                                           0
+#define RTL_AGG_PROGRESS                                       1
+#define RTL_AGG_START                                          2
+#define RTL_AGG_OPERATIONAL                                    3
+#define RTL_RX_AGG_START                                       1
+#define RTL_RX_AGG_STOP                                                0
+
+struct rtl_priv;
+struct rtl_io {
+       struct device *dev;
+
+       /*PCI MEM map */
+       unsigned long pci_mem_end;      /*shared mem end        */
+       unsigned long pci_mem_start;    /*shared mem start */
+
+       /*PCI IO map */
+       unsigned long pci_base_addr;    /*device I/O address */
+
+       void (*write8_async)(struct rtl_priv *rtlpriv, u32 addr, u8 val);
+       void (*write16_async)(struct rtl_priv *rtlpriv, u32 addr, u16 val);
+       void (*write32_async)(struct rtl_priv *rtlpriv, u32 addr, u32 val);
+
+       u8 (*read8_sync)(struct rtl_priv *rtlpriv, u32 addr);
+       u16 (*read16_sync)(struct rtl_priv *rtlpriv, u32 addr);
+       u32 (*read32_sync)(struct rtl_priv *rtlpriv, u32 addr);
+
+};
+
+struct rtl_mac {
+       u8 mac_addr[ETH_ALEN];
+       u8 mac80211_registered;
+       u8 beacon_enabled;
+
+       u32 tx_ss_num;
+       u32 rx_ss_num;
+
+       struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
+       struct ieee80211_hw *hw;
+       struct ieee80211_vif *vif;
+       enum nl80211_iftype opmode;
+
+       /*Probe Beacon management */
+       enum rtl_link_state link_state;
+
+       int n_channels;
+       int n_bitrates;
+
+       bool offchan_deley;
+       u8 p2p; /*using p2p role*/
+       bool p2p_in_use;
+
+       /*filters */
+       u32 rx_conf;
+
+       bool act_scanning;
+       u8 cnt_after_linked;
+       bool skip_scan;
+
+       /* early mode */
+       /* skb wait queue */
+       struct sk_buff_head skb_waitq[MAX_TID_COUNT];
+
+       /*RDG*/
+       bool rdg_en;
+
+       u8 ht_stbc_cap;
+       u8 ht_cur_stbc;
+
+       /*vht support*/
+       u8 vht_enable;
+       u8 bw_80;
+       u8 vht_cur_ldpc;
+       u8 vht_cur_stbc;
+       u8 vht_stbc_cap;
+       u8 vht_ldpc_cap;
+
+       /*AP*/
+       u8 bssid[6];
+       u32 vendor;
+       u32 basic_rates; /* b/g rates */
+       u8 ht_enable;
+       u8 bw_40;
+       u8 mode;                /* wireless mode */
+       u8 slot_time;
+       u8 short_preamble;
+       u8 use_cts_protect;
+       u8 cur_40_prime_sc;
+       u8 cur_40_prime_sc_bk;
+       u8 cur_80_prime_sc;
+       u64 tsf;
+       u8 retry_short;
+       u8 retry_long;
+       u16 assoc_id;
+       bool bhiddenssid;
+
+       /*IBSS*/
+       int beacon_interval;
+
+       /*AMPDU*/
+       u8 min_space_cfg;       /*For Min spacing configurations */
+       u8 max_mss_density;
+       u8 current_ampdu_factor;
+       u8 current_ampdu_density;
+
+       /*QOS & EDCA */
+       struct ieee80211_tx_queue_params edca_param[RTL_MAC80211_NUM_QUEUE];
+       struct rtl_qos_parameters ac[AC_MAX];
+};
+
+struct rtl_hal {
+       struct ieee80211_hw *hw;
+
+       bool driver_is_goingto_unload;
+       bool up_first_time;
+       bool bfirst_init;
+       bool being_init_adapter;
+       bool b_bbrf_ready;
+       bool b_mac_func_enable;
+       bool b_pre_edcca_enable;
+
+       enum intf_type interface;
+       u16 hw_type;            /*92c or 92d or 92s and so on */
+       u8 ic_class;
+       u8 oem_id;
+       u32 version;            /*version of chip */
+       u8 state;               /*stop 0, start 1 */
+       u8 boad_type;
+
+       u8 pa_mode;
+       u8 pa_type_2g;
+       u8 pa_type_5g;
+       u8 lna_type_2g;
+       u8 lna_type_5g;
+       u8 external_pa_2g;
+       u8 external_lna_2g;
+       u8 external_pa_5g;
+       u8 external_lna_5g;
+       u8 rfe_type;
+
+       /*firmware */
+       u32 fwsize;
+       u8 *pfirmware;
+       u16 fw_version;
+       u16 fw_subversion;
+       bool b_h2c_setinprogress;
+       u8 last_hmeboxnum;
+       bool bfw_ready;
+
+       /*Reserve page start offset except beacon in TxQ. */
+       u8 fw_rsvdpage_startoffset;
+       u8 h2c_txcmd_seq;
+       u8 current_ra_rate;
+
+       /* FW Cmd IO related */
+       u16 fwcmd_iomap;
+       u32 fwcmd_ioparam;
+       bool set_fwcmd_inprogress;
+       u8 current_fwcmd_io;
+
+       bool bfw_clk_change_in_progress;
+       bool ballow_sw_to_change_hwclc;
+       u8 fw_ps_state;
+        struct p2p_ps_offload_t p2p_ps_offload;
+       /**/
+       bool driver_going2unload;
+
+       /*AMPDU init min space*/
+       u8 minspace_cfg;        /*For Min spacing configurations */
+
+       /* Dul mac */
+       enum macphy_mode macphymode;
+       enum band_type current_bandtype;        /* 0:2.4G, 1:5G */
+       enum band_type current_bandtypebackup;
+       enum band_type bandset;
+       /* dual MAC 0--Mac0 1--Mac1 */
+       u32 interfaceindex;
+       /* just for DulMac S3S4 */
+       u8 macphyctl_reg;
+       bool b_earlymode_enable;
+       u8 max_earlymode_num;
+       /* Dul mac*/
+       bool during_mac0init_radiob;
+       bool during_mac1init_radioa;
+       bool reloadtxpowerindex;
+       /* True if IMR or IQK  have done
+       for 2.4G in scan progress */
+       bool b_load_imrandiqk_setting_for2g;
+
+       bool disable_amsdu_8k;
+       bool bmaster_of_dmsp;
+       bool bslave_of_dmsp;
+
+       u16 rx_tag;/*for 92ee*/
+       u8 rts_en;
+
+       /*for wowlan*/
+       bool wow_enable;
+       bool b_enter_pnp_sleep;
+       bool b_wake_from_pnp_sleep;
+       bool wow_enabled;
+       __kernel_time_t last_suspend_sec;
+       u32 wowlan_fwsize;
+       u8 *p_wowlan_firmware;
+
+       u8 hw_rof_enable; /*Enable GPIO[9] as WL RF HW PDn source*/
+
+       bool real_wow_v2_enable;
+       bool re_init_llt_table;
+};
+
+struct rtl_security {
+       /*default 0 */
+       bool use_sw_sec;
+
+       bool being_setkey;
+       bool use_defaultkey;
+       /*Encryption Algorithm for Unicast Packet */
+       enum rt_enc_alg pairwise_enc_algorithm;
+       /*Encryption Algorithm for Brocast/Multicast */
+       enum rt_enc_alg group_enc_algorithm;
+       /*Cam Entry Bitmap */
+       u32 hwsec_cam_bitmap;
+       u8 hwsec_cam_sta_addr[TOTAL_CAM_ENTRY][ETH_ALEN];
+       /*local Key buffer, indx 0 is for
+          pairwise key 1-4 is for agoup key. */
+       u8 key_buf[KEY_BUF_SIZE][MAX_KEY_LEN];
+       u8 key_len[KEY_BUF_SIZE];
+
+       /*The pointer of Pairwise Key,
+          it always points to KeyBuf[4] */
+       u8 *pairwise_key;
+};
+
+struct rtl_dig {
+       u8 dig_enable_flag;
+       u8 dig_ext_port_stage;
+
+       u32 rssi_lowthresh;
+       u32 rssi_highthresh;
+
+       u32 fa_lowthresh;
+       u32 fa_highthresh;
+
+       u8 cursta_connectstate;
+       u8 presta_connectstate;
+       u8 curmultista_connectstate;
+
+       u8 pre_igvalue;
+       u8 cur_igvalue;
+
+       char backoff_val;
+       char backoff_val_range_max;
+       char backoff_val_range_min;
+       u8 rx_gain_range_max;
+       u8 rx_gain_range_min;
+       u8 rssi_val_min;
+       u8 min_undecorated_pwdb_for_dm;
+       long last_min_undecorated_pwdb_for_dm;
+
+       u8 pre_cck_pd_state;
+       u8 cur_cck_pd_state;
+
+       u8 large_fa_hit;
+       u8 forbidden_igi;
+       u32 recover_cnt;
+
+};
+
+struct rtl_pstbl {
+       u8 pre_ccastate;
+       u8 cur_ccasate;
+
+       u8 pre_rfstate;
+       u8 cur_rfstate;
+
+       long rssi_val_min;
+
+};
+
+#define ASSOCIATE_ENTRY_NUM    (32 + 1)
+
+struct fast_ant_trainning {
+       u8 bssid[6];
+       u8 antsel_rx_keep_0;
+       u8 antsel_rx_keep_1;
+       u8 antsel_rx_keep_2;
+       u32 ant_sum_rssi[7];
+       u32 ant_rssi_cnt[7];
+       u32 ant_ave_rssi[7];
+       u8 fat_state;
+       u32 train_idx;
+       u8 antsel_a[ASSOCIATE_ENTRY_NUM];
+       u8 antsel_b[ASSOCIATE_ENTRY_NUM];
+       u8 antsel_c[ASSOCIATE_ENTRY_NUM];
+       u32 main_ant_sum[ASSOCIATE_ENTRY_NUM];
+       u32 aux_ant_sum[ASSOCIATE_ENTRY_NUM];
+       u32 main_ant_cnt[ASSOCIATE_ENTRY_NUM];
+       u32 aux_ant_cnt[ASSOCIATE_ENTRY_NUM];
+       u8 rx_idle_ant;
+       bool b_becomelinked;
+};
+
+struct dm_phy_dbg_info {
+       char rx_snrdb[4];
+       u64 num_qry_phy_status;
+       u64 num_qry_phy_status_cck;
+       u64 num_qry_phy_status_ofdm;
+       u16 num_qry_beacon_pkt;
+       u16 num_non_be_pkt;
+       s32 rx_evm[4];
+};
+
+struct rtl_dm {
+       /*PHY status for DM */
+       long entry_min_undecoratedsmoothed_pwdb;
+       long undecorated_smoothed_pwdb; /*out dm */
+       long entry_max_undecoratedsmoothed_pwdb;
+       bool b_dm_initialgain_enable;
+       bool bdynamic_txpower_enable;
+       bool bcurrent_turbo_edca;
+       bool bis_any_nonbepkts; /*out dm */
+       bool bis_cur_rdlstate;
+       bool btxpower_trackinginit;
+       bool b_disable_framebursting;
+       bool b_cck_inch14;
+       bool btxpower_tracking;
+       bool b_useramask;
+       bool brfpath_rxenable[4];
+       bool binform_fw_driverctrldm;
+       bool bcurrent_mrc_switch;
+       u8 txpowercount;
+
+       u8 thermalvalue_rxgain;
+       u8 thermalvalue_iqk;
+       u8 thermalvalue_lck;
+       u8 thermalvalue;
+       u8 thermalvalue_avg[AVG_THERMAL_NUM];
+       u8 thermalvalue_avg_index;
+       bool bdone_txpower;
+       u8 last_dtp_lvl;
+       u8 dynamic_txhighpower_lvl;     /*Tx high power level */
+       u8 dm_flag;     /*Indicate if each dynamic mechanism's status. */
+       u8 dm_type;
+       u8 txpower_track_control;
+       bool binterrupt_migration;
+       bool bdisable_tx_int;
+       char ofdm_index[MAX_RF_PATH];
+       char cck_index;
+       u8 default_ofdm_index;
+       u8 default_cck_index;
+       char delta_power_index[MAX_RF_PATH];
+       char delta_power_index_last[MAX_RF_PATH];
+       char power_index_offset[MAX_RF_PATH];
+       char aboslute_ofdm_swing_idx[MAX_RF_PATH];
+       char remnant_ofdm_swing_idx[MAX_RF_PATH];
+       char remnant_cck_idx;
+       bool modify_txagc_flag_path_a;
+       bool modify_txagc_flag_path_b;
+
+       bool b_one_entry_only;
+       struct dm_phy_dbg_info dbginfo;
+       /* Dynamic ATC switch */
+
+       bool atc_status;
+       bool large_cfo_hit;
+       bool is_freeze;
+       int cfo_tail[2];
+       int cfo_ave_pre;
+       int crystal_cap;
+       u8 cfo_threshold;
+       u32 packet_count;
+       u32 packet_count_pre;
+       u8 tx_rate;
+
+
+       /*88e tx power tracking*/
+       u8 bb_swing_idx_ofdm[2];
+       u8 bb_swing_idx_ofdm_current;
+       u8 bb_swing_idx_ofdm_base[MAX_RF_PATH];
+       bool bb_swing_flag_Ofdm;
+       u8 bb_swing_idx_cck;
+       u8 bb_swing_idx_cck_current;
+       u8 bb_swing_idx_cck_base;
+       bool bb_swing_flag_cck;
+
+       char bb_swing_diff_2g;
+       char bb_swing_diff_5g;
+
+       /* DMSP */
+       bool supp_phymode_switch;
+
+       /* DulMac */
+       struct rtl_dig dm_digtable;
+       struct rtl_pstbl dm_pstable;
+       struct fast_ant_trainning fat_table;
+
+       u8 linked_interval;
+
+       u64 last_tx_ok_cnt;
+       u64 last_rx_ok_cnt;
+
+       bool cck_high_power;
+};
+
+#define        EFUSE_MAX_LOGICAL_SIZE          256
+
+struct rtl_efuse {
+       bool bautoLoad_ok;
+       bool bootfromefuse;
+       u16 max_physical_size;
+
+       u8 efuse_map[2][EFUSE_MAX_LOGICAL_SIZE];
+       u16 efuse_usedbytes;
+       u8 efuse_usedpercentage;
+       u8 autoload_failflag;
+       u8 autoload_status;
+
+       short epromtype;
+       u16 eeprom_vid;
+       u16 eeprom_did;
+       u16 eeprom_svid;
+       u16 eeprom_smid;
+       u8 eeprom_oemid;
+       u16 eeprom_channelplan;
+       u8 eeprom_version;
+
+       u8 dev_addr[6];
+       u8 board_type;
+       u8 wowlan_enable;
+       u8 antenna_div_cfg;
+       u8 antenna_div_type;
+
+       bool b_txpwr_fromeprom;
+       u8 eeprom_crystalcap;
+       u8 eeprom_tssi[2];
+       u8 eeprom_tssi_5g[3][2]; /* for 5GL/5GM/5GH band. */
+       u8 eeprom_pwrlimit_ht20[CHANNEL_GROUP_MAX];
+       u8 eeprom_pwrlimit_ht40[CHANNEL_GROUP_MAX];
+       u8 eeprom_chnlarea_txpwr_cck[2][CHANNEL_GROUP_MAX_2G];
+       u8 eeprom_chnlarea_txpwr_ht40_1s[2][CHANNEL_GROUP_MAX];
+       u8 eeprom_chnlarea_txpwr_ht40_2sdiif[2][CHANNEL_GROUP_MAX];
+
+
+       u8 internal_pa_5g[2];   /* pathA / pathB */
+       u8 eeprom_c9;
+       u8 eeprom_cc;
+
+       /*For power group */
+       u8 eeprom_pwrgroup[2][3];
+       u8 pwrgroup_ht20[2][CHANNEL_MAX_NUMBER];
+       u8 pwrgroup_ht40[2][CHANNEL_MAX_NUMBER];
+
+       u8 txpwrlevel_cck[MAX_RF_PATH][CHANNEL_MAX_NUMBER_2G];
+       /*For HT 40MHZ pwr */
+       u8 txpwrlevel_ht40_1s[MAX_RF_PATH][CHANNEL_MAX_NUMBER];
+       /*For HT 40MHZ pwr */
+       u8 txpwrlevel_ht40_2s[MAX_RF_PATH][CHANNEL_MAX_NUMBER];
+
+       /*--------------------------------------------------------*
+        * 8192CE\8192SE\8192DE\8723AE use the following 4 arrays,
+        * other ICs (8188EE\8723BE\8192EE\8812AE...)
+        * define new arrays in Windows code.
+        * BUT, in linux code, we use the same array for all ICs.
+        *
+        * The Correspondance relation between two arrays is:
+        * txpwr_cckdiff[][] == CCK_24G_Diff[][]
+        * txpwr_ht20diff[][] == BW20_24G_Diff[][]
+        * txpwr_ht40diff[][] == BW40_24G_Diff[][]
+        * txpwr_legacyhtdiff[][] == OFDM_24G_Diff[][]
+        *
+        * Sizes of these arrays are decided by the larger ones.
+        */
+       char txpwr_cckdiff[MAX_RF_PATH][CHANNEL_MAX_NUMBER];
+       char txpwr_ht20diff[MAX_RF_PATH][CHANNEL_MAX_NUMBER];
+       char txpwr_ht40diff[MAX_RF_PATH][CHANNEL_MAX_NUMBER];
+       char txpwr_legacyhtdiff[MAX_RF_PATH][CHANNEL_MAX_NUMBER];
+       /*--------------------------------------------------------*/
+
+       u8 txpwr_5g_bw40base[MAX_RF_PATH][CHANNEL_MAX_NUMBER];
+       u8 txpwr_5g_bw80base[MAX_RF_PATH][CHANNEL_MAX_NUMBER_5G_80M];
+       char txpwr_5g_ofdmdiff[MAX_RF_PATH][MAX_TX_COUNT];
+       char txpwr_5g_bw20diff[MAX_RF_PATH][MAX_TX_COUNT];
+       char txpwr_5g_bw40diff[MAX_RF_PATH][MAX_TX_COUNT];
+       char txpwr_5g_bw80diff[MAX_RF_PATH][MAX_TX_COUNT];
+
+       u8 txpwr_safetyflag;            /* Band edge enable flag */
+       u16 eeprom_txpowerdiff;
+       u8 legacy_httxpowerdiff;        /* Legacy to HT rate power diff */
+       u8 antenna_txpwdiff[3];
+
+       u8 eeprom_regulatory;
+       u8 eeprom_thermalmeter;
+       u8 thermalmeter[2];/*ThermalMeter, index 0 for RFIC0, and 1 for RFIC1 */
+       u16 tssi_13dbm;
+       u8 crystalcap;          /* CrystalCap. */
+       u8 delta_iqk;
+       u8 delta_lck;
+
+       u8 legacy_ht_txpowerdiff;       /*Legacy to HT rate power diff */
+       bool b_apk_thermalmeterignore;
+
+       bool b1x1_recvcombine;
+       bool b1ss_support;
+
+       /*channel plan */
+       u8 channel_plan;
+};
+
+struct rtl_ps_ctl {
+       bool pwrdomain_protect;
+       bool b_in_powersavemode;
+       bool rfchange_inprogress;
+       bool b_swrf_processing;
+       bool b_hwradiooff;
+       /*
+        * just for PCIE ASPM
+        * If it supports ASPM, Offset[560h] = 0x40,
+        * otherwise Offset[560h] = 0x00.
+        * */
+       bool b_support_aspm;
+       bool b_support_backdoor;
+
+       /*for LPS */
+       enum rt_psmode dot11_psmode;    /*Power save mode configured. */
+       bool b_swctrl_lps;
+       bool b_fwctrl_lps;
+       u8 fwctrl_psmode;
+       /*For Fw control LPS mode */
+       u8 b_reg_fwctrl_lps;
+       /*Record Fw PS mode status. */
+       bool b_fw_current_inpsmode;
+       u8 reg_max_lps_awakeintvl;
+       bool report_linked;
+       bool b_low_power_enable;/*for 32k*/
+
+       /*for IPS */
+       bool b_inactiveps;
+
+       u32 rfoff_reason;
+
+       /*RF OFF Level */
+       u32 cur_ps_level;
+       u32 reg_rfps_level;
+
+       /*just for PCIE ASPM */
+       u8 const_amdpci_aspm;
+
+       enum rf_pwrstate inactive_pwrstate;
+       enum rf_pwrstate rfpwr_state;   /*cur power state */
+
+       /* for SW LPS*/
+       bool sw_ps_enabled;
+       bool state;
+       bool state_inap;
+       bool multi_buffered;
+       u16 nullfunc_seq;
+       unsigned int dtim_counter;
+       unsigned int sleep_ms;
+       unsigned long last_sleep_jiffies;
+       unsigned long last_awake_jiffies;
+       unsigned long last_delaylps_stamp_jiffies;
+       unsigned long last_dtim;
+       unsigned long last_beacon;
+       unsigned long last_action;
+       unsigned long last_slept;
+
+       /*For P2P PS */
+       struct rtl_p2p_ps_info p2p_ps_info;
+       u8 pwr_mode;
+       u8 smart_ps;
+
+       /* wake up on line */
+       u8 wo_wlan_mode;
+       u8 arp_offload_enable;
+       u8 gtk_offload_enable;
+       /* Used for WOL, indicates the reason for waking event.*/
+       u32 wakeup_reason;
+       /* Record the last waking time for comparison with setting key. */
+       u64 last_wakeup_time;
+};
+
+struct rtl_stats {
+       u8 psaddr[ETH_ALEN];
+       u32 mac_time[2];
+       s8 rssi;
+       u8 signal;
+       u8 noise;
+       u8 rate;                /* hw desc rate */
+       u8 rawdata;
+       u8 received_channel;
+       u8 control;
+       u8 mask;
+       u8 freq;
+       u16 len;
+       u64 tsf;
+       u32 beacon_time;
+       u8 nic_type;
+       u16 length;
+       u8 signalquality;       /*in 0-100 index. */
+       /*
+        * Real power in dBm for this packet,
+        * no beautification and aggregation.
+        * */
+       s32 recvsignalpower;
+       s8 rxpower;             /*in dBm Translate from PWdB */
+       u8 signalstrength;      /*in 0-100 index. */
+       u16 b_hwerror:1;
+       u16 b_crc:1;
+       u16 b_icv:1;
+       u16 b_shortpreamble:1;
+       u16 antenna:1;
+       u16 decrypted:1;
+       u16 wakeup:1;
+       u32 timestamp_low;
+       u32 timestamp_high;
+       bool b_shift;
+
+       u8 rx_drvinfo_size;
+       u8 rx_bufshift;
+       bool b_isampdu;
+       bool b_isfirst_ampdu;
+       bool rx_is40Mhzpacket;
+       u8 rx_packet_bw;
+       u32 rx_pwdb_all;
+       u8 rx_mimo_signalstrength[4];   /*in 0~100 index */
+       s8 rx_mimo_signalquality[4];
+       u8 rx_mimo_evm_dbm[4];
+       u16 cfo_short[4];               /* per-path's Cfo_short */
+       u16 cfo_tail[4];
+
+       u8 rx_pwr[4]; /* per-path's pwdb */
+       u8 rx_snr[4]; /* per-path's SNR */
+       u8 bandwidth;
+       u8 bt_coex_pwr_adjust;
+       bool b_packet_matchbssid;
+       bool b_is_cck;
+       bool b_is_ht;
+       bool b_packet_toself;
+       bool b_packet_beacon;   /*for rssi */
+       char cck_adc_pwdb[4];   /*for rx path selection */
+
+       bool b_is_vht;
+       bool b_is_short_gi;
+       u8 vht_nss;
+
+       u8 packet_report_type;
+
+       u32 macid;
+       u8 wake_match;
+       u32 bt_rx_rssi_percentage;
+       u32 macid_valid_entry[2];
+};
+
+struct rt_link_detect {
+       /* count for raoming */
+       u32 bcn_rx_inperiod;
+       u32 roam_times;
+
+       u32 num_tx_in4period[4];
+       u32 num_rx_in4period[4];
+
+       u32 num_tx_inperiod;
+       u32 num_rx_inperiod;
+
+       bool b_busytraffic;
+       bool b_tx_busy_traffic;
+       bool b_rx_busy_traffic;
+       bool b_higher_busytraffic;
+       bool b_higher_busyrxtraffic;
+
+       u32 tidtx_in4period[MAX_TID_COUNT][4];
+       u32 tidtx_inperiod[MAX_TID_COUNT];
+       bool higher_busytxtraffic[MAX_TID_COUNT];
+};
+
+struct rtl_tcb_desc {
+       u8 packet_bw:2;
+       u8 b_multicast:1;
+       u8 b_broadcast:1;
+
+       u8 b_rts_stbc:1;
+       u8 b_rts_enable:1;
+       u8 b_cts_enable:1;
+       u8 b_rts_use_shortpreamble:1;
+       u8 b_rts_use_shortgi:1;
+       u8 rts_sc:1;
+       u8 b_rts_bw:1;
+       u8 rts_rate;
+
+       u8 use_shortgi:1;
+       u8 use_shortpreamble:1;
+       u8 use_driver_rate:1;
+       u8 disable_ratefallback:1;
+
+       u8 ratr_index;
+       u8 mac_id;
+       u8 hw_rate;
+
+       u8 b_last_inipkt:1;
+       u8 b_cmd_or_init:1;
+       u8 queue_index;
+
+       /* early mode */
+       u8 empkt_num;
+       /* The max value by HW */
+       u32 empkt_len[10];
+       bool btx_enable_sw_calc_duration;
+       /* used for hal construct pkt,
+        * we may set desc when tx */
+       u8 self_desc;
+};
+
+struct rtl_wow_pattern {
+       u8 type;
+       u16 crc;
+       u32 mask[4];
+};
+
+struct proxim {
+       bool proxim_on;
+
+       void *proximity_priv;
+       int (*proxim_rx)(struct ieee80211_hw *hw, struct rtl_stats *status,
+                        struct sk_buff *skb);
+       u8  (*proxim_get_var)(struct ieee80211_hw *hw, u8 type);
+};
+
+struct rtl_hal_ops {
+       int (*init_sw_vars)(struct ieee80211_hw *hw);
+       void (*deinit_sw_vars)(struct ieee80211_hw *hw);
+       void (*read_eeprom_info)(struct ieee80211_hw *hw);
+       void (*interrupt_recognized)(struct ieee80211_hw *hw,
+                                    u32 *p_inta, u32 *p_intb);
+       int (*hw_init)(struct ieee80211_hw *hw);
+       void (*hw_disable)(struct ieee80211_hw *hw);
+       void (*hw_suspend)(struct ieee80211_hw *hw);
+       void (*hw_resume)(struct ieee80211_hw *hw);
+       void (*enable_interrupt)(struct ieee80211_hw *hw);
+       void (*disable_interrupt)(struct ieee80211_hw *hw);
+       int (*set_network_type)(struct ieee80211_hw *hw,
+                               enum nl80211_iftype type);
+       void (*set_chk_bssid)(struct ieee80211_hw *hw,
+                             bool check_bssid);
+       void (*set_bw_mode)(struct ieee80211_hw *hw,
+                           enum nl80211_channel_type ch_type);
+       u8 (*switch_channel)(struct ieee80211_hw *hw);
+       void (*set_qos)(struct ieee80211_hw *hw, int aci);
+       void (*set_bcn_reg)(struct ieee80211_hw *hw);
+       void (*set_bcn_intv)(struct ieee80211_hw *hw);
+       void (*update_interrupt_mask)(struct ieee80211_hw *hw,
+                                     u32 add_msr, u32 rm_msr);
+       void (*get_hw_reg)(struct ieee80211_hw *hw, u8 variable, u8 *val);
+       void (*set_hw_reg)(struct ieee80211_hw *hw, u8 variable, u8 *val);
+       void (*update_rate_tbl)(struct ieee80211_hw *hw,
+                               struct ieee80211_sta *sta, u8 rssi_level);
+       void (*pre_fill_tx_bd_desc)(struct ieee80211_hw *hw, u8 *tx_bd_desc,
+                                   u8 *desc, u8 queue_index,
+                                   struct sk_buff *skb, dma_addr_t addr);
+       u16 (*rx_desc_buff_remained_cnt)(struct ieee80211_hw *hw,
+                                        u8 queue_index);
+       void (*rx_check_dma_ok)(struct ieee80211_hw *hw, u8 *header_desc,
+                               u8 queue_index);
+       void (*fill_tx_desc)(struct ieee80211_hw *hw,
+                            struct ieee80211_hdr *hdr,
+                            u8 *pdesc_tx, u8 *pbd_desc,
+                            struct ieee80211_tx_info *info,
+                            struct ieee80211_sta *sta,
+                            struct sk_buff *skb, u8 hw_queue,
+                            struct rtl_tcb_desc *ptcb_desc);
+       void (*fill_tx_cmddesc)(struct ieee80211_hw *hw, u8 *pdesc,
+                               bool b_firstseg, bool b_lastseg,
+                               struct sk_buff *skb);
+       bool (*query_rx_desc)(struct ieee80211_hw *hw,
+                             struct rtl_stats *status,
+                             struct ieee80211_rx_status *rx_status,
+                             u8 *pdesc, struct sk_buff *skb);
+       void (*set_channel_access)(struct ieee80211_hw *hw);
+       bool (*radio_onoff_checking)(struct ieee80211_hw *hw, u8 *valid);
+       void (*dm_watchdog)(struct ieee80211_hw *hw);
+       void (*scan_operation_backup)(struct ieee80211_hw *hw, u8 operation);
+       bool (*set_rf_power_state)(struct ieee80211_hw *hw,
+                                  enum rf_pwrstate rfpwr_state);
+       void (*led_control)(struct ieee80211_hw *hw,
+                           enum led_ctl_mode ledaction);
+       void (*set_desc)(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
+                        u8 desc_name, u8 *val);
+       u32 (*get_desc)(u8 *pdesc, bool istx, u8 desc_name);
+       bool (*is_tx_desc_closed)(struct ieee80211_hw *hw,
+                                 u8 hw_queue, u16 index);
+       void (*tx_polling)(struct ieee80211_hw *hw, u8 hw_queue);
+       void (*enable_hw_sec)(struct ieee80211_hw *hw);
+       void (*set_key)(struct ieee80211_hw *hw, u32 key_index,
+                       u8 *p_macaddr, bool is_group, u8 enc_algo,
+                       bool is_wepkey, bool clear_all);
+       void (*init_sw_leds)(struct ieee80211_hw *hw);
+       u32 (*get_bbreg)(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask);
+       void (*set_bbreg)(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask,
+                         u32 data);
+       u32 (*get_rfreg)(struct ieee80211_hw *hw, enum radio_path rfpath,
+                        u32 regaddr, u32 bitmask);
+       void (*set_rfreg)(struct ieee80211_hw *hw, enum radio_path rfpath,
+                         u32 regaddr, u32 bitmask, u32 data);
+       void (*allow_all_destaddr)(struct ieee80211_hw *hw,
+                                  bool allow_all_da, bool write_into_reg);
+       void (*linked_set_reg)(struct ieee80211_hw *hw);
+       void (*check_switch_to_dmdp)(struct ieee80211_hw *hw);
+       void (*dualmac_easy_concurrent)(struct ieee80211_hw *hw);
+       void (*dualmac_switch_to_dmdp)(struct ieee80211_hw *hw);
+       void (*c2h_command_handle)(struct ieee80211_hw *hw);
+       void (*bt_wifi_media_status_notify)(struct ieee80211_hw *hw,
+                                           bool mstate);
+       void (*bt_turn_off_bt_coexist_before_enter_lps)(struct ieee80211_hw *w);
+       void (*fill_h2c_cmd)(struct ieee80211_hw *hw, u8 element_id,
+                            u32 cmd_len, u8 *p_cmdbuffer);
+       bool (*get_btc_status)(void);
+       u32 (*rx_command_packet)(struct ieee80211_hw *hw,
+                                struct rtl_stats status, struct sk_buff *skb);
+       void (*add_wowlan_pattern)(struct ieee80211_hw *hw,
+                                  struct rtl_wow_pattern *rtl_pattern,
+                                  u8 index);
+};
+
+struct rtl_intf_ops {
+       /*com */
+       void (*read92e_efuse_byte)(struct ieee80211_hw *hw, u16 _offset,
+                                  u8 *pbuf);
+       int (*adapter_start)(struct ieee80211_hw *hw);
+       void (*adapter_stop)(struct ieee80211_hw *hw);
+       bool (*check_buddy_priv)(struct ieee80211_hw *hw,
+                                struct rtl_priv **buddy_priv);
+
+       int (*adapter_tx)(struct ieee80211_hw *hw,
+                         struct ieee80211_sta *sta,
+                         struct sk_buff *skb,
+                         struct rtl_tcb_desc *ptcb_desc);
+       void (*flush)(struct ieee80211_hw *hw, u32 queues, bool drop);
+       int (*reset_trx_ring)(struct ieee80211_hw *hw);
+       bool (*waitq_insert)(struct ieee80211_hw *hw,
+                            struct ieee80211_sta *sta,
+                            struct sk_buff *skb);
+
+       /*pci */
+       void (*disable_aspm)(struct ieee80211_hw *hw);
+       void (*enable_aspm)(struct ieee80211_hw *hw);
+
+       /*usb */
+};
+
+struct rtl_mod_params {
+       /* default: 0 = using hardware encryption */
+       bool sw_crypto;
+
+       /* default: 0 = DBG_EMERG (0)*/
+       int debug;
+
+       /* default: 1 = using no linked power save */
+       bool b_inactiveps;
+
+       /* default: 1 = using linked sw power save */
+       bool b_swctrl_lps;
+
+       /* default: 1 = using linked fw power save */
+       bool b_fwctrl_lps;
+};
+
+struct rtl_hal_cfg {
+       u8 bar_id;
+       bool write_readback;
+       char *name;
+       char *fw_name;
+       struct rtl_hal_ops *ops;
+       struct rtl_mod_params *mod_params;
+
+       /*this map used for some registers or vars
+          defined int HAL but used in MAIN */
+       u32 maps[RTL_VAR_MAP_MAX];
+
+};
+
+struct rtl_locks {
+       /* mutex */
+       struct mutex conf_mutex;
+
+       /*spin lock */
+       spinlock_t ips_lock;
+       spinlock_t irq_th_lock;
+       spinlock_t h2c_lock;
+       spinlock_t rf_ps_lock;
+       spinlock_t rf_lock;
+       spinlock_t lps_lock;
+       spinlock_t waitq_lock;
+       spinlock_t entry_list_lock;
+
+       /*FW clock change */
+       spinlock_t fw_ps_lock;
+
+       /*Dul mac*/
+       spinlock_t cck_and_rw_pagea_lock;
+
+       /*Easy concurrent*/
+       spinlock_t check_sendpkt_lock;
+
+       spinlock_t iqk_lock;
+};
+
+struct rtl_works {
+       struct ieee80211_hw *hw;
+
+       /*timer */
+       struct timer_list watchdog_timer;
+       struct timer_list dualmac_easyconcurrent_retrytimer;
+       struct timer_list fw_clockoff_timer;
+       struct timer_list fast_antenna_trainning_timer;
+       /*task */
+       struct tasklet_struct irq_tasklet;
+       struct tasklet_struct irq_prepare_bcn_tasklet;
+
+       /*work queue */
+       struct workqueue_struct *rtl_wq;
+       struct delayed_work watchdog_wq;
+       struct delayed_work ips_nic_off_wq;
+
+       /* For SW LPS */
+       struct delayed_work ps_work;
+       struct delayed_work ps_rfon_wq;
+       struct delayed_work fwevt_wq;
+};
+
+struct rtl_debug {
+       u32 dbgp_type[DBGP_TYPE_MAX];
+       u32 global_debuglevel;
+       u64 global_debugcomponents;
+
+       /* add for proc debug */
+       struct proc_dir_entry *proc_dir;
+       char proc_name[20];
+};
+
+#define MIMO_PS_STATIC                 0
+#define MIMO_PS_DYNAMIC                        1
+#define MIMO_PS_NOLIMIT                        3
+
+struct rtl_dualmac_easy_concurrent_ctl {
+       enum band_type currentbandtype_backfordmdp;
+       bool bclose_bbandrf_for_dmsp;
+       bool bchange_to_dmdp;
+       bool bchange_to_dmsp;
+       bool bswitch_in_process;
+};
+
+struct rtl_dmsp_ctl {
+       bool bactivescan_for_slaveofdmsp;
+       bool bscan_for_anothermac_fordmsp;
+       bool bscan_for_itself_fordmsp;
+       bool bwritedig_for_anothermacofdmsp;
+       u32 curdigvalue_for_anothermacofdmsp;
+       bool bchangecckpdstate_for_anothermacofdmsp;
+       u8 curcckpdstate_for_anothermacofdmsp;
+       bool bchangetxhighpowerlvl_for_anothermacofdmsp;
+       u8 curtxhighlvl_for_anothermacofdmsp;
+       long rssivalmin_for_anothermacofdmsp;
+};
+
+struct rtl_global_var {
+       /* from this list we can get
+        * other adapter's rtl_priv */
+       struct list_head glb_priv_list;
+       spinlock_t glb_list_lock;
+};
+
+struct rtl_btc_info {
+       u8 bt_type;
+       u8 btcoexist;
+       u8 ant_num;
+};
+
+struct rtl_btc_ops {
+       void (*btc_init_variables)(struct rtl_priv *rtlpriv);
+       void (*btc_init_hal_vars)(struct rtl_priv *rtlpriv);
+       void (*btc_init_hw_config)(struct rtl_priv *rtlpriv);
+       void (*btc_ips_notify)(struct rtl_priv *rtlpriv, u8 type);
+       void (*btc_lps_notify)(struct rtl_priv *rtlpriv, u8 type);
+       void (*btc_scan_notify)(struct rtl_priv *rtlpriv, u8 scantype);
+       void (*btc_connect_notify)(struct rtl_priv *rtlpriv, u8 action);
+       void (*btc_mediastatus_notify)(struct rtl_priv *rtlpriv,
+                                      enum rt_media_status mstatus);
+       void (*btc_periodical)(struct rtl_priv *rtlpriv);
+       void (*btc_halt_notify)(void);
+       void (*btc_btinfo_notify)(struct rtl_priv *rtlpriv,
+                                 u8 *tmp_buf, u8 length);
+       bool (*btc_is_limited_dig)(struct rtl_priv *rtlpriv);
+       bool (*btc_is_disable_edca_turbo)(struct rtl_priv *rtlpriv);
+       bool (*btc_is_bt_disabled)(struct rtl_priv *rtlpriv);
+       void (*btc_special_packet_notify)(struct rtl_priv *rtlpriv,
+                                         u8 pkt_type);
+};
+
+struct rtl_bt_coexist {
+       struct rtl_btc_ops *btc_ops;
+       struct rtl_btc_info btc_info;
+};
+
+
+struct rtl_priv {
+       struct list_head list;
+       struct rtl_priv *buddy_priv;
+       struct rtl_global_var *glb_var;
+       struct rtl_dualmac_easy_concurrent_ctl easy_concurrent_ctl;
+       struct rtl_dmsp_ctl dmsp_ctl;
+       struct rtl_locks locks;
+       struct rtl_works works;
+       struct rtl_mac mac80211;
+       struct rtl_hal rtlhal;
+       struct rtl_regulatory regd;
+       struct rtl_rfkill rfkill;
+       struct rtl_io io;
+       struct rtl_phy phy;
+       struct rtl_dm dm;
+       struct rtl_security sec;
+       struct rtl_efuse efuse;
+
+       struct rtl_ps_ctl psc;
+       struct rate_adaptive ra;
+       struct dynamic_primary_cca primarycca;
+       struct wireless_stats stats;
+       struct rt_link_detect link_info;
+       struct false_alarm_statistics falsealm_cnt;
+
+       struct rtl_rate_priv *rate_priv;
+
+       struct rtl_debug dbg;
+
+       /* sta entry list for ap adhoc or mesh */
+       struct list_head entry_list;
+
+       /*
+        *hal_cfg : for diff cards
+        *intf_ops : for diff interrface usb/pcie
+        */
+       struct rtl_hal_cfg *cfg;
+       struct rtl_intf_ops *intf_ops;
+
+       /*this var will be set by set_bit,
+          and was used to indicate status of
+          interface or hardware */
+       unsigned long status;
+
+       /* intel Proximity, should be alloc mem
+        * in intel Proximity module and can only
+        * be used in intel Proximity mode */
+       struct proxim proximity;
+
+       /*for bt coexist use*/
+       struct rtl_bt_coexist btcoexist;
+
+       /* seperate 92ee from other ICs,
+         * 92ee use new trx flow. */
+       bool use_new_trx_flow;
+
+#ifdef CONFIG_PM
+       struct wiphy_wowlan_support wowlan;
+#endif
+       /*This must be the last item so
+          that it points to the data allocated
+          beyond  this structure like:
+          rtl_pci_priv or rtl_usb_priv */
+       u8 priv[0];
+};
+
+#define rtl_priv(hw)           (((struct rtl_priv *)(hw)->priv))
+#define rtl_mac(rtlpriv)       (&((rtlpriv)->mac80211))
+#define rtl_hal(rtlpriv)       (&((rtlpriv)->rtlhal))
+#define rtl_efuse(rtlpriv)     (&((rtlpriv)->efuse))
+#define rtl_psc(rtlpriv)       (&((rtlpriv)->psc))
+#define rtl_sec(rtlpriv)       (&((rtlpriv)->sec))
+#define rtl_dm(rtlpriv)        (&((rtlpriv)->dm))
+/***************************************
+    Bluetooth Co-existance Related
+****************************************/
+
+enum bt_ant_num {
+       ANT_X2 = 0,
+       ANT_X1 = 1,
+};
+
+enum bt_co_type {
+       BT_2WIRE = 0,
+       BT_ISSC_3WIRE = 1,
+       BT_ACCEL = 2,
+       BT_CSR_BC4 = 3,
+       BT_CSR_BC8 = 4,
+       BT_RTL8756 = 5,
+       BT_RTL8723A = 6,
+       BT_RTL8821A = 7,
+       BT_RTL8723B = 8,
+       BT_RTL8192E = 9,
+       BT_RTL8812A = 11,
+};
+
+enum bt_total_ant_num {
+       ANT_TOTAL_X2 = 0,
+       ANT_TOTAL_X1 = 1
+};
+
+enum bt_cur_state {
+       BT_OFF = 0,
+       BT_ON = 1,
+};
+
+enum bt_service_type {
+       BT_SCO = 0,
+       BT_A2DP = 1,
+       BT_HID = 2,
+       BT_HID_IDLE = 3,
+       BT_SCAN = 4,
+       BT_IDLE = 5,
+       BT_OTHER_ACTION = 6,
+       BT_BUSY = 7,
+       BT_OTHERBUSY = 8,
+       BT_PAN = 9,
+};
+
+enum bt_radio_shared {
+       BT_RADIO_SHARED = 0,
+       BT_RADIO_INDIVIDUAL = 1,
+};
+
+struct bt_coexist_info {
+       /* EEPROM BT info. */
+       u8 eeprom_bt_coexist;
+       u8 eeprom_bt_type;
+       u8 eeprom_bt_ant_num;
+       u8 eeprom_bt_ant_isolation;
+       u8 eeprom_bt_radio_shared;
+
+       u8 bt_coexistence;
+       u8 bt_ant_num;
+       u8 bt_coexist_type;
+       u8 bt_state;
+       u8 bt_cur_state;        /* 0:on, 1:off */
+       u8 bt_ant_isolation;    /* 0:good, 1:bad */
+       u8 bt_pape_ctrl;        /* 0:SW, 1:SW/HW dynamic */
+       u8 bt_service;
+       u8 bt_radio_shared_type;
+       u8 bt_rfreg_origin_1e;
+       u8 bt_rfreg_origin_1f;
+       u8 bt_rssi_state;
+       u32 ratio_tx;
+       u32 ratio_pri;
+       u32 bt_edca_ul;
+       u32 bt_edca_dl;
+
+       bool b_init_set;
+       bool b_bt_busy_traffic;
+       bool b_bt_traffic_mode_set;
+       bool b_bt_non_traffic_mode_set;
+
+       bool b_fw_coexist_all_off;
+       bool b_sw_coexist_all_off;
+       bool b_hw_coexist_all_off;
+       u32 current_state;
+       u32 previous_state;
+       u32 current_state_h;
+       u32 previous_state_h;
+
+       u8 bt_pre_rssi_state;
+       u8 bt_pre_rssi_state1;
+
+       u8 b_reg_bt_iso;
+       u8 b_reg_bt_sco;
+       bool b_balance_on;
+       u8 bt_active_zero_cnt;
+       bool b_cur_bt_disabled;
+       bool b_pre_bt_disabled;
+
+       u8 bt_profile_case;
+       u8 bt_profile_action;
+       bool b_bt_busy;
+       bool b_hold_for_bt_operation;
+       u8 lps_counter;
+};
+
+/****************************************
+       mem access macro define start
+       Call endian free function when
+       1. Read/write packet content.
+       2. Before write integer to IO.
+       3. After read integer from IO.
+****************************************/
+/* Convert little data endian to host ordering */
+#define EF1BYTE(_val)          \
+       ((u8)(_val))
+#define EF2BYTE(_val)          \
+       (le16_to_cpu(_val))
+#define EF4BYTE(_val)          \
+       (le32_to_cpu(_val))
+
+/* Read data from memory */
+#define READEF1BYTE(_ptr)      \
+       EF1BYTE(*((u8 *)(_ptr)))
+/* Read le16 data from memory and convert to host ordering */
+#define READEF2BYTE(_ptr)      \
+       EF2BYTE(*(_ptr))
+#define READEF4BYTE(_ptr)      \
+       EF4BYTE(*(_ptr))
+
+/* Write data to memory */
+#define WRITEEF1BYTE(_ptr, _val)       \
+       (*((u8 *)(_ptr))) = EF1BYTE(_val)
+/* Write le16 data to memory in host ordering */
+#define WRITEEF2BYTE(_ptr, _val)       \
+       (*((u16 *)(_ptr))) = EF2BYTE(_val)
+#define WRITEEF4BYTE(_ptr, _val)       \
+       (*((u32 *)(_ptr))) = EF2BYTE(_val)
+
+/* Create a bit mask
+ * Examples:
+ * BIT_LEN_MASK_32(0) => 0x00000000
+ * BIT_LEN_MASK_32(1) => 0x00000001
+ * BIT_LEN_MASK_32(2) => 0x00000003
+ * BIT_LEN_MASK_32(32) => 0xFFFFFFFF
+ */
+#define BIT_LEN_MASK_32(__bitlen)       \
+       (0xFFFFFFFF >> (32 - (__bitlen)))
+#define BIT_LEN_MASK_16(__bitlen)       \
+       (0xFFFF >> (16 - (__bitlen)))
+#define BIT_LEN_MASK_8(__bitlen) \
+       (0xFF >> (8 - (__bitlen)))
+
+/* Create an offset bit mask
+ * Examples:
+ * BIT_OFFSET_LEN_MASK_32(0, 2) => 0x00000003
+ * BIT_OFFSET_LEN_MASK_32(16, 2) => 0x00030000
+ */
+#define BIT_OFFSET_LEN_MASK_32(__bitoffset, __bitlen) \
+       (BIT_LEN_MASK_32(__bitlen) << (__bitoffset))
+#define BIT_OFFSET_LEN_MASK_16(__bitoffset, __bitlen) \
+       (BIT_LEN_MASK_16(__bitlen) << (__bitoffset))
+#define BIT_OFFSET_LEN_MASK_8(__bitoffset, __bitlen) \
+       (BIT_LEN_MASK_8(__bitlen) << (__bitoffset))
+
+/*Description:
+ * Return 4-byte value in host byte ordering from
+ * 4-byte pointer in little-endian system.
+ */
+#define LE_P4BYTE_TO_HOST_4BYTE(__pstart) \
+       (EF4BYTE(*((__le32 *)(__pstart))))
+#define LE_P2BYTE_TO_HOST_2BYTE(__pstart) \
+       (EF2BYTE(*((__le16 *)(__pstart))))
+#define LE_P1BYTE_TO_HOST_1BYTE(__pstart) \
+       (EF1BYTE(*((u8 *)(__pstart))))
+
+/*Description:
+Translate subfield (continuous bits in little-endian) of 4-byte
+value to host byte ordering.*/
+#define LE_BITS_TO_4BYTE(__pstart, __bitoffset, __bitlen) \
+       ( \
+               (LE_P4BYTE_TO_HOST_4BYTE(__pstart) >> (__bitoffset))  & \
+               BIT_LEN_MASK_32(__bitlen) \
+       )
+#define LE_BITS_TO_2BYTE(__pstart, __bitoffset, __bitlen) \
+       ( \
+               (LE_P2BYTE_TO_HOST_2BYTE(__pstart) >> (__bitoffset)) & \
+               BIT_LEN_MASK_16(__bitlen) \
+       )
+#define LE_BITS_TO_1BYTE(__pstart, __bitoffset, __bitlen) \
+       ( \
+               (LE_P1BYTE_TO_HOST_1BYTE(__pstart) >> (__bitoffset)) & \
+               BIT_LEN_MASK_8(__bitlen) \
+       )
+
+/* Description:
+ * Mask subfield (continuous bits in little-endian) of 4-byte value
+ * and return the result in 4-byte value in host byte ordering.
+ */
+#define LE_BITS_CLEARED_TO_4BYTE(__pstart, __bitoffset, __bitlen) \
+       ( \
+               LE_P4BYTE_TO_HOST_4BYTE(__pstart)  & \
+               (~BIT_OFFSET_LEN_MASK_32(__bitoffset, __bitlen)) \
+       )
+#define LE_BITS_CLEARED_TO_2BYTE(__pstart, __bitoffset, __bitlen) \
+       ( \
+               LE_P2BYTE_TO_HOST_2BYTE(__pstart) & \
+               (~BIT_OFFSET_LEN_MASK_16(__bitoffset, __bitlen)) \
+       )
+#define LE_BITS_CLEARED_TO_1BYTE(__pstart, __bitoffset, __bitlen) \
+       ( \
+               LE_P1BYTE_TO_HOST_1BYTE(__pstart) & \
+               (~BIT_OFFSET_LEN_MASK_8(__bitoffset, __bitlen)) \
+       )
+
+/* Description:
+ * Set subfield of little-endian 4-byte value to specified value.
+ */
+#define SET_BITS_TO_LE_4BYTE(__pstart, __bitoffset, __bitlen, __val) \
+       *((u32 *)(__pstart)) = \
+       ( \
+               LE_BITS_CLEARED_TO_4BYTE(__pstart, __bitoffset, __bitlen) | \
+               ((((u32)__val) & BIT_LEN_MASK_32(__bitlen)) << (__bitoffset)) \
+       );
+#define SET_BITS_TO_LE_2BYTE(__pstart, __bitoffset, __bitlen, __val) \
+       *((u16 *)(__pstart)) = \
+       ( \
+               LE_BITS_CLEARED_TO_2BYTE(__pstart, __bitoffset, __bitlen) | \
+               ((((u16)__val) & BIT_LEN_MASK_16(__bitlen)) << (__bitoffset)) \
+       );
+#define SET_BITS_TO_LE_1BYTE(__pstart, __bitoffset, __bitlen, __val) \
+       *((u8 *)(__pstart)) = EF1BYTE \
+       ( \
+               LE_BITS_CLEARED_TO_1BYTE(__pstart, __bitoffset, __bitlen) | \
+               ((((u8)__val) & BIT_LEN_MASK_8(__bitlen)) << (__bitoffset)) \
+       );
+
+#define        N_BYTE_ALIGMENT(__value, __aligment) ((__aligment == 1) ? \
+       (__value) : (((__value + __aligment - 1) / __aligment) * __aligment))
+
+/****************************************
+       mem access macro define end
+****************************************/
+
+#define byte(x , n) ((x >> (8 * n)) & 0xff)
+
+#define packet_get_type(_packet) (EF1BYTE((_packet).octet[0]) & 0xFC)
+#define RTL_WATCH_DOG_TIME     2000
+#define MSECS(t)               msecs_to_jiffies(t)
+#define WLAN_FC_GET_VERS(fc)   (le16_to_cpu(fc) & IEEE80211_FCTL_VERS)
+#define WLAN_FC_GET_TYPE(fc)   (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE)
+#define WLAN_FC_GET_STYPE(fc)  (le16_to_cou(fc) & IEEE80211_FCTL_STYPE)
+#define WLAN_FC_MORE_DATA(fc)  (le16_to_cpu(fc) & IEEE80211_FCTL_MOREDATA)
+#define SEQ_TO_SN(seq)         (((seq) & IEEE80211_SCTL_SEQ) >> 4)
+#define SN_TO_SEQ(ssn)         (((ssn) << 4) & IEEE80211_SCTL_SEQ)
+#define MAX_SN                 ((IEEE80211_SCTL_SEQ) >> 4)
+
+#define        RT_RF_OFF_LEVL_ASPM             BIT(0)  /*PCI ASPM */
+#define        RT_RF_OFF_LEVL_CLK_REQ          BIT(1)  /*PCI clock request */
+#define        RT_RF_OFF_LEVL_PCI_D3           BIT(2)  /*PCI D3 mode */
+/*NIC halt, re-initialize hw parameters*/
+#define        RT_RF_OFF_LEVL_HALT_NIC         BIT(3)
+#define        RT_RF_OFF_LEVL_FREE_FW          BIT(4)  /*FW free, re-download the FW */
+#define        RT_RF_OFF_LEVL_FW_32K           BIT(5)  /*FW in 32k */
+/*Always enable ASPM and Clock Req in initialization.*/
+#define        RT_RF_PS_LEVEL_ALWAYS_ASPM      BIT(6)
+/* no matter RFOFF or SLEEP we set PS_ASPM_LEVL*/
+#define        RT_PS_LEVEL_ASPM                BIT(7)
+/*When LPS is on, disable 2R if no packet is received or transmittd.*/
+#define        RT_RF_LPS_DISALBE_2R            BIT(30)
+#define        RT_RF_LPS_LEVEL_ASPM            BIT(31) /*LPS with ASPM */
+#define        RT_IN_PS_LEVEL(ppsc, _ps_flg)           \
+       ((ppsc->cur_ps_level & _ps_flg) ? true : false)
+#define        RT_CLEAR_PS_LEVEL(ppsc, _ps_flg)        \
+       (ppsc->cur_ps_level &= (~(_ps_flg)))
+#define        RT_SET_PS_LEVEL(ppsc, _ps_flg)          \
+       (ppsc->cur_ps_level |= _ps_flg)
+
+#define container_of_dwork_rtl(x , y , z) \
+       container_of(container_of(x, struct delayed_work, work), y, z)
+
+#define FILL_OCTET_STRING(_os , _octet , _len) \
+               (_os).octet = (u8 *)(_octet);           \
+               (_os).length = (_len);
+
+#define CP_MACADDR(des , src)  \
+       ((des)[0] = (src)[0] , (des)[1] = (src)[1],\
+       (des)[2] = (src)[2] , (des)[3] = (src)[3],\
+       (des)[4] = (src)[4] , (des)[5] = (src)[5])
+
+#define        LDPC_HT_ENABLE_RX                       BIT(0)
+#define        LDPC_HT_ENABLE_TX                       BIT(1)
+#define        LDPC_HT_TEST_TX_ENABLE                  BIT(2)
+#define        LDPC_HT_CAP_TX                          BIT(3)
+
+#define        STBC_HT_ENABLE_RX                       BIT(0)
+#define        STBC_HT_ENABLE_TX                       BIT(1)
+#define        STBC_HT_TEST_TX_ENABLE                  BIT(2)
+#define        STBC_HT_CAP_TX                          BIT(3)
+
+
+#define        LDPC_VHT_ENABLE_RX                      BIT(0)
+#define        LDPC_VHT_ENABLE_TX                      BIT(1)
+#define        LDPC_VHT_TEST_TX_ENABLE                 BIT(2)
+#define        LDPC_VHT_CAP_TX                         BIT(3)
+
+#define        STBC_VHT_ENABLE_RX                      BIT(0)
+#define        STBC_VHT_ENABLE_TX                      BIT(1)
+#define        STBC_VHT_TEST_TX_ENABLE                 BIT(2)
+#define        STBC_VHT_CAP_TX                         BIT(3)
+
+
+static inline u8 rtl_read_byte(struct rtl_priv *rtlpriv, u32 addr)
+{
+       return rtlpriv->io.read8_sync(rtlpriv, addr);
+}
+
+static inline u16 rtl_read_word(struct rtl_priv *rtlpriv, u32 addr)
+{
+       return rtlpriv->io.read16_sync(rtlpriv, addr);
+}
+
+static inline u32 rtl_read_dword(struct rtl_priv *rtlpriv, u32 addr)
+{
+       return rtlpriv->io.read32_sync(rtlpriv, addr);
+}
+
+static inline void rtl_write_byte(struct rtl_priv *rtlpriv, u32 addr, u8 val8)
+{
+       rtlpriv->io.write8_async(rtlpriv, addr, val8);
+
+       if (rtlpriv->cfg->write_readback)
+               rtlpriv->io.read8_sync(rtlpriv, addr);
+}
+
+static inline void rtl_write_word(struct rtl_priv *rtlpriv, u32 addr, u16 val16)
+{
+       rtlpriv->io.write16_async(rtlpriv, addr, val16);
+
+       if (rtlpriv->cfg->write_readback)
+               rtlpriv->io.read16_sync(rtlpriv, addr);
+}
+
+static inline void rtl_write_dword(struct rtl_priv *rtlpriv,
+                                  u32 addr, u32 val32)
+{
+       rtlpriv->io.write32_async(rtlpriv, addr, val32);
+
+       if (rtlpriv->cfg->write_readback)
+               rtlpriv->io.read32_sync(rtlpriv, addr);
+}
+
+static inline u32 rtl_get_bbreg(struct ieee80211_hw *hw,
+                               u32 regaddr, u32 bitmask)
+{
+       return ((struct rtl_priv *)(hw)->priv)->cfg->ops->get_bbreg(hw,
+                                                                   regaddr,
+                                                                   bitmask);
+}
+
+static inline void rtl_set_bbreg(struct ieee80211_hw *hw, u32 regaddr,
+                                u32 bitmask, u32 data)
+{
+       struct rtl_priv *rtlpriv = hw->priv;
+
+       rtlpriv->cfg->ops->set_bbreg(hw, regaddr, bitmask, data);
+}
+
+static inline u32 rtl_get_rfreg(struct ieee80211_hw *hw,
+                               enum radio_path rfpath, u32 regaddr,
+                               u32 bitmask)
+{
+       return ((struct rtl_priv *)(hw)->priv)->cfg->ops->get_rfreg(hw,
+                                                                   rfpath,
+                                                                   regaddr,
+                                                                   bitmask);
+}
+
+static inline void rtl_set_rfreg(struct ieee80211_hw *hw,
+                                enum radio_path rfpath, u32 regaddr,
+                                u32 bitmask, u32 data)
+{
+       ((struct rtl_priv *)(hw)->priv)->cfg->ops->set_rfreg(hw,
+                                                            rfpath, regaddr,
+                                                            bitmask, data);
+}
+
+static inline bool is_hal_stop(struct rtl_hal *rtlhal)
+{
+       return _HAL_STATE_STOP == rtlhal->state;
+}
+
+static inline void set_hal_start(struct rtl_hal *rtlhal)
+{
+       rtlhal->state = _HAL_STATE_START;
+}
+
+static inline void set_hal_stop(struct rtl_hal *rtlhal)
+{
+       rtlhal->state = _HAL_STATE_STOP;
+}
+
+static inline u8 get_rf_type(struct rtl_phy *rtlphy)
+{
+       return rtlphy->rf_type;
+}
+
+static inline struct ieee80211_hdr *rtl_get_hdr(struct sk_buff *skb)
+{
+       return (struct ieee80211_hdr *)(skb->data);
+}
+
+static inline __le16 rtl_get_fc(struct sk_buff *skb)
+{
+       return rtl_get_hdr(skb)->frame_control;
+}
+
+static inline u16 rtl_get_tid_h(struct ieee80211_hdr *hdr)
+{
+       return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK;
+}
+
+static inline u16 rtl_get_tid(struct sk_buff *skb)
+{
+       return rtl_get_tid_h(rtl_get_hdr(skb));
+}
+
+static inline struct ieee80211_sta *rtl_find_sta(struct ieee80211_hw *hw,
+                                                u8 *mac_addr)
+{
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       return ieee80211_find_sta(mac->vif, mac_addr);
+}
+
+struct ieee80211_hw *rtl_pci_get_hw_pointer(void);
+#endif